diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md index 9ccda17a6ef47..1d93939e23360 100644 --- a/.github/ISSUE_TEMPLATE/documentation.md +++ b/.github/ISSUE_TEMPLATE/documentation.md @@ -4,28 +4,13 @@ about: Create a report for a documentation problem. labels: A-docs --- ### Location ### Summary + diff --git a/.gitmodules b/.gitmodules index cca60e337d2d8..a524098845a48 100644 --- a/.gitmodules +++ b/.gitmodules @@ -38,6 +38,9 @@ [submodule "src/doc/embedded-book"] path = src/doc/embedded-book url = https://github.com/rust-embedded/book.git +[submodule "src/tools/rust-analyzer"] + path = src/tools/rust-analyzer + url = https://github.com/rust-analyzer/rust-analyzer.git [submodule "library/backtrace"] path = library/backtrace url = https://github.com/rust-lang/backtrace-rs.git diff --git a/Cargo.lock b/Cargo.lock index 58c3982de2333..db8e3d5adbb9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -202,9 +202,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.3.2" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "bitmaps" @@ -319,9 +319,9 @@ checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da" [[package]] name = "camino" -version = "1.0.9" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" +checksum = "52d74260d9bf6944e2208aa46841b4b8f0d7ffc0849a06837b2f510337f86b2b" dependencies = [ "serde", ] @@ -506,19 +506,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "cargo_metadata" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36" -dependencies = [ - "camino", - "cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "semver", - "serde", - "serde_json", -] - [[package]] name = "cargotest2" version = "0.1.0" @@ -689,7 +676,6 @@ dependencies = [ "tester", "tokio", "toml", - "walkdir", ] [[package]] @@ -710,7 +696,7 @@ dependencies = [ name = "clippy_lints" version = "0.1.64" dependencies = [ - "cargo_metadata 0.14.0", + "cargo_metadata", "clippy_utils", "if_chain", "itertools", @@ -1727,9 +1713,18 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758" dependencies = [ "ahash", "compiler_builtins", @@ -1888,12 +1883,12 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "1.9.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.11.2", "rustc-rayon", "serde", ] @@ -1964,9 +1959,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.2" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" [[package]] name = "jemalloc-sys" @@ -2353,9 +2348,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.21" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23f3e133c6d515528745ffd3b9f0c7d975ae039f0b6abb099f2168daa2afb4f9" +checksum = "13cdad8057b09a519c6c63e6d7c93ea854f5d7fbfe284df864d5e1140d215a2d" dependencies = [ "ammonia", "anyhow", @@ -2381,9 +2376,9 @@ dependencies = [ [[package]] name = "measureme" -version = "10.1.0" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbdc226fa10994e8f66a4d2f6f000148bc563a1c671b6dcd2135737018033d8a" +checksum = "bd460fad6e55ca82fa0cd9dab0d315294188fd9ec6efbf4105e5635d4872ef9c" dependencies = [ "log", "memmap2", @@ -2395,9 +2390,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -2568,6 +2563,19 @@ dependencies = [ "rustc-std-workspace-core", ] +[[package]] +name = "object" +version = "0.28.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +dependencies = [ + "crc32fast", + "flate2", + "hashbrown 0.11.2", + "indexmap", + "memchr", +] + [[package]] name = "object" version = "0.29.0" @@ -2575,8 +2583,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ "crc32fast", - "flate2", - "hashbrown", + "hashbrown 0.12.0", "indexmap", "memchr", ] @@ -3045,9 +3052,9 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.9.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63" +checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6" dependencies = [ "bitflags", "memchr", @@ -3309,7 +3316,7 @@ dependencies = [ "anyhow", "cargo", "cargo-util", - "cargo_metadata 0.14.0", + "cargo_metadata", "clippy_lints", "crossbeam-channel", "difference", @@ -4499,7 +4506,6 @@ dependencies = [ name = "rustc_symbol_mangling" version = "0.0.0" dependencies = [ - "bitflags", "punycode", "rustc-demangle", "rustc_data_structures", @@ -4717,7 +4723,7 @@ dependencies = [ "annotate-snippets 0.9.1", "anyhow", "bytecount", - "cargo_metadata 0.14.0", + "cargo_metadata", "clap", "derive-new", "diff", @@ -4815,27 +4821,27 @@ checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af" [[package]] name = "semver" -version = "1.0.12" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" +checksum = "5f3aac57ee7f3272d8395c6e4f502f434f0e289fcd62876f70daa008c20dcabe" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.140" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.140" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2", "quote", @@ -4853,9 +4859,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.82" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" dependencies = [ "indexmap", "itoa", @@ -5048,7 +5054,7 @@ dependencies = [ "core", "dlmalloc", "fortanix-sgx-abi", - "hashbrown", + "hashbrown 0.12.0", "hermit-abi 0.2.0", "libc", "miniz_oxide 0.4.0", @@ -5259,13 +5265,13 @@ dependencies = [ [[package]] name = "thorin-dwp" -version = "0.3.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6cb0c7868d7f90407531108ab03263d9452a8811b7cdd87675343a40d4aa254" +checksum = "dd95b4559c196987c8451b4e14d08a4c796c2844f9adf4d2a2dbc9b3142843be" dependencies = [ "gimli 0.26.1", - "hashbrown", - "object 0.29.0", + "hashbrown 0.11.2", + "object 0.28.4", "tracing", ] @@ -5282,7 +5288,7 @@ dependencies = [ name = "tidy" version = "0.1.0" dependencies = [ - "cargo_metadata 0.14.0", + "cargo_metadata", "crossbeam-utils", "lazy_static", "regex", @@ -5512,7 +5518,6 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" name = "ui_test" version = "0.1.0" dependencies = [ - "cargo_metadata 0.15.0", "color-eyre", "colored", "crossbeam", diff --git a/Cargo.toml b/Cargo.toml index ffc886d47f399..ed024192c1503 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,7 +60,7 @@ exclude = [ # verify that this is the case. This requires, however, that the crate is built # without overflow checks and debug assertions. Forcefully disable debug # assertions and overflow checks here which should ensure that even if these -# assertions are enabled for libstd we won't enable them for compiler_builtins +# assertions are enabled for libstd we won't enable then for compiler_builtins # which should ensure we still link everything correctly. debug-assertions = false overflow-checks = false diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 4166b4fc2e5bc..cd77dbca3c440 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -4,7 +4,8 @@ use super::LoweringContext; use rustc_ast::ptr::P; use rustc_ast::*; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a1bf0f94964bb..7cd360623ec42 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1835,6 +1835,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { debug!(?self.captured_lifetimes); let name = match res { LifetimeRes::Param { mut param, binder } => { + debug_assert_ne!(ident.name, kw::UnderscoreLifetime); let p_name = ParamName::Plain(ident); if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() { if !captured_lifetimes.binders_to_ignore.contains(&binder) { @@ -1883,7 +1884,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } hir::LifetimeName::Param(param, ParamName::Fresh) } - LifetimeRes::Infer => hir::LifetimeName::Infer, + LifetimeRes::Anonymous { binder, elided } => { + let mut l_name = None; + if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() { + if !captured_lifetimes.binders_to_ignore.contains(&binder) { + let p_id = self.next_node_id(); + let p_def_id = self.create_def( + captured_lifetimes.parent_def_id, + p_id, + DefPathData::LifetimeNs(kw::UnderscoreLifetime), + ); + captured_lifetimes + .captures + .insert(p_def_id, (span, p_id, ParamName::Fresh, res)); + l_name = Some(hir::LifetimeName::Param(p_def_id, ParamName::Fresh)); + } + self.captured_lifetimes = Some(captured_lifetimes); + }; + l_name.unwrap_or(if elided { + hir::LifetimeName::Implicit + } else { + hir::LifetimeName::Underscore + }) + } LifetimeRes::Static => hir::LifetimeName::Static, LifetimeRes::Error => hir::LifetimeName::Error, res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span), diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 60560b1c00e25..334326e927fad 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1272,7 +1272,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.visit_vis(&item.vis); self.visit_ident(item.ident); self.visit_generics(generics); - self.with_tilde_const_allowed(|this| { + self.with_banned_tilde_const(|this| { walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) }); walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait); diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 10a9cfb626e63..64a6f91f02206 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -138,7 +138,7 @@ pub enum StabilityLevel { /// `#[unstable]` Unstable { /// Reason for the current stability level. - reason: UnstableReason, + reason: Option, /// Relevant `rust-lang/rust` issue. issue: Option, is_soft: bool, @@ -182,32 +182,6 @@ impl StabilityLevel { } } -#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] -#[derive(HashStable_Generic)] -pub enum UnstableReason { - None, - Default, - Some(Symbol), -} - -impl UnstableReason { - fn from_opt_reason(reason: Option) -> Self { - // UnstableReason::Default constructed manually - match reason { - Some(r) => Self::Some(r), - None => Self::None, - } - } - - pub fn to_opt_reason(&self) -> Option { - match self { - Self::None => None, - Self::Default => Some(sym::unstable_location_reason_default), - Self::Some(r) => Some(*r), - } - } -} - /// Collects stability info from all stability attributes in `attrs`. /// Returns `None` if no stability attributes are found. pub fn find_stability( @@ -397,12 +371,7 @@ where ); continue; } - let level = Unstable { - reason: UnstableReason::from_opt_reason(reason), - issue: issue_num, - is_soft, - implied_by, - }; + let level = Unstable { reason, issue: issue_num, is_soft, implied_by }; if sym::unstable == meta_name { stab = Some((Stability { level, feature }, attr.span)); } else { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 176090c3b7a14..0e6a05478a07e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1,6 +1,6 @@ //! Error reporting machinery for lifetime errors. -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; @@ -78,8 +78,6 @@ pub(crate) enum RegionErrorKind<'tcx> { span: Span, /// The hidden type. hidden_ty: Ty<'tcx>, - /// The opaque type. - key: ty::OpaqueTypeKey<'tcx>, /// The unexpected region. member_region: ty::Region<'tcx>, }, @@ -207,16 +205,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, key, member_region } => { + RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, member_region } => { let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty); - let named_key = self.regioncx.name_regions(self.infcx.tcx, key); let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region); self.buffer_error(unexpected_hidden_region_diagnostic( self.infcx.tcx, span, named_ty, named_region, - named_key, )); } @@ -854,11 +850,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { debug!("trait spans found: {:?}", traits); for span in &traits { let mut multi_span: MultiSpan = vec![*span].into(); - multi_span - .push_span_label(*span, "this has an implicit `'static` lifetime requirement"); + multi_span.push_span_label( + *span, + "this has an implicit `'static` lifetime requirement".to_string(), + ); multi_span.push_span_label( ident.span, - "calling this method introduces the `impl`'s 'static` requirement", + "calling this method introduces the `impl`'s 'static` requirement".to_string(), ); err.span_note(multi_span, "the used `impl` has a `'static` requirement"); err.span_suggestion_verbose( diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 0662d4d882f6a..4cf1ac4d7abc0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -589,7 +589,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { hir::LifetimeName::Param(_, hir::ParamName::Fresh) | hir::LifetimeName::ImplicitObjectLifetimeDefault - | hir::LifetimeName::Infer => { + | hir::LifetimeName::Implicit + | hir::LifetimeName::Underscore => { // In this case, the user left off the lifetime; so // they wrote something like: // diff --git a/compiler/rustc_borrowck/src/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs index 43253a2aab00c..e91fcf1472df1 100644 --- a/compiler/rustc_borrowck/src/member_constraints.rs +++ b/compiler/rustc_borrowck/src/member_constraints.rs @@ -38,8 +38,6 @@ pub(crate) struct NllMemberConstraint<'tcx> { /// The hidden type in which `R0` appears. (Used in error reporting.) pub(crate) hidden_ty: Ty<'tcx>, - pub(crate) key: ty::OpaqueTypeKey<'tcx>, - /// The region `R0`. pub(crate) member_region_vid: ty::RegionVid, @@ -92,7 +90,6 @@ impl<'tcx> MemberConstraintSet<'tcx, ty::RegionVid> { member_region_vid, definition_span: m_c.definition_span, hidden_ty: m_c.hidden_ty, - key: m_c.key, start_index, end_index, }); diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 2894c6d29ec43..9040cfcf54f41 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1763,7 +1763,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { errors_buffer.push(RegionErrorKind::UnexpectedHiddenRegion { span: m_c.definition_span, hidden_ty: m_c.hidden_ty, - key: m_c.key, member_region, }); } diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index d6712b6a4799c..407bbf48813c3 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -246,7 +246,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // after producing an error for each of them. let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new( self.tcx, - opaque_type_key, + def_id, map, instantiated_ty.ty, instantiated_ty.span, @@ -429,7 +429,7 @@ fn check_opaque_type_parameter_valid( struct ReverseMapper<'tcx> { tcx: TyCtxt<'tcx>, - key: ty::OpaqueTypeKey<'tcx>, + opaque_type_def_id: LocalDefId, map: FxHashMap, GenericArg<'tcx>>, map_missing_regions_to_empty: bool, @@ -443,14 +443,14 @@ struct ReverseMapper<'tcx> { impl<'tcx> ReverseMapper<'tcx> { fn new( tcx: TyCtxt<'tcx>, - key: ty::OpaqueTypeKey<'tcx>, + opaque_type_def_id: LocalDefId, map: FxHashMap, GenericArg<'tcx>>, hidden_ty: Ty<'tcx>, span: Span, ) -> Self { Self { tcx, - key, + opaque_type_def_id, map, map_missing_regions_to_empty: false, hidden_ty: Some(hidden_ty), @@ -504,7 +504,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { } } - let generics = self.tcx().generics_of(self.key.def_id); + let generics = self.tcx().generics_of(self.opaque_type_def_id); match self.map.get(&r.into()).map(|k| k.unpack()) { Some(GenericArgKind::Lifetime(r1)) => r1, Some(u) => panic!("region mapped to unexpected kind: {:?}", u), @@ -513,10 +513,9 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { if let Some(hidden_ty) = self.hidden_ty.take() { unexpected_hidden_region_diagnostic( self.tcx, - self.tcx.def_span(self.key.def_id), + self.tcx.def_span(self.opaque_type_def_id), hidden_ty, r, - self.key, ) .emit(); } diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 167960918308c..3f9c0cecccc68 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -22,16 +22,6 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, tcx: TyCtxt<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, - /// Each RBP `GK: 'a` is assumed to be true. These encode - /// relationships like `T: 'a` that are added via implicit bounds - /// or the `param_env`. - /// - /// Each region here is guaranteed to be a key in the `indices` - /// map. We use the "original" regions (i.e., the keys from the - /// map, and not the values) because the code in - /// `process_registered_region_obligations` has some special-cased - /// logic expecting to see (e.g.) `ReStatic`, and if we supplied - /// our special inference variable there, we would mess that up. region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index cc0318ede54a0..fe66821ad752b 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -2,7 +2,6 @@ use rustc_data_structures::frozen::Frozen; use rustc_data_structures::transitive_relation::TransitiveRelation; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives; -use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::region_constraints::GenericKind; use rustc_infer::infer::InferCtxt; use rustc_middle::mir::ConstraintCategory; @@ -35,6 +34,18 @@ pub(crate) struct UniversalRegionRelations<'tcx> { inverse_outlives: TransitiveRelation, } +/// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to +/// be true. These encode relationships like `T: 'a` that are +/// added via implicit bounds. +/// +/// Each region here is guaranteed to be a key in the `indices` +/// map. We use the "original" regions (i.e., the keys from the +/// map, and not the values) because the code in +/// `process_registered_region_obligations` has some special-cased +/// logic expecting to see (e.g.) `ReStatic`, and if we supplied +/// our special inference variable there, we would mess that up. +type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>; + /// As part of computing the free region relations, we also have to /// normalize the input-output types, which we then need later. So we /// return those. This vector consists of first the input types and @@ -60,7 +71,7 @@ pub(crate) fn create<'tcx>( implicit_region_bound, constraints, universal_regions: universal_regions.clone(), - region_bound_pairs: Default::default(), + region_bound_pairs: Vec::new(), relations: UniversalRegionRelations { universal_regions: universal_regions.clone(), outlives: Default::default(), @@ -360,13 +371,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { } OutlivesBound::RegionSubParam(r_a, param_b) => { - self.region_bound_pairs - .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a)); + self.region_bound_pairs.push((r_a, GenericKind::Param(param_b))); } OutlivesBound::RegionSubProjection(r_a, projection_b) => { - self.region_bound_pairs - .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a)); + self.region_bound_pairs.push((r_a, GenericKind::Projection(projection_b))); } } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index cf2140097e6da..eb9df281e7d24 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -21,6 +21,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi use rustc_infer::infer::{ InferCtxt, InferOk, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin, }; +use rustc_infer::traits::ObligationCause; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::AssertKind; @@ -224,6 +225,26 @@ pub(crate) fn type_check<'mir, 'tcx>( ) .unwrap(); let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type); + // Check that RPITs are only constrained in their outermost + // function, otherwise report a mismatched types error. + if let OpaqueTyOrigin::FnReturn(parent) | OpaqueTyOrigin::AsyncFn(parent) + = infcx.opaque_ty_origin_unchecked(opaque_type_key.def_id, hidden_type.span) + && parent.to_def_id() != body.source.def_id() + { + infcx + .report_mismatched_types( + &ObligationCause::misc( + hidden_type.span, + infcx.tcx.hir().local_def_id_to_hir_id( + body.source.def_id().expect_local(), + ), + ), + infcx.tcx.mk_opaque(opaque_type_key.def_id.to_def_id(), opaque_type_key.substs), + hidden_type.ty, + ty::error::TypeError::Mismatch, + ) + .emit(); + } trace!( "finalized opaque type {:?} to {:#?}", opaque_type_key, diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index a2205c3613d92..829eaa305e8c0 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -656,7 +656,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option { + parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => { if idx >= args.operands.len() || named_pos.contains_key(&idx) || args.reg_args.contains(&idx) diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 082c78934262b..3b7e2102ffa9b 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -11,11 +11,12 @@ use rustc_errors::{pluralize, Applicability, MultiSpan, PResult}; use rustc_expand::base::{self, *}; use rustc_parse_format as parse; use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{BytePos, InnerSpan, Span}; +use rustc_span::{InnerSpan, Span}; use smallvec::SmallVec; use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId}; +use rustc_parse_format::Count; use std::borrow::Cow; use std::collections::hash_map::Entry; @@ -31,136 +32,6 @@ enum Position { Named(Symbol, InnerSpan), } -/// Indicates how positional named argument (i.e. an named argument which is used by position -/// instead of by name) is used in format string -/// * `Arg` is the actual argument to print -/// * `Width` is width format argument -/// * `Precision` is precion format argument -/// Example: `{Arg:Width$.Precision$} -#[derive(Debug, Eq, PartialEq)] -enum PositionalNamedArgType { - Arg, - Width, - Precision, -} - -/// Contains information necessary to create a lint for a positional named argument -#[derive(Debug)] -struct PositionalNamedArg { - ty: PositionalNamedArgType, - /// The piece of the using this argument (multiple pieces can use the same argument) - cur_piece: usize, - /// The InnerSpan for in the string to be replaced with the named argument - /// This will be None when the position is implicit - inner_span_to_replace: Option, - /// The name to use instead of the position - replacement: Symbol, - /// The span for the positional named argument (so the lint can point a message to it) - positional_named_arg_span: Span, -} - -impl PositionalNamedArg { - /// Determines what span to replace with the name of the named argument - fn get_span_to_replace(&self, cx: &Context<'_, '_>) -> Option { - if let Some(inner_span) = &self.inner_span_to_replace { - return Some( - cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end }), - ); - } else if self.ty == PositionalNamedArgType::Arg { - // In the case of a named argument whose position is implicit, there will not be a span - // to replace. Instead, we insert the name after the `{`, which is the first character - // of arg_span. - return cx - .arg_spans - .get(self.cur_piece) - .map(|arg_span| arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo()); - } - - None - } -} - -/// Encapsulates all the named arguments that have been used positionally -#[derive(Debug)] -struct PositionalNamedArgsLint { - positional_named_args: Vec, -} - -impl PositionalNamedArgsLint { - /// For a given positional argument, check if the index is for a named argument. - /// - /// Since positional arguments are required to come before named arguments, if the positional - /// index is greater than or equal to the start of named arguments, we know it's a named - /// argument used positionally. - /// - /// Example: - /// println!("{} {} {2}", 0, a=1, b=2); - /// - /// In this case, the first piece (`{}`) would be ArgumentImplicitlyIs with an index of 0. The - /// total number of arguments is 3 and the number of named arguments is 2, so the start of named - /// arguments is index 1. Therefore, the index of 0 is okay. - /// - /// The second piece (`{}`) would be ArgumentImplicitlyIs with an index of 1, which is the start - /// of named arguments, and so we should add a lint to use the named argument `a`. - /// - /// The third piece (`{2}`) would be ArgumentIs with an index of 2, which is greater than the - /// start of named arguments, and so we should add a lint to use the named argument `b`. - /// - /// This same check also works for width and precision formatting when either or both are - /// CountIsParam, which contains an index into the arguments. - fn maybe_add_positional_named_arg( - &mut self, - current_positional_arg: usize, - total_args_length: usize, - format_argument_index: usize, - ty: PositionalNamedArgType, - cur_piece: usize, - inner_span_to_replace: Option, - names: &FxHashMap, - ) { - let start_of_named_args = total_args_length - names.len(); - if current_positional_arg >= start_of_named_args { - self.maybe_push(format_argument_index, ty, cur_piece, inner_span_to_replace, names) - } - } - - /// Try constructing a PositionalNamedArg struct and pushing it into the vec of positional - /// named arguments. If a named arg associated with `format_argument_index` cannot be found, - /// a new item will not be added as the lint cannot be emitted in this case. - fn maybe_push( - &mut self, - format_argument_index: usize, - ty: PositionalNamedArgType, - cur_piece: usize, - inner_span_to_replace: Option, - names: &FxHashMap, - ) { - let named_arg = names - .iter() - .find(|&(_, &(index, _))| index == format_argument_index) - .map(|found| found.clone()); - - if let Some((&replacement, &(_, positional_named_arg_span))) = named_arg { - // In FormatSpec, `precision_span` starts at the leading `.`, which we want to keep in - // the lint suggestion, so increment `start` by 1 when `PositionalArgumentType` is - // `Precision`. - let inner_span_to_replace = if ty == PositionalNamedArgType::Precision { - inner_span_to_replace - .map(|is| rustc_parse_format::InnerSpan { start: is.start + 1, end: is.end }) - } else { - inner_span_to_replace - }; - self.positional_named_args.push(PositionalNamedArg { - ty, - cur_piece, - inner_span_to_replace, - replacement, - positional_named_arg_span, - }); - } - } -} - struct Context<'a, 'b> { ecx: &'a mut ExtCtxt<'b>, /// The macro's call site. References to unstable formatting internals must @@ -247,7 +118,6 @@ struct Context<'a, 'b> { /// Whether this format string came from a string literal, as opposed to a macro. is_literal: bool, - unused_names_lint: PositionalNamedArgsLint, } /// Parses the arguments from the given list of tokens, returning the diagnostic @@ -372,7 +242,7 @@ impl<'a, 'b> Context<'a, 'b> { self.args.len() - self.num_captured_args } - fn resolve_name_inplace(&mut self, p: &mut parse::Piece<'_>) { + fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) { // NOTE: the `unwrap_or` branch is needed in case of invalid format // arguments, e.g., `format_args!("{foo}")`. let lookup = @@ -382,7 +252,7 @@ impl<'a, 'b> Context<'a, 'b> { parse::String(_) => {} parse::NextArgument(ref mut arg) => { if let parse::ArgumentNamed(s, _) = arg.position { - arg.position = parse::ArgumentIs(lookup(s), None); + arg.position = parse::ArgumentIs(lookup(s)); } if let parse::CountIsName(s, _) = arg.format.width { arg.format.width = parse::CountIsParam(lookup(s)); @@ -403,48 +273,15 @@ impl<'a, 'b> Context<'a, 'b> { parse::NextArgument(ref arg) => { // width/precision first, if they have implicit positional // parameters it makes more sense to consume them first. - self.verify_count( - arg.format.width, - &arg.format.width_span, - PositionalNamedArgType::Width, - ); - self.verify_count( - arg.format.precision, - &arg.format.precision_span, - PositionalNamedArgType::Precision, - ); + self.verify_count(arg.format.width); + self.verify_count(arg.format.precision); // argument second, if it's an implicit positional parameter // it's written second, so it should come after width/precision. let pos = match arg.position { - parse::ArgumentIs(i, arg_end) => { - self.unused_names_lint.maybe_add_positional_named_arg( - i, - self.args.len(), - i, - PositionalNamedArgType::Arg, - self.curpiece, - arg_end, - &self.names, - ); - - Exact(i) - } - parse::ArgumentImplicitlyIs(i) => { - self.unused_names_lint.maybe_add_positional_named_arg( - i, - self.args.len(), - i, - PositionalNamedArgType::Arg, - self.curpiece, - None, - &self.names, - ); - Exact(i) - } + parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i), parse::ArgumentNamed(s, span) => { - let symbol = Symbol::intern(s); - Named(symbol, InnerSpan::new(span.start, span.end)) + Named(Symbol::intern(s), InnerSpan::new(span.start, span.end)) } }; @@ -512,24 +349,10 @@ impl<'a, 'b> Context<'a, 'b> { } } - fn verify_count( - &mut self, - c: parse::Count<'_>, - inner_span: &Option, - named_arg_type: PositionalNamedArgType, - ) { + fn verify_count(&mut self, c: parse::Count<'_>) { match c { parse::CountImplied | parse::CountIs(..) => {} parse::CountIsParam(i) => { - self.unused_names_lint.maybe_add_positional_named_arg( - i, - self.args.len(), - i, - named_arg_type, - self.curpiece, - *inner_span, - &self.names, - ); self.verify_arg_type(Exact(i), Count); } parse::CountIsName(s, span) => { @@ -662,7 +485,7 @@ impl<'a, 'b> Context<'a, 'b> { if let Some(span) = fmt.width_span { let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end)); match fmt.width { - parse::CountIsParam(pos) if pos >= self.num_args() => { + parse::CountIsParam(pos) if pos > self.num_args() => { e.span_label( span, &format!( @@ -850,7 +673,7 @@ impl<'a, 'b> Context<'a, 'b> { // Build the position let pos = { match arg.position { - parse::ArgumentIs(i, ..) | parse::ArgumentImplicitlyIs(i) => { + parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => { // Map to index in final generated argument array // in case of multiple types specified let arg_idx = match arg_index_consumed.get_mut(i) { @@ -878,7 +701,7 @@ impl<'a, 'b> Context<'a, 'b> { // track the current argument ourselves. let i = self.curarg; self.curarg += 1; - parse::ArgumentIs(i, None) + parse::ArgumentIs(i) }, format: parse::FormatSpec { fill: arg.format.fill, @@ -1148,27 +971,45 @@ pub fn expand_format_args_nl<'cx>( expand_format_args_impl(ecx, sp, tts, true) } -fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>) { - for named_arg in &cx.unused_names_lint.positional_named_args { - let arg_span = named_arg.get_span_to_replace(cx); - - let msg = format!("named argument `{}` is not used by name", named_arg.replacement); - let replacement = match named_arg.ty { - PositionalNamedArgType::Arg => named_arg.replacement.to_string(), - _ => named_arg.replacement.to_string() + "$", - }; +fn lint_named_arguments_used_positionally( + names: FxHashMap, + cx: &mut Context<'_, '_>, + unverified_pieces: Vec>, +) { + let mut used_argument_names = FxHashSet::<&str>::default(); + for piece in unverified_pieces { + if let rustc_parse_format::Piece::NextArgument(a) = piece { + match a.position { + rustc_parse_format::Position::ArgumentNamed(arg_name, _) => { + used_argument_names.insert(arg_name); + } + _ => {} + }; + if let Count::CountIsName(s, _) = a.format.width { + used_argument_names.insert(s); + } + if let Count::CountIsName(s, _) = a.format.precision { + used_argument_names.insert(s); + } + } + } - cx.ecx.buffered_early_lint.push(BufferedEarlyLint { - span: MultiSpan::from_span(named_arg.positional_named_arg_span), - msg: msg.clone(), - node_id: ast::CRATE_NODE_ID, - lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY), - diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally( - arg_span, - named_arg.positional_named_arg_span, - replacement, - ), - }); + for (symbol, (index, span)) in names { + if !used_argument_names.contains(symbol.as_str()) { + let msg = format!("named argument `{}` is not used by name", symbol.as_str()); + let arg_span = cx.arg_spans.get(index).copied(); + cx.ecx.buffered_early_lint.push(BufferedEarlyLint { + span: MultiSpan::from_span(span), + msg: msg.clone(), + node_id: ast::CRATE_NODE_ID, + lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY), + diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally( + arg_span, + span, + symbol.to_string(), + ), + }); + } } } @@ -1280,6 +1121,11 @@ pub fn expand_preparsed_format_args( let named_pos: FxHashSet = names.values().cloned().map(|(i, _)| i).collect(); + // Clone `names` because `names` in Context get updated by verify_piece, which includes usages + // of the names of named arguments, resulting in incorrect errors if a name argument is used + // but not declared, such as: `println!("x = {x}");` + let named_arguments = names.clone(); + let mut cx = Context { ecx, args, @@ -1304,12 +1150,13 @@ pub fn expand_preparsed_format_args( arg_spans, arg_with_formatting: Vec::new(), is_literal: parser.is_literal, - unused_names_lint: PositionalNamedArgsLint { positional_named_args: vec![] }, }; - // This needs to happen *after* the Parser has consumed all pieces to create all the spans + // This needs to happen *after* the Parser has consumed all pieces to create all the spans. + // unverified_pieces is used later to check named argument names are used, so clone each piece. let pieces = unverified_pieces - .into_iter() + .iter() + .cloned() .map(|mut piece| { cx.verify_piece(&piece); cx.resolve_name_inplace(&mut piece); @@ -1319,7 +1166,7 @@ pub fn expand_preparsed_format_args( let numbered_position_args = pieces.iter().any(|arg: &parse::Piece<'_>| match *arg { parse::String(_) => false, - parse::NextArgument(arg) => matches!(arg.position, parse::Position::ArgumentIs(..)), + parse::NextArgument(arg) => matches!(arg.position, parse::Position::ArgumentIs(_)), }); cx.build_index_map(); @@ -1471,10 +1318,11 @@ pub fn expand_preparsed_format_args( } diag.emit(); - } else if cx.invalid_refs.is_empty() && cx.ecx.sess.err_count() == 0 { + } else if cx.invalid_refs.is_empty() && !named_arguments.is_empty() { // Only check for unused named argument names if there are no other errors to avoid causing // too much noise in output errors, such as when a named argument is entirely unused. - create_lints_for_named_arguments_used_positionally(&mut cx); + // We also only need to perform this check if there are actually named arguments. + lint_named_arguments_used_positionally(named_arguments, &mut cx, unverified_pieces); } cx.into_expr() diff --git a/compiler/rustc_codegen_cranelift/.vscode/settings.json b/compiler/rustc_codegen_cranelift/.vscode/settings.json index d88309e412ed0..ecb20f22d8c92 100644 --- a/compiler/rustc_codegen_cranelift/.vscode/settings.json +++ b/compiler/rustc_codegen_cranelift/.vscode/settings.json @@ -1,9 +1,10 @@ { // source for rustc_* is not included in the rust-src component; disable the errors about this "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"], - "rust-analyzer.imports.granularity.enforce": true, - "rust-analyzer.imports.granularity.group": "module", - "rust-analyzer.imports.prefix": "crate", + "rust-analyzer.assist.importGranularity": "module", + "rust-analyzer.assist.importEnforceGranularity": true, + "rust-analyzer.assist.importPrefix": "crate", + "rust-analyzer.cargo.runBuildScripts": true, "rust-analyzer.cargo.features": ["unstable-features"], "rust-analyzer.linkedProjects": [ "./Cargo.toml", diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 532049c858d4f..da18ac7eacbfc 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -2,17 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - [[package]] name = "anyhow" version = "1.0.56" @@ -36,12 +25,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - [[package]] name = "cfg-if" version = "1.0.0" @@ -50,57 +33,56 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.85.3" +version = "0.83.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "749d0d6022c9038dccf480bdde2a38d435937335bf2bb0f14e815d94517cdce8" +checksum = "ed44413e7e2fe3260d0ed73e6956ab188b69c10ee92b892e401e0f4f6808c68b" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.85.3" +version = "0.83.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94370cc7b37bf652ccd8bb8f09bd900997f7ccf97520edfc75554bb5c4abbea" +checksum = "0b5d83f0f26bf213f971f45589d17e5b65e4861f9ed22392b0cbb6eaa5bd329c" dependencies = [ "cranelift-bforest", "cranelift-codegen-meta", "cranelift-codegen-shared", "cranelift-entity", - "cranelift-isle", "gimli", "log", - "regalloc2", + "regalloc", "smallvec", "target-lexicon", ] [[package]] name = "cranelift-codegen-meta" -version = "0.85.3" +version = "0.83.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a3cea8fdab90e44018c5b9a1dfd460d8ee265ac354337150222a354628bdb6" +checksum = "6800dc386177df6ecc5a32680607ed8ba1fa0d31a2a59c8c61fbf44826b8191d" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.85.3" +version = "0.83.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac72f76f2698598951ab26d8c96eaa854810e693e7dd52523958b5909fde6b2" +checksum = "c961f85070985ebc8fcdb81b838a5cf842294d1e6ed4852446161c7e246fd455" [[package]] name = "cranelift-entity" -version = "0.85.3" +version = "0.83.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09eaeacfcd2356fe0e66b295e8f9d59fdd1ac3ace53ba50de14d628ec902f72d" +checksum = "2347b2b8d1d5429213668f2a8e36c85ee3c73984a2f6a79007e365d3e575e7ed" [[package]] name = "cranelift-frontend" -version = "0.85.3" +version = "0.83.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba69c9980d5ffd62c18a2bde927855fcd7c8dc92f29feaf8636052662cbd99c" +checksum = "4cbcdbf7bed29e363568b778649b69dabc3d727256d5d25236096ef693757654" dependencies = [ "cranelift-codegen", "log", @@ -108,17 +90,11 @@ dependencies = [ "target-lexicon", ] -[[package]] -name = "cranelift-isle" -version = "0.85.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2920dc1e05cac40304456ed3301fde2c09bd6a9b0210bcfa2f101398d628d5b" - [[package]] name = "cranelift-jit" -version = "0.85.3" +version = "0.83.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c3c5ed067f2c81577e431f3039148a9c187b33cc79e0d1731fede27d801ec56" +checksum = "7c769d4e0d76f59c8b2a3bf0477d89ee149bb0731b53fbb245ee081d49063095" dependencies = [ "anyhow", "cranelift-codegen", @@ -134,9 +110,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.85.3" +version = "0.83.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee6784303bf9af235237a4885f7417e09a35df896d38ea969a0081064b3ede4" +checksum = "0ab57d399a2401074bb0cc40b3031e420f3d66d46ec0cf21eeae53ac04bd73e2" dependencies = [ "anyhow", "cranelift-codegen", @@ -144,9 +120,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.85.3" +version = "0.83.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04dfa45f9b2a6f587c564d6b63388e00cd6589d2df6ea2758cf79e1a13285e6" +checksum = "8f4cdf93552e5ceb2e3c042829ebb4de4378492705f769eadc6a7c6c5251624c" dependencies = [ "cranelift-codegen", "libc", @@ -155,9 +131,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.85.3" +version = "0.83.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf38b2c505db749276793116c0cb30bd096206c7810e471677a453134881881" +checksum = "cf8e65f4839c26e6237fc0744911d79b0a2ac5e76b4e4eebd14db2b8d849fd31" dependencies = [ "anyhow", "cranelift-codegen", @@ -176,26 +152,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "getrandom" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - [[package]] name = "gimli" version = "0.26.1" @@ -210,31 +166,22 @@ name = "hashbrown" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "indexmap" -version = "1.9.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ "autocfg", - "hashbrown 0.12.3", + "hashbrown", ] [[package]] name = "libc" -version = "0.2.126" +version = "0.2.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" [[package]] name = "libloading" @@ -272,12 +219,11 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "object" -version = "0.28.4" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" dependencies = [ "crc32fast", - "hashbrown 0.11.2", "indexmap", "memchr", ] @@ -289,14 +235,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" [[package]] -name = "regalloc2" -version = "0.2.3" +name = "regalloc" +version = "0.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a8d23b35d7177df3b9d31ed8a9ab4bf625c668be77a319d4f5efd4a5257701c" +checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02" dependencies = [ - "fxhash", "log", - "slice-group-by", + "rustc-hash", "smallvec", ] @@ -312,6 +257,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_codegen_cranelift" version = "0.1.0" @@ -332,12 +283,6 @@ dependencies = [ "target-lexicon", ] -[[package]] -name = "slice-group-by" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" - [[package]] name = "smallvec" version = "1.8.1" @@ -350,18 +295,6 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1" -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" - [[package]] name = "winapi" version = "0.3.9" diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 61e977e3e69bf..ec2c1f2ca71b3 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -8,18 +8,18 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.85.3", features = ["unwind", "all-arch"] } -cranelift-frontend = "0.85.3" -cranelift-module = "0.85.3" -cranelift-native = "0.85.3" -cranelift-jit = { version = "0.85.3", optional = true } -cranelift-object = "0.85.3" +cranelift-codegen = { version = "0.83.0", features = ["unwind", "all-arch"] } +cranelift-frontend = "0.83.0" +cranelift-module = "0.83.0" +cranelift-native = "0.83.0" +cranelift-jit = { version = "0.83.0", optional = true } +cranelift-object = "0.83.0" target-lexicon = "0.12.0" gimli = { version = "0.26.0", default-features = false, features = ["write"]} -object = { version = "0.28.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } +object = { version = "0.27.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" } -indexmap = "1.9.1" +indexmap = "1.8.0" libloading = { version = "0.6.0", optional = true } once_cell = "1.10.0" smallvec = "1.8.1" diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock index 7b2cdd273366f..efee6ef3f3780 100644 --- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock @@ -56,9 +56,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.75" +version = "0.1.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e3183e88f659a862835db8f4b67dbeed3d93e44dd4927eef78edb1c149d784" +checksum = "afdbb35d279238cf77f0c9e8d90ad50d6c7bff476ab342baafa29440f0f10bff" dependencies = [ "rustc-std-workspace-core", ] @@ -112,9 +112,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -123,21 +123,20 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.2.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7668753748e445859e4e373c3d41117235d9feed578392f5a3a73efdc751ca4a" +checksum = "1ab7905ea95c6d9af62940f9d7dd9596d54c334ae2c15300c482051292d5637f" dependencies = [ "compiler_builtins", "libc", - "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] [[package]] name = "libc" -version = "0.2.126" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" dependencies = [ "rustc-std-workspace-core", ] diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs index 16cce83dd9c85..8682204f4fd30 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs @@ -205,7 +205,7 @@ fn build_clif_sysroot_for_triple( { let entry = entry.unwrap(); if let Some(ext) = entry.path().extension() { - if ext == "rmeta" || ext == "d" || ext == "dSYM" || ext == "clif" { + if ext == "rmeta" || ext == "d" || ext == "dSYM" { continue; } } else { diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 8b6042a3d6638..489259d1a6bc6 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -458,7 +458,7 @@ pub trait FnMut: FnOnce { #[lang = "panic"] #[track_caller] -pub fn panic(_msg: &'static str) -> ! { +pub fn panic(_msg: &str) -> ! { unsafe { libc::puts("Panicking\n\0" as *const str as *const i8); intrinsics::abort(); @@ -497,7 +497,7 @@ pub trait Deref { #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(1)] #[rustc_nonnull_optimization_guaranteed] -pub struct NonNull(pub *const T); +pub struct NonNull(pub *mut T); impl CoerceUnsized> for NonNull where T: Unsize {} impl DispatchFromDyn> for NonNull where T: Unsize {} @@ -521,7 +521,7 @@ impl Drop for Box { } } -impl Deref for Box { +impl Deref for Box { type Target = T; fn deref(&self) -> &Self::Target { diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index aa1f239bae23e..0f1245c2758ed 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -124,23 +124,6 @@ fn call_return_u128_pair() { return_u128_pair(); } -#[repr(C)] -pub struct bool_11 { - field0: bool, - field1: bool, - field2: bool, - field3: bool, - field4: bool, - field5: bool, - field6: bool, - field7: bool, - field8: bool, - field9: bool, - field10: bool, -} - -extern "C" fn bool_struct_in_11(arg0: bool_11) {} - #[allow(unreachable_code)] // FIXME false positive fn main() { take_unique(Unique { @@ -151,20 +134,6 @@ fn main() { call_return_u128_pair(); - bool_struct_in_11(bool_11 { - field0: true, - field1: true, - field2: true, - field3: true, - field4: true, - field5: true, - field6: true, - field7: true, - field8: true, - field9: true, - field10: true, - }); - let slice = &[0, 1] as &[i32]; let slice_ptr = slice as *const [i32] as *const i32; @@ -330,17 +299,6 @@ fn main() { static REF1: &u8 = &42; static REF2: &u8 = REF1; assert_eq!(*REF1, *REF2); - - extern "C" { - type A; - } - - fn main() { - let x: &A = unsafe { &*(1usize as *const A) }; - - assert_eq!(unsafe { intrinsics::size_of_val(x) }, 0); - assert_eq!(unsafe { intrinsics::min_align_of_val(x) }, 1); -} } #[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))] diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index 0b5b6cd55d720..0a2bce2621d96 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -128,25 +128,6 @@ fn main() { 0 => loop {}, v => panic(v), }; - - if black_box(false) { - // Based on https://github.com/rust-lang/rust/blob/2f320a224e827b400be25966755a621779f797cc/src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs - let _ = Foo::::new(); - - #[allow(dead_code)] - struct Foo { - base: Never, - value: T, - } - - impl Foo { - pub fn new() -> Box> { - todo!() - } - } - - enum Never {} - } } fn panic(_: u128) { diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 3ab395d89d50e..e98e92e468e93 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-07-25" +channel = "nightly-2022-05-15" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh index 091bfa1e9926f..4d0dfa16c5ecf 100644 --- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -29,15 +29,14 @@ diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/ru index 8431aa7b818..a3ff7e68ce5 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs -@@ -3489,12 +3489,7 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S - let compiler_src_dir = base_dir.join("compiler"); - normalize_path(&compiler_src_dir, "$(echo '$COMPILER_DIR')"); +@@ -3489,11 +3489,7 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S + .join("library"); + normalize_path(&src_dir, "$(echo '$SRC_DIR')"); - if let Some(virtual_rust_source_base_dir) = - option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from) - { - normalize_path(&virtual_rust_source_base_dir.join("library"), "$(echo '$SRC_DIR')"); -- normalize_path(&virtual_rust_source_base_dir.join("compiler"), "$(echo '$COMPILER_DIR')"); - } + normalize_path(&Path::new("$(cd ../build_sysroot/sysroot_src/library; pwd)"), "$(echo '$SRC_DIR')"); @@ -63,6 +62,3 @@ deny-warnings = false verbose-tests = false EOF popd - -# FIXME remove once inline asm is fully supported -export RUSTFLAGS="$RUSTFLAGS --cfg=rustix_use_libc" diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index 944787612d8bc..9bdb9f22c549a 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -33,7 +33,6 @@ rm src/test/ui/test-attrs/test-fn-signature-verification-for-explicit-return-typ rm src/test/ui/async-await/async-fn-size-moved-locals.rs # -Cpanic=abort shrinks some generator by one byte rm src/test/ui/async-await/async-fn-size-uninit-locals.rs # same rm src/test/ui/generator/size-moved-locals.rs # same -rm -r src/test/ui/macros/rfc-2011-nicer-assert-messages/ # vendor intrinsics rm src/test/ui/sse2.rs # cpuid not supported, so sse2 not detected @@ -66,13 +65,11 @@ rm src/test/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and n rm src/test/ui/target-feature/missing-plusminus.rs # error not implemented rm src/test/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment rm -r src/test/run-make/emit-named-files # requires full --emit support -rm src/test/ui/abi/stack-probes.rs # stack probes not yet implemented # optimization tests # ================== -rm src/test/ui/codegen/issue-28950.rs # depends on stack size optimizations +rm src/test/ui/issues/issue-28950.rs # depends on stack size optimizations rm src/test/ui/codegen/init-large-type.rs # same -rm src/test/ui/issues/issue-40883.rs # same rm -r src/test/run-make/fmt-write-bloat/ # tests an optimization # backend specific tests @@ -92,13 +89,14 @@ rm src/test/ui/consts/issue-33537.rs # same rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/ rm -r src/test/run-make/unstable-flag-required # same rm -r src/test/run-make/rustdoc-* # same -rm -r src/test/run-make/issue-88756-default-output # same -rm -r src/test/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump # genuine bugs # ============ rm src/test/ui/allocator/no_std-alloc-error-handler-default.rs # missing rust_oom definition +rm -r src/test/ui/polymorphization/ # polymorphization not yet supported +rm src/test/codegen-units/polymorphization/unused_type_parameters.rs # same + rm src/test/incremental/spike-neg1.rs # errors out for some reason rm src/test/incremental/spike-neg2.rs # same rm src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs # gives a stackoverflow before the backend runs @@ -113,8 +111,6 @@ rm src/test/ui/backtrace.rs # TODO warning rm src/test/ui/empty_global_asm.rs # TODO add needs-asm-support rm src/test/ui/simple_global_asm.rs # TODO add needs-asm-support rm src/test/ui/test-attrs/test-type.rs # TODO panic message on stderr. correct stdout -# not sure if this is actually a bug in the test suite, but the symbol list shows the function without leading _ for some reason -rm -r src/test/run-make/native-link-modifier-bundle echo "[TEST] rustc test suite" RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui,incremental} diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 815450f689e4a..ffa5d747b1160 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -4,7 +4,6 @@ mod comments; mod pass_mode; mod returning; -use cranelift_module::ModuleError; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::layout::FnAbiOf; use rustc_target::abi::call::{Conv, FnAbi}; @@ -70,17 +69,7 @@ pub(crate) fn import_function<'tcx>( ) -> FuncId { let name = tcx.symbol_name(inst).name; let sig = get_function_sig(tcx, module.isa().triple(), inst); - match module.declare_function(name, Linkage::Import, &sig) { - Ok(func_id) => func_id, - Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!( - "attempt to declare `{name}` as function, but it was already declared as static" - )), - Err(ModuleError::IncompatibleSignature(_, prev_sig, new_sig)) => tcx.sess.fatal(&format!( - "attempt to declare `{name}` with signature {new_sig:?}, \ - but it was already declared with signature {prev_sig:?}" - )), - Err(err) => Err::<_, _>(err).unwrap(), - } + module.declare_function(name, Linkage::Import, &sig).unwrap() } impl<'tcx> FunctionCx<'_, '_, 'tcx> { @@ -193,15 +182,6 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_ } let fn_abi = fx.fn_abi.take().unwrap(); - - // FIXME implement variadics in cranelift - if fn_abi.c_variadic { - fx.tcx.sess.span_fatal( - fx.mir.span, - "Defining variadic functions is not yet supported by Cranelift", - ); - } - let mut arg_abis_iter = fn_abi.args.iter(); let func_params = fx @@ -396,15 +376,9 @@ pub(crate) fn codegen_terminator_call<'tcx>( RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_ty.fn_sig(fx.tcx), extra_args) }; - let is_cold = if fn_sig.abi == Abi::RustCold { - true - } else { - instance - .map(|inst| { - fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD) - }) - .unwrap_or(false) - }; + let is_cold = instance + .map(|inst| fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD)) + .unwrap_or(false); if is_cold { fx.bcx.set_cold_block(fx.bcx.current_block().unwrap()); if let Some(destination_block) = target { diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index 6c10baa53d415..9f0bd31e95fcc 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -18,9 +18,9 @@ fn reg_to_abi_param(reg: Reg) -> AbiParam { let clif_ty = match (reg.kind, reg.size.bytes()) { (RegKind::Integer, 1) => types::I8, (RegKind::Integer, 2) => types::I16, - (RegKind::Integer, 3..=4) => types::I32, - (RegKind::Integer, 5..=8) => types::I64, - (RegKind::Integer, 9..=16) => types::I128, + (RegKind::Integer, 4) => types::I32, + (RegKind::Integer, 8) => types::I64, + (RegKind::Integer, 16) => types::I128, (RegKind::Float, 4) => types::F32, (RegKind::Float, 8) => types::F64, (RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(), @@ -48,9 +48,23 @@ fn cast_target_to_abi_params(cast: CastTarget) -> SmallVec<[AbiParam; 2]> { ) }; - // Note: Unlike the LLVM equivalent of this code we don't have separate branches for when there - // is no prefix as a single unit, an array and a heterogeneous struct are not represented using - // different types in Cranelift IR. Instead a single array of primitive types is used. + if cast.prefix.iter().all(|x| x.is_none()) { + // Simplify to a single unit when there is no prefix and size <= unit size + if cast.rest.total <= cast.rest.unit.size { + let clif_ty = match (cast.rest.unit.kind, cast.rest.unit.size.bytes()) { + (RegKind::Integer, 1) => types::I8, + (RegKind::Integer, 2) => types::I16, + (RegKind::Integer, 3..=4) => types::I32, + (RegKind::Integer, 5..=8) => types::I64, + (RegKind::Integer, 9..=16) => types::I128, + (RegKind::Float, 4) => types::F32, + (RegKind::Float, 8) => types::F64, + (RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(), + _ => unreachable!("{:?}", cast.rest.unit), + }; + return smallvec![AbiParam::new(clif_ty)]; + } + } // Create list of fields in the main structure let mut args = cast @@ -216,7 +230,7 @@ pub(super) fn adjust_arg_for_abi<'tcx>( arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, is_owned: bool, ) -> SmallVec<[Value; 2]> { - assert_assignable(fx, arg.layout().ty, arg_abi.layout.ty, 16); + assert_assignable(fx, arg.layout().ty, arg_abi.layout.ty); match arg_abi.mode { PassMode::Ignore => smallvec![], PassMode::Direct(_) => smallvec![arg.load_scalar(fx)], diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index c92c105113954..0812f930b5dea 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -86,7 +86,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { let mut entries = Vec::new(); - for (mut entry_name, entry) in self.entries { + for (entry_name, entry) in self.entries { // FIXME only read the symbol table of the object files to avoid having to keep all // object files in memory at once, or read them twice. let data = match entry { @@ -109,23 +109,6 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { }; if !self.no_builtin_ranlib { - if symbol_table.contains_key(&entry_name) { - // The ar crate can't handle creating a symbol table in case of multiple archive - // members with the same name. Work around this by prepending a number until we - // get a unique name. - for i in 1.. { - let new_name = format!("{}_", i) - .into_bytes() - .into_iter() - .chain(entry_name.iter().copied()) - .collect::>(); - if !symbol_table.contains_key(&new_name) { - entry_name = new_name; - break; - } - } - } - match object::File::parse(&*data) { Ok(object) => { symbol_table.insert( @@ -221,16 +204,12 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { any_members } - fn sess(&self) -> &Session { - self.sess - } - - fn create_dll_import_lib( - _sess: &Session, + fn inject_dll_import_lib( + &mut self, _lib_name: &str, _dll_imports: &[rustc_session::cstore::DllImport], - _tmpdir: &Path, - ) -> PathBuf { - bug!("creating dll imports is not supported"); + _tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir, + ) { + bug!("injecting dll imports is not supported"); } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 122e103ff62bc..63cd4d6de4c3e 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -175,37 +175,10 @@ fn compile_fn<'tcx>( ); }); - #[cfg(any())] // This is never true - let _clif_guard = { - use std::fmt::Write; - - let func_clone = context.func.clone(); - let clif_comments_clone = clif_comments.clone(); - let mut clif = String::new(); - for flag in module.isa().flags().iter() { - writeln!(clif, "set {}", flag).unwrap(); - } - write!(clif, "target {}", module.isa().triple().architecture.to_string()).unwrap(); - for isa_flag in module.isa().isa_flags().iter() { - write!(clif, " {}", isa_flag).unwrap(); - } - writeln!(clif, "\n").unwrap(); - crate::PrintOnPanic(move || { - let mut clif = clif.clone(); - ::cranelift_codegen::write::decorate_function( - &mut &clif_comments_clone, - &mut clif, - &func_clone, - ) - .unwrap(); - clif - }) - }; - // Define function tcx.sess.time("define function", || { context.want_disasm = crate::pretty_clif::should_write_ir(tcx); - module.define_function(func_id, context).unwrap(); + module.define_function(func_id, context).unwrap() }); // Write optimized function to file for debugging @@ -842,7 +815,15 @@ pub(crate) fn codegen_place<'tcx>( for elem in place.projection { match elem { PlaceElem::Deref => { - cplace = cplace.place_deref(fx); + if cplace.layout().ty.is_box() { + cplace = cplace + .place_field(fx, Field::new(0)) // Box -> Unique + .place_field(fx, Field::new(0)) // Unique -> NonNull + .place_field(fx, Field::new(0)) // NonNull -> *mut T + .place_deref(fx); + } else { + cplace = cplace.place_deref(fx); + } } PlaceElem::Field(field, _ty) => { cplace = cplace.place_field(fx, field); diff --git a/compiler/rustc_codegen_cranelift/src/cast.rs b/compiler/rustc_codegen_cranelift/src/cast.rs index bad5d1f08a9cf..b24e49e94c91e 100644 --- a/compiler/rustc_codegen_cranelift/src/cast.rs +++ b/compiler/rustc_codegen_cranelift/src/cast.rs @@ -149,8 +149,17 @@ pub(crate) fn clif_int_or_float_cast( } let is_not_nan = fx.bcx.ins().fcmp(FloatCC::Equal, from, from); - let zero = fx.bcx.ins().iconst(to_ty, 0); - fx.bcx.ins().select(is_not_nan, val, zero) + if to_ty == types::I128 { + // FIXME(bytecodealliance/wasmtime#3963): select.i128 on fcmp eq miscompiles + let (lsb, msb) = fx.bcx.ins().isplit(val); + let zero = fx.bcx.ins().iconst(types::I64, 0); + let lsb = fx.bcx.ins().select(is_not_nan, lsb, zero); + let msb = fx.bcx.ins().select(is_not_nan, msb, zero); + fx.bcx.ins().iconcat(lsb, msb) + } else { + let zero = fx.bcx.ins().iconst(to_ty, 0); + fx.bcx.ins().select(is_not_nan, val, zero) + } } else if from_ty.is_float() && to_ty.is_float() { // float -> float match (from_ty, to_ty) { diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 7f7fd0e9c579d..48972321a9f40 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -195,8 +195,9 @@ pub(crate) fn codegen_const_value<'tcx>( } Scalar::Ptr(ptr, _size) => { let (alloc_id, offset) = ptr.into_parts(); // we know the `offset` is relative - let base_addr = match fx.tcx.global_alloc(alloc_id) { - GlobalAlloc::Memory(alloc) => { + let alloc_kind = fx.tcx.get_global_alloc(alloc_id); + let base_addr = match alloc_kind { + Some(GlobalAlloc::Memory(alloc)) => { let data_id = data_id_for_alloc_id( &mut fx.constants_cx, fx.module, @@ -210,27 +211,13 @@ pub(crate) fn codegen_const_value<'tcx>( } fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } - GlobalAlloc::Function(instance) => { + Some(GlobalAlloc::Function(instance)) => { let func_id = crate::abi::import_function(fx.tcx, fx.module, instance); let local_func_id = fx.module.declare_func_in_func(func_id, &mut fx.bcx.func); fx.bcx.ins().func_addr(fx.pointer_type, local_func_id) } - GlobalAlloc::VTable(ty, trait_ref) => { - let alloc_id = fx.tcx.vtable_allocation((ty, trait_ref)); - let alloc = fx.tcx.global_alloc(alloc_id).unwrap_memory(); - // FIXME: factor this common code with the `Memory` arm into a function? - let data_id = data_id_for_alloc_id( - &mut fx.constants_cx, - fx.module, - alloc_id, - alloc.inner().mutability, - ); - let local_data_id = - fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); - fx.bcx.ins().global_value(fx.pointer_type, local_data_id) - } - GlobalAlloc::Static(def_id) => { + Some(GlobalAlloc::Static(def_id)) => { assert!(fx.tcx.is_static(def_id)); let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false); let local_data_id = @@ -240,6 +227,7 @@ pub(crate) fn codegen_const_value<'tcx>( } fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } + None => bug!("missing allocation {:?}", alloc_id), }; let val = if offset.bytes() != 0 { fx.bcx.ins().iadd_imm(base_addr, i64::try_from(offset.bytes()).unwrap()) @@ -328,18 +316,14 @@ fn data_id_for_static( let attrs = tcx.codegen_fn_attrs(def_id); - let data_id = match module.declare_data( - &*symbol_name, - linkage, - is_mutable, - attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL), - ) { - Ok(data_id) => data_id, - Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!( - "attempt to declare `{symbol_name}` as static, but it was already declared as function" - )), - Err(err) => Err::<_, _>(err).unwrap(), - }; + let data_id = module + .declare_data( + &*symbol_name, + linkage, + is_mutable, + attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL), + ) + .unwrap(); if rlinkage.is_some() { // Comment copied from https://github.com/rust-lang/rust/blob/45060c2a66dfd667f88bd8b94261b28a58d85bd5/src/librustc_codegen_llvm/consts.rs#L141 @@ -373,11 +357,10 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant while let Some(todo_item) = cx.todo.pop() { let (data_id, alloc, section_name) = match todo_item { TodoItem::Alloc(alloc_id) => { - let alloc = match tcx.global_alloc(alloc_id) { + //println!("alloc_id {}", alloc_id); + let alloc = match tcx.get_global_alloc(alloc_id).unwrap() { GlobalAlloc::Memory(alloc) => alloc, - GlobalAlloc::Function(_) | GlobalAlloc::Static(_) | GlobalAlloc::VTable(..) => { - unreachable!() - } + GlobalAlloc::Function(_) | GlobalAlloc::Static(_) => unreachable!(), }; let data_id = *cx.anon_allocs.entry(alloc_id).or_insert_with(|| { module @@ -441,12 +424,11 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant read_target_uint(endianness, bytes).unwrap() }; - let reloc_target_alloc = tcx.global_alloc(alloc_id); + let reloc_target_alloc = tcx.get_global_alloc(alloc_id).unwrap(); let data_id = match reloc_target_alloc { GlobalAlloc::Function(instance) => { assert_eq!(addend, 0); - let func_id = - crate::abi::import_function(tcx, module, instance.polymorphize(tcx)); + let func_id = crate::abi::import_function(tcx, module, instance); let local_func_id = module.declare_func_in_data(func_id, &mut data_ctx); data_ctx.write_function_addr(offset.bytes() as u32, local_func_id); continue; @@ -454,10 +436,6 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant GlobalAlloc::Memory(target_alloc) => { data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability) } - GlobalAlloc::VTable(ty, trait_ref) => { - let alloc_id = tcx.vtable_allocation((ty, trait_ref)); - data_id_for_alloc_id(cx, module, alloc_id, Mutability::Not) - } GlobalAlloc::Static(def_id) => { if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 241de5e36530c..deac5dfd3ec1a 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -18,96 +18,86 @@ pub(crate) fn codegen_inline_asm<'tcx>( ) { // FIXME add .eh_frame unwind info directives - if !template.is_empty() { - if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) { - let true_ = fx.bcx.ins().iconst(types::I32, 1); - fx.bcx.ins().trapnz(true_, TrapCode::User(1)); - return; - } else if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string()) - && matches!( - template[1], - InlineAsmTemplatePiece::Placeholder { - operand_idx: 0, - modifier: Some('r'), - span: _ - } - ) - && template[2] == InlineAsmTemplatePiece::String("\n".to_string()) - && template[3] == InlineAsmTemplatePiece::String("cpuid".to_string()) - && template[4] == InlineAsmTemplatePiece::String("\n".to_string()) - && template[5] == InlineAsmTemplatePiece::String("xchgq %rbx, ".to_string()) - && matches!( - template[6], - InlineAsmTemplatePiece::Placeholder { - operand_idx: 0, - modifier: Some('r'), - span: _ - } - ) - { - assert_eq!(operands.len(), 4); - let (leaf, eax_place) = match operands[1] { - InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => { - assert_eq!( - reg, - InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)) - ); - ( - crate::base::codegen_operand(fx, in_value).load_scalar(fx), - crate::base::codegen_place(fx, out_place.unwrap()), - ) - } - _ => unreachable!(), - }; - let ebx_place = match operands[0] { - InlineAsmOperand::Out { reg, late: true, place } => { - assert_eq!( - reg, - InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86( - X86InlineAsmRegClass::reg - )) - ); - crate::base::codegen_place(fx, place.unwrap()) - } - _ => unreachable!(), - }; - let (sub_leaf, ecx_place) = match operands[2] { - InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => { - assert_eq!( - reg, - InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)) - ); - ( - crate::base::codegen_operand(fx, in_value).load_scalar(fx), - crate::base::codegen_place(fx, out_place.unwrap()), - ) - } - _ => unreachable!(), - }; - let edx_place = match operands[3] { - InlineAsmOperand::Out { reg, late: true, place } => { - assert_eq!( - reg, - InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)) - ); - crate::base::codegen_place(fx, place.unwrap()) - } - _ => unreachable!(), - }; - - let (eax, ebx, ecx, edx) = crate::intrinsics::codegen_cpuid_call(fx, leaf, sub_leaf); - - eax_place.write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32))); - ebx_place.write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32))); - ecx_place.write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32))); - edx_place.write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32))); - return; - } else if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") { - // ___chkstk, ___chkstk_ms and __alloca are only used on Windows - crate::trap::trap_unimplemented(fx, "Stack probes are not supported"); - } else if fx.tcx.symbol_name(fx.instance).name == "__alloca" { - crate::trap::trap_unimplemented(fx, "Alloca is not supported"); - } + if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) { + let true_ = fx.bcx.ins().iconst(types::I32, 1); + fx.bcx.ins().trapnz(true_, TrapCode::User(1)); + return; + } else if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string()) + && matches!( + template[1], + InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ } + ) + && template[2] == InlineAsmTemplatePiece::String("\n".to_string()) + && template[3] == InlineAsmTemplatePiece::String("cpuid".to_string()) + && template[4] == InlineAsmTemplatePiece::String("\n".to_string()) + && template[5] == InlineAsmTemplatePiece::String("xchgq %rbx, ".to_string()) + && matches!( + template[6], + InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ } + ) + { + assert_eq!(operands.len(), 4); + let (leaf, eax_place) = match operands[1] { + InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => { + assert_eq!( + reg, + InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)) + ); + ( + crate::base::codegen_operand(fx, in_value).load_scalar(fx), + crate::base::codegen_place(fx, out_place.unwrap()), + ) + } + _ => unreachable!(), + }; + let ebx_place = match operands[0] { + InlineAsmOperand::Out { reg, late: true, place } => { + assert_eq!( + reg, + InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86( + X86InlineAsmRegClass::reg + )) + ); + crate::base::codegen_place(fx, place.unwrap()) + } + _ => unreachable!(), + }; + let (sub_leaf, ecx_place) = match operands[2] { + InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => { + assert_eq!( + reg, + InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)) + ); + ( + crate::base::codegen_operand(fx, in_value).load_scalar(fx), + crate::base::codegen_place(fx, out_place.unwrap()), + ) + } + _ => unreachable!(), + }; + let edx_place = match operands[3] { + InlineAsmOperand::Out { reg, late: true, place } => { + assert_eq!( + reg, + InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)) + ); + crate::base::codegen_place(fx, place.unwrap()) + } + _ => unreachable!(), + }; + + let (eax, ebx, ecx, edx) = crate::intrinsics::codegen_cpuid_call(fx, leaf, sub_leaf); + + eax_place.write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32))); + ebx_place.write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32))); + ecx_place.write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32))); + edx_place.write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32))); + return; + } else if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") { + // ___chkstk, ___chkstk_ms and __alloca are only used on Windows + crate::trap::trap_unimplemented(fx, "Stack probes are not supported"); + } else if fx.tcx.symbol_name(fx.instance).name == "__alloca" { + crate::trap::trap_unimplemented(fx, "Alloca is not supported"); } let mut inputs = Vec::new(); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs index 869670c8cfac7..77ac46540a9ba 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs @@ -13,11 +13,15 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( ret: CPlace<'tcx>, target: Option, ) { - match intrinsic { - // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8` - "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd" => { - intrinsic_args!(fx, args => (a); intrinsic); + intrinsic_match! { + fx, intrinsic, args, + _ => { + fx.tcx.sess.warn(&format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic)); + crate::trap::trap_unimplemented(fx, intrinsic); + }; + // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8` + "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd", (c a) { let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx); let lane_ty = fx.clif_type(lane_ty).unwrap(); assert!(lane_count <= 32); @@ -25,8 +29,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( let mut res = fx.bcx.ins().iconst(types::I32, 0); for lane in (0..lane_count).rev() { - let a_lane = - a.value_field(fx, mir::Field::new(lane.try_into().unwrap())).load_scalar(fx); + let a_lane = a.value_field(fx, mir::Field::new(lane.try_into().unwrap())).load_scalar(fx); // cast float to int let a_lane = match lane_ty { @@ -46,29 +49,26 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32)); ret.write_cvalue(fx, res); - } - "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd" => { - let (x, y, kind) = match args { - [x, y, kind] => (x, y, kind), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let x = codegen_operand(fx, x); - let y = codegen_operand(fx, y); - let kind = crate::constant::mir_operand_get_const_val(fx, kind) - .expect("llvm.x86.sse2.cmp.* kind not const"); - - let flt_cc = match kind - .try_to_bits(Size::from_bytes(1)) - .unwrap_or_else(|| panic!("kind not scalar: {:?}", kind)) - { + }; + "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd", (c x, c y, o kind) { + let kind = crate::constant::mir_operand_get_const_val(fx, kind).expect("llvm.x86.sse2.cmp.* kind not const"); + let flt_cc = match kind.try_to_bits(Size::from_bytes(1)).unwrap_or_else(|| panic!("kind not scalar: {:?}", kind)) { 0 => FloatCC::Equal, 1 => FloatCC::LessThan, 2 => FloatCC::LessThanOrEqual, - 7 => FloatCC::Ordered, - 3 => FloatCC::Unordered, + 7 => { + unimplemented!("Compares corresponding elements in `a` and `b` to see if neither is `NaN`."); + } + 3 => { + unimplemented!("Compares corresponding elements in `a` and `b` to see if either is `NaN`."); + } 4 => FloatCC::NotEqual, - 5 => FloatCC::UnorderedOrGreaterThanOrEqual, - 6 => FloatCC::UnorderedOrGreaterThan, + 5 => { + unimplemented!("not less than"); + } + 6 => { + unimplemented!("not less than or equal"); + } kind => unreachable!("kind {:?}", kind), }; @@ -79,67 +79,50 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( }; bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane) }); - } - "llvm.x86.sse2.psrli.d" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.sse2.psrli.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), + }; + "llvm.x86.sse2.psrli.d", (c a, o imm8) { + let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const"); + simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| { + match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) { + imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)), + _ => fx.bcx.ins().iconst(types::I32, 0), + } }); - } - "llvm.x86.sse2.pslli.d" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.sse2.psrli.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), + }; + "llvm.x86.sse2.pslli.d", (c a, o imm8) { + let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const"); + simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| { + match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) { + imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)), + _ => fx.bcx.ins().iconst(types::I32, 0), + } }); - } - "llvm.x86.sse2.storeu.dq" => { - intrinsic_args!(fx, args => (mem_addr, a); intrinsic); - let mem_addr = mem_addr.load_scalar(fx); - + }; + "llvm.x86.sse2.storeu.dq", (v mem_addr, c a) { // FIXME correctly handle the unalignment let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout()); dest.write_cvalue(fx, a); - } - "llvm.x86.addcarry.64" => { - intrinsic_args!(fx, args => (c_in, a, b); intrinsic); - let c_in = c_in.load_scalar(fx); - - llvm_add_sub(fx, BinOp::Add, ret, c_in, a, b); - } - "llvm.x86.subborrow.64" => { - intrinsic_args!(fx, args => (b_in, a, b); intrinsic); - let b_in = b_in.load_scalar(fx); - - llvm_add_sub(fx, BinOp::Sub, ret, b_in, a, b); - } - _ => { - fx.tcx - .sess - .warn(&format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic)); - crate::trap::trap_unimplemented(fx, intrinsic); - } + }; + "llvm.x86.addcarry.64", (v c_in, c a, c b) { + llvm_add_sub( + fx, + BinOp::Add, + ret, + c_in, + a, + b + ); + }; + "llvm.x86.subborrow.64", (v b_in, c a, c b) { + llvm_add_sub( + fx, + BinOp::Sub, + ret, + b_in, + a, + b + ); + }; } let dest = target.expect("all llvm intrinsics used by stdlib should return"); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index b2a83e1d4ebc9..4b2207f375879 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1,14 +1,50 @@ //! Codegen of intrinsics. This includes `extern "rust-intrinsic"`, `extern "platform-intrinsic"` //! and LLVM intrinsics that have symbol names starting with `llvm.`. -macro_rules! intrinsic_args { - ($fx:expr, $args:expr => ($($arg:tt),*); $intrinsic:expr) => { - #[allow(unused_parens)] - let ($($arg),*) = if let [$($arg),*] = $args { - ($(codegen_operand($fx, $arg)),*) - } else { - $crate::intrinsics::bug_on_incorrect_arg_count($intrinsic); - }; +macro_rules! intrinsic_pat { + (_) => { + _ + }; + ($name:ident) => { + sym::$name + }; + (kw.$name:ident) => { + kw::$name + }; + ($name:literal) => { + $name + }; +} + +macro_rules! intrinsic_arg { + (o $fx:expr, $arg:ident) => {}; + (c $fx:expr, $arg:ident) => { + let $arg = codegen_operand($fx, $arg); + }; + (v $fx:expr, $arg:ident) => { + let $arg = codegen_operand($fx, $arg).load_scalar($fx); + }; +} + +macro_rules! intrinsic_match { + ($fx:expr, $intrinsic:expr, $args:expr, + _ => $unknown:block; + $( + $($($name:tt).*)|+ $(if $cond:expr)?, ($($a:ident $arg:ident),*) $content:block; + )*) => { + match $intrinsic { + $( + $(intrinsic_pat!($($name).*))|* $(if $cond)? => { + if let [$($arg),*] = $args { + $(intrinsic_arg!($a $fx, $arg);)* + $content + } else { + bug!("wrong number of args for intrinsic {:?}", $intrinsic); + } + } + )* + _ => $unknown, + } } } @@ -26,10 +62,6 @@ use rustc_span::symbol::{kw, sym, Symbol}; use crate::prelude::*; use cranelift_codegen::ir::AtomicRmwOp; -fn bug_on_incorrect_arg_count(intrinsic: impl std::fmt::Display) -> ! { - bug!("wrong number of args for intrinsic {}", intrinsic); -} - fn report_atomic_type_validation_error<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, intrinsic: Symbol, @@ -319,31 +351,28 @@ fn codegen_regular_intrinsic_call<'tcx>( ) { let usize_layout = fx.layout_of(fx.tcx.types.usize); - match intrinsic { - sym::assume => { - intrinsic_args!(fx, args => (_a); intrinsic); - } - sym::likely | sym::unlikely => { - intrinsic_args!(fx, args => (a); intrinsic); + intrinsic_match! { + fx, intrinsic, args, + _ => { + fx.tcx.sess.span_fatal(source_info.span, &format!("unsupported intrinsic {}", intrinsic)); + }; + assume, (c _a) {}; + likely | unlikely, (c a) { ret.write_cvalue(fx, a); - } - sym::breakpoint => { - intrinsic_args!(fx, args => (); intrinsic); - + }; + breakpoint, () { fx.bcx.ins().debugtrap(); - } - sym::copy | sym::copy_nonoverlapping => { - intrinsic_args!(fx, args => (src, dst, count); intrinsic); - let src = src.load_scalar(fx); - let dst = dst.load_scalar(fx); - let count = count.load_scalar(fx); - + }; + copy | copy_nonoverlapping, (v src, v dst, v count) { let elem_ty = substs.type_at(0); let elem_size: u64 = fx.layout_of(elem_ty).size.bytes(); assert_eq!(args.len(), 3); - let byte_amount = - if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count }; + let byte_amount = if elem_size != 1 { + fx.bcx.ins().imul_imm(count, elem_size as i64) + } else { + count + }; if intrinsic == sym::copy_nonoverlapping { // FIXME emit_small_memcpy @@ -352,19 +381,17 @@ fn codegen_regular_intrinsic_call<'tcx>( // FIXME emit_small_memmove fx.bcx.call_memmove(fx.target_config, dst, src, byte_amount); } - } - sym::volatile_copy_memory | sym::volatile_copy_nonoverlapping_memory => { - // NOTE: the volatile variants have src and dst swapped - intrinsic_args!(fx, args => (dst, src, count); intrinsic); - let dst = dst.load_scalar(fx); - let src = src.load_scalar(fx); - let count = count.load_scalar(fx); - + }; + // NOTE: the volatile variants have src and dst swapped + volatile_copy_memory | volatile_copy_nonoverlapping_memory, (v dst, v src, v count) { let elem_ty = substs.type_at(0); let elem_size: u64 = fx.layout_of(elem_ty).size.bytes(); assert_eq!(args.len(), 3); - let byte_amount = - if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count }; + let byte_amount = if elem_size != 1 { + fx.bcx.ins().imul_imm(count, elem_size as i64) + } else { + count + }; // FIXME make the copy actually volatile when using emit_small_mem{cpy,move} if intrinsic == sym::volatile_copy_nonoverlapping_memory { @@ -374,64 +401,38 @@ fn codegen_regular_intrinsic_call<'tcx>( // FIXME emit_small_memmove fx.bcx.call_memmove(fx.target_config, dst, src, byte_amount); } - } - sym::size_of_val => { - intrinsic_args!(fx, args => (ptr); intrinsic); - + }; + size_of_val, (c ptr) { let layout = fx.layout_of(substs.type_at(0)); - // Note: Can't use is_unsized here as truly unsized types need to take the fixed size - // branch - let size = if let Abi::ScalarPair(_, _) = ptr.layout().abi { + let size = if layout.is_unsized() { let (_ptr, info) = ptr.load_scalar_pair(fx); let (size, _align) = crate::unsize::size_and_align_of_dst(fx, layout, info); size } else { - fx.bcx.ins().iconst(fx.pointer_type, layout.size.bytes() as i64) + fx + .bcx + .ins() + .iconst(fx.pointer_type, layout.size.bytes() as i64) }; ret.write_cvalue(fx, CValue::by_val(size, usize_layout)); - } - sym::min_align_of_val => { - intrinsic_args!(fx, args => (ptr); intrinsic); - + }; + min_align_of_val, (c ptr) { let layout = fx.layout_of(substs.type_at(0)); - // Note: Can't use is_unsized here as truly unsized types need to take the fixed size - // branch - let align = if let Abi::ScalarPair(_, _) = ptr.layout().abi { + let align = if layout.is_unsized() { let (_ptr, info) = ptr.load_scalar_pair(fx); let (_size, align) = crate::unsize::size_and_align_of_dst(fx, layout, info); align } else { - fx.bcx.ins().iconst(fx.pointer_type, layout.align.abi.bytes() as i64) + fx + .bcx + .ins() + .iconst(fx.pointer_type, layout.align.abi.bytes() as i64) }; ret.write_cvalue(fx, CValue::by_val(align, usize_layout)); - } - - sym::vtable_size => { - intrinsic_args!(fx, args => (vtable); intrinsic); - let vtable = vtable.load_scalar(fx); - - let size = crate::vtable::size_of_obj(fx, vtable); - ret.write_cvalue(fx, CValue::by_val(size, usize_layout)); - } - - sym::vtable_align => { - intrinsic_args!(fx, args => (vtable); intrinsic); - let vtable = vtable.load_scalar(fx); - - let align = crate::vtable::min_align_of_obj(fx, vtable); - ret.write_cvalue(fx, CValue::by_val(align, usize_layout)); - } - - sym::unchecked_add - | sym::unchecked_sub - | sym::unchecked_mul - | sym::unchecked_div - | sym::exact_div - | sym::unchecked_rem - | sym::unchecked_shl - | sym::unchecked_shr => { - intrinsic_args!(fx, args => (x, y); intrinsic); + }; + unchecked_add | unchecked_sub | unchecked_mul | unchecked_div | exact_div | unchecked_rem + | unchecked_shl | unchecked_shr, (c x, c y) { // FIXME trap on overflow let bin_op = match intrinsic { sym::unchecked_add => BinOp::Add, @@ -445,10 +446,8 @@ fn codegen_regular_intrinsic_call<'tcx>( }; let res = crate::num::codegen_int_binop(fx, bin_op, x, y); ret.write_cvalue(fx, res); - } - sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { - intrinsic_args!(fx, args => (x, y); intrinsic); - + }; + add_with_overflow | sub_with_overflow | mul_with_overflow, (c x, c y) { assert_eq!(x.layout().ty, y.layout().ty); let bin_op = match intrinsic { sym::add_with_overflow => BinOp::Add, @@ -457,12 +456,15 @@ fn codegen_regular_intrinsic_call<'tcx>( _ => unreachable!(), }; - let res = crate::num::codegen_checked_int_binop(fx, bin_op, x, y); + let res = crate::num::codegen_checked_int_binop( + fx, + bin_op, + x, + y, + ); ret.write_cvalue(fx, res); - } - sym::saturating_add | sym::saturating_sub => { - intrinsic_args!(fx, args => (lhs, rhs); intrinsic); - + }; + saturating_add | saturating_sub, (c lhs, c rhs) { assert_eq!(lhs.layout().ty, rhs.layout().ty); let bin_op = match intrinsic { sym::saturating_add => BinOp::Add, @@ -472,7 +474,12 @@ fn codegen_regular_intrinsic_call<'tcx>( let signed = type_sign(lhs.layout().ty); - let checked_res = crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs); + let checked_res = crate::num::codegen_checked_int_binop( + fx, + bin_op, + lhs, + rhs, + ); let (val, has_overflow) = checked_res.load_scalar_pair(fx); let clif_ty = fx.clif_type(lhs.layout().ty).unwrap(); @@ -484,15 +491,13 @@ fn codegen_regular_intrinsic_call<'tcx>( (sym::saturating_sub, false) => fx.bcx.ins().select(has_overflow, min, val), (sym::saturating_add, true) => { let rhs = rhs.load_scalar(fx); - let rhs_ge_zero = - fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0); + let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0); let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min); fx.bcx.ins().select(has_overflow, sat_val, val) } (sym::saturating_sub, true) => { let rhs = rhs.load_scalar(fx); - let rhs_ge_zero = - fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0); + let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0); let sat_val = fx.bcx.ins().select(rhs_ge_zero, min, max); fx.bcx.ins().select(has_overflow, sat_val, val) } @@ -502,32 +507,23 @@ fn codegen_regular_intrinsic_call<'tcx>( let res = CValue::by_val(val, lhs.layout()); ret.write_cvalue(fx, res); - } - sym::rotate_left => { - intrinsic_args!(fx, args => (x, y); intrinsic); - let y = y.load_scalar(fx); - + }; + rotate_left, (c x, v y) { let layout = x.layout(); let x = x.load_scalar(fx); let res = fx.bcx.ins().rotl(x, y); ret.write_cvalue(fx, CValue::by_val(res, layout)); - } - sym::rotate_right => { - intrinsic_args!(fx, args => (x, y); intrinsic); - let y = y.load_scalar(fx); - + }; + rotate_right, (c x, v y) { let layout = x.layout(); let x = x.load_scalar(fx); let res = fx.bcx.ins().rotr(x, y); ret.write_cvalue(fx, CValue::by_val(res, layout)); - } + }; // The only difference between offset and arith_offset is regarding UB. Because Cranelift // doesn't have UB both are codegen'ed the same way - sym::offset | sym::arith_offset => { - intrinsic_args!(fx, args => (base, offset); intrinsic); - let offset = offset.load_scalar(fx); - + offset | arith_offset, (c base, v offset) { let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty; let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let ptr_diff = if pointee_size != 1 { @@ -538,18 +534,12 @@ fn codegen_regular_intrinsic_call<'tcx>( let base_val = base.load_scalar(fx); let res = fx.bcx.ins().iadd(base_val, ptr_diff); ret.write_cvalue(fx, CValue::by_val(res, base.layout())); - } - - sym::transmute => { - intrinsic_args!(fx, args => (from); intrinsic); + }; + transmute, (c from) { ret.write_cvalue_transmute(fx, from); - } - sym::write_bytes | sym::volatile_set_memory => { - intrinsic_args!(fx, args => (dst, val, count); intrinsic); - let val = val.load_scalar(fx); - let count = count.load_scalar(fx); - + }; + write_bytes | volatile_set_memory, (c dst, v val, v count) { let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap().ty; let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let count = if pointee_size != 1 { @@ -561,42 +551,34 @@ fn codegen_regular_intrinsic_call<'tcx>( // FIXME make the memset actually volatile when switching to emit_small_memset // FIXME use emit_small_memset fx.bcx.call_memset(fx.target_config, dst_ptr, val, count); - } - sym::ctlz | sym::ctlz_nonzero => { - intrinsic_args!(fx, args => (arg); intrinsic); + }; + ctlz | ctlz_nonzero, (c arg) { let val = arg.load_scalar(fx); - // FIXME trap on `ctlz_nonzero` with zero arg. let res = fx.bcx.ins().clz(val); let res = CValue::by_val(res, arg.layout()); ret.write_cvalue(fx, res); - } - sym::cttz | sym::cttz_nonzero => { - intrinsic_args!(fx, args => (arg); intrinsic); + }; + cttz | cttz_nonzero, (c arg) { let val = arg.load_scalar(fx); - // FIXME trap on `cttz_nonzero` with zero arg. let res = fx.bcx.ins().ctz(val); let res = CValue::by_val(res, arg.layout()); ret.write_cvalue(fx, res); - } - sym::ctpop => { - intrinsic_args!(fx, args => (arg); intrinsic); + }; + ctpop, (c arg) { let val = arg.load_scalar(fx); - let res = fx.bcx.ins().popcnt(val); let res = CValue::by_val(res, arg.layout()); ret.write_cvalue(fx, res); - } - sym::bitreverse => { - intrinsic_args!(fx, args => (arg); intrinsic); + }; + bitreverse, (c arg) { let val = arg.load_scalar(fx); - let res = fx.bcx.ins().bitrev(val); let res = CValue::by_val(res, arg.layout()); ret.write_cvalue(fx, res); - } - sym::bswap => { + }; + bswap, (c arg) { // FIXME(CraneStation/cranelift#794) add bswap instruction to cranelift fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value { match bcx.func.dfg.value_type(v) { @@ -672,15 +654,11 @@ fn codegen_regular_intrinsic_call<'tcx>( ty => unreachable!("bswap {}", ty), } } - intrinsic_args!(fx, args => (arg); intrinsic); let val = arg.load_scalar(fx); - let res = CValue::by_val(swap(&mut fx.bcx, val), arg.layout()); ret.write_cvalue(fx, res); - } - sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => { - intrinsic_args!(fx, args => (); intrinsic); - + }; + assert_inhabited | assert_zero_valid | assert_uninit_valid, () { let layout = fx.layout_of(substs.type_at(0)); if layout.abi.is_uninhabited() { with_no_trimmed_paths!({ @@ -697,10 +675,7 @@ fn codegen_regular_intrinsic_call<'tcx>( with_no_trimmed_paths!({ crate::base::codegen_panic( fx, - &format!( - "attempted to zero-initialize type `{}`, which is invalid", - layout.ty - ), + &format!("attempted to zero-initialize type `{}`, which is invalid", layout.ty), source_info, ); }); @@ -711,53 +686,41 @@ fn codegen_regular_intrinsic_call<'tcx>( with_no_trimmed_paths!({ crate::base::codegen_panic( fx, - &format!( - "attempted to leave type `{}` uninitialized, which is invalid", - layout.ty - ), + &format!("attempted to leave type `{}` uninitialized, which is invalid", layout.ty), source_info, ) }); return; } - } - - sym::volatile_load | sym::unaligned_volatile_load => { - intrinsic_args!(fx, args => (ptr); intrinsic); + }; + volatile_load | unaligned_volatile_load, (c ptr) { // Cranelift treats loads as volatile by default // FIXME correctly handle unaligned_volatile_load - let inner_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty); + let inner_layout = + fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty); let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), inner_layout); ret.write_cvalue(fx, val); - } - sym::volatile_store | sym::unaligned_volatile_store => { - intrinsic_args!(fx, args => (ptr, val); intrinsic); - let ptr = ptr.load_scalar(fx); - + }; + volatile_store | unaligned_volatile_store, (v ptr, c val) { // Cranelift treats stores as volatile by default // FIXME correctly handle unaligned_volatile_store let dest = CPlace::for_ptr(Pointer::new(ptr), val.layout()); dest.write_cvalue(fx, val); - } - - sym::pref_align_of - | sym::needs_drop - | sym::type_id - | sym::type_name - | sym::variant_count => { - intrinsic_args!(fx, args => (); intrinsic); + }; + pref_align_of | needs_drop | type_id | type_name | variant_count, () { let const_val = fx.tcx.const_eval_instance(ParamEnv::reveal_all(), instance, None).unwrap(); - let val = crate::constant::codegen_const_value(fx, const_val, ret.layout().ty); + let val = crate::constant::codegen_const_value( + fx, + const_val, + ret.layout().ty, + ); ret.write_cvalue(fx, val); - } + }; - sym::ptr_offset_from | sym::ptr_offset_from_unsigned => { - intrinsic_args!(fx, args => (ptr, base); intrinsic); - let ptr = ptr.load_scalar(fx); - let base = base.load_scalar(fx); + ptr_offset_from | ptr_offset_from_unsigned, (v ptr, v base) { let ty = substs.type_at(0); let pointee_size: u64 = fx.layout_of(ty).size.bytes(); @@ -773,44 +736,31 @@ fn codegen_regular_intrinsic_call<'tcx>( CValue::by_val(fx.bcx.ins().sdiv_imm(diff_bytes, pointee_size as i64), isize_layout) }; ret.write_cvalue(fx, val); - } - - sym::ptr_guaranteed_eq => { - intrinsic_args!(fx, args => (a, b); intrinsic); + }; + ptr_guaranteed_eq, (c a, c b) { let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b); ret.write_cvalue(fx, val); - } - - sym::ptr_guaranteed_ne => { - intrinsic_args!(fx, args => (a, b); intrinsic); + }; + ptr_guaranteed_ne, (c a, c b) { let val = crate::num::codegen_ptr_binop(fx, BinOp::Ne, a, b); ret.write_cvalue(fx, val); - } - - sym::caller_location => { - intrinsic_args!(fx, args => (); intrinsic); + }; + caller_location, () { let caller_location = fx.get_caller_location(source_info); ret.write_cvalue(fx, caller_location); - } - - _ if intrinsic.as_str().starts_with("atomic_fence") => { - intrinsic_args!(fx, args => (); intrinsic); + }; + _ if intrinsic.as_str().starts_with("atomic_fence"), () { fx.bcx.ins().fence(); - } - _ if intrinsic.as_str().starts_with("atomic_singlethreadfence") => { - intrinsic_args!(fx, args => (); intrinsic); - + }; + _ if intrinsic.as_str().starts_with("atomic_singlethreadfence"), () { // FIXME use a compiler fence once Cranelift supports it fx.bcx.ins().fence(); - } - _ if intrinsic.as_str().starts_with("atomic_load") => { - intrinsic_args!(fx, args => (ptr); intrinsic); - let ptr = ptr.load_scalar(fx); - + }; + _ if intrinsic.as_str().starts_with("atomic_load"), (v ptr) { let ty = substs.type_at(0); match ty.kind() { ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => { @@ -822,9 +772,7 @@ fn codegen_regular_intrinsic_call<'tcx>( fx.bcx.ins().jump(ret_block, &[]); return; } else { - fx.tcx - .sess - .span_fatal(source_info.span, "128bit atomics not yet supported"); + fx.tcx.sess.span_fatal(source_info.span, "128bit atomics not yet supported"); } } ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} @@ -839,11 +787,8 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(ty)); ret.write_cvalue(fx, val); - } - _ if intrinsic.as_str().starts_with("atomic_store") => { - intrinsic_args!(fx, args => (ptr, val); intrinsic); - let ptr = ptr.load_scalar(fx); - + }; + _ if intrinsic.as_str().starts_with("atomic_store"), (v ptr, c val) { let ty = substs.type_at(0); match ty.kind() { ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => { @@ -855,9 +800,7 @@ fn codegen_regular_intrinsic_call<'tcx>( fx.bcx.ins().jump(ret_block, &[]); return; } else { - fx.tcx - .sess - .span_fatal(source_info.span, "128bit atomics not yet supported"); + fx.tcx.sess.span_fatal(source_info.span, "128bit atomics not yet supported"); } } ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} @@ -870,11 +813,8 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = val.load_scalar(fx); fx.bcx.ins().atomic_store(MemFlags::trusted(), val, ptr); - } - _ if intrinsic.as_str().starts_with("atomic_xchg") => { - intrinsic_args!(fx, args => (ptr, new); intrinsic); - let ptr = ptr.load_scalar(fx); - + }; + _ if intrinsic.as_str().starts_with("atomic_xchg"), (v ptr, c new) { let layout = new.layout(); match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} @@ -891,12 +831,8 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); - } - _ if intrinsic.as_str().starts_with("atomic_cxchg") => { - // both atomic_cxchg_* and atomic_cxchgweak_* - intrinsic_args!(fx, args => (ptr, test_old, new); intrinsic); - let ptr = ptr.load_scalar(fx); - + }; + _ if intrinsic.as_str().starts_with("atomic_cxchg"), (v ptr, c test_old, c new) { // both atomic_cxchg_* and atomic_cxchgweak_* let layout = new.layout(); match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} @@ -912,15 +848,11 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = fx.bcx.ins().atomic_cas(MemFlags::trusted(), ptr, test_old, new); let is_eq = fx.bcx.ins().icmp(IntCC::Equal, old, test_old); - let ret_val = - CValue::by_val_pair(old, fx.bcx.ins().bint(types::I8, is_eq), ret.layout()); + let ret_val = CValue::by_val_pair(old, fx.bcx.ins().bint(types::I8, is_eq), ret.layout()); ret.write_cvalue(fx, ret_val) - } - - _ if intrinsic.as_str().starts_with("atomic_xadd") => { - intrinsic_args!(fx, args => (ptr, amount); intrinsic); - let ptr = ptr.load_scalar(fx); + }; + _ if intrinsic.as_str().starts_with("atomic_xadd"), (v ptr, c amount) { let layout = amount.layout(); match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} @@ -933,16 +865,12 @@ fn codegen_regular_intrinsic_call<'tcx>( let amount = amount.load_scalar(fx); - let old = - fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Add, ptr, amount); + let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Add, ptr, amount); let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); - } - _ if intrinsic.as_str().starts_with("atomic_xsub") => { - intrinsic_args!(fx, args => (ptr, amount); intrinsic); - let ptr = ptr.load_scalar(fx); - + }; + _ if intrinsic.as_str().starts_with("atomic_xsub"), (v ptr, c amount) { let layout = amount.layout(); match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} @@ -955,16 +883,12 @@ fn codegen_regular_intrinsic_call<'tcx>( let amount = amount.load_scalar(fx); - let old = - fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Sub, ptr, amount); + let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Sub, ptr, amount); let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); - } - _ if intrinsic.as_str().starts_with("atomic_and") => { - intrinsic_args!(fx, args => (ptr, src); intrinsic); - let ptr = ptr.load_scalar(fx); - + }; + _ if intrinsic.as_str().starts_with("atomic_and"), (v ptr, c src) { let layout = src.layout(); match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} @@ -981,11 +905,8 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); - } - _ if intrinsic.as_str().starts_with("atomic_or") => { - intrinsic_args!(fx, args => (ptr, src); intrinsic); - let ptr = ptr.load_scalar(fx); - + }; + _ if intrinsic.as_str().starts_with("atomic_or"), (v ptr, c src) { let layout = src.layout(); match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} @@ -1002,11 +923,8 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); - } - _ if intrinsic.as_str().starts_with("atomic_xor") => { - intrinsic_args!(fx, args => (ptr, src); intrinsic); - let ptr = ptr.load_scalar(fx); - + }; + _ if intrinsic.as_str().starts_with("atomic_xor"), (v ptr, c src) { let layout = src.layout(); match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} @@ -1023,11 +941,8 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); - } - _ if intrinsic.as_str().starts_with("atomic_nand") => { - intrinsic_args!(fx, args => (ptr, src); intrinsic); - let ptr = ptr.load_scalar(fx); - + }; + _ if intrinsic.as_str().starts_with("atomic_nand"), (v ptr, c src) { let layout = src.layout(); match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} @@ -1044,11 +959,8 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); - } - _ if intrinsic.as_str().starts_with("atomic_max") => { - intrinsic_args!(fx, args => (ptr, src); intrinsic); - let ptr = ptr.load_scalar(fx); - + }; + _ if intrinsic.as_str().starts_with("atomic_max"), (v ptr, c src) { let layout = src.layout(); match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} @@ -1065,11 +977,8 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); - } - _ if intrinsic.as_str().starts_with("atomic_umax") => { - intrinsic_args!(fx, args => (ptr, src); intrinsic); - let ptr = ptr.load_scalar(fx); - + }; + _ if intrinsic.as_str().starts_with("atomic_umax"), (v ptr, c src) { let layout = src.layout(); match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} @@ -1086,11 +995,8 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); - } - _ if intrinsic.as_str().starts_with("atomic_min") => { - intrinsic_args!(fx, args => (ptr, src); intrinsic); - let ptr = ptr.load_scalar(fx); - + }; + _ if intrinsic.as_str().starts_with("atomic_min"), (v ptr, c src) { let layout = src.layout(); match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} @@ -1107,11 +1013,8 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); - } - _ if intrinsic.as_str().starts_with("atomic_umin") => { - intrinsic_args!(fx, args => (ptr, src); intrinsic); - let ptr = ptr.load_scalar(fx); - + }; + _ if intrinsic.as_str().starts_with("atomic_umin"), (v ptr, c src) { let layout = src.layout(); match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} @@ -1128,51 +1031,30 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); - } - - sym::minnumf32 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); + }; + minnumf32, (v a, v b) { let val = crate::num::codegen_float_min(fx, a, b); let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32)); ret.write_cvalue(fx, val); - } - sym::minnumf64 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - + }; + minnumf64, (v a, v b) { let val = crate::num::codegen_float_min(fx, a, b); let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); ret.write_cvalue(fx, val); - } - sym::maxnumf32 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - + }; + maxnumf32, (v a, v b) { let val = crate::num::codegen_float_max(fx, a, b); let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32)); ret.write_cvalue(fx, val); - } - sym::maxnumf64 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - + }; + maxnumf64, (v a, v b) { let val = crate::num::codegen_float_max(fx, a, b); let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); ret.write_cvalue(fx, val); - } - - kw::Try => { - intrinsic_args!(fx, args => (f, data, catch_fn); intrinsic); - let f = f.load_scalar(fx); - let data = data.load_scalar(fx); - let _catch_fn = catch_fn.load_scalar(fx); + }; + kw.Try, (v f, v data, v _catch_fn) { // FIXME once unwinding is supported, change this to actually catch panics let f_sig = fx.bcx.func.import_signature(Signature { call_conv: fx.target_config.default_call_conv, @@ -1185,30 +1067,20 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = ret.layout(); let ret_val = CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size)); ret.write_cvalue(fx, ret_val); - } - - sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { - intrinsic_args!(fx, args => (x, y); intrinsic); + }; - let res = crate::num::codegen_float_binop( - fx, - match intrinsic { - sym::fadd_fast => BinOp::Add, - sym::fsub_fast => BinOp::Sub, - sym::fmul_fast => BinOp::Mul, - sym::fdiv_fast => BinOp::Div, - sym::frem_fast => BinOp::Rem, - _ => unreachable!(), - }, - x, - y, - ); + fadd_fast | fsub_fast | fmul_fast | fdiv_fast | frem_fast, (c x, c y) { + let res = crate::num::codegen_float_binop(fx, match intrinsic { + sym::fadd_fast => BinOp::Add, + sym::fsub_fast => BinOp::Sub, + sym::fmul_fast => BinOp::Mul, + sym::fdiv_fast => BinOp::Div, + sym::frem_fast => BinOp::Rem, + _ => unreachable!(), + }, x, y); ret.write_cvalue(fx, res); - } - sym::float_to_int_unchecked => { - intrinsic_args!(fx, args => (f); intrinsic); - let f = f.load_scalar(fx); - + }; + float_to_int_unchecked, (v f) { let res = crate::cast::clif_int_or_float_cast( fx, f, @@ -1217,74 +1089,52 @@ fn codegen_regular_intrinsic_call<'tcx>( type_sign(ret.layout().ty), ); ret.write_cvalue(fx, CValue::by_val(res, ret.layout())); - } - - sym::raw_eq => { - intrinsic_args!(fx, args => (lhs_ref, rhs_ref); intrinsic); - let lhs_ref = lhs_ref.load_scalar(fx); - let rhs_ref = rhs_ref.load_scalar(fx); + }; + raw_eq, (v lhs_ref, v rhs_ref) { let size = fx.layout_of(substs.type_at(0)).layout.size(); // FIXME add and use emit_small_memcmp - let is_eq_value = if size == Size::ZERO { - // No bytes means they're trivially equal - fx.bcx.ins().iconst(types::I8, 1) - } else if let Some(clty) = size.bits().try_into().ok().and_then(Type::int) { - // Can't use `trusted` for these loads; they could be unaligned. - let mut flags = MemFlags::new(); - flags.set_notrap(); - let lhs_val = fx.bcx.ins().load(clty, flags, lhs_ref, 0); - let rhs_val = fx.bcx.ins().load(clty, flags, rhs_ref, 0); - let eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val); - fx.bcx.ins().bint(types::I8, eq) - } else { - // Just call `memcmp` (like slices do in core) when the - // size is too large or it's not a power-of-two. - let signed_bytes = i64::try_from(size.bytes()).unwrap(); - let bytes_val = fx.bcx.ins().iconst(fx.pointer_type, signed_bytes); - let params = vec![AbiParam::new(fx.pointer_type); 3]; - let returns = vec![AbiParam::new(types::I32)]; - let args = &[lhs_ref, rhs_ref, bytes_val]; - let cmp = fx.lib_call("memcmp", params, returns, args)[0]; - let eq = fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0); - fx.bcx.ins().bint(types::I8, eq) - }; + let is_eq_value = + if size == Size::ZERO { + // No bytes means they're trivially equal + fx.bcx.ins().iconst(types::I8, 1) + } else if let Some(clty) = size.bits().try_into().ok().and_then(Type::int) { + // Can't use `trusted` for these loads; they could be unaligned. + let mut flags = MemFlags::new(); + flags.set_notrap(); + let lhs_val = fx.bcx.ins().load(clty, flags, lhs_ref, 0); + let rhs_val = fx.bcx.ins().load(clty, flags, rhs_ref, 0); + let eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val); + fx.bcx.ins().bint(types::I8, eq) + } else { + // Just call `memcmp` (like slices do in core) when the + // size is too large or it's not a power-of-two. + let signed_bytes = i64::try_from(size.bytes()).unwrap(); + let bytes_val = fx.bcx.ins().iconst(fx.pointer_type, signed_bytes); + let params = vec![AbiParam::new(fx.pointer_type); 3]; + let returns = vec![AbiParam::new(types::I32)]; + let args = &[lhs_ref, rhs_ref, bytes_val]; + let cmp = fx.lib_call("memcmp", params, returns, args)[0]; + let eq = fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0); + fx.bcx.ins().bint(types::I8, eq) + }; ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout())); - } - - sym::const_allocate => { - intrinsic_args!(fx, args => (_size, _align); intrinsic); + }; + const_allocate, (c _size, c _align) { // returns a null pointer at runtime. let null = fx.bcx.ins().iconst(fx.pointer_type, 0); ret.write_cvalue(fx, CValue::by_val(null, ret.layout())); - } + }; - sym::const_deallocate => { - intrinsic_args!(fx, args => (_ptr, _size, _align); intrinsic); + const_deallocate, (c _ptr, c _size, c _align) { // nop at runtime. - } - - sym::black_box => { - intrinsic_args!(fx, args => (a); intrinsic); + }; + black_box, (c a) { // FIXME implement black_box semantics ret.write_cvalue(fx, a); - } - - // FIXME implement variadics in cranelift - sym::va_copy | sym::va_arg | sym::va_end => { - fx.tcx.sess.span_fatal( - source_info.span, - "Defining variadic functions is not yet supported by Cranelift", - ); - } - - _ => { - fx.tcx - .sess - .span_fatal(source_info.span, &format!("unsupported intrinsic {}", intrinsic)); - } + }; } let ret_block = fx.get_block(destination.unwrap()); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 30e3d112594a6..d1ca9edf2e0f1 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -25,10 +25,13 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ret: CPlace<'tcx>, span: Span, ) { - match intrinsic { - sym::simd_cast => { - intrinsic_args!(fx, args => (a); intrinsic); + intrinsic_match! { + fx, intrinsic, args, + _ => { + fx.tcx.sess.span_fatal(span, &format!("Unknown SIMD intrinsic {}", intrinsic)); + }; + simd_cast, (c a) { if !a.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty); return; @@ -42,11 +45,9 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( clif_int_or_float_cast(fx, lane, from_signed, ret_lane_clif_ty, to_signed) }); - } - - sym::simd_eq | sym::simd_ne | sym::simd_lt | sym::simd_le | sym::simd_gt | sym::simd_ge => { - intrinsic_args!(fx, args => (x, y); intrinsic); + }; + simd_eq | simd_ne | simd_lt | simd_le | simd_gt | simd_ge, (c x, c y) { if !x.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty); return; @@ -56,9 +57,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, res_lane_ty, x_lane, y_lane| { let res_lane = match (lane_ty.kind(), intrinsic) { (ty::Uint(_), sym::simd_eq) => fx.bcx.ins().icmp(IntCC::Equal, x_lane, y_lane), - (ty::Uint(_), sym::simd_ne) => { - fx.bcx.ins().icmp(IntCC::NotEqual, x_lane, y_lane) - } + (ty::Uint(_), sym::simd_ne) => fx.bcx.ins().icmp(IntCC::NotEqual, x_lane, y_lane), (ty::Uint(_), sym::simd_lt) => { fx.bcx.ins().icmp(IntCC::UnsignedLessThan, x_lane, y_lane) } @@ -73,12 +72,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( } (ty::Int(_), sym::simd_eq) => fx.bcx.ins().icmp(IntCC::Equal, x_lane, y_lane), - (ty::Int(_), sym::simd_ne) => { - fx.bcx.ins().icmp(IntCC::NotEqual, x_lane, y_lane) - } - (ty::Int(_), sym::simd_lt) => { - fx.bcx.ins().icmp(IntCC::SignedLessThan, x_lane, y_lane) - } + (ty::Int(_), sym::simd_ne) => fx.bcx.ins().icmp(IntCC::NotEqual, x_lane, y_lane), + (ty::Int(_), sym::simd_lt) => fx.bcx.ins().icmp(IntCC::SignedLessThan, x_lane, y_lane), (ty::Int(_), sym::simd_le) => { fx.bcx.ins().icmp(IntCC::SignedLessThanOrEqual, x_lane, y_lane) } @@ -89,21 +84,13 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( fx.bcx.ins().icmp(IntCC::SignedGreaterThanOrEqual, x_lane, y_lane) } - (ty::Float(_), sym::simd_eq) => { - fx.bcx.ins().fcmp(FloatCC::Equal, x_lane, y_lane) - } - (ty::Float(_), sym::simd_ne) => { - fx.bcx.ins().fcmp(FloatCC::NotEqual, x_lane, y_lane) - } - (ty::Float(_), sym::simd_lt) => { - fx.bcx.ins().fcmp(FloatCC::LessThan, x_lane, y_lane) - } + (ty::Float(_), sym::simd_eq) => fx.bcx.ins().fcmp(FloatCC::Equal, x_lane, y_lane), + (ty::Float(_), sym::simd_ne) => fx.bcx.ins().fcmp(FloatCC::NotEqual, x_lane, y_lane), + (ty::Float(_), sym::simd_lt) => fx.bcx.ins().fcmp(FloatCC::LessThan, x_lane, y_lane), (ty::Float(_), sym::simd_le) => { fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, x_lane, y_lane) } - (ty::Float(_), sym::simd_gt) => { - fx.bcx.ins().fcmp(FloatCC::GreaterThan, x_lane, y_lane) - } + (ty::Float(_), sym::simd_gt) => fx.bcx.ins().fcmp(FloatCC::GreaterThan, x_lane, y_lane), (ty::Float(_), sym::simd_ge) => { fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, x_lane, y_lane) } @@ -116,19 +103,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let res_lane = fx.bcx.ins().bint(ty, res_lane); fx.bcx.ins().ineg(res_lane) }); - } + }; // simd_shuffle32(x: T, y: T, idx: [u32; 32]) -> U - _ if intrinsic.as_str().starts_with("simd_shuffle") => { - let (x, y, idx) = match args { - [x, y, idx] => (x, y, idx), - _ => { - bug!("wrong number of args for intrinsic {intrinsic}"); - } - }; - let x = codegen_operand(fx, x); - let y = codegen_operand(fx, y); - + _ if intrinsic.as_str().starts_with("simd_shuffle"), (c x, c y, o idx) { if !x.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty); return; @@ -141,13 +119,11 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( // version of this intrinsic. let idx_ty = fx.monomorphize(idx.ty(fx.mir, fx.tcx)); match idx_ty.kind() { - ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => len - .try_eval_usize(fx.tcx, ty::ParamEnv::reveal_all()) - .unwrap_or_else(|| { + ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => { + len.try_eval_usize(fx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(|| { span_bug!(span, "could not evaluate shuffle index array length") - }) - .try_into() - .unwrap(), + }).try_into().unwrap() + } _ => { fx.tcx.sess.span_err( span, @@ -178,30 +154,24 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let indexes = { use rustc_middle::mir::interpret::*; - let idx_const = crate::constant::mir_operand_get_const_val(fx, idx) - .expect("simd_shuffle* idx not const"); + let idx_const = crate::constant::mir_operand_get_const_val(fx, idx).expect("simd_shuffle* idx not const"); let idx_bytes = match idx_const { ConstValue::ByRef { alloc, offset } => { - let size = Size::from_bytes( - 4 * ret_lane_count, /* size_of([u32; ret_lane_count]) */ - ); + let size = Size::from_bytes(4 * ret_lane_count /* size_of([u32; ret_lane_count]) */); alloc.inner().get_bytes(fx, alloc_range(offset, size)).unwrap() } _ => unreachable!("{:?}", idx_const), }; - (0..ret_lane_count) - .map(|i| { - let i = usize::try_from(i).unwrap(); - let idx = rustc_middle::mir::interpret::read_target_uint( - fx.tcx.data_layout.endian, - &idx_bytes[4 * i..4 * i + 4], - ) - .expect("read_target_uint"); - u16::try_from(idx).expect("try_from u32") - }) - .collect::>() + (0..ret_lane_count).map(|i| { + let i = usize::try_from(i).unwrap(); + let idx = rustc_middle::mir::interpret::read_target_uint( + fx.tcx.data_layout.endian, + &idx_bytes[4*i.. 4*i + 4], + ).expect("read_target_uint"); + u16::try_from(idx).expect("try_from u32") + }).collect::>() }; for &idx in &indexes { @@ -217,63 +187,43 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let out_lane = ret.place_lane(fx, u64::try_from(out_idx).unwrap()); out_lane.write_cvalue(fx, in_lane); } - } - - sym::simd_insert => { - let (base, idx, val) = match args { - [base, idx, val] => (base, idx, val), - _ => { - bug!("wrong number of args for intrinsic {intrinsic}"); - } - }; - let base = codegen_operand(fx, base); - let val = codegen_operand(fx, val); + }; + simd_insert, (c base, o idx, c val) { // FIXME validate - let idx_const = if let Some(idx_const) = - crate::constant::mir_operand_get_const_val(fx, idx) - { + let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) { idx_const } else { - fx.tcx.sess.span_fatal(span, "Index argument for `simd_insert` is not a constant"); + fx.tcx.sess.span_fatal( + span, + "Index argument for `simd_insert` is not a constant", + ); }; - let idx = idx_const - .try_to_bits(Size::from_bytes(4 /* u32*/)) - .unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); + let idx = idx_const.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx); if idx >= lane_count.into() { - fx.tcx.sess.span_fatal( - fx.mir.span, - &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count), - ); + fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count)); } ret.write_cvalue(fx, base); let ret_lane = ret.place_field(fx, mir::Field::new(idx.try_into().unwrap())); ret_lane.write_cvalue(fx, val); - } - - sym::simd_extract => { - let (v, idx) = match args { - [v, idx] => (v, idx), - _ => { - bug!("wrong number of args for intrinsic {intrinsic}"); - } - }; - let v = codegen_operand(fx, v); + }; + simd_extract, (c v, o idx) { if !v.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); return; } - let idx_const = if let Some(idx_const) = - crate::constant::mir_operand_get_const_val(fx, idx) - { + let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) { idx_const } else { - fx.tcx.sess.span_warn(span, "Index argument for `simd_extract` is not a constant"); + fx.tcx.sess.span_warn( + span, + "Index argument for `simd_extract` is not a constant", + ); let res = crate::trap::trap_unimplemented_ret_value( fx, ret.layout(), @@ -283,105 +233,89 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( return; }; - let idx = idx_const - .try_to_bits(Size::from_bytes(4 /* u32*/)) - .unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); + let idx = idx_const.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx); if idx >= lane_count.into() { - fx.tcx.sess.span_fatal( - fx.mir.span, - &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count), - ); + fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count)); } let ret_lane = v.value_lane(fx, idx.try_into().unwrap()); ret.write_cvalue(fx, ret_lane); - } - - sym::simd_neg => { - intrinsic_args!(fx, args => (a); intrinsic); + }; + simd_neg, (c a) { if !a.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty); return; } - simd_for_each_lane( - fx, - a, - ret, - &|fx, lane_ty, _ret_lane_ty, lane| match lane_ty.kind() { + simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| { + match lane_ty.kind() { ty::Int(_) => fx.bcx.ins().ineg(lane), ty::Float(_) => fx.bcx.ins().fneg(lane), - _ => unreachable!(), - }, - ); - } - - sym::simd_add - | sym::simd_sub - | sym::simd_mul - | sym::simd_div - | sym::simd_rem - | sym::simd_shl - | sym::simd_shr - | sym::simd_and - | sym::simd_or - | sym::simd_xor => { - intrinsic_args!(fx, args => (x, y); intrinsic); - - // FIXME use vector instructions when possible - simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, _ret_lane_ty, x_lane, y_lane| { - match (lane_ty.kind(), intrinsic) { - (ty::Uint(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane), - (ty::Uint(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane), - (ty::Uint(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane), - (ty::Uint(_), sym::simd_div) => fx.bcx.ins().udiv(x_lane, y_lane), - (ty::Uint(_), sym::simd_rem) => fx.bcx.ins().urem(x_lane, y_lane), - - (ty::Int(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane), - (ty::Int(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane), - (ty::Int(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane), - (ty::Int(_), sym::simd_div) => fx.bcx.ins().sdiv(x_lane, y_lane), - (ty::Int(_), sym::simd_rem) => fx.bcx.ins().srem(x_lane, y_lane), - - (ty::Float(_), sym::simd_add) => fx.bcx.ins().fadd(x_lane, y_lane), - (ty::Float(_), sym::simd_sub) => fx.bcx.ins().fsub(x_lane, y_lane), - (ty::Float(_), sym::simd_mul) => fx.bcx.ins().fmul(x_lane, y_lane), - (ty::Float(_), sym::simd_div) => fx.bcx.ins().fdiv(x_lane, y_lane), - (ty::Float(FloatTy::F32), sym::simd_rem) => fx.lib_call( - "fmodf", - vec![AbiParam::new(types::F32), AbiParam::new(types::F32)], - vec![AbiParam::new(types::F32)], - &[x_lane, y_lane], - )[0], - (ty::Float(FloatTy::F64), sym::simd_rem) => fx.lib_call( - "fmod", - vec![AbiParam::new(types::F64), AbiParam::new(types::F64)], - vec![AbiParam::new(types::F64)], - &[x_lane, y_lane], - )[0], - - (ty::Uint(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane), - (ty::Uint(_), sym::simd_shr) => fx.bcx.ins().ushr(x_lane, y_lane), - (ty::Uint(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane), - (ty::Uint(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane), - (ty::Uint(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane), - - (ty::Int(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane), - (ty::Int(_), sym::simd_shr) => fx.bcx.ins().sshr(x_lane, y_lane), - (ty::Int(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane), - (ty::Int(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane), - (ty::Int(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane), - _ => unreachable!(), } }); - } + }; + + simd_add | simd_sub | simd_mul | simd_div | simd_rem + | simd_shl | simd_shr | simd_and | simd_or | simd_xor, (c x, c y) { + if !x.layout().ty.is_simd() { + report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty); + return; + } - sym::simd_fma => { - intrinsic_args!(fx, args => (a, b, c); intrinsic); + // FIXME use vector instructions when possible + simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, _ret_lane_ty, x_lane, y_lane| match ( + lane_ty.kind(), + intrinsic, + ) { + (ty::Uint(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane), + (ty::Uint(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane), + (ty::Uint(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane), + (ty::Uint(_), sym::simd_div) => fx.bcx.ins().udiv(x_lane, y_lane), + (ty::Uint(_), sym::simd_rem) => fx.bcx.ins().urem(x_lane, y_lane), + + (ty::Int(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane), + (ty::Int(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane), + (ty::Int(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane), + (ty::Int(_), sym::simd_div) => fx.bcx.ins().sdiv(x_lane, y_lane), + (ty::Int(_), sym::simd_rem) => fx.bcx.ins().srem(x_lane, y_lane), + + (ty::Float(_), sym::simd_add) => fx.bcx.ins().fadd(x_lane, y_lane), + (ty::Float(_), sym::simd_sub) => fx.bcx.ins().fsub(x_lane, y_lane), + (ty::Float(_), sym::simd_mul) => fx.bcx.ins().fmul(x_lane, y_lane), + (ty::Float(_), sym::simd_div) => fx.bcx.ins().fdiv(x_lane, y_lane), + (ty::Float(FloatTy::F32), sym::simd_rem) => fx.lib_call( + "fmodf", + vec![AbiParam::new(types::F32), AbiParam::new(types::F32)], + vec![AbiParam::new(types::F32)], + &[x_lane, y_lane], + )[0], + (ty::Float(FloatTy::F64), sym::simd_rem) => fx.lib_call( + "fmod", + vec![AbiParam::new(types::F64), AbiParam::new(types::F64)], + vec![AbiParam::new(types::F64)], + &[x_lane, y_lane], + )[0], + + (ty::Uint(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane), + (ty::Uint(_), sym::simd_shr) => fx.bcx.ins().ushr(x_lane, y_lane), + (ty::Uint(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane), + (ty::Uint(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane), + (ty::Uint(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane), + + (ty::Int(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane), + (ty::Int(_), sym::simd_shr) => fx.bcx.ins().sshr(x_lane, y_lane), + (ty::Int(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane), + (ty::Int(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane), + (ty::Int(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane), + + _ => unreachable!(), + }); + }; + simd_fma, (c a, c b, c c) { if !a.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty); return; @@ -399,22 +333,16 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let c_lane = c.value_lane(fx, lane); let res_lane = match lane_ty.kind() { - ty::Float(FloatTy::F32) => { - fx.easy_call("fmaf", &[a_lane, b_lane, c_lane], lane_ty) - } - ty::Float(FloatTy::F64) => { - fx.easy_call("fma", &[a_lane, b_lane, c_lane], lane_ty) - } + ty::Float(FloatTy::F32) => fx.easy_call("fmaf", &[a_lane, b_lane, c_lane], lane_ty), + ty::Float(FloatTy::F64) => fx.easy_call("fma", &[a_lane, b_lane, c_lane], lane_ty), _ => unreachable!(), }; ret.place_lane(fx, lane).write_cvalue(fx, res_lane); } - } - - sym::simd_fmin | sym::simd_fmax => { - intrinsic_args!(fx, args => (x, y); intrinsic); + }; + simd_fmin | simd_fmax, (c x, c y) { if !x.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty); return; @@ -423,7 +351,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( // FIXME use vector instructions when possible simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, _ret_lane_ty, x_lane, y_lane| { match lane_ty.kind() { - ty::Float(_) => {} + ty::Float(_) => {}, _ => unreachable!("{:?}", lane_ty), } match intrinsic { @@ -432,21 +360,16 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( _ => unreachable!(), } }); - } - - sym::simd_round => { - intrinsic_args!(fx, args => (a); intrinsic); + }; + simd_round, (c a) { if !a.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty); return; } - simd_for_each_lane( - fx, - a, - ret, - &|fx, lane_ty, _ret_lane_ty, lane| match lane_ty.kind() { + simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| { + match lane_ty.kind() { ty::Float(FloatTy::F32) => fx.lib_call( "roundf", vec![AbiParam::new(types::F32)], @@ -460,13 +383,11 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( &[lane], )[0], _ => unreachable!("{:?}", lane_ty), - }, - ); - } - - sym::simd_fabs | sym::simd_fsqrt | sym::simd_ceil | sym::simd_floor | sym::simd_trunc => { - intrinsic_args!(fx, args => (a); intrinsic); + } + }); + }; + simd_fabs | simd_fsqrt | simd_ceil | simd_floor | simd_trunc, (c a) { if !a.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty); return; @@ -474,7 +395,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| { match lane_ty.kind() { - ty::Float(_) => {} + ty::Float(_) => {}, _ => unreachable!("{:?}", lane_ty), } match intrinsic { @@ -486,12 +407,9 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( _ => unreachable!(), } }); - } - - sym::simd_reduce_add_ordered | sym::simd_reduce_add_unordered => { - intrinsic_args!(fx, args => (v, acc); intrinsic); - let acc = acc.load_scalar(fx); + }; + simd_reduce_add_ordered | simd_reduce_add_unordered, (c v, v acc) { // FIXME there must be no acc param for integer vectors if !v.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); @@ -505,12 +423,9 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( fx.bcx.ins().iadd(a, b) } }); - } - - sym::simd_reduce_mul_ordered | sym::simd_reduce_mul_unordered => { - intrinsic_args!(fx, args => (v, acc); intrinsic); - let acc = acc.load_scalar(fx); + }; + simd_reduce_mul_ordered | simd_reduce_mul_unordered, (c v, v acc) { // FIXME there must be no acc param for integer vectors if !v.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); @@ -524,66 +439,54 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( fx.bcx.ins().imul(a, b) } }); - } - - sym::simd_reduce_all => { - intrinsic_args!(fx, args => (v); intrinsic); + }; + simd_reduce_all, (c v) { if !v.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); return; } simd_reduce_bool(fx, v, ret, &|fx, a, b| fx.bcx.ins().band(a, b)); - } - - sym::simd_reduce_any => { - intrinsic_args!(fx, args => (v); intrinsic); + }; + simd_reduce_any, (c v) { if !v.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); return; } simd_reduce_bool(fx, v, ret, &|fx, a, b| fx.bcx.ins().bor(a, b)); - } - - sym::simd_reduce_and => { - intrinsic_args!(fx, args => (v); intrinsic); + }; + simd_reduce_and, (c v) { if !v.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); return; } simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().band(a, b)); - } - - sym::simd_reduce_or => { - intrinsic_args!(fx, args => (v); intrinsic); + }; + simd_reduce_or, (c v) { if !v.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); return; } simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().bor(a, b)); - } - - sym::simd_reduce_xor => { - intrinsic_args!(fx, args => (v); intrinsic); + }; + simd_reduce_xor, (c v) { if !v.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); return; } simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().bxor(a, b)); - } - - sym::simd_reduce_min => { - intrinsic_args!(fx, args => (v); intrinsic); + }; + simd_reduce_min, (c v) { if !v.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); return; @@ -598,11 +501,9 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }; fx.bcx.ins().select(lt, a, b) }); - } - - sym::simd_reduce_max => { - intrinsic_args!(fx, args => (v); intrinsic); + }; + simd_reduce_max, (c v) { if !v.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); return; @@ -617,11 +518,9 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }; fx.bcx.ins().select(gt, a, b) }); - } - - sym::simd_select => { - intrinsic_args!(fx, args => (m, a, b); intrinsic); + }; + simd_select, (c m, c a, c b) { if !m.layout().ty.is_simd() { report_simd_type_validation_error(fx, intrinsic, span, m.layout().ty); return; @@ -641,19 +540,15 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let b_lane = b.value_lane(fx, lane).load_scalar(fx); let m_lane = fx.bcx.ins().icmp_imm(IntCC::Equal, m_lane, 0); - let res_lane = - CValue::by_val(fx.bcx.ins().select(m_lane, b_lane, a_lane), lane_layout); + let res_lane = CValue::by_val(fx.bcx.ins().select(m_lane, b_lane, a_lane), lane_layout); ret.place_lane(fx, lane).write_cvalue(fx, res_lane); } - } + }; // simd_saturating_* // simd_bitmask // simd_scatter // simd_gather - _ => { - fx.tcx.sess.span_fatal(span, &format!("Unknown SIMD intrinsic {}", intrinsic)); - } } } diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 568bb20a3f4a7..3ed3453c6c7b3 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -141,11 +141,7 @@ impl<'tcx> CodegenCx<'tcx> { let unwind_context = UnwindContext::new(isa, matches!(backend_config.codegen_mode, CodegenMode::Aot)); - let debug_context = if debug_info && !tcx.sess.target.options.is_like_windows { - Some(DebugContext::new(tcx, isa)) - } else { - None - }; + let debug_context = if debug_info { Some(DebugContext::new(tcx, isa)) } else { None }; CodegenCx { tcx, global_asm: String::new(), @@ -247,7 +243,6 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box "elf_gd", diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index c67b6e98b32c7..2f71a70a44946 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -109,8 +109,7 @@ pub(crate) fn maybe_create_entry_wrapper( tcx.mk_substs([GenericArg::from(main_ret_ty)].iter()), ) .unwrap() - .unwrap() - .polymorphize(tcx); + .unwrap(); let report_name = tcx.symbol_name(report).name; let report_sig = get_function_sig(tcx, m.isa().triple(), report); diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs index 1d1ec21680e30..ca7116b887d5a 100644 --- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs +++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs @@ -66,7 +66,7 @@ use rustc_session::config::OutputType; use crate::prelude::*; -#[derive(Clone, Debug)] +#[derive(Debug)] pub(crate) struct CommentWriter { enabled: bool, global_comments: Vec, @@ -237,7 +237,6 @@ pub(crate) fn write_clif_file<'tcx>( func: &cranelift_codegen::ir::Function, mut clif_comments: &CommentWriter, ) { - // FIXME work around filename too long errors write_ir_file( tcx, || format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix), diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 052ca0a082b3c..fd63c3ecddbdf 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -153,7 +153,11 @@ pub(crate) fn size_and_align_of_dst<'tcx>( layout: TyAndLayout<'tcx>, info: Value, ) -> (Value, Value) { - assert!(layout.is_unsized() || layout.abi == Abi::Uninhabited); + if !layout.is_unsized() { + let size = fx.bcx.ins().iconst(fx.pointer_type, layout.size.bytes() as i64); + let align = fx.bcx.ins().iconst(fx.pointer_type, layout.align.abi.bytes() as i64); + return (size, align); + } match layout.ty.kind() { ty::Dynamic(..) => { // load size/align from vtable diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 45ae2bd8f07cb..a68225de58b32 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -324,12 +324,6 @@ impl<'tcx> CPlace<'tcx> { }; } - if layout.size.bytes() >= u64::from(u32::MAX - 16) { - fx.tcx - .sess - .fatal(&format!("values of type {} are too big to store on the stack", layout.ty)); - } - let stack_slot = fx.bcx.create_stack_slot(StackSlotData { kind: StackSlotKind::ExplicitSlot, // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to @@ -426,7 +420,7 @@ impl<'tcx> CPlace<'tcx> { } pub(crate) fn write_cvalue(self, fx: &mut FunctionCx<'_, '_, 'tcx>, from: CValue<'tcx>) { - assert_assignable(fx, from.layout().ty, self.layout().ty, 16); + assert_assignable(fx, from.layout().ty, self.layout().ty); self.write_cvalue_maybe_transmute(fx, from, "write_cvalue"); } @@ -780,25 +774,18 @@ pub(crate) fn assert_assignable<'tcx>( fx: &FunctionCx<'_, '_, 'tcx>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, - limit: usize, ) { - if limit == 0 { - // assert_assignable exists solely to catch bugs in cg_clif. it isn't necessary for - // soundness. don't attempt to check deep types to avoid exponential behavior in certain - // cases. - return; - } match (from_ty.kind(), to_ty.kind()) { (ty::Ref(_, a, _), ty::Ref(_, b, _)) | ( ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }), ) => { - assert_assignable(fx, *a, *b, limit - 1); + assert_assignable(fx, *a, *b); } (ty::Ref(_, a, _), ty::RawPtr(TypeAndMut { ty: b, mutbl: _ })) | (ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), ty::Ref(_, b, _)) => { - assert_assignable(fx, *a, *b, limit - 1); + assert_assignable(fx, *a, *b); } (ty::FnPtr(_), ty::FnPtr(_)) => { let from_sig = fx.tcx.normalize_erasing_late_bound_regions( @@ -828,17 +815,6 @@ pub(crate) fn assert_assignable<'tcx>( } // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed } - (&ty::Tuple(types_a), &ty::Tuple(types_b)) => { - let mut types_a = types_a.iter(); - let mut types_b = types_b.iter(); - loop { - match (types_a.next(), types_b.next()) { - (Some(a), Some(b)) => assert_assignable(fx, a, b, limit - 1), - (None, None) => return, - (Some(_), None) | (None, Some(_)) => panic!("{:#?}/{:#?}", from_ty, to_ty), - } - } - } (&ty::Adt(adt_def_a, substs_a), &ty::Adt(adt_def_b, substs_b)) if adt_def_a.did() == adt_def_b.did() => { @@ -846,37 +822,18 @@ pub(crate) fn assert_assignable<'tcx>( let mut types_b = substs_b.types(); loop { match (types_a.next(), types_b.next()) { - (Some(a), Some(b)) => assert_assignable(fx, a, b, limit - 1), + (Some(a), Some(b)) => assert_assignable(fx, a, b), (None, None) => return, (Some(_), None) | (None, Some(_)) => panic!("{:#?}/{:#?}", from_ty, to_ty), } } } - (ty::Array(a, _), ty::Array(b, _)) => assert_assignable(fx, *a, *b, limit - 1), - (&ty::Closure(def_id_a, substs_a), &ty::Closure(def_id_b, substs_b)) - if def_id_a == def_id_b => - { - let mut types_a = substs_a.types(); - let mut types_b = substs_b.types(); - loop { - match (types_a.next(), types_b.next()) { - (Some(a), Some(b)) => assert_assignable(fx, a, b, limit - 1), - (None, None) => return, - (Some(_), None) | (None, Some(_)) => panic!("{:#?}/{:#?}", from_ty, to_ty), - } - } - } - (ty::Param(_), _) | (_, ty::Param(_)) if fx.tcx.sess.opts.unstable_opts.polymorphize => { - // No way to check if it is correct or not with polymorphization enabled - } + (ty::Array(a, _), ty::Array(b, _)) => assert_assignable(fx, *a, *b), _ => { assert_eq!( - from_ty, - to_ty, + from_ty, to_ty, "Can't write value with incompatible type {:?} to place with type {:?}\n\n{:#?}", - from_ty.kind(), - to_ty.kind(), - fx, + from_ty, to_ty, fx, ); } } diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 0ed3e1fbe93f6..2c796d0f69e59 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -1,6 +1,6 @@ use gccjit::{ToLValue, ToRValue, Type}; use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_middle::bug; use rustc_middle::ty::Ty; use rustc_target::abi::call::{CastTarget, FnAbi, PassMode, Reg, RegKind}; diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs index 21f62a6b0096a..411ec27139e42 100644 --- a/compiler/rustc_codegen_gcc/src/archive.rs +++ b/compiler/rustc_codegen_gcc/src/archive.rs @@ -4,6 +4,7 @@ use std::path::{Path, PathBuf}; use rustc_codegen_ssa::back::archive::ArchiveBuilder; use rustc_session::Session; +use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_session::cstore::DllImport; struct ArchiveConfig<'a> { @@ -176,16 +177,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { any_members } - fn sess(&self) -> &Session { - self.config.sess - } - - fn create_dll_import_lib( - _sess: &Session, - _lib_name: &str, - _dll_imports: &[DllImport], - _tmpdir: &Path, - ) -> PathBuf { + fn inject_dll_import_lib(&mut self, _lib_name: &str, _dll_imports: &[DllImport], _tmpdir: &MaybeTempDir) { unimplemented!(); } } diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 4d40dd0994dd2..fa490fe3f222e 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -30,7 +30,7 @@ use rustc_codegen_ssa::traits::{ OverflowOp, StaticBuilderMethods, }; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_span::Span; @@ -784,6 +784,16 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // TODO(antoyo) } + fn type_metadata(&mut self, _function: RValue<'gcc>, _typeid: String) { + // Unsupported. + } + + fn typeid_metadata(&mut self, _typeid: String) -> RValue<'gcc> { + // Unsupported. + self.context.new_rvalue_from_int(self.int_type, 0) + } + + fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { self.store_with_flags(val, ptr, align, MemFlags::empty()) } diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index ccb6cbbc2c8a7..fc391f53f18e7 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -201,11 +201,6 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { GlobalAlloc::Function(fn_instance) => { self.get_fn_addr(fn_instance) }, - GlobalAlloc::VTable(ty, trait_ref) => { - let alloc = self.tcx.global_alloc(self.tcx.vtable_allocation((ty, trait_ref))).unwrap_memory(); - let init = const_alloc_to_gcc(self, alloc); - self.static_addr_of(init, alloc.inner().align, None) - } GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); self.get_static(def_id).get_address(None) diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs index 68bdb8d4e55f4..002b95db36dee 100644 --- a/compiler/rustc_codegen_gcc/src/type_.rs +++ b/compiler/rustc_codegen_gcc/src/type_.rs @@ -1,7 +1,7 @@ use std::convert::TryInto; use gccjit::{RValue, Struct, Type}; -use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, TypeMembershipMethods}; +use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods}; use rustc_codegen_ssa::common::TypeKind; use rustc_middle::{bug, ty}; use rustc_middle::ty::layout::TyAndLayout; @@ -290,14 +290,3 @@ pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout (result, packed) } - -impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> { - fn set_type_metadata(&self, _function: RValue<'gcc>, _typeid: String) { - // Unsupported. - } - - fn typeid_metadata(&self, _typeid: String) -> RValue<'gcc> { - // Unsupported. - self.context.new_rvalue_from_int(self.int_type, 0) - } -} diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index f9a5463efcd8a..d8fbd0a84fb36 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -18,6 +18,7 @@ rustc_middle = { path = "../rustc_middle" } rustc-demangle = "0.1.21" rustc_attr = { path = "../rustc_attr" } rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } +rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fs_util = { path = "../rustc_fs_util" } @@ -29,7 +30,6 @@ rustc_metadata = { path = "../rustc_metadata" } rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } rustc_serialize = { path = "../rustc_serialize" } -rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 9eb3574e77b00..d4437bd449d50 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -569,22 +569,6 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { &[cmse_nonsecure_call], ); } - - // Some intrinsics require that an elementtype attribute (with the pointee type of a - // pointer argument) is added to the callsite. - let element_type_index = unsafe { llvm::LLVMRustGetElementTypeArgIndex(callsite) }; - if element_type_index >= 0 { - let arg_ty = self.args[element_type_index as usize].layout.ty; - let pointee_ty = arg_ty.builtin_deref(true).expect("Must be pointer argument").ty; - let element_type_attr = unsafe { - llvm::LLVMRustCreateElementTypeAttr(bx.llcx, bx.layout_of(pointee_ty).llvm_type(bx)) - }; - attributes::apply_to_callsite( - callsite, - llvm::AttributePlace::Argument(element_type_index as u32), - &[element_type_attr], - ); - } } } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index aabbe8ac276d7..62da99ac3fb66 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -13,7 +13,7 @@ use smallvec::SmallVec; use crate::attributes; use crate::llvm::AttributePlace::Function; -use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace}; +use crate::llvm::{self, Attribute, AttributeKind, AttributePlace}; use crate::llvm_util; pub use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr}; @@ -69,9 +69,6 @@ pub fn sanitize_attrs<'ll>( if enabled.contains(SanitizerSet::HWADDRESS) { attrs.push(llvm::AttributeKind::SanitizeHWAddress.create_attr(cx.llcx)); } - if enabled.contains(SanitizerSet::SHADOWCALLSTACK) { - attrs.push(llvm::AttributeKind::ShadowCallStack.create_attr(cx.llcx)); - } if enabled.contains(SanitizerSet::MEMTAG) { // Check to make sure the mte target feature is actually enabled. let features = cx.tcx.global_backend_features(()); @@ -227,10 +224,6 @@ pub(crate) fn default_optimisation_attrs<'ll>( attrs } -fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute { - llvm::CreateAttrStringValue(llcx, "alloc-family", "__rust_alloc") -} - /// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`) /// attributes. pub fn from_fn_attrs<'ll, 'tcx>( @@ -313,54 +306,11 @@ pub fn from_fn_attrs<'ll, 'tcx>( // Need this for AArch64. to_add.push(llvm::CreateAttrStringValue(cx.llcx, "branch-target-enforcement", "false")); } - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) - || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED) - { - if llvm_util::get_version() >= (15, 0, 0) { - to_add.push(create_alloc_family_attr(cx.llcx)); - // apply to argument place instead of function - let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::Argument(1), &[alloc_align]); - to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 0)); - let mut flags = AllocKindFlags::Alloc | AllocKindFlags::Aligned; - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) { - flags |= AllocKindFlags::Uninitialized; - } else { - flags |= AllocKindFlags::Zeroed; - } - to_add.push(llvm::CreateAllocKindAttr(cx.llcx, flags)); - } + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) { // apply to return place instead of function (unlike all other attributes applied in this function) let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx); attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]); } - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::REALLOCATOR) { - if llvm_util::get_version() >= (15, 0, 0) { - to_add.push(create_alloc_family_attr(cx.llcx)); - to_add.push(llvm::CreateAllocKindAttr( - cx.llcx, - AllocKindFlags::Realloc | AllocKindFlags::Aligned, - )); - // applies to argument place instead of function place - let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); - // apply to argument place instead of function - let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::Argument(2), &[alloc_align]); - to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 3)); - } - let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]); - } - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::DEALLOCATOR) { - if llvm_util::get_version() >= (15, 0, 0) { - to_add.push(create_alloc_family_attr(cx.llcx)); - to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free)); - // applies to argument place instead of function place - let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); - } - } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) { to_add.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry")); } diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index baa858709a0c6..bccc2a995a30c 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -11,6 +11,7 @@ use std::str; use crate::llvm::archive_ro::{ArchiveRO, Child}; use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport}; use rustc_codegen_ssa::back::archive::ArchiveBuilder; +use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_session::cstore::{DllCallingConvention, DllImport}; use rustc_session::Session; @@ -95,23 +96,19 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { } } - fn sess(&self) -> &Session { - self.sess - } - - fn create_dll_import_lib( - sess: &Session, + fn inject_dll_import_lib( + &mut self, lib_name: &str, dll_imports: &[DllImport], - tmpdir: &Path, - ) -> PathBuf { + tmpdir: &MaybeTempDir, + ) { let output_path = { - let mut output_path: PathBuf = tmpdir.to_path_buf(); + let mut output_path: PathBuf = tmpdir.as_ref().to_path_buf(); output_path.push(format!("{}_imports", lib_name)); output_path.with_extension("lib") }; - let target = &sess.target; + let target = &self.sess.target; let mingw_gnu_toolchain = target.vendor == "pc" && target.os == "windows" && target.env == "gnu" @@ -120,7 +117,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { let import_name_and_ordinal_vector: Vec<(String, Option)> = dll_imports .iter() .map(|import: &DllImport| { - if sess.target.arch == "x86" { + if self.sess.target.arch == "x86" { ( LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain), import.ordinal, @@ -137,7 +134,8 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { // that loaded but crashed with an AV upon calling one of the imported // functions. Therefore, use binutils to create the import library instead, // by writing a .DEF file to the temp dir and calling binutils's dlltool. - let def_file_path = tmpdir.join(format!("{}_imports", lib_name)).with_extension("def"); + let def_file_path = + tmpdir.as_ref().join(format!("{}_imports", lib_name)).with_extension("def"); let def_file_content = format!( "EXPORTS\n{}", @@ -156,11 +154,11 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { match std::fs::write(&def_file_path, def_file_content) { Ok(_) => {} Err(e) => { - sess.fatal(&format!("Error writing .DEF file: {}", e)); + self.sess.fatal(&format!("Error writing .DEF file: {}", e)); } }; - let dlltool = find_binutils_dlltool(sess); + let dlltool = find_binutils_dlltool(self.sess); let result = std::process::Command::new(dlltool) .args([ "-d", @@ -174,9 +172,9 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { match result { Err(e) => { - sess.fatal(&format!("Error calling dlltool: {}", e)); + self.sess.fatal(&format!("Error calling dlltool: {}", e)); } - Ok(output) if !output.status.success() => sess.fatal(&format!( + Ok(output) if !output.status.success() => self.sess.fatal(&format!( "Dlltool could not create import library: {}\n{}", String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr) @@ -222,13 +220,13 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { output_path_z.as_ptr(), ffi_exports.as_ptr(), ffi_exports.len(), - llvm_machine_type(&sess.target.arch) as u16, - !sess.target.is_like_msvc, + llvm_machine_type(&self.sess.target.arch) as u16, + !self.sess.target.is_like_msvc, ) }; if result == crate::llvm::LLVMRustResult::Failure { - sess.fatal(&format!( + self.sess.fatal(&format!( "Error creating import library for {}: {}", lib_name, llvm::last_error().unwrap_or("unknown LLVM error".to_string()) @@ -236,7 +234,13 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { } }; - output_path + self.add_archive(&output_path, |_| false).unwrap_or_else(|e| { + self.sess.fatal(&format!( + "failed to add native library {}: {}", + output_path.display(), + e + )); + }); } } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 3731c6bcfe77b..be539499b5610 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -199,7 +199,7 @@ pub(crate) fn run_thin( pub(crate) fn prepare_thin(module: ModuleCodegen) -> (String, ThinBuffer) { let name = module.name.clone(); - let buffer = ThinBuffer::new(module.module_llvm.llmod(), true); + let buffer = ThinBuffer::new(module.module_llvm.llmod()); (name, buffer) } @@ -695,9 +695,9 @@ unsafe impl Send for ThinBuffer {} unsafe impl Sync for ThinBuffer {} impl ThinBuffer { - pub fn new(m: &llvm::Module, is_thin: bool) -> ThinBuffer { + pub fn new(m: &llvm::Module) -> ThinBuffer { unsafe { - let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin); + let buffer = llvm::LLVMRustThinLTOBufferCreate(m); ThinBuffer(buffer) } } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 534d32e8a90e9..2b465ce40e7d4 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -790,7 +790,7 @@ pub(crate) unsafe fn codegen( let _timer = cgcx .prof .generic_activity_with_arg("LLVM_module_codegen_make_bitcode", &*module.name); - let thin = ThinBuffer::new(llmod, config.emit_thin_lto); + let thin = ThinBuffer::new(llmod); let data = thin.data(); if let Some(bitcode_filename) = bc_out.file_name() { diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index d3096c73a8a9d..4a4cccb490d1c 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -626,6 +626,32 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } + fn type_metadata(&mut self, function: &'ll Value, typeid: String) { + let typeid_metadata = self.typeid_metadata(typeid); + let v = [self.const_usize(0), typeid_metadata]; + unsafe { + llvm::LLVMGlobalSetMetadata( + function, + llvm::MD_type as c_uint, + llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext( + self.cx.llcx, + v.as_ptr(), + v.len() as c_uint, + )), + ) + } + } + + fn typeid_metadata(&mut self, typeid: String) -> Self::Value { + unsafe { + llvm::LLVMMDStringInContext( + self.cx.llcx, + typeid.as_ptr() as *const c_char, + typeid.as_bytes().len() as c_uint, + ) + } + } + fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value { self.store_with_flags(val, ptr, align, MemFlags::empty()) } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index fb4da9a5f3370..77cbbf4c6cacf 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -257,15 +257,6 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { self.get_fn_addr(fn_instance.polymorphize(self.tcx)), self.data_layout().instruction_address_space, ), - GlobalAlloc::VTable(ty, trait_ref) => { - let alloc = self - .tcx - .global_alloc(self.tcx.vtable_allocation((ty, trait_ref))) - .unwrap_memory(); - let init = const_alloc_to_llvm(self, alloc); - let value = self.static_addr_of(init, alloc.inner().align, None); - (value, AddressSpace::DATA) - } GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); assert!(!self.tcx.is_thread_local_static(def_id)); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 18467e37082d6..2b16ae1a88de0 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -101,9 +101,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation< let address_space = match cx.tcx.global_alloc(alloc_id) { GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space, - GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => { - AddressSpace::DATA - } + GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) => AddressSpace::DATA, }; llvals.push(cx.scalar_to_backend( @@ -537,20 +535,10 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { // The semantics of #[used] in Rust only require the symbol to make it into the // object file. It is explicitly allowed for the linker to strip the symbol if it - // is dead, which means we are allowed use `llvm.compiler.used` instead of - // `llvm.used` here. - // + // is dead. As such, use llvm.compiler.used instead of llvm.used. // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs - // in the handling of `.init_array` (the static constructor list) in versions of - // the gold linker (prior to the one released with binutils 2.36). - // - // That said, we only ever emit these when compiling for ELF targets, unless - // `#[used(compiler)]` is explicitly requested. This is to avoid similar breakage - // on other targets, in particular MachO targets have *their* static constructor - // lists broken if `llvm.compiler.used` is emitted rather than llvm.used. However, - // that check happens when assigning the `CodegenFnAttrFlags` in `rustc_typeck`, - // so we don't need to take care of it here. + // in some versions of the gold linker. self.add_compiler_used_global(g); } if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index bd84100e0e883..f8bd2d234f32a 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1420,7 +1420,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>( cx, type_map::stub( cx, - Stub::VTableTy { vtable_holder }, + Stub::VtableTy { vtable_holder }, unique_type_id, &vtable_type_name, (size, pointer_align), diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index ce2f419c4acdc..8fc8118849bae 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -146,7 +146,7 @@ impl<'ll> DINodeCreationResult<'ll> { pub enum Stub<'ll> { Struct, Union, - VTableTy { vtable_holder: &'ll DIType }, + VtableTy { vtable_holder: &'ll DIType }, } pub struct StubInfo<'ll, 'tcx> { @@ -180,9 +180,9 @@ pub(super) fn stub<'ll, 'tcx>( let unique_type_id_str = unique_type_id.generate_unique_id_string(cx.tcx); let metadata = match kind { - Stub::Struct | Stub::VTableTy { .. } => { + Stub::Struct | Stub::VtableTy { .. } => { let vtable_holder = match kind { - Stub::VTableTy { vtable_holder } => Some(vtable_holder), + Stub::VtableTy { vtable_holder } => Some(vtable_holder), _ => None, }; unsafe { diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index fa0ecd18fc895..5a5c4f7f8603d 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -18,9 +18,7 @@ use crate::llvm; use crate::llvm::AttributePlace::Function; use crate::type_::Type; use crate::value::Value; -use rustc_codegen_ssa::traits::TypeMembershipMethods; use rustc_middle::ty::Ty; -use rustc_symbol_mangling::typeid::typeid_for_fnabi; use smallvec::SmallVec; use tracing::debug; @@ -99,12 +97,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { fn_abi.llvm_type(self), ); fn_abi.apply_attrs_llfn(self, llfn); - - if self.tcx.sess.is_sanitizer_cfi_enabled() { - let typeid = typeid_for_fnabi(self.tcx, fn_abi); - self.set_type_metadata(llfn, typeid); - } - llfn } diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs index 45de284d22a67..e2fa5e488edd0 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs @@ -20,6 +20,19 @@ pub enum OptimizationDiagnosticKind { OptimizationRemarkOther, } +impl OptimizationDiagnosticKind { + pub fn describe(self) -> &'static str { + match self { + OptimizationRemark | OptimizationRemarkOther => "remark", + OptimizationMissed => "missed", + OptimizationAnalysis => "analysis", + OptimizationAnalysisFPCommute => "floating-point", + OptimizationAnalysisAliasing => "aliasing", + OptimizationFailure => "failure", + } + } +} + pub struct OptimizationDiagnostic<'ll> { pub kind: OptimizationDiagnosticKind, pub pass_name: String, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 3139f93bfefae..73cedb59349d3 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -192,10 +192,6 @@ pub enum AttributeKind { NoUndef = 33, SanitizeMemTag = 34, NoCfCheck = 35, - ShadowCallStack = 36, - AllocSize = 37, - AllocatedPointer = 38, - AllocAlign = 39, } /// LLVMIntPredicate @@ -572,6 +568,16 @@ pub enum ArchiveKind { K_COFF, } +/// LLVMRustPassKind +#[derive(Copy, Clone, PartialEq, Debug)] +#[repr(C)] +#[allow(dead_code)] // Variants constructed by C++. +pub enum PassKind { + Other, + Function, + Module, +} + // LLVMRustThinLTOData extern "C" { pub type ThinLTOData; @@ -582,6 +588,10 @@ extern "C" { pub type ThinLTOBuffer; } +// LLVMRustModuleNameCallback +pub type ThinLTOModuleNameCallback = + unsafe extern "C" fn(*mut c_void, *const c_char, *const c_char); + /// LLVMRustThinLTOModule #[repr(C)] pub struct ThinLTOModule { @@ -647,6 +657,9 @@ extern "C" { } #[repr(C)] pub struct Builder<'a>(InvariantOpaque<'a>); +extern "C" { + pub type MemoryBuffer; +} #[repr(C)] pub struct PassManager<'a>(InvariantOpaque<'a>); extern "C" { @@ -972,22 +985,6 @@ pub mod debuginfo { } } -use bitflags::bitflags; -// These values **must** match with LLVMRustAllocKindFlags -bitflags! { - #[repr(transparent)] - #[derive(Default)] - pub struct AllocKindFlags : u64 { - const Unknown = 0; - const Alloc = 1; - const Realloc = 1 << 1; - const Free = 1 << 2; - const Uninitialized = 1 << 3; - const Zeroed = 1 << 4; - const Aligned = 1 << 5; - } -} - extern "C" { pub type ModuleBuffer; } @@ -1015,6 +1012,7 @@ extern "C" { pub fn LLVMSetDataLayout(M: &Module, Triple: *const c_char); /// See Module::setModuleInlineAsm. + pub fn LLVMSetModuleInlineAsm2(M: &Module, Asm: *const c_char, AsmLen: size_t); pub fn LLVMRustAppendModuleInlineAsm(M: &Module, Asm: *const c_char, AsmLen: size_t); /// See llvm::LLVMTypeKind::getTypeID. @@ -1168,6 +1166,7 @@ extern "C" { pub fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>; pub fn LLVMSetInitializer<'a>(GlobalVar: &'a Value, ConstantVal: &'a Value); pub fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool; + pub fn LLVMSetThreadLocal(GlobalVar: &Value, IsThreadLocal: Bool); pub fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode); pub fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; pub fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); @@ -1192,10 +1191,7 @@ extern "C" { pub fn LLVMRustCreateDereferenceableOrNullAttr(C: &Context, bytes: u64) -> &Attribute; pub fn LLVMRustCreateByValAttr<'a>(C: &'a Context, ty: &'a Type) -> &'a Attribute; pub fn LLVMRustCreateStructRetAttr<'a>(C: &'a Context, ty: &'a Type) -> &'a Attribute; - pub fn LLVMRustCreateElementTypeAttr<'a>(C: &'a Context, ty: &'a Type) -> &'a Attribute; pub fn LLVMRustCreateUWTableAttr(C: &Context, async_: bool) -> &Attribute; - pub fn LLVMRustCreateAllocSizeAttr(C: &Context, size_arg: u32) -> &Attribute; - pub fn LLVMRustCreateAllocKindAttr(C: &Context, size_arg: u64) -> &Attribute; // Operations on functions pub fn LLVMRustGetOrInsertFunction<'a>( @@ -2249,6 +2245,7 @@ extern "C" { pub fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>; + pub fn LLVMRustPassKind(Pass: &Pass) -> PassKind; pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> Option<&'static mut Pass>; pub fn LLVMRustCreateAddressSanitizerFunctionPass(Recover: bool) -> &'static mut Pass; pub fn LLVMRustCreateModuleAddressSanitizerPass(Recover: bool) -> &'static mut Pass; @@ -2365,6 +2362,7 @@ extern "C" { ) -> LLVMRustResult; pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char); pub fn LLVMRustPrintPasses(); + pub fn LLVMRustGetInstructionCount(M: &Module) -> u32; pub fn LLVMRustSetNormalizedTarget(M: &Module, triple: *const c_char); pub fn LLVMRustAddAlwaysInlinePass(P: &PassManagerBuilder, AddLifetimes: bool); pub fn LLVMRustRunRestrictionPass(M: &Module, syms: *const *const c_char, len: size_t); @@ -2462,6 +2460,7 @@ extern "C" { pub fn LLVMRustPositionBuilderAtStart<'a>(B: &Builder<'a>, BB: &'a BasicBlock); pub fn LLVMRustSetComdat<'a>(M: &'a Module, V: &'a Value, Name: *const c_char, NameLen: size_t); + pub fn LLVMRustUnsetComdat(V: &Value); pub fn LLVMRustSetModulePICLevel(M: &Module); pub fn LLVMRustSetModulePIELevel(M: &Module); pub fn LLVMRustSetModuleCodeModel(M: &Module, Model: CodeModel); @@ -2471,7 +2470,7 @@ extern "C" { pub fn LLVMRustModuleBufferFree(p: &'static mut ModuleBuffer); pub fn LLVMRustModuleCost(M: &Module) -> u64; - pub fn LLVMRustThinLTOBufferCreate(M: &Module, is_thin: bool) -> &'static mut ThinLTOBuffer; + pub fn LLVMRustThinLTOBufferCreate(M: &Module) -> &'static mut ThinLTOBuffer; pub fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer); pub fn LLVMRustThinLTOBufferPtr(M: &ThinLTOBuffer) -> *const c_char; pub fn LLVMRustThinLTOBufferLen(M: &ThinLTOBuffer) -> size_t; @@ -2493,6 +2492,11 @@ extern "C" { Module: &Module, Target: &TargetMachine, ) -> bool; + pub fn LLVMRustGetThinLTOModuleImports( + Data: *const ThinLTOData, + ModuleNameCallback: ThinLTOModuleNameCallback, + CallbackPayload: *mut c_void, + ); pub fn LLVMRustFreeThinLTOData(Data: &'static mut ThinLTOData); pub fn LLVMRustParseBitcodeForLTO( Context: &Context, @@ -2542,6 +2546,4 @@ extern "C" { #[allow(improper_ctypes)] pub fn LLVMRustGetMangledName(V: &Value, out: &RustString); - - pub fn LLVMRustGetElementTypeArgIndex(CallSite: &Value) -> i32; } diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 6602a4ab8636c..48fbc1de8ee44 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -95,14 +95,6 @@ pub fn CreateUWTableAttr(llcx: &Context, async_: bool) -> &Attribute { unsafe { LLVMRustCreateUWTableAttr(llcx, async_) } } -pub fn CreateAllocSizeAttr(llcx: &Context, size_arg: u32) -> &Attribute { - unsafe { LLVMRustCreateAllocSizeAttr(llcx, size_arg) } -} - -pub fn CreateAllocKindAttr(llcx: &Context, kind_arg: AllocKindFlags) -> &Attribute { - unsafe { LLVMRustCreateAllocKindAttr(llcx, kind_arg.bits()) } -} - #[derive(Copy, Clone)] pub enum AttributePlace { ReturnValue, @@ -166,6 +158,12 @@ pub fn SetUniqueComdat(llmod: &Module, val: &Value) { } } +pub fn UnsetComdat(val: &Value) { + unsafe { + LLVMRustUnsetComdat(val); + } +} + pub fn SetUnnamedAddress(global: &Value, unnamed: UnnamedAddr) { unsafe { LLVMSetUnnamedAddress(global, unnamed); diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index eeb38d4ecf591..cf2d3c423c335 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -19,7 +19,7 @@ use rustc_target::abi::{AddressSpace, Align, Integer, Size}; use std::fmt; use std::ptr; -use libc::{c_char, c_uint}; +use libc::c_uint; impl PartialEq for Type { fn eq(&self, other: &Self) -> bool { @@ -289,31 +289,3 @@ impl<'ll, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { ty.llvm_type(self) } } - -impl<'ll, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn set_type_metadata(&self, function: &'ll Value, typeid: String) { - let typeid_metadata = self.typeid_metadata(typeid); - let v = [self.const_usize(0), typeid_metadata]; - unsafe { - llvm::LLVMGlobalSetMetadata( - function, - llvm::MD_type as c_uint, - llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext( - self.llcx, - v.as_ptr(), - v.len() as c_uint, - )), - ) - } - } - - fn typeid_metadata(&self, typeid: String) -> &'ll Value { - unsafe { - llvm::LLVMMDStringInContext( - self.llcx, - typeid.as_ptr() as *const c_char, - typeid.len() as c_uint, - ) - } - } -} diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 46d6344dbb2ef..81c8b9ceb136e 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -14,7 +14,7 @@ tracing = "0.1" libc = "0.2.50" jobserver = "0.1.22" tempfile = "3.2" -thorin-dwp = "0.3" +thorin-dwp = "0.2" pathdiff = "0.2.0" serde_json = "1.0.59" snap = "1" diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 53550b049db09..1cb8d34238129 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -51,37 +51,10 @@ pub trait ArchiveBuilder<'a> { fn build(self) -> bool; - fn sess(&self) -> &Session; - - /// Creates a DLL Import Library . - /// and returns the path on disk to that import library. - /// This functions doesn't take `self` so that it can be called from - /// `linker_with_args`, which is specialized on `ArchiveBuilder` but - /// doesn't take or create an instance of that type. - fn create_dll_import_lib( - sess: &Session, - lib_name: &str, - dll_imports: &[DllImport], - tmpdir: &Path, - ) -> PathBuf; - - /// Creates a DLL Import Library - /// and adds it to the current compilation's set of archives. fn inject_dll_import_lib( &mut self, lib_name: &str, dll_imports: &[DllImport], tmpdir: &MaybeTempDir, - ) { - let output_path = - Self::create_dll_import_lib(self.sess(), lib_name, dll_imports, tmpdir.as_ref()); - - self.add_archive(&output_path, |_| false).unwrap_or_else(|e| { - self.sess().fatal(&format!( - "failed to add native library {}: {}", - output_path.display(), - e - )); - }); - } + ); } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index f0d320c7c21c9..878a670cba3ef 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -120,7 +120,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( &out_filename, codegen_results, path.as_ref(), - )?; + ); } } if sess.opts.json_artifact_notifications { @@ -650,7 +650,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( out_filename: &Path, codegen_results: &CodegenResults, tmpdir: &Path, -) -> Result<(), ErrorGuaranteed> { +) { info!("preparing {:?} to {:?}", crate_type, out_filename); let (linker_path, flavor) = linker_and_flavor(sess); let mut cmd = linker_with_args::( @@ -661,7 +661,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( tmpdir, out_filename, codegen_results, - )?; + ); linker::disable_localization(&mut cmd); @@ -1000,8 +1000,6 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( (Strip::None, _) => {} } } - - Ok(()) } // Temporarily support both -Z strip and -C strip @@ -1850,7 +1848,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( tmpdir: &Path, out_filename: &Path, codegen_results: &CodegenResults, -) -> Result { +) -> Command { let crt_objects_fallback = crt_objects_fallback(sess, crate_type); let cmd = &mut *super::linker::get_linker( sess, @@ -1957,18 +1955,6 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( add_upstream_native_libraries(cmd, sess, codegen_results); } - // Link with the import library generated for any raw-dylib functions. - for (raw_dylib_name, raw_dylib_imports) in - collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)? - { - cmd.add_object(&B::create_dll_import_lib( - sess, - &raw_dylib_name, - &raw_dylib_imports, - tmpdir, - )); - } - // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make // command line shorter, reset it to default here before adding more libraries. cmd.reset_per_library_state(); @@ -2012,7 +1998,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( // to it and remove the option. add_post_link_args(cmd, sess, flavor); - Ok(cmd.take_cmd()) + cmd.take_cmd() } fn add_order_independent_options( @@ -2096,12 +2082,7 @@ fn add_order_independent_options( // sections to ensure we have all the data for PGO. let keep_metadata = crate_type == CrateType::Dylib || sess.opts.cg.profile_generate.enabled(); - if crate_type != CrateType::Executable || !sess.opts.unstable_opts.export_executable_symbols - { - cmd.gc_sections(keep_metadata); - } else { - cmd.no_gc_sections(); - } + cmd.gc_sections(keep_metadata); } cmd.set_output_kind(link_output_kind, out_filename); @@ -2241,7 +2222,8 @@ fn add_local_native_libraries( } } NativeLibKind::RawDylib => { - // Ignore RawDylib here, they are handled separately in linker_with_args(). + // FIXME(#58713): Proper handling for raw dylibs. + bug!("raw_dylib feature not yet implemented"); } } } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index a4bbdefbb87f8..d4a9db4af23a2 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -566,7 +566,9 @@ impl<'a> Linker for GccLinker<'a> { } fn no_gc_sections(&mut self) { - if self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm { + if self.sess.target.is_like_osx { + self.linker_arg("-no_dead_strip"); + } else if self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm { self.linker_arg("--no-gc-sections"); } } @@ -638,14 +640,9 @@ impl<'a> Linker for GccLinker<'a> { fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) { // Symbol visibility in object files typically takes care of this. - if crate_type == CrateType::Executable { - let should_export_executable_symbols = - self.sess.opts.unstable_opts.export_executable_symbols; - if self.sess.target.override_export_symbols.is_none() - && !should_export_executable_symbols - { - return; - } + if crate_type == CrateType::Executable && self.sess.target.override_export_symbols.is_none() + { + return; } // We manually create a list of exported symbols to ensure we don't expose any more. @@ -972,11 +969,7 @@ impl<'a> Linker for MsvcLinker<'a> { fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) { // Symbol visibility takes care of this typically if crate_type == CrateType::Executable { - let should_export_executable_symbols = - self.sess.opts.unstable_opts.export_executable_symbols; - if !should_export_executable_symbols { - return; - } + return; } let path = tmpdir.join("lib.def"); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 1b5ad87107af6..c2ac21eec6723 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -37,7 +37,6 @@ use rustc_target::spec::{MergeFunctions, SanitizerSet}; use std::any::Any; use std::fs; use std::io; -use std::marker::PhantomData; use std::mem; use std::path::{Path, PathBuf}; use std::str; @@ -100,7 +99,6 @@ pub struct ModuleConfig { pub emit_ir: bool, pub emit_asm: bool, pub emit_obj: EmitObj, - pub emit_thin_lto: bool, pub bc_cmdline: String, // Miscellaneous flags. These are mostly copied from command-line @@ -220,7 +218,6 @@ impl ModuleConfig { false ), emit_obj, - emit_thin_lto: sess.opts.unstable_opts.emit_thin_lto, bc_cmdline: sess.target.bitcode_llvm_cmdline.to_string(), verify_llvm_ir: sess.verify_llvm_ir(), @@ -476,13 +473,10 @@ pub fn start_async_codegen( metadata_module, crate_info, + coordinator_send, codegen_worker_receive, shared_emitter_main, - coordinator: Coordinator { - sender: coordinator_send, - future: Some(coordinator_thread), - phantom: PhantomData, - }, + future: coordinator_thread, output_filenames: tcx.output_filenames(()).clone(), } } @@ -1277,7 +1271,6 @@ fn start_executing_work( // work to be done. while !codegen_done || running > 0 - || main_thread_worker_state == MainThreadWorkerState::LLVMing || (!codegen_aborted && !(work_items.is_empty() && needs_fat_lto.is_empty() @@ -1475,12 +1468,14 @@ fn start_executing_work( if !cgcx.opts.unstable_opts.no_parallel_llvm { helper.request_token(); } + assert!(!codegen_aborted); assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning); main_thread_worker_state = MainThreadWorkerState::Idle; } Message::CodegenComplete => { codegen_done = true; + assert!(!codegen_aborted); assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning); main_thread_worker_state = MainThreadWorkerState::Idle; } @@ -1492,8 +1487,10 @@ fn start_executing_work( // then conditions above will ensure no more work is spawned but // we'll keep executing this loop until `running` hits 0. Message::CodegenAborted => { + assert!(!codegen_aborted); codegen_done = true; codegen_aborted = true; + assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning); } Message::Done { result: Ok(compiled_module), worker_id } => { free_worker(worker_id); @@ -1533,20 +1530,13 @@ fn start_executing_work( Message::Done { result: Err(None), worker_id: _ } => { bug!("worker thread panicked"); } - Message::Done { result: Err(Some(WorkerFatalError)), worker_id } => { - // Similar to CodegenAborted, wait for remaining work to finish. - free_worker(worker_id); - codegen_done = true; - codegen_aborted = true; + Message::Done { result: Err(Some(WorkerFatalError)), worker_id: _ } => { + return Err(()); } Message::CodegenItem => bug!("the coordinator should not receive codegen requests"), } } - if codegen_aborted { - return Err(()); - } - let needs_link = mem::take(&mut needs_link); if !needs_link.is_empty() { assert!(compiled_modules.is_empty()); @@ -1836,39 +1826,16 @@ impl SharedEmitterMain { } } -pub struct Coordinator { - pub sender: Sender>, - future: Option>>, - // Only used for the Message type. - phantom: PhantomData, -} - -impl Coordinator { - fn join(mut self) -> std::thread::Result> { - self.future.take().unwrap().join() - } -} - -impl Drop for Coordinator { - fn drop(&mut self) { - if let Some(future) = self.future.take() { - // If we haven't joined yet, signal to the coordinator that it should spawn no more - // work, and wait for worker threads to finish. - drop(self.sender.send(Box::new(Message::CodegenAborted::))); - drop(future.join()); - } - } -} - pub struct OngoingCodegen { pub backend: B, pub metadata: EncodedMetadata, pub metadata_module: Option, pub crate_info: CrateInfo, + pub coordinator_send: Sender>, pub codegen_worker_receive: Receiver>, pub shared_emitter_main: SharedEmitterMain, + pub future: thread::JoinHandle>, pub output_filenames: Arc, - pub coordinator: Coordinator, } impl OngoingCodegen { @@ -1876,7 +1843,8 @@ impl OngoingCodegen { let _timer = sess.timer("finish_ongoing_codegen"); self.shared_emitter_main.check(sess, true); - let compiled_modules = sess.time("join_worker_thread", || match self.coordinator.join() { + let future = self.future; + let compiled_modules = sess.time("join_worker_thread", || match future.join() { Ok(Ok(compiled_modules)) => compiled_modules, Ok(Err(())) => { sess.abort_if_errors(); @@ -1924,13 +1892,26 @@ impl OngoingCodegen { // These are generally cheap and won't throw off scheduling. let cost = 0; - submit_codegened_module_to_llvm(&self.backend, &self.coordinator.sender, module, cost); + submit_codegened_module_to_llvm(&self.backend, &self.coordinator_send, module, cost); } pub fn codegen_finished(&self, tcx: TyCtxt<'_>) { self.wait_for_signal_to_codegen_item(); self.check_for_errors(tcx.sess); - drop(self.coordinator.sender.send(Box::new(Message::CodegenComplete::))); + drop(self.coordinator_send.send(Box::new(Message::CodegenComplete::))); + } + + /// Consumes this context indicating that codegen was entirely aborted, and + /// we need to exit as quickly as possible. + /// + /// This method blocks the current thread until all worker threads have + /// finished, and all worker threads should have exited or be real close to + /// exiting at this point. + pub fn codegen_aborted(self) { + // Signal to the coordinator it should spawn no more work and start + // shutdown. + drop(self.coordinator_send.send(Box::new(Message::CodegenAborted::))); + drop(self.future.join()); } pub fn check_for_errors(&self, sess: &Session) { diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index a840b27097492..7def30af2b309 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -39,6 +39,7 @@ use rustc_target::abi::{Align, VariantIdx}; use std::collections::BTreeSet; use std::convert::TryFrom; +use std::ops::{Deref, DerefMut}; use std::time::{Duration, Instant}; use itertools::Itertools; @@ -170,7 +171,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ); let new_vptr = bx.load(ptr_ty, gep, ptr_align); bx.nonnull_metadata(new_vptr); - // VTable loads are invariant. + // Vtable loads are invariant. bx.set_invariant_load(new_vptr); new_vptr } else { @@ -582,6 +583,7 @@ pub fn codegen_crate( metadata_module, codegen_units.len(), ); + let ongoing_codegen = AbortCodegenOnDrop::(Some(ongoing_codegen)); // Codegen an allocator shim, if necessary. // @@ -702,7 +704,7 @@ pub fn codegen_crate( submit_codegened_module_to_llvm( &backend, - &ongoing_codegen.coordinator.sender, + &ongoing_codegen.coordinator_send, module, cost, ); @@ -712,7 +714,7 @@ pub fn codegen_crate( submit_pre_lto_module_to_llvm( &backend, tcx, - &ongoing_codegen.coordinator.sender, + &ongoing_codegen.coordinator_send, CachedModuleCodegen { name: cgu.name().to_string(), source: cgu.previous_work_product(tcx), @@ -723,7 +725,7 @@ pub fn codegen_crate( CguReuse::PostLto => { submit_post_lto_module_to_llvm( &backend, - &ongoing_codegen.coordinator.sender, + &ongoing_codegen.coordinator_send, CachedModuleCodegen { name: cgu.name().to_string(), source: cgu.previous_work_product(tcx), @@ -750,7 +752,55 @@ pub fn codegen_crate( } ongoing_codegen.check_for_errors(tcx.sess); - ongoing_codegen + + ongoing_codegen.into_inner() +} + +/// A curious wrapper structure whose only purpose is to call `codegen_aborted` +/// when it's dropped abnormally. +/// +/// In the process of working on rust-lang/rust#55238 a mysterious segfault was +/// stumbled upon. The segfault was never reproduced locally, but it was +/// suspected to be related to the fact that codegen worker threads were +/// sticking around by the time the main thread was exiting, causing issues. +/// +/// This structure is an attempt to fix that issue where the `codegen_aborted` +/// message will block until all workers have finished. This should ensure that +/// even if the main codegen thread panics we'll wait for pending work to +/// complete before returning from the main thread, hopefully avoiding +/// segfaults. +/// +/// If you see this comment in the code, then it means that this workaround +/// worked! We may yet one day track down the mysterious cause of that +/// segfault... +struct AbortCodegenOnDrop(Option>); + +impl AbortCodegenOnDrop { + fn into_inner(mut self) -> OngoingCodegen { + self.0.take().unwrap() + } +} + +impl Deref for AbortCodegenOnDrop { + type Target = OngoingCodegen; + + fn deref(&self) -> &OngoingCodegen { + self.0.as_ref().unwrap() + } +} + +impl DerefMut for AbortCodegenOnDrop { + fn deref_mut(&mut self) -> &mut OngoingCodegen { + self.0.as_mut().unwrap() + } +} + +impl Drop for AbortCodegenOnDrop { + fn drop(&mut self) { + if let Some(codegen) = self.0.take() { + codegen.codegen_aborted(); + } + } } impl CrateInfo { diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 27d791d90a51a..df42d80456690 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -39,7 +39,7 @@ impl<'a, 'tcx> VirtualIndex { let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]); let ptr = bx.load(llty, gep, ptr_align); bx.nonnull_metadata(ptr); - // VTable loads are invariant. + // Vtable loads are invariant. bx.set_invariant_load(ptr); ptr } @@ -58,7 +58,7 @@ impl<'a, 'tcx> VirtualIndex { let usize_align = bx.tcx().data_layout.pointer_align.abi; let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]); let ptr = bx.load(llty, gep, usize_align); - // VTable loads are invariant. + // Vtable loads are invariant. bx.set_invariant_load(ptr); ptr } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 3eee58d9d1c84..773c55cf551d5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -20,7 +20,7 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, Ty, TypeVisitable}; use rustc_span::source_map::Span; use rustc_span::{sym, Symbol}; -use rustc_symbol_mangling::typeid::typeid_for_fnabi; +use rustc_symbol_mangling::typeid_for_fnabi; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; use rustc_target::abi::{self, HasDataLayout, WrappingRange}; use rustc_target::spec::abi::Abi; @@ -918,7 +918,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // FIXME(rcvalle): Add support for generalized identifiers. // FIXME(rcvalle): Create distinct unnamed MDNodes for internal identifiers. let typeid = typeid_for_fnabi(bx.tcx(), fn_abi); - let typeid_metadata = self.cx.typeid_metadata(typeid); + let typeid_metadata = bx.typeid_metadata(typeid); // Test whether the function pointer is associated with the type identifier. let cond = bx.type_test(fn_ptr, typeid_metadata); diff --git a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs index f1fe495282abc..a283bf1de763a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs @@ -9,8 +9,11 @@ use super::FunctionCx; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn codegen_coverage(&self, bx: &mut Bx, coverage: Coverage, scope: SourceScope) { // Determine the instance that coverage data was originally generated for. - let instance = if let Some(inlined) = scope.inlined_instance(&self.mir.source_scopes) { - self.monomorphize(inlined) + let scope_data = &self.mir.source_scopes[scope]; + let instance = if let Some((inlined_instance, _)) = scope_data.inlined { + self.monomorphize(inlined_instance) + } else if let Some(inlined_scope) = scope_data.inlined_parent_scope { + self.monomorphize(self.mir.source_scopes[inlined_scope].inlined.unwrap().0) } else { self.instance }; diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 94ac71a4dd263..645afae30d887 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -3,16 +3,12 @@ use super::place::PlaceRef; use super::FunctionCx; use crate::common::{span_invalid_monomorphization_error, IntPredicate}; use crate::glue; -use crate::meth; use crate::traits::*; use crate::MemFlags; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::{sym, Span}; -use rustc_target::abi::{ - call::{FnAbi, PassMode}, - WrappingRange, -}; +use rustc_target::abi::call::{FnAbi, PassMode}; fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, @@ -106,20 +102,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.const_usize(bx.layout_of(tp_ty).align.abi.bytes()) } } - sym::vtable_size | sym::vtable_align => { - let vtable = args[0].immediate(); - let idx = match name { - sym::vtable_size => ty::COMMON_VTABLE_ENTRIES_SIZE, - sym::vtable_align => ty::COMMON_VTABLE_ENTRIES_ALIGN, - _ => bug!(), - }; - let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable); - if name == sym::vtable_align { - // Alignment is always nonzero. - bx.range_metadata(value, WrappingRange { start: 1, end: !0 }); - }; - value - } sym::pref_align_of | sym::needs_drop | sym::type_id diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 8ee375fa9e3e9..ec3f7a2156a4a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -3,6 +3,7 @@ use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TypeFoldable, TypeVisitable}; +use rustc_symbol_mangling::typeid_for_fnabi; use rustc_target::abi::call::{FnAbi, PassMode}; use std::iter; @@ -246,6 +247,13 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( for (bb, _) in traversal::reverse_postorder(&mir) { fx.codegen_block(bb); } + + // For backends that support CFI using type membership (i.e., testing whether a given pointer + // is associated with a type identifier). + if cx.tcx().sess.is_sanitizer_cfi_enabled() { + let typeid = typeid_for_fnabi(cx.tcx(), fn_abi); + bx.type_metadata(llfn, typeid); + } } /// Produces, for each argument, a `Value` pointing at the diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 268c4d7650305..58cee0c8bb0db 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -435,12 +435,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::Place(place) => place, LocalRef::UnsizedPlace(place) => bx.load_operand(place).deref(cx), LocalRef::Operand(..) => { - if place_ref.has_deref() { - base = 1; + if let Some(elem) = place_ref + .projection + .iter() + .enumerate() + .find(|elem| matches!(elem.1, mir::ProjectionElem::Deref)) + { + base = elem.0 + 1; let cg_base = self.codegen_consume( bx, - mir::PlaceRef { projection: &place_ref.projection[..0], ..place_ref }, + mir::PlaceRef { projection: &place_ref.projection[..elem.0], ..place_ref }, ); + cg_base.deref(bx.cx()) } else { bug!("using operand local {:?} as place", place_ref); diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index ecad0518533ec..bfdef2dc0e80c 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -249,7 +249,6 @@ const WASM_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("bulk-memory", Some(sym::wasm_target_feature)), ("mutable-globals", Some(sym::wasm_target_feature)), ("reference-types", Some(sym::wasm_target_feature)), - ("sign-ext", Some(sym::wasm_target_feature)), ]; const BPF_ALLOWED_FEATURES: &[(&str, Option)] = &[("alu32", Some(sym::bpf_target_feature))]; diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 9f49749bb41fb..1bbe10141fc7e 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -160,6 +160,8 @@ pub trait BuilderMethods<'a, 'tcx>: fn range_metadata(&mut self, load: Self::Value, range: WrappingRange); fn nonnull_metadata(&mut self, load: Self::Value); + fn type_metadata(&mut self, function: Self::Function, typeid: String); + fn typeid_metadata(&mut self, typeid: String) -> Self::Value; fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value; fn store_with_flags( diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 782fdadbfb87c..396768e0a42d0 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -40,8 +40,7 @@ pub use self::intrinsic::IntrinsicCallMethods; pub use self::misc::MiscMethods; pub use self::statics::{StaticBuilderMethods, StaticMethods}; pub use self::type_::{ - ArgAbiMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMembershipMethods, - TypeMethods, + ArgAbiMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods, }; pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; diff --git a/compiler/rustc_codegen_ssa/src/traits/statics.rs b/compiler/rustc_codegen_ssa/src/traits/statics.rs index 413d31bb94293..a2a3cb56c7806 100644 --- a/compiler/rustc_codegen_ssa/src/traits/statics.rs +++ b/compiler/rustc_codegen_ssa/src/traits/statics.rs @@ -13,9 +13,7 @@ pub trait StaticMethods: BackendTypes { /// Same as add_used_global(), but only prevent the compiler from potentially removing an /// otherwise unused symbol. The linker is still permitted to drop it. /// - /// This corresponds to the documented semantics of the `#[used]` attribute, although - /// on some targets (non-ELF), we may use `add_used_global` for `#[used]` statics - /// instead. + /// This corresponds to the semantics of the `#[used]` attribute. fn add_compiler_used_global(&self, global: Self::Value); } diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index 8158e8dd01123..5d3f07317a37b 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -117,13 +117,6 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> { ) -> Self::Type; } -// For backends that support CFI using type membership (i.e., testing whether a given pointer is -// associated with a type identifier). -pub trait TypeMembershipMethods<'tcx>: Backend<'tcx> { - fn set_type_metadata(&self, function: Self::Function, typeid: String); - fn typeid_metadata(&self, typeid: String) -> Self::Value; -} - pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> { fn store_fn_arg( &mut self, @@ -140,12 +133,6 @@ pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> { fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Self::Type; } -pub trait TypeMethods<'tcx>: - DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> + TypeMembershipMethods<'tcx> -{ -} +pub trait TypeMethods<'tcx>: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> {} -impl<'tcx, T> TypeMethods<'tcx> for T where - Self: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> + TypeMembershipMethods<'tcx> -{ -} +impl<'tcx, T> TypeMethods<'tcx> for T where Self: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> {} 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 ba8222dc15218..f03ceb54830c8 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -173,17 +173,18 @@ pub(super) fn op_to_const<'tcx>( Immediate::ScalarPair(a, b) => { debug!("ScalarPair(a: {:?}, b: {:?})", a, b); // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (data, start) = match a.to_pointer(ecx).unwrap().into_parts() { - (Some(alloc_id), offset) => { - (ecx.tcx.global_alloc(alloc_id).unwrap_memory(), offset.bytes()) - } - (None, _offset) => ( - ecx.tcx.intern_const_alloc(Allocation::from_bytes_byte_aligned_immutable( - b"" as &[u8], - )), - 0, - ), - }; + let (data, start) = + match ecx.scalar_to_ptr(a.check_init().unwrap()).unwrap().into_parts() { + (Some(alloc_id), offset) => { + (ecx.tcx.global_alloc(alloc_id).unwrap_memory(), offset.bytes()) + } + (None, _offset) => ( + ecx.tcx.intern_const_alloc( + Allocation::from_bytes_byte_aligned_immutable(b"" as &[u8]), + ), + 0, + ), + }; let len = b.to_machine_usize(ecx).unwrap(); let start = start.try_into().unwrap(); let len: usize = len.try_into().unwrap(); diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index fc2e6652a3d72..e00e667fb71e2 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -309,7 +309,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], - dest: &PlaceTy<'tcx, Self::Provenance>, + dest: &PlaceTy<'tcx, Self::PointerTag>, target: Option, _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { @@ -369,7 +369,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, // we don't deallocate it. let (alloc_id, _, _) = ecx.ptr_get_alloc_id(ptr)?; let is_allocated_in_another_const = matches!( - ecx.tcx.try_get_global_alloc(alloc_id), + ecx.tcx.get_global_alloc(alloc_id), Some(interpret::GlobalAlloc::Memory(_)) ); @@ -470,14 +470,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, #[inline(always)] fn stack<'a>( ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] { + ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { &ecx.machine.stack } #[inline(always)] fn stack_mut<'a>( ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec> { + ) -> &'a mut Vec> { &mut ecx.machine.stack } diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 948c334949826..edc4c13b6e8f6 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -138,7 +138,7 @@ pub(crate) fn deref_mir_constant<'tcx>( let mplace = ecx.deref_operand(&op).unwrap(); if let Some(alloc_id) = mplace.ptr.provenance { assert_eq!( - tcx.global_alloc(alloc_id).unwrap_memory().0.0.mutability, + tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().0.0.mutability, Mutability::Not, "deref_mir_constant cannot be used with mutable allocations as \ that could allow pattern matching to observe mutable statics", diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index c97c31eb9dadf..5d598b65c7224 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -18,10 +18,10 @@ use super::{ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn cast( &mut self, - src: &OpTy<'tcx, M::Provenance>, + src: &OpTy<'tcx, M::PointerTag>, cast_kind: CastKind, cast_ty: Ty<'tcx>, - dest: &PlaceTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { use rustc_middle::mir::CastKind::*; // FIXME: In which cases should we trigger UB when the source is uninit? @@ -114,9 +114,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn misc_cast( &mut self, - src: &ImmTy<'tcx, M::Provenance>, + src: &ImmTy<'tcx, M::PointerTag>, cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate> { + ) -> InterpResult<'tcx, Immediate> { use rustc_type_ir::sty::TyKind::*; trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty); @@ -173,14 +173,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn pointer_expose_address_cast( &mut self, - src: &ImmTy<'tcx, M::Provenance>, + src: &ImmTy<'tcx, M::PointerTag>, cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate> { + ) -> InterpResult<'tcx, Immediate> { assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_)); assert!(cast_ty.is_integral()); let scalar = src.to_scalar()?; - let ptr = scalar.to_pointer(self)?; + let ptr = self.scalar_to_ptr(scalar)?; match ptr.into_pointer_or_addr() { Ok(ptr) => M::expose_ptr(self, ptr)?, Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP. @@ -190,9 +190,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn pointer_from_exposed_address_cast( &mut self, - src: &ImmTy<'tcx, M::Provenance>, + src: &ImmTy<'tcx, M::PointerTag>, cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate> { + ) -> InterpResult<'tcx, Immediate> { assert!(src.layout.ty.is_integral()); assert_matches!(cast_ty.kind(), ty::RawPtr(_)); @@ -208,10 +208,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn cast_from_int_like( &self, - scalar: Scalar, // input value (there is no ScalarTy so we separate data+layout) + scalar: Scalar, // input value (there is no ScalarTy so we separate data+layout) src_layout: TyAndLayout<'tcx>, cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { // Let's make sure v is sign-extended *if* it has a signed type. let signed = src_layout.abi.is_signed(); // Also asserts that abi is `Scalar`. @@ -245,9 +245,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }) } - fn cast_from_float(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar + fn cast_from_float(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar where - F: Float + Into> + FloatConvert + FloatConvert, + F: Float + Into> + FloatConvert + FloatConvert, { use rustc_type_ir::sty::TyKind::*; match *dest_ty.kind() { @@ -279,8 +279,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn unsize_into_ptr( &mut self, - src: &OpTy<'tcx, M::Provenance>, - dest: &PlaceTy<'tcx, M::Provenance>, + src: &OpTy<'tcx, M::PointerTag>, + dest: &PlaceTy<'tcx, M::PointerTag>, // The pointee types source_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, @@ -298,18 +298,30 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_immediate(val, dest) } (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { - let (old_data, old_vptr) = self.read_immediate(src)?.to_scalar_pair()?; - let old_vptr = old_vptr.to_pointer(self)?; - let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?; - if old_trait != data_a.principal() { - throw_ub_format!("upcast on a pointer whose vtable does not match its type"); + let val = self.read_immediate(src)?; + if data_a.principal_def_id() == data_b.principal_def_id() { + return self.write_immediate(*val, dest); + } + // trait upcasting coercion + let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot(( + src_pointee_ty, + dest_pointee_ty, + )); + + if let Some(entry_idx) = vptr_entry_idx { + let entry_idx = u64::try_from(entry_idx).unwrap(); + let (old_data, old_vptr) = val.to_scalar_pair()?; + let old_vptr = self.scalar_to_ptr(old_vptr)?; + let new_vptr = self + .read_new_vtable_after_trait_upcasting_from_vtable(old_vptr, entry_idx)?; + self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) + } else { + self.write_immediate(*val, dest) } - let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?; - self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) } (_, &ty::Dynamic(ref data, _)) => { // Initial cast from sized to dyn trait - let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?; + let vtable = self.get_vtable(src_pointee_ty, data.principal())?; let ptr = self.read_immediate(src)?.to_scalar()?; let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx); self.write_immediate(val, dest) @@ -323,9 +335,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn unsize_into( &mut self, - src: &OpTy<'tcx, M::Provenance>, + src: &OpTy<'tcx, M::PointerTag>, cast_ty: TyAndLayout<'tcx>, - dest: &PlaceTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty); match (&src.layout.ty.kind(), &cast_ty.ty.kind()) { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 150d6589b0807..6feb5219ab1f9 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -81,7 +81,7 @@ impl Drop for SpanGuard { } /// A stack frame. -pub struct Frame<'mir, 'tcx, Prov: Provenance = AllocId, Extra = ()> { +pub struct Frame<'mir, 'tcx, Tag: Provenance = AllocId, Extra = ()> { //////////////////////////////////////////////////////////////////////////////// // Function and callsite information //////////////////////////////////////////////////////////////////////////////// @@ -102,7 +102,7 @@ pub struct Frame<'mir, 'tcx, Prov: Provenance = AllocId, Extra = ()> { /// The location where the result of the current stack frame should be written to, /// and its layout in the caller. - pub return_place: PlaceTy<'tcx, Prov>, + pub return_place: PlaceTy<'tcx, Tag>, /// The list of locals for this stack frame, stored in order as /// `[return_ptr, arguments..., variables..., temporaries...]`. @@ -111,7 +111,7 @@ pub struct Frame<'mir, 'tcx, Prov: Provenance = AllocId, Extra = ()> { /// can either directly contain `Scalar` or refer to some part of an `Allocation`. /// /// Do *not* access this directly; always go through the machine hook! - pub locals: IndexVec>, + pub locals: IndexVec>, /// The span of the `tracing` crate is stored here. /// When the guard is dropped, the span is exited. This gives us @@ -166,15 +166,15 @@ pub enum StackPopCleanup { /// State of a local variable including a memoized layout #[derive(Clone, Debug)] -pub struct LocalState<'tcx, Prov: Provenance = AllocId> { - pub value: LocalValue, +pub struct LocalState<'tcx, Tag: Provenance = AllocId> { + pub value: LocalValue, /// Don't modify if `Some`, this is only used to prevent computing the layout twice pub layout: Cell>>, } /// Current value of a local variable #[derive(Copy, Clone, Debug)] // Miri debug-prints these -pub enum LocalValue { +pub enum LocalValue { /// This local is not currently alive, and cannot be used at all. Dead, /// A normal, live local. @@ -182,16 +182,16 @@ pub enum LocalValue { /// This is an optimization over just always having a pointer here; /// we can thus avoid doing an allocation when the local just stores /// immediate values *and* never has its address taken. - Live(Operand), + Live(Operand), } -impl<'tcx, Prov: Provenance + 'static> LocalState<'tcx, Prov> { +impl<'tcx, Tag: Provenance + 'static> LocalState<'tcx, Tag> { /// Read the local's value or error if the local is not yet live or not live anymore. /// /// Note: This may only be invoked from the `Machine::access_local` hook and not from /// anywhere else. You may be invalidating machine invariants if you do! #[inline] - pub fn access(&self) -> InterpResult<'tcx, &Operand> { + pub fn access(&self) -> InterpResult<'tcx, &Operand> { match &self.value { LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"? LocalValue::Live(val) => Ok(val), @@ -204,7 +204,7 @@ impl<'tcx, Prov: Provenance + 'static> LocalState<'tcx, Prov> { /// Note: This may only be invoked from the `Machine::access_local_mut` hook and not from /// anywhere else. You may be invalidating machine invariants if you do! #[inline] - pub fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand> { + pub fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand> { match &mut self.value { LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"? LocalValue::Live(val) => Ok(val), @@ -212,8 +212,8 @@ impl<'tcx, Prov: Provenance + 'static> LocalState<'tcx, Prov> { } } -impl<'mir, 'tcx, Prov: Provenance> Frame<'mir, 'tcx, Prov> { - pub fn with_extra(self, extra: Extra) -> Frame<'mir, 'tcx, Prov, Extra> { +impl<'mir, 'tcx, Tag: Provenance> Frame<'mir, 'tcx, Tag> { + pub fn with_extra(self, extra: Extra) -> Frame<'mir, 'tcx, Tag, Extra> { Frame { body: self.body, instance: self.instance, @@ -227,7 +227,7 @@ impl<'mir, 'tcx, Prov: Provenance> Frame<'mir, 'tcx, Prov> { } } -impl<'mir, 'tcx, Prov: Provenance, Extra> Frame<'mir, 'tcx, Prov, Extra> { +impl<'mir, 'tcx, Tag: Provenance, Extra> Frame<'mir, 'tcx, Tag, Extra> { /// Get the current location within the Frame. /// /// If this is `Err`, we are not currently executing any particular statement in @@ -422,14 +422,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } #[inline(always)] - pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>] { + pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>] { M::stack(self) } #[inline(always)] pub(crate) fn stack_mut( &mut self, - ) -> &mut Vec> { + ) -> &mut Vec> { M::stack_mut(self) } @@ -441,12 +441,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } #[inline(always)] - pub fn frame(&self) -> &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra> { + pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> { self.stack().last().expect("no call frames exist") } #[inline(always)] - pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::Provenance, M::FrameExtra> { + pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> { self.stack_mut().last_mut().expect("no call frames exist") } @@ -503,7 +503,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// stack frame), to bring it into the proper environment for this interpreter. pub(super) fn subst_from_frame_and_normalize_erasing_regions>( &self, - frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>, + frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, value: T, ) -> Result> { frame @@ -540,7 +540,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn layout_of_local( &self, - frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>, + frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, local: mir::Local, layout: Option>, ) -> InterpResult<'tcx, TyAndLayout<'tcx>> { @@ -569,7 +569,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// This can fail to provide an answer for extern types. pub(super) fn size_and_align_of( &self, - metadata: &MemPlaceMeta, + metadata: &MemPlaceMeta, layout: &TyAndLayout<'tcx>, ) -> InterpResult<'tcx, Option<(Size, Align)>> { if !layout.is_unsized() { @@ -629,9 +629,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(Some((size, align))) } ty::Dynamic(..) => { - let vtable = metadata.unwrap_meta().to_pointer(self)?; + let vtable = self.scalar_to_ptr(metadata.unwrap_meta())?; // Read size and align from vtable (already checks size). - Ok(Some(self.get_vtable_size_and_align(vtable)?)) + Ok(Some(self.read_size_and_align_from_vtable(vtable)?)) } ty::Slice(_) | ty::Str => { @@ -655,7 +655,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline] pub fn size_and_align_of_mplace( &self, - mplace: &MPlaceTy<'tcx, M::Provenance>, + mplace: &MPlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, Option<(Size, Align)>> { self.size_and_align_of(&mplace.meta, &mplace.layout) } @@ -665,7 +665,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &mut self, instance: ty::Instance<'tcx>, body: &'mir mir::Body<'tcx>, - return_place: &PlaceTy<'tcx, M::Provenance>, + return_place: &PlaceTy<'tcx, M::PointerTag>, return_to_block: StackPopCleanup, ) -> InterpResult<'tcx> { trace!("body: {:#?}", body); @@ -891,7 +891,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } #[instrument(skip(self), level = "debug")] - fn deallocate_local(&mut self, local: LocalValue) -> InterpResult<'tcx> { + fn deallocate_local(&mut self, local: LocalValue) -> InterpResult<'tcx> { if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local { // All locals have a backing allocation, even if the allocation is empty // due to the local having ZST type. Hence we can `unwrap`. @@ -909,7 +909,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn eval_to_allocation( &self, gid: GlobalId<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics // and thus don't care about the parameter environment. While we could just use // `self.param_env`, that would mean we invoke the query to evaluate the static @@ -927,7 +927,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } #[must_use] - pub fn dump_place(&self, place: Place) -> PlacePrinter<'_, 'mir, 'tcx, M> { + pub fn dump_place(&self, place: Place) -> PlacePrinter<'_, 'mir, 'tcx, M> { PlacePrinter { ecx: self, place } } @@ -956,7 +956,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Helper struct for the `dump_place` function. pub struct PlacePrinter<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { ecx: &'a InterpCx<'mir, 'tcx, M>, - place: Place, + place: Place, } impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 376b8872c90ac..7616e7a63d107 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -33,7 +33,7 @@ pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine< 'mir, 'tcx, MemoryKind = T, - Provenance = AllocId, + PointerTag = AllocId, ExtraFnVal = !, FrameExtra = (), AllocExtra = (), @@ -94,7 +94,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval: // to validation to error -- it has the much better error messages, pointing out where // in the value the dangling reference lies. // The `delay_span_bug` ensures that we don't forget such a check in validation. - if tcx.try_get_global_alloc(alloc_id).is_none() { + if tcx.get_global_alloc(alloc_id).is_none() { tcx.sess.delay_span_bug(ecx.tcx.span, "tried to intern dangling pointer"); } // treat dangling pointers like other statics @@ -245,7 +245,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory if let ty::Dynamic(..) = tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind() { - let ptr = mplace.meta.unwrap_meta().to_pointer(&tcx)?; + let ptr = self.ecx.scalar_to_ptr(mplace.meta.unwrap_meta())?; if let Some(alloc_id) = ptr.provenance { // Explicitly choose const mode here, since vtables are immutable, even // if the reference of the fat pointer is mutable. @@ -454,7 +454,7 @@ pub fn intern_const_alloc_recursive< .sess .span_err(ecx.tcx.span, "encountered dangling pointer in final constant"); return Err(reported); - } else if ecx.tcx.try_get_global_alloc(alloc_id).is_none() { + } else if ecx.tcx.get_global_alloc(alloc_id).is_none() { // We have hit an `AllocId` that is neither in local or global memory and isn't // marked as dangling by local memory. That should be impossible. span_bug!(ecx.tcx.span, "encountered unknown alloc id {:?}", alloc_id); @@ -474,7 +474,7 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>> layout: TyAndLayout<'tcx>, f: impl FnOnce( &mut InterpCx<'mir, 'tcx, M>, - &PlaceTy<'tcx, M::Provenance>, + &PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, ()>, ) -> InterpResult<'tcx, ConstAllocation<'tcx>> { let dest = self.allocate(layout, MemoryKind::Stack)?; diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 08209eb793216..c6030604aed37 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -7,7 +7,7 @@ use std::convert::TryFrom; use rustc_hir::def_id::DefId; use rustc_middle::mir::{ self, - interpret::{ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar}, + interpret::{ConstValue, GlobalId, InterpResult, Scalar}, BinOp, }; use rustc_middle::ty; @@ -25,7 +25,7 @@ use super::{ mod caller_location; mod type_name; -fn numeric_intrinsic(name: Symbol, bits: u128, kind: Primitive) -> Scalar { +fn numeric_intrinsic(name: Symbol, bits: u128, kind: Primitive) -> Scalar { let size = match kind { Primitive::Int(integer, _) => integer.size(), _ => bug!("invalid `{}` argument: {:?}", name, bits), @@ -114,8 +114,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn emulate_intrinsic( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, M::Provenance>], - dest: &PlaceTy<'tcx, M::Provenance>, + args: &[OpTy<'tcx, M::PointerTag>], + dest: &PlaceTy<'tcx, M::PointerTag>, ret: Option, ) -> InterpResult<'tcx, bool> { let substs = instance.substs; @@ -328,7 +328,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // We managed to find a valid allocation for one pointer, but not the other. // That means they are definitely not pointing to the same allocation. throw_ub_format!( - "`{}` called on pointers into different allocations", + "{} called on pointers into different allocations", intrinsic_name ); } @@ -336,7 +336,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Found allocation for both. They must be into the same allocation. if a_alloc_id != b_alloc_id { throw_ub_format!( - "`{}` called on pointers into different allocations", + "{} called on pointers into different allocations", intrinsic_name ); } @@ -346,71 +346,47 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; // Compute distance. - let dist = { - // Addresses are unsigned, so this is a `usize` computation. We have to do the - // overflow check separately anyway. - let (val, overflowed, _ty) = { - let a_offset = ImmTy::from_uint(a_offset, usize_layout); - let b_offset = ImmTy::from_uint(b_offset, usize_layout); - self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)? - }; + let distance = { + // The subtraction is always done in `isize` to enforce + // the "no more than `isize::MAX` apart" requirement. + let a_offset = ImmTy::from_uint(a_offset, isize_layout); + let b_offset = ImmTy::from_uint(b_offset, isize_layout); + let (val, overflowed, _ty) = + self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?; if overflowed { - // a < b - if intrinsic_name == sym::ptr_offset_from_unsigned { - throw_ub_format!( - "`{}` called when first pointer has smaller offset than second: {} < {}", - intrinsic_name, - a_offset, - b_offset, - ); - } - // The signed form of the intrinsic allows this. If we interpret the - // difference as isize, we'll get the proper signed difference. If that - // seems *positive*, they were more than isize::MAX apart. - let dist = val.to_machine_isize(self)?; - if dist >= 0 { - throw_ub_format!( - "`{}` called when first pointer is too far before second", - intrinsic_name - ); - } - dist - } else { - // b >= a - let dist = val.to_machine_isize(self)?; - // If converting to isize produced a *negative* result, we had an overflow - // because they were more than isize::MAX apart. - if dist < 0 { - throw_ub_format!( - "`{}` called when first pointer is too far ahead of second", - intrinsic_name - ); - } - dist + throw_ub_format!("pointers were too far apart for {}", intrinsic_name); } + val.to_machine_isize(self)? }; // Check that the range between them is dereferenceable ("in-bounds or one past the // end of the same allocation"). This is like the check in ptr_offset_inbounds. - let min_ptr = if dist >= 0 { b } else { a }; + let min_ptr = if distance >= 0 { b } else { a }; self.check_ptr_access_align( min_ptr, - Size::from_bytes(dist.unsigned_abs()), + Size::from_bytes(distance.unsigned_abs()), Align::ONE, CheckInAllocMsg::OffsetFromTest, )?; + if intrinsic_name == sym::ptr_offset_from_unsigned && distance < 0 { + throw_ub_format!( + "{} called when first pointer has smaller offset than second: {} < {}", + intrinsic_name, + a_offset, + b_offset, + ); + } + // Perform division by size to compute return value. let ret_layout = if intrinsic_name == sym::ptr_offset_from_unsigned { - assert!(0 <= dist && dist <= self.machine_isize_max()); usize_layout } else { - assert!(self.machine_isize_min() <= dist && dist <= self.machine_isize_max()); isize_layout }; let pointee_layout = self.layout_of(substs.type_at(0))?; // If ret_layout is unsigned, we checked that so is the distance, so we are good. - let val = ImmTy::from_int(dist, ret_layout); + let val = ImmTy::from_int(distance, ret_layout); let size = ImmTy::from_int(pointee_layout.size.bytes(), ret_layout); self.exact_div(&val, &size, dest)?; } @@ -516,18 +492,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let result = self.raw_eq_intrinsic(&args[0], &args[1])?; self.write_scalar(result, dest)?; } - - sym::vtable_size => { - let ptr = self.read_pointer(&args[0])?; - let (size, _align) = self.get_vtable_size_and_align(ptr)?; - self.write_scalar(Scalar::from_machine_usize(size.bytes(), self), dest)?; - } - sym::vtable_align => { - let ptr = self.read_pointer(&args[0])?; - let (_size, align) = self.get_vtable_size_and_align(ptr)?; - self.write_scalar(Scalar::from_machine_usize(align.bytes(), self), dest)?; - } - _ => return Ok(false), } @@ -538,9 +502,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn exact_div( &mut self, - a: &ImmTy<'tcx, M::Provenance>, - b: &ImmTy<'tcx, M::Provenance>, - dest: &PlaceTy<'tcx, M::Provenance>, + a: &ImmTy<'tcx, M::PointerTag>, + b: &ImmTy<'tcx, M::PointerTag>, + dest: &PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`. @@ -557,9 +521,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn saturating_arith( &self, mir_op: BinOp, - l: &ImmTy<'tcx, M::Provenance>, - r: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Scalar> { + l: &ImmTy<'tcx, M::PointerTag>, + r: &ImmTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, Scalar> { assert!(matches!(mir_op, BinOp::Add | BinOp::Sub)); let (val, overflowed, _ty) = self.overflowing_binary_op(mir_op, l, r)?; Ok(if overflowed { @@ -602,10 +566,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value. pub fn ptr_offset_inbounds( &self, - ptr: Pointer>, + ptr: Pointer>, pointee_ty: Ty<'tcx>, offset_count: i64, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer>> { // We cannot overflow i64 as a type's size must be <= isize::MAX. let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); // The computed offset, in bytes, must not overflow an isize. @@ -633,9 +597,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Copy `count*size_of::()` many bytes from `*src` to `*dst`. pub(crate) fn copy_intrinsic( &mut self, - src: &OpTy<'tcx, >::Provenance>, - dst: &OpTy<'tcx, >::Provenance>, - count: &OpTy<'tcx, >::Provenance>, + src: &OpTy<'tcx, >::PointerTag>, + dst: &OpTy<'tcx, >::PointerTag>, + count: &OpTy<'tcx, >::PointerTag>, nonoverlapping: bool, ) -> InterpResult<'tcx> { let count = self.read_scalar(&count)?.to_machine_usize(self)?; @@ -658,9 +622,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub(crate) fn write_bytes_intrinsic( &mut self, - dst: &OpTy<'tcx, >::Provenance>, - byte: &OpTy<'tcx, >::Provenance>, - count: &OpTy<'tcx, >::Provenance>, + dst: &OpTy<'tcx, >::PointerTag>, + byte: &OpTy<'tcx, >::PointerTag>, + count: &OpTy<'tcx, >::PointerTag>, ) -> InterpResult<'tcx> { let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?; @@ -681,9 +645,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub(crate) fn raw_eq_intrinsic( &mut self, - lhs: &OpTy<'tcx, >::Provenance>, - rhs: &OpTy<'tcx, >::Provenance>, - ) -> InterpResult<'tcx, Scalar> { + lhs: &OpTy<'tcx, >::PointerTag>, + rhs: &OpTy<'tcx, >::PointerTag>, + ) -> InterpResult<'tcx, Scalar> { let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?; assert!(!layout.is_unsized()); diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs index 5864b92155287..14fde2c305e96 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs @@ -79,7 +79,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { filename: Symbol, line: u32, col: u32, - ) -> MPlaceTy<'tcx, M::Provenance> { + ) -> MPlaceTy<'tcx, M::PointerTag> { let loc_details = &self.tcx.sess.opts.unstable_opts.location_detail; let file = if loc_details.file { self.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not) @@ -123,7 +123,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) } - pub fn alloc_caller_location_for_span(&mut self, span: Span) -> MPlaceTy<'tcx, M::Provenance> { + pub fn alloc_caller_location_for_span(&mut self, span: Span) -> MPlaceTy<'tcx, M::PointerTag> { let (file, line, column) = self.location_triple_for_span(span); self.alloc_caller_location(file, line, column) } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 71ccd1799fa95..7f8eea94aeeda 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -85,11 +85,11 @@ pub trait Machine<'mir, 'tcx>: Sized { type MemoryKind: Debug + std::fmt::Display + MayLeak + Eq + 'static; /// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to. - type Provenance: Provenance + Eq + Hash + 'static; + type PointerTag: Provenance + Eq + Hash + 'static; - /// When getting the AllocId of a pointer, some extra data is also obtained from the provenance + /// When getting the AllocId of a pointer, some extra data is also obtained from the tag /// that is passed to memory access hooks so they can do things with it. - type ProvenanceExtra: Copy + 'static; + type TagExtra: Copy + 'static; /// Machines can define extra (non-instance) things that represent values of function pointers. /// For example, Miri uses this to return a function pointer from `dlsym` @@ -105,7 +105,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Memory's allocation map type MemoryMap: AllocMap< AllocId, - (MemoryKind, Allocation), + (MemoryKind, Allocation), > + Default + Clone; @@ -113,7 +113,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// or None if such memory should not be mutated and thus any such attempt will cause /// a `ModifiedStatic` error to be raised. /// Statics are copied under two circumstances: When they are mutated, and when - /// `adjust_allocation` (see below) returns an owned allocation + /// `tag_allocation` (see below) returns an owned allocation /// that is added to the memory so that the work is not done twice. const GLOBAL_KIND: Option; @@ -126,7 +126,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Whether, when checking alignment, we should `force_int` and thus support /// custom alignment logic based on whatever the integer address happens to be. /// - /// Requires Provenance::OFFSET_IS_ADDR to be true. + /// Requires PointerTag::OFFSET_IS_ADDR to be true. fn force_int_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; /// Whether to enforce the validity invariant @@ -135,6 +135,9 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Whether to enforce integers and floats being initialized. fn enforce_number_init(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; + /// Whether to enforce integers and floats not having provenance. + fn enforce_number_no_provenance(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; + /// Whether function calls should be [ABI](CallAbi)-checked. fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { true @@ -167,8 +170,8 @@ pub trait Machine<'mir, 'tcx>: Sized { ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, abi: CallAbi, - args: &[OpTy<'tcx, Self::Provenance>], - destination: &PlaceTy<'tcx, Self::Provenance>, + args: &[OpTy<'tcx, Self::PointerTag>], + destination: &PlaceTy<'tcx, Self::PointerTag>, target: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>>; @@ -179,8 +182,8 @@ pub trait Machine<'mir, 'tcx>: Sized { ecx: &mut InterpCx<'mir, 'tcx, Self>, fn_val: Self::ExtraFnVal, abi: CallAbi, - args: &[OpTy<'tcx, Self::Provenance>], - destination: &PlaceTy<'tcx, Self::Provenance>, + args: &[OpTy<'tcx, Self::PointerTag>], + destination: &PlaceTy<'tcx, Self::PointerTag>, target: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx>; @@ -190,8 +193,8 @@ pub trait Machine<'mir, 'tcx>: Sized { fn call_intrinsic( ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Self::Provenance>], - destination: &PlaceTy<'tcx, Self::Provenance>, + args: &[OpTy<'tcx, Self::PointerTag>], + destination: &PlaceTy<'tcx, Self::PointerTag>, target: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx>; @@ -214,18 +217,18 @@ pub trait Machine<'mir, 'tcx>: Sized { fn binary_ptr_op( ecx: &InterpCx<'mir, 'tcx, Self>, bin_op: mir::BinOp, - left: &ImmTy<'tcx, Self::Provenance>, - right: &ImmTy<'tcx, Self::Provenance>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; + left: &ImmTy<'tcx, Self::PointerTag>, + right: &ImmTy<'tcx, Self::PointerTag>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; /// Called to read the specified `local` from the `frame`. /// Since reading a ZST is not actually accessing memory or locals, this is never invoked /// for ZST reads. #[inline] fn access_local<'a>( - frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, + frame: &'a Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, local: mir::Local, - ) -> InterpResult<'tcx, &'a Operand> + ) -> InterpResult<'tcx, &'a Operand> where 'tcx: 'mir, { @@ -240,7 +243,7 @@ pub trait Machine<'mir, 'tcx>: Sized { ecx: &'a mut InterpCx<'mir, 'tcx, Self>, frame: usize, local: mir::Local, - ) -> InterpResult<'tcx, &'a mut Operand> + ) -> InterpResult<'tcx, &'a mut Operand> where 'tcx: 'mir, { @@ -272,7 +275,7 @@ pub trait Machine<'mir, 'tcx>: Sized { fn thread_local_static_base_pointer( _ecx: &mut InterpCx<'mir, 'tcx, Self>, def_id: DefId, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, Pointer> { throw_unsup!(ThreadLocalStatic(def_id)) } @@ -280,28 +283,35 @@ pub trait Machine<'mir, 'tcx>: Sized { fn extern_static_base_pointer( ecx: &InterpCx<'mir, 'tcx, Self>, def_id: DefId, - ) -> InterpResult<'tcx, Pointer>; + ) -> InterpResult<'tcx, Pointer>; /// Return a "base" pointer for the given allocation: the one that is used for direct /// accesses to this static/const/fn allocation, or the one returned from the heap allocator. /// /// Not called on `extern` or thread-local statics (those use the methods above). - fn adjust_alloc_base_pointer( + fn tag_alloc_base_pointer( ecx: &InterpCx<'mir, 'tcx, Self>, ptr: Pointer, - ) -> Pointer; + ) -> Pointer; /// "Int-to-pointer cast" fn ptr_from_addr_cast( ecx: &InterpCx<'mir, 'tcx, Self>, addr: u64, - ) -> InterpResult<'tcx, Pointer>>; + ) -> InterpResult<'tcx, Pointer>>; + + /// Hook for returning a pointer from a transmute-like operation on an addr. + /// This is only needed to support Miri's (unsound) "allow-ptr-int-transmute" flag. + fn ptr_from_addr_transmute( + ecx: &InterpCx<'mir, 'tcx, Self>, + addr: u64, + ) -> Pointer>; /// Marks a pointer as exposed, allowing it's provenance /// to be recovered. "Pointer-to-int cast" fn expose_ptr( ecx: &mut InterpCx<'mir, 'tcx, Self>, - ptr: Pointer, + ptr: Pointer, ) -> InterpResult<'tcx>; /// Convert a pointer with provenance into an allocation-offset pair @@ -312,30 +322,30 @@ pub trait Machine<'mir, 'tcx>: Sized { /// When this fails, that means the pointer does not point to a live allocation. fn ptr_get_alloc( ecx: &InterpCx<'mir, 'tcx, Self>, - ptr: Pointer, - ) -> Option<(AllocId, Size, Self::ProvenanceExtra)>; - - /// Called to adjust allocations to the Provenance and AllocExtra of this machine. - /// - /// The way we construct allocations is to always first construct it without extra and then add - /// the extra. This keeps uniform code paths for handling both allocations created by CTFE for - /// globals, and allocations created by Miri during evaluation. + ptr: Pointer, + ) -> Option<(AllocId, Size, Self::TagExtra)>; + + /// Called to initialize the "extra" state of an allocation and make the pointers + /// it contains (in relocations) tagged. The way we construct allocations is + /// to always first construct it without extra and then add the extra. + /// This keeps uniform code paths for handling both allocations created by CTFE + /// for globals, and allocations created by Miri during evaluation. /// - /// `kind` is the kind of the allocation being adjusted; it can be `None` when + /// `kind` is the kind of the allocation being tagged; it can be `None` when /// it's a global and `GLOBAL_KIND` is `None`. /// /// This should avoid copying if no work has to be done! If this returns an owned - /// allocation (because a copy had to be done to adjust things), machine memory will + /// allocation (because a copy had to be done to add tags or metadata), machine memory will /// cache the result. (This relies on `AllocMap::get_or` being able to add the /// owned allocation to the map even when the map is shared.) /// /// This must only fail if `alloc` contains relocations. - fn adjust_allocation<'b>( + fn init_allocation_extra<'b>( ecx: &InterpCx<'mir, 'tcx, Self>, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - ) -> InterpResult<'tcx, Cow<'b, Allocation>>; + ) -> InterpResult<'tcx, Cow<'b, Allocation>>; /// Hook for performing extra checks on a memory read access. /// @@ -347,7 +357,7 @@ pub trait Machine<'mir, 'tcx>: Sized { _tcx: TyCtxt<'tcx>, _machine: &Self, _alloc_extra: &Self::AllocExtra, - _prov: (AllocId, Self::ProvenanceExtra), + _tag: (AllocId, Self::TagExtra), _range: AllocRange, ) -> InterpResult<'tcx> { Ok(()) @@ -359,7 +369,7 @@ pub trait Machine<'mir, 'tcx>: Sized { _tcx: TyCtxt<'tcx>, _machine: &mut Self, _alloc_extra: &mut Self::AllocExtra, - _prov: (AllocId, Self::ProvenanceExtra), + _tag: (AllocId, Self::TagExtra), _range: AllocRange, ) -> InterpResult<'tcx> { Ok(()) @@ -371,7 +381,7 @@ pub trait Machine<'mir, 'tcx>: Sized { _tcx: TyCtxt<'tcx>, _machine: &mut Self, _alloc_extra: &mut Self::AllocExtra, - _prov: (AllocId, Self::ProvenanceExtra), + _tag: (AllocId, Self::TagExtra), _range: AllocRange, ) -> InterpResult<'tcx> { Ok(()) @@ -382,7 +392,7 @@ pub trait Machine<'mir, 'tcx>: Sized { fn retag( _ecx: &mut InterpCx<'mir, 'tcx, Self>, _kind: mir::RetagKind, - _place: &PlaceTy<'tcx, Self::Provenance>, + _place: &PlaceTy<'tcx, Self::PointerTag>, ) -> InterpResult<'tcx> { Ok(()) } @@ -390,18 +400,18 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Called immediately before a new stack frame gets pushed. fn init_frame_extra( ecx: &mut InterpCx<'mir, 'tcx, Self>, - frame: Frame<'mir, 'tcx, Self::Provenance>, - ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>>; + frame: Frame<'mir, 'tcx, Self::PointerTag>, + ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>>; /// Borrow the current thread's stack. fn stack<'a>( ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>]; + ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>]; /// Mutably borrow the current thread's stack. fn stack_mut<'a>( ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec>; + ) -> &'a mut Vec>; /// Called immediately after a stack frame got pushed and its locals got initialized. fn after_stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { @@ -412,7 +422,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// The `locals` have already been destroyed! fn after_stack_pop( _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, + _frame: Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, unwinding: bool, ) -> InterpResult<'tcx, StackPopJump> { // By default, we do not support unwinding from panics @@ -424,8 +434,8 @@ pub trait Machine<'mir, 'tcx>: Sized { // A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines // (CTFE and ConstProp) use the same instance. Here, we share that code. pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { - type Provenance = AllocId; - type ProvenanceExtra = (); + type PointerTag = AllocId; + type TagExtra = (); type ExtraFnVal = !; @@ -459,6 +469,11 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { true } + #[inline(always)] + fn enforce_number_no_provenance(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { + true + } + #[inline(always)] fn checked_binop_checks_overflow(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { true @@ -470,7 +485,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { fn_val: !, _abi: CallAbi, _args: &[OpTy<$tcx>], - _destination: &PlaceTy<$tcx, Self::Provenance>, + _destination: &PlaceTy<$tcx, Self::PointerTag>, _target: Option, _unwind: StackPopUnwind, ) -> InterpResult<$tcx> { @@ -478,12 +493,13 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { } #[inline(always)] - fn adjust_allocation<'b>( + fn init_allocation_extra<'b>( _ecx: &InterpCx<$mir, $tcx, Self>, _id: AllocId, alloc: Cow<'b, Allocation>, _kind: Option>, - ) -> InterpResult<$tcx, Cow<'b, Allocation>> { + ) -> InterpResult<$tcx, Cow<'b, Allocation>> { + // We do not use a tag so we can just cheaply forward the allocation Ok(alloc) } @@ -496,13 +512,21 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { } #[inline(always)] - fn adjust_alloc_base_pointer( + fn tag_alloc_base_pointer( _ecx: &InterpCx<$mir, $tcx, Self>, ptr: Pointer, ) -> Pointer { ptr } + #[inline(always)] + fn ptr_from_addr_transmute( + _ecx: &InterpCx<$mir, $tcx, Self>, + addr: u64, + ) -> Pointer> { + Pointer::from_addr(addr) + } + #[inline(always)] fn ptr_from_addr_cast( _ecx: &InterpCx<$mir, $tcx, Self>, @@ -517,7 +541,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { fn ptr_get_alloc( _ecx: &InterpCx<$mir, $tcx, Self>, ptr: Pointer, - ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> { + ) -> Option<(AllocId, Size, Self::TagExtra)> { // We know `offset` is relative to the allocation, so we can use `into_parts`. let (alloc_id, offset) = ptr.into_parts(); Some((alloc_id, offset, ())) diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index ed2c4edf9dd72..509fe576893b7 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -9,13 +9,14 @@ use std::assert_matches::assert_matches; use std::borrow::Cow; use std::collections::VecDeque; +use std::convert::TryFrom; use std::fmt; use std::ptr; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::display_allocation; -use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{Instance, ParamEnv, TyCtxt}; use rustc_target::abi::{Align, HasDataLayout, Size}; use super::{ @@ -61,8 +62,6 @@ pub enum AllocKind { LiveData, /// A function allocation (that fn ptrs point to). Function, - /// A (symbolic) vtable allocation. - VTable, /// A dead allocation. Dead, } @@ -113,16 +112,16 @@ pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// A reference to some allocation that was already bounds-checked for the given region /// and had the on-access machine hooks run. #[derive(Copy, Clone)] -pub struct AllocRef<'a, 'tcx, Prov, Extra> { - alloc: &'a Allocation, +pub struct AllocRef<'a, 'tcx, Tag, Extra> { + alloc: &'a Allocation, range: AllocRange, tcx: TyCtxt<'tcx>, alloc_id: AllocId, } /// A reference to some allocation that was already bounds-checked for the given region /// and had the on-access machine hooks run. -pub struct AllocRefMut<'a, 'tcx, Prov, Extra> { - alloc: &'a mut Allocation, +pub struct AllocRefMut<'a, 'tcx, Tag, Extra> { + alloc: &'a mut Allocation, range: AllocRange, tcx: TyCtxt<'tcx>, alloc_id: AllocId, @@ -157,10 +156,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn global_base_pointer( &self, ptr: Pointer, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, Pointer> { let alloc_id = ptr.provenance; // We need to handle `extern static`. - match self.tcx.try_get_global_alloc(alloc_id) { + match self.tcx.get_global_alloc(alloc_id) { Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => { bug!("global memory cannot point to thread-local static") } @@ -169,14 +168,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } _ => {} } - // And we need to get the provenance. - Ok(M::adjust_alloc_base_pointer(self, ptr)) + // And we need to get the tag. + Ok(M::tag_alloc_base_pointer(self, ptr)) } pub fn create_fn_alloc_ptr( &mut self, fn_val: FnVal<'tcx, M::ExtraFnVal>, - ) -> Pointer { + ) -> Pointer { let id = match fn_val { FnVal::Instance(instance) => self.tcx.create_fn_alloc(instance), FnVal::Other(extra) => { @@ -197,7 +196,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { size: Size, align: Align, kind: MemoryKind, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, Pointer> { let alloc = Allocation::uninit(size, align, M::PANIC_ON_ALLOC_FAIL)?; // We can `unwrap` since `alloc` contains no pointers. Ok(self.allocate_raw_ptr(alloc, kind).unwrap()) @@ -209,7 +208,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { align: Align, kind: MemoryKind, mutability: Mutability, - ) -> Pointer { + ) -> Pointer { let alloc = Allocation::from_bytes(bytes, align, mutability); // We can `unwrap` since `alloc` contains no pointers. self.allocate_raw_ptr(alloc, kind).unwrap() @@ -220,27 +219,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &mut self, alloc: Allocation, kind: MemoryKind, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, Pointer> { let id = self.tcx.reserve_alloc_id(); debug_assert_ne!( Some(kind), M::GLOBAL_KIND.map(MemoryKind::Machine), "dynamically allocating global memory" ); - let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?; + let alloc = M::init_allocation_extra(self, id, Cow::Owned(alloc), Some(kind))?; self.memory.alloc_map.insert(id, (kind, alloc.into_owned())); - Ok(M::adjust_alloc_base_pointer(self, Pointer::from(id))) + Ok(M::tag_alloc_base_pointer(self, Pointer::from(id))) } pub fn reallocate_ptr( &mut self, - ptr: Pointer>, + ptr: Pointer>, old_size_and_align: Option<(Size, Align)>, new_size: Size, new_align: Align, kind: MemoryKind, - ) -> InterpResult<'tcx, Pointer> { - let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr)?; + ) -> InterpResult<'tcx, Pointer> { + let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?; if offset.bytes() != 0 { throw_ub_format!( "reallocating {:?} which does not point to the beginning of an object", @@ -272,11 +271,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[instrument(skip(self), level = "debug")] pub fn deallocate_ptr( &mut self, - ptr: Pointer>, + ptr: Pointer>, old_size_and_align: Option<(Size, Align)>, kind: MemoryKind, ) -> InterpResult<'tcx> { - let (alloc_id, offset, prov) = self.ptr_get_alloc_id(ptr)?; + let (alloc_id, offset, tag) = self.ptr_get_alloc_id(ptr)?; trace!("deallocating: {alloc_id:?}"); if offset.bytes() != 0 { @@ -288,13 +287,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let Some((alloc_kind, mut alloc)) = self.memory.alloc_map.remove(&alloc_id) else { // Deallocating global memory -- always an error - return Err(match self.tcx.try_get_global_alloc(alloc_id) { + return Err(match self.tcx.get_global_alloc(alloc_id) { Some(GlobalAlloc::Function(..)) => { err_ub_format!("deallocating {alloc_id:?}, which is a function") } - Some(GlobalAlloc::VTable(..)) => { - err_ub_format!("deallocating {alloc_id:?}, which is a vtable") - } Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { err_ub_format!("deallocating {alloc_id:?}, which is static memory") } @@ -331,7 +327,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { *self.tcx, &mut self.machine, &mut alloc.extra, - (alloc_id, prov), + (alloc_id, tag), alloc_range(Size::ZERO, size), )?; @@ -348,19 +344,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] fn get_ptr_access( &self, - ptr: Pointer>, + ptr: Pointer>, size: Size, align: Align, - ) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>> { + ) -> InterpResult<'tcx, Option<(AllocId, Size, M::TagExtra)>> { let align = M::enforce_alignment(&self).then_some(align); self.check_and_deref_ptr( ptr, size, align, CheckInAllocMsg::MemoryAccessTest, - |alloc_id, offset, prov| { + |alloc_id, offset, tag| { let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?; - Ok((size, align, (alloc_id, offset, prov))) + Ok((size, align, (alloc_id, offset, tag))) }, ) } @@ -371,7 +367,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn check_ptr_access_align( &self, - ptr: Pointer>, + ptr: Pointer>, size: Size, align: Align, msg: CheckInAllocMsg, @@ -389,15 +385,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// is done. Returns `None` for size 0, and otherwise `Some` of what `alloc_size` returned. fn check_and_deref_ptr( &self, - ptr: Pointer>, + ptr: Pointer>, size: Size, align: Option, msg: CheckInAllocMsg, - alloc_size: impl FnOnce( - AllocId, - Size, - M::ProvenanceExtra, - ) -> InterpResult<'tcx, (Size, Align, T)>, + alloc_size: impl FnOnce(AllocId, Size, M::TagExtra) -> InterpResult<'tcx, (Size, Align, T)>, ) -> InterpResult<'tcx, Option> { fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> { if offset % align.bytes() == 0 { @@ -425,8 +417,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } None } - Ok((alloc_id, offset, prov)) => { - let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?; + Ok((alloc_id, offset, tag)) => { + let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, tag)?; // Test bounds. This also ensures non-null. // It is sufficient to check this for the end pointer. Also check for overflow! if offset.checked_add(size, &self.tcx).map_or(true, |end| end > alloc_size) { @@ -439,7 +431,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }) } // Ensure we never consider the null pointer dereferencable. - if M::Provenance::OFFSET_IS_ADDR { + if M::PointerTag::OFFSET_IS_ADDR { assert_ne!(ptr.addr(), Size::ZERO); } // Test align. Check this last; if both bounds and alignment are violated @@ -470,20 +462,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Helper function to obtain a global (tcx) allocation. /// This attempts to return a reference to an existing allocation if /// one can be found in `tcx`. That, however, is only possible if `tcx` and - /// this machine use the same pointer provenance, so it is indirected through - /// `M::adjust_allocation`. + /// this machine use the same pointer tag, so it is indirected through + /// `M::tag_allocation`. fn get_global_alloc( &self, id: AllocId, is_write: bool, - ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { - let (alloc, def_id) = match self.tcx.try_get_global_alloc(id) { + ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { + let (alloc, def_id) = match self.tcx.get_global_alloc(id) { Some(GlobalAlloc::Memory(mem)) => { // Memory of a constant or promoted or anonymous memory referenced by a static. (mem, None) } Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)), - Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)), None => throw_ub!(PointerUseAfterFree(id)), Some(GlobalAlloc::Static(def_id)) => { assert!(self.tcx.is_static(def_id)); @@ -499,8 +490,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // contains a reference to memory that was created during its evaluation (i.e., not // to another static), those inner references only exist in "resolved" form. if self.tcx.is_foreign_item(def_id) { - // This is unreachable in Miri, but can happen in CTFE where we actually *do* support - // referencing arbitrary (declared) extern statics. throw_unsup!(ReadExternStatic(def_id)); } @@ -510,7 +499,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; M::before_access_global(*self.tcx, &self.machine, id, alloc, def_id, is_write)?; // We got tcx memory. Let the machine initialize its "extra" stuff. - M::adjust_allocation( + M::init_allocation_extra( self, id, // always use the ID we got as input, not the "hidden" one. Cow::Borrowed(alloc.inner()), @@ -523,11 +512,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn get_alloc_raw( &self, id: AllocId, - ) -> InterpResult<'tcx, &Allocation> { + ) -> InterpResult<'tcx, &Allocation> { // The error type of the inner closure here is somewhat funny. We have two // ways of "erroring": An actual error, or because we got a reference from // `get_global_alloc` that we can actually use directly without inserting anything anywhere. - // So the error type is `InterpResult<'tcx, &Allocation>`. + // So the error type is `InterpResult<'tcx, &Allocation>`. let a = self.memory.alloc_map.get_or(id, || { let alloc = self.get_global_alloc(id, /*is_write*/ false).map_err(Err)?; match alloc { @@ -556,24 +545,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// "Safe" (bounds and align-checked) allocation access. pub fn get_ptr_alloc<'a>( &'a self, - ptr: Pointer>, + ptr: Pointer>, size: Size, align: Align, - ) -> InterpResult<'tcx, Option>> { + ) -> InterpResult<'tcx, Option>> { let align = M::enforce_alignment(self).then_some(align); let ptr_and_alloc = self.check_and_deref_ptr( ptr, size, align, CheckInAllocMsg::MemoryAccessTest, - |alloc_id, offset, prov| { + |alloc_id, offset, tag| { let alloc = self.get_alloc_raw(alloc_id)?; - Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc))) + Ok((alloc.size(), alloc.align, (alloc_id, offset, tag, alloc))) }, )?; - if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc { + if let Some((alloc_id, offset, tag, alloc)) = ptr_and_alloc { let range = alloc_range(offset, size); - M::memory_read(*self.tcx, &self.machine, &alloc.extra, (alloc_id, prov), range)?; + M::memory_read(*self.tcx, &self.machine, &alloc.extra, (alloc_id, tag), range)?; Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id })) } else { // Even in this branch we have to be sure that we actually access the allocation, in @@ -597,7 +586,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn get_alloc_raw_mut( &mut self, id: AllocId, - ) -> InterpResult<'tcx, (&mut Allocation, &mut M)> { + ) -> InterpResult<'tcx, (&mut Allocation, &mut M)> { // We have "NLL problem case #3" here, which cannot be worked around without loss of // efficiency even for the common case where the key is in the map. // @@ -623,18 +612,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// "Safe" (bounds and align-checked) allocation access. pub fn get_ptr_alloc_mut<'a>( &'a mut self, - ptr: Pointer>, + ptr: Pointer>, size: Size, align: Align, - ) -> InterpResult<'tcx, Option>> { + ) -> InterpResult<'tcx, Option>> { let parts = self.get_ptr_access(ptr, size, align)?; - if let Some((alloc_id, offset, prov)) = parts { + if let Some((alloc_id, offset, tag)) = parts { let tcx = *self.tcx; // FIXME: can we somehow avoid looking up the allocation twice here? // We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`. let (alloc, machine) = self.get_alloc_raw_mut(alloc_id)?; let range = alloc_range(offset, size); - M::memory_written(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?; + M::memory_written(tcx, machine, &mut alloc.extra, (alloc_id, tag), range)?; Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id })) } else { Ok(None) @@ -670,14 +659,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // # Statics // Can't do this in the match argument, we may get cycle errors since the lock would // be held throughout the match. - match self.tcx.try_get_global_alloc(id) { - Some(GlobalAlloc::Static(def_id)) => { - assert!(self.tcx.is_static(def_id)); - assert!(!self.tcx.is_thread_local_static(def_id)); + match self.tcx.get_global_alloc(id) { + Some(GlobalAlloc::Static(did)) => { + assert!(!self.tcx.is_thread_local_static(did)); // Use size and align of the type. - let ty = self.tcx.type_of(def_id); + let ty = self.tcx.type_of(did); let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); - assert!(!layout.is_unsized()); (layout.size, layout.align.abi, AllocKind::LiveData) } Some(GlobalAlloc::Memory(alloc)) => { @@ -687,10 +674,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (alloc.size(), alloc.align, AllocKind::LiveData) } Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"), - Some(GlobalAlloc::VTable(..)) => { - // No data to be accessed here. But vtables are pointer-aligned. - return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::VTable); - } // The rest must be dead. None => { // Deallocated pointers are allowed, we should be able to find @@ -718,7 +701,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if let Some(extra) = self.memory.extra_fn_ptr_map.get(&id) { Some(FnVal::Other(*extra)) } else { - match self.tcx.try_get_global_alloc(id) { + match self.tcx.get_global_alloc(id) { Some(GlobalAlloc::Function(instance)) => Some(FnVal::Instance(instance)), _ => None, } @@ -727,10 +710,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn get_ptr_fn( &self, - ptr: Pointer>, + ptr: Pointer>, ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { - trace!("get_ptr_fn({:?})", ptr); - let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr)?; + trace!("get_fn({:?})", ptr); + let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?; if offset.bytes() != 0 { throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))) } @@ -738,21 +721,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into()) } - pub fn get_ptr_vtable( - &self, - ptr: Pointer>, - ) -> InterpResult<'tcx, (Ty<'tcx>, Option>)> { - trace!("get_ptr_vtable({:?})", ptr); - let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?; - if offset.bytes() != 0 { - throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset))) - } - match self.tcx.try_get_global_alloc(alloc_id) { - Some(GlobalAlloc::VTable(ty, trait_ref)) => Ok((ty, trait_ref)), - _ => throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset))), - } - } - pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> { self.get_alloc_raw_mut(id)?.0.mutability = Mutability::Not; Ok(()) @@ -791,7 +759,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // This is a new allocation, add its relocations to `todo`. if let Some((_, alloc)) = self.memory.alloc_map.get(id) { todo.extend( - alloc.relocations().values().filter_map(|prov| prov.get_alloc_id()), + alloc.relocations().values().filter_map(|tag| tag.get_alloc_id()), ); } } @@ -820,14 +788,14 @@ pub struct DumpAllocs<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, 'mir, 'tcx, M> { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // Cannot be a closure because it is generic in `Prov`, `Extra`. - fn write_allocation_track_relocs<'tcx, Prov: Provenance, Extra>( + // Cannot be a closure because it is generic in `Tag`, `Extra`. + fn write_allocation_track_relocs<'tcx, Tag: Provenance, Extra>( fmt: &mut std::fmt::Formatter<'_>, tcx: TyCtxt<'tcx>, allocs_to_print: &mut VecDeque, - alloc: &Allocation, + alloc: &Allocation, ) -> std::fmt::Result { - for alloc_id in alloc.relocations().values().filter_map(|prov| prov.get_alloc_id()) { + for alloc_id in alloc.relocations().values().filter_map(|tag| tag.get_alloc_id()) { allocs_to_print.push_back(alloc_id); } write!(fmt, "{}", display_allocation(tcx, alloc)) @@ -857,7 +825,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, } None => { // global alloc - match self.ecx.tcx.try_get_global_alloc(id) { + match self.ecx.tcx.get_global_alloc(id) { Some(GlobalAlloc::Memory(alloc)) => { write!(fmt, " (unchanged global, ")?; write_allocation_track_relocs( @@ -868,13 +836,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, )?; } Some(GlobalAlloc::Function(func)) => { - write!(fmt, " (fn: {func})")?; - } - Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => { - write!(fmt, " (vtable: impl {trait_ref} for {ty})")?; - } - Some(GlobalAlloc::VTable(ty, None)) => { - write!(fmt, " (vtable: impl for {ty})")?; + write!(fmt, " (fn: {})", func)?; } Some(GlobalAlloc::Static(did)) => { write!(fmt, " (static: {})", self.ecx.tcx.def_path_str(did))?; @@ -892,12 +854,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, } /// Reading and writing. -impl<'tcx, 'a, Prov: Provenance, Extra> AllocRefMut<'a, 'tcx, Prov, Extra> { +impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> { /// `range` is relative to this allocation reference, not the base of the allocation. pub fn write_scalar( &mut self, range: AllocRange, - val: ScalarMaybeUninit, + val: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let range = self.range.subrange(range); debug!("write_scalar at {:?}{range:?}: {val:?}", self.alloc_id); @@ -911,7 +873,7 @@ impl<'tcx, 'a, Prov: Provenance, Extra> AllocRefMut<'a, 'tcx, Prov, Extra> { pub fn write_ptr_sized( &mut self, offset: Size, - val: ScalarMaybeUninit, + val: ScalarMaybeUninit, ) -> InterpResult<'tcx> { self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size), val) } @@ -925,13 +887,13 @@ impl<'tcx, 'a, Prov: Provenance, Extra> AllocRefMut<'a, 'tcx, Prov, Extra> { } } -impl<'tcx, 'a, Prov: Provenance, Extra> AllocRef<'a, 'tcx, Prov, Extra> { +impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> { /// `range` is relative to this allocation reference, not the base of the allocation. pub fn read_scalar( &self, range: AllocRange, read_provenance: bool, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { let range = self.range.subrange(range); let res = self .alloc @@ -942,12 +904,12 @@ impl<'tcx, 'a, Prov: Provenance, Extra> AllocRef<'a, 'tcx, Prov, Extra> { } /// `range` is relative to this allocation reference, not the base of the allocation. - pub fn read_integer(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit> { + pub fn read_integer(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit> { self.read_scalar(range, /*read_provenance*/ false) } /// `offset` is relative to this allocation reference, not the base of the allocation. - pub fn read_pointer(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit> { + pub fn read_pointer(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit> { self.read_scalar( alloc_range(offset, self.tcx.data_layout().pointer_size), /*read_provenance*/ true, @@ -979,7 +941,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Performs appropriate bounds checks. pub fn read_bytes_ptr( &self, - ptr: Pointer>, + ptr: Pointer>, size: Size, ) -> InterpResult<'tcx, &[u8]> { let Some(alloc_ref) = self.get_ptr_alloc(ptr, size, Align::ONE)? else { @@ -999,7 +961,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Performs appropriate bounds checks. pub fn write_bytes_ptr( &mut self, - ptr: Pointer>, + ptr: Pointer>, src: impl IntoIterator, ) -> InterpResult<'tcx> { let mut src = src.into_iter(); @@ -1036,9 +998,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn mem_copy( &mut self, - src: Pointer>, + src: Pointer>, src_align: Align, - dest: Pointer>, + dest: Pointer>, dest_align: Align, size: Size, nonoverlapping: bool, @@ -1048,9 +1010,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn mem_copy_repeatedly( &mut self, - src: Pointer>, + src: Pointer>, src_align: Align, - dest: Pointer>, + dest: Pointer>, dest_align: Align, size: Size, num_copies: u64, @@ -1065,16 +1027,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // and once below to get the underlying `&[mut] Allocation`. // Source alloc preparations and access hooks. - let Some((src_alloc_id, src_offset, src_prov)) = src_parts else { + let Some((src_alloc_id, src_offset, src_tag)) = src_parts else { // Zero-sized *source*, that means dst is also zero-sized and we have nothing to do. return Ok(()); }; let src_alloc = self.get_alloc_raw(src_alloc_id)?; let src_range = alloc_range(src_offset, size); - M::memory_read(*tcx, &self.machine, &src_alloc.extra, (src_alloc_id, src_prov), src_range)?; + M::memory_read(*tcx, &self.machine, &src_alloc.extra, (src_alloc_id, src_tag), src_range)?; // We need the `dest` ptr for the next operation, so we get it now. // We already did the source checks and called the hooks so we are good to return early. - let Some((dest_alloc_id, dest_offset, dest_prov)) = dest_parts else { + let Some((dest_alloc_id, dest_offset, dest_tag)) = dest_parts else { // Zero-sized *destination*. return Ok(()); }; @@ -1100,7 +1062,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { *tcx, extra, &mut dest_alloc.extra, - (dest_alloc_id, dest_prov), + (dest_alloc_id, dest_tag), dest_range, )?; let dest_bytes = dest_alloc @@ -1171,14 +1133,34 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Machine pointer introspection. impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { + pub fn scalar_to_ptr( + &self, + scalar: Scalar, + ) -> InterpResult<'tcx, Pointer>> { + // We use `to_bits_or_ptr_internal` since we are just implementing the method people need to + // call to force getting out a pointer. + Ok( + match scalar + .to_bits_or_ptr_internal(self.pointer_size()) + .map_err(|s| err_ub!(ScalarSizeMismatch(s)))? + { + Err(ptr) => ptr.into(), + Ok(bits) => { + let addr = u64::try_from(bits).unwrap(); + M::ptr_from_addr_transmute(&self, addr) + } + }, + ) + } + /// Test if this value might be null. /// If the machine does not support ptr-to-int casts, this is conservative. - pub fn scalar_may_be_null(&self, scalar: Scalar) -> InterpResult<'tcx, bool> { + pub fn scalar_may_be_null(&self, scalar: Scalar) -> InterpResult<'tcx, bool> { Ok(match scalar.try_to_int() { Ok(int) => int.is_null(), Err(_) => { // Can only happen during CTFE. - let ptr = scalar.to_pointer(self)?; + let ptr = self.scalar_to_ptr(scalar)?; match self.ptr_try_get_alloc_id(ptr) { Ok((alloc_id, offset, _)) => { let (size, _align, _kind) = self.get_alloc_info(alloc_id); @@ -1196,13 +1178,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// about where it points), or an absolute address. pub fn ptr_try_get_alloc_id( &self, - ptr: Pointer>, - ) -> Result<(AllocId, Size, M::ProvenanceExtra), u64> { + ptr: Pointer>, + ) -> Result<(AllocId, Size, M::TagExtra), u64> { match ptr.into_pointer_or_addr() { Ok(ptr) => match M::ptr_get_alloc(self, ptr) { Some((alloc_id, offset, extra)) => Ok((alloc_id, offset, extra)), None => { - assert!(M::Provenance::OFFSET_IS_ADDR); + assert!(M::PointerTag::OFFSET_IS_ADDR); let (_, addr) = ptr.into_parts(); Err(addr.bytes()) } @@ -1215,8 +1197,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn ptr_get_alloc_id( &self, - ptr: Pointer>, - ) -> InterpResult<'tcx, (AllocId, Size, M::ProvenanceExtra)> { + ptr: Pointer>, + ) -> InterpResult<'tcx, (AllocId, Size, M::TagExtra)> { self.ptr_try_get_alloc_id(ptr).map_err(|offset| { err_ub!(DanglingIntPointer(offset, CheckInAllocMsg::InboundsTest)).into() }) diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index de284bd3bae37..de6eb1c03361b 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -14,7 +14,7 @@ use rustc_target::abi::{VariantIdx, Variants}; use super::{ alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, GlobalId, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Place, PlaceTy, Pointer, - Provenance, Scalar, ScalarMaybeUninit, + PointerArithmetic, Provenance, Scalar, ScalarMaybeUninit, }; /// An `Immediate` represents a single immediate self-contained Rust value. @@ -25,14 +25,14 @@ use super::{ /// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely /// defined on `Immediate`, and do not have to work with a `Place`. #[derive(Copy, Clone, Debug)] -pub enum Immediate { +pub enum Immediate { /// A single scalar value (must have *initialized* `Scalar` ABI). /// FIXME: we also currently often use this for ZST. /// `ScalarMaybeUninit` should reject ZST, and we should use `Uninit` for them instead. - Scalar(ScalarMaybeUninit), + Scalar(ScalarMaybeUninit), /// A pair of two scalar value (must have `ScalarPair` ABI where both fields are /// `Scalar::Initialized`). - ScalarPair(ScalarMaybeUninit, ScalarMaybeUninit), + ScalarPair(ScalarMaybeUninit, ScalarMaybeUninit), /// A value of fully uninitialized memory. Can have and size and layout. Uninit, } @@ -40,36 +40,36 @@ pub enum Immediate { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(Immediate, 56); -impl From> for Immediate { +impl From> for Immediate { #[inline(always)] - fn from(val: ScalarMaybeUninit) -> Self { + fn from(val: ScalarMaybeUninit) -> Self { Immediate::Scalar(val) } } -impl From> for Immediate { +impl From> for Immediate { #[inline(always)] - fn from(val: Scalar) -> Self { + fn from(val: Scalar) -> Self { Immediate::Scalar(val.into()) } } -impl<'tcx, Prov: Provenance> Immediate { - pub fn from_pointer(p: Pointer, cx: &impl HasDataLayout) -> Self { +impl<'tcx, Tag: Provenance> Immediate { + pub fn from_pointer(p: Pointer, cx: &impl HasDataLayout) -> Self { Immediate::Scalar(ScalarMaybeUninit::from_pointer(p, cx)) } - pub fn from_maybe_pointer(p: Pointer>, cx: &impl HasDataLayout) -> Self { + pub fn from_maybe_pointer(p: Pointer>, cx: &impl HasDataLayout) -> Self { Immediate::Scalar(ScalarMaybeUninit::from_maybe_pointer(p, cx)) } - pub fn new_slice(val: Scalar, len: u64, cx: &impl HasDataLayout) -> Self { + pub fn new_slice(val: Scalar, len: u64, cx: &impl HasDataLayout) -> Self { Immediate::ScalarPair(val.into(), Scalar::from_machine_usize(len, cx).into()) } pub fn new_dyn_trait( - val: Scalar, - vtable: Pointer>, + val: Scalar, + vtable: Pointer>, cx: &impl HasDataLayout, ) -> Self { Immediate::ScalarPair(val.into(), ScalarMaybeUninit::from_maybe_pointer(vtable, cx)) @@ -77,7 +77,7 @@ impl<'tcx, Prov: Provenance> Immediate { #[inline] #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn to_scalar_or_uninit(self) -> ScalarMaybeUninit { + pub fn to_scalar_or_uninit(self) -> ScalarMaybeUninit { match self { Immediate::Scalar(val) => val, Immediate::ScalarPair(..) => bug!("Got a scalar pair where a scalar was expected"), @@ -87,13 +87,13 @@ impl<'tcx, Prov: Provenance> Immediate { #[inline] #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn to_scalar(self) -> InterpResult<'tcx, Scalar> { + pub fn to_scalar(self) -> InterpResult<'tcx, Scalar> { self.to_scalar_or_uninit().check_init() } #[inline] #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn to_scalar_or_uninit_pair(self) -> (ScalarMaybeUninit, ScalarMaybeUninit) { + pub fn to_scalar_or_uninit_pair(self) -> (ScalarMaybeUninit, ScalarMaybeUninit) { match self { Immediate::ScalarPair(val1, val2) => (val1, val2), Immediate::Scalar(..) => bug!("Got a scalar where a scalar pair was expected"), @@ -103,7 +103,7 @@ impl<'tcx, Prov: Provenance> Immediate { #[inline] #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar, Scalar)> { + pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar, Scalar)> { let (val1, val2) = self.to_scalar_or_uninit_pair(); Ok((val1.check_init()?, val2.check_init()?)) } @@ -112,20 +112,20 @@ impl<'tcx, Prov: Provenance> Immediate { // ScalarPair needs a type to interpret, so we often have an immediate and a type together // as input for binary and cast operations. #[derive(Clone, Debug)] -pub struct ImmTy<'tcx, Prov: Provenance = AllocId> { - imm: Immediate, +pub struct ImmTy<'tcx, Tag: Provenance = AllocId> { + imm: Immediate, pub layout: TyAndLayout<'tcx>, } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(ImmTy<'_>, 72); -impl std::fmt::Display for ImmTy<'_, Prov> { +impl std::fmt::Display for ImmTy<'_, Tag> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { /// Helper function for printing a scalar to a FmtPrinter - fn p<'a, 'tcx, Prov: Provenance>( + fn p<'a, 'tcx, Tag: Provenance>( cx: FmtPrinter<'a, 'tcx>, - s: ScalarMaybeUninit, + s: ScalarMaybeUninit, ty: Ty<'tcx>, ) -> Result, std::fmt::Error> { match s { @@ -170,10 +170,10 @@ impl std::fmt::Display for ImmTy<'_, Prov> { } } -impl<'tcx, Prov: Provenance> std::ops::Deref for ImmTy<'tcx, Prov> { - type Target = Immediate; +impl<'tcx, Tag: Provenance> std::ops::Deref for ImmTy<'tcx, Tag> { + type Target = Immediate; #[inline(always)] - fn deref(&self) -> &Immediate { + fn deref(&self) -> &Immediate { &self.imm } } @@ -182,17 +182,17 @@ impl<'tcx, Prov: Provenance> std::ops::Deref for ImmTy<'tcx, Prov> { /// or still in memory. The latter is an optimization, to delay reading that chunk of /// memory and to avoid having to store arbitrary-sized data here. #[derive(Copy, Clone, Debug)] -pub enum Operand { - Immediate(Immediate), - Indirect(MemPlace), +pub enum Operand { + Immediate(Immediate), + Indirect(MemPlace), } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(Operand, 64); #[derive(Clone, Debug)] -pub struct OpTy<'tcx, Prov: Provenance = AllocId> { - op: Operand, // Keep this private; it helps enforce invariants. +pub struct OpTy<'tcx, Tag: Provenance = AllocId> { + op: Operand, // Keep this private; it helps enforce invariants. pub layout: TyAndLayout<'tcx>, /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: /// it needs to have a different alignment than the field type would usually have. @@ -207,50 +207,50 @@ pub struct OpTy<'tcx, Prov: Provenance = AllocId> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(OpTy<'_>, 88); -impl<'tcx, Prov: Provenance> std::ops::Deref for OpTy<'tcx, Prov> { - type Target = Operand; +impl<'tcx, Tag: Provenance> std::ops::Deref for OpTy<'tcx, Tag> { + type Target = Operand; #[inline(always)] - fn deref(&self) -> &Operand { + fn deref(&self) -> &Operand { &self.op } } -impl<'tcx, Prov: Provenance> From> for OpTy<'tcx, Prov> { +impl<'tcx, Tag: Provenance> From> for OpTy<'tcx, Tag> { #[inline(always)] - fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self { + fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self { OpTy { op: Operand::Indirect(*mplace), layout: mplace.layout, align: Some(mplace.align) } } } -impl<'tcx, Prov: Provenance> From<&'_ MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> { +impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> { #[inline(always)] - fn from(mplace: &MPlaceTy<'tcx, Prov>) -> Self { + fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self { OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout, align: Some(mplace.align) } } } -impl<'tcx, Prov: Provenance> From<&'_ mut MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> { +impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> { #[inline(always)] - fn from(mplace: &mut MPlaceTy<'tcx, Prov>) -> Self { + fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self { OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout, align: Some(mplace.align) } } } -impl<'tcx, Prov: Provenance> From> for OpTy<'tcx, Prov> { +impl<'tcx, Tag: Provenance> From> for OpTy<'tcx, Tag> { #[inline(always)] - fn from(val: ImmTy<'tcx, Prov>) -> Self { + fn from(val: ImmTy<'tcx, Tag>) -> Self { OpTy { op: Operand::Immediate(val.imm), layout: val.layout, align: None } } } -impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { +impl<'tcx, Tag: Provenance> ImmTy<'tcx, Tag> { #[inline] - pub fn from_scalar(val: Scalar, layout: TyAndLayout<'tcx>) -> Self { + pub fn from_scalar(val: Scalar, layout: TyAndLayout<'tcx>) -> Self { ImmTy { imm: val.into(), layout } } #[inline] - pub fn from_immediate(imm: Immediate, layout: TyAndLayout<'tcx>) -> Self { + pub fn from_immediate(imm: Immediate, layout: TyAndLayout<'tcx>) -> Self { ImmTy { imm, layout } } @@ -286,7 +286,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { } } -impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { +impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> { pub fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { if self.layout.is_unsized() { // There are no unsized immediates. @@ -302,7 +302,7 @@ impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { pub fn offset_with_meta( &self, offset: Size, - meta: MemPlaceMeta, + meta: MemPlaceMeta, layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Self> { @@ -338,9 +338,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// This is an internal function; call `read_immediate` instead. fn read_immediate_from_mplace_raw( &self, - mplace: &MPlaceTy<'tcx, M::Provenance>, + mplace: &MPlaceTy<'tcx, M::PointerTag>, force: bool, - ) -> InterpResult<'tcx, Option>> { + ) -> InterpResult<'tcx, Option>> { if mplace.layout.is_unsized() { // Don't touch unsized return Ok(None); @@ -363,11 +363,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Abi::Scalar(s) if force => Some(s.primitive()), _ => None, }; + let read_provenance = |s: abi::Primitive, size| { + // Should be just `s.is_ptr()`, but we support a Miri flag that accepts more + // questionable ptr-int transmutes. + let number_may_have_provenance = !M::enforce_number_no_provenance(self); + s.is_ptr() || (number_may_have_provenance && size == self.pointer_size()) + }; if let Some(s) = scalar_layout { let size = s.size(self); assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size"); - let scalar = alloc - .read_scalar(alloc_range(Size::ZERO, size), /*read_provenance*/ s.is_ptr())?; + let scalar = + alloc.read_scalar(alloc_range(Size::ZERO, size), read_provenance(s, size))?; return Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout })); } let scalar_pair_layout = match mplace.layout.abi { @@ -385,12 +391,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (a_size, b_size) = (a.size(self), b.size(self)); let b_offset = a_size.align_to(b.align(self).abi); assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields - let a_val = alloc.read_scalar( - alloc_range(Size::ZERO, a_size), - /*read_provenance*/ a.is_ptr(), - )?; - let b_val = alloc - .read_scalar(alloc_range(b_offset, b_size), /*read_provenance*/ b.is_ptr())?; + let a_val = + alloc.read_scalar(alloc_range(Size::ZERO, a_size), read_provenance(a, a_size))?; + let b_val = + alloc.read_scalar(alloc_range(b_offset, b_size), read_provenance(b, b_size))?; return Ok(Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout, @@ -414,9 +418,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// ConstProp needs it, though. pub fn read_immediate_raw( &self, - src: &OpTy<'tcx, M::Provenance>, + src: &OpTy<'tcx, M::PointerTag>, force: bool, - ) -> InterpResult<'tcx, Result, MPlaceTy<'tcx, M::Provenance>>> { + ) -> InterpResult<'tcx, Result, MPlaceTy<'tcx, M::PointerTag>>> { Ok(match src.try_as_mplace() { Ok(ref mplace) => { if let Some(val) = self.read_immediate_from_mplace_raw(mplace, force)? { @@ -433,8 +437,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn read_immediate( &self, - op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { + op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { if let Ok(imm) = self.read_immediate_raw(op, /*force*/ false)? { Ok(imm) } else { @@ -445,21 +449,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Read a scalar from a place pub fn read_scalar( &self, - op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, ScalarMaybeUninit> { Ok(self.read_immediate(op)?.to_scalar_or_uninit()) } /// Read a pointer from a place. pub fn read_pointer( &self, - op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Pointer>> { - self.read_scalar(op)?.to_pointer(self) + op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, Pointer>> { + self.scalar_to_ptr(self.read_scalar(op)?.check_init()?) } /// Turn the wide MPlace into a string (must already be dereferenced!) - pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx, &str> { + pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> { let len = mplace.len(self)?; let bytes = self.read_bytes_ptr(mplace.ptr, Size::from_bytes(len))?; let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?; @@ -472,8 +476,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Can (but does not always) trigger UB if `op` is uninitialized. pub fn operand_to_simd( &self, - op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> { + op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> { // Basically we just transmute this place into an array following simd_size_and_type. // This only works in memory, but repr(simd) types should never be immediates anyway. assert!(op.layout.ty.is_simd()); @@ -497,10 +501,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// OpTy from a local. pub fn local_to_op( &self, - frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>, + frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, local: mir::Local, layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let layout = self.layout_of_local(frame, local, layout)?; let op = if layout.is_zst() { // Bypass `access_local` (helps in ConstProp) @@ -517,8 +521,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn place_to_op( &self, - place: &PlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + place: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let op = match **place { Place::Ptr(mplace) => Operand::Indirect(mplace), Place::Local { frame, local } => { @@ -534,7 +538,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, mir_place: mir::Place<'tcx>, layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { // Do not use the layout passed in as argument if the base we are looking at // here is not the entire place. let layout = if mir_place.projection.is_empty() { layout } else { None }; @@ -571,7 +575,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, mir_op: &mir::Operand<'tcx>, layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { use rustc_middle::mir::Operand::*; let op = match *mir_op { // FIXME: do some more logic on `move` to invalidate the old location @@ -596,7 +600,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub(super) fn eval_operands( &self, ops: &[mir::Operand<'tcx>], - ) -> InterpResult<'tcx, Vec>> { + ) -> InterpResult<'tcx, Vec>> { ops.iter().map(|op| self.eval_operand(op, None)).collect() } @@ -608,7 +612,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, c: ty::Const<'tcx>, layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { match c.kind() { ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => { @@ -633,7 +637,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, val: &mir::ConstantKind<'tcx>, layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { match val { mir::ConstantKind::Ty(ct) => self.const_to_op(*ct, layout), mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, *ty, layout), @@ -645,9 +649,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { val_val: ConstValue<'tcx>, ty: Ty<'tcx>, layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { // Other cases need layout. - let adjust_scalar = |scalar| -> InterpResult<'tcx, _> { + let tag_scalar = |scalar| -> InterpResult<'tcx, _> { Ok(match scalar { Scalar::Ptr(ptr, size) => Scalar::Ptr(self.global_base_pointer(ptr)?, size), Scalar::Int(int) => Scalar::Int(int), @@ -662,7 +666,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let ptr = self.global_base_pointer(Pointer::new(id, offset))?; Operand::Indirect(MemPlace::from_ptr(ptr.into())) } - ConstValue::Scalar(x) => Operand::Immediate(adjust_scalar(x)?.into()), + ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x)?.into()), ConstValue::ZeroSized => Operand::Immediate(Immediate::Uninit), ConstValue::Slice { data, start, end } => { // We rely on mutability being set correctly in `data` to prevent writes @@ -685,8 +689,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Can also legally be called on non-enums (e.g. through the discriminant_value intrinsic)! pub fn read_discriminant( &self, - op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (Scalar, VariantIdx)> { + op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, (Scalar, VariantIdx)> { trace!("read_discriminant_value {:#?}", op.layout); // Get type and layout of the discriminant. let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?; diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index f9912d706fb11..88999e3b47b5e 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -19,9 +19,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &mut self, op: mir::BinOp, force_overflow_checks: bool, - left: &ImmTy<'tcx, M::Provenance>, - right: &ImmTy<'tcx, M::Provenance>, - dest: &PlaceTy<'tcx, M::Provenance>, + left: &ImmTy<'tcx, M::PointerTag>, + right: &ImmTy<'tcx, M::PointerTag>, + dest: &PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { let (val, overflowed, ty) = self.overflowing_binary_op(op, &left, &right)?; debug_assert_eq!( @@ -58,9 +58,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn binop_ignore_overflow( &mut self, op: mir::BinOp, - left: &ImmTy<'tcx, M::Provenance>, - right: &ImmTy<'tcx, M::Provenance>, - dest: &PlaceTy<'tcx, M::Provenance>, + left: &ImmTy<'tcx, M::PointerTag>, + right: &ImmTy<'tcx, M::PointerTag>, + dest: &PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?; assert_eq!(ty, dest.layout.ty, "type mismatch for result of {:?}", op); @@ -74,7 +74,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { bin_op: mir::BinOp, l: char, r: char, - ) -> (Scalar, bool, Ty<'tcx>) { + ) -> (Scalar, bool, Ty<'tcx>) { use rustc_middle::mir::BinOp::*; let res = match bin_op { @@ -94,7 +94,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { bin_op: mir::BinOp, l: bool, r: bool, - ) -> (Scalar, bool, Ty<'tcx>) { + ) -> (Scalar, bool, Ty<'tcx>) { use rustc_middle::mir::BinOp::*; let res = match bin_op { @@ -112,13 +112,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (Scalar::from_bool(res), false, self.tcx.types.bool) } - fn binary_float_op>>( + fn binary_float_op>>( &self, bin_op: mir::BinOp, ty: Ty<'tcx>, l: F, r: F, - ) -> (Scalar, bool, Ty<'tcx>) { + ) -> (Scalar, bool, Ty<'tcx>) { use rustc_middle::mir::BinOp::*; let (val, ty) = match bin_op { @@ -146,7 +146,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { left_layout: TyAndLayout<'tcx>, r: u128, right_layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { use rustc_middle::mir::BinOp::*; // Shift ops can have an RHS with a different numeric type. @@ -314,9 +314,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn overflowing_binary_op( &self, bin_op: mir::BinOp, - left: &ImmTy<'tcx, M::Provenance>, - right: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + left: &ImmTy<'tcx, M::PointerTag>, + right: &ImmTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { trace!( "Running binary op {:?}: {:?} ({:?}), {:?} ({:?})", bin_op, @@ -393,9 +393,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn binary_op( &self, bin_op: mir::BinOp, - left: &ImmTy<'tcx, M::Provenance>, - right: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { + left: &ImmTy<'tcx, M::PointerTag>, + right: &ImmTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?; Ok(ImmTy::from_scalar(val, self.layout_of(ty)?)) } @@ -405,8 +405,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn overflowing_unary_op( &self, un_op: mir::UnOp, - val: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + val: &ImmTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { use rustc_middle::mir::UnOp::*; let layout = val.layout; @@ -455,8 +455,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn unary_op( &self, un_op: mir::UnOp, - val: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { + val: &ImmTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { let (val, _overflow, ty) = self.overflowing_unary_op(un_op, val)?; Ok(ImmTy::from_scalar(val, self.layout_of(ty)?)) } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 473da71a0ab9c..bc71bfe4327d4 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -18,9 +18,9 @@ use super::{ #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] /// Information required for the sound usage of a `MemPlace`. -pub enum MemPlaceMeta { +pub enum MemPlaceMeta { /// The unsized payload (e.g. length for slices or vtable pointer for trait objects). - Meta(Scalar), + Meta(Scalar), /// `Sized` types or unsized `extern type` None, } @@ -28,8 +28,8 @@ pub enum MemPlaceMeta { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(MemPlaceMeta, 24); -impl MemPlaceMeta { - pub fn unwrap_meta(self) -> Scalar { +impl MemPlaceMeta { + pub fn unwrap_meta(self) -> Scalar { match self { Self::Meta(s) => s, Self::None => { @@ -47,13 +47,13 @@ impl MemPlaceMeta { } #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] -pub struct MemPlace { - /// The pointer can be a pure integer, with the `None` provenance. - pub ptr: Pointer>, +pub struct MemPlace { + /// The pointer can be a pure integer, with the `None` tag. + pub ptr: Pointer>, /// Metadata for unsized places. Interpretation is up to the type. /// Must not be present for sized types, but can be missing for unsized types /// (e.g., `extern type`). - pub meta: MemPlaceMeta, + pub meta: MemPlaceMeta, } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] @@ -61,8 +61,8 @@ rustc_data_structures::static_assert_size!(MemPlace, 40); /// A MemPlace with its layout. Constructing it is only possible in this module. #[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)] -pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> { - mplace: MemPlace, +pub struct MPlaceTy<'tcx, Tag: Provenance = AllocId> { + mplace: MemPlace, pub layout: TyAndLayout<'tcx>, /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: /// it needs to have a different alignment than the field type would usually have. @@ -75,9 +75,9 @@ pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> { rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 64); #[derive(Copy, Clone, Debug)] -pub enum Place { +pub enum Place { /// A place referring to a value allocated in the `Memory` system. - Ptr(MemPlace), + Ptr(MemPlace), /// To support alloc-free locals, we are able to write directly to a local. /// (Without that optimization, we'd just always be a `MemPlace`.) @@ -88,8 +88,8 @@ pub enum Place { rustc_data_structures::static_assert_size!(Place, 48); #[derive(Clone, Debug)] -pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> { - place: Place, // Keep this private; it helps enforce invariants. +pub struct PlaceTy<'tcx, Tag: Provenance = AllocId> { + place: Place, // Keep this private; it helps enforce invariants. pub layout: TyAndLayout<'tcx>, /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: /// it needs to have a different alignment than the field type would usually have. @@ -101,58 +101,58 @@ pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(PlaceTy<'_>, 72); -impl<'tcx, Prov: Provenance> std::ops::Deref for PlaceTy<'tcx, Prov> { - type Target = Place; +impl<'tcx, Tag: Provenance> std::ops::Deref for PlaceTy<'tcx, Tag> { + type Target = Place; #[inline(always)] - fn deref(&self) -> &Place { + fn deref(&self) -> &Place { &self.place } } -impl<'tcx, Prov: Provenance> std::ops::Deref for MPlaceTy<'tcx, Prov> { - type Target = MemPlace; +impl<'tcx, Tag: Provenance> std::ops::Deref for MPlaceTy<'tcx, Tag> { + type Target = MemPlace; #[inline(always)] - fn deref(&self) -> &MemPlace { + fn deref(&self) -> &MemPlace { &self.mplace } } -impl<'tcx, Prov: Provenance> From> for PlaceTy<'tcx, Prov> { +impl<'tcx, Tag: Provenance> From> for PlaceTy<'tcx, Tag> { #[inline(always)] - fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self { + fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self { PlaceTy { place: Place::Ptr(*mplace), layout: mplace.layout, align: mplace.align } } } -impl<'tcx, Prov: Provenance> From<&'_ MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> { +impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> { #[inline(always)] - fn from(mplace: &MPlaceTy<'tcx, Prov>) -> Self { + fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self { PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align } } } -impl<'tcx, Prov: Provenance> From<&'_ mut MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> { +impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> { #[inline(always)] - fn from(mplace: &mut MPlaceTy<'tcx, Prov>) -> Self { + fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self { PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align } } } -impl MemPlace { +impl MemPlace { #[inline(always)] - pub fn from_ptr(ptr: Pointer>) -> Self { + pub fn from_ptr(ptr: Pointer>) -> Self { MemPlace { ptr, meta: MemPlaceMeta::None } } /// Adjust the provenance of the main pointer (metadata is unaffected). - pub fn map_provenance(self, f: impl FnOnce(Option) -> Option) -> Self { + pub fn map_provenance(self, f: impl FnOnce(Option) -> Option) -> Self { MemPlace { ptr: self.ptr.map_provenance(f), ..self } } /// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space. /// This is the inverse of `ref_to_mplace`. #[inline(always)] - pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate { + pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate { match self.meta { MemPlaceMeta::None => Immediate::from(Scalar::from_maybe_pointer(self.ptr, cx)), MemPlaceMeta::Meta(meta) => { @@ -165,14 +165,14 @@ impl MemPlace { pub fn offset_with_meta<'tcx>( self, offset: Size, - meta: MemPlaceMeta, + meta: MemPlaceMeta, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Self> { Ok(MemPlace { ptr: self.ptr.offset(offset, cx)?, meta }) } } -impl Place { +impl Place { /// Asserts that this points to some local variable. /// Returns the frame idx and the variable idx. #[inline] @@ -185,7 +185,7 @@ impl Place { } } -impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> { +impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> { /// Produces a MemPlace that works for ZST but nothing else. /// Conceptually this is a new allocation, but it doesn't actually create an allocation so you /// don't need to worry about memory leaks. @@ -201,7 +201,7 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> { pub fn offset_with_meta( &self, offset: Size, - meta: MemPlaceMeta, + meta: MemPlaceMeta, layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Self> { @@ -223,15 +223,15 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> { } #[inline] - pub fn from_aligned_ptr(ptr: Pointer>, layout: TyAndLayout<'tcx>) -> Self { + pub fn from_aligned_ptr(ptr: Pointer>, layout: TyAndLayout<'tcx>) -> Self { MPlaceTy { mplace: MemPlace::from_ptr(ptr), layout, align: layout.align.abi } } #[inline] pub fn from_aligned_ptr_with_meta( - ptr: Pointer>, + ptr: Pointer>, layout: TyAndLayout<'tcx>, - meta: MemPlaceMeta, + meta: MemPlaceMeta, ) -> Self { let mut mplace = MemPlace::from_ptr(ptr); mplace.meta = meta; @@ -258,7 +258,7 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> { } #[inline] - pub(super) fn vtable(&self) -> Scalar { + pub(super) fn vtable(&self) -> Scalar { match self.layout.ty.kind() { ty::Dynamic(..) => self.mplace.meta.unwrap_meta(), _ => bug!("vtable not supported on type {:?}", self.layout.ty), @@ -267,11 +267,11 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> { } // These are defined here because they produce a place. -impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { +impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> { #[inline(always)] /// Note: do not call `as_ref` on the resulting place. This function should only be used to /// read from the resulting mplace, not to get its address back. - pub fn try_as_mplace(&self) -> Result, ImmTy<'tcx, Prov>> { + pub fn try_as_mplace(&self) -> Result, ImmTy<'tcx, Tag>> { match **self { Operand::Indirect(mplace) => { Ok(MPlaceTy { mplace, layout: self.layout, align: self.align.unwrap() }) @@ -284,15 +284,15 @@ impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) /// Note: do not call `as_ref` on the resulting place. This function should only be used to /// read from the resulting mplace, not to get its address back. - pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Prov> { + pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Tag> { self.try_as_mplace().unwrap() } } -impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> { +impl<'tcx, Tag: Provenance> PlaceTy<'tcx, Tag> { /// A place is either an mplace or some local. #[inline] - pub fn try_as_mplace(&self) -> Result, (usize, mir::Local)> { + pub fn try_as_mplace(&self) -> Result, (usize, mir::Local)> { match **self { Place::Ptr(mplace) => Ok(MPlaceTy { mplace, layout: self.layout, align: self.align }), Place::Local { frame, local } => Err((frame, local)), @@ -301,16 +301,16 @@ impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> { #[inline(always)] #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Prov> { + pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> { self.try_as_mplace().unwrap() } } // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 -impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M> +impl<'mir, 'tcx: 'mir, Tag, M> InterpCx<'mir, 'tcx, M> where - Prov: Provenance + Eq + Hash + 'static, - M: Machine<'mir, 'tcx, Provenance = Prov>, + Tag: Provenance + Eq + Hash + 'static, + M: Machine<'mir, 'tcx, PointerTag = Tag>, { /// Take a value, which represents a (thin or wide) reference, and make it a place. /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`. @@ -320,8 +320,8 @@ where /// Generally prefer `deref_operand`. pub fn ref_to_mplace( &self, - val: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { + val: &ImmTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { let pointee_type = val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty; let layout = self.layout_of(pointee_type)?; @@ -331,7 +331,7 @@ where Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), }; - let mplace = MemPlace { ptr: ptr.to_pointer(self)?, meta }; + let mplace = MemPlace { ptr: self.scalar_to_ptr(ptr.check_init()?)?, meta }; // When deref'ing a pointer, the *static* alignment given by the type is what matters. let align = layout.align.abi; Ok(MPlaceTy { mplace, layout, align }) @@ -342,8 +342,8 @@ where #[instrument(skip(self), level = "debug")] pub fn deref_operand( &self, - src: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { + src: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { let val = self.read_immediate(src)?; trace!("deref to {} on {:?}", val.layout.ty, *val); @@ -359,8 +359,8 @@ where #[inline] pub(super) fn get_place_alloc( &self, - place: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Option>> { + place: &MPlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, Option>> { assert!(!place.layout.is_unsized()); assert!(!place.meta.has_meta()); let size = place.layout.size; @@ -370,8 +370,8 @@ where #[inline] pub(super) fn get_place_alloc_mut( &mut self, - place: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Option>> { + place: &MPlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, Option>> { assert!(!place.layout.is_unsized()); assert!(!place.meta.has_meta()); let size = place.layout.size; @@ -381,7 +381,7 @@ where /// Check if this mplace is dereferenceable and sufficiently aligned. fn check_mplace_access( &self, - mplace: MPlaceTy<'tcx, M::Provenance>, + mplace: MPlaceTy<'tcx, M::PointerTag>, msg: CheckInAllocMsg, ) -> InterpResult<'tcx> { let (size, align) = self @@ -397,8 +397,8 @@ where /// Also returns the number of elements. pub fn mplace_to_simd( &self, - mplace: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> { + mplace: &MPlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> { // Basically we just transmute this place into an array following simd_size_and_type. // (Transmuting is okay since this is an in-memory place. We also double-check the size // stays the same.) @@ -413,8 +413,8 @@ where /// Also returns the number of elements. pub fn place_to_simd( &mut self, - place: &PlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> { + place: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> { let mplace = self.force_allocation(place)?; self.mplace_to_simd(&mplace) } @@ -423,7 +423,7 @@ where &self, frame: usize, local: mir::Local, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { let layout = self.layout_of_local(&self.stack()[frame], local, None)?; let place = Place::Local { frame, local }; Ok(PlaceTy { place, layout, align: layout.align.abi }) @@ -435,7 +435,7 @@ where pub fn eval_place( &mut self, mir_place: mir::Place<'tcx>, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { let mut place = self.local_to_place(self.frame_idx(), mir_place.local)?; // Using `try_fold` turned out to be bad for performance, hence the loop. for elem in mir_place.projection.iter() { @@ -465,8 +465,8 @@ where #[instrument(skip(self), level = "debug")] pub fn write_immediate( &mut self, - src: Immediate, - dest: &PlaceTy<'tcx, M::Provenance>, + src: Immediate, + dest: &PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { self.write_immediate_no_validate(src, dest)?; @@ -482,8 +482,8 @@ where #[inline(always)] pub fn write_scalar( &mut self, - val: impl Into>, - dest: &PlaceTy<'tcx, M::Provenance>, + val: impl Into>, + dest: &PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { self.write_immediate(Immediate::Scalar(val.into()), dest) } @@ -492,8 +492,8 @@ where #[inline(always)] pub fn write_pointer( &mut self, - ptr: impl Into>>, - dest: &PlaceTy<'tcx, M::Provenance>, + ptr: impl Into>>, + dest: &PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { self.write_scalar(Scalar::from_maybe_pointer(ptr.into(), self), dest) } @@ -503,8 +503,8 @@ where /// right type. fn write_immediate_no_validate( &mut self, - src: Immediate, - dest: &PlaceTy<'tcx, M::Provenance>, + src: Immediate, + dest: &PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { assert!(!dest.layout.is_unsized(), "Cannot write unsized data"); trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty); @@ -537,10 +537,10 @@ where /// right layout. fn write_immediate_to_mplace_no_validate( &mut self, - value: Immediate, + value: Immediate, layout: TyAndLayout<'tcx>, align: Align, - dest: MemPlace, + dest: MemPlace, ) -> InterpResult<'tcx> { // Note that it is really important that the type here is the right one, and matches the // type things are read at. In case `value` is a `ScalarPair`, we don't do any magic here @@ -589,7 +589,7 @@ where } } - pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { + pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { let mplace = match dest.try_as_mplace() { Ok(mplace) => mplace, Err((frame, local)) => { @@ -619,8 +619,8 @@ where #[instrument(skip(self), level = "debug")] pub fn copy_op( &mut self, - src: &OpTy<'tcx, M::Provenance>, - dest: &PlaceTy<'tcx, M::Provenance>, + src: &OpTy<'tcx, M::PointerTag>, + dest: &PlaceTy<'tcx, M::PointerTag>, allow_transmute: bool, ) -> InterpResult<'tcx> { self.copy_op_no_validate(src, dest, allow_transmute)?; @@ -640,8 +640,8 @@ where #[instrument(skip(self), level = "debug")] fn copy_op_no_validate( &mut self, - src: &OpTy<'tcx, M::Provenance>, - dest: &PlaceTy<'tcx, M::Provenance>, + src: &OpTy<'tcx, M::PointerTag>, + dest: &PlaceTy<'tcx, M::PointerTag>, allow_transmute: bool, ) -> InterpResult<'tcx> { // We do NOT compare the types for equality, because well-typed code can @@ -713,8 +713,8 @@ where #[instrument(skip(self), level = "debug")] pub fn force_allocation( &mut self, - place: &PlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { + place: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { let mplace = match place.place { Place::Local { frame, local } => { match M::access_local_mut(self, frame, local)? { @@ -760,7 +760,7 @@ where &mut self, layout: TyAndLayout<'tcx>, kind: MemoryKind, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { assert!(!layout.is_unsized()); let ptr = self.allocate_ptr(layout.size, layout.align.abi, kind)?; Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout)) @@ -772,7 +772,7 @@ where str: &str, kind: MemoryKind, mutbl: Mutability, - ) -> MPlaceTy<'tcx, M::Provenance> { + ) -> MPlaceTy<'tcx, M::PointerTag> { let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl); let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self); let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) }; @@ -790,7 +790,7 @@ where pub fn write_discriminant( &mut self, variant_index: VariantIdx, - dest: &PlaceTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { // This must be an enum or generator. match dest.layout.ty.kind() { @@ -876,7 +876,7 @@ where pub fn raw_const_to_mplace( &self, raw: ConstAlloc<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { // This must be an allocation in `tcx` let _ = self.tcx.global_alloc(raw.alloc_id); let ptr = self.global_base_pointer(Pointer::from(raw.alloc_id))?; @@ -885,19 +885,28 @@ where } /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type. + /// Also return some more information so drop doesn't have to run the same code twice. pub(super) fn unpack_dyn_trait( &self, - mplace: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { - let vtable = mplace.vtable().to_pointer(self)?; // also sanity checks the type - let (ty, _) = self.get_ptr_vtable(vtable)?; + mplace: &MPlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> { + let vtable = self.scalar_to_ptr(mplace.vtable())?; // also sanity checks the type + let (instance, ty) = self.read_drop_type_from_vtable(vtable)?; let layout = self.layout_of(ty)?; + // More sanity checks + if cfg!(debug_assertions) { + let (size, align) = self.read_size_and_align_from_vtable(vtable)?; + assert_eq!(size, layout.size); + // only ABI alignment is preserved + assert_eq!(align, layout.align.abi); + } + let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace }, layout, align: layout.align.abi, }; - Ok(mplace) + Ok((instance, mplace)) } } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 742339f2b0aff..61d58232dc29c 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -20,10 +20,10 @@ use super::{ }; // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 -impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M> +impl<'mir, 'tcx: 'mir, Tag, M> InterpCx<'mir, 'tcx, M> where - Prov: Provenance + Eq + Hash + 'static, - M: Machine<'mir, 'tcx, Provenance = Prov>, + Tag: Provenance + Eq + Hash + 'static, + M: Machine<'mir, 'tcx, PointerTag = Tag>, { //# Field access @@ -35,9 +35,9 @@ where /// For indexing into arrays, use `mplace_index`. pub fn mplace_field( &self, - base: &MPlaceTy<'tcx, M::Provenance>, + base: &MPlaceTy<'tcx, M::PointerTag>, field: usize, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { let offset = base.layout.fields.offset(field); let field_layout = base.layout.field(self, field); @@ -72,9 +72,9 @@ where /// into the field of a local `ScalarPair`, we have to first allocate it. pub fn place_field( &mut self, - base: &PlaceTy<'tcx, M::Provenance>, + base: &PlaceTy<'tcx, M::PointerTag>, field: usize, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { // FIXME: We could try to be smarter and avoid allocation for fields that span the // entire place. let base = self.force_allocation(base)?; @@ -83,9 +83,9 @@ where pub fn operand_field( &self, - base: &OpTy<'tcx, M::Provenance>, + base: &OpTy<'tcx, M::PointerTag>, field: usize, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let base = match base.try_as_mplace() { Ok(ref mplace) => { // We can reuse the mplace field computation logic for indirect operands. @@ -139,9 +139,9 @@ where pub fn mplace_downcast( &self, - base: &MPlaceTy<'tcx, M::Provenance>, + base: &MPlaceTy<'tcx, M::PointerTag>, variant: VariantIdx, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { // Downcasts only change the layout. // (In particular, no check about whether this is even the active variant -- that's by design, // see https://github.com/rust-lang/rust/issues/93688#issuecomment-1032929496.) @@ -153,9 +153,9 @@ where pub fn place_downcast( &self, - base: &PlaceTy<'tcx, M::Provenance>, + base: &PlaceTy<'tcx, M::PointerTag>, variant: VariantIdx, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { // Downcast just changes the layout let mut base = base.clone(); base.layout = base.layout.for_variant(self, variant); @@ -164,9 +164,9 @@ where pub fn operand_downcast( &self, - base: &OpTy<'tcx, M::Provenance>, + base: &OpTy<'tcx, M::PointerTag>, variant: VariantIdx, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { // Downcast just changes the layout let mut base = base.clone(); base.layout = base.layout.for_variant(self, variant); @@ -178,9 +178,9 @@ where #[inline(always)] pub fn operand_index( &self, - base: &OpTy<'tcx, M::Provenance>, + base: &OpTy<'tcx, M::PointerTag>, index: u64, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { // Not using the layout method because we want to compute on u64 match base.layout.fields { abi::FieldsShape::Array { stride, count: _ } => { @@ -207,8 +207,8 @@ where // same by repeatedly calling `operand_index`. pub fn operand_array_fields<'a>( &self, - base: &'a OpTy<'tcx, Prov>, - ) -> InterpResult<'tcx, impl Iterator>> + 'a> { + base: &'a OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, impl Iterator>> + 'a> { let len = base.len(self)?; // also asserts that we have a type where this makes sense let abi::FieldsShape::Array { stride, .. } = base.layout.fields else { span_bug!(self.cur_span(), "operand_array_fields: expected an array layout"); @@ -222,17 +222,17 @@ where /// Index into an array. pub fn mplace_index( &self, - base: &MPlaceTy<'tcx, M::Provenance>, + base: &MPlaceTy<'tcx, M::PointerTag>, index: u64, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { Ok(self.operand_index(&base.into(), index)?.assert_mem_place()) } pub fn place_index( &mut self, - base: &PlaceTy<'tcx, M::Provenance>, + base: &PlaceTy<'tcx, M::PointerTag>, index: u64, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { // There's not a lot we can do here, since we cannot have a place to a part of a local. If // we are accessing the only element of a 1-element array, it's still the entire local... // that doesn't seem worth it. @@ -244,11 +244,11 @@ where fn operand_constant_index( &self, - base: &OpTy<'tcx, M::Provenance>, + base: &OpTy<'tcx, M::PointerTag>, offset: u64, min_length: u64, from_end: bool, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let n = base.len(self)?; if n < min_length { // This can only be reached in ConstProp and non-rustc-MIR. @@ -268,11 +268,11 @@ where fn place_constant_index( &mut self, - base: &PlaceTy<'tcx, M::Provenance>, + base: &PlaceTy<'tcx, M::PointerTag>, offset: u64, min_length: u64, from_end: bool, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { let base = self.force_allocation(base)?; Ok(self .operand_constant_index(&base.into(), offset, min_length, from_end)? @@ -284,11 +284,11 @@ where fn operand_subslice( &self, - base: &OpTy<'tcx, M::Provenance>, + base: &OpTy<'tcx, M::PointerTag>, from: u64, to: u64, from_end: bool, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let len = base.len(self)?; // also asserts that we have a type where this makes sense let actual_to = if from_end { if from.checked_add(to).map_or(true, |to| to > len) { @@ -329,11 +329,11 @@ where pub fn place_subslice( &mut self, - base: &PlaceTy<'tcx, M::Provenance>, + base: &PlaceTy<'tcx, M::PointerTag>, from: u64, to: u64, from_end: bool, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { let base = self.force_allocation(base)?; Ok(self.operand_subslice(&base.into(), from, to, from_end)?.assert_mem_place().into()) } @@ -344,9 +344,9 @@ where #[instrument(skip(self), level = "trace")] pub fn place_projection( &mut self, - base: &PlaceTy<'tcx, M::Provenance>, + base: &PlaceTy<'tcx, M::PointerTag>, proj_elem: mir::PlaceElem<'tcx>, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { use rustc_middle::mir::ProjectionElem::*; Ok(match proj_elem { Field(field, _) => self.place_field(base, field.index())?, @@ -368,9 +368,9 @@ where #[instrument(skip(self), level = "trace")] pub fn operand_projection( &self, - base: &OpTy<'tcx, M::Provenance>, + base: &OpTy<'tcx, M::PointerTag>, proj_elem: mir::PlaceElem<'tcx>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { use rustc_middle::mir::ProjectionElem::*; Ok(match proj_elem { Field(field, _) => self.operand_field(base, field.index())?, diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index d563e35f9102d..d0c9b5319ddc1 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::convert::TryFrom; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; use rustc_middle::ty::Instance; @@ -266,10 +267,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn pass_argument<'x, 'y>( &mut self, caller_args: &mut impl Iterator< - Item = (&'x OpTy<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>), + Item = (&'x OpTy<'tcx, M::PointerTag>, &'y ArgAbi<'tcx, Ty<'tcx>>), >, callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, - callee_arg: &PlaceTy<'tcx, M::Provenance>, + callee_arg: &PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> where 'tcx: 'x, @@ -335,9 +336,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &mut self, fn_val: FnVal<'tcx, M::ExtraFnVal>, (caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>), - args: &[OpTy<'tcx, M::Provenance>], + args: &[OpTy<'tcx, M::PointerTag>], with_caller_location: bool, - destination: &PlaceTy<'tcx, M::Provenance>, + destination: &PlaceTy<'tcx, M::PointerTag>, target: Option, mut unwind: StackPopUnwind, ) -> InterpResult<'tcx> { @@ -364,7 +365,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // caller_fn_abi is not relevant here, we interpret the arguments directly for each intrinsic. M::call_intrinsic(self, instance, args, destination, target, unwind) } - ty::InstanceDef::VTableShim(..) + ty::InstanceDef::VtableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::FnPtrShim(..) @@ -436,7 +437,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // last incoming argument. These two iterators do not have the same type, // so to keep the code paths uniform we accept an allocation // (for RustCall ABI only). - let caller_args: Cow<'_, [OpTy<'tcx, M::Provenance>]> = + let caller_args: Cow<'_, [OpTy<'tcx, M::PointerTag>]> = if caller_abi == Abi::RustCall && !args.is_empty() { // Untuple let (untuple_arg, args) = args.split_last().unwrap(); @@ -448,7 +449,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (0..untuple_arg.layout.fields.count()) .map(|i| self.operand_field(untuple_arg, i)), ) - .collect::>>>( + .collect::>>>( )?, ) } else { @@ -519,7 +520,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } // cannot use the shim here, because that will only result in infinite recursion - ty::InstanceDef::Virtual(def_id, idx) => { + ty::InstanceDef::Virtual(_, idx) => { let mut args = args.to_vec(); // We have to implement all "object safe receivers". So we have to go search for a // pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively @@ -552,52 +553,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } }; - // Obtain the underlying trait we are working on. - let receiver_tail = self - .tcx - .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env); - let ty::Dynamic(data, ..) = receiver_tail.kind() else { - span_bug!(self.cur_span(), "dyanmic call on non-`dyn` type {}", receiver_tail) - }; - - // Get the required information from the vtable. - let vptr = receiver_place.meta.unwrap_meta().to_pointer(self)?; - let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?; - if dyn_trait != data.principal() { - throw_ub_format!( - "`dyn` call on a pointer whose vtable does not match its type" - ); - } - - // Now determine the actual method to call. We can do that in two different ways and - // compare them to ensure everything fits. - let Some(ty::VtblEntry::Method(fn_inst)) = self.get_vtable_entries(vptr)?.get(idx).copied() else { - throw_ub_format!("`dyn` call trying to call something that is not a method") - }; - if cfg!(debug_assertions) { - let tcx = *self.tcx; - - let trait_def_id = tcx.trait_of_item(def_id).unwrap(); - let virtual_trait_ref = - ty::TraitRef::from_method(tcx, trait_def_id, instance.substs); - assert_eq!( - receiver_tail, - virtual_trait_ref.self_ty(), - "mismatch in underlying dyn trait computation within Miri and MIR building", - ); - let existential_trait_ref = - ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref); - let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty); - - let concrete_method = Instance::resolve_for_vtable( - tcx, - self.param_env, - def_id, - instance.substs.rebase_onto(tcx, trait_def_id, concrete_trait_ref.substs), - ) - .unwrap(); - assert_eq!(fn_inst, concrete_method); - } + // Find and consult vtable. The type now could be something like RcBox, + // i.e., it is still not necessarily `ty::Dynamic` (so we cannot use + // `place.vtable()`), but it should have a `dyn Trait` tail. + assert!(matches!( + self.tcx + .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env) + .kind(), + ty::Dynamic(..) + )); + let vtable = self.scalar_to_ptr(receiver_place.meta.unwrap_meta())?; + let fn_val = self.get_vtable_slot(vtable, u64::try_from(idx).unwrap())?; // `*mut receiver_place.layout.ty` is almost the layout that we // want for args[0]: We have to project to field 0 because we want @@ -613,7 +579,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { trace!("Patched receiver operand to {:#?}", args[0]); // recurse with concrete function self.eval_fn_call( - FnVal::Instance(fn_inst), + fn_val, (caller_abi, caller_fn_abi), &args, with_caller_location, @@ -627,7 +593,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn drop_in_place( &mut self, - place: &PlaceTy<'tcx, M::Provenance>, + place: &PlaceTy<'tcx, M::PointerTag>, instance: ty::Instance<'tcx>, target: mir::BasicBlock, unwind: Option, @@ -640,10 +606,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (instance, place) = match place.layout.ty.kind() { ty::Dynamic(..) => { - // Dropping a trait object. Need to find actual drop fn. - let place = self.unpack_dyn_trait(&place)?; - let instance = ty::Instance::resolve_drop_in_place(*self.tcx, place.layout.ty); - (instance, place) + // Dropping a trait object. + self.unpack_dyn_trait(&place)? } _ => (instance, place), }; diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index b3a511d5a492b..22c23df7b1ab3 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -1,24 +1,27 @@ -use rustc_middle::mir::interpret::{InterpResult, Pointer}; -use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use std::convert::TryFrom; + +use rustc_middle::mir::interpret::{alloc_range, InterpResult, Pointer, PointerArithmetic}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, COMMON_VTABLE_ENTRIES_ALIGN, COMMON_VTABLE_ENTRIES_DROPINPLACE, + COMMON_VTABLE_ENTRIES_SIZE, +}; use rustc_target::abi::{Align, Size}; use super::util::ensure_monomorphic_enough; -use super::{InterpCx, Machine}; +use super::{FnVal, InterpCx, Machine}; impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for /// objects. /// - /// The `trait_ref` encodes the erased self type. Hence, if we are making an object `Foo` - /// from a value of type `Foo`, then `trait_ref` would map `T: Trait`. `None` here means that - /// this is an auto trait without any methods, so we only need the basic vtable (drop, size, - /// align). - pub fn get_vtable_ptr( - &self, + /// The `trait_ref` encodes the erased self type. Hence, if we are + /// making an object `Foo` from a value of type `Foo`, then + /// `trait_ref` would map `T: Trait`. + pub fn get_vtable( + &mut self, ty: Ty<'tcx>, poly_trait_ref: Option>, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer>> { trace!("get_vtable(trait_ref={:?})", poly_trait_ref); let (ty, poly_trait_ref) = self.tcx.erase_regions((ty, poly_trait_ref)); @@ -27,33 +30,114 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ensure_monomorphic_enough(*self.tcx, ty)?; ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?; - let vtable_symbolic_allocation = self.tcx.create_vtable_alloc(ty, poly_trait_ref); - let vtable_ptr = self.global_base_pointer(Pointer::from(vtable_symbolic_allocation))?; + let vtable_allocation = self.tcx.vtable_allocation((ty, poly_trait_ref)); + + let vtable_ptr = self.global_base_pointer(Pointer::from(vtable_allocation))?; + Ok(vtable_ptr.into()) } - /// Returns a high-level representation of the entires of the given vtable. - pub fn get_vtable_entries( + /// Resolves the function at the specified slot in the provided + /// vtable. Currently an index of '3' (`TyCtxt::COMMON_VTABLE_ENTRIES.len()`) + /// corresponds to the first method declared in the trait of the provided vtable. + pub fn get_vtable_slot( + &self, + vtable: Pointer>, + idx: u64, + ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { + let ptr_size = self.pointer_size(); + let vtable_slot = vtable.offset(ptr_size * idx, self)?; + let vtable_slot = self + .get_ptr_alloc(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)? + .expect("cannot be a ZST"); + let fn_ptr = self.scalar_to_ptr(vtable_slot.read_pointer(Size::ZERO)?.check_init()?)?; + self.get_ptr_fn(fn_ptr) + } + + /// Returns the drop fn instance as well as the actual dynamic type. + pub fn read_drop_type_from_vtable( &self, - vtable: Pointer>, - ) -> InterpResult<'tcx, &'tcx [ty::VtblEntry<'tcx>]> { - let (ty, poly_trait_ref) = self.get_ptr_vtable(vtable)?; - Ok(if let Some(poly_trait_ref) = poly_trait_ref { - let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty); - let trait_ref = self.tcx.erase_regions(trait_ref); - self.tcx.vtable_entries(trait_ref) - } else { - TyCtxt::COMMON_VTABLE_ENTRIES - }) + vtable: Pointer>, + ) -> InterpResult<'tcx, (ty::Instance<'tcx>, Ty<'tcx>)> { + let pointer_size = self.pointer_size(); + // We don't care about the pointee type; we just want a pointer. + let vtable = self + .get_ptr_alloc( + vtable, + pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(), + self.tcx.data_layout.pointer_align.abi, + )? + .expect("cannot be a ZST"); + let drop_fn = vtable + .read_pointer(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_DROPINPLACE).unwrap())? + .check_init()?; + // We *need* an instance here, no other kind of function value, to be able + // to determine the type. + let drop_instance = self.get_ptr_fn(self.scalar_to_ptr(drop_fn)?)?.as_instance()?; + trace!("Found drop fn: {:?}", drop_instance); + let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx); + let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig); + // The drop function takes `*mut T` where `T` is the type being dropped, so get that. + let args = fn_sig.inputs(); + if args.len() != 1 { + throw_ub!(InvalidVtableDropFn(fn_sig)); + } + let ty = + args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidVtableDropFn(fn_sig)))?.ty; + Ok((drop_instance, ty)) } - pub fn get_vtable_size_and_align( + pub fn read_size_and_align_from_vtable( &self, - vtable: Pointer>, + vtable: Pointer>, ) -> InterpResult<'tcx, (Size, Align)> { - let (ty, _trait_ref) = self.get_ptr_vtable(vtable)?; - let layout = self.layout_of(ty)?; - assert!(!layout.is_unsized(), "there are no vtables for unsized types"); - Ok((layout.size, layout.align.abi)) + let pointer_size = self.pointer_size(); + // We check for `size = 3 * ptr_size`, which covers the drop fn (unused here), + // the size, and the align (which we read below). + let vtable = self + .get_ptr_alloc( + vtable, + pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(), + self.tcx.data_layout.pointer_align.abi, + )? + .expect("cannot be a ZST"); + let size = vtable + .read_integer(alloc_range( + pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap(), + pointer_size, + ))? + .check_init()?; + let size = size.to_machine_usize(self)?; + let size = Size::from_bytes(size); + let align = vtable + .read_integer(alloc_range( + pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap(), + pointer_size, + ))? + .check_init()?; + let align = align.to_machine_usize(self)?; + let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?; + + if size > self.max_size_of_val() { + throw_ub!(InvalidVtableSize); + } + Ok((size, align)) + } + + pub fn read_new_vtable_after_trait_upcasting_from_vtable( + &self, + vtable: Pointer>, + idx: u64, + ) -> InterpResult<'tcx, Pointer>> { + let pointer_size = self.pointer_size(); + + let vtable_slot = vtable.offset(pointer_size * idx, self)?; + let new_vtable = self + .get_ptr_alloc(vtable_slot, pointer_size, self.tcx.data_layout.pointer_align.abi)? + .expect("cannot be a ZST"); + + let new_vtable = self.scalar_to_ptr(new_vtable.read_pointer(Size::ZERO)?.check_init()?)?; + + Ok(new_vtable) } } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index d20f16755c391..2e5492ecf5601 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -206,7 +206,7 @@ struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// starts must not be changed! `visit_fields` and `visit_array` rely on /// this stack discipline. path: Vec, - ref_tracking: Option<&'rt mut RefTracking, Vec>>, + ref_tracking: Option<&'rt mut RefTracking, Vec>>, /// `None` indicates this is not validating for CTFE (but for runtime). ctfe_mode: Option, ecx: &'rt InterpCx<'mir, 'tcx, M>, @@ -306,22 +306,57 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn check_wide_ptr_meta( &mut self, - meta: MemPlaceMeta, + meta: MemPlaceMeta, pointee: TyAndLayout<'tcx>, ) -> InterpResult<'tcx> { let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); match tail.kind() { ty::Dynamic(..) => { - let vtable = meta.unwrap_meta().to_pointer(self.ecx)?; - // Make sure it is a genuine vtable pointer. - let (_ty, _trait) = try_validation!( - self.ecx.get_ptr_vtable(vtable), + let vtable = self.ecx.scalar_to_ptr(meta.unwrap_meta())?; + // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. + try_validation!( + self.ecx.check_ptr_access_align( + vtable, + 3 * self.ecx.tcx.data_layout.pointer_size, // drop, size, align + self.ecx.tcx.data_layout.pointer_align.abi, + CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message + ), self.path, err_ub!(DanglingIntPointer(..)) | - err_ub!(InvalidVTablePointer(..)) => - { "{vtable}" } expected { "a vtable pointer" }, + err_ub!(PointerUseAfterFree(..)) => + { "dangling vtable pointer in wide pointer" }, + err_ub!(AlignmentCheckFailed { .. }) => + { "unaligned vtable pointer in wide pointer" }, + err_ub!(PointerOutOfBounds { .. }) => + { "too small vtable" }, ); - // FIXME: check if the type/trait match what ty::Dynamic says? + try_validation!( + self.ecx.read_drop_type_from_vtable(vtable), + self.path, + err_ub!(DanglingIntPointer(..)) | + err_ub!(InvalidFunctionPointer(..)) => + { "invalid drop function pointer in vtable (not pointing to a function)" }, + err_ub!(InvalidVtableDropFn(..)) => + { "invalid drop function pointer in vtable (function has incompatible signature)" }, + // Stacked Borrows errors can happen here, see https://github.com/rust-lang/miri/issues/2123. + // (We assume there are no other MachineStop errors possible here.) + InterpError::MachineStop(_) => + { "vtable pointer does not have permission to read drop function pointer" }, + ); + try_validation!( + self.ecx.read_size_and_align_from_vtable(vtable), + self.path, + err_ub!(InvalidVtableSize) => + { "invalid vtable: size is bigger than largest supported object" }, + err_ub!(InvalidVtableAlignment(msg)) => + { "invalid vtable: alignment {}", msg }, + err_unsup!(ReadPointerAsBytes) => { "invalid size or align in vtable" }, + // Stacked Borrows errors can happen here, see https://github.com/rust-lang/miri/issues/2123. + // (We assume there are no other MachineStop errors possible here.) + InterpError::MachineStop(_) => + { "vtable pointer does not have permission to read size and alignment" }, + ); + // FIXME: More checks for the vtable. } ty::Slice(..) | ty::Str => { let _len = try_validation!( @@ -345,7 +380,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' /// Check a reference or `Box`. fn check_safe_pointer( &mut self, - value: &OpTy<'tcx, M::Provenance>, + value: &OpTy<'tcx, M::PointerTag>, kind: &str, ) -> InterpResult<'tcx> { let value = try_validation!( @@ -410,9 +445,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' if let Some(ref mut ref_tracking) = self.ref_tracking { // Proceed recursively even for ZST, no reason to skip them! // `!` is a ZST and we want to validate it. - if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr) { + if let Ok((alloc_id, _offset, _tag)) = self.ecx.ptr_try_get_alloc_id(place.ptr) { // Special handling for pointers to statics (irrespective of their type). - let alloc_kind = self.ecx.tcx.try_get_global_alloc(alloc_id); + let alloc_kind = self.ecx.tcx.get_global_alloc(alloc_id); if let Some(GlobalAlloc::Static(did)) = alloc_kind { assert!(!self.ecx.tcx.is_thread_local_static(did)); assert!(self.ecx.tcx.is_static(did)); @@ -456,8 +491,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn read_scalar( &self, - op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, ScalarMaybeUninit> { Ok(try_validation!( self.ecx.read_scalar(op), self.path, @@ -467,8 +502,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn read_immediate_forced( &self, - op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Immediate> { + op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, Immediate> { Ok(*try_validation!( self.ecx.read_immediate_raw(op, /*force*/ true), self.path, @@ -480,7 +515,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' /// at that type. Return `true` if the type is indeed primitive. fn try_visit_primitive( &mut self, - value: &OpTy<'tcx, M::Provenance>, + value: &OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, bool> { // Go over all the primitive types let ty = value.layout.ty; @@ -517,13 +552,15 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' { "{:x}", value } expected { "initialized bytes" } ); } - // As a special exception we *do* match on a `Scalar` here, since we truly want - // to know its underlying representation (and *not* cast it to an integer). - let is_ptr = value.check_init().map_or(false, |v| matches!(v, Scalar::Ptr(..))); - if is_ptr { - throw_validation_failure!(self.path, - { "{:x}", value } expected { "plain (non-pointer) bytes" } - ) + if M::enforce_number_no_provenance(self.ecx) { + // As a special exception we *do* match on a `Scalar` here, since we truly want + // to know its underlying representation (and *not* cast it to an integer). + let is_ptr = value.check_init().map_or(false, |v| matches!(v, Scalar::Ptr(..))); + if is_ptr { + throw_validation_failure!(self.path, + { "{:x}", value } expected { "plain (non-pointer) bytes" } + ) + } } Ok(true) } @@ -566,13 +603,15 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // If we check references recursively, also check that this points to a function. if let Some(_) = self.ref_tracking { - let ptr = value.to_pointer(self.ecx)?; + let ptr = self.ecx.scalar_to_ptr(value)?; let _fn = try_validation!( self.ecx.get_ptr_fn(ptr), self.path, + err_ub!(DanglingIntPointer(0, _)) => + { "a null function pointer" }, err_ub!(DanglingIntPointer(..)) | err_ub!(InvalidFunctionPointer(..)) => - { "{ptr}" } expected { "a function pointer" }, + { "{:x}", value } expected { "a function pointer" }, ); // FIXME: Check if the signature matches } else { @@ -613,7 +652,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn visit_scalar( &mut self, - scalar: ScalarMaybeUninit, + scalar: ScalarMaybeUninit, scalar_layout: ScalarAbi, ) -> InterpResult<'tcx> { // We check `is_full_range` in a slightly complicated way because *if* we are checking @@ -696,7 +735,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> for ValidityVisitor<'rt, 'mir, 'tcx, M> { - type V = OpTy<'tcx, M::Provenance>; + type V = OpTy<'tcx, M::PointerTag>; #[inline(always)] fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> { @@ -705,7 +744,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> fn read_discriminant( &mut self, - op: &OpTy<'tcx, M::Provenance>, + op: &OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, VariantIdx> { self.with_elem(PathElem::EnumTag, move |this| { Ok(try_validation!( @@ -725,9 +764,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> #[inline] fn visit_field( &mut self, - old_op: &OpTy<'tcx, M::Provenance>, + old_op: &OpTy<'tcx, M::PointerTag>, field: usize, - new_op: &OpTy<'tcx, M::Provenance>, + new_op: &OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { let elem = self.aggregate_field_path_elem(old_op.layout, field); self.with_elem(elem, move |this| this.visit_value(new_op)) @@ -736,9 +775,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> #[inline] fn visit_variant( &mut self, - old_op: &OpTy<'tcx, M::Provenance>, + old_op: &OpTy<'tcx, M::PointerTag>, variant_id: VariantIdx, - new_op: &OpTy<'tcx, M::Provenance>, + new_op: &OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { let name = match old_op.layout.ty.kind() { ty::Adt(adt, _) => PathElem::Variant(adt.variant(variant_id).name), @@ -752,7 +791,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> #[inline(always)] fn visit_union( &mut self, - op: &OpTy<'tcx, M::Provenance>, + op: &OpTy<'tcx, M::PointerTag>, _fields: NonZeroUsize, ) -> InterpResult<'tcx> { // Special check preventing `UnsafeCell` inside unions in the inner part of constants. @@ -765,13 +804,13 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } #[inline] - fn visit_box(&mut self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { + fn visit_box(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { self.check_safe_pointer(op, "box")?; Ok(()) } #[inline] - fn visit_value(&mut self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { + fn visit_value(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { trace!("visit_value: {:?}, {:?}", *op, op.layout); // Check primitive types -- the leaves of our recursive descent. @@ -842,7 +881,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> fn visit_aggregate( &mut self, - op: &OpTy<'tcx, M::Provenance>, + op: &OpTy<'tcx, M::PointerTag>, fields: impl Iterator>, ) -> InterpResult<'tcx> { match op.layout.ty.kind() { @@ -904,7 +943,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> match alloc.check_bytes( alloc_range(Size::ZERO, size), /*allow_uninit*/ !M::enforce_number_init(self.ecx), - /*allow_ptr*/ false, + /*allow_ptr*/ !M::enforce_number_no_provenance(self.ecx), ) { // In the happy case, we needn't check anything else. Ok(()) => {} @@ -953,9 +992,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn validate_operand_internal( &self, - op: &OpTy<'tcx, M::Provenance>, + op: &OpTy<'tcx, M::PointerTag>, path: Vec, - ref_tracking: Option<&mut RefTracking, Vec>>, + ref_tracking: Option<&mut RefTracking, Vec>>, ctfe_mode: Option, ) -> InterpResult<'tcx> { trace!("validate_operand_internal: {:?}, {:?}", *op, op.layout.ty); @@ -992,9 +1031,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn const_validate_operand( &self, - op: &OpTy<'tcx, M::Provenance>, + op: &OpTy<'tcx, M::PointerTag>, path: Vec, - ref_tracking: &mut RefTracking, Vec>, + ref_tracking: &mut RefTracking, Vec>, ctfe_mode: CtfeValidationMode, ) -> InterpResult<'tcx> { self.validate_operand_internal(op, path, Some(ref_tracking), Some(ctfe_mode)) @@ -1004,7 +1043,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// `op` is assumed to cover valid memory if it is an indirect operand. /// It will error if the bits at the destination do not match the ones described by the layout. #[inline(always)] - pub fn validate_operand(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { + pub fn validate_operand(&self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { self.validate_operand_internal(op, vec![], None, None) } } diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index aee1f93b1a39c..5956b7e4cb91d 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -21,20 +21,20 @@ pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Sized { fn to_op_for_read( &self, ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>; + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; /// Makes this into an `OpTy`, in a potentially more expensive way that is good for projections. fn to_op_for_proj( &self, ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { self.to_op_for_read(ecx) } /// Creates this from an `OpTy`. /// /// If `to_op_for_proj` only ever produces `Indirect` operands, then this one is definitely `Indirect`. - fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self; + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self; /// Projects to the given enum variant. fn project_downcast( @@ -62,18 +62,18 @@ pub trait ValueMut<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Sized { fn to_op_for_read( &self, ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>; + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; /// Makes this into an `OpTy`, in a potentially more expensive way that is good for projections. fn to_op_for_proj( &self, ecx: &mut InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>; + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; /// Creates this from an `OpTy`. /// /// If `to_op_for_proj` only ever produces `Indirect` operands, then this one is definitely `Indirect`. - fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self; + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self; /// Projects to the given enum variant. fn project_downcast( @@ -95,7 +95,7 @@ pub trait ValueMut<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Sized { // So we have some copy-paste here. (We could have a macro but since we only have 2 types with this // double-impl, that would barely make the code shorter, if at all.) -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tcx, M::Provenance> { +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tcx, M::PointerTag> { #[inline(always)] fn layout(&self) -> TyAndLayout<'tcx> { self.layout @@ -105,12 +105,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tc fn to_op_for_read( &self, _ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { Ok(self.clone()) } #[inline(always)] - fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self { + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { op.clone() } @@ -134,7 +134,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tc } impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> - for OpTy<'tcx, M::Provenance> + for OpTy<'tcx, M::PointerTag> { #[inline(always)] fn layout(&self) -> TyAndLayout<'tcx> { @@ -145,7 +145,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> fn to_op_for_read( &self, _ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { Ok(self.clone()) } @@ -153,12 +153,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> fn to_op_for_proj( &self, _ecx: &mut InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { Ok(self.clone()) } #[inline(always)] - fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self { + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { op.clone() } @@ -182,7 +182,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> } impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> - for MPlaceTy<'tcx, M::Provenance> + for MPlaceTy<'tcx, M::PointerTag> { #[inline(always)] fn layout(&self) -> TyAndLayout<'tcx> { @@ -193,12 +193,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> fn to_op_for_read( &self, _ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { Ok(self.into()) } #[inline(always)] - fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self { + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { // assert is justified because our `to_op_for_read` only ever produces `Indirect` operands. op.assert_mem_place() } @@ -223,7 +223,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> } impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> - for MPlaceTy<'tcx, M::Provenance> + for MPlaceTy<'tcx, M::PointerTag> { #[inline(always)] fn layout(&self) -> TyAndLayout<'tcx> { @@ -234,7 +234,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> fn to_op_for_read( &self, _ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { Ok(self.into()) } @@ -242,12 +242,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> fn to_op_for_proj( &self, _ecx: &mut InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { Ok(self.into()) } #[inline(always)] - fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self { + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { // assert is justified because our `to_op_for_proj` only ever produces `Indirect` operands. op.assert_mem_place() } @@ -272,7 +272,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> } impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> - for PlaceTy<'tcx, M::Provenance> + for PlaceTy<'tcx, M::PointerTag> { #[inline(always)] fn layout(&self) -> TyAndLayout<'tcx> { @@ -283,7 +283,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> fn to_op_for_read( &self, ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { // We `force_allocation` here so that `from_op` below can work. ecx.place_to_op(self) } @@ -292,13 +292,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> fn to_op_for_proj( &self, ecx: &mut InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { // We `force_allocation` here so that `from_op` below can work. Ok(ecx.force_allocation(self)?.into()) } #[inline(always)] - fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self { + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { // assert is justified because our `to_op` only ever produces `Indirect` operands. op.assert_mem_place().into() } @@ -336,7 +336,7 @@ macro_rules! make_value_visitor { #[inline(always)] fn read_discriminant( &mut self, - op: &OpTy<'tcx, M::Provenance>, + op: &OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, VariantIdx> { Ok(self.ecx().read_discriminant(op)?.1) } @@ -425,7 +425,7 @@ macro_rules! make_value_visitor { // unsized values are never immediate, so we can assert_mem_place let op = v.to_op_for_read(self.ecx())?; let dest = op.assert_mem_place(); - let inner_mplace = self.ecx().unpack_dyn_trait(&dest)?; + let inner_mplace = self.ecx().unpack_dyn_trait(&dest)?.1; trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout); // recurse with the inner type return self.visit_field(&v, 0, &$value_trait::from_op(&inner_mplace.into())); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 3380226164460..1d083b0bf8268 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -23,8 +23,8 @@ use rustc_trait_selection::traits::SelectionContext; use super::ConstCx; use crate::errors::{ - MutDerefErr, NonConstOpErr, PanicNonStrErr, RawPtrToIntErr, StaticAccessErr, - TransientMutBorrowErr, TransientMutBorrowErrRaw, + MutDerefErr, NonConstOpErr, PanicNonStrErr, RawPtrComparisonErr, RawPtrToIntErr, + StaticAccessErr, TransientMutBorrowErr, TransientMutBorrowErrRaw, }; use crate::util::{call_kind, CallDesugaringKind, CallKind}; @@ -654,10 +654,10 @@ pub struct RawPtrComparison; impl<'tcx> NonConstOp<'tcx> for RawPtrComparison { fn build_error( &self, - _: &ConstCx<'_, 'tcx>, + ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - span_bug!(span, "raw ptr comparison should already be caught in the trait system"); + ccx.tcx.sess.create_err(RawPtrComparisonErr { span }) } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index e099445117225..29464cf8c4e4f 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -226,7 +226,7 @@ impl Qualif for CustomEq { // because that component may be part of an enum variant (e.g., // `Option::::Some`), in which case some values of this type may be // structural-match (`Option::None`). - traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty).is_some() + traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty, true).is_some() } fn in_adt_inherently<'tcx>( diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 5c641f54f686d..2a801d0e70269 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -9,7 +9,7 @@ doctest = false [dependencies] arrayvec = { version = "0.7", default-features = false } ena = "0.14" -indexmap = { version = "1.9.1" } +indexmap = { version = "1.8.2" } tracing = "0.1" jobserver_crate = { version = "0.1.13", package = "jobserver" } rustc_serialize = { path = "../rustc_serialize" } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 265f45b72d1bf..0a2d2b4070904 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -61,10 +61,12 @@ pub mod sip128; pub mod small_c_str; pub mod small_str; pub mod snapshot_map; +pub mod stable_map; pub mod svh; pub use ena::snapshot_vec; pub mod memmap; pub mod sorted_map; +pub mod stable_set; #[macro_use] pub mod stable_hasher; mod atomic_ref; diff --git a/compiler/rustc_data_structures/src/stable_map.rs b/compiler/rustc_data_structures/src/stable_map.rs new file mode 100644 index 0000000000000..670452d0d8c5a --- /dev/null +++ b/compiler/rustc_data_structures/src/stable_map.rs @@ -0,0 +1,100 @@ +pub use rustc_hash::FxHashMap; +use std::borrow::Borrow; +use std::collections::hash_map::Entry; +use std::fmt; +use std::hash::Hash; + +/// A deterministic wrapper around FxHashMap that does not provide iteration support. +/// +/// It supports insert, remove, get and get_mut functions from FxHashMap. +/// It also allows to convert hashmap to a sorted vector with the method `into_sorted_vector()`. +#[derive(Clone)] +pub struct StableMap { + base: FxHashMap, +} + +impl Default for StableMap +where + K: Eq + Hash, +{ + fn default() -> StableMap { + StableMap::new() + } +} + +impl fmt::Debug for StableMap +where + K: Eq + Hash + fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.base) + } +} + +impl PartialEq for StableMap +where + K: Eq + Hash, + V: PartialEq, +{ + fn eq(&self, other: &StableMap) -> bool { + self.base == other.base + } +} + +impl Eq for StableMap +where + K: Eq + Hash, + V: Eq, +{ +} + +impl StableMap +where + K: Eq + Hash, +{ + pub fn new() -> StableMap { + StableMap { base: FxHashMap::default() } + } + + pub fn into_sorted_vector(self) -> Vec<(K, V)> + where + K: Ord + Copy, + { + let mut vector = self.base.into_iter().collect::>(); + vector.sort_unstable_by_key(|pair| pair.0); + vector + } + + pub fn entry(&mut self, k: K) -> Entry<'_, K, V> { + self.base.entry(k) + } + + pub fn get(&self, k: &Q) -> Option<&V> + where + K: Borrow, + Q: Hash + Eq, + { + self.base.get(k) + } + + pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> + where + K: Borrow, + Q: Hash + Eq, + { + self.base.get_mut(k) + } + + pub fn insert(&mut self, k: K, v: V) -> Option { + self.base.insert(k, v) + } + + pub fn remove(&mut self, k: &Q) -> Option + where + K: Borrow, + Q: Hash + Eq, + { + self.base.remove(k) + } +} diff --git a/compiler/rustc_data_structures/src/stable_set.rs b/compiler/rustc_data_structures/src/stable_set.rs new file mode 100644 index 0000000000000..c7ca74f5fbd9d --- /dev/null +++ b/compiler/rustc_data_structures/src/stable_set.rs @@ -0,0 +1,77 @@ +pub use rustc_hash::FxHashSet; +use std::borrow::Borrow; +use std::fmt; +use std::hash::Hash; + +/// A deterministic wrapper around FxHashSet that does not provide iteration support. +/// +/// It supports insert, remove, get functions from FxHashSet. +/// It also allows to convert hashset to a sorted vector with the method `into_sorted_vector()`. +#[derive(Clone)] +pub struct StableSet { + base: FxHashSet, +} + +impl Default for StableSet +where + T: Eq + Hash, +{ + fn default() -> StableSet { + StableSet::new() + } +} + +impl fmt::Debug for StableSet +where + T: Eq + Hash + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.base) + } +} + +impl PartialEq> for StableSet +where + T: Eq + Hash, +{ + fn eq(&self, other: &StableSet) -> bool { + self.base == other.base + } +} + +impl Eq for StableSet where T: Eq + Hash {} + +impl StableSet { + pub fn new() -> StableSet { + StableSet { base: FxHashSet::default() } + } + + pub fn into_sorted_vector(self) -> Vec + where + T: Ord, + { + let mut vector = self.base.into_iter().collect::>(); + vector.sort_unstable(); + vector + } + + pub fn get(&self, value: &Q) -> Option<&T> + where + T: Borrow, + Q: Hash + Eq, + { + self.base.get(value) + } + + pub fn insert(&mut self, value: T) -> bool { + self.base.insert(value) + } + + pub fn remove(&mut self, value: &Q) -> bool + where + T: Borrow, + Q: Hash + Eq, + { + self.base.remove(value) + } +} diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 53ae913f94f12..f5b059793cf4b 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -123,7 +123,8 @@ impl Callbacks for TimePassesCallbacks { fn config(&mut self, config: &mut interface::Config) { // If a --prints=... option has been given, we don't print the "total" // time because it will mess up the --prints output. See #64339. - self.time_passes = config.opts.prints.is_empty() && config.opts.time_passes(); + self.time_passes = config.opts.prints.is_empty() + && (config.opts.unstable_opts.time_passes || config.opts.unstable_opts.time); config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath; } } @@ -248,7 +249,7 @@ fn run_compiler( if sopts.describe_lints { let mut lint_store = rustc_lint::new_lint_store( sopts.unstable_opts.no_interleave_lints, - compiler.session().enable_internal_lints(), + compiler.session().unstable_options(), ); let registered_lints = if let Some(register_lints) = compiler.register_lints() { diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 854625579ee7b..97766b8368ab6 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -559,7 +559,7 @@ E0790: include_str!("./error_codes/E0790.md"), // E0273, // on_unimplemented #1 // E0274, // on_unimplemented #2 // E0278, // requirement is not satisfied -// E0279, + E0279, // requirement is not satisfied E0280, // requirement is not satisfied // E0285, // overflow evaluation builtin bounds // E0296, // replaced with a generic attribute input check diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index b17eb9c2d260e..04c67cf8ff73a 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -149,116 +149,3 @@ passes-cold = {passes-should-be-applied-to-fn} passes-link = attribute should be applied to an `extern` block with non-Rust ABI .warn = {-passes-previously-accepted} .label = not an `extern` block - -passes-link-name = attribute should be applied to a foreign function or static - .warn = {-passes-previously-accepted} - .label = not a foreign function or static - .help = try `#[link(name = "{$value}")]` instead - -passes-no-link = attribute should be applied to an `extern crate` item - .label = not an `extern crate` item - -passes-export-name = attribute should be applied to a free function, impl method or static - .label = not a free function, impl method or static - -passes-rustc-layout-scalar-valid-range-not-struct = attribute should be applied to a struct - .label = not a struct - -passes-rustc-layout-scalar-valid-range-arg = expected exactly one integer literal argument - -passes-rustc-legacy-const-generics-only = #[rustc_legacy_const_generics] functions must only have const generics - .label = non-const generic parameter - -passes-rustc-legacy-const-generics-index = #[rustc_legacy_const_generics] must have one index for each generic parameter - .label = generic parameters - -passes-rustc-legacy-const-generics-index-exceed = index exceeds number of arguments - .label = there {$arg_count -> - [one] is - *[other] are - } only {$arg_count} {$arg_count -> - [one] argument - *[other] arguments - } - -passes-rustc-legacy-const-generics-index-negative = arguments should be non-negative integers - -passes-rustc-dirty-clean = attribute requires -Z query-dep-graph to be enabled - -passes-link-section = attribute should be applied to a function or static - .warn = {-passes-previously-accepted} - .label = not a function or static - -passes-no-mangle-foreign = `#[no_mangle]` has no effect on a foreign {$foreign_item_kind} - .warn = {-passes-previously-accepted} - .label = foreign {$foreign_item_kind} - .note = symbol names in extern blocks are not mangled - .suggestion = remove this attribute - -passes-no-mangle = attribute should be applied to a free function, impl method or static - .warn = {-passes-previously-accepted} - .label = not a free function, impl method or static - -passes-repr-ident = meta item in `repr` must be an identifier - -passes-repr-conflicting = conflicting representation hints - -passes-used-static = attribute must be applied to a `static` variable - -passes-used-compiler-linker = `used(compiler)` and `used(linker)` can't be used together - -passes-allow-internal-unstable = attribute should be applied to a macro - .label = not a macro - -passes-debug-visualizer-placement = attribute should be applied to a module - -passes-debug-visualizer-invalid = invalid argument - .note-1 = expected: `natvis_file = "..."` - .note-2 = OR - .note-3 = expected: `gdb_script_file = "..."` - -passes-rustc-allow-const-fn-unstable = attribute should be applied to `const fn` - .label = not a `const fn` - -passes-rustc-std-internal-symbol = attribute should be applied to functions or statics - .label = not a function or static - -passes-const-trait = attribute should be applied to a trait - -passes-stability-promotable = attribute cannot be applied to an expression - -passes-deprecated = attribute is ignored here - -passes-macro-use = `#[{$name}]` only has an effect on `extern crate` and modules - -passes-macro-export = `#[macro_export]` only has an effect on macro definitions - -passes-plugin-registrar = `#[plugin_registrar]` only has an effect on functions - -passes-unused-empty-lints-note = attribute `{$name}` with an empty list has no effect - -passes-unused-no-lints-note = attribute `{$name}` without any lints has no effect - -passes-unused-default-method-body-const-note = - `default_method_body_is_const` has been replaced with `#[const_trait]` on traits - -passes-unused = unused attribute - .suggestion = remove this attribute - -passes-non-exported-macro-invalid-attrs = attribute should be applied to function or closure - .label = not a function or closure - -passes-unused-duplicate = unused attribute - .suggestion = remove this attribute - .note = attribute also specified here - .warn = {-passes-previously-accepted} - -passes-unused-multiple = multiple `{$name}` attributes - .suggestion = remove this attribute - .note = attribute also specified here - -passes-rustc-lint-opt-ty = `#[rustc_lint_opt_ty]` should be applied to a struct - .label = not a struct - -passes-rustc-lint-opt-deny-field-access = `#[rustc_lint_opt_deny_field_access]` should be applied to a field - .label = not a field diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 2ac5c1960cd56..6b961eaeb42af 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -299,7 +299,7 @@ impl DiagnosticMessage { /// - If `self` is non-translatable then return `self`'s message. pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self { let attr = match sub { - SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s), + SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s.clone()), SubdiagnosticMessage::FluentIdentifier(id) => { return DiagnosticMessage::FluentIdentifier(id, None); } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 2a4f609a2d8a4..7d7f3e1833576 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -3,7 +3,7 @@ use crate::{ CodeSuggestion, DiagnosticMessage, EmissionGuarantee, Level, LintDiagnosticBuilder, MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, }; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_map::FxHashMap; use rustc_error_messages::FluentValue; use rustc_hir as hir; use rustc_lint_defs::{Applicability, LintExpectationId}; @@ -390,17 +390,18 @@ impl Diagnostic { expected: DiagnosticStyledString, found: DiagnosticStyledString, ) -> &mut Self { - let mut msg: Vec<_> = vec![("required when trying to coerce from type `", Style::NoStyle)]; + let mut msg: Vec<_> = + vec![("required when trying to coerce from type `".to_string(), Style::NoStyle)]; msg.extend(expected.0.iter().map(|x| match *x { - StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle), - StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight), + StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), })); - msg.push(("` to type '", Style::NoStyle)); + msg.push(("` to type '".to_string(), Style::NoStyle)); msg.extend(found.0.iter().map(|x| match *x { - StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle), - StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight), + StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), })); - msg.push(("`", Style::NoStyle)); + msg.push(("`".to_string(), Style::NoStyle)); // For now, just attach these as notes self.highlighted_note(msg); diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 6e093811fcf6e..e1f19064d522f 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -8,7 +8,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, Attribute, HasAttrs, Item, NodeId, PatKind}; use rustc_attr::{self as attr, Deprecation, Stability}; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, PResult}; use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; @@ -985,7 +985,7 @@ pub struct ExtCtxt<'a> { /// Error recovery mode entered when expansion is stuck /// (or during eager expansion, but that's a hack). pub force_mode: bool, - pub expansions: FxIndexMap>, + pub expansions: FxHashMap>, /// Used for running pre-expansion lints on freshly loaded modules. pub(super) lint_store: LintStoreExpandDyn<'a>, /// Used for storing lints generated during expansion, like `NAMED_ARGUMENTS_USED_POSITIONALLY` @@ -1020,7 +1020,7 @@ impl<'a> ExtCtxt<'a> { is_trailing_mac: false, }, force_mode: false, - expansions: FxIndexMap::default(), + expansions: FxHashMap::default(), expanded_inert_attrs: MarkedAttrs::new(), buffered_early_lint: vec![], } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index ccc29adc0153e..2b941ec68098a 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -129,7 +129,7 @@ fn get_features( .span_suggestion( mi.span(), "expected just one word", - ident.name, + format!("{}", ident.name), Applicability::MaybeIncorrect, ) .emit(); diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 20d01b6dc2688..03b75d809a088 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(rustc::potential_query_instability)] #![feature(array_windows)] #![feature(associated_type_bounds)] #![feature(associated_type_defaults)] diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 3d44c408d8f1a..3e9ddd6aec075 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -13,7 +13,7 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, TransparencyError}; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_feature::Features; use rustc_lint_defs::builtin::{ @@ -198,7 +198,7 @@ fn macro_rules_dummy_expander<'cx>( DummyResult::any(span) } -fn trace_macros_note(cx_expansions: &mut FxIndexMap>, sp: Span, message: String) { +fn trace_macros_note(cx_expansions: &mut FxHashMap>, sp: Span, message: String) { let sp = sp.macro_backtrace().last().map_or(sp, |trace| trace.call_site); cx_expansions.entry(sp).or_default().push(message); } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 3037855ae28a6..fdd8dc93fc1a5 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -512,18 +512,7 @@ fn out_of_bounds_err<'a>( span: Span, ty: &str, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - let msg = if max == 0 { - format!( - "meta-variable expression `{ty}` with depth parameter \ - must be called inside of a macro repetition" - ) - } else { - format!( - "depth parameter on meta-variable expression `{ty}` \ - must be less than {max}" - ) - }; - cx.struct_span_err(span, &msg) + cx.struct_span_err(span, &format!("{ty} depth must be less than {max}")) } fn transcribe_metavar_expr<'a>( diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 0e73d8fd7f600..c806df8214586 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -532,9 +532,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), - rustc_attr!(rustc_reallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), - rustc_attr!(rustc_deallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), - rustc_attr!(rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), gated!( alloc_error_handler, Normal, template!(Word), WarnFollowing, experimental!(alloc_error_handler) @@ -619,12 +616,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Used by the `rustc::untranslatable_diagnostic` and `rustc::diagnostic_outside_of_impl` lints // to assist in changes to diagnostic APIs. rustc_attr!(rustc_lint_diagnostics, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), - // Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions` - // types (as well as any others in future). - rustc_attr!(rustc_lint_opt_ty, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), - // Used by the `rustc::bad_opt_access` lint on fields - // types (as well as any others in future). - rustc_attr!(rustc_lint_opt_deny_field_access, Normal, template!(List: "message"), WarnFollowing, INTERNAL_UNSTABLE), // ========================================================================== // Internal attributes, Const related: diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index be5b7eccbafb2..d0893cd09d8db 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -713,7 +713,7 @@ impl Res { } /// Resolution for a lifetime appearing in a type. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug)] pub enum LifetimeRes { /// Successfully linked the lifetime to a generic parameter. Param { @@ -738,8 +738,13 @@ pub enum LifetimeRes { binder: NodeId, }, /// This variant is used for anonymous lifetimes that we did not resolve during - /// late resolution. Those lifetimes will be inferred by typechecking. - Infer, + /// late resolution. Shifting the work to the HIR lifetime resolver. + Anonymous { + /// Id of the introducing place. See `Param`. + binder: NodeId, + /// Whether this lifetime was spelled or elided. + elided: bool, + }, /// Explicit `'static` lifetime. Static, /// Resolution failure. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f71400898e60b..48a41c8bd245a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -90,6 +90,9 @@ pub enum LifetimeName { /// User-given names or fresh (synthetic) names. Param(LocalDefId, ParamName), + /// User wrote nothing (e.g., the lifetime in `&u32`). + Implicit, + /// Implicit lifetime in a context like `dyn Foo`. This is /// distinguished from implicit lifetimes elsewhere because the /// lifetime that they default to must appear elsewhere within the @@ -107,9 +110,8 @@ pub enum LifetimeName { /// that was already reported. Error, - /// User wrote an anonymous lifetime, either `'_` or nothing. - /// The semantics of this lifetime should be inferred by typechecking code. - Infer, + /// User wrote specifies `'_`. + Underscore, /// User wrote `'static`. Static, @@ -118,8 +120,10 @@ pub enum LifetimeName { impl LifetimeName { pub fn ident(&self) -> Ident { match *self { - LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Error => Ident::empty(), - LifetimeName::Infer => Ident::with_dummy_span(kw::UnderscoreLifetime), + LifetimeName::ImplicitObjectLifetimeDefault + | LifetimeName::Implicit + | LifetimeName::Error => Ident::empty(), + LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime), LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime), LifetimeName::Param(_, param_name) => param_name.ident(), } @@ -128,7 +132,8 @@ impl LifetimeName { pub fn is_anonymous(&self) -> bool { match *self { LifetimeName::ImplicitObjectLifetimeDefault - | LifetimeName::Infer + | LifetimeName::Implicit + | LifetimeName::Underscore | LifetimeName::Param(_, ParamName::Fresh) | LifetimeName::Error => true, LifetimeName::Static | LifetimeName::Param(..) => false, @@ -137,7 +142,9 @@ impl LifetimeName { pub fn is_elided(&self) -> bool { match self { - LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Infer => true, + LifetimeName::ImplicitObjectLifetimeDefault + | LifetimeName::Implicit + | LifetimeName::Underscore => true, // It might seem surprising that `Fresh` counts as // *not* elided -- but this is because, as far as the code @@ -947,16 +954,6 @@ pub struct Block<'hir> { pub targeted_by_break: bool, } -impl<'hir> Block<'hir> { - pub fn innermost_block(&self) -> &Block<'hir> { - let mut block = self; - while let Some(Expr { kind: ExprKind::Block(inner_block, _), .. }) = block.expr { - block = inner_block; - } - block - } -} - #[derive(Debug, HashStable_Generic)] pub struct Pat<'hir> { #[stable_hasher(ignore)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 640974115b926..d00b65da7e6a5 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -496,8 +496,9 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime | LifetimeName::Param(_, ParamName::Error) | LifetimeName::Static | LifetimeName::Error + | LifetimeName::Implicit | LifetimeName::ImplicitObjectLifetimeDefault - | LifetimeName::Infer => {} + | LifetimeName::Underscore => {} } } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 13b3e954e1f58..b0bfac8e1f5ec 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -11,7 +11,7 @@ use crate::def_id::DefId; use crate::{MethodKind, Target}; use rustc_ast as ast; -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::HashStable_Generic; use rustc_span::symbol::{kw, sym, Symbol}; @@ -134,8 +134,8 @@ macro_rules! language_item_table { } /// A mapping from the name of the lang item to its order and the form it must be of. - pub static ITEM_REFS: LazyLock> = LazyLock::new(|| { - let mut item_refs = FxIndexMap::default(); + pub static ITEM_REFS: LazyLock> = LazyLock::new(|| { + let mut item_refs = FxHashMap::default(); $( item_refs.insert($module::$name, (LangItem::$variant as usize, $target)); )* item_refs }); diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index 93112199b6030..b30076100bb2c 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -1,7 +1,7 @@ use crate::def::{CtorOf, DefKind, Res}; use crate::def_id::DefId; use crate::hir::{self, HirId, PatKind}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::Ident; use rustc_span::Span; diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs index b6a85c0472e02..dad22725511ed 100644 --- a/compiler/rustc_hir/src/weak_lang_items.rs +++ b/compiler/rustc_hir/src/weak_lang_items.rs @@ -4,7 +4,7 @@ use crate::def_id::DefId; use crate::{lang_items, LangItem, LanguageItems}; use rustc_ast as ast; -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::stable_map::StableMap; use rustc_span::symbol::{sym, Symbol}; use std::sync::LazyLock; @@ -12,8 +12,8 @@ use std::sync::LazyLock; macro_rules! weak_lang_items { ($($name:ident, $item:ident, $sym:ident;)*) => ( -pub static WEAK_ITEMS_REFS: LazyLock> = LazyLock::new(|| { - let mut map = FxIndexMap::default(); +pub static WEAK_ITEMS_REFS: LazyLock> = LazyLock::new(|| { + let mut map = StableMap::default(); $(map.insert(sym::$name, LangItem::$item);)* map }); diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs index 89d419bc8e90f..00aefac645f18 100644 --- a/compiler/rustc_incremental/src/assert_module_sources.rs +++ b/compiler/rustc_incremental/src/assert_module_sources.rs @@ -23,7 +23,7 @@ //! was re-used. use rustc_ast as ast; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::mir::mono::CodegenUnitNameBuilder; use rustc_middle::ty::TyCtxt; diff --git a/compiler/rustc_incremental/src/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs index 2f1853c441eee..1b184eca964c3 100644 --- a/compiler/rustc_incremental/src/persist/work_product.rs +++ b/compiler/rustc_incremental/src/persist/work_product.rs @@ -3,7 +3,7 @@ //! [work products]: WorkProduct use crate::persist::fs::*; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_map::FxHashMap; use rustc_fs_util::link_or_copy; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 30ff364210da8..1a55519d7b120 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -234,9 +234,7 @@ impl IndexVec { self.raw.get_mut(index.index()) } - /// Returns mutable references to two distinct elements, `a` and `b`. - /// - /// Panics if `a == b`. + /// Returns mutable references to two distinct elements, a and b. Panics if a == b. #[inline] pub fn pick2_mut(&mut self, a: I, b: I) -> (&mut T, &mut T) { let (ai, bi) = (a.index(), b.index()); @@ -251,9 +249,7 @@ impl IndexVec { } } - /// Returns mutable references to three distinct elements. - /// - /// Panics if the elements are not distinct. + /// Returns mutable references to three distinct elements or panics otherwise. #[inline] pub fn pick3_mut(&mut self, a: I, b: I, c: I) -> (&mut T, &mut T, &mut T) { let (ai, bi, ci) = (a.index(), b.index(), c.index()); diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 130214a653f7c..ce2698ef44cd4 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -65,7 +65,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Self { tcx: self.tcx, defining_use_anchor: self.defining_use_anchor, - considering_regions: self.considering_regions, in_progress_typeck_results: self.in_progress_typeck_results, inner: self.inner.clone(), skip_leak_check: self.skip_leak_check.clone(), diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 39faed0bf365c..d7505717bf3d2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -237,14 +237,12 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( span: Span, hidden_ty: Ty<'tcx>, hidden_region: ty::Region<'tcx>, - opaque_ty: ty::OpaqueTypeKey<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let opaque_ty = tcx.mk_opaque(opaque_ty.def_id.to_def_id(), opaque_ty.substs); let mut err = struct_span_err!( tcx.sess, span, E0700, - "hidden type for `{opaque_ty}` captures lifetime that does not appear in bounds", + "hidden type for `impl Trait` captures lifetime that does not appear in bounds", ); // Explain the region we are capturing. @@ -318,6 +316,37 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( err } +/// Structurally compares two types, modulo any inference variables. +/// +/// Returns `true` if two types are equal, or if one type is an inference variable compatible +/// with the other type. A TyVar inference type is compatible with any type, and an IntVar or +/// FloatVar inference type are compatible with themselves or their concrete types (Int and +/// Float types, respectively). When comparing two ADTs, these rules apply recursively. +pub fn same_type_modulo_infer<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { + match (&a.kind(), &b.kind()) { + (&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => { + if did_a != did_b { + return false; + } + + substs_a.types().zip(substs_b.types()).all(|(a, b)| same_type_modulo_infer(a, b)) + } + (&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_))) + | (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Int(_) | &ty::Infer(ty::InferTy::IntVar(_))) + | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_))) + | ( + &ty::Infer(ty::InferTy::FloatVar(_)), + &ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)), + ) + | (&ty::Infer(ty::InferTy::TyVar(_)), _) + | (_, &ty::Infer(ty::InferTy::TyVar(_))) => true, + (&ty::Ref(_, ty_a, mut_a), &ty::Ref(_, ty_b, mut_b)) => { + mut_a == mut_b && same_type_modulo_infer(*ty_a, *ty_b) + } + _ => a == b, + } +} + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_region_errors( &self, @@ -616,16 +645,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.span_label(span, "expected due to this"); } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - arm_block_id, - arm_span, - arm_ty, - prior_arm_block_id, - prior_arm_span, - prior_arm_ty, + semi_span, source, ref prior_arms, + last_ty, scrut_hir_id, opt_suggest_box_span, + arm_span, scrut_span, .. }) => match source { @@ -656,10 +682,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } _ => { - // `prior_arm_ty` can be `!`, `expected` will have better info when present. + // `last_ty` can be `!`, `expected` will have better info when present. let t = self.resolve_vars_if_possible(match exp_found { Some(ty::error::ExpectedFound { expected, .. }) => expected, - _ => prior_arm_ty, + _ => last_ty, }); let source_map = self.tcx.sess.source_map(); let mut any_multiline_arm = source_map.is_multiline(arm_span); @@ -684,15 +710,37 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; let msg = "`match` arms have incompatible types"; err.span_label(outer_error_span, msg); - self.suggest_remove_semi_or_return_binding( - err, - prior_arm_block_id, - prior_arm_ty, - prior_arm_span, - arm_block_id, - arm_ty, - arm_span, - ); + if let Some((sp, boxed)) = semi_span { + if let (StatementAsExpression::NeedsBoxing, [.., prior_arm]) = + (boxed, &prior_arms[..]) + { + err.multipart_suggestion( + "consider removing this semicolon and boxing the expressions", + vec![ + (prior_arm.shrink_to_lo(), "Box::new(".to_string()), + (prior_arm.shrink_to_hi(), ")".to_string()), + (arm_span.shrink_to_lo(), "Box::new(".to_string()), + (arm_span.shrink_to_hi(), ")".to_string()), + (sp, String::new()), + ], + Applicability::HasPlaceholders, + ); + } else if matches!(boxed, StatementAsExpression::NeedsBoxing) { + err.span_suggestion_short( + sp, + "consider removing this semicolon and boxing the expressions", + "", + Applicability::MachineApplicable, + ); + } else { + err.span_suggestion_short( + sp, + "consider removing this semicolon", + "", + Applicability::MachineApplicable, + ); + } + } if let Some(ret_sp) = opt_suggest_box_span { // Get return type span and point to it. self.suggest_boxing_for_return_impl_trait( @@ -704,33 +752,43 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } }, ObligationCauseCode::IfExpression(box IfExpressionCause { - then_id, - else_id, - then_ty, - else_ty, - outer_span, + then, + else_sp, + outer, + semicolon, opt_suggest_box_span, }) => { - let then_span = self.find_block_span_from_hir_id(then_id); - let else_span = self.find_block_span_from_hir_id(then_id); - err.span_label(then_span, "expected because of this"); - if let Some(sp) = outer_span { + err.span_label(then, "expected because of this"); + if let Some(sp) = outer { err.span_label(sp, "`if` and `else` have incompatible types"); } - self.suggest_remove_semi_or_return_binding( - err, - Some(then_id), - then_ty, - then_span, - Some(else_id), - else_ty, - else_span, - ); + if let Some((sp, boxed)) = semicolon { + if matches!(boxed, StatementAsExpression::NeedsBoxing) { + err.multipart_suggestion( + "consider removing this semicolon and boxing the expression", + vec![ + (then.shrink_to_lo(), "Box::new(".to_string()), + (then.shrink_to_hi(), ")".to_string()), + (else_sp.shrink_to_lo(), "Box::new(".to_string()), + (else_sp.shrink_to_hi(), ")".to_string()), + (sp, String::new()), + ], + Applicability::MachineApplicable, + ); + } else { + err.span_suggestion_short( + sp, + "consider removing this semicolon", + "", + Applicability::MachineApplicable, + ); + } + } if let Some(ret_sp) = opt_suggest_box_span { self.suggest_boxing_for_return_impl_trait( err, ret_sp, - [then_span, else_span].into_iter(), + [then, else_sp].into_iter(), ); } } @@ -750,56 +808,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - fn suggest_remove_semi_or_return_binding( - &self, - err: &mut Diagnostic, - first_id: Option, - first_ty: Ty<'tcx>, - first_span: Span, - second_id: Option, - second_ty: Ty<'tcx>, - second_span: Span, - ) { - let remove_semicolon = - [(first_id, second_ty), (second_id, first_ty)].into_iter().find_map(|(id, ty)| { - let hir::Node::Block(blk) = self.tcx.hir().get(id?) else { return None }; - self.could_remove_semicolon(blk, ty) - }); - match remove_semicolon { - Some((sp, StatementAsExpression::NeedsBoxing)) => { - err.multipart_suggestion( - "consider removing this semicolon and boxing the expressions", - vec![ - (first_span.shrink_to_lo(), "Box::new(".to_string()), - (first_span.shrink_to_hi(), ")".to_string()), - (second_span.shrink_to_lo(), "Box::new(".to_string()), - (second_span.shrink_to_hi(), ")".to_string()), - (sp, String::new()), - ], - Applicability::MachineApplicable, - ); - } - Some((sp, StatementAsExpression::CorrectType)) => { - err.span_suggestion_short( - sp, - "consider removing this semicolon", - "", - Applicability::MachineApplicable, - ); - } - None => { - for (id, ty) in [(first_id, second_ty), (second_id, first_ty)] { - if let Some(id) = id - && let hir::Node::Block(blk) = self.tcx.hir().get(id) - && self.consider_returning_binding(blk, ty, err) - { - break; - } - } - } - } - } - fn suggest_boxing_for_return_impl_trait( &self, err: &mut Diagnostic, @@ -1715,14 +1723,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; debug!("exp_found {:?} terr {:?} cause.code {:?}", exp_found, terr, cause.code()); if let Some(exp_found) = exp_found { - let should_suggest_fixes = - if let ObligationCauseCode::Pattern { root_ty, .. } = cause.code() { - // Skip if the root_ty of the pattern is not the same as the expected_ty. - // If these types aren't equal then we've probably peeled off a layer of arrays. - self.same_type_modulo_infer(*root_ty, exp_found.expected) - } else { - true - }; + let should_suggest_fixes = if let ObligationCauseCode::Pattern { root_ty, .. } = + cause.code() + { + // Skip if the root_ty of the pattern is not the same as the expected_ty. + // If these types aren't equal then we've probably peeled off a layer of arrays. + same_type_modulo_infer(self.resolve_vars_if_possible(*root_ty), exp_found.expected) + } else { + true + }; if should_suggest_fixes { self.suggest_tuple_pattern(cause, &exp_found, diag); @@ -1777,7 +1786,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .filter_map(|variant| { let sole_field = &variant.fields[0]; let sole_field_ty = sole_field.ty(self.tcx, substs); - if self.same_type_modulo_infer(sole_field_ty, exp_found.found) { + if same_type_modulo_infer(sole_field_ty, exp_found.found) { let variant_path = with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id)); // FIXME #56861: DRYer prelude filtering @@ -1885,7 +1894,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { exp_span, exp_found.expected, exp_found.found, ); - if let ObligationCauseCode::CompareImplItemObligation { .. } = cause.code() { + if let ObligationCauseCode::CompareImplMethodObligation { .. } = cause.code() { return; } @@ -1893,15 +1902,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.get_impl_future_output_ty(exp_found.expected).map(Binder::skip_binder), self.get_impl_future_output_ty(exp_found.found).map(Binder::skip_binder), ) { - (Some(exp), Some(found)) if self.same_type_modulo_infer(exp, found) => match cause - .code() - { - ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => { - let then_span = self.find_block_span_from_hir_id(*then_id); + (Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match cause.code() { + ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => { diag.multipart_suggestion( "consider `await`ing on both `Future`s", vec![ - (then_span.shrink_to_hi(), ".await".to_string()), + (then.shrink_to_hi(), ".await".to_string()), (exp_span.shrink_to_hi(), ".await".to_string()), ], Applicability::MaybeIncorrect, @@ -1928,7 +1934,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { diag.help("consider `await`ing on both `Future`s"); } }, - (_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => { + (_, Some(ty)) if same_type_modulo_infer(exp_found.expected, ty) => { diag.span_suggestion_verbose( exp_span.shrink_to_hi(), "consider `await`ing on the `Future`", @@ -1936,20 +1942,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } - (Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code() - { - ObligationCauseCode::Pattern { span: Some(then_span), .. } => { + (Some(ty), _) if same_type_modulo_infer(ty, exp_found.found) => match cause.code() { + ObligationCauseCode::Pattern { span: Some(span), .. } + | ObligationCauseCode::IfExpression(box IfExpressionCause { then: span, .. }) => { diag.span_suggestion_verbose( - then_span.shrink_to_hi(), - "consider `await`ing on the `Future`", - ".await", - Applicability::MaybeIncorrect, - ); - } - ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => { - let then_span = self.find_block_span_from_hir_id(*then_id); - diag.span_suggestion_verbose( - then_span.shrink_to_hi(), + span.shrink_to_hi(), "consider `await`ing on the `Future`", ".await", Applicability::MaybeIncorrect, @@ -1995,7 +1992,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .iter() .filter(|field| field.vis.is_accessible_from(field.did, self.tcx)) .map(|field| (field.name, field.ty(self.tcx, expected_substs))) - .find(|(_, ty)| self.same_type_modulo_infer(*ty, exp_found.found)) + .find(|(_, ty)| same_type_modulo_infer(*ty, exp_found.found)) { if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { @@ -2060,7 +2057,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { | (_, ty::Infer(_)) | (ty::Param(_), _) | (ty::Infer(_), _) => {} - _ if self.same_type_modulo_infer(exp_ty, found_ty) => {} + _ if same_type_modulo_infer(exp_ty, found_ty) => {} _ => show_suggestion = false, }; } @@ -2182,7 +2179,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) { let [expected_tup_elem] = expected_fields[..] else { return }; - if !self.same_type_modulo_infer(expected_tup_elem, found) { + if !same_type_modulo_infer(expected_tup_elem, found) { return; } @@ -2353,7 +2350,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { GenericKind::Projection(ref p) => format!("the associated type `{}`", p), }; - if let Some(SubregionOrigin::CompareImplItemObligation { + if let Some(SubregionOrigin::CompareImplMethodObligation { span, impl_item_def_id, trait_item_def_id, @@ -2412,9 +2409,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { #[derive(Debug)] enum SubOrigin<'hir> { GAT(&'hir hir::Generics<'hir>), - Impl, - Trait, - Fn, + Impl(&'hir hir::Generics<'hir>), + Trait(&'hir hir::Generics<'hir>), + Fn(&'hir hir::Generics<'hir>), Unknown, } let sub_origin = 'origin: { @@ -2429,30 +2426,34 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { kind: hir::ImplItemKind::TyAlias(..), generics, .. - }) - | Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Type(..), - generics, - .. }) => SubOrigin::GAT(generics), Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), + generics, .. - }) - | Node::TraitItem(hir::TraitItem { + }) => SubOrigin::Fn(generics), + Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Type(..), + generics, + .. + }) => SubOrigin::GAT(generics), + Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), + generics, .. - }) - | Node::Item(hir::Item { - kind: hir::ItemKind::Fn(..), .. - }) => SubOrigin::Fn, + }) => SubOrigin::Fn(generics), Node::Item(hir::Item { - kind: hir::ItemKind::Trait(..), + kind: hir::ItemKind::Trait(_, _, generics, _, _), .. - }) => SubOrigin::Trait, + }) => SubOrigin::Trait(generics), Node::Item(hir::Item { - kind: hir::ItemKind::Impl(..), .. - }) => SubOrigin::Impl, + kind: hir::ItemKind::Impl(hir::Impl { generics, .. }), + .. + }) => SubOrigin::Impl(generics), + Node::Item(hir::Item { + kind: hir::ItemKind::Fn(_, generics, _), + .. + }) => SubOrigin::Fn(generics), _ => continue, }; } @@ -2646,76 +2647,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span.is_desugaring(DesugaringKind::QuestionMark) && self.tcx.is_diagnostic_item(sym::From, trait_def_id) } - - /// Structurally compares two types, modulo any inference variables. - /// - /// Returns `true` if two types are equal, or if one type is an inference variable compatible - /// with the other type. A TyVar inference type is compatible with any type, and an IntVar or - /// FloatVar inference type are compatible with themselves or their concrete types (Int and - /// Float types, respectively). When comparing two ADTs, these rules apply recursively. - pub fn same_type_modulo_infer(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - let (a, b) = self.resolve_vars_if_possible((a, b)); - match (a.kind(), b.kind()) { - (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) => { - if def_a != def_b { - return false; - } - - substs_a - .types() - .zip(substs_b.types()) - .all(|(a, b)| self.same_type_modulo_infer(a, b)) - } - (&ty::FnDef(did_a, substs_a), &ty::FnDef(did_b, substs_b)) => { - if did_a != did_b { - return false; - } - - substs_a - .types() - .zip(substs_b.types()) - .all(|(a, b)| self.same_type_modulo_infer(a, b)) - } - (&ty::Int(_) | &ty::Uint(_), &ty::Infer(ty::InferTy::IntVar(_))) - | ( - &ty::Infer(ty::InferTy::IntVar(_)), - &ty::Int(_) | &ty::Uint(_) | &ty::Infer(ty::InferTy::IntVar(_)), - ) - | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_))) - | ( - &ty::Infer(ty::InferTy::FloatVar(_)), - &ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)), - ) - | (&ty::Infer(ty::InferTy::TyVar(_)), _) - | (_, &ty::Infer(ty::InferTy::TyVar(_))) => true, - (&ty::Ref(_, ty_a, mut_a), &ty::Ref(_, ty_b, mut_b)) => { - mut_a == mut_b && self.same_type_modulo_infer(ty_a, ty_b) - } - (&ty::RawPtr(a), &ty::RawPtr(b)) => { - a.mutbl == b.mutbl && self.same_type_modulo_infer(a.ty, b.ty) - } - (&ty::Slice(a), &ty::Slice(b)) => self.same_type_modulo_infer(a, b), - (&ty::Array(a_ty, a_ct), &ty::Array(b_ty, b_ct)) => { - self.same_type_modulo_infer(a_ty, b_ty) && a_ct == b_ct - } - (&ty::Tuple(a), &ty::Tuple(b)) => { - if a.len() != b.len() { - return false; - } - std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b)) - } - (&ty::FnPtr(a), &ty::FnPtr(b)) => { - let a = a.skip_binder().inputs_and_output; - let b = b.skip_binder().inputs_and_output; - if a.len() != b.len() { - return false; - } - std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b)) - } - // FIXME(compiler-errors): This needs to be generalized more - _ => a == b, - } - } } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { @@ -2786,15 +2717,8 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { use self::FailureCode::*; use crate::traits::ObligationCauseCode::*; match self.code() { - CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => { - Error0308("method not compatible with trait") - } - CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => { - Error0308("type not compatible with trait") - } - CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => { - Error0308("const not compatible with trait") - } + CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"), + CompareImplTypeObligation { .. } => Error0308("type not compatible with trait"), MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => { Error0308(match source { hir::MatchSource::TryDesugar => "`?` operator has incompatible types", @@ -2828,15 +2752,8 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { fn as_requirement_str(&self) -> &'static str { use crate::traits::ObligationCauseCode::*; match self.code() { - CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => { - "method type is compatible with trait" - } - CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => { - "associated type is compatible with trait" - } - CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => { - "const is compatible with trait" - } + CompareImplMethodObligation { .. } => "method type is compatible with trait", + CompareImplTypeObligation { .. } => "associated type is compatible with trait", ExprAssignable => "expression is assignable", IfExpression { .. } => "`if` and `else` have incompatible types", IfExpressionWithNoElse => "`if` missing an `else` returns `()`", @@ -2881,237 +2798,3 @@ impl TyCategory { } } } - -impl<'tcx> InferCtxt<'_, 'tcx> { - /// Given a [`hir::Block`], get the span of its last expression or - /// statement, peeling off any inner blocks. - pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span { - let block = block.innermost_block(); - if let Some(expr) = &block.expr { - expr.span - } else if let Some(stmt) = block.stmts.last() { - // possibly incorrect trailing `;` in the else arm - stmt.span - } else { - // empty block; point at its entirety - block.span - } - } - - /// Given a [`hir::HirId`] for a block, get the span of its last expression - /// or statement, peeling off any inner blocks. - pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span { - match self.tcx.hir().get(hir_id) { - hir::Node::Block(blk) => self.find_block_span(blk), - // The parser was in a weird state if either of these happen, but - // it's better not to panic. - hir::Node::Expr(e) => e.span, - _ => rustc_span::DUMMY_SP, - } - } - - /// Be helpful when the user wrote `{... expr; }` and taking the `;` off - /// is enough to fix the error. - pub fn could_remove_semicolon( - &self, - blk: &'tcx hir::Block<'tcx>, - expected_ty: Ty<'tcx>, - ) -> Option<(Span, StatementAsExpression)> { - let blk = blk.innermost_block(); - // Do not suggest if we have a tail expr. - if blk.expr.is_some() { - return None; - } - let last_stmt = blk.stmts.last()?; - let hir::StmtKind::Semi(ref last_expr) = last_stmt.kind else { - return None; - }; - let last_expr_ty = self.in_progress_typeck_results?.borrow().expr_ty_opt(*last_expr)?; - let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) { - _ if last_expr_ty.references_error() => return None, - _ if self.same_type_modulo_infer(last_expr_ty, expected_ty) => { - StatementAsExpression::CorrectType - } - (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _)) - if last_def_id == exp_def_id => - { - StatementAsExpression::CorrectType - } - (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => { - debug!( - "both opaque, likely future {:?} {:?} {:?} {:?}", - last_def_id, last_bounds, exp_def_id, exp_bounds - ); - - let last_local_id = last_def_id.as_local()?; - let exp_local_id = exp_def_id.as_local()?; - - match ( - &self.tcx.hir().expect_item(last_local_id).kind, - &self.tcx.hir().expect_item(exp_local_id).kind, - ) { - ( - hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }), - hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }), - ) if iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| { - match (left, right) { - ( - hir::GenericBound::Trait(tl, ml), - hir::GenericBound::Trait(tr, mr), - ) if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id() - && ml == mr => - { - true - } - ( - hir::GenericBound::LangItemTrait(langl, _, _, argsl), - hir::GenericBound::LangItemTrait(langr, _, _, argsr), - ) if langl == langr => { - // FIXME: consider the bounds! - debug!("{:?} {:?}", argsl, argsr); - true - } - _ => false, - } - }) => - { - StatementAsExpression::NeedsBoxing - } - _ => StatementAsExpression::CorrectType, - } - } - _ => return None, - }; - let span = if last_stmt.span.from_expansion() { - let mac_call = rustc_span::source_map::original_sp(last_stmt.span, blk.span); - self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)? - } else { - last_stmt.span.with_lo(last_stmt.span.hi() - BytePos(1)) - }; - Some((span, needs_box)) - } - - /// Suggest returning a local binding with a compatible type if the block - /// has no return expression. - pub fn consider_returning_binding( - &self, - blk: &'tcx hir::Block<'tcx>, - expected_ty: Ty<'tcx>, - err: &mut Diagnostic, - ) -> bool { - let blk = blk.innermost_block(); - // Do not suggest if we have a tail expr. - if blk.expr.is_some() { - return false; - } - let mut shadowed = FxHashSet::default(); - let mut candidate_idents = vec![]; - let mut find_compatible_candidates = |pat: &hir::Pat<'_>| { - if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind - && let Some(pat_ty) = self - .in_progress_typeck_results - .and_then(|typeck_results| typeck_results.borrow().node_type_opt(*hir_id)) - { - let pat_ty = self.resolve_vars_if_possible(pat_ty); - if self.same_type_modulo_infer(pat_ty, expected_ty) - && !(pat_ty, expected_ty).references_error() - && shadowed.insert(ident.name) - { - candidate_idents.push((*ident, pat_ty)); - } - } - true - }; - - let hir = self.tcx.hir(); - for stmt in blk.stmts.iter().rev() { - let hir::StmtKind::Local(local) = &stmt.kind else { continue; }; - local.pat.walk(&mut find_compatible_candidates); - } - match hir.find(hir.get_parent_node(blk.hir_id)) { - Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => { - match hir.find(hir.get_parent_node(*hir_id)) { - Some(hir::Node::Arm(hir::Arm { pat, .. })) => { - pat.walk(&mut find_compatible_candidates); - } - Some( - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. }) - | hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(_, body), - .. - }) - | hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)), - .. - }) - | hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(hir::Closure { body, .. }), - .. - }), - ) => { - for param in hir.body(*body).params { - param.pat.walk(&mut find_compatible_candidates); - } - } - Some(hir::Node::Expr(hir::Expr { - kind: - hir::ExprKind::If( - hir::Expr { kind: hir::ExprKind::Let(let_), .. }, - then_block, - _, - ), - .. - })) if then_block.hir_id == *hir_id => { - let_.pat.walk(&mut find_compatible_candidates); - } - _ => {} - } - } - _ => {} - } - - match &candidate_idents[..] { - [(ident, _ty)] => { - let sm = self.tcx.sess.source_map(); - if let Some(stmt) = blk.stmts.last() { - let stmt_span = sm.stmt_span(stmt.span, blk.span); - let sugg = if sm.is_multiline(blk.span) - && let Some(spacing) = sm.indentation_before(stmt_span) - { - format!("\n{spacing}{ident}") - } else { - format!(" {ident}") - }; - err.span_suggestion_verbose( - stmt_span.shrink_to_hi(), - format!("consider returning the local binding `{ident}`"), - sugg, - Applicability::MaybeIncorrect, - ); - } else { - let sugg = if sm.is_multiline(blk.span) - && let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo()) - { - format!("\n{spacing} {ident}\n{spacing}") - } else { - format!(" {ident} ") - }; - let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi(); - err.span_suggestion_verbose( - sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span), - format!("consider returning the local binding `{ident}`"), - sugg, - Applicability::MaybeIncorrect, - ); - } - true - } - values if (1..3).contains(&values.len()) => { - let spans = values.iter().map(|(ident, _)| ident.span).collect::>(); - err.span_note(spans, "consider returning one of these bindings"); - true - } - _ => false, - } - } -} diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 561d1354edd21..b267140daa971 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -1,4 +1,4 @@ -use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use crate::infer::type_variable::TypeVariableOriginKind; use crate::infer::InferCtxt; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; @@ -8,12 +8,12 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource}; use rustc_middle::hir::nested_filter; -use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use rustc_middle::infer::unify_key::ConstVariableOriginKind; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; use rustc_middle::ty::{self, DefIdTree, InferConst}; -use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults}; +use rustc_middle::ty::{Ty, TyCtxt, TypeckResults}; use rustc_span::symbol::{kw, Ident}; use rustc_span::{BytePos, Span}; use std::borrow::Cow; @@ -407,40 +407,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.span_label(span, cannot_infer_msg); - let args = fmt_printer(self, Namespace::TypeNS) - .comma_sep(generic_args.iter().copied().map(|arg| { - if arg.is_suggestable(self.tcx, true) { - return arg; - } - - match arg.unpack() { - GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), - GenericArgKind::Type(_) => self - .next_ty_var(TypeVariableOrigin { - span: rustc_span::DUMMY_SP, - kind: TypeVariableOriginKind::MiscVariable, - }) - .into(), - GenericArgKind::Const(arg) => self - .next_const_var( - arg.ty(), - ConstVariableOrigin { - span: rustc_span::DUMMY_SP, - kind: ConstVariableOriginKind::MiscVariable, - }, - ) - .into(), - } - })) - .unwrap() - .into_buffer(); - + let printer = fmt_printer(self, Namespace::TypeNS); + let args = printer.comma_sep(generic_args.iter().copied()).unwrap().into_buffer(); err.span_suggestion_verbose( insert_span, - &format!( - "consider specifying the generic argument{}", - pluralize!(generic_args.len()), - ), + &format!("consider specifying the generic argument{}", pluralize!(args.len()),), format!("::<{}>", args), Applicability::HasPlaceholders, ); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index c1b201da69121..e5ae835e81349 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -100,6 +100,23 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { // the lifetime of the TyRptr let hir_id = lifetime.hir_id; match (self.tcx.named_region(hir_id), self.bound_region) { + // Find the index of the anonymous region that was part of the + // error. We will then search the function parameters for a bound + // region at the right depth with the same index + ( + Some(rl::Region::LateBoundAnon(debruijn_index, _, anon_index)), + ty::BrAnon(br_index), + ) => { + debug!( + "LateBoundAnon depth = {:?} anon_index = {:?} br_index={:?}", + debruijn_index, anon_index, br_index + ); + if debruijn_index == self.current_index && anon_index == br_index { + self.found_type = Some(arg); + return; // we can stop visiting now + } + } + // Find the index of the named region that was part of the // error. We will then search the function parameters for a bound // region at the right depth with the same index @@ -134,7 +151,8 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { rl::Region::Static | rl::Region::Free(_, _) | rl::Region::EarlyBound(_, _) - | rl::Region::LateBound(_, _, _), + | rl::Region::LateBound(_, _, _) + | rl::Region::LateBoundAnon(_, _, _), ) | None, _, @@ -188,6 +206,16 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) { match (self.tcx.named_region(lifetime.hir_id), self.bound_region) { // the lifetime of the TyPath! + ( + Some(rl::Region::LateBoundAnon(debruijn_index, _, anon_index)), + ty::BrAnon(br_index), + ) => { + if debruijn_index == self.current_index && anon_index == br_index { + self.found_it = true; + return; + } + } + (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); if id == def_id { @@ -211,6 +239,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { rl::Region::Static | rl::Region::EarlyBound(_, _) | rl::Region::LateBound(_, _, _) + | rl::Region::LateBoundAnon(_, _, _) | rl::Region::Free(_, _), ) | None, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs index 893ca3cf79d70..43d5c9fdf33a6 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs @@ -6,7 +6,7 @@ use crate::infer::error_reporting::note_and_explain_region; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::ObligationCauseCode; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 246d27be71cff..02928c4aa57cd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -4,7 +4,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCauseCode, UnifyReceiverContext}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, Visitor}; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index da465a7642992..91bf9695dfc14 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -2,17 +2,17 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; -use crate::infer::Subtype; -use crate::traits::ObligationCauseCode::CompareImplItemObligation; +use crate::infer::{SubregionOrigin, Subtype}; +use crate::traits::ObligationCauseCode::CompareImplMethodObligation; use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; use rustc_middle::ty::print::RegionHighlightMode; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use std::ops::ControlFlow; @@ -22,22 +22,38 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let error = self.error.as_ref()?; debug!("try_report_impl_not_conforming_to_trait {:?}", error); if let RegionResolutionError::SubSupConflict( - _, - var_origin, - sub_origin, - _sub, - sup_origin, - _sup, - _, + _, var_origin, sub_origin, _sub, sup_origin, _sup, _, ) = error.clone() - && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin) - && let sub_expected_found @ Some((sub_expected, sub_found)) = sub_trace.values.ty() - && let sup_expected_found @ Some(_) = sup_trace.values.ty() - && let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code() + && let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) + && let ( + sub_expected_found @ Some((sub_expected, sub_found)), + sup_expected_found @ Some(_), + CompareImplMethodObligation { trait_item_def_id, .. }, + ) = (sub_trace.values.ty(), sup_trace.values.ty(), sub_trace.cause.code()) && sup_expected_found == sub_expected_found { - let guar = - self.emit_err(var_origin.span(), sub_expected, sub_found, *trait_item_def_id); + let guar = self.emit_err( + var_origin.span(), + sub_expected, + sub_found, + *trait_item_def_id, + ); + return Some(guar); + } + if let RegionResolutionError::ConcreteFailure(origin, _, _) + | RegionResolutionError::GenericBoundFailure(origin, _, _) = error.clone() + && let SubregionOrigin::CompareImplTypeObligation { + span, + impl_item_def_id, + trait_item_def_id, + } = origin + { + let guar = self.emit_associated_type_err( + span, + self.infcx.tcx.item_name(impl_item_def_id.to_def_id()), + impl_item_def_id, + trait_item_def_id, + ); return Some(guar); } None @@ -131,6 +147,25 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } err.emit() } + + fn emit_associated_type_err( + &self, + span: Span, + item_name: Symbol, + impl_item_def_id: LocalDefId, + trait_item_def_id: DefId, + ) -> ErrorGuaranteed { + let impl_sp = self.tcx().def_span(impl_item_def_id); + let trait_sp = self.tcx().def_span(trait_item_def_id); + let mut err = self + .tcx() + .sess + .struct_span_err(span, &format!("`impl` associated type signature for `{}` doesn't match `trait` associated type signature", item_name)); + err.span_label(impl_sp, "found"); + err.span_label(trait_sp, "expected"); + + err.emit() + } } struct TypeParamSpanVisitor<'tcx> { diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index c1940c5c0824a..67bbace39e3ca 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -86,7 +86,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "...so that the declared lifetime parameter bounds are satisfied", ); } - infer::CompareImplItemObligation { span, .. } => { + infer::CompareImplMethodObligation { span, .. } => { + label_or_note( + span, + "...so that the definition in impl matches the definition from the trait", + ); + } + infer::CompareImplTypeObligation { span, .. } => { label_or_note( span, "...so that the definition in impl matches the definition from the trait", @@ -323,7 +329,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); err } - infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self + infer::CompareImplMethodObligation { span, impl_item_def_id, trait_item_def_id } => { + self.report_extra_impl_obligation( + span, + impl_item_def_id, + trait_item_def_id, + &format!("`{}: {}`", sup, sub), + ) + } + infer::CompareImplTypeObligation { span, impl_item_def_id, trait_item_def_id } => self .report_extra_impl_obligation( span, impl_item_def_id, @@ -343,7 +357,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id); let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id); - let impl_predicates: rustc_data_structures::fx::FxHashSet<_> = + let impl_predicates: rustc_data_structures::stable_set::FxHashSet<_> = impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect(); let clauses: Vec<_> = trait_predicates .predicates diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 0ac6e8c541b55..0e44d4e7c972b 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -21,7 +21,7 @@ use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::traits::select; -use rustc_middle::ty::abstract_const::{AbstractConst, FailureKind}; +use rustc_middle::ty::abstract_const::AbstractConst; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::relate::RelateResult; @@ -265,11 +265,6 @@ pub struct InferCtxt<'a, 'tcx> { /// might come up during inference or typeck. pub defining_use_anchor: DefiningAnchor, - /// Whether this inference context should care about region obligations in - /// the root universe. Most notably, this is used during hir typeck as region - /// solving is left to borrowck instead. - pub considering_regions: bool, - /// During type-checking/inference of a body, `in_progress_typeck_results` /// contains a reference to the typeck results being built up, which are /// used for reading closure kinds/signatures as they are inferred, @@ -405,7 +400,15 @@ pub enum SubregionOrigin<'tcx> { /// Comparing the signature and requirements of an impl method against /// the containing trait. - CompareImplItemObligation { span: Span, impl_item_def_id: LocalDefId, trait_item_def_id: DefId }, + CompareImplMethodObligation { + span: Span, + impl_item_def_id: LocalDefId, + trait_item_def_id: DefId, + }, + + /// Comparing the signature and requirements of an impl associated type + /// against the containing trait + CompareImplTypeObligation { span: Span, impl_item_def_id: LocalDefId, trait_item_def_id: DefId }, /// Checking that the bounds of a trait's associated type hold for a given impl CheckAssociatedTypeBounds { @@ -536,9 +539,8 @@ impl<'tcx> fmt::Display for FixupError<'tcx> { /// without using `Rc` or something similar. pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, - defining_use_anchor: DefiningAnchor, - considering_regions: bool, fresh_typeck_results: Option>>, + defining_use_anchor: DefiningAnchor, } pub trait TyCtxtInferExt<'tcx> { @@ -550,7 +552,6 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { InferCtxtBuilder { tcx: self, defining_use_anchor: DefiningAnchor::Error, - considering_regions: true, fresh_typeck_results: None, } } @@ -576,11 +577,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } - pub fn ignoring_regions(mut self) -> Self { - self.considering_regions = false; - self - } - /// Given a canonical value `C` as a starting point, create an /// inference context that contains each of the bound values /// within instantiated as a fresh variable. The `f` closure is @@ -605,17 +601,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> { } pub fn enter(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R { - let InferCtxtBuilder { - tcx, - defining_use_anchor, - considering_regions, - ref fresh_typeck_results, - } = *self; + let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self; let in_progress_typeck_results = fresh_typeck_results.as_ref(); f(InferCtxt { tcx, defining_use_anchor, - considering_regions, in_progress_typeck_results, inner: RefCell::new(InferCtxtInner::new()), lexical_region_resolutions: RefCell::new(None), @@ -966,14 +956,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub fn member_constraint( &self, - key: ty::OpaqueTypeKey<'tcx>, + opaque_type_def_id: LocalDefId, definition_span: Span, hidden_ty: Ty<'tcx>, region: ty::Region<'tcx>, in_regions: &Lrc>>, ) { self.inner.borrow_mut().unwrap_region_constraints().member_constraint( - key, + opaque_type_def_id, definition_span, hidden_ty, region, @@ -1053,11 +1043,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, cause: &traits::ObligationCause<'tcx>, predicate: ty::PolyRegionOutlivesPredicate<'tcx>, - ) { - let ty::OutlivesPredicate(r_a, r_b) = self.replace_bound_vars_with_placeholders(predicate); - let origin = - SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span)); - self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` + ) -> UnitResult<'tcx> { + self.commit_if_ok(|_snapshot| { + let ty::OutlivesPredicate(r_a, r_b) = + self.replace_bound_vars_with_placeholders(predicate); + let origin = SubregionOrigin::from_obligation_cause(cause, || { + RelateRegionParamBound(cause.span) + }); + self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` + Ok(()) + }) } /// Number of type variables created so far. @@ -1675,7 +1670,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub fn const_eval_resolve( &self, - mut param_env: ty::ParamEnv<'tcx>, + param_env: ty::ParamEnv<'tcx>, unevaluated: ty::Unevaluated<'tcx>, span: Option, ) -> EvalToValTreeResult<'tcx> { @@ -1686,19 +1681,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // variables if substs.has_infer_types_or_consts() { let ac = AbstractConst::new(self.tcx, unevaluated.shrink()); - match ac { - Ok(None) => { - substs = InternalSubsts::identity_for_item(self.tcx, unevaluated.def.did); - param_env = self.tcx.param_env(unevaluated.def.did); - } - Ok(Some(ct)) => { - if ct.unify_failure_kind(self.tcx) == FailureKind::Concrete { - substs = replace_param_and_infer_substs_with_placeholder(self.tcx, substs); - } else { - return Err(ErrorHandled::TooGeneric); - } - } - Err(guar) => return Err(ErrorHandled::Reported(guar)), + if let Ok(None) = ac { + substs = InternalSubsts::identity_for_item(self.tcx, unevaluated.def.did); + } else { + return Err(ErrorHandled::TooGeneric); } } @@ -1946,7 +1932,8 @@ impl<'tcx> SubregionOrigin<'tcx> { ReborrowUpvar(a, _) => a, DataBorrowed(_, a) => a, ReferenceOutlivesReferent(_, a) => a, - CompareImplItemObligation { span, .. } => span, + CompareImplMethodObligation { span, .. } => span, + CompareImplTypeObligation { span, .. } => span, CheckAssociatedTypeBounds { ref parent, .. } => parent.span(), } } @@ -1960,11 +1947,19 @@ impl<'tcx> SubregionOrigin<'tcx> { SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span) } - traits::ObligationCauseCode::CompareImplItemObligation { + traits::ObligationCauseCode::CompareImplMethodObligation { impl_item_def_id, trait_item_def_id, - kind: _, - } => SubregionOrigin::CompareImplItemObligation { + } => SubregionOrigin::CompareImplMethodObligation { + span: cause.span, + impl_item_def_id, + trait_item_def_id, + }, + + traits::ObligationCauseCode::CompareImplTypeObligation { + impl_item_def_id, + trait_item_def_id, + } => SubregionOrigin::CompareImplTypeObligation { span: cause.span, impl_item_def_id, trait_item_def_id, @@ -2009,43 +2004,3 @@ impl<'tcx> fmt::Debug for RegionObligation<'tcx> { ) } } - -/// Replaces substs that reference param or infer variables with suitable -/// placeholders. This function is meant to remove these param and infer -/// substs when they're not actually needed to evaluate a constant. -fn replace_param_and_infer_substs_with_placeholder<'tcx>( - tcx: TyCtxt<'tcx>, - substs: SubstsRef<'tcx>, -) -> SubstsRef<'tcx> { - tcx.mk_substs(substs.iter().enumerate().map(|(idx, arg)| { - match arg.unpack() { - GenericArgKind::Type(_) - if arg.has_param_types_or_consts() || arg.has_infer_types_or_consts() => - { - tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { - universe: ty::UniverseIndex::ROOT, - name: ty::BoundVar::from_usize(idx), - })) - .into() - } - GenericArgKind::Const(ct) - if ct.has_infer_types_or_consts() || ct.has_param_types_or_consts() => - { - let ty = ct.ty(); - // If the type references param or infer, replace that too... - if ty.has_param_types_or_consts() || ty.has_infer_types_or_consts() { - bug!("const `{ct}`'s type should not reference params or types"); - } - tcx.mk_const(ty::ConstS { - ty, - kind: ty::ConstKind::Placeholder(ty::PlaceholderConst { - universe: ty::UniverseIndex::ROOT, - name: ty::BoundConst { ty, var: ty::BoundVar::from_usize(idx) }, - }), - }) - .into() - } - _ => arg, - } - })) -} diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index a1c7b70bd9cdf..7b0ff9552a3a4 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -394,7 +394,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { - op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions), + op: |r| { + self.member_constraint( + opaque_type_key.def_id, + span, + concrete_ty, + r, + &choice_regions, + ) + }, }); } @@ -430,7 +438,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } #[instrument(skip(self), level = "trace")] - fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin { + pub fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin { let origin = match self.tcx.hir().expect_item(def_id).kind { hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin, ref itemkind => { diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index b2decd64f0fd9..b897de7315a02 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -1,7 +1,6 @@ use crate::infer::free_regions::FreeRegionMap; use crate::infer::{GenericKind, InferCtxt}; use crate::traits::query::OutlivesBound; -use rustc_data_structures::fx::FxIndexSet; use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region}; use super::explicit_outlives_bounds; @@ -54,8 +53,7 @@ pub struct OutlivesEnvironment<'tcx> { /// "Region-bound pairs" tracks outlives relations that are known to /// be true, either because of explicit where-clauses like `T: 'a` or /// because of implied bounds. -pub type RegionBoundPairs<'tcx> = - FxIndexSet, Region<'tcx>>>; +pub type RegionBoundPairs<'tcx> = Vec<(Region<'tcx>, GenericKind<'tcx>)>; impl<'a, 'tcx> OutlivesEnvironment<'tcx> { pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self { @@ -99,12 +97,10 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound); match outlives_bound { OutlivesBound::RegionSubParam(r_a, param_b) => { - self.region_bound_pairs - .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a)); + self.region_bound_pairs.push((r_a, GenericKind::Param(param_b))); } OutlivesBound::RegionSubProjection(r_a, projection_b) => { - self.region_bound_pairs - .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a)); + self.region_bound_pairs.push((r_a, GenericKind::Projection(projection_b))); } OutlivesBound::RegionSubRegion(r_a, r_b) => { if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) { diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index c7d7ef40d9d41..faa0a18f93d9a 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -6,7 +6,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::sso::SsoHashSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, Subst}; -use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, Ty, TyCtxt}; +use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; use smallvec::smallvec; @@ -259,17 +259,16 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // The problem is that the type of `x` is `&'a A`. To be // well-formed, then, A must outlive `'a`, but we don't know that // this holds from first principles. - let from_region_bound_pairs = - self.region_bound_pairs.iter().filter_map(|&OutlivesPredicate(p, r)| { - debug!( - "declared_generic_bounds_from_env_for_erased_ty: region_bound_pair = {:?}", - (r, p) - ); - let p_ty = p.to_ty(tcx); - let erased_p_ty = self.tcx.erase_regions(p_ty); - (erased_p_ty == erased_ty) - .then_some(ty::Binder::dummy(ty::OutlivesPredicate(p.to_ty(tcx), r))) - }); + let from_region_bound_pairs = self.region_bound_pairs.iter().filter_map(|&(r, p)| { + debug!( + "declared_generic_bounds_from_env_for_erased_ty: region_bound_pair = {:?}", + (r, p) + ); + let p_ty = p.to_ty(tcx); + let erased_p_ty = self.tcx.erase_regions(p_ty); + (erased_p_ty == erased_ty) + .then_some(ty::Binder::dummy(ty::OutlivesPredicate(p.to_ty(tcx), r))) + }); param_bounds .chain(from_region_bound_pairs) diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 0d4472a1cfd9c..551f398e0c2c4 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -12,6 +12,7 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify as ut; +use rustc_hir::def_id::LocalDefId; use rustc_index::vec::IndexVec; use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion}; use rustc_middle::ty::ReStatic; @@ -532,7 +533,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { pub fn member_constraint( &mut self, - key: ty::OpaqueTypeKey<'tcx>, + opaque_type_def_id: LocalDefId, definition_span: Span, hidden_ty: Ty<'tcx>, member_region: ty::Region<'tcx>, @@ -545,7 +546,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } self.data.member_constraints.push(MemberConstraint { - key, + opaque_type_def_id, definition_span, hidden_ty, member_region, diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 38ff9343537dc..674c75fdee561 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -145,12 +145,7 @@ impl<'tcx> Elaborator<'tcx> { // Get predicates declared on the trait. let predicates = tcx.super_predicates_of(data.def_id()); - let obligations = predicates.predicates.iter().map(|&(mut pred, _)| { - // when parent predicate is non-const, elaborate it to non-const predicates. - if data.constness == ty::BoundConstness::NotConst { - pred = pred.without_const(tcx); - } - + let obligations = predicates.predicates.iter().map(|&(pred, _)| { predicate_obligation( pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)), obligation.param_env, diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 94f81b6607798..6c7ddb4531ef8 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -329,8 +329,6 @@ pub fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R }) } -// JUSTIFICATION: before session exists, only config -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R { tracing::trace!("run_compiler"); util::run_in_thread_pool_with_globals( diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 8f0835917861a..334a595a88ae6 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -210,7 +210,7 @@ pub fn register_plugins<'a>( let mut lint_store = rustc_lint::new_lint_store( sess.opts.unstable_opts.no_interleave_lints, - sess.enable_internal_lints(), + sess.unstable_options(), ); register_lints(sess, &mut lint_store); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 57ce4933a3b3f..3eef3308770be 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -1,4 +1,3 @@ -#![cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] use crate::interface::parse_cfgspecs; use rustc_data_structures::fx::FxHashSet; @@ -670,7 +669,6 @@ fn test_unstable_options_tracking_hash() { untracked!(ls, true); untracked!(macro_backtrace, true); untracked!(meta_stats, true); - untracked!(mir_pretty_relative_line_numbers, true); untracked!(nll_facts, true); untracked!(no_analysis, true); untracked!(no_interleave_lints, true); @@ -735,10 +733,8 @@ fn test_unstable_options_tracking_hash() { tracked!(debug_macros, true); tracked!(dep_info_omit_d_target, true); tracked!(drop_tracking, true); - tracked!(export_executable_symbols, true); tracked!(dual_proc_macros, true); tracked!(dwarf_version, Some(5)); - tracked!(emit_thin_lto, false); tracked!(fewer_names, Some(true)); tracked!(force_unstable_if_unmarked, true); tracked!(fuel, Some(("abc".to_string(), 99))); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 4c64e679b9571..97856ecf22c66 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -559,8 +559,6 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec( cx: &LateContext<'tcx>, expr: &Expr<'_>, ) -> Option<(Span, DefId, ty::subst::SubstsRef<'tcx>)> { + // FIXME(rustdoc): Lints which use this function use typecheck results which can cause + // `rustdoc` to error if there are resolution failures. + // + // As internal lints are currently always run if there are `unstable_options`, they are added + // to the lint store of rustdoc. Internal lints are also not used via the `lint_mod` query. + // Crate lints run outside of a query so rustdoc currently doesn't disable them. + // + // Instead of relying on this, either change crate lints to a query disabled by rustdoc, only + // run internal lints if the user is explicitly opting in or figure out a different way to + // avoid running lints for rustdoc. + if cx.tcx.sess.opts.actually_rustdoc { + return None; + } + match expr.kind { ExprKind::MethodCall(segment, _, _) if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => @@ -432,38 +446,3 @@ impl LateLintPass<'_> for Diagnostics { } } } - -declare_tool_lint! { - pub rustc::BAD_OPT_ACCESS, - Deny, - "prevent using options by field access when there is a wrapper function", - report_in_external_macro: true -} - -declare_lint_pass!(BadOptAccess => [ BAD_OPT_ACCESS ]); - -impl LateLintPass<'_> for BadOptAccess { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - let ExprKind::Field(base, target) = expr.kind else { return }; - let Some(adt_def) = cx.typeck_results().expr_ty(base).ty_adt_def() else { return }; - // Skip types without `#[rustc_lint_opt_ty]` - only so that the rest of the lint can be - // avoided. - if !cx.tcx.has_attr(adt_def.did(), sym::rustc_lint_opt_ty) { - return; - } - - for field in adt_def.all_fields() { - if field.name == target.name && - let Some(attr) = cx.tcx.get_attr(field.did, sym::rustc_lint_opt_deny_field_access) && - let Some(items) = attr.meta_item_list() && - let Some(item) = items.first() && - let Some(literal) = item.literal() && - let ast::LitKind::Str(val, _) = literal.kind - { - cx.struct_span_lint(BAD_OPT_ACCESS, expr.span, |lint| { - lint.build(val.as_str()).emit(); } - ); - } - } - } -} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 7b0702dad75de..8726d36498bed 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -509,14 +509,8 @@ fn register_internals(store: &mut LintStore) { store.register_late_pass(|| Box::new(TyTyKind)); store.register_lints(&Diagnostics::get_lints()); store.register_late_pass(|| Box::new(Diagnostics)); - store.register_lints(&BadOptAccess::get_lints()); - store.register_late_pass(|| Box::new(BadOptAccess)); store.register_lints(&PassByValue::get_lints()); store.register_late_pass(|| Box::new(PassByValue)); - // FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and - // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and - // these lints will trigger all of the time - change this once migration to diagnostic structs - // and translation is completed store.register_group( false, "rustc::internal", @@ -529,7 +523,6 @@ fn register_internals(store: &mut LintStore) { LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO), LintId::of(USAGE_OF_QUALIFIED_TY), LintId::of(EXISTING_DOC_KEYWORD), - LintId::of(BAD_OPT_ACCESS), ], ); } diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index 93f302b44e87c..9fe84a6309b9c 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -85,10 +85,6 @@ enum LLVMRustAttribute { NoUndef = 33, SanitizeMemTag = 34, NoCfCheck = 35, - ShadowCallStack = 36, - AllocSize = 37, - AllocatedPointer = 38, - AllocAlign = 39, }; typedef struct OpaqueRustString *RustStringRef; diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 0a6bd49992d99..be8fbf7677bcf 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -34,7 +34,6 @@ #include "llvm/Transforms/Utils/AddDiscriminators.h" #include "llvm/Transforms/Utils/FunctionImportUtils.h" #include "llvm/LTO/LTO.h" -#include "llvm/Bitcode/BitcodeWriterPass.h" #include "llvm-c/Transforms/PassManagerBuilder.h" #include "llvm/Transforms/Instrumentation.h" @@ -90,6 +89,23 @@ extern "C" void LLVMTimeTraceProfilerFinish(const char* FileName) { timeTraceProfilerCleanup(); } +enum class LLVMRustPassKind { + Other, + Function, + Module, +}; + +static LLVMRustPassKind toRust(PassKind Kind) { + switch (Kind) { + case PT_Function: + return LLVMRustPassKind::Function; + case PT_Module: + return LLVMRustPassKind::Module; + default: + return LLVMRustPassKind::Other; + } +} + extern "C" LLVMPassRef LLVMRustFindAndCreatePass(const char *PassName) { #if LLVM_VERSION_LT(15, 0) StringRef SR(PassName); @@ -155,6 +171,12 @@ extern "C" LLVMPassRef LLVMRustCreateHWAddressSanitizerPass(bool Recover) { #endif } +extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) { + assert(RustPass); + Pass *Pass = unwrap(RustPass); + return toRust(Pass->getPassKind()); +} + extern "C" void LLVMRustAddPass(LLVMPassManagerRef PMR, LLVMPassRef RustPass) { #if LLVM_VERSION_LT(15, 0) assert(RustPass); @@ -1581,6 +1603,28 @@ LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M, return true; } +extern "C" typedef void (*LLVMRustModuleNameCallback)(void*, // payload + const char*, // importing module name + const char*); // imported module name + +// Calls `module_name_callback` for each module import done by ThinLTO. +// The callback is provided with regular null-terminated C strings. +extern "C" void +LLVMRustGetThinLTOModules(const LLVMRustThinLTOData *data, + LLVMRustModuleNameCallback module_name_callback, + void* callback_payload) { + for (const auto& importing_module : data->ImportLists) { + const std::string importing_module_id = importing_module.getKey().str(); + const auto& imports = importing_module.getValue(); + for (const auto& imported_module : imports) { + const std::string imported_module_id = imported_module.getKey().str(); + module_name_callback(callback_payload, + importing_module_id.c_str(), + imported_module_id.c_str()); + } + } +} + // This struct and various functions are sort of a hack right now, but the // problem is that we've got in-memory LLVM modules after we generate and // optimize all codegen-units for one compilation in rustc. To be compatible @@ -1594,17 +1638,13 @@ struct LLVMRustThinLTOBuffer { }; extern "C" LLVMRustThinLTOBuffer* -LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) { +LLVMRustThinLTOBufferCreate(LLVMModuleRef M) { auto Ret = std::make_unique(); { raw_string_ostream OS(Ret->data); { legacy::PassManager PM; - if (is_thin) { - PM.add(createWriteThinLTOBitcodePass(OS)); - } else { - PM.add(createBitcodeWriterPass(OS)); - } + PM.add(createWriteThinLTOBitcodePass(OS)); PM.run(*unwrap(M)); } } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index c333738ded458..2d35ee8976e67 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -6,7 +6,6 @@ #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" -#include "llvm/IR/IntrinsicsARM.h" #include "llvm/IR/Mangler.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFFImportFile.h" @@ -89,6 +88,10 @@ extern "C" char *LLVMRustGetLastError(void) { return Ret; } +extern "C" unsigned int LLVMRustGetInstructionCount(LLVMModuleRef M) { + return unwrap(M)->getInstructionCount(); +} + extern "C" void LLVMRustSetLastError(const char *Err) { free((void *)LastError); LastError = strdup(Err); @@ -229,16 +232,6 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { return Attribute::NoUndef; case SanitizeMemTag: return Attribute::SanitizeMemTag; - case ShadowCallStack: - return Attribute::ShadowCallStack; - case AllocSize: - return Attribute::AllocSize; -#if LLVM_VERSION_GE(15, 0) - case AllocatedPointer: - return Attribute::AllocatedPointer; - case AllocAlign: - return Attribute::AllocAlign; -#endif } report_fatal_error("bad AttributeKind"); } @@ -301,14 +294,6 @@ extern "C" LLVMAttributeRef LLVMRustCreateStructRetAttr(LLVMContextRef C, LLVMTy return wrap(Attribute::getWithStructRetType(*unwrap(C), unwrap(Ty))); } -extern "C" LLVMAttributeRef LLVMRustCreateElementTypeAttr(LLVMContextRef C, LLVMTypeRef Ty) { -#if LLVM_VERSION_GE(15, 0) - return wrap(Attribute::get(*unwrap(C), Attribute::ElementType, unwrap(Ty))); -#else - report_fatal_error("Should not be needed on LLVM < 15"); -#endif -} - extern "C" LLVMAttributeRef LLVMRustCreateUWTableAttr(LLVMContextRef C, bool Async) { #if LLVM_VERSION_LT(15, 0) return wrap(Attribute::get(*unwrap(C), Attribute::UWTable)); @@ -318,67 +303,6 @@ extern "C" LLVMAttributeRef LLVMRustCreateUWTableAttr(LLVMContextRef C, bool Asy #endif } -extern "C" LLVMAttributeRef LLVMRustCreateAllocSizeAttr(LLVMContextRef C, uint32_t ElementSizeArg) { - return wrap(Attribute::getWithAllocSizeArgs(*unwrap(C), ElementSizeArg, None)); -} - -#if LLVM_VERSION_GE(15, 0) - -// These values **must** match ffi::AllocKindFlags. -// It _happens_ to match the LLVM values of llvm::AllocFnKind, -// but that's happenstance and we do explicit conversions before -// passing them to LLVM. -enum class LLVMRustAllocKindFlags : uint64_t { - Unknown = 0, - Alloc = 1, - Realloc = 1 << 1, - Free = 1 << 2, - Uninitialized = 1 << 3, - Zeroed = 1 << 4, - Aligned = 1 << 5, -}; - -static LLVMRustAllocKindFlags operator&(LLVMRustAllocKindFlags A, LLVMRustAllocKindFlags B) { - return static_cast(static_cast(A) & - static_cast(B)); -} - -static bool isSet(LLVMRustAllocKindFlags F) { return F != LLVMRustAllocKindFlags::Unknown; } - -static llvm::AllocFnKind allocKindFromRust(LLVMRustAllocKindFlags F) { - llvm::AllocFnKind AFK = llvm::AllocFnKind::Unknown; - if (isSet(F & LLVMRustAllocKindFlags::Alloc)) { - AFK |= llvm::AllocFnKind::Alloc; - } - if (isSet(F & LLVMRustAllocKindFlags::Realloc)) { - AFK |= llvm::AllocFnKind::Realloc; - } - if (isSet(F & LLVMRustAllocKindFlags::Free)) { - AFK |= llvm::AllocFnKind::Free; - } - if (isSet(F & LLVMRustAllocKindFlags::Uninitialized)) { - AFK |= llvm::AllocFnKind::Uninitialized; - } - if (isSet(F & LLVMRustAllocKindFlags::Zeroed)) { - AFK |= llvm::AllocFnKind::Zeroed; - } - if (isSet(F & LLVMRustAllocKindFlags::Aligned)) { - AFK |= llvm::AllocFnKind::Aligned; - } - return AFK; -} -#endif - -extern "C" LLVMAttributeRef LLVMRustCreateAllocKindAttr(LLVMContextRef C, uint64_t AllocKindArg) { -#if LLVM_VERSION_GE(15, 0) - return wrap(Attribute::get(*unwrap(C), Attribute::AllocKind, - static_cast(allocKindFromRust(static_cast(AllocKindArg))))); -#else - report_fatal_error( - "allockind attributes are new in LLVM 15 and should not be used on older LLVMs"); -#endif -} - // Enable a fast-math flag // // https://llvm.org/docs/LangRef.html#fast-math-flags @@ -1534,6 +1458,11 @@ extern "C" void LLVMRustSetComdat(LLVMModuleRef M, LLVMValueRef V, } } +extern "C" void LLVMRustUnsetComdat(LLVMValueRef V) { + GlobalObject *GV = unwrap(V); + GV->setComdat(nullptr); +} + enum class LLVMRustLinkage { ExternalLinkage = 0, AvailableExternallyLinkage = 1, @@ -1952,16 +1881,3 @@ extern "C" LLVMValueRef LLVMGetAggregateElement(LLVMValueRef C, unsigned Idx) { return wrap(unwrap(C)->getAggregateElement(Idx)); } #endif - -extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) { -#if LLVM_VERSION_GE(15, 0) - auto *CB = unwrap(CallSite); - switch (CB->getIntrinsicID()) { - case Intrinsic::arm_ldrex: - return 0; - case Intrinsic::arm_strex: - return 1; - } -#endif - return -1; -} diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 6c9561925fe8c..5c5275b7cfb92 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -212,7 +212,7 @@ impl DiagnosticDeriveBuilder { } NestedMeta::Meta(meta @ Meta::NameValue(_)) if !is_help_note_or_warn - && meta.path().segments.last().unwrap().ident == "code" => + && meta.path().segments.last().unwrap().ident.to_string() == "code" => { // don't error for valid follow-up attributes } diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs index 562d5e9f4d25e..1170d2b3c59a4 100644 --- a/compiler/rustc_macros/src/diagnostics/fluent.rs +++ b/compiler/rustc_macros/src/diagnostics/fluent.rs @@ -194,8 +194,8 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok let snake_name = Ident::new( // FIXME: should probably trim prefix, not replace all occurrences &name - .replace(&format!("{}-", res.ident).replace('_', "-"), "") - .replace('-', "_"), + .replace(&format!("{}-", res.ident).replace("_", "-"), "") + .replace("-", "_"), span, ); constants.extend(quote! { @@ -207,7 +207,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok }); for Attribute { id: Identifier { name: attr_name }, .. } in attributes { - let snake_name = Ident::new(&attr_name.replace('-', "_"), span); + let snake_name = Ident::new(&attr_name.replace("-", "_"), span); if !previous_attrs.insert(snake_name.clone()) { continue; } diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 2c1c84b0be26a..a72bcb9a2dbd1 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -67,7 +67,7 @@ //! //! ## What criterion to select on? //! -//! This is a pretty tricky area of loading crates. Given a file, how do we know +//! This a pretty tricky area of loading crates. Given a file, how do we know //! whether it's the right crate? Currently, the rules look along these lines: //! //! 1. Does the filename match an rlib/dylib pattern? That is to say, does the diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 8fa703a776075..aa5705d3fcdc3 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -41,7 +41,7 @@ use std::io; use std::iter::TrustedLen; use std::mem; use std::num::NonZeroUsize; -use std::path::Path; +use std::path::PathBuf; use tracing::debug; pub(super) use cstore_impl::provide; @@ -1474,30 +1474,30 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { /// Proc macro crates don't currently export spans, so this function does not have /// to work for them. fn imported_source_files(self, sess: &Session) -> &'a [ImportedSourceFile] { - fn filter<'a>(sess: &Session, path: Option<&'a Path>) -> Option<&'a Path> { - path.filter(|_| { - // Only spend time on further checks if we have what to translate *to*. - sess.opts.real_rust_source_base_dir.is_some() - // Some tests need the translation to be always skipped. - && sess.opts.unstable_opts.translate_remapped_path_to_local_path - }) - .filter(|virtual_dir| { - // Don't translate away `/rustc/$hash` if we're still remapping to it, - // since that means we're still building `std`/`rustc` that need it, - // and we don't want the real path to leak into codegen/debuginfo. - !sess.opts.remap_path_prefix.iter().any(|(_from, to)| to == virtual_dir) - }) - } - // Translate the virtual `/rustc/$hash` prefix back to a real directory // that should hold actual sources, where possible. // // NOTE: if you update this, you might need to also update bootstrap's code for generating // the `rust-src` component in `Src::run` in `src/bootstrap/dist.rs`. let virtual_rust_source_base_dir = [ - filter(sess, option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(Path::new)), - filter(sess, sess.opts.unstable_opts.simulate_remapped_rust_src_base.as_deref()), - ]; + option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from), + sess.opts.unstable_opts.simulate_remapped_rust_src_base.clone(), + ] + .into_iter() + .filter(|_| { + // Only spend time on further checks if we have what to translate *to*. + sess.opts.real_rust_source_base_dir.is_some() + // Some tests need the translation to be always skipped. + && sess.opts.unstable_opts.translate_remapped_path_to_local_path + }) + .flatten() + .filter(|virtual_dir| { + // Don't translate away `/rustc/$hash` if we're still remapping to it, + // since that means we're still building `std`/`rustc` that need it, + // and we don't want the real path to leak into codegen/debuginfo. + !sess.opts.remap_path_prefix.iter().any(|(_from, to)| to == virtual_dir) + }) + .collect::>(); let try_to_translate_virtual_to_real = |name: &mut rustc_span::FileName| { debug!( @@ -1506,7 +1506,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { name, virtual_rust_source_base_dir, sess.opts.real_rust_source_base_dir, ); - for virtual_dir in virtual_rust_source_base_dir.iter().flatten() { + for virtual_dir in &virtual_rust_source_base_dir { if let Some(real_dir) = &sess.opts.real_rust_source_base_dir { if let rustc_span::FileName::Real(old_name) = name { if let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } = diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 6bf237b8ed5df..65cae29c58dcb 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -375,13 +375,9 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { use std::collections::vec_deque::VecDeque; let mut visible_parent_map: DefIdMap = Default::default(); - // This is a secondary visible_parent_map, storing the DefId of - // parents that re-export the child as `_` or module parents - // which are `#[doc(hidden)]`. Since we prefer paths that don't - // do this, merge this map at the end, only if we're missing - // keys from the former. - // This is a rudimentary check that does not catch all cases, - // just the easiest. + // This is a secondary visible_parent_map, storing the DefId of parents that re-export + // the child as `_`. Since we prefer parents that don't do this, merge this map at the + // end, only if we're missing any keys from the former. let mut fallback_map: DefIdMap = Default::default(); // Issue 46112: We want the map to prefer the shortest @@ -416,11 +412,6 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { return; } - if ty::util::is_doc_hidden(tcx, parent) { - fallback_map.insert(def_id, parent); - return; - } - match visible_parent_map.entry(def_id) { Entry::Occupied(mut entry) => { // If `child` is defined in crate `cnum`, ensure @@ -448,9 +439,8 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { } } - // Fill in any missing entries with the less preferable path. - // If this path re-exports the child as `_`, we still use this - // path in a diagnostic that suggests importing `::*`. + // Fill in any missing entries with the (less preferable) path ending in `::_`. + // We still use this path in a diagnostic that suggests importing `::*`. for (child, parent) in fallback_map { visible_parent_map.entry(child).or_insert(parent); } diff --git a/compiler/rustc_middle/src/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs index 38868c2104953..8b2f9bdfd486b 100644 --- a/compiler/rustc_middle/src/infer/mod.rs +++ b/compiler/rustc_middle/src/infer/mod.rs @@ -2,8 +2,9 @@ pub mod canonical; pub mod unify_key; use crate::ty::Region; -use crate::ty::{OpaqueTypeKey, Ty}; +use crate::ty::Ty; use rustc_data_structures::sync::Lrc; +use rustc_hir::def_id::LocalDefId; use rustc_span::Span; /// Requires that `region` must be equal to one of the regions in `choice_regions`. @@ -14,9 +15,8 @@ use rustc_span::Span; /// ``` #[derive(Debug, Clone, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct MemberConstraint<'tcx> { - /// The `DefId` and substs of the opaque type causing this constraint. - /// Used for error reporting. - pub key: OpaqueTypeKey<'tcx>, + /// The `DefId` of the opaque type causing this constraint: used for error reporting. + pub opaque_type_def_id: LocalDefId, /// The span where the hidden type was instantiated. pub definition_span: Span, diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 45d33a1659ffa..321fcd43797cc 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -50,7 +50,7 @@ bitflags! { /// the hot path. const COLD = 1 << 0; /// `#[rustc_allocator]`: a hint to LLVM that the pointer returned from this - /// function is never null and the function has no side effects other than allocating. + /// function is never null. const ALLOCATOR = 1 << 1; /// An indicator that function will never unwind. Will become obsolete /// once C-unwind is fully stabilized. @@ -91,12 +91,6 @@ bitflags! { const NO_COVERAGE = 1 << 15; /// `#[used(linker)]`: indicates that LLVM nor the linker can eliminate this function. const USED_LINKER = 1 << 16; - /// `#[rustc_deallocator]`: a hint to LLVM that the function only deallocates memory. - const DEALLOCATOR = 1 << 17; - /// `#[rustc_reallocator]`: a hint to LLVM that the function only reallocates memory. - const REALLOCATOR = 1 << 18; - /// `#[rustc_allocator_zeroed]`: a hint to LLVM that the function only allocates zeroed memory. - const ALLOCATOR_ZEROED = 1 << 19; } } diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs index 9b2f445670532..c71ba7b175313 100644 --- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs +++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs @@ -12,6 +12,7 @@ pub enum Region { Static, EarlyBound(/* index */ u32, /* lifetime decl */ DefId), LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* lifetime decl */ DefId), + LateBoundAnon(ty::DebruijnIndex, /* late-bound index */ u32, /* anon index */ u32), Free(DefId, /* lifetime decl */ DefId), } diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 414912dd0f7d8..0fbad3f0f0f06 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -475,13 +475,7 @@ impl<'tcx> TyCtxt<'tcx> { } let suggestion = suggestion_for_allocator_api(self, def_id, span, feature); - EvalResult::Deny { - feature, - reason: reason.to_opt_reason(), - issue, - suggestion, - is_soft, - } + EvalResult::Deny { feature, reason, issue, suggestion, is_soft } } Some(_) => { // Stable APIs are always ok to call and deprecated APIs are diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index db7e0fb8a3bdb..eed52ca3eeaa6 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -30,7 +30,7 @@ use crate::ty; // hashed. (see the `Hash` impl below for more details), so the impl is not derived. #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] #[derive(HashStable)] -pub struct Allocation { +pub struct Allocation { /// The actual bytes of the allocation. /// Note that the bytes of a pointer represent the offset of the pointer. bytes: Box<[u8]>, @@ -38,7 +38,7 @@ pub struct Allocation { /// Only the first byte of a pointer is inserted into the map; i.e., /// every entry in this map applies to `pointer_size` consecutive bytes starting /// at the given offset. - relocations: Relocations, + relocations: Relocations, /// Denotes which part of this allocation is initialized. init_mask: InitMask, /// The alignment of the allocation to detect unaligned reads. @@ -102,8 +102,8 @@ impl hash::Hash for Allocation { /// (`ConstAllocation`) are used quite a bit. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_pass_by_value] -pub struct ConstAllocation<'tcx, Prov = AllocId, Extra = ()>( - pub Interned<'tcx, Allocation>, +pub struct ConstAllocation<'tcx, Tag = AllocId, Extra = ()>( + pub Interned<'tcx, Allocation>, ); impl<'tcx> fmt::Debug for ConstAllocation<'tcx> { @@ -114,8 +114,8 @@ impl<'tcx> fmt::Debug for ConstAllocation<'tcx> { } } -impl<'tcx, Prov, Extra> ConstAllocation<'tcx, Prov, Extra> { - pub fn inner(self) -> &'tcx Allocation { +impl<'tcx, Tag, Extra> ConstAllocation<'tcx, Tag, Extra> { + pub fn inner(self) -> &'tcx Allocation { self.0.0 } } @@ -200,7 +200,7 @@ impl AllocRange { } // The constructors are all without extra; the extra gets added by a machine hook later. -impl Allocation { +impl Allocation { /// Creates an allocation initialized by the given bytes pub fn from_bytes<'a>( slice: impl Into>, @@ -256,15 +256,14 @@ impl Allocation { } impl Allocation { - /// Adjust allocation from the ones in tcx to a custom Machine instance - /// with a different Provenance and Extra type. - pub fn adjust_from_tcx( + /// Convert Tag and add Extra fields + pub fn convert_tag_add_extra( self, cx: &impl HasDataLayout, extra: Extra, - mut adjust_ptr: impl FnMut(Pointer) -> Result, Err>, - ) -> Result, Err> { - // Compute new pointer provenance, which also adjusts the bytes. + mut tagger: impl FnMut(Pointer) -> Result, Err>, + ) -> Result, Err> { + // Compute new pointer tags, which also adjusts the bytes. let mut bytes = self.bytes; let mut new_relocations = Vec::with_capacity(self.relocations.0.len()); let ptr_size = cx.data_layout().pointer_size.bytes_usize(); @@ -273,10 +272,10 @@ impl Allocation { let idx = offset.bytes_usize(); let ptr_bytes = &mut bytes[idx..idx + ptr_size]; let bits = read_target_uint(endian, ptr_bytes).unwrap(); - let (ptr_prov, ptr_offset) = - adjust_ptr(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_parts(); + let (ptr_tag, ptr_offset) = + tagger(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_parts(); write_target_uint(endian, ptr_bytes, ptr_offset.bytes().into()).unwrap(); - new_relocations.push((offset, ptr_prov)); + new_relocations.push((offset, ptr_tag)); } // Create allocation. Ok(Allocation { @@ -291,7 +290,7 @@ impl Allocation { } /// Raw accessors. Provide access to otherwise private bytes. -impl Allocation { +impl Allocation { pub fn len(&self) -> usize { self.bytes.len() } @@ -314,13 +313,13 @@ impl Allocation { } /// Returns the relocation list. - pub fn relocations(&self) -> &Relocations { + pub fn relocations(&self) -> &Relocations { &self.relocations } } /// Byte accessors. -impl Allocation { +impl Allocation { /// This is the entirely abstraction-violating way to just grab the raw bytes without /// caring about relocations. It just deduplicates some code between `read_scalar` /// and `get_bytes_internal`. @@ -414,7 +413,7 @@ impl Allocation { } /// Reading and writing. -impl Allocation { +impl Allocation { /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a /// relocation. If `allow_uninit`/`allow_ptr` is `false`, also enforces that the memory in the /// given range contains no uninitialized bytes/relocations. @@ -452,7 +451,7 @@ impl Allocation { cx: &impl HasDataLayout, range: AllocRange, read_provenance: bool, - ) -> AllocResult> { + ) -> AllocResult> { if read_provenance { assert_eq!(range.size, cx.data_layout().pointer_size); } @@ -476,7 +475,7 @@ impl Allocation { // If we are *not* reading a pointer, and we can just ignore relocations, // then do exactly that. - if !read_provenance && Prov::OFFSET_IS_ADDR { + if !read_provenance && Tag::OFFSET_IS_ADDR { // We just strip provenance. let bytes = self.get_bytes_even_more_internal(range); let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap(); @@ -507,7 +506,7 @@ impl Allocation { &mut self, cx: &impl HasDataLayout, range: AllocRange, - val: ScalarMaybeUninit, + val: ScalarMaybeUninit, ) -> AllocResult { assert!(self.mutability == Mutability::Mut); @@ -549,9 +548,9 @@ impl Allocation { } /// Relocations. -impl Allocation { +impl Allocation { /// Returns all relocations overlapping with the given pointer-offset pair. - fn get_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> &[(Size, Prov)] { + fn get_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> &[(Size, Tag)] { // We have to go back `pointer_size - 1` bytes, as that one would still overlap with // the beginning of this range. let start = range.start.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1); @@ -581,7 +580,7 @@ impl Allocation { /// immediately in that case. fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult where - Prov: Provenance, + Tag: Provenance, { // Find the start and end of the given range and its outermost relocations. let (first, last) = { @@ -603,7 +602,7 @@ impl Allocation { // FIXME: Miri should preserve partial relocations; see // https://github.com/rust-lang/miri/issues/2181. if first < start { - if Prov::ERR_ON_PARTIAL_PTR_OVERWRITE { + if Tag::ERR_ON_PARTIAL_PTR_OVERWRITE { return Err(AllocError::PartialPointerOverwrite(first)); } warn!( @@ -612,7 +611,7 @@ impl Allocation { self.init_mask.set_range(first, start, false); } if last > end { - if Prov::ERR_ON_PARTIAL_PTR_OVERWRITE { + if Tag::ERR_ON_PARTIAL_PTR_OVERWRITE { return Err(AllocError::PartialPointerOverwrite( last - cx.data_layout().pointer_size, )); @@ -643,22 +642,22 @@ impl Allocation { /// "Relocations" stores the provenance information of pointers stored in memory. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] -pub struct Relocations(SortedMap); +pub struct Relocations(SortedMap); -impl Relocations { +impl Relocations { pub fn new() -> Self { Relocations(SortedMap::new()) } // The caller must guarantee that the given relocations are already sorted // by address and contain no duplicates. - pub fn from_presorted(r: Vec<(Size, Prov)>) -> Self { + pub fn from_presorted(r: Vec<(Size, Tag)>) -> Self { Relocations(SortedMap::from_presorted_elements(r)) } } -impl Deref for Relocations { - type Target = SortedMap; +impl Deref for Relocations { + type Target = SortedMap; fn deref(&self) -> &Self::Target { &self.0 @@ -668,18 +667,18 @@ impl Deref for Relocations { /// A partial, owned list of relocations to transfer into another allocation. /// /// Offsets are already adjusted to the destination allocation. -pub struct AllocationRelocations { - dest_relocations: Vec<(Size, Prov)>, +pub struct AllocationRelocations { + dest_relocations: Vec<(Size, Tag)>, } -impl Allocation { +impl Allocation { pub fn prepare_relocation_copy( &self, cx: &impl HasDataLayout, src: AllocRange, dest: Size, count: u64, - ) -> AllocationRelocations { + ) -> AllocationRelocations { let relocations = self.get_relocations(cx, src); if relocations.is_empty() { return AllocationRelocations { dest_relocations: Vec::new() }; @@ -689,7 +688,7 @@ impl Allocation { let mut new_relocations = Vec::with_capacity(relocations.len() * (count as usize)); // If `count` is large, this is rather wasteful -- we are allocating a big array here, which - // is mostly filled with redundant information since it's just N copies of the same `Prov`s + // is mostly filled with redundant information since it's just N copies of the same `Tag`s // at slightly adjusted offsets. The reason we do this is so that in `mark_relocation_range` // we can use `insert_presorted`. That wouldn't work with an `Iterator` that just produces // the right sequence of relocations for all N copies. @@ -714,7 +713,7 @@ impl Allocation { /// /// This is dangerous to use as it can violate internal `Allocation` invariants! /// It only exists to support an efficient implementation of `mem_copy_repeatedly`. - pub fn mark_relocation_range(&mut self, relocations: AllocationRelocations) { + pub fn mark_relocation_range(&mut self, relocations: AllocationRelocations) { self.relocations.0.insert_presorted(relocations.dest_relocations); } } @@ -1179,7 +1178,7 @@ impl<'a> Iterator for InitChunkIter<'a> { } /// Uninitialized bytes. -impl Allocation { +impl Allocation { /// Checks whether the given range is entirely initialized. /// /// Returns `Ok(())` if it's initialized. Otherwise returns the range of byte @@ -1227,7 +1226,7 @@ impl InitMaskCompressed { } /// Transferring the initialization mask to other allocations. -impl Allocation { +impl Allocation { /// Creates a run-length encoding of the initialization mask; panics if range is empty. /// /// This is essentially a more space-efficient version of diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index cecb55578d332..795f23edb3186 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,7 +1,7 @@ use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar}; use crate::mir::interpret::ConstValue; -use crate::ty::{layout, query::TyCtxtAt, tls, Ty, ValTree}; +use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree}; use rustc_data_structures::sync::Lock; use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed}; @@ -219,7 +219,7 @@ pub struct ScalarSizeMismatch { } /// Error information for when the program caused Undefined Behavior. -pub enum UndefinedBehaviorInfo { +pub enum UndefinedBehaviorInfo<'tcx> { /// Free-form case. Only for errors that are never caught! Ub(String), /// Unreachable code was executed. @@ -241,6 +241,12 @@ pub enum UndefinedBehaviorInfo { PointerArithOverflow, /// Invalid metadata in a wide pointer (using `str` to avoid allocations). InvalidMeta(&'static str), + /// Invalid drop function in vtable. + InvalidVtableDropFn(FnSig<'tcx>), + /// Invalid size in a vtable: too large. + InvalidVtableSize, + /// Invalid alignment in a vtable: too large, or not a power of 2. + InvalidVtableAlignment(String), /// Reading a C string that does not end within its allocation. UnterminatedCString(Pointer), /// Dereferencing a dangling pointer after it got freed. @@ -265,8 +271,6 @@ pub enum UndefinedBehaviorInfo { WriteToReadOnly(AllocId), // Trying to access the data behind a function pointer. DerefFunctionPointer(AllocId), - // Trying to access the data behind a vtable pointer. - DerefVTablePointer(AllocId), /// The value validity check found a problem. /// Should only be thrown by `validity.rs` and always point out which part of the value /// is the problem. @@ -284,8 +288,6 @@ pub enum UndefinedBehaviorInfo { InvalidTag(Scalar), /// Using a pointer-not-to-a-function as function pointer. InvalidFunctionPointer(Pointer), - /// Using a pointer-not-to-a-vtable as vtable pointer. - InvalidVTablePointer(Pointer), /// Using a string that is not valid UTF-8, InvalidStr(std::str::Utf8Error), /// Using uninitialized data where it is not allowed. @@ -298,7 +300,7 @@ pub enum UndefinedBehaviorInfo { UninhabitedEnumVariantWritten, } -impl fmt::Display for UndefinedBehaviorInfo { +impl fmt::Display for UndefinedBehaviorInfo<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use UndefinedBehaviorInfo::*; match self { @@ -313,6 +315,14 @@ impl fmt::Display for UndefinedBehaviorInfo { RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"), PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"), InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {msg}"), + InvalidVtableDropFn(sig) => write!( + f, + "invalid drop function signature: got {sig}, expected exactly one argument which must be a pointer type", + ), + InvalidVtableSize => { + write!(f, "invalid vtable: size is bigger than largest supported object") + } + InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {msg}"), UnterminatedCString(p) => write!( f, "reading a null-terminated string starting at {p:?} with no null found before end of allocation", @@ -349,7 +359,6 @@ impl fmt::Display for UndefinedBehaviorInfo { ), WriteToReadOnly(a) => write!(f, "writing to {a:?} which is read-only"), DerefFunctionPointer(a) => write!(f, "accessing {a:?} which contains a function"), - DerefVTablePointer(a) => write!(f, "accessing {a:?} which contains a vtable"), ValidationFailure { path: None, msg } => { write!(f, "constructing invalid value: {msg}") } @@ -366,9 +375,6 @@ impl fmt::Display for UndefinedBehaviorInfo { InvalidFunctionPointer(p) => { write!(f, "using {p:?} as function pointer but it does not point to a function") } - InvalidVTablePointer(p) => { - write!(f, "using {p:?} as vtable pointer but it does not point to a vtable") - } InvalidStr(err) => write!(f, "this string is not valid UTF-8: {err}"), InvalidUninitBytes(Some((alloc, info))) => write!( f, @@ -488,7 +494,7 @@ impl dyn MachineStopType { pub enum InterpError<'tcx> { /// The program caused undefined behavior. - UndefinedBehavior(UndefinedBehaviorInfo), + UndefinedBehavior(UndefinedBehaviorInfo<'tcx>), /// The program did something the interpreter does not support (some of these *might* be UB /// but the interpreter is not sure). Unsupported(UnsupportedOpInfo), diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 967f8ece16cf9..698024b23301e 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -196,7 +196,6 @@ impl fmt::Debug for AllocId { enum AllocDiscriminant { Alloc, Fn, - VTable, Static, } @@ -216,12 +215,6 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder>>( AllocDiscriminant::Fn.encode(encoder); fn_instance.encode(encoder); } - GlobalAlloc::VTable(ty, poly_trait_ref) => { - trace!("encoding {:?} with {ty:#?}, {poly_trait_ref:#?}", alloc_id); - AllocDiscriminant::VTable.encode(encoder); - ty.encode(encoder); - poly_trait_ref.encode(encoder); - } GlobalAlloc::Static(did) => { assert!(!tcx.is_thread_local_static(did)); // References to statics doesn't need to know about their allocations, @@ -312,9 +305,7 @@ impl<'s> AllocDecodingSession<'s> { State::InProgress(TinyList::new_single(self.session_id), alloc_id); Some(alloc_id) } - AllocDiscriminant::Fn - | AllocDiscriminant::Static - | AllocDiscriminant::VTable => { + AllocDiscriminant::Fn | AllocDiscriminant::Static => { // Fns and statics cannot be cyclic, and their `AllocId` // is determined later by interning. *entry = @@ -364,16 +355,6 @@ impl<'s> AllocDecodingSession<'s> { let alloc_id = decoder.interner().create_fn_alloc(instance); alloc_id } - AllocDiscriminant::VTable => { - assert!(alloc_id.is_none()); - trace!("creating vtable alloc ID"); - let ty = as Decodable>::decode(decoder); - let poly_trait_ref = - > as Decodable>::decode(decoder); - trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}"); - let alloc_id = decoder.interner().create_vtable_alloc(ty, poly_trait_ref); - alloc_id - } AllocDiscriminant::Static => { assert!(alloc_id.is_none()); trace!("creating extern static alloc ID"); @@ -399,8 +380,6 @@ impl<'s> AllocDecodingSession<'s> { pub enum GlobalAlloc<'tcx> { /// The alloc ID is used as a function pointer. Function(Instance<'tcx>), - /// This alloc ID points to a symbolic (not-reified) vtable. - VTable(Ty<'tcx>, Option>), /// The alloc ID points to a "lazy" static variable that did not get computed (yet). /// This is also used to break the cycle in recursive statics. Static(DefId), @@ -428,16 +407,6 @@ impl<'tcx> GlobalAlloc<'tcx> { _ => bug!("expected function, got {:?}", self), } } - - /// Panics if the `GlobalAlloc` is not `GlobalAlloc::VTable` - #[track_caller] - #[inline] - pub fn unwrap_vtable(&self) -> (Ty<'tcx>, Option>) { - match *self { - GlobalAlloc::VTable(ty, poly_trait_ref) => (ty, poly_trait_ref), - _ => bug!("expected vtable, got {:?}", self), - } - } } pub(crate) struct AllocMap<'tcx> { @@ -485,12 +454,12 @@ impl<'tcx> TyCtxt<'tcx> { } /// Reserves a new ID *if* this allocation has not been dedup-reserved before. - /// Should only be used for "symbolic" allocations (function pointers, vtables, statics), we - /// don't want to dedup IDs for "real" memory! + /// Should only be used for function pointers and statics, we don't want + /// to dedup IDs for "real" memory! fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId { let mut alloc_map = self.alloc_map.lock(); match alloc { - GlobalAlloc::Function(..) | GlobalAlloc::Static(..) | GlobalAlloc::VTable(..) => {} + GlobalAlloc::Function(..) | GlobalAlloc::Static(..) => {} GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"), } if let Some(&alloc_id) = alloc_map.dedup.get(&alloc) { @@ -535,15 +504,6 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated. - pub fn create_vtable_alloc( - self, - ty: Ty<'tcx>, - poly_trait_ref: Option>, - ) -> AllocId { - self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, poly_trait_ref)) - } - /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical /// `Allocation` with a different `AllocId`. /// Statics with identical content will still point to the same `Allocation`, i.e., @@ -561,7 +521,7 @@ impl<'tcx> TyCtxt<'tcx> { /// This function exists to allow const eval to detect the difference between evaluation- /// local dangling pointers and allocations in constants/statics. #[inline] - pub fn try_get_global_alloc(self, id: AllocId) -> Option> { + pub fn get_global_alloc(self, id: AllocId) -> Option> { self.alloc_map.lock().alloc_map.get(&id).cloned() } @@ -572,7 +532,7 @@ impl<'tcx> TyCtxt<'tcx> { /// ids), this function is frequently used throughout rustc, but should not be used within /// the miri engine. pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> { - match self.try_get_global_alloc(id) { + match self.get_global_alloc(id) { Some(alloc) => alloc, None => bug!("could not find allocation for {id:?}"), } diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 384954cbbd5f7..d4cdf45d18661 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -159,34 +159,34 @@ impl Provenance for AllocId { /// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)] #[derive(HashStable)] -pub struct Pointer { - pub(super) offset: Size, // kept private to avoid accidental misinterpretation (meaning depends on `Prov` type) - pub provenance: Prov, +pub struct Pointer { + pub(super) offset: Size, // kept private to avoid accidental misinterpretation (meaning depends on `Tag` type) + pub provenance: Tag, } static_assert_size!(Pointer, 16); -// `Option` pointers are also passed around quite a bit +// `Option` pointers are also passed around quite a bit // (but not stored in permanent machine state). static_assert_size!(Pointer>, 16); // We want the `Debug` output to be readable as it is used by `derive(Debug)` for // all the Miri types. -impl fmt::Debug for Pointer { +impl fmt::Debug for Pointer { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Provenance::fmt(self, f) } } -impl fmt::Debug for Pointer> { +impl fmt::Debug for Pointer> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.provenance { - Some(prov) => Provenance::fmt(&Pointer::new(prov, self.offset), f), + Some(tag) => Provenance::fmt(&Pointer::new(tag, self.offset), f), None => write!(f, "{:#x}[noalloc]", self.offset.bytes()), } } } -impl fmt::Display for Pointer> { +impl fmt::Display for Pointer> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.provenance.is_none() && self.offset.bytes() == 0 { write!(f, "null pointer") @@ -204,38 +204,38 @@ impl From for Pointer { } } -impl From> for Pointer> { +impl From> for Pointer> { #[inline(always)] - fn from(ptr: Pointer) -> Self { - let (prov, offset) = ptr.into_parts(); - Pointer::new(Some(prov), offset) + fn from(ptr: Pointer) -> Self { + let (tag, offset) = ptr.into_parts(); + Pointer::new(Some(tag), offset) } } -impl Pointer> { - /// Convert this pointer that *might* have a provenance into a pointer that *definitely* has a - /// provenance, or an absolute address. +impl Pointer> { + /// Convert this pointer that *might* have a tag into a pointer that *definitely* has a tag, or + /// an absolute address. /// /// This is rarely what you want; call `ptr_try_get_alloc_id` instead. - pub fn into_pointer_or_addr(self) -> Result, Size> { + pub fn into_pointer_or_addr(self) -> Result, Size> { match self.provenance { - Some(prov) => Ok(Pointer::new(prov, self.offset)), + Some(tag) => Ok(Pointer::new(tag, self.offset)), None => Err(self.offset), } } /// Returns the absolute address the pointer points to. - /// Only works if Prov::OFFSET_IS_ADDR is true! + /// Only works if Tag::OFFSET_IS_ADDR is true! pub fn addr(self) -> Size where - Prov: Provenance, + Tag: Provenance, { - assert!(Prov::OFFSET_IS_ADDR); + assert!(Tag::OFFSET_IS_ADDR); self.offset } } -impl Pointer> { +impl Pointer> { #[inline(always)] pub fn from_addr(addr: u64) -> Self { Pointer { provenance: None, offset: Size::from_bytes(addr) } @@ -247,21 +247,21 @@ impl Pointer> { } } -impl<'tcx, Prov> Pointer { +impl<'tcx, Tag> Pointer { #[inline(always)] - pub fn new(provenance: Prov, offset: Size) -> Self { + pub fn new(provenance: Tag, offset: Size) -> Self { Pointer { provenance, offset } } - /// Obtain the constituents of this pointer. Not that the meaning of the offset depends on the type `Prov`! + /// Obtain the constituents of this pointer. Not that the meaning of the offset depends on the type `Tag`! /// This function must only be used in the implementation of `Machine::ptr_get_alloc`, /// and when a `Pointer` is taken apart to be stored efficiently in an `Allocation`. #[inline(always)] - pub fn into_parts(self) -> (Prov, Size) { + pub fn into_parts(self) -> (Tag, Size) { (self.provenance, self.offset) } - pub fn map_provenance(self, f: impl FnOnce(Prov) -> Prov) -> Self { + pub fn map_provenance(self, f: impl FnOnce(Tag) -> Tag) -> Self { Pointer { provenance: f(self.provenance), ..self } } diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 834c114ee1c58..22bbe29c10555 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -126,7 +126,7 @@ impl<'tcx> ConstValue<'tcx> { /// Do *not* match on a `Scalar`! Use the various `to_*` methods instead. #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)] #[derive(HashStable)] -pub enum Scalar { +pub enum Scalar { /// The raw bytes of a simple value. Int(ScalarInt), @@ -137,7 +137,7 @@ pub enum Scalar { /// We also store the size of the pointer, such that a `Scalar` always knows how big it is. /// The size is always the pointer size of the current target, but this is not information /// that we always have readily available. - Ptr(Pointer, u8), + Ptr(Pointer, u8), } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] @@ -145,7 +145,7 @@ static_assert_size!(Scalar, 24); // We want the `Debug` output to be readable as it is used by `derive(Debug)` for // all the Miri types. -impl fmt::Debug for Scalar { +impl fmt::Debug for Scalar { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Scalar::Ptr(ptr, _size) => write!(f, "{:?}", ptr), @@ -154,7 +154,7 @@ impl fmt::Debug for Scalar { } } -impl fmt::Display for Scalar { +impl fmt::Display for Scalar { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr), @@ -163,7 +163,7 @@ impl fmt::Display for Scalar { } } -impl fmt::LowerHex for Scalar { +impl fmt::LowerHex for Scalar { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr), @@ -172,38 +172,37 @@ impl fmt::LowerHex for Scalar { } } -impl From for Scalar { +impl From for Scalar { #[inline(always)] fn from(f: Single) -> Self { Scalar::from_f32(f) } } -impl From for Scalar { +impl From for Scalar { #[inline(always)] fn from(f: Double) -> Self { Scalar::from_f64(f) } } -impl From for Scalar { +impl From for Scalar { #[inline(always)] fn from(ptr: ScalarInt) -> Self { Scalar::Int(ptr) } } -impl Scalar { +impl Scalar { #[inline(always)] - pub fn from_pointer(ptr: Pointer, cx: &impl HasDataLayout) -> Self { + pub fn from_pointer(ptr: Pointer, cx: &impl HasDataLayout) -> Self { Scalar::Ptr(ptr, u8::try_from(cx.pointer_size().bytes()).unwrap()) } - /// Create a Scalar from a pointer with an `Option<_>` provenance (where `None` represents a - /// plain integer / "invalid" pointer). - pub fn from_maybe_pointer(ptr: Pointer>, cx: &impl HasDataLayout) -> Self { + /// Create a Scalar from a pointer with an `Option<_>` tag (where `None` represents a plain integer). + pub fn from_maybe_pointer(ptr: Pointer>, cx: &impl HasDataLayout) -> Self { match ptr.into_parts() { - (Some(prov), offset) => Scalar::from_pointer(Pointer::new(prov, offset), cx), + (Some(tag), offset) => Scalar::from_pointer(Pointer::new(tag, offset), cx), (None, offset) => { Scalar::Int(ScalarInt::try_from_uint(offset.bytes(), cx.pointer_size()).unwrap()) } @@ -311,7 +310,7 @@ impl Scalar { pub fn to_bits_or_ptr_internal( self, target_size: Size, - ) -> Result>, ScalarSizeMismatch> { + ) -> Result>, ScalarSizeMismatch> { assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); Ok(match self { Scalar::Int(int) => Ok(int.to_bits(target_size).map_err(|size| { @@ -330,20 +329,7 @@ impl Scalar { } } -impl<'tcx, Prov: Provenance> Scalar { - pub fn to_pointer(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, Pointer>> { - match self - .to_bits_or_ptr_internal(cx.pointer_size()) - .map_err(|s| err_ub!(ScalarSizeMismatch(s)))? - { - Err(ptr) => Ok(ptr.into()), - Ok(bits) => { - let addr = u64::try_from(bits).unwrap(); - Ok(Pointer::from_addr(addr)) - } - } - } - +impl<'tcx, Tag: Provenance> Scalar { /// Fundamental scalar-to-int (cast) operation. Many convenience wrappers exist below, that you /// likely want to use instead. /// @@ -355,13 +341,13 @@ impl<'tcx, Prov: Provenance> Scalar { match self { Scalar::Int(int) => Ok(int), Scalar::Ptr(ptr, sz) => { - if Prov::OFFSET_IS_ADDR { + if Tag::OFFSET_IS_ADDR { Ok(ScalarInt::try_from_uint(ptr.offset.bytes(), Size::from_bytes(sz)).unwrap()) } else { // We know `offset` is relative, since `OFFSET_IS_ADDR == false`. - let (prov, offset) = ptr.into_parts(); + let (tag, offset) = ptr.into_parts(); // Because `OFFSET_IS_ADDR == false`, this unwrap can never fail. - Err(Scalar::Ptr(Pointer::new(prov.get_alloc_id().unwrap(), offset), sz)) + Err(Scalar::Ptr(Pointer::new(tag.get_alloc_id().unwrap(), offset), sz)) } } } @@ -503,24 +489,24 @@ impl<'tcx, Prov: Provenance> Scalar { } #[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, HashStable, Hash)] -pub enum ScalarMaybeUninit { - Scalar(Scalar), +pub enum ScalarMaybeUninit { + Scalar(Scalar), Uninit, } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(ScalarMaybeUninit, 24); -impl From> for ScalarMaybeUninit { +impl From> for ScalarMaybeUninit { #[inline(always)] - fn from(s: Scalar) -> Self { + fn from(s: Scalar) -> Self { ScalarMaybeUninit::Scalar(s) } } // We want the `Debug` output to be readable as it is used by `derive(Debug)` for // all the Miri types. -impl fmt::Debug for ScalarMaybeUninit { +impl fmt::Debug for ScalarMaybeUninit { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ScalarMaybeUninit::Uninit => write!(f, ""), @@ -529,7 +515,7 @@ impl fmt::Debug for ScalarMaybeUninit { } } -impl fmt::LowerHex for ScalarMaybeUninit { +impl fmt::LowerHex for ScalarMaybeUninit { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ScalarMaybeUninit::Uninit => write!(f, "uninitialized bytes"), @@ -538,19 +524,19 @@ impl fmt::LowerHex for ScalarMaybeUninit { } } -impl ScalarMaybeUninit { +impl ScalarMaybeUninit { #[inline] - pub fn from_pointer(ptr: Pointer, cx: &impl HasDataLayout) -> Self { + pub fn from_pointer(ptr: Pointer, cx: &impl HasDataLayout) -> Self { ScalarMaybeUninit::Scalar(Scalar::from_pointer(ptr, cx)) } #[inline] - pub fn from_maybe_pointer(ptr: Pointer>, cx: &impl HasDataLayout) -> Self { + pub fn from_maybe_pointer(ptr: Pointer>, cx: &impl HasDataLayout) -> Self { ScalarMaybeUninit::Scalar(Scalar::from_maybe_pointer(ptr, cx)) } #[inline] - pub fn check_init<'tcx>(self) -> InterpResult<'tcx, Scalar> { + pub fn check_init<'tcx>(self) -> InterpResult<'tcx, Scalar> { match self { ScalarMaybeUninit::Scalar(scalar) => Ok(scalar), ScalarMaybeUninit::Uninit => throw_ub!(InvalidUninitBytes(None)), @@ -558,12 +544,7 @@ impl ScalarMaybeUninit { } } -impl<'tcx, Prov: Provenance> ScalarMaybeUninit { - #[inline(always)] - pub fn to_pointer(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, Pointer>> { - self.check_init()?.to_pointer(cx) - } - +impl<'tcx, Tag: Provenance> ScalarMaybeUninit { #[inline(always)] pub fn to_bool(self) -> InterpResult<'tcx, bool> { self.check_init()?.to_bool() diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index f7311ebdabfd9..f61cb7e8c472e 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1461,14 +1461,6 @@ impl<'tcx> Place<'tcx> { self.projection.iter().any(|elem| elem.is_indirect()) } - /// If MirPhase >= Derefered and if projection contains Deref, - /// It's guaranteed to be in the first place - pub fn has_deref(&self) -> bool { - // To make sure this is not accidently used in wrong mir phase - debug_assert!(!self.projection[1..].contains(&PlaceElem::Deref)); - self.projection.first() == Some(&PlaceElem::Deref) - } - /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or /// a single deref of a local. #[inline(always)] @@ -1541,12 +1533,6 @@ impl<'tcx> PlaceRef<'tcx> { } } - /// If MirPhase >= Derefered and if projection contains Deref, - /// It's guaranteed to be in the first place - pub fn has_deref(&self) -> bool { - self.projection.first() == Some(&PlaceElem::Deref) - } - /// If this place represents a local variable like `_X` with no /// projections, return `Some(_X)`. #[inline] @@ -1676,22 +1662,6 @@ impl SourceScope { ClearCrossCrate::Clear => None, } } - - /// The instance this source scope was inlined from, if any. - #[inline] - pub fn inlined_instance<'tcx>( - self, - source_scopes: &IndexVec>, - ) -> Option> { - let scope_data = &source_scopes[self]; - if let Some((inlined_instance, _)) = scope_data.inlined { - Some(inlined_instance) - } else if let Some(inlined_scope) = scope_data.inlined_parent_scope { - Some(source_scopes[inlined_scope].inlined.unwrap().0) - } else { - None - } - } } #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 21ae121e1ce69..8b51c5b3da50a 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -362,7 +362,7 @@ impl<'tcx> CodegenUnit<'tcx> { // the codegen tests and can even make item order // unstable. InstanceDef::Item(def) => def.did.as_local().map(Idx::index), - InstanceDef::VTableShim(..) + InstanceDef::VtableShim(..) | InstanceDef::ReifyShim(..) | InstanceDef::Intrinsic(..) | InstanceDef::FnPtrShim(..) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 0ce41337b910d..970043d427ff2 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -360,7 +360,7 @@ where "{:A$} // {}{}", indented_body, if tcx.sess.verbose() { format!("{:?}: ", current_location) } else { String::new() }, - comment(tcx, statement.source_info, body.span), + comment(tcx, statement.source_info), A = ALIGN, )?; @@ -381,7 +381,7 @@ where "{:A$} // {}{}", indented_terminator, if tcx.sess.verbose() { format!("{:?}: ", current_location) } else { String::new() }, - comment(tcx, data.terminator().source_info, body.span), + comment(tcx, data.terminator().source_info), A = ALIGN, )?; @@ -518,14 +518,8 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { } } -fn comment(tcx: TyCtxt<'_>, SourceInfo { span, scope }: SourceInfo, function_span: Span) -> String { - let location = if tcx.sess.opts.unstable_opts.mir_pretty_relative_line_numbers { - tcx.sess.source_map().span_to_relative_line_string(span, function_span) - } else { - tcx.sess.source_map().span_to_embeddable_string(span) - }; - - format!("scope {} at {}", scope.index(), location,) +fn comment(tcx: TyCtxt<'_>, SourceInfo { span, scope }: SourceInfo) -> String { + format!("scope {} at {}", scope.index(), tcx.sess.source_map().span_to_embeddable_string(span)) } /// Prints local variables in a scope tree. @@ -556,7 +550,7 @@ fn write_scope_tree( "{0:1$} // in {2}", indented_debug_info, ALIGN, - comment(tcx, var_debug_info.source_info, body.span), + comment(tcx, var_debug_info.source_info), )?; } @@ -591,7 +585,7 @@ fn write_scope_tree( indented_decl, ALIGN, local_name, - comment(tcx, local_decl.source_info, body.span), + comment(tcx, local_decl.source_info), )?; } @@ -726,17 +720,11 @@ pub fn write_allocations<'tcx>( write!(w, "{}", display_allocation(tcx, alloc.inner())) }; write!(w, "\n{id:?}")?; - match tcx.try_get_global_alloc(id) { + match tcx.get_global_alloc(id) { // This can't really happen unless there are bugs, but it doesn't cost us anything to // gracefully handle it and allow buggy rustc to be debugged via allocation printing. None => write!(w, " (deallocated)")?, Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {inst})")?, - Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => { - write!(w, " (vtable: impl {trait_ref} for {ty})")? - } - Some(GlobalAlloc::VTable(ty, None)) => { - write!(w, " (vtable: impl for {ty})")? - } Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { match tcx.eval_static_initializer(did) { Ok(alloc) => { @@ -779,21 +767,21 @@ pub fn write_allocations<'tcx>( /// After the hex dump, an ascii dump follows, replacing all unprintable characters (control /// characters or characters whose value is larger than 127) with a `.` /// This also prints relocations adequately. -pub fn display_allocation<'a, 'tcx, Prov, Extra>( +pub fn display_allocation<'a, 'tcx, Tag, Extra>( tcx: TyCtxt<'tcx>, - alloc: &'a Allocation, -) -> RenderAllocation<'a, 'tcx, Prov, Extra> { + alloc: &'a Allocation, +) -> RenderAllocation<'a, 'tcx, Tag, Extra> { RenderAllocation { tcx, alloc } } #[doc(hidden)] -pub struct RenderAllocation<'a, 'tcx, Prov, Extra> { +pub struct RenderAllocation<'a, 'tcx, Tag, Extra> { tcx: TyCtxt<'tcx>, - alloc: &'a Allocation, + alloc: &'a Allocation, } -impl<'a, 'tcx, Prov: Provenance, Extra> std::fmt::Display - for RenderAllocation<'a, 'tcx, Prov, Extra> +impl<'a, 'tcx, Tag: Provenance, Extra> std::fmt::Display + for RenderAllocation<'a, 'tcx, Tag, Extra> { fn fmt(&self, w: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let RenderAllocation { tcx, alloc } = *self; @@ -837,9 +825,9 @@ fn write_allocation_newline( /// The `prefix` argument allows callers to add an arbitrary prefix before each line (even if there /// is only one line). Note that your prefix should contain a trailing space as the lines are /// printed directly after it. -fn write_allocation_bytes<'tcx, Prov: Provenance, Extra>( +fn write_allocation_bytes<'tcx, Tag: Provenance, Extra>( tcx: TyCtxt<'tcx>, - alloc: &Allocation, + alloc: &Allocation, w: &mut dyn std::fmt::Write, prefix: &str, ) -> std::fmt::Result { @@ -873,7 +861,7 @@ fn write_allocation_bytes<'tcx, Prov: Provenance, Extra>( if i != line_start { write!(w, " ")?; } - if let Some(&prov) = alloc.relocations().get(&i) { + if let Some(&tag) = alloc.relocations().get(&i) { // Memory with a relocation must be defined assert!(alloc.init_mask().is_range_initialized(i, i + ptr_size).is_ok()); let j = i.bytes_usize(); @@ -882,7 +870,7 @@ fn write_allocation_bytes<'tcx, Prov: Provenance, Extra>( let offset = read_target_uint(tcx.data_layout.endian, offset).unwrap(); let offset = Size::from_bytes(offset); let relocation_width = |bytes| bytes * 3; - let ptr = Pointer::new(prov, offset); + let ptr = Pointer::new(tag, offset); let mut target = format!("{:?}", ptr); if target.len() > relocation_width(ptr_size.bytes_usize() - 1) { // This is too long, try to save some space. diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index dd9f8795f94ff..423e84d88cf73 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -2,7 +2,7 @@ use crate::mir::{Body, ConstantKind, Promoted}; use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_map::FxHashMap; use rustc_data_structures::vec_map::VecMap; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; diff --git a/compiler/rustc_middle/src/mir/switch_sources.rs b/compiler/rustc_middle/src/mir/switch_sources.rs index b91c0c25782f4..d1f3e6b6fe6bd 100644 --- a/compiler/rustc_middle/src/mir/switch_sources.rs +++ b/compiler/rustc_middle/src/mir/switch_sources.rs @@ -1,8 +1,8 @@ //! Lazily compute the inverse of each `SwitchInt`'s switch targets. Modeled after //! `Predecessors`/`PredecessorCache`. -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stable_map::FxHashMap; use rustc_data_structures::sync::OnceCell; use rustc_index::vec::IndexVec; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 891608764017c..d285728ec0783 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -394,7 +394,7 @@ macro_rules! make_mir_visitor { ty::InstanceDef::Item(_def_id) => {} ty::InstanceDef::Intrinsic(_def_id) | - ty::InstanceDef::VTableShim(_def_id) | + ty::InstanceDef::VtableShim(_def_id) | ty::InstanceDef::ReifyShim(_def_id) | ty::InstanceDef::Virtual(_def_id, _) | ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 72b848c3ee2dd..75559d4f8b843 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -311,10 +311,18 @@ pub enum ObligationCauseCode<'tcx> { }, /// Error derived when matching traits/impls; see ObligationCause for more details - CompareImplItemObligation { + CompareImplConstObligation, + + /// Error derived when matching traits/impls; see ObligationCause for more details + CompareImplMethodObligation { + impl_item_def_id: LocalDefId, + trait_item_def_id: DefId, + }, + + /// Error derived when matching traits/impls; see ObligationCause for more details + CompareImplTypeObligation { impl_item_def_id: LocalDefId, trait_item_def_id: DefId, - kind: ty::AssocKind, }, /// Checking that the bounds of a trait's associated type hold for a given impl @@ -343,7 +351,7 @@ pub enum ObligationCauseCode<'tcx> { ConstPatternStructural, /// Computing common supertype in an if expression - IfExpression(Box>), + IfExpression(Box), /// Computing common supertype of an if expression with no else counter-part IfExpressionWithNoElse, @@ -480,27 +488,22 @@ impl<'tcx> ty::Lift<'tcx> for StatementAsExpression { #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] pub struct MatchExpressionArmCause<'tcx> { - pub arm_block_id: Option, - pub arm_ty: Ty<'tcx>, pub arm_span: Span, - pub prior_arm_block_id: Option, - pub prior_arm_ty: Ty<'tcx>, - pub prior_arm_span: Span, pub scrut_span: Span, + pub semi_span: Option<(Span, StatementAsExpression)>, pub source: hir::MatchSource, pub prior_arms: Vec, + pub last_ty: Ty<'tcx>, pub scrut_hir_id: hir::HirId, pub opt_suggest_box_span: Option, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(Lift, TypeFoldable, TypeVisitable)] -pub struct IfExpressionCause<'tcx> { - pub then_id: hir::HirId, - pub else_id: hir::HirId, - pub then_ty: Ty<'tcx>, - pub else_ty: Ty<'tcx>, - pub outer_span: Option, +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct IfExpressionCause { + pub then: Span, + pub else_sp: Span, + pub outer: Option, + pub semicolon: Option<(Span, StatementAsExpression)>, pub opt_suggest_box_span: Option, } diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs index 7fbd57ac7354a..8f1a1564fc8e8 100644 --- a/compiler/rustc_middle/src/traits/structural_impls.rs +++ b/compiler/rustc_middle/src/traits/structural_impls.rs @@ -130,6 +130,7 @@ impl fmt::Debug for traits::ImplSourceConstDestructData { // Lift implementations TrivialTypeTraversalAndLiftImpls! { + super::IfExpressionCause, super::ImplSourceDiscriminantKindData, super::ImplSourcePointeeData, } diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs index d54b8c599d954..8ce428c9799f5 100644 --- a/compiler/rustc_middle/src/traits/util.rs +++ b/compiler/rustc_middle/src/traits/util.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use crate::ty::{PolyTraitRef, TyCtxt}; diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index eb732148e3eb4..2c93af506679d 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -105,16 +105,6 @@ impl AssocKind { } } -impl std::fmt::Display for AssocKind { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - AssocKind::Fn => write!(f, "method"), - AssocKind::Const => write!(f, "associated const"), - AssocKind::Type => write!(f, "associated type"), - } - } -} - /// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name. /// /// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 51137c52659db..e6ea3d8885376 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -523,5 +523,4 @@ impl_binder_encode_decode! { ty::ExistentialPredicate<'tcx>, ty::TraitRef<'tcx>, Vec>, - ty::ExistentialTraitRef<'tcx>, } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index f8792edc017b2..a4e7a12bba323 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -203,7 +203,7 @@ impl<'tcx> Const<'tcx> { pub fn to_valtree(self) -> ty::ValTree<'tcx> { match self.kind() { ty::ConstKind::Value(valtree) => valtree, - _ => bug!("expected ConstKind::Value, got {:?}", self.kind()), + _ => bug!("expected ConstKind::Value"), } } diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 93707bb18ceec..973dc3dd4a10a 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -80,25 +80,33 @@ impl<'tcx> ValTree<'tcx> { } /// Get the values inside the ValTree as a slice of bytes. This only works for - /// constants with types &str, &[u8], or [u8; _]. + /// constants with types &str and &[u8]. pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx [u8]> { match ty.kind() { ty::Ref(_, inner_ty, _) => match inner_ty.kind() { - // `&str` can be interpreted as raw bytes - ty::Str => {} - // `&[u8]` can be interpreted as raw bytes - ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {} - // other `&_` can't be interpreted as raw bytes - _ => return None, + ty::Str => { + let leafs = self + .unwrap_branch() + .into_iter() + .map(|v| v.unwrap_leaf().try_to_u8().unwrap()) + .collect::>(); + + return Some(tcx.arena.alloc_from_iter(leafs.into_iter())); + } + ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => { + let leafs = self + .unwrap_branch() + .into_iter() + .map(|v| v.unwrap_leaf().try_to_u8().unwrap()) + .collect::>(); + + return Some(tcx.arena.alloc_from_iter(leafs.into_iter())); + } + _ => {} }, - // `[u8; N]` can be interpreted as raw bytes - ty::Array(array_ty, _) if *array_ty == tcx.types.u8 => {} - // Otherwise, type cannot be interpreted as raw bytes - _ => return None, + _ => {} } - Some(tcx.arena.alloc_from_iter( - self.unwrap_branch().into_iter().map(|v| v.unwrap_leaf().try_to_u8().unwrap()), - )) + None } } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index dd2f43210603a..25bc6dc616784 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use crate::ty::{ - visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferConst, InferTy, + visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy, PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, }; @@ -82,18 +82,15 @@ pub trait IsSuggestable<'tcx> { /// meaningful rendered suggestions when pretty-printed. We leave some /// nonsense, such as region vars, since those render as `'_` and are /// usually okay to reinterpret as elided lifetimes. - /// - /// Only if `infer_suggestable` is true, we consider type and const - /// inference variables to be suggestable. - fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool; + fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool; } impl<'tcx, T> IsSuggestable<'tcx> for T where T: TypeVisitable<'tcx>, { - fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool { - self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue() + fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool { + self.visit_with(&mut IsSuggestableVisitor { tcx }).is_continue() } } @@ -103,7 +100,7 @@ pub fn suggest_arbitrary_trait_bound<'tcx>( err: &mut Diagnostic, trait_pred: PolyTraitPredicate<'tcx>, ) -> bool { - if !trait_pred.is_suggestable(tcx, false) { + if !trait_pred.is_suggestable(tcx) { return false; } @@ -422,7 +419,6 @@ impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> { pub struct IsSuggestableVisitor<'tcx> { tcx: TyCtxt<'tcx>, - infer_suggestable: bool, } impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { @@ -430,8 +426,6 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { - Infer(InferTy::TyVar(_)) if self.infer_suggestable => {} - FnDef(..) | Closure(..) | Infer(..) @@ -485,8 +479,6 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow { match c.kind() { - ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => {} - ConstKind::Infer(..) | ConstKind::Bound(..) | ConstKind::Placeholder(..) diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 91246051316fa..49a518b101dd1 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -660,8 +660,12 @@ impl Trait for X { | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }), ) ); - let impl_comparison = - matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. }); + let impl_comparison = matches!( + cause_code, + ObligationCauseCode::CompareImplMethodObligation { .. } + | ObligationCauseCode::CompareImplTypeObligation { .. } + | ObligationCauseCode::CompareImplConstObligation + ); let assoc = self.associated_item(proj_ty.item_def_id); if !callable_scope || impl_comparison { // We do not want to suggest calling functions when the reason of the diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index 263d64a57776a..88397a2bb56ba 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -147,15 +147,15 @@ impl<'a> HashStable> for mir::interpret::AllocId { ty::tls::with_opt(|tcx| { trace!("hashing {:?}", *self); let tcx = tcx.expect("can't hash AllocIds during hir lowering"); - tcx.try_get_global_alloc(*self).hash_stable(hcx, hasher); + tcx.get_global_alloc(*self).hash_stable(hcx, hasher); }); } } // `Relocations` with default type parameters is a sorted map. -impl<'a, Prov> HashStable> for mir::interpret::Relocations +impl<'a, Tag> HashStable> for mir::interpret::Relocations where - Prov: HashStable>, + Tag: HashStable>, { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.len().hash_stable(hcx, hasher); diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 33a46f809b0d3..4f9bbc135ec12 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -49,7 +49,7 @@ pub enum InstanceDef<'tcx> { /// /// The generated shim will take `Self` via `*mut Self` - conceptually this is `&owned Self` - /// and dereference the argument to call the original function. - VTableShim(DefId), + VtableShim(DefId), /// `fn()` pointer where the function itself cannot be turned into a pointer. /// @@ -145,7 +145,7 @@ impl<'tcx> InstanceDef<'tcx> { pub fn def_id(self) -> DefId { match self { InstanceDef::Item(def) => def.did, - InstanceDef::VTableShim(def_id) + InstanceDef::VtableShim(def_id) | InstanceDef::ReifyShim(def_id) | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) @@ -161,7 +161,7 @@ impl<'tcx> InstanceDef<'tcx> { match self { ty::InstanceDef::Item(def) => Some(def.did), ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id), - InstanceDef::VTableShim(..) + InstanceDef::VtableShim(..) | InstanceDef::ReifyShim(..) | InstanceDef::FnPtrShim(..) | InstanceDef::Virtual(..) @@ -176,7 +176,7 @@ impl<'tcx> InstanceDef<'tcx> { pub fn with_opt_param(self) -> ty::WithOptConstParam { match self { InstanceDef::Item(def) => def, - InstanceDef::VTableShim(def_id) + InstanceDef::VtableShim(def_id) | InstanceDef::ReifyShim(def_id) | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) @@ -273,7 +273,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::Intrinsic(..) | InstanceDef::ReifyShim(..) | InstanceDef::Virtual(..) - | InstanceDef::VTableShim(..) => true, + | InstanceDef::VtableShim(..) => true, } } } @@ -290,7 +290,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> { match self.def { InstanceDef::Item(_) => Ok(()), - InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"), + InstanceDef::VtableShim(_) => write!(f, " - shim(vtable)"), InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"), InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"), InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num), @@ -434,7 +434,7 @@ impl<'tcx> Instance<'tcx> { && tcx.generics_of(def_id).has_self; if is_vtable_shim { debug!(" => associated item with unsizeable self: Self"); - Some(Instance { def: InstanceDef::VTableShim(def_id), substs }) + Some(Instance { def: InstanceDef::VtableShim(def_id), substs }) } else { Instance::resolve(tcx, param_env, def_id, substs).ok().flatten().map(|mut resolved| { match resolved.def { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index dde55dd96554b..4491965347bd6 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2618,14 +2618,14 @@ where // Use conservative pointer kind if not optimizing. This saves us the // Freeze/Unpin queries, and can save time in the codegen backend (noalias // attributes in LLVM have compile-time cost even in unoptimized builds). - PointerKind::SharedMutable + PointerKind::Shared } else { match mt { hir::Mutability::Not => { if ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env()) { PointerKind::Frozen } else { - PointerKind::SharedMutable + PointerKind::Shared } } hir::Mutability::Mut => { @@ -2636,7 +2636,7 @@ where if ty.is_unpin(tcx.at(DUMMY_SP), cx.param_env()) { PointerKind::UniqueBorrowed } else { - PointerKind::UniqueBorrowedPinned + PointerKind::Shared } } } @@ -2771,7 +2771,7 @@ impl<'tcx> ty::Instance<'tcx> { _ => unreachable!(), }; - if let ty::InstanceDef::VTableShim(..) = self.def { + if let ty::InstanceDef::VtableShim(..) = self.def { // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`. sig = sig.map_bound(|mut sig| { let mut inputs_and_output = sig.inputs_and_output.to_vec(); @@ -3255,13 +3255,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable // for the entire duration of the function as they can be deallocated - // at any time. Same for shared mutable references. If LLVM had a - // way to say "dereferenceable on entry" we could use it here. + // at any time. Set their valid size to 0. attrs.pointee_size = match kind { - PointerKind::UniqueBorrowed - | PointerKind::UniqueBorrowedPinned - | PointerKind::Frozen => pointee.size, - PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO, + PointerKind::UniqueOwned => Size::ZERO, + _ => pointee.size, }; // `Box`, `&T`, and `&mut T` cannot be undef. @@ -3288,9 +3285,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // or not to actually emit the attribute. It can also be controlled with the // `-Zmutable-noalias` debugging option. let no_alias = match kind { - PointerKind::SharedMutable - | PointerKind::UniqueBorrowed - | PointerKind::UniqueBorrowedPinned => false, + PointerKind::Shared | PointerKind::UniqueBorrowed => false, PointerKind::UniqueOwned => noalias_for_box, PointerKind::Frozen => !is_return, }; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 31c523aaca9ae..53919826bf617 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -575,19 +575,6 @@ impl<'tcx> Predicate<'tcx> { Some(tcx.mk_predicate(kind)) } - - pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> Self { - if let PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) = self.kind().skip_binder() - && constness != BoundConstness::NotConst - { - self = tcx.mk_predicate(self.kind().rebind(PredicateKind::Trait(TraitPredicate { - trait_ref, - constness: BoundConstness::NotConst, - polarity, - }))); - } - self - } } impl<'a, 'tcx> HashStable> for Predicate<'tcx> { @@ -803,15 +790,22 @@ pub struct TraitPredicate<'tcx> { pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>; impl<'tcx> TraitPredicate<'tcx> { - pub fn remap_constness(&mut self, param_env: &mut ParamEnv<'tcx>) { - *param_env = param_env.with_constness(self.constness.and(param_env.constness())) + pub fn remap_constness(&mut self, tcx: TyCtxt<'tcx>, param_env: &mut ParamEnv<'tcx>) { + if std::intrinsics::unlikely(Some(self.trait_ref.def_id) == tcx.lang_items().drop_trait()) { + // remap without changing constness of this predicate. + // this is because `T: ~const Drop` has a different meaning to `T: Drop` + // FIXME(fee1-dead): remove this logic after beta bump + param_env.remap_constness_with(self.constness) + } else { + *param_env = param_env.with_constness(self.constness.and(param_env.constness())) + } } /// Remap the constness of this predicate before emitting it for diagnostics. pub fn remap_constness_diag(&mut self, param_env: ParamEnv<'tcx>) { // this is different to `remap_constness` that callees want to print this predicate // in case of selection errors. `T: ~const Drop` bounds cannot end up here when the - // param_env is not const because it is always satisfied in non-const contexts. + // param_env is not const because we it is always satisfied in non-const contexts. if let hir::Constness::NotConst = param_env.constness() { self.constness = ty::BoundConstness::NotConst; } @@ -829,14 +823,6 @@ impl<'tcx> TraitPredicate<'tcx> { pub fn is_const_if_const(self) -> bool { self.constness == BoundConstness::ConstIfConst } - - pub fn is_constness_satisfied_by(self, constness: hir::Constness) -> bool { - match (self.constness, constness) { - (BoundConstness::NotConst, _) - | (BoundConstness::ConstIfConst, hir::Constness::Const) => true, - (BoundConstness::ConstIfConst, hir::Constness::NotConst) => false, - } - } } impl<'tcx> PolyTraitPredicate<'tcx> { @@ -2149,7 +2135,7 @@ impl<'tcx> TyCtxt<'tcx> { } } } - ty::InstanceDef::VTableShim(..) + ty::InstanceDef::VtableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::FnPtrShim(..) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 7f2e81a71a93d..96e84bc8f0acf 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1269,7 +1269,7 @@ pub trait PrettyPrinter<'tcx>: if let ty::Array(elem, len) = inner.kind() { if let ty::Uint(ty::UintTy::U8) = elem.kind() { if let ty::ConstKind::Value(ty::ValTree::Leaf(int)) = len.kind() { - match self.tcx().try_get_global_alloc(alloc_id) { + match self.tcx().get_global_alloc(alloc_id) { Some(GlobalAlloc::Memory(alloc)) => { let len = int.assert_bits(self.tcx().data_layout.pointer_size); let range = @@ -1282,12 +1282,11 @@ pub trait PrettyPrinter<'tcx>: p!("") } } - // FIXME: for statics, vtables, and functions, we could in principle print more detail. + // FIXME: for statics and functions, we could in principle print more detail. Some(GlobalAlloc::Static(def_id)) => { p!(write("", def_id)) } Some(GlobalAlloc::Function(_)) => p!(""), - Some(GlobalAlloc::VTable(..)) => p!(""), None => p!(""), } return Ok(self); @@ -1298,8 +1297,7 @@ pub trait PrettyPrinter<'tcx>: ty::FnPtr(_) => { // FIXME: We should probably have a helper method to share code with the "Byte strings" // printing above (which also has to handle pointers to all sorts of things). - if let Some(GlobalAlloc::Function(instance)) = - self.tcx().try_get_global_alloc(alloc_id) + if let Some(GlobalAlloc::Function(instance)) = self.tcx().get_global_alloc(alloc_id) { self = self.typed_value( |this| this.print_value_path(instance.def_id(), instance.substs), @@ -1379,9 +1377,9 @@ pub trait PrettyPrinter<'tcx>: /// This is overridden for MIR printing because we only want to hide alloc ids from users, not /// from MIR where it is actually useful. - fn pretty_print_const_pointer( + fn pretty_print_const_pointer( mut self, - _: Pointer, + _: Pointer, ty: Ty<'tcx>, print_ty: bool, ) -> Result { @@ -1452,7 +1450,7 @@ pub trait PrettyPrinter<'tcx>: } }, (ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => { - let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| { + let bytes = valtree.try_to_raw_bytes(self.tcx(), *t).unwrap_or_else(|| { bug!("expected to convert valtree to raw bytes for type {:?}", t) }); p!("*"); @@ -1729,7 +1727,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { } fn print_const(self, ct: ty::Const<'tcx>) -> Result { - self.pretty_print_const(ct, false) + self.pretty_print_const(ct, true) } fn path_crate(mut self, cnum: CrateNum) -> Result { @@ -1954,9 +1952,9 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { } } - fn pretty_print_const_pointer( + fn pretty_print_const_pointer( self, - p: Pointer, + p: Pointer, ty: Ty<'tcx>, print_ty: bool, ) -> Result { @@ -2556,7 +2554,7 @@ define_print_and_forward_display! { ty::TraitPredicate<'tcx> { p!(print(self.trait_ref.self_ty()), ": "); - if let ty::BoundConstness::ConstIfConst = self.constness && cx.tcx().features().const_trait_impl { + if let ty::BoundConstness::ConstIfConst = self.constness { p!("~const "); } p!(print(self.trait_ref.print_only_trait_path())) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 7660a2f3af60a..391a0a20c9662 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -224,7 +224,6 @@ TrivialTypeTraversalAndLiftImpls! { // general `Region`. crate::ty::BoundRegionKind, crate::ty::AssocItem, - crate::ty::AssocKind, crate::ty::Placeholder, crate::ty::ClosureKind, crate::ty::FreeRegion, @@ -625,7 +624,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> { fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { match self { ty::InstanceDef::Item(def_id) => Some(ty::InstanceDef::Item(def_id)), - ty::InstanceDef::VTableShim(def_id) => Some(ty::InstanceDef::VTableShim(def_id)), + ty::InstanceDef::VtableShim(def_id) => Some(ty::InstanceDef::VtableShim(def_id)), ty::InstanceDef::ReifyShim(def_id) => Some(ty::InstanceDef::ReifyShim(def_id)), ty::InstanceDef::Intrinsic(def_id) => Some(ty::InstanceDef::Intrinsic(def_id)), ty::InstanceDef::FnPtrShim(def_id, ty) => { @@ -928,7 +927,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { substs: self.substs.try_fold_with(folder)?, def: match self.def { Item(def) => Item(def.try_fold_with(folder)?), - VTableShim(did) => VTableShim(did.try_fold_with(folder)?), + VtableShim(did) => VtableShim(did.try_fold_with(folder)?), ReifyShim(did) => ReifyShim(did.try_fold_with(folder)?), Intrinsic(did) => Intrinsic(did.try_fold_with(folder)?), FnPtrShim(did, ty) => { @@ -955,7 +954,7 @@ impl<'tcx> TypeVisitable<'tcx> for ty::instance::Instance<'tcx> { self.substs.visit_with(visitor)?; match self.def { Item(def) => def.visit_with(visitor), - VTableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => { + VtableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => { did.visit_with(visitor) } FnPtrShim(did, ty) | CloneShim(did, ty) => { @@ -1123,7 +1122,6 @@ impl<'tcx> TypeVisitable<'tcx> for ty::Predicate<'tcx> { visitor.visit_predicate(*self) } - #[inline] fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool { self.outer_exclusive_binder() > binder } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index b4fa9837aed91..3a524d7b0f307 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -11,6 +11,7 @@ use rustc_data_structures::intern::{Interned, WithStableHash}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_serialize::{self, Decodable, Encodable}; +use rustc_span::DUMMY_SP; use smallvec::SmallVec; use core::intrinsics; @@ -524,7 +525,6 @@ struct SubstFolder<'a, 'tcx> { } impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { - #[inline] fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { self.tcx } @@ -540,16 +540,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - #[cold] - #[inline(never)] - fn region_param_out_of_range(data: ty::EarlyBoundRegion) -> ! { - bug!( - "Region parameter out of range when substituting in region {} (index={})", - data.name, - data.index - ) - } - // Note: This routine only handles regions that are bound on // type declarations and other outer declarations, not those // bound in *fn types*. Region substitution of the bound @@ -560,7 +550,14 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { let rk = self.substs.get(data.index as usize).map(|k| k.unpack()); match rk { Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt), - _ => region_param_out_of_range(data), + _ => { + let msg = format!( + "Region parameter out of range \ + when substituting in region {} (index={})", + data.name, data.index + ); + span_bug!(DUMMY_SP, "{}", msg); + } } } _ => r, @@ -598,80 +595,67 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { let opt_ty = self.substs.get(p.index as usize).map(|k| k.unpack()); let ty = match opt_ty { Some(GenericArgKind::Type(ty)) => ty, - Some(kind) => self.type_param_expected(p, source_ty, kind), - None => self.type_param_out_of_range(p, source_ty), + Some(kind) => { + span_bug!( + DUMMY_SP, + "expected type for `{:?}` ({:?}/{}) but found {:?} \ + when substituting, substs={:?}", + p, + source_ty, + p.index, + kind, + self.substs, + ); + } + None => { + span_bug!( + DUMMY_SP, + "type parameter `{:?}` ({:?}/{}) out of range \ + when substituting, substs={:?}", + p, + source_ty, + p.index, + self.substs, + ); + } }; self.shift_vars_through_binders(ty) } - #[cold] - #[inline(never)] - fn type_param_expected(&self, p: ty::ParamTy, ty: Ty<'tcx>, kind: GenericArgKind<'tcx>) -> ! { - bug!( - "expected type for `{:?}` ({:?}/{}) but found {:?} when substituting, substs={:?}", - p, - ty, - p.index, - kind, - self.substs, - ) - } - - #[cold] - #[inline(never)] - fn type_param_out_of_range(&self, p: ty::ParamTy, ty: Ty<'tcx>) -> ! { - bug!( - "type parameter `{:?}` ({:?}/{}) out of range when substituting, substs={:?}", - p, - ty, - p.index, - self.substs, - ) - } - fn const_for_param(&self, p: ParamConst, source_ct: ty::Const<'tcx>) -> ty::Const<'tcx> { // Look up the const in the substitutions. It really should be in there. let opt_ct = self.substs.get(p.index as usize).map(|k| k.unpack()); let ct = match opt_ct { Some(GenericArgKind::Const(ct)) => ct, - Some(kind) => self.const_param_expected(p, source_ct, kind), - None => self.const_param_out_of_range(p, source_ct), + Some(kind) => { + span_bug!( + DUMMY_SP, + "expected const for `{:?}` ({:?}/{}) but found {:?} \ + when substituting substs={:?}", + p, + source_ct, + p.index, + kind, + self.substs, + ); + } + None => { + span_bug!( + DUMMY_SP, + "const parameter `{:?}` ({:?}/{}) out of range \ + when substituting substs={:?}", + p, + source_ct, + p.index, + self.substs, + ); + } }; self.shift_vars_through_binders(ct) } - #[cold] - #[inline(never)] - fn const_param_expected( - &self, - p: ty::ParamConst, - ct: ty::Const<'tcx>, - kind: GenericArgKind<'tcx>, - ) -> ! { - bug!( - "expected const for `{:?}` ({:?}/{}) but found {:?} when substituting substs={:?}", - p, - ct, - p.index, - kind, - self.substs, - ) - } - - #[cold] - #[inline(never)] - fn const_param_out_of_range(&self, p: ty::ParamConst, ct: ty::Const<'tcx>) -> ! { - bug!( - "const parameter `{:?}` ({:?}/{}) out of range when substituting substs={:?}", - p, - ct, - p.index, - self.substs, - ) - } - /// It is sometimes necessary to adjust the De Bruijn indices during substitution. This occurs /// when we are substituting a type with escaping bound vars into a context where we have /// passed through binders. That's quite a mouthful. Let's see an example: diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 3435f127c72e2..5bd1fad0bcb9f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -951,7 +951,7 @@ fn adt_defined_here<'p, 'tcx>( let mut span: MultiSpan = if spans.is_empty() { def_span.into() } else { spans.clone().into() }; - span.push_span_label(def_span, ""); + span.push_span_label(def_span, String::new()); for pat in spans { span.push_span_label(pat, "not covered"); } 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 d6dd0f017941a..e32e0b11ba497 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 @@ -120,35 +120,37 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option { - traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| { - with_no_trimmed_paths!(match non_sm_ty.kind() { - ty::Adt(adt, _) => self.adt_derive_msg(*adt), - ty::Dynamic(..) => { - "trait objects cannot be used in patterns".to_string() - } - ty::Opaque(..) => { - "opaque types cannot be used in patterns".to_string() - } - ty::Closure(..) => { - "closures cannot be used in patterns".to_string() - } - ty::Generator(..) | ty::GeneratorWitness(..) => { - "generators cannot be used in patterns".to_string() - } - ty::Float(..) => { - "floating-point numbers cannot be used in patterns".to_string() - } - ty::FnPtr(..) => { - "function pointers cannot be used in patterns".to_string() - } - ty::RawPtr(..) => { - "raw pointers cannot be used in patterns".to_string() - } - _ => { - bug!("use of a value of `{non_sm_ty}` inside a pattern") - } - }) - }) + traits::search_for_structural_match_violation(self.span, self.tcx(), ty, true).map( + |non_sm_ty| { + with_no_trimmed_paths!(match non_sm_ty.kind { + traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt), + traits::NonStructuralMatchTyKind::Dynamic => { + "trait objects cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTyKind::Opaque => { + "opaque types cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTyKind::Closure => { + "closures cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTyKind::Generator => { + "generators cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTyKind::Float => { + "floating-point numbers cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTyKind::Param => { + bug!("use of a constant whose type is a parameter inside a pattern") + } + traits::NonStructuralMatchTyKind::Projection => { + bug!("use of a constant whose type is a projection inside a pattern") + } + traits::NonStructuralMatchTyKind::Foreign => { + bug!("use of a value of a foreign type inside a pattern") + } + }) + }, + ) } fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool { diff --git a/compiler/rustc_mir_dataflow/src/un_derefer.rs b/compiler/rustc_mir_dataflow/src/un_derefer.rs index 2ab7eddcac922..ec2e516f7ac5f 100644 --- a/compiler/rustc_mir_dataflow/src/un_derefer.rs +++ b/compiler/rustc_mir_dataflow/src/un_derefer.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_map::FxHashMap; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index 9c5896c4e4aed..b91ae083cf594 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -15,9 +15,22 @@ pub struct AddRetag; /// (Concurrent accesses by other threads are no problem as these are anyway non-atomic /// copies. Data races are UB.) fn is_stable(place: PlaceRef<'_>) -> bool { - // Which place this evaluates to can change with any memory write, - // so cannot assume deref to be stable. - !place.has_deref() + place.projection.iter().all(|elem| { + match elem { + // Which place this evaluates to can change with any memory write, + // so cannot assume this to be stable. + ProjectionElem::Deref => false, + // Array indices are interesting, but MIR building generates a *fresh* + // temporary for every array access, so the index cannot be changed as + // a side-effect. + ProjectionElem::Index { .. } | + // The rest is completely boring, they just offset by a constant. + ProjectionElem::Field { .. } | + ProjectionElem::ConstantIndex { .. } | + ProjectionElem::Subslice { .. } | + ProjectionElem::Downcast { .. } => true, + } + }) } /// Determine whether this type may contain a reference (or box), and thus needs retagging. @@ -78,8 +91,11 @@ impl<'tcx> MirPass<'tcx> for AddRetag { }; let place_base_raw = |place: &Place<'tcx>| { // If this is a `Deref`, get the type of what we are deref'ing. - if place.has_deref() { - let ty = &local_decls[place.local].ty; + let deref_base = + place.projection.iter().rposition(|p| matches!(p, ProjectionElem::Deref)); + if let Some(deref_base) = deref_base { + let base_proj = &place.projection[..deref_base]; + let ty = Place::ty_from(place.local, base_proj, &*local_decls, tcx).ty; ty.is_unsafe_ptr() } else { // Not a deref, and thus not raw. diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs index 3b7ba3f9a67ac..2eb38941f1a50 100644 --- a/compiler/rustc_mir_transform/src/check_packed_ref.rs +++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs @@ -36,16 +36,13 @@ fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) { tcx.struct_span_lint_hir(UNALIGNED_REFERENCES, lint_hir_id, tcx.def_span(def_id), |lint| { // FIXME: when we make this a hard error, this should have its // own error code. - let extra = if tcx.generics_of(def_id).own_requires_monomorphization() { - "with type or const parameters" + let message = if tcx.generics_of(def_id).own_requires_monomorphization() { + "`#[derive]` can't be used on a `#[repr(packed)]` struct with \ + type or const parameters (error E0133)" } else { - "that does not derive `Copy`" + "`#[derive]` can't be used on a `#[repr(packed)]` struct that \ + does not derive Copy (error E0133)" }; - let message = format!( - "`{}` can't be derived on this `#[repr(packed)]` struct {}", - tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")), - extra - ); lint.build(message).emit(); }); } diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 85ad6b8f2feff..2fd026b1bcaf6 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -155,18 +155,18 @@ impl<'tcx> MirPass<'tcx> for ConstProp { } } -pub struct ConstPropMachine<'mir, 'tcx> { +struct ConstPropMachine<'mir, 'tcx> { /// The virtual call stack. stack: Vec>, /// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end. - pub written_only_inside_own_block_locals: FxHashSet, + written_only_inside_own_block_locals: FxHashSet, /// Locals that need to be cleared after every block terminates. - pub only_propagate_inside_block_locals: BitSet, - pub can_const_prop: IndexVec, + only_propagate_inside_block_locals: BitSet, + can_const_prop: IndexVec, } impl ConstPropMachine<'_, '_> { - pub fn new( + fn new( only_propagate_inside_block_locals: BitSet, can_const_prop: IndexVec, ) -> Self { @@ -234,9 +234,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> } fn access_local<'a>( - frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, + frame: &'a Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, local: Local, - ) -> InterpResult<'tcx, &'a interpret::Operand> { + ) -> InterpResult<'tcx, &'a interpret::Operand> { let l = &frame.locals[local]; if matches!( @@ -255,7 +255,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> ecx: &'a mut InterpCx<'mir, 'tcx, Self>, frame: usize, local: Local, - ) -> InterpResult<'tcx, &'a mut interpret::Operand> { + ) -> InterpResult<'tcx, &'a mut interpret::Operand> { if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation { throw_machine_stop_str!("tried to write to a local that is marked as not propagatable") } @@ -274,7 +274,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _tcx: TyCtxt<'tcx>, _machine: &Self, _alloc_id: AllocId, - alloc: ConstAllocation<'tcx, Self::Provenance, Self::AllocExtra>, + alloc: ConstAllocation<'tcx, Self::PointerTag, Self::AllocExtra>, _static_def_id: Option, is_write: bool, ) -> InterpResult<'tcx> { @@ -309,14 +309,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> #[inline(always)] fn stack<'a>( ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] { + ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { &ecx.machine.stack } #[inline(always)] fn stack_mut<'a>( ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec> { + ) -> &'a mut Vec> { &mut ecx.machine.stack } } @@ -816,7 +816,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { /// The mode that `ConstProp` is allowed to run in for a given `Local`. #[derive(Clone, Copy, Debug, PartialEq)] -pub enum ConstPropMode { +enum ConstPropMode { /// The `Local` can be propagated into and reads of this `Local` can also be propagated. FullConstProp, /// The `Local` can only be propagated into and from its own block. @@ -828,7 +828,7 @@ pub enum ConstPropMode { NoPropagation, } -pub struct CanConstProp { +struct CanConstProp { can_const_prop: IndexVec, // False at the beginning. Once set, no more assignments are allowed to that local. found_assignment: BitSet, @@ -838,7 +838,7 @@ pub struct CanConstProp { impl CanConstProp { /// Returns true if `local` can be propagated - pub fn check<'tcx>( + fn check<'tcx>( tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, body: &Body<'tcx>, diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 3ae6a88a140ea..9c843f11c1ed1 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -1,24 +1,19 @@ //! Propagates constants for early reporting of statically known //! assertion failures -use crate::const_prop::CanConstProp; -use crate::const_prop::ConstPropMachine; -use crate::const_prop::ConstPropMode; -use crate::MirLint; -use rustc_const_eval::const_eval::ConstEvalErr; -use rustc_const_eval::interpret::{ - self, InterpCx, InterpResult, LocalState, LocalValue, MemoryKind, OpTy, Scalar, - ScalarMaybeUninit, StackPopCleanup, -}; +use std::cell::Cell; + +use rustc_ast::Mutability; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::DefKind; use rustc_hir::HirId; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; -use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{ - AssertKind, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, Location, Operand, Place, - Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, - TerminatorKind, UnOp, RETURN_PLACE, + AssertKind, BasicBlock, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, LocalKind, + Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, + StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE, }; use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; @@ -27,15 +22,42 @@ use rustc_middle::ty::{ TypeVisitable, }; use rustc_session::lint; -use rustc_span::Span; +use rustc_span::{def_id::DefId, Span}; use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; +use rustc_target::spec::abi::Abi as CallAbi; use rustc_trait_selection::traits; -use std::cell::Cell; + +use crate::MirLint; +use rustc_const_eval::const_eval::ConstEvalErr; +use rustc_const_eval::interpret::{ + self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult, + LocalState, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, + StackPopCleanup, StackPopUnwind, +}; /// The maximum number of bytes that we'll allocate space for a local or the return value. /// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just /// Severely regress performance. const MAX_ALLOC_LIMIT: u64 = 1024; + +/// Macro for machine-specific `InterpError` without allocation. +/// (These will never be shown to the user, but they help diagnose ICEs.) +macro_rules! throw_machine_stop_str { + ($($tt:tt)*) => {{ + // We make a new local type for it. The type itself does not carry any information, + // but its vtable (for the `MachineStopType` trait) does. + struct Zst; + // Printing this type shows the desired string. + impl std::fmt::Display for Zst { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, $($tt)*) + } + } + impl rustc_middle::mir::interpret::MachineStopType for Zst {} + throw_machine_stop!(Zst) + }}; +} + pub struct ConstProp; impl<'tcx> MirLint<'tcx> for ConstProp { @@ -129,6 +151,172 @@ impl<'tcx> MirLint<'tcx> for ConstProp { } } +struct ConstPropMachine<'mir, 'tcx> { + /// The virtual call stack. + stack: Vec>, + /// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end. + written_only_inside_own_block_locals: FxHashSet, + /// Locals that need to be cleared after every block terminates. + only_propagate_inside_block_locals: BitSet, + can_const_prop: IndexVec, +} + +impl ConstPropMachine<'_, '_> { + fn new( + only_propagate_inside_block_locals: BitSet, + can_const_prop: IndexVec, + ) -> Self { + Self { + stack: Vec::new(), + written_only_inside_own_block_locals: Default::default(), + only_propagate_inside_block_locals, + can_const_prop, + } + } +} + +impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> { + compile_time_machine!(<'mir, 'tcx>); + const PANIC_ON_ALLOC_FAIL: bool = true; // all allocations are small (see `MAX_ALLOC_LIMIT`) + + type MemoryKind = !; + + fn load_mir( + _ecx: &InterpCx<'mir, 'tcx, Self>, + _instance: ty::InstanceDef<'tcx>, + ) -> InterpResult<'tcx, &'tcx Body<'tcx>> { + throw_machine_stop_str!("calling functions isn't supported in ConstProp") + } + + fn find_mir_or_eval_fn( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _instance: ty::Instance<'tcx>, + _abi: CallAbi, + _args: &[OpTy<'tcx>], + _destination: &PlaceTy<'tcx>, + _target: Option, + _unwind: StackPopUnwind, + ) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> { + Ok(None) + } + + fn call_intrinsic( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _instance: ty::Instance<'tcx>, + _args: &[OpTy<'tcx>], + _destination: &PlaceTy<'tcx>, + _target: Option, + _unwind: StackPopUnwind, + ) -> InterpResult<'tcx> { + throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp") + } + + fn assert_panic( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _msg: &rustc_middle::mir::AssertMessage<'tcx>, + _unwind: Option, + ) -> InterpResult<'tcx> { + bug!("panics terminators are not evaluated in ConstProp") + } + + fn binary_ptr_op( + _ecx: &InterpCx<'mir, 'tcx, Self>, + _bin_op: BinOp, + _left: &ImmTy<'tcx>, + _right: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + // We can't do this because aliasing of memory can differ between const eval and llvm + throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp") + } + + fn access_local<'a>( + frame: &'a Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + local: Local, + ) -> InterpResult<'tcx, &'a interpret::Operand> { + let l = &frame.locals[local]; + + if matches!( + l.value, + LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)) + ) { + // For us "uninit" means "we don't know its value, might be initiailized or not". + // So stop here. + throw_machine_stop_str!("tried to access a local with unknown value") + } + + l.access() + } + + fn access_local_mut<'a>( + ecx: &'a mut InterpCx<'mir, 'tcx, Self>, + frame: usize, + local: Local, + ) -> InterpResult<'tcx, &'a mut interpret::Operand> { + if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation { + throw_machine_stop_str!("tried to write to a local that is marked as not propagatable") + } + if frame == 0 && ecx.machine.only_propagate_inside_block_locals.contains(local) { + trace!( + "mutating local {:?} which is restricted to its block. \ + Will remove it from const-prop after block is finished.", + local + ); + ecx.machine.written_only_inside_own_block_locals.insert(local); + } + ecx.machine.stack[frame].locals[local].access_mut() + } + + fn before_access_global( + _tcx: TyCtxt<'tcx>, + _machine: &Self, + _alloc_id: AllocId, + alloc: ConstAllocation<'tcx, Self::PointerTag, Self::AllocExtra>, + _static_def_id: Option, + is_write: bool, + ) -> InterpResult<'tcx> { + if is_write { + throw_machine_stop_str!("can't write to global"); + } + // If the static allocation is mutable, then we can't const prop it as its content + // might be different at runtime. + if alloc.inner().mutability == Mutability::Mut { + throw_machine_stop_str!("can't access mutable globals in ConstProp"); + } + + Ok(()) + } + + #[inline(always)] + fn expose_ptr( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ptr: Pointer, + ) -> InterpResult<'tcx> { + throw_machine_stop_str!("exposing pointers isn't supported in ConstProp") + } + + #[inline(always)] + fn init_frame_extra( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + frame: Frame<'mir, 'tcx>, + ) -> InterpResult<'tcx, Frame<'mir, 'tcx>> { + Ok(frame) + } + + #[inline(always)] + fn stack<'a>( + ecx: &'a InterpCx<'mir, 'tcx, Self>, + ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { + &ecx.machine.stack + } + + #[inline(always)] + fn stack_mut<'a>( + ecx: &'a mut InterpCx<'mir, 'tcx, Self>, + ) -> &'a mut Vec> { + &mut ecx.machine.stack + } +} + /// Finds optimization opportunities on the MIR. struct ConstPropagator<'mir, 'tcx> { ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, @@ -523,6 +711,139 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } +/// The mode that `ConstProp` is allowed to run in for a given `Local`. +#[derive(Clone, Copy, Debug, PartialEq)] +enum ConstPropMode { + /// The `Local` can be propagated into and reads of this `Local` can also be propagated. + FullConstProp, + /// The `Local` can only be propagated into and from its own block. + OnlyInsideOwnBlock, + /// The `Local` can be propagated into but reads cannot be propagated. + OnlyPropagateInto, + /// The `Local` cannot be part of propagation at all. Any statement + /// referencing it either for reading or writing will not get propagated. + NoPropagation, +} + +struct CanConstProp { + can_const_prop: IndexVec, + // False at the beginning. Once set, no more assignments are allowed to that local. + found_assignment: BitSet, + // Cache of locals' information + local_kinds: IndexVec, +} + +impl CanConstProp { + /// Returns true if `local` can be propagated + fn check<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + body: &Body<'tcx>, + ) -> IndexVec { + let mut cpv = CanConstProp { + can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls), + found_assignment: BitSet::new_empty(body.local_decls.len()), + local_kinds: IndexVec::from_fn_n( + |local| body.local_kind(local), + body.local_decls.len(), + ), + }; + for (local, val) in cpv.can_const_prop.iter_enumerated_mut() { + let ty = body.local_decls[local].ty; + match tcx.layout_of(param_env.and(ty)) { + Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {} + // Either the layout fails to compute, then we can't use this local anyway + // or the local is too large, then we don't want to. + _ => { + *val = ConstPropMode::NoPropagation; + continue; + } + } + // Cannot use args at all + // Cannot use locals because if x < y { y - x } else { x - y } would + // lint for x != y + // FIXME(oli-obk): lint variables until they are used in a condition + // FIXME(oli-obk): lint if return value is constant + if cpv.local_kinds[local] == LocalKind::Arg { + *val = ConstPropMode::OnlyPropagateInto; + trace!( + "local {:?} can't be const propagated because it's a function argument", + local + ); + } else if cpv.local_kinds[local] == LocalKind::Var { + *val = ConstPropMode::OnlyInsideOwnBlock; + trace!( + "local {:?} will only be propagated inside its block, because it's a user variable", + local + ); + } + } + cpv.visit_body(&body); + cpv.can_const_prop + } +} + +impl Visitor<'_> for CanConstProp { + fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { + use rustc_middle::mir::visit::PlaceContext::*; + match context { + // Projections are fine, because `&mut foo.x` will be caught by + // `MutatingUseContext::Borrow` elsewhere. + MutatingUse(MutatingUseContext::Projection) + // These are just stores, where the storing is not propagatable, but there may be later + // mutations of the same local via `Store` + | MutatingUse(MutatingUseContext::Call) + | MutatingUse(MutatingUseContext::AsmOutput) + | MutatingUse(MutatingUseContext::Deinit) + // Actual store that can possibly even propagate a value + | MutatingUse(MutatingUseContext::SetDiscriminant) + | MutatingUse(MutatingUseContext::Store) => { + if !self.found_assignment.insert(local) { + match &mut self.can_const_prop[local] { + // If the local can only get propagated in its own block, then we don't have + // to worry about multiple assignments, as we'll nuke the const state at the + // end of the block anyway, and inside the block we overwrite previous + // states as applicable. + ConstPropMode::OnlyInsideOwnBlock => {} + ConstPropMode::NoPropagation => {} + ConstPropMode::OnlyPropagateInto => {} + other @ ConstPropMode::FullConstProp => { + trace!( + "local {:?} can't be propagated because of multiple assignments. Previous state: {:?}", + local, other, + ); + *other = ConstPropMode::OnlyInsideOwnBlock; + } + } + } + } + // Reading constants is allowed an arbitrary number of times + NonMutatingUse(NonMutatingUseContext::Copy) + | NonMutatingUse(NonMutatingUseContext::Move) + | NonMutatingUse(NonMutatingUseContext::Inspect) + | NonMutatingUse(NonMutatingUseContext::Projection) + | NonUse(_) => {} + + // These could be propagated with a smarter analysis or just some careful thinking about + // whether they'd be fine right now. + MutatingUse(MutatingUseContext::Yield) + | MutatingUse(MutatingUseContext::Drop) + | MutatingUse(MutatingUseContext::Retag) + // These can't ever be propagated under any scheme, as we can't reason about indirect + // mutation. + | NonMutatingUse(NonMutatingUseContext::SharedBorrow) + | NonMutatingUse(NonMutatingUseContext::ShallowBorrow) + | NonMutatingUse(NonMutatingUseContext::UniqueBorrow) + | NonMutatingUse(NonMutatingUseContext::AddressOf) + | MutatingUse(MutatingUseContext::Borrow) + | MutatingUse(MutatingUseContext::AddressOf) => { + trace!("local {:?} can't be propagaged because it's used: {:?}", local, context); + self.can_const_prop[local] = ConstPropMode::NoPropagation; + } + } + } +} + impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { fn visit_body(&mut self, body: &Body<'tcx>) { for (bb, data) in body.basic_blocks().iter_enumerated() { diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 1e46b0a0e8164..dc5d5cee879f8 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -246,7 +246,7 @@ impl<'tcx> Inliner<'tcx> { // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we // do not need to catch this here, we can wait until the inliner decides to continue // inlining a second time. - InstanceDef::VTableShim(_) + InstanceDef::VtableShim(_) | InstanceDef::ReifyShim(_) | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 7810218fd6744..a3a35f95071e9 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -79,7 +79,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( // These have MIR and if that MIR is inlined, substituted and then inlining is run // again, a function item can end up getting inlined. Thus we'll be able to cause // a cycle that way - InstanceDef::VTableShim(_) + InstanceDef::VtableShim(_) | InstanceDef::ReifyShim(_) | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index 2f02d00ec9fb0..47848cfa497f3 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -11,7 +11,7 @@ pub struct LowerSliceLenCalls; impl<'tcx> MirPass<'tcx> for LowerSliceLenCalls { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() > 0 + sess.opts.mir_opt_level() > 0 } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs index 4919ad40098cb..8ea550fa123b6 100644 --- a/compiler/rustc_mir_transform/src/reveal_all.rs +++ b/compiler/rustc_mir_transform/src/reveal_all.rs @@ -9,7 +9,7 @@ pub struct RevealAll; impl<'tcx> MirPass<'tcx> for RevealAll { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() >= 3 || super::inline::Inline.is_enabled(sess) + sess.opts.mir_opt_level() >= 3 || super::inline::Inline.is_enabled(sess) } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 3620e94bec7d7..eaa61d8614d8c 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -32,7 +32,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' let mut result = match instance { ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance), - ty::InstanceDef::VTableShim(def_id) => { + ty::InstanceDef::VtableShim(def_id) => { build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id)) } ty::InstanceDef::FnPtrShim(def_id, ty) => { @@ -113,7 +113,7 @@ enum Adjustment { /// We get passed `&[mut] self` and call the target with `*self`. /// /// This either copies `self` (if `Self: Copy`, eg. for function items), or moves out of it - /// (for `VTableShim`, which effectively is passed `&own Self`). + /// (for `VtableShim`, which effectively is passed `&own Self`). Deref, /// We get passed `self: Self` and call the target with `&mut self`. @@ -569,7 +569,7 @@ fn build_call_shim<'tcx>( // FIXME(eddyb) avoid having this snippet both here and in // `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?). - if let ty::InstanceDef::VTableShim(..) = instance { + if let ty::InstanceDef::VtableShim(..) = instance { // Modify fn(self, ...) to fn(self: *mut Self, ...) let mut inputs_and_output = sig.inputs_and_output.to_vec(); let self_arg = &mut inputs_and_output[0]; diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 180f4c7dcd6e8..980af98436281 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -28,7 +28,6 @@ //! return. use crate::MirPass; -use rustc_data_structures::fx::FxHashSet; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::coverage::*; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; @@ -268,8 +267,7 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { return; } - let basic_blocks = body.basic_blocks.as_mut(); - let source_scopes = &body.source_scopes; + let basic_blocks = body.basic_blocks_mut(); let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); let mut used_blocks = 0; for alive_index in reachable.iter() { @@ -284,7 +282,7 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } if tcx.sess.instrument_coverage() { - save_unreachable_coverage(basic_blocks, source_scopes, used_blocks); + save_unreachable_coverage(basic_blocks, used_blocks); } basic_blocks.raw.truncate(used_blocks); @@ -313,72 +311,56 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { /// `Unreachable` coverage statements. These are non-executable statements whose /// code regions are still recorded in the coverage map, representing regions /// with `0` executions. -/// -/// If there are no live `Counter` `Coverage` statements remaining, we remove -/// `Coverage` statements along with the dead blocks. Since at least one -/// counter per function is required by LLVM (and necessary, to add the -/// `function_hash` to the counter's call to the LLVM intrinsic -/// `instrprof.increment()`). -/// -/// The `generator::StateTransform` MIR pass and MIR inlining can create -/// atypical conditions, where all live `Counter`s are dropped from the MIR. -/// -/// With MIR inlining we can have coverage counters belonging to different -/// instances in a single body, so the strategy described above is applied to -/// coverage counters from each instance individually. fn save_unreachable_coverage( basic_blocks: &mut IndexVec>, - source_scopes: &IndexVec>, first_dead_block: usize, ) { - // Identify instances that still have some live coverage counters left. - let mut live = FxHashSet::default(); - for basic_block in &basic_blocks.raw[0..first_dead_block] { - for statement in &basic_block.statements { - let StatementKind::Coverage(coverage) = &statement.kind else { continue }; - let CoverageKind::Counter { .. } = coverage.kind else { continue }; - let instance = statement.source_info.scope.inlined_instance(source_scopes); - live.insert(instance); - } - } - - for block in &mut basic_blocks.raw[..first_dead_block] { - for statement in &mut block.statements { - let StatementKind::Coverage(_) = &statement.kind else { continue }; - let instance = statement.source_info.scope.inlined_instance(source_scopes); - if !live.contains(&instance) { - statement.make_nop(); + let has_live_counters = basic_blocks.raw[0..first_dead_block].iter().any(|live_block| { + live_block.statements.iter().any(|statement| { + if let StatementKind::Coverage(coverage) = &statement.kind { + matches!(coverage.kind, CoverageKind::Counter { .. }) + } else { + false } - } - } - - if live.is_empty() { + }) + }); + if !has_live_counters { + // If there are no live `Counter` `Coverage` statements anymore, don't + // move dead coverage to the `START_BLOCK`. Just allow the dead + // `Coverage` statements to be dropped with the dead blocks. + // + // The `generator::StateTransform` MIR pass can create atypical + // conditions, where all live `Counter`s are dropped from the MIR. + // + // At least one Counter per function is required by LLVM (and necessary, + // to add the `function_hash` to the counter's call to the LLVM + // intrinsic `instrprof.increment()`). return; } - // Retain coverage for instances that still have some live counters left. - let mut retained_coverage = Vec::new(); - for dead_block in &basic_blocks.raw[first_dead_block..] { - for statement in &dead_block.statements { - let StatementKind::Coverage(coverage) = &statement.kind else { continue }; - let Some(code_region) = &coverage.code_region else { continue }; - let instance = statement.source_info.scope.inlined_instance(source_scopes); - if live.contains(&instance) { - retained_coverage.push((statement.source_info, code_region.clone())); + // Retain coverage info for dead blocks, so coverage reports will still + // report `0` executions for the uncovered code regions. + let mut dropped_coverage = Vec::new(); + for dead_block in basic_blocks.raw[first_dead_block..].iter() { + for statement in dead_block.statements.iter() { + if let StatementKind::Coverage(coverage) = &statement.kind { + if let Some(code_region) = &coverage.code_region { + dropped_coverage.push((statement.source_info, code_region.clone())); + } } } } let start_block = &mut basic_blocks[START_BLOCK]; - start_block.statements.extend(retained_coverage.into_iter().map( - |(source_info, code_region)| Statement { + for (source_info, code_region) in dropped_coverage { + start_block.statements.push(Statement { source_info, kind: StatementKind::Coverage(Box::new(Coverage { kind: CoverageKind::Unreachable, code_region: Some(code_region), })), - }, - )); + }) + } } pub struct SimplifyLocals; diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs index 30be64f5b2f2e..bd196f1187966 100644 --- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs @@ -1,7 +1,7 @@ //! A pass that eliminates branches on uninhabited enum variants. use crate::MirPass; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_middle::mir::{ BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, Terminator, TerminatorKind, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 68b65658c72b5..e3cfb034e40ad 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -25,7 +25,7 @@ //! codegen unit: //! //! - Constants -//! - VTables +//! - Vtables //! - Object Shims //! //! @@ -992,7 +992,7 @@ fn visit_instance_use<'tcx>( } } ty::InstanceDef::DropGlue(_, Some(_)) - | ty::InstanceDef::VTableShim(..) + | ty::InstanceDef::VtableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::Item(..) @@ -1427,10 +1427,6 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIte output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP)); } } - GlobalAlloc::VTable(ty, trait_ref) => { - let alloc_id = tcx.vtable_allocation((ty, trait_ref)); - collect_miri(tcx, alloc_id, output) - } } } diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs index 15276569c32f5..d18b1c26c174f 100644 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ b/compiler/rustc_monomorphize/src/partitioning/default.rs @@ -271,7 +271,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( MonoItem::Fn(instance) => { let def_id = match instance.def { ty::InstanceDef::Item(def) => def.did, - ty::InstanceDef::VTableShim(..) + ty::InstanceDef::VtableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::ClosureOnceShim { .. } @@ -425,7 +425,7 @@ fn mono_item_visibility<'tcx>( InstanceDef::DropGlue(def_id, Some(_)) => def_id, // These are all compiler glue and such, never exported, always hidden. - InstanceDef::VTableShim(..) + InstanceDef::VtableShim(..) | InstanceDef::ReifyShim(..) | InstanceDef::FnPtrShim(..) | InstanceDef::Virtual(..) diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index ff2d386932858..36243803f994e 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -98,7 +98,6 @@ mod merging; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync; use rustc_hir::def_id::DefIdSet; -use rustc_middle::mir; use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::{CodegenUnit, Linkage}; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -480,14 +479,9 @@ fn codegened_and_inlined_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx DefIdSe if !visited.insert(did) { continue; } - let body = tcx.instance_mir(instance.def); - for block in body.basic_blocks() { - for statement in &block.statements { - let mir::StatementKind::Coverage(_) = statement.kind else { continue }; - let scope = statement.source_info.scope; - if let Some(inlined) = scope.inlined_instance(&body.source_scopes) { - result.insert(inlined.def_id()); - } + for scope in &tcx.instance_mir(instance.def).source_scopes { + if let Some((ref inlined, _)) = scope.inlined { + result.insert(inlined.def_id()); } } } diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 261adbfc34671..d56e3773dc7a0 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -117,12 +117,12 @@ pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path, sp: Option) -> Parser<'_> { panictry_buffer!(&sess.span_diagnostic, maybe_source_file_to_parser(sess, source_file)) } -/// Given a session and a `source_file`, return a parser. Returns any buffered errors from lexing the +/// Given a `source_file` and config, return a parser. Returns any buffered errors from lexing the /// initial token stream. fn maybe_source_file_to_parser( sess: &ParseSess, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 43b4861397664..8e1b279d9b6c2 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2356,7 +2356,10 @@ impl<'a> Parser<'a> { let is_in_a_let_chains_context_but_nested_in_other_expr = self.let_expr_allowed && !matches!( self.prev_token.kind, - TokenKind::AndAnd | TokenKind::Ident(kw::If, _) | TokenKind::Ident(kw::While, _) + TokenKind::AndAnd + | TokenKind::CloseDelim(Delimiter::Brace) + | TokenKind::Ident(kw::If, _) + | TokenKind::Ident(kw::While, _) ); if !self.let_expr_allowed || is_in_a_let_chains_context_but_nested_in_other_expr { self.struct_span_err(self.token.span, "expected expression, found `let` statement") diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index a14a7fc0610cb..87bc0d9762ea5 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1677,6 +1677,7 @@ impl<'a> Parser<'a> { } /// Is this a possibly malformed start of a `macro_rules! foo` item definition? + fn is_macro_rules_item(&mut self) -> IsMacroRulesItem { if self.check_keyword(kw::MacroRules) { let macro_rules_span = self.token.span; diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 5deb17b8651b6..f6fa19030acb9 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -104,8 +104,8 @@ pub struct FormatSpec<'a> { pub enum Position<'a> { /// The argument is implied to be located at an index ArgumentImplicitlyIs(usize), - /// The argument is located at a specific index given in the format, - ArgumentIs(usize, Option), + /// The argument is located at a specific index given in the format + ArgumentIs(usize), /// The argument has a name. ArgumentNamed(&'a str, InnerSpan), } @@ -113,7 +113,7 @@ pub enum Position<'a> { impl Position<'_> { pub fn index(&self) -> Option { match self { - ArgumentIs(i, ..) | ArgumentImplicitlyIs(i) => Some(*i), + ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i), _ => None, } } @@ -502,15 +502,8 @@ impl<'a> Parser<'a> { /// Returns `Some(parsed_position)` if the position is not implicitly /// consuming a macro argument, `None` if it's the case. fn position(&mut self) -> Option> { - let start_position = self.cur.peek().map(|item| item.0); if let Some(i) = self.integer() { - let inner_span = start_position.and_then(|start| { - self.cur - .peek() - .cloned() - .and_then(|item| Some(self.to_span_index(start).to(self.to_span_index(item.0)))) - }); - Some(ArgumentIs(i, inner_span)) + Some(ArgumentIs(i)) } else { match self.cur.peek() { Some(&(start, c)) if rustc_lexer::is_id_start(c) => { @@ -579,14 +572,9 @@ impl<'a> Parser<'a> { // '0' flag and then an ill-formatted format string with just a '$' // and no count, but this is better if we instead interpret this as // no '0' flag and '0$' as the width instead. - if let Some(end) = self.consume_pos('$') { + if self.consume('$') { spec.width = CountIsParam(0); - - if let Some((pos, _)) = self.cur.peek().cloned() { - spec.width_span = Some(self.to_span_index(pos - 2).to(self.to_span_index(pos))); - } havewidth = true; - spec.width_span = Some(self.to_span_index(end - 1).to(self.to_span_index(end + 1))); } else { spec.flags |= 1 << (FlagSignAwareZeroPad as u32); } @@ -597,7 +585,6 @@ impl<'a> Parser<'a> { spec.width = w; spec.width_span = sp; } - if let Some(start) = self.consume_pos('.') { if let Some(end) = self.consume_pos('*') { // Resolve `CountIsNextParam`. diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs index a98f816644bd6..c9667922ee7c3 100644 --- a/compiler/rustc_parse_format/src/tests.rs +++ b/compiler/rustc_parse_format/src/tests.rs @@ -62,30 +62,18 @@ fn format_nothing() { } #[test] fn format_position() { - same( - "{3}", - &[NextArgument(Argument { - position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })), - format: fmtdflt(), - })], - ); + same("{3}", &[NextArgument(Argument { position: ArgumentIs(3), format: fmtdflt() })]); } #[test] fn format_position_nothing_else() { - same( - "{3:}", - &[NextArgument(Argument { - position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })), - format: fmtdflt(), - })], - ); + same("{3:}", &[NextArgument(Argument { position: ArgumentIs(3), format: fmtdflt() })]); } #[test] fn format_type() { same( "{3:x}", &[NextArgument(Argument { - position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })), + position: ArgumentIs(3), format: FormatSpec { fill: None, align: AlignUnknown, @@ -105,7 +93,7 @@ fn format_align_fill() { same( "{3:>}", &[NextArgument(Argument { - position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })), + position: ArgumentIs(3), format: FormatSpec { fill: None, align: AlignRight, @@ -122,7 +110,7 @@ fn format_align_fill() { same( "{3:0<}", &[NextArgument(Argument { - position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })), + position: ArgumentIs(3), format: FormatSpec { fill: Some('0'), align: AlignLeft, @@ -139,7 +127,7 @@ fn format_align_fill() { same( "{3:* { sym::rustc_lint_diagnostics => { self.check_rustc_lint_diagnostics(&attr, span, target) } - sym::rustc_lint_opt_ty => self.check_rustc_lint_opt_ty(&attr, span, target), - sym::rustc_lint_opt_deny_field_access => { - self.check_rustc_lint_opt_deny_field_access(&attr, span, target) - } sym::rustc_clean | sym::rustc_dirty | sym::rustc_if_this_changed @@ -1184,22 +1180,30 @@ impl CheckAttrVisitor<'_> { _ => { // FIXME: #[cold] was previously allowed on non-functions/statics and some crates // used this, so only emit a warning. - let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span); - if let Some(s) = attr.value_str() { - self.tcx.emit_spanned_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span, - errors::LinkName { span, attr_span, value: s.as_str() }, + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + let mut diag = + lint.build("attribute should be applied to a foreign function or static"); + diag.warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", ); - } else { - self.tcx.emit_spanned_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span, - errors::LinkName { span, attr_span, value: "..." }, - ); - }; + + // See issue #47725 + if let Target::ForeignMod = target { + if let Some(value) = attr.value_str() { + diag.span_help( + attr.span, + &format!(r#"try `#[link(name = "{value}")]` instead"#), + ); + } else { + diag.span_help(attr.span, r#"try `#[link(name = "...")]` instead"#); + } + } + + diag.span_label(span, "not a foreign function or static"); + diag.emit(); + }); } } } @@ -1217,7 +1221,14 @@ impl CheckAttrVisitor<'_> { true } _ => { - self.tcx.sess.emit_err(errors::NoLink { attr_span: attr.span, span }); + self.tcx + .sess + .struct_span_err( + attr.span, + "attribute should be applied to an `extern crate` item", + ) + .span_label(span, "not an `extern crate` item") + .emit(); false } } @@ -1247,7 +1258,14 @@ impl CheckAttrVisitor<'_> { true } _ => { - self.tcx.sess.emit_err(errors::ExportName { attr_span: attr.span, span }); + self.tcx + .sess + .struct_span_err( + attr.span, + "attribute should be applied to a free function, impl method or static", + ) + .span_label(span, "not a free function, impl method or static") + .emit(); false } } @@ -1260,10 +1278,11 @@ impl CheckAttrVisitor<'_> { target: Target, ) -> bool { if target != Target::Struct { - self.tcx.sess.emit_err(errors::RustcLayoutScalarValidRangeNotStruct { - attr_span: attr.span, - span, - }); + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to a struct") + .span_label(span, "not a struct") + .emit(); return false; } @@ -1274,7 +1293,10 @@ impl CheckAttrVisitor<'_> { if matches!(&list[..], &[NestedMetaItem::Literal(Lit { kind: LitKind::Int(..), .. })]) { true } else { - self.tcx.sess.emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span }); + self.tcx + .sess + .struct_span_err(attr.span, "expected exactly one integer literal argument") + .emit(); false } } @@ -1289,10 +1311,11 @@ impl CheckAttrVisitor<'_> { ) -> bool { let is_function = matches!(target, Target::Fn); if !is_function { - self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn { - attr_span: attr.span, - defn_span: span, - }); + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to a function") + .span_label(span, "not a function") + .emit(); return false; } @@ -1312,20 +1335,29 @@ impl CheckAttrVisitor<'_> { match param.kind { hir::GenericParamKind::Const { .. } => {} _ => { - self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsOnly { - attr_span: attr.span, - param_span: param.span, - }); + self.tcx + .sess + .struct_span_err( + attr.span, + "#[rustc_legacy_const_generics] functions must \ + only have const generics", + ) + .span_label(param.span, "non-const generic parameter") + .emit(); return false; } } } if list.len() != generics.params.len() { - self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndex { - attr_span: attr.span, - generics_span: generics.span, - }); + self.tcx + .sess + .struct_span_err( + attr.span, + "#[rustc_legacy_const_generics] must have one index for each generic parameter", + ) + .span_label(generics.span, "generic parameters") + .emit(); return false; } @@ -1335,10 +1367,19 @@ impl CheckAttrVisitor<'_> { if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) { if *val >= arg_count { let span = meta.span(); - self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndexExceed { - span, - arg_count: arg_count as usize, - }); + self.tcx + .sess + .struct_span_err(span, "index exceeds number of arguments") + .span_label( + span, + format!( + "there {} only {} argument{}", + pluralize!("is", arg_count), + arg_count, + pluralize!(arg_count) + ), + ) + .emit(); return false; } } else { @@ -1347,7 +1388,10 @@ impl CheckAttrVisitor<'_> { } if !invalid_args.is_empty() { - self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndexNegative { invalid_args }); + self.tcx + .sess + .struct_span_err(invalid_args, "arguments should be non-negative integers") + .emit(); false } else { true @@ -1359,10 +1403,11 @@ impl CheckAttrVisitor<'_> { fn check_applied_to_fn_or_method(&self, attr: &Attribute, span: Span, target: Target) -> bool { let is_function = matches!(target, Target::Fn | Target::Method(..)); if !is_function { - self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn { - attr_span: attr.span, - defn_span: span, - }); + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to a function") + .span_label(span, "not a function") + .emit(); false } else { true @@ -1386,42 +1431,16 @@ impl CheckAttrVisitor<'_> { self.check_applied_to_fn_or_method(attr, span, target) } - /// Checks that the `#[rustc_lint_opt_ty]` attribute is only applied to a struct. - fn check_rustc_lint_opt_ty(&self, attr: &Attribute, span: Span, target: Target) -> bool { - match target { - Target::Struct => true, - _ => { - self.tcx.sess.emit_err(errors::RustcLintOptTy { attr_span: attr.span, span }); - false - } - } - } - - /// Checks that the `#[rustc_lint_opt_deny_field_access]` attribute is only applied to a field. - fn check_rustc_lint_opt_deny_field_access( - &self, - attr: &Attribute, - span: Span, - target: Target, - ) -> bool { - match target { - Target::Field => true, - _ => { - self.tcx - .sess - .emit_err(errors::RustcLintOptDenyFieldAccess { attr_span: attr.span, span }); - false - } - } - } - /// Checks that the dep-graph debugging attributes are only present when the query-dep-graph /// option is passed to the compiler. fn check_rustc_dirty_clean(&self, attr: &Attribute) -> bool { if self.tcx.sess.opts.unstable_opts.query_dep_graph { true } else { - self.tcx.sess.emit_err(errors::RustcDirtyClean { span: attr.span }); + self.tcx + .sess + .struct_span_err(attr.span, "attribute requires -Z query-dep-graph to be enabled") + .emit(); false } } @@ -1440,12 +1459,16 @@ impl CheckAttrVisitor<'_> { _ => { // FIXME: #[link_section] was previously allowed on non-functions/statics and some // crates used this, so only emit a warning. - self.tcx.emit_spanned_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span, - errors::LinkSection { span }, - ); + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("attribute should be applied to a function or static") + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .span_label(span, "not a function or static") + .emit(); + }); } } } @@ -1471,22 +1494,41 @@ impl CheckAttrVisitor<'_> { Target::ForeignStatic => "static", _ => unreachable!(), }; - self.tcx.emit_spanned_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span, - errors::NoMangleForeign { span, attr_span: attr.span, foreign_item_kind }, - ); + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build(&format!( + "`#[no_mangle]` has no effect on a foreign {foreign_item_kind}" + )) + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .span_label(span, format!("foreign {foreign_item_kind}")) + .note("symbol names in extern blocks are not mangled") + .span_suggestion( + attr.span, + "remove this attribute", + "", + Applicability::MachineApplicable, + ) + .emit(); + }); } _ => { // FIXME: #[no_mangle] was previously allowed on non-functions/statics and some // crates used this, so only emit a warning. - self.tcx.emit_spanned_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span, - errors::NoMangle { span }, - ); + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build( + "attribute should be applied to a free function, impl method or static", + ) + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .span_label(span, "not a free function, impl method or static") + .emit(); + }); } } } @@ -1519,7 +1561,13 @@ impl CheckAttrVisitor<'_> { for hint in &hints { if !hint.is_meta_item() { - self.tcx.sess.emit_err(errors::ReprIdent { span: hint.span() }); + struct_span_err!( + self.tcx.sess, + hint.span(), + E0565, + "meta item in `repr` must be an identifier" + ) + .emit(); continue; } @@ -1640,11 +1688,15 @@ impl CheckAttrVisitor<'_> { return false; })) { - self.tcx.emit_spanned_lint( + self.tcx.struct_span_lint_hir( CONFLICTING_REPR_HINTS, hir_id, hint_spans.collect::>(), - errors::ReprConflicting, + |lint| { + lint.build("conflicting representation hints") + .code(rustc_errors::error_code!(E0566)) + .emit(); + }, ); } } @@ -1654,7 +1706,9 @@ impl CheckAttrVisitor<'_> { let mut used_compiler_span = None; for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) { if target != Target::Static { - self.tcx.sess.emit_err(errors::UsedStatic { span: attr.span }); + self.tcx + .sess + .span_err(attr.span, "attribute must be applied to a `static` variable"); } let inner = attr.meta_item_list(); match inner.as_deref() { @@ -1680,9 +1734,14 @@ impl CheckAttrVisitor<'_> { } } if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) { + let spans = vec![linker_span, compiler_span]; self.tcx .sess - .emit_err(errors::UsedCompilerLinker { spans: vec![linker_span, compiler_span] }); + .struct_span_err( + spans, + "`used(compiler)` and `used(linker)` can't be used together", + ) + .emit(); } } @@ -1724,7 +1783,9 @@ impl CheckAttrVisitor<'_> { _ => { self.tcx .sess - .emit_err(errors::AllowInternalUnstable { attr_span: attr.span, span }); + .struct_span_err(attr.span, "attribute should be applied to a macro") + .span_label(span, "not a macro") + .emit(); false } } @@ -1735,26 +1796,29 @@ impl CheckAttrVisitor<'_> { match target { Target::Mod => {} _ => { - self.tcx.sess.emit_err(errors::DebugVisualizerPlacement { span: attr.span }); + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to a module") + .emit(); return false; } } let Some(hints) = attr.meta_item_list() else { - self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span }); + self.emit_debugger_visualizer_err(attr.span); return false; }; let hint = match hints.len() { 1 => &hints[0], _ => { - self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span }); + self.emit_debugger_visualizer_err(attr.span); return false; } }; let Some(meta_item) = hint.meta_item() else { - self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span }); + self.emit_debugger_visualizer_err(attr.span); return false; }; @@ -1762,7 +1826,7 @@ impl CheckAttrVisitor<'_> { (sym::natvis_file, Some(value)) => value, (sym::gdb_script_file, Some(value)) => value, (_, _) => { - self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: meta_item.span }); + self.emit_debugger_visualizer_err(meta_item.span); return false; } }; @@ -1791,6 +1855,16 @@ impl CheckAttrVisitor<'_> { } } + fn emit_debugger_visualizer_err(&self, span: Span) { + self.tcx + .sess + .struct_span_err(span, "invalid argument") + .note(r#"expected: `natvis_file = "..."`"#) + .note(r#"OR"#) + .note(r#"expected: `gdb_script_file = "..."`"#) + .emit(); + } + /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros. /// (Allows proc_macro functions) fn check_rustc_allow_const_fn_unstable( @@ -1817,7 +1891,9 @@ impl CheckAttrVisitor<'_> { _ => { self.tcx .sess - .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span, span }); + .struct_span_err(attr.span, "attribute should be applied to `const fn`") + .span_label(span, "not a `const fn`") + .emit(); false } } @@ -1834,7 +1910,9 @@ impl CheckAttrVisitor<'_> { _ => { self.tcx .sess - .emit_err(errors::RustcStdInternalSymbol { attr_span: attr.span, span }); + .struct_span_err(attr.span, "attribute should be applied functions or statics") + .span_label(span, "not a function or static") + .emit(); false } } @@ -1845,7 +1923,10 @@ impl CheckAttrVisitor<'_> { match target { Target::Trait => true, _ => { - self.tcx.sess.emit_err(errors::ConstTrait { attr_span: attr.span }); + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to a trait") + .emit(); false } } @@ -1854,7 +1935,10 @@ impl CheckAttrVisitor<'_> { fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Target) -> bool { match target { Target::Expression => { - self.tcx.sess.emit_err(errors::StabilityPromotable { attr_span: attr.span }); + self.tcx + .sess + .struct_span_err(attr.span, "attribute cannot be applied to an expression") + .emit(); false } _ => true, @@ -1864,12 +1948,9 @@ impl CheckAttrVisitor<'_> { fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target: Target) { match target { Target::Closure | Target::Expression | Target::Statement | Target::Arm => { - self.tcx.emit_spanned_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span, - errors::Deprecated, - ); + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("attribute is ignored here").emit(); + }); } _ => {} } @@ -1880,30 +1961,29 @@ impl CheckAttrVisitor<'_> { match target { Target::ExternCrate | Target::Mod => {} _ => { - self.tcx.emit_spanned_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span, - errors::MacroUse { name }, - ); + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build(&format!( + "`#[{name}]` only has an effect on `extern crate` and modules" + )) + .emit(); + }); } } } fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) { if target != Target::MacroDef { - self.tcx.emit_spanned_lint(UNUSED_ATTRIBUTES, hir_id, attr.span, errors::MacroExport); + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("`#[macro_export]` only has an effect on macro definitions").emit(); + }); } } fn check_plugin_registrar(&self, hir_id: HirId, attr: &Attribute, target: Target) { if target != Target::Fn { - self.tcx.emit_spanned_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span, - errors::PluginRegistrar, - ); + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("`#[plugin_registrar]` only has an effect on functions").emit(); + }); } } @@ -1922,7 +2002,10 @@ impl CheckAttrVisitor<'_> { | sym::target_feature ) && attr.meta_item_list().map_or(false, |list| list.is_empty()) { - errors::UnusedNote::EmptyList { name: attr.name_or_empty() } + format!( + "attribute `{}` with an empty list has no effect", + attr.name_or_empty() + ) } else if matches!( attr.name_or_empty(), sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect @@ -1932,19 +2015,27 @@ impl CheckAttrVisitor<'_> { && let MetaItemKind::NameValue(_) = &item.kind && item.path == sym::reason { - errors::UnusedNote::NoLints { name: attr.name_or_empty() } + format!( + "attribute `{}` without any lints has no effect", + attr.name_or_empty() + ) } else if attr.name_or_empty() == sym::default_method_body_is_const { - errors::UnusedNote::DefaultMethodBodyConst + format!("`default_method_body_is_const` has been replaced with `#[const_trait]` on traits") } else { return; }; - self.tcx.emit_spanned_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span, - errors::Unused { attr_span: attr.span, note }, - ); + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("unused attribute") + .span_suggestion( + attr.span, + "remove this attribute", + "", + Applicability::MachineApplicable, + ) + .note(¬e) + .emit(); + }); } } @@ -2115,7 +2206,14 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) for attr in attrs { if attr.has_name(sym::inline) { - tcx.sess.emit_err(errors::NonExportedMacroInvalidAttrs { attr_span: attr.span }); + struct_span_err!( + tcx.sess, + attr.span, + E0518, + "attribute should be applied to function or closure", + ) + .span_label(attr.span, "not a function or closure") + .emit(); } } } @@ -2155,20 +2253,23 @@ fn check_duplicates( } else { (attr.span, *entry.get()) }; - tcx.emit_spanned_lint( - UNUSED_ATTRIBUTES, - hir_id, - this, - errors::UnusedDuplicate { + tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, this, |lint| { + let mut db = lint.build("unused attribute"); + db.span_note(other, "attribute also specified here").span_suggestion( this, - other, - warning: matches!( - duplicates, - FutureWarnFollowing | FutureWarnPreceding - ) - .then_some(()), - }, - ); + "remove this attribute", + "", + Applicability::MachineApplicable, + ); + if matches!(duplicates, FutureWarnFollowing | FutureWarnPreceding) { + db.warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ); + } + db.emit(); + }); } Entry::Vacant(entry) => { entry.insert(attr.span); @@ -2183,11 +2284,19 @@ fn check_duplicates( } else { (attr.span, *entry.get()) }; - tcx.sess.emit_err(errors::UnusedMultiple { - this, - other, - name: attr.name_or_empty(), - }); + tcx.sess + .struct_span_err( + this, + &format!("multiple `{}` attributes", attr.name_or_empty()), + ) + .span_note(other, "attribute also specified here") + .span_suggestion( + this, + "remove this attribute", + "", + Applicability::MachineApplicable, + ) + .emit(); } Entry::Vacant(entry) => { entry.insert(attr.span); diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 5feb0e2956b74..fcd1e9363b1be 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1,5 +1,5 @@ use rustc_errors::{Applicability, MultiSpan}; -use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; +use rustc_macros::{LintDiagnostic, SessionDiagnostic}; use rustc_span::{Span, Symbol}; #[derive(LintDiagnostic)] @@ -360,286 +360,3 @@ pub struct Link { #[label] pub span: Option, } - -#[derive(LintDiagnostic)] -#[lint(passes::link_name)] -#[warn_] -pub struct LinkName<'a> { - #[help] - pub attr_span: Option, - #[label] - pub span: Span, - pub value: &'a str, -} - -#[derive(SessionDiagnostic)] -#[error(passes::no_link)] -pub struct NoLink { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - -#[derive(SessionDiagnostic)] -#[error(passes::export_name)] -pub struct ExportName { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - -#[derive(SessionDiagnostic)] -#[error(passes::rustc_layout_scalar_valid_range_not_struct)] -pub struct RustcLayoutScalarValidRangeNotStruct { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - -#[derive(SessionDiagnostic)] -#[error(passes::rustc_layout_scalar_valid_range_arg)] -pub struct RustcLayoutScalarValidRangeArg { - #[primary_span] - pub attr_span: Span, -} - -#[derive(SessionDiagnostic)] -#[error(passes::rustc_legacy_const_generics_only)] -pub struct RustcLegacyConstGenericsOnly { - #[primary_span] - pub attr_span: Span, - #[label] - pub param_span: Span, -} - -#[derive(SessionDiagnostic)] -#[error(passes::rustc_legacy_const_generics_index)] -pub struct RustcLegacyConstGenericsIndex { - #[primary_span] - pub attr_span: Span, - #[label] - pub generics_span: Span, -} - -#[derive(SessionDiagnostic)] -#[error(passes::rustc_legacy_const_generics_index_exceed)] -pub struct RustcLegacyConstGenericsIndexExceed { - #[primary_span] - #[label] - pub span: Span, - pub arg_count: usize, -} - -#[derive(SessionDiagnostic)] -#[error(passes::rustc_legacy_const_generics_index_negative)] -pub struct RustcLegacyConstGenericsIndexNegative { - #[primary_span] - pub invalid_args: Vec, -} - -#[derive(SessionDiagnostic)] -#[error(passes::rustc_dirty_clean)] -pub struct RustcDirtyClean { - #[primary_span] - pub span: Span, -} - -#[derive(LintDiagnostic)] -#[lint(passes::link_section)] -#[warn_] -pub struct LinkSection { - #[label] - pub span: Span, -} - -#[derive(LintDiagnostic)] -#[lint(passes::no_mangle_foreign)] -#[warn_] -#[note] -pub struct NoMangleForeign { - #[label] - pub span: Span, - #[suggestion(applicability = "machine-applicable")] - pub attr_span: Span, - pub foreign_item_kind: &'static str, -} - -#[derive(LintDiagnostic)] -#[lint(passes::no_mangle)] -#[warn_] -pub struct NoMangle { - #[label] - pub span: Span, -} - -#[derive(SessionDiagnostic)] -#[error(passes::repr_ident, code = "E0565")] -pub struct ReprIdent { - #[primary_span] - pub span: Span, -} - -#[derive(LintDiagnostic)] -#[lint(passes::repr_conflicting, code = "E0566")] -pub struct ReprConflicting; - -#[derive(SessionDiagnostic)] -#[error(passes::used_static)] -pub struct UsedStatic { - #[primary_span] - pub span: Span, -} - -#[derive(SessionDiagnostic)] -#[error(passes::used_compiler_linker)] -pub struct UsedCompilerLinker { - #[primary_span] - pub spans: Vec, -} - -#[derive(SessionDiagnostic)] -#[error(passes::allow_internal_unstable)] -pub struct AllowInternalUnstable { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - -#[derive(SessionDiagnostic)] -#[error(passes::debug_visualizer_placement)] -pub struct DebugVisualizerPlacement { - #[primary_span] - pub span: Span, -} - -#[derive(SessionDiagnostic)] -#[error(passes::debug_visualizer_invalid)] -#[note(passes::note_1)] -#[note(passes::note_2)] -#[note(passes::note_3)] -pub struct DebugVisualizerInvalid { - #[primary_span] - pub span: Span, -} - -#[derive(SessionDiagnostic)] -#[error(passes::rustc_allow_const_fn_unstable)] -pub struct RustcAllowConstFnUnstable { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - -#[derive(SessionDiagnostic)] -#[error(passes::rustc_std_internal_symbol)] -pub struct RustcStdInternalSymbol { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - -#[derive(SessionDiagnostic)] -#[error(passes::const_trait)] -pub struct ConstTrait { - #[primary_span] - pub attr_span: Span, -} - -#[derive(SessionDiagnostic)] -#[error(passes::stability_promotable)] -pub struct StabilityPromotable { - #[primary_span] - pub attr_span: Span, -} - -#[derive(LintDiagnostic)] -#[lint(passes::deprecated)] -pub struct Deprecated; - -#[derive(LintDiagnostic)] -#[lint(passes::macro_use)] -pub struct MacroUse { - pub name: Symbol, -} - -#[derive(LintDiagnostic)] -#[lint(passes::macro_export)] -pub struct MacroExport; - -#[derive(LintDiagnostic)] -#[lint(passes::plugin_registrar)] -pub struct PluginRegistrar; - -#[derive(SessionSubdiagnostic)] -pub enum UnusedNote { - #[note(passes::unused_empty_lints_note)] - EmptyList { name: Symbol }, - #[note(passes::unused_no_lints_note)] - NoLints { name: Symbol }, - #[note(passes::unused_default_method_body_const_note)] - DefaultMethodBodyConst, -} - -#[derive(LintDiagnostic)] -#[lint(passes::unused)] -pub struct Unused { - #[suggestion(applicability = "machine-applicable")] - pub attr_span: Span, - #[subdiagnostic] - pub note: UnusedNote, -} - -#[derive(SessionDiagnostic)] -#[error(passes::non_exported_macro_invalid_attrs, code = "E0518")] -pub struct NonExportedMacroInvalidAttrs { - #[primary_span] - #[label] - pub attr_span: Span, -} - -#[derive(LintDiagnostic)] -#[lint(passes::unused_duplicate)] -pub struct UnusedDuplicate { - #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] - pub this: Span, - #[note] - pub other: Span, - #[warn_] - pub warning: Option<()>, -} - -#[derive(SessionDiagnostic)] -#[error(passes::unused_multiple)] -pub struct UnusedMultiple { - #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] - pub this: Span, - #[note] - pub other: Span, - pub name: Symbol, -} - -#[derive(SessionDiagnostic)] -#[error(passes::rustc_lint_opt_ty)] -pub struct RustcLintOptTy { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - -#[derive(SessionDiagnostic)] -#[error(passes::rustc_lint_opt_deny_field_access)] -pub struct RustcLintOptDenyFieldAccess { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index ca6a2ac3db34c..81b04c414ed9b 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -2,7 +2,7 @@ //! propagating default levels lexically from parent to children ast nodes. use attr::StabilityLevel; -use rustc_attr::{self as attr, ConstStability, Stability, Unstable, UnstableReason}; +use rustc_attr::{self as attr, ConstStability, Stability, Unstable}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; @@ -634,9 +634,12 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { // while maintaining the invariant that all sysroot crates are unstable // by default and are unable to be used. if tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { + let reason = "this crate is being loaded from the sysroot, an \ + unstable location; did you mean to load this crate \ + from crates.io via `Cargo.toml` instead?"; let stability = Stability { level: attr::StabilityLevel::Unstable { - reason: UnstableReason::Default, + reason: Some(Symbol::intern(reason)), issue: NonZeroU32::new(27812), is_soft: false, implied_by: None, diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index c48b4ecf87a3a..3291be05807f6 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -68,7 +68,7 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) { } } - for (name, &item) in WEAK_ITEMS_REFS.iter() { + for (name, item) in WEAK_ITEMS_REFS.clone().into_sorted_vector().into_iter() { if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() { if item == LangItem::PanicImpl { tcx.sess.err("`#[panic_handler]` function required, but not found"); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 390d6f5a856af..9a835808d4935 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1754,6 +1754,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { || self.in_assoc_ty || self.tcx.resolutions(()).has_pub_restricted { + let descr = descr.to_string(); let vis_span = self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id)); if kind == "trait" { diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index eda61df7700d7..7c1fdc4e306a4 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -37,7 +37,7 @@ mod values; use self::values::Value; pub use rustc_query_system::query::QueryConfig; -pub(crate) use rustc_query_system::query::{QueryDescription, QueryVTable}; +pub(crate) use rustc_query_system::query::{QueryDescription, QueryVtable}; mod on_disk_cache; pub use on_disk_cache::OnDiskCache; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index eda4401c81d01..333dc5aa668b0 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -340,11 +340,11 @@ macro_rules! define_queries { #[inline] fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) -> - QueryVTable, Self::Key, Self::Value> + QueryVtable, Self::Key, Self::Value> { let compute = get_provider!([$($modifiers)*][tcx, $name, key]); let cache_on_disk = Self::cache_on_disk(tcx.tcx, key); - QueryVTable { + QueryVtable { anon: is_anon!([$($modifiers)*]), eval_always: is_eval_always!([$($modifiers)*]), dep_kind: dep_graph::DepKind::$name, diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index 964914a1326bd..7ca668f8a1f06 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -19,7 +19,7 @@ pub trait QueryConfig { type Stored: Clone; } -pub struct QueryVTable { +pub struct QueryVtable { pub anon: bool, pub dep_kind: CTX::DepKind, pub eval_always: bool, @@ -31,7 +31,7 @@ pub struct QueryVTable { pub try_load_from_disk: Option Option>, } -impl QueryVTable { +impl QueryVtable { pub(crate) fn to_dep_node(&self, tcx: CTX::DepContext, key: &K) -> DepNode where K: crate::dep_graph::DepNodeParams, @@ -69,7 +69,7 @@ pub trait QueryDescription: QueryConfig { CTX: 'a; // Don't use this method to compute query results, instead use the methods on TyCtxt - fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVTable; + fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVtable; fn cache_on_disk(tcx: CTX::DepContext, key: &Self::Key) -> bool; } diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index fb2258434f4d3..f698a853d1e7b 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -12,7 +12,7 @@ pub use self::caches::{ }; mod config; -pub use self::config::{QueryConfig, QueryDescription, QueryVTable}; +pub use self::config::{QueryConfig, QueryDescription, QueryVtable}; use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex}; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 5e8ea07d00f99..792f2b0317357 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -4,7 +4,7 @@ use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams}; use crate::query::caches::QueryCache; -use crate::query::config::{QueryDescription, QueryVTable}; +use crate::query::config::{QueryDescription, QueryVtable}; use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo}; use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame}; use rustc_data_structures::fingerprint::Fingerprint; @@ -331,7 +331,7 @@ fn try_execute_query( span: Span, key: C::Key, dep_node: Option>, - query: &QueryVTable, + query: &QueryVtable, ) -> (C::Stored, Option) where C: QueryCache, @@ -368,7 +368,7 @@ fn execute_job( tcx: CTX, key: K, mut dep_node_opt: Option>, - query: &QueryVTable, + query: &QueryVtable, job_id: QueryJobId, ) -> (V, DepNodeIndex) where @@ -437,7 +437,7 @@ fn try_load_from_disk_and_cache_in_memory( tcx: CTX, key: &K, dep_node: &DepNode, - query: &QueryVTable, + query: &QueryVtable, ) -> Option<(V, DepNodeIndex)> where K: Clone, @@ -530,7 +530,7 @@ fn incremental_verify_ich( tcx: CTX::DepContext, result: &V, dep_node: &DepNode, - query: &QueryVTable, + query: &QueryVtable, ) where CTX: QueryContext, { @@ -642,7 +642,7 @@ fn incremental_verify_ich_cold(sess: &Session, dep_node: DebugArg<'_>, result: D fn ensure_must_run( tcx: CTX, key: &K, - query: &QueryVTable, + query: &QueryVtable, ) -> (bool, Option>) where K: crate::dep_graph::DepNodeParams, diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index e955a1798b735..6631470f2191b 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -524,7 +524,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let crate_root = self.r.resolve_crate_root(source.ident); let crate_name = match crate_root.kind { ModuleKind::Def(.., name) => name, - ModuleKind::Block => unreachable!(), + ModuleKind::Block(..) => unreachable!(), }; // HACK(eddyb) unclear how good this is, but keeping `$crate` // in `source` breaks `src/test/ui/imports/import-crate-var.rs`, @@ -936,7 +936,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { if self.block_needs_anonymous_module(block) { let module = self.r.new_module( Some(parent), - ModuleKind::Block, + ModuleKind::Block(block.id), expansion.to_expn_id(), block.span, parent.no_implicit_prelude, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 22a307a15edc0..7a1695fc862bf 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -163,7 +163,7 @@ impl<'a> Resolver<'a> { let container = match parent.kind { ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()), - ModuleKind::Block => "block", + ModuleKind::Block(..) => "block", }; let old_noun = match old_binding.is_import() { @@ -565,7 +565,8 @@ impl<'a> Resolver<'a> { } else if let Some(sp) = sm.generate_fn_name_span(span) { err.span_label( sp, - "try adding a local generic parameter in this method instead", + "try adding a local generic parameter in this method instead" + .to_string(), ); } else { err.help("try using a local generic parameter instead"); @@ -2023,7 +2024,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { span: Span, mut path: Vec, parent_scope: &ParentScope<'b>, - ) -> Option<(Vec, Option)> { + ) -> Option<(Vec, Vec)> { debug!("make_path_suggestion: span={:?} path={:?}", span, path); match (path.get(0), path.get(1)) { @@ -2058,12 +2059,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> { &mut self, mut path: Vec, parent_scope: &ParentScope<'b>, - ) -> Option<(Vec, Option)> { + ) -> Option<(Vec, Vec)> { // Replace first ident with `self` and check if that is valid. path[0].ident.name = kw::SelfLower; let result = self.r.maybe_resolve_path(&path, None, parent_scope); debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result); - if let PathResult::Module(..) = result { Some((path, None)) } else { None } + if let PathResult::Module(..) = result { Some((path, Vec::new())) } else { None } } /// Suggests a missing `crate::` if that resolves to an correct module. @@ -2077,7 +2078,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { &mut self, mut path: Vec, parent_scope: &ParentScope<'b>, - ) -> Option<(Vec, Option)> { + ) -> Option<(Vec, Vec)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Crate; let result = self.r.maybe_resolve_path(&path, None, parent_scope); @@ -2085,12 +2086,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if let PathResult::Module(..) = result { Some(( path, - Some( + vec![ "`use` statements changed in Rust 2018; read more at \ " .to_string(), - ), + ], )) } else { None @@ -2108,12 +2109,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> { &mut self, mut path: Vec, parent_scope: &ParentScope<'b>, - ) -> Option<(Vec, Option)> { + ) -> Option<(Vec, Vec)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Super; let result = self.r.maybe_resolve_path(&path, None, parent_scope); debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result); - if let PathResult::Module(..) = result { Some((path, None)) } else { None } + if let PathResult::Module(..) = result { Some((path, Vec::new())) } else { None } } /// Suggests a missing external crate name if that resolves to an correct module. @@ -2130,7 +2131,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { &mut self, mut path: Vec, parent_scope: &ParentScope<'b>, - ) -> Option<(Vec, Option)> { + ) -> Option<(Vec, Vec)> { if path[1].ident.span.rust_2015() { return None; } @@ -2151,7 +2152,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { name, path, result ); if let PathResult::Module(..) = result { - return Some((path, None)); + return Some((path, Vec::new())); } } @@ -2175,7 +2176,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { import: &'b Import<'b>, module: ModuleOrUniformRoot<'b>, ident: Ident, - ) -> Option<(Option, Option)> { + ) -> Option<(Option, Vec)> { let ModuleOrUniformRoot::Module(mut crate_module) = module else { return None; }; @@ -2287,9 +2288,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> { String::from("a macro with this name exists at the root of the crate"), Applicability::MaybeIncorrect, )); - Some((suggestion, Some("this could be because a macro annotated with `#[macro_export]` will be exported \ - at the root of the crate instead of the module where it is defined" - .to_string()))) + let note = vec![ + "this could be because a macro annotated with `#[macro_export]` will be exported \ + at the root of the crate instead of the module where it is defined" + .to_string(), + ]; + Some((suggestion, note)) } else { None } @@ -2599,12 +2603,12 @@ fn show_candidates( .skip(1) .all(|(_, descr, _, _)| descr == descr_first) { - descr_first + descr_first.to_string() } else { - "item" + "item".to_string() }; let plural_descr = - if descr.ends_with('s') { format!("{}es", descr) } else { format!("{}s", descr) }; + if descr.ends_with("s") { format!("{}es", descr) } else { format!("{}s", descr) }; let mut msg = format!("{}these {} exist but are inaccessible", prefix, plural_descr); let mut has_colon = false; diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 6e6782881427b..0cc6d05d1d086 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -218,7 +218,7 @@ impl<'a> Resolver<'a> { return Some((self.expn_def_scope(ctxt.remove_mark()), None)); } - if let ModuleKind::Block = module.kind { + if let ModuleKind::Block(..) = module.kind { return Some((module.parent.unwrap().nearest_item_scope(), None)); } @@ -333,7 +333,7 @@ impl<'a> Resolver<'a> { }; match module.kind { - ModuleKind::Block => {} // We can see through blocks + ModuleKind::Block(..) => {} // We can see through blocks _ => break, } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index b89273990d8e5..e6060ad46650e 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -336,7 +336,7 @@ impl<'a> Resolver<'a> { struct UnresolvedImportError { span: Span, label: Option, - note: Option, + note: Vec, suggestion: Option, } @@ -427,7 +427,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let err = UnresolvedImportError { span: import.span, label: None, - note: None, + note: Vec::new(), suggestion: None, }; if path.contains("::") { @@ -463,8 +463,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut diag = struct_span_err!(self.r.session, span, E0432, "{}", &msg); - if let Some((_, UnresolvedImportError { note: Some(note), .. })) = errors.iter().last() { - diag.note(note); + if let Some((_, UnresolvedImportError { note, .. })) = errors.iter().last() { + for message in note { + diag.note(message); + } } for (_, err) in errors.into_iter().take(MAX_LABEL_COUNT) { @@ -642,7 +644,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { None => UnresolvedImportError { span, label: Some(label), - note: None, + note: Vec::new(), suggestion, }, }; @@ -684,7 +686,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { return Some(UnresolvedImportError { span: import.span, label: Some(String::from("cannot glob-import a module into itself")), - note: None, + note: Vec::new(), suggestion: None, }); } @@ -828,7 +830,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let (suggestion, note) = match self.check_for_module_export_macro(import, module, ident) { Some((suggestion, note)) => (suggestion.or(lev_suggestion), note), - _ => (lev_suggestion, None), + _ => (lev_suggestion, Vec::new()), }; let label = match module { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ed65100ae7751..49761023ec333 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -21,7 +21,6 @@ use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::{PrimTy, TraitCandidate}; -use rustc_middle::middle::resolve_lifetime::Set1; use rustc_middle::ty::DefIdTree; use rustc_middle::{bug, span_bug}; use rustc_session::lint; @@ -44,10 +43,6 @@ type IdentMap = FxHashMap; /// Map from the name in a pattern to its binding mode. type BindingMap = IdentMap; -use diagnostics::{ - ElisionFnParameter, LifetimeElisionCandidate, MissingLifetime, MissingLifetimeKind, -}; - #[derive(Copy, Clone, Debug)] struct BindingInfo { span: Span, @@ -262,11 +257,8 @@ enum LifetimeRibKind { /// error on default object bounds (e.g., `Box`). AnonymousReportError, - /// Replace all anonymous lifetimes by provided lifetime. - Elided(LifetimeRes), - - /// Signal we cannot find which should be the anonymous lifetime. - ElisionFailure, + /// Pass responsibility to `resolve_lifetime` code for all cases. + AnonymousPassThrough(NodeId, /* in_fn_return */ bool), } #[derive(Copy, Clone, Debug)] @@ -530,10 +522,6 @@ struct DiagnosticMetadata<'ast> { /// When processing impl trait currently_processing_impl_trait: Option<(TraitRef, Ty)>, - - /// Accumulate the errors due to missed lifetime elision, - /// and report them all at once for each function. - current_elision_failures: Vec, } struct LateResolutionVisitor<'a, 'b, 'ast> { @@ -552,13 +540,6 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { /// The current set of local scopes for lifetimes. lifetime_ribs: Vec, - /// We are looking for lifetimes in an elision context. - /// The set contains all the resolutions that we encountered so far. - /// They will be used to determine the correct lifetime for the fn return type. - /// The `LifetimeElisionCandidate` is used for diagnostics, to suggest introducing named - /// lifetimes. - lifetime_elision_candidates: Option>, - /// The trait that the current context can refer to. current_trait_ref: Option<(Module<'a>, TraitRef)>, @@ -599,9 +580,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { fn visit_anon_const(&mut self, constant: &'ast AnonConst) { // We deal with repeat expressions explicitly in `resolve_expr`. self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| { - this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { - this.resolve_anon_const(constant, IsRepeatExpr::No); - }) + this.resolve_anon_const(constant, IsRepeatExpr::No); }) } fn visit_expr(&mut self, expr: &'ast Expr) { @@ -628,10 +607,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { TyKind::Rptr(None, _) => { // Elided lifetime in reference: we resolve as if there was some lifetime `'_` with // NodeId `ty.id`. - // This span will be used in case of elision failure. let span = self.r.session.source_map().next_point(ty.span.shrink_to_lo()); self.resolve_elided_lifetime(ty.id, span); - visit::walk_ty(self, ty); } TyKind::Path(ref qself, ref path) => { self.diagnostic_metadata.current_type_path = Some(ty); @@ -657,8 +634,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { }, |this| this.visit_path(&path, ty.id), ); - } else { - visit::walk_ty(self, ty) + self.diagnostic_metadata.current_type_path = prev_ty; + return; } } TyKind::ImplicitSelf => { @@ -672,16 +649,9 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { ) .map_or(Res::Err, |d| d.res()); self.r.record_partial_res(ty.id, PartialRes::new(res)); - visit::walk_ty(self, ty) - } - TyKind::ImplTrait(..) => { - let candidates = self.lifetime_elision_candidates.take(); - visit::walk_ty(self, ty); - self.lifetime_elision_candidates = candidates; } TyKind::TraitObject(ref bounds, ..) => { self.diagnostic_metadata.current_trait_object = Some(&bounds[..]); - visit::walk_ty(self, ty) } TyKind::BareFn(ref bare_fn) => { let span = ty.span.shrink_to_lo().to(bare_fn.decl_span.shrink_to_lo()); @@ -700,26 +670,20 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { binder: ty.id, report_in_path: false, }, - |this| { - this.resolve_fn_signature( - ty.id, - false, - // We don't need to deal with patterns in parameters, because - // they are not possible for foreign or bodiless functions. - bare_fn - .decl - .inputs - .iter() - .map(|Param { ty, .. }| (None, &**ty)), - &bare_fn.decl.output, - ) - }, + |this| walk_list!(this, visit_param, &bare_fn.decl.inputs), + ); + this.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough(ty.id, true), + |this| this.visit_fn_ret_ty(&bare_fn.decl.output), ); }, - ) + ); + self.diagnostic_metadata.current_trait_object = prev; + return; } - _ => visit::walk_ty(self, ty), + _ => (), } + visit::walk_ty(self, ty); self.diagnostic_metadata.current_trait_object = prev; self.diagnostic_metadata.current_type_path = prev_ty; } @@ -793,19 +757,18 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { | FnKind::Fn(_, _, sig, _, generics, None) => { self.visit_fn_header(&sig.header); self.visit_generics(generics); + // We don't need to deal with patterns in parameters, because + // they are not possible for foreign or bodiless functions. self.with_lifetime_rib( LifetimeRibKind::AnonymousCreateParameter { binder: fn_id, report_in_path: false, }, - |this| { - this.resolve_fn_signature( - fn_id, - sig.decl.has_self(), - sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)), - &sig.decl.output, - ) - }, + |this| walk_list!(this, visit_param, &sig.decl.inputs), + ); + self.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough(fn_id, true), + |this| this.visit_fn_ret_ty(&sig.decl.output), ); return; } @@ -830,22 +793,19 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { let declaration = &sig.decl; let async_node_id = sig.header.asyncness.opt_return_id(); + // Argument-position elided lifetimes must be transformed into fresh + // generic parameters. This is especially useful for `async fn`, where + // these fresh generic parameters can be applied to the opaque `impl Trait` + // return type. this.with_lifetime_rib( LifetimeRibKind::AnonymousCreateParameter { binder: fn_id, + // Only emit a hard error for `async fn`, since this kind of + // elision has always been allowed in regular `fn`s. report_in_path: async_node_id.is_some(), }, - |this| { - this.resolve_fn_signature( - fn_id, - declaration.has_self(), - declaration - .inputs - .iter() - .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)), - &declaration.output, - ) - }, + // Add each argument to the rib. + |this| this.resolve_params(&declaration.inputs), ); // Construct the list of in-scope lifetime parameters for async lowering. @@ -884,13 +844,23 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { .insert(async_node_id, extra_lifetime_params); } + this.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough( + // For async fn, the return type appears inside a custom + // `impl Future` RPIT, so we override the binder's id. + async_node_id.unwrap_or(fn_id), + true, + ), + |this| visit::walk_fn_ret_ty(this, &declaration.output), + ); + if let Some(body) = body { // Ignore errors in function bodies if this is rustdoc // Be sure not to set this until the function signature has been resolved. let previous_state = replace(&mut this.in_func_body, true); // Resolve the function body, potentially inside the body of an async closure this.with_lifetime_rib( - LifetimeRibKind::Elided(LifetimeRes::Infer), + LifetimeRibKind::AnonymousPassThrough(fn_id, false), |this| this.visit_block(body), ); @@ -918,7 +888,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { this.with_lifetime_rib( match binder { ClosureBinder::NotPresent => { - LifetimeRibKind::Elided(LifetimeRes::Infer) + LifetimeRibKind::AnonymousPassThrough(fn_id, true) } ClosureBinder::For { .. } => LifetimeRibKind::AnonymousReportError, }, @@ -930,7 +900,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { let previous_state = replace(&mut this.in_func_body, true); // Resolve the function body, potentially inside the body of an async closure this.with_lifetime_rib( - LifetimeRibKind::Elided(LifetimeRes::Infer), + LifetimeRibKind::AnonymousPassThrough(fn_id, false), |this| this.visit_expr(body), ); @@ -1065,14 +1035,11 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { binder, report_in_path: false, }, - |this| { - this.resolve_fn_signature( - binder, - false, - p_args.inputs.iter().map(|ty| (None, &**ty)), - &p_args.output, - ) - }, + |this| walk_list!(this, visit_ty, &p_args.inputs), + ); + self.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough(binder, true), + |this| visit::walk_fn_ret_ty(this, &p_args.output), ); break; } @@ -1082,10 +1049,9 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { visit::walk_generic_args(self, path_span, args); break; } - LifetimeRibKind::AnonymousCreateParameter { .. } + LifetimeRibKind::AnonymousPassThrough(..) + | LifetimeRibKind::AnonymousCreateParameter { .. } | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::Elided(_) - | LifetimeRibKind::ElisionFailure | LifetimeRibKind::AnonConst | LifetimeRibKind::ConstGeneric => {} } @@ -1190,7 +1156,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }, label_ribs: Vec::new(), lifetime_ribs: Vec::new(), - lifetime_elision_candidates: None, current_trait_ref: None, diagnostic_metadata: Box::new(DiagnosticMetadata::default()), // errors at module scope should always be reported @@ -1397,9 +1362,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { work: impl FnOnce(&mut Self) -> T, ) -> T { self.lifetime_ribs.push(LifetimeRib::new(kind)); - let outer_elision_candidates = self.lifetime_elision_candidates.take(); let ret = work(self); - self.lifetime_elision_candidates = outer_elision_candidates; self.lifetime_ribs.pop(); ret } @@ -1409,11 +1372,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let ident = lifetime.ident; if ident.name == kw::StaticLifetime { - self.record_lifetime_res( - lifetime.id, - LifetimeRes::Static, - LifetimeElisionCandidate::Named, - ); + self.record_lifetime_res(lifetime.id, LifetimeRes::Static); return; } @@ -1426,7 +1385,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let rib = &self.lifetime_ribs[i]; let normalized_ident = ident.normalize_to_macros_2_0(); if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) { - self.record_lifetime_res(lifetime.id, res, LifetimeElisionCandidate::Named); + self.record_lifetime_res(lifetime.id, res); if let LifetimeRes::Param { param, .. } = res { match self.lifetime_uses.entry(param) { @@ -1440,19 +1399,15 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Do not suggest eliding a lifetime where an anonymous // lifetime would be illegal. LifetimeRibKind::Item - | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many), + | LifetimeRibKind::AnonymousPassThrough(_, true) + | LifetimeRibKind::AnonymousReportError => { + Some(LifetimeUseSet::Many) + } // An anonymous lifetime is legal here, go ahead. - LifetimeRibKind::AnonymousCreateParameter { .. } => { + LifetimeRibKind::AnonymousPassThrough(_, false) + | LifetimeRibKind::AnonymousCreateParameter { .. } => { Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt }) } - // Only report if eliding the lifetime would have the same - // semantics. - LifetimeRibKind::Elided(r) => Some(if res == r { - LifetimeUseSet::One { use_span: ident.span, use_ctxt } - } else { - LifetimeUseSet::Many - }), LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric | LifetimeRibKind::AnonConst => None, @@ -1474,20 +1429,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { LifetimeRibKind::Item => break, LifetimeRibKind::ConstGeneric => { self.emit_non_static_lt_in_const_generic_error(lifetime); - self.record_lifetime_res( - lifetime.id, - LifetimeRes::Error, - LifetimeElisionCandidate::Ignore, - ); + self.r.lifetimes_res_map.insert(lifetime.id, LifetimeRes::Error); return; } LifetimeRibKind::AnonConst => { self.maybe_emit_forbidden_non_static_lifetime_error(lifetime); - self.record_lifetime_res( - lifetime.id, - LifetimeRes::Error, - LifetimeElisionCandidate::Ignore, - ); + self.r.lifetimes_res_map.insert(lifetime.id, LifetimeRes::Error); return; } _ => {} @@ -1505,31 +1452,19 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } self.emit_undeclared_lifetime_error(lifetime, outer_res); - self.record_lifetime_res(lifetime.id, LifetimeRes::Error, LifetimeElisionCandidate::Named); + self.record_lifetime_res(lifetime.id, LifetimeRes::Error); } #[tracing::instrument(level = "debug", skip(self))] fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) { debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime); - let missing_lifetime = MissingLifetime { - id: lifetime.id, - span: lifetime.ident.span, - kind: if elided { - MissingLifetimeKind::Ampersand - } else { - MissingLifetimeKind::Underscore - }, - count: 1, - }; - let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime); for i in (0..self.lifetime_ribs.len()).rev() { let rib = &mut self.lifetime_ribs[i]; - debug!(?rib.kind); match rib.kind { LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { let res = self.create_fresh_lifetime(lifetime.id, lifetime.ident, binder); - self.record_lifetime_res(lifetime.id, res, elision_candidate); + self.record_lifetime_res(lifetime.id, res); return; } LifetimeRibKind::AnonymousReportError => { @@ -1551,16 +1486,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { .span_label(lifetime.ident.span, note) .emit(); - self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate); + self.record_lifetime_res(lifetime.id, LifetimeRes::Error); return; } - LifetimeRibKind::Elided(res) => { - self.record_lifetime_res(lifetime.id, res, elision_candidate); - return; - } - LifetimeRibKind::ElisionFailure => { - self.diagnostic_metadata.current_elision_failures.push(missing_lifetime); - self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate); + LifetimeRibKind::AnonymousPassThrough(node_id, _) => { + self.record_lifetime_res( + lifetime.id, + LifetimeRes::Anonymous { binder: node_id, elided }, + ); return; } LifetimeRibKind::Item => break, @@ -1569,20 +1502,23 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { | LifetimeRibKind::AnonConst => {} } } - self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate); - self.report_missing_lifetime_specifiers(vec![missing_lifetime], None); + // This resolution is wrong, it passes the work to HIR lifetime resolution. + // We cannot use `LifetimeRes::Error` because we do not emit a diagnostic. + self.record_lifetime_res( + lifetime.id, + LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided }, + ); } #[tracing::instrument(level = "debug", skip(self))] fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) { let id = self.r.next_node_id(); - let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) }; - self.record_lifetime_res( anchor_id, LifetimeRes::ElidedAnchor { start: id, end: NodeId::from_u32(id.as_u32() + 1) }, - LifetimeElisionCandidate::Ignore, ); + + let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) }; self.resolve_anonymous_lifetime(<, true); } @@ -1651,9 +1587,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { | PathSource::Struct | PathSource::TupleStruct(..) => false, }; - if !missing && !segment.has_generic_args { - continue; - } let elided_lifetime_span = if segment.has_generic_args { // If there are brackets, but not generic arguments, then use the opening bracket @@ -1670,31 +1603,43 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.record_lifetime_res( segment_id, LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end }, - LifetimeElisionCandidate::Ignore, ); if !missing { // Do not create a parameter for patterns and expressions. - for id in node_ids { - self.record_lifetime_res( - id, - LifetimeRes::Infer, - LifetimeElisionCandidate::Named, - ); + for rib in self.lifetime_ribs.iter().rev() { + match rib.kind { + LifetimeRibKind::AnonymousPassThrough(binder, _) => { + let res = LifetimeRes::Anonymous { binder, elided: true }; + for id in node_ids { + self.record_lifetime_res(id, res); + } + break; + } + // `LifetimeRes::Error`, which would usually be used in the case of + // `ReportError`, is unsuitable here, as we don't emit an error yet. Instead, + // we simply resolve to an implicit lifetime, which will be checked later, at + // which point a suitable error will be emitted. + LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => { + // FIXME(cjgillot) This resolution is wrong, but this does not matter + // since these cases are erroneous anyway. Lifetime resolution should + // emit a "missing lifetime specifier" diagnostic. + let res = + LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true }; + for id in node_ids { + self.record_lifetime_res(id, res); + } + break; + } + LifetimeRibKind::AnonymousCreateParameter { .. } + | LifetimeRibKind::Generics { .. } + | LifetimeRibKind::ConstGeneric + | LifetimeRibKind::AnonConst => {} + } } continue; } - let missing_lifetime = MissingLifetime { - id: node_ids.start, - span: elided_lifetime_span, - kind: if segment.has_generic_args { - MissingLifetimeKind::Comma - } else { - MissingLifetimeKind::Brackets - }, - count: expected_lifetimes, - }; let mut should_lint = true; for rib in self.lifetime_ribs.iter().rev() { match rib.kind { @@ -1725,47 +1670,23 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { should_lint = false; for id in node_ids { - self.record_lifetime_res( - id, - LifetimeRes::Error, - LifetimeElisionCandidate::Named, - ); + self.record_lifetime_res(id, LifetimeRes::Error); } break; } // Do not create a parameter for patterns and expressions. LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { - // Group all suggestions into the first record. - let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime); for id in node_ids { let res = self.create_fresh_lifetime(id, ident, binder); - self.record_lifetime_res( - id, - res, - replace(&mut candidate, LifetimeElisionCandidate::Named), - ); + self.record_lifetime_res(id, res); } break; } - LifetimeRibKind::Elided(res) => { - let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime); + // `PassThrough` is the normal case. + LifetimeRibKind::AnonymousPassThrough(binder, _) => { + let res = LifetimeRes::Anonymous { binder, elided: true }; for id in node_ids { - self.record_lifetime_res( - id, - res, - replace(&mut candidate, LifetimeElisionCandidate::Ignore), - ); - } - break; - } - LifetimeRibKind::ElisionFailure => { - self.diagnostic_metadata.current_elision_failures.push(missing_lifetime); - for id in node_ids { - self.record_lifetime_res( - id, - LifetimeRes::Error, - LifetimeElisionCandidate::Ignore, - ); + self.record_lifetime_res(id, res); } break; } @@ -1774,14 +1695,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // we simply resolve to an implicit lifetime, which will be checked later, at // which point a suitable error will be emitted. LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => { + // FIXME(cjgillot) This resolution is wrong, but this does not matter + // since these cases are erroneous anyway. Lifetime resolution should + // emit a "missing lifetime specifier" diagnostic. + let res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true }; for id in node_ids { - self.record_lifetime_res( - id, - LifetimeRes::Error, - LifetimeElisionCandidate::Ignore, - ); + self.record_lifetime_res(id, res); } - self.report_missing_lifetime_specifiers(vec![missing_lifetime], None); break; } LifetimeRibKind::Generics { .. } @@ -1808,214 +1728,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } #[tracing::instrument(level = "debug", skip(self))] - fn record_lifetime_res( - &mut self, - id: NodeId, - res: LifetimeRes, - candidate: LifetimeElisionCandidate, - ) { + fn record_lifetime_res(&mut self, id: NodeId, res: LifetimeRes) { if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) { panic!( "lifetime {:?} resolved multiple times ({:?} before, {:?} now)", id, prev_res, res ) } - match res { - LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static => { - if let Some(ref mut candidates) = self.lifetime_elision_candidates { - candidates.insert(res, candidate); - } - } - LifetimeRes::Infer | LifetimeRes::Error | LifetimeRes::ElidedAnchor { .. } => {} - } - } - - #[tracing::instrument(level = "debug", skip(self))] - fn record_lifetime_param(&mut self, id: NodeId, res: LifetimeRes) { - if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) { - panic!( - "lifetime parameter {:?} resolved multiple times ({:?} before, {:?} now)", - id, prev_res, res - ) - } - } - - /// Perform resolution of a function signature, accounting for lifetime elision. - #[tracing::instrument(level = "debug", skip(self, inputs))] - fn resolve_fn_signature( - &mut self, - fn_id: NodeId, - has_self: bool, - inputs: impl Iterator, &'ast Ty)> + Clone, - output_ty: &'ast FnRetTy, - ) { - // Add each argument to the rib. - let elision_lifetime = self.resolve_fn_params(has_self, inputs); - debug!(?elision_lifetime); - - let outer_failures = take(&mut self.diagnostic_metadata.current_elision_failures); - let output_rib = if let Ok(res) = elision_lifetime.as_ref() { - LifetimeRibKind::Elided(*res) - } else { - LifetimeRibKind::ElisionFailure - }; - self.with_lifetime_rib(output_rib, |this| visit::walk_fn_ret_ty(this, &output_ty)); - let elision_failures = - replace(&mut self.diagnostic_metadata.current_elision_failures, outer_failures); - if !elision_failures.is_empty() { - let Err(failure_info) = elision_lifetime else { bug!() }; - self.report_missing_lifetime_specifiers(elision_failures, Some(failure_info)); - } - } - - /// Resolve inside function parameters and parameter types. - /// Returns the lifetime for elision in fn return type, - /// or diagnostic information in case of elision failure. - fn resolve_fn_params( - &mut self, - has_self: bool, - inputs: impl Iterator, &'ast Ty)>, - ) -> Result, Vec)> { - let outer_candidates = - replace(&mut self.lifetime_elision_candidates, Some(Default::default())); - - let mut elision_lifetime = None; - let mut lifetime_count = 0; - let mut parameter_info = Vec::new(); - - let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; - for (index, (pat, ty)) in inputs.enumerate() { - debug!(?pat, ?ty); - if let Some(pat) = pat { - self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings); - } - self.visit_ty(ty); - - if let Some(ref candidates) = self.lifetime_elision_candidates { - let new_count = candidates.len(); - let local_count = new_count - lifetime_count; - if local_count != 0 { - parameter_info.push(ElisionFnParameter { - index, - ident: if let Some(pat) = pat && let PatKind::Ident(_, ident, _) = pat.kind { - Some(ident) - } else { - None - }, - lifetime_count: local_count, - span: ty.span, - }); - } - lifetime_count = new_count; - } - - // Handle `self` specially. - if index == 0 && has_self { - let self_lifetime = self.find_lifetime_for_self(ty); - if let Set1::One(lifetime) = self_lifetime { - elision_lifetime = Some(lifetime); - self.lifetime_elision_candidates = None; - } else { - self.lifetime_elision_candidates = Some(Default::default()); - lifetime_count = 0; - } - } - debug!("(resolving function / closure) recorded parameter"); - } - - let all_candidates = replace(&mut self.lifetime_elision_candidates, outer_candidates); - debug!(?all_candidates); - - if let Some(res) = elision_lifetime { - return Ok(res); - } - - // We do not have a `self` candidate, look at the full list. - let all_candidates = all_candidates.unwrap(); - if all_candidates.len() == 1 { - Ok(*all_candidates.first().unwrap().0) - } else { - let all_candidates = all_candidates - .into_iter() - .filter_map(|(_, candidate)| match candidate { - LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => None, - LifetimeElisionCandidate::Missing(missing) => Some(missing), - }) - .collect(); - Err((all_candidates, parameter_info)) - } - } - - /// List all the lifetimes that appear in the provided type. - fn find_lifetime_for_self(&self, ty: &'ast Ty) -> Set1 { - struct SelfVisitor<'r, 'a> { - r: &'r Resolver<'a>, - impl_self: Option, - lifetime: Set1, - } - - impl SelfVisitor<'_, '_> { - // Look for `self: &'a Self` - also desugared from `&'a self`, - // and if that matches, use it for elision and return early. - fn is_self_ty(&self, ty: &Ty) -> bool { - match ty.kind { - TyKind::ImplicitSelf => true, - TyKind::Path(None, _) => { - let path_res = self.r.partial_res_map[&ty.id].base_res(); - if let Res::SelfTy { .. } = path_res { - return true; - } - Some(path_res) == self.impl_self - } - _ => false, - } - } - } - - impl<'a> Visitor<'a> for SelfVisitor<'_, '_> { - fn visit_ty(&mut self, ty: &'a Ty) { - trace!("SelfVisitor considering ty={:?}", ty); - if let TyKind::Rptr(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) { - let lt_id = if let Some(lt) = lt { - lt.id - } else { - let res = self.r.lifetimes_res_map[&ty.id]; - let LifetimeRes::ElidedAnchor { start, .. } = res else { bug!() }; - start - }; - let lt_res = self.r.lifetimes_res_map[<_id]; - trace!("SelfVisitor inserting res={:?}", lt_res); - self.lifetime.insert(lt_res); - } - visit::walk_ty(self, ty) - } - } - - let impl_self = self - .diagnostic_metadata - .current_self_type - .as_ref() - .and_then(|ty| { - if let TyKind::Path(None, _) = ty.kind { - self.r.partial_res_map.get(&ty.id) - } else { - None - } - }) - .map(|res| res.base_res()) - .filter(|res| { - // Permit the types that unambiguously always - // result in the same type constructor being used - // (it can't differ between `Self` and `self`). - matches!( - res, - Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_) - ) - }); - let mut visitor = SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty }; - visitor.visit_ty(ty); - trace!("SelfVisitor found={:?}", visitor.lifetime); - visitor.lifetime } /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved @@ -2240,26 +1959,22 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => { self.with_item_rib(|this| { - this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { - this.visit_ty(ty); - }); - this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { - if let Some(expr) = expr { - let constant_item_kind = match item.kind { - ItemKind::Const(..) => ConstantItemKind::Const, - ItemKind::Static(..) => ConstantItemKind::Static, - _ => unreachable!(), - }; - // We already forbid generic params because of the above item rib, - // so it doesn't matter whether this is a trivial constant. - this.with_constant_rib( - IsRepeatExpr::No, - HasGenericParams::Yes, - Some((item.ident, constant_item_kind)), - |this| this.visit_expr(expr), - ); - } - }); + this.visit_ty(ty); + if let Some(expr) = expr { + let constant_item_kind = match item.kind { + ItemKind::Const(..) => ConstantItemKind::Const, + ItemKind::Static(..) => ConstantItemKind::Static, + _ => unreachable!(), + }; + // We already forbid generic params because of the above item rib, + // so it doesn't matter whether this is a trivial constant. + this.with_constant_rib( + IsRepeatExpr::No, + HasGenericParams::Yes, + Some((item.ident, constant_item_kind)), + |this| this.visit_expr(expr), + ); + } }); } @@ -2330,7 +2045,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { { diagnostics::signal_lifetime_shadowing(self.r.session, original, param.ident); // Record lifetime res, so lowering knows there is something fishy. - self.record_lifetime_param(param.id, LifetimeRes::Error); + self.record_lifetime_res(param.id, LifetimeRes::Error); continue; } @@ -2341,7 +2056,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.report_error(param.ident.span, err); if let GenericParamKind::Lifetime = param.kind { // Record lifetime res, so lowering knows there is something fishy. - self.record_lifetime_param(param.id, LifetimeRes::Error); + self.record_lifetime_res(param.id, LifetimeRes::Error); continue; } } @@ -2360,7 +2075,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { .span_label(param.ident.span, "`'_` is a reserved lifetime name") .emit(); // Record lifetime res, so lowering knows there is something fishy. - self.record_lifetime_param(param.id, LifetimeRes::Error); + self.record_lifetime_res(param.id, LifetimeRes::Error); continue; } @@ -2375,7 +2090,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { .span_label(param.ident.span, "'static is a reserved lifetime name") .emit(); // Record lifetime res, so lowering knows there is something fishy. - self.record_lifetime_param(param.id, LifetimeRes::Error); + self.record_lifetime_res(param.id, LifetimeRes::Error); continue; } @@ -2387,7 +2102,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam), GenericParamKind::Lifetime => { let res = LifetimeRes::Param { param: def_id, binder }; - self.record_lifetime_param(param.id, res); + self.record_lifetime_res(param.id, res); function_lifetime_rib.bindings.insert(ident, (param.id, res)); continue; } @@ -2396,7 +2111,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let res = match kind { ItemRibKind(..) | AssocItemRibKind => Res::Def(def_kind, def_id.to_def_id()), NormalRibKind => Res::Err, - _ => span_bug!(param.ident.span, "Unexpected rib kind {:?}", kind), + _ => bug!("Unexpected rib kind {:?}", kind), }; self.r.record_partial_res(param.id, PartialRes::new(res)); rib.bindings.insert(ident, res); @@ -2410,14 +2125,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.ribs[TypeNS].pop(); self.ribs[ValueNS].pop(); - let function_lifetime_rib = self.lifetime_ribs.pop().unwrap(); - - // Do not account for the parameters we just bound for function lifetime elision. - if let Some(ref mut candidates) = self.lifetime_elision_candidates { - for (_, res) in function_lifetime_rib.bindings.values() { - candidates.remove(res); - } - } + self.lifetime_ribs.pop(); if let LifetimeBinderKind::BareFnType | LifetimeBinderKind::WhereBound @@ -2515,26 +2223,20 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // // Type parameters can already be used and as associated consts are // not used as part of the type system, this is far less surprising. - self.with_lifetime_rib( - LifetimeRibKind::Elided(LifetimeRes::Infer), - |this| { - this.with_constant_rib( - IsRepeatExpr::No, - HasGenericParams::Yes, - None, - |this| this.visit_expr(expr), - ) - }, + self.with_constant_rib( + IsRepeatExpr::No, + HasGenericParams::Yes, + None, + |this| this.visit_expr(expr), ); } } AssocItemKind::Fn(box Fn { generics, .. }) => { walk_assoc_item(self, generics, LifetimeBinderKind::Function, item); } - AssocItemKind::TyAlias(box TyAlias { generics, .. }) => self - .with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { - walk_assoc_item(this, generics, LifetimeBinderKind::Item, item) - }), + AssocItemKind::TyAlias(box TyAlias { generics, .. }) => { + walk_assoc_item(self, generics, LifetimeBinderKind::Item, item); + } AssocItemKind::MacCall(_) => { panic!("unexpanded macro in resolve!") } @@ -2605,7 +2307,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { LifetimeRibKind::Generics { span: generics.span, binder: item_id, - kind: LifetimeBinderKind::ImplBlock, + kind: LifetimeBinderKind::ImplBlock }, |this| { // Dummy self type for better errors if `Self` is used in the trait path. @@ -2625,11 +2327,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Register the trait definitions from here. if let Some(trait_id) = trait_id { - this.r - .trait_impls - .entry(trait_id) - .or_default() - .push(item_def_id); + this.r.trait_impls.entry(trait_id).or_default().push(item_def_id); } let item_def_id = item_def_id.to_def_id(); @@ -2648,17 +2346,21 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { this.visit_generics(generics); // Resolve the items within the impl. - this.with_current_self_type(self_type, |this| { - this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| { - debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); - for item in impl_items { - this.resolve_impl_item(&**item); - } - }); - }); + this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(item_id,false), + |this| { + this.with_current_self_type(self_type, |this| { + this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| { + debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); + for item in impl_items { + this.resolve_impl_item(&**item); + } + }); + }); + }, + ); }); }, - ) + ); }, ); }); @@ -2689,13 +2391,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // // Type parameters can already be used and as associated consts are // not used as part of the type system, this is far less surprising. - self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { - this.with_constant_rib( - IsRepeatExpr::No, - HasGenericParams::Yes, - None, - |this| this.visit_expr(expr), - ) + self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| { + this.visit_expr(expr) }); } } @@ -2738,20 +2435,18 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { kind: LifetimeBinderKind::Item, }, |this| { - this.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { - // If this is a trait impl, ensure the type - // exists in trait - this.check_trait_item( - item.id, - item.ident, - &item.kind, - TypeNS, - item.span, - |i, s, c| TypeNotMemberOfTrait(i, s, c), - ); + // If this is a trait impl, ensure the type + // exists in trait + this.check_trait_item( + item.id, + item.ident, + &item.kind, + TypeNS, + item.span, + |i, s, c| TypeNotMemberOfTrait(i, s, c), + ); - visit::walk_assoc_item(this, item, AssocCtxt::Impl) - }); + visit::walk_assoc_item(this, item, AssocCtxt::Impl) }, ); } @@ -3886,9 +3581,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ExprKind::Repeat(ref elem, ref ct) => { self.visit_expr(elem); self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| { - this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { - this.resolve_anon_const(ct, IsRepeatExpr::Yes) - }) + this.resolve_anon_const(ct, IsRepeatExpr::Yes) }); } ExprKind::ConstBlock(ref ct) => { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 6b49c6b1ac63e..e428bae479bc2 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1,6 +1,7 @@ use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion}; +use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext}; use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind}; -use crate::late::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseSet}; +use crate::late::{LifetimeBinderKind, LifetimeRibKind, LifetimeUseSet}; use crate::path_names_to_string; use crate::{Module, ModuleKind, ModuleOrUniformRoot}; use crate::{PathResult, PathSource, Segment}; @@ -8,10 +9,10 @@ use crate::{PathResult, PathSource, Segment}; use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt}; use rustc_ast::{ self as ast, AssocItemKind, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind, - NodeId, Path, Ty, TyKind, DUMMY_NODE_ID, + NodeId, Path, Ty, TyKind, }; use rustc_ast_pretty::pprust::path_segment_to_string; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::{ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, @@ -19,7 +20,7 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; -use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::PrimTy; use rustc_session::lint; use rustc_session::parse::feature_err; @@ -28,7 +29,7 @@ use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, Span}; +use rustc_span::{BytePos, Span, DUMMY_SP}; use std::iter; use std::ops::Deref; @@ -58,6 +59,45 @@ impl AssocSuggestion { } } +pub(crate) enum MissingLifetimeSpot<'tcx> { + Generics(&'tcx hir::Generics<'tcx>), + HigherRanked { span: Span, span_type: ForLifetimeSpanType }, + Static, +} + +pub(crate) enum ForLifetimeSpanType { + BoundEmpty, + BoundTail, + TypeEmpty, + TypeTail, + ClosureEmpty, + ClosureTail, +} + +impl ForLifetimeSpanType { + pub(crate) fn descr(&self) -> &'static str { + match self { + Self::BoundEmpty | Self::BoundTail => "bound", + Self::TypeEmpty | Self::TypeTail => "type", + Self::ClosureEmpty | Self::ClosureTail => "closure", + } + } + + pub(crate) fn suggestion(&self, sugg: impl std::fmt::Display) -> String { + match self { + Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg), + Self::ClosureEmpty => format!("for<{}>", sugg), + Self::BoundTail | Self::TypeTail | Self::ClosureTail => format!(", {}", sugg), + } + } +} + +impl<'tcx> Into> for &&'tcx hir::Generics<'tcx> { + fn into(self) -> MissingLifetimeSpot<'tcx> { + MissingLifetimeSpot::Generics(self) + } +} + fn is_self_type(path: &[Segment], namespace: Namespace) -> bool { namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper } @@ -82,56 +122,6 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str (variant_path_string, enum_path_string) } -/// Description of an elided lifetime. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub(super) struct MissingLifetime { - /// Used to overwrite the resolution with the suggestion, to avoid cascasing errors. - pub id: NodeId, - /// Where to suggest adding the lifetime. - pub span: Span, - /// How the lifetime was introduced, to have the correct space and comma. - pub kind: MissingLifetimeKind, - /// Number of elided lifetimes, used for elision in path. - pub count: usize, -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub(super) enum MissingLifetimeKind { - /// An explicit `'_`. - Underscore, - /// An elided lifetime `&' ty`. - Ampersand, - /// An elided lifetime in brackets with written brackets. - Comma, - /// An elided lifetime with elided brackets. - Brackets, -} - -/// Description of the lifetimes appearing in a function parameter. -/// This is used to provide a literal explanation to the elision failure. -#[derive(Clone, Debug)] -pub(super) struct ElisionFnParameter { - /// The index of the argument in the original definition. - pub index: usize, - /// The name of the argument if it's a simple ident. - pub ident: Option, - /// The number of lifetimes in the parameter. - pub lifetime_count: usize, - /// The span of the parameter. - pub span: Span, -} - -/// Description of lifetimes that appear as candidates for elision. -/// This is used to suggest introducing an explicit lifetime. -#[derive(Debug)] -pub(super) enum LifetimeElisionCandidate { - /// This is not a real lifetime. - Ignore, - /// There is a named lifetime, we won't suggest anything. - Named, - Missing(MissingLifetime), -} - impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { fn def_span(&self, def_id: DefId) -> Option { match def_id.krate { @@ -1444,7 +1434,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { // Items from this module self.r.add_module_candidates(module, &mut names, &filter_fn); - if let ModuleKind::Block = module.kind { + if let ModuleKind::Block(..) = module.kind { // We can see through blocks } else { // Items from the prelude @@ -2013,35 +2003,18 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { err.span_label(lifetime_ref.ident.span, "undeclared lifetime"); err }; - self.suggest_introducing_lifetime( - &mut err, - Some(lifetime_ref.ident.name.as_str()), - |err, _, span, message, suggestion| { - err.span_suggestion(span, message, suggestion, Applicability::MaybeIncorrect); - true - }, - ); - err.emit(); - } - - fn suggest_introducing_lifetime( - &self, - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, - name: Option<&str>, - suggest: impl Fn(&mut DiagnosticBuilder<'_, ErrorGuaranteed>, bool, Span, &str, String) -> bool, - ) { let mut suggest_note = true; + for rib in self.lifetime_ribs.iter().rev() { - let mut should_continue = true; match rib.kind { LifetimeRibKind::Generics { binder: _, span, kind } => { - if !span.can_be_used_for_suggestions() && suggest_note && let Some(name) = name { + if !span.can_be_used_for_suggestions() && suggest_note { suggest_note = false; // Avoid displaying the same help multiple times. err.span_label( span, &format!( "lifetime `{}` is missing in item created through this procedural macro", - name, + lifetime_ref.ident, ), ); continue; @@ -2057,42 +2030,46 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let sugg = format!( "{}<{}>{}", if higher_ranked { "for" } else { "" }, - name.unwrap_or("'a"), + lifetime_ref.ident, if higher_ranked { " " } else { "" }, ); (span, sugg) } else { let span = self.r.session.source_map().span_through_char(span, '<').shrink_to_hi(); - let sugg = format!("{}, ", name.unwrap_or("'a")); + let sugg = format!("{}, ", lifetime_ref.ident); (span, sugg) }; if higher_ranked { - let message = format!( - "consider making the {} lifetime-generic with a new `{}` lifetime", - kind.descr(), - name.unwrap_or("'a"), + err.span_suggestion( + span, + &format!( + "consider making the {} lifetime-generic with a new `{}` lifetime", + kind.descr(), + lifetime_ref + ), + sugg, + Applicability::MaybeIncorrect, ); - should_continue = suggest(err, true, span, &message, sugg); err.note_once( "for more information on higher-ranked polymorphism, visit \ https://doc.rust-lang.org/nomicon/hrtb.html", ); - } else if let Some(name) = name { - let message = format!("consider introducing lifetime `{}` here", name); - should_continue = suggest(err, false, span, &message, sugg); } else { - let message = format!("consider introducing a named lifetime parameter"); - should_continue = suggest(err, false, span, &message, sugg); + err.span_suggestion( + span, + &format!("consider introducing lifetime `{}` here", lifetime_ref.ident), + sugg, + Applicability::MaybeIncorrect, + ); } } LifetimeRibKind::Item => break, _ => {} } - if !should_continue { - break; - } } + + err.emit(); } pub(crate) fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &ast::Lifetime) { @@ -2128,209 +2105,552 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { .emit(); } } +} - pub(crate) fn report_missing_lifetime_specifiers( - &mut self, - lifetime_refs: Vec, - function_param_lifetimes: Option<(Vec, Vec)>, - ) -> ErrorGuaranteed { - let num_lifetimes: usize = lifetime_refs.iter().map(|lt| lt.count).sum(); - let spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect(); +/// Report lifetime/lifetime shadowing as an error. +pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) { + let mut err = struct_span_err!( + sess, + shadower.span, + E0496, + "lifetime name `{}` shadows a lifetime name that is already in scope", + orig.name, + ); + err.span_label(orig.span, "first declared here"); + err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name)); + err.emit(); +} - let mut err = struct_span_err!( - self.r.session, +/// Shadowing involving a label is only a warning for historical reasons. +//FIXME: make this a proper lint. +pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) { + let name = shadower.name; + let shadower = shadower.span; + let mut err = sess.struct_span_warn( + shadower, + &format!("label name `{}` shadows a label name that is already in scope", name), + ); + err.span_label(orig, "first declared here"); + err.span_label(shadower, format!("label `{}` already in scope", name)); + err.emit(); +} + +impl<'tcx> LifetimeContext<'_, 'tcx> { + pub(crate) fn report_missing_lifetime_specifiers( + &self, + spans: Vec, + count: usize, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + struct_span_err!( + self.tcx.sess, spans, E0106, "missing lifetime specifier{}", - pluralize!(num_lifetimes) - ); - self.add_missing_lifetime_specifiers_label( - &mut err, - lifetime_refs, - function_param_lifetimes, - ); - err.emit() + pluralize!(count) + ) } - pub(crate) fn add_missing_lifetime_specifiers_label( - &mut self, - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, - lifetime_refs: Vec, - function_param_lifetimes: Option<(Vec, Vec)>, - ) { - for < in &lifetime_refs { - err.span_label( - lt.span, - format!( - "expected {} lifetime parameter{}", - if lt.count == 1 { "named".to_string() } else { lt.count.to_string() }, - pluralize!(lt.count), - ), - ); - } - - let mut in_scope_lifetimes: Vec<_> = self - .lifetime_ribs - .iter() - .rev() - .take_while(|rib| !matches!(rib.kind, LifetimeRibKind::Item)) - .flat_map(|rib| rib.bindings.iter()) - .map(|(&ident, &res)| (ident, res)) - .filter(|(ident, _)| ident.name != kw::UnderscoreLifetime) - .collect(); - debug!(?in_scope_lifetimes); - - debug!(?function_param_lifetimes); - if let Some((param_lifetimes, params)) = &function_param_lifetimes { - let elided_len = param_lifetimes.len(); - let num_params = params.len(); + /// Returns whether to add `'static` lifetime to the suggested lifetime list. + pub(crate) fn report_elision_failure( + &self, + diag: &mut Diagnostic, + params: &[ElisionFailureInfo], + ) -> bool { + let mut m = String::new(); + let len = params.len(); - let mut m = String::new(); + let elided_params: Vec<_> = + params.iter().cloned().filter(|info| info.lifetime_count > 0).collect(); - for (i, info) in params.iter().enumerate() { - let ElisionFnParameter { ident, index, lifetime_count, span } = *info; - debug_assert_ne!(lifetime_count, 0); + let elided_len = elided_params.len(); - err.span_label(span, ""); + for (i, info) in elided_params.into_iter().enumerate() { + let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } = + info; - if i != 0 { - if i + 1 < num_params { - m.push_str(", "); - } else if num_params == 2 { - m.push_str(" or "); - } else { - m.push_str(", or "); - } - } + diag.span_label(span, ""); + let help_name = if let Some(ident) = + parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident()) + { + format!("`{}`", ident) + } else { + format!("argument {}", index + 1) + }; - let help_name = if let Some(ident) = ident { - format!("`{}`", ident) + m.push_str( + &(if n == 1 { + help_name } else { - format!("argument {}", index + 1) - }; + format!( + "one of {}'s {} {}lifetimes", + help_name, + n, + if have_bound_regions { "free " } else { "" } + ) + })[..], + ); - if lifetime_count == 1 { - m.push_str(&help_name[..]) - } else { - m.push_str(&format!("one of {}'s {} lifetimes", help_name, lifetime_count)[..]) - } + if elided_len == 2 && i == 0 { + m.push_str(" or "); + } else if i + 2 == elided_len { + m.push_str(", or "); + } else if i != elided_len - 1 { + m.push_str(", "); } + } - if num_params == 0 { - err.help( - "this function's return type contains a borrowed value, \ + if len == 0 { + diag.help( + "this function's return type contains a borrowed value, \ but there is no value for it to be borrowed from", - ); - if in_scope_lifetimes.is_empty() { - in_scope_lifetimes = vec![( - Ident::with_dummy_span(kw::StaticLifetime), - (DUMMY_NODE_ID, LifetimeRes::Static), - )]; - } - } else if elided_len == 0 { - err.help( - "this function's return type contains a borrowed value with \ + ); + true + } else if elided_len == 0 { + diag.help( + "this function's return type contains a borrowed value with \ an elided lifetime, but the lifetime cannot be derived from \ the arguments", - ); - if in_scope_lifetimes.is_empty() { - in_scope_lifetimes = vec![( - Ident::with_dummy_span(kw::StaticLifetime), - (DUMMY_NODE_ID, LifetimeRes::Static), - )]; - } - } else if num_params == 1 { - err.help(&format!( - "this function's return type contains a borrowed value, \ + ); + true + } else if elided_len == 1 { + diag.help(&format!( + "this function's return type contains a borrowed value, \ but the signature does not say which {} it is borrowed from", - m - )); - } else { - err.help(&format!( - "this function's return type contains a borrowed value, \ + m + )); + false + } else { + diag.help(&format!( + "this function's return type contains a borrowed value, \ but the signature does not say whether it is borrowed from {}", - m - )); - } + m + )); + false } + } - let existing_name = match &in_scope_lifetimes[..] { - [] => Symbol::intern("'a"), - [(existing, _)] => existing.name, - _ => Symbol::intern("'lifetime"), + pub(crate) fn is_trait_ref_fn_scope( + &mut self, + trait_ref: &'tcx hir::PolyTraitRef<'tcx>, + ) -> bool { + if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res { + if [ + self.tcx.lang_items().fn_once_trait(), + self.tcx.lang_items().fn_trait(), + self.tcx.lang_items().fn_mut_trait(), + ] + .contains(&Some(did)) + { + let (span, span_type) = if let Some(bound) = + trait_ref.bound_generic_params.iter().rfind(|param| { + matches!( + param.kind, + hir::GenericParamKind::Lifetime { + kind: hir::LifetimeParamKind::Explicit + } + ) + }) { + (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail) + } else { + (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty) + }; + self.missing_named_lifetime_spots + .push(MissingLifetimeSpot::HigherRanked { span, span_type }); + return true; + } }; + false + } - let mut spans_suggs: Vec<_> = Vec::new(); - let build_sugg = |lt: MissingLifetime| match lt.kind { - MissingLifetimeKind::Underscore => { - debug_assert_eq!(lt.count, 1); - (lt.span, existing_name.to_string()) - } - MissingLifetimeKind::Ampersand => { - debug_assert_eq!(lt.count, 1); - (lt.span.shrink_to_hi(), format!("{} ", existing_name)) - } - MissingLifetimeKind::Comma => { - let sugg: String = std::iter::repeat([existing_name.as_str(), ", "]) - .take(lt.count) - .flatten() - .collect(); - (lt.span.shrink_to_hi(), sugg) + pub(crate) fn add_missing_lifetime_specifiers_label( + &self, + err: &mut Diagnostic, + mut spans_with_counts: Vec<(Span, usize)>, + in_scope_lifetimes: FxIndexSet, + params: Option<&[ElisionFailureInfo]>, + ) { + let (mut lifetime_names, lifetime_spans): (FxHashSet<_>, Vec<_>) = in_scope_lifetimes + .iter() + .filter_map(|def_id| { + let name = self.tcx.item_name(def_id.to_def_id()); + let span = self.tcx.def_ident_span(def_id.to_def_id())?; + Some((name, span)) + }) + .filter(|&(n, _)| n != kw::UnderscoreLifetime) + .unzip(); + + if let Some(params) = params { + // If there's no lifetime available, suggest `'static`. + if self.report_elision_failure(err, params) && lifetime_names.is_empty() { + lifetime_names.insert(kw::StaticLifetime); } - MissingLifetimeKind::Brackets => { - let sugg: String = std::iter::once("<") - .chain( - std::iter::repeat(existing_name.as_str()).take(lt.count).intersperse(", "), - ) - .chain([">"]) - .collect(); - (lt.span.shrink_to_hi(), sugg) + } + let params = params.unwrap_or(&[]); + + let snippets: Vec> = spans_with_counts + .iter() + .map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok()) + .collect(); + + // Empty generics are marked with a span of "<", but since from now on + // that information is in the snippets it can be removed from the spans. + for ((span, _), snippet) in spans_with_counts.iter_mut().zip(&snippets) { + if snippet.as_deref() == Some("<") { + *span = span.shrink_to_hi(); } - }; - for < in &lifetime_refs { - spans_suggs.push(build_sugg(lt)); } - debug!(?spans_suggs); - match in_scope_lifetimes.len() { - 0 => { - if let Some((param_lifetimes, _)) = function_param_lifetimes { - for lt in param_lifetimes { - spans_suggs.push(build_sugg(lt)) + + for &(span, count) in &spans_with_counts { + err.span_label( + span, + format!( + "expected {} lifetime parameter{}", + if count == 1 { "named".to_string() } else { count.to_string() }, + pluralize!(count), + ), + ); + } + + let suggest_existing = + |err: &mut Diagnostic, + name: Symbol, + formatters: Vec String>>>| { + if let Some(MissingLifetimeSpot::HigherRanked { span: for_span, span_type }) = + self.missing_named_lifetime_spots.iter().rev().next() + { + // When we have `struct S<'a>(&'a dyn Fn(&X) -> &X);` we want to not only suggest + // using `'a`, but also introduce the concept of HRLTs by suggesting + // `struct S<'a>(&'a dyn for<'b> Fn(&X) -> &'b X);`. (#72404) + let mut introduce_suggestion = vec![]; + + let a_to_z_repeat_n = |n| { + (b'a'..=b'z').map(move |c| { + let mut s = '\''.to_string(); + s.extend(std::iter::repeat(char::from(c)).take(n)); + s + }) + }; + + // If all single char lifetime names are present, we wrap around and double the chars. + let lt_name = (1..) + .flat_map(a_to_z_repeat_n) + .map(|lt| Symbol::intern(<)) + .find(|lt| !lifetime_names.contains(lt)) + .unwrap(); + let msg = format!( + "consider making the {} lifetime-generic with a new `{}` lifetime", + span_type.descr(), + lt_name, + ); + err.note( + "for more information on higher-ranked polymorphism, visit \ + https://doc.rust-lang.org/nomicon/hrtb.html", + ); + let for_sugg = span_type.suggestion(<_name); + for param in params { + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) + { + if snippet.starts_with('&') && !snippet.starts_with("&'") { + introduce_suggestion + .push((param.span, format!("&{} {}", lt_name, &snippet[1..]))); + } else if let Some(stripped) = snippet.strip_prefix("&'_ ") { + introduce_suggestion + .push((param.span, format!("&{} {}", lt_name, stripped))); + } + } } + introduce_suggestion.push((*for_span, for_sugg)); + for ((span, _), formatter) in spans_with_counts.iter().zip(formatters.iter()) { + if let Some(formatter) = formatter { + introduce_suggestion.push((*span, formatter(lt_name))); + } + } + err.multipart_suggestion_verbose( + &msg, + introduce_suggestion, + Applicability::MaybeIncorrect, + ); } - self.suggest_introducing_lifetime( - err, - None, - |err, higher_ranked, span, message, intro_sugg| { + + let spans_suggs: Vec<_> = formatters + .into_iter() + .zip(spans_with_counts.iter()) + .filter_map(|(formatter, (span, _))| { + if let Some(formatter) = formatter { + Some((*span, formatter(name))) + } else { + None + } + }) + .collect(); + if spans_suggs.is_empty() { + // If all the spans come from macros, we cannot extract snippets and then + // `formatters` only contains None and `spans_suggs` is empty. + return; + } + err.multipart_suggestion_verbose( + &format!( + "consider using the `{}` lifetime", + lifetime_names.iter().next().unwrap() + ), + spans_suggs, + Applicability::MaybeIncorrect, + ); + }; + let suggest_new = |err: &mut Diagnostic, suggs: Vec>| { + for missing in self.missing_named_lifetime_spots.iter().rev() { + let mut introduce_suggestion = vec![]; + let msg; + let should_break; + introduce_suggestion.push(match missing { + MissingLifetimeSpot::Generics(generics) => { + if generics.span == DUMMY_SP { + // Account for malformed generics in the HIR. This shouldn't happen, + // but if we make a mistake elsewhere, mainly by keeping something in + // `missing_named_lifetime_spots` that we shouldn't, like associated + // `const`s or making a mistake in the AST lowering we would provide + // nonsensical suggestions. Guard against that by skipping these. + // (#74264) + continue; + } + msg = "consider introducing a named lifetime parameter".to_string(); + should_break = true; + if let Some(param) = generics.params.iter().find(|p| { + !matches!( + p.kind, + hir::GenericParamKind::Type { synthetic: true, .. } + | hir::GenericParamKind::Lifetime { + kind: hir::LifetimeParamKind::Elided + } + ) + }) { + (param.span.shrink_to_lo(), "'a, ".to_string()) + } else { + (generics.span, "<'a>".to_string()) + } + } + MissingLifetimeSpot::HigherRanked { span, span_type } => { + msg = format!( + "consider making the {} lifetime-generic with a new `'a` lifetime", + span_type.descr(), + ); + should_break = false; + err.note( + "for more information on higher-ranked polymorphism, visit \ + https://doc.rust-lang.org/nomicon/hrtb.html", + ); + (*span, span_type.suggestion("'a")) + } + MissingLifetimeSpot::Static => { + let mut spans_suggs = Vec::new(); + for ((span, count), snippet) in + spans_with_counts.iter().copied().zip(snippets.iter()) + { + let (span, sugg) = match snippet.as_deref() { + Some("&") => (span.shrink_to_hi(), "'static ".to_owned()), + Some("'_") => (span, "'static".to_owned()), + Some(snippet) if !snippet.ends_with('>') => { + if snippet == "" { + ( + span, + std::iter::repeat("'static") + .take(count) + .collect::>() + .join(", "), + ) + } else if snippet == "<" || snippet == "(" { + ( + span.shrink_to_hi(), + std::iter::repeat("'static") + .take(count) + .collect::>() + .join(", "), + ) + } else { + ( + span.shrink_to_hi(), + format!( + "<{}>", + std::iter::repeat("'static") + .take(count) + .collect::>() + .join(", "), + ), + ) + } + } + _ => continue, + }; + spans_suggs.push((span, sugg.to_string())); + } err.multipart_suggestion_verbose( - message, - std::iter::once((span, intro_sugg)) - .chain(spans_suggs.clone()) - .collect(), + "consider using the `'static` lifetime", + spans_suggs, Applicability::MaybeIncorrect, ); - higher_ranked + continue; + } + }); + + struct Lifetime(Span, String); + impl Lifetime { + fn is_unnamed(&self) -> bool { + self.1.starts_with('&') && !self.1.starts_with("&'") + } + fn is_underscore(&self) -> bool { + self.1.starts_with("&'_ ") + } + fn is_named(&self) -> bool { + self.1.starts_with("&'") + } + fn suggestion(&self, sugg: String) -> Option<(Span, String)> { + Some( + match ( + self.is_unnamed(), + self.is_underscore(), + self.is_named(), + sugg.starts_with('&'), + ) { + (true, _, _, false) => (self.span_unnamed_borrow(), sugg), + (true, _, _, true) => { + (self.span_unnamed_borrow(), sugg[1..].to_string()) + } + (_, true, _, false) => { + (self.span_underscore_borrow(), sugg.trim().to_string()) + } + (_, true, _, true) => { + (self.span_underscore_borrow(), sugg[1..].trim().to_string()) + } + (_, _, true, false) => { + (self.span_named_borrow(), sugg.trim().to_string()) + } + (_, _, true, true) => { + (self.span_named_borrow(), sugg[1..].trim().to_string()) + } + _ => return None, + }, + ) + } + fn span_unnamed_borrow(&self) -> Span { + let lo = self.0.lo() + BytePos(1); + self.0.with_lo(lo).with_hi(lo) + } + fn span_named_borrow(&self) -> Span { + let lo = self.0.lo() + BytePos(1); + self.0.with_lo(lo) + } + fn span_underscore_borrow(&self) -> Span { + let lo = self.0.lo() + BytePos(1); + let hi = lo + BytePos(2); + self.0.with_lo(lo).with_hi(hi) + } + } + + for param in params { + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) { + if let Some((span, sugg)) = + Lifetime(param.span, snippet).suggestion("'a ".to_string()) + { + introduce_suggestion.push((span, sugg)); + } + } + } + for (span, sugg) in spans_with_counts.iter().copied().zip(suggs.iter()).filter_map( + |((span, _), sugg)| match &sugg { + Some(sugg) => Some((span, sugg.to_string())), + _ => None, }, - ); - } - 1 => { + ) { + let (span, sugg) = self + .tcx + .sess + .source_map() + .span_to_snippet(span) + .ok() + .and_then(|snippet| Lifetime(span, snippet).suggestion(sugg.clone())) + .unwrap_or((span, sugg)); + introduce_suggestion.push((span, sugg.to_string())); + } err.multipart_suggestion_verbose( - &format!("consider using the `{}` lifetime", existing_name), - spans_suggs, + &msg, + introduce_suggestion, Applicability::MaybeIncorrect, ); + if should_break { + break; + } + } + }; - // Record as using the suggested resolution. - let (_, (_, res)) = in_scope_lifetimes[0]; - for < in &lifetime_refs { - self.r.lifetimes_res_map.insert(lt.id, res); + let lifetime_names: Vec<_> = lifetime_names.iter().collect(); + match &lifetime_names[..] { + [name] => { + let mut suggs: Vec String>>> = Vec::new(); + for (snippet, (_, count)) in snippets.iter().zip(spans_with_counts.iter().copied()) + { + suggs.push(match snippet.as_deref() { + Some("&") => Some(Box::new(|name| format!("&{} ", name))), + Some("'_") => Some(Box::new(|n| n.to_string())), + Some("") => Some(Box::new(move |n| format!("{}, ", n).repeat(count))), + Some("<") => Some(Box::new(move |n| { + std::iter::repeat(n) + .take(count) + .map(|n| n.to_string()) + .collect::>() + .join(", ") + })), + Some(snippet) if !snippet.ends_with('>') => Some(Box::new(move |name| { + format!( + "{}<{}>", + snippet, + std::iter::repeat(name.to_string()) + .take(count) + .collect::>() + .join(", ") + ) + })), + _ => None, + }); } + suggest_existing(err, **name, suggs); } - _ => { - let lifetime_spans: Vec<_> = - in_scope_lifetimes.iter().map(|(ident, _)| ident.span).collect(); + [] => { + let mut suggs = Vec::new(); + for (snippet, (_, count)) in + snippets.iter().cloned().zip(spans_with_counts.iter().copied()) + { + suggs.push(match snippet.as_deref() { + Some("&") => Some("&'a ".to_string()), + Some("'_") => Some("'a".to_string()), + Some("") => { + Some(std::iter::repeat("'a, ").take(count).collect::>().join("")) + } + Some("<") => { + Some(std::iter::repeat("'a").take(count).collect::>().join(", ")) + } + Some(snippet) => Some(format!( + "{}<{}>", + snippet, + std::iter::repeat("'a").take(count).collect::>().join(", "), + )), + None => None, + }); + } + suggest_new(err, suggs); + } + lts if lts.len() > 1 => { err.span_note(lifetime_spans, "these named lifetimes are available to use"); + let mut spans_suggs: Vec<_> = Vec::new(); + for ((span, _), snippet) in spans_with_counts.iter().copied().zip(snippets.iter()) { + match snippet.as_deref() { + Some("") => spans_suggs.push((span, "'lifetime, ".to_string())), + Some("&") => spans_suggs + .push((span.with_lo(span.lo() + BytePos(1)), "'lifetime ".to_string())), + _ => {} + } + } + if spans_suggs.len() > 0 { // This happens when we have `Foo` where we point at the space before `T`, // but this can be confusing so we give a suggestion with placeholders. @@ -2341,34 +2661,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { ); } } + _ => unreachable!(), } } } - -/// Report lifetime/lifetime shadowing as an error. -pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) { - let mut err = struct_span_err!( - sess, - shadower.span, - E0496, - "lifetime name `{}` shadows a lifetime name that is already in scope", - orig.name, - ); - err.span_label(orig.span, "first declared here"); - err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name)); - err.emit(); -} - -/// Shadowing involving a label is only a warning for historical reasons. -//FIXME: make this a proper lint. -pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) { - let name = shadower.name; - let shadower = shadower.span; - let mut err = sess.struct_span_warn( - shadower, - &format!("label name `{}` shadows a label name that is already in scope", name), - ); - err.span_label(orig, "first declared here"); - err.span_label(shadower, format!("label `{}` already in scope", name)); - err.emit(); -} diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 94460e33d8b01..0eb11cd3e9fad 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1,11 +1,12 @@ -//! Resolution of early vs late bound lifetimes. +// ignore-tidy-filelength +//! Name resolution for lifetimes. //! -//! Name resolution for lifetimes is performed on the AST and embedded into HIR. From this -//! information, typechecking needs to transform the lifetime parameters into bound lifetimes. -//! Lifetimes can be early-bound or late-bound. Construction of typechecking terms needs to visit -//! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file -//! is also responsible for assigning their semantics to implicit lifetimes in trait objects. +//! Name resolution for lifetimes follows *much* simpler rules than the +//! full resolve. For example, lifetime names are never exported or +//! used between functions, and they operate in a purely top-down +//! way. Therefore, we break lifetime name resolution into a separate pass. +use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot}; use rustc_ast::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::struct_span_err; @@ -13,16 +14,18 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefIdMap, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node}; -use rustc_middle::bug; +use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node}; +use rustc_hir::{GenericParamKind, HirIdMap, LifetimeParamKind}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_lifetime::*; use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; -use rustc_span::symbol::{sym, Ident}; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use std::borrow::Cow; +use std::cell::Cell; use std::fmt; use std::mem::take; @@ -31,6 +34,8 @@ trait RegionExt { fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region); + fn late_anon(named_late_bound_vars: u32, index: &Cell) -> Region; + fn id(&self) -> Option; fn shifted(self, amount: u32) -> Region; @@ -61,9 +66,16 @@ impl RegionExt for Region { (def_id, Region::LateBound(depth, idx, def_id.to_def_id())) } + fn late_anon(named_late_bound_vars: u32, index: &Cell) -> Region { + let i = index.get(); + index.set(i + 1); + let depth = ty::INNERMOST; + Region::LateBoundAnon(depth, named_late_bound_vars + i, i) + } + fn id(&self) -> Option { match *self { - Region::Static => None, + Region::Static | Region::LateBoundAnon(..) => None, Region::EarlyBound(_, id) | Region::LateBound(_, _, id) | Region::Free(_, id) => { Some(id) @@ -76,6 +88,9 @@ impl RegionExt for Region { Region::LateBound(debruijn, idx, id) => { Region::LateBound(debruijn.shifted_in(amount), idx, id) } + Region::LateBoundAnon(debruijn, index, anon_index) => { + Region::LateBoundAnon(debruijn.shifted_in(amount), index, anon_index) + } _ => self, } } @@ -85,6 +100,9 @@ impl RegionExt for Region { Region::LateBound(debruijn, index, id) => { Region::LateBound(debruijn.shifted_out_to_binder(binder), index, id) } + Region::LateBoundAnon(debruijn, index, anon_index) => { + Region::LateBoundAnon(debruijn.shifted_out_to_binder(binder), index, anon_index) + } _ => self, } } @@ -134,6 +152,10 @@ pub(crate) struct LifetimeContext<'a, 'tcx> { /// Cache for cross-crate per-definition object lifetime defaults. xcrate_object_lifetime_defaults: DefIdMap>, + + /// When encountering an undefined named lifetime, we will suggest introducing it in these + /// places. + pub(crate) missing_named_lifetime_spots: Vec>, } #[derive(Debug)] @@ -176,6 +198,10 @@ enum Scope<'a> { s: ScopeRef<'a>, + /// In some cases not allowing late bounds allows us to avoid ICEs. + /// This is almost ways set to true. + allow_late_bound: bool, + /// If this binder comes from a where clause, specify how it was created. /// This is used to diagnose inaccessible lifetimes in APIT: /// ```ignore (illustrative) @@ -194,8 +220,9 @@ enum Scope<'a> { }, /// A scope which either determines unspecified lifetimes or errors - /// on them (e.g., due to ambiguity). + /// on them (e.g., due to ambiguity). For more details, see `Elide`. Elision { + elide: Elide, s: ScopeRef<'a>, }, @@ -251,6 +278,7 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { opaque_type_parent, scope_type, hir_id, + allow_late_bound, where_bound_origin, s: _, } => f @@ -260,13 +288,16 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { .field("opaque_type_parent", opaque_type_parent) .field("scope_type", scope_type) .field("hir_id", hir_id) + .field("allow_late_bound", allow_late_bound) .field("where_bound_origin", where_bound_origin) .field("s", &"..") .finish(), Scope::Body { id, s: _ } => { f.debug_struct("Body").field("id", id).field("s", &"..").finish() } - Scope::Elision { s: _ } => f.debug_struct("Elision").field("s", &"..").finish(), + Scope::Elision { elide, s: _ } => { + f.debug_struct("Elision").field("elide", elide).field("s", &"..").finish() + } Scope::ObjectLifetimeDefault { lifetime, s: _ } => f .debug_struct("ObjectLifetimeDefault") .field("lifetime", lifetime) @@ -283,6 +314,32 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { } } +#[derive(Clone, Debug)] +enum Elide { + /// Use a fresh anonymous late-bound lifetime each time, by + /// incrementing the counter to generate sequential indices. All + /// anonymous lifetimes must start *after* named bound vars. + FreshLateAnon(u32, Cell), + /// Always use this one lifetime. + Exact(Region), + /// Less or more than one lifetime were found, error on unspecified. + Error(Vec), + /// Forbid lifetime elision inside of a larger scope where it would be + /// permitted. For example, in let position impl trait. + Forbid, +} + +#[derive(Clone, Debug)] +pub(crate) struct ElisionFailureInfo { + /// Where we can find the argument pattern. + pub(crate) parent: Option, + /// The index of the argument in the original definition. + pub(crate) index: usize, + pub(crate) lifetime_count: usize, + pub(crate) have_bound_regions: bool, + pub(crate) span: Span, +} + type ScopeRef<'a> = &'a Scope<'a>; const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; @@ -364,6 +421,7 @@ fn do_resolve( scope: ROOT_SCOPE, trait_definition_only, xcrate_object_lifetime_defaults: Default::default(), + missing_named_lifetime_spots: vec![], }; visitor.visit_item(item); @@ -445,6 +503,9 @@ fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty:: let name = tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id.expect_local())); ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name)) } + Region::LateBoundAnon(_, _, anon_idx) => { + ty::BoundVariableKind::Region(ty::BrAnon(*anon_idx)) + } _ => bug!("{:?} is not a late region", region), } } @@ -579,14 +640,44 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { next_early_index, opaque_type_parent: false, scope_type: BinderScopeType::Normal, + allow_late_bound: true, where_bound_origin: None, }; + if let &hir::ClosureBinder::For { span, .. } = binder { + let last_lt = bound_generic_params + .iter() + .filter(|p| { + matches!( + p, + GenericParam { + kind: GenericParamKind::Lifetime { + kind: LifetimeParamKind::Explicit + }, + .. + } + ) + }) + .last(); + let (span, span_type) = match last_lt { + Some(GenericParam { span: last_sp, .. }) => { + (last_sp.shrink_to_hi(), ForLifetimeSpanType::ClosureTail) + } + None => (span, ForLifetimeSpanType::ClosureEmpty), + }; + self.missing_named_lifetime_spots + .push(MissingLifetimeSpot::HigherRanked { span, span_type }); + } + self.with(scope, |this| { // a closure has no bounds, so everything // contained within is scoped within its binder. intravisit::walk_expr(this, e) }); + + if let hir::ClosureBinder::For { .. } = binder { + self.missing_named_lifetime_spots.pop(); + } } else { intravisit::walk_expr(self, e) } @@ -603,9 +694,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } match item.kind { hir::ItemKind::Fn(_, ref generics, _) => { + self.missing_named_lifetime_spots.push(generics.into()); self.visit_early_late(None, item.hir_id(), generics, |this| { intravisit::walk_item(this, item); }); + self.missing_named_lifetime_spots.pop(); } hir::ItemKind::ExternCrate(_) @@ -619,9 +712,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => { // No lifetime parameters, but implied 'static. - self.with(Scope::Elision { s: self.scope }, |this| { - intravisit::walk_item(this, item) - }); + let scope = Scope::Elision { elide: Elide::Exact(Region::Static), s: ROOT_SCOPE }; + self.with(scope, |this| intravisit::walk_item(this, item)); } hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => { // Opaque types are visited when we visit the @@ -669,6 +761,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { | hir::ItemKind::Trait(_, _, ref generics, ..) | hir::ItemKind::TraitAlias(ref generics, ..) | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => { + self.missing_named_lifetime_spots.push(generics.into()); + // These kinds of items have only early-bound lifetime parameters. let mut index = if sub_items_have_self_param(&item.kind) { 1 // Self comes before lifetimes @@ -697,6 +791,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { opaque_type_parent: true, scope_type: BinderScopeType::Normal, s: ROOT_SCOPE, + allow_late_bound: false, where_bound_origin: None, }; self.with(scope, |this| { @@ -705,6 +800,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { intravisit::walk_item(this, item); }); }); + self.missing_named_lifetime_spots.pop(); } } } @@ -730,6 +826,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { match ty.kind { hir::TyKind::BareFn(ref c) => { let next_early_index = self.next_early_index(); + let lifetime_span: Option = + c.generic_params.iter().rev().find_map(|param| match param.kind { + GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } => { + Some(param.span) + } + _ => None, + }); + let (span, span_type) = if let Some(span) = lifetime_span { + (span.shrink_to_hi(), ForLifetimeSpanType::TypeTail) + } else { + (ty.span.shrink_to_lo(), ForLifetimeSpanType::TypeEmpty) + }; + self.missing_named_lifetime_spots + .push(MissingLifetimeSpot::HigherRanked { span, span_type }); let (lifetimes, binders): (FxIndexMap, Vec<_>) = c .generic_params .iter() @@ -749,6 +859,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { next_early_index, opaque_type_parent: false, scope_type: BinderScopeType::Normal, + allow_late_bound: true, where_bound_origin: None, }; self.with(scope, |this| { @@ -756,6 +867,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // contained within is scoped within its binder. intravisit::walk_ty(this, ty); }); + self.missing_named_lifetime_spots.pop(); } hir::TyKind::TraitObject(bounds, ref lifetime, _) => { debug!(?bounds, ?lifetime, "TraitObject"); @@ -766,6 +878,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } }); match lifetime.name { + LifetimeName::Implicit => { + // For types like `dyn Foo`, we should + // generate a special form of elided. + span_bug!(ty.span, "object-lifetime-default expected, not implicit",); + } LifetimeName::ImplicitObjectLifetimeDefault => { // If the user does not write *anything*, we // use the object lifetime defaulting @@ -773,12 +890,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // `Box`. self.resolve_object_lifetime_default(lifetime) } - LifetimeName::Infer => { + LifetimeName::Underscore => { // If the user writes `'_`, we use the *ordinary* elision // rules. So the `'_` in e.g., `Box` will be // resolved the same as the `'_` in `&'_ Foo`. // // cc #48468 + self.resolve_elided_lifetimes(&[lifetime]) } LifetimeName::Param(..) | LifetimeName::Static => { // If the user wrote an explicit name, use that. @@ -813,7 +931,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // position impl Trait let scope = Scope::TraitRefBoundary { s: self.scope }; self.with(scope, |this| { - let scope = Scope::Elision { s: this.scope }; + let scope = Scope::Elision { elide: Elide::Forbid, s: this.scope }; this.with(scope, |this| { intravisit::walk_item(this, opaque_ty); }) @@ -889,14 +1007,24 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let mut index = self.next_early_index_for_opaque_type(); debug!(?index); + let mut elision = None; let mut lifetimes = FxIndexMap::default(); let mut non_lifetime_count = 0; - debug!(?generics.params); for param in generics.params { match param.kind { GenericParamKind::Lifetime { .. } => { let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, ¶m); - lifetimes.insert(def_id, reg); + if let hir::ParamName::Plain(Ident { + name: kw::UnderscoreLifetime, + .. + }) = param.name + { + // Pick the elided lifetime "definition" if one exists + // and use it to make an elision scope. + elision = Some(reg); + } else { + lifetimes.insert(def_id, reg); + } } GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { non_lifetime_count += 1; @@ -906,24 +1034,51 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let next_early_index = index + non_lifetime_count; self.map.late_bound_vars.insert(ty.hir_id, vec![]); - let scope = Scope::Binder { - hir_id: ty.hir_id, - lifetimes, - next_early_index, - s: self.scope, - opaque_type_parent: false, - scope_type: BinderScopeType::Normal, - where_bound_origin: None, - }; - self.with(scope, |this| { - let scope = Scope::TraitRefBoundary { s: this.scope }; - this.with(scope, |this| { - this.visit_generics(generics); - for bound in bounds { - this.visit_param_bound(bound); - } - }) - }); + if let Some(elision_region) = elision { + let scope = + Scope::Elision { elide: Elide::Exact(elision_region), s: self.scope }; + self.with(scope, |this| { + let scope = Scope::Binder { + hir_id: ty.hir_id, + lifetimes, + next_early_index, + s: this.scope, + opaque_type_parent: false, + scope_type: BinderScopeType::Normal, + allow_late_bound: false, + where_bound_origin: None, + }; + this.with(scope, |this| { + this.visit_generics(generics); + let scope = Scope::TraitRefBoundary { s: this.scope }; + this.with(scope, |this| { + for bound in bounds { + this.visit_param_bound(bound); + } + }) + }); + }); + } else { + let scope = Scope::Binder { + hir_id: ty.hir_id, + lifetimes, + next_early_index, + s: self.scope, + opaque_type_parent: false, + scope_type: BinderScopeType::Normal, + allow_late_bound: false, + where_bound_origin: None, + }; + self.with(scope, |this| { + let scope = Scope::TraitRefBoundary { s: this.scope }; + this.with(scope, |this| { + this.visit_generics(generics); + for bound in bounds { + this.visit_param_bound(bound); + } + }) + }); + } } _ => intravisit::walk_ty(self, ty), } @@ -933,6 +1088,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { use self::hir::TraitItemKind::*; match trait_item.kind { Fn(_, _) => { + self.missing_named_lifetime_spots.push((&trait_item.generics).into()); let tcx = self.tcx; self.visit_early_late( Some(tcx.hir().get_parent_item(trait_item.hir_id())), @@ -940,8 +1096,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { &trait_item.generics, |this| intravisit::walk_trait_item(this, trait_item), ); + self.missing_named_lifetime_spots.pop(); } Type(bounds, ref ty) => { + self.missing_named_lifetime_spots.push((&trait_item.generics).into()); let generics = &trait_item.generics; let mut index = self.next_early_index(); debug!("visit_ty: index = {}", index); @@ -967,6 +1125,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { s: self.scope, opaque_type_parent: true, scope_type: BinderScopeType::Normal, + allow_late_bound: false, where_bound_origin: None, }; self.with(scope, |this| { @@ -981,11 +1140,14 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } }) }); + self.missing_named_lifetime_spots.pop(); } Const(_, _) => { // Only methods and types support generics. assert!(trait_item.generics.params.is_empty()); + self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static); intravisit::walk_trait_item(self, trait_item); + self.missing_named_lifetime_spots.pop(); } } } @@ -994,6 +1156,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { use self::hir::ImplItemKind::*; match impl_item.kind { Fn(..) => { + self.missing_named_lifetime_spots.push((&impl_item.generics).into()); let tcx = self.tcx; self.visit_early_late( Some(tcx.hir().get_parent_item(impl_item.hir_id())), @@ -1001,9 +1164,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { &impl_item.generics, |this| intravisit::walk_impl_item(this, impl_item), ); + self.missing_named_lifetime_spots.pop(); } TyAlias(ref ty) => { let generics = &impl_item.generics; + self.missing_named_lifetime_spots.push(generics.into()); let mut index = self.next_early_index(); let mut non_lifetime_count = 0; debug!("visit_ty: index = {}", index); @@ -1028,6 +1193,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { s: self.scope, opaque_type_parent: true, scope_type: BinderScopeType::Normal, + allow_late_bound: true, where_bound_origin: None, }; self.with(scope, |this| { @@ -1037,11 +1203,14 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { this.visit_ty(ty); }) }); + self.missing_named_lifetime_spots.pop(); } Const(_, _) => { // Only methods and types support generics. assert!(impl_item.generics.params.is_empty()); + self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static); intravisit::walk_impl_item(self, impl_item); + self.missing_named_lifetime_spots.pop(); } } } @@ -1049,14 +1218,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { #[tracing::instrument(level = "debug", skip(self))] fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { match lifetime_ref.name { + hir::LifetimeName::ImplicitObjectLifetimeDefault + | hir::LifetimeName::Implicit + | hir::LifetimeName::Underscore => self.resolve_elided_lifetimes(&[lifetime_ref]), hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static), hir::LifetimeName::Param(param_def_id, _) => { self.resolve_lifetime_ref(param_def_id, lifetime_ref) } // If we've already reported an error, just ignore `lifetime_ref`. hir::LifetimeName::Error => {} - // Those will be resolved by typechecking. - hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Infer => {} } } @@ -1069,21 +1239,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } - fn visit_fn( - &mut self, - fk: intravisit::FnKind<'tcx>, - fd: &'tcx hir::FnDecl<'tcx>, - body_id: hir::BodyId, - _: Span, - _: hir::HirId, - ) { + fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) { let output = match fd.output { hir::FnRetTy::DefaultReturn(_) => None, hir::FnRetTy::Return(ref ty) => Some(&**ty), }; - self.visit_fn_like_elision(&fd.inputs, output, matches!(fk, intravisit::FnKind::Closure)); - intravisit::walk_fn_kind(self, fk); - self.visit_nested_body(body_id) + self.visit_fn_like_elision(&fd.inputs, output); } fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { @@ -1141,6 +1302,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { next_early_index, opaque_type_parent: false, scope_type: BinderScopeType::Normal, + allow_late_bound: true, where_bound_origin: Some(origin), }; this.with(scope, |this| { @@ -1213,6 +1375,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { next_early_index: self.next_early_index(), opaque_type_parent: false, scope_type, + allow_late_bound: true, where_bound_origin: None, }; self.with(scope, |this| { @@ -1230,6 +1393,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { ) { debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); + let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref); + let next_early_index = self.next_early_index(); let (mut binders, scope_type) = self.poly_trait_ref_binder_info(); @@ -1263,12 +1428,17 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { next_early_index, opaque_type_parent: false, scope_type, + allow_late_bound: true, where_bound_origin: None, }; self.with(scope, |this| { walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); this.visit_trait_ref(&trait_ref.trait_ref); }); + + if should_pop_missing_lt { + self.missing_named_lifetime_spots.pop(); + } } } @@ -1414,12 +1584,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { { let LifetimeContext { tcx, map, .. } = self; let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults); + let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots); let mut this = LifetimeContext { tcx: *tcx, map, scope: &wrap_scope, trait_definition_only: self.trait_definition_only, xcrate_object_lifetime_defaults, + missing_named_lifetime_spots, }; let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope)); { @@ -1427,6 +1599,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { f(&mut this); } self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; + self.missing_named_lifetime_spots = this.missing_named_lifetime_spots; } /// Visits self by adding a scope and handling recursive walk over the contents with `walk`. @@ -1516,6 +1689,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { s: self.scope, opaque_type_parent: true, scope_type: BinderScopeType::Normal, + allow_late_bound: true, where_bound_origin: None, }; self.with(scope, walk); @@ -1691,18 +1865,30 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { ); if generic_args.parenthesized { - self.visit_fn_like_elision( - generic_args.inputs(), - Some(generic_args.bindings[0].ty()), - false, - ); + self.visit_fn_like_elision(generic_args.inputs(), Some(generic_args.bindings[0].ty())); return; } - for arg in generic_args.args { - if let hir::GenericArg::Lifetime(lt) = arg { - self.visit_lifetime(lt); - } + let mut elide_lifetimes = true; + let lifetimes: Vec<_> = generic_args + .args + .iter() + .filter_map(|arg| match arg { + hir::GenericArg::Lifetime(lt) => { + if !lt.is_elided() { + elide_lifetimes = false; + } + Some(lt) + } + _ => None, + }) + .collect(); + // We short-circuit here if all are elided in order to pluralize + // possible errors + if elide_lifetimes { + self.resolve_elided_lifetimes(&lifetimes); + } else { + lifetimes.iter().for_each(|lt| self.visit_lifetime(lt)); } // Figure out if this is a type/trait segment, @@ -1958,21 +2144,438 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { &mut self, inputs: &'tcx [hir::Ty<'tcx>], output: Option<&'tcx hir::Ty<'tcx>>, - in_closure: bool, ) { - self.with(Scope::Elision { s: self.scope }, |this| { + debug!("visit_fn_like_elision: enter"); + let mut scope = &*self.scope; + let hir_id = loop { + match scope { + Scope::Binder { hir_id, allow_late_bound: true, .. } => { + break *hir_id; + } + Scope::ObjectLifetimeDefault { ref s, .. } + | Scope::Elision { ref s, .. } + | Scope::Supertrait { ref s, .. } + | Scope::TraitRefBoundary { ref s, .. } => { + scope = *s; + } + Scope::Root + | Scope::Body { .. } + | Scope::Binder { allow_late_bound: false, .. } => { + // See issues #83907 and #83693. Just bail out from looking inside. + // See the issue #95023 for not allowing late bound + self.tcx.sess.delay_span_bug( + rustc_span::DUMMY_SP, + "In fn_like_elision without appropriate scope above", + ); + return; + } + } + }; + // While not strictly necessary, we gather anon lifetimes *before* actually + // visiting the argument types. + let mut gather = GatherAnonLifetimes { anon_count: 0 }; + for input in inputs { + gather.visit_ty(input); + } + trace!(?gather.anon_count); + let late_bound_vars = self.map.late_bound_vars.entry(hir_id).or_default(); + let named_late_bound_vars = late_bound_vars.len() as u32; + late_bound_vars.extend( + (0..gather.anon_count).map(|var| ty::BoundVariableKind::Region(ty::BrAnon(var))), + ); + let arg_scope = Scope::Elision { + elide: Elide::FreshLateAnon(named_late_bound_vars, Cell::new(0)), + s: self.scope, + }; + self.with(arg_scope, |this| { for input in inputs { this.visit_ty(input); } - if !in_closure && let Some(output) = output { - this.visit_ty(output); - } }); - if in_closure && let Some(output) = output { - self.visit_ty(output); + + let Some(output) = output else { return }; + + debug!("determine output"); + + // Figure out if there's a body we can get argument names from, + // and whether there's a `self` argument (treated specially). + let mut assoc_item_kind = None; + let mut impl_self = None; + let parent = self.tcx.hir().get_parent_node(output.hir_id); + let body = match self.tcx.hir().get(parent) { + // `fn` definitions and methods. + Node::Item(&hir::Item { kind: hir::ItemKind::Fn(.., body), .. }) => Some(body), + + Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(_, ref m), .. }) => { + if let hir::ItemKind::Trait(.., ref trait_items) = + self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind + { + assoc_item_kind = + trait_items.iter().find(|ti| ti.id.hir_id() == parent).map(|ti| ti.kind); + } + match *m { + hir::TraitFn::Required(_) => None, + hir::TraitFn::Provided(body) => Some(body), + } + } + + Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body), .. }) => { + if let hir::ItemKind::Impl(hir::Impl { ref self_ty, ref items, .. }) = + self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind + { + impl_self = Some(self_ty); + assoc_item_kind = + items.iter().find(|ii| ii.id.hir_id() == parent).map(|ii| ii.kind); + } + Some(body) + } + + // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds). + Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None, + + Node::TypeBinding(_) if let Node::TraitRef(_) = self.tcx.hir().get(self.tcx.hir().get_parent_node(parent)) => None, + + // Everything else (only closures?) doesn't + // actually enjoy elision in return types. + _ => { + self.visit_ty(output); + return; + } + }; + + let has_self = match assoc_item_kind { + Some(hir::AssocItemKind::Fn { has_self }) => has_self, + _ => false, + }; + + // In accordance with the rules for lifetime elision, we can determine + // what region to use for elision in the output type in two ways. + // First (determined here), if `self` is by-reference, then the + // implied output region is the region of the self parameter. + if has_self { + struct SelfVisitor<'a> { + map: &'a NamedRegionMap, + impl_self: Option<&'a hir::TyKind<'a>>, + lifetime: Set1, + } + + impl SelfVisitor<'_> { + // Look for `self: &'a Self` - also desugared from `&'a self`, + // and if that matches, use it for elision and return early. + fn is_self_ty(&self, res: Res) -> bool { + if let Res::SelfTy { .. } = res { + return true; + } + + // Can't always rely on literal (or implied) `Self` due + // to the way elision rules were originally specified. + if let Some(&hir::TyKind::Path(hir::QPath::Resolved(None, ref path))) = + self.impl_self + { + match path.res { + // Permit the types that unambiguously always + // result in the same type constructor being used + // (it can't differ between `Self` and `self`). + Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _) + | Res::PrimTy(_) => return res == path.res, + _ => {} + } + } + + false + } + } + + impl<'a> Visitor<'a> for SelfVisitor<'a> { + fn visit_ty(&mut self, ty: &'a hir::Ty<'a>) { + if let hir::TyKind::Rptr(lifetime_ref, ref mt) = ty.kind { + if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.kind + { + if self.is_self_ty(path.res) { + if let Some(lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { + self.lifetime.insert(*lifetime); + } + } + } + } + intravisit::walk_ty(self, ty) + } + } + + let mut visitor = SelfVisitor { + map: self.map, + impl_self: impl_self.map(|ty| &ty.kind), + lifetime: Set1::Empty, + }; + visitor.visit_ty(&inputs[0]); + if let Set1::One(lifetime) = visitor.lifetime { + let scope = Scope::Elision { elide: Elide::Exact(lifetime), s: self.scope }; + self.with(scope, |this| this.visit_ty(output)); + return; + } + } + + // Second, if there was exactly one lifetime (either a substitution or a + // reference) in the arguments, then any anonymous regions in the output + // have that lifetime. + let mut possible_implied_output_region = None; + let mut lifetime_count = 0; + let arg_lifetimes = inputs + .iter() + .enumerate() + .skip(has_self as usize) + .map(|(i, input)| { + let mut gather = GatherLifetimes { + map: self.map, + outer_index: ty::INNERMOST, + have_bound_regions: false, + lifetimes: Default::default(), + }; + gather.visit_ty(input); + + lifetime_count += gather.lifetimes.len(); + + if lifetime_count == 1 && gather.lifetimes.len() == 1 { + // there's a chance that the unique lifetime of this + // iteration will be the appropriate lifetime for output + // parameters, so lets store it. + possible_implied_output_region = gather.lifetimes.iter().cloned().next(); + } + + ElisionFailureInfo { + parent: body, + index: i, + lifetime_count: gather.lifetimes.len(), + have_bound_regions: gather.have_bound_regions, + span: input.span, + } + }) + .collect(); + + let elide = if lifetime_count == 1 { + Elide::Exact(possible_implied_output_region.unwrap()) + } else { + Elide::Error(arg_lifetimes) + }; + + debug!(?elide); + + let scope = Scope::Elision { elide, s: self.scope }; + self.with(scope, |this| this.visit_ty(output)); + + struct GatherLifetimes<'a> { + map: &'a NamedRegionMap, + outer_index: ty::DebruijnIndex, + have_bound_regions: bool, + lifetimes: FxHashSet, + } + + impl<'v, 'a> Visitor<'v> for GatherLifetimes<'a> { + fn visit_ty(&mut self, ty: &hir::Ty<'_>) { + if let hir::TyKind::BareFn(_) = ty.kind { + self.outer_index.shift_in(1); + } + match ty.kind { + hir::TyKind::TraitObject(bounds, ref lifetime, _) => { + for bound in bounds { + self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); + } + + // Stay on the safe side and don't include the object + // lifetime default (which may not end up being used). + if !lifetime.is_elided() { + self.visit_lifetime(lifetime); + } + } + _ => { + intravisit::walk_ty(self, ty); + } + } + if let hir::TyKind::BareFn(_) = ty.kind { + self.outer_index.shift_out(1); + } + } + + fn visit_generic_param(&mut self, param: &hir::GenericParam<'_>) { + if let hir::GenericParamKind::Lifetime { .. } = param.kind { + // FIXME(eddyb) Do we want this? It only makes a difference + // if this `for<'a>` lifetime parameter is never used. + self.have_bound_regions = true; + } + + intravisit::walk_generic_param(self, param); + } + + fn visit_poly_trait_ref( + &mut self, + trait_ref: &hir::PolyTraitRef<'_>, + modifier: hir::TraitBoundModifier, + ) { + self.outer_index.shift_in(1); + intravisit::walk_poly_trait_ref(self, trait_ref, modifier); + self.outer_index.shift_out(1); + } + + fn visit_param_bound(&mut self, bound: &hir::GenericBound<'_>) { + if let hir::GenericBound::LangItemTrait { .. } = bound { + self.outer_index.shift_in(1); + intravisit::walk_param_bound(self, bound); + self.outer_index.shift_out(1); + } else { + intravisit::walk_param_bound(self, bound); + } + } + + fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { + if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { + match lifetime { + Region::LateBound(debruijn, _, _) + | Region::LateBoundAnon(debruijn, _, _) + if debruijn < self.outer_index => + { + self.have_bound_regions = true; + } + _ => { + // FIXME(jackh726): nested trait refs? + self.lifetimes.insert(lifetime.shifted_out_to_binder(self.outer_index)); + } + } + } + } + } + + struct GatherAnonLifetimes { + anon_count: u32, + } + impl<'v> Visitor<'v> for GatherAnonLifetimes { + #[instrument(skip(self), level = "trace")] + fn visit_ty(&mut self, ty: &hir::Ty<'_>) { + // If we enter a `BareFn`, then we enter a *new* binding scope + if let hir::TyKind::BareFn(_) = ty.kind { + return; + } + intravisit::walk_ty(self, ty); + } + + fn visit_generic_args( + &mut self, + path_span: Span, + generic_args: &'v hir::GenericArgs<'v>, + ) { + // parenthesized args enter a new elision scope + if generic_args.parenthesized { + return; + } + intravisit::walk_generic_args(self, path_span, generic_args) + } + + #[instrument(skip(self), level = "trace")] + fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { + if lifetime_ref.is_elided() { + self.anon_count += 1; + } + } } } + fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[&'tcx hir::Lifetime]) { + debug!("resolve_elided_lifetimes(lifetime_refs={:?})", lifetime_refs); + + if lifetime_refs.is_empty() { + return; + } + + let mut late_depth = 0; + let mut scope = self.scope; + let mut in_scope_lifetimes = FxIndexSet::default(); + let error = loop { + match *scope { + // Do not assign any resolution, it will be inferred. + Scope::Body { .. } => return, + + Scope::Root => break None, + + Scope::Binder { s, ref lifetimes, scope_type, .. } => { + // collect named lifetimes for suggestions + in_scope_lifetimes.extend(lifetimes.keys().copied()); + match scope_type { + BinderScopeType::Normal => late_depth += 1, + BinderScopeType::Concatenating => {} + } + scope = s; + } + + Scope::Elision { + elide: Elide::FreshLateAnon(named_late_bound_vars, ref counter), + .. + } => { + for lifetime_ref in lifetime_refs { + let lifetime = + Region::late_anon(named_late_bound_vars, counter).shifted(late_depth); + + self.insert_lifetime(lifetime_ref, lifetime); + } + return; + } + + Scope::Elision { elide: Elide::Exact(l), .. } => { + let lifetime = l.shifted(late_depth); + for lifetime_ref in lifetime_refs { + self.insert_lifetime(lifetime_ref, lifetime); + } + return; + } + + Scope::Elision { elide: Elide::Error(ref e), ref s, .. } => { + let mut scope = s; + loop { + match scope { + Scope::Binder { ref lifetimes, s, .. } => { + // Collect named lifetimes for suggestions. + in_scope_lifetimes.extend(lifetimes.keys().copied()); + scope = s; + } + Scope::ObjectLifetimeDefault { ref s, .. } + | Scope::Elision { ref s, .. } + | Scope::TraitRefBoundary { ref s, .. } => { + scope = s; + } + _ => break, + } + } + break Some(&e[..]); + } + + Scope::Elision { elide: Elide::Forbid, .. } => break None, + + Scope::ObjectLifetimeDefault { s, .. } + | Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s, .. } => { + scope = s; + } + } + }; + + let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect(); + spans.sort(); + let mut spans_dedup = spans.clone(); + spans_dedup.dedup(); + let spans_with_counts: Vec<_> = spans_dedup + .into_iter() + .map(|sp| (sp, spans.iter().filter(|nsp| *nsp == &sp).count())) + .collect(); + + let mut err = self.report_missing_lifetime_specifiers(spans.clone(), lifetime_refs.len()); + + self.add_missing_lifetime_specifiers_label( + &mut err, + spans_with_counts, + in_scope_lifetimes, + error, + ); + err.emit(); + } + fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) { debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref); let mut late_depth = 0; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 31d10008efbfb..2fcbe1d4c14a5 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -11,7 +11,6 @@ #![feature(drain_filter)] #![feature(if_let_guard)] #![cfg_attr(bootstrap, feature(let_chains))] -#![feature(iter_intersperse)] #![feature(let_else)] #![feature(never_type)] #![recursion_limit = "256"] @@ -437,7 +436,7 @@ enum ModuleKind { /// f(); // Resolves to (1) /// } /// ``` - Block, + Block(NodeId), /// Any module with a name. /// /// This could be: @@ -454,7 +453,7 @@ impl ModuleKind { /// Get name of the module. pub fn name(&self) -> Option { match self { - ModuleKind::Block => None, + ModuleKind::Block(..) => None, ModuleKind::Def(.., name) => Some(*name), } } @@ -530,7 +529,7 @@ impl<'a> ModuleData<'a> { ) -> Self { let is_foreign = match kind { ModuleKind::Def(_, def_id, _) => !def_id.is_local(), - ModuleKind::Block => false, + ModuleKind::Block(_) => false, }; ModuleData { parent, diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 070fb9c721b40..2b5eb12a8a890 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -812,7 +812,7 @@ impl<'a> Resolver<'a> { stability::report_unstable( self.session, feature, - reason.to_opt_reason(), + reason, issue, None, is_soft, diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml index dbc5c15195c86..5056163b7fe7d 100644 --- a/compiler/rustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" edition = "2021" [dependencies] -indexmap = "1.9.1" +indexmap = "1.8.0" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } [dev-dependencies] diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index fe9ef6045415e..55307b9cebb70 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -948,8 +948,6 @@ fn default_configuration(sess: &Session) -> CrateConfig { if sess.opts.debug_assertions { ret.insert((sym::debug_assertions, None)); } - // JUSTIFICATION: before wrapper fn is available - #[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] if sess.opts.crate_types.contains(&CrateType::ProcMacro) { ret.insert((sym::proc_macro, None)); } @@ -2198,8 +2196,6 @@ fn parse_remap_path_prefix( mapping } -// JUSTIFICATION: before wrapper fn is available -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] pub fn build_session_options(matches: &getopts::Matches) -> Options { let color = parse_color(matches); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index ef314115043b2..5d365fc524628 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -102,6 +102,28 @@ macro_rules! top_level_options { ); } +impl Options { + pub fn mir_opt_level(&self) -> usize { + self.unstable_opts + .mir_opt_level + .unwrap_or_else(|| if self.optimize != OptLevel::No { 2 } else { 1 }) + } + + pub fn instrument_coverage(&self) -> bool { + self.cg.instrument_coverage.unwrap_or(InstrumentCoverage::Off) != InstrumentCoverage::Off + } + + pub fn instrument_coverage_except_unused_generics(&self) -> bool { + self.cg.instrument_coverage.unwrap_or(InstrumentCoverage::Off) + == InstrumentCoverage::ExceptUnusedGenerics + } + + pub fn instrument_coverage_except_unused_functions(&self) -> bool { + self.cg.instrument_coverage.unwrap_or(InstrumentCoverage::Off) + == InstrumentCoverage::ExceptUnusedFunctions + } +} + top_level_options!( /// The top-level command-line options struct. /// @@ -127,11 +149,9 @@ top_level_options!( /// `CodegenOptions`, think about how it influences incremental compilation. If in /// doubt, specify `[TRACKED]`, which is always "correct" but might lead to /// unnecessary re-compilation. - #[cfg_attr(not(bootstrap), rustc_lint_opt_ty)] pub struct Options { /// The crate config requested for the session, which may be combined /// with additional crate configurations during the compile process. - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::crate_types` instead of this field"))] crate_types: Vec [TRACKED], optimize: OptLevel [TRACKED], /// Include the `debug_assertions` flag in dependency tracking, since it @@ -178,9 +198,7 @@ top_level_options!( /// what rustc was invoked with, but massaged a bit to agree with /// commands like `--emit llvm-ir` which they're often incompatible with /// if we otherwise use the defaults of rustc. - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::codegen_units` instead of this field"))] cli_forced_codegen_units: Option [UNTRACKED], - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field"))] cli_forced_thinlto_off: bool [UNTRACKED], /// Remap source path prefixes in all output (messages, object files, debug, etc.). @@ -231,12 +249,11 @@ macro_rules! options { ),* ,) => ( #[derive(Clone)] - #[cfg_attr(not(bootstrap), rustc_lint_opt_ty)] - pub struct $struct_name { $( $( #[$attr] )* pub $opt: $t),* } + pub struct $struct_name { $(pub $opt: $t),* } impl Default for $struct_name { fn default() -> $struct_name { - $struct_name { $($opt: $init),* } + $struct_name { $( $( #[$attr] )* $opt: $init),* } } } @@ -280,22 +297,6 @@ macro_rules! options { ) } -impl Options { - // JUSTIFICATION: defn of the suggested wrapper fn - #[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] - pub fn time_passes(&self) -> bool { - self.unstable_opts.time_passes || self.unstable_opts.time - } -} - -impl CodegenOptions { - // JUSTIFICATION: defn of the suggested wrapper fn - #[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] - pub fn instrument_coverage(&self) -> InstrumentCoverage { - self.instrument_coverage.unwrap_or(InstrumentCoverage::Off) - } -} - // Sometimes different options need to build a common structure. // That structure can be kept in one of the options' fields, the others become dummy. macro_rules! redirect_field { @@ -376,7 +377,7 @@ mod desc { pub const parse_opt_panic_strategy: &str = parse_panic_strategy; pub const parse_oom_strategy: &str = "either `panic` or `abort`"; pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; - pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, `shadow-call-stack`, or `thread`"; + pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, or `thread`"; pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2"; pub const parse_cfguard: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; @@ -534,7 +535,7 @@ mod parse { ) -> bool { match v { Some(s) => { - for s in s.split(',') { + for s in s.split(",") { let Some(pass_name) = s.strip_prefix(&['+', '-'][..]) else { return false }; slot.push((pass_name.to_string(), &s[..1] == "+")); } @@ -682,7 +683,6 @@ mod parse { "leak" => SanitizerSet::LEAK, "memory" => SanitizerSet::MEMORY, "memtag" => SanitizerSet::MEMTAG, - "shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK, "thread" => SanitizerSet::THREAD, "hwaddress" => SanitizerSet::HWADDRESS, _ => return false, @@ -1075,7 +1075,6 @@ options! { ar: String = (String::new(), parse_string, [UNTRACKED], "this option is deprecated and does nothing"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field"))] code_model: Option = (None, parse_code_model, [TRACKED], "choose the code model to use (`rustc --print code-models` for details)"), codegen_units: Option = (None, parse_opt_number, [UNTRACKED], @@ -1095,14 +1094,12 @@ options! { "extra data to put in each output filename"), force_frame_pointers: Option = (None, parse_opt_bool, [TRACKED], "force use of the frame pointers"), - #[cfg_attr(not(bootstrap), 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], "force use of unwind tables"), incremental: Option = (None, parse_opt_string, [UNTRACKED], "enable incremental compilation"), inline_threshold: Option = (None, parse_opt_number, [TRACKED], "set the threshold for inlining a function"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field"))] instrument_coverage: Option = (None, parse_instrument_coverage, [TRACKED], "instrument the generated code to support LLVM source-based code coverage \ reports (note, the compiler build config must include `profiler = true`); \ @@ -1115,7 +1112,6 @@ options! { "a single extra argument to append to the linker invocation (can be used several times)"), link_args: Vec = (Vec::new(), parse_list, [UNTRACKED], "extra arguments to append to the linker invocation (space separated)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::link_dead_code` instead of this field"))] link_dead_code: Option = (None, parse_opt_bool, [TRACKED], "keep dead code at link time (useful for code coverage) (default: no)"), link_self_contained: Option = (None, parse_opt_bool, [UNTRACKED], @@ -1130,7 +1126,6 @@ options! { "generate build artifacts that are compatible with linker-based LTO"), llvm_args: Vec = (Vec::new(), parse_list, [TRACKED], "a list of arguments to pass to LLVM (space separated)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field"))] lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED], "perform LLVM link-time optimizations"), metadata: Vec = (Vec::new(), parse_list, [TRACKED], @@ -1147,10 +1142,8 @@ options! { "disable LLVM's SLP vectorization pass"), opt_level: String = ("0".to_string(), parse_string, [TRACKED], "optimization level (0-3, s, or z; default: 0)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::overflow_checks` instead of this field"))] overflow_checks: Option = (None, parse_opt_bool, [TRACKED], "use overflow checks for integer arithmetic"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::panic_strategy` instead of this field"))] panic: Option = (None, parse_opt_panic_strategy, [TRACKED], "panic strategy to compile crate with"), passes: Vec = (Vec::new(), parse_list, [TRACKED], @@ -1162,7 +1155,6 @@ options! { "compile the program with profiling instrumentation"), profile_use: Option = (None, parse_opt_pathbuf, [TRACKED], "use the given `.profdata` file for profile-guided optimization"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::relocation_model` instead of this field"))] relocation_model: Option = (None, parse_relocation_model, [TRACKED], "control generation of position-independent code (PIC) \ (`rustc --print relocation-models` for details)"), @@ -1174,7 +1166,6 @@ options! { "save all temporary output files during compilation (default: no)"), soft_float: bool = (false, parse_bool, [TRACKED], "use soft float ABI (*eabihf targets only) (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::split_debuginfo` instead of this field"))] split_debuginfo: Option = (None, parse_split_debuginfo, [TRACKED], "how to handle split-debuginfo, a platform-specific option"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], @@ -1210,13 +1201,11 @@ options! { "encode MIR of all functions into the crate metadata (default: no)"), assume_incomplete_release: bool = (false, parse_bool, [TRACKED], "make cfg(version) treat the current version as incomplete (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::asm_comments` instead of this field"))] asm_comments: bool = (false, parse_bool, [TRACKED], "generate comments into the assembly (may change behavior) (default: no)"), assert_incr_state: Option = (None, parse_opt_string, [UNTRACKED], "assert that the incremental cache is in given state: \ either `loaded` or `not-loaded`."), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field"))] binary_dep_depinfo: bool = (false, parse_bool, [TRACKED], "include artifacts (sysroot, crate dependencies) used during compilation in dep-info \ (default: no)"), @@ -1290,11 +1279,6 @@ options! { "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), - emit_thin_lto: bool = (true, parse_bool, [TRACKED], - "emit the bc module with thin LTO info (default: yes)"), - export_executable_symbols: bool = (false, parse_bool, [TRACKED], - "export symbols from executables, as if they were dynamic libraries"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field"))] fewer_names: Option = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ (default: no)"), @@ -1337,7 +1321,6 @@ options! { "control whether `#[inline]` functions are in all CGUs"), input_stats: bool = (false, parse_bool, [UNTRACKED], "gather statistics about the input (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field"))] instrument_coverage: Option = (None, parse_instrument_coverage, [TRACKED], "instrument the generated code to support LLVM source-based code coverage \ reports (note, the compiler build config must include `profiler = true`); \ @@ -1346,7 +1329,6 @@ options! { `=except-unused-generics` `=except-unused-functions` `=off` (default)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::instrument_mcount` instead of this field"))] instrument_mcount: bool = (false, parse_bool, [TRACKED], "insert function instrument code for mcount-based tracing (default: no)"), keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED], @@ -1369,7 +1351,6 @@ options! { merge_functions: Option = (None, parse_merge_functions, [TRACKED], "control the operation of the MergeFunctions LLVM pass, taking \ the same values as the target option of the same name"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::meta_stats` instead of this field"))] meta_stats: bool = (false, parse_bool, [UNTRACKED], "gather metadata statistics (default: no)"), mir_emit_retag: bool = (false, parse_bool, [TRACKED], @@ -1379,9 +1360,6 @@ options! { "use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be \ enabled, overriding all other checks. Passes that are not specified are enabled or \ disabled by other flags as usual."), - mir_pretty_relative_line_numbers: bool = (false, parse_bool, [UNTRACKED], - "use line numbers relative to the function in mir pretty printing"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field"))] mir_opt_level: Option = (None, parse_opt_number, [TRACKED], "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"), move_size_limit: Option = (None, parse_opt_number, [TRACKED], @@ -1448,7 +1426,6 @@ options! { See #77382 and #74551."), print_fuel: Option = (None, parse_opt_string, [TRACKED], "make rustc print the total optimization fuel used by a crate"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::print_llvm_passes` instead of this field"))] print_llvm_passes: bool = (false, parse_bool, [UNTRACKED], "print the LLVM optimization passes being run (default: no)"), print_mono_items: Option = (None, parse_opt_string, [UNTRACKED], @@ -1523,7 +1500,6 @@ options! { "exclude spans when debug-printing compiler state (default: no)"), src_hash_algorithm: Option = (None, parse_src_file_hash, [TRACKED], "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field"))] stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED], "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"), strict_init_checks: bool = (false, parse_bool, [TRACKED], @@ -1544,7 +1520,6 @@ options! { symbol_mangling_version: Option = (None, parse_symbol_mangling_version, [TRACKED], "which mangling version to use for symbol names ('legacy' (default) or 'v0')"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::teach` instead of this field"))] teach: bool = (false, parse_bool, [TRACKED], "show extended diagnostic help (default: no)"), temps_dir: Option = (None, parse_opt_string, [UNTRACKED], @@ -1560,7 +1535,6 @@ options! { "emit directionality isolation markers in translated diagnostics"), tune_cpu: Option = (None, parse_opt_string, [TRACKED], "select processor to schedule for (`rustc --print target-cpus` for details)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field"))] thinlto: Option = (None, parse_opt_bool, [TRACKED], "enable ThinLTO when possible"), thir_unsafeck: bool = (false, parse_bool, [TRACKED], @@ -1569,19 +1543,14 @@ options! { /// a sequential compiler for now. This'll likely be adjusted /// in the future. Note that -Zthreads=0 is the way to get /// the num_cpus behavior. - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::threads` instead of this field"))] threads: usize = (1, parse_threads, [UNTRACKED], "use a thread pool with N threads"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::time_passes` instead of this field"))] time: bool = (false, parse_bool, [UNTRACKED], "measure time of rustc processes (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::time_llvm_passes` instead of this field"))] time_llvm_passes: bool = (false, parse_bool, [UNTRACKED], "measure time of each LLVM pass (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::time_passes` instead of this field"))] time_passes: bool = (false, parse_bool, [UNTRACKED], "measure time of each rustc pass (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field"))] tls_model: Option = (None, parse_tls_model, [TRACKED], "choose the TLS model to use (`rustc --print tls-models` for details)"), trace_macros: bool = (false, parse_bool, [UNTRACKED], @@ -1616,17 +1585,14 @@ options! { "enable unsound and buggy MIR optimizations (default: no)"), /// This name is kind of confusing: Most unstable options enable something themselves, while /// this just allows "normal" options to be feature-gated. - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::unstable_options` instead of this field"))] unstable_options: bool = (false, parse_bool, [UNTRACKED], "adds unstable command line options to rustc interface (default: no)"), use_ctors_section: Option = (None, parse_opt_bool, [TRACKED], "use legacy .ctors section for initializers rather than .init_array"), validate_mir: bool = (false, parse_bool, [UNTRACKED], "validate MIR after each transformation"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::verbose` instead of this field"))] verbose: bool = (false, parse_bool, [UNTRACKED], "in general, enable more debug printouts (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::verify_llvm_ir` instead of this field"))] verify_llvm_ir: bool = (false, parse_bool, [TRACKED], "verify LLVM IR (default: no)"), virtual_function_elimination: bool = (false, parse_bool, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 9669287b3f370..854cad79a2040 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1,7 +1,7 @@ use crate::cgu_reuse_tracker::CguReuseTracker; use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}; -use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, SwitchWithOptPath}; +use crate::config::{self, CrateType, OutputType, SwitchWithOptPath}; use crate::parse::{add_feature_diagnostics, ParseSess}; use crate::search_paths::{PathKind, SearchPath}; use crate::{filesearch, lint}; @@ -583,356 +583,50 @@ impl Session { pub fn source_map(&self) -> &SourceMap { self.parse_sess.source_map() } - - pub fn time_passes(&self) -> bool { - self.opts.time_passes() - } - - /// Returns `true` if internal lints should be added to the lint store - i.e. if - /// `-Zunstable-options` is provided and this isn't rustdoc (internal lints can trigger errors - /// to be emitted under rustdoc). - pub fn enable_internal_lints(&self) -> bool { - self.unstable_options() && !self.opts.actually_rustdoc - } - - pub fn instrument_coverage(&self) -> bool { - self.opts.cg.instrument_coverage() != InstrumentCoverage::Off - } - - pub fn instrument_coverage_except_unused_generics(&self) -> bool { - self.opts.cg.instrument_coverage() == InstrumentCoverage::ExceptUnusedGenerics - } - - pub fn instrument_coverage_except_unused_functions(&self) -> bool { - self.opts.cg.instrument_coverage() == InstrumentCoverage::ExceptUnusedFunctions - } - - /// Gets the features enabled for the current compilation session. - /// DO NOT USE THIS METHOD if there is a TyCtxt available, as it circumvents - /// dependency tracking. Use tcx.features() instead. - #[inline] - pub fn features_untracked(&self) -> &rustc_feature::Features { - self.features.get().unwrap() - } - - pub fn init_features(&self, features: rustc_feature::Features) { - match self.features.set(features) { - Ok(()) => {} - Err(_) => panic!("`features` was initialized twice"), - } - } - - pub fn is_sanitizer_cfi_enabled(&self) -> bool { - self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI) - } - - /// Check whether this compile session and crate type use static crt. - pub fn crt_static(&self, crate_type: Option) -> bool { - if !self.target.crt_static_respected { - // If the target does not opt in to crt-static support, use its default. - return self.target.crt_static_default; - } - - let requested_features = self.opts.cg.target_feature.split(','); - let found_negative = requested_features.clone().any(|r| r == "-crt-static"); - let found_positive = requested_features.clone().any(|r| r == "+crt-static"); - - // JUSTIFICATION: necessary use of crate_types directly (see FIXME below) - #[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] - if found_positive || found_negative { - found_positive - } else if crate_type == Some(CrateType::ProcMacro) - || crate_type == None && self.opts.crate_types.contains(&CrateType::ProcMacro) - { - // FIXME: When crate_type is not available, - // we use compiler options to determine the crate_type. - // We can't check `#![crate_type = "proc-macro"]` here. - false - } else { - self.target.crt_static_default - } - } - - pub fn is_wasi_reactor(&self) -> bool { - self.target.options.os == "wasi" - && matches!( - self.opts.unstable_opts.wasi_exec_model, - Some(config::WasiExecModel::Reactor) - ) - } - - pub fn target_can_use_split_dwarf(&self) -> bool { - !self.target.is_like_windows && !self.target.is_like_osx - } - - pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String { - format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.to_u64()) - } - - pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> { - filesearch::FileSearch::new( - &self.sysroot, - self.opts.target_triple.triple(), - &self.opts.search_paths, - &self.target_tlib_path, - kind, - ) - } - pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> { - filesearch::FileSearch::new( - &self.sysroot, - config::host_triple(), - &self.opts.search_paths, - &self.host_tlib_path, - kind, - ) - } - - /// Returns a list of directories where target-specific tool binaries are located. - pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec { - let rustlib_path = rustc_target::target_rustlib_path(&self.sysroot, &config::host_triple()); - let p = PathBuf::from_iter([ - Path::new(&self.sysroot), - Path::new(&rustlib_path), - Path::new("bin"), - ]); - if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] } - } - - pub fn init_incr_comp_session( - &self, - session_dir: PathBuf, - lock_file: flock::Lock, - load_dep_graph: bool, - ) { - let mut incr_comp_session = self.incr_comp_session.borrow_mut(); - - if let IncrCompSession::NotInitialized = *incr_comp_session { - } else { - panic!("Trying to initialize IncrCompSession `{:?}`", *incr_comp_session) - } - - *incr_comp_session = - IncrCompSession::Active { session_directory: session_dir, lock_file, load_dep_graph }; - } - - pub fn finalize_incr_comp_session(&self, new_directory_path: PathBuf) { - let mut incr_comp_session = self.incr_comp_session.borrow_mut(); - - if let IncrCompSession::Active { .. } = *incr_comp_session { - } else { - panic!("trying to finalize `IncrCompSession` `{:?}`", *incr_comp_session); - } - - // Note: this will also drop the lock file, thus unlocking the directory. - *incr_comp_session = IncrCompSession::Finalized { session_directory: new_directory_path }; - } - - pub fn mark_incr_comp_session_as_invalid(&self) { - let mut incr_comp_session = self.incr_comp_session.borrow_mut(); - - let session_directory = match *incr_comp_session { - IncrCompSession::Active { ref session_directory, .. } => session_directory.clone(), - IncrCompSession::InvalidBecauseOfErrors { .. } => return, - _ => panic!("trying to invalidate `IncrCompSession` `{:?}`", *incr_comp_session), - }; - - // Note: this will also drop the lock file, thus unlocking the directory. - *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors { session_directory }; - } - - pub fn incr_comp_session_dir(&self) -> cell::Ref<'_, PathBuf> { - let incr_comp_session = self.incr_comp_session.borrow(); - cell::Ref::map(incr_comp_session, |incr_comp_session| match *incr_comp_session { - IncrCompSession::NotInitialized => panic!( - "trying to get session directory from `IncrCompSession`: {:?}", - *incr_comp_session, - ), - IncrCompSession::Active { ref session_directory, .. } - | IncrCompSession::Finalized { ref session_directory } - | IncrCompSession::InvalidBecauseOfErrors { ref session_directory } => { - session_directory - } - }) - } - - pub fn incr_comp_session_dir_opt(&self) -> Option> { - self.opts.incremental.as_ref().map(|_| self.incr_comp_session_dir()) - } - - pub fn print_perf_stats(&self) { - eprintln!( - "Total time spent computing symbol hashes: {}", - duration_to_secs_str(*self.perf_stats.symbol_hash_time.lock()) - ); - eprintln!( - "Total queries canonicalized: {}", - self.perf_stats.queries_canonicalized.load(Ordering::Relaxed) - ); - eprintln!( - "normalize_generic_arg_after_erasing_regions: {}", - self.perf_stats.normalize_generic_arg_after_erasing_regions.load(Ordering::Relaxed) - ); - eprintln!( - "normalize_projection_ty: {}", - self.perf_stats.normalize_projection_ty.load(Ordering::Relaxed) - ); - } - - /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. - /// This expends fuel if applicable, and records fuel if applicable. - pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { - let mut ret = true; - if let Some((ref c, _)) = self.opts.unstable_opts.fuel { - if c == crate_name { - assert_eq!(self.threads(), 1); - let mut fuel = self.optimization_fuel.lock(); - ret = fuel.remaining != 0; - if fuel.remaining == 0 && !fuel.out_of_fuel { - if self.diagnostic().can_emit_warnings() { - // We only call `msg` in case we can actually emit warnings. - // Otherwise, this could cause a `delay_good_path_bug` to - // trigger (issue #79546). - self.warn(&format!("optimization-fuel-exhausted: {}", msg())); - } - fuel.out_of_fuel = true; - } else if fuel.remaining > 0 { - fuel.remaining -= 1; - } - } - } - if let Some(ref c) = self.opts.unstable_opts.print_fuel { - if c == crate_name { - assert_eq!(self.threads(), 1); - self.print_fuel.fetch_add(1, SeqCst); - } - } - ret - } - - pub fn rust_2015(&self) -> bool { - self.edition() == Edition::Edition2015 - } - - /// Are we allowed to use features from the Rust 2018 edition? - pub fn rust_2018(&self) -> bool { - self.edition() >= Edition::Edition2018 - } - - /// Are we allowed to use features from the Rust 2021 edition? - pub fn rust_2021(&self) -> bool { - self.edition() >= Edition::Edition2021 - } - - /// Are we allowed to use features from the Rust 2024 edition? - pub fn rust_2024(&self) -> bool { - self.edition() >= Edition::Edition2024 - } - - /// Returns `true` if we cannot skip the PLT for shared library calls. - pub fn needs_plt(&self) -> bool { - // Check if the current target usually needs PLT to be enabled. - // The user can use the command line flag to override it. - let needs_plt = self.target.needs_plt; - - let dbg_opts = &self.opts.unstable_opts; - - let relro_level = dbg_opts.relro_level.unwrap_or(self.target.relro_level); - - // Only enable this optimization by default if full relro is also enabled. - // In this case, lazy binding was already unavailable, so nothing is lost. - // This also ensures `-Wl,-z,now` is supported by the linker. - let full_relro = RelroLevel::Full == relro_level; - - // If user didn't explicitly forced us to use / skip the PLT, - // then try to skip it where possible. - dbg_opts.plt.unwrap_or(needs_plt || !full_relro) - } - - /// Checks if LLVM lifetime markers should be emitted. - pub fn emit_lifetime_markers(&self) -> bool { - self.opts.optimize != config::OptLevel::No - // AddressSanitizer uses lifetimes to detect use after scope bugs. - // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables. - // HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future. - || self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS) - } - - pub fn is_proc_macro_attr(&self, attr: &Attribute) -> bool { - [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] - .iter() - .any(|kind| attr.has_name(*kind)) - } - - pub fn contains_name(&self, attrs: &[Attribute], name: Symbol) -> bool { - attrs.iter().any(|item| item.has_name(name)) - } - - pub fn find_by_name<'a>( - &'a self, - attrs: &'a [Attribute], - name: Symbol, - ) -> Option<&'a Attribute> { - attrs.iter().find(|attr| attr.has_name(name)) - } - - pub fn filter_by_name<'a>( - &'a self, - attrs: &'a [Attribute], - name: Symbol, - ) -> impl Iterator { - attrs.iter().filter(move |attr| attr.has_name(name)) - } - - pub fn first_attr_value_str_by_name( - &self, - attrs: &[Attribute], - name: Symbol, - ) -> Option { - attrs.iter().find(|at| at.has_name(name)).and_then(|at| at.value_str()) - } -} - -// JUSTIFICATION: defn of the suggested wrapper fns -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] -impl Session { pub fn verbose(&self) -> bool { self.opts.unstable_opts.verbose } - + pub fn time_passes(&self) -> bool { + self.opts.unstable_opts.time_passes || self.opts.unstable_opts.time + } pub fn instrument_mcount(&self) -> bool { self.opts.unstable_opts.instrument_mcount } - pub fn time_llvm_passes(&self) -> bool { self.opts.unstable_opts.time_llvm_passes } - pub fn meta_stats(&self) -> bool { self.opts.unstable_opts.meta_stats } - pub fn asm_comments(&self) -> bool { self.opts.unstable_opts.asm_comments } - pub fn verify_llvm_ir(&self) -> bool { self.opts.unstable_opts.verify_llvm_ir || option_env!("RUSTC_VERIFY_LLVM_IR").is_some() } - pub fn print_llvm_passes(&self) -> bool { self.opts.unstable_opts.print_llvm_passes } - pub fn binary_dep_depinfo(&self) -> bool { self.opts.unstable_opts.binary_dep_depinfo } - pub fn mir_opt_level(&self) -> usize { - self.opts - .unstable_opts - .mir_opt_level - .unwrap_or_else(|| if self.opts.optimize != OptLevel::No { 2 } else { 1 }) + self.opts.mir_opt_level() + } + + /// Gets the features enabled for the current compilation session. + /// DO NOT USE THIS METHOD if there is a TyCtxt available, as it circumvents + /// dependency tracking. Use tcx.features() instead. + #[inline] + pub fn features_untracked(&self) -> &rustc_feature::Features { + self.features.get().unwrap() + } + + pub fn init_features(&self, features: rustc_feature::Features) { + match self.features.set(features) { + Ok(()) => {} + Err(_) => panic!("`features` was initialized twice"), + } } /// Calculates the flavor of LTO to use for this compilation. @@ -1008,7 +702,6 @@ impl Session { pub fn panic_strategy(&self) -> PanicStrategy { self.opts.cg.panic.unwrap_or(self.target.panic_strategy) } - pub fn fewer_names(&self) -> bool { if let Some(fewer_names) = self.opts.unstable_opts.fewer_names { fewer_names @@ -1024,15 +717,41 @@ impl Session { pub fn unstable_options(&self) -> bool { self.opts.unstable_opts.unstable_options } - pub fn is_nightly_build(&self) -> bool { self.opts.unstable_features.is_nightly_build() } - + pub fn is_sanitizer_cfi_enabled(&self) -> bool { + self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI) + } pub fn overflow_checks(&self) -> bool { self.opts.cg.overflow_checks.unwrap_or(self.opts.debug_assertions) } + /// Check whether this compile session and crate type use static crt. + pub fn crt_static(&self, crate_type: Option) -> bool { + if !self.target.crt_static_respected { + // If the target does not opt in to crt-static support, use its default. + return self.target.crt_static_default; + } + + let requested_features = self.opts.cg.target_feature.split(','); + let found_negative = requested_features.clone().any(|r| r == "-crt-static"); + let found_positive = requested_features.clone().any(|r| r == "+crt-static"); + + if found_positive || found_negative { + found_positive + } else if crate_type == Some(CrateType::ProcMacro) + || crate_type == None && self.opts.crate_types.contains(&CrateType::ProcMacro) + { + // FIXME: When crate_type is not available, + // we use compiler options to determine the crate_type. + // We can't check `#![crate_type = "proc-macro"]` here. + false + } else { + self.target.crt_static_default + } + } + pub fn relocation_model(&self) -> RelocModel { self.opts.cg.relocation_model.unwrap_or(self.target.relocation_model) } @@ -1045,6 +764,14 @@ impl Session { self.opts.unstable_opts.tls_model.unwrap_or(self.target.tls_model) } + pub fn is_wasi_reactor(&self) -> bool { + self.target.options.os == "wasi" + && matches!( + self.opts.unstable_opts.wasi_exec_model, + Some(config::WasiExecModel::Reactor) + ) + } + pub fn split_debuginfo(&self) -> SplitDebuginfo { self.opts.cg.split_debuginfo.unwrap_or(self.target.split_debuginfo) } @@ -1057,6 +784,10 @@ impl Session { } } + pub fn target_can_use_split_dwarf(&self) -> bool { + !self.target.is_like_windows && !self.target.is_like_osx + } + pub fn must_emit_unwind_tables(&self) -> bool { // This is used to control the emission of the `uwtable` attribute on // LLVM functions. @@ -1084,6 +815,151 @@ impl Session { ) } + pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String { + format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.to_u64()) + } + + pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> { + filesearch::FileSearch::new( + &self.sysroot, + self.opts.target_triple.triple(), + &self.opts.search_paths, + &self.target_tlib_path, + kind, + ) + } + pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> { + filesearch::FileSearch::new( + &self.sysroot, + config::host_triple(), + &self.opts.search_paths, + &self.host_tlib_path, + kind, + ) + } + + /// Returns a list of directories where target-specific tool binaries are located. + pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec { + let rustlib_path = rustc_target::target_rustlib_path(&self.sysroot, &config::host_triple()); + let p = PathBuf::from_iter([ + Path::new(&self.sysroot), + Path::new(&rustlib_path), + Path::new("bin"), + ]); + if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] } + } + + pub fn init_incr_comp_session( + &self, + session_dir: PathBuf, + lock_file: flock::Lock, + load_dep_graph: bool, + ) { + let mut incr_comp_session = self.incr_comp_session.borrow_mut(); + + if let IncrCompSession::NotInitialized = *incr_comp_session { + } else { + panic!("Trying to initialize IncrCompSession `{:?}`", *incr_comp_session) + } + + *incr_comp_session = + IncrCompSession::Active { session_directory: session_dir, lock_file, load_dep_graph }; + } + + pub fn finalize_incr_comp_session(&self, new_directory_path: PathBuf) { + let mut incr_comp_session = self.incr_comp_session.borrow_mut(); + + if let IncrCompSession::Active { .. } = *incr_comp_session { + } else { + panic!("trying to finalize `IncrCompSession` `{:?}`", *incr_comp_session); + } + + // Note: this will also drop the lock file, thus unlocking the directory. + *incr_comp_session = IncrCompSession::Finalized { session_directory: new_directory_path }; + } + + pub fn mark_incr_comp_session_as_invalid(&self) { + let mut incr_comp_session = self.incr_comp_session.borrow_mut(); + + let session_directory = match *incr_comp_session { + IncrCompSession::Active { ref session_directory, .. } => session_directory.clone(), + IncrCompSession::InvalidBecauseOfErrors { .. } => return, + _ => panic!("trying to invalidate `IncrCompSession` `{:?}`", *incr_comp_session), + }; + + // Note: this will also drop the lock file, thus unlocking the directory. + *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors { session_directory }; + } + + pub fn incr_comp_session_dir(&self) -> cell::Ref<'_, PathBuf> { + let incr_comp_session = self.incr_comp_session.borrow(); + cell::Ref::map(incr_comp_session, |incr_comp_session| match *incr_comp_session { + IncrCompSession::NotInitialized => panic!( + "trying to get session directory from `IncrCompSession`: {:?}", + *incr_comp_session, + ), + IncrCompSession::Active { ref session_directory, .. } + | IncrCompSession::Finalized { ref session_directory } + | IncrCompSession::InvalidBecauseOfErrors { ref session_directory } => { + session_directory + } + }) + } + + pub fn incr_comp_session_dir_opt(&self) -> Option> { + self.opts.incremental.as_ref().map(|_| self.incr_comp_session_dir()) + } + + pub fn print_perf_stats(&self) { + eprintln!( + "Total time spent computing symbol hashes: {}", + duration_to_secs_str(*self.perf_stats.symbol_hash_time.lock()) + ); + eprintln!( + "Total queries canonicalized: {}", + self.perf_stats.queries_canonicalized.load(Ordering::Relaxed) + ); + eprintln!( + "normalize_generic_arg_after_erasing_regions: {}", + self.perf_stats.normalize_generic_arg_after_erasing_regions.load(Ordering::Relaxed) + ); + eprintln!( + "normalize_projection_ty: {}", + self.perf_stats.normalize_projection_ty.load(Ordering::Relaxed) + ); + } + + /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. + /// This expends fuel if applicable, and records fuel if applicable. + pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { + let mut ret = true; + if let Some((ref c, _)) = self.opts.unstable_opts.fuel { + if c == crate_name { + assert_eq!(self.threads(), 1); + let mut fuel = self.optimization_fuel.lock(); + ret = fuel.remaining != 0; + if fuel.remaining == 0 && !fuel.out_of_fuel { + if self.diagnostic().can_emit_warnings() { + // We only call `msg` in case we can actually emit warnings. + // Otherwise, this could cause a `delay_good_path_bug` to + // trigger (issue #79546). + self.warn(&format!("optimization-fuel-exhausted: {}", msg())); + } + fuel.out_of_fuel = true; + } else if fuel.remaining > 0 { + fuel.remaining -= 1; + } + } + } + if let Some(ref c) = self.opts.unstable_opts.print_fuel { + if c == crate_name { + assert_eq!(self.threads(), 1); + self.print_fuel.fetch_add(1, SeqCst); + } + } + ret + } + /// Returns the number of query threads that should be used for this /// compilation pub fn threads(&self) -> usize { @@ -1164,17 +1040,109 @@ impl Session { self.opts.unstable_opts.teach && self.diagnostic().must_teach(code) } + pub fn rust_2015(&self) -> bool { + self.opts.edition == Edition::Edition2015 + } + + /// Are we allowed to use features from the Rust 2018 edition? + pub fn rust_2018(&self) -> bool { + self.opts.edition >= Edition::Edition2018 + } + + /// Are we allowed to use features from the Rust 2021 edition? + pub fn rust_2021(&self) -> bool { + self.opts.edition >= Edition::Edition2021 + } + + /// Are we allowed to use features from the Rust 2024 edition? + pub fn rust_2024(&self) -> bool { + self.opts.edition >= Edition::Edition2024 + } + pub fn edition(&self) -> Edition { self.opts.edition } + /// Returns `true` if we cannot skip the PLT for shared library calls. + pub fn needs_plt(&self) -> bool { + // Check if the current target usually needs PLT to be enabled. + // The user can use the command line flag to override it. + let needs_plt = self.target.needs_plt; + + let dbg_opts = &self.opts.unstable_opts; + + let relro_level = dbg_opts.relro_level.unwrap_or(self.target.relro_level); + + // Only enable this optimization by default if full relro is also enabled. + // In this case, lazy binding was already unavailable, so nothing is lost. + // This also ensures `-Wl,-z,now` is supported by the linker. + let full_relro = RelroLevel::Full == relro_level; + + // If user didn't explicitly forced us to use / skip the PLT, + // then try to skip it where possible. + dbg_opts.plt.unwrap_or(needs_plt || !full_relro) + } + + /// Checks if LLVM lifetime markers should be emitted. + pub fn emit_lifetime_markers(&self) -> bool { + self.opts.optimize != config::OptLevel::No + // AddressSanitizer uses lifetimes to detect use after scope bugs. + // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables. + // HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future. + || self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS) + } + pub fn link_dead_code(&self) -> bool { self.opts.cg.link_dead_code.unwrap_or(false) } + + pub fn instrument_coverage(&self) -> bool { + self.opts.instrument_coverage() + } + + pub fn instrument_coverage_except_unused_generics(&self) -> bool { + self.opts.instrument_coverage_except_unused_generics() + } + + pub fn instrument_coverage_except_unused_functions(&self) -> bool { + self.opts.instrument_coverage_except_unused_functions() + } + + pub fn is_proc_macro_attr(&self, attr: &Attribute) -> bool { + [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] + .iter() + .any(|kind| attr.has_name(*kind)) + } + + pub fn contains_name(&self, attrs: &[Attribute], name: Symbol) -> bool { + attrs.iter().any(|item| item.has_name(name)) + } + + pub fn find_by_name<'a>( + &'a self, + attrs: &'a [Attribute], + name: Symbol, + ) -> Option<&'a Attribute> { + attrs.iter().find(|attr| attr.has_name(name)) + } + + pub fn filter_by_name<'a>( + &'a self, + attrs: &'a [Attribute], + name: Symbol, + ) -> impl Iterator { + attrs.iter().filter(move |attr| attr.has_name(name)) + } + + pub fn first_attr_value_str_by_name( + &self, + attrs: &[Attribute], + name: Symbol, + ) -> Option { + attrs.iter().find(|at| at.has_name(name)).and_then(|at| at.value_str()) + } } -// JUSTIFICATION: part of session construction -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] fn default_emitter( sopts: &config::Options, registry: rustc_errors::registry::Registry, @@ -1259,8 +1227,6 @@ pub enum DiagnosticOutput { Raw(Box), } -// JUSTIFICATION: literally session construction -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] pub fn build_session( sopts: config::Options, local_crate_source_file: Option, @@ -1382,8 +1348,11 @@ pub fn build_session( CguReuseTracker::new_disabled() }; - let prof = - SelfProfilerRef::new(self_profiler, sopts.time_passes(), sopts.unstable_opts.time_passes); + let prof = SelfProfilerRef::new( + self_profiler, + sopts.unstable_opts.time_passes || sopts.unstable_opts.time, + sopts.unstable_opts.time_passes, + ); let ctfe_backtrace = Lock::new(match env::var("RUSTC_CTFE_BACKTRACE") { Ok(ref val) if val == "immediate" => CtfeBacktrace::Immediate, @@ -1432,12 +1401,8 @@ pub fn build_session( sess } -/// Validate command line arguments with a `Session`. -/// -/// If it is useful to have a Session available already for validating a commandline argument, you -/// can do so here. -// JUSTIFICATION: needs to access args to validate them -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] +// If it is useful to have a Session available already for validating a +// commandline argument, you can do so here. fn validate_commandline_args_with_session_available(sess: &Session) { // Since we don't know if code in an rlib will be linked to statically or // dynamically downstream, rustc generates `__imp_` symbols that help linkers diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 28381157d50a9..b4a4424e876cd 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -463,33 +463,6 @@ impl SourceMap { self.span_to_string(sp, FileNameDisplayPreference::Remapped) } - /// Format the span location suitable for pretty printing anotations with relative line numbers - pub fn span_to_relative_line_string(&self, sp: Span, relative_to: Span) -> String { - if self.files.borrow().source_files.is_empty() || sp.is_dummy() || relative_to.is_dummy() { - return "no-location".to_string(); - } - - let lo = self.lookup_char_pos(sp.lo()); - let hi = self.lookup_char_pos(sp.hi()); - let offset = self.lookup_char_pos(relative_to.lo()); - - if lo.file.name != offset.file.name { - return self.span_to_embeddable_string(sp); - } - - let lo_line = lo.line.saturating_sub(offset.line); - let hi_line = hi.line.saturating_sub(offset.line); - - format!( - "{}:+{}:{}: +{}:{}", - lo.file.name.display(FileNameDisplayPreference::Remapped), - lo_line, - lo.col.to_usize() + 1, - hi_line, - hi.col.to_usize() + 1, - ) - } - /// Format the span location to be printed in diagnostics. Must not be emitted /// to build artifacts as this may leak local file paths. Use span_to_embeddable_string /// for string suitable for embedding. @@ -613,6 +586,17 @@ impl SourceMap { } } + /// Returns whether or not this span points into a file + /// in the current crate. This may be `false` for spans + /// produced by a macro expansion, or for spans associated + /// with the definition of an item in a foreign crate + pub fn is_local_span(&self, sp: Span) -> bool { + let local_begin = self.lookup_byte_offset(sp.lo()); + let local_end = self.lookup_byte_offset(sp.hi()); + // This might be a weird span that covers multiple files + local_begin.sf.src.is_some() && local_end.sf.src.is_some() + } + pub fn is_span_accessible(&self, sp: Span) -> bool { self.span_to_source(sp, |src, start_index, end_index| { Ok(src.get(start_index..end_index).is_some()) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 060e7a7b90aee..2ac1ecfe87eb5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1202,7 +1202,6 @@ symbols! { rustc, rustc_allocator, rustc_allocator_nounwind, - rustc_allocator_zeroed, rustc_allow_const_fn_unstable, rustc_allow_incoherent_impl, rustc_allowed_through_unstable_modules, @@ -1215,7 +1214,6 @@ symbols! { rustc_const_stable, rustc_const_unstable, rustc_conversion_suggestion, - rustc_deallocator, rustc_def_path, rustc_diagnostic_item, rustc_diagnostic_macros, @@ -1238,8 +1236,6 @@ symbols! { rustc_layout_scalar_valid_range_start, rustc_legacy_const_generics, rustc_lint_diagnostics, - rustc_lint_opt_deny_field_access, - rustc_lint_opt_ty, rustc_lint_query_instability, rustc_macro_transparency, rustc_main, @@ -1262,7 +1258,6 @@ symbols! { rustc_private, rustc_proc_macro_decls, rustc_promotable, - rustc_reallocator, rustc_regions, rustc_reservation_impl, rustc_serialize, @@ -1289,7 +1284,6 @@ symbols! { self_in_typedefs, self_struct_ctor, semitransparent, - shadow_call_stack, shl, shl_assign, should_panic, @@ -1533,9 +1527,6 @@ symbols! { unsized_locals, unsized_tuple_coercion, unstable, - unstable_location_reason_default: "this crate is being loaded from the sysroot, an \ - unstable location; did you mean to load this crate \ - from crates.io via `Cargo.toml` instead?", untagged_unions, unused_imports, unused_qualifications, @@ -1574,8 +1565,6 @@ symbols! { volatile_store, vreg, vreg_low16, - vtable_align, - vtable_size, warn, wasm_abi, wasm_import_module, diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index b104a40c23115..d5befa10e2363 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" doctest = false [dependencies] -bitflags = "1.2.1" tracing = "0.1" punycode = "0.4.0" rustc-demangle = "0.1.21" diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 9241fd82c745f..e3045c9321d1c 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -67,7 +67,7 @@ pub(super) fn mangle<'tcx>( ) .unwrap(); - if let ty::InstanceDef::VTableShim(..) = instance.def { + if let ty::InstanceDef::VtableShim(..) = instance.def { let _ = printer.write_str("{{vtable-shim}}"); } @@ -129,7 +129,7 @@ fn get_symbol_hash<'tcx>( } // We want to avoid accidental collision between different types of instances. - // Especially, `VTableShim`s and `ReifyShim`s may overlap with their original + // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original // instances without this. discriminant(&instance.def).hash_stable(hcx, &mut hasher); }); diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 5fc992023caa0..bed0e81e66e14 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -102,8 +102,9 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, Instance, TyCtxt}; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::config::SymbolManglingVersion; +use rustc_target::abi::call::FnAbi; use tracing::debug; @@ -111,7 +112,6 @@ mod legacy; mod v0; pub mod test; -pub mod typeid; /// This function computes the symbol name for the given `instance` and the /// given instantiating crate. That is, if you know that instance X is @@ -150,6 +150,11 @@ fn symbol_name_provider<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty ty::SymbolName::new(tcx, &symbol_name) } +/// This function computes the typeid for the given function ABI. +pub fn typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String { + v0::mangle_typeid_for_fnabi(tcx, fn_abi) +} + pub fn typeid_for_trait_ref<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyExistentialTraitRef<'tcx>, diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs deleted file mode 100644 index 9228bea43f932..0000000000000 --- a/compiler/rustc_symbol_mangling/src/typeid.rs +++ /dev/null @@ -1,18 +0,0 @@ -// For more information about type metadata and type metadata identifiers for cross-language LLVM -// CFI support, see Type metadata in the design document in the tracking issue #89653. - -use rustc_middle::ty::{FnSig, Ty, TyCtxt}; -use rustc_target::abi::call::FnAbi; - -mod typeid_itanium_cxx_abi; -use typeid_itanium_cxx_abi::TypeIdOptions; - -/// Returns a type metadata identifier for the specified FnAbi. -pub fn typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String { - typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, TypeIdOptions::NO_OPTIONS) -} - -/// Returns a type metadata identifier for the specified FnSig. -pub fn typeid_for_fnsig<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: &FnSig<'tcx>) -> String { - typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, TypeIdOptions::NO_OPTIONS) -} diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs deleted file mode 100644 index a09b52fbfdf97..0000000000000 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ /dev/null @@ -1,929 +0,0 @@ -// For more information about type metadata and type metadata identifiers for cross-language LLVM -// CFI support, see Type metadata in the design document in the tracking issue #89653. - -// FIXME(rcvalle): Identify C char and integer type uses and encode them with their respective -// builtin type encodings as specified by the Itanium C++ ABI for extern function types with the "C" -// calling convention to use this encoding for cross-language LLVM CFI. - -use bitflags::bitflags; -use core::fmt::Display; -use rustc_data_structures::base_n; -use rustc_data_structures::fx::FxHashMap; -use rustc_hir as hir; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; -use rustc_middle::ty::{ - self, Binder, Const, ExistentialPredicate, FloatTy, FnSig, IntTy, List, Region, RegionKind, - Term, Ty, TyCtxt, UintTy, -}; -use rustc_span::def_id::DefId; -use rustc_span::symbol::sym; -use rustc_target::abi::call::{Conv, FnAbi}; -use rustc_target::spec::abi::Abi; -use std::fmt::Write as _; - -/// Type and extended type qualifiers. -#[derive(Eq, Hash, PartialEq)] -enum TyQ { - None, - Const, - Mut, -} - -/// Substitution dictionary key. -#[derive(Eq, Hash, PartialEq)] -enum DictKey<'tcx> { - Ty(Ty<'tcx>, TyQ), - Region(Region<'tcx>), - Const(Const<'tcx>), - Predicate(ExistentialPredicate<'tcx>), -} - -bitflags! { - /// Options for typeid_for_fnabi and typeid_for_fnsig. - pub struct TypeIdOptions: u32 { - const NO_OPTIONS = 0; - const GENERALIZE_POINTERS = 1; - const GENERALIZE_REPR_C = 2; - } -} - -/// Options for encode_ty. -type EncodeTyOptions = TypeIdOptions; - -/// Options for transform_ty. -type TransformTyOptions = TypeIdOptions; - -/// Converts a number to a disambiguator (see -/// ). -fn to_disambiguator(num: u64) -> String { - if let Some(num) = num.checked_sub(1) { - format!("s{}_", base_n::encode(num as u128, 62)) - } else { - "s_".to_string() - } -} - -/// Converts a number to a sequence number (see -/// ). -fn to_seq_id(num: usize) -> String { - if let Some(num) = num.checked_sub(1) { - base_n::encode(num as u128, 36).to_uppercase() - } else { - "".to_string() - } -} - -/// Substitutes a component if found in the substitution dictionary (see -/// ). -fn compress<'tcx>( - dict: &mut FxHashMap, usize>, - key: DictKey<'tcx>, - comp: &mut String, -) { - match dict.get(&key) { - Some(num) => { - comp.clear(); - let _ = write!(comp, "S{}_", to_seq_id(*num)); - } - None => { - dict.insert(key, dict.len()); - } - } -} - -// FIXME(rcvalle): Move to compiler/rustc_middle/src/ty/sty.rs after C types work is done, possibly -// along with other is_c_type methods. -/// Returns whether a `ty::Ty` is `c_void`. -fn is_c_void_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind() { - ty::Adt(adt_def, ..) => { - let def_id = adt_def.0.did; - let crate_name = tcx.crate_name(def_id.krate); - if tcx.item_name(def_id).as_str() == "c_void" - && (crate_name == sym::core || crate_name == sym::std || crate_name == sym::libc) - { - true - } else { - false - } - } - _ => false, - } -} - -/// Encodes a const using the Itanium C++ ABI as a literal argument (see -/// ). -fn encode_const<'tcx>( - tcx: TyCtxt<'tcx>, - c: Const<'tcx>, - dict: &mut FxHashMap, usize>, - options: EncodeTyOptions, -) -> String { - // L[n]E as literal argument - let mut s = String::from('L'); - - // Element type - s.push_str(&encode_ty(tcx, c.ty(), dict, options)); - - // The only allowed types of const parameters are bool, u8, u16, u32, u64, u128, usize i8, i16, - // i32, i64, i128, isize, and char. The bool value false is encoded as 0 and true as 1. - fn push_signed_value(s: &mut String, value: T, zero: T) { - if value < zero { - s.push('n') - }; - let _ = write!(s, "{}", value); - } - - fn push_unsigned_value(s: &mut String, value: T) { - let _ = write!(s, "{}", value); - } - - if let Some(scalar_int) = c.kind().try_to_scalar_int() { - let signed = c.ty().is_signed(); - match scalar_int.size().bits() { - 8 if signed => push_signed_value(&mut s, scalar_int.try_to_i8().unwrap(), 0), - 16 if signed => push_signed_value(&mut s, scalar_int.try_to_i16().unwrap(), 0), - 32 if signed => push_signed_value(&mut s, scalar_int.try_to_i32().unwrap(), 0), - 64 if signed => push_signed_value(&mut s, scalar_int.try_to_i64().unwrap(), 0), - 128 if signed => push_signed_value(&mut s, scalar_int.try_to_i128().unwrap(), 0), - 8 => push_unsigned_value(&mut s, scalar_int.try_to_u8().unwrap()), - 16 => push_unsigned_value(&mut s, scalar_int.try_to_u16().unwrap()), - 32 => push_unsigned_value(&mut s, scalar_int.try_to_u32().unwrap()), - 64 => push_unsigned_value(&mut s, scalar_int.try_to_u64().unwrap()), - 128 => push_unsigned_value(&mut s, scalar_int.try_to_u128().unwrap()), - _ => { - bug!("encode_const: unexpected size `{:?}`", scalar_int.size().bits()); - } - }; - } else { - bug!("encode_const: unexpected type `{:?}`", c.ty()); - } - - // Close the "L..E" pair - s.push('E'); - - compress(dict, DictKey::Const(c), &mut s); - - s -} - -/// Encodes a FnSig using the Itanium C++ ABI with vendor extended type qualifiers and types for -/// Rust types that are not used at the FFI boundary. -fn encode_fnsig<'tcx>( - tcx: TyCtxt<'tcx>, - fn_sig: &FnSig<'tcx>, - dict: &mut FxHashMap, usize>, - options: TypeIdOptions, -) -> String { - // Function types are delimited by an "F..E" pair - let mut s = String::from("F"); - - let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits()) - .unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits())); - match fn_sig.abi { - Abi::C { .. } => { - encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C); - } - _ => { - encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C); - } - } - - // Encode the return type - let transform_ty_options = TransformTyOptions::from_bits(options.bits()) - .unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits())); - let ty = transform_ty(tcx, fn_sig.output(), transform_ty_options); - s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options)); - - // Encode the parameter types - let tys = fn_sig.inputs(); - if !tys.is_empty() { - for ty in tys { - let ty = transform_ty(tcx, *ty, transform_ty_options); - s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options)); - } - - if fn_sig.c_variadic { - s.push('z'); - } - } else { - if fn_sig.c_variadic { - s.push('z'); - } else { - // Empty parameter lists, whether declared as () or conventionally as (void), are - // encoded with a void parameter specifier "v". - s.push('v') - } - } - - // Close the "F..E" pair - s.push('E'); - - s -} - -/// Encodes a predicate using the Itanium C++ ABI with vendor extended type qualifiers and types for -/// Rust types that are not used at the FFI boundary. -fn encode_predicate<'tcx>( - tcx: TyCtxt<'tcx>, - predicate: Binder<'tcx, ExistentialPredicate<'tcx>>, - dict: &mut FxHashMap, usize>, - options: EncodeTyOptions, -) -> String { - // u[IE], where is , as vendor - // extended type. - let mut s = String::new(); - match predicate.as_ref().skip_binder() { - ty::ExistentialPredicate::Trait(trait_ref) => { - let name = encode_ty_name(tcx, trait_ref.def_id); - let _ = write!(s, "u{}{}", name.len(), &name); - s.push_str(&encode_substs(tcx, trait_ref.substs, dict, options)); - } - ty::ExistentialPredicate::Projection(projection) => { - let name = encode_ty_name(tcx, projection.item_def_id); - let _ = write!(s, "u{}{}", name.len(), &name); - s.push_str(&encode_substs(tcx, projection.substs, dict, options)); - match projection.term { - Term::Ty(ty) => { - s.push_str(&encode_ty(tcx, ty, dict, options)); - } - Term::Const(c) => { - s.push_str(&encode_const(tcx, c, dict, options)); - } - } - } - ty::ExistentialPredicate::AutoTrait(def_id) => { - let name = encode_ty_name(tcx, *def_id); - let _ = write!(s, "u{}{}", name.len(), &name); - } - }; - compress(dict, DictKey::Predicate(*predicate.as_ref().skip_binder()), &mut s); - s -} - -/// Encodes predicates using the Itanium C++ ABI with vendor extended type qualifiers and types for -/// Rust types that are not used at the FFI boundary. -fn encode_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - predicates: &List>>, - dict: &mut FxHashMap, usize>, - options: EncodeTyOptions, -) -> String { - // E as part of vendor extended type - let mut s = String::new(); - let predicates: Vec>> = - predicates.iter().map(|predicate| predicate).collect(); - for predicate in predicates { - s.push_str(&encode_predicate(tcx, predicate, dict, options)); - } - s -} - -/// Encodes a region using the Itanium C++ ABI as a vendor extended type. -fn encode_region<'tcx>( - _tcx: TyCtxt<'tcx>, - region: Region<'tcx>, - dict: &mut FxHashMap, usize>, - _options: EncodeTyOptions, -) -> String { - // u6region[I[][]E] as vendor extended type - let mut s = String::new(); - match region.kind() { - RegionKind::ReLateBound(debruijn, r) => { - s.push_str("u6regionI"); - // Debruijn index, which identifies the binder, as region disambiguator - let num = debruijn.index() as u64; - if num > 0 { - s.push_str(&to_disambiguator(num)); - } - // Index within the binder - let _ = write!(s, "{}", r.var.index() as u64); - s.push('E'); - compress(dict, DictKey::Region(region), &mut s); - } - RegionKind::ReErased => { - s.push_str("u6region"); - compress(dict, DictKey::Region(region), &mut s); - } - RegionKind::ReEarlyBound(..) - | RegionKind::ReFree(..) - | RegionKind::ReStatic - | RegionKind::ReVar(..) - | RegionKind::RePlaceholder(..) - | RegionKind::ReEmpty(..) => { - bug!("encode_region: unexpected `{:?}`", region.kind()); - } - } - s -} - -/// Encodes substs using the Itanium C++ ABI with vendor extended type qualifiers and types for Rust -/// types that are not used at the FFI boundary. -fn encode_substs<'tcx>( - tcx: TyCtxt<'tcx>, - substs: SubstsRef<'tcx>, - dict: &mut FxHashMap, usize>, - options: EncodeTyOptions, -) -> String { - // [IE] as part of vendor extended type - let mut s = String::new(); - let substs: Vec> = substs.iter().map(|subst| subst).collect(); - if !substs.is_empty() { - s.push('I'); - for subst in substs { - match subst.unpack() { - GenericArgKind::Lifetime(region) => { - s.push_str(&encode_region(tcx, region, dict, options)); - } - GenericArgKind::Type(ty) => { - s.push_str(&encode_ty(tcx, ty, dict, options)); - } - GenericArgKind::Const(c) => { - s.push_str(&encode_const(tcx, c, dict, options)); - } - } - } - s.push('E'); - } - s -} - -/// Encodes a ty:Ty name, including its crate and path disambiguators and names. -fn encode_ty_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> String { - // Encode for use in u[IE], where - // is , using v0's without v0's extended form of paths: - // - // N..N - // C - // .. - // - // With additional tags for DefPathData::Impl and DefPathData::ForeignMod. For instance: - // - // pub type Type1 = impl Send; - // let _: Type1 = >::foo; - // fn foo1(_: Type1) { } - // - // pub type Type2 = impl Send; - // let _: Type2 = >::foo; - // fn foo2(_: Type2) { } - // - // pub type Type3 = impl Send; - // let _: Type3 = >::foo; - // fn foo3(_: Type3) { } - // - // pub type Type4 = impl Send; - // let _: Type4 = as Trait1>::foo; - // fn foo3(_: Type4) { } - // - // Are encoded as: - // - // _ZTSFvu29NvNIC1234_5crate8{{impl}}3fooIu3i32EE - // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3dynIu21NtC1234_5crate6Trait1Iu3i32Eu6regionES_EE - // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3i32S_EE - // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu22NtC1234_5crate7Struct1Iu3i32ES_EE - // - // The reason for not using v0's extended form of paths is to use a consistent and simpler - // encoding, as the reasoning for using it isn't relevand for type metadata identifiers (i.e., - // keep symbol names close to how methods are represented in error messages). See - // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html#methods. - let mut s = String::new(); - - // Start and namespace tags - let mut def_path = tcx.def_path(def_id); - def_path.data.reverse(); - for disambiguated_data in &def_path.data { - s.push('N'); - s.push_str(match disambiguated_data.data { - hir::definitions::DefPathData::Impl => "I", // Not specified in v0's - hir::definitions::DefPathData::ForeignMod => "F", // Not specified in v0's - hir::definitions::DefPathData::TypeNs(..) => "t", - hir::definitions::DefPathData::ValueNs(..) => "v", - hir::definitions::DefPathData::ClosureExpr => "C", - hir::definitions::DefPathData::Ctor => "c", - hir::definitions::DefPathData::AnonConst => "k", - hir::definitions::DefPathData::ImplTrait => "i", - hir::definitions::DefPathData::CrateRoot - | hir::definitions::DefPathData::Use - | hir::definitions::DefPathData::GlobalAsm - | hir::definitions::DefPathData::MacroNs(..) - | hir::definitions::DefPathData::LifetimeNs(..) => { - bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data); - } - }); - } - - // Crate disambiguator and name - s.push('C'); - s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).to_u64())); - let crate_name = tcx.crate_name(def_path.krate).to_string(); - let _ = write!(s, "{}{}", crate_name.len(), &crate_name); - - // Disambiguators and names - def_path.data.reverse(); - for disambiguated_data in &def_path.data { - let num = disambiguated_data.disambiguator as u64; - if num > 0 { - s.push_str(&to_disambiguator(num)); - } - - let name = disambiguated_data.data.to_string(); - let _ = write!(s, "{}", name.len()); - - // Prepend a '_' if name starts with a digit or '_' - if let Some(first) = name.as_bytes().get(0) { - if first.is_ascii_digit() || *first == b'_' { - s.push('_'); - } - } else { - bug!("encode_ty_name: invalid name `{:?}`", name); - } - - s.push_str(&name); - } - - s -} - -/// Encodes a ty:Ty using the Itanium C++ ABI with vendor extended type qualifiers and types for -/// Rust types that are not used at the FFI boundary. -fn encode_ty<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - dict: &mut FxHashMap, usize>, - options: EncodeTyOptions, -) -> String { - let mut typeid = String::new(); - - match ty.kind() { - // Primitive types - ty::Bool => { - typeid.push('b'); - } - - ty::Int(..) | ty::Uint(..) | ty::Float(..) => { - // u as vendor extended type - let mut s = String::from(match ty.kind() { - ty::Int(IntTy::I8) => "u2i8", - ty::Int(IntTy::I16) => "u3i16", - ty::Int(IntTy::I32) => "u3i32", - ty::Int(IntTy::I64) => "u3i64", - ty::Int(IntTy::I128) => "u4i128", - ty::Int(IntTy::Isize) => "u5isize", - ty::Uint(UintTy::U8) => "u2u8", - ty::Uint(UintTy::U16) => "u3u16", - ty::Uint(UintTy::U32) => "u3u32", - ty::Uint(UintTy::U64) => "u3u64", - ty::Uint(UintTy::U128) => "u4u128", - ty::Uint(UintTy::Usize) => "u5usize", - ty::Float(FloatTy::F32) => "u3f32", - ty::Float(FloatTy::F64) => "u3f64", - _ => "", - }); - compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); - typeid.push_str(&s); - } - - ty::Char => { - // u4char as vendor extended type - let mut s = String::from("u4char"); - compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); - typeid.push_str(&s); - } - - ty::Str => { - // u3str as vendor extended type - let mut s = String::from("u3str"); - compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); - typeid.push_str(&s); - } - - ty::Never => { - // u5never as vendor extended type - let mut s = String::from("u5never"); - compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); - typeid.push_str(&s); - } - - // Compound types - // () in Rust is equivalent to void return type in C - _ if ty.is_unit() => { - typeid.push('v'); - } - - // Sequence types - ty::Tuple(tys) => { - // u5tupleIE as vendor extended type - let mut s = String::from("u5tupleI"); - for ty in tys.iter() { - s.push_str(&encode_ty(tcx, ty, dict, options)); - } - s.push('E'); - compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); - typeid.push_str(&s); - } - - ty::Array(ty0, len) => { - // A - let mut s = String::from("A"); - let _ = write!(s, "{}", &len.kind().try_to_scalar().unwrap().to_u64().unwrap()); - s.push_str(&encode_ty(tcx, *ty0, dict, options)); - compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); - typeid.push_str(&s); - } - - ty::Slice(ty0) => { - // u5sliceIE as vendor extended type - let mut s = String::from("u5sliceI"); - s.push_str(&encode_ty(tcx, *ty0, dict, options)); - s.push('E'); - compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); - typeid.push_str(&s); - } - - // User-defined types - ty::Adt(adt_def, substs) => { - let mut s = String::new(); - let def_id = adt_def.0.did; - if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() { - // For for cross-language CFI support, the encoding must be compatible at the FFI - // boundary. For instance: - // - // struct type1 {}; - // void foo(struct type1* bar) {} - // - // Is encoded as: - // - // _ZTSFvP5type1E - // - // So, encode any repr(C) user-defined type for extern function types with the "C" - // calling convention (or extern types [i.e., ty::Foreign]) as , where - // is . - let name = tcx.item_name(def_id).to_string(); - let _ = write!(s, "{}{}", name.len(), &name); - compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); - } else { - // u[IE], where is - // , as vendor extended type. - let name = encode_ty_name(tcx, def_id); - let _ = write!(s, "u{}{}", name.len(), &name); - s.push_str(&encode_substs(tcx, substs, dict, options)); - compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); - } - typeid.push_str(&s); - } - - ty::Foreign(def_id) => { - // , where is - let mut s = String::new(); - let name = tcx.item_name(*def_id).to_string(); - let _ = write!(s, "{}{}", name.len(), &name); - compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); - typeid.push_str(&s); - } - - // Function types - ty::FnDef(def_id, substs) - | ty::Closure(def_id, substs) - | ty::Generator(def_id, substs, ..) => { - // u[IE], where is , - // as vendor extended type. - let mut s = String::new(); - let name = encode_ty_name(tcx, *def_id); - let _ = write!(s, "u{}{}", name.len(), &name); - s.push_str(&encode_substs(tcx, substs, dict, options)); - compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); - typeid.push_str(&s); - } - - // Pointer types - ty::Ref(region, ty0, ..) => { - // [U3mut]u3refIE as vendor extended type qualifier and type - let mut s = String::new(); - s.push_str("u3refI"); - s.push_str(&encode_ty(tcx, *ty0, dict, options)); - s.push('E'); - compress(dict, DictKey::Ty(tcx.mk_imm_ref(*region, *ty0), TyQ::None), &mut s); - if ty.is_mutable_ptr() { - s = format!("{}{}", "U3mut", &s); - compress(dict, DictKey::Ty(ty, TyQ::Mut), &mut s); - } - typeid.push_str(&s); - } - - ty::RawPtr(tm) => { - // P[K] - let mut s = String::new(); - s.push_str(&encode_ty(tcx, tm.ty, dict, options)); - if !ty.is_mutable_ptr() { - s = format!("{}{}", "K", &s); - compress(dict, DictKey::Ty(tm.ty, TyQ::Const), &mut s); - }; - s = format!("{}{}", "P", &s); - compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); - typeid.push_str(&s); - } - - ty::FnPtr(fn_sig) => { - // PFE - let mut s = String::from("P"); - s.push_str(&encode_fnsig(tcx, &fn_sig.skip_binder(), dict, TypeIdOptions::NO_OPTIONS)); - compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); - typeid.push_str(&s); - } - - // Trait types - ty::Dynamic(predicates, region) => { - // u3dynIE, where is , as - // vendor extended type. - let mut s = String::from("u3dynI"); - s.push_str(&encode_predicates(tcx, predicates, dict, options)); - s.push_str(&encode_region(tcx, *region, dict, options)); - s.push('E'); - compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); - typeid.push_str(&s); - } - - // Unexpected types - ty::Bound(..) - | ty::Error(..) - | ty::GeneratorWitness(..) - | ty::Infer(..) - | ty::Opaque(..) - | ty::Param(..) - | ty::Placeholder(..) - | ty::Projection(..) => { - bug!("encode_ty: unexpected `{:?}`", ty.kind()); - } - }; - - typeid -} - -// Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all -// c_void types into unit types unconditionally, and generalizes all pointers if -// TransformTyOptions::GENERALIZE_POINTERS option is set. -fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptions) -> Ty<'tcx> { - let mut ty = ty; - - match ty.kind() { - ty::Bool - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Char - | ty::Str - | ty::Never - | ty::Foreign(..) - | ty::Dynamic(..) => {} - - _ if ty.is_unit() => {} - - ty::Tuple(tys) => { - ty = tcx.mk_tup(tys.iter().map(|ty| transform_ty(tcx, ty, options))); - } - - ty::Array(ty0, len) => { - let len = len.kind().try_to_scalar().unwrap().to_u64().unwrap(); - ty = tcx.mk_array(transform_ty(tcx, *ty0, options), len); - } - - ty::Slice(ty0) => { - ty = tcx.mk_slice(transform_ty(tcx, *ty0, options)); - } - - ty::Adt(adt_def, substs) => { - if is_c_void_ty(tcx, ty) { - ty = tcx.mk_unit(); - } else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() - { - ty = tcx.mk_adt(*adt_def, ty::List::empty()); - } else if adt_def.repr().transparent() && adt_def.is_struct() { - let variant = adt_def.non_enum_variant(); - let param_env = tcx.param_env(variant.def_id); - let field = variant.fields.iter().find(|field| { - let ty = tcx.type_of(field.did); - let is_zst = - tcx.layout_of(param_env.and(ty)).map_or(false, |layout| layout.is_zst()); - !is_zst - }); - if field.is_none() { - // Transform repr(transparent) types without non-ZST field into () - ty = tcx.mk_unit(); - } else { - let ty0 = tcx.type_of(field.unwrap().did); - // Generalize any repr(transparent) user-defined type that is either a pointer - // or reference, and either references itself or any other type that contains or - // references itself, to avoid a reference cycle. - if ty0.is_any_ptr() && ty0.contains(ty) { - ty = transform_ty( - tcx, - ty0, - options | TransformTyOptions::GENERALIZE_POINTERS, - ); - } else { - ty = transform_ty(tcx, ty0, options); - } - } - } else { - ty = tcx.mk_adt(*adt_def, transform_substs(tcx, substs, options)); - } - } - - ty::FnDef(def_id, substs) => { - ty = tcx.mk_fn_def(*def_id, transform_substs(tcx, substs, options)); - } - - ty::Closure(def_id, substs) => { - ty = tcx.mk_closure(*def_id, transform_substs(tcx, substs, options)); - } - - ty::Generator(def_id, substs, movability) => { - ty = tcx.mk_generator(*def_id, transform_substs(tcx, substs, options), *movability); - } - - ty::Ref(region, ty0, ..) => { - if options.contains(TransformTyOptions::GENERALIZE_POINTERS) { - if ty.is_mutable_ptr() { - ty = tcx.mk_mut_ref(tcx.lifetimes.re_static, tcx.mk_unit()); - } else { - ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_unit()); - } - } else { - if ty.is_mutable_ptr() { - ty = tcx.mk_mut_ref(*region, transform_ty(tcx, *ty0, options)); - } else { - ty = tcx.mk_imm_ref(*region, transform_ty(tcx, *ty0, options)); - } - } - } - - ty::RawPtr(tm) => { - if options.contains(TransformTyOptions::GENERALIZE_POINTERS) { - if ty.is_mutable_ptr() { - ty = tcx.mk_mut_ptr(tcx.mk_unit()); - } else { - ty = tcx.mk_imm_ptr(tcx.mk_unit()); - } - } else { - if ty.is_mutable_ptr() { - ty = tcx.mk_mut_ptr(transform_ty(tcx, tm.ty, options)); - } else { - ty = tcx.mk_imm_ptr(transform_ty(tcx, tm.ty, options)); - } - } - } - - ty::FnPtr(fn_sig) => { - if options.contains(TransformTyOptions::GENERALIZE_POINTERS) { - ty = tcx.mk_imm_ptr(tcx.mk_unit()); - } else { - let parameters: Vec> = fn_sig - .skip_binder() - .inputs() - .iter() - .map(|ty| transform_ty(tcx, *ty, options)) - .collect(); - let output = transform_ty(tcx, fn_sig.skip_binder().output(), options); - ty = tcx.mk_fn_ptr(ty::Binder::bind_with_vars( - tcx.mk_fn_sig( - parameters.iter(), - &output, - fn_sig.c_variadic(), - fn_sig.unsafety(), - fn_sig.abi(), - ), - fn_sig.bound_vars(), - )); - } - } - - ty::Bound(..) - | ty::Error(..) - | ty::GeneratorWitness(..) - | ty::Infer(..) - | ty::Opaque(..) - | ty::Param(..) - | ty::Placeholder(..) - | ty::Projection(..) => { - bug!("transform_ty: unexpected `{:?}`", ty.kind()); - } - } - - ty -} - -/// Transforms substs for being encoded and used in the substitution dictionary. -fn transform_substs<'tcx>( - tcx: TyCtxt<'tcx>, - substs: SubstsRef<'tcx>, - options: TransformTyOptions, -) -> SubstsRef<'tcx> { - let substs: Vec> = substs - .iter() - .map(|subst| { - if let GenericArgKind::Type(ty) = subst.unpack() { - if is_c_void_ty(tcx, ty) { - tcx.mk_unit().into() - } else { - transform_ty(tcx, ty, options).into() - } - } else { - subst - } - }) - .collect(); - tcx.mk_substs(substs.iter()) -} - -/// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor -/// extended type qualifiers and types for Rust types that are not used at the FFI boundary. -pub fn typeid_for_fnabi<'tcx>( - tcx: TyCtxt<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - options: TypeIdOptions, -) -> String { - // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions - // its type. - let mut typeid = String::from("_Z"); - - // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type - // metadata identifiers for function pointers. The typeinfo name encoding is a two-character - // code (i.e., 'TS') prefixed to the type encoding for the function. - typeid.push_str("TS"); - - // Function types are delimited by an "F..E" pair - typeid.push('F'); - - // A dictionary of substitution candidates used for compression (see - // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression). - let mut dict: FxHashMap, usize> = FxHashMap::default(); - - let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits()) - .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits())); - match fn_abi.conv { - Conv::C => { - encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C); - } - _ => { - encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C); - } - } - - // Encode the return type - let transform_ty_options = TransformTyOptions::from_bits(options.bits()) - .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits())); - let ty = transform_ty(tcx, fn_abi.ret.layout.ty, transform_ty_options); - typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); - - // Encode the parameter types - if !fn_abi.c_variadic { - if !fn_abi.args.is_empty() { - for arg in fn_abi.args.iter() { - let ty = transform_ty(tcx, arg.layout.ty, transform_ty_options); - typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); - } - } else { - // Empty parameter lists, whether declared as () or conventionally as (void), are - // encoded with a void parameter specifier "v". - typeid.push('v'); - } - } else { - for n in 0..fn_abi.fixed_count { - let ty = transform_ty(tcx, fn_abi.args[n].layout.ty, transform_ty_options); - typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); - } - - typeid.push('z'); - } - - // Close the "F..E" pair - typeid.push('E'); - - typeid -} - -/// Returns a type metadata identifier for the specified FnSig using the Itanium C++ ABI with vendor -/// extended type qualifiers and types for Rust types that are not used at the FFI boundary. -pub fn typeid_for_fnsig<'tcx>( - tcx: TyCtxt<'tcx>, - fn_sig: &FnSig<'tcx>, - options: TypeIdOptions, -) -> String { - // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions - // its type. - let mut typeid = String::from("_Z"); - - // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type - // metadata identifiers for function pointers. The typeinfo name encoding is a two-character - // code (i.e., 'TS') prefixed to the type encoding for the function. - typeid.push_str("TS"); - - // A dictionary of substitution candidates used for compression (see - // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression). - let mut dict: FxHashMap, usize> = FxHashMap::default(); - - // Encode the function signature - typeid.push_str(&encode_fnsig(tcx, fn_sig, &mut dict, options)); - - typeid -} diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 71fa5a4488708..13229a3995c22 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -12,6 +12,7 @@ use rustc_middle::ty::{ self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeVisitable, UintTy, }; use rustc_span::symbol::kw; +use rustc_target::abi::call::FnAbi; use rustc_target::abi::Integer; use rustc_target::spec::abi::Abi; @@ -41,7 +42,7 @@ pub(super) fn mangle<'tcx>( // Append `::{shim:...#0}` to shims that can coexist with a non-shim instance. let shim_kind = match instance.def { - ty::InstanceDef::VTableShim(_) => Some("vtable"), + ty::InstanceDef::VtableShim(_) => Some("vtable"), ty::InstanceDef::ReifyShim(_) => Some("reify"), _ => None, @@ -58,6 +59,41 @@ pub(super) fn mangle<'tcx>( std::mem::take(&mut cx.out) } +pub(super) fn mangle_typeid_for_fnabi<'tcx>( + _tcx: TyCtxt<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, +) -> String { + // LLVM uses type metadata to allow IR modules to aggregate pointers by their types.[1] This + // type metadata is used by LLVM Control Flow Integrity to test whether a given pointer is + // associated with a type identifier (i.e., test type membership). + // + // Clang uses the Itanium C++ ABI's[2] virtual tables and RTTI typeinfo structure name[3] as + // type metadata identifiers for function pointers. The typeinfo name encoding is a + // two-character code (i.e., “TS”) prefixed to the type encoding for the function. + // + // For cross-language LLVM CFI support, a compatible encoding must be used by either + // + // a. Using a superset of types that encompasses types used by Clang (i.e., Itanium C++ ABI's + // type encodings[4]), or at least types used at the FFI boundary. + // b. Reducing the types to the least common denominator between types used by Clang (or at + // least types used at the FFI boundary) and Rust compilers (if even possible). + // c. Creating a new ABI for cross-language CFI and using it for Clang and Rust compilers (and + // possibly other compilers). + // + // Option (b) may weaken the protection for Rust-compiled only code, so it should be provided + // as an alternative to a Rust-specific encoding for when mixing Rust and C and C++ -compiled + // code. Option (c) would require changes to Clang to use the new ABI. + // + // [1] https://llvm.org/docs/TypeMetadata.html + // [2] https://itanium-cxx-abi.github.io/cxx-abi/abi.html + // [3] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-special-vtables + // [4] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-type + // + // FIXME(rcvalle): See comment above. + let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize; + format!("typeid{}", arg_count) +} + pub(super) fn mangle_typeid_for_trait_ref<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyExistentialTraitRef<'tcx>, diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index b35502d9ee42b..6f4d073d70486 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -1350,19 +1350,15 @@ impl<'a, Ty> Deref for TyAndLayout<'a, Ty> { #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum PointerKind { /// Most general case, we know no restrictions to tell LLVM. - SharedMutable, + Shared, - /// `&T` where `T` contains no `UnsafeCell`, is `dereferenceable`, `noalias` and `readonly`. + /// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`. Frozen, - /// `&mut T` which is `dereferenceable` and `noalias` but not `readonly`. + /// `&mut T` which is `noalias` but not `readonly`. UniqueBorrowed, - /// `&mut !Unpin`, which is `dereferenceable` but neither `noalias` nor `readonly`. - UniqueBorrowedPinned, - - /// `Box`, which is `noalias` (even on return types, unlike the above) but neither `readonly` - /// nor `dereferenceable`. + /// `Box`, unlike `UniqueBorrowed`, it also has `noalias` on returns. UniqueOwned, } diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs index 62a0f9fb03470..25842049413bd 100644 --- a/compiler/rustc_target/src/asm/aarch64.rs +++ b/compiler/rustc_target/src/asm/aarch64.rs @@ -1,6 +1,6 @@ use super::{InlineAsmArch, InlineAsmType}; use crate::spec::{RelocModel, Target}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs index 0db3eb6fcac0c..aaa632333db38 100644 --- a/compiler/rustc_target/src/asm/arm.rs +++ b/compiler/rustc_target/src/asm/arm.rs @@ -1,6 +1,6 @@ use super::{InlineAsmArch, InlineAsmType}; use crate::spec::{RelocModel, Target}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_macros::HashStable_Generic; use rustc_span::{sym, Symbol}; use std::fmt; diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs index e41bdc9a58c8a..987bf97052933 100644 --- a/compiler/rustc_target/src/asm/riscv.rs +++ b/compiler/rustc_target/src/asm/riscv.rs @@ -1,6 +1,6 @@ use super::{InlineAsmArch, InlineAsmType}; use crate::spec::{RelocModel, Target}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_macros::HashStable_Generic; use rustc_span::{sym, Symbol}; use std::fmt; diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs index 238c365093f08..e35035fd25af6 100644 --- a/compiler/rustc_target/src/asm/x86.rs +++ b/compiler/rustc_target/src/asm/x86.rs @@ -1,6 +1,6 @@ use super::{InlineAsmArch, InlineAsmType}; use crate::spec::{RelocModel, Target}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; diff --git a/compiler/rustc_target/src/spec/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/aarch64_linux_android.rs index c85f7f62a4239..5e31859aaef30 100644 --- a/compiler/rustc_target/src/spec/aarch64_linux_android.rs +++ b/compiler/rustc_target/src/spec/aarch64_linux_android.rs @@ -17,7 +17,6 @@ pub fn target() -> Target { supported_sanitizers: SanitizerSet::CFI | SanitizerSet::HWADDRESS | SanitizerSet::MEMTAG - | SanitizerSet::SHADOWCALLSTACK | SanitizerSet::ADDRESS, ..super::android_base::opts() }, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f7abeafd38f10..1a6bb4a2eaf34 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -618,7 +618,6 @@ bitflags::bitflags! { const HWADDRESS = 1 << 4; const CFI = 1 << 5; const MEMTAG = 1 << 6; - const SHADOWCALLSTACK = 1 << 7; } } @@ -633,7 +632,6 @@ impl SanitizerSet { SanitizerSet::LEAK => "leak", SanitizerSet::MEMORY => "memory", SanitizerSet::MEMTAG => "memtag", - SanitizerSet::SHADOWCALLSTACK => "shadow-call-stack", SanitizerSet::THREAD => "thread", SanitizerSet::HWADDRESS => "hwaddress", _ => return None, @@ -668,7 +666,6 @@ impl IntoIterator for SanitizerSet { SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::MEMTAG, - SanitizerSet::SHADOWCALLSTACK, SanitizerSet::THREAD, SanitizerSet::HWADDRESS, ] @@ -1963,7 +1960,6 @@ impl Target { Some("leak") => SanitizerSet::LEAK, Some("memory") => SanitizerSet::MEMORY, Some("memtag") => SanitizerSet::MEMTAG, - Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK, Some("thread") => SanitizerSet::THREAD, Some("hwaddress") => SanitizerSet::HWADDRESS, Some(s) => return Err(format!("unknown sanitizer {}", s)), diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 5763e6d1b559e..65ff9ceb67ecb 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -793,7 +793,9 @@ impl<'tcx> AutoTraitFinder<'tcx> { } ty::PredicateKind::RegionOutlives(binder) => { let binder = bound_predicate.rebind(binder); - select.infcx().region_outlives_predicate(&dummy_cause, binder) + if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() { + return false; + } } ty::PredicateKind::TypeOutlives(binder) => { let binder = bound_predicate.rebind(binder); diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index 5fcaa52d41747..c2b2e3199511e 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -30,9 +30,7 @@ pub fn codegen_fulfill_obligation<'tcx>( // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. - let mut infcx_builder = - tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble); - infcx_builder.enter(|infcx| { + tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter(|infcx| { //~^ HACK `Bubble` is required for // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs let mut selcx = SelectionContext::new(&infcx); diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index fa94aa19abda5..52ca23c4b303e 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -22,12 +22,11 @@ use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitor}; +use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; use std::fmt::Debug; use std::iter; -use std::ops::ControlFlow; /// Whether we do the orphan check relative to this crate or /// to some remote crate. @@ -579,175 +578,220 @@ fn orphan_check_trait_ref<'tcx>( ); } - let mut checker = OrphanChecker::new(tcx, in_crate); - match trait_ref.visit_with(&mut checker) { - ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)), - ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(ty)) => { - // Does there exist some local type after the `ParamTy`. - checker.search_first_local_ty = true; - if let Some(OrphanCheckEarlyExit::LocalTy(local_ty)) = - trait_ref.visit_with(&mut checker).break_value() - { - Err(OrphanCheckErr::UncoveredTy(ty, Some(local_ty))) - } else { - Err(OrphanCheckErr::UncoveredTy(ty, None)) + // Given impl Trait for T0, an impl is valid only + // if at least one of the following is true: + // + // - Trait is a local trait + // (already checked in orphan_check prior to calling this function) + // - All of + // - At least one of the types T0..=Tn must be a local type. + // Let Ti be the first such type. + // - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti) + // + fn uncover_fundamental_ty<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + in_crate: InCrate, + ) -> Vec> { + // FIXME: this is currently somewhat overly complicated, + // but fixing this requires a more complicated refactor. + if !contained_non_local_types(tcx, ty, in_crate).is_empty() { + if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) { + return inner_tys + .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) + .collect(); } } - ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(_)) => Ok(()), + + vec![ty] + } + + let mut non_local_spans = vec![]; + for (i, input_ty) in trait_ref + .substs + .types() + .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) + .enumerate() + { + debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty); + let non_local_tys = contained_non_local_types(tcx, input_ty, in_crate); + if non_local_tys.is_empty() { + debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty); + return Ok(()); + } else if let ty::Param(_) = input_ty.kind() { + debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty); + let local_type = trait_ref + .substs + .types() + .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) + .find(|&ty| ty_is_local_constructor(tcx, ty, in_crate)); + + debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type); + + return Err(OrphanCheckErr::UncoveredTy(input_ty, local_type)); + } + + non_local_spans.extend(non_local_tys.into_iter().map(|input_ty| (input_ty, i == 0))); } + // If we exit above loop, never found a local type. + debug!("orphan_check_trait_ref: no local type"); + Err(OrphanCheckErr::NonLocalInputType(non_local_spans)) } -struct OrphanChecker<'tcx> { +/// Returns a list of relevant non-local types for `ty`. +/// +/// This is just `ty` itself unless `ty` is `#[fundamental]`, +/// in which case we recursively look into this type. +/// +/// If `ty` is local itself, this method returns an empty `Vec`. +/// +/// # Examples +/// +/// - `u32` is not local, so this returns `[u32]`. +/// - for `Foo`, where `Foo` is a local type, this returns `[]`. +/// - `&mut u32` returns `[u32]`, as `&mut` is a fundamental type, similar to `Box`. +/// - `Box>` returns `[]`, as `Box` is a fundamental type and `Foo` is local. +fn contained_non_local_types<'tcx>( tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, in_crate: InCrate, - in_self_ty: bool, - /// Ignore orphan check failures and exclusively search for the first - /// local type. - search_first_local_ty: bool, - non_local_tys: Vec<(Ty<'tcx>, bool)>, -} - -impl<'tcx> OrphanChecker<'tcx> { - fn new(tcx: TyCtxt<'tcx>, in_crate: InCrate) -> Self { - OrphanChecker { - tcx, - in_crate, - in_self_ty: true, - search_first_local_ty: false, - non_local_tys: Vec::new(), +) -> Vec> { + if ty_is_local_constructor(tcx, ty, in_crate) { + Vec::new() + } else { + match fundamental_ty_inner_tys(tcx, ty) { + Some(inner_tys) => { + inner_tys.flat_map(|ty| contained_non_local_types(tcx, ty, in_crate)).collect() + } + None => vec![ty], } } +} - fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow> { - self.non_local_tys.push((t, self.in_self_ty)); - ControlFlow::CONTINUE - } +/// For `#[fundamental]` ADTs and `&T` / `&mut T`, returns `Some` with the +/// type parameters of the ADT, or `T`, respectively. For non-fundamental +/// types, returns `None`. +fn fundamental_ty_inner_tys<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Option>> { + let (first_ty, rest_tys) = match *ty.kind() { + ty::Ref(_, ty, _) => (ty, ty::subst::InternalSubsts::empty().types()), + ty::Adt(def, substs) if def.is_fundamental() => { + let mut types = substs.types(); + + // FIXME(eddyb) actually validate `#[fundamental]` up-front. + match types.next() { + None => { + tcx.sess.span_err( + tcx.def_span(def.did()), + "`#[fundamental]` requires at least one type parameter", + ); + + return None; + } - fn found_param_ty(&mut self, t: Ty<'tcx>) -> ControlFlow> { - if self.search_first_local_ty { - ControlFlow::CONTINUE - } else { - ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(t)) + Some(first_ty) => (first_ty, types), + } } - } + _ => return None, + }; - fn def_id_is_local(&mut self, def_id: DefId) -> bool { - match self.in_crate { - InCrate::Local => def_id.is_local(), - InCrate::Remote => false, - } - } + Some(iter::once(first_ty).chain(rest_tys)) } -enum OrphanCheckEarlyExit<'tcx> { - ParamTy(Ty<'tcx>), - LocalTy(Ty<'tcx>), +fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool { + match in_crate { + // The type is local to *this* crate - it will not be + // local in any other crate. + InCrate::Remote => false, + InCrate::Local => def_id.is_local(), + } } -impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { - type BreakTy = OrphanCheckEarlyExit<'tcx>; - fn visit_region(&mut self, _r: ty::Region<'tcx>) -> ControlFlow { - ControlFlow::CONTINUE - } +fn ty_is_local_constructor(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool { + debug!("ty_is_local_constructor({:?})", ty); + + match *ty.kind() { + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Str + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Array(..) + | ty::Slice(..) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::Never + | ty::Tuple(..) + | ty::Param(..) + | ty::Projection(..) => false, + + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match in_crate { + InCrate::Local => false, + // The inference variable might be unified with a local + // type in that remote crate. + InCrate::Remote => true, + }, + + ty::Adt(def, _) => def_id_is_local(def.did(), in_crate), + ty::Foreign(did) => def_id_is_local(did, in_crate), + ty::Opaque(..) => { + // This merits some explanation. + // Normally, opaque types are not involved when performing + // coherence checking, since it is illegal to directly + // implement a trait on an opaque type. However, we might + // end up looking at an opaque type during coherence checking + // if an opaque type gets used within another type (e.g. as + // a type parameter). This requires us to decide whether or + // not an opaque type should be considered 'local' or not. + // + // We choose to treat all opaque types as non-local, even + // those that appear within the same crate. This seems + // somewhat surprising at first, but makes sense when + // you consider that opaque types are supposed to hide + // the underlying type *within the same crate*. When an + // opaque type is used from outside the module + // where it is declared, it should be impossible to observe + // anything about it other than the traits that it implements. + // + // The alternative would be to look at the underlying type + // to determine whether or not the opaque type itself should + // be considered local. However, this could make it a breaking change + // to switch the underlying ('defining') type from a local type + // to a remote type. This would violate the rule that opaque + // types should be completely opaque apart from the traits + // that they implement, so we don't use this behavior. + false + } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - let result = match *ty.kind() { - ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Str - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Array(..) - | ty::Slice(..) - | ty::RawPtr(..) - | ty::Never - | ty::Tuple(..) - | ty::Projection(..) => self.found_non_local_ty(ty), - - ty::Param(..) => self.found_param_ty(ty), - - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match self.in_crate { - InCrate::Local => self.found_non_local_ty(ty), - // The inference variable might be unified with a local - // type in that remote crate. - InCrate::Remote => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), - }, - - // For fundamental types, we just look inside of them. - ty::Ref(_, ty, _) => ty.visit_with(self), - ty::Adt(def, substs) => { - if self.def_id_is_local(def.did()) { - ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) - } else if def.is_fundamental() { - substs.visit_with(self) - } else { - self.found_non_local_ty(ty) - } - } - ty::Foreign(def_id) => { - if self.def_id_is_local(def_id) { - ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) - } else { - self.found_non_local_ty(ty) - } - } - ty::Dynamic(tt, ..) => { - let principal = tt.principal().map(|p| p.def_id()); - if principal.map_or(false, |p| self.def_id_is_local(p)) { - ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) - } else { - self.found_non_local_ty(ty) - } - } - ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), - ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => { - self.tcx.sess.delay_span_bug( - DUMMY_SP, - format!("ty_is_local invoked on closure or generator: {:?}", ty), - ); - ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) - } - ty::Opaque(..) => { - // This merits some explanation. - // Normally, opaque types are not involved when performing - // coherence checking, since it is illegal to directly - // implement a trait on an opaque type. However, we might - // end up looking at an opaque type during coherence checking - // if an opaque type gets used within another type (e.g. as - // the type of a field) when checking for auto trait or `Sized` - // impls. This requires us to decide whether or not an opaque - // type should be considered 'local' or not. - // - // We choose to treat all opaque types as non-local, even - // those that appear within the same crate. This seems - // somewhat surprising at first, but makes sense when - // you consider that opaque types are supposed to hide - // the underlying type *within the same crate*. When an - // opaque type is used from outside the module - // where it is declared, it should be impossible to observe - // anything about it other than the traits that it implements. - // - // The alternative would be to look at the underlying type - // to determine whether or not the opaque type itself should - // be considered local. However, this could make it a breaking change - // to switch the underlying ('defining') type from a local type - // to a remote type. This would violate the rule that opaque - // types should be completely opaque apart from the traits - // that they implement, so we don't use this behavior. - self.found_non_local_ty(ty) + ty::Dynamic(ref tt, ..) => { + if let Some(principal) = tt.principal() { + def_id_is_local(principal.def_id(), in_crate) + } else { + false } - }; - // A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so - // the first type we visit is always the self type. - self.in_self_ty = false; - result - } + } - // FIXME: Constants should participate in orphan checking. - fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow { - ControlFlow::CONTINUE + ty::Error(_) => true, + + // These variants should never appear during coherence checking because they + // cannot be named directly. + // + // They could be indirectly used through an opaque type. While using opaque types + // in impls causes an error, this path can still be hit afterwards. + // + // See `test/ui/coherence/coherence-with-closure.rs` for an example where this + // could happens. + ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => { + tcx.sess.delay_span_bug( + DUMMY_SP, + format!("ty_is_local invoked on closure or generator: {:?}", ty), + ); + true + } } } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 254bc4ab66386..e6284b1c4ace0 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -185,12 +185,15 @@ pub fn is_const_evaluatable<'cx, 'tcx>( } let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span)); match concrete { - Err(ErrorHandled::TooGeneric) => { - Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug( - span, - format!("Missing value for constant, but no error reported?"), - ))) - } + Err(ErrorHandled::TooGeneric) => Err(if !uv.has_infer_types_or_consts() { + infcx + .tcx + .sess + .delay_span_bug(span, &format!("unexpected `TooGeneric` for {:?}", uv)); + NotConstEvaluatable::MentionsParam + } else { + NotConstEvaluatable::MentionsInfer + }), Err(ErrorHandled::Linted) => { let reported = infcx .tcx @@ -237,11 +240,8 @@ pub fn is_const_evaluatable<'cx, 'tcx>( Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() { NotConstEvaluatable::MentionsInfer - } else if uv.has_param_types_or_consts() { + } else { NotConstEvaluatable::MentionsParam - } else { - let guar = infcx.tcx.sess.delay_span_bug(span, format!("Missing value for constant, but no error reported?")); - NotConstEvaluatable::Error(guar) }), Err(ErrorHandled::Linted) => { let reported = diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 6c177f6388704..0f7dc6a1257e5 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -15,6 +15,8 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; pub trait TraitEngineExt<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> Box; + + fn new_ignoring_regions(tcx: TyCtxt<'tcx>) -> Box; } impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { @@ -25,6 +27,14 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { Box::new(FulfillmentContext::new()) } } + + fn new_ignoring_regions(tcx: TyCtxt<'tcx>) -> Box { + if tcx.sess.opts.unstable_opts.chalk { + Box::new(ChalkFulfillmentContext::new()) + } else { + Box::new(FulfillmentContext::new_ignoring_regions()) + } + } } /// Used if you want to have pleasant experience when dealing diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 25ba520ace2ba..29df771b95780 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -22,6 +22,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::GenericParam; use rustc_hir::Item; use rustc_hir::Node; +use rustc_infer::infer::error_reporting::same_type_modulo_infer; use rustc_infer::traits::TraitEngine; use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::abstract_const::NotConstEvaluatable; @@ -301,10 +302,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { span = obligation.cause.span; } } - if let ObligationCauseCode::CompareImplItemObligation { + if let ObligationCauseCode::CompareImplMethodObligation { + impl_item_def_id, + trait_item_def_id, + } + | ObligationCauseCode::CompareImplTypeObligation { impl_item_def_id, trait_item_def_id, - kind: _, } = *obligation.cause.code() { self.report_extra_impl_obligation( @@ -631,12 +635,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &format!( "expected a closure taking {} argument{}, but one taking {} argument{} was given", given.len(), - pluralize!(given.len()), + if given.len() == 1 { "" } else { "s" }, expected.len(), - pluralize!(expected.len()), + if expected.len() == 1 { "" } else { "s" }, ) ); - } else if !self.same_type_modulo_infer(given_ty, expected_ty) { + } else if !same_type_modulo_infer(given_ty, expected_ty) { // Print type mismatch let (expected_args, given_args) = self.cmp(given_ty, expected_ty); @@ -666,7 +670,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ); } else if !suggested { // Can't show anything else useful, try to find similar impls. - let impl_candidates = self.find_similar_impl_candidates(trait_predicate); + let impl_candidates = self.find_similar_impl_candidates(trait_ref); if !self.report_similar_impl_candidates( impl_candidates, trait_ref, @@ -701,7 +705,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { { let trait_ref = trait_pred.to_poly_trait_ref(); let impl_candidates = - self.find_similar_impl_candidates(trait_pred); + self.find_similar_impl_candidates(trait_ref); self.report_similar_impl_candidates( impl_candidates, trait_ref, @@ -785,9 +789,24 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate) } - ty::PredicateKind::RegionOutlives(..) - | ty::PredicateKind::Projection(..) - | ty::PredicateKind::TypeOutlives(..) => { + ty::PredicateKind::RegionOutlives(predicate) => { + let predicate = bound_predicate.rebind(predicate); + let predicate = self.resolve_vars_if_possible(predicate); + let err = self + .region_outlives_predicate(&obligation.cause, predicate) + .err() + .unwrap(); + struct_span_err!( + self.tcx.sess, + span, + E0279, + "the requirement `{}` is not satisfied (`{}`)", + predicate, + err, + ) + } + + ty::PredicateKind::Projection(..) | ty::PredicateKind::TypeOutlives(..) => { let predicate = self.resolve_vars_if_possible(obligation.predicate); struct_span_err!( self.tcx.sess, @@ -1325,7 +1344,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> { fn find_similar_impl_candidates( &self, - trait_pred: ty::PolyTraitPredicate<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, ) -> Vec>; fn report_similar_impl_candidates( @@ -1694,22 +1713,18 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { fn find_similar_impl_candidates( &self, - trait_pred: ty::PolyTraitPredicate<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, ) -> Vec> { self.tcx - .all_impls(trait_pred.def_id()) + .all_impls(trait_ref.def_id()) .filter_map(|def_id| { - if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative - || !trait_pred - .skip_binder() - .is_constness_satisfied_by(self.tcx.constness(def_id)) - { + if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative { return None; } let imp = self.tcx.impl_trait_ref(def_id).unwrap(); - self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false) + self.fuzzy_match_tys(trait_ref.skip_binder().self_ty(), imp.self_ty(), false) .map(|similarity| ImplCandidate { trait_ref: imp, similarity }) }) .collect() diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 6c8faed0df486..bca80e7ab8abf 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -184,7 +184,7 @@ pub trait InferCtxtExt<'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool; - fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option; + fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option; fn suggest_fn_call( &self, @@ -378,7 +378,7 @@ fn suggest_restriction<'tcx>( replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name)) .to_ty(tcx), }); - if !trait_pred.is_suggestable(tcx, false) { + if !trait_pred.is_suggestable(tcx) { return; } // We know we have an `impl Trait` that doesn't satisfy a required projection. @@ -417,7 +417,7 @@ fn suggest_restriction<'tcx>( Applicability::MaybeIncorrect, ); } else { - if !trait_pred.is_suggestable(tcx, false) { + if !trait_pred.is_suggestable(tcx) { return; } // Trivial case: `T` needs an extra bound: `T: Bound`. @@ -586,7 +586,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // else in the predicate. if !trait_pred.skip_binder().trait_ref.substs[1..] .iter() - .all(|g| g.is_suggestable(self.tcx, false)) + .all(|g| g.is_suggestable(self.tcx)) { return; } @@ -607,10 +607,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { "{}, {}={}>", &constraint[..constraint.len() - 1], item.name, - term + term.to_string() ); } else { - constraint.push_str(&format!("<{}={}>", item.name, term)); + constraint.push_str(&format!("<{}={}>", item.name, term.to_string())); } } @@ -737,13 +737,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// Given a closure's `DefId`, return the given name of the closure. /// /// This doesn't account for reassignments, but it's only used for suggestions. - fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option { - let get_name = |err: &mut Diagnostic, kind: &hir::PatKind<'_>| -> Option { + fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option { + let get_name = |err: &mut Diagnostic, kind: &hir::PatKind<'_>| -> Option { // Get the local name of this closure. This can be inaccurate because // of the possibility of reassignment, but this should be good enough. match &kind { - hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, None) => { - Some(ident.name) + hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => { + Some(format!("{}", name)) } _ => { err.note(msg); @@ -2682,11 +2682,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) }); } - ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => { + ObligationCauseCode::CompareImplMethodObligation { trait_item_def_id, .. } => { let item_name = self.tcx.item_name(trait_item_def_id); let msg = format!( - "the requirement `{}` appears on the `impl`'s {kind} `{}` but not on the \ - corresponding trait's {kind}", + "the requirement `{}` appears on the impl method `{}` but not on the \ + corresponding trait method", predicate, item_name, ); let sp = self @@ -2697,7 +2697,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let mut assoc_span: MultiSpan = sp.into(); assoc_span.push_span_label( sp, - format!("this trait's {kind} doesn't have the requirement `{}`", predicate), + format!("this trait method doesn't have the requirement `{}`", predicate), ); if let Some(ident) = self .tcx @@ -2708,6 +2708,38 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } err.span_note(assoc_span, &msg); } + ObligationCauseCode::CompareImplTypeObligation { trait_item_def_id, .. } => { + let item_name = self.tcx.item_name(trait_item_def_id); + let msg = format!( + "the requirement `{}` appears on the associated impl type `{}` but not on the \ + corresponding associated trait type", + predicate, item_name, + ); + let sp = self.tcx.def_span(trait_item_def_id); + let mut assoc_span: MultiSpan = sp.into(); + assoc_span.push_span_label( + sp, + format!( + "this trait associated type doesn't have the requirement `{}`", + predicate, + ), + ); + if let Some(ident) = self + .tcx + .opt_associated_item(trait_item_def_id) + .and_then(|i| self.tcx.opt_item_ident(i.container.id())) + { + assoc_span.push_span_label(ident.span, "in this trait"); + } + err.span_note(assoc_span, &msg); + } + ObligationCauseCode::CompareImplConstObligation => { + err.note(&format!( + "the requirement `{}` appears on the associated impl constant \ + but not on the corresponding associated trait constant", + predicate + )); + } ObligationCauseCode::TrivialBound => { err.help("see issue #48214"); if tcx.sess.opts.unstable_features.is_nightly_build() { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 556ef466cd11a..34b37c4e41028 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -58,6 +58,19 @@ pub struct FulfillmentContext<'tcx> { relationships: FxHashMap, + // Should this fulfillment context register type-lives-for-region + // obligations on its parent infcx? In some cases, region + // obligations are either already known to hold (normalization) or + // hopefully verified elsewhere (type-impls-bound), and therefore + // should not be checked. + // + // Note that if we are normalizing a type that we already + // know is well-formed, there should be no harm setting this + // to true - all the region variables should be determinable + // using the RFC 447 rules, which don't depend on + // type-lives-for-region constraints, and because the type + // is well-formed, the constraints should hold. + register_region_obligations: bool, // Is it OK to register obligations into this infcx inside // an infcx snapshot? // @@ -90,6 +103,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), relationships: FxHashMap::default(), + register_region_obligations: true, usable_in_snapshot: false, } } @@ -98,18 +112,30 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), relationships: FxHashMap::default(), + register_region_obligations: true, usable_in_snapshot: true, } } + pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> { + FulfillmentContext { + predicates: ObligationForest::new(), + relationships: FxHashMap::default(), + register_region_obligations: false, + usable_in_snapshot: false, + } + } + /// Attempts to select obligations using `selcx`. fn select(&mut self, selcx: &mut SelectionContext<'a, 'tcx>) -> Vec> { let span = debug_span!("select", obligation_forest_size = ?self.predicates.len()); let _enter = span.enter(); // Process pending obligations. - let outcome: Outcome<_, _> = - self.predicates.process_obligations(&mut FulfillProcessor { selcx }); + let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut FulfillProcessor { + selcx, + register_region_obligations: self.register_region_obligations, + }); // FIXME: if we kept the original cache key, we could mark projection // obligations as complete for the projection cache here. @@ -213,6 +239,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { struct FulfillProcessor<'a, 'b, 'tcx> { selcx: &'a mut SelectionContext<'b, 'tcx>, + register_region_obligations: bool, } fn mk_pending(os: Vec>) -> Vec> { @@ -358,16 +385,19 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } ty::PredicateKind::RegionOutlives(data) => { - if infcx.considering_regions || data.has_placeholders() { - infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)); + match infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)) { + Ok(()) => ProcessResult::Changed(vec![]), + Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)), } - - ProcessResult::Changed(vec![]) } ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t_a, r_b)) => { - if infcx.considering_regions { - infcx.register_region_obligation_with_cause(t_a, r_b, &obligation.cause); + if self.register_region_obligations { + self.selcx.infcx().register_region_obligation_with_cause( + t_a, + r_b, + &obligation.cause, + ); } ProcessResult::Changed(vec![]) } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index d0a17f712d3df..a14bf72242bed 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -60,9 +60,8 @@ pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError pub use self::specialize::specialization_graph::FutureCompatOverlapError; pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; -pub use self::structural_match::{ - search_for_adt_const_param_violation, search_for_structural_match_violation, -}; +pub use self::structural_match::search_for_structural_match_violation; +pub use self::structural_match::{NonStructuralMatchTy, NonStructuralMatchTyKind}; pub use self::util::{ elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span, elaborate_trait_ref, elaborate_trait_refs, @@ -164,7 +163,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( // The handling of regions in this area of the code is terrible, // see issue #29149. We should be able to improve on this with // NLL. - let mut fulfill_cx = FulfillmentContext::new(); + let mut fulfill_cx = FulfillmentContext::new_ignoring_regions(); // We can use a dummy node-id here because we won't pay any mind // to region obligations that arise (there shouldn't really be any @@ -208,21 +207,21 @@ fn do_normalize_predicates<'tcx>( predicates: Vec>, ) -> Result>, ErrorGuaranteed> { let span = cause.span; - // FIXME. We should really... do something with these region - // obligations. But this call just continues the older - // behavior (i.e., doesn't cause any new bugs), and it would - // take some further refactoring to actually solve them. In - // particular, we would have to handle implied bounds - // properly, and that code is currently largely confined to - // regionck (though I made some efforts to extract it - // out). -nmatsakis - // - // @arielby: In any case, these obligations are checked - // by wfcheck anyway, so I'm not sure we have to check - // them here too, and we will remove this function when - // we move over to lazy normalization *anyway*. - tcx.infer_ctxt().ignoring_regions().enter(|infcx| { - let fulfill_cx = FulfillmentContext::new(); + tcx.infer_ctxt().enter(|infcx| { + // FIXME. We should really... do something with these region + // obligations. But this call just continues the older + // behavior (i.e., doesn't cause any new bugs), and it would + // take some further refactoring to actually solve them. In + // particular, we would have to handle implied bounds + // properly, and that code is currently largely confined to + // regionck (though I made some efforts to extract it + // out). -nmatsakis + // + // @arielby: In any case, these obligations are checked + // by wfcheck anyway, so I'm not sure we have to check + // them here too, and we will remove this function when + // we move over to lazy normalization *anyway*. + let fulfill_cx = FulfillmentContext::new_ignoring_regions(); let predicates = match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, predicates) { Ok(predicates) => predicates, diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs index 4d3b0b4cf077c..ed7d16f7a5419 100644 --- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs @@ -337,7 +337,7 @@ impl<'tcx> OnUnimplementedFormatString { } } // `{:1}` and `{}` are not to be used - Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => { + Position::ArgumentIs(_) | Position::ArgumentImplicitlyIs(_) => { let reported = struct_span_err!( tcx.sess, span, diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs index 8148e2b787196..56bdeafeecae4 100644 --- a/compiler/rustc_trait_selection/src/traits/relationships.rs +++ b/compiler/rustc_trait_selection/src/traits/relationships.rs @@ -31,14 +31,14 @@ pub(crate) fn update<'tcx, T>( obligation .predicate .kind() - .rebind( + .map_bound(|_| { // (*) binder moved here ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: tpred.constness, polarity: tpred.polarity, }) - ) + }) .to_predicate(infcx.tcx), ); // Don't report overflow errors. Otherwise equivalent to may_hold. diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index d4c9fd1c5f9cd..da8ca6e574916 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -42,96 +42,115 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, candidate: SelectionCandidate<'tcx>, ) -> Result, SelectionError<'tcx>> { - let mut impl_src = match candidate { + let mut obligation = obligation; + let new_obligation; + + // HACK(const_trait_impl): the surrounding environment is remapped to a non-const context + // because nested obligations might be actually `~const` then (incorrectly) requiring + // const impls. for example: + // ``` + // pub trait Super {} + // pub trait Sub: Super {} + // + // impl const Super for &A where A: ~const Super {} + // impl const Sub for &A where A: ~const Sub {} + // ``` + // + // The procedure to check the code above without the remapping code is as follows: + // ``` + // CheckWf(impl const Sub for &A where A: ~const Sub) // <- const env + // CheckPredicate(&A: Super) + // CheckPredicate(A: ~const Super) // <- still const env, failure + // ``` + if obligation.param_env.is_const() && !obligation.predicate.is_const_if_const() { + new_obligation = TraitObligation { + cause: obligation.cause.clone(), + param_env: obligation.param_env.without_const(), + ..*obligation + }; + obligation = &new_obligation; + } + + match candidate { BuiltinCandidate { has_nested } => { let data = self.confirm_builtin_candidate(obligation, has_nested); - ImplSource::Builtin(data) + Ok(ImplSource::Builtin(data)) } ParamCandidate(param) => { let obligations = self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref)); - ImplSource::Param(obligations, param.skip_binder().constness) + Ok(ImplSource::Param(obligations, param.skip_binder().constness)) } ImplCandidate(impl_def_id) => { - ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id)) + Ok(ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id))) } AutoImplCandidate(trait_def_id) => { let data = self.confirm_auto_impl_candidate(obligation, trait_def_id); - ImplSource::AutoImpl(data) + Ok(ImplSource::AutoImpl(data)) } ProjectionCandidate(idx) => { let obligations = self.confirm_projection_candidate(obligation, idx)?; // FIXME(jschievink): constness - ImplSource::Param(obligations, ty::BoundConstness::NotConst) + Ok(ImplSource::Param(obligations, ty::BoundConstness::NotConst)) } ObjectCandidate(idx) => { let data = self.confirm_object_candidate(obligation, idx)?; - ImplSource::Object(data) + Ok(ImplSource::Object(data)) } ClosureCandidate => { let vtable_closure = self.confirm_closure_candidate(obligation)?; - ImplSource::Closure(vtable_closure) + Ok(ImplSource::Closure(vtable_closure)) } GeneratorCandidate => { let vtable_generator = self.confirm_generator_candidate(obligation)?; - ImplSource::Generator(vtable_generator) + Ok(ImplSource::Generator(vtable_generator)) } FnPointerCandidate { .. } => { let data = self.confirm_fn_pointer_candidate(obligation)?; - ImplSource::FnPointer(data) + Ok(ImplSource::FnPointer(data)) } DiscriminantKindCandidate => { - ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) + Ok(ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)) } - PointeeCandidate => ImplSource::Pointee(ImplSourcePointeeData), + PointeeCandidate => Ok(ImplSource::Pointee(ImplSourcePointeeData)), TraitAliasCandidate(alias_def_id) => { let data = self.confirm_trait_alias_candidate(obligation, alias_def_id); - ImplSource::TraitAlias(data) + Ok(ImplSource::TraitAlias(data)) } BuiltinObjectCandidate => { // This indicates something like `Trait + Send: Send`. In this case, we know that // this holds because that's what the object type is telling us, and there's really // no additional obligations to prove and no types in particular to unify, etc. - ImplSource::Param(Vec::new(), ty::BoundConstness::NotConst) + Ok(ImplSource::Param(Vec::new(), ty::BoundConstness::NotConst)) } BuiltinUnsizeCandidate => { let data = self.confirm_builtin_unsize_candidate(obligation)?; - ImplSource::Builtin(data) + Ok(ImplSource::Builtin(data)) } TraitUpcastingUnsizeCandidate(idx) => { let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?; - ImplSource::TraitUpcasting(data) + Ok(ImplSource::TraitUpcasting(data)) } ConstDestructCandidate(def_id) => { let data = self.confirm_const_destruct_candidate(obligation, def_id)?; - ImplSource::ConstDestruct(data) + Ok(ImplSource::ConstDestruct(data)) } - }; - - if !obligation.predicate.is_const_if_const() { - // normalize nested predicates according to parent predicate's constness. - impl_src = impl_src.map(|mut o| { - o.predicate = o.predicate.without_const(self.tcx()); - o - }); } - - Ok(impl_src) } fn confirm_projection_candidate( diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 17f34012d1dd3..fa2d2c751d929 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -789,7 +789,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut param_env = obligation.param_env; fresh_trait_pred = fresh_trait_pred.map_bound(|mut pred| { - pred.remap_constness(&mut param_env); + pred.remap_constness(self.tcx(), &mut param_env); pred }); @@ -1321,7 +1321,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } let tcx = self.tcx(); let mut pred = cache_fresh_trait_pred.skip_binder(); - pred.remap_constness(&mut param_env); + pred.remap_constness(tcx, &mut param_env); if self.can_use_global_caches(param_env) { if let Some(res) = tcx.selection_cache.get(&(param_env, pred), tcx) { @@ -1375,7 +1375,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); let mut pred = cache_fresh_trait_pred.skip_binder(); - pred.remap_constness(&mut param_env); + pred.remap_constness(tcx, &mut param_env); if !self.can_cache_candidate(&candidate) { debug!(?pred, ?candidate, "insert_candidate_cache - candidate is not cacheable"); diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 5f77aae6f221f..2c4a453aefc34 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -207,7 +207,18 @@ fn fulfill_implication<'a, 'tcx>( // (which are packed up in penv) infcx.save_and_restore_in_snapshot_flag(|infcx| { - let mut fulfill_cx = FulfillmentContext::new(); + // If we came from `translate_substs`, we already know that the + // predicates for our impl hold (after all, we know that a more + // specialized impl holds, so our impl must hold too), and + // we only want to process the projections to determine the + // the types in our substs using RFC 447, so we can safely + // ignore region obligations, which allows us to avoid threading + // a node-id to assign them with. + // + // If we came from specialization graph construction, then + // we already make a mockery out of the region system, so + // why not ignore them a bit earlier? + let mut fulfill_cx = FulfillmentContext::new_ignoring_regions(); for oblig in obligations.chain(more_obligations) { fulfill_cx.register_predicate_obligation(&infcx, oblig); } diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index c278752e3d9f4..6c0b83fbd0304 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -6,10 +6,29 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_span::Span; use std::ops::ControlFlow; +#[derive(Debug)] +pub struct NonStructuralMatchTy<'tcx> { + pub ty: Ty<'tcx>, + pub kind: NonStructuralMatchTyKind<'tcx>, +} + +#[derive(Debug)] +pub enum NonStructuralMatchTyKind<'tcx> { + Adt(AdtDef<'tcx>), + Param, + Dynamic, + Foreign, + Opaque, + Closure, + Generator, + Projection, + Float, +} + /// This method traverses the structure of `ty`, trying to find an /// instance of an ADT (i.e. struct or enum) that doesn't implement /// the structural-match traits, or a generic type parameter @@ -35,28 +54,15 @@ use std::ops::ControlFlow; /// For more background on why Rust has this requirement, and issues /// that arose when the requirement was not enforced completely, see /// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307. -pub fn search_for_structural_match_violation<'tcx>( - span: Span, - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, -) -> Option> { - ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), adt_const_param: false }) - .break_value() -} - -/// This method traverses the structure of `ty`, trying to find any -/// types that are not allowed to be used in a const generic. /// -/// This is either because the type does not implement `StructuralEq` -/// and `StructuralPartialEq`, or because the type is intentionally -/// not supported in const generics (such as floats and raw pointers, -/// which are allowed in match blocks). -pub fn search_for_adt_const_param_violation<'tcx>( +/// The floats_allowed flag is used to deny constants in floating point +pub fn search_for_structural_match_violation<'tcx>( span: Span, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, -) -> Option> { - ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), adt_const_param: true }) + floats_allowed: bool, +) -> Option> { + ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), floats_allowed }) .break_value() } @@ -119,10 +125,7 @@ struct Search<'tcx> { /// we will not recur on them again. seen: FxHashSet, - // Additionally deny things that have been allowed in patterns, - // but are not allowed in adt const params, such as floats and - // fn ptrs. - adt_const_param: bool, + floats_allowed: bool, } impl<'tcx> Search<'tcx> { @@ -132,7 +135,7 @@ impl<'tcx> Search<'tcx> { } impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { - type BreakTy = Ty<'tcx>; + type BreakTy = NonStructuralMatchTy<'tcx>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { debug!("Search visiting ty: {:?}", ty); @@ -140,27 +143,51 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { let (adt_def, substs) = match *ty.kind() { ty::Adt(adt_def, substs) => (adt_def, substs), ty::Param(_) => { - return ControlFlow::Break(ty); + let kind = NonStructuralMatchTyKind::Param; + return ControlFlow::Break(NonStructuralMatchTy { ty, kind }); } ty::Dynamic(..) => { - return ControlFlow::Break(ty); + let kind = NonStructuralMatchTyKind::Dynamic; + return ControlFlow::Break(NonStructuralMatchTy { ty, kind }); } ty::Foreign(_) => { - return ControlFlow::Break(ty); + let kind = NonStructuralMatchTyKind::Foreign; + return ControlFlow::Break(NonStructuralMatchTy { ty, kind }); } ty::Opaque(..) => { - return ControlFlow::Break(ty); + let kind = NonStructuralMatchTyKind::Opaque; + return ControlFlow::Break(NonStructuralMatchTy { ty, kind }); } ty::Projection(..) => { - return ControlFlow::Break(ty); + let kind = NonStructuralMatchTyKind::Projection; + return ControlFlow::Break(NonStructuralMatchTy { ty, kind }); } ty::Closure(..) => { - return ControlFlow::Break(ty); + let kind = NonStructuralMatchTyKind::Closure; + return ControlFlow::Break(NonStructuralMatchTy { ty, kind }); } ty::Generator(..) | ty::GeneratorWitness(..) => { - return ControlFlow::Break(ty); + let kind = NonStructuralMatchTyKind::Generator; + return ControlFlow::Break(NonStructuralMatchTy { ty, kind }); + } + ty::RawPtr(..) => { + // structural-match ignores substructure of + // `*const _`/`*mut _`, so skip `super_visit_with`. + // + // For example, if you have: + // ``` + // struct NonStructural; + // #[derive(PartialEq, Eq)] + // struct T(*const NonStructural); + // const C: T = T(std::ptr::null()); + // ``` + // + // Even though `NonStructural` does not implement `PartialEq`, + // structural equality on `T` does not recur into the raw + // pointer. Therefore, one can still use `C` in a pattern. + return ControlFlow::CONTINUE; } - ty::FnDef(..) => { + ty::FnDef(..) | ty::FnPtr(..) => { // Types of formals and return in `fn(_) -> _` are also irrelevant; // so we do not recur into them via `super_visit_with` return ControlFlow::CONTINUE; @@ -179,41 +206,14 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { return ControlFlow::CONTINUE; } - ty::FnPtr(..) => { - if !self.adt_const_param { - return ControlFlow::CONTINUE; - } else { - return ControlFlow::Break(ty); - } - } - - ty::RawPtr(..) => { - if !self.adt_const_param { - // structural-match ignores substructure of - // `*const _`/`*mut _`, so skip `super_visit_with`. - // - // For example, if you have: - // ``` - // struct NonStructural; - // #[derive(PartialEq, Eq)] - // struct T(*const NonStructural); - // const C: T = T(std::ptr::null()); - // ``` - // - // Even though `NonStructural` does not implement `PartialEq`, - // structural equality on `T` does not recur into the raw - // pointer. Therefore, one can still use `C` in a pattern. - return ControlFlow::CONTINUE; - } else { - return ControlFlow::Break(ty); - } - } - ty::Float(_) => { - if !self.adt_const_param { + if self.floats_allowed { return ControlFlow::CONTINUE; } else { - return ControlFlow::Break(ty); + return ControlFlow::Break(NonStructuralMatchTy { + ty, + kind: NonStructuralMatchTyKind::Float, + }); } } @@ -239,7 +239,8 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { if !self.type_marked_structural(ty) { debug!("Search found ty: {:?}", ty); - return ControlFlow::Break(ty); + let kind = NonStructuralMatchTyKind::Adt(adt_def); + return ControlFlow::Break(NonStructuralMatchTy { ty, kind }); } // structural-match does not care about the diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 414857f0acc80..6b758ba63cd0f 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -85,7 +85,7 @@ pub fn trait_obligations<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, - trait_pred: &ty::TraitPredicate<'tcx>, + trait_ref: &ty::TraitRef<'tcx>, span: Span, item: &'tcx hir::Item<'tcx>, ) -> Vec> { @@ -98,7 +98,7 @@ pub fn trait_obligations<'a, 'tcx>( recursion_depth: 0, item: Some(item), }; - wf.compute_trait_pred(trait_pred, Elaborate::All); + wf.compute_trait_ref(trait_ref, Elaborate::All); debug!(obligations = ?wf.out); wf.normalize(infcx) } @@ -123,7 +123,7 @@ pub fn predicate_obligations<'a, 'tcx>( // It's ok to skip the binder here because wf code is prepared for it match predicate.kind().skip_binder() { ty::PredicateKind::Trait(t) => { - wf.compute_trait_pred(&t, Elaborate::None); + wf.compute_trait_ref(&t.trait_ref, Elaborate::None); } ty::PredicateKind::RegionOutlives(..) => {} ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => { @@ -301,18 +301,11 @@ impl<'tcx> WfPredicates<'tcx> { } /// Pushes the obligations required for `trait_ref` to be WF into `self.out`. - fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) { + fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) { let tcx = self.tcx; - let trait_ref = &trait_pred.trait_ref; + let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); - // if the trait predicate is not const, the wf obligations should not be const as well. - let obligations = if trait_pred.constness == ty::BoundConstness::NotConst { - self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs) - } else { - self.nominal_obligations(trait_ref.def_id, trait_ref.substs) - }; - - debug!("compute_trait_pred obligations {:?}", obligations); + debug!("compute_trait_ref obligations {:?}", obligations); let param_env = self.param_env; let depth = self.recursion_depth; @@ -692,11 +685,10 @@ impl<'tcx> WfPredicates<'tcx> { } #[instrument(level = "debug", skip(self))] - fn nominal_obligations_inner( + fn nominal_obligations( &mut self, def_id: DefId, substs: SubstsRef<'tcx>, - remap_constness: bool, ) -> Vec> { let predicates = self.tcx.predicates_of(def_id); let mut origins = vec![def_id; predicates.predicates.len()]; @@ -711,38 +703,19 @@ impl<'tcx> WfPredicates<'tcx> { debug_assert_eq!(predicates.predicates.len(), origins.len()); iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev()) - .map(|((mut pred, span), origin_def_id)| { + .map(|((pred, span), origin_def_id)| { let code = if span.is_dummy() { traits::MiscObligation } else { traits::BindingObligation(origin_def_id, span) }; let cause = self.cause(code); - if remap_constness { - pred = pred.without_const(self.tcx); - } traits::Obligation::with_depth(cause, self.recursion_depth, self.param_env, pred) }) .filter(|pred| !pred.has_escaping_bound_vars()) .collect() } - fn nominal_obligations( - &mut self, - def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> Vec> { - self.nominal_obligations_inner(def_id, substs, false) - } - - fn nominal_obligations_without_const( - &mut self, - def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> Vec> { - self.nominal_obligations_inner(def_id, substs, true) - } - fn from_object_ty( &mut self, ty: Ty<'tcx>, diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index 49c9ba459632d..3fc141471b92a 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -1,4 +1,4 @@ -use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_span::source_map::DUMMY_SP; @@ -16,9 +16,7 @@ fn evaluate_obligation<'tcx>( canonical_goal: CanonicalPredicateGoal<'tcx>, ) -> Result { debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal); - // HACK This bubble is required for this tests to pass: - // impl-trait/issue99642.rs - tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter_with_canonical( + tcx.infer_ctxt().enter_with_canonical( DUMMY_SP, &canonical_goal, |ref infcx, goal, _canonical_inference_vars| { diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 4d4d55de5f457..c7cac8fca899b 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -47,7 +47,7 @@ fn compute_implied_outlives_bounds<'tcx>( // process it next. Because the resulting predicates aren't always // guaranteed to be a subset of the original type, so we need to store the // WF args we've computed in a set. - let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default(); + let mut checked_wf_args = rustc_data_structures::stable_set::FxHashSet::default(); let mut wf_args = vec![ty.into()]; let mut implied_bounds = vec![]; diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index d895b647db0b1..f8bac1d7b263f 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -2,7 +2,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; -use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt}; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts}; @@ -258,15 +258,10 @@ fn type_op_prove_predicate<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { - // HACK This bubble is required for this test to pass: - // impl-trait/issue-99642.rs - tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter_canonical_trait_query( - &canonicalized, - |infcx, fulfill_cx, key| { - type_op_prove_predicate_with_cause(infcx, fulfill_cx, key, ObligationCause::dummy()); - Ok(()) - }, - ) + tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { + type_op_prove_predicate_with_cause(infcx, fulfill_cx, key, ObligationCause::dummy()); + Ok(()) + }) } /// The core of the `type_op_prove_predicate` query: for diagnostics purposes in NLL HRTB errors, diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 979e997f24491..5e58f2379827e 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -280,11 +280,6 @@ fn resolve_associated_item<'tcx>( return Ok(None); } - // If the item does not have a value, then we cannot return an instance. - if !leaf_def.item.defaultness.has_value() { - return Ok(None); - } - let substs = tcx.erase_regions(substs); // Check if we just resolved an associated `const` declaration from diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index eded7891682ea..7efc82efd15c3 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -1,5 +1,5 @@ //! Check whether a type is representable. -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_map::FxHashMap; use rustc_hir as hir; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; diff --git a/compiler/rustc_type_ir/src/codec.rs b/compiler/rustc_type_ir/src/codec.rs index ee249050cc64e..6a9ea790a3020 100644 --- a/compiler/rustc_type_ir/src/codec.rs +++ b/compiler/rustc_type_ir/src/codec.rs @@ -1,6 +1,6 @@ use crate::Interner; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_map::FxHashMap; use rustc_serialize::{Decoder, Encoder}; /// The shorthand encoding uses an enum's variant index `usize` diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 791e9e0f5a359..fd6376ef6ee9d 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -310,7 +310,6 @@ impl DebruijnIndex { /// for<'a> fn(for<'b> fn(&'a x)) /// /// you would need to shift the index for `'a` into a new binder. - #[inline] #[must_use] pub fn shifted_in(self, amount: u32) -> DebruijnIndex { DebruijnIndex::from_u32(self.as_u32() + amount) @@ -318,21 +317,18 @@ impl DebruijnIndex { /// Update this index in place by shifting it "in" through /// `amount` number of binders. - #[inline] pub fn shift_in(&mut self, amount: u32) { *self = self.shifted_in(amount); } /// Returns the resulting index when this value is moved out from /// `amount` number of new binders. - #[inline] #[must_use] pub fn shifted_out(self, amount: u32) -> DebruijnIndex { DebruijnIndex::from_u32(self.as_u32() - amount) } /// Update in place by shifting out from `amount` binders. - #[inline] pub fn shift_out(&mut self, amount: u32) { *self = self.shifted_out(amount); } @@ -357,7 +353,6 @@ impl DebruijnIndex { /// If we invoke `shift_out_to_binder` and the region is in fact /// bound by one of the binders we are shifting out of, that is an /// error (and should fail an assertion failure). - #[inline] pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self { self.shifted_out(to_binder.as_u32() - INNERMOST.as_u32()) } diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index 99a8101dc96ba..c873cf27e42c5 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -8,7 +8,7 @@ use rustc_middle::ty; use rustc_session::parse::feature_err; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{sym, Ident}; -use rustc_span::{Span, Symbol, DUMMY_SP}; +use rustc_span::{Span, DUMMY_SP}; use std::collections::BTreeSet; @@ -17,7 +17,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// the type parameter's name as a placeholder. pub(crate) fn complain_about_missing_type_params( &self, - missing_type_params: Vec, + missing_type_params: Vec, def_id: DefId, span: Span, empty_generic_args: bool, diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 40aa27a29e957..612dc38452188 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -86,7 +86,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let param_type = tcx.infer_ctxt().enter(|infcx| { infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id)) }); - if param_type.is_suggestable(tcx, false) { + if param_type.is_suggestable(tcx) { err.span_suggestion( tcx.def_span(src_def_id), "consider changing this type parameter to be a `const` generic", diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 08e8e6f7d0f40..9e4da0580522b 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -221,6 +221,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.mk_region(ty::ReLateBound(debruijn, br)) } + Some(rl::Region::LateBoundAnon(debruijn, index, anon_index)) => { + let br = ty::BoundRegion { + var: ty::BoundVar::from_u32(index), + kind: ty::BrAnon(anon_index), + }; + tcx.mk_region(ty::ReLateBound(debruijn, br)) + } + Some(rl::Region::EarlyBound(index, id)) => { let name = lifetime_name(id.expect_local()); tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: id, index, name })) @@ -374,7 +382,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def_id: DefId, generic_args: &'a GenericArgs<'a>, span: Span, - missing_type_params: Vec, + missing_type_params: Vec, inferred_params: Vec, infer_args: bool, is_object: bool, @@ -506,7 +514,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // defaults. This will lead to an ICE if we are not // careful! if self.default_needs_object_self(param) { - self.missing_type_params.push(param.name); + self.missing_type_params.push(param.name.to_string()); tcx.ty_error().into() } else { // This is a default type parameter. @@ -1142,12 +1150,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .expect("missing associated type"); if !assoc_item.vis.is_accessible_from(def_scope, tcx) { + let kind = match assoc_item.kind { + ty::AssocKind::Type => "type", + ty::AssocKind::Const => "const", + _ => unreachable!(), + }; tcx.sess .struct_span_err( binding.span, - &format!("{} `{}` is private", assoc_item.kind, binding.item_name), + &format!("associated {kind} `{}` is private", binding.item_name), ) - .span_label(binding.span, &format!("private {}", assoc_item.kind)) + .span_label(binding.span, &format!("private associated {kind}")) .emit(); } tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None); @@ -2663,7 +2676,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { span, ty, opt_sugg: Some((span, Applicability::MachineApplicable)) - .filter(|_| ty.is_suggestable(tcx, false)), + .filter(|_| ty.is_suggestable(tcx)), }); ty diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 147d87e7594c5..c733f0d3c86d0 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -9,6 +9,7 @@ use rustc_span::Span; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, + StatementAsExpression, }; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -74,8 +75,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let mut other_arms = vec![]; // Used only for diagnostics. - let mut prior_arm = None; - for arm in arms { + let mut prior_arm_ty = None; + for (i, arm) in arms.iter().enumerate() { if let Some(g) = &arm.guard { self.diverges.set(Diverges::Maybe); match g { @@ -95,28 +96,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let opt_suggest_box_span = self.opt_suggest_box_span(arm_ty, orig_expected); - let (arm_block_id, arm_span) = if let hir::ExprKind::Block(blk, _) = arm.body.kind { - (Some(blk.hir_id), self.find_block_span(blk)) - } else { - (None, arm.body.span) - }; - - let (span, code) = match prior_arm { + let (arm_span, semi_span) = + self.get_appropriate_arm_semicolon_removal_span(&arms, i, prior_arm_ty, arm_ty); + let (span, code) = match i { // The reason for the first arm to fail is not that the match arms diverge, // but rather that there's a prior obligation that doesn't hold. - None => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)), - Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => ( + 0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)), + _ => ( expr.span, ObligationCauseCode::MatchExpressionArm(Box::new(MatchExpressionArmCause { - arm_block_id, arm_span, - arm_ty, - prior_arm_block_id, - prior_arm_ty, - prior_arm_span, scrut_span: scrut.span, + semi_span, source: match_src, prior_arms: other_arms.clone(), + last_ty: prior_arm_ty.unwrap(), scrut_hir_id: scrut.hir_id, opt_suggest_box_span, })), @@ -145,7 +139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ret_ty = ret_coercion.borrow().expected_ty(); let ret_ty = self.inh.infcx.shallow_resolve(ret_ty); self.can_coerce(arm_ty, ret_ty) - && prior_arm.map_or(true, |(_, t, _)| self.can_coerce(t, ret_ty)) + && prior_arm_ty.map_or(true, |t| self.can_coerce(t, ret_ty)) // The match arms need to unify for the case of `impl Trait`. && !matches!(ret_ty.kind(), ty::Opaque(..)) } @@ -187,8 +181,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if other_arms.len() > 5 { other_arms.remove(0); } - - prior_arm = Some((arm_block_id, arm_ty, arm_span)); + prior_arm_ty = Some(arm_ty); } // If all of the arms in the `match` diverge, @@ -214,6 +207,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match_ty } + fn get_appropriate_arm_semicolon_removal_span( + &self, + arms: &'tcx [hir::Arm<'tcx>], + i: usize, + prior_arm_ty: Option>, + arm_ty: Ty<'tcx>, + ) -> (Span, Option<(Span, StatementAsExpression)>) { + let arm = &arms[i]; + let (arm_span, mut semi_span) = if let hir::ExprKind::Block(blk, _) = &arm.body.kind { + self.find_block_span(blk, prior_arm_ty) + } else { + (arm.body.span, None) + }; + if semi_span.is_none() && i > 0 { + if let hir::ExprKind::Block(blk, _) = &arms[i - 1].body.kind { + let (_, semi_span_prev) = self.find_block_span(blk, Some(arm_ty)); + semi_span = semi_span_prev; + } + } + (arm_span, semi_span) + } + /// When the previously checked expression (the scrutinee) diverges, /// warn the user about the match arms being unreachable. fn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [hir::Arm<'tcx>]) { @@ -298,7 +313,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { else_ty: Ty<'tcx>, opt_suggest_box_span: Option, ) -> ObligationCause<'tcx> { - let mut outer_span = if self.tcx.sess.source_map().is_multiline(span) { + let mut outer_sp = if self.tcx.sess.source_map().is_multiline(span) { // The `if`/`else` isn't in one line in the output, include some context to make it // clear it is an if/else expression: // ``` @@ -324,67 +339,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None }; - let (error_sp, else_id) = if let ExprKind::Block(block, _) = &else_expr.kind { - let block = block.innermost_block(); - - // Avoid overlapping spans that aren't as readable: - // ``` - // 2 | let x = if true { - // | _____________- - // 3 | | 3 - // | | - expected because of this - // 4 | | } else { - // | |____________^ - // 5 | || - // 6 | || }; - // | || ^ - // | ||_____| - // | |______if and else have incompatible types - // | expected integer, found `()` - // ``` - // by not pointing at the entire expression: - // ``` - // 2 | let x = if true { - // | ------- `if` and `else` have incompatible types - // 3 | 3 - // | - expected because of this - // 4 | } else { - // | ____________^ - // 5 | | - // 6 | | }; - // | |_____^ expected integer, found `()` - // ``` - if block.expr.is_none() && block.stmts.is_empty() - && let Some(outer_span) = &mut outer_span - { - *outer_span = self.tcx.sess.source_map().guess_head_span(*outer_span); + let mut remove_semicolon = None; + let error_sp = if let ExprKind::Block(block, _) = &else_expr.kind { + let (error_sp, semi_sp) = self.find_block_span(block, Some(then_ty)); + remove_semicolon = semi_sp; + if block.expr.is_none() && block.stmts.is_empty() { + // Avoid overlapping spans that aren't as readable: + // ``` + // 2 | let x = if true { + // | _____________- + // 3 | | 3 + // | | - expected because of this + // 4 | | } else { + // | |____________^ + // 5 | || + // 6 | || }; + // | || ^ + // | ||_____| + // | |______if and else have incompatible types + // | expected integer, found `()` + // ``` + // by not pointing at the entire expression: + // ``` + // 2 | let x = if true { + // | ------- `if` and `else` have incompatible types + // 3 | 3 + // | - expected because of this + // 4 | } else { + // | ____________^ + // 5 | | + // 6 | | }; + // | |_____^ expected integer, found `()` + // ``` + if outer_sp.is_some() { + outer_sp = Some(self.tcx.sess.source_map().guess_head_span(span)); + } } - - (self.find_block_span(block), block.hir_id) + error_sp } else { - (else_expr.span, else_expr.hir_id) + // shouldn't happen unless the parser has done something weird + else_expr.span }; - let then_id = if let ExprKind::Block(block, _) = &then_expr.kind { - let block = block.innermost_block(); - // Exclude overlapping spans + // Compute `Span` of `then` part of `if`-expression. + let then_sp = if let ExprKind::Block(block, _) = &then_expr.kind { + let (then_sp, semi_sp) = self.find_block_span(block, Some(else_ty)); + remove_semicolon = remove_semicolon.or(semi_sp); if block.expr.is_none() && block.stmts.is_empty() { - outer_span = None; + outer_sp = None; // same as in `error_sp`; cleanup output } - block.hir_id + then_sp } else { - then_expr.hir_id + // shouldn't happen unless the parser has done something weird + then_expr.span }; // Finally construct the cause: self.cause( error_sp, ObligationCauseCode::IfExpression(Box::new(IfExpressionCause { - else_id, - then_id, - then_ty, - else_ty, - outer_span, + then: then_sp, + else_sp: error_sp, + outer: outer_sp, + semicolon: remove_semicolon, opt_suggest_box_span, })), ) @@ -465,6 +482,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn find_block_span( + &self, + block: &'tcx hir::Block<'tcx>, + expected_ty: Option>, + ) -> (Span, Option<(Span, StatementAsExpression)>) { + if let Some(expr) = &block.expr { + (expr.span, None) + } else if let Some(stmt) = block.stmts.last() { + // possibly incorrect trailing `;` in the else arm + (stmt.span, expected_ty.and_then(|ty| self.could_remove_semicolon(block, ty))) + } else { + // empty block; point at its entirety + (block.span, None) + } + } + // When we have a `match` as a tail expression in a `fn` with a returned `impl Trait` // we check if the different arms would work with boxed trait objects instead and // provide a structured suggestion in that case. @@ -488,7 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref: ty::TraitRef { def_id: t.def_id(), - substs: self.tcx.mk_substs_trait(outer_ty, &[]), + substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]), }, constness: t.constness, polarity: t.polarity, @@ -496,9 +529,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let obl = Obligation::new( o.cause.clone(), self.param_env, - pred.to_predicate(self.tcx), + pred.to_predicate(self.infcx.tcx), ); - suggest_box &= self.predicate_must_hold_modulo_regions(&obl); + suggest_box &= self.infcx.predicate_must_hold_modulo_regions(&obl); if !suggest_box { // We've encountered some obligation that didn't hold, so the // return expression can't just be boxed. We don't need to diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 0836f15a1221b..00c8aa3a1bbda 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -376,7 +376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.param_env, *predicate, ); - let result = self.evaluate_obligation(&obligation); + let result = self.infcx.evaluate_obligation(&obligation); self.tcx .sess .struct_span_err( diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 7aaddc2bd7aab..66dd558249052 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -69,7 +69,7 @@ enum PointerKind<'tcx> { /// No metadata attached, ie pointer to sized type or foreign type Thin, /// A trait object - VTable(Option), + Vtable(Option), /// Slice Length, /// The unsize info of this projection @@ -102,7 +102,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(match *t.kind() { ty::Slice(_) | ty::Str => Some(PointerKind::Length), - ty::Dynamic(ref tty, ..) => Some(PointerKind::VTable(tty.principal_def_id())), + ty::Dynamic(ref tty, ..) => Some(PointerKind::Vtable(tty.principal_def_id())), ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().fields.last() { None => Some(PointerKind::Thin), Some(f) => { @@ -951,7 +951,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { match fcx.pointer_kind(m_cast.ty, self.span)? { None => Err(CastError::UnknownCastPtrKind), Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast), - Some(PointerKind::VTable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))), + Some(PointerKind::Vtable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))), Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))), Some( PointerKind::OfProjection(_) diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index fee872155f5b2..1681e6af81239 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -96,7 +96,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.typeck_root_def_id(expr_def_id.to_def_id()), ); - let tupled_upvars_ty = self.next_ty_var(TypeVariableOrigin { + let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::ClosureSynthetic, span: self.tcx.hir().span(expr.hir_id), }); @@ -141,7 +141,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Create a type variable (for now) to represent the closure kind. // It will be unified during the upvar inference phase (`upvar.rs`) - None => self.next_ty_var(TypeVariableOrigin { + None => self.infcx.next_ty_var(TypeVariableOrigin { // FIXME(eddyb) distinguish closure kind inference variables from the rest. kind: TypeVariableOriginKind::ClosureSynthetic, span: expr.span, @@ -182,9 +182,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::PredicateKind::Projection(proj_predicate) => self .deduce_sig_from_projection( Some(span.0), - pred.0 - .kind() - .rebind(pred.rebind(proj_predicate).subst(self.tcx, substs)), + pred.0.kind().rebind( + pred.map_bound(|_| proj_predicate).subst(self.tcx, substs), + ), ), _ => None, }); @@ -531,7 +531,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // [c1]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341089706 // [c2]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341096796 - self.commit_if_ok(|_| { + self.infcx.commit_if_ok(|_| { let mut all_obligations = vec![]; // The liberated version of this signature should be a subtype @@ -544,7 +544,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_sigs.liberated_sig.inputs(), // `liberated_sig` is E'. ) { // Instantiate (this part of..) S to S', i.e., with fresh variables. - let supplied_ty = self.replace_bound_vars_with_fresh_vars( + let supplied_ty = self.infcx.replace_bound_vars_with_fresh_vars( hir_ty.span, LateBoundRegionConversionTime::FnCall, supplied_sig.inputs().rebind(supplied_ty), @@ -557,7 +557,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { all_obligations.extend(obligations); } - let supplied_output_ty = self.replace_bound_vars_with_fresh_vars( + let supplied_output_ty = self.infcx.replace_bound_vars_with_fresh_vars( decl.output.span(), LateBoundRegionConversionTime::FnCall, supplied_sig.output(), diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 639cab98f1741..9c9a2096ae9a4 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -241,13 +241,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec>, ) -> CoerceResult<'tcx> { debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b); - assert!(a.is_ty_var() && self.shallow_resolve(a) == a); - assert!(self.shallow_resolve(b) == b); + assert!(a.is_ty_var() && self.infcx.shallow_resolve(a) == a); + assert!(self.infcx.shallow_resolve(b) == b); if b.is_ty_var() { // Two unresolved type variables: create a `Coerce` predicate. let target_ty = if self.use_lub { - self.next_ty_var(TypeVariableOrigin { + self.infcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::LatticeVariable, span: self.cause.span, }) @@ -991,7 +991,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.autoderef(rustc_span::DUMMY_SP, expr_ty).nth(1).and_then(|(deref_ty, _)| { self.infcx .type_implements_trait( - self.tcx.lang_items().deref_mut_trait()?, + self.infcx.tcx.lang_items().deref_mut_trait()?, expr_ty, ty::List::empty(), self.param_env, diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index af77efc3c2d57..020aa95d0be21 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -2,7 +2,7 @@ use super::potentially_plural_count; use crate::check::regionck::OutlivesEnvironmentExt; use crate::check::wfcheck; use crate::errors::LifetimesOrBoundsMismatchOnTrait; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -90,10 +90,9 @@ fn compare_predicate_entailment<'tcx>( let mut cause = ObligationCause::new( impl_m_span, impl_m_hir_id, - ObligationCauseCode::CompareImplItemObligation { + ObligationCauseCode::CompareImplMethodObligation { impl_item_def_id: impl_m.def_id.expect_local(), trait_item_def_id: trait_m.def_id, - kind: impl_m.kind, }, ); @@ -224,10 +223,9 @@ fn compare_predicate_entailment<'tcx>( let cause = ObligationCause::new( span, impl_m_hir_id, - ObligationCauseCode::CompareImplItemObligation { + ObligationCauseCode::CompareImplMethodObligation { impl_item_def_id: impl_m.def_id.expect_local(), trait_item_def_id: trait_m.def_id, - kind: impl_m.kind, }, ); ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate)); @@ -1081,11 +1079,7 @@ pub(crate) fn compare_const_impl<'tcx>( let mut cause = ObligationCause::new( impl_c_span, impl_c_hir_id, - ObligationCauseCode::CompareImplItemObligation { - impl_item_def_id: impl_c.def_id.expect_local(), - trait_item_def_id: trait_c.def_id, - kind: impl_c.kind, - }, + ObligationCauseCode::CompareImplConstObligation, ); // There is no "body" here, so just pass dummy id. @@ -1218,6 +1212,15 @@ fn compare_type_predicate_entailment<'tcx>( // `ObligationCause` (and the `FnCtxt`). This is what // `regionck_item` expects. let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()); + let cause = ObligationCause::new( + impl_ty_span, + impl_ty_hir_id, + ObligationCauseCode::CompareImplTypeObligation { + impl_item_def_id: impl_ty.def_id.expect_local(), + trait_item_def_id: trait_ty.def_id, + }, + ); + debug!("compare_type_predicate_entailment: trait_to_impl_substs={:?}", trait_to_impl_substs); // The predicates declared by the impl definition, the trait and the @@ -1236,7 +1239,7 @@ fn compare_type_predicate_entailment<'tcx>( Reveal::UserFacing, hir::Constness::NotConst, ); - let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); + let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause.clone()); tcx.infer_ctxt().enter(|infcx| { let ocx = ObligationCtxt::new(&infcx); @@ -1244,25 +1247,12 @@ fn compare_type_predicate_entailment<'tcx>( let mut selcx = traits::SelectionContext::new(&infcx); - assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len()); - for (span, predicate) in - std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates) - { - let cause = ObligationCause::misc(span, impl_ty_hir_id); + for predicate in impl_ty_own_bounds.predicates { let traits::Normalized { value: predicate, obligations } = - traits::normalize(&mut selcx, param_env, cause, predicate); + traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate); - let cause = ObligationCause::new( - span, - impl_ty_hir_id, - ObligationCauseCode::CompareImplItemObligation { - impl_item_def_id: impl_ty.def_id.expect_local(), - trait_item_def_id: trait_ty.def_id, - kind: impl_ty.kind, - }, - ); ocx.register_obligations(obligations); - ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate)); + ocx.register_obligation(traits::Obligation::new(cause.clone(), param_env, predicate)); } // Check that all obligations are satisfied by the implementation's diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 58b0399c5c927..a2d8765289c55 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -287,21 +287,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_ty: Ty<'tcx>, ) { if let ty::Adt(expected_adt, substs) = expected.kind() { - if let hir::ExprKind::Field(base, ident) = expr.kind { - let base_ty = self.typeck_results.borrow().expr_ty(base); - if self.can_eq(self.param_env, base_ty, expected).is_ok() - && let Some(base_span) = base.span.find_ancestor_inside(expr.span) - { - err.span_suggestion_verbose( - expr.span.with_lo(base_span.hi()), - format!("consider removing the tuple struct field `{ident}`"), - "", - Applicability::MaybeIncorrect, - ); - return - } - } - // If the expression is of type () and it's the return expression of a block, // we suggest adding a separate return expression instead. // (To avoid things like suggesting `Ok(while .. { .. })`.) @@ -830,7 +815,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr), _, &ty::Ref(_, checked, _), - ) if self.can_sub(self.param_env, checked, expected).is_ok() => { + ) if self.infcx.can_sub(self.param_env, checked, expected).is_ok() => { // We have `&T`, check if what was expected was `T`. If so, // we may want to suggest removing a `&`. if sm.is_imported(expr.span) { @@ -974,7 +959,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // For this suggestion to make sense, the type would need to be `Copy`, // or we have to be moving out of a `Box` - if self.type_is_copy_modulo_regions(self.param_env, expected, sp) + if self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp) // FIXME(compiler-errors): We can actually do this if the checked_ty is // `steps` layers of boxes, not just one, but this is easier and most likely. || (checked_ty.is_box() && steps == 1) diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index ba5ef5edc8630..2d22e9bc76e5a 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1803,7 +1803,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .source_map() .span_to_snippet(range_end.expr.span) .map(|s| format!(" from `{s}`")) - .unwrap_or_default(); + .unwrap_or(String::new()); err.span_suggestion( range_start.span.shrink_to_hi(), &format!("to set the remaining fields{instead}, separate the last named field with a comma"), @@ -2235,7 +2235,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base: &'tcx hir::Expr<'tcx>, ty: Ty<'tcx>, ) { - let output_ty = match self.get_impl_future_output_ty(ty) { + let output_ty = match self.infcx.get_impl_future_output_ty(ty) { Some(output_ty) => self.resolve_vars_if_possible(output_ty), _ => return, }; @@ -2362,7 +2362,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false }; let expr_snippet = - self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or_default(); + self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or(String::new()); let is_wrapped = expr_snippet.starts_with('(') && expr_snippet.ends_with(')'); let after_open = expr.span.lo() + rustc_span::BytePos(1); let before_close = expr.span.hi() - rustc_span::BytePos(1); diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs index 4059b3403b19f..15788f410f195 100644 --- a/compiler/rustc_typeck/src/check/fallback.rs +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -1,8 +1,9 @@ use crate::check::FnCtxt; use rustc_data_structures::{ - fx::{FxHashMap, FxHashSet}, + fx::FxHashMap, graph::WithSuccessors, graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, + stable_set::FxHashSet, }; use rustc_middle::ty::{self, Ty}; @@ -218,9 +219,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> { .diverging_type_vars .borrow() .iter() - .map(|&ty| self.shallow_resolve(ty)) + .map(|&ty| self.infcx.shallow_resolve(ty)) .filter_map(|ty| ty.ty_vid()) - .map(|vid| self.root_var(vid)) + .map(|vid| self.infcx.root_var(vid)) .collect(); debug!( "calculate_diverging_fallback: diverging_type_vars={:?}", @@ -236,7 +237,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let mut diverging_vids = vec![]; let mut non_diverging_vids = vec![]; for unsolved_vid in unsolved_vids { - let root_vid = self.root_var(unsolved_vid); + let root_vid = self.infcx.root_var(unsolved_vid); debug!( "calculate_diverging_fallback: unsolved_vid={:?} root_vid={:?} diverges={:?}", unsolved_vid, @@ -271,7 +272,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // variables. (Note that this set consists of "root variables".) let mut roots_reachable_from_non_diverging = DepthFirstSearch::new(&coercion_graph); for &non_diverging_vid in &non_diverging_vids { - let root_vid = self.root_var(non_diverging_vid); + let root_vid = self.infcx.root_var(non_diverging_vid); if roots_reachable_from_diverging.visited(root_vid) { continue; } @@ -294,7 +295,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { diverging_fallback.reserve(diverging_vids.len()); for &diverging_vid in &diverging_vids { let diverging_ty = self.tcx.mk_ty_var(diverging_vid); - let root_vid = self.root_var(diverging_vid); + let root_vid = self.infcx.root_var(diverging_vid); let can_reach_non_diverging = coercion_graph .depth_first_search(root_vid) .any(|n| roots_reachable_from_non_diverging.visited(n)); @@ -302,7 +303,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let mut relationship = ty::FoundRelationships { self_in_trait: false, output: false }; for (vid, rel) in relationships.iter() { - if self.root_var(*vid) == root_vid { + if self.infcx.root_var(*vid) == root_vid { relationship.self_in_trait |= rel.self_in_trait; relationship.output |= rel.output; } @@ -387,12 +388,12 @@ impl<'tcx> FnCtxt<'_, 'tcx> { }) .collect(); debug!("create_coercion_graph: coercion_edges={:?}", coercion_edges); - let num_ty_vars = self.num_ty_vars(); + let num_ty_vars = self.infcx.num_ty_vars(); VecGraph::new(num_ty_vars, coercion_edges) } /// If `ty` is an unresolved type variable, returns its root vid. fn root_vid(&self, ty: Ty<'tcx>) -> Option { - Some(self.root_var(self.shallow_resolve(ty).ty_vid()?)) + Some(self.infcx.root_var(self.infcx.shallow_resolve(ty).ty_vid()?)) } } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index d1c10a3b63c65..d079aeb4801ca 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -30,15 +30,17 @@ use rustc_middle::ty::{ }; use rustc_session::lint; use rustc_span::hygiene::DesugaringKind; +use rustc_span::source_map::{original_sp, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{self, BytePos, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{ - self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt, + self, ObligationCause, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt, }; use std::collections::hash_map::Entry; +use std::iter; use std::slice; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -185,12 +187,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !method.substs.is_empty() { let method_generics = self.tcx.generics_of(method.def_id); if !method_generics.params.is_empty() { - let user_type_annotation = self.probe(|_| { + let user_type_annotation = self.infcx.probe(|_| { let user_substs = UserSubsts { substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| { let i = param.index as usize; if i < method_generics.parent_count { - self.var_for_def(DUMMY_SP, param) + self.infcx.var_for_def(DUMMY_SP, param) } else { method.substs[i] } @@ -198,7 +200,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { user_self_ty: None, // not relevant here }; - self.canonicalize_user_type_annotation(UserType::TypeOf( + self.infcx.canonicalize_user_type_annotation(UserType::TypeOf( method.def_id, user_substs, )) @@ -236,7 +238,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("fcx {}", self.tag()); if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) { - let canonicalized = self.canonicalize_user_type_annotation(UserType::TypeOf( + let canonicalized = self.infcx.canonicalize_user_type_annotation(UserType::TypeOf( def_id, UserSubsts { substs, user_self_ty }, )); @@ -480,7 +482,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("to_ty_saving_user_provided_ty: ty={:?}", ty); if Self::can_contain_user_lifetime_bounds(ty) { - let c_ty = self.canonicalize_response(UserType::Ty(ty)); + let c_ty = self.infcx.canonicalize_response(UserType::Ty(ty)); debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty); self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty); } @@ -764,7 +766,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::subst::GenericArgKind::Type(ty) = ty.unpack() && let ty::Opaque(def_id, _) = *ty.kind() && let Some(def_id) = def_id.as_local() - && self.opaque_type_origin(def_id, DUMMY_SP).is_some() { + && self.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() { return None; } } @@ -826,7 +828,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { self.tcx.bound_type_of(def_id) }; - let substs = self.fresh_substs_for_item(span, def_id); + let substs = self.infcx.fresh_substs_for_item(span, def_id); let ty = item_ty.subst(self.tcx, substs); self.write_resolution(hir_id, Ok((def_kind, def_id))); @@ -1057,6 +1059,84 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } + pub(in super::super) fn could_remove_semicolon( + &self, + blk: &'tcx hir::Block<'tcx>, + expected_ty: Ty<'tcx>, + ) -> Option<(Span, StatementAsExpression)> { + // Be helpful when the user wrote `{... expr;}` and + // taking the `;` off is enough to fix the error. + let last_stmt = blk.stmts.last()?; + let hir::StmtKind::Semi(ref last_expr) = last_stmt.kind else { + return None; + }; + let last_expr_ty = self.node_ty(last_expr.hir_id); + let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) { + (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _)) + if last_def_id == exp_def_id => + { + StatementAsExpression::CorrectType + } + (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => { + debug!( + "both opaque, likely future {:?} {:?} {:?} {:?}", + last_def_id, last_bounds, exp_def_id, exp_bounds + ); + + let last_local_id = last_def_id.as_local()?; + let exp_local_id = exp_def_id.as_local()?; + + match ( + &self.tcx.hir().expect_item(last_local_id).kind, + &self.tcx.hir().expect_item(exp_local_id).kind, + ) { + ( + hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }), + hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }), + ) if iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| { + match (left, right) { + ( + hir::GenericBound::Trait(tl, ml), + hir::GenericBound::Trait(tr, mr), + ) if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id() + && ml == mr => + { + true + } + ( + hir::GenericBound::LangItemTrait(langl, _, _, argsl), + hir::GenericBound::LangItemTrait(langr, _, _, argsr), + ) if langl == langr => { + // FIXME: consider the bounds! + debug!("{:?} {:?}", argsl, argsr); + true + } + _ => false, + } + }) => + { + StatementAsExpression::NeedsBoxing + } + _ => StatementAsExpression::CorrectType, + } + } + _ => StatementAsExpression::CorrectType, + }; + if (matches!(last_expr_ty.kind(), ty::Error(_)) + || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err()) + && matches!(needs_box, StatementAsExpression::CorrectType) + { + return None; + } + let span = if last_stmt.span.from_expansion() { + let mac_call = original_sp(last_stmt.span, blk.span); + self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)? + } else { + last_stmt.span.with_lo(last_stmt.span.hi() - BytePos(1)) + }; + Some((span, needs_box)) + } + // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. #[instrument(skip(self, span), level = "debug")] diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index eb22938fb61c4..e3db70845ddf1 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -15,7 +15,7 @@ use crate::check::{ use crate::structured_errors::StructuredDiagnostic; use rustc_ast as ast; -use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticId, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -481,17 +481,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.set_tainted_by_errors(); let tcx = self.tcx; - // Get the argument span in the context of the call span so that - // suggestions and labels are (more) correct when an arg is a - // macro invocation. - let normalize_span = |span: Span| -> Span { - let normalized_span = span.find_ancestor_inside(error_span).unwrap_or(span); - // Sometimes macros mess up the spans, so do not normalize the - // arg span to equal the error span, because that's less useful - // than pointing out the arg expr in the wrong context. - if normalized_span.source_equal(error_span) { span } else { normalized_span } - }; - // Precompute the provided types and spans, since that's all we typically need for below let provided_arg_tys: IndexVec, Span)> = provided_args .iter() @@ -501,7 +490,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .borrow() .expr_ty_adjusted_opt(*expr) .unwrap_or_else(|| tcx.ty_error()); - (self.resolve_vars_if_possible(ty), normalize_span(expr.span)) + (self.resolve_vars_if_possible(ty), expr.span) }) .collect(); let callee_expr = match &call_expr.peel_blocks().kind { @@ -611,10 +600,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Take some care with spans, so we don't suggest wrapping a macro's // innards in parenthesis, for example. if satisfied - && let Some((_, lo)) = - provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx)) - && let Some((_, hi)) = - provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx + tys.len() - 1)) + && let Some(lo) = + provided_args[mismatch_idx.into()].span.find_ancestor_inside(error_span) + && let Some(hi) = provided_args[(mismatch_idx + tys.len() - 1).into()] + .span + .find_ancestor_inside(error_span) { let mut err; if tys.len() == 1 { @@ -622,7 +612,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // so don't do anything special here. err = self.report_and_explain_type_error( TypeTrace::types( - &self.misc(*lo), + &self.misc(lo), true, formal_and_expected_inputs[mismatch_idx.into()].1, provided_arg_tys[mismatch_idx.into()].0, @@ -645,7 +635,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "argument" ), potentially_plural_count(provided_args.len(), "argument"), - pluralize!("was", provided_args.len()) + if provided_args.len() == 1 { "was" } else { "were" } ), DiagnosticId::Error(err_code.to_owned()), ); @@ -770,7 +760,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if c_variadic { "at least " } else { "" }, potentially_plural_count(formal_and_expected_inputs.len(), "argument"), potentially_plural_count(provided_args.len(), "argument"), - pluralize!("was", provided_args.len()) + if provided_args.len() == 1 { "was" } else { "were" } ), DiagnosticId::Error(err_code.to_owned()), ) @@ -1062,7 +1052,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let suggestion_text = if let Some(provided_idx) = provided_idx && let (_, provided_span) = provided_arg_tys[*provided_idx] && let Ok(arg_text) = - source_map.span_to_snippet(provided_span) + source_map.span_to_snippet(provided_span.source_callsite()) { arg_text } else { @@ -1070,7 +1060,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; if expected_ty.is_unit() { "()".to_string() - } else if expected_ty.is_suggestable(tcx, false) { + } else if expected_ty.is_suggestable(tcx) { format!("/* {} */", expected_ty) } else { "/* value */".to_string() @@ -1520,13 +1510,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// ``` fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span { let check_in_progress = |elem: &hir::Expr<'_>| { - self.typeck_results.borrow().node_type_opt(elem.hir_id).filter(|ty| !ty.is_never()).map( - |_| match elem.kind { - // Point at the tail expression when possible. - hir::ExprKind::Block(block, _) => block.expr.map_or(block.span, |e| e.span), - _ => elem.span, - }, - ) + self.in_progress_typeck_results + .and_then(|typeck_results| typeck_results.borrow().node_type_opt(elem.hir_id)) + .and_then(|ty| { + if ty.is_never() { + None + } else { + Some(match elem.kind { + // Point at the tail expression when possible. + hir::ExprKind::Block(block, _) => { + block.expr.map_or(block.span, |e| e.span) + } + _ => elem.span, + }) + } + }) }; if let hir::ExprKind::If(_, _, Some(el)) = expr.kind { @@ -1759,11 +1757,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .flat_map(|a| a.args.iter()) { if let hir::GenericArg::Type(hir_ty) = &arg { - let ty = self.resolve_vars_if_possible( - self.typeck_results.borrow().node_type(hir_ty.hir_id), - ); - if ty == predicate.self_ty() { - error.obligation.cause.span = hir_ty.span; + if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) = + &hir_ty.kind + { + // Avoid ICE with associated types. As this is best + // effort only, it's ok to ignore the case. It + // would trigger in `is_send::();` + // from `typeck-default-trait-impl-assoc-type.rs`. + } else { + let ty = >::ast_ty_to_ty(self, hir_ty); + let ty = self.resolve_vars_if_possible(ty); + if ty == predicate.self_ty() { + error.obligation.cause.span = hir_ty.span; + } } } } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 097fff6418e11..d5ee299c0f98d 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -3,6 +3,7 @@ use crate::astconv::AstConv; use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel}; use rustc_ast::util::parser::ExprPrecedence; +use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::{Applicability, Diagnostic, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind}; @@ -13,7 +14,7 @@ use rustc_hir::{ use rustc_infer::infer::{self, TyCtxtInferExt}; use rustc_infer::traits::{self, StatementAsExpression}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty}; +use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty, TypeVisitable}; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -506,12 +507,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found)); // Only suggest changing the return type for methods that // haven't set a return type at all (and aren't `fn main()` or an impl). - match ( - &fn_decl.output, - found.is_suggestable(self.tcx, false), - can_suggest, - expected.is_unit(), - ) { + match (&fn_decl.output, found.is_suggestable(self.tcx), can_suggest, expected.is_unit()) { (&hir::FnRetTy::DefaultReturn(span), true, true, true) => { err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found }); true @@ -908,4 +904,117 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } } + + pub(crate) fn consider_returning_binding( + &self, + blk: &'tcx hir::Block<'tcx>, + expected_ty: Ty<'tcx>, + err: &mut Diagnostic, + ) { + let mut shadowed = FxHashSet::default(); + let mut candidate_idents = vec![]; + let mut find_compatible_candidates = |pat: &hir::Pat<'_>| { + if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind + && let Some(pat_ty) = self.typeck_results.borrow().node_type_opt(*hir_id) + { + let pat_ty = self.resolve_vars_if_possible(pat_ty); + if self.can_coerce(pat_ty, expected_ty) + && !(pat_ty, expected_ty).references_error() + && shadowed.insert(ident.name) + { + candidate_idents.push((*ident, pat_ty)); + } + } + true + }; + + let hir = self.tcx.hir(); + for stmt in blk.stmts.iter().rev() { + let StmtKind::Local(local) = &stmt.kind else { continue; }; + local.pat.walk(&mut find_compatible_candidates); + } + match hir.find(hir.get_parent_node(blk.hir_id)) { + Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => { + match hir.find(hir.get_parent_node(*hir_id)) { + Some(hir::Node::Arm(hir::Arm { pat, .. })) => { + pat.walk(&mut find_compatible_candidates); + } + Some( + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. }) + | hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(_, body), + .. + }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)), + .. + }) + | hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(hir::Closure { body, .. }), + .. + }), + ) => { + for param in hir.body(*body).params { + param.pat.walk(&mut find_compatible_candidates); + } + } + Some(hir::Node::Expr(hir::Expr { + kind: + hir::ExprKind::If( + hir::Expr { kind: hir::ExprKind::Let(let_), .. }, + then_block, + _, + ), + .. + })) if then_block.hir_id == *hir_id => { + let_.pat.walk(&mut find_compatible_candidates); + } + _ => {} + } + } + _ => {} + } + + match &candidate_idents[..] { + [(ident, _ty)] => { + let sm = self.tcx.sess.source_map(); + if let Some(stmt) = blk.stmts.last() { + let stmt_span = sm.stmt_span(stmt.span, blk.span); + let sugg = if sm.is_multiline(blk.span) + && let Some(spacing) = sm.indentation_before(stmt_span) + { + format!("\n{spacing}{ident}") + } else { + format!(" {ident}") + }; + err.span_suggestion_verbose( + stmt_span.shrink_to_hi(), + format!("consider returning the local binding `{ident}`"), + sugg, + Applicability::MachineApplicable, + ); + } else { + let sugg = if sm.is_multiline(blk.span) + && let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo()) + { + format!("\n{spacing} {ident}\n{spacing}") + } else { + format!(" {ident} ") + }; + let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi(); + err.span_suggestion_verbose( + sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span), + format!("consider returning the local binding `{ident}`"), + sugg, + Applicability::MachineApplicable, + ); + } + } + values if (1..3).contains(&values.len()) => { + let spans = values.iter().map(|(ident, _)| ident.span).collect::>(); + err.span_note(spans, "consider returning one of these bindings"); + } + _ => {} + } + } } diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs index 518cd7342366c..14b226d91cbf8 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs @@ -17,7 +17,8 @@ use self::record_consumed_borrow::find_consumed_and_borrowed; use crate::check::FnCtxt; use hir::def_id::DefId; use hir::{Body, HirId, HirIdMap, Node}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_set::FxHashSet; use rustc_hir as hir; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs index a2c23db162b03..da2db3f2e30ab 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs @@ -6,7 +6,7 @@ use hir::{ intravisit::{self, Visitor}, Body, Expr, ExprKind, Guard, HirId, LoopIdError, }; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::{fx::FxHashMap, stable_set::FxHashSet}; use rustc_hir as hir; use rustc_index::vec::IndexVec; use rustc_middle::{ diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs index ded0888c33e15..67cc46f21f00b 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs @@ -4,7 +4,7 @@ use crate::{ expr_use_visitor::{self, ExprUseVisitor}, }; use hir::{def_id::DefId, Body, HirId, HirIdMap}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_hir as hir; use rustc_middle::hir::place::{PlaceBase, Projection, ProjectionKind}; use rustc_middle::ty::{ParamEnv, TyCtxt}; @@ -72,8 +72,9 @@ impl<'tcx> ExprUseDelegate<'tcx> { } fn mark_consumed(&mut self, consumer: HirId, target: TrackedValue) { - self.places.consumed.entry(consumer).or_insert_with(|| <_>::default()); - + if !self.places.consumed.contains_key(&consumer) { + self.places.consumed.insert(consumer, <_>::default()); + } debug!(?consumer, ?target, "mark_consumed"); self.places.consumed.get_mut(&consumer).map(|places| places.insert(target)); } diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index a499179b95f10..4afbc00b37c73 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -1,4 +1,5 @@ use super::callee::DeferredCallResolution; +use super::MaybeInProgressTables; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; @@ -28,7 +29,7 @@ use std::ops::Deref; pub struct Inherited<'a, 'tcx> { pub(super) infcx: InferCtxt<'a, 'tcx>, - pub(super) typeck_results: &'a RefCell>, + pub(super) typeck_results: super::MaybeInProgressTables<'a, 'tcx>, pub(super) locals: RefCell>>, @@ -85,10 +86,7 @@ impl<'tcx> Inherited<'_, 'tcx> { let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner; InheritedBuilder { - infcx: tcx - .infer_ctxt() - .ignoring_regions() - .with_fresh_in_progress_typeck_results(hir_owner), + infcx: tcx.infer_ctxt().with_fresh_in_progress_typeck_results(hir_owner), def_id, } } @@ -109,13 +107,13 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { let tcx = infcx.tcx; let item_id = tcx.hir().local_def_id_to_hir_id(def_id); let body_id = tcx.hir().maybe_body_owned_by(item_id); - let typeck_results = - infcx.in_progress_typeck_results.expect("building `FnCtxt` without typeck results"); Inherited { - typeck_results, + typeck_results: MaybeInProgressTables { + maybe_typeck_results: infcx.in_progress_typeck_results, + }, infcx, - fulfillment_cx: RefCell::new(>::new(tcx)), + fulfillment_cx: RefCell::new(>::new_ignoring_regions(tcx)), locals: RefCell::new(Default::default()), deferred_sized_obligations: RefCell::new(Vec::new()), deferred_call_resolutions: RefCell::new(Default::default()), diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 3f2a0da8d6515..7fe710cf8f4f2 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -400,10 +400,6 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)), - sym::vtable_size | sym::vtable_align => { - (0, vec![tcx.mk_imm_ptr(tcx.mk_unit())], tcx.types.usize) - } - other => { tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other }); return; diff --git a/compiler/rustc_typeck/src/check/intrinsicck.rs b/compiler/rustc_typeck/src/check/intrinsicck.rs index df94abbafb1bd..0adf0d28aae10 100644 --- a/compiler/rustc_typeck/src/check/intrinsicck.rs +++ b/compiler/rustc_typeck/src/check/intrinsicck.rs @@ -1,5 +1,5 @@ use rustc_ast::InlineAsmTemplatePiece; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_index::vec::Idx; diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 8f5f3657fc972..416d33c7aa040 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -343,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { OP: FnOnce(ProbeContext<'a, 'tcx>) -> Result>, { let mut orig_values = OriginalQueryValues::default(); - let param_env_and_self_ty = self.canonicalize_query( + let param_env_and_self_ty = self.infcx.canonicalize_query( ParamEnvAnd { param_env: self.param_env, value: self_ty }, &mut orig_values, ); @@ -351,7 +351,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let steps = if mode == Mode::MethodCall { self.tcx.method_autoderef_steps(param_env_and_self_ty) } else { - self.probe(|_| { + self.infcx.probe(|_| { // Mode::Path - the deref steps is "trivial". This turns // our CanonicalQuery into a "trivial" QueryResponse. This // is a bit inefficient, but I don't think that writing diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 56fcd9e0a8907..7f96e421a9ae3 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -865,26 +865,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .join("\n"); let actual_prefix = actual.prefix_string(self.tcx); info!("unimplemented_traits.len() == {}", unimplemented_traits.len()); - let (primary_message, label) = - if unimplemented_traits.len() == 1 && unimplemented_traits_only { - unimplemented_traits - .into_iter() - .next() - .map(|(_, (trait_ref, obligation))| { - if trait_ref.self_ty().references_error() - || actual.references_error() - { - // Avoid crashing. - return (None, None); - } - let OnUnimplementedNote { message, label, .. } = - self.on_unimplemented_note(trait_ref, &obligation); - (message, label) - }) - .unwrap_or((None, None)) - } else { - (None, None) - }; + let (primary_message, label) = if unimplemented_traits.len() == 1 + && unimplemented_traits_only + { + unimplemented_traits + .into_iter() + .next() + .map(|(_, (trait_ref, obligation))| { + if trait_ref.self_ty().references_error() + || actual.references_error() + { + // Avoid crashing. + return (None, None); + } + let OnUnimplementedNote { message, label, .. } = + self.infcx.on_unimplemented_note(trait_ref, &obligation); + (message, label) + }) + .unwrap_or((None, None)) + } else { + (None, None) + }; let primary_message = primary_message.unwrap_or_else(|| format!( "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied" )); @@ -1122,7 +1123,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { add a `use` for {one_of_them}:", an = if candidates.len() == 1 { "an" } else { "" }, s = pluralize!(candidates.len()), - were = pluralize!("was", candidates.len()), + were = if candidates.len() == 1 { "was" } else { "were" }, one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" }, ); self.suggest_use_candidates(&mut err, help, candidates); @@ -1647,7 +1648,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call: &hir::Expr<'_>, span: Span, ) { - let output_ty = match self.get_impl_future_output_ty(ty) { + let output_ty = match self.infcx.get_impl_future_output_ty(ty) { Some(output_ty) => self.resolve_vars_if_possible(output_ty).skip_binder(), _ => return, }; diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 17c2e4868aac7..2b037c3fd2b0e 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -87,10 +87,10 @@ mod op; mod pat; mod place_op; mod region; -pub mod regionck; +mod regionck; pub mod rvalue_scopes; mod upvar; -pub mod wfcheck; +mod wfcheck; pub mod writeback; use check::{check_abi, check_fn, check_mod_item_types}; @@ -128,7 +128,8 @@ use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; -use std::cell::RefCell; + +use std::cell::{Ref, RefCell, RefMut}; use crate::require_c_abi_if_c_variadic; use crate::util::common::indenter; @@ -899,6 +900,32 @@ enum TupleArgumentsFlag { TupleArguments, } +/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field. +#[derive(Copy, Clone)] +struct MaybeInProgressTables<'a, 'tcx> { + maybe_typeck_results: Option<&'a RefCell>>, +} + +impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> { + fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> { + match self.maybe_typeck_results { + Some(typeck_results) => typeck_results.borrow(), + None => bug!( + "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results" + ), + } + } + + fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> { + match self.maybe_typeck_results { + Some(typeck_results) => typeck_results.borrow_mut(), + None => bug!( + "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results" + ), + } + } +} + fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) { tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id)); } diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 920b3e688089b..9858cd8fa1970 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -475,7 +475,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { suggest_deref_binop(lhs_deref_ty); } else if is_assign == IsAssign::No && let Ref(_, lhs_deref_ty, _) = lhs_ty.kind() { - if self.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty, lhs_expr.span) { + if self.infcx.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty, lhs_expr.span) { suggest_deref_binop(*lhs_deref_ty); } } @@ -523,7 +523,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, }; - self.suggest_restricting_param_bound( + self.infcx.suggest_restricting_param_bound( &mut err, trait_pred, proj_pred, @@ -740,7 +740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error.obligation.predicate.to_opt_poly_trait_pred() }); for pred in predicates { - self.suggest_restricting_param_bound( + self.infcx.suggest_restricting_param_bound( &mut err, pred, None, diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index d49a6138f7a02..1c3c5f999bca8 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -1,5 +1,5 @@ use crate::outlives::outlives_bounds::InferCtxtExt as _; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_set::FxHashSet; use rustc_hir as hir; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::InferCtxt; diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index d72e215934a0d..3bd3e2d80917d 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -49,7 +49,8 @@ use rustc_span::sym; use rustc_span::{BytePos, Pos, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::stable_map::FxHashMap; +use rustc_data_structures::stable_set::FxHashSet; use rustc_index::vec::Idx; use rustc_target::abi::VariantIdx; @@ -948,7 +949,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let root_var_min_capture_list = min_captures.and_then(|m| m.get(&var_hir_id))?; - let ty = self.resolve_vars_if_possible(self.node_ty(var_hir_id)); + let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id)); let ty = match closure_clause { hir::CaptureBy::Value => ty, // For move closure the capture kind should be by value @@ -1064,7 +1065,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { closure_clause: hir::CaptureBy, var_hir_id: hir::HirId, ) -> Option> { - let ty = self.resolve_vars_if_possible(self.node_ty(var_hir_id)); + let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id)); if !ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local())) { debug!("does not have significant drop"); diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index faab862cc3c3c..6df59ea10969c 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -2,13 +2,14 @@ use crate::check::regionck::OutlivesEnvironmentExt; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; -use rustc_infer::infer::outlives::env::{OutlivesEnvironment, RegionBoundPairs}; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::obligations::TypeOutlives; +use rustc_infer::infer::region_constraints::GenericKind; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::Normalized; use rustc_middle::ty::query::Providers; @@ -182,7 +183,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { // We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span. match (tcx.impl_polarity(def_id), impl_.polarity) { (ty::ImplPolarity::Positive, _) => { - check_impl(tcx, item, impl_.self_ty, &impl_.of_trait, impl_.constness); + check_impl(tcx, item, impl_.self_ty, &impl_.of_trait); } (ty::ImplPolarity::Negative, ast::ImplPolarity::Negative(span)) => { // FIXME(#27579): what amount of WF checking do we need for neg impls? @@ -473,7 +474,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe unsatisfied_bounds.sort(); if !unsatisfied_bounds.is_empty() { - let plural = pluralize!(unsatisfied_bounds.len()); + let plural = if unsatisfied_bounds.len() > 1 { "s" } else { "" }; let mut err = tcx.sess.struct_span_err( gat_item_hir.span, &format!("missing required bound{} on `{}`", plural, gat_item_hir.ident), @@ -688,7 +689,10 @@ fn resolve_regions_with_wf_tys<'tcx>( id: hir::HirId, param_env: ty::ParamEnv<'tcx>, wf_tys: &FxHashSet>, - add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'a, 'tcx>, &'a RegionBoundPairs<'tcx>), + add_constraints: impl for<'a> FnOnce( + &'a InferCtxt<'a, 'tcx>, + &'a Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>, + ), ) -> bool { // Unfortunately, we have to use a new `InferCtxt` each call, because // region constraints get added and solved there and we need to test each @@ -844,13 +848,29 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id)); if tcx.features().adt_const_params { + let err = match ty.peel_refs().kind() { + ty::FnPtr(_) => Some("function pointers"), + ty::RawPtr(_) => Some("raw pointers"), + _ => None, + }; + + if let Some(unsupported_type) = err { + tcx.sess.span_err( + hir_ty.span, + &format!( + "using {} as const generic parameters is forbidden", + unsupported_type + ), + ); + } + if let Some(non_structural_match_ty) = - traits::search_for_adt_const_param_violation(param.span, tcx, ty) + traits::search_for_structural_match_violation(param.span, tcx, ty, false) { // We use the same error code in both branches, because this is really the same // issue: we just special-case the message for type parameters to make it // clearer. - match non_structural_match_ty.kind() { + match ty.peel_refs().kind() { ty::Param(_) => { // Const parameters may not have type parameters as their types, // because we cannot be sure that the type parameter derives `PartialEq` @@ -882,24 +902,6 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { .note("floats do not derive `Eq` or `Ord`, which are required for const parameters") .emit(); } - ty::FnPtr(_) => { - struct_span_err!( - tcx.sess, - hir_ty.span, - E0741, - "using function pointers as const generic parameters is forbidden", - ) - .emit(); - } - ty::RawPtr(_) => { - struct_span_err!( - tcx.sess, - hir_ty.span, - E0741, - "using raw pointers as const generic parameters is forbidden", - ) - .emit(); - } _ => { let mut diag = struct_span_err!( tcx.sess, @@ -907,10 +909,10 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { E0741, "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \ the type of a const parameter", - non_structural_match_ty, + non_structural_match_ty.ty, ); - if ty == non_structural_match_ty { + if ty == non_structural_match_ty.ty { diag.span_label( hir_ty.span, format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"), @@ -1240,7 +1242,6 @@ fn check_impl<'tcx>( item: &'tcx hir::Item<'tcx>, ast_self_ty: &hir::Ty<'_>, ast_trait_ref: &Option>, - constness: hir::Constness, ) { enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| { match *ast_trait_ref { @@ -1250,19 +1251,11 @@ fn check_impl<'tcx>( // won't hold). let trait_ref = tcx.impl_trait_ref(item.def_id).unwrap(); let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref); - let trait_pred = ty::TraitPredicate { - trait_ref, - constness: match constness { - hir::Constness::Const => ty::BoundConstness::ConstIfConst, - hir::Constness::NotConst => ty::BoundConstness::NotConst, - }, - polarity: ty::ImplPolarity::Positive, - }; let obligations = traits::wf::trait_obligations( wfcx.infcx, wfcx.param_env, wfcx.body_id, - &trait_pred, + &trait_ref, ast_trait_ref.path.span, item, ); @@ -1920,7 +1913,7 @@ impl<'a, 'tcx> WfCheckingCtxt<'a, 'tcx> { } } -pub fn impl_implied_bounds<'tcx>( +pub(super) fn impl_implied_bounds<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, impl_def_id: LocalDefId, diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index fa6053ac39585..23ac638b2f430 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -5,7 +5,7 @@ use crate::check::FnCtxt; use hir::def_id::LocalDefId; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_map::FxHashMap; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -748,7 +748,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { // (e.g. keep `for<'a>` named `for<'a>`). // This allows NLL to generate error messages that // refer to the higher-ranked lifetime names written by the user. - EraseEarlyRegions { tcx: self.tcx }.fold_ty(t) + EraseEarlyRegions { tcx: self.infcx.tcx }.fold_ty(t) } Err(_) => { debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); @@ -766,7 +766,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { match self.infcx.fully_resolve(ct) { - Ok(ct) => self.tcx.erase_regions(ct), + Ok(ct) => self.infcx.tcx.erase_regions(ct), Err(_) => { debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct); self.report_const_error(ct); diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs index d8e42729ff31d..a92c37ff143b4 100644 --- a/compiler/rustc_typeck/src/coherence/builtin.rs +++ b/compiler/rustc_typeck/src/coherence/builtin.rs @@ -116,8 +116,8 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { // why this field does not implement Copy. This is useful because sometimes // it is not immediately clear why Copy is not implemented for a field, since // all we point at is the field itself. - tcx.infer_ctxt().ignoring_regions().enter(|infcx| { - let mut fulfill_cx = traits::FulfillmentContext::new(); + tcx.infer_ctxt().enter(|infcx| { + let mut fulfill_cx = traits::FulfillmentContext::new_ignoring_regions(); fulfill_cx.register_bound( &infcx, param_env, diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 60c0694ca0e45..6ec741269e8eb 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1346,8 +1346,16 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option {} - Some(rl::Region::LateBound(debruijn, _, _)) if debruijn < self.outer_index => {} - Some(rl::Region::LateBound(..) | rl::Region::Free(..)) | None => { + Some( + rl::Region::LateBound(debruijn, _, _) + | rl::Region::LateBoundAnon(debruijn, _, _), + ) if debruijn < self.outer_index => {} + Some( + rl::Region::LateBound(..) + | rl::Region::LateBoundAnon(..) + | rl::Region::Free(..), + ) + | None => { self.has_late_bound_regions = Some(lt.span); } } @@ -1921,7 +1929,7 @@ fn infer_return_ty_for_fn_sig<'tcx>( visitor.visit_ty(ty); let mut diag = bad_placeholder(tcx, visitor.0, "return type"); let ret_ty = fn_sig.skip_binder().output(); - if ret_ty.is_suggestable(tcx, false) { + if ret_ty.is_suggestable(tcx) { diag.span_suggestion( ty.span, "replace with the correct return type", @@ -1930,12 +1938,7 @@ fn infer_return_ty_for_fn_sig<'tcx>( ); } else if matches!(ret_ty.kind(), ty::FnDef(..)) { let fn_sig = ret_ty.fn_sig(tcx); - if fn_sig - .skip_binder() - .inputs_and_output - .iter() - .all(|t| t.is_suggestable(tcx, false)) - { + if fn_sig.skip_binder().inputs_and_output.iter().all(|t| t.is_suggestable(tcx)) { diag.span_suggestion( ty.span, "replace with the correct return type", @@ -2082,17 +2085,10 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { // from the trait itself that *shouldn't* be shown as the source of // an obligation and instead be skipped. Otherwise we'd use // `tcx.def_span(def_id);` - - let constness = if tcx.has_attr(def_id, sym::const_trait) { - ty::BoundConstness::ConstIfConst - } else { - ty::BoundConstness::NotConst - }; - let span = rustc_span::DUMMY_SP; result.predicates = tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once(( - ty::TraitRef::identity(tcx, def_id).with_constness(constness).to_predicate(tcx), + ty::TraitRef::identity(tcx, def_id).without_const().to_predicate(tcx), span, )))); } @@ -2774,12 +2770,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { } } else if attr.has_name(sym::rustc_allocator_nounwind) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND; - } else if attr.has_name(sym::rustc_reallocator) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR; - } else if attr.has_name(sym::rustc_deallocator) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR; - } else if attr.has_name(sym::rustc_allocator_zeroed) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED; } else if attr.has_name(sym::naked) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED; } else if attr.has_name(sym::no_mangle) { @@ -2823,37 +2813,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { ) .emit(); } - None => { - // Unfortunately, unconditionally using `llvm.used` causes - // issues in handling `.init_array` with the gold linker, - // but using `llvm.compiler.used` caused a nontrival amount - // of unintentional ecosystem breakage -- particularly on - // Mach-O targets. - // - // As a result, we emit `llvm.compiler.used` only on ELF - // targets. This is somewhat ad-hoc, but actually follows - // our pre-LLVM 13 behavior (prior to the ecosystem - // breakage), and seems to match `clang`'s behavior as well - // (both before and after LLVM 13), possibly because they - // have similar compatibility concerns to us. See - // https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146 - // and following comments for some discussion of this, as - // well as the comments in `rustc_codegen_llvm` where these - // flags are handled. - // - // Anyway, to be clear: this is still up in the air - // somewhat, and is subject to change in the future (which - // is a good thing, because this would ideally be a bit - // more firmed up). - let is_like_elf = !(tcx.sess.target.is_like_osx - || tcx.sess.target.is_like_windows - || tcx.sess.target.is_like_wasm); - codegen_fn_attrs.flags |= if is_like_elf { - CodegenFnAttrFlags::USED - } else { - CodegenFnAttrFlags::USED_LINKER - }; - } + None => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED, } } else if attr.has_name(sym::cmse_nonsecure_entry) { if !matches!(tcx.fn_sig(did).abi(), abi::Abi::C { .. }) { @@ -2979,8 +2939,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY; } else if item.has_name(sym::memtag) { codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG; - } else if item.has_name(sym::shadow_call_stack) { - codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK; } else if item.has_name(sym::thread) { codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD; } else if item.has_name(sym::hwaddress) { @@ -2988,7 +2946,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { } else { tcx.sess .struct_span_err(item.span(), "invalid argument for `no_sanitize`") - .note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread`") + .note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`") .emit(); } } diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 64ac655e0c393..faa4f3700bba8 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -335,11 +335,37 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { tcx.mk_adt(def, substs) } ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => { - find_opaque_ty_constraints_for_tait(tcx, def_id) + find_opaque_ty_constraints(tcx, def_id) } // Opaque types desugared from `impl Trait`. ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), .. }) => { - find_opaque_ty_constraints_for_rpit(tcx, def_id, owner) + let concrete_ty = tcx + .mir_borrowck(owner) + .concrete_opaque_types + .get(&def_id) + .copied() + .map(|concrete| concrete.ty) + .unwrap_or_else(|| { + let table = tcx.typeck(owner); + if let Some(_) = table.tainted_by_errors { + // Some error in the + // owner fn prevented us from populating + // the `concrete_opaque_types` table. + tcx.ty_error() + } else { + table.concrete_opaque_types.get(&def_id).copied().unwrap_or_else(|| { + // We failed to resolve the opaque type or it + // resolves to itself. We interpret this as the + // no values of the hidden type ever being constructed, + // so we can just make the hidden type be `!`. + // For backwards compatibility reasons, we fall back to + // `()` until we the diverging default is changed. + Some(tcx.mk_diverging_default()) + }).expect("RPIT always have a hidden type from typeck") + } + }); + debug!("concrete_ty = {:?}", concrete_ty); + concrete_ty } ItemKind::Trait(..) | ItemKind::TraitAlias(..) @@ -493,7 +519,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { /// fn b() -> Foo { .. } /// ``` /// -fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { +fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { use rustc_hir::{Expr, ImplItem, Item, TraitItem}; struct ConstraintLocator<'tcx> { @@ -512,9 +538,9 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T impl ConstraintLocator<'_> { #[instrument(skip(self), level = "debug")] - fn check(&mut self, item_def_id: LocalDefId) { + fn check(&mut self, def_id: LocalDefId) { // Don't try to check items that cannot possibly constrain the type. - if !self.tcx.has_typeck_results(item_def_id) { + if !self.tcx.has_typeck_results(def_id) { debug!("no constraint: no typeck results"); return; } @@ -529,20 +555,26 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T // // because we again need to reveal `Foo` so we can check whether the // // constant does not contain interior mutability. // ``` - let tables = self.tcx.typeck(item_def_id); + let tables = self.tcx.typeck(def_id); if let Some(_) = tables.tainted_by_errors { self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error() }); return; } - if !tables.concrete_opaque_types.contains_key(&self.def_id) { + if tables.concrete_opaque_types.get(&self.def_id).is_none() { debug!("no constraints in typeck results"); return; } // Use borrowck to get the type with unerased regions. - let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types; + let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types; debug!(?concrete_opaque_types); - if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) { + for &(def_id, concrete_type) in concrete_opaque_types { + if def_id != self.def_id { + // Ignore constraints for other opaque types. + continue; + } + debug!(?concrete_type, "found constraint"); + if let Some(prev) = self.found { if concrete_type.ty != prev.ty && !(concrete_type, prev).references_error() { prev.report_mismatch(&concrete_type, self.tcx); @@ -634,122 +666,6 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T } } -fn find_opaque_ty_constraints_for_rpit( - tcx: TyCtxt<'_>, - def_id: LocalDefId, - owner_def_id: LocalDefId, -) -> Ty<'_> { - use rustc_hir::{Expr, ImplItem, Item, TraitItem}; - - struct ConstraintChecker<'tcx> { - tcx: TyCtxt<'tcx>, - - /// def_id of the opaque type whose defining uses are being checked - def_id: LocalDefId, - - found: ty::OpaqueHiddenType<'tcx>, - } - - impl ConstraintChecker<'_> { - #[instrument(skip(self), level = "debug")] - fn check(&self, def_id: LocalDefId) { - // Use borrowck to get the type with unerased regions. - let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types; - debug!(?concrete_opaque_types); - for &(def_id, concrete_type) in concrete_opaque_types { - if def_id != self.def_id { - // Ignore constraints for other opaque types. - continue; - } - - debug!(?concrete_type, "found constraint"); - - if concrete_type.ty != self.found.ty - && !(concrete_type, self.found).references_error() - { - self.found.report_mismatch(&concrete_type, self.tcx); - } - } - } - } - - impl<'tcx> intravisit::Visitor<'tcx> for ConstraintChecker<'tcx> { - type NestedFilter = nested_filter::OnlyBodies; - - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() - } - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { - if let hir::ExprKind::Closure { .. } = ex.kind { - let def_id = self.tcx.hir().local_def_id(ex.hir_id); - self.check(def_id); - } - intravisit::walk_expr(self, ex); - } - fn visit_item(&mut self, it: &'tcx Item<'tcx>) { - trace!(?it.def_id); - // The opaque type itself or its children are not within its reveal scope. - if it.def_id != self.def_id { - self.check(it.def_id); - intravisit::walk_item(self, it); - } - } - fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) { - trace!(?it.def_id); - // The opaque type itself or its children are not within its reveal scope. - if it.def_id != self.def_id { - self.check(it.def_id); - intravisit::walk_impl_item(self, it); - } - } - fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { - trace!(?it.def_id); - self.check(it.def_id); - intravisit::walk_trait_item(self, it); - } - } - - let concrete = tcx.mir_borrowck(owner_def_id).concrete_opaque_types.get(&def_id).copied(); - - if let Some(concrete) = concrete { - let scope = tcx.hir().local_def_id_to_hir_id(owner_def_id); - debug!(?scope); - let mut locator = ConstraintChecker { def_id: def_id, tcx, found: concrete }; - - match tcx.hir().get(scope) { - Node::Item(it) => intravisit::walk_item(&mut locator, it), - Node::ImplItem(it) => intravisit::walk_impl_item(&mut locator, it), - Node::TraitItem(it) => intravisit::walk_trait_item(&mut locator, it), - other => bug!("{:?} is not a valid scope for an opaque type item", other), - } - } - - concrete.map(|concrete| concrete.ty).unwrap_or_else(|| { - let table = tcx.typeck(owner_def_id); - if let Some(_) = table.tainted_by_errors { - // Some error in the - // owner fn prevented us from populating - // the `concrete_opaque_types` table. - tcx.ty_error() - } else { - table - .concrete_opaque_types - .get(&def_id) - .copied() - .unwrap_or_else(|| { - // We failed to resolve the opaque type or it - // resolves to itself. We interpret this as the - // no values of the hidden type ever being constructed, - // so we can just make the hidden type be `!`. - // For backwards compatibility reasons, we fall back to - // `()` until we the diverging default is changed. - Some(tcx.mk_diverging_default()) - }) - .expect("RPIT always have a hidden type from typeck") - } - }) -} - fn infer_placeholder_type<'a>( tcx: TyCtxt<'a>, def_id: LocalDefId, diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 0438ac02ea91a..4cdec615d8290 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -244,7 +244,7 @@ pub struct UnconstrainedOpaqueType { pub struct MissingTypeParams { pub span: Span, pub def_span: Span, - pub missing_type_params: Vec, + pub missing_type_params: Vec, pub empty_generic_args: bool, } @@ -285,15 +285,7 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams { err.span_suggestion( self.span, rustc_errors::fluent::typeck::suggestion, - format!( - "{}<{}>", - snippet, - self.missing_type_params - .iter() - .map(|n| n.to_string()) - .collect::>() - .join(", ") - ), + format!("{}<{}>", snippet, self.missing_type_params.join(", ")), Applicability::HasPlaceholders, ); suggested = true; diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index f16888345e9d5..6ece955de643c 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -65,8 +65,6 @@ //! cause use after frees with purely safe code in the same way as specializing //! on traits with methods can. -use crate::check::regionck::OutlivesEnvironmentExt; -use crate::check::wfcheck::impl_implied_bounds; use crate::constrained_generic_params as cgp; use crate::errors::SubstsOnOverriddenImpl; @@ -150,15 +148,8 @@ fn get_impl_substs<'tcx>( let impl2_substs = translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node); - let mut outlives_env = OutlivesEnvironment::new(param_env); - let implied_bounds = - impl_implied_bounds(infcx.tcx, param_env, impl1_def_id, tcx.def_span(impl1_def_id)); - outlives_env.add_implied_bounds( - infcx, - implied_bounds, - tcx.hir().local_def_id_to_hir_id(impl1_def_id), - ); - infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env); + // Conservatively use an empty `ParamEnv`. + let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty()); infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env); let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else { let span = tcx.def_span(impl1_def_id); diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index 99729391e02b0..469f7d1172ae6 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -420,10 +420,12 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let provided_lt_args = self.num_provided_lifetime_args(); let provided_type_or_const_args = self.num_provided_type_or_const_args(); + let get_verb = |num_args| if num_args == 1 { "was" } else { "were" }; + let (provided_args_str, verb) = match self.gen_args_info { MissingLifetimes { .. } | ExcessLifetimes { .. } => ( format!("{} lifetime argument{}", provided_lt_args, pluralize!(provided_lt_args)), - pluralize!("was", provided_lt_args), + get_verb(provided_lt_args), ), MissingTypesOrConsts { .. } | ExcessTypesOrConsts { .. } => ( format!( @@ -431,7 +433,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { provided_type_or_const_args, pluralize!(provided_type_or_const_args) ), - pluralize!("was", provided_type_or_const_args), + get_verb(provided_type_or_const_args), ), }; diff --git a/library/alloc/benches/lib.rs b/library/alloc/benches/lib.rs index 72ac897d4f178..7dc0f7cebd535 100644 --- a/library/alloc/benches/lib.rs +++ b/library/alloc/benches/lib.rs @@ -2,7 +2,6 @@ // See https://github.com/rust-lang/rust/issues/73535#event-3477699747 #![cfg(not(target_os = "android"))] #![feature(btree_drain_filter)] -#![feature(iter_next_chunk)] #![feature(map_first_last)] #![feature(repr_simd)] #![feature(slice_partition_dedup)] diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs index 663f6b9dd1c9c..efc47327e8a86 100644 --- a/library/alloc/benches/vec.rs +++ b/library/alloc/benches/vec.rs @@ -762,23 +762,3 @@ fn bench_retain_whole_100000(b: &mut Bencher) { let mut v = black_box(vec![826u32; 100000]); b.iter(|| v.retain(|x| *x == 826u32)); } - -#[bench] -fn bench_next_chunk(b: &mut Bencher) { - let v = vec![13u8; 2048]; - - b.iter(|| { - const CHUNK: usize = 8; - - let mut sum = [0u32; CHUNK]; - let mut iter = black_box(v.clone()).into_iter(); - - while let Ok(chunk) = iter.next_chunk::() { - for i in 0..CHUNK { - sum[i] += chunk[i] as u32; - } - } - - sum - }) -} diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index cc8da7bccff75..efdc86bf57a8a 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -25,18 +25,15 @@ extern "Rust" { // (the code expanding that attribute macro generates those functions), or to call // the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`) // otherwise. - // The rustc fork of LLVM 14 and earlier also special-cases these function names to be able to optimize them + // The rustc fork of LLVM also special-cases these function names to be able to optimize them // like `malloc`, `realloc`, and `free`, respectively. #[rustc_allocator] #[rustc_allocator_nounwind] fn __rust_alloc(size: usize, align: usize) -> *mut u8; - #[cfg_attr(not(bootstrap), rustc_deallocator)] #[rustc_allocator_nounwind] fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); - #[cfg_attr(not(bootstrap), rustc_reallocator)] #[rustc_allocator_nounwind] fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8; - #[cfg_attr(not(bootstrap), rustc_allocator_zeroed)] #[rustc_allocator_nounwind] fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; } diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index cacbd54b6c246..0bddd7a990699 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -178,8 +178,6 @@ pub struct BTreeMap< length: usize, /// `ManuallyDrop` to control drop order (needs to be dropped after all the nodes). pub(super) alloc: ManuallyDrop, - // For dropck; the `Box` avoids making the `Unpin` impl more strict than before - _marker: PhantomData>, } #[stable(feature = "btree_drop", since = "1.7.0")] @@ -189,19 +187,6 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V, A: Allocator + Clone> Drop for BTr } } -// FIXME: This implementation is "wrong", but changing it would be a breaking change. -// (The bounds of the automatic `UnwindSafe` implementation have been like this since Rust 1.50.) -// Maybe we can fix it nonetheless with a crater run, or if the `UnwindSafe` -// traits are deprecated, or disarmed (no longer causing hard errors) in the future. -#[stable(feature = "btree_unwindsafe", since = "1.64.0")] -impl core::panic::UnwindSafe for BTreeMap -where - A: core::panic::UnwindSafe, - K: core::panic::RefUnwindSafe, - V: core::panic::RefUnwindSafe, -{ -} - #[stable(feature = "rust1", since = "1.0.0")] impl Clone for BTreeMap { fn clone(&self) -> BTreeMap { @@ -219,7 +204,6 @@ impl Clone for BTreeMap { root: Some(Root::new(alloc.clone())), length: 0, alloc: ManuallyDrop::new(alloc), - _marker: PhantomData, }; { @@ -583,7 +567,7 @@ impl BTreeMap { #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")] #[must_use] pub const fn new() -> BTreeMap { - BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(Global), _marker: PhantomData } + BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(Global) } } } @@ -609,7 +593,6 @@ impl BTreeMap { root: mem::replace(&mut self.root, None), length: mem::replace(&mut self.length, 0), alloc: self.alloc.clone(), - _marker: PhantomData, }); } @@ -632,7 +615,7 @@ impl BTreeMap { /// ``` #[unstable(feature = "btreemap_alloc", issue = "32838")] pub fn new_in(alloc: A) -> BTreeMap { - BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(alloc), _marker: PhantomData } + BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(alloc) } } } @@ -1337,12 +1320,7 @@ impl BTreeMap { let (new_left_len, right_len) = Root::calc_split_length(total_num, &left_root, &right_root); self.length = new_left_len; - BTreeMap { - root: Some(right_root), - length: right_len, - alloc: self.alloc.clone(), - _marker: PhantomData, - } + BTreeMap { root: Some(right_root), length: right_len, alloc: self.alloc.clone() } } /// Creates an iterator that visits all elements (key-value pairs) in @@ -1467,7 +1445,7 @@ impl BTreeMap { let mut root = Root::new(alloc.clone()); let mut length = 0; root.bulk_push(DedupSortedIter::new(iter.into_iter()), &mut length, alloc.clone()); - BTreeMap { root: Some(root), length, alloc: ManuallyDrop::new(alloc), _marker: PhantomData } + BTreeMap { root: Some(root), length, alloc: ManuallyDrop::new(alloc) } } } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 8b6f4054851dd..315469387e5ae 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -89,7 +89,6 @@ #![feature(alloc_layout_extra)] #![feature(allocator_api)] #![feature(array_chunks)] -#![feature(array_into_iter_constructors)] #![feature(array_methods)] #![feature(array_windows)] #![feature(assert_matches)] @@ -118,11 +117,8 @@ #![feature(hasher_prefixfree_extras)] #![feature(inplace_iteration)] #![feature(iter_advance_by)] -#![feature(iter_next_chunk)] #![feature(layout_for_ptr)] -#![feature(maybe_uninit_array_assume_init)] #![feature(maybe_uninit_slice)] -#![feature(maybe_uninit_uninit_array)] #![cfg_attr(test, feature(new_uninit))] #![feature(nonnull_slice_from_raw_parts)] #![feature(pattern)] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index a5118e5333b82..b1513e5e0f31c 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -317,11 +317,11 @@ use crate::vec::Vec; /// /// ```text /// 0 -/// 8 -/// 16 -/// 16 -/// 32 -/// 32 +/// 5 +/// 10 +/// 20 +/// 20 +/// 40 /// ``` /// /// At first, we have no memory allocated at all, but as we append to the diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 1b483e3fc7793..28979457b7fd3 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -2,14 +2,13 @@ use super::AsVecIntoIter; use crate::alloc::{Allocator, Global}; use crate::raw_vec::RawVec; -use core::array; use core::fmt; use core::intrinsics::arith_offset; use core::iter::{ FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce, }; use core::marker::PhantomData; -use core::mem::{self, ManuallyDrop, MaybeUninit}; +use core::mem::{self, ManuallyDrop}; #[cfg(not(no_global_oom_handling))] use core::ops::Deref; use core::ptr::{self, NonNull}; @@ -125,6 +124,7 @@ impl IntoIter { } /// Forgets to Drop the remaining elements while still allowing the backing allocation to be freed. + #[cfg(not(no_global_oom_handling))] pub(crate) fn forget_remaining_elements(&mut self) { self.ptr = self.end; } @@ -204,43 +204,6 @@ impl Iterator for IntoIter { self.len() } - #[inline] - fn next_chunk(&mut self) -> Result<[T; N], core::array::IntoIter> { - let mut raw_ary = MaybeUninit::uninit_array(); - - let len = self.len(); - - if mem::size_of::() == 0 { - if len < N { - self.forget_remaining_elements(); - // Safety: ZSTs can be conjured ex nihilo, only the amount has to be correct - return Err(unsafe { array::IntoIter::new_unchecked(raw_ary, 0..len) }); - } - - self.ptr = unsafe { arith_offset(self.ptr as *const i8, N as isize) as *mut T }; - // Safety: ditto - return Ok(unsafe { MaybeUninit::array_assume_init(raw_ary) }); - } - - if len < N { - // Safety: `len` indicates that this many elements are available and we just checked that - // it fits into the array. - unsafe { - ptr::copy_nonoverlapping(self.ptr, raw_ary.as_mut_ptr() as *mut T, len); - self.forget_remaining_elements(); - return Err(array::IntoIter::new_unchecked(raw_ary, 0..len)); - } - } - - // Safety: `len` is larger than the array size. Copy a fixed amount here to fully initialize - // the array. - return unsafe { - ptr::copy_nonoverlapping(self.ptr, raw_ary.as_mut_ptr() as *mut T, N); - self.ptr = self.ptr.add(N); - Ok(MaybeUninit::array_assume_init(raw_ary)) - }; - } - unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item where Self: TrustedRandomAccessNoCoerce, diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs index 92a32779b8e64..edf270db81d4d 100644 --- a/library/alloc/src/vec/is_zero.rs +++ b/library/alloc/src/vec/is_zero.rs @@ -17,14 +17,12 @@ macro_rules! impl_is_zero { }; } -impl_is_zero!(i8, |x| x == 0); // It is needed to impl for arrays and tuples of i8. impl_is_zero!(i16, |x| x == 0); impl_is_zero!(i32, |x| x == 0); impl_is_zero!(i64, |x| x == 0); impl_is_zero!(i128, |x| x == 0); impl_is_zero!(isize, |x| x == 0); -impl_is_zero!(u8, |x| x == 0); // It is needed to impl for arrays and tuples of u8. impl_is_zero!(u16, |x| x == 0); impl_is_zero!(u32, |x| x == 0); impl_is_zero!(u64, |x| x == 0); @@ -56,41 +54,15 @@ unsafe impl IsZero for [T; N] { fn is_zero(&self) -> bool { // Because this is generated as a runtime check, it's not obvious that // it's worth doing if the array is really long. The threshold here - // is largely arbitrary, but was picked because as of 2022-07-01 LLVM - // fails to const-fold the check in `vec![[1; 32]; n]` - // See https://github.com/rust-lang/rust/pull/97581#issuecomment-1166628022 + // is largely arbitrary, but was picked because as of 2022-05-01 LLVM + // can const-fold the check in `vec![[0; 32]; n]` but not in + // `vec![[0; 64]; n]`: https://godbolt.org/z/WTzjzfs5b // Feel free to tweak if you have better evidence. - N <= 16 && self.iter().all(IsZero::is_zero) + N <= 32 && self.iter().all(IsZero::is_zero) } } -// This is recursive macro. -macro_rules! impl_for_tuples { - // Stopper - () => { - // No use for implementing for empty tuple because it is ZST. - }; - ($first_arg:ident $(,$rest:ident)*) => { - unsafe impl <$first_arg: IsZero, $($rest: IsZero,)*> IsZero for ($first_arg, $($rest,)*){ - #[inline] - fn is_zero(&self) -> bool{ - // Destructure tuple to N references - // Rust allows to hide generic params by local variable names. - #[allow(non_snake_case)] - let ($first_arg, $($rest,)*) = self; - - $first_arg.is_zero() - $( && $rest.is_zero() )* - } - } - - impl_for_tuples!($($rest),*); - } -} - -impl_for_tuples!(A, B, C, D, E, F, G, H); - // `Option<&T>` and `Option>` are guaranteed to represent `None` as null. // For fat pointers, the bytes that would be the pointer metadata in the `Some` // variant are padding in the `None` variant, so ignoring them and diff --git a/library/alloc/src/vec/spec_from_elem.rs b/library/alloc/src/vec/spec_from_elem.rs index ff364c033ee98..de610174783c4 100644 --- a/library/alloc/src/vec/spec_from_elem.rs +++ b/library/alloc/src/vec/spec_from_elem.rs @@ -1,7 +1,6 @@ -use core::ptr; - use crate::alloc::Allocator; use crate::raw_vec::RawVec; +use core::ptr::{self}; use super::{ExtendElement, IsZero, Vec}; @@ -18,18 +17,6 @@ impl SpecFromElem for T { } } -impl SpecFromElem for T { - #[inline] - default fn from_elem(elem: T, n: usize, alloc: A) -> Vec { - if elem.is_zero() { - return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; - } - let mut v = Vec::with_capacity_in(n, alloc); - v.extend_with(n, ExtendElement(elem)); - v - } -} - impl SpecFromElem for i8 { #[inline] fn from_elem(elem: i8, n: usize, alloc: A) -> Vec { @@ -59,3 +46,15 @@ impl SpecFromElem for u8 { } } } + +impl SpecFromElem for T { + #[inline] + fn from_elem(elem: T, n: usize, alloc: A) -> Vec { + if elem.is_zero() { + return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; + } + let mut v = Vec::with_capacity_in(n, alloc); + v.extend_with(n, ExtendElement(elem)); + v + } +} diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index d83cd29ddbad9..c29e7b9c81efb 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -27,7 +27,6 @@ #![feature(binary_heap_as_slice)] #![feature(inplace_iteration)] #![feature(iter_advance_by)] -#![feature(iter_next_chunk)] #![feature(round_char_boundary)] #![feature(slice_group_by)] #![feature(slice_partition_dedup)] diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index d94da8f5f5a0e..699567be5a004 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1,5 +1,4 @@ use core::alloc::{Allocator, Layout}; -use core::iter::IntoIterator; use core::ptr::NonNull; use std::alloc::System; use std::assert_matches::assert_matches; @@ -931,15 +930,6 @@ fn test_into_iter_count() { assert_eq!([1, 2, 3].into_iter().count(), 3); } -#[test] -fn test_into_iter_next_chunk() { - let mut iter = b"lorem".to_vec().into_iter(); - - assert_eq!(iter.next_chunk().unwrap(), [b'l', b'o']); // N is inferred as 2 - assert_eq!(iter.next_chunk().unwrap(), [b'r', b'e', b'm']); // N is inferred as 3 - assert_eq!(iter.next_chunk::<4>().unwrap_err().as_slice(), &[]); // N is explicitly 4 -} - #[test] fn test_into_iter_clone() { fn iter_equal>(it: I, slice: &[i32]) { diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index fb4454c94cb33..8a37fadc56f4c 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1766,24 +1766,15 @@ impl fmt::Display for RefMut<'_, T> { /// /// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious: /// -/// - If you create a safe reference with lifetime `'a` (either a `&T` or `&mut T` reference), then -/// you must not access the data in any way that contradicts that reference for the remainder of -/// `'a`. For example, this means that if you take the `*mut T` from an `UnsafeCell` and cast it -/// to an `&T`, then the data in `T` must remain immutable (modulo any `UnsafeCell` data found -/// within `T`, of course) until that reference's lifetime expires. Similarly, if you create a `&mut -/// T` reference that is released to safe code, then you must not access the data within the -/// `UnsafeCell` until that reference expires. -/// -/// - For both `&T` without `UnsafeCell<_>` and `&mut T`, you must also not deallocate the data -/// until the reference expires. As a special exception, given an `&T`, any part of it that is -/// inside an `UnsafeCell<_>` may be deallocated during the lifetime of the reference, after the -/// last time the reference is used (dereferenced or reborrowed). Since you cannot deallocate a part -/// of what a reference points to, this means the memory an `&T` points to can be deallocted only if -/// *every part of it* (including padding) is inside an `UnsafeCell`. -/// -/// However, whenever a `&UnsafeCell` is constructed or dereferenced, it must still point to -/// live memory and the compiler is allowed to insert spurious reads if it can prove that this -/// memory has not yet been deallocated. +/// - If you create a safe reference with lifetime `'a` (either a `&T` or `&mut T` +/// reference) that is accessible by safe code (for example, because you returned it), +/// then you must not access the data in any way that contradicts that reference for the +/// remainder of `'a`. For example, this means that if you take the `*mut T` from an +/// `UnsafeCell` and cast it to an `&T`, then the data in `T` must remain immutable +/// (modulo any `UnsafeCell` data found within `T`, of course) until that reference's +/// lifetime expires. Similarly, if you create a `&mut T` reference that is released to +/// safe code, then you must not access the data within the `UnsafeCell` until that +/// reference expires. /// /// - At all times, you must avoid data races. If multiple threads have access to /// the same `UnsafeCell`, then any writes must have a proper happens-before relation to all other diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index eae567cad00e6..0bec38a877ed5 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -892,16 +892,7 @@ impl char { /// /// The general categories for numbers (`Nd` for decimal digits, `Nl` for letter-like numeric /// characters, and `No` for other numeric characters) are specified in the [Unicode Character - /// Database][ucd] [`UnicodeData.txt`]. Note that this means ideographic numbers like '三' - /// are considered alphabetic, not numeric. Please consider to use `is_ascii_digit` or `is_digit`. - /// - /// This method doesn't cover everything that could be considered a number, e.g. ideographic numbers like '三'. - /// If you want everything including characters with overlapping purposes then you might want to use - /// a unicode or language-processing library that exposes the appropriate character properties instead - /// of looking at the unicode categories. - /// - /// If you want to parse ASCII decimal digits (0-9) or ASCII base-N, use - /// `is_ascii_digit` or `is_digit` instead. + /// Database][ucd] [`UnicodeData.txt`]. /// /// [Unicode Standard]: https://www.unicode.org/versions/latest/ /// [ucd]: https://www.unicode.org/reports/tr44/ @@ -920,7 +911,6 @@ impl char { /// assert!(!'K'.is_numeric()); /// assert!(!'و'.is_numeric()); /// assert!(!'藏'.is_numeric()); - /// assert!(!'三'.is_numeric()); /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 20bb67687848f..1d3466696ed04 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -22,8 +22,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::marker::Destruct; - use self::Ordering::*; /// Trait for equality comparisons which are [partial equivalence @@ -605,8 +603,7 @@ impl Ordering { pub struct Reverse(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T); #[stable(feature = "reverse_cmp_key", since = "1.19.0")] -#[rustc_const_unstable(feature = "const_cmp", issue = "92391")] -impl const PartialOrd for Reverse { +impl PartialOrd for Reverse { #[inline] fn partial_cmp(&self, other: &Reverse) -> Option { other.0.partial_cmp(&self.0) @@ -764,7 +761,6 @@ impl Clone for Reverse { #[doc(alias = ">=")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Ord"] -#[const_trait] pub trait Ord: Eq + PartialOrd { /// This method returns an [`Ordering`] between `self` and `other`. /// @@ -800,15 +796,8 @@ pub trait Ord: Eq + PartialOrd { fn max(self, other: Self) -> Self where Self: Sized, - Self: ~const Destruct, { - // HACK(fee1-dead): go back to using `self.max_by(other, Ord::cmp)` - // when trait methods are allowed to be used when a const closure is - // expected. - match self.cmp(&other) { - Ordering::Less | Ordering::Equal => other, - Ordering::Greater => self, - } + max_by(self, other, Ord::cmp) } /// Compares and returns the minimum of two values. @@ -827,15 +816,8 @@ pub trait Ord: Eq + PartialOrd { fn min(self, other: Self) -> Self where Self: Sized, - Self: ~const Destruct, { - // HACK(fee1-dead): go back to using `self.min_by(other, Ord::cmp)` - // when trait methods are allowed to be used when a const closure is - // expected. - match self.cmp(&other) { - Ordering::Less | Ordering::Equal => self, - Ordering::Greater => other, - } + min_by(self, other, Ord::cmp) } /// Restrict a value to a certain interval. @@ -859,8 +841,6 @@ pub trait Ord: Eq + PartialOrd { fn clamp(self, min: Self, max: Self) -> Self where Self: Sized, - Self: ~const Destruct, - Self: ~const PartialOrd, { assert!(min <= max); if self < min { @@ -882,8 +862,7 @@ pub macro Ord($item:item) { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_cmp", issue = "92391")] -impl const Ord for Ordering { +impl Ord for Ordering { #[inline] fn cmp(&self, other: &Ordering) -> Ordering { (*self as i32).cmp(&(*other as i32)) @@ -891,8 +870,7 @@ impl const Ord for Ordering { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_cmp", issue = "92391")] -impl const PartialOrd for Ordering { +impl PartialOrd for Ordering { #[inline] fn partial_cmp(&self, other: &Ordering) -> Option { (*self as i32).partial_cmp(&(*other as i32)) @@ -1209,9 +1187,8 @@ pub macro PartialOrd($item:item) { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_cmp", issue = "92391")] #[cfg_attr(not(test), rustc_diagnostic_item = "cmp_min")] -pub const fn min(v1: T, v2: T) -> T { +pub fn min(v1: T, v2: T) -> T { v1.min(v2) } @@ -1273,9 +1250,8 @@ pub fn min_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_cmp", issue = "92391")] #[cfg_attr(not(test), rustc_diagnostic_item = "cmp_max")] -pub const fn max(v1: T, v2: T) -> T { +pub fn max(v1: T, v2: T) -> T { v1.max(v2) } @@ -1328,8 +1304,7 @@ mod impls { macro_rules! partial_eq_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] - impl const PartialEq for $t { + impl PartialEq for $t { #[inline] fn eq(&self, other: &$t) -> bool { (*self) == (*other) } #[inline] @@ -1339,8 +1314,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] - impl const PartialEq for () { + impl PartialEq for () { #[inline] fn eq(&self, _other: &()) -> bool { true @@ -1367,8 +1341,7 @@ mod impls { macro_rules! partial_ord_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] - impl const PartialOrd for $t { + impl PartialOrd for $t { #[inline] fn partial_cmp(&self, other: &$t) -> Option { match (*self <= *other, *self >= *other) { @@ -1391,8 +1364,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] - impl const PartialOrd for () { + impl PartialOrd for () { #[inline] fn partial_cmp(&self, _: &()) -> Option { Some(Equal) @@ -1400,8 +1372,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] - impl const PartialOrd for bool { + impl PartialOrd for bool { #[inline] fn partial_cmp(&self, other: &bool) -> Option { Some(self.cmp(other)) @@ -1413,8 +1384,7 @@ mod impls { macro_rules! ord_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] - impl const PartialOrd for $t { + impl PartialOrd for $t { #[inline] fn partial_cmp(&self, other: &$t) -> Option { Some(self.cmp(other)) @@ -1430,8 +1400,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] - impl const Ord for $t { + impl Ord for $t { #[inline] fn cmp(&self, other: &$t) -> Ordering { // The order here is important to generate more optimal assembly. @@ -1445,8 +1414,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] - impl const Ord for () { + impl Ord for () { #[inline] fn cmp(&self, _other: &()) -> Ordering { Equal @@ -1454,8 +1422,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] - impl const Ord for bool { + impl Ord for bool { #[inline] fn cmp(&self, other: &bool) -> Ordering { // Casting to i8's and converting the difference to an Ordering generates @@ -1474,8 +1441,7 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } #[unstable(feature = "never_type", issue = "35121")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] - impl const PartialEq for ! { + impl PartialEq for ! { fn eq(&self, _: &!) -> bool { *self } @@ -1485,16 +1451,14 @@ mod impls { impl Eq for ! {} #[unstable(feature = "never_type", issue = "35121")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] - impl const PartialOrd for ! { + impl PartialOrd for ! { fn partial_cmp(&self, _: &!) -> Option { *self } } #[unstable(feature = "never_type", issue = "35121")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] - impl const Ord for ! { + impl Ord for ! { fn cmp(&self, _: &!) -> Ordering { *self } @@ -1503,10 +1467,9 @@ mod impls { // & pointers #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] - impl const PartialEq<&B> for &A + impl PartialEq<&B> for &A where - A: ~const PartialEq, + A: PartialEq, { #[inline] fn eq(&self, other: &&B) -> bool { diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 81b6d5737ea75..7ae1bfd4f351a 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -96,7 +96,6 @@ use crate::intrinsics; #[inline] #[stable(feature = "unreachable", since = "1.27.0")] #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unreachable_unchecked() -> ! { // SAFETY: the safety contract for `intrinsics::unreachable` must // be upheld by the caller. diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 7e65f4ebdad8a..998f7be3f7396 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2291,16 +2291,6 @@ extern "rust-intrinsic" { /// [`std::hint::black_box`]: crate::hint::black_box #[rustc_const_unstable(feature = "const_black_box", issue = "none")] pub fn black_box(dummy: T) -> T; - - /// `ptr` must point to a vtable. - /// The intrinsic will return the size stored in that vtable. - #[cfg(not(bootstrap))] - pub fn vtable_size(ptr: *const ()) -> usize; - - /// `ptr` must point to a vtable. - /// The intrinsic will return the alignment stored in that vtable. - #[cfg(not(bootstrap))] - pub fn vtable_align(ptr: *const ()) -> usize; } // Some functions are defined here because they accidentally got made @@ -2449,7 +2439,6 @@ pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) - #[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] #[inline] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] @@ -2536,7 +2525,6 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us #[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] #[inline] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] @@ -2566,23 +2554,14 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { /// /// * `dst` must be properly aligned. /// +/// Additionally, the caller must ensure that writing `count * +/// size_of::()` bytes to the given region of memory results in a valid +/// value of `T`. Using a region of memory typed as a `T` that contains an +/// invalid value of `T` is undefined behavior. +/// /// Note that even if the effectively copied size (`count * size_of::()`) is /// `0`, the pointer must be non-null and properly aligned. /// -/// Additionally, note that changing `*dst` in this way can easily lead to undefined behavior (UB) -/// later if the written bytes are not a valid representation of some `T`. For instance, the -/// following is an **incorrect** use of this function: -/// -/// ```rust,no_run -/// unsafe { -/// let mut value: u8 = 0; -/// let ptr: *mut bool = &mut value as *mut u8 as *mut bool; -/// let _bool = ptr.read(); // This is fine, `ptr` points to a valid `bool`. -/// ptr.write_bytes(42u8, 1); // This function itself does not cause UB... -/// let _bool = ptr.read(); // ...but it makes this operation UB! ⚠️ -/// } -/// ``` -/// /// [valid]: crate::ptr#safety /// /// # Examples @@ -2599,12 +2578,43 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { /// } /// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]); /// ``` +/// +/// Creating an invalid value: +/// +/// ``` +/// use std::ptr; +/// +/// let mut v = Box::new(0i32); +/// +/// unsafe { +/// // Leaks the previously held value by overwriting the `Box` with +/// // a null pointer. +/// ptr::write_bytes(&mut v as *mut Box, 0, 1); +/// } +/// +/// // At this point, using or dropping `v` results in undefined behavior. +/// // drop(v); // ERROR +/// +/// // Even leaking `v` "uses" it, and hence is undefined behavior. +/// // mem::forget(v); // ERROR +/// +/// // In fact, `v` is invalid according to basic type layout invariants, so *any* +/// // operation touching it is undefined behavior. +/// // let v2 = v; // ERROR +/// +/// unsafe { +/// // Let us instead put in a valid value +/// ptr::write(&mut v as *mut Box, Box::new(42i32)); +/// } +/// +/// // Now the box is fine +/// assert_eq!(*v, 42); +/// ``` #[doc(alias = "memset")] #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 24742bb49b9a5..f24a7ab61ae89 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -105,7 +105,6 @@ #![feature(const_cell_into_inner)] #![feature(const_char_convert)] #![feature(const_clone)] -#![feature(const_cmp)] #![feature(const_discriminant)] #![feature(const_eval_select)] #![feature(const_float_bits_conv)] @@ -164,7 +163,6 @@ #![feature(allow_internal_unstable)] #![feature(associated_type_bounds)] #![feature(auto_traits)] -#![feature(cfg_sanitize)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_has_atomic_equal_alignment)] #![feature(const_fn_floating_point_arithmetic)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 3a115a8b8b6c6..bd62bc5c3056c 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -496,9 +496,10 @@ macro_rules! r#try { #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "write_macro")] macro_rules! write { - ($dst:expr, $($arg:tt)*) => { - $dst.write_fmt($crate::format_args!($($arg)*)) - }; + ($dst:expr, $($arg:tt)*) => {{ + let result = $dst.write_fmt($crate::format_args!($($arg)*)); + result + }}; } /// Write formatted data into a buffer, with a newline appended. @@ -553,9 +554,10 @@ macro_rules! writeln { ($dst:expr $(,)?) => { $crate::write!($dst, "\n") }; - ($dst:expr, $($arg:tt)*) => { - $dst.write_fmt($crate::format_args_nl!($($arg)*)) - }; + ($dst:expr, $($arg:tt)*) => {{ + let result = $dst.write_fmt($crate::format_args_nl!($($arg)*)); + result + }}; } /// Indicates unreachable code. diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 6351e6fbd1374..66af491607435 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -654,8 +654,6 @@ pub unsafe fn zeroed() -> T { /// produce a value of type `T`, while doing nothing at all. /// /// **This function is deprecated.** Use [`MaybeUninit`] instead. -/// It also might be slower than using `MaybeUninit` due to mitigations that were put in place to -/// limit the potential harm caused by incorrect use of this function in legacy code. /// /// The reason for deprecation is that the function basically cannot be used /// correctly: it has the same effect as [`MaybeUninit::uninit().assume_init()`][uninit]. @@ -685,15 +683,7 @@ pub unsafe fn uninitialized() -> T { // SAFETY: the caller must guarantee that an uninitialized value is valid for `T`. unsafe { intrinsics::assert_uninit_valid::(); - let mut val = MaybeUninit::::uninit(); - - // Fill memory with 0x01, as an imperfect mitigation for old code that uses this function on - // bool, nonnull, and noundef types. But don't do this if we actively want to detect UB. - if !cfg!(any(miri, sanitize = "memory")) { - val.as_mut_ptr().write_bytes(0x01, 1); - } - - val.assume_init() + MaybeUninit::uninit().assume_init() } } @@ -1010,7 +1000,7 @@ pub fn copy(x: &T) -> T { /// /// This function will unsafely assume the pointer `src` is valid for [`size_of::`][size_of] /// bytes by transmuting `&T` to `&U` and then reading the `&U` (except that this is done in a way -/// that is correct even when `&U` has stricter alignment requirements than `&T`). It will also +/// that is correct even when `&U` makes stricter alignment requirements than `&T`). It will also /// unsafely create a copy of the contained value instead of moving out of `src`. /// /// It is not a compile-time error if `T` and `U` have different sizes, but it @@ -1134,7 +1124,6 @@ impl fmt::Debug for Discriminant { #[stable(feature = "discriminant_value", since = "1.21.0")] #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")] #[cfg_attr(not(test), rustc_diagnostic_item = "mem_discriminant")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const fn discriminant(v: &T) -> Discriminant { Discriminant(intrinsics::discriminant_value(v)) } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index a66de19bad0ed..eb458f3866e63 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -449,7 +449,6 @@ macro_rules! int_impl { without modifying the original"] #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_add(self, rhs: Self) -> Self { // SAFETY: the caller must uphold the safety contract for // `unchecked_add`. @@ -518,7 +517,6 @@ macro_rules! int_impl { without modifying the original"] #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self { // SAFETY: the caller must uphold the safety contract for // `unchecked_sub`. @@ -587,7 +585,6 @@ macro_rules! int_impl { without modifying the original"] #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self { // SAFETY: the caller must uphold the safety contract for // `unchecked_mul`. @@ -760,7 +757,6 @@ macro_rules! int_impl { without modifying the original"] #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self { // SAFETY: the caller must uphold the safety contract for // `unchecked_shl`. @@ -807,7 +803,6 @@ macro_rules! int_impl { without modifying the original"] #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self { // SAFETY: the caller must uphold the safety contract for // `unchecked_shr`. diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 73365544233eb..715e78350a499 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -459,7 +459,6 @@ macro_rules! uint_impl { without modifying the original"] #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_add(self, rhs: Self) -> Self { // SAFETY: the caller must uphold the safety contract for // `unchecked_add`. @@ -529,7 +528,6 @@ macro_rules! uint_impl { without modifying the original"] #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self { // SAFETY: the caller must uphold the safety contract for // `unchecked_sub`. @@ -576,7 +574,6 @@ macro_rules! uint_impl { without modifying the original"] #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self { // SAFETY: the caller must uphold the safety contract for // `unchecked_mul`. @@ -936,7 +933,6 @@ macro_rules! uint_impl { without modifying the original"] #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self { // SAFETY: the caller must uphold the safety contract for // `unchecked_shl`. @@ -983,7 +979,6 @@ macro_rules! uint_impl { without modifying the original"] #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self { // SAFETY: the caller must uphold the safety contract for // `unchecked_shr`. diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index b1f5559dcfc17..e34e26746c0a5 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -195,41 +195,6 @@ impl ControlFlow { ControlFlow::Break(x) => ControlFlow::Break(f(x)), } } - - /// Converts the `ControlFlow` into an `Option` which is `Some` if the - /// `ControlFlow` was `Continue` and `None` otherwise. - /// - /// # Examples - /// - /// ``` - /// #![feature(control_flow_enum)] - /// use std::ops::ControlFlow; - /// - /// assert_eq!(ControlFlow::::Break(3).continue_value(), None); - /// assert_eq!(ControlFlow::::Continue(3).continue_value(), Some(3)); - /// ``` - #[inline] - #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] - pub fn continue_value(self) -> Option { - match self { - ControlFlow::Continue(x) => Some(x), - ControlFlow::Break(..) => None, - } - } - - /// Maps `ControlFlow` to `ControlFlow` by applying a function - /// to the continue value in case it exists. - #[inline] - #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] - pub fn map_continue(self, f: F) -> ControlFlow - where - F: FnOnce(C) -> T, - { - match self { - ControlFlow::Continue(x) => ControlFlow::Continue(f(x)), - ControlFlow::Break(x) => ControlFlow::Break(x), - } - } } /// These are used only as part of implementing the iterator adapters. diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index e0655d68d2cfa..74aa0d9c7bcb2 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -97,7 +97,7 @@ impl *const T { /// refactored. #[unstable(feature = "ptr_const_cast", issue = "92675")] #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")] - pub const fn cast_mut(self) -> *mut T { + pub const fn as_mut(self) -> *mut T { self as _ } @@ -449,7 +449,6 @@ impl *const T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn offset(self, count: isize) -> *const T where T: Sized, @@ -472,7 +471,6 @@ impl *const T { #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "96283")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset`. let this = unsafe { self.cast::().offset(count).cast::<()>() }; @@ -643,7 +641,6 @@ impl *const T { #[stable(feature = "ptr_offset_from", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized, @@ -666,7 +663,6 @@ impl *const T { #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "96283")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize { // SAFETY: the caller must uphold the safety contract for `offset_from`. unsafe { self.cast::().offset_from(origin.cast::()) } @@ -730,12 +726,11 @@ impl *const T { /// } /// /// // This would be incorrect, as the pointers are not correctly ordered: - /// // ptr1.sub_ptr(ptr2) + /// // ptr1.offset_from(ptr2) /// ``` #[unstable(feature = "ptr_sub_ptr", issue = "95892")] #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn sub_ptr(self, origin: *const T) -> usize where T: Sized, @@ -867,7 +862,6 @@ impl *const T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn add(self, count: usize) -> Self where T: Sized, @@ -890,7 +884,6 @@ impl *const T { #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "96283")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add`. let this = unsafe { self.cast::().add(count).cast::<()>() }; @@ -953,7 +946,6 @@ impl *const T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn sub(self, count: usize) -> Self where T: Sized, @@ -977,7 +969,6 @@ impl *const T { #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "96283")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub`. let this = unsafe { self.cast::().sub(count).cast::<()>() }; @@ -1153,7 +1144,6 @@ impl *const T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read(self) -> T where T: Sized, @@ -1174,7 +1164,6 @@ impl *const T { /// [`ptr::read_volatile`]: crate::ptr::read_volatile() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn read_volatile(self) -> T where T: Sized, @@ -1194,7 +1183,6 @@ impl *const T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read_unaligned(self) -> T where T: Sized, @@ -1214,7 +1202,6 @@ impl *const T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn copy_to(self, dest: *mut T, count: usize) where T: Sized, @@ -1234,7 +1221,6 @@ impl *const T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) where T: Sized, diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index cd5edee0460ad..287ae69acd198 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -180,20 +180,10 @@ pub struct DynMetadata { phantom: crate::marker::PhantomData, } -#[cfg(not(bootstrap))] -extern "C" { - /// Opaque type for accessing vtables. - /// - /// Private implementation detail of `DynMetadata::size_of` etc. - /// There is conceptually not actually any Abstract Machine memory behind this pointer. - type VTable; -} - /// The common prefix of all vtables. It is followed by function pointers for trait methods. /// /// Private implementation detail of `DynMetadata::size_of` etc. #[repr(C)] -#[cfg(bootstrap)] struct VTable { drop_in_place: fn(*mut ()), size_of: usize, @@ -204,28 +194,13 @@ impl DynMetadata { /// Returns the size of the type associated with this vtable. #[inline] pub fn size_of(self) -> usize { - // Note that "size stored in vtable" is *not* the same as "result of size_of_val_raw". - // Consider a reference like `&(i32, dyn Send)`: the vtable will only store the size of the - // `Send` part! - #[cfg(bootstrap)] - return self.vtable_ptr.size_of; - #[cfg(not(bootstrap))] - // SAFETY: DynMetadata always contains a valid vtable pointer - return unsafe { - crate::intrinsics::vtable_size(self.vtable_ptr as *const VTable as *const ()) - }; + self.vtable_ptr.size_of } /// Returns the alignment of the type associated with this vtable. #[inline] pub fn align_of(self) -> usize { - #[cfg(bootstrap)] - return self.vtable_ptr.align_of; - #[cfg(not(bootstrap))] - // SAFETY: DynMetadata always contains a valid vtable pointer - return unsafe { - crate::intrinsics::vtable_align(self.vtable_ptr as *const VTable as *const ()) - }; + self.vtable_ptr.align_of } /// Returns the size and alignment together as a `Layout` diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 40e28e636d851..62548b5fadd2e 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1095,7 +1095,6 @@ pub const unsafe fn replace(dst: *mut T, mut src: T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read(src: *const T) -> T { // We are calling the intrinsics directly to avoid function calls in the generated code // as `intrinsics::copy_nonoverlapping` is a wrapper function. @@ -1195,7 +1194,6 @@ pub const unsafe fn read(src: *const T) -> T { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read_unaligned(src: *const T) -> T { let mut tmp = MaybeUninit::::uninit(); // SAFETY: the caller must guarantee that `src` is valid for reads. @@ -1292,7 +1290,6 @@ pub const unsafe fn read_unaligned(src: *const T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write(dst: *mut T, src: T) { // We are calling the intrinsics directly to avoid function calls in the generated code // as `intrinsics::copy_nonoverlapping` is a wrapper function. @@ -1390,7 +1387,6 @@ pub const unsafe fn write(dst: *mut T, src: T) { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write_unaligned(dst: *mut T, src: T) { // SAFETY: the caller must guarantee that `dst` is valid for writes. // `dst` cannot overlap `src` because the caller has mutable access @@ -1464,7 +1460,6 @@ pub const unsafe fn write_unaligned(dst: *mut T, src: T) { /// ``` #[inline] #[stable(feature = "volatile", since = "1.9.0")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn read_volatile(src: *const T) -> T { // SAFETY: the caller must uphold the safety contract for `volatile_load`. unsafe { @@ -1535,7 +1530,6 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// ``` #[inline] #[stable(feature = "volatile", since = "1.9.0")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn write_volatile(dst: *mut T, src: T) { // SAFETY: the caller must uphold the safety contract for `volatile_store`. unsafe { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index fc3dd2a9b25a9..b988090f4bc4c 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -96,13 +96,11 @@ impl *mut T { /// refactored. /// /// While not strictly required (`*mut T` coerces to `*const T`), this is provided for symmetry - /// with [`cast_mut`] on `*const T` and may have documentation value if used instead of implicit + /// with `as_mut()` on `*const T` and may have documentation value if used instead of implicit /// coercion. - /// - /// [`cast_mut`]: #method.cast_mut #[unstable(feature = "ptr_const_cast", issue = "92675")] #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")] - pub const fn cast_const(self) -> *const T { + pub const fn as_const(self) -> *const T { self as _ } @@ -291,7 +289,7 @@ impl *mut T { /// For the mutable counterpart see [`as_mut`]. /// /// [`as_uninit_ref`]: #method.as_uninit_ref-1 - /// [`as_mut`]: #method.as_mut + /// [`as_mut`]: #method.as_mut-1 /// /// # Safety /// @@ -461,7 +459,6 @@ impl *mut T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn offset(self, count: isize) -> *mut T where T: Sized, @@ -486,7 +483,6 @@ impl *mut T { #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "96283")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset`. let this = unsafe { self.cast::().offset(count).cast::<()>() }; @@ -826,7 +822,6 @@ impl *mut T { #[stable(feature = "ptr_offset_from", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized, @@ -847,7 +842,6 @@ impl *mut T { #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "96283")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize { // SAFETY: the caller must uphold the safety contract for `offset_from`. unsafe { self.cast::().offset_from(origin.cast::()) } @@ -917,7 +911,6 @@ impl *mut T { #[unstable(feature = "ptr_sub_ptr", issue = "95892")] #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn sub_ptr(self, origin: *const T) -> usize where T: Sized, @@ -981,7 +974,6 @@ impl *mut T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn add(self, count: usize) -> Self where T: Sized, @@ -1004,7 +996,6 @@ impl *mut T { #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "96283")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add`. let this = unsafe { self.cast::().add(count).cast::<()>() }; @@ -1067,7 +1058,6 @@ impl *mut T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn sub(self, count: usize) -> Self where T: Sized, @@ -1091,7 +1081,6 @@ impl *mut T { #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "96283")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub`. let this = unsafe { self.cast::().sub(count).cast::<()>() }; @@ -1267,7 +1256,6 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read(self) -> T where T: Sized, @@ -1288,7 +1276,6 @@ impl *mut T { /// [`ptr::read_volatile`]: crate::ptr::read_volatile() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn read_volatile(self) -> T where T: Sized, @@ -1308,7 +1295,6 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read_unaligned(self) -> T where T: Sized, @@ -1328,7 +1314,6 @@ impl *mut T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn copy_to(self, dest: *mut T, count: usize) where T: Sized, @@ -1348,7 +1333,6 @@ impl *mut T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) where T: Sized, @@ -1368,7 +1352,6 @@ impl *mut T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn copy_from(self, src: *const T, count: usize) where T: Sized, @@ -1388,7 +1371,6 @@ impl *mut T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize) where T: Sized, @@ -1418,7 +1400,6 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write(self, val: T) where T: Sized, @@ -1437,7 +1418,6 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write_bytes(self, val: u8, count: usize) where T: Sized, @@ -1458,7 +1438,6 @@ impl *mut T { /// [`ptr::write_volatile`]: crate::ptr::write_volatile() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn write_volatile(self, val: T) where T: Sized, @@ -1478,7 +1457,6 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write_unaligned(self, val: T) where T: Sized, diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 45b052c824d31..8a68cdf7d651b 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1009,15 +1009,6 @@ impl Result { /// Returns the contained [`Ok`] value, consuming the `self` value. /// - /// Because this function may panic, its use is generally discouraged. - /// Instead, prefer to use pattern matching and handle the [`Err`] - /// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or - /// [`unwrap_or_default`]. - /// - /// [`unwrap_or`]: Result::unwrap_or - /// [`unwrap_or_else`]: Result::unwrap_or_else - /// [`unwrap_or_default`]: Result::unwrap_or_default - /// /// # Panics /// /// Panics if the value is an [`Err`], with a panic message including the diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 76b4a534e5db5..a1889e3d21cb8 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1628,21 +1628,14 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Chunks<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ChunksMut<'a, T: 'a> { - /// # Safety - /// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally, - /// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot - /// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing - /// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw - /// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap. - v: *mut [T], + v: &'a mut [T], chunk_size: usize, - _marker: PhantomData<&'a mut T>, } impl<'a, T: 'a> ChunksMut<'a, T> { #[inline] pub(super) fn new(slice: &'a mut [T], size: usize) -> Self { - Self { v: slice, chunk_size: size, _marker: PhantomData } + Self { v: slice, chunk_size: size } } } @@ -1656,11 +1649,10 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { None } else { let sz = cmp::min(self.v.len(), self.chunk_size); - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (head, tail) = unsafe { self.v.split_at_mut(sz) }; + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(sz); self.v = tail; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *head }) + Some(head) } } @@ -1692,13 +1684,11 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { Some(sum) => cmp::min(self.v.len(), sum), None => self.v.len(), }; - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (head, tail) = unsafe { self.v.split_at_mut(end) }; - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (_, nth) = unsafe { head.split_at_mut(start) }; + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(end); + let (_, nth) = head.split_at_mut(start); self.v = tail; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *nth }) + Some(nth) } } @@ -1708,14 +1698,13 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { None } else { let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *self.v.get_unchecked_mut(start..) }) + Some(&mut self.v[start..]) } } unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let start = idx * self.chunk_size; - // SAFETY: see comments for `Chunks::__iterator_get_unchecked` and `self.v`. + // SAFETY: see comments for `Chunks::__iterator_get_unchecked`. // // Also note that the caller also guarantees that we're never called // with the same index again, and that no other methods that will @@ -1737,12 +1726,12 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { } else { let remainder = self.v.len() % self.chunk_size; let sz = if remainder != 0 { remainder } else { self.chunk_size }; - let len = self.v.len(); + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); // SAFETY: Similar to `Chunks::next_back` - let (head, tail) = unsafe { self.v.split_at_mut_unchecked(len - sz) }; + let (head, tail) = unsafe { tmp.split_at_mut_unchecked(tmp_len - sz) }; self.v = head; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *tail }) + Some(tail) } } @@ -1758,13 +1747,10 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { Some(res) => cmp::min(self.v.len(), res), None => self.v.len(), }; - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (temp, _tail) = unsafe { self.v.split_at_mut(end) }; - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (head, nth_back) = unsafe { temp.split_at_mut(start) }; + let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (head, nth_back) = temp.split_at_mut(start); self.v = head; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *nth_back }) + Some(nth_back) } } } @@ -1970,16 +1956,9 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExact<'a, T> { #[stable(feature = "chunks_exact", since = "1.31.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ChunksExactMut<'a, T: 'a> { - /// # Safety - /// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally, - /// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot - /// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing - /// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw - /// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap. - v: *mut [T], - rem: &'a mut [T], // The iterator never yields from here, so this can be unique + v: &'a mut [T], + rem: &'a mut [T], chunk_size: usize, - _marker: PhantomData<&'a mut T>, } impl<'a, T> ChunksExactMut<'a, T> { @@ -1989,7 +1968,7 @@ impl<'a, T> ChunksExactMut<'a, T> { let fst_len = slice.len() - rem; // SAFETY: 0 <= fst_len <= slice.len() by construction above let (fst, snd) = unsafe { slice.split_at_mut_unchecked(fst_len) }; - Self { v: fst, rem: snd, chunk_size, _marker: PhantomData } + Self { v: fst, rem: snd, chunk_size } } /// Returns the remainder of the original slice that is not going to be @@ -2011,11 +1990,10 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> { if self.v.len() < self.chunk_size { None } else { - // SAFETY: self.chunk_size is inbounds because we compared above against self.v.len() - let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) }; + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(self.chunk_size); self.v = tail; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *head }) + Some(head) } } @@ -2037,8 +2015,8 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> { self.v = &mut []; None } else { - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (_, snd) = unsafe { self.v.split_at_mut(start) }; + let tmp = mem::replace(&mut self.v, &mut []); + let (_, snd) = tmp.split_at_mut(start); self.v = snd; self.next() } @@ -2051,7 +2029,7 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> { unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let start = idx * self.chunk_size; - // SAFETY: see comments for `Chunks::__iterator_get_unchecked` and `self.v`. + // SAFETY: see comments for `ChunksMut::__iterator_get_unchecked`. unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } } } @@ -2063,11 +2041,11 @@ impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { if self.v.len() < self.chunk_size { None } else { - // SAFETY: This subtraction is inbounds because of the check above - let (head, tail) = unsafe { self.v.split_at_mut(self.v.len() - self.chunk_size) }; + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); self.v = head; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *tail }) + Some(tail) } } @@ -2080,13 +2058,10 @@ impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { } else { let start = (len - 1 - n) * self.chunk_size; let end = start + self.chunk_size; - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (temp, _tail) = unsafe { mem::replace(&mut self.v, &mut []).split_at_mut(end) }; - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (head, nth_back) = unsafe { temp.split_at_mut(start) }; + let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (head, nth_back) = temp.split_at_mut(start); self.v = head; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *nth_back }) + Some(nth_back) } } } @@ -2670,21 +2645,14 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunks<'a, T> { #[stable(feature = "rchunks", since = "1.31.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct RChunksMut<'a, T: 'a> { - /// # Safety - /// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally, - /// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot - /// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing - /// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw - /// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap. - v: *mut [T], + v: &'a mut [T], chunk_size: usize, - _marker: PhantomData<&'a mut T>, } impl<'a, T: 'a> RChunksMut<'a, T> { #[inline] pub(super) fn new(slice: &'a mut [T], size: usize) -> Self { - Self { v: slice, chunk_size: size, _marker: PhantomData } + Self { v: slice, chunk_size: size } } } @@ -2698,16 +2666,16 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { None } else { let sz = cmp::min(self.v.len(), self.chunk_size); - let len = self.v.len(); + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); // SAFETY: split_at_mut_unchecked just requires the argument be less // than the length. This could only happen if the expression - // `len - sz` overflows. This could only happen if `sz > - // len`, which is impossible as we initialize it as the `min` of - // `self.v.len()` (e.g. `len`) and `self.chunk_size`. - let (head, tail) = unsafe { self.v.split_at_mut_unchecked(len - sz) }; + // `tmp_len - sz` overflows. This could only happen if `sz > + // tmp_len`, which is impossible as we initialize it as the `min` of + // `self.v.len()` (e.g. `tmp_len`) and `self.chunk_size`. + let (head, tail) = unsafe { tmp.split_at_mut_unchecked(tmp_len - sz) }; self.v = head; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *tail }) + Some(tail) } } @@ -2741,15 +2709,11 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { Some(sum) => sum, None => 0, }; - // SAFETY: This type ensures that self.v is a valid pointer with a correct len. - // Therefore the bounds check in split_at_mut guarantess the split point is inbounds. - let (head, tail) = unsafe { self.v.split_at_mut(start) }; - // SAFETY: This type ensures that self.v is a valid pointer with a correct len. - // Therefore the bounds check in split_at_mut guarantess the split point is inbounds. - let (nth, _) = unsafe { tail.split_at_mut(end - start) }; + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(start); + let (nth, _) = tail.split_at_mut(end - start); self.v = head; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *nth }) + Some(nth) } } @@ -2760,8 +2724,7 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { } else { let rem = self.v.len() % self.chunk_size; let end = if rem == 0 { self.chunk_size } else { rem }; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *self.v.get_unchecked_mut(0..end) }) + Some(&mut self.v[0..end]) } } @@ -2772,7 +2735,7 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { Some(start) => start, }; // SAFETY: see comments for `RChunks::__iterator_get_unchecked` and - // `ChunksMut::__iterator_get_unchecked`, `self.v`. + // `ChunksMut::__iterator_get_unchecked` unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } } } @@ -2786,11 +2749,11 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { } else { let remainder = self.v.len() % self.chunk_size; let sz = if remainder != 0 { remainder } else { self.chunk_size }; + let tmp = mem::replace(&mut self.v, &mut []); // SAFETY: Similar to `Chunks::next_back` - let (head, tail) = unsafe { self.v.split_at_mut_unchecked(sz) }; + let (head, tail) = unsafe { tmp.split_at_mut_unchecked(sz) }; self.v = tail; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *head }) + Some(head) } } @@ -2805,13 +2768,10 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { let offset_from_end = (len - 1 - n) * self.chunk_size; let end = self.v.len() - offset_from_end; let start = end.saturating_sub(self.chunk_size); - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (tmp, tail) = unsafe { self.v.split_at_mut(end) }; - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (_, nth_back) = unsafe { tmp.split_at_mut(start) }; + let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (_, nth_back) = tmp.split_at_mut(start); self.v = tail; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *nth_back }) + Some(nth_back) } } } @@ -2937,7 +2897,8 @@ impl<'a, T> Iterator for RChunksExact<'a, T> { unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let end = self.v.len() - idx * self.chunk_size; let start = end - self.chunk_size; - // SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`. + // SAFETY: + // SAFETY: mostmy identical to `Chunks::__iterator_get_unchecked`. unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } } } @@ -3020,13 +2981,7 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExact<'a, T> { #[stable(feature = "rchunks", since = "1.31.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct RChunksExactMut<'a, T: 'a> { - /// # Safety - /// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally, - /// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot - /// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing - /// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw - /// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap. - v: *mut [T], + v: &'a mut [T], rem: &'a mut [T], chunk_size: usize, } @@ -3059,12 +3014,11 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> { if self.v.len() < self.chunk_size { None } else { - let len = self.v.len(); - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (head, tail) = unsafe { self.v.split_at_mut(len - self.chunk_size) }; + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); self.v = head; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *tail }) + Some(tail) } } @@ -3086,9 +3040,9 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> { self.v = &mut []; None } else { - let len = self.v.len(); - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (fst, _) = unsafe { self.v.split_at_mut(len - end) }; + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (fst, _) = tmp.split_at_mut(tmp_len - end); self.v = fst; self.next() } @@ -3102,7 +3056,7 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> { unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let end = self.v.len() - idx * self.chunk_size; let start = end - self.chunk_size; - // SAFETY: see comments for `RChunksMut::__iterator_get_unchecked` and `self.v`. + // SAFETY: see comments for `RChunksMut::__iterator_get_unchecked`. unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } } } @@ -3114,11 +3068,10 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { if self.v.len() < self.chunk_size { None } else { - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) }; + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(self.chunk_size); self.v = tail; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *head }) + Some(head) } } @@ -3134,13 +3087,10 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { let offset = (len - n) * self.chunk_size; let start = self.v.len() - offset; let end = start + self.chunk_size; - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (tmp, tail) = unsafe { self.v.split_at_mut(end) }; - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (_, nth_back) = unsafe { tmp.split_at_mut(start) }; + let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (_, nth_back) = tmp.split_at_mut(start); self.v = tail; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *nth_back }) + Some(nth_back) } } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e6ca6ef82673e..1270a72634b9d 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3569,7 +3569,6 @@ impl [T] { /// /// ``` /// #![feature(portable_simd)] - /// use core::simd::SimdFloat; /// /// let short = &[1, 2, 3]; /// let (prefix, middle, suffix) = short.as_simd::<4>(); @@ -4101,66 +4100,6 @@ impl [[T; N]] { } } -#[cfg(not(bootstrap))] -#[cfg(not(test))] -impl [f32] { - /// Sorts the slice of floats. - /// - /// This sort is in-place (i.e. does not allocate), *O*(*n* \* log(*n*)) worst-case, and uses - /// the ordering defined by [`f32::total_cmp`]. - /// - /// # Current implementation - /// - /// This uses the same sorting algorithm as [`sort_unstable_by`](slice::sort_unstable_by). - /// - /// # Examples - /// - /// ``` - /// #![feature(sort_floats)] - /// let mut v = [2.6, -5e-8, f32::NAN, 8.29, f32::INFINITY, -1.0, 0.0, -f32::INFINITY, -0.0]; - /// - /// v.sort_floats(); - /// let sorted = [-f32::INFINITY, -1.0, -5e-8, -0.0, 0.0, 2.6, 8.29, f32::INFINITY, f32::NAN]; - /// assert_eq!(&v[..8], &sorted[..8]); - /// assert!(v[8].is_nan()); - /// ``` - #[unstable(feature = "sort_floats", issue = "93396")] - #[inline] - pub fn sort_floats(&mut self) { - self.sort_unstable_by(f32::total_cmp); - } -} - -#[cfg(not(bootstrap))] -#[cfg(not(test))] -impl [f64] { - /// Sorts the slice of floats. - /// - /// This sort is in-place (i.e. does not allocate), *O*(*n* \* log(*n*)) worst-case, and uses - /// the ordering defined by [`f64::total_cmp`]. - /// - /// # Current implementation - /// - /// This uses the same sorting algorithm as [`sort_unstable_by`](slice::sort_unstable_by). - /// - /// # Examples - /// - /// ``` - /// #![feature(sort_floats)] - /// let mut v = [2.6, -5e-8, f64::NAN, 8.29, f64::INFINITY, -1.0, 0.0, -f64::INFINITY, -0.0]; - /// - /// v.sort_floats(); - /// let sorted = [-f64::INFINITY, -1.0, -5e-8, -0.0, 0.0, 2.6, 8.29, f64::INFINITY, f64::NAN]; - /// assert_eq!(&v[..8], &sorted[..8]); - /// assert!(v[8].is_nan()); - /// ``` - #[unstable(feature = "sort_floats", issue = "93396")] - #[inline] - pub fn sort_floats(&mut self) { - self.sort_unstable_by(f64::total_cmp); - } -} - trait CloneFromSpec { fn spec_clone_from(&mut self, src: &[T]); } diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 5e2e0c4d8cc1b..b636dc491a4b1 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -449,7 +449,6 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn load(&self, order: Ordering) -> bool { // SAFETY: any data races are prevented by atomic intrinsics and the raw // pointer passed in is valid because we got it from a reference. @@ -477,7 +476,6 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn store(&self, val: bool, order: Ordering) { // SAFETY: any data races are prevented by atomic intrinsics and the raw // pointer passed in is valid because we got it from a reference. @@ -509,7 +507,6 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(target_has_atomic = "8")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn swap(&self, val: bool, order: Ordering) -> bool { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 } @@ -566,7 +563,6 @@ impl AtomicBool { note = "Use `compare_exchange` or `compare_exchange_weak` instead" )] #[cfg(target_has_atomic = "8")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool { match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) { Ok(x) => x, @@ -614,7 +610,6 @@ impl AtomicBool { #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[doc(alias = "compare_and_swap")] #[cfg(target_has_atomic = "8")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_exchange( &self, current: bool, @@ -669,7 +664,6 @@ impl AtomicBool { #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[doc(alias = "compare_and_swap")] #[cfg(target_has_atomic = "8")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_exchange_weak( &self, current: bool, @@ -721,7 +715,6 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(target_has_atomic = "8")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_and(&self, val: bool, order: Ordering) -> bool { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_and(self.v.get(), val as u8, order) != 0 } @@ -763,7 +756,6 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(target_has_atomic = "8")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool { // We can't use atomic_nand here because it can result in a bool with // an invalid value. This happens because the atomic operation is done @@ -815,7 +807,6 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(target_has_atomic = "8")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_or(&self, val: bool, order: Ordering) -> bool { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_or(self.v.get(), val as u8, order) != 0 } @@ -856,7 +847,6 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(target_has_atomic = "8")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 } @@ -894,7 +884,6 @@ impl AtomicBool { #[inline] #[unstable(feature = "atomic_bool_fetch_not", issue = "98485")] #[cfg(target_has_atomic = "8")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_not(&self, order: Ordering) -> bool { self.fetch_xor(true, order) } @@ -969,7 +958,6 @@ impl AtomicBool { #[inline] #[stable(feature = "atomic_fetch_update", since = "1.53.0")] #[cfg(target_has_atomic = "8")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_update( &self, set_order: Ordering, @@ -1177,7 +1165,6 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn load(&self, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_load(self.p.get(), order) } @@ -1206,7 +1193,6 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn store(&self, ptr: *mut T, order: Ordering) { // SAFETY: data races are prevented by atomic intrinsics. unsafe { @@ -1239,7 +1225,6 @@ impl AtomicPtr { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(target_has_atomic = "ptr")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_swap(self.p.get(), ptr, order) } @@ -1295,7 +1280,6 @@ impl AtomicPtr { note = "Use `compare_exchange` or `compare_exchange_weak` instead" )] #[cfg(target_has_atomic = "ptr")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T { match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) { Ok(x) => x, @@ -1335,7 +1319,6 @@ impl AtomicPtr { #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[cfg(target_has_atomic = "ptr")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_exchange( &self, current: *mut T, @@ -1384,7 +1367,6 @@ impl AtomicPtr { #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[cfg(target_has_atomic = "ptr")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_exchange_weak( &self, current: *mut T, @@ -1445,7 +1427,6 @@ impl AtomicPtr { #[inline] #[stable(feature = "atomic_fetch_update", since = "1.53.0")] #[cfg(target_has_atomic = "ptr")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_update( &self, set_order: Ordering, @@ -1501,7 +1482,6 @@ impl AtomicPtr { #[inline] #[cfg(target_has_atomic = "ptr")] #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_ptr_add(&self, val: usize, order: Ordering) -> *mut T { self.fetch_byte_add(val.wrapping_mul(core::mem::size_of::()), order) } @@ -1546,7 +1526,6 @@ impl AtomicPtr { #[inline] #[cfg(target_has_atomic = "ptr")] #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_ptr_sub(&self, val: usize, order: Ordering) -> *mut T { self.fetch_byte_sub(val.wrapping_mul(core::mem::size_of::()), order) } @@ -1582,7 +1561,6 @@ impl AtomicPtr { #[inline] #[cfg(target_has_atomic = "ptr")] #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T { #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. @@ -1626,7 +1604,6 @@ impl AtomicPtr { #[inline] #[cfg(target_has_atomic = "ptr")] #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T { #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. @@ -1685,7 +1662,6 @@ impl AtomicPtr { #[inline] #[cfg(target_has_atomic = "ptr")] #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T { #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. @@ -1743,7 +1719,6 @@ impl AtomicPtr { #[inline] #[cfg(target_has_atomic = "ptr")] #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T { #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. @@ -1799,7 +1774,6 @@ impl AtomicPtr { #[inline] #[cfg(target_has_atomic = "ptr")] #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T { #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. @@ -2111,7 +2085,6 @@ macro_rules! atomic_int { /// ``` #[inline] #[$stable] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn load(&self, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_load(self.v.get(), order) } @@ -2138,7 +2111,6 @@ macro_rules! atomic_int { /// ``` #[inline] #[$stable] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn store(&self, val: $int_type, order: Ordering) { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_store(self.v.get(), val, order); } @@ -2166,7 +2138,6 @@ macro_rules! atomic_int { #[inline] #[$stable] #[$cfg_cas] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_swap(self.v.get(), val, order) } @@ -2224,7 +2195,6 @@ macro_rules! atomic_int { note = "Use `compare_exchange` or `compare_exchange_weak` instead") ] #[$cfg_cas] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_and_swap(&self, current: $int_type, new: $int_type, @@ -2278,7 +2248,6 @@ macro_rules! atomic_int { #[inline] #[$stable_cxchg] #[$cfg_cas] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_exchange(&self, current: $int_type, new: $int_type, @@ -2327,7 +2296,6 @@ macro_rules! atomic_int { #[inline] #[$stable_cxchg] #[$cfg_cas] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_exchange_weak(&self, current: $int_type, new: $int_type, @@ -2363,7 +2331,6 @@ macro_rules! atomic_int { #[inline] #[$stable] #[$cfg_cas] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_add(self.v.get(), val, order) } @@ -2393,7 +2360,6 @@ macro_rules! atomic_int { #[inline] #[$stable] #[$cfg_cas] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_sub(self.v.get(), val, order) } @@ -2426,7 +2392,6 @@ macro_rules! atomic_int { #[inline] #[$stable] #[$cfg_cas] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_and(self.v.get(), val, order) } @@ -2459,7 +2424,6 @@ macro_rules! atomic_int { #[inline] #[$stable_nand] #[$cfg_cas] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_nand(self.v.get(), val, order) } @@ -2492,7 +2456,6 @@ macro_rules! atomic_int { #[inline] #[$stable] #[$cfg_cas] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_or(self.v.get(), val, order) } @@ -2525,7 +2488,6 @@ macro_rules! atomic_int { #[inline] #[$stable] #[$cfg_cas] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_xor(self.v.get(), val, order) } @@ -2566,7 +2528,6 @@ macro_rules! atomic_int { #[inline] #[stable(feature = "no_more_cas", since = "1.45.0")] #[$cfg_cas] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_update(&self, set_order: Ordering, fetch_order: Ordering, @@ -2620,7 +2581,6 @@ macro_rules! atomic_int { #[inline] #[stable(feature = "atomic_min_max", since = "1.45.0")] #[$cfg_cas] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { $max_fn(self.v.get(), val, order) } @@ -2666,7 +2626,6 @@ macro_rules! atomic_int { #[inline] #[stable(feature = "atomic_min_max", since = "1.45.0")] #[$cfg_cas] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { $min_fn(self.v.get(), val, order) } @@ -2980,7 +2939,6 @@ fn strongest_failure_ordering(order: Ordering) -> Ordering { } #[inline] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_store(dst: *mut T, val: T, order: Ordering) { // SAFETY: the caller must uphold the safety contract for `atomic_store`. unsafe { @@ -2995,7 +2953,6 @@ unsafe fn atomic_store(dst: *mut T, val: T, order: Ordering) { } #[inline] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_load(dst: *const T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_load`. unsafe { @@ -3011,7 +2968,6 @@ unsafe fn atomic_load(dst: *const T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic = "8")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_swap`. unsafe { @@ -3028,7 +2984,6 @@ unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { /// Returns the previous value (like __sync_fetch_and_add). #[inline] #[cfg(target_has_atomic = "8")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_add`. unsafe { @@ -3045,7 +3000,6 @@ unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { /// Returns the previous value (like __sync_fetch_and_sub). #[inline] #[cfg(target_has_atomic = "8")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_sub`. unsafe { @@ -3061,7 +3015,6 @@ unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic = "8")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_compare_exchange( dst: *mut T, old: T, @@ -3104,7 +3057,6 @@ unsafe fn atomic_compare_exchange( #[inline] #[cfg(target_has_atomic = "8")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_compare_exchange_weak( dst: *mut T, old: T, @@ -3147,7 +3099,6 @@ unsafe fn atomic_compare_exchange_weak( #[inline] #[cfg(target_has_atomic = "8")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_and` unsafe { @@ -3163,7 +3114,6 @@ unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic = "8")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_nand(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_nand` unsafe { @@ -3179,7 +3129,6 @@ unsafe fn atomic_nand(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic = "8")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_or` unsafe { @@ -3195,7 +3144,6 @@ unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic = "8")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_xor` unsafe { @@ -3212,7 +3160,6 @@ unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { /// returns the max value (signed comparison) #[inline] #[cfg(target_has_atomic = "8")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_max(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_max` unsafe { @@ -3229,7 +3176,6 @@ unsafe fn atomic_max(dst: *mut T, val: T, order: Ordering) -> T { /// returns the min value (signed comparison) #[inline] #[cfg(target_has_atomic = "8")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_min(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_min` unsafe { @@ -3246,7 +3192,6 @@ unsafe fn atomic_min(dst: *mut T, val: T, order: Ordering) -> T { /// returns the max value (unsigned comparison) #[inline] #[cfg(target_has_atomic = "8")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_umax(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_umax` unsafe { @@ -3263,7 +3208,6 @@ unsafe fn atomic_umax(dst: *mut T, val: T, order: Ordering) -> T { /// returns the min value (unsigned comparison) #[inline] #[cfg(target_has_atomic = "8")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_umin(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_umin` unsafe { @@ -3354,7 +3298,6 @@ unsafe fn atomic_umin(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "fence"] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fence(order: Ordering) { // SAFETY: using an atomic fence is safe. unsafe { @@ -3437,7 +3380,6 @@ pub fn fence(order: Ordering) { #[inline] #[stable(feature = "compiler_fences", since = "1.21.0")] #[rustc_diagnostic_item = "compiler_fence"] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compiler_fence(order: Ordering) { // SAFETY: using an atomic fence is safe. unsafe { diff --git a/library/core/tests/simd.rs b/library/core/tests/simd.rs index 565c8975eb94f..5b516a72360aa 100644 --- a/library/core/tests/simd.rs +++ b/library/core/tests/simd.rs @@ -1,5 +1,4 @@ use core::simd::f32x4; -use core::simd::SimdFloat; #[test] fn testing() { diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 6d1516958f39b..5751a91721d1f 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -409,50 +409,6 @@ fn test_chunks_mut_zip() { assert_eq!(v1, [13, 14, 19, 20, 14]); } -#[test] -fn test_chunks_mut_zip_aliasing() { - let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - let mut it = v1.chunks_mut(2).zip(v2.chunks(2)); - let first = it.next().unwrap(); - let _ = it.next().unwrap(); - assert_eq!(first, (&mut [0, 1][..], &[6, 7][..])); -} - -#[test] -fn test_chunks_exact_mut_zip_aliasing() { - let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - let mut it = v1.chunks_exact_mut(2).zip(v2.chunks(2)); - let first = it.next().unwrap(); - let _ = it.next().unwrap(); - assert_eq!(first, (&mut [0, 1][..], &[6, 7][..])); -} - -#[test] -fn test_rchunks_mut_zip_aliasing() { - let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - let mut it = v1.rchunks_mut(2).zip(v2.chunks(2)); - let first = it.next().unwrap(); - let _ = it.next().unwrap(); - assert_eq!(first, (&mut [3, 4][..], &[6, 7][..])); -} - -#[test] -fn test_rchunks_exact_mut_zip_aliasing() { - let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - let mut it = v1.rchunks_exact_mut(2).zip(v2.chunks(2)); - let first = it.next().unwrap(); - let _ = it.next().unwrap(); - assert_eq!(first, (&mut [3, 4][..], &[6, 7][..])); -} - #[test] fn test_chunks_exact_count() { let v: &[i32] = &[0, 1, 2, 3, 4, 5]; diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index 8801c670bc979..6a01b4a2e2841 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -37,11 +37,12 @@ pub unsafe fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 { abort(); cfg_if::cfg_if! { - if #[cfg(any(unix, target_os = "solid_asp3"))] { + if #[cfg(unix)] { unsafe fn abort() -> ! { libc::abort(); } } else if #[cfg(any(target_os = "hermit", + target_os = "solid_asp3", all(target_vendor = "fortanix", target_env = "sgx") ))] { unsafe fn abort() -> ! { diff --git a/library/portable-simd/beginners-guide.md b/library/portable-simd/beginners-guide.md index 17ade06ae80f9..75158e5aa8550 100644 --- a/library/portable-simd/beginners-guide.md +++ b/library/portable-simd/beginners-guide.md @@ -82,10 +82,5 @@ Fortunately, most SIMD types have a fairly predictable size. `i32x4` is bit-equi However, this is not the same as alignment. Computer architectures generally prefer aligned accesses, especially when moving data between memory and vector registers, and while some support specialized operations that can bend the rules to help with this, unaligned access is still typically slow, or even undefined behavior. In addition, different architectures can require different alignments when interacting with their native SIMD types. For this reason, any `#[repr(simd)]` type has a non-portable alignment. If it is necessary to directly interact with the alignment of these types, it should be via [`mem::align_of`]. -When working with slices, data correctly aligned for SIMD can be acquired using the [`as_simd`] and [`as_simd_mut`] methods of the slice primitive. - [`mem::transmute`]: https://doc.rust-lang.org/core/mem/fn.transmute.html [`mem::align_of`]: https://doc.rust-lang.org/core/mem/fn.align_of.html -[`as_simd`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.as_simd -[`as_simd_mut`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.as_simd_mut - diff --git a/library/portable-simd/crates/core_simd/Cargo.toml b/library/portable-simd/crates/core_simd/Cargo.toml index 8a29cf15696ed..8877c6df66eda 100644 --- a/library/portable-simd/crates/core_simd/Cargo.toml +++ b/library/portable-simd/crates/core_simd/Cargo.toml @@ -9,8 +9,7 @@ categories = ["hardware-support", "no-std"] license = "MIT OR Apache-2.0" [features] -default = ["as_crate"] -as_crate = [] +default = [] std = [] generic_const_exprs = [] diff --git a/library/portable-simd/crates/core_simd/src/comparisons.rs b/library/portable-simd/crates/core_simd/src/comparisons.rs new file mode 100644 index 0000000000000..7b0d0a6864b9e --- /dev/null +++ b/library/portable-simd/crates/core_simd/src/comparisons.rs @@ -0,0 +1,120 @@ +use crate::simd::intrinsics; +use crate::simd::{LaneCount, Mask, Simd, SimdElement, SupportedLaneCount}; + +impl Simd +where + T: SimdElement + PartialEq, + LaneCount: SupportedLaneCount, +{ + /// Test if each lane is equal to the corresponding lane in `other`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn lanes_eq(self, other: Self) -> Mask { + // Safety: `self` is a vector, and the result of the comparison + // is always a valid mask. + unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) } + } + + /// Test if each lane is not equal to the corresponding lane in `other`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn lanes_ne(self, other: Self) -> Mask { + // Safety: `self` is a vector, and the result of the comparison + // is always a valid mask. + unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) } + } +} + +impl Simd +where + T: SimdElement + PartialOrd, + LaneCount: SupportedLaneCount, +{ + /// Test if each lane is less than the corresponding lane in `other`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn lanes_lt(self, other: Self) -> Mask { + // Safety: `self` is a vector, and the result of the comparison + // is always a valid mask. + unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) } + } + + /// Test if each lane is greater than the corresponding lane in `other`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn lanes_gt(self, other: Self) -> Mask { + // Safety: `self` is a vector, and the result of the comparison + // is always a valid mask. + unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) } + } + + /// Test if each lane is less than or equal to the corresponding lane in `other`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn lanes_le(self, other: Self) -> Mask { + // Safety: `self` is a vector, and the result of the comparison + // is always a valid mask. + unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) } + } + + /// Test if each lane is greater than or equal to the corresponding lane in `other`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn lanes_ge(self, other: Self) -> Mask { + // Safety: `self` is a vector, and the result of the comparison + // is always a valid mask. + unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) } + } +} + +macro_rules! impl_ord_methods_vector { + { $type:ty } => { + impl Simd<$type, LANES> + where + LaneCount: SupportedLaneCount, + { + /// Returns the lane-wise minimum with `other`. + #[must_use = "method returns a new vector and does not mutate the original value"] + #[inline] + pub fn min(self, other: Self) -> Self { + self.lanes_gt(other).select(other, self) + } + + /// Returns the lane-wise maximum with `other`. + #[must_use = "method returns a new vector and does not mutate the original value"] + #[inline] + pub fn max(self, other: Self) -> Self { + self.lanes_lt(other).select(other, self) + } + + /// Restrict each lane to a certain interval. + /// + /// For each lane, returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max` on any lane. + #[must_use = "method returns a new vector and does not mutate the original value"] + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + assert!( + min.lanes_le(max).all(), + "each lane in `min` must be less than or equal to the corresponding lane in `max`", + ); + self.max(min).min(max) + } + } + } +} + +impl_ord_methods_vector!(i8); +impl_ord_methods_vector!(i16); +impl_ord_methods_vector!(i32); +impl_ord_methods_vector!(i64); +impl_ord_methods_vector!(isize); +impl_ord_methods_vector!(u8); +impl_ord_methods_vector!(u16); +impl_ord_methods_vector!(u32); +impl_ord_methods_vector!(u64); +impl_ord_methods_vector!(usize); diff --git a/library/portable-simd/crates/core_simd/src/elements.rs b/library/portable-simd/crates/core_simd/src/elements.rs deleted file mode 100644 index 701eb66b248af..0000000000000 --- a/library/portable-simd/crates/core_simd/src/elements.rs +++ /dev/null @@ -1,11 +0,0 @@ -mod float; -mod int; -mod uint; - -mod sealed { - pub trait Sealed {} -} - -pub use float::*; -pub use int::*; -pub use uint::*; diff --git a/library/portable-simd/crates/core_simd/src/elements/float.rs b/library/portable-simd/crates/core_simd/src/elements/float.rs deleted file mode 100644 index d602232705560..0000000000000 --- a/library/portable-simd/crates/core_simd/src/elements/float.rs +++ /dev/null @@ -1,357 +0,0 @@ -use super::sealed::Sealed; -use crate::simd::{ - intrinsics, LaneCount, Mask, Simd, SimdElement, SimdPartialEq, SimdPartialOrd, - SupportedLaneCount, -}; - -/// Operations on SIMD vectors of floats. -pub trait SimdFloat: Copy + Sealed { - /// Mask type used for manipulating this SIMD vector type. - type Mask; - - /// Scalar type contained by this SIMD vector type. - type Scalar; - - /// Bit representation of this SIMD vector type. - type Bits; - - /// Raw transmutation to an unsigned integer vector type with the - /// same size and number of lanes. - #[must_use = "method returns a new vector and does not mutate the original value"] - fn to_bits(self) -> Self::Bits; - - /// Raw transmutation from an unsigned integer vector type with the - /// same size and number of lanes. - #[must_use = "method returns a new vector and does not mutate the original value"] - fn from_bits(bits: Self::Bits) -> Self; - - /// Produces a vector where every lane has the absolute value of the - /// equivalently-indexed lane in `self`. - #[must_use = "method returns a new vector and does not mutate the original value"] - fn abs(self) -> Self; - - /// Takes the reciprocal (inverse) of each lane, `1/x`. - #[must_use = "method returns a new vector and does not mutate the original value"] - fn recip(self) -> Self; - - /// Converts each lane from radians to degrees. - #[must_use = "method returns a new vector and does not mutate the original value"] - fn to_degrees(self) -> Self; - - /// Converts each lane from degrees to radians. - #[must_use = "method returns a new vector and does not mutate the original value"] - fn to_radians(self) -> Self; - - /// Returns true for each lane if it has a positive sign, including - /// `+0.0`, `NaN`s with positive sign bit and positive infinity. - #[must_use = "method returns a new mask and does not mutate the original value"] - fn is_sign_positive(self) -> Self::Mask; - - /// Returns true for each lane if it has a negative sign, including - /// `-0.0`, `NaN`s with negative sign bit and negative infinity. - #[must_use = "method returns a new mask and does not mutate the original value"] - fn is_sign_negative(self) -> Self::Mask; - - /// Returns true for each lane if its value is `NaN`. - #[must_use = "method returns a new mask and does not mutate the original value"] - fn is_nan(self) -> Self::Mask; - - /// Returns true for each lane if its value is positive infinity or negative infinity. - #[must_use = "method returns a new mask and does not mutate the original value"] - fn is_infinite(self) -> Self::Mask; - - /// Returns true for each lane if its value is neither infinite nor `NaN`. - #[must_use = "method returns a new mask and does not mutate the original value"] - fn is_finite(self) -> Self::Mask; - - /// Returns true for each lane if its value is subnormal. - #[must_use = "method returns a new mask and does not mutate the original value"] - fn is_subnormal(self) -> Self::Mask; - - /// Returns true for each lane if its value is neither zero, infinite, - /// subnormal, nor `NaN`. - #[must_use = "method returns a new mask and does not mutate the original value"] - fn is_normal(self) -> Self::Mask; - - /// Replaces each lane with a number that represents its sign. - /// - /// * `1.0` if the number is positive, `+0.0`, or `INFINITY` - /// * `-1.0` if the number is negative, `-0.0`, or `NEG_INFINITY` - /// * `NAN` if the number is `NAN` - #[must_use = "method returns a new vector and does not mutate the original value"] - fn signum(self) -> Self; - - /// Returns each lane with the magnitude of `self` and the sign of `sign`. - /// - /// For any lane containing a `NAN`, a `NAN` with the sign of `sign` is returned. - #[must_use = "method returns a new vector and does not mutate the original value"] - fn copysign(self, sign: Self) -> Self; - - /// Returns the minimum of each lane. - /// - /// If one of the values is `NAN`, then the other value is returned. - #[must_use = "method returns a new vector and does not mutate the original value"] - fn simd_min(self, other: Self) -> Self; - - /// Returns the maximum of each lane. - /// - /// If one of the values is `NAN`, then the other value is returned. - #[must_use = "method returns a new vector and does not mutate the original value"] - fn simd_max(self, other: Self) -> Self; - - /// Restrict each lane to a certain interval unless it is NaN. - /// - /// For each lane in `self`, returns the corresponding lane in `max` if the lane is - /// greater than `max`, and the corresponding lane in `min` if the lane is less - /// than `min`. Otherwise returns the lane in `self`. - #[must_use = "method returns a new vector and does not mutate the original value"] - fn simd_clamp(self, min: Self, max: Self) -> Self; - - /// Returns the sum of the lanes of the vector. - /// - /// # Examples - /// - /// ``` - /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{f32x2, SimdFloat}; - /// let v = f32x2::from_array([1., 2.]); - /// assert_eq!(v.reduce_sum(), 3.); - /// ``` - fn reduce_sum(self) -> Self::Scalar; - - /// Reducing multiply. Returns the product of the lanes of the vector. - /// - /// # Examples - /// - /// ``` - /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{f32x2, SimdFloat}; - /// let v = f32x2::from_array([3., 4.]); - /// assert_eq!(v.reduce_product(), 12.); - /// ``` - fn reduce_product(self) -> Self::Scalar; - - /// Returns the maximum lane in the vector. - /// - /// Returns values based on equality, so a vector containing both `0.` and `-0.` may - /// return either. - /// - /// This function will not return `NaN` unless all lanes are `NaN`. - /// - /// # Examples - /// - /// ``` - /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{f32x2, SimdFloat}; - /// let v = f32x2::from_array([1., 2.]); - /// assert_eq!(v.reduce_max(), 2.); - /// - /// // NaN values are skipped... - /// let v = f32x2::from_array([1., f32::NAN]); - /// assert_eq!(v.reduce_max(), 1.); - /// - /// // ...unless all values are NaN - /// let v = f32x2::from_array([f32::NAN, f32::NAN]); - /// assert!(v.reduce_max().is_nan()); - /// ``` - fn reduce_max(self) -> Self::Scalar; - - /// Returns the minimum lane in the vector. - /// - /// Returns values based on equality, so a vector containing both `0.` and `-0.` may - /// return either. - /// - /// This function will not return `NaN` unless all lanes are `NaN`. - /// - /// # Examples - /// - /// ``` - /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{f32x2, SimdFloat}; - /// let v = f32x2::from_array([3., 7.]); - /// assert_eq!(v.reduce_min(), 3.); - /// - /// // NaN values are skipped... - /// let v = f32x2::from_array([1., f32::NAN]); - /// assert_eq!(v.reduce_min(), 1.); - /// - /// // ...unless all values are NaN - /// let v = f32x2::from_array([f32::NAN, f32::NAN]); - /// assert!(v.reduce_min().is_nan()); - /// ``` - fn reduce_min(self) -> Self::Scalar; -} - -macro_rules! impl_trait { - { $($ty:ty { bits: $bits_ty:ty, mask: $mask_ty:ty }),* } => { - $( - impl Sealed for Simd<$ty, LANES> - where - LaneCount: SupportedLaneCount, - { - } - - impl SimdFloat for Simd<$ty, LANES> - where - LaneCount: SupportedLaneCount, - { - type Mask = Mask<<$mask_ty as SimdElement>::Mask, LANES>; - type Scalar = $ty; - type Bits = Simd<$bits_ty, LANES>; - - #[inline] - fn to_bits(self) -> Simd<$bits_ty, LANES> { - assert_eq!(core::mem::size_of::(), core::mem::size_of::()); - // Safety: transmuting between vector types is safe - unsafe { core::mem::transmute_copy(&self) } - } - - #[inline] - fn from_bits(bits: Simd<$bits_ty, LANES>) -> Self { - assert_eq!(core::mem::size_of::(), core::mem::size_of::()); - // Safety: transmuting between vector types is safe - unsafe { core::mem::transmute_copy(&bits) } - } - - #[inline] - fn abs(self) -> Self { - // Safety: `self` is a float vector - unsafe { intrinsics::simd_fabs(self) } - } - - #[inline] - fn recip(self) -> Self { - Self::splat(1.0) / self - } - - #[inline] - fn to_degrees(self) -> Self { - // to_degrees uses a special constant for better precision, so extract that constant - self * Self::splat(Self::Scalar::to_degrees(1.)) - } - - #[inline] - fn to_radians(self) -> Self { - self * Self::splat(Self::Scalar::to_radians(1.)) - } - - #[inline] - fn is_sign_positive(self) -> Self::Mask { - !self.is_sign_negative() - } - - #[inline] - fn is_sign_negative(self) -> Self::Mask { - let sign_bits = self.to_bits() & Simd::splat((!0 >> 1) + 1); - sign_bits.simd_gt(Simd::splat(0)) - } - - #[inline] - fn is_nan(self) -> Self::Mask { - self.simd_ne(self) - } - - #[inline] - fn is_infinite(self) -> Self::Mask { - self.abs().simd_eq(Self::splat(Self::Scalar::INFINITY)) - } - - #[inline] - fn is_finite(self) -> Self::Mask { - self.abs().simd_lt(Self::splat(Self::Scalar::INFINITY)) - } - - #[inline] - fn is_subnormal(self) -> Self::Mask { - self.abs().simd_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(Self::Scalar::INFINITY).to_bits()).simd_eq(Simd::splat(0)) - } - - #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] - fn is_normal(self) -> Self::Mask { - !(self.abs().simd_eq(Self::splat(0.0)) | self.is_nan() | self.is_subnormal() | self.is_infinite()) - } - - #[inline] - fn signum(self) -> Self { - self.is_nan().select(Self::splat(Self::Scalar::NAN), Self::splat(1.0).copysign(self)) - } - - #[inline] - fn copysign(self, sign: Self) -> Self { - let sign_bit = sign.to_bits() & Self::splat(-0.).to_bits(); - let magnitude = self.to_bits() & !Self::splat(-0.).to_bits(); - Self::from_bits(sign_bit | magnitude) - } - - #[inline] - fn simd_min(self, other: Self) -> Self { - // Safety: `self` and `other` are float vectors - unsafe { intrinsics::simd_fmin(self, other) } - } - - #[inline] - fn simd_max(self, other: Self) -> Self { - // Safety: `self` and `other` are floating point vectors - unsafe { intrinsics::simd_fmax(self, other) } - } - - #[inline] - fn simd_clamp(self, min: Self, max: Self) -> Self { - assert!( - min.simd_le(max).all(), - "each lane in `min` must be less than or equal to the corresponding lane in `max`", - ); - let mut x = self; - x = x.simd_lt(min).select(min, x); - x = x.simd_gt(max).select(max, x); - x - } - - #[inline] - fn reduce_sum(self) -> Self::Scalar { - // LLVM sum is inaccurate on i586 - if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) { - self.as_array().iter().sum() - } else { - // Safety: `self` is a float vector - unsafe { intrinsics::simd_reduce_add_ordered(self, 0.) } - } - } - - #[inline] - fn reduce_product(self) -> Self::Scalar { - // LLVM product is inaccurate on i586 - if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) { - self.as_array().iter().product() - } else { - // Safety: `self` is a float vector - unsafe { intrinsics::simd_reduce_mul_ordered(self, 1.) } - } - } - - #[inline] - fn reduce_max(self) -> Self::Scalar { - // Safety: `self` is a float vector - unsafe { intrinsics::simd_reduce_max(self) } - } - - #[inline] - fn reduce_min(self) -> Self::Scalar { - // Safety: `self` is a float vector - unsafe { intrinsics::simd_reduce_min(self) } - } - } - )* - } -} - -impl_trait! { f32 { bits: u32, mask: i32 }, f64 { bits: u64, mask: i64 } } diff --git a/library/portable-simd/crates/core_simd/src/elements/int.rs b/library/portable-simd/crates/core_simd/src/elements/int.rs deleted file mode 100644 index 9b8c37ed466ec..0000000000000 --- a/library/portable-simd/crates/core_simd/src/elements/int.rs +++ /dev/null @@ -1,298 +0,0 @@ -use super::sealed::Sealed; -use crate::simd::{ - intrinsics, LaneCount, Mask, Simd, SimdElement, SimdPartialOrd, SupportedLaneCount, -}; - -/// Operations on SIMD vectors of signed integers. -pub trait SimdInt: Copy + Sealed { - /// Mask type used for manipulating this SIMD vector type. - type Mask; - - /// Scalar type contained by this SIMD vector type. - type Scalar; - - /// Lanewise saturating add. - /// - /// # Examples - /// ``` - /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdInt}; - /// use core::i32::{MIN, MAX}; - /// let x = Simd::from_array([MIN, 0, 1, MAX]); - /// let max = Simd::splat(MAX); - /// let unsat = x + max; - /// let sat = x.saturating_add(max); - /// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2])); - /// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX])); - /// ``` - fn saturating_add(self, second: Self) -> Self; - - /// Lanewise saturating subtract. - /// - /// # Examples - /// ``` - /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdInt}; - /// use core::i32::{MIN, MAX}; - /// let x = Simd::from_array([MIN, -2, -1, MAX]); - /// let max = Simd::splat(MAX); - /// let unsat = x - max; - /// let sat = x.saturating_sub(max); - /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0])); - /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0])); - fn saturating_sub(self, second: Self) -> Self; - - /// Lanewise absolute value, implemented in Rust. - /// Every lane becomes its absolute value. - /// - /// # Examples - /// ``` - /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdInt}; - /// use core::i32::{MIN, MAX}; - /// let xs = Simd::from_array([MIN, MIN +1, -5, 0]); - /// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0])); - /// ``` - fn abs(self) -> Self; - - /// Lanewise saturating absolute value, implemented in Rust. - /// As abs(), except the MIN value becomes MAX instead of itself. - /// - /// # Examples - /// ``` - /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdInt}; - /// use core::i32::{MIN, MAX}; - /// let xs = Simd::from_array([MIN, -2, 0, 3]); - /// let unsat = xs.abs(); - /// let sat = xs.saturating_abs(); - /// assert_eq!(unsat, Simd::from_array([MIN, 2, 0, 3])); - /// assert_eq!(sat, Simd::from_array([MAX, 2, 0, 3])); - /// ``` - fn saturating_abs(self) -> Self; - - /// Lanewise saturating negation, implemented in Rust. - /// As neg(), except the MIN value becomes MAX instead of itself. - /// - /// # Examples - /// ``` - /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdInt}; - /// use core::i32::{MIN, MAX}; - /// let x = Simd::from_array([MIN, -2, 3, MAX]); - /// let unsat = -x; - /// let sat = x.saturating_neg(); - /// assert_eq!(unsat, Simd::from_array([MIN, 2, -3, MIN + 1])); - /// assert_eq!(sat, Simd::from_array([MAX, 2, -3, MIN + 1])); - /// ``` - fn saturating_neg(self) -> Self; - - /// Returns true for each positive lane and false if it is zero or negative. - fn is_positive(self) -> Self::Mask; - - /// Returns true for each negative lane and false if it is zero or positive. - fn is_negative(self) -> Self::Mask; - - /// Returns numbers representing the sign of each lane. - /// * `0` if the number is zero - /// * `1` if the number is positive - /// * `-1` if the number is negative - fn signum(self) -> Self; - - /// Returns the sum of the lanes of the vector, with wrapping addition. - /// - /// # Examples - /// - /// ``` - /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{i32x4, SimdInt}; - /// let v = i32x4::from_array([1, 2, 3, 4]); - /// assert_eq!(v.reduce_sum(), 10); - /// - /// // SIMD integer addition is always wrapping - /// let v = i32x4::from_array([i32::MAX, 1, 0, 0]); - /// assert_eq!(v.reduce_sum(), i32::MIN); - /// ``` - fn reduce_sum(self) -> Self::Scalar; - - /// Returns the product of the lanes of the vector, with wrapping multiplication. - /// - /// # Examples - /// - /// ``` - /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{i32x4, SimdInt}; - /// let v = i32x4::from_array([1, 2, 3, 4]); - /// assert_eq!(v.reduce_product(), 24); - /// - /// // SIMD integer multiplication is always wrapping - /// let v = i32x4::from_array([i32::MAX, 2, 1, 1]); - /// assert!(v.reduce_product() < i32::MAX); - /// ``` - fn reduce_product(self) -> Self::Scalar; - - /// Returns the maximum lane in the vector. - /// - /// # Examples - /// - /// ``` - /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{i32x4, SimdInt}; - /// let v = i32x4::from_array([1, 2, 3, 4]); - /// assert_eq!(v.reduce_max(), 4); - /// ``` - fn reduce_max(self) -> Self::Scalar; - - /// Returns the minimum lane in the vector. - /// - /// # Examples - /// - /// ``` - /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{i32x4, SimdInt}; - /// let v = i32x4::from_array([1, 2, 3, 4]); - /// assert_eq!(v.reduce_min(), 1); - /// ``` - fn reduce_min(self) -> Self::Scalar; - - /// Returns the cumulative bitwise "and" across the lanes of the vector. - fn reduce_and(self) -> Self::Scalar; - - /// Returns the cumulative bitwise "or" across the lanes of the vector. - fn reduce_or(self) -> Self::Scalar; - - /// Returns the cumulative bitwise "xor" across the lanes of the vector. - fn reduce_xor(self) -> Self::Scalar; -} - -macro_rules! impl_trait { - { $($ty:ty),* } => { - $( - impl Sealed for Simd<$ty, LANES> - where - LaneCount: SupportedLaneCount, - { - } - - impl SimdInt for Simd<$ty, LANES> - where - LaneCount: SupportedLaneCount, - { - type Mask = Mask<<$ty as SimdElement>::Mask, LANES>; - type Scalar = $ty; - - #[inline] - fn saturating_add(self, second: Self) -> Self { - // Safety: `self` is a vector - unsafe { intrinsics::simd_saturating_add(self, second) } - } - - #[inline] - fn saturating_sub(self, second: Self) -> Self { - // Safety: `self` is a vector - unsafe { intrinsics::simd_saturating_sub(self, second) } - } - - #[inline] - fn abs(self) -> Self { - const SHR: $ty = <$ty>::BITS as $ty - 1; - let m = self >> Simd::splat(SHR); - (self^m) - m - } - - #[inline] - fn saturating_abs(self) -> Self { - // arith shift for -1 or 0 mask based on sign bit, giving 2s complement - const SHR: $ty = <$ty>::BITS as $ty - 1; - let m = self >> Simd::splat(SHR); - (self^m).saturating_sub(m) - } - - #[inline] - fn saturating_neg(self) -> Self { - Self::splat(0).saturating_sub(self) - } - - #[inline] - fn is_positive(self) -> Self::Mask { - self.simd_gt(Self::splat(0)) - } - - #[inline] - fn is_negative(self) -> Self::Mask { - self.simd_lt(Self::splat(0)) - } - - #[inline] - fn signum(self) -> Self { - self.is_positive().select( - Self::splat(1), - self.is_negative().select(Self::splat(-1), Self::splat(0)) - ) - } - - #[inline] - fn reduce_sum(self) -> Self::Scalar { - // Safety: `self` is an integer vector - unsafe { intrinsics::simd_reduce_add_ordered(self, 0) } - } - - #[inline] - fn reduce_product(self) -> Self::Scalar { - // Safety: `self` is an integer vector - unsafe { intrinsics::simd_reduce_mul_ordered(self, 1) } - } - - #[inline] - fn reduce_max(self) -> Self::Scalar { - // Safety: `self` is an integer vector - unsafe { intrinsics::simd_reduce_max(self) } - } - - #[inline] - fn reduce_min(self) -> Self::Scalar { - // Safety: `self` is an integer vector - unsafe { intrinsics::simd_reduce_min(self) } - } - - #[inline] - fn reduce_and(self) -> Self::Scalar { - // Safety: `self` is an integer vector - unsafe { intrinsics::simd_reduce_and(self) } - } - - #[inline] - fn reduce_or(self) -> Self::Scalar { - // Safety: `self` is an integer vector - unsafe { intrinsics::simd_reduce_or(self) } - } - - #[inline] - fn reduce_xor(self) -> Self::Scalar { - // Safety: `self` is an integer vector - unsafe { intrinsics::simd_reduce_xor(self) } - } - } - )* - } -} - -impl_trait! { i8, i16, i32, i64, isize } diff --git a/library/portable-simd/crates/core_simd/src/elements/uint.rs b/library/portable-simd/crates/core_simd/src/elements/uint.rs deleted file mode 100644 index 21e7e76eb3de5..0000000000000 --- a/library/portable-simd/crates/core_simd/src/elements/uint.rs +++ /dev/null @@ -1,139 +0,0 @@ -use super::sealed::Sealed; -use crate::simd::{intrinsics, LaneCount, Simd, SupportedLaneCount}; - -/// Operations on SIMD vectors of unsigned integers. -pub trait SimdUint: Copy + Sealed { - /// Scalar type contained by this SIMD vector type. - type Scalar; - - /// Lanewise saturating add. - /// - /// # Examples - /// ``` - /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdUint}; - /// use core::u32::MAX; - /// let x = Simd::from_array([2, 1, 0, MAX]); - /// let max = Simd::splat(MAX); - /// let unsat = x + max; - /// let sat = x.saturating_add(max); - /// assert_eq!(unsat, Simd::from_array([1, 0, MAX, MAX - 1])); - /// assert_eq!(sat, max); - /// ``` - fn saturating_add(self, second: Self) -> Self; - - /// Lanewise saturating subtract. - /// - /// # Examples - /// ``` - /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdUint}; - /// use core::u32::MAX; - /// let x = Simd::from_array([2, 1, 0, MAX]); - /// let max = Simd::splat(MAX); - /// let unsat = x - max; - /// let sat = x.saturating_sub(max); - /// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0])); - /// assert_eq!(sat, Simd::splat(0)); - fn saturating_sub(self, second: Self) -> Self; - - /// Returns the sum of the lanes of the vector, with wrapping addition. - fn reduce_sum(self) -> Self::Scalar; - - /// Returns the product of the lanes of the vector, with wrapping multiplication. - fn reduce_product(self) -> Self::Scalar; - - /// Returns the maximum lane in the vector. - fn reduce_max(self) -> Self::Scalar; - - /// Returns the minimum lane in the vector. - fn reduce_min(self) -> Self::Scalar; - - /// Returns the cumulative bitwise "and" across the lanes of the vector. - fn reduce_and(self) -> Self::Scalar; - - /// Returns the cumulative bitwise "or" across the lanes of the vector. - fn reduce_or(self) -> Self::Scalar; - - /// Returns the cumulative bitwise "xor" across the lanes of the vector. - fn reduce_xor(self) -> Self::Scalar; -} - -macro_rules! impl_trait { - { $($ty:ty),* } => { - $( - impl Sealed for Simd<$ty, LANES> - where - LaneCount: SupportedLaneCount, - { - } - - impl SimdUint for Simd<$ty, LANES> - where - LaneCount: SupportedLaneCount, - { - type Scalar = $ty; - - #[inline] - fn saturating_add(self, second: Self) -> Self { - // Safety: `self` is a vector - unsafe { intrinsics::simd_saturating_add(self, second) } - } - - #[inline] - fn saturating_sub(self, second: Self) -> Self { - // Safety: `self` is a vector - unsafe { intrinsics::simd_saturating_sub(self, second) } - } - - #[inline] - fn reduce_sum(self) -> Self::Scalar { - // Safety: `self` is an integer vector - unsafe { intrinsics::simd_reduce_add_ordered(self, 0) } - } - - #[inline] - fn reduce_product(self) -> Self::Scalar { - // Safety: `self` is an integer vector - unsafe { intrinsics::simd_reduce_mul_ordered(self, 1) } - } - - #[inline] - fn reduce_max(self) -> Self::Scalar { - // Safety: `self` is an integer vector - unsafe { intrinsics::simd_reduce_max(self) } - } - - #[inline] - fn reduce_min(self) -> Self::Scalar { - // Safety: `self` is an integer vector - unsafe { intrinsics::simd_reduce_min(self) } - } - - #[inline] - fn reduce_and(self) -> Self::Scalar { - // Safety: `self` is an integer vector - unsafe { intrinsics::simd_reduce_and(self) } - } - - #[inline] - fn reduce_or(self) -> Self::Scalar { - // Safety: `self` is an integer vector - unsafe { intrinsics::simd_reduce_or(self) } - } - - #[inline] - fn reduce_xor(self) -> Self::Scalar { - // Safety: `self` is an integer vector - unsafe { intrinsics::simd_reduce_xor(self) } - } - } - )* - } -} - -impl_trait! { u8, u16, u32, u64, usize } diff --git a/library/portable-simd/crates/core_simd/src/eq.rs b/library/portable-simd/crates/core_simd/src/eq.rs deleted file mode 100644 index c7111f720a8ac..0000000000000 --- a/library/portable-simd/crates/core_simd/src/eq.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdElement, SupportedLaneCount}; - -/// Parallel `PartialEq`. -pub trait SimdPartialEq { - /// The mask type returned by each comparison. - type Mask; - - /// Test if each lane is equal to the corresponding lane in `other`. - #[must_use = "method returns a new mask and does not mutate the original value"] - fn simd_eq(self, other: Self) -> Self::Mask; - - /// Test if each lane is equal to the corresponding lane in `other`. - #[must_use = "method returns a new mask and does not mutate the original value"] - fn simd_ne(self, other: Self) -> Self::Mask; -} - -macro_rules! impl_number { - { $($number:ty),* } => { - $( - impl SimdPartialEq for Simd<$number, LANES> - where - LaneCount: SupportedLaneCount, - { - type Mask = Mask<<$number as SimdElement>::Mask, LANES>; - - #[inline] - fn simd_eq(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) } - } - - #[inline] - fn simd_ne(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) } - } - } - )* - } -} - -impl_number! { f32, f64, u8, u16, u32, u64, usize, i8, i16, i32, i64, isize } - -macro_rules! impl_mask { - { $($integer:ty),* } => { - $( - impl SimdPartialEq for Mask<$integer, LANES> - where - LaneCount: SupportedLaneCount, - { - type Mask = Self; - - #[inline] - fn simd_eq(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Self::from_int_unchecked(intrinsics::simd_eq(self.to_int(), other.to_int())) } - } - - #[inline] - fn simd_ne(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Self::from_int_unchecked(intrinsics::simd_ne(self.to_int(), other.to_int())) } - } - } - )* - } -} - -impl_mask! { i8, i16, i32, i64, isize } diff --git a/library/portable-simd/crates/core_simd/src/lane_count.rs b/library/portable-simd/crates/core_simd/src/lane_count.rs index 63723e2ec13c4..3b316f12b3e56 100644 --- a/library/portable-simd/crates/core_simd/src/lane_count.rs +++ b/library/portable-simd/crates/core_simd/src/lane_count.rs @@ -3,7 +3,7 @@ mod sealed { } use sealed::Sealed; -/// Specifies the number of lanes in a SIMD vector as a type. +/// A type representing a vector lane count. pub struct LaneCount; impl LaneCount { @@ -11,11 +11,7 @@ impl LaneCount { pub const BITMASK_LEN: usize = (LANES + 7) / 8; } -/// Statically guarantees that a lane count is marked as supported. -/// -/// This trait is *sealed*: the list of implementors below is total. -/// Users do not have the ability to mark additional `LaneCount` values as supported. -/// Only SIMD vectors with supported lane counts are constructable. +/// Helper trait for vector lane counts. pub trait SupportedLaneCount: Sealed { #[doc(hidden)] type BitMask: Copy + Default + AsRef<[u8]> + AsMut<[u8]>; diff --git a/library/portable-simd/crates/core_simd/src/lib.rs b/library/portable-simd/crates/core_simd/src/lib.rs index 715f258f617df..2632073622edf 100644 --- a/library/portable-simd/crates/core_simd/src/lib.rs +++ b/library/portable-simd/crates/core_simd/src/lib.rs @@ -12,7 +12,7 @@ #![cfg_attr(feature = "generic_const_exprs", feature(generic_const_exprs))] #![cfg_attr(feature = "generic_const_exprs", allow(incomplete_features))] #![warn(missing_docs)] -#![deny(unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks)] +#![deny(unsafe_op_in_unsafe_fn)] #![unstable(feature = "portable_simd", issue = "86656")] //! Portable SIMD module. diff --git a/library/portable-simd/crates/core_simd/src/masks.rs b/library/portable-simd/crates/core_simd/src/masks.rs index c36c336d8a216..e1cd793045046 100644 --- a/library/portable-simd/crates/core_simd/src/masks.rs +++ b/library/portable-simd/crates/core_simd/src/masks.rs @@ -15,10 +15,7 @@ mod mask_impl; mod to_bitmask; pub use to_bitmask::ToBitMask; -#[cfg(feature = "generic_const_exprs")] -pub use to_bitmask::{bitmask_len, ToBitMaskArray}; - -use crate::simd::{intrinsics, LaneCount, Simd, SimdElement, SimdPartialEq, SupportedLaneCount}; +use crate::simd::{intrinsics, LaneCount, Simd, SimdElement, SupportedLaneCount}; use core::cmp::Ordering; use core::{fmt, mem}; @@ -59,7 +56,7 @@ macro_rules! impl_element { where LaneCount: SupportedLaneCount, { - (value.simd_eq(Simd::splat(0 as _)) | value.simd_eq(Simd::splat(-1 as _))).all() + (value.lanes_eq(Simd::splat(0)) | value.lanes_eq(Simd::splat(-1))).all() } fn eq(self, other: Self) -> bool { self == other } @@ -68,7 +65,6 @@ macro_rules! impl_element { const FALSE: Self = 0; } - // Safety: this is a valid mask element type unsafe impl MaskElement for $ty {} } } @@ -81,8 +77,6 @@ impl_element! { isize } /// A SIMD vector mask for `LANES` elements of width specified by `Element`. /// -/// Masks represent boolean inclusion/exclusion on a per-lane basis. -/// /// The layout of this type is unspecified. #[repr(transparent)] pub struct Mask(mask_impl::Mask) @@ -185,13 +179,6 @@ where self.0.to_int() } - /// Converts the mask to a mask of any other lane size. - #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] - pub fn cast(self) -> Mask { - Mask(self.0.convert()) - } - /// Tests the value of the specified lane. /// /// # Safety @@ -520,58 +507,58 @@ where } } -/// A mask for SIMD vectors with eight elements of 8 bits. +/// Vector of eight 8-bit masks pub type mask8x8 = Mask; -/// A mask for SIMD vectors with 16 elements of 8 bits. +/// Vector of 16 8-bit masks pub type mask8x16 = Mask; -/// A mask for SIMD vectors with 32 elements of 8 bits. +/// Vector of 32 8-bit masks pub type mask8x32 = Mask; -/// A mask for SIMD vectors with 64 elements of 8 bits. +/// Vector of 16 8-bit masks pub type mask8x64 = Mask; -/// A mask for SIMD vectors with four elements of 16 bits. +/// Vector of four 16-bit masks pub type mask16x4 = Mask; -/// A mask for SIMD vectors with eight elements of 16 bits. +/// Vector of eight 16-bit masks pub type mask16x8 = Mask; -/// A mask for SIMD vectors with 16 elements of 16 bits. +/// Vector of 16 16-bit masks pub type mask16x16 = Mask; -/// A mask for SIMD vectors with 32 elements of 16 bits. +/// Vector of 32 16-bit masks pub type mask16x32 = Mask; -/// A mask for SIMD vectors with two elements of 32 bits. +/// Vector of two 32-bit masks pub type mask32x2 = Mask; -/// A mask for SIMD vectors with four elements of 32 bits. +/// Vector of four 32-bit masks pub type mask32x4 = Mask; -/// A mask for SIMD vectors with eight elements of 32 bits. +/// Vector of eight 32-bit masks pub type mask32x8 = Mask; -/// A mask for SIMD vectors with 16 elements of 32 bits. +/// Vector of 16 32-bit masks pub type mask32x16 = Mask; -/// A mask for SIMD vectors with two elements of 64 bits. +/// Vector of two 64-bit masks pub type mask64x2 = Mask; -/// A mask for SIMD vectors with four elements of 64 bits. +/// Vector of four 64-bit masks pub type mask64x4 = Mask; -/// A mask for SIMD vectors with eight elements of 64 bits. +/// Vector of eight 64-bit masks pub type mask64x8 = Mask; -/// A mask for SIMD vectors with two elements of pointer width. +/// Vector of two pointer-width masks pub type masksizex2 = Mask; -/// A mask for SIMD vectors with four elements of pointer width. +/// Vector of four pointer-width masks pub type masksizex4 = Mask; -/// A mask for SIMD vectors with eight elements of pointer width. +/// Vector of eight pointer-width masks pub type masksizex8 = Mask; macro_rules! impl_from { @@ -582,7 +569,7 @@ macro_rules! impl_from { LaneCount: SupportedLaneCount, { fn from(value: Mask<$from, LANES>) -> Self { - value.cast() + Self(value.0.convert()) } } )* diff --git a/library/portable-simd/crates/core_simd/src/masks/bitmask.rs b/library/portable-simd/crates/core_simd/src/masks/bitmask.rs index 365ecc0a3251e..ec4dd357ee98c 100644 --- a/library/portable-simd/crates/core_simd/src/masks/bitmask.rs +++ b/library/portable-simd/crates/core_simd/src/masks/bitmask.rs @@ -115,26 +115,6 @@ where unsafe { Self(intrinsics::simd_bitmask(value), PhantomData) } } - #[cfg(feature = "generic_const_exprs")] - #[inline] - #[must_use = "method returns a new array and does not mutate the original value"] - pub fn to_bitmask_array(self) -> [u8; N] { - assert!(core::mem::size_of::() == N); - - // Safety: converting an integer to an array of bytes of the same size is safe - unsafe { core::mem::transmute_copy(&self.0) } - } - - #[cfg(feature = "generic_const_exprs")] - #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] - pub fn from_bitmask_array(bitmask: [u8; N]) -> Self { - assert!(core::mem::size_of::() == N); - - // Safety: converting an array of bytes to an integer of the same size is safe - Self(unsafe { core::mem::transmute_copy(&bitmask) }, PhantomData) - } - #[inline] pub fn to_bitmask_integer(self) -> U where diff --git a/library/portable-simd/crates/core_simd/src/masks/full_masks.rs b/library/portable-simd/crates/core_simd/src/masks/full_masks.rs index adf0fcbeae2bd..8bbdf637de84d 100644 --- a/library/portable-simd/crates/core_simd/src/masks/full_masks.rs +++ b/library/portable-simd/crates/core_simd/src/masks/full_masks.rs @@ -4,9 +4,6 @@ use super::MaskElement; use crate::simd::intrinsics; use crate::simd::{LaneCount, Simd, SupportedLaneCount, ToBitMask}; -#[cfg(feature = "generic_const_exprs")] -use crate::simd::ToBitMaskArray; - #[repr(transparent)] pub struct Mask(Simd) where @@ -71,26 +68,14 @@ where // Used for bitmask bit order workaround pub(crate) trait ReverseBits { - // Reverse the least significant `n` bits of `self`. - // (Remaining bits must be 0.) - fn reverse_bits(self, n: usize) -> Self; + fn reverse_bits(self) -> Self; } macro_rules! impl_reverse_bits { { $($int:ty),* } => { $( impl ReverseBits for $int { - #[inline(always)] - fn reverse_bits(self, n: usize) -> Self { - let rev = <$int>::reverse_bits(self); - let bitsize = core::mem::size_of::<$int>() * 8; - if n < bitsize { - // Shift things back to the right - rev >> (bitsize - n) - } else { - rev - } - } + fn reverse_bits(self) -> Self { <$int>::reverse_bits(self) } } )* } @@ -142,68 +127,6 @@ where unsafe { Mask(intrinsics::simd_cast(self.0)) } } - #[cfg(feature = "generic_const_exprs")] - #[inline] - #[must_use = "method returns a new array and does not mutate the original value"] - pub fn to_bitmask_array(self) -> [u8; N] - where - super::Mask: ToBitMaskArray, - [(); as ToBitMaskArray>::BYTES]: Sized, - { - assert_eq!( as ToBitMaskArray>::BYTES, N); - - // Safety: N is the correct bitmask size - unsafe { - // Compute the bitmask - let bitmask: [u8; as ToBitMaskArray>::BYTES] = - intrinsics::simd_bitmask(self.0); - - // Transmute to the return type, previously asserted to be the same size - let mut bitmask: [u8; N] = core::mem::transmute_copy(&bitmask); - - // LLVM assumes bit order should match endianness - if cfg!(target_endian = "big") { - for x in bitmask.as_mut() { - *x = x.reverse_bits(); - } - }; - - bitmask - } - } - - #[cfg(feature = "generic_const_exprs")] - #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] - pub fn from_bitmask_array(mut bitmask: [u8; N]) -> Self - where - super::Mask: ToBitMaskArray, - [(); as ToBitMaskArray>::BYTES]: Sized, - { - assert_eq!( as ToBitMaskArray>::BYTES, N); - - // Safety: N is the correct bitmask size - unsafe { - // LLVM assumes bit order should match endianness - if cfg!(target_endian = "big") { - for x in bitmask.as_mut() { - *x = x.reverse_bits(); - } - } - - // Transmute to the bitmask type, previously asserted to be the same size - let bitmask: [u8; as ToBitMaskArray>::BYTES] = - core::mem::transmute_copy(&bitmask); - - // Compute the regular mask - Self::from_int_unchecked(intrinsics::simd_select_bitmask( - bitmask, - Self::splat(true).to_int(), - Self::splat(false).to_int(), - )) - } - } - #[inline] pub(crate) fn to_bitmask_integer(self) -> U where @@ -214,7 +137,7 @@ where // LLVM assumes bit order should match endianness if cfg!(target_endian = "big") { - bitmask.reverse_bits(LANES) + bitmask.reverse_bits() } else { bitmask } @@ -227,7 +150,7 @@ where { // LLVM assumes bit order should match endianness let bitmask = if cfg!(target_endian = "big") { - bitmask.reverse_bits(LANES) + bitmask.reverse_bits() } else { bitmask }; diff --git a/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs b/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs index 65d3ce9be65ec..c263f6a4eec38 100644 --- a/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs +++ b/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs @@ -16,7 +16,11 @@ where /// Converts masks to and from integer bitmasks. /// /// Each bit of the bitmask corresponds to a mask lane, starting with the LSB. -pub trait ToBitMask: Sealed { +/// +/// # Safety +/// This trait is `unsafe` and sealed, since the `BitMask` type must match the number of lanes in +/// the mask. +pub unsafe trait ToBitMask: Sealed { /// The integer bitmask type. type BitMask; @@ -27,25 +31,10 @@ pub trait ToBitMask: Sealed { fn from_bitmask(bitmask: Self::BitMask) -> Self; } -/// Converts masks to and from byte array bitmasks. -/// -/// Each bit of the bitmask corresponds to a mask lane, starting with the LSB of the first byte. -#[cfg(feature = "generic_const_exprs")] -pub trait ToBitMaskArray: Sealed { - /// The length of the bitmask array. - const BYTES: usize; - - /// Converts a mask to a bitmask. - fn to_bitmask_array(self) -> [u8; Self::BYTES]; - - /// Converts a bitmask to a mask. - fn from_bitmask_array(bitmask: [u8; Self::BYTES]) -> Self; -} - macro_rules! impl_integer_intrinsic { - { $(impl ToBitMask for Mask<_, $lanes:literal>)* } => { + { $(unsafe impl ToBitMask for Mask<_, $lanes:literal>)* } => { $( - impl ToBitMask for Mask { + unsafe impl ToBitMask for Mask { type BitMask = $int; fn to_bitmask(self) -> $int { @@ -61,33 +50,11 @@ macro_rules! impl_integer_intrinsic { } impl_integer_intrinsic! { - impl ToBitMask for Mask<_, 1> - impl ToBitMask for Mask<_, 2> - impl ToBitMask for Mask<_, 4> - impl ToBitMask for Mask<_, 8> - impl ToBitMask for Mask<_, 16> - impl ToBitMask for Mask<_, 32> - impl ToBitMask for Mask<_, 64> -} - -/// Returns the minimum numnber of bytes in a bitmask with `lanes` lanes. -#[cfg(feature = "generic_const_exprs")] -pub const fn bitmask_len(lanes: usize) -> usize { - (lanes + 7) / 8 -} - -#[cfg(feature = "generic_const_exprs")] -impl ToBitMaskArray for Mask -where - LaneCount: SupportedLaneCount, -{ - const BYTES: usize = bitmask_len(LANES); - - fn to_bitmask_array(self) -> [u8; Self::BYTES] { - self.0.to_bitmask_array() - } - - fn from_bitmask_array(bitmask: [u8; Self::BYTES]) -> Self { - Mask(mask_impl::Mask::from_bitmask_array(bitmask)) - } + unsafe impl ToBitMask for Mask<_, 1> + unsafe impl ToBitMask for Mask<_, 2> + unsafe impl ToBitMask for Mask<_, 4> + unsafe impl ToBitMask for Mask<_, 8> + unsafe impl ToBitMask for Mask<_, 16> + unsafe impl ToBitMask for Mask<_, 32> + unsafe impl ToBitMask for Mask<_, 64> } diff --git a/library/portable-simd/crates/core_simd/src/math.rs b/library/portable-simd/crates/core_simd/src/math.rs new file mode 100644 index 0000000000000..606021e983ed1 --- /dev/null +++ b/library/portable-simd/crates/core_simd/src/math.rs @@ -0,0 +1,156 @@ +use crate::simd::intrinsics::{simd_saturating_add, simd_saturating_sub}; +use crate::simd::{LaneCount, Simd, SupportedLaneCount}; + +macro_rules! impl_uint_arith { + ($($ty:ty),+) => { + $( impl Simd<$ty, LANES> where LaneCount: SupportedLaneCount { + + /// Lanewise saturating add. + /// + /// # Examples + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::Simd; + #[doc = concat!("# use core::", stringify!($ty), "::MAX;")] + /// let x = Simd::from_array([2, 1, 0, MAX]); + /// let max = Simd::splat(MAX); + /// let unsat = x + max; + /// let sat = x.saturating_add(max); + /// assert_eq!(unsat, Simd::from_array([1, 0, MAX, MAX - 1])); + /// assert_eq!(sat, max); + /// ``` + #[inline] + pub fn saturating_add(self, second: Self) -> Self { + // Safety: `self` is a vector + unsafe { simd_saturating_add(self, second) } + } + + /// Lanewise saturating subtract. + /// + /// # Examples + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::Simd; + #[doc = concat!("# use core::", stringify!($ty), "::MAX;")] + /// let x = Simd::from_array([2, 1, 0, MAX]); + /// let max = Simd::splat(MAX); + /// let unsat = x - max; + /// let sat = x.saturating_sub(max); + /// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0])); + /// assert_eq!(sat, Simd::splat(0)); + #[inline] + pub fn saturating_sub(self, second: Self) -> Self { + // Safety: `self` is a vector + unsafe { simd_saturating_sub(self, second) } + } + })+ + } +} + +macro_rules! impl_int_arith { + ($($ty:ty),+) => { + $( impl Simd<$ty, LANES> where LaneCount: SupportedLaneCount { + + /// Lanewise saturating add. + /// + /// # Examples + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::Simd; + #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")] + /// let x = Simd::from_array([MIN, 0, 1, MAX]); + /// let max = Simd::splat(MAX); + /// let unsat = x + max; + /// let sat = x.saturating_add(max); + /// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2])); + /// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX])); + /// ``` + #[inline] + pub fn saturating_add(self, second: Self) -> Self { + // Safety: `self` is a vector + unsafe { simd_saturating_add(self, second) } + } + + /// Lanewise saturating subtract. + /// + /// # Examples + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::Simd; + #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")] + /// let x = Simd::from_array([MIN, -2, -1, MAX]); + /// let max = Simd::splat(MAX); + /// let unsat = x - max; + /// let sat = x.saturating_sub(max); + /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0])); + /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0])); + #[inline] + pub fn saturating_sub(self, second: Self) -> Self { + // Safety: `self` is a vector + unsafe { simd_saturating_sub(self, second) } + } + + /// Lanewise absolute value, implemented in Rust. + /// Every lane becomes its absolute value. + /// + /// # Examples + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::Simd; + #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")] + /// let xs = Simd::from_array([MIN, MIN +1, -5, 0]); + /// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0])); + /// ``` + #[inline] + pub fn abs(self) -> Self { + const SHR: $ty = <$ty>::BITS as $ty - 1; + let m = self >> Simd::splat(SHR); + (self^m) - m + } + + /// Lanewise saturating absolute value, implemented in Rust. + /// As abs(), except the MIN value becomes MAX instead of itself. + /// + /// # Examples + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::Simd; + #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")] + /// let xs = Simd::from_array([MIN, -2, 0, 3]); + /// let unsat = xs.abs(); + /// let sat = xs.saturating_abs(); + /// assert_eq!(unsat, Simd::from_array([MIN, 2, 0, 3])); + /// assert_eq!(sat, Simd::from_array([MAX, 2, 0, 3])); + /// ``` + #[inline] + pub fn saturating_abs(self) -> Self { + // arith shift for -1 or 0 mask based on sign bit, giving 2s complement + const SHR: $ty = <$ty>::BITS as $ty - 1; + let m = self >> Simd::splat(SHR); + (self^m).saturating_sub(m) + } + + /// Lanewise saturating negation, implemented in Rust. + /// As neg(), except the MIN value becomes MAX instead of itself. + /// + /// # Examples + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::Simd; + #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")] + /// let x = Simd::from_array([MIN, -2, 3, MAX]); + /// let unsat = -x; + /// let sat = x.saturating_neg(); + /// assert_eq!(unsat, Simd::from_array([MIN, 2, -3, MIN + 1])); + /// assert_eq!(sat, Simd::from_array([MAX, 2, -3, MIN + 1])); + /// ``` + #[inline] + pub fn saturating_neg(self) -> Self { + Self::splat(0).saturating_sub(self) + } + })+ + } +} + +impl_uint_arith! { u8, u16, u32, u64, usize } +impl_int_arith! { i8, i16, i32, i64, isize } diff --git a/library/portable-simd/crates/core_simd/src/mod.rs b/library/portable-simd/crates/core_simd/src/mod.rs index b472aa3abe210..85026265956a2 100644 --- a/library/portable-simd/crates/core_simd/src/mod.rs +++ b/library/portable-simd/crates/core_simd/src/mod.rs @@ -1,3 +1,6 @@ +#[macro_use] +mod reduction; + #[macro_use] mod swizzle; @@ -6,14 +9,14 @@ pub(crate) mod intrinsics; #[cfg(feature = "generic_const_exprs")] mod to_bytes; -mod elements; -mod eq; +mod comparisons; mod fmt; mod iter; mod lane_count; mod masks; +mod math; mod ops; -mod ord; +mod round; mod select; mod vector; mod vendor; @@ -22,11 +25,8 @@ mod vendor; pub mod simd { pub(crate) use crate::core_simd::intrinsics; - pub use crate::core_simd::elements::*; - pub use crate::core_simd::eq::*; pub use crate::core_simd::lane_count::{LaneCount, SupportedLaneCount}; pub use crate::core_simd::masks::*; - pub use crate::core_simd::ord::*; pub use crate::core_simd::swizzle::*; pub use crate::core_simd::vector::*; } diff --git a/library/portable-simd/crates/core_simd/src/ops.rs b/library/portable-simd/crates/core_simd/src/ops.rs index 5a077a469d839..1b35b3e717a32 100644 --- a/library/portable-simd/crates/core_simd/src/ops.rs +++ b/library/portable-simd/crates/core_simd/src/ops.rs @@ -1,4 +1,4 @@ -use crate::simd::{LaneCount, Simd, SimdElement, SimdPartialEq, SupportedLaneCount}; +use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount}; use core::ops::{Add, Mul}; use core::ops::{BitAnd, BitOr, BitXor}; use core::ops::{Div, Rem, Sub}; @@ -33,7 +33,6 @@ where macro_rules! unsafe_base { ($lhs:ident, $rhs:ident, {$simd_call:ident}, $($_:tt)*) => { - // Safety: $lhs and $rhs are vectors unsafe { $crate::simd::intrinsics::$simd_call($lhs, $rhs) } }; } @@ -49,8 +48,6 @@ macro_rules! unsafe_base { // cg_clif defaults to this, and scalar MIR shifts also default to wrapping macro_rules! wrap_bitshift { ($lhs:ident, $rhs:ident, {$simd_call:ident}, $int:ident) => { - #[allow(clippy::suspicious_arithmetic_impl)] - // Safety: $lhs and the bitand result are vectors unsafe { $crate::simd::intrinsics::$simd_call( $lhs, @@ -77,7 +74,7 @@ macro_rules! int_divrem_guard { $simd_call:ident }, $int:ident ) => { - if $rhs.simd_eq(Simd::splat(0 as _)).any() { + if $rhs.lanes_eq(Simd::splat(0)).any() { panic!($zero); } else { // Prevent otherwise-UB overflow on the MIN / -1 case. @@ -85,15 +82,14 @@ macro_rules! int_divrem_guard { // This should, at worst, optimize to a few branchless logical ops // Ideally, this entire conditional should evaporate // Fire LLVM and implement those manually if it doesn't get the hint - ($lhs.simd_eq(Simd::splat(<$int>::MIN)) + ($lhs.lanes_eq(Simd::splat(<$int>::MIN)) // type inference can break here, so cut an SInt to size - & $rhs.simd_eq(Simd::splat(-1i64 as _))) - .select(Simd::splat(1 as _), $rhs) + & $rhs.lanes_eq(Simd::splat(-1i64 as _))) + .select(Simd::splat(1), $rhs) } else { // Nice base case to make it easy to const-fold away the other branch. $rhs }; - // Safety: $lhs and rhs are vectors unsafe { $crate::simd::intrinsics::$simd_call($lhs, rhs) } } }; diff --git a/library/portable-simd/crates/core_simd/src/ops/unary.rs b/library/portable-simd/crates/core_simd/src/ops/unary.rs index 4ad02215034be..4ebea560fc65f 100644 --- a/library/portable-simd/crates/core_simd/src/ops/unary.rs +++ b/library/portable-simd/crates/core_simd/src/ops/unary.rs @@ -14,7 +14,6 @@ macro_rules! neg { #[inline] #[must_use = "operator returns a new vector without mutating the input"] fn neg(self) -> Self::Output { - // Safety: `self` is a signed vector unsafe { intrinsics::simd_neg(self) } } })* diff --git a/library/portable-simd/crates/core_simd/src/ord.rs b/library/portable-simd/crates/core_simd/src/ord.rs deleted file mode 100644 index 9a87bc2e34460..0000000000000 --- a/library/portable-simd/crates/core_simd/src/ord.rs +++ /dev/null @@ -1,213 +0,0 @@ -use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount}; - -/// Parallel `PartialOrd`. -pub trait SimdPartialOrd: SimdPartialEq { - /// Test if each lane is less than the corresponding lane in `other`. - #[must_use = "method returns a new mask and does not mutate the original value"] - fn simd_lt(self, other: Self) -> Self::Mask; - - /// Test if each lane is less than or equal to the corresponding lane in `other`. - #[must_use = "method returns a new mask and does not mutate the original value"] - fn simd_le(self, other: Self) -> Self::Mask; - - /// Test if each lane is greater than the corresponding lane in `other`. - #[must_use = "method returns a new mask and does not mutate the original value"] - fn simd_gt(self, other: Self) -> Self::Mask; - - /// Test if each lane is greater than or equal to the corresponding lane in `other`. - #[must_use = "method returns a new mask and does not mutate the original value"] - fn simd_ge(self, other: Self) -> Self::Mask; -} - -/// Parallel `Ord`. -pub trait SimdOrd: SimdPartialOrd { - /// Returns the lane-wise maximum with `other`. - #[must_use = "method returns a new vector and does not mutate the original value"] - fn simd_max(self, other: Self) -> Self; - - /// Returns the lane-wise minimum with `other`. - #[must_use = "method returns a new vector and does not mutate the original value"] - fn simd_min(self, other: Self) -> Self; - - /// Restrict each lane to a certain interval. - /// - /// For each lane, returns `max` if `self` is greater than `max`, and `min` if `self` is - /// less than `min`. Otherwise returns `self`. - /// - /// # Panics - /// - /// Panics if `min > max` on any lane. - #[must_use = "method returns a new vector and does not mutate the original value"] - fn simd_clamp(self, min: Self, max: Self) -> Self; -} - -macro_rules! impl_integer { - { $($integer:ty),* } => { - $( - impl SimdPartialOrd for Simd<$integer, LANES> - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn simd_lt(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) } - } - - #[inline] - fn simd_le(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) } - } - - #[inline] - fn simd_gt(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) } - } - - #[inline] - fn simd_ge(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) } - } - } - - impl SimdOrd for Simd<$integer, LANES> - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn simd_max(self, other: Self) -> Self { - self.simd_lt(other).select(other, self) - } - - #[inline] - fn simd_min(self, other: Self) -> Self { - self.simd_gt(other).select(other, self) - } - - #[inline] - fn simd_clamp(self, min: Self, max: Self) -> Self { - assert!( - min.simd_le(max).all(), - "each lane in `min` must be less than or equal to the corresponding lane in `max`", - ); - self.simd_max(min).simd_min(max) - } - } - )* - } -} - -impl_integer! { u8, u16, u32, u64, usize, i8, i16, i32, i64, isize } - -macro_rules! impl_float { - { $($float:ty),* } => { - $( - impl SimdPartialOrd for Simd<$float, LANES> - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn simd_lt(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) } - } - - #[inline] - fn simd_le(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) } - } - - #[inline] - fn simd_gt(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) } - } - - #[inline] - fn simd_ge(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) } - } - } - )* - } -} - -impl_float! { f32, f64 } - -macro_rules! impl_mask { - { $($integer:ty),* } => { - $( - impl SimdPartialOrd for Mask<$integer, LANES> - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn simd_lt(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Self::from_int_unchecked(intrinsics::simd_lt(self.to_int(), other.to_int())) } - } - - #[inline] - fn simd_le(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Self::from_int_unchecked(intrinsics::simd_le(self.to_int(), other.to_int())) } - } - - #[inline] - fn simd_gt(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Self::from_int_unchecked(intrinsics::simd_gt(self.to_int(), other.to_int())) } - } - - #[inline] - fn simd_ge(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Self::from_int_unchecked(intrinsics::simd_ge(self.to_int(), other.to_int())) } - } - } - - impl SimdOrd for Mask<$integer, LANES> - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn simd_max(self, other: Self) -> Self { - self.simd_gt(other).select_mask(other, self) - } - - #[inline] - fn simd_min(self, other: Self) -> Self { - self.simd_lt(other).select_mask(other, self) - } - - #[inline] - fn simd_clamp(self, min: Self, max: Self) -> Self { - assert!( - min.simd_le(max).all(), - "each lane in `min` must be less than or equal to the corresponding lane in `max`", - ); - self.simd_max(min).simd_min(max) - } - } - )* - } -} - -impl_mask! { i8, i16, i32, i64, isize } diff --git a/library/portable-simd/crates/core_simd/src/reduction.rs b/library/portable-simd/crates/core_simd/src/reduction.rs new file mode 100644 index 0000000000000..3177fd167fc44 --- /dev/null +++ b/library/portable-simd/crates/core_simd/src/reduction.rs @@ -0,0 +1,153 @@ +use crate::simd::intrinsics::{ + simd_reduce_add_ordered, simd_reduce_and, simd_reduce_max, simd_reduce_min, + simd_reduce_mul_ordered, simd_reduce_or, simd_reduce_xor, +}; +use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount}; +use core::ops::{BitAnd, BitOr, BitXor}; + +macro_rules! impl_integer_reductions { + { $scalar:ty } => { + impl Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + /// Reducing wrapping add. Returns the sum of the lanes of the vector, with wrapping addition. + #[inline] + pub fn reduce_sum(self) -> $scalar { + // Safety: `self` is an integer vector + unsafe { simd_reduce_add_ordered(self, 0) } + } + + /// Reducing wrapping multiply. Returns the product of the lanes of the vector, with wrapping multiplication. + #[inline] + pub fn reduce_product(self) -> $scalar { + // Safety: `self` is an integer vector + unsafe { simd_reduce_mul_ordered(self, 1) } + } + + /// Reducing maximum. Returns the maximum lane in the vector. + #[inline] + pub fn reduce_max(self) -> $scalar { + // Safety: `self` is an integer vector + unsafe { simd_reduce_max(self) } + } + + /// Reducing minimum. Returns the minimum lane in the vector. + #[inline] + pub fn reduce_min(self) -> $scalar { + // Safety: `self` is an integer vector + unsafe { simd_reduce_min(self) } + } + } + } +} + +impl_integer_reductions! { i8 } +impl_integer_reductions! { i16 } +impl_integer_reductions! { i32 } +impl_integer_reductions! { i64 } +impl_integer_reductions! { isize } +impl_integer_reductions! { u8 } +impl_integer_reductions! { u16 } +impl_integer_reductions! { u32 } +impl_integer_reductions! { u64 } +impl_integer_reductions! { usize } + +macro_rules! impl_float_reductions { + { $scalar:ty } => { + impl Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + + /// Reducing add. Returns the sum of the lanes of the vector. + #[inline] + pub fn reduce_sum(self) -> $scalar { + // LLVM sum is inaccurate on i586 + if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) { + self.as_array().iter().sum() + } else { + // Safety: `self` is a float vector + unsafe { simd_reduce_add_ordered(self, 0.) } + } + } + + /// Reducing multiply. Returns the product of the lanes of the vector. + #[inline] + pub fn reduce_product(self) -> $scalar { + // LLVM product is inaccurate on i586 + if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) { + self.as_array().iter().product() + } else { + // Safety: `self` is a float vector + unsafe { simd_reduce_mul_ordered(self, 1.) } + } + } + + /// Reducing maximum. Returns the maximum lane in the vector. + /// + /// Returns values based on equality, so a vector containing both `0.` and `-0.` may + /// return either. This function will not return `NaN` unless all lanes are `NaN`. + #[inline] + pub fn reduce_max(self) -> $scalar { + // Safety: `self` is a float vector + unsafe { simd_reduce_max(self) } + } + + /// Reducing minimum. Returns the minimum lane in the vector. + /// + /// Returns values based on equality, so a vector containing both `0.` and `-0.` may + /// return either. This function will not return `NaN` unless all lanes are `NaN`. + #[inline] + pub fn reduce_min(self) -> $scalar { + // Safety: `self` is a float vector + unsafe { simd_reduce_min(self) } + } + } + } +} + +impl_float_reductions! { f32 } +impl_float_reductions! { f64 } + +impl Simd +where + Self: BitAnd, + T: SimdElement + BitAnd, + LaneCount: SupportedLaneCount, +{ + /// Reducing bitwise "and". Returns the cumulative bitwise "and" across the lanes of + /// the vector. + #[inline] + pub fn reduce_and(self) -> T { + unsafe { simd_reduce_and(self) } + } +} + +impl Simd +where + Self: BitOr, + T: SimdElement + BitOr, + LaneCount: SupportedLaneCount, +{ + /// Reducing bitwise "or". Returns the cumulative bitwise "or" across the lanes of + /// the vector. + #[inline] + pub fn reduce_or(self) -> T { + unsafe { simd_reduce_or(self) } + } +} + +impl Simd +where + Self: BitXor, + T: SimdElement + BitXor, + LaneCount: SupportedLaneCount, +{ + /// Reducing bitwise "xor". Returns the cumulative bitwise "xor" across the lanes of + /// the vector. + #[inline] + pub fn reduce_xor(self) -> T { + unsafe { simd_reduce_xor(self) } + } +} diff --git a/library/portable-simd/crates/core_simd/src/round.rs b/library/portable-simd/crates/core_simd/src/round.rs new file mode 100644 index 0000000000000..556bc2cc1feee --- /dev/null +++ b/library/portable-simd/crates/core_simd/src/round.rs @@ -0,0 +1,40 @@ +use crate::simd::intrinsics; +use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount}; +use core::convert::FloatToInt; + +macro_rules! implement { + { + $type:ty + } => { + impl Simd<$type, LANES> + where + LaneCount: SupportedLaneCount, + { + /// Rounds toward zero and converts to the same-width integer type, assuming that + /// the value is finite and fits in that type. + /// + /// # Safety + /// The value must: + /// + /// * Not be NaN + /// * Not be infinite + /// * Be representable in the return type, after truncating off its fractional part + /// + /// If these requirements are infeasible or costly, consider using the safe function [cast], + /// which saturates on conversion. + /// + /// [cast]: Simd::cast + #[inline] + pub unsafe fn to_int_unchecked(self) -> Simd + where + $type: FloatToInt, + I: SimdElement, + { + unsafe { intrinsics::simd_cast(self) } + } + } + } +} + +implement! { f32 } +implement! { f64 } diff --git a/library/portable-simd/crates/core_simd/src/swizzle.rs b/library/portable-simd/crates/core_simd/src/swizzle.rs index 22999d24950f8..ef47c4f3a4c5e 100644 --- a/library/portable-simd/crates/core_simd/src/swizzle.rs +++ b/library/portable-simd/crates/core_simd/src/swizzle.rs @@ -1,46 +1,44 @@ use crate::simd::intrinsics; use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount}; -/// Constructs a new SIMD vector by copying elements from selected lanes in other vectors. +/// Constructs a new vector by selecting values from the lanes of the source vector or vectors to use. /// -/// When swizzling one vector, lanes are selected by a `const` array of `usize`, -/// like [`Swizzle`]. -/// -/// When swizzling two vectors, lanes are selected by a `const` array of [`Which`], -/// like [`Swizzle2`]. +/// When swizzling one vector, the indices of the result vector are indicated by a `const` array +/// of `usize`, like [`Swizzle`]. +/// When swizzling two vectors, the indices are indicated by a `const` array of [`Which`], like +/// [`Swizzle2`]. /// /// # Examples -/// -/// With a single SIMD vector, the const array specifies lane indices in that vector: +/// ## One source vector /// ``` /// # #![feature(portable_simd)] -/// # use core::simd::{u32x2, u32x4, simd_swizzle}; -/// let v = u32x4::from_array([10, 11, 12, 13]); +/// # use core::simd::{Simd, simd_swizzle}; +/// let v = Simd::::from_array([0., 1., 2., 3.]); /// /// // Keeping the same size -/// let r: u32x4 = simd_swizzle!(v, [3, 0, 1, 2]); -/// assert_eq!(r.to_array(), [13, 10, 11, 12]); +/// let r = simd_swizzle!(v, [3, 0, 1, 2]); +/// assert_eq!(r.to_array(), [3., 0., 1., 2.]); /// /// // Changing the number of lanes -/// let r: u32x2 = simd_swizzle!(v, [3, 1]); -/// assert_eq!(r.to_array(), [13, 11]); +/// let r = simd_swizzle!(v, [3, 1]); +/// assert_eq!(r.to_array(), [3., 1.]); /// ``` /// -/// With two input SIMD vectors, the const array uses `Which` to specify the source of each index: +/// ## Two source vectors /// ``` /// # #![feature(portable_simd)] -/// # use core::simd::{u32x2, u32x4, simd_swizzle, Which}; -/// use Which::{First, Second}; -/// let a = u32x4::from_array([0, 1, 2, 3]); -/// let b = u32x4::from_array([4, 5, 6, 7]); +/// # use core::simd::{Simd, simd_swizzle, Which}; +/// use Which::*; +/// let a = Simd::::from_array([0., 1., 2., 3.]); +/// let b = Simd::::from_array([4., 5., 6., 7.]); /// /// // Keeping the same size -/// let r: u32x4 = simd_swizzle!(a, b, [First(0), First(1), Second(2), Second(3)]); -/// assert_eq!(r.to_array(), [0, 1, 6, 7]); +/// let r = simd_swizzle!(a, b, [First(0), First(1), Second(2), Second(3)]); +/// assert_eq!(r.to_array(), [0., 1., 6., 7.]); /// /// // Changing the number of lanes -/// let r: u32x2 = simd_swizzle!(a, b, [First(0), Second(0)]); -/// assert_eq!(r.to_array(), [0, 4]); +/// let r = simd_swizzle!(a, b, [First(0), Second(0)]); +/// assert_eq!(r.to_array(), [0., 4.]); /// ``` #[allow(unused_macros)] pub macro simd_swizzle { @@ -70,14 +68,12 @@ pub macro simd_swizzle { } } -/// Specifies a lane index into one of two SIMD vectors. -/// -/// This is an input type for [Swizzle2] and helper macros like [simd_swizzle]. +/// An index into one of two vectors. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Which { - /// Index of a lane in the first input SIMD vector. + /// Indexes the first vector. First(usize), - /// Index of a lane in the second input SIMD vector. + /// Indexes the second vector. Second(usize), } diff --git a/library/portable-simd/crates/core_simd/src/vector.rs b/library/portable-simd/crates/core_simd/src/vector.rs index 78f56402eba40..b9cd2e2021eae 100644 --- a/library/portable-simd/crates/core_simd/src/vector.rs +++ b/library/portable-simd/crates/core_simd/src/vector.rs @@ -9,9 +9,8 @@ pub use uint::*; // Vectors of pointers are not for public use at the current time. pub(crate) mod ptr; -use crate::simd::{ - intrinsics, LaneCount, Mask, MaskElement, SimdPartialOrd, SupportedLaneCount, Swizzle, -}; +use crate::simd::intrinsics; +use crate::simd::{LaneCount, Mask, MaskElement, SupportedLaneCount}; /// A SIMD vector of `LANES` elements of type `T`. `Simd` has the same shape as [`[T; N]`](array), but operates like `T`. /// @@ -100,50 +99,17 @@ where /// Number of lanes in this vector. pub const LANES: usize = LANES; - /// Returns the number of lanes in this SIMD vector. - /// - /// # Examples - /// - /// ``` - /// # #![feature(portable_simd)] - /// # use core::simd::u32x4; - /// let v = u32x4::splat(0); - /// assert_eq!(v.lanes(), 4); - /// ``` + /// Get the number of lanes in this vector. pub const fn lanes(&self) -> usize { LANES } - /// Constructs a new SIMD vector with all lanes set to the given value. - /// - /// # Examples - /// - /// ``` - /// # #![feature(portable_simd)] - /// # use core::simd::u32x4; - /// let v = u32x4::splat(8); - /// assert_eq!(v.as_array(), &[8, 8, 8, 8]); - /// ``` - pub fn splat(value: T) -> Self { - // This is preferred over `[value; LANES]`, since it's explicitly a splat: - // https://github.com/rust-lang/rust/issues/97804 - struct Splat; - impl Swizzle<1, LANES> for Splat { - const INDEX: [usize; LANES] = [0; LANES]; - } - Splat::swizzle(Simd::::from([value])) + /// Construct a SIMD vector by setting all lanes to the given value. + pub const fn splat(value: T) -> Self { + Self([value; LANES]) } /// Returns an array reference containing the entire SIMD vector. - /// - /// # Examples - /// - /// ``` - /// # #![feature(portable_simd)] - /// # use core::simd::{Simd, u64x4}; - /// let v: u64x4 = Simd::from_array([0, 1, 2, 3]); - /// assert_eq!(v.as_array(), &[0, 1, 2, 3]); - /// ``` pub const fn as_array(&self) -> &[T; LANES] { &self.0 } @@ -163,21 +129,9 @@ where self.0 } - /// Converts a slice to a SIMD vector containing `slice[..LANES]`. - /// + /// Converts a slice to a SIMD vector containing `slice[..LANES]` /// # Panics - /// - /// Panics if the slice's length is less than the vector's `Simd::LANES`. - /// - /// # Examples - /// - /// ``` - /// # #![feature(portable_simd)] - /// # use core::simd::u32x4; - /// let source = vec![1, 2, 3, 4, 5, 6]; - /// let v = u32x4::from_slice(&source); - /// assert_eq!(v.as_array(), &[1, 2, 3, 4]); - /// ``` + /// `from_slice` will panic if the slice's `len` is less than the vector's `Simd::LANES`. #[must_use] pub const fn from_slice(slice: &[T]) -> Self { assert!(slice.len() >= LANES, "slice length must be at least the number of lanes"); @@ -191,7 +145,6 @@ where } /// Performs lanewise conversion of a SIMD vector's elements to another SIMD-valid type. - /// /// This follows the semantics of Rust's `as` conversion for casting /// integers to unsigned integers (interpreting as the other type, so `-1` to `MAX`), /// and from floats to integers (truncating, or saturating at the limits) for each lane, @@ -216,35 +169,10 @@ where #[must_use] #[inline] pub fn cast(self) -> Simd { - // Safety: The input argument is a vector of a valid SIMD element type. + // Safety: The input argument is a vector of a known SIMD type. unsafe { intrinsics::simd_as(self) } } - /// Rounds toward zero and converts to the same-width integer type, assuming that - /// the value is finite and fits in that type. - /// - /// # Safety - /// The value must: - /// - /// * Not be NaN - /// * Not be infinite - /// * Be representable in the return type, after truncating off its fractional part - /// - /// If these requirements are infeasible or costly, consider using the safe function [cast], - /// which saturates on conversion. - /// - /// [cast]: Simd::cast - #[inline] - pub unsafe fn to_int_unchecked(self) -> Simd - where - T: core::convert::FloatToInt, - I: SimdElement, - { - // Safety: `self` is a vector, and `FloatToInt` ensures the type can be casted to - // an integer. - unsafe { intrinsics::simd_cast(self) } - } - /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector. /// If an index is out-of-bounds, the lane is instead selected from the `or` vector. /// @@ -311,7 +239,7 @@ where idxs: Simd, or: Self, ) -> Self { - let enable: Mask = enable & idxs.simd_lt(Simd::splat(slice.len())); + let enable: Mask = enable & idxs.lanes_lt(Simd::splat(slice.len())); // Safety: We have masked-off out-of-bounds lanes. unsafe { Self::gather_select_unchecked(slice, enable, idxs, or) } } @@ -328,15 +256,13 @@ where /// # Examples /// ``` /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdPartialOrd, Mask}; + /// # use core::simd::{Simd, Mask}; /// let vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; /// let idxs = Simd::from_array([9, 3, 0, 5]); /// let alt = Simd::from_array([-5, -4, -3, -2]); /// let enable = Mask::from_array([true, true, true, false]); // Note the final mask lane. /// // If this mask was used to gather, it would be unsound. Let's fix that. - /// let enable = enable & idxs.simd_lt(Simd::splat(vec.len())); + /// let enable = enable & idxs.lanes_lt(Simd::splat(vec.len())); /// /// // We have masked the OOB lane, so it's safe to gather now. /// let result = unsafe { Simd::gather_select_unchecked(&vec, enable, idxs, alt) }; @@ -387,9 +313,7 @@ where /// # Examples /// ``` /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, Mask}; + /// # use core::simd::{Simd, Mask}; /// let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; /// let idxs = Simd::from_array([9, 3, 0, 0]); /// let vals = Simd::from_array([-27, 82, -41, 124]); @@ -405,7 +329,7 @@ where enable: Mask, idxs: Simd, ) { - let enable: Mask = enable & idxs.simd_lt(Simd::splat(slice.len())); + let enable: Mask = enable & idxs.lanes_lt(Simd::splat(slice.len())); // Safety: We have masked-off out-of-bounds lanes. unsafe { self.scatter_select_unchecked(slice, enable, idxs) } } @@ -423,15 +347,13 @@ where /// # Examples /// ``` /// # #![feature(portable_simd)] - /// # #[cfg(feature = "as_crate")] use core_simd::simd; - /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdPartialOrd, Mask}; + /// # use core::simd::{Simd, Mask}; /// let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; /// let idxs = Simd::from_array([9, 3, 0, 0]); /// let vals = Simd::from_array([-27, 82, -41, 124]); /// let enable = Mask::from_array([true, true, true, false]); // Note the mask of the last lane. /// // If this mask was used to scatter, it would be unsound. Let's fix that. - /// let enable = enable & idxs.simd_lt(Simd::splat(vec.len())); + /// let enable = enable & idxs.lanes_lt(Simd::splat(vec.len())); /// /// // We have masked the OOB lane, so it's safe to scatter now. /// unsafe { vals.scatter_select_unchecked(&mut vec, enable, idxs); } @@ -503,27 +425,8 @@ where { #[inline] fn eq(&self, other: &Self) -> bool { - // Safety: All SIMD vectors are SimdPartialEq, and the comparison produces a valid mask. - let mask = unsafe { - let tfvec: Simd<::Mask, LANES> = intrinsics::simd_eq(*self, *other); - Mask::from_int_unchecked(tfvec) - }; - - // Two vectors are equal if all lanes tested true for vertical equality. - mask.all() - } - - #[allow(clippy::partialeq_ne_impl)] - #[inline] - fn ne(&self, other: &Self) -> bool { - // Safety: All SIMD vectors are SimdPartialEq, and the comparison produces a valid mask. - let mask = unsafe { - let tfvec: Simd<::Mask, LANES> = intrinsics::simd_ne(*self, *other); - Mask::from_int_unchecked(tfvec) - }; - - // Two vectors are non-equal if any lane tested true for vertical non-equality. - mask.any() + // TODO use SIMD equality + self.to_array() == other.to_array() } } @@ -658,85 +561,61 @@ pub unsafe trait SimdElement: Sealed + Copy { } impl Sealed for u8 {} - -// Safety: u8 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for u8 { type Mask = i8; } impl Sealed for u16 {} - -// Safety: u16 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for u16 { type Mask = i16; } impl Sealed for u32 {} - -// Safety: u32 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for u32 { type Mask = i32; } impl Sealed for u64 {} - -// Safety: u64 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for u64 { type Mask = i64; } impl Sealed for usize {} - -// Safety: usize is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for usize { type Mask = isize; } impl Sealed for i8 {} - -// Safety: i8 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for i8 { type Mask = i8; } impl Sealed for i16 {} - -// Safety: i16 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for i16 { type Mask = i16; } impl Sealed for i32 {} - -// Safety: i32 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for i32 { type Mask = i32; } impl Sealed for i64 {} - -// Safety: i64 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for i64 { type Mask = i64; } impl Sealed for isize {} - -// Safety: isize is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for isize { type Mask = isize; } impl Sealed for f32 {} - -// Safety: f32 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for f32 { type Mask = i32; } impl Sealed for f64 {} - -// Safety: f64 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for f64 { type Mask = i64; } diff --git a/library/portable-simd/crates/core_simd/src/vector/float.rs b/library/portable-simd/crates/core_simd/src/vector/float.rs index f836c99b1e2dc..fcc7f6d8d1c50 100644 --- a/library/portable-simd/crates/core_simd/src/vector/float.rs +++ b/library/portable-simd/crates/core_simd/src/vector/float.rs @@ -1,24 +1,199 @@ #![allow(non_camel_case_types)] -use crate::simd::Simd; +use crate::simd::intrinsics; +use crate::simd::{LaneCount, Mask, Simd, SupportedLaneCount}; -/// A 64-bit SIMD vector with two elements of type `f32`. +/// Implements inherent methods for a float vector containing multiple +/// `$lanes` of float `$type`, which uses `$bits_ty` as its binary +/// representation. +macro_rules! impl_float_vector { + { $type:ty, $bits_ty:ty, $mask_ty:ty } => { + impl Simd<$type, LANES> + where + LaneCount: SupportedLaneCount, + { + /// Raw transmutation to an unsigned integer vector type with the + /// same size and number of lanes. + #[inline] + #[must_use = "method returns a new vector and does not mutate the original value"] + pub fn to_bits(self) -> Simd<$bits_ty, LANES> { + assert_eq!(core::mem::size_of::(), core::mem::size_of::>()); + unsafe { core::mem::transmute_copy(&self) } + } + + /// Raw transmutation from an unsigned integer vector type with the + /// same size and number of lanes. + #[inline] + #[must_use = "method returns a new vector and does not mutate the original value"] + pub fn from_bits(bits: Simd<$bits_ty, LANES>) -> Self { + assert_eq!(core::mem::size_of::(), core::mem::size_of::>()); + unsafe { core::mem::transmute_copy(&bits) } + } + + /// Produces a vector where every lane has the absolute value of the + /// equivalently-indexed lane in `self`. + #[inline] + #[must_use = "method returns a new vector and does not mutate the original value"] + pub fn abs(self) -> Self { + unsafe { intrinsics::simd_fabs(self) } + } + + /// Takes the reciprocal (inverse) of each lane, `1/x`. + #[inline] + #[must_use = "method returns a new vector and does not mutate the original value"] + pub fn recip(self) -> Self { + Self::splat(1.0) / self + } + + /// Converts each lane from radians to degrees. + #[inline] + #[must_use = "method returns a new vector and does not mutate the original value"] + pub fn to_degrees(self) -> Self { + // to_degrees uses a special constant for better precision, so extract that constant + self * Self::splat(<$type>::to_degrees(1.)) + } + + /// Converts each lane from degrees to radians. + #[inline] + #[must_use = "method returns a new vector and does not mutate the original value"] + pub fn to_radians(self) -> Self { + self * Self::splat(<$type>::to_radians(1.)) + } + + /// Returns true for each lane if it has a positive sign, including + /// `+0.0`, `NaN`s with positive sign bit and positive infinity. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn is_sign_positive(self) -> Mask<$mask_ty, LANES> { + !self.is_sign_negative() + } + + /// Returns true for each lane if it has a negative sign, including + /// `-0.0`, `NaN`s with negative sign bit and negative infinity. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn is_sign_negative(self) -> Mask<$mask_ty, LANES> { + let sign_bits = self.to_bits() & Simd::splat((!0 >> 1) + 1); + sign_bits.lanes_gt(Simd::splat(0)) + } + + /// Returns true for each lane if its value is `NaN`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn is_nan(self) -> Mask<$mask_ty, LANES> { + self.lanes_ne(self) + } + + /// Returns true for each lane if its value is positive infinity or negative infinity. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn is_infinite(self) -> Mask<$mask_ty, LANES> { + self.abs().lanes_eq(Self::splat(<$type>::INFINITY)) + } + + /// Returns true for each lane if its value is neither infinite nor `NaN`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn is_finite(self) -> Mask<$mask_ty, LANES> { + self.abs().lanes_lt(Self::splat(<$type>::INFINITY)) + } + + /// Returns true for each lane if its value is subnormal. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn is_subnormal(self) -> Mask<$mask_ty, LANES> { + self.abs().lanes_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(<$type>::INFINITY).to_bits()).lanes_eq(Simd::splat(0)) + } + + /// Returns true for each lane if its value is neither zero, infinite, + /// subnormal, nor `NaN`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn is_normal(self) -> Mask<$mask_ty, LANES> { + !(self.abs().lanes_eq(Self::splat(0.0)) | self.is_nan() | self.is_subnormal() | self.is_infinite()) + } + + /// Replaces each lane with a number that represents its sign. + /// + /// * `1.0` if the number is positive, `+0.0`, or `INFINITY` + /// * `-1.0` if the number is negative, `-0.0`, or `NEG_INFINITY` + /// * `NAN` if the number is `NAN` + #[inline] + #[must_use = "method returns a new vector and does not mutate the original value"] + pub fn signum(self) -> Self { + self.is_nan().select(Self::splat(<$type>::NAN), Self::splat(1.0).copysign(self)) + } + + /// Returns each lane with the magnitude of `self` and the sign of `sign`. + /// + /// If any lane is a `NAN`, then a `NAN` with the sign of `sign` is returned. + #[inline] + #[must_use = "method returns a new vector and does not mutate the original value"] + pub fn copysign(self, sign: Self) -> Self { + let sign_bit = sign.to_bits() & Self::splat(-0.).to_bits(); + let magnitude = self.to_bits() & !Self::splat(-0.).to_bits(); + Self::from_bits(sign_bit | magnitude) + } + + /// Returns the minimum of each lane. + /// + /// If one of the values is `NAN`, then the other value is returned. + #[inline] + #[must_use = "method returns a new vector and does not mutate the original value"] + pub fn min(self, other: Self) -> Self { + unsafe { intrinsics::simd_fmin(self, other) } + } + + /// Returns the maximum of each lane. + /// + /// If one of the values is `NAN`, then the other value is returned. + #[inline] + #[must_use = "method returns a new vector and does not mutate the original value"] + pub fn max(self, other: Self) -> Self { + unsafe { intrinsics::simd_fmax(self, other) } + } + + /// Restrict each lane to a certain interval unless it is NaN. + /// + /// For each lane in `self`, returns the corresponding lane in `max` if the lane is + /// greater than `max`, and the corresponding lane in `min` if the lane is less + /// than `min`. Otherwise returns the lane in `self`. + #[inline] + #[must_use = "method returns a new vector and does not mutate the original value"] + pub fn clamp(self, min: Self, max: Self) -> Self { + assert!( + min.lanes_le(max).all(), + "each lane in `min` must be less than or equal to the corresponding lane in `max`", + ); + let mut x = self; + x = x.lanes_lt(min).select(min, x); + x = x.lanes_gt(max).select(max, x); + x + } + } + }; +} + +impl_float_vector! { f32, u32, i32 } +impl_float_vector! { f64, u64, i64 } + +/// Vector of two `f32` values pub type f32x2 = Simd; -/// A 128-bit SIMD vector with four elements of type `f32`. +/// Vector of four `f32` values pub type f32x4 = Simd; -/// A 256-bit SIMD vector with eight elements of type `f32`. +/// Vector of eight `f32` values pub type f32x8 = Simd; -/// A 512-bit SIMD vector with 16 elements of type `f32`. +/// Vector of 16 `f32` values pub type f32x16 = Simd; -/// A 128-bit SIMD vector with two elements of type `f64`. +/// Vector of two `f64` values pub type f64x2 = Simd; -/// A 256-bit SIMD vector with four elements of type `f64`. +/// Vector of four `f64` values pub type f64x4 = Simd; -/// A 512-bit SIMD vector with eight elements of type `f64`. +/// Vector of eight `f64` values pub type f64x8 = Simd; diff --git a/library/portable-simd/crates/core_simd/src/vector/int.rs b/library/portable-simd/crates/core_simd/src/vector/int.rs index 20e56c7dc6443..3eac02a27618c 100644 --- a/library/portable-simd/crates/core_simd/src/vector/int.rs +++ b/library/portable-simd/crates/core_simd/src/vector/int.rs @@ -1,63 +1,103 @@ #![allow(non_camel_case_types)] -use crate::simd::Simd; - -/// A SIMD vector with two elements of type `isize`. +use crate::simd::{LaneCount, Mask, Simd, SupportedLaneCount}; + +/// Implements additional integer traits (Eq, Ord, Hash) on the specified vector `$name`, holding multiple `$lanes` of `$type`. +macro_rules! impl_integer_vector { + { $type:ty } => { + impl Simd<$type, LANES> + where + LaneCount: SupportedLaneCount, + { + /// Returns true for each positive lane and false if it is zero or negative. + #[inline] + pub fn is_positive(self) -> Mask<$type, LANES> { + self.lanes_gt(Self::splat(0)) + } + + /// Returns true for each negative lane and false if it is zero or positive. + #[inline] + pub fn is_negative(self) -> Mask<$type, LANES> { + self.lanes_lt(Self::splat(0)) + } + + /// Returns numbers representing the sign of each lane. + /// * `0` if the number is zero + /// * `1` if the number is positive + /// * `-1` if the number is negative + #[inline] + pub fn signum(self) -> Self { + self.is_positive().select( + Self::splat(1), + self.is_negative().select(Self::splat(-1), Self::splat(0)) + ) + } + } + } +} + +impl_integer_vector! { isize } +impl_integer_vector! { i16 } +impl_integer_vector! { i32 } +impl_integer_vector! { i64 } +impl_integer_vector! { i8 } + +/// Vector of two `isize` values pub type isizex2 = Simd; -/// A SIMD vector with four elements of type `isize`. +/// Vector of four `isize` values pub type isizex4 = Simd; -/// A SIMD vector with eight elements of type `isize`. +/// Vector of eight `isize` values pub type isizex8 = Simd; -/// A 32-bit SIMD vector with two elements of type `i16`. +/// Vector of two `i16` values pub type i16x2 = Simd; -/// A 64-bit SIMD vector with four elements of type `i16`. +/// Vector of four `i16` values pub type i16x4 = Simd; -/// A 128-bit SIMD vector with eight elements of type `i16`. +/// Vector of eight `i16` values pub type i16x8 = Simd; -/// A 256-bit SIMD vector with 16 elements of type `i16`. +/// Vector of 16 `i16` values pub type i16x16 = Simd; -/// A 512-bit SIMD vector with 32 elements of type `i16`. +/// Vector of 32 `i16` values pub type i16x32 = Simd; -/// A 64-bit SIMD vector with two elements of type `i32`. +/// Vector of two `i32` values pub type i32x2 = Simd; -/// A 128-bit SIMD vector with four elements of type `i32`. +/// Vector of four `i32` values pub type i32x4 = Simd; -/// A 256-bit SIMD vector with eight elements of type `i32`. +/// Vector of eight `i32` values pub type i32x8 = Simd; -/// A 512-bit SIMD vector with 16 elements of type `i32`. +/// Vector of 16 `i32` values pub type i32x16 = Simd; -/// A 128-bit SIMD vector with two elements of type `i64`. +/// Vector of two `i64` values pub type i64x2 = Simd; -/// A 256-bit SIMD vector with four elements of type `i64`. +/// Vector of four `i64` values pub type i64x4 = Simd; -/// A 512-bit SIMD vector with eight elements of type `i64`. +/// Vector of eight `i64` values pub type i64x8 = Simd; -/// A 32-bit SIMD vector with four elements of type `i8`. +/// Vector of four `i8` values pub type i8x4 = Simd; -/// A 64-bit SIMD vector with eight elements of type `i8`. +/// Vector of eight `i8` values pub type i8x8 = Simd; -/// A 128-bit SIMD vector with 16 elements of type `i8`. +/// Vector of 16 `i8` values pub type i8x16 = Simd; -/// A 256-bit SIMD vector with 32 elements of type `i8`. +/// Vector of 32 `i8` values pub type i8x32 = Simd; -/// A 512-bit SIMD vector with 64 elements of type `i8`. +/// Vector of 64 `i8` values pub type i8x64 = Simd; diff --git a/library/portable-simd/crates/core_simd/src/vector/uint.rs b/library/portable-simd/crates/core_simd/src/vector/uint.rs index b4a69c44363f1..ed91fc3640e74 100644 --- a/library/portable-simd/crates/core_simd/src/vector/uint.rs +++ b/library/portable-simd/crates/core_simd/src/vector/uint.rs @@ -2,62 +2,62 @@ use crate::simd::Simd; -/// A SIMD vector with two elements of type `usize`. +/// Vector of two `usize` values pub type usizex2 = Simd; -/// A SIMD vector with four elements of type `usize`. +/// Vector of four `usize` values pub type usizex4 = Simd; -/// A SIMD vector with eight elements of type `usize`. +/// Vector of eight `usize` values pub type usizex8 = Simd; -/// A 32-bit SIMD vector with two elements of type `u16`. +/// Vector of two `u16` values pub type u16x2 = Simd; -/// A 64-bit SIMD vector with four elements of type `u16`. +/// Vector of four `u16` values pub type u16x4 = Simd; -/// A 128-bit SIMD vector with eight elements of type `u16`. +/// Vector of eight `u16` values pub type u16x8 = Simd; -/// A 256-bit SIMD vector with 16 elements of type `u16`. +/// Vector of 16 `u16` values pub type u16x16 = Simd; -/// A 512-bit SIMD vector with 32 elements of type `u16`. +/// Vector of 32 `u16` values pub type u16x32 = Simd; -/// A 64-bit SIMD vector with two elements of type `u32`. +/// Vector of two `u32` values pub type u32x2 = Simd; -/// A 128-bit SIMD vector with four elements of type `u32`. +/// Vector of four `u32` values pub type u32x4 = Simd; -/// A 256-bit SIMD vector with eight elements of type `u32`. +/// Vector of eight `u32` values pub type u32x8 = Simd; -/// A 512-bit SIMD vector with 16 elements of type `u32`. +/// Vector of 16 `u32` values pub type u32x16 = Simd; -/// A 128-bit SIMD vector with two elements of type `u64`. +/// Vector of two `u64` values pub type u64x2 = Simd; -/// A 256-bit SIMD vector with four elements of type `u64`. +/// Vector of four `u64` values pub type u64x4 = Simd; -/// A 512-bit SIMD vector with eight elements of type `u64`. +/// Vector of eight `u64` values pub type u64x8 = Simd; -/// A 32-bit SIMD vector with four elements of type `u8`. +/// Vector of four `u8` values pub type u8x4 = Simd; -/// A 64-bit SIMD vector with eight elements of type `u8`. +/// Vector of eight `u8` values pub type u8x8 = Simd; -/// A 128-bit SIMD vector with 16 elements of type `u8`. +/// Vector of 16 `u8` values pub type u8x16 = Simd; -/// A 256-bit SIMD vector with 32 elements of type `u8`. +/// Vector of 32 `u8` values pub type u8x32 = Simd; -/// A 512-bit SIMD vector with 64 elements of type `u8`. +/// Vector of 64 `u8` values pub type u8x64 = Simd; diff --git a/library/portable-simd/crates/core_simd/tests/i16_ops.rs b/library/portable-simd/crates/core_simd/tests/i16_ops.rs index f6c5d74fbbcc6..171e5b472fa76 100644 --- a/library/portable-simd/crates/core_simd/tests/i16_ops.rs +++ b/library/portable-simd/crates/core_simd/tests/i16_ops.rs @@ -1,5 +1,32 @@ #![feature(portable_simd)] +use core_simd::i16x2; #[macro_use] mod ops_macros; impl_signed_tests! { i16 } + +#[test] +fn max_is_not_lexicographic() { + let a = i16x2::splat(10); + let b = i16x2::from_array([-4, 12]); + assert_eq!(a.max(b), i16x2::from_array([10, 12])); +} + +#[test] +fn min_is_not_lexicographic() { + let a = i16x2::splat(10); + let b = i16x2::from_array([12, -4]); + assert_eq!(a.min(b), i16x2::from_array([10, -4])); +} + +#[test] +fn clamp_is_not_lexicographic() { + let a = i16x2::splat(10); + let lo = i16x2::from_array([-12, -4]); + let up = i16x2::from_array([-4, 12]); + assert_eq!(a.clamp(lo, up), i16x2::from_array([-4, 10])); + + let x = i16x2::from_array([1, 10]); + let y = x.clamp(i16x2::splat(0), i16x2::splat(9)); + assert_eq!(y, i16x2::from_array([1, 9])); +} diff --git a/library/portable-simd/crates/core_simd/tests/masks.rs b/library/portable-simd/crates/core_simd/tests/masks.rs index 673d0db93fee5..3aec36ca7b746 100644 --- a/library/portable-simd/crates/core_simd/tests/masks.rs +++ b/library/portable-simd/crates/core_simd/tests/masks.rs @@ -80,62 +80,6 @@ macro_rules! test_mask_api { assert_eq!(bitmask, 0b1000001101001001); assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask); } - - #[test] - fn roundtrip_bitmask_conversion_short() { - use core_simd::ToBitMask; - - let values = [ - false, false, false, true, - ]; - let mask = core_simd::Mask::<$type, 4>::from_array(values); - let bitmask = mask.to_bitmask(); - assert_eq!(bitmask, 0b1000); - assert_eq!(core_simd::Mask::<$type, 4>::from_bitmask(bitmask), mask); - - let values = [true, false]; - let mask = core_simd::Mask::<$type, 2>::from_array(values); - let bitmask = mask.to_bitmask(); - assert_eq!(bitmask, 0b01); - assert_eq!(core_simd::Mask::<$type, 2>::from_bitmask(bitmask), mask); - } - - #[test] - fn cast() { - fn cast_impl() - where - core_simd::Mask<$type, 8>: Into>, - { - let values = [true, false, false, true, false, false, true, false]; - let mask = core_simd::Mask::<$type, 8>::from_array(values); - - let cast_mask = mask.cast::(); - assert_eq!(values, cast_mask.to_array()); - - let into_mask: core_simd::Mask = mask.into(); - assert_eq!(values, into_mask.to_array()); - } - - cast_impl::(); - cast_impl::(); - cast_impl::(); - cast_impl::(); - cast_impl::(); - } - - #[cfg(feature = "generic_const_exprs")] - #[test] - fn roundtrip_bitmask_array_conversion() { - use core_simd::ToBitMaskArray; - let values = [ - true, false, false, true, false, false, true, false, - true, true, false, false, false, false, false, true, - ]; - let mask = core_simd::Mask::<$type, 16>::from_array(values); - let bitmask = mask.to_bitmask_array(); - assert_eq!(bitmask, [0b01001001, 0b10000011]); - assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask_array(bitmask), mask); - } } } } diff --git a/library/portable-simd/crates/core_simd/tests/ops_macros.rs b/library/portable-simd/crates/core_simd/tests/ops_macros.rs index f759394d07582..7c9b17673efe3 100644 --- a/library/portable-simd/crates/core_simd/tests/ops_macros.rs +++ b/library/portable-simd/crates/core_simd/tests/ops_macros.rs @@ -172,7 +172,6 @@ macro_rules! impl_common_integer_tests { macro_rules! impl_signed_tests { { $scalar:tt } => { mod $scalar { - use core_simd::simd::SimdInt; type Vector = core_simd::Simd; type Scalar = $scalar; @@ -223,37 +222,34 @@ macro_rules! impl_signed_tests { assert_eq!(a % b, Vector::::splat(0)); } - fn simd_min() { - use core_simd::simd::SimdOrd; + fn min() { let a = Vector::::splat(Scalar::MIN); let b = Vector::::splat(0); - assert_eq!(a.simd_min(b), a); + assert_eq!(a.min(b), a); let a = Vector::::splat(Scalar::MAX); let b = Vector::::splat(0); - assert_eq!(a.simd_min(b), b); + assert_eq!(a.min(b), b); } - fn simd_max() { - use core_simd::simd::SimdOrd; + fn max() { let a = Vector::::splat(Scalar::MIN); let b = Vector::::splat(0); - assert_eq!(a.simd_max(b), b); + assert_eq!(a.max(b), b); let a = Vector::::splat(Scalar::MAX); let b = Vector::::splat(0); - assert_eq!(a.simd_max(b), a); + assert_eq!(a.max(b), a); } - fn simd_clamp() { - use core_simd::simd::SimdOrd; + fn clamp() { let min = Vector::::splat(Scalar::MIN); let max = Vector::::splat(Scalar::MAX); let zero = Vector::::splat(0); let one = Vector::::splat(1); let negone = Vector::::splat(-1); - assert_eq!(zero.simd_clamp(min, max), zero); - assert_eq!(zero.simd_clamp(min, one), zero); - assert_eq!(zero.simd_clamp(one, max), one); - assert_eq!(zero.simd_clamp(min, negone), negone); + assert_eq!(zero.clamp(min, max), zero); + assert_eq!(zero.clamp(min, one), zero); + assert_eq!(zero.clamp(one, max), one); + assert_eq!(zero.clamp(min, negone), negone); } } @@ -313,7 +309,6 @@ macro_rules! impl_signed_tests { macro_rules! impl_unsigned_tests { { $scalar:tt } => { mod $scalar { - use core_simd::simd::SimdUint; type Vector = core_simd::Simd; type Scalar = $scalar; @@ -348,7 +343,6 @@ macro_rules! impl_unsigned_tests { macro_rules! impl_float_tests { { $scalar:tt, $int_scalar:tt } => { mod $scalar { - use core_simd::SimdFloat; type Vector = core_simd::Simd; type Scalar = $scalar; @@ -464,10 +458,10 @@ macro_rules! impl_float_tests { ) } - fn simd_min() { + fn min() { // Regular conditions (both values aren't zero) test_helpers::test_binary_elementwise( - &Vector::::simd_min, + &Vector::::min, &Scalar::min, // Reject the case where both values are zero with different signs &|a, b| { @@ -483,14 +477,14 @@ macro_rules! impl_float_tests { // Special case where both values are zero let p_zero = Vector::::splat(0.); let n_zero = Vector::::splat(-0.); - assert!(p_zero.simd_min(n_zero).to_array().iter().all(|x| *x == 0.)); - assert!(n_zero.simd_min(p_zero).to_array().iter().all(|x| *x == 0.)); + assert!(p_zero.min(n_zero).to_array().iter().all(|x| *x == 0.)); + assert!(n_zero.min(p_zero).to_array().iter().all(|x| *x == 0.)); } - fn simd_max() { + fn max() { // Regular conditions (both values aren't zero) test_helpers::test_binary_elementwise( - &Vector::::simd_max, + &Vector::::max, &Scalar::max, // Reject the case where both values are zero with different signs &|a, b| { @@ -506,11 +500,11 @@ macro_rules! impl_float_tests { // Special case where both values are zero let p_zero = Vector::::splat(0.); let n_zero = Vector::::splat(-0.); - assert!(p_zero.simd_max(n_zero).to_array().iter().all(|x| *x == 0.)); - assert!(n_zero.simd_max(p_zero).to_array().iter().all(|x| *x == 0.)); + assert!(p_zero.max(n_zero).to_array().iter().all(|x| *x == 0.)); + assert!(n_zero.max(p_zero).to_array().iter().all(|x| *x == 0.)); } - fn simd_clamp() { + fn clamp() { test_helpers::test_3(&|value: [Scalar; LANES], mut min: [Scalar; LANES], mut max: [Scalar; LANES]| { for (min, max) in min.iter_mut().zip(max.iter_mut()) { if max < min { @@ -528,7 +522,7 @@ macro_rules! impl_float_tests { for i in 0..LANES { result_scalar[i] = value[i].clamp(min[i], max[i]); } - let result_vector = Vector::from_array(value).simd_clamp(min.into(), max.into()).to_array(); + let result_vector = Vector::from_array(value).clamp(min.into(), max.into()).to_array(); test_helpers::prop_assert_biteq!(result_scalar, result_vector); Ok(()) }) diff --git a/library/portable-simd/crates/core_simd/tests/round.rs b/library/portable-simd/crates/core_simd/tests/round.rs index 484fd5bf47d1b..7feb0320a16c5 100644 --- a/library/portable-simd/crates/core_simd/tests/round.rs +++ b/library/portable-simd/crates/core_simd/tests/round.rs @@ -59,7 +59,7 @@ macro_rules! float_rounding_test { const MAX_REPRESENTABLE_VALUE: Scalar = (ALL_MANTISSA_BITS << (core::mem::size_of::() * 8 - ::MANTISSA_DIGITS as usize - 1)) as Scalar; - let mut runner = test_helpers::make_runner(); + let mut runner = proptest::test_runner::TestRunner::default(); runner.run( &test_helpers::array::UniformArrayStrategy::new(-MAX_REPRESENTABLE_VALUE..MAX_REPRESENTABLE_VALUE), |x| { diff --git a/library/portable-simd/crates/test_helpers/src/lib.rs b/library/portable-simd/crates/test_helpers/src/lib.rs index 141bee18a9a40..8bf7f5ed3d2a4 100644 --- a/library/portable-simd/crates/test_helpers/src/lib.rs +++ b/library/portable-simd/crates/test_helpers/src/lib.rs @@ -78,11 +78,11 @@ impl DefaultStrategy } #[cfg(not(miri))] -pub fn make_runner() -> proptest::test_runner::TestRunner { +fn make_runner() -> proptest::test_runner::TestRunner { Default::default() } #[cfg(miri)] -pub fn make_runner() -> proptest::test_runner::TestRunner { +fn make_runner() -> proptest::test_runner::TestRunner { // Only run a few tests on Miri proptest::test_runner::TestRunner::new(proptest::test_runner::Config::with_cases(4)) } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 8e478cd7bc8a2..5cf16bdd08cdd 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -382,14 +382,6 @@ pub mod token_stream { bridge::TokenTree::Literal(tt) => TokenTree::Literal(Literal(tt)), }) } - - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - - fn count(self) -> usize { - self.0.count() - } } #[stable(feature = "proc_macro_lib2", since = "1.29.0")] @@ -1492,7 +1484,7 @@ impl fmt::Debug for Literal { } /// Tracked access to environment variables. -#[unstable(feature = "proc_macro_tracked_env", issue = "99515")] +#[unstable(feature = "proc_macro_tracked_env", issue = "74690")] pub mod tracked_env { use std::env::{self, VarError}; use std::ffi::OsStr; @@ -1502,7 +1494,7 @@ pub mod tracked_env { /// compilation, and will be able to rerun the build when the value of that variable changes. /// Besides the dependency tracking this function should be equivalent to `env::var` from the /// standard library, except that the argument must be UTF-8. - #[unstable(feature = "proc_macro_tracked_env", issue = "99515")] + #[unstable(feature = "proc_macro_tracked_env", issue = "74690")] pub fn var + AsRef>(key: K) -> Result { let key: &str = key.as_ref(); let value = env::var(key); @@ -1512,13 +1504,13 @@ pub mod tracked_env { } /// Tracked access to additional files. -#[unstable(feature = "track_path", issue = "99515")] +#[unstable(feature = "track_path", issue = "73921")] pub mod tracked_path { /// Track a file explicitly. /// /// Commonly used for tracking asset preprocessing. - #[unstable(feature = "track_path", issue = "99515")] + #[unstable(feature = "track_path", issue = "73921")] pub fn path>(path: P) { let path: &str = path.as_ref(); crate::bridge::client::FreeFunctions::track_path(path); diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index f7fbaa9c27649..989cec976b72f 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -1,10 +1,9 @@ -mod buffer; - +use crate::cmp; use crate::fmt; use crate::io::{ self, BufRead, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE, }; -use buffer::Buffer; +use crate::mem::MaybeUninit; /// The `BufReader` struct adds buffering to any reader. /// @@ -49,7 +48,10 @@ use buffer::Buffer; #[stable(feature = "rust1", since = "1.0.0")] pub struct BufReader { inner: R, - buf: Buffer, + buf: Box<[MaybeUninit]>, + pos: usize, + cap: usize, + init: usize, } impl BufReader { @@ -91,7 +93,8 @@ impl BufReader { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize, inner: R) -> BufReader { - BufReader { inner, buf: Buffer::with_capacity(capacity) } + let buf = Box::new_uninit_slice(capacity); + BufReader { inner, buf, pos: 0, cap: 0, init: 0 } } } @@ -167,7 +170,8 @@ impl BufReader { /// ``` #[stable(feature = "bufreader_buffer", since = "1.37.0")] pub fn buffer(&self) -> &[u8] { - self.buf.buffer() + // SAFETY: self.cap is always <= self.init, so self.buf[self.pos..self.cap] is always init + unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[self.pos..self.cap]) } } /// Returns the number of bytes the internal buffer can hold at once. @@ -190,7 +194,7 @@ impl BufReader { /// ``` #[stable(feature = "buffered_io_capacity", since = "1.46.0")] pub fn capacity(&self) -> usize { - self.buf.capacity() + self.buf.len() } /// Unwraps this `BufReader`, returning the underlying reader. @@ -220,7 +224,8 @@ impl BufReader { /// Invalidates all data in the internal buffer. #[inline] fn discard_buffer(&mut self) { - self.buf.discard_buffer() + self.pos = 0; + self.cap = 0; } } @@ -231,15 +236,15 @@ impl BufReader { /// must track this information themselves if it is required. #[stable(feature = "bufreader_seek_relative", since = "1.53.0")] pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> { - let pos = self.buf.pos() as u64; + let pos = self.pos as u64; if offset < 0 { - if let Some(_) = pos.checked_sub((-offset) as u64) { - self.buf.unconsume((-offset) as usize); + if let Some(new_pos) = pos.checked_sub((-offset) as u64) { + self.pos = new_pos as usize; return Ok(()); } } else if let Some(new_pos) = pos.checked_add(offset as u64) { - if new_pos <= self.buf.filled() as u64 { - self.buf.consume(offset as usize); + if new_pos <= self.cap as u64 { + self.pos = new_pos as usize; return Ok(()); } } @@ -254,7 +259,7 @@ impl Read for BufReader { // If we don't have any buffered data and we're doing a massive read // (larger than our internal buffer), bypass our internal buffer // entirely. - if self.buf.pos() == self.buf.filled() && buf.len() >= self.capacity() { + if self.pos == self.cap && buf.len() >= self.buf.len() { self.discard_buffer(); return self.inner.read(buf); } @@ -270,7 +275,7 @@ impl Read for BufReader { // If we don't have any buffered data and we're doing a massive read // (larger than our internal buffer), bypass our internal buffer // entirely. - if self.buf.pos() == self.buf.filled() && buf.remaining() >= self.capacity() { + if self.pos == self.cap && buf.remaining() >= self.buf.len() { self.discard_buffer(); return self.inner.read_buf(buf); } @@ -290,7 +295,9 @@ impl Read for BufReader { // generation for the common path where the buffer has enough bytes to fill the passed-in // buffer. fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - if self.buf.consume_with(buf.len(), |claimed| buf.copy_from_slice(claimed)) { + if self.buffer().len() >= buf.len() { + buf.copy_from_slice(&self.buffer()[..buf.len()]); + self.consume(buf.len()); return Ok(()); } @@ -299,7 +306,7 @@ impl Read for BufReader { fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { let total_len = bufs.iter().map(|b| b.len()).sum::(); - if self.buf.pos() == self.buf.filled() && total_len >= self.capacity() { + if self.pos == self.cap && total_len >= self.buf.len() { self.discard_buffer(); return self.inner.read_vectored(bufs); } @@ -318,9 +325,8 @@ impl Read for BufReader { // The inner reader might have an optimized `read_to_end`. Drain our buffer and then // delegate to the inner implementation. fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - let inner_buf = self.buffer(); - buf.extend_from_slice(inner_buf); - let nread = inner_buf.len(); + let nread = self.cap - self.pos; + buf.extend_from_slice(&self.buffer()); self.discard_buffer(); Ok(nread + self.inner.read_to_end(buf)?) } @@ -365,11 +371,33 @@ impl Read for BufReader { #[stable(feature = "rust1", since = "1.0.0")] impl BufRead for BufReader { fn fill_buf(&mut self) -> io::Result<&[u8]> { - self.buf.fill_buf(&mut self.inner) + // If we've reached the end of our internal buffer then we need to fetch + // some more data from the underlying reader. + // Branch using `>=` instead of the more correct `==` + // to tell the compiler that the pos..cap slice is always valid. + if self.pos >= self.cap { + debug_assert!(self.pos == self.cap); + + let mut readbuf = ReadBuf::uninit(&mut self.buf); + + // SAFETY: `self.init` is either 0 or set to `readbuf.initialized_len()` + // from the last time this function was called + unsafe { + readbuf.assume_init(self.init); + } + + self.inner.read_buf(&mut readbuf)?; + + self.cap = readbuf.filled_len(); + self.init = readbuf.initialized_len(); + + self.pos = 0; + } + Ok(self.buffer()) } fn consume(&mut self, amt: usize) { - self.buf.consume(amt) + self.pos = cmp::min(self.pos + amt, self.cap); } } @@ -381,10 +409,7 @@ where fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("BufReader") .field("reader", &self.inner) - .field( - "buffer", - &format_args!("{}/{}", self.buf.filled() - self.buf.pos(), self.capacity()), - ) + .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len())) .finish() } } @@ -416,7 +441,7 @@ impl Seek for BufReader { fn seek(&mut self, pos: SeekFrom) -> io::Result { let result: u64; if let SeekFrom::Current(n) = pos { - let remainder = (self.buf.filled() - self.buf.pos()) as i64; + let remainder = (self.cap - self.pos) as i64; // it should be safe to assume that remainder fits within an i64 as the alternative // means we managed to allocate 8 exbibytes and that's absurd. // But it's not out of the realm of possibility for some weird underlying reader to @@ -474,7 +499,7 @@ impl Seek for BufReader { /// } /// ``` fn stream_position(&mut self) -> io::Result { - let remainder = (self.buf.filled() - self.buf.pos()) as u64; + let remainder = (self.cap - self.pos) as u64; self.inner.stream_position().map(|pos| { pos.checked_sub(remainder).expect( "overflow when subtracting remaining buffer size from inner stream position", diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs deleted file mode 100644 index 8ae01f3b0ad8a..0000000000000 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ /dev/null @@ -1,105 +0,0 @@ -///! An encapsulation of `BufReader`'s buffer management logic. -/// -/// This module factors out the basic functionality of `BufReader` in order to protect two core -/// invariants: -/// * `filled` bytes of `buf` are always initialized -/// * `pos` is always <= `filled` -/// Since this module encapsulates the buffer management logic, we can ensure that the range -/// `pos..filled` is always a valid index into the initialized region of the buffer. This means -/// that user code which wants to do reads from a `BufReader` via `buffer` + `consume` can do so -/// without encountering any runtime bounds checks. -use crate::cmp; -use crate::io::{self, Read, ReadBuf}; -use crate::mem::MaybeUninit; - -pub struct Buffer { - // The buffer. - buf: Box<[MaybeUninit]>, - // The current seek offset into `buf`, must always be <= `filled`. - pos: usize, - // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are - // initialized with bytes from a read. - filled: usize, -} - -impl Buffer { - #[inline] - pub fn with_capacity(capacity: usize) -> Self { - let buf = Box::new_uninit_slice(capacity); - Self { buf, pos: 0, filled: 0 } - } - - #[inline] - pub fn buffer(&self) -> &[u8] { - // SAFETY: self.pos and self.cap are valid, and self.cap => self.pos, and - // that region is initialized because those are all invariants of this type. - unsafe { MaybeUninit::slice_assume_init_ref(self.buf.get_unchecked(self.pos..self.filled)) } - } - - #[inline] - pub fn capacity(&self) -> usize { - self.buf.len() - } - - #[inline] - pub fn filled(&self) -> usize { - self.filled - } - - #[inline] - pub fn pos(&self) -> usize { - self.pos - } - - #[inline] - pub fn discard_buffer(&mut self) { - self.pos = 0; - self.filled = 0; - } - - #[inline] - pub fn consume(&mut self, amt: usize) { - self.pos = cmp::min(self.pos + amt, self.filled); - } - - /// If there are `amt` bytes available in the buffer, pass a slice containing those bytes to - /// `visitor` and return true. If there are not enough bytes available, return false. - #[inline] - pub fn consume_with(&mut self, amt: usize, mut visitor: V) -> bool - where - V: FnMut(&[u8]), - { - if let Some(claimed) = self.buffer().get(..amt) { - visitor(claimed); - // If the indexing into self.buffer() succeeds, amt must be a valid increment. - self.pos += amt; - true - } else { - false - } - } - - #[inline] - pub fn unconsume(&mut self, amt: usize) { - self.pos = self.pos.saturating_sub(amt); - } - - #[inline] - pub fn fill_buf(&mut self, mut reader: impl Read) -> io::Result<&[u8]> { - // If we've reached the end of our internal buffer then we need to fetch - // some more data from the reader. - // Branch using `>=` instead of the more correct `==` - // to tell the compiler that the pos..cap slice is always valid. - if self.pos >= self.filled { - debug_assert!(self.pos == self.filled); - - let mut readbuf = ReadBuf::uninit(&mut self.buf); - - reader.read_buf(&mut readbuf)?; - - self.filled = readbuf.filled_len(); - self.pos = 0; - } - Ok(self.buffer()) - } -} diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs index fe45b13263844..9d429e7090e83 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/std/src/io/buffered/tests.rs @@ -523,7 +523,6 @@ fn bench_buffered_reader_small_reads(b: &mut test::Bencher) { let mut buf = [0u8; 4]; for _ in 0..1024 { reader.read_exact(&mut buf).unwrap(); - core::hint::black_box(&buf); } }); } diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 96addbd1a0558..f4f2e3f243457 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -898,7 +898,7 @@ pub trait Read { /// use std::fs::File; /// /// fn main() -> io::Result<()> { - /// let f = File::open("foo.txt")?; + /// let mut f = File::open("foo.txt")?; /// /// for byte in f.bytes() { /// println!("{}", byte.unwrap()); @@ -932,8 +932,8 @@ pub trait Read { /// use std::fs::File; /// /// fn main() -> io::Result<()> { - /// let f1 = File::open("foo.txt")?; - /// let f2 = File::open("bar.txt")?; + /// let mut f1 = File::open("foo.txt")?; + /// let mut f2 = File::open("bar.txt")?; /// /// let mut handle = f1.chain(f2); /// let mut buffer = String::new(); @@ -973,7 +973,7 @@ pub trait Read { /// use std::fs::File; /// /// fn main() -> io::Result<()> { - /// let f = File::open("foo.txt")?; + /// let mut f = File::open("foo.txt")?; /// let mut buffer = [0; 5]; /// /// // read at most five bytes @@ -2577,7 +2577,6 @@ impl Read for Take { let max = cmp::min(buf.len() as u64, self.limit) as usize; let n = self.inner.read(&mut buf[..max])?; - assert!(n as u64 <= self.limit, "number of read bytes exceeds limit"); self.limit -= n as u64; Ok(n) } diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 4d3736f79146c..e3b62894d0f22 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -220,7 +220,7 @@ fn handle_ebadf(r: io::Result, default: T) -> io::Result { /// /// fn main() -> io::Result<()> { /// let mut buffer = String::new(); -/// let stdin = io::stdin(); // We get `Stdin` here. +/// let mut stdin = io::stdin(); // We get `Stdin` here. /// stdin.read_line(&mut buffer)?; /// Ok(()) /// } diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index f357f33ec52c5..d5a8c93b0ce9f 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -583,25 +583,6 @@ fn test_write_all_vectored() { } } -// Issue 94981 -#[test] -#[should_panic = "number of read bytes exceeds limit"] -fn test_take_wrong_length() { - struct LieAboutSize(bool); - - impl Read for LieAboutSize { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - // Lie about the read size at first time of read. - if core::mem::take(&mut self.0) { Ok(buf.len() + 1) } else { Ok(buf.len()) } - } - } - - let mut buffer = vec![0; 4]; - let mut reader = LieAboutSize(true).take(4); - // Primed the `Limit` by lying about the read size. - let _ = reader.read(&mut buffer[..]); -} - #[bench] fn bench_take_read(b: &mut test::Bencher) { b.iter(|| { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 6b0c0ad7c2166..9fd426d3ac4e2 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -276,7 +276,6 @@ #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] #![feature(int_error_internals)] -#![feature(is_some_with)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_write_slice)] #![feature(mixed_integer_ops)] diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index a463bc41db7aa..d661a13edc5e5 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -356,7 +356,7 @@ impl From for crate::net::UdpSocket { } } -#[stable(feature = "asfd_ptrs", since = "1.64.0")] +#[stable(feature = "io_safety", since = "1.63.0")] /// This impl allows implementing traits that require `AsFd` on Arc. /// ``` /// # #[cfg(any(unix, target_os = "wasi"))] mod group_cfg { @@ -379,7 +379,7 @@ impl AsFd for crate::sync::Arc { } } -#[stable(feature = "asfd_ptrs", since = "1.64.0")] +#[stable(feature = "io_safety", since = "1.63.0")] impl AsFd for Box { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 081915ed148b3..ff4e25b792ad0 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -14,7 +14,6 @@ use crate::os::wasi::io::OwnedFd; use crate::sys_common::{AsInner, IntoInner}; /// Raw file descriptors. -#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[stable(feature = "rust1", since = "1.0.0")] pub type RawFd = raw::c_int; @@ -23,7 +22,6 @@ pub type RawFd = raw::c_int; /// This is only available on unix and WASI platforms and must be imported in /// order to call the method. Windows platforms have a corresponding /// `AsRawHandle` and `AsRawSocket` set of traits. -#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawFd { /// Extracts the raw file descriptor. @@ -59,7 +57,6 @@ pub trait AsRawFd { /// A trait to express the ability to construct an object from a raw file /// descriptor. -#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[stable(feature = "from_raw_os", since = "1.1.0")] pub trait FromRawFd { /// Constructs a new instance of `Self` from the given raw file @@ -103,7 +100,6 @@ pub trait FromRawFd { /// A trait to express the ability to consume an object and acquire ownership of /// its raw file descriptor. -#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[stable(feature = "into_raw_os", since = "1.4.0")] pub trait IntoRawFd { /// Consumes this object, returning the raw underlying file descriptor. diff --git a/library/std/src/os/wasi/io/raw.rs b/library/std/src/os/wasi/io/raw.rs index da3b36adad409..0e0c5824e3404 100644 --- a/library/std/src/os/wasi/io/raw.rs +++ b/library/std/src/os/wasi/io/raw.rs @@ -2,19 +2,4 @@ #![unstable(feature = "wasi_ext", issue = "71213")] -// NOTE: despite the fact that this module is unstable, -// stable Rust had the capability to access the stable -// re-exported items from os::fd::raw through this -// unstable module. -// In PR #95956 the stability checker was changed to check -// all path segments of an item rather than just the last, -// which caused the aforementioned stable usage to regress -// (see issue #99502). -// As a result, the items in os::fd::raw were given the -// rustc_allowed_through_unstable_modules attribute. -// No regression tests were added to ensure this property, -// as CI is not configured to test wasm32-wasi. -// If this module is stabilized, -// you may want to remove those attributes -// (assuming no other unstable modules need them). pub use crate::os::fd::raw::*; diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index a091f06dd532c..f15baff59dbfb 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -7,7 +7,6 @@ use crate::fs::{self, Metadata, OpenOptions}; use crate::io; use crate::path::Path; -use crate::sealed::Sealed; use crate::sys; use crate::sys_common::{AsInner, AsInnerMut}; @@ -503,20 +502,17 @@ impl MetadataExt for Metadata { /// Windows-specific extensions to [`fs::FileType`]. /// /// On Windows, a symbolic link knows whether it is a file or directory. -#[stable(feature = "windows_file_type_ext", since = "1.64.0")] -pub trait FileTypeExt: Sealed { +#[unstable(feature = "windows_file_type_ext", issue = "none")] +pub trait FileTypeExt { /// Returns `true` if this file type is a symbolic link that is also a directory. - #[stable(feature = "windows_file_type_ext", since = "1.64.0")] + #[unstable(feature = "windows_file_type_ext", issue = "none")] fn is_symlink_dir(&self) -> bool; /// Returns `true` if this file type is a symbolic link that is also a file. - #[stable(feature = "windows_file_type_ext", since = "1.64.0")] + #[unstable(feature = "windows_file_type_ext", issue = "none")] fn is_symlink_file(&self) -> bool; } -#[stable(feature = "windows_file_type_ext", since = "1.64.0")] -impl Sealed for fs::FileType {} - -#[stable(feature = "windows_file_type_ext", since = "1.64.0")] +#[unstable(feature = "windows_file_type_ext", issue = "none")] impl FileTypeExt for fs::FileType { fn is_symlink_dir(&self) -> bool { self.as_inner().is_symlink_dir() diff --git a/library/std/src/sys/solid/abi/mod.rs b/library/std/src/sys/solid/abi/mod.rs index 8440d572cfbd3..1afc83f766df3 100644 --- a/library/std/src/sys/solid/abi/mod.rs +++ b/library/std/src/sys/solid/abi/mod.rs @@ -4,6 +4,32 @@ mod fs; pub mod sockets; pub use self::fs::*; +#[inline(always)] +pub fn breakpoint_program_exited(tid: usize) { + unsafe { + match () { + // SOLID_BP_PROGRAM_EXITED = 15 + #[cfg(target_arch = "arm")] + () => core::arch::asm!("bkpt #15", in("r0") tid), + #[cfg(target_arch = "aarch64")] + () => core::arch::asm!("hlt #15", in("x0") tid), + } + } +} + +#[inline(always)] +pub fn breakpoint_abort() { + unsafe { + match () { + // SOLID_BP_CSABORT = 16 + #[cfg(target_arch = "arm")] + () => core::arch::asm!("bkpt #16"), + #[cfg(target_arch = "aarch64")] + () => core::arch::asm!("hlt #16"), + } + } +} + // `solid_types.h` pub use super::itron::abi::{ER, ER_ID, E_TMOUT, ID}; diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs index 778a589d1b724..2d21e4764fc21 100644 --- a/library/std/src/sys/solid/mod.rs +++ b/library/std/src/sys/solid/mod.rs @@ -76,9 +76,20 @@ pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind { error::decode_error_kind(code) } -#[inline] +#[inline(always)] pub fn abort_internal() -> ! { - unsafe { libc::abort() } + loop { + abi::breakpoint_abort(); + } +} + +// This function is needed by the panic runtime. The symbol is named in +// pre-link args for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +// NB. used by both libunwind and libpanic_abort +pub extern "C" fn __rust_abort() { + abort_internal(); } pub fn hashmap_random_keys() -> (u64, u64) { diff --git a/library/std/src/sys/solid/os.rs b/library/std/src/sys/solid/os.rs index b5649d6e0ffb0..719d95bbe50a8 100644 --- a/library/std/src/sys/solid/os.rs +++ b/library/std/src/sys/solid/os.rs @@ -11,7 +11,7 @@ use crate::path::{self, PathBuf}; use crate::sys_common::rwlock::StaticRwLock; use crate::vec; -use super::{error, itron, memchr}; +use super::{abi, error, itron, memchr}; // `solid` directly maps `errno`s to μITRON error codes. impl itron::error::ItronError { @@ -184,8 +184,11 @@ pub fn home_dir() -> Option { None } -pub fn exit(code: i32) -> ! { - rtabort!("exit({}) called", code); +pub fn exit(_code: i32) -> ! { + let tid = itron::task::try_current_task_id().unwrap_or(0); + loop { + abi::breakpoint_program_exited(tid as usize); + } } pub fn getpid() -> u32 { diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 71522865b7dcf..7c8824694408c 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1126,19 +1126,6 @@ impl fmt::Debug for File { Some(PathBuf::from(OsString::from_vec(buf))) } - #[cfg(all(target_os = "freebsd", target_arch = "x86_64"))] - fn get_path(fd: c_int) -> Option { - let info = Box::::new_zeroed(); - let mut info = unsafe { info.assume_init() }; - info.kf_structsize = mem::size_of::() as libc::c_int; - let n = unsafe { libc::fcntl(fd, libc::F_KINFO, &mut *info) }; - if n == -1 { - return None; - } - let buf = unsafe { CStr::from_ptr(info.kf_path.as_mut_ptr()).to_bytes().to_vec() }; - Some(PathBuf::from(OsString::from_vec(buf))) - } - #[cfg(target_os = "vxworks")] fn get_path(fd: c_int) -> Option { let mut buf = vec![0; libc::PATH_MAX as usize]; @@ -1155,7 +1142,6 @@ impl fmt::Debug for File { target_os = "linux", target_os = "macos", target_os = "vxworks", - all(target_os = "freebsd", target_arch = "x86_64"), target_os = "netbsd" )))] fn get_path(_fd: c_int) -> Option { diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs index 8d5b540212a17..ab516a7f76dd0 100644 --- a/library/std/src/sys/unix/futex.rs +++ b/library/std/src/sys/unix/futex.rs @@ -240,25 +240,17 @@ pub fn futex_wake_all(futex: &AtomicU32) { } #[cfg(target_os = "fuchsia")] -pub mod zircon { - pub type zx_futex_t = crate::sync::atomic::AtomicU32; - pub type zx_handle_t = u32; - pub type zx_status_t = i32; - pub type zx_time_t = i64; +mod zircon { + type zx_time_t = i64; + type zx_futex_t = crate::sync::atomic::AtomicU32; + type zx_handle_t = u32; + type zx_status_t = i32; pub const ZX_HANDLE_INVALID: zx_handle_t = 0; - - pub const ZX_TIME_INFINITE: zx_time_t = zx_time_t::MAX; - - pub const ZX_OK: zx_status_t = 0; - pub const ZX_ERR_INVALID_ARGS: zx_status_t = -10; - pub const ZX_ERR_BAD_HANDLE: zx_status_t = -11; - pub const ZX_ERR_WRONG_TYPE: zx_status_t = -12; - pub const ZX_ERR_BAD_STATE: zx_status_t = -20; pub const ZX_ERR_TIMED_OUT: zx_status_t = -21; + pub const ZX_TIME_INFINITE: zx_time_t = zx_time_t::MAX; extern "C" { - pub fn zx_clock_get_monotonic() -> zx_time_t; pub fn zx_futex_wait( value_ptr: *const zx_futex_t, current_value: zx_futex_t, @@ -266,8 +258,7 @@ pub mod zircon { deadline: zx_time_t, ) -> zx_status_t; pub fn zx_futex_wake(value_ptr: *const zx_futex_t, wake_count: u32) -> zx_status_t; - pub fn zx_futex_wake_single_owner(value_ptr: *const zx_futex_t) -> zx_status_t; - pub fn zx_thread_self() -> zx_handle_t; + pub fn zx_clock_get_monotonic() -> zx_time_t; } } @@ -296,8 +287,3 @@ pub fn futex_wake(futex: &AtomicU32) -> bool { unsafe { zircon::zx_futex_wake(futex, 1) }; false } - -#[cfg(target_os = "fuchsia")] -pub fn futex_wake_all(futex: &AtomicU32) { - unsafe { zircon::zx_futex_wake(futex, u32::MAX) }; -} diff --git a/library/std/src/sys/unix/locks/fuchsia_mutex.rs b/library/std/src/sys/unix/locks/fuchsia_mutex.rs deleted file mode 100644 index ce427599c3bdd..0000000000000 --- a/library/std/src/sys/unix/locks/fuchsia_mutex.rs +++ /dev/null @@ -1,165 +0,0 @@ -//! A priority inheriting mutex for Fuchsia. -//! -//! This is a port of the [mutex in Fuchsia's libsync]. Contrary to the original, -//! it does not abort the process when reentrant locking is detected, but deadlocks. -//! -//! Priority inheritance is achieved by storing the owning thread's handle in an -//! atomic variable. Fuchsia's futex operations support setting an owner thread -//! for a futex, which can boost that thread's priority while the futex is waited -//! upon. -//! -//! libsync is licenced under the following BSD-style licence: -//! -//! Copyright 2016 The Fuchsia Authors. -//! -//! Redistribution and use in source and binary forms, with or without -//! modification, are permitted provided that the following conditions are -//! met: -//! -//! * Redistributions of source code must retain the above copyright -//! notice, this list of conditions and the following disclaimer. -//! * Redistributions in binary form must reproduce the above -//! copyright notice, this list of conditions and the following -//! disclaimer in the documentation and/or other materials provided -//! with the distribution. -//! -//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -//! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -//! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -//! A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -//! OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -//! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -//! LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -//! DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -//! THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -//! (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -//! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -//! -//! [mutex in Fuchsia's libsync]: https://cs.opensource.google/fuchsia/fuchsia/+/main:zircon/system/ulib/sync/mutex.c - -use crate::sync::atomic::{ - AtomicU32, - Ordering::{Acquire, Relaxed, Release}, -}; -use crate::sys::futex::zircon::{ - zx_futex_wait, zx_futex_wake_single_owner, zx_handle_t, zx_thread_self, ZX_ERR_BAD_HANDLE, - ZX_ERR_BAD_STATE, ZX_ERR_INVALID_ARGS, ZX_ERR_TIMED_OUT, ZX_ERR_WRONG_TYPE, ZX_OK, - ZX_TIME_INFINITE, -}; - -// The lowest two bits of a `zx_handle_t` are always set, so the lowest bit is used to mark the -// mutex as contested by clearing it. -const CONTESTED_BIT: u32 = 1; -// This can never be a valid `zx_handle_t`. -const UNLOCKED: u32 = 0; - -pub type MovableMutex = Mutex; - -pub struct Mutex { - futex: AtomicU32, -} - -#[inline] -fn to_state(owner: zx_handle_t) -> u32 { - owner -} - -#[inline] -fn to_owner(state: u32) -> zx_handle_t { - state | CONTESTED_BIT -} - -#[inline] -fn is_contested(state: u32) -> bool { - state & CONTESTED_BIT == 0 -} - -#[inline] -fn mark_contested(state: u32) -> u32 { - state & !CONTESTED_BIT -} - -impl Mutex { - #[inline] - pub const fn new() -> Mutex { - Mutex { futex: AtomicU32::new(UNLOCKED) } - } - - #[inline] - pub unsafe fn init(&mut self) {} - - #[inline] - pub unsafe fn try_lock(&self) -> bool { - let thread_self = zx_thread_self(); - self.futex.compare_exchange(UNLOCKED, to_state(thread_self), Acquire, Relaxed).is_ok() - } - - #[inline] - pub unsafe fn lock(&self) { - let thread_self = zx_thread_self(); - if let Err(state) = - self.futex.compare_exchange(UNLOCKED, to_state(thread_self), Acquire, Relaxed) - { - self.lock_contested(state, thread_self); - } - } - - #[cold] - fn lock_contested(&self, mut state: u32, thread_self: zx_handle_t) { - let owned_state = mark_contested(to_state(thread_self)); - loop { - // Mark the mutex as contested if it is not already. - let contested = mark_contested(state); - if is_contested(state) - || self.futex.compare_exchange(state, contested, Relaxed, Relaxed).is_ok() - { - // The mutex has been marked as contested, wait for the state to change. - unsafe { - match zx_futex_wait( - &self.futex, - AtomicU32::new(contested), - to_owner(state), - ZX_TIME_INFINITE, - ) { - ZX_OK | ZX_ERR_BAD_STATE | ZX_ERR_TIMED_OUT => (), - // Note that if a thread handle is reused after its associated thread - // exits without unlocking the mutex, an arbitrary thread's priority - // could be boosted by the wait, but there is currently no way to - // prevent that. - ZX_ERR_INVALID_ARGS | ZX_ERR_BAD_HANDLE | ZX_ERR_WRONG_TYPE => { - panic!( - "either the current thread is trying to lock a mutex it has - already locked, or the previous owner did not unlock the mutex - before exiting" - ) - } - error => panic!("unexpected error in zx_futex_wait: {error}"), - } - } - } - - // The state has changed or a wakeup occured, try to lock the mutex. - match self.futex.compare_exchange(UNLOCKED, owned_state, Acquire, Relaxed) { - Ok(_) => return, - Err(updated) => state = updated, - } - } - } - - #[inline] - pub unsafe fn unlock(&self) { - if is_contested(self.futex.swap(UNLOCKED, Release)) { - // The woken thread will mark the mutex as contested again, - // and return here, waking until there are no waiters left, - // in which case this is a noop. - self.wake(); - } - } - - #[cold] - fn wake(&self) { - unsafe { - zx_futex_wake_single_owner(&self.futex); - } - } -} diff --git a/library/std/src/sys/unix/locks/futex_mutex.rs b/library/std/src/sys/unix/locks/futex.rs similarity index 62% rename from library/std/src/sys/unix/locks/futex_mutex.rs rename to library/std/src/sys/unix/locks/futex.rs index 99ba86e5f996d..a9a1a32c5afb0 100644 --- a/library/std/src/sys/unix/locks/futex_mutex.rs +++ b/library/std/src/sys/unix/locks/futex.rs @@ -2,9 +2,11 @@ use crate::sync::atomic::{ AtomicU32, Ordering::{Acquire, Relaxed, Release}, }; -use crate::sys::futex::{futex_wait, futex_wake}; +use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all}; +use crate::time::Duration; pub type MovableMutex = Mutex; +pub type MovableCondvar = Condvar; pub struct Mutex { /// 0: unlocked @@ -99,3 +101,55 @@ impl Mutex { futex_wake(&self.futex); } } + +pub struct Condvar { + // The value of this atomic is simply incremented on every notification. + // This is used by `.wait()` to not miss any notifications after + // unlocking the mutex and before waiting for notifications. + futex: AtomicU32, +} + +impl Condvar { + #[inline] + pub const fn new() -> Self { + Self { futex: AtomicU32::new(0) } + } + + // All the memory orderings here are `Relaxed`, + // because synchronization is done by unlocking and locking the mutex. + + pub unsafe fn notify_one(&self) { + self.futex.fetch_add(1, Relaxed); + futex_wake(&self.futex); + } + + pub unsafe fn notify_all(&self) { + self.futex.fetch_add(1, Relaxed); + futex_wake_all(&self.futex); + } + + pub unsafe fn wait(&self, mutex: &Mutex) { + self.wait_optional_timeout(mutex, None); + } + + pub unsafe fn wait_timeout(&self, mutex: &Mutex, timeout: Duration) -> bool { + self.wait_optional_timeout(mutex, Some(timeout)) + } + + unsafe fn wait_optional_timeout(&self, mutex: &Mutex, timeout: Option) -> bool { + // Examine the notification counter _before_ we unlock the mutex. + let futex_value = self.futex.load(Relaxed); + + // Unlock the mutex before going to sleep. + mutex.unlock(); + + // Wait, but only if there hasn't been any + // notification since we unlocked the mutex. + let r = futex_wait(&self.futex, futex_value, timeout); + + // Lock the mutex again. + mutex.lock(); + + r + } +} diff --git a/library/std/src/sys/unix/locks/futex_condvar.rs b/library/std/src/sys/unix/locks/futex_condvar.rs deleted file mode 100644 index c0576c17880e1..0000000000000 --- a/library/std/src/sys/unix/locks/futex_condvar.rs +++ /dev/null @@ -1,58 +0,0 @@ -use super::Mutex; -use crate::sync::atomic::{AtomicU32, Ordering::Relaxed}; -use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all}; -use crate::time::Duration; - -pub type MovableCondvar = Condvar; - -pub struct Condvar { - // The value of this atomic is simply incremented on every notification. - // This is used by `.wait()` to not miss any notifications after - // unlocking the mutex and before waiting for notifications. - futex: AtomicU32, -} - -impl Condvar { - #[inline] - pub const fn new() -> Self { - Self { futex: AtomicU32::new(0) } - } - - // All the memory orderings here are `Relaxed`, - // because synchronization is done by unlocking and locking the mutex. - - pub unsafe fn notify_one(&self) { - self.futex.fetch_add(1, Relaxed); - futex_wake(&self.futex); - } - - pub unsafe fn notify_all(&self) { - self.futex.fetch_add(1, Relaxed); - futex_wake_all(&self.futex); - } - - pub unsafe fn wait(&self, mutex: &Mutex) { - self.wait_optional_timeout(mutex, None); - } - - pub unsafe fn wait_timeout(&self, mutex: &Mutex, timeout: Duration) -> bool { - self.wait_optional_timeout(mutex, Some(timeout)) - } - - unsafe fn wait_optional_timeout(&self, mutex: &Mutex, timeout: Option) -> bool { - // Examine the notification counter _before_ we unlock the mutex. - let futex_value = self.futex.load(Relaxed); - - // Unlock the mutex before going to sleep. - mutex.unlock(); - - // Wait, but only if there hasn't been any - // notification since we unlocked the mutex. - let r = futex_wait(&self.futex, futex_value, timeout); - - // Lock the mutex again. - mutex.lock(); - - r - } -} diff --git a/library/std/src/sys/unix/locks/mod.rs b/library/std/src/sys/unix/locks/mod.rs index f5f92f6935830..03400efa3c9aa 100644 --- a/library/std/src/sys/unix/locks/mod.rs +++ b/library/std/src/sys/unix/locks/mod.rs @@ -7,19 +7,10 @@ cfg_if::cfg_if! { target_os = "openbsd", target_os = "dragonfly", ))] { - mod futex_mutex; + mod futex; mod futex_rwlock; - mod futex_condvar; - pub(crate) use futex_mutex::{Mutex, MovableMutex}; + pub(crate) use futex::{Mutex, MovableMutex, MovableCondvar}; pub(crate) use futex_rwlock::{RwLock, MovableRwLock}; - pub(crate) use futex_condvar::MovableCondvar; - } else if #[cfg(target_os = "fuchsia")] { - mod fuchsia_mutex; - mod futex_rwlock; - mod futex_condvar; - pub(crate) use fuchsia_mutex::{Mutex, MovableMutex}; - pub(crate) use futex_rwlock::{RwLock, MovableRwLock}; - pub(crate) use futex_condvar::MovableCondvar; } else { mod pthread_mutex; mod pthread_rwlock; diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 36a3fa6023bfb..6533625876f89 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -285,7 +285,7 @@ pub fn available_parallelism() -> io::Result { ))] { #[cfg(any(target_os = "android", target_os = "linux"))] { - let quota = cgroups::quota().max(1); + let quota = cgroup2_quota().max(1); let mut set: libc::cpu_set_t = unsafe { mem::zeroed() }; unsafe { if libc::sched_getaffinity(0, mem::size_of::(), &mut set) == 0 { @@ -379,88 +379,49 @@ pub fn available_parallelism() -> io::Result { } } +/// Returns cgroup CPU quota in core-equivalents, rounded down, or usize::MAX if the quota cannot +/// be determined or is not set. #[cfg(any(target_os = "android", target_os = "linux"))] -mod cgroups { - //! Currently not covered - //! * cgroup v2 in non-standard mountpoints - //! * paths containing control characters or spaces, since those would be escaped in procfs - //! output and we don't unescape - use crate::borrow::Cow; +fn cgroup2_quota() -> usize { use crate::ffi::OsString; use crate::fs::{try_exists, File}; use crate::io::Read; - use crate::io::{BufRead, BufReader}; use crate::os::unix::ffi::OsStringExt; - use crate::path::Path; use crate::path::PathBuf; - use crate::str::from_utf8; - #[derive(PartialEq)] - enum Cgroup { - V1, - V2, - } - - /// Returns cgroup CPU quota in core-equivalents, rounded down or usize::MAX if the quota cannot - /// be determined or is not set. - pub(super) fn quota() -> usize { - let mut quota = usize::MAX; - if cfg!(miri) { - // Attempting to open a file fails under default flags due to isolation. - // And Miri does not have parallelism anyway. - return quota; - } - - let _: Option<()> = try { - let mut buf = Vec::with_capacity(128); - // find our place in the cgroup hierarchy - File::open("/proc/self/cgroup").ok()?.read_to_end(&mut buf).ok()?; - let (cgroup_path, version) = - buf.split(|&c| c == b'\n').fold(None, |previous, line| { - let mut fields = line.splitn(3, |&c| c == b':'); - // 2nd field is a list of controllers for v1 or empty for v2 - let version = match fields.nth(1) { - Some(b"") => Cgroup::V2, - Some(controllers) - if from_utf8(controllers) - .is_ok_and(|c| c.split(",").any(|c| c == "cpu")) => - { - Cgroup::V1 - } - _ => return previous, - }; - - // already-found v1 trumps v2 since it explicitly specifies its controllers - if previous.is_some() && version == Cgroup::V2 { - return previous; - } - - let path = fields.last()?; - // skip leading slash - Some((path[1..].to_owned(), version)) - })?; - let cgroup_path = PathBuf::from(OsString::from_vec(cgroup_path)); - - quota = match version { - Cgroup::V1 => quota_v1(cgroup_path), - Cgroup::V2 => quota_v2(cgroup_path), - }; - }; - - quota - } - - fn quota_v2(group_path: PathBuf) -> usize { - let mut quota = usize::MAX; + let mut quota = usize::MAX; + if cfg!(miri) { + // Attempting to open a file fails under default flags due to isolation. + // And Miri does not have parallelism anyway. + return quota; + } + + let _: Option<()> = try { + let mut buf = Vec::with_capacity(128); + // find our place in the cgroup hierarchy + File::open("/proc/self/cgroup").ok()?.read_to_end(&mut buf).ok()?; + let cgroup_path = buf + .split(|&c| c == b'\n') + .filter_map(|line| { + let mut fields = line.splitn(3, |&c| c == b':'); + // expect cgroupv2 which has an empty 2nd field + if fields.nth(1) != Some(b"") { + return None; + } + let path = fields.last()?; + // skip leading slash + Some(path[1..].to_owned()) + }) + .next()?; + let cgroup_path = PathBuf::from(OsString::from_vec(cgroup_path)); let mut path = PathBuf::with_capacity(128); let mut read_buf = String::with_capacity(20); - // standard mount location defined in file-hierarchy(7) manpage let cgroup_mount = "/sys/fs/cgroup"; path.push(cgroup_mount); - path.push(&group_path); + path.push(&cgroup_path); path.push("cgroup.controllers"); @@ -471,134 +432,30 @@ mod cgroups { path.pop(); - let _: Option<()> = try { - while path.starts_with(cgroup_mount) { - path.push("cpu.max"); - - read_buf.clear(); - - if File::open(&path).and_then(|mut f| f.read_to_string(&mut read_buf)).is_ok() { - let raw_quota = read_buf.lines().next()?; - let mut raw_quota = raw_quota.split(' '); - let limit = raw_quota.next()?; - let period = raw_quota.next()?; - match (limit.parse::(), period.parse::()) { - (Ok(limit), Ok(period)) => { - quota = quota.min(limit / period); - } - _ => {} - } - } - - path.pop(); // pop filename - path.pop(); // pop dir - } - }; - - quota - } - - fn quota_v1(group_path: PathBuf) -> usize { - let mut quota = usize::MAX; - let mut path = PathBuf::with_capacity(128); - let mut read_buf = String::with_capacity(20); + while path.starts_with(cgroup_mount) { + path.push("cpu.max"); - // Hardcode commonly used locations mentioned in the cgroups(7) manpage - // if that doesn't work scan mountinfo and adjust `group_path` for bind-mounts - let mounts: &[fn(&Path) -> Option<(_, &Path)>] = &[ - |p| Some((Cow::Borrowed("/sys/fs/cgroup/cpu"), p)), - |p| Some((Cow::Borrowed("/sys/fs/cgroup/cpu,cpuacct"), p)), - // this can be expensive on systems with tons of mountpoints - // but we only get to this point when /proc/self/cgroups explicitly indicated - // this process belongs to a cpu-controller cgroup v1 and the defaults didn't work - find_mountpoint, - ]; - - for mount in mounts { - let Some((mount, group_path)) = mount(&group_path) else { continue }; - - path.clear(); - path.push(mount.as_ref()); - path.push(&group_path); - - // skip if we guessed the mount incorrectly - if matches!(try_exists(&path), Err(_) | Ok(false)) { - continue; - } + read_buf.clear(); - while path.starts_with(mount.as_ref()) { - let mut parse_file = |name| { - path.push(name); - read_buf.clear(); - - let f = File::open(&path); - path.pop(); // restore buffer before any early returns - f.ok()?.read_to_string(&mut read_buf).ok()?; - let parsed = read_buf.trim().parse::().ok()?; - - Some(parsed) - }; - - let limit = parse_file("cpu.cfs_quota_us"); - let period = parse_file("cpu.cfs_period_us"); - - match (limit, period) { - (Some(limit), Some(period)) => quota = quota.min(limit / period), + if File::open(&path).and_then(|mut f| f.read_to_string(&mut read_buf)).is_ok() { + let raw_quota = read_buf.lines().next()?; + let mut raw_quota = raw_quota.split(' '); + let limit = raw_quota.next()?; + let period = raw_quota.next()?; + match (limit.parse::(), period.parse::()) { + (Ok(limit), Ok(period)) => { + quota = quota.min(limit / period); + } _ => {} } - - path.pop(); } - // we passed the try_exists above so we should have traversed the correct hierarchy - // when reaching this line - break; + path.pop(); // pop filename + path.pop(); // pop dir } + }; - quota - } - - /// Scan mountinfo for cgroup v1 mountpoint with a cpu controller - /// - /// If the cgroupfs is a bind mount then `group_path` is adjusted to skip - /// over the already-included prefix - fn find_mountpoint(group_path: &Path) -> Option<(Cow<'static, str>, &Path)> { - let mut reader = BufReader::new(File::open("/proc/self/mountinfo").ok()?); - let mut line = String::with_capacity(256); - loop { - line.clear(); - if reader.read_line(&mut line).ok()? == 0 { - break; - } - - let line = line.trim(); - let mut items = line.split(' '); - - let sub_path = items.nth(3)?; - let mount_point = items.next()?; - let mount_opts = items.next_back()?; - let filesystem_type = items.nth_back(1)?; - - if filesystem_type != "cgroup" || !mount_opts.split(',').any(|opt| opt == "cpu") { - // not a cgroup / not a cpu-controller - continue; - } - - let sub_path = Path::new(sub_path).strip_prefix("/").ok()?; - - if !group_path.starts_with(sub_path) { - // this is a bind-mount and the bound subdirectory - // does not contain the cgroup this process belongs to - continue; - } - - let trimmed_group_path = group_path.strip_prefix(sub_path).ok()?; - - return Some((Cow::Owned(mount_point.to_owned()), trimmed_group_path)); - } - - None - } + quota } #[cfg(all( diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 44c8a50fd860a..d28c7b58b20ba 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1577,15 +1577,10 @@ fn _assert_sync_and_send() { /// /// On Linux: /// - It may overcount the amount of parallelism available when limited by a -/// process-wide affinity mask or cgroup quotas and `sched_getaffinity()` or cgroup fs can't be +/// process-wide affinity mask or cgroup quotas and cgroup2 fs or `sched_getaffinity()` can't be /// queried, e.g. due to sandboxing. /// - It may undercount the amount of parallelism if the current thread's affinity mask /// does not reflect the process' cpuset, e.g. due to pinned threads. -/// - If the process is in a cgroup v1 cpu controller, this may need to -/// scan mountpoints to find the corresponding cgroup v1 controller, -/// which may take time on systems with large numbers of mountpoints. -/// (This does not apply to cgroup v2, or to processes not in a -/// cgroup.) /// /// On all targets: /// - It may overcount the amount of parallelism available when running in a VM diff --git a/library/test/src/console.rs b/library/test/src/console.rs index e9dda98966de3..dc0123cf43266 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -137,7 +137,7 @@ impl ConsoleTestState { // List the tests to console, and optionally to logfile. Filters are honored. pub fn list_tests_console(opts: &TestOpts, tests: Vec) -> io::Result<()> { let mut output = match term::stdout() { - None => OutputLocation::Raw(io::stdout().lock()), + None => OutputLocation::Raw(io::stdout()), Some(t) => OutputLocation::Pretty(t), }; diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 0ab4824ac0a73..575cbc3beb2e7 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -601,7 +601,6 @@ impl<'a> Builder<'a> { tool::Cargo, tool::Rls, tool::RustAnalyzer, - tool::RustAnalyzerProcMacroSrv, tool::RustDemangler, tool::Rustdoc, tool::Clippy, @@ -622,7 +621,6 @@ impl<'a> Builder<'a> { check::Clippy, check::Miri, check::Rls, - check::RustAnalyzer, check::Rustfmt, check::Bootstrap ), @@ -650,7 +648,6 @@ impl<'a> Builder<'a> { test::Cargotest, test::Cargo, test::Rls, - test::RustAnalyzer, test::ErrorIndex, test::Distcheck, test::RunMakeFullDeps, @@ -1554,7 +1551,7 @@ impl<'a> Builder<'a> { Mode::ToolStd => { // Right now this is just compiletest and a few other tools that build on stable. // Allow them to use `feature(test)`, but nothing else. - rustflags.arg("-Zallow-features=binary-dep-depinfo,test,backtrace,proc_macro_internals,proc_macro_diagnostic,proc_macro_span"); + rustflags.arg("-Zallow-features=binary-dep-depinfo,test,backtrace"); } Mode::Std | Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {} } diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 394bd8b4e2825..9196b78c513fe 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -301,68 +301,6 @@ impl Step for CodegenBackend { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct RustAnalyzer { - pub target: TargetSelection, -} - -impl Step for RustAnalyzer { - type Output = (); - const ONLY_HOSTS: bool = true; - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/tools/rust-analyzer") - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(RustAnalyzer { target: run.target }); - } - - fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(builder.top_stage, builder.config.build); - let target = self.target; - - builder.ensure(Std { target }); - - let mut cargo = prepare_tool_cargo( - builder, - compiler, - Mode::ToolStd, - target, - cargo_subcommand(builder.kind), - "src/tools/rust-analyzer", - SourceType::InTree, - &["rust-analyzer/in-rust-tree".to_owned()], - ); - - cargo.rustflag( - "-Zallow-features=proc_macro_internals,proc_macro_diagnostic,proc_macro_span", - ); - - // For ./x.py clippy, don't check those targets because - // linting tests and benchmarks can produce very noisy results - if builder.kind != Kind::Clippy { - // can't use `--all-targets` because `--examples` doesn't work well - cargo.arg("--bins"); - cargo.arg("--tests"); - cargo.arg("--benches"); - } - - builder.info(&format!( - "Checking stage{} {} artifacts ({} -> {})", - compiler.stage, "rust-analyzer", &compiler.host.triple, target.triple - )); - run_cargo(builder, cargo, args(builder), &stamp(builder, compiler, target), vec![], true); - - /// Cargo's output path in a given stage, compiled by a particular - /// compiler for the specified target. - fn stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf { - builder.cargo_out(compiler, Mode::ToolStd, target).join(".rust-analyzer-check.stamp") - } - } -} - macro_rules! tool_check_step { ($name:ident, $path:literal, $($alias:literal, )* $source_type:path $(, $default:literal )?) => { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index aa7cda46bda69..3d678b2290d1c 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -651,12 +651,6 @@ impl Step for Rustc { panic!("Cannot use and generate PGO profiles at the same time"); } - // With LLD, we can use ICF (identical code folding) to reduce the executable size - // of librustc_driver/rustc and to improve i-cache utilization. - if builder.config.use_lld { - cargo.rustflag("-Clink-args=-Wl,--icf=all"); - } - let is_collecting = if let Some(path) = &builder.config.rust_profile_generate { if compiler.stage == 1 { cargo.rustflag(&format!("-Cprofile-generate={}", path)); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index c7212ad2c2166..ea0f78e2a6be9 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -411,11 +411,7 @@ pub struct Target { impl Target { pub fn from_triple(triple: &str) -> Self { let mut target: Self = Default::default(); - if triple.contains("-none") - || triple.contains("nvptx") - || triple.contains("switch") - || triple.contains("-uefi") - { + if triple.contains("-none") || triple.contains("nvptx") || triple.contains("switch") { target.no_std = true; } target diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 6291b204e485f..cba013b5bb689 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -362,18 +362,6 @@ impl Step for Rustc { builder.install(&builder.rustdoc(compiler), &image.join("bin"), 0o755); - let ra_proc_macro_srv = builder - .ensure(tool::RustAnalyzerProcMacroSrv { - compiler: builder.compiler_for( - compiler.stage, - builder.config.build, - compiler.host, - ), - target: compiler.host, - }) - .expect("rust-analyzer-proc-macro-server always builds"); - builder.install(&ra_proc_macro_srv, &image.join("libexec"), 0o755); - let libdir_relative = builder.libdir_relative(compiler); // Copy runtime DLLs needed by the compiler @@ -1070,7 +1058,7 @@ impl Step for RustAnalyzer { } let rust_analyzer = builder - .ensure(tool::RustAnalyzer { compiler, target }) + .ensure(tool::RustAnalyzer { compiler, target, extra_features: Vec::new() }) .expect("rust-analyzer always builds"); let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index fd583da908255..4c6b5ba0afc08 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -352,64 +352,6 @@ impl Step for Rls { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct RustAnalyzer { - stage: u32, - host: TargetSelection, -} - -impl Step for RustAnalyzer { - type Output = (); - const ONLY_HOSTS: bool = true; - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/tools/rust-analyzer") - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Self { stage: run.builder.top_stage, host: run.target }); - } - - /// Runs `cargo test` for rust-analyzer - fn run(self, builder: &Builder<'_>) { - let stage = self.stage; - let host = self.host; - let compiler = builder.compiler(stage, host); - - builder.ensure(tool::RustAnalyzer { compiler, target: self.host }).expect("in-tree tool"); - - let workspace_path = "src/tools/rust-analyzer"; - // until the whole RA test suite runs on `i686`, we only run - // `proc-macro-srv` tests - let crate_path = "src/tools/rust-analyzer/crates/proc-macro-srv"; - let mut cargo = tool::prepare_tool_cargo( - builder, - compiler, - Mode::ToolStd, - host, - "test", - crate_path, - SourceType::InTree, - &["sysroot-abi".to_owned()], - ); - - let dir = builder.src.join(workspace_path); - // needed by rust-analyzer to find its own text fixtures, cf. - // https://github.com/rust-analyzer/expect-test/issues/33 - cargo.env("CARGO_WORKSPACE_DIR", &dir); - - // RA's test suite tries to write to the source directory, that can't - // work in Rust CI - cargo.env("SKIP_SLOW_TESTS", "1"); - - cargo.add_rustc_lib_path(builder, compiler); - cargo.arg("--").args(builder.config.cmd.test_args()); - - builder.run(&mut cargo.into()); - } -} - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Rustfmt { stage: u32, @@ -533,9 +475,6 @@ impl Step for Miri { let stage = self.stage; let host = self.host; let compiler = builder.compiler(stage, host); - // We need the stdlib for the *next* stage, as it was built with this compiler that also built Miri. - // Except if we are at stage 2, the bootstrap loop is complete and we can stick with our current stage. - let compiler_std = builder.compiler(if stage < 2 { stage + 1 } else { stage }, host); let miri = builder.ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() }); @@ -544,10 +483,6 @@ impl Step for Miri { target: self.host, extra_features: Vec::new(), }); - // The stdlib we need might be at a different stage. And just asking for the - // sysroot does not seem to populate it, so we do that first. - builder.ensure(compile::Std::new(compiler_std, host)); - let sysroot = builder.sysroot(compiler_std); if let (Some(miri), Some(_cargo_miri)) = (miri, cargo_miri) { let mut cargo = builder.cargo(compiler, Mode::ToolRustc, SourceType::Submodule, host, "install"); @@ -627,7 +562,6 @@ impl Step for Miri { // miri tests need to know about the stage sysroot cargo.env("MIRI_SYSROOT", miri_sysroot); - cargo.env("MIRI_HOST_SYSROOT", sysroot); cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); cargo.env("MIRI", miri); diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 839a6d27199f1..f659ccbe2507f 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use std::env; use std::fs; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::process::Command; use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; @@ -683,94 +683,6 @@ impl Step for LldWrapper { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub struct RustAnalyzer { - pub compiler: Compiler, - pub target: TargetSelection, -} - -impl Step for RustAnalyzer { - type Output = Option; - const DEFAULT: bool = true; - const ONLY_HOSTS: bool = false; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - let builder = run.builder; - run.path("src/tools/rust-analyzer").default_condition( - builder.config.extended - && builder - .config - .tools - .as_ref() - .map_or(true, |tools| tools.iter().any(|tool| tool == "rust-analyzer")), - ) - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(RustAnalyzer { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), - target: run.target, - }); - } - - fn run(self, builder: &Builder<'_>) -> Option { - builder.ensure(ToolBuild { - compiler: self.compiler, - target: self.target, - tool: "rust-analyzer", - mode: Mode::ToolStd, - path: "src/tools/rust-analyzer", - extra_features: vec!["rust-analyzer/in-rust-tree".to_owned()], - is_optional_tool: false, - source_type: SourceType::InTree, - }) - } -} - -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub struct RustAnalyzerProcMacroSrv { - pub compiler: Compiler, - pub target: TargetSelection, -} - -impl Step for RustAnalyzerProcMacroSrv { - type Output = Option; - const DEFAULT: bool = true; - const ONLY_HOSTS: bool = false; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - let builder = run.builder; - run.path("src/tools/rust-analyzer").default_condition( - builder.config.extended - && builder - .config - .tools - .as_ref() - .map_or(true, |tools| tools.iter().any(|tool| tool == "rust-analyzer")), - ) - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(RustAnalyzerProcMacroSrv { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), - target: run.target, - }); - } - - fn run(self, builder: &Builder<'_>) -> Option { - builder.ensure(ToolBuild { - compiler: self.compiler, - target: self.target, - tool: "rust-analyzer-proc-macro-srv", - mode: Mode::ToolStd, - path: "src/tools/rust-analyzer/crates/proc-macro-srv-cli", - extra_features: vec!["proc-macro-srv/sysroot-abi".to_owned()], - is_optional_tool: false, - source_type: SourceType::InTree, - }) - } -} - macro_rules! tool_extended { (($sel:ident, $builder:ident), $($name:ident, @@ -868,6 +780,7 @@ tool_extended!((self, builder), // and this is close enough for now. RustDemangler, rust_demangler, "src/tools/rust-demangler", "rust-demangler", stable=false, in_tree=true, tool_std=true, {}; Rustfmt, rustfmt, "src/tools/rustfmt", "rustfmt", stable=true, in_tree=true, {}; + RustAnalyzer, rust_analyzer, "src/tools/rust-analyzer/crates/rust-analyzer", "rust-analyzer", stable=true, submodule="rust-analyzer", {}; ); impl<'a> Builder<'a> { diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index f262bc3c7d8d2..ab6c888030e1b 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -122,8 +122,7 @@ ENV RUST_CONFIGURE_ARGS \ --set target.x86_64-unknown-linux-gnu.ranlib=/rustroot/bin/llvm-ranlib \ --set llvm.thin-lto=true \ --set llvm.ninja=false \ - --set rust.jemalloc \ - --set rust.use-lld=true + --set rust.jemalloc ENV SCRIPT ../src/ci/pgo.sh python3 ../x.py dist \ --host $HOSTS --target $HOSTS \ --include-default-paths \ diff --git a/src/ci/pgo.sh b/src/ci/pgo.sh index 4773dc09960a0..28bed1fa0353b 100755 --- a/src/ci/pgo.sh +++ b/src/ci/pgo.sh @@ -195,7 +195,3 @@ rm -r $BUILD_ARTIFACTS/llvm $BUILD_ARTIFACTS/lld $@ \ --rust-profile-use=${RUSTC_PROFILE_MERGED_FILE} \ --llvm-profile-use=${LLVM_PROFILE_MERGED_FILE} - -echo "Rustc binary size" -ls -la ./build/$PGO_HOST/stage2/bin -ls -la ./build/$PGO_HOST/stage2/lib diff --git a/src/doc/book b/src/doc/book index 36383b4da21db..cf2653a5ca553 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 36383b4da21dbd0a0781473bc8ad7ef0ed1b6751 +Subproject commit cf2653a5ca553cbbb4a17f1a7db1947820f6a775 diff --git a/src/doc/nomicon b/src/doc/nomicon index 8d1e4dccf7111..70db9e4189f64 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 8d1e4dccf71114ff56f328f671f2026d8e6b62a2 +Subproject commit 70db9e4189f64d1d8e2451b1046111fb356b6dc2 diff --git a/src/doc/reference b/src/doc/reference index a92be0fef439b..9fce337a55ee4 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit a92be0fef439b3d8e0468d82cb24812d303520a0 +Subproject commit 9fce337a55ee4a4629205f6094656195cecad231 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 3155db49b0d57..83724ca387a2a 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 3155db49b0d57cd82c65456ac210b69ecec5ccb1 +Subproject commit 83724ca387a2a1cd3e8d848f62820020760e358b diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index d5201cddace97..eb83839e903a0 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit d5201cddace979b299ec1bf9fd8997338151aa9d +Subproject commit eb83839e903a0a8f1406f7e941886273f189b26b diff --git a/src/doc/rustdoc/src/deprecated-features.md b/src/doc/rustdoc/src/deprecated-features.md index 9438948af544a..2bc6e8fc8ae4d 100644 --- a/src/doc/rustdoc/src/deprecated-features.md +++ b/src/doc/rustdoc/src/deprecated-features.md @@ -10,4 +10,4 @@ change in any release. In the past the most common use case for customizing passes was to omit the `strip-private` pass. You can do this more easily, and without risk of the pass being changed, by passing -[`--document-private-items`](command-line-arguments.md#--document-private-items-show-items-that-are-not-public). +[`--document-private-items`](./unstable-features.md#--document-private-items). diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 32b350074903e..30b3d6defb4b8 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -466,7 +466,7 @@ Note that the third item is the crate root, which in this case is undocumented. and is also accepted on stable toolchains. It can also be used with `--show-coverage`. Take a look at its -[documentation](#--show-coverage-calculate-the-percentage-of-items-with-documentation) for more +[documentation](#--show-coverage-get-statistics-about-code-documentation-coverage) for more information. ### `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index 7f7549aaf5a96..e83c4d98cc7a4 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -18,13 +18,11 @@ This feature allows for use of one of following sanitizers: * [MemorySanitizer][clang-msan] a detector of uninitialized reads. * [MemTagSanitizer][clang-memtag] fast memory error detector based on Armv8.5-A Memory Tagging Extension. -* [ShadowCallStack][clang-scs] provides backward-edge control flow protection. * [ThreadSanitizer][clang-tsan] a fast data race detector. To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`, `-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`, -`-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or `-Zsanitizer=thread`. -You might also need the `--target` and `build-std` flags. Example: +`-Zsanitizer=memtag`, or `-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags. Example: ```shell $ RUSTFLAGS=-Zsanitizer=address cargo build -Zbuild-std --target x86_64-unknown-linux-gnu ``` @@ -193,8 +191,7 @@ Shadow byte legend (one shadow byte represents 8 application bytes): The LLVM Control Flow Integrity (CFI) support in the Rust compiler initially provides forward-edge control flow protection for Rust-compiled code only by -aggregating function pointers in groups identified by their return and parameter -types. +aggregating function pointers in groups identified by their number of arguments. Forward-edge control flow protection for C or C++ and Rust -compiled code "mixed binaries" (i.e., for when C or C++ and Rust -compiled code share the same @@ -246,7 +243,7 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { fn main() { let answer = do_twice(add_one, 5); - println!("The answer is: {}", answer); + println!("The answer is: {answer}"); println!("With CFI enabled, you should not see the next answer"); let f: fn(i32) -> i32 = unsafe { @@ -256,18 +253,18 @@ fn main() { }; let next_answer = do_twice(f, 5); - println!("The next answer is: {}", next_answer); + println!("The next answer is: {next_answer}"); } ``` Fig. 1. Modified example from the [Advanced Functions and Closures][rust-book-ch19-05] chapter of the [The Rust Programming Language][rust-book] book. +[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged) + ```shell -$ cargo run --release - Compiling rust-cfi-1 v0.1.0 (/home/rcvalle/rust-cfi-1) - Finished release [optimized] target(s) in 0.76s - Running `target/release/rust-cfi-1` +$ rustc rust_cfi.rs -o rust_cfi +$ ./rust_cfi The answer is: 12 With CFI enabled, you should not see the next answer The next answer is: 14 @@ -275,11 +272,11 @@ $ ``` Fig. 2. Build and execution of the modified example with LLVM CFI disabled. +[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged) + ```shell -$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release - Compiling rust-cfi-1 v0.1.0 (/home/rcvalle/rust-cfi-1) - Finished release [optimized] target(s) in 3.39s - Running `target/release/rust-cfi-1` +$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi +$ ./rust_cfi The answer is: 12 With CFI enabled, you should not see the next answer Illegal instruction @@ -309,25 +306,25 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { fn main() { let answer = do_twice(add_one, 5); - println!("The answer is: {}", answer); + println!("The answer is: {answer}"); println!("With CFI enabled, you should not see the next answer"); let f: fn(i32) -> i32 = unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) }; let next_answer = do_twice(f, 5); - println!("The next answer is: {}", next_answer); + println!("The next answer is: {next_answer}"); } ``` Fig. 4. Another modified example from the [Advanced Functions and Closures][rust-book-ch19-05] chapter of the [The Rust Programming Language][rust-book] book. +[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged) + ```shell -$ cargo run --release - Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2) - Finished release [optimized] target(s) in 0.76s - Running `target/release/rust-cfi-2` +$ rustc rust_cfi.rs -o rust_cfi +$ ./rust_cfi The answer is: 12 With CFI enabled, you should not see the next answer The next answer is: 14 @@ -335,11 +332,11 @@ $ ``` Fig. 5. Build and execution of the modified example with LLVM CFI disabled. +[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged) + ```shell -$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release - Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2) - Finished release [optimized] target(s) in 3.38s - Running `target/release/rust-cfi-2` +$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi +$ ./rust_cfi The answer is: 12 With CFI enabled, you should not see the next answer Illegal instruction @@ -349,69 +346,14 @@ Fig. 6. Build and execution of the modified example with LLVM CFI enabled. When LLVM CFI is enabled, if there are any attempts to change/hijack control flow using an indirect branch/call to a function with different number of -parameters than arguments intended/passed in the call/branch site, the -execution is also terminated (see Fig. 6). - -```rust -use std::mem; - -fn add_one(x: i32) -> i32 { - x + 1 -} - -fn add_two(x: i64) -> i64 { - x + 2 -} - -fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { - f(arg) + f(arg) -} - -fn main() { - let answer = do_twice(add_one, 5); - - println!("The answer is: {}", answer); - - println!("With CFI enabled, you should not see the next answer"); - let f: fn(i32) -> i32 = - unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) }; - let next_answer = do_twice(f, 5); +arguments than intended/passed in the call/branch site, the execution is also +terminated (see Fig. 6). - println!("The next answer is: {}", next_answer); -} -``` -Fig. 7. Another modified example from the [Advanced Functions and -Closures][rust-book-ch19-05] chapter of the [The Rust Programming -Language][rust-book] book. - -```shell - cargo run --release - Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3) - Finished release [optimized] target(s) in 0.74s - Running `target/release/rust-cfi-3` -The answer is: 12 -With CFI enabled, you should not see the next answer -The next answer is: 14 -$ -``` -Fig. 8. Build and execution of the modified example with LLVM CFI disabled. - -```shell -$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release - Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3) - Finished release [optimized] target(s) in 3.40s - Running `target/release/rust-cfi-3` -The answer is: 12 -With CFI enabled, you should not see the next answer -Illegal instruction -$ -``` -Fig. 9. Build and execution of the modified example with LLVM CFI enabled. - -When LLVM CFI is enabled, if there are any attempts to change/hijack control -flow using an indirect branch/call to a function with different return and -parameter types than the return type expected and arguments intended/passed in -the call/branch site, the execution is also terminated (see Fig. 9). +Forward-edge control flow protection not only by aggregating function pointers +in groups identified by their number of arguments, but also their argument +types, will also be provided in later work by defining and using compatible type +identifiers (see Type metadata in the design document in the tracking +issue [#89653](https://github.com/rust-lang/rust/issues/89653)). [rust-book-ch19-05]: https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html [rust-book]: https://doc.rust-lang.org/book/title-page.html @@ -571,18 +513,6 @@ To enable this target feature compile with `-C target-feature="+mte"`. More information can be found in the associated [LLVM documentation](https://llvm.org/docs/MemTagSanitizer.html). -# ShadowCallStack - -ShadowCallStack provides backward edge control flow protection by storing a function's return address in a separately allocated 'shadow call stack' and loading the return address from that shadow call stack. - -ShadowCallStack requires a platform ABI which reserves `x18` as the instrumentation makes use of this register. - -ShadowCallStack can be enabled with `-Zsanitizer=shadow-call-stack` option and is supported on the following targets: - -* `aarch64-linux-android` - -A runtime must be provided by the application or operating system. See the [LLVM documentation][clang-scs] for further details. - # ThreadSanitizer ThreadSanitizer is a data race detection tool. It is supported on the following @@ -680,5 +610,4 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT [clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html -[clang-scs]: https://clang.llvm.org/docs/ShadowCallStack.html [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index ddaa7438e1778..0bd72625f1509 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" arrayvec = { version = "0.7", default-features = false } askama = { version = "0.11", default-features = false, features = ["config"] } atty = "0.2" -pulldown-cmark = { version = "0.9.2", default-features = false } +pulldown-cmark = { version = "0.9", default-features = false } minifier = "0.2.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index c43fd1ad24173..e6f006135e29a 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -121,7 +121,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { unsafety: hir::Unsafety::Normal, generics: new_generics, trait_: Some(trait_ref.clean(self.cx)), - for_: clean_middle_ty(ty, self.cx, None), + for_: ty.clean(self.cx), items: Vec::new(), polarity, kind: ImplKind::Auto, diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index c64c5895079be..12137667e7bf8 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -116,14 +116,14 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { // FIXME(eddyb) compute both `trait_` and `for_` from // the post-inference `trait_ref`, as it's more accurate. trait_: Some(trait_ref.0.clean(cx)), - for_: clean_middle_ty(ty.0, cx, None), + for_: ty.0.clean(cx), items: cx.tcx .associated_items(impl_def_id) .in_definition_order() .map(|x| x.clean(cx)) .collect::>(), polarity: ty::ImplPolarity::Positive, - kind: ImplKind::Blanket(Box::new(clean_middle_ty(trait_ref.0.self_ty(), cx, None))), + kind: ImplKind::Blanket(Box::new(trait_ref.0.self_ty().clean(cx))), })), cfg: None, }); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 4b91f7ba096cb..ce10ca9aa3df4 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -16,8 +16,8 @@ use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; use crate::clean::{ - self, clean_fn_decl_from_did_and_sig, clean_middle_field, clean_middle_ty, clean_ty, - clean_ty_generics, utils, Attributes, AttributesExt, Clean, ImplKind, ItemId, Type, Visibility, + self, clean_fn_decl_from_did_and_sig, clean_ty_generics, utils, Attributes, AttributesExt, + Clean, ImplKind, ItemId, Type, Visibility, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -214,7 +214,14 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates); let generics = filter_non_trait_generics(did, generics); let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); - clean::Trait { def_id: did, generics, items: trait_items, bounds: supertrait_bounds } + let is_auto = cx.tcx.trait_is_auto(did); + clean::Trait { + unsafety: cx.tcx.trait_def(did).unsafety, + generics, + items: trait_items, + bounds: supertrait_bounds, + is_auto, + } } fn build_external_function<'tcx>(cx: &mut DocContext<'tcx>, did: DefId) -> clean::Function { @@ -246,7 +253,7 @@ fn build_struct(cx: &mut DocContext<'_>, did: DefId) -> clean::Struct { clean::Struct { struct_type: variant.ctor_kind, generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates), - fields: variant.fields.iter().map(|x| clean_middle_field(x, cx)).collect(), + fields: variant.fields.iter().map(|x| x.clean(cx)).collect(), } } @@ -255,13 +262,13 @@ fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union { let variant = cx.tcx.adt_def(did).non_enum_variant(); let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates); - let fields = variant.fields.iter().map(|x| clean_middle_field(x, cx)).collect(); + let fields = variant.fields.iter().map(|x| x.clean(cx)).collect(); clean::Union { generics, fields } } fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::Typedef { let predicates = cx.tcx.explicit_predicates_of(did); - let type_ = clean_middle_ty(cx.tcx.type_of(did), cx, Some(did)); + let type_ = cx.tcx.type_of(did).clean(cx); clean::Typedef { type_, @@ -357,8 +364,8 @@ pub(crate) fn build_impl( }; let for_ = match &impl_item { - Some(impl_) => clean_ty(impl_.self_ty, cx), - None => clean_middle_ty(tcx.type_of(did), cx, Some(did)), + Some(impl_) => impl_.self_ty.clean(cx), + None => tcx.type_of(did).clean(cx), }; // Only inline impl if the implementing type is @@ -577,14 +584,14 @@ pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String { fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant { clean::Constant { - type_: clean_middle_ty(cx.tcx.type_of(def_id), cx, Some(def_id)), + type_: cx.tcx.type_of(def_id).clean(cx), kind: clean::ConstantKind::Extern { def_id }, } } fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::Static { clean::Static { - type_: clean_middle_ty(cx.tcx.type_of(did), cx, Some(did)), + type_: cx.tcx.type_of(did).clean(cx), mutability: if mutable { Mutability::Mut } else { Mutability::Not }, expr: None, } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2f2fbc9d4ba8d..9865601da5fc7 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -237,22 +237,15 @@ impl<'tcx> Clean<'tcx, Lifetime> for hir::Lifetime { } } -pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg, cx: &mut DocContext<'tcx>) -> Constant { - let def_id = cx.tcx.hir().body_owner_def_id(constant.value.body).to_def_id(); - Constant { - type_: clean_middle_ty(cx.tcx.type_of(def_id), cx, Some(def_id)), - kind: ConstantKind::Anonymous { body: constant.value.body }, - } -} - -pub(crate) fn clean_middle_const<'tcx>( - constant: ty::Const<'tcx>, - cx: &mut DocContext<'tcx>, -) -> Constant { - // FIXME: instead of storing the stringified expression, store `self` directly instead. - Constant { - type_: clean_middle_ty(constant.ty(), cx, None), - kind: ConstantKind::TyConst { expr: constant.to_string() }, +impl<'tcx> Clean<'tcx, Constant> for hir::ConstArg { + fn clean(&self, cx: &mut DocContext<'tcx>) -> Constant { + Constant { + type_: cx + .tcx + .type_of(cx.tcx.hir().body_owner_def_id(self.value.body).to_def_id()) + .clean(cx), + kind: ConstantKind::Anonymous { body: self.value.body }, + } } } @@ -304,7 +297,7 @@ impl<'tcx> Clean<'tcx, Option> for hir::WherePredicate<'tcx> { }) .collect(); WherePredicate::BoundPredicate { - ty: clean_ty(wbp.bounded_ty, cx), + ty: wbp.bounded_ty.clean(cx), bounds: wbp.bounds.iter().filter_map(|x| x.clean(cx)).collect(), bound_params, } @@ -316,8 +309,8 @@ impl<'tcx> Clean<'tcx, Option> for hir::WherePredicate<'tcx> { }, hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate { - lhs: clean_ty(wrp.lhs_ty, cx), - rhs: clean_ty(wrp.rhs_ty, cx).into(), + lhs: wrp.lhs_ty.clean(cx), + rhs: wrp.rhs_ty.clean(cx).into(), }, }) } @@ -327,12 +320,10 @@ impl<'tcx> Clean<'tcx, Option> for ty::Predicate<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> Option { let bound_predicate = self.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Trait(pred) => { - clean_poly_trait_predicate(bound_predicate.rebind(pred), cx) - } - ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred, cx), - ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx), - ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)), + ty::PredicateKind::Trait(pred) => bound_predicate.rebind(pred).clean(cx), + ty::PredicateKind::RegionOutlives(pred) => pred.clean(cx), + ty::PredicateKind::TypeOutlives(pred) => pred.clean(cx), + ty::PredicateKind::Projection(pred) => Some(pred.clean(cx)), ty::PredicateKind::ConstEvaluatable(..) => None, ty::PredicateKind::WellFormed(..) => None, @@ -346,83 +337,84 @@ impl<'tcx> Clean<'tcx, Option> for ty::Predicate<'tcx> { } } -fn clean_poly_trait_predicate<'tcx>( - pred: ty::PolyTraitPredicate<'tcx>, - cx: &mut DocContext<'tcx>, -) -> Option { - // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op. - if pred.skip_binder().constness == ty::BoundConstness::ConstIfConst - && Some(pred.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait() - { - return None; - } +impl<'tcx> Clean<'tcx, Option> for ty::PolyTraitPredicate<'tcx> { + fn clean(&self, cx: &mut DocContext<'tcx>) -> Option { + // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op. + if self.skip_binder().constness == ty::BoundConstness::ConstIfConst + && Some(self.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait() + { + return None; + } - let poly_trait_ref = pred.map_bound(|pred| pred.trait_ref); - Some(WherePredicate::BoundPredicate { - ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None), - bounds: vec![poly_trait_ref.clean(cx)], - bound_params: Vec::new(), - }) + let poly_trait_ref = self.map_bound(|pred| pred.trait_ref); + Some(WherePredicate::BoundPredicate { + ty: poly_trait_ref.skip_binder().self_ty().clean(cx), + bounds: vec![poly_trait_ref.clean(cx)], + bound_params: Vec::new(), + }) + } } -fn clean_region_outlives_predicate<'tcx>( - pred: ty::OutlivesPredicate, ty::Region<'tcx>>, - cx: &mut DocContext<'tcx>, -) -> Option { - let ty::OutlivesPredicate(a, b) = pred; +impl<'tcx> Clean<'tcx, Option> + for ty::OutlivesPredicate, ty::Region<'tcx>> +{ + fn clean(&self, cx: &mut DocContext<'tcx>) -> Option { + let ty::OutlivesPredicate(a, b) = self; - if a.is_empty() && b.is_empty() { - return None; - } + if a.is_empty() && b.is_empty() { + return None; + } - Some(WherePredicate::RegionPredicate { - lifetime: a.clean(cx).expect("failed to clean lifetime"), - bounds: vec![GenericBound::Outlives(b.clean(cx).expect("failed to clean bounds"))], - }) + Some(WherePredicate::RegionPredicate { + lifetime: a.clean(cx).expect("failed to clean lifetime"), + bounds: vec![GenericBound::Outlives(b.clean(cx).expect("failed to clean bounds"))], + }) + } } -fn clean_type_outlives_predicate<'tcx>( - pred: ty::OutlivesPredicate, ty::Region<'tcx>>, - cx: &mut DocContext<'tcx>, -) -> Option { - let ty::OutlivesPredicate(ty, lt) = pred; +impl<'tcx> Clean<'tcx, Option> + for ty::OutlivesPredicate, ty::Region<'tcx>> +{ + fn clean(&self, cx: &mut DocContext<'tcx>) -> Option { + let ty::OutlivesPredicate(ty, lt) = self; - if lt.is_empty() { - return None; - } + if lt.is_empty() { + return None; + } - Some(WherePredicate::BoundPredicate { - ty: clean_middle_ty(ty, cx, None), - bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))], - bound_params: Vec::new(), - }) + Some(WherePredicate::BoundPredicate { + ty: ty.clean(cx), + bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))], + bound_params: Vec::new(), + }) + } } -fn clean_middle_term<'tcx>(term: ty::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term { - match term { - ty::Term::Ty(ty) => Term::Type(clean_middle_ty(ty, cx, None)), - ty::Term::Const(c) => Term::Constant(clean_middle_const(c, cx)), +impl<'tcx> Clean<'tcx, Term> for ty::Term<'tcx> { + fn clean(&self, cx: &mut DocContext<'tcx>) -> Term { + match self { + ty::Term::Ty(ty) => Term::Type(ty.clean(cx)), + ty::Term::Const(c) => Term::Constant(c.clean(cx)), + } } } -fn clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term { - match term { - hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)), - hir::Term::Const(c) => { - let def_id = cx.tcx.hir().local_def_id(c.hir_id); - Term::Constant(clean_middle_const(ty::Const::from_anon_const(cx.tcx, def_id), cx)) +impl<'tcx> Clean<'tcx, Term> for hir::Term<'tcx> { + fn clean(&self, cx: &mut DocContext<'tcx>) -> Term { + match self { + hir::Term::Ty(ty) => Term::Type(ty.clean(cx)), + hir::Term::Const(c) => { + let def_id = cx.tcx.hir().local_def_id(c.hir_id); + Term::Constant(ty::Const::from_anon_const(cx.tcx, def_id).clean(cx)) + } } } } -fn clean_projection_predicate<'tcx>( - pred: ty::ProjectionPredicate<'tcx>, - cx: &mut DocContext<'tcx>, -) -> WherePredicate { - let ty::ProjectionPredicate { projection_ty, term } = pred; - WherePredicate::EqPredicate { - lhs: clean_projection(projection_ty, cx, None), - rhs: clean_middle_term(term, cx), +impl<'tcx> Clean<'tcx, WherePredicate> for ty::ProjectionPredicate<'tcx> { + fn clean(&self, cx: &mut DocContext<'tcx>) -> WherePredicate { + let ty::ProjectionPredicate { projection_ty, term } = self; + WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: term.clean(cx) } } } @@ -433,7 +425,7 @@ fn clean_projection<'tcx>( ) -> Type { let lifted = ty.lift_to_tcx(cx.tcx).unwrap(); let trait_ = lifted.trait_ref(cx.tcx).clean(cx); - let self_type = clean_middle_ty(ty.self_ty(), cx, None); + let self_type = ty.self_ty().clean(cx); let self_def_id = if let Some(def_id) = def_id { cx.tcx.opt_parent(def_id).or(Some(def_id)) } else { @@ -448,6 +440,12 @@ fn clean_projection<'tcx>( } } +impl<'tcx> Clean<'tcx, Type> for ty::ProjectionTy<'tcx> { + fn clean(&self, cx: &mut DocContext<'tcx>) -> Type { + clean_projection(*self, cx, None) + } +} + fn compute_should_show_cast(self_def_id: Option, trait_: &Path, self_type: &Type) -> bool { !trait_.segments.is_empty() && self_def_id @@ -470,44 +468,43 @@ fn projection_to_path_segment<'tcx>( } } -fn clean_generic_param_def<'tcx>( - def: &ty::GenericParamDef, - cx: &mut DocContext<'tcx>, -) -> GenericParamDef { - let (name, kind) = match def.kind { - ty::GenericParamDefKind::Lifetime => { - (def.name, GenericParamDefKind::Lifetime { outlives: vec![] }) - } - ty::GenericParamDefKind::Type { has_default, synthetic, .. } => { - let default = if has_default { - Some(clean_middle_ty(cx.tcx.type_of(def.def_id), cx, Some(def.def_id))) - } else { - None - }; - ( - def.name, - GenericParamDefKind::Type { - did: def.def_id, - bounds: vec![], // These are filled in from the where-clauses. - default: default.map(Box::new), - synthetic, - }, - ) - } - ty::GenericParamDefKind::Const { has_default } => ( - def.name, - GenericParamDefKind::Const { - did: def.def_id, - ty: Box::new(clean_middle_ty(cx.tcx.type_of(def.def_id), cx, Some(def.def_id))), - default: match has_default { - true => Some(Box::new(cx.tcx.const_param_default(def.def_id).to_string())), - false => None, +impl<'tcx> Clean<'tcx, GenericParamDef> for ty::GenericParamDef { + fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericParamDef { + let (name, kind) = match self.kind { + ty::GenericParamDefKind::Lifetime => { + (self.name, GenericParamDefKind::Lifetime { outlives: vec![] }) + } + ty::GenericParamDefKind::Type { has_default, synthetic, .. } => { + let default = if has_default { + Some(clean_ty(cx.tcx.type_of(self.def_id), cx, Some(self.def_id))) + } else { + None + }; + ( + self.name, + GenericParamDefKind::Type { + did: self.def_id, + bounds: vec![], // These are filled in from the where-clauses. + default: default.map(Box::new), + synthetic, + }, + ) + } + ty::GenericParamDefKind::Const { has_default } => ( + self.name, + GenericParamDefKind::Const { + did: self.def_id, + ty: Box::new(cx.tcx.type_of(self.def_id).clean(cx)), + default: match has_default { + true => Some(Box::new(cx.tcx.const_param_default(self.def_id).to_string())), + false => None, + }, }, - }, - ), - }; + ), + }; - GenericParamDef { name, kind } + GenericParamDef { name, kind } + } } fn clean_generic_param<'tcx>( @@ -549,7 +546,7 @@ fn clean_generic_param<'tcx>( GenericParamDefKind::Type { did: did.to_def_id(), bounds, - default: default.map(|t| clean_ty(t, cx)).map(Box::new), + default: default.map(|t| t.clean(cx)).map(Box::new), synthetic, }, ) @@ -558,7 +555,7 @@ fn clean_generic_param<'tcx>( param.name.ident().name, GenericParamDefKind::Const { did: did.to_def_id(), - ty: Box::new(clean_ty(ty, cx)), + ty: Box::new(ty.clean(cx)), default: default.map(|ct| { let def_id = cx.tcx.hir().local_def_id(ct.hir_id); Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string()) @@ -665,7 +662,7 @@ fn clean_ty_generics<'tcx>( .iter() .filter_map(|param| match param.kind { ty::GenericParamDefKind::Lifetime if param.name == kw::UnderscoreLifetime => None, - ty::GenericParamDefKind::Lifetime => Some(clean_generic_param_def(param, cx)), + ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)), ty::GenericParamDefKind::Type { synthetic, .. } => { if param.name == kw::SelfUpper { assert_eq!(param.index, 0); @@ -675,9 +672,9 @@ fn clean_ty_generics<'tcx>( impl_trait.insert(param.index.into(), vec![]); return None; } - Some(clean_generic_param_def(param, cx)) + Some(param.clean(cx)) } - ty::GenericParamDefKind::Const { .. } => Some(clean_generic_param_def(param, cx)), + ty::GenericParamDefKind::Const { .. } => Some(param.clean(cx)), }) .collect::>(); @@ -726,12 +723,8 @@ fn clean_ty_generics<'tcx>( .filter(|b| !b.is_sized_bound(cx)), ); - let proj = projection.map(|p| { - ( - clean_projection(p.skip_binder().projection_ty, cx, None), - p.skip_binder().term, - ) - }); + let proj = projection + .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().term)); if let Some(((_, trait_did, name), rhs)) = proj .as_ref() .and_then(|(lhs, rhs): &(Type, _)| Some((lhs.projection()?, rhs))) @@ -759,7 +752,7 @@ fn clean_ty_generics<'tcx>( if let crate::core::ImplTraitParam::ParamIndex(idx) = param { if let Some(proj) = impl_trait_proj.remove(&idx) { for (trait_did, name, rhs) in proj { - let rhs = clean_middle_ty(rhs, cx, None); + let rhs = rhs.clean(cx); simplify::merge_bounds(cx, &mut bounds, trait_did, name, &Term::Type(rhs)); } } @@ -933,7 +926,7 @@ fn clean_args_from_types_and_names<'tcx>( if name.is_empty() { name = kw::Underscore; } - Argument { name, type_: clean_ty(ty, cx), is_const: false } + Argument { name, type_: ty.clean(cx), is_const: false } }) .collect(), } @@ -952,7 +945,7 @@ fn clean_args_from_types_and_body_id<'tcx>( .enumerate() .map(|(i, ty)| Argument { name: name_from_pat(body.params[i].pat), - type_: clean_ty(ty, cx), + type_: ty.clean(cx), is_const: false, }) .collect(), @@ -976,7 +969,7 @@ fn clean_fn_decl_from_did_and_sig<'tcx>( // We assume all empty tuples are default return type. This theoretically can discard `-> ()`, // but shouldn't change any code meaning. - let output = match clean_middle_ty(sig.skip_binder().output(), cx, None) { + let output = match sig.skip_binder().output().clean(cx) { Type::Tuple(inner) if inner.is_empty() => DefaultReturn, ty => Return(ty), }; @@ -990,7 +983,7 @@ fn clean_fn_decl_from_did_and_sig<'tcx>( .inputs() .iter() .map(|t| Argument { - type_: clean_middle_ty(*t, cx, None), + type_: t.clean(cx), name: names.next().map_or(kw::Empty, |i| i.name), is_const: false, }) @@ -1002,7 +995,7 @@ fn clean_fn_decl_from_did_and_sig<'tcx>( impl<'tcx> Clean<'tcx, FnRetTy> for hir::FnRetTy<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> FnRetTy { match *self { - Self::Return(typ) => Return(clean_ty(typ, cx)), + Self::Return(typ) => Return(typ.clean(cx)), Self::DefaultReturn(..) => DefaultReturn, } } @@ -1045,10 +1038,10 @@ impl<'tcx> Clean<'tcx, Item> for hir::TraitItem<'tcx> { cx.with_param_env(local_did, |cx| { let inner = match self.kind { hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem( - clean_ty(ty, cx), + ty.clean(cx), ConstantKind::Local { def_id: local_did, body: default }, ), - hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)), + hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(ty.clean(cx)), hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { let m = clean_function(cx, sig, self.generics, body); MethodItem(m, None) @@ -1066,13 +1059,9 @@ impl<'tcx> Clean<'tcx, Item> for hir::TraitItem<'tcx> { hir::TraitItemKind::Type(bounds, Some(default)) => { let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx)); let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect(); - let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None); + let item_type = hir_ty_to_ty(cx.tcx, default).clean(cx); AssocTypeItem( - Typedef { - type_: clean_ty(default, cx), - generics, - item_type: Some(item_type), - }, + Typedef { type_: default.clean(cx), generics, item_type: Some(item_type) }, bounds, ) } @@ -1097,7 +1086,7 @@ impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> { let inner = match self.kind { hir::ImplItemKind::Const(ty, expr) => { let default = ConstantKind::Local { def_id: local_did, body: expr }; - AssocConstItem(clean_ty(ty, cx), default) + AssocConstItem(ty.clean(cx), default) } hir::ImplItemKind::Fn(ref sig, body) => { let m = clean_function(cx, sig, self.generics, body); @@ -1105,9 +1094,9 @@ impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> { MethodItem(m, Some(defaultness)) } hir::ImplItemKind::TyAlias(hir_ty) => { - let type_ = clean_ty(hir_ty, cx); + let type_ = hir_ty.clean(cx); let generics = self.generics.clean(cx); - let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None); + let item_type = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx); AssocTypeItem( Typedef { type_, generics, item_type: Some(item_type) }, Vec::new(), @@ -1136,7 +1125,7 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem { let tcx = cx.tcx; let kind = match self.kind { ty::AssocKind::Const => { - let ty = clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id)); + let ty = tcx.type_of(self.def_id).clean(cx); let provided = match self.container { ty::ImplContainer(_) => true, @@ -1283,11 +1272,7 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem { if self.defaultness.has_value() { AssocTypeItem( Typedef { - type_: clean_middle_ty( - tcx.type_of(self.def_id), - cx, - Some(self.def_id), - ), + type_: tcx.type_of(self.def_id).clean(cx), generics, // FIXME: should we obtain the Type from HIR and pass it on here? item_type: None, @@ -1301,7 +1286,7 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem { // FIXME: when could this happen? Associated items in inherent impls? AssocTypeItem( Typedef { - type_: clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id)), + type_: tcx.type_of(self.def_id).clean(cx), generics: Generics { params: Vec::new(), where_predicates: Vec::new() }, item_type: None, }, @@ -1352,7 +1337,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type // Try to normalize `::T` to a type let ty = hir_ty_to_ty(cx.tcx, hir_ty); if let Some(normalized_value) = normalize(cx, ty) { - return clean_middle_ty(normalized_value, cx, None); + return normalized_value.clean(cx); } let trait_segments = &p.segments[..p.segments.len() - 1]; @@ -1363,7 +1348,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type }; register_res(cx, trait_.res); let self_def_id = DefId::local(qself.hir_id.owner.local_def_index); - let self_type = clean_ty(qself, cx); + let self_type = qself.clean(cx); let should_show_cast = compute_should_show_cast(Some(self_def_id), &trait_, &self_type); Type::QPath { assoc: Box::new(p.segments.last().expect("segments were empty").clean(cx)), @@ -1383,7 +1368,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type let trait_ = hir::Path { span, res, segments: &[] }.clean(cx); register_res(cx, trait_.res); let self_def_id = res.opt_def_id(); - let self_type = clean_ty(qself, cx); + let self_type = qself.clean(cx); let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type); Type::QPath { assoc: Box::new(segment.clean(cx)), @@ -1450,12 +1435,9 @@ fn maybe_expand_private_type_alias<'tcx>( _ => None, }); if let Some(ty) = type_ { - substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(clean_ty(ty, cx))); + substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(ty.clean(cx))); } else if let Some(default) = *default { - substs.insert( - ty_param_def_id.to_def_id(), - SubstParam::Type(clean_ty(default, cx)), - ); + substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(default.clean(cx))); } indices.types += 1; } @@ -1473,10 +1455,8 @@ fn maybe_expand_private_type_alias<'tcx>( _ => None, }); if let Some(ct) = const_ { - substs.insert( - const_param_def_id.to_def_id(), - SubstParam::Constant(clean_const(ct, cx)), - ); + substs + .insert(const_param_def_id.to_def_id(), SubstParam::Constant(ct.clean(cx))); } // FIXME(const_generics_defaults) indices.consts += 1; @@ -1484,68 +1464,70 @@ fn maybe_expand_private_type_alias<'tcx>( } } - Some(cx.enter_alias(substs, |cx| clean_ty(ty, cx))) -} - -pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type { - use rustc_hir::*; + Some(cx.enter_alias(substs, |cx| ty.clean(cx))) +} + +impl<'tcx> Clean<'tcx, Type> for hir::Ty<'tcx> { + fn clean(&self, cx: &mut DocContext<'tcx>) -> Type { + use rustc_hir::*; + + match self.kind { + TyKind::Never => Primitive(PrimitiveType::Never), + TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(m.ty.clean(cx))), + TyKind::Rptr(ref l, ref m) => { + // There are two times a `Fresh` lifetime can be created: + // 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`. + // 2. For `&x` as a parameter to an `async fn`. This corresponds to `elided_ref_lifetime in `rustc_ast_lowering`. + // See #59286 for more information. + // Ideally we would only hide the `'_` for case 2., but I don't know a way to distinguish it. + // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though; + // there's no case where it could cause the function to fail to compile. + let elided = + l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh)); + let lifetime = if elided { None } else { Some(l.clean(cx)) }; + BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(m.ty.clean(cx)) } + } + TyKind::Slice(ty) => Slice(Box::new(ty.clean(cx))), + TyKind::Array(ty, ref length) => { + let length = match length { + hir::ArrayLen::Infer(_, _) => "_".to_string(), + hir::ArrayLen::Body(anon_const) => { + let def_id = cx.tcx.hir().local_def_id(anon_const.hir_id); + // NOTE(min_const_generics): We can't use `const_eval_poly` for constants + // as we currently do not supply the parent generics to anonymous constants + // but do allow `ConstKind::Param`. + // + // `const_eval_poly` tries to to first substitute generic parameters which + // results in an ICE while manually constructing the constant and using `eval` + // does nothing for `ConstKind::Param`. + let ct = ty::Const::from_anon_const(cx.tcx, def_id); + let param_env = cx.tcx.param_env(def_id); + print_const(cx, ct.eval(cx.tcx, param_env)) + } + }; - match ty.kind { - TyKind::Never => Primitive(PrimitiveType::Never), - TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(clean_ty(m.ty, cx))), - TyKind::Rptr(ref l, ref m) => { - // There are two times a `Fresh` lifetime can be created: - // 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`. - // 2. For `&x` as a parameter to an `async fn`. This corresponds to `elided_ref_lifetime in `rustc_ast_lowering`. - // See #59286 for more information. - // Ideally we would only hide the `'_` for case 2., but I don't know a way to distinguish it. - // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though; - // there's no case where it could cause the function to fail to compile. - let elided = - l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh)); - let lifetime = if elided { None } else { Some(l.clean(cx)) }; - BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) } - } - TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))), - TyKind::Array(ty, ref length) => { - let length = match length { - hir::ArrayLen::Infer(_, _) => "_".to_string(), - hir::ArrayLen::Body(anon_const) => { - let def_id = cx.tcx.hir().local_def_id(anon_const.hir_id); - // NOTE(min_const_generics): We can't use `const_eval_poly` for constants - // as we currently do not supply the parent generics to anonymous constants - // but do allow `ConstKind::Param`. - // - // `const_eval_poly` tries to to first substitute generic parameters which - // results in an ICE while manually constructing the constant and using `eval` - // does nothing for `ConstKind::Param`. - let ct = ty::Const::from_anon_const(cx.tcx, def_id); - let param_env = cx.tcx.param_env(def_id); - print_const(cx, ct.eval(cx.tcx, param_env)) + Array(Box::new(ty.clean(cx)), length) + } + TyKind::Tup(tys) => Tuple(tys.iter().map(|x| x.clean(cx)).collect()), + TyKind::OpaqueDef(item_id, _) => { + let item = cx.tcx.hir().item(item_id); + if let hir::ItemKind::OpaqueTy(ref ty) = item.kind { + ImplTrait(ty.bounds.iter().filter_map(|x| x.clean(cx)).collect()) + } else { + unreachable!() } - }; - - Array(Box::new(clean_ty(ty, cx)), length) - } - TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()), - TyKind::OpaqueDef(item_id, _) => { - let item = cx.tcx.hir().item(item_id); - if let hir::ItemKind::OpaqueTy(ref ty) = item.kind { - ImplTrait(ty.bounds.iter().filter_map(|x| x.clean(cx)).collect()) - } else { - unreachable!() } + TyKind::Path(_) => clean_qpath(self, cx), + TyKind::TraitObject(bounds, ref lifetime, _) => { + let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect(); + let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None }; + DynTrait(bounds, lifetime) + } + TyKind::BareFn(barefn) => BareFunction(Box::new(barefn.clean(cx))), + // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. + TyKind::Infer | TyKind::Err => Infer, + TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind), } - TyKind::Path(_) => clean_qpath(ty, cx), - TyKind::TraitObject(bounds, ref lifetime, _) => { - let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect(); - let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None }; - DynTrait(bounds, lifetime) - } - TyKind::BareFn(barefn) => BareFunction(Box::new(barefn.clean(cx))), - // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. - TyKind::Infer | TyKind::Err => Infer, - TyKind::Typeof(..) => panic!("unimplemented type {:?}", ty.kind), } } @@ -1580,11 +1562,7 @@ fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option> { } } -pub(crate) fn clean_middle_ty<'tcx>( - this: Ty<'tcx>, - cx: &mut DocContext<'tcx>, - def_id: Option, -) -> Type { +fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option) -> Type { trace!("cleaning type: {:?}", this); let ty = normalize(cx, this).unwrap_or(this); match *ty.kind() { @@ -1595,19 +1573,17 @@ pub(crate) fn clean_middle_ty<'tcx>( ty::Uint(uint_ty) => Primitive(uint_ty.into()), ty::Float(float_ty) => Primitive(float_ty.into()), ty::Str => Primitive(PrimitiveType::Str), - ty::Slice(ty) => Slice(Box::new(clean_middle_ty(ty, cx, None))), + ty::Slice(ty) => Slice(Box::new(ty.clean(cx))), ty::Array(ty, n) => { let mut n = cx.tcx.lift(n).expect("array lift failed"); n = n.eval(cx.tcx, ty::ParamEnv::reveal_all()); let n = print_const(cx, n); - Array(Box::new(clean_middle_ty(ty, cx, None)), n) + Array(Box::new(ty.clean(cx)), n) + } + ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(mt.ty.clean(cx))), + ty::Ref(r, ty, mutbl) => { + BorrowedRef { lifetime: r.clean(cx), mutability: mutbl, type_: Box::new(ty.clean(cx)) } } - ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(clean_middle_ty(mt.ty, cx, None))), - ty::Ref(r, ty, mutbl) => BorrowedRef { - lifetime: r.clean(cx), - mutability: mutbl, - type_: Box::new(clean_middle_ty(ty, cx, None)), - }, ty::FnDef(..) | ty::FnPtr(_) => { let ty = cx.tcx.lift(this).expect("FnPtr lift failed"); let sig = ty.fn_sig(cx.tcx); @@ -1675,9 +1651,7 @@ pub(crate) fn clean_middle_ty<'tcx>( .projection_ty, cx, ), - kind: TypeBindingKind::Equality { - term: clean_middle_term(pb.skip_binder().term, cx), - }, + kind: TypeBindingKind::Equality { term: pb.skip_binder().term.clean(cx) }, }); } @@ -1686,7 +1660,7 @@ pub(crate) fn clean_middle_ty<'tcx>( DynTrait(bounds, lifetime) } - ty::Tuple(t) => Tuple(t.iter().map(|t| clean_middle_ty(t, cx, None)).collect()), + ty::Tuple(t) => Tuple(t.iter().map(|t| t.clean(cx)).collect()), ty::Projection(ref data) => clean_projection(*data, cx, def_id), @@ -1741,7 +1715,7 @@ pub(crate) fn clean_middle_ty<'tcx>( Some(TypeBinding { assoc: projection_to_path_segment(proj.projection_ty, cx), kind: TypeBindingKind::Equality { - term: clean_middle_term(proj.term, cx), + term: proj.term.clean(cx), }, }) } else { @@ -1773,26 +1747,36 @@ pub(crate) fn clean_middle_ty<'tcx>( } } -pub(crate) fn clean_field<'tcx>(field: &hir::FieldDef<'tcx>, cx: &mut DocContext<'tcx>) -> Item { - let def_id = cx.tcx.hir().local_def_id(field.hir_id).to_def_id(); - clean_field_with_def_id(def_id, field.ident.name, clean_ty(field.ty, cx), cx) +impl<'tcx> Clean<'tcx, Type> for Ty<'tcx> { + fn clean(&self, cx: &mut DocContext<'tcx>) -> Type { + clean_ty(*self, cx, None) + } } -pub(crate) fn clean_middle_field<'tcx>(field: &ty::FieldDef, cx: &mut DocContext<'tcx>) -> Item { - clean_field_with_def_id( - field.did, - field.name, - clean_middle_ty(cx.tcx.type_of(field.did), cx, Some(field.did)), - cx, - ) +impl<'tcx> Clean<'tcx, Constant> for ty::Const<'tcx> { + fn clean(&self, cx: &mut DocContext<'tcx>) -> Constant { + // FIXME: instead of storing the stringified expression, store `self` directly instead. + Constant { + type_: self.ty().clean(cx), + kind: ConstantKind::TyConst { expr: self.to_string() }, + } + } } -pub(crate) fn clean_field_with_def_id( - def_id: DefId, - name: Symbol, - ty: Type, - cx: &mut DocContext<'_>, -) -> Item { +impl<'tcx> Clean<'tcx, Item> for hir::FieldDef<'tcx> { + fn clean(&self, cx: &mut DocContext<'tcx>) -> Item { + let def_id = cx.tcx.hir().local_def_id(self.hir_id).to_def_id(); + clean_field(def_id, self.ident.name, self.ty.clean(cx), cx) + } +} + +impl<'tcx> Clean<'tcx, Item> for ty::FieldDef { + fn clean(&self, cx: &mut DocContext<'tcx>) -> Item { + clean_field(self.did, self.name, cx.tcx.type_of(self.did).clean(cx), cx) + } +} + +fn clean_field(def_id: DefId, name: Symbol, ty: Type, cx: &mut DocContext<'_>) -> Item { let what_rustc_thinks = Item::from_def_id_and_parts(def_id, Some(name), StructFieldItem(ty), cx); if is_field_vis_inherited(cx.tcx, def_id) { @@ -1830,14 +1814,14 @@ impl<'tcx> Clean<'tcx, VariantStruct> for rustc_hir::VariantData<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> VariantStruct { VariantStruct { struct_type: CtorKind::from_hir(self), - fields: self.fields().iter().map(|x| clean_field(x, cx)).collect(), + fields: self.fields().iter().map(|x| x.clean(cx)).collect(), } } } impl<'tcx> Clean<'tcx, Vec> for hir::VariantData<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> Vec { - self.fields().iter().map(|x| clean_field(x, cx)).collect() + self.fields().iter().map(|x| x.clean(cx)).collect() } } @@ -1845,12 +1829,12 @@ impl<'tcx> Clean<'tcx, Item> for ty::VariantDef { fn clean(&self, cx: &mut DocContext<'tcx>) -> Item { let kind = match self.ctor_kind { CtorKind::Const => Variant::CLike, - CtorKind::Fn => Variant::Tuple( - self.fields.iter().map(|field| clean_middle_field(field, cx)).collect(), - ), + CtorKind::Fn => { + Variant::Tuple(self.fields.iter().map(|field| field.clean(cx)).collect()) + } CtorKind::Fictive => Variant::Struct(VariantStruct { struct_type: CtorKind::Fictive, - fields: self.fields.iter().map(|field| clean_middle_field(field, cx)).collect(), + fields: self.fields.iter().map(|field| field.clean(cx)).collect(), }), }; let what_rustc_thinks = @@ -1879,10 +1863,10 @@ impl<'tcx> Clean<'tcx, Path> for hir::Path<'tcx> { impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericArgs { if self.parenthesized { - let output = clean_ty(self.bindings[0].ty(), cx); + let output = self.bindings[0].ty().clean(cx); let output = if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None }; - let inputs = self.inputs().iter().map(|x| clean_ty(x, cx)).collect::>().into(); + let inputs = self.inputs().iter().map(|x| x.clean(cx)).collect::>().into(); GenericArgs::Parenthesized { inputs, output } } else { let args = self @@ -1893,8 +1877,8 @@ impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> { GenericArg::Lifetime(lt.clean(cx)) } hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()), - hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)), - hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))), + hir::GenericArg::Type(ty) => GenericArg::Type(ty.clean(cx)), + hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(ct.clean(cx))), hir::GenericArg::Infer(_inf) => GenericArg::Infer, }) .collect::>() @@ -1941,10 +1925,10 @@ fn clean_maybe_renamed_item<'tcx>( cx.with_param_env(def_id, |cx| { let kind = match item.kind { ItemKind::Static(ty, mutability, body_id) => { - StaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: Some(body_id) }) + StaticItem(Static { type_: ty.clean(cx), mutability, expr: Some(body_id) }) } ItemKind::Const(ty, body_id) => ConstantItem(Constant { - type_: clean_ty(ty, cx), + type_: ty.clean(cx), kind: ConstantKind::Local { body: body_id, def_id }, }), ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy { @@ -1952,8 +1936,8 @@ fn clean_maybe_renamed_item<'tcx>( generics: ty.generics.clean(cx), }), ItemKind::TyAlias(hir_ty, generics) => { - let rustdoc_ty = clean_ty(hir_ty, cx); - let ty = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None); + let rustdoc_ty = hir_ty.clean(cx); + let ty = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx); TypedefItem(Typedef { type_: rustdoc_ty, generics: generics.clean(cx), @@ -1970,12 +1954,12 @@ fn clean_maybe_renamed_item<'tcx>( }), ItemKind::Union(ref variant_data, generics) => UnionItem(Union { generics: generics.clean(cx), - fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), + fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(), }), ItemKind::Struct(ref variant_data, generics) => StructItem(Struct { struct_type: CtorKind::from_hir(variant_data), generics: generics.clean(cx), - fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), + fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(), }), ItemKind::Impl(impl_) => return clean_impl(impl_, item.hir_id(), cx), // proc macros can have a name set by attributes @@ -1988,15 +1972,15 @@ fn clean_maybe_renamed_item<'tcx>( source: display_macro_source(cx, name, macro_def, def_id, ty_vis), }) } - ItemKind::Trait(_, _, generics, bounds, item_ids) => { + ItemKind::Trait(is_auto, unsafety, generics, bounds, item_ids) => { let items = item_ids.iter().map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)).collect(); - TraitItem(Trait { - def_id, + unsafety, items, generics: generics.clean(cx), bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(), + is_auto: is_auto.clean(cx), }) } ItemKind::ExternCrate(orig_name) => { @@ -2040,9 +2024,9 @@ fn clean_impl<'tcx>( build_deref_target_impls(cx, &items, &mut ret); } - let for_ = clean_ty(impl_.self_ty, cx); + let for_ = impl_.self_ty.clean(cx); let type_alias = for_.def_id(&cx.cache).and_then(|did| match tcx.def_kind(did) { - DefKind::TyAlias => Some(clean_middle_ty(tcx.type_of(did), cx, Some(did))), + DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)), _ => None, }); let mut make_item = |trait_: Option, for_: Type, items: Vec| { @@ -2251,7 +2235,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>( ForeignFunctionItem(Function { decl, generics }) } hir::ForeignItemKind::Static(ty, mutability) => { - ForeignStaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: None }) + ForeignStaticItem(Static { type_: ty.clean(cx), mutability, expr: None }) } hir::ForeignItemKind::Type => ForeignTypeItem, }; @@ -2278,7 +2262,7 @@ impl<'tcx> Clean<'tcx, TypeBindingKind> for hir::TypeBindingKind<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> TypeBindingKind { match *self { hir::TypeBindingKind::Equality { ref term } => { - TypeBindingKind::Equality { term: clean_hir_term(term, cx) } + TypeBindingKind::Equality { term: term.clean(cx) } } hir::TypeBindingKind::Constraint { bounds } => TypeBindingKind::Constraint { bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 83d8ed3fc87fb..8c08f77667904 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -496,7 +496,8 @@ impl Item { // Primitives and Keywords are written in the source code as private modules. // The modules need to be private so that nobody actually uses them, but the // keywords and primitives that they are documenting are public. - let visibility = if matches!(&kind, ItemKind::KeywordItem | ItemKind::PrimitiveItem(..)) { + let visibility = if matches!(&kind, ItemKind::KeywordItem(..) | ItemKind::PrimitiveItem(..)) + { Visibility::Public } else { cx.tcx.visibility(def_id).clean(cx) @@ -768,7 +769,7 @@ pub(crate) enum ItemKind { AssocTypeItem(Typedef, Vec), /// An item that has been stripped by a rustdoc pass StrippedItem(Box), - KeywordItem, + KeywordItem(Symbol), } impl ItemKind { @@ -807,7 +808,7 @@ impl ItemKind { | TyAssocTypeItem(..) | AssocTypeItem(..) | StrippedItem(_) - | KeywordItem => [].iter(), + | KeywordItem(_) => [].iter(), } } } @@ -1513,19 +1514,11 @@ impl FnRetTy { #[derive(Clone, Debug)] pub(crate) struct Trait { - pub(crate) def_id: DefId, + pub(crate) unsafety: hir::Unsafety, pub(crate) items: Vec, pub(crate) generics: Generics, pub(crate) bounds: Vec, -} - -impl Trait { - pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool { - tcx.trait_is_auto(self.def_id) - } - pub(crate) fn unsafety(&self, tcx: TyCtxt<'_>) -> hir::Unsafety { - tcx.trait_def(self.def_id).unsafety - } + pub(crate) is_auto: bool, } #[derive(Clone, Debug)] @@ -2175,8 +2168,8 @@ impl Path { pub(crate) fn whole_name(&self) -> String { self.segments .iter() - .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() }) - .intersperse("::") + .map(|s| if s.name == kw::PathRoot { String::new() } else { s.name.to_string() }) + .intersperse("::".into()) .collect() } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 27ecea5cc40bd..22b1e2335fd84 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -2,9 +2,8 @@ use crate::clean::auto_trait::AutoTraitFinder; use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::render_macro_matchers::render_macro_matcher; use crate::clean::{ - clean_middle_const, clean_middle_ty, inline, Clean, Crate, ExternalCrate, Generic, GenericArg, - GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path, PathSegment, Primitive, - PrimitiveType, Type, TypeBinding, Visibility, + inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, + ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -70,7 +69,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { ) })); m.items.extend(keywords.into_iter().map(|(def_id, kw)| { - Item::from_def_id_and_parts(def_id, Some(kw), ItemKind::KeywordItem, cx) + Item::from_def_id_and_parts(def_id, Some(kw), ItemKind::KeywordItem(kw), cx) })); } @@ -92,8 +91,8 @@ pub(crate) fn substs_to_args<'tcx>( skip_first = false; None } - GenericArgKind::Type(ty) => Some(GenericArg::Type(clean_middle_ty(ty, cx, None))), - GenericArgKind::Const(ct) => Some(GenericArg::Const(Box::new(clean_middle_const(ct, cx)))), + GenericArgKind::Type(ty) => Some(GenericArg::Type(ty.clean(cx))), + GenericArgKind::Const(ct) => Some(GenericArg::Const(Box::new(ct.clean(cx)))), })); ret_val } @@ -111,7 +110,7 @@ fn external_generic_args<'tcx>( let inputs = // The trait's first substitution is the one after self, if there is one. match substs.iter().nth(if has_self { 1 } else { 0 }).unwrap().expect_ty().kind() { - ty::Tuple(tys) => tys.iter().map(|t| clean_middle_ty(t, cx, None)).collect::>().into(), + ty::Tuple(tys) => tys.iter().map(|t| t.clean(cx)).collect::>().into(), _ => return GenericArgs::AngleBracketed { args: args.into(), bindings: bindings.into() }, }; let output = None; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index f46fde7b35a6d..0e9a9e0e50646 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -390,7 +390,8 @@ pub(crate) fn run_global_ctxt( // // Note that in case of `#![no_core]`, the trait is not available. if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() { - let sized_trait = build_external_trait(&mut ctxt, sized_trait_did); + let mut sized_trait = build_external_trait(&mut ctxt, sized_trait_did); + sized_trait.is_auto = true; ctxt.external_traits .borrow_mut() .insert(sized_trait_did, TraitWithExtraInfo { trait_: sized_trait, is_notable: false }); diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index c93897236db69..336448904d165 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -69,7 +69,7 @@ pub(crate) trait DocFolder: Sized { | AssocConstItem(..) | TyAssocTypeItem(..) | AssocTypeItem(..) - | KeywordItem => kind, + | KeywordItem(_) => kind, } } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index b9774eb70ea02..d7276a427c468 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -413,7 +413,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { | clean::TyAssocTypeItem(..) | clean::AssocTypeItem(..) | clean::StrippedItem(..) - | clean::KeywordItem => { + | clean::KeywordItem(..) => { // FIXME: Do these need handling? // The person writing this comment doesn't know. // So would rather leave them to an expert, diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index 0a7ee2005915b..9cb3327d7c781 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -91,7 +91,7 @@ impl<'a> From<&'a clean::Item> for ItemType { clean::TyAssocConstItem(..) | clean::AssocConstItem(..) => ItemType::AssocConst, clean::TyAssocTypeItem(..) | clean::AssocTypeItem(..) => ItemType::AssocType, clean::ForeignTypeItem => ItemType::ForeignType, - clean::KeywordItem => ItemType::Keyword, + clean::KeywordItem(..) => ItemType::Keyword, clean::TraitAliasItem(..) => ItemType::TraitAlias, clean::ProcMacroItem(ref mac) => match mac.kind { MacroKind::Bang => ItemType::Macro, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 52a2effca0ff7..4170c73b24625 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1485,7 +1485,6 @@ fn init_id_map() -> FxHashMap, usize> { map.insert("synthetic-implementations-list".into(), 1); map.insert("blanket-implementations-list".into(), 1); map.insert("deref-methods".into(), 1); - map.insert("layout".into(), 1); map } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 89d372da32278..c1fdece9ec6da 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2295,7 +2295,7 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean sidebar_assoc_items(cx, buf, it); print_sidebar_title(buf, "implementors", "Implementors"); - if t.is_auto(cx.tcx()) { + if t.is_auto { print_sidebar_title(buf, "synthetic-implementors", "Auto Implementors"); } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 69d66693f752e..daacc57a55a3a 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1,5 +1,9 @@ use clean::AttributesExt; +use std::cmp::Ordering; +use std::fmt; +use std::rc::Rc; + use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::CtorKind; @@ -11,9 +15,6 @@ use rustc_middle::ty::{Adt, TyCtxt}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_target::abi::{Layout, Primitive, TagEncoding, Variants}; -use std::cmp::Ordering; -use std::fmt; -use std::rc::Rc; use super::{ collect_paths_for_type, document, ensure_trailing_slash, item_ty_to_section, @@ -36,7 +37,6 @@ use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine}; use crate::html::url_parts_builder::UrlPartsBuilder; use askama::Template; -use itertools::Itertools; const ITEM_TABLE_OPEN: &str = "
"; const ITEM_TABLE_CLOSE: &str = "
"; @@ -104,7 +104,7 @@ pub(super) fn print_item( clean::StaticItem(..) | clean::ForeignStaticItem(..) => "Static ", clean::ConstantItem(..) => "Constant ", clean::ForeignTypeItem => "Foreign Type ", - clean::KeywordItem => "Keyword ", + clean::KeywordItem(..) => "Keyword ", clean::OpaqueTyItem(..) => "Opaque Type ", clean::TraitAliasItem(..) => "Trait Alias ", _ => { @@ -175,7 +175,7 @@ pub(super) fn print_item( clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => item_static(buf, cx, item, i), clean::ConstantItem(ref c) => item_constant(buf, cx, item, c), clean::ForeignTypeItem => item_foreign_type(buf, cx, item), - clean::KeywordItem => item_keyword(buf, cx, item), + clean::KeywordItem(_) => item_keyword(buf, cx, item), clean::OpaqueTyItem(ref e) => item_opaque_ty(buf, cx, item, e), clean::TraitAliasItem(ref ta) => item_trait_alias(buf, cx, item, ta), _ => { @@ -539,8 +539,6 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: let count_types = required_types.len() + provided_types.len(); let count_consts = required_consts.len() + provided_consts.len(); let count_methods = required_methods.len() + provided_methods.len(); - let must_implement_one_of_functions = - cx.tcx().trait_def(t.def_id).must_implement_one_of.clone(); // Output the trait definition wrap_into_docblock(w, |w| { @@ -550,8 +548,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: w, "{}{}{}trait {}{}{}", it.visibility.print_with_space(it.item_id, cx), - t.unsafety(cx.tcx()).print_with_space(), - if t.is_auto(cx.tcx()) { "auto " } else { "" }, + t.unsafety.print_with_space(), + if t.is_auto { "auto " } else { "" }, it.name.unwrap(), t.generics.print(cx), bounds @@ -786,22 +784,13 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } // Output the documentation for each function individually - if !required_methods.is_empty() || must_implement_one_of_functions.is_some() { + if !required_methods.is_empty() { write_small_section_header( w, "required-methods", "Required Methods", "
", ); - - if let Some(list) = must_implement_one_of_functions.as_deref() { - write!( - w, - "
At least one of the `{}` methods is required.
", - list.iter().join("`, `") - ); - } - for m in required_methods { trait_item(w, cx, m, it); } @@ -894,7 +883,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } w.write_str("
"); - if t.is_auto(cx.tcx()) { + if t.is_auto { write_small_section_header( w, "synthetic-implementors", @@ -923,7 +912,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: "
", ); - if t.is_auto(cx.tcx()) { + if t.is_auto { write_small_section_header( w, "synthetic-implementors", @@ -1880,11 +1869,7 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) { return; } - writeln!( - w, - "
" - ); + writeln!(w, "

Layout

"); writeln!(w, "
"); let tcx = cx.tcx(); diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index aecc9aa879a69..c6933a8254bc2 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -167,7 +167,7 @@ h2, h3, h4 { h2, .top-doc .docblock > h3, .top-doc .docblock > h4 { - border-bottom: 1px solid var(--headings-border-bottom-color); + border-bottom: 1px solid; } h3.code-header { font-size: 1.125rem; /* 18px */ @@ -216,15 +216,6 @@ details.rustdoc-toggle > summary::before, div.impl-items > div:not(.docblock):not(.item-info), .content ul.crate a.crate, a.srclink, -#main-content > .since, -#help-button > button, -details.rustdoc-toggle.top-doc > summary, -details.rustdoc-toggle.top-doc > summary::before, -details.rustdoc-toggle.non-exhaustive > summary, -details.rustdoc-toggle.non-exhaustive > summary::before, -.scraped-example-title, -.more-examples-toggle summary, .more-examples-toggle .hide-more, -.example-links a, /* This selector is for the items listed in the "all items" page. */ #main-content > ul.docblock > li > a { font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif; @@ -652,7 +643,7 @@ h2.location a { } .top-doc .docblock h2 { font-size: 1.375rem; } -.top-doc .docblock h3 { font-size: 1.25rem; } +.top-doc .docblock h3 { font-size: 1.25; } .top-doc .docblock h4, .top-doc .docblock h5 { font-size: 1.125rem; @@ -711,6 +702,7 @@ pre, .rustdoc.source .example-wrap { } #main-content > .since { top: inherit; + font-family: "Fira Sans", Arial, sans-serif; } .content table:not(.table-display) { @@ -957,7 +949,7 @@ table, #crate-search { min-width: 115px; margin-top: 5px; - padding-left: 0.15em; + padding-left: 0.3125em; padding-right: 23px; border: 1px solid; border-radius: 4px; @@ -966,6 +958,8 @@ table, -moz-appearance: none; -webkit-appearance: none; /* Removes default arrow from firefox */ + text-indent: 0.01px; + text-overflow: ""; background-repeat: no-repeat; background-color: transparent; background-size: 20px; @@ -992,6 +986,7 @@ table, border-radius: 2px; padding: 8px; font-size: 1rem; + transition: border-color 300ms ease; width: 100%; } @@ -1526,6 +1521,7 @@ input:checked + .slider { } #help-button > button { + font-family: "Fira Sans", Arial, sans-serif; text-align: center; /* Rare exception to specifying font sizes in rem. Since this is acting as an icon, it's okay to specify their sizes in pixels. */ @@ -1697,6 +1693,7 @@ details.rustdoc-toggle.top-doc > summary, details.rustdoc-toggle.top-doc > summary::before, details.rustdoc-toggle.non-exhaustive > summary, details.rustdoc-toggle.non-exhaustive > summary::before { + font-family: 'Fira Sans'; font-size: 1rem; } @@ -1855,6 +1852,7 @@ in storage.js plus the media query with (min-width: 701px) the sidebar stays visible for screen readers, which is useful for navigation. */ left: -1000px; margin-left: 0; + background-color: rgba(0,0,0,0); margin: 0; padding: 0; z-index: 11; @@ -2181,6 +2179,10 @@ in storage.js plus the media query with (min-width: 701px) border-radius: 50px; } +.scraped-example-title { + font-family: 'Fira Sans'; +} + .scraped-example .code-wrapper { position: relative; display: flex; @@ -2284,6 +2286,10 @@ in storage.js plus the media query with (min-width: 701px) cursor: pointer; } +.more-examples-toggle summary, .more-examples-toggle .hide-more { + font-family: 'Fira Sans'; +} + .more-scraped-examples { margin-left: 5px; display: flex; @@ -2318,6 +2324,7 @@ in storage.js plus the media query with (min-width: 701px) .example-links a { margin-top: 20px; + font-family: 'Fira Sans'; } .example-links ul { diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index e82ec04263718..e531e6ce6bbde 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -41,7 +41,9 @@ .toggle { position: relative; + display: inline-block; width: 100%; + height: 27px; margin-right: 20px; display: flex; align-items: center; @@ -56,7 +58,6 @@ .slider { position: relative; width: 45px; - min-width: 45px; display: block; height: 28px; margin-right: 20px; diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index c42cac59bd6fa..142ce456c5213 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -184,13 +184,7 @@ details.rustdoc-toggle > summary::before { #crate-search, .search-input { background-color: #141920; - border-color: #424c57; -} - -#crate-search { - /* Without the `!important`, the border-color is ignored for ``... */ border-color: #424c57 !important; } @@ -205,13 +199,11 @@ details.rustdoc-toggle > summary::before { /* Created this empty rule to satisfy the theme checks. */ .stab.empty-impl {} -.stab.must_implement {} .stab.unstable, .stab.deprecated, .stab.portability, -.stab.empty-impl, -.stab.must_implement { +.stab.empty-impl { color: #c5c5c5; background: #314559 !important; border-style: none !important; diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index a550eb1c130af..aeaca7515f962 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -42,6 +42,10 @@ input:focus + .slider { background-color: #0a042f !important; } +.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { + border-bottom-color: #DDD; +} + .docblock table td, .docblock table th { border-color: #ddd; } @@ -155,13 +159,7 @@ details.rustdoc-toggle > summary::before { #crate-search, .search-input { color: #111; background-color: #f0f0f0; - border-color: #f0f0f0; -} - -#crate-search { - /* Without the `!important`, the border-color is ignored for ``... */ border-color: #f0f0f0 !important; } @@ -176,7 +174,6 @@ details.rustdoc-toggle > summary::before { .stab.empty-impl { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; } .stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; } .stab.deprecated { background: #ffc4c4; border-color: #db7b7b; color: #2f2f2f; } -.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; } .stab.portability { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; } .stab.portability > code { background: none; } diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index b751acff152cb..54d1a7b65d665 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -146,13 +146,7 @@ details.rustdoc-toggle > summary::before { #crate-search, .search-input { background-color: white; - border-color: #e0e0e0; -} - -#crate-search { - /* Without the `!important`, the border-color is ignored for ``... */ border-color: #e0e0e0 !important; } @@ -163,7 +157,6 @@ details.rustdoc-toggle > summary::before { .stab.empty-impl { background: #FFF5D6; border-color: #FFC600; } .stab.unstable { background: #FFF5D6; border-color: #FFC600; } .stab.deprecated { background: #ffc4c4; border-color: #db7b7b; } -.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; } .stab.portability { background: #F3DFFF; border-color: #b07bdb; } .stab.portability > code { background: none; } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 5f3dd57061051..9000ab472d96e 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -43,7 +43,7 @@ impl JsonRenderer<'_> { let span = item.span(self.tcx); let clean::Item { name, attrs: _, kind: _, visibility, item_id, cfg: _ } = item; let inner = match *item.kind { - clean::KeywordItem => return None, + clean::KeywordItem(_) => return None, clean::StrippedItem(ref inner) => { match &**inner { // We document non-empty stripped modules as with `Module::is_stripped` set to @@ -269,7 +269,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { default: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)), }, // `convert_item` early returns `None` for stripped items and keywords. - KeywordItem => unreachable!(), + KeywordItem(_) => unreachable!(), StrippedItem(inner) => { match *inner { ModuleItem(m) => ItemEnum::Module(Module { @@ -554,12 +554,10 @@ impl FromWithTcx for FnDecl { impl FromWithTcx for Trait { fn from_tcx(trait_: clean::Trait, tcx: TyCtxt<'_>) -> Self { - let is_auto = trait_.is_auto(tcx); - let is_unsafe = trait_.unsafety(tcx) == rustc_hir::Unsafety::Unsafe; - let clean::Trait { items, generics, bounds, .. } = trait_; + let clean::Trait { unsafety, items, generics, bounds, is_auto } = trait_; Trait { is_auto, - is_unsafe, + is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, items: ids(items, tcx), generics: generics.into_tcx(tcx), bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 3a96884d45d9f..7429f2b6ab148 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -788,7 +788,7 @@ fn main_options(options: config::Options) -> MainResult { if sess.opts.describe_lints { let mut lint_store = rustc_lint::new_lint_store( sess.opts.unstable_opts.no_interleave_lints, - sess.enable_internal_lints(), + sess.unstable_options(), ); let registered_lints = if let Some(register_lints) = compiler.register_lints() { register_lints(sess, &mut lint_store); diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index e80a94fe749de..735a077fe1f6b 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -69,7 +69,7 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) - | clean::ExternCrateItem { .. } | clean::ImportItem(_) | clean::PrimitiveItem(_) - | clean::KeywordItem + | clean::KeywordItem(_) // check for trait impl | clean::ImplItem(clean::Impl { trait_: Some(_), .. }) ) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 1751249fa626d..83d8fe9ef1110 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -4,10 +4,7 @@ use pulldown_cmark::LinkType; use rustc_ast::util::comments::may_have_doc_links; -use rustc_data_structures::{ - fx::{FxHashMap, FxHashSet}, - intern::Interned, -}; +use rustc_data_structures::{fx::FxHashMap, intern::Interned, stable_set::FxHashSet}; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::def::Namespace::*; use rustc_hir::def::{DefKind, Namespace, PerNS}; diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index 0d419042a10a4..5f2f50e712b53 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -98,7 +98,7 @@ impl<'a> DocFolder for Stripper<'a> { clean::PrimitiveItem(..) => {} // Keywords are never stripped - clean::KeywordItem => {} + clean::KeywordItem(..) => {} } let fastreturn = match *i.kind { diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs index 0bb41977c97ca..75e1dd41a63e3 100644 --- a/src/librustdoc/visit.rs +++ b/src/librustdoc/visit.rs @@ -43,7 +43,7 @@ pub(crate) trait DocVisitor: Sized { | AssocConstItem(..) | TyAssocTypeItem(..) | AssocTypeItem(..) - | KeywordItem => {} + | KeywordItem(_) => {} } } diff --git a/src/stage0.json b/src/stage0.json index aa80d08e084cf..ab8a79e2af595 100644 --- a/src/stage0.json +++ b/src/stage0.json @@ -17,349 +17,349 @@ "tool is executed." ], "compiler": { - "date": "2022-07-16", + "date": "2022-06-29", "version": "beta" }, "rustfmt": { - "date": "2022-07-21", + "date": "2022-06-29", "version": "nightly" }, "checksums_sha256": { - "dist/2022-07-16/cargo-beta-aarch64-apple-darwin.tar.gz": "d114c9c7d39fa092e291d39eeed2cac5ec67a9d7f1e392014f83629dffd500f6", - "dist/2022-07-16/cargo-beta-aarch64-apple-darwin.tar.xz": "d3d0090e4afb944da8ae9b6b5441486e03066e83de69a2a9606a51444e601196", - "dist/2022-07-16/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "99d64f68bdbeff55552efe0860a2170db6c0cda155a7a955322d4ccfced2a2e7", - "dist/2022-07-16/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "209b0514a99341bdcaf62ad4785b807383aff2572105f143e89fc89f67bea0d4", - "dist/2022-07-16/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "6dc3c9f6739418e14d5d505b1f215c12768d9db2cc26912cae09ec75d6a5b336", - "dist/2022-07-16/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "741f7d7a55fcab360d6e0d91e0f83bf8ee6aaf19b0e880a7c3e91af22a4d7ca9", - "dist/2022-07-16/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "15185b7f4b806cf8dd5e785625df73efa27a5653e8c38476040372f372a11b1f", - "dist/2022-07-16/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "0122b5d493383d97d39d6593bd9cc709a1809f29f1713d3553ae242b78047e34", - "dist/2022-07-16/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "e3e2b281ff1233f6596b27db8b593252867d7f26c1ce91b779a164234d2cfd86", - "dist/2022-07-16/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "0c71da4b8daeab00da01bca07eef363c5a17a03c1eaf48014d3508c7f228e24b", - "dist/2022-07-16/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "6bce124d863189178f06cf430466c18d9ba0cd0e42851e18bb38254d00bdad64", - "dist/2022-07-16/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "0ae2a35e0e4f2946dd78420b11f17a54a370e15e12367ba29b63e3f087fb0c71", - "dist/2022-07-16/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "eee82cd57578eade5cbc07cf3d48be243a4789e6fba6d7db5772038f87e243f9", - "dist/2022-07-16/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "e27b8fe73df64a2733002007503995d9f914d16f852d5e643ac539408086435d", - "dist/2022-07-16/cargo-beta-i686-pc-windows-gnu.tar.gz": "0aa99ee73efa4940ffd6789f98d3774bf33a3a54c579759b1f9f0e92cb403134", - "dist/2022-07-16/cargo-beta-i686-pc-windows-gnu.tar.xz": "244a98bc858d800a1a36018d7b9fbb77471842b9a130301f9dc19e427c336fb2", - "dist/2022-07-16/cargo-beta-i686-pc-windows-msvc.tar.gz": "6b19412e037eb918b05e993ab1c62d96da8cbf92b0a9fc1480a76ad2dc331f0f", - "dist/2022-07-16/cargo-beta-i686-pc-windows-msvc.tar.xz": "0420980cc9381249bb187c274f42472997e6283acf95bebf1f93b50d5c138942", - "dist/2022-07-16/cargo-beta-i686-unknown-linux-gnu.tar.gz": "95d0e17823ee02ebc3d73982e54b96a110afbf97656ed581da0e71e2635cfb51", - "dist/2022-07-16/cargo-beta-i686-unknown-linux-gnu.tar.xz": "75a65a917ad25c1927c9c8306e76d13989f1ea42c6ca063269685e33811e1fb1", - "dist/2022-07-16/cargo-beta-mips-unknown-linux-gnu.tar.gz": "ac12e969fc6a892621ce9ffa2108a21381033800526d3b0dc6c1dd343b10af09", - "dist/2022-07-16/cargo-beta-mips-unknown-linux-gnu.tar.xz": "3be48fe74c14e48c084fe395b9eef153d97fca57dfc12b5a07f2de143c5df4fc", - "dist/2022-07-16/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "1727662c7307c3fec52663d356ccc147dd0c2608cd5607f83057a3f2f315e578", - "dist/2022-07-16/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "47b32153e287a972d6b7278a7d9b2339d16e8d9a938a42221536d12762d0df92", - "dist/2022-07-16/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "14d56231996a7c20e91c204658412142b8288668109d46f3ed9771186937fff5", - "dist/2022-07-16/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "83410621415f07b345d6989fd146303594c811449fd5e3c7609158a9404ba236", - "dist/2022-07-16/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "5362caf0bd6af50fc4bd89864beddcc909d1d53d0ce2b4049eca4b9019b9d922", - "dist/2022-07-16/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "6b5007890a41aead77f919ad7ff0fc29c32e460ab3402837ea0e6ded21f2e4c0", - "dist/2022-07-16/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "e4c914ef7b6e97aeb437d0fb2100f0fe621519ef8f6bdee98a4b3e731d5626d6", - "dist/2022-07-16/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "33a77edf6f85fc2ea790a10c3108811c0ccb22a0c4c0d1e3a6c3ba27c43ab6d9", - "dist/2022-07-16/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "85969807dc0d2999fe4dffdb0f8290bfeaf65646cf333924a933adaa4b045d05", - "dist/2022-07-16/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "b36b74e1032d6f83da8b18847df80d52fdf3375b2d45140020452e35c2b9af00", - "dist/2022-07-16/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "203402c33bb81ed9c176ee7579fde97671b2f32ad5e7fb3200cd1b77f434d52b", - "dist/2022-07-16/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "1bf1daa9660d4fe96e7b9d35fde4995e0e12efcdcb0247cb574495d20de080a1", - "dist/2022-07-16/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "a5aec71139c49fb950c03bb4b6af19bac0eec2d6ba2520e49c2d1a08eeae36ee", - "dist/2022-07-16/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "f0c5b7813073502316e25b71ab41eb600baffd8e51d6ad8134bf14aee53820ac", - "dist/2022-07-16/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "b64be7c8c471c9b4a2d9380ecf7d23431b1ea255bd080635ba58380a820cbe23", - "dist/2022-07-16/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "a0a6f204ce1f38482939caeb2efe645b60760e8b4c7a68ee4edcf51fc93409d7", - "dist/2022-07-16/cargo-beta-x86_64-apple-darwin.tar.gz": "9ab770b4d43ca4020c40b2c234867b67d99794945bb274382f69f9d1e4b0d042", - "dist/2022-07-16/cargo-beta-x86_64-apple-darwin.tar.xz": "66201509e2d1eb5b447f85b019467a2193fb9d3eaa12df025aff6746a47f49a7", - "dist/2022-07-16/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "295bfb182c85aad35fa5c25691acb03c037a28a8178b9b049df88d40176e418b", - "dist/2022-07-16/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "c1d4578521feb07b04c38b5431eb93830d518bbee47bb458e8f745a7bbd4b312", - "dist/2022-07-16/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "7eda4ebd7d8ade6e62772604bd6fe1a64f7123da1002c22810a752906893429d", - "dist/2022-07-16/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "7eb53b58d63c3f11faf58c819da9bf828f47b579904f9cc801a97b044bb7814c", - "dist/2022-07-16/cargo-beta-x86_64-unknown-freebsd.tar.gz": "cce8a7f5d0e561ab9ede68e535b601396a7a46c2737d01b9c9f008b6cf4b510f", - "dist/2022-07-16/cargo-beta-x86_64-unknown-freebsd.tar.xz": "c1989f0a6bb75c8ae4fb56fac60c880a62e92dbb225fa86b5383242573e62e9a", - "dist/2022-07-16/cargo-beta-x86_64-unknown-illumos.tar.gz": "eb5a4e9bd6a2216e4b72afb5bc542d49583a23a3bb3146ef2c02aa9f15887d24", - "dist/2022-07-16/cargo-beta-x86_64-unknown-illumos.tar.xz": "42c5330ba2ce1b8e4045e7b8671ad1254bc2d6119bc34996467c5956108897f9", - "dist/2022-07-16/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "35fcf80d8cb8bcc5ab413128575bc6a843c145b4b748df2de9cc9697d535fb6b", - "dist/2022-07-16/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "4070423142b86fac1ad312ea74880456343fbfe2f5f73e465993b21f4f019b93", - "dist/2022-07-16/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "4d3adc8d1cc15d45a4e7498965b92b9313cce8fa9a8f1391000d4dbe0258603a", - "dist/2022-07-16/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "2a39a68b74b7a62fb89f4ccbd202679fed65b425c1678451ac268b94c8294228", - "dist/2022-07-16/cargo-beta-x86_64-unknown-netbsd.tar.gz": "8508973b3595a0b0a65050d761c108119251a57ba3013d4942f65d0f4f634a7a", - "dist/2022-07-16/cargo-beta-x86_64-unknown-netbsd.tar.xz": "4309d7b2c2c26e454fee473e0345947b7447b6e107f795ce9d4cedfca3baa199", - "dist/2022-07-16/rust-std-beta-aarch64-apple-darwin.tar.gz": "2168776e63da0bb2b6d09e90510f0d481c68d4aaaa1e1cfc79317add45a01d5a", - "dist/2022-07-16/rust-std-beta-aarch64-apple-darwin.tar.xz": "bb9a83c1b5468e740a9b444052afe91a3d8d3223acdf1626e4302475f864acdd", - "dist/2022-07-16/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "44f00f44ee97a5f05b156a0be66151fefb79452b94b5d764564702194fb84ba1", - "dist/2022-07-16/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "b06f7599e3024cea98f90ea4a9dc0fac9d458dcce63aecc2497e2ec15a00eda8", - "dist/2022-07-16/rust-std-beta-aarch64-apple-ios.tar.gz": "35d7c8d11aac14f2e4ce3a1e236a8e59642a6be1e474be7d741c0e38ffcb9d5d", - "dist/2022-07-16/rust-std-beta-aarch64-apple-ios.tar.xz": "7fef57b2788303b10b267c228b80f6347c437a10dd2b77bea71e7280a11db008", - "dist/2022-07-16/rust-std-beta-aarch64-fuchsia.tar.gz": "d83d4186e499853f337513b5603c4cdf287012bc121a33537eb514b2d47e8963", - "dist/2022-07-16/rust-std-beta-aarch64-fuchsia.tar.xz": "92d3caab76907cea85fe78c10f902661ea0887c6689888f6eb9fffa2f443339f", - "dist/2022-07-16/rust-std-beta-aarch64-linux-android.tar.gz": "82ca00fd9913e2d55bc0ecf06313a2f9004f71c40c44f01b3d7d9cd8d1799fb0", - "dist/2022-07-16/rust-std-beta-aarch64-linux-android.tar.xz": "dc7c287887bba704fe988e7f5f7d080aff576de7a214f1dc63ded4fc784eba0b", - "dist/2022-07-16/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "fe47ed76b388f7b01d5e3d1d51918beb0f04ca7e015353479f7eff78e49b9794", - "dist/2022-07-16/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "0bcece81cf9b81c5ace02459f945b97be181f81704cade21687460f1db00343a", - "dist/2022-07-16/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "9f28057d4828f7a07eeefd8eb03c9e807babd86e67443099491421f7c5afa67f", - "dist/2022-07-16/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "b21f0deee74041385b7018979e7db1dfd071530f064b1bc500f9281cfafc38cc", - "dist/2022-07-16/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "588d6952722ec461de5d0c10c5f01c6d6735740a74b8162e2e2ebb848f9175d4", - "dist/2022-07-16/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "c6731bcd0e4e15d79dcdc6f974b5a4f7a379692ad2183c0bfd56e6619d9f0fe1", - "dist/2022-07-16/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "588585fd26813de3ae2a8a49c6e6fea5f0f7311911a54c015372010883cf5938", - "dist/2022-07-16/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "a5e820bbbf113250c4f814dd0f4aaa9b20b1a7d61613b7157993d25fb0ff3518", - "dist/2022-07-16/rust-std-beta-aarch64-unknown-none.tar.gz": "69ec1ef2f456a8cd294ec3f7c485f45401e6f200df9f525419726cf9da60dc60", - "dist/2022-07-16/rust-std-beta-aarch64-unknown-none.tar.xz": "b13d0099a55a928dfbfe07d80426e9bd53b6e35cfc6b634ad2ee02174ce42f7a", - "dist/2022-07-16/rust-std-beta-arm-linux-androideabi.tar.gz": "a90a4cc72263b96ada453dd3c8443d076ec150ed910ad30f26f825cd668516e9", - "dist/2022-07-16/rust-std-beta-arm-linux-androideabi.tar.xz": "0d7c8c13a18888cd7e9613c7d88ef227d9b2034739d0d16507aca28403328b42", - "dist/2022-07-16/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "9fcd72dfd5568a3e7023c416720ba4d5e42aa6d425c7ce6feb2ebf1b650d7591", - "dist/2022-07-16/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "43efd4e1ca95f54fef097f14483a4f4d96d499c38c5ad3d3a290e02f7c4c4637", - "dist/2022-07-16/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "7d2c708aaeb01014856ee7d2c6c4c85883f17fd00fca912aabb93d84170e3e61", - "dist/2022-07-16/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "97d3c092fd702dc7df0df83722046371b4d418aabc60fbbf0807ddddf3e7dcda", - "dist/2022-07-16/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "74e8fe4152eb12ee8b9d4fd4e3cfe5d506329c94ab515319fb2aaf013bacea5f", - "dist/2022-07-16/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "a207d79cf57f3e13b6f85761373a00fa8afde8f513e14a3e0c0a70f40d89e890", - "dist/2022-07-16/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "4660ec4d1fe1960e70b54bce58cae6775b8df86c3ecbc96f4df0067dcd90a3cf", - "dist/2022-07-16/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "c86a999f7affd8f4d2e0d509cf3e2229a3cd40768ef86b1ac36b5dccbbe56bdf", - "dist/2022-07-16/rust-std-beta-armebv7r-none-eabi.tar.gz": "5ecc032c10a8f8d3e1e40256ca7c7e03cc98ae35d56105f70df94a4519412dbb", - "dist/2022-07-16/rust-std-beta-armebv7r-none-eabi.tar.xz": "8e2c1c97083aa141d3b31476903a6325fd11f0ae5350909eb0295b8be19eb1f8", - "dist/2022-07-16/rust-std-beta-armebv7r-none-eabihf.tar.gz": "e111491ee2412c8d770b0a93fe402566e46c2faa855c71f24da77a989f36ea2a", - "dist/2022-07-16/rust-std-beta-armebv7r-none-eabihf.tar.xz": "7c814fece60ece924f5dffff6ee6f1605965841f4b864cd271c5c4f3b3c18042", - "dist/2022-07-16/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "0d4e93aa2f04f1d255d319653b3f4c02bd3557cc8227e6be4e0f1769aeadd2a8", - "dist/2022-07-16/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "d60246292f63abeb9eb35ddf93901ea9f75cba358a67589595aa1cfc9d35e6aa", - "dist/2022-07-16/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "085e236212a908e0e363d78dd3ce8c676cd2dbc8e817601486502389ba8d0734", - "dist/2022-07-16/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "654e655cb257dbed0490ec0c75e0cc0b7e35512d4f6f9f5dddc10bab0cd02098", - "dist/2022-07-16/rust-std-beta-armv7-linux-androideabi.tar.gz": "10fb120b0269a65f554a592e05ec26703b0888dbeaf06c15b43522b730c943cd", - "dist/2022-07-16/rust-std-beta-armv7-linux-androideabi.tar.xz": "470eec8bd47f66409e28eac2b86b5c6c0644531c91135637f667f54edb7fd6a9", - "dist/2022-07-16/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "520e83ebeb2dd29fea43087399af6227fe90b5a571572322301cc6d9b76f5027", - "dist/2022-07-16/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "a7527bcd5ee6017de7fde1a6f1d98db831e7bddf5a64b54ce12cadafaa3d560b", - "dist/2022-07-16/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "bb0ac318b0a5dd972356f4e94789b68caae1a14e5996493a3bed1a579bb1145d", - "dist/2022-07-16/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "cc1e65bf50246be9d9578487580038a7015f3a61444dc53afb7c4f2afc8181f8", - "dist/2022-07-16/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "7ff2051b2324f51bf0b3fe7581e1b5e02c4e2fb4075950c36716e8ba783b1b42", - "dist/2022-07-16/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "d4e32fcf2da983adc8db7043175cded76e56894f136766c5d9afe08ef6f0e766", - "dist/2022-07-16/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "6f7b86e7b51ba9d8187c61ff0d7a6d28fe65201bc94b94bd5a845490fbcff3e4", - "dist/2022-07-16/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "3ac410ea3f641b578ec1183856306b1eb4e0d02ba58534df114ab45a91fafd1d", - "dist/2022-07-16/rust-std-beta-armv7a-none-eabi.tar.gz": "abe93aa78a72eda2735d2f78cc98ea9b7a50752320d83b70464bac86a4a765ee", - "dist/2022-07-16/rust-std-beta-armv7a-none-eabi.tar.xz": "059560de23b47a43800319fc968a5dd34d44ab61f486a8f33a075798c66f0528", - "dist/2022-07-16/rust-std-beta-armv7r-none-eabi.tar.gz": "b08a4b0b56d86182e735d5dc6f47083a4f8a0101b4a712e02f14c9f3d1720001", - "dist/2022-07-16/rust-std-beta-armv7r-none-eabi.tar.xz": "d65cb28ea5f5cb7e5649a85a591609b5f49c0e3b0d02c1ff8d2b1dc10ea3b4a3", - "dist/2022-07-16/rust-std-beta-armv7r-none-eabihf.tar.gz": "cb13a879797483d7a7fd2073be2af0c83f98c4226e81ea0333670eddffc4f77e", - "dist/2022-07-16/rust-std-beta-armv7r-none-eabihf.tar.xz": "4965ee9c27d6104f572bcfd19944e19a3f70d58a5d0d215059f2cc52f7bc9c1e", - "dist/2022-07-16/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "e8437c9df42118b8607723c1e4f04a7b7a302e9894dc52ab8c212f07964ac994", - "dist/2022-07-16/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "b05f10cee7b5c8aeea44689c11ddfe6f266a8779dfb0fa9df51c7c784f9f31a6", - "dist/2022-07-16/rust-std-beta-i586-pc-windows-msvc.tar.gz": "65f66e8690c742b13c3371c1af4219d701b66f61e4fd984b1d67bb89d6468566", - "dist/2022-07-16/rust-std-beta-i586-pc-windows-msvc.tar.xz": "cabea5fef3004aee4c3108a47fba945f434bd29b4c55250236ec009405e41b36", - "dist/2022-07-16/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "8349e67b9760f9c257c745c4d87015bd623e1cf073703429f64400f7dc9c1210", - "dist/2022-07-16/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "ee6473059771a8f49ce5ca8f36913a9ef31be3def32c63c5a31f50a896aa565e", - "dist/2022-07-16/rust-std-beta-i586-unknown-linux-musl.tar.gz": "7edb1155a5fab3c123e0a847c0397b6c347cd7b4a6a15996d93f45281c2d8eb1", - "dist/2022-07-16/rust-std-beta-i586-unknown-linux-musl.tar.xz": "49360ce15d751ef01403459fe3eaa30061160a79e4454eee7f5c63fc65a3666d", - "dist/2022-07-16/rust-std-beta-i686-linux-android.tar.gz": "5d62f8e1b15b44998f7b039b7e6ab7deff85ba13130a11309b2541c70834538a", - "dist/2022-07-16/rust-std-beta-i686-linux-android.tar.xz": "4b2e1b2835919299113d28eca09b1e12471054786156da0cb63bc0620d6afe00", - "dist/2022-07-16/rust-std-beta-i686-pc-windows-gnu.tar.gz": "39a9c3f2392240b29f52ed525f57d548537e7cc7a57438bd84f7efbd85b49811", - "dist/2022-07-16/rust-std-beta-i686-pc-windows-gnu.tar.xz": "d8ae971791693c23260b73c8faf94570a1bddbcecfa9c339fbd23682c8cd2bb5", - "dist/2022-07-16/rust-std-beta-i686-pc-windows-msvc.tar.gz": "e57020d959cbe2e7331808f425e8d95e5204f4e9c33cdd301c6809aa06ba6d90", - "dist/2022-07-16/rust-std-beta-i686-pc-windows-msvc.tar.xz": "35b4504603903e7c753487585fcc75237f4f8a0ee933c52941abaf2c6913e0f0", - "dist/2022-07-16/rust-std-beta-i686-unknown-freebsd.tar.gz": "dd5c6dd4fe4bfb1acdda726ac9f6fa0944f745be946ed175a8e3c62c0d4c46f7", - "dist/2022-07-16/rust-std-beta-i686-unknown-freebsd.tar.xz": "95a9f3bcce8780522d678822cac8b06ba662112df51afa312f4c7ed76a3987ed", - "dist/2022-07-16/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "52b49a92f66cbc2b250a7272f58acfb9732fdb7073baa430b47ff9ebfe0c98a2", - "dist/2022-07-16/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "2f6b5de99c83cdd01c44b388ea059d10ee7f0f62ca17547b7a6d8d66fdf349f4", - "dist/2022-07-16/rust-std-beta-i686-unknown-linux-musl.tar.gz": "24d81d4d181c86dc02fe5b3fb54c50f78f72f73c2d9c319710d275fb08a53980", - "dist/2022-07-16/rust-std-beta-i686-unknown-linux-musl.tar.xz": "32c99f24396601c8a4afb250cda4718d6d5fae57f9534d5c3c3962e4c076d261", - "dist/2022-07-16/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "d476561d571d62d31c03b57fd380591acbb809fd4f26873e2ef2e4b3f583da46", - "dist/2022-07-16/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "93d3d0511508351f5e3322a3e4360586c2c2bdb60ca0c4aaea4fe5e7da081e92", - "dist/2022-07-16/rust-std-beta-mips-unknown-linux-musl.tar.gz": "d8c354f83a5481508a88fa6ced6fb458458678ddfa7814e47415b5daa66b0470", - "dist/2022-07-16/rust-std-beta-mips-unknown-linux-musl.tar.xz": "19f272db8772fa7b77cb9d5e1c56a1a2062a6e087b2980131128ab01b025f571", - "dist/2022-07-16/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "775aaac7be36438ce4e8f1cda3926c3540f90fc9b74e387d5e4497227ceaad97", - "dist/2022-07-16/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "bc460e80f4fd82492cc8e66f11320ef22c71fe26a4255606c73c325bbd2f8516", - "dist/2022-07-16/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "7ebb73739bafa8f412756575f4033b45629b62a92a35460bb37f3f691640bcc9", - "dist/2022-07-16/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "1483cde530d3d50116f4dbcb42a3b22cf7bb04559cc9bebd762f82e8b3ebea40", - "dist/2022-07-16/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "a7f813851b5a9c67ba16c80da5b80397db1f4c9b5a10f4877f52b6861b856b1d", - "dist/2022-07-16/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "3fd132910d46fb9d769d8697e81b89aff7f739d9b197e4a54b00797e217a0a66", - "dist/2022-07-16/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "8ddc74476e1023ee58ee5564d7357082cbba2a7d930abd7c704dbdf49439e2cf", - "dist/2022-07-16/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "f773cbcfb9010491f92cbeeccff0dfc8109d4407af4c10269766674a51e84b68", - "dist/2022-07-16/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "85bebea249c436f016fddef2865850adcb16585cccd6fd4fbd9baf0be971160c", - "dist/2022-07-16/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "74a519aa2b595b093510b81b0c65b9a864dc2cb3cb4ff5af8619531afd436b8a", - "dist/2022-07-16/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "f8dcb0e03629d23715e7cba213b91753d99a9e0ce8b0111e360a8c6e062b9f41", - "dist/2022-07-16/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "e2ad66f17aca663689d80e59b6ab854fe27aabda318c0ae41febf9fff700ac7f", - "dist/2022-07-16/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "6351ee40b19c7981f9b4aa2900bda8cf6fec04f5953bca78c0f480f885b78425", - "dist/2022-07-16/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "8c8f6ca9717ef1f4168d9ac4c4eb0f771149dcbc77ee4ec179031b10f9de13a2", - "dist/2022-07-16/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "706d3e633e8fdbc8f672153f16638ed2ade39321beefde054f63864bfac4e9af", - "dist/2022-07-16/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "0b7b37b4eee8fcccad684d606aa5b326f60473ed9f567cd2d17def4cbd8c3b63", - "dist/2022-07-16/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "40a2572f1a4297bef43708d1dafd1709373a0258f2bbe7914a9f954ca4dbe2f0", - "dist/2022-07-16/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "78ebece93dd1b8e6825d6026444484f0beca982d802651149da32b13d8de69c3", - "dist/2022-07-16/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "4a362a752fb6270c75fc24dc7cae00a70d4272972b1f0409a0a32582d1293acd", - "dist/2022-07-16/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "f1b8eb010818955e3ed21b2b4e3c42180fa817dcc0aa6b75520149fccd2b9d1c", - "dist/2022-07-16/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "0eb83977d0fb83eb498ff7858edd3fdfc0a2e40efa859a23b9a03972fd0f0c10", - "dist/2022-07-16/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "b39894ecc6fd00b8398b1430285d7876f8955eeae43949e54a45a0e374ad8c37", - "dist/2022-07-16/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "402e022a2a7f1eb06e91ba883532b6354e94dbd1314a7ab406f37e56026e6097", - "dist/2022-07-16/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "97762f1261461a996626dc922f7d2b9791d38d216e871065d1c9f3fe21dd10e2", - "dist/2022-07-16/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "0999c8f23113ed6cdb98f0751779d90fe368d6b322a49506dd5df96e9c00ce0b", - "dist/2022-07-16/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "7b289c284b7b53f7f12b05f841be6d6024dc581bbe59abf07402d87f87b78231", - "dist/2022-07-16/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "f6a71af82c15e20aa20881fdf0daa5815c2c9589c6fab1a69fade2380c9c740c", - "dist/2022-07-16/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "3adc7fd340e08b482259eece4c1abc210ec32f97fe6d5fdf6847ddeebe7e8e10", - "dist/2022-07-16/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "2136b39139393e6b9454b0c84a0c25256a444a940b9a6c207fddc7ef2b25a22d", - "dist/2022-07-16/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "ec9f3f7c62dd6fcc5339579d5becd5e5542c0eb45b415b91a9a2b6ebde18bd7c", - "dist/2022-07-16/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "79e21a41c5400e646f4ff76d8c4c0bea12501338742ce800093ee1e06d0d6932", - "dist/2022-07-16/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "f686a014f19efed6d8357d0ff88702779a0132bc412cd1e6eb93b535ebf26686", - "dist/2022-07-16/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "45a9dbab6143f10131f702c446768e542180572033811060947d4a1d79a7c2a0", - "dist/2022-07-16/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "eefcfb4558b26145aebfafb193420972be8d8e6ca1b8d83a648ab9718cdbf97b", - "dist/2022-07-16/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "96e69f7db947588df72b49975b53387a02d102eb1295ecc8712f5cdcf0191ba7", - "dist/2022-07-16/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "10c2dfa886225fdcd991db70c0ae077432a9ace7f69c5464222555f1cbe9b51c", - "dist/2022-07-16/rust-std-beta-sparcv9-sun-solaris.tar.gz": "254a8a83f480947878a377feb64803e6b396a967e07957513741aa7aa3ef6a07", - "dist/2022-07-16/rust-std-beta-sparcv9-sun-solaris.tar.xz": "a18a04dfdcb6fecea8376908114690e0ca5ca54b2aced5e922f463799483d882", - "dist/2022-07-16/rust-std-beta-thumbv6m-none-eabi.tar.gz": "643b8d6e5b17aa5ed0696550439039651e178695348dfb11567520e0439091a3", - "dist/2022-07-16/rust-std-beta-thumbv6m-none-eabi.tar.xz": "9cb7f0543dfd4f13b6126a6de336a6b11eea9a241cdbbf00290ed0c7a1d331ea", - "dist/2022-07-16/rust-std-beta-thumbv7em-none-eabi.tar.gz": "58d094491df31e051e9fc85d4376df165ef103651b676e494beba2b689382254", - "dist/2022-07-16/rust-std-beta-thumbv7em-none-eabi.tar.xz": "5e44398411718fb4cd22bc13a5fd091adb23938c2010d45ce63ac0a547435406", - "dist/2022-07-16/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "186ac77a1844786df52e5325e9aacd519db8f61ab72cd08376e8af869ce71e22", - "dist/2022-07-16/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "737d50c6ad0f0918580b29bdf3cf811f43a49fc5fcfd3b4e5f0cfdfde4acbf15", - "dist/2022-07-16/rust-std-beta-thumbv7m-none-eabi.tar.gz": "7e6bb04375764e3c80f2d477b2a982baa170339029a8c3f99caeefb280acd95e", - "dist/2022-07-16/rust-std-beta-thumbv7m-none-eabi.tar.xz": "e15af6e720e2b19884a1bfa3b6c2d394082786bf95483b0962ed134d7787161c", - "dist/2022-07-16/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "80a32a6988b945861eb834f3bfc0cbbf594a0b2b7cb1594f150e7ac8f2919065", - "dist/2022-07-16/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "75f986807dbeb40418b049264334580cf0d324db80e3e86d047d65e6ebb50a2b", - "dist/2022-07-16/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "d86a80418c9cc9b883faf2b5e681b530ea09c550fb39b9e558a381ab67d3f43f", - "dist/2022-07-16/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "30af6048b67ee64c378250b23227383b799c598aa24e3a09cf50baa4e15a9833", - "dist/2022-07-16/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "ed57999629478f3d1efd164249bb471eaf866a95da7c0916572bd0537f40c964", - "dist/2022-07-16/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "232f3099d833785dc6e50dadb205ade5440e850ec24821cdd24a534a19b93cb1", - "dist/2022-07-16/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "56ea2a0a2ff89efaeb791df36751cd6493161878e281d3dce507f9637044e304", - "dist/2022-07-16/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "820b1c2fa96e952a09b32ba0a5a94239bf69ecde2bdcb769d073f35e5ee13383", - "dist/2022-07-16/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "a1b9d35ed7346f43025a354c38e5836340c1be3a9b2173845c91afe7bbfadfc4", - "dist/2022-07-16/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "e3da59132bdef040b4618037f9d7f0c38511701420a676c9d451544cbfda0ce4", - "dist/2022-07-16/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "e92dce094d5c503c3a66c7419f4b2b341a0647678596f6c5ec5ddebaa4107905", - "dist/2022-07-16/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "b7a2e4db89f9dde15b51dea0044b57204326898e351fcb45df1da31c5edbe929", - "dist/2022-07-16/rust-std-beta-wasm32-unknown-unknown.tar.gz": "608834a5a7d60024e2f7275ac5615d7dc1c1723b2195695eb889dbd633a45e2c", - "dist/2022-07-16/rust-std-beta-wasm32-unknown-unknown.tar.xz": "646cbf64202df1f11d829d371810867e12120e12266895125b53600e4d678d26", - "dist/2022-07-16/rust-std-beta-wasm32-wasi.tar.gz": "b1802f8dd97e213466bdaaa769ef4b03ea1baf5cd14475edba8b70dd6736b855", - "dist/2022-07-16/rust-std-beta-wasm32-wasi.tar.xz": "f47bf0b5aaea9d52deea681b85daab38920db504168fb9a0eeea161996eaf494", - "dist/2022-07-16/rust-std-beta-x86_64-apple-darwin.tar.gz": "cd5be7559517ea844335c88e3cd5846990cad18bbb4dd96c1c1add6d873b5ef3", - "dist/2022-07-16/rust-std-beta-x86_64-apple-darwin.tar.xz": "3e028523c2a23a5681b6a9f4ed4f4313bbc0295f3f0e986e0c6bffad69454368", - "dist/2022-07-16/rust-std-beta-x86_64-apple-ios.tar.gz": "7c18b0d86b4cb7da00139112966e86de05da9286fea72458056dbf1607eab774", - "dist/2022-07-16/rust-std-beta-x86_64-apple-ios.tar.xz": "4aeaf6925f7a591a7ff0449d98b1ee5b1fd2fbca93e8bfb7fd2b279ecd2ec2ed", - "dist/2022-07-16/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "62ac06824cb70a0b02292ccdca9ae4e2660644fa9a0abb186c73d64e9632c733", - "dist/2022-07-16/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "8642bd83f1bf709d38260ee54fbb4de679bbec802d5c72f09e1146e82195577a", - "dist/2022-07-16/rust-std-beta-x86_64-fuchsia.tar.gz": "caf561a7b5efb474c9db48dd5ac3ceb32505f60813324b2665fadc639e6103e1", - "dist/2022-07-16/rust-std-beta-x86_64-fuchsia.tar.xz": "c6481548b0ef6b9c4a82b1f697842cb7c38176acb06699d559c825243fbbaf4a", - "dist/2022-07-16/rust-std-beta-x86_64-linux-android.tar.gz": "be110f47348bc63d27b541af4093167cd48d5f011897482ca7a940abcfeeb1a7", - "dist/2022-07-16/rust-std-beta-x86_64-linux-android.tar.xz": "11ccae4e0bfc76df7bd33d858fe47ead9294cd0707aee3f42ac3683a140d583f", - "dist/2022-07-16/rust-std-beta-x86_64-pc-solaris.tar.gz": "78d6662fbfb469c7cb0b2f381523ebab1b566edf2dfa676c8a509a6d584e17f2", - "dist/2022-07-16/rust-std-beta-x86_64-pc-solaris.tar.xz": "034be03c974835fa0d2747364c8b26f50d83762316d4a266473972622e2627d6", - "dist/2022-07-16/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "759eed3f19e2c8203a7b03ab90eedf4b09e0edfff9fea49bcb2fc795aef66a4f", - "dist/2022-07-16/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "119c6fbaa021130baa881738164810d7829ee54234e8adb6e82f1f6cba9da876", - "dist/2022-07-16/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "b0369c5804ab496b5ae9a2643f5da959e62cf574d394d3a74a06524816bd2fc6", - "dist/2022-07-16/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "130b922369beb56a30666dfb6f36881105e5446284f196eef6817939f94f1b02", - "dist/2022-07-16/rust-std-beta-x86_64-sun-solaris.tar.gz": "5405406252ab897de56c46023de48c08d03fce7791e7db06c009d10e4c9c03f3", - "dist/2022-07-16/rust-std-beta-x86_64-sun-solaris.tar.xz": "b91c6f6dfbe142102a8d72b5c91f8efd1873c20e73e34d9240898a08f63d6be3", - "dist/2022-07-16/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "17526319a486038ef77e7a0f8c1ffbc6e43b4ac3eef4d14c4b70307cbd937c5e", - "dist/2022-07-16/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "8cccb4640373abd1f17418c5b7d5198e8da3af3886206dff559fa2e23c4994e2", - "dist/2022-07-16/rust-std-beta-x86_64-unknown-illumos.tar.gz": "ff3f98720355eede902bc3c12d5ecdfc6e7f53b70133492e26b4cd464ff585f2", - "dist/2022-07-16/rust-std-beta-x86_64-unknown-illumos.tar.xz": "73531fe83d87304fe54adee9ede87e82220afd4dcb5c1a27878a1d9dd7dce9d9", - "dist/2022-07-16/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "936855bb97c47c0978caa65748515e3e7550916beb5d06aa569dab6192738886", - "dist/2022-07-16/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "e8b95205019e5f73e86247da9f5dab22f8ceaa98f6afa8f0eb7c6d92a258b97e", - "dist/2022-07-16/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "2f016727a0d761960923f4a83cce489d2f4d87b354352d109be1e89ad45f99e4", - "dist/2022-07-16/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "16f0829deae2df1fee609dfae7ec51bbcb7da5a9dcfe48f4d517d07934463b42", - "dist/2022-07-16/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "8bb4f4c9bb114cdee7c3d95c78e66f9c574ae47116b3aa0401712eb29c41461f", - "dist/2022-07-16/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "8a4977f3bb54c0f260c4b41f2fc7bf0fb06fd69e6eb9a9c88c438274f7ea993d", - "dist/2022-07-16/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "2b361b36d6a6f917b17a92b68dc9fb80c05e0b90a1987f4761b05ecb970ef4c6", - "dist/2022-07-16/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "5a4069a5ee239d289e13f8071c3fab252dab944706c2e223f763107509730fda", - "dist/2022-07-16/rust-std-beta-x86_64-unknown-none.tar.gz": "d4b0d375705732ac44da55e5272bde7c0756231bed205fabfa5b8b265e0d8e79", - "dist/2022-07-16/rust-std-beta-x86_64-unknown-none.tar.xz": "5d4f05830dc0530d60e0d570e692b0c4d7ee48e68d4bb3838878fead474bc063", - "dist/2022-07-16/rust-std-beta-x86_64-unknown-redox.tar.gz": "c43fb78286169bcdede9e092d84a9f2e7762ad67bdd2ed7a14d6d3234af52b9e", - "dist/2022-07-16/rust-std-beta-x86_64-unknown-redox.tar.xz": "905d5a8f6f642a978e55afc45329f6b7b6083a34ec6f51de0bb854685c5e3add", - "dist/2022-07-16/rustc-beta-aarch64-apple-darwin.tar.gz": "86afdc287964673c25d3c625b5bf03231d897d46fe8565e1078747e7b85bc627", - "dist/2022-07-16/rustc-beta-aarch64-apple-darwin.tar.xz": "8cd87fd24927617793bb06edc581184edfc12de7c961f03a530aee7eb793166f", - "dist/2022-07-16/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "6c2858cc584d845ebcb8cc4dbadc5b0bf4e875dd0920b2d9106791b8bb7567e7", - "dist/2022-07-16/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "dde2c77b23b8ecedbec8427c3b8f6a889d96b053de74787a73faef366cdb30c1", - "dist/2022-07-16/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "5ff5ae57cc7eacf26a3410c499d23e520ed9ef20f7aa50e77a3354a7bbed541f", - "dist/2022-07-16/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "850f4456625e7ae545c3036338b5bdcb1982a2fca4d1664efc835630a7e42468", - "dist/2022-07-16/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "5409263cbb71867780c8a2bcce126665217632d8eb7e4dab95c199ebfee8755e", - "dist/2022-07-16/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "deeeff68790e4857d625fdc1e0ed430e4d31b4e5e87b5534d899cdf7fec2adf5", - "dist/2022-07-16/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "0701e5f5d04db2cc677366ec769fa3f6c39351a9527f8493fd54d29086294a00", - "dist/2022-07-16/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "a133838e0eb1d9177fe0c052667ba9820a6ba5cbba604a80ad732ca5c1e23846", - "dist/2022-07-16/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "9ad3ad6c0c27d50238f83821b526a1d6f598ff293a36381d0a8a28cbd0a7ab4e", - "dist/2022-07-16/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "3313866d0d78c82b0b571e889d6ed85fce80dc2ea3dcc495f4738672e8d3b972", - "dist/2022-07-16/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "0459cf4a11cc6d41aa95d837b73a339fbf1c50ecfc078a95705c110d03a9c941", - "dist/2022-07-16/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "16b092bd7fccc84d6776f8cf3794c302b258fe9b3bf2adcc2ba1551197d3ab92", - "dist/2022-07-16/rustc-beta-i686-pc-windows-gnu.tar.gz": "c3c49711e23a87fb78d2a85d4838893963f151918464708f61cbd0a0ef8d6841", - "dist/2022-07-16/rustc-beta-i686-pc-windows-gnu.tar.xz": "eac7e88ef96b4eb99d5f15e168c7b782f0c9bfced92e5852559414e4c95a18c4", - "dist/2022-07-16/rustc-beta-i686-pc-windows-msvc.tar.gz": "fe6f0c952dccbe7262678615c8a850ce76f510295202427a16755005f3505744", - "dist/2022-07-16/rustc-beta-i686-pc-windows-msvc.tar.xz": "bd596d7e1fac9b4e02a036aa1e59819317d210044b3298bf4ec3633817f2ec2b", - "dist/2022-07-16/rustc-beta-i686-unknown-linux-gnu.tar.gz": "5dbbdd77e606ad28421a39d9ec95d2254e2658033247d94a733dec05a2368cb5", - "dist/2022-07-16/rustc-beta-i686-unknown-linux-gnu.tar.xz": "f9471eb60265b18f755c76dc4786895804fdc2b0ed8c8c8e58a454dbd1eca3b3", - "dist/2022-07-16/rustc-beta-mips-unknown-linux-gnu.tar.gz": "e4e8e67a0c4240ccb478631ee3b7a0fcc22d68b2adce26228f5fc9fff34dc03c", - "dist/2022-07-16/rustc-beta-mips-unknown-linux-gnu.tar.xz": "c7879912b5b6bfbaea4b424562ac1174bab8e30a4d20b3a82291b606a5a5f09e", - "dist/2022-07-16/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "3b437ea0fe1c9f52505cc7e5cfe2b3b103973e3ba3c132ba304d828c210e7eb1", - "dist/2022-07-16/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "d1c144f58626f3b0df9a24ffe5db9b2df45a410071df551fec48e0a7097bb17a", - "dist/2022-07-16/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "364647a234f7d40095d38cf01fcbdf554128436829d2972cb22f91fde18b346a", - "dist/2022-07-16/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "fc2c9200111139a051c8e3bb41f936b2126d24ca91ba175d88de95d59b6e00da", - "dist/2022-07-16/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "884a0da049f646196964f6cf93f03d9211e3864b39190432ee2e369c34051717", - "dist/2022-07-16/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "d82cd504ff34e741c9cf246fd6d8829f8af74d36670de46daea858a2c282f286", - "dist/2022-07-16/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "0fdd190eec39c72972d8d4df7fb59c77ffd9e9fad4d219264b6ceaa301c0250f", - "dist/2022-07-16/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "e74704b5c21a77c3d1dd7f265a7f24e9f904405afc3170d5f3836c8d28105ee0", - "dist/2022-07-16/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "90c1480f585ad1d9e0c3b564f5eb87667eedf5992ce46f73d6462dbb9a136182", - "dist/2022-07-16/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "e5b3e75d5d85e84fbf8c0d4b8e1f4c20421e1d20c18805f413f785d594c14a4c", - "dist/2022-07-16/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "5163f545aca9e56edb0510c30eb9343dbdd95ce3704677cdbebcb70947437838", - "dist/2022-07-16/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "f6c61e0c2bb404f248986287dcf7f4bcf8458fd17e678bbb53c43ce5ef19d5eb", - "dist/2022-07-16/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "fce64768b803f67470e093422926f44cf621eca5052eff4d9c6b89b94556b411", - "dist/2022-07-16/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "e99f1ae947b812047c4367d87f0f4dde6581c0af02240625500b1ddc9133025e", - "dist/2022-07-16/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "c6bb4bd5eaea57d15dd995de614471aeaddd103158e609ecdf43177f1843c25b", - "dist/2022-07-16/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "8e54cc288f3bb2a268fe37f2815ce94c3810438aefdfab9dd679ef572dbc127b", - "dist/2022-07-16/rustc-beta-x86_64-apple-darwin.tar.gz": "dc06d6cc19934b091cb3894c42debf6189f7b2d54162cc93418cb8851c967154", - "dist/2022-07-16/rustc-beta-x86_64-apple-darwin.tar.xz": "2f177aa386c389ce18ec47495d5c48d5512bee00aed0e3dad53809fbdb81f55a", - "dist/2022-07-16/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "e6af40fc7d92ddfd3bdab6ed92b8bb614df2ef7158a8f59291593034191d483a", - "dist/2022-07-16/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "5c51250a55d9e424ced7f91a90a801d53bfcf489be033a06c15adfcd587f5e47", - "dist/2022-07-16/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "f4bc463f82baa6681ad7292c512836bde962743b32b28ba118c38622dc3478f4", - "dist/2022-07-16/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "a25e397cd228f44c0280f61621bdbab028fb07a20551a3c1b25606d0eefc4745", - "dist/2022-07-16/rustc-beta-x86_64-unknown-freebsd.tar.gz": "27e0d39b8bdde40899a1486fc39b6bc612068dc4d4db65d52a4b3c85f03675e4", - "dist/2022-07-16/rustc-beta-x86_64-unknown-freebsd.tar.xz": "74f59446e6e6b031fedd12d10380bd33c119b09d0d1435488008f104a4297a97", - "dist/2022-07-16/rustc-beta-x86_64-unknown-illumos.tar.gz": "9b49259f9446ffdc510b80b3cb67084f006cbf86bc6c14e6a6a42128657773eb", - "dist/2022-07-16/rustc-beta-x86_64-unknown-illumos.tar.xz": "2a5b5c0f33dcdf79afce7445d6dd0183ba95f898becfca6eace5858e6836706f", - "dist/2022-07-16/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "b891c82a6acbb2ee5e3b46c4e5ebfc4a215e70415879425125934b7fa8c33329", - "dist/2022-07-16/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "e33bf0cd9e7e50469c9cd98c9404aa7495268192e4be70117c75607a9a18bb95", - "dist/2022-07-16/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "f5ed5f80204fa0608e888750866b880575d9eba63bbcd69b71708713a27fe27c", - "dist/2022-07-16/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "3f69e388b687cbdafaf59ca3486eed4dda510652a8ee37fde9efeff096258801", - "dist/2022-07-16/rustc-beta-x86_64-unknown-netbsd.tar.gz": "57eb4ebf820c11e5d4700f6c3ec414e6d2b70475f71579f854aec66650ab9eb3", - "dist/2022-07-16/rustc-beta-x86_64-unknown-netbsd.tar.xz": "979c3d20834c4bdee5b47598fddc26c3e02edd7678ee34faf97ac5f11aa8314b", - "dist/2022-07-21/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "9099fe96569cf008c9bb92f86efe1773a1e6f8542e71af037727d411ca3e4c92", - "dist/2022-07-21/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "085c6086a977725738ee44c4e0b748be255847c740fbce4aec62519afa91c088", - "dist/2022-07-21/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "c829b598f2a7d815ddb1772153aa847e5f1fe844710acc01e18f626d5af1daaf", - "dist/2022-07-21/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "50d3336081798cf6dffa615e1217845b51f82017375b4b0cf18167a939de0a5c", - "dist/2022-07-21/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "40a86effd1d5b60735d15c33090e31a0ed1cccdcca7cece013176071a90f3c93", - "dist/2022-07-21/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "ee29ab772f2f24f7f4f8655cbab2a64ad7fd2253ce04a4a72c497cdd18fd71cc", - "dist/2022-07-21/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "d739d788caf9190fccbab1a00e42f75bb7e10d94263b556578175bdd11826468", - "dist/2022-07-21/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "9775c98de87876ade2a7896e0df6519334ffb21cca12f60afa1874105b7dc75b", - "dist/2022-07-21/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "241d9983b1314829b9311bb7e1743e422b81d22342eed7216ba534788df77016", - "dist/2022-07-21/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "df50d81cf63dfea4a17f32318d4b4111944323395641ad9f7c989f9f74dbd383", - "dist/2022-07-21/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "1953f4f8c244c81e60a97c9480f78c0a3e0373c44ef7c188306ea26a6ff087e1", - "dist/2022-07-21/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "296273dfe9ad0ebf0ef47bb0a566050f90ec235bdb3d7776371b0b249466764e", - "dist/2022-07-21/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "da67ad4667d2b39862e21d43b9e0a99ad0bbd36ccc936779ed6dacb9b2fd17c2", - "dist/2022-07-21/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "efc5eb6d3c6fabdb03b83c9e9215b13955f82ceec62255aafd78db0e28ba8421", - "dist/2022-07-21/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "e603216f64f6fcf3ca21581dcdd283b41a1b6a59779c7760b8aa79b4c593e7e8", - "dist/2022-07-21/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "7c5c47faf6f014b63e1193cbf27de51bec82e9811537a17cb9b4922b709618c8", - "dist/2022-07-21/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "ac605732e74a1c344ea7c6ef84a6ca1823d3ed51024ef895ec9a181a6f91f8c3", - "dist/2022-07-21/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "7044d68341f8ea2fef122600f3995fff681599dc1a545ab2b45d1b2302fd6436", - "dist/2022-07-21/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "b7d57d01a9985826333ecac8447e0a1a5a753cf0ed11770de70d47b59050215b", - "dist/2022-07-21/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "13076a20f555c18db2d38deaaf33aeaed0f27b8cb5a2962b26661b6989dc3a5f", - "dist/2022-07-21/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "c64ab15040368af0c595102a7232b405b1a52164fe39e06ba189b2a26c70fe9d", - "dist/2022-07-21/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "a05b3aa95231a7e6631f0da01869d8cb8b6e3a5c184eb411591583cc78cd3aaf", - "dist/2022-07-21/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "242650636f9b33adc71a8c1bba1dc3a2928ba7723c976ae5645428b47862c658", - "dist/2022-07-21/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "7a2a54f05cac08aa65645e099d2597504477bba269b6f74e99f2df397a660eaf", - "dist/2022-07-21/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "2c3f944a0b8a5b06c4a341882934b737a451baf38f7a902f0794b0f41e1102e3", - "dist/2022-07-21/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "506e4f89b5243b8c2f6709d69a8b8facad5d7a555b108bed4f689dbd3fe1e46e", - "dist/2022-07-21/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "fe3a12786f8eecf26213286045a69bc1046d7138a401511618b86b74a70eb66a", - "dist/2022-07-21/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "37409a8573c5d0c9ea1fd0a745990a4e85f325a87a25c9916dd25617b6059783", - "dist/2022-07-21/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "e74050fa0288e7368a9e65f2739498f38ca9c91d36c519674e4590c17d86fcd7", - "dist/2022-07-21/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "10da2c6d12e14f4a2c6c9a7f1d2c161a62e4f9956ed7ee100ba31fce9446ea78", - "dist/2022-07-21/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "a0cf070555fed25a8aa9f20d704149936dca1ccb7c3aa55aabad2be84a7860f7", - "dist/2022-07-21/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "f388ba16822251f2dff0d9fd837dc19c5ca181ebabc93ed81759530d07dce72f", - "dist/2022-07-21/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "6056b5c1f46807fce83c4c3e2a443beb66b433e678fb090ca253aef5a87d2927", - "dist/2022-07-21/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "642046b17142d6e9ecd207243ed82108088c941b04ee5d8f6b1371b07da60601", - "dist/2022-07-21/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "600b5e7a11e3cb583fae2ef9f9dc784c2bef08e355da9e3a37204e0c81a63451", - "dist/2022-07-21/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "a9019c838270635f2fe383da5b11fdef2c7b23f838bc5edee7ba5882e7102c63", - "dist/2022-07-21/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "613539dc9a67c78216d8d11b0d9baf068d48c4067d628c8144bccec2d899afd1", - "dist/2022-07-21/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "55d992631c567da8ea082ca6dfcfdbf4774374ec430050a16001def2221adafe", - "dist/2022-07-21/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "9bade75f59be530972a26618f4e283c89bda864cfd162f47c8d1782d31163148", - "dist/2022-07-21/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "39f21c72c31dc0cf945db142cead8aa8f9208769d8f4336905794ec52848e90e", - "dist/2022-07-21/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "3b5cdcc58acad278a1b4eb84dc5aacd8eafe0bd2ac0ab62c5056c918661a9364", - "dist/2022-07-21/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "159dd0daacf54993386b2d1cefab13354d9c7614983745d43c28a1a873fbe498", - "dist/2022-07-21/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "cfef1baac5ef48912a3d30b3ba6513da50e6a35d1ad8687452dfe64e671effc7", - "dist/2022-07-21/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "8c72ca088ae104dd3cd1ce711e083a1816d16876ddd1a07af983d9c22cec1a33", - "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "fdecac3b5e42523e9f5200080f682e3b557b6820ae0f67a02620e1d1fba6f571", - "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "cbf56b942479ee95c89e14b060765ab8e21b2152b2c3e02ffb47957e37cec4cf", - "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "309be4a29a875ba17ed14e351a6aff7a649e0e6897f3d2c3394f2f2ae966a275", - "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "72e6bfd09cb22f8400dbef4017cd09deb2881cdf67df61d4e4d2d2ed5221a683", - "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "d40edc2217657dedee45336aad31289190a7da43bc5620b5d36b7dc0fce1f211", - "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "1df1787f682e9a8bd97a054f76094281fccd4d321c3067e2600860327dd088e3", - "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "91ed27676b13193eecb93839c0c748e667e869f091de88cea4183c51870efbe8", - "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "ccb0245ac982c34c9db9f6ffc3c30769e2b62637a18d88dc30a4ed3c1922fa7e", - "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "54344a42f2fca291c0c10f84386135e2797c9b81519eab0c6db633a95c109f20", - "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "4a276eac1bdace68484b49104b8bb2c48f93a775404f2bd29e9c3d4c6ce7367f" + "dist/2022-06-29/cargo-beta-aarch64-apple-darwin.tar.gz": "8e50ef7a6fbc0e7212621e124de66d123b9c772a04cdb04b5528cb68543f89d0", + "dist/2022-06-29/cargo-beta-aarch64-apple-darwin.tar.xz": "f74e110c8740321406acde67c37fc3dbb47e9d98e25bf20f5ad19790b89b9b9c", + "dist/2022-06-29/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "14067f4013c5e112531ee4f76e7ba61149b46a67d1d8bf0256dc2ee1410f44c9", + "dist/2022-06-29/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "9252a221a244308228a16f5e9729755d9f09421e2e316ea82f64da1d9a8c4725", + "dist/2022-06-29/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "38c0b9186fb251a6ac15ced667d3cd719e81acc0eb7a92303c6422c92b701842", + "dist/2022-06-29/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "b328753578ecb5ca9578f9ac89107804249eb4f802ca0f07c9bdd063aab931b5", + "dist/2022-06-29/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "747d836695e7a385e6af22911966f72410abafe8b400b33690804e4290e750ee", + "dist/2022-06-29/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "94cb8c5e70ba4da6de86777c3c2092ab0616da9d12fbff6928e901fd6c48c099", + "dist/2022-06-29/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "d3fa253a3a470d65f726dd59201c3b6e90e8d2343d3b5a1d27ba395d16ebe025", + "dist/2022-06-29/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "84f4684cb6e86e58279b768e8cc00c55da09a0ee8cdad77dfe4153748eaa3b60", + "dist/2022-06-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "58c3faea04e4a21425555afa5486e2f7704c8e5d5773cda73d618b1049e0575d", + "dist/2022-06-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "6b16b89b4e7b3ca9ba6ca7b0ae881aeb7c81a450ff4f32eca3d0907aadf10fd1", + "dist/2022-06-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "eb504aea2b96402b371e7b7bba7cbc5fdeb9f470be70927b11a340b5937513be", + "dist/2022-06-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c78dba1f0c58a7e8817ee9d5ddeb377e087432a1375ea3d99ee27b4a9f7d0ba2", + "dist/2022-06-29/cargo-beta-i686-pc-windows-gnu.tar.gz": "4d29aed70bd5df7525c8c8e8d88cdabee235c229821a9adba08c38a3a7e3b967", + "dist/2022-06-29/cargo-beta-i686-pc-windows-gnu.tar.xz": "2fdb9c3c42a3c97d3f8eec7b0e4bcd7a6db24abdf928d51a3c645f24aa7e41a4", + "dist/2022-06-29/cargo-beta-i686-pc-windows-msvc.tar.gz": "afdb95f020eb318ea66b3150593787ead14f1e8590ab950bec5516d1641c39da", + "dist/2022-06-29/cargo-beta-i686-pc-windows-msvc.tar.xz": "f1156f6f02262d12c777cee11d02b9c5cf9b4f28a27f4f9de9c154a8843d3d4b", + "dist/2022-06-29/cargo-beta-i686-unknown-linux-gnu.tar.gz": "aa972fcd1411e69464233fc54f34ac09aa04eb593410c7345718495e2ba684f9", + "dist/2022-06-29/cargo-beta-i686-unknown-linux-gnu.tar.xz": "ffa60e4ef87e7bb7229be6cd14f562d652e30e5badaa5892c0a7bc9563c56fbe", + "dist/2022-06-29/cargo-beta-mips-unknown-linux-gnu.tar.gz": "cb827715805de35449a17b190e1cb978bcd7d8b0a5501fe06d8f4313dce5b06d", + "dist/2022-06-29/cargo-beta-mips-unknown-linux-gnu.tar.xz": "63bc1122b296a89371d4a3560c06e1ce2f3a00482879d0ded87bd52f87fdec9e", + "dist/2022-06-29/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "b4d4222040865e4aa1d034f85511f436e08a1502c5213b6eacaf103d417755c6", + "dist/2022-06-29/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "e1d19f8de4278c01914d3999038c49001c214ab9ec5286beab327322d30fb564", + "dist/2022-06-29/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "b82d0a96510ca9933540bd8fc1534a1f91f92f92512a018b10cc007240ea13f1", + "dist/2022-06-29/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "e4805b270f9763adef25a0f970d28d2d69a92ddd9ab6d7f14fa746ad61b4e635", + "dist/2022-06-29/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "f3f9ed7f57299511610bf0d44abc79d9a0cf994c979546895b9a42b72b17734f", + "dist/2022-06-29/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "08c1c3cef4f257841f9600bfe2f67312cd76fbeca1e4326963715ca77668a0eb", + "dist/2022-06-29/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "1a1bba0cb974217cbff68001c83270c631f13193b5e3227f22a8b32613f7d570", + "dist/2022-06-29/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "cb32c1d4addc20433b15751db0da67cef5bcc576c17319bd79566596c153af80", + "dist/2022-06-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "7b6713071c93bdbb68f80f4045deaa8078382abe3179c60c92e0de5a0d93f161", + "dist/2022-06-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "313e6b05c3178b7e481ab09b71c1491b7136a47a9577649506823bdc698b279d", + "dist/2022-06-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0d7d4dc600ff03857b60767c50a79c0de8a0a6a78ef3f309121b8338583526c5", + "dist/2022-06-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "4b7d7da12ffe1ee279db21f6ef5b6124330ccee03711f3801561f68b303e15c0", + "dist/2022-06-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "154938148945148682bd165836e503064c248752cb24f1437d20a3ad128d6c91", + "dist/2022-06-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "be4c8a5b14fa9db00ad2f8efac052bbd6f7981610baf692b1d01f3bfb3be96f4", + "dist/2022-06-29/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "9ed70575f47e5a6bec063ed19eff165e35efbf6941403def15e48bf6560b949a", + "dist/2022-06-29/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "ad90bd85638cf26ecd72ffc0b09d1384c64fb990b4aa62f69e39d205609ba06f", + "dist/2022-06-29/cargo-beta-x86_64-apple-darwin.tar.gz": "54f71eff8e1ad3d22f49106b2c7b04713e7927a3f54cfc452c61e810e2b57129", + "dist/2022-06-29/cargo-beta-x86_64-apple-darwin.tar.xz": "b3f136e3d2bd5776887fb0071bc6434a1eb2cd42fccfe95eb8a32ca1bd36de29", + "dist/2022-06-29/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "e57239d7d3b889ec4dad8db20bbaa0140a2f0a471ab62e4a1c48558490f33d36", + "dist/2022-06-29/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "4f14c69c15e3038508df42e254027f0b59ed798cc26f0952fcaa8068341fb55b", + "dist/2022-06-29/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "2898e0a9dc793fe85835b8167b8e4e4cd4d0b044fff37a85034624a92a8e8f76", + "dist/2022-06-29/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "667a8a268fda0c44878498b2c68239bfe7387d9d8f9d39ec4445a79409e65a1a", + "dist/2022-06-29/cargo-beta-x86_64-unknown-freebsd.tar.gz": "da4ab4baae0f241653591c0f69091724ac8949b18e261c69069ff368f86e76b3", + "dist/2022-06-29/cargo-beta-x86_64-unknown-freebsd.tar.xz": "333295a07edac2f7aa9acec4284c3f2417ec764a9c09e8735ebbb69621d80aa5", + "dist/2022-06-29/cargo-beta-x86_64-unknown-illumos.tar.gz": "3b0899c1cdeebe01d8dabf5d0cd4f9762c07012e874111c77909840f917295d0", + "dist/2022-06-29/cargo-beta-x86_64-unknown-illumos.tar.xz": "ad698922172524912ecba24c966df6bdf18a21e530c2467d835c297709f1f413", + "dist/2022-06-29/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "f9efa10a31e31857644ecd8877b08ae96f80962bc96efbb374128220d659c2c5", + "dist/2022-06-29/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "5392a4bc11097ac95e208c9cea7b0773b966f713f3b1e0ba42f1323484b1d27c", + "dist/2022-06-29/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "a6177b8b69eb5d4bd3507d50054009734854775f8821b74b6ad603cda1e0b351", + "dist/2022-06-29/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "33a00ce744789c49438fe8accf40a17c99282339ca69adc7a3e8a810cad9f1f0", + "dist/2022-06-29/cargo-beta-x86_64-unknown-netbsd.tar.gz": "4b042e30402804c20abd84b39384b0b7d88743d27a9f0a34f90d7626f07a4f47", + "dist/2022-06-29/cargo-beta-x86_64-unknown-netbsd.tar.xz": "2e9fe2e92129a3952f1ae32760fd818a637b829a575194b84ab6d793d74c2c04", + "dist/2022-06-29/rust-std-beta-aarch64-apple-darwin.tar.gz": "031b3c2134e2c54aeb29ba2e46a5b6db11c65ff3a364cedd14c79d741a1f9ddc", + "dist/2022-06-29/rust-std-beta-aarch64-apple-darwin.tar.xz": "55f82ac681d5c8b6f0777939e747e8856707822e34b3060e9a85ec5935c8a406", + "dist/2022-06-29/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "53cc84de66c0c70b988b6136aa55c4051e51d27952e67db066ea409d56166fbb", + "dist/2022-06-29/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "6e9fa64aa157eb32e3ea4deb8d42256e5bbfee5fd4dae111f107033d792d28ad", + "dist/2022-06-29/rust-std-beta-aarch64-apple-ios.tar.gz": "d0e27984f1a2133af4e2fe9fd79a22f3e8a792a81111a496f80cfd9f3019b5e0", + "dist/2022-06-29/rust-std-beta-aarch64-apple-ios.tar.xz": "404780fc534501fbdd6fb34aeb3f338086feadebfef420a9530c6c4b48b803bb", + "dist/2022-06-29/rust-std-beta-aarch64-fuchsia.tar.gz": "bdafb54b1798812a0144029c421cc784a441ee82fc433f5788712f2c05fe4391", + "dist/2022-06-29/rust-std-beta-aarch64-fuchsia.tar.xz": "198be344c4a1c4247d8fb21efd9c84787272c0ae6208b341cae508adb8ba0ca4", + "dist/2022-06-29/rust-std-beta-aarch64-linux-android.tar.gz": "9c51ebdba4c211050cc8c6733e21faec7d7fb2591abb38226b0593f449d7e8b2", + "dist/2022-06-29/rust-std-beta-aarch64-linux-android.tar.xz": "f97595685703d22b0689b3f2822b3f69780eefc74a3169fdd1cf1d9a4538342d", + "dist/2022-06-29/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "2c32867f2e8ef81d1a8b0b3af14055be79f1da6dfe514155c9f9fd1eb98a99bb", + "dist/2022-06-29/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "bfc34e4077ece9675ed044a0e518bf8c38d0f351b62b6ea0d674f0c77c7af671", + "dist/2022-06-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "547505e533d6654d33df44e362cb421ea8fc69458efe51a357afc3665e19c826", + "dist/2022-06-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "f14478bd5bc6fea393111cd6f2dbbd1bc5a8d50adf0faa95b6d804c882d30415", + "dist/2022-06-29/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "ed17ac700cb1e4e773fd832c59aec036cebad714009786fec422077af35336e8", + "dist/2022-06-29/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "32b670e1e29d50c8af4ec0647b34855a07f9ab7a0142305a6a629cd4124c067e", + "dist/2022-06-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "225d33281ca9c69c3cdea76714e0383ae543c4f778859dd63cdd37dac09fa9d4", + "dist/2022-06-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "d55f5260e2c50a608f760d50e7fa653284f2a8b8a64588a80dfb13419061b014", + "dist/2022-06-29/rust-std-beta-aarch64-unknown-none.tar.gz": "3719244c77c4d5870accfe562f30a9dc3290a14dc3da399e64909402d116c482", + "dist/2022-06-29/rust-std-beta-aarch64-unknown-none.tar.xz": "78bb343bb519070c0761ea7ed3c4e56b6d821095ac931ad7f812743600dffb64", + "dist/2022-06-29/rust-std-beta-arm-linux-androideabi.tar.gz": "452973239e8c0995a8b9522417e020b883f2f4052764b18b8cd50c9d08cb4f14", + "dist/2022-06-29/rust-std-beta-arm-linux-androideabi.tar.xz": "b1952ef69d1c4c32bc0aad4b4beddc6e6bd56155eafce1ffcaafceff8cb6d77d", + "dist/2022-06-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "c1ad87f6a2f4e1bc1eb2f732285546fb062faad9b27c4dc248ff174e4a2ec60e", + "dist/2022-06-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "ef6611b0ee43efdfc0a27dc3a7b65eeb8cba0d10624233fb473d521392c7d3f4", + "dist/2022-06-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "4efd4c3e06a3bc3c2f873901a956827e69cecfd38ed62ba1d8cfaf979d6a67e6", + "dist/2022-06-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "2c99a7541c6ca5b1c1fad00e76736e74d7ae50af3cd891aeed8f4f8747d4292d", + "dist/2022-06-29/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "3d5c2be1e0e5b4ce33e2aa4765e869872b247709db1b194512d12146be439c80", + "dist/2022-06-29/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "e0b7e25f78e29a62d05eec6220000bcee815bcda24d857225ae47fcf3612fcf9", + "dist/2022-06-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "0639d8e52de274f02f34ca547a2c692defb329bae290a4ee977b05e9a3deca52", + "dist/2022-06-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "256a4ddafddacad0024be539cb038e7742b37f34038a774a06e9a43b29558d5a", + "dist/2022-06-29/rust-std-beta-armebv7r-none-eabi.tar.gz": "468113b22041adf0b7746838643ee316063f6049c20d499aa52ac2d9241091ce", + "dist/2022-06-29/rust-std-beta-armebv7r-none-eabi.tar.xz": "5b614aa0b7a360a8ee79bb0dca0b2adc3cc0b8f4f2266806bfb0d07b811c11d0", + "dist/2022-06-29/rust-std-beta-armebv7r-none-eabihf.tar.gz": "d13f0a0abcc35bf6ccd035ba9bdd5b0760b995c885902bae73cf8a22cddc847e", + "dist/2022-06-29/rust-std-beta-armebv7r-none-eabihf.tar.xz": "c7ffd2f6df10e754480bb1cb84b823084cf95cb6bbae2017437d5b9ffcd90b77", + "dist/2022-06-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "ad94a6356dbee95031bd943212eedc441d596cb11da1206010cef611e436975f", + "dist/2022-06-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "b8c78492bb88d317580d01e96a70d9eb42d2f9f8396806bd810e348706924d25", + "dist/2022-06-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "cd09bcb2d9d9fa25ddbcc81d9bf2ed2e68a177a1d61e1f9611516c95ca4f5e3e", + "dist/2022-06-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "efd2795a1484cd7331cbd849757a3b6cdbd50ae466bff760d9ec8e7ff965536f", + "dist/2022-06-29/rust-std-beta-armv7-linux-androideabi.tar.gz": "10ac8daf897263a1c51f0ed9df13f707261048c6d11e7a024470ba71c3d3ef34", + "dist/2022-06-29/rust-std-beta-armv7-linux-androideabi.tar.xz": "3968db993db3c861856dfa0974207b0709fba871cc17bc857c29f59063af15e5", + "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "33d19cbc173f71771b7a00a009789eef8f0b2cf65072642e0689bb86b191df4c", + "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "e896810ee1322ed011d662678839161e7c39faa27f1a8af963bc0a1e3b40a88f", + "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "d6b81169c6b77b7b93e03ac2d8289539e7ce6436106709f63b79a195b98d6fe8", + "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "6db5dfcdb0bba850db005a11e76cb3750befde0b6ef03b600c3c0e67a4c5d46a", + "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "5a729bb3471ccd07de54ca8fbc570fb617d4ba059a620754becc7aa48620f092", + "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "deb76d6f0bb0e4c9931df9976e869dcfc2548a851a06db89d656856bcab4fa8a", + "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "464bcf3a881d107747e241f88e71361dc5cabe7c27fe0e0f370c7ef90f8b77ad", + "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "0b66291a56ea5b7aa6b194fcf08d844a067940a3ec4cac11a377c87947a5cf4e", + "dist/2022-06-29/rust-std-beta-armv7a-none-eabi.tar.gz": "583e0b2e03386dcc0397dec2802659937e73dad04a52263218128ee2bab8c412", + "dist/2022-06-29/rust-std-beta-armv7a-none-eabi.tar.xz": "b9ebb07f4b461cef81b5fbbb38ac89245f4df13215fc64ad04e6972c1c2d405a", + "dist/2022-06-29/rust-std-beta-armv7r-none-eabi.tar.gz": "12a5b49d776cbdb26a1a6c1e2c38d62f562cf9f99fd4868da317b08d4df1bb84", + "dist/2022-06-29/rust-std-beta-armv7r-none-eabi.tar.xz": "a1b7b2c27236e36893056dccfd9d15db906db53e8c0f931d1dfc9daa147642a0", + "dist/2022-06-29/rust-std-beta-armv7r-none-eabihf.tar.gz": "9d1f6a6694e82528a6dc98d94f63aa253c0f2eac2cf1e9db97fb1fd9d9e68f46", + "dist/2022-06-29/rust-std-beta-armv7r-none-eabihf.tar.xz": "179e6d158a2f27bca2be54059414526de20de76a9eaf26c99e01ef9b1c7743be", + "dist/2022-06-29/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "eda6db1398471b8cda7b7449ba86db47587398c7b322e995039f59caabe8c815", + "dist/2022-06-29/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "9a079f124309edf9a187a0980b59085f5a1cb9c94236154a9f53cd7ca67a71e9", + "dist/2022-06-29/rust-std-beta-i586-pc-windows-msvc.tar.gz": "af4a7d3da748a9f2ff867fb7e6b87e0b4696904bab60a2e38df21cf41c658ee3", + "dist/2022-06-29/rust-std-beta-i586-pc-windows-msvc.tar.xz": "420801efc6deddaaee5a7e17672e0ff520d965ece9a2b8aa1534d86ce839777b", + "dist/2022-06-29/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "82d3b6bbc71b5e138f8715bfcba5107f0d1cde6aee8fe6bddaf85fa646ddf1d1", + "dist/2022-06-29/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "1eba8240509d6d5d0650f7e8e42cce89246aa1d416b859db496013d83983d4bd", + "dist/2022-06-29/rust-std-beta-i586-unknown-linux-musl.tar.gz": "d846e2ea559ad467945369d8230321734cca6634b8d1a4088475f8cafc9854d8", + "dist/2022-06-29/rust-std-beta-i586-unknown-linux-musl.tar.xz": "d5d8df8255a252af0c3eb66596d42a6d6cb9fcf3036fa8ab3f85ca1f344394c0", + "dist/2022-06-29/rust-std-beta-i686-linux-android.tar.gz": "55bca00de9caed1f5443592373b8a2581b1bc1ade24bd062a8f2ba396c82e520", + "dist/2022-06-29/rust-std-beta-i686-linux-android.tar.xz": "4db58c08b4e58584bf1a38205f100e0bfe79a74a4ff00280d5a29a3367302ca3", + "dist/2022-06-29/rust-std-beta-i686-pc-windows-gnu.tar.gz": "76c72088f1d77d84270b8ad00ee87a79cc8607c852291c5d2b82f59e6efd96cd", + "dist/2022-06-29/rust-std-beta-i686-pc-windows-gnu.tar.xz": "17eb428984599dd696554d9710cec60fcb01c8d341c0e59a0c1c00370c0d9c72", + "dist/2022-06-29/rust-std-beta-i686-pc-windows-msvc.tar.gz": "9dd0184f99be287f318952ace8190af2cd7accc47a7b3f388d34c77cff60c5ae", + "dist/2022-06-29/rust-std-beta-i686-pc-windows-msvc.tar.xz": "d76d255d3db0b9a5b5e8b1670b3eff4feaed8dc938187a6783a3323fb4998b8a", + "dist/2022-06-29/rust-std-beta-i686-unknown-freebsd.tar.gz": "8f8d60ba72543402b0c62bd68192891ee290fc7daff104e9ff8b10c9d109d791", + "dist/2022-06-29/rust-std-beta-i686-unknown-freebsd.tar.xz": "030629f57e1f05c7a1e96a147f7a2086c0968a6abfecbd375f9093c4a2859fbb", + "dist/2022-06-29/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "a5d01dba11d59ac1a11404905c54425594bc69f40cad8814d3ffd00d1b38c52a", + "dist/2022-06-29/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "5f2ea9f7e62fb429f4f0575a267eb46a014b9ae727939f909ec5e3777e32e65b", + "dist/2022-06-29/rust-std-beta-i686-unknown-linux-musl.tar.gz": "6e76c8616ee86d1b51c9b055b324f715c1a9cbb1c1564982d1f7e6fd623cd292", + "dist/2022-06-29/rust-std-beta-i686-unknown-linux-musl.tar.xz": "54641f169e424a73cb386e41563af5ed9ba833379edc148579f67bdcdab281ba", + "dist/2022-06-29/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "64303412deb9264dfd15a16341203df39af2e9206ce1d22ca5eaa83762e1f62a", + "dist/2022-06-29/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "4c4cb3fb0ee51f9294cb805c7263f716a921e7d76503cbbd24f8600c485c58aa", + "dist/2022-06-29/rust-std-beta-mips-unknown-linux-musl.tar.gz": "e197dab9c9b11cf98404aed094d1d8bc03a6755ebf4046423c11baeb0143f254", + "dist/2022-06-29/rust-std-beta-mips-unknown-linux-musl.tar.xz": "81a80fa315dc3da8111f487b9dd6dbe56991276fac138de4469c0e0b688bae07", + "dist/2022-06-29/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "9cc065dd7fe550716efa403c910d9eaf8c18d90d7d3e316772fac72f7f16c45f", + "dist/2022-06-29/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "6bde95f6c57f6ce4de4f1ce9837b386e374eb291d8778956bee0956b150c3917", + "dist/2022-06-29/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "1262105c31f7ec6248b24b71f0003014a8558220444cfc88c611ad2aa94efebd", + "dist/2022-06-29/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "cb35ba7184ba5a74f5d6c8592e67e08faed205e091784f85137872e02541ae99", + "dist/2022-06-29/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "31d7af84b431c9185b2ef98c18eaadb957e22e427b331a8ed4ab8b2b6ae364ae", + "dist/2022-06-29/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "674b1c886ae4a2273edd6e49539d45a2a02e73874f6a65ba820dbea75d8ca8c6", + "dist/2022-06-29/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "cc620438e90fbd086b4f237454b099a81e4cc3dae9582e7526b2a10648663e4c", + "dist/2022-06-29/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "425ce38ad1bb048756a37e8642ab6b43f8189bee244e4ee011e95fd45f3a3747", + "dist/2022-06-29/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "40b0df32d5df53fe8774000804738d56e7c8768cba1baaf52721a9956d62c557", + "dist/2022-06-29/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "7df34f8ddb1b14698c6473eaaeffd5d6da23ddcde23a74a3482194e01fa5ace7", + "dist/2022-06-29/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "65b3db3bac29c8aad57c8cabe7fbe622acfdcd9221c11af4419d74c24452a939", + "dist/2022-06-29/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "9a4a382945631425fc8227d6b42d0f97988dc39c8e79646280e080595d82aa31", + "dist/2022-06-29/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "30fc151ae3a6423e027aacd70bcd45d13243aa5394ff2d6cf285c55d3c5c6e23", + "dist/2022-06-29/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "28cef1191d2181004b8e5032bc3f7b548996149dac8ffb5b8a5431b32d396683", + "dist/2022-06-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "a6b79a07cdd6cd6d0e468132ab504464e3d6c41f28111cf15c6053d7d560b8b7", + "dist/2022-06-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "67aa93c917f234b0b61dbd3fac21a1d6d4ef20cc8dd7fdc6a8bb8e688e3920ca", + "dist/2022-06-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "e4dd3483a85060d75a7dff95dda7a121943f1121983e5d33eff166f4c3e97e6c", + "dist/2022-06-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "36f2b7305e8ed58666c206c26e28cc5e8708fdf104f1d67dd0c692f9e36a1482", + "dist/2022-06-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "f232913783443410614af3e27a832740b06d392563f5d0aa6d0ac0558d7bbb6f", + "dist/2022-06-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "f54f1f0c7fe7b31ff97bde512573225f7380bd1c35876862ea798fc2b38cd4fc", + "dist/2022-06-29/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "728135a1f7c89a129c78c2adf360ab06feb79f28b10f993797d498a9effab9e9", + "dist/2022-06-29/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "ba91db121409dc9414377759fd27e8947e46dbb9f3788521d82a67b063c2a9d6", + "dist/2022-06-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "c092940c2eaea9c9168061b8f5b87f1b735c1d0ffe05bc834252719c42f3ff33", + "dist/2022-06-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "2906008d17bb17bc84709d8e47c8c065b2749355240e630cdb1f0c173721a05a", + "dist/2022-06-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "7815f8bf5838e2f497e2d42cad55c3e738f64957e031af90f82d80fa7ce78f1a", + "dist/2022-06-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "16bbac000585cc3985582698b42635d1e3af68445e2ef4340600087e1fc38e26", + "dist/2022-06-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "2fdb717d0fa4f3e162ab8603d2b5233c6ec20a587af874d0987b1b040ea95dfa", + "dist/2022-06-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "f4f2445d1e9f8cd0af34ce0063a44041465df0b6d5b73546595d0d37f0342087", + "dist/2022-06-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "a2df1578a4ec47fb925102fd6604add216ed7d27bdf323176328afef48f2faca", + "dist/2022-06-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "e3839aa18e35d7d050ce00210774a63b84b3070bc28be1d70ffd4c939b6d8cc0", + "dist/2022-06-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "4ad1c23982c5d5b45935e52fc1a0e36e08e853a993a0adb5c9fb9e703ee2cb7f", + "dist/2022-06-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "1308041c43eca228f265cd1cdb3d419bb7e4e1461e117536b719cc3ec8527798", + "dist/2022-06-29/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "0fdbbe00f9b655e657d93e97bd1b625afd1531249cd32d013c0a1d62e48fdbad", + "dist/2022-06-29/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "cd9120d576a533106721b11e4e457c317be7ff484613d2c7592606a379c0fb3f", + "dist/2022-06-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "c570c55584f9d725c69bf092e0187dd7830839b6badc6fba62b5fbaa19b75548", + "dist/2022-06-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "d3e63b5f8f139e32a40ccbc7d877714e88d68a31e1644cf4d1cc91771d5459c9", + "dist/2022-06-29/rust-std-beta-sparcv9-sun-solaris.tar.gz": "61169fbfdab7d66712f04a53d6ab8766766158a566bf606075132002a67bda0f", + "dist/2022-06-29/rust-std-beta-sparcv9-sun-solaris.tar.xz": "f137dbdf000903de091c076fd3800466097caf2f9c48e4ebae9c3072fc2aaca4", + "dist/2022-06-29/rust-std-beta-thumbv6m-none-eabi.tar.gz": "b81429647fa2fd42fa7a5b4c15d15b1595023e81a7e4289e06bd214c6666127b", + "dist/2022-06-29/rust-std-beta-thumbv6m-none-eabi.tar.xz": "4a741ba60918138ab24cac1d6fda432d38d02bbf0a22103270df13e0d40c8a86", + "dist/2022-06-29/rust-std-beta-thumbv7em-none-eabi.tar.gz": "ac20977687a1831ea2883568eac148821ad9f1ad199a9b728447f7d15f518e1e", + "dist/2022-06-29/rust-std-beta-thumbv7em-none-eabi.tar.xz": "57262c3ddf2351b80ff8dcc03fe8e16b441e1b0014c0e4534e2e493902928ea7", + "dist/2022-06-29/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "be9111bfcd464b5f107642b18fc375eeea16a1d758de71cfb6258e0302c9ae7a", + "dist/2022-06-29/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "63f84a900c52caac4eed1c58bbfc604e591c56e0fc1afcebe7ae832a9610c060", + "dist/2022-06-29/rust-std-beta-thumbv7m-none-eabi.tar.gz": "51f5266d9790f4e691493e403edcd664541afd448123fea3fbd1de2d50c87f1e", + "dist/2022-06-29/rust-std-beta-thumbv7m-none-eabi.tar.xz": "12f7be43c58de67c761ed17bb555509e639c31c5cc0783d9ca55e78c4586317a", + "dist/2022-06-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "37f3baa3a2db1b15315915910447332bcf5b9f36666f4cc08868b551d27022cb", + "dist/2022-06-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "e1f457d3da72a9989b90395692310c78c5e5fdcea35fc1bc2f450eba62b7d21d", + "dist/2022-06-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "77a461b06eff56bc00361e9f771e0a81087fed2999e5d1f2f53632a61e90829b", + "dist/2022-06-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "29a4f3a426e380b886bc7a468b08d2dad38ff704d74ec2f243ba5ba7720c7e9a", + "dist/2022-06-29/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "cd0285f0254f4042ee70f02ea576ec713e34ec00e2fc0309cd7c891ca26674ca", + "dist/2022-06-29/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "43dd490c8068897a5f45ee0da36ea8854496cfb54faff9f759e2795f22d46cb7", + "dist/2022-06-29/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "cea8f1a52c3829f4781c321bb43486e44ee8fc94602249d1084e8a6e9269e2ce", + "dist/2022-06-29/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "9a6b827b4958d412d4f413219458582142d1536f313d14ded54cf666a43946bf", + "dist/2022-06-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "a032c778052e77eb32eef136ca431ce2bfbd6e43ba5a82e90b2ef3dd414b2cd0", + "dist/2022-06-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "cb560e7b3c62bd2598e701360b11a6edb16e730700c4aa5e5d284dd1ceb570c3", + "dist/2022-06-29/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "c8e3309f94e8187e41d5de922c7988d610439be3a90e06c9eab76b4a3850343d", + "dist/2022-06-29/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "f1388800ff04b85fa549191a5cae8e4964baff89ddadd57fccdef85a1da99e4a", + "dist/2022-06-29/rust-std-beta-wasm32-unknown-unknown.tar.gz": "c0a18d66485400b692011d72af2226fc609eddd19fd1e95f370ed6a864f6dd8a", + "dist/2022-06-29/rust-std-beta-wasm32-unknown-unknown.tar.xz": "f3772ae732dcc6a63c2143d3530d8253b35c7412b2266ed9583d14f6000b214a", + "dist/2022-06-29/rust-std-beta-wasm32-wasi.tar.gz": "aa204e3377e1c4272c18231bcdaa439678fbb1158d794ee8b2699fbad382c828", + "dist/2022-06-29/rust-std-beta-wasm32-wasi.tar.xz": "25c90365da9be1307e4aa80f699ed14eec03bd48b8271570d9e9e9d4dd0f701d", + "dist/2022-06-29/rust-std-beta-x86_64-apple-darwin.tar.gz": "24754ac282a434638de5bd2a548b3960149b811f03422cf875a5018dfb229441", + "dist/2022-06-29/rust-std-beta-x86_64-apple-darwin.tar.xz": "0806c72137fd994acfb304039af85e028999ab941d3d95cd037f298a66377aa5", + "dist/2022-06-29/rust-std-beta-x86_64-apple-ios.tar.gz": "588bd3b637531ae3399a91e805d52481c927477d15822636714091d2371e95cf", + "dist/2022-06-29/rust-std-beta-x86_64-apple-ios.tar.xz": "27d75a39fec3ead30dca470f0f6c96561a48bffa8d22c283001f7543b0d62f0b", + "dist/2022-06-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "b7b32388857ecd8f1f16fdd5354a9411c84c463b8b40a1ec2982d5dee11e2318", + "dist/2022-06-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "5ea72074aedac44961823a6a8788bb7aecb905dffe2c25d52c417275be39676d", + "dist/2022-06-29/rust-std-beta-x86_64-fuchsia.tar.gz": "5f53ff113fa233161183bd1c79a946aa13770f52f08ab3d8a62a080ee2682163", + "dist/2022-06-29/rust-std-beta-x86_64-fuchsia.tar.xz": "5541a85df4ac431a14830b09bcda0d030236ea31419b1ccfdf2e761638a1c484", + "dist/2022-06-29/rust-std-beta-x86_64-linux-android.tar.gz": "d17d49d6e416941c1aeed7d145b47d2d61a7bcb563720ed5dd9b867cd0522f05", + "dist/2022-06-29/rust-std-beta-x86_64-linux-android.tar.xz": "41aa64b361c17afd7466b621923a44e80d61edefd7052e06df1eb96ee0cad3b1", + "dist/2022-06-29/rust-std-beta-x86_64-pc-solaris.tar.gz": "2527ecd6465989f54570e7ed61b51c8a00bc5e1c613e972c93b028df0ad60ec5", + "dist/2022-06-29/rust-std-beta-x86_64-pc-solaris.tar.xz": "91f243a73494de90c5250a663f111b3a999925a923cb92220d1853428e2b1aea", + "dist/2022-06-29/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "e41010c4f7bec5b06205085fba4e538cec40222c18c5d560c2a1a2f5c2d4b859", + "dist/2022-06-29/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "af8185b065f2ab37f92ec671eae1652368b26b6917e34c24f2a15779f1e447c7", + "dist/2022-06-29/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "1fc3c51f18174e07ba21bd8bb4da495540273ac3f89d2e106172bd6cbfd08ae3", + "dist/2022-06-29/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "b5ffbbda960fd38bc11bf56e154990b385940fa6fd95563feed0a403317aeca4", + "dist/2022-06-29/rust-std-beta-x86_64-sun-solaris.tar.gz": "8bc7de9a99c3eb1954a1dfd17a39629449e41d743ee85437dcc67f37ccfa9cfa", + "dist/2022-06-29/rust-std-beta-x86_64-sun-solaris.tar.xz": "919ffd2e0221c6e6125cecf5f1c21c4b03d3e98c4e1322e5ec664e4079d37fce", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "fbcdbf0d7a8dc6970fadc835455a6fce455ecbdb16ec435957e19477efe94af6", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "09bb9ef104f7eeaf6fae591d908a0f8cbaaf98f1a14e788f468cf99dcbecd8ce", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-illumos.tar.gz": "9b0176f89bbff3c2fef94ca3731dbf9e3c079288aee88827efb42a6296ff8168", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-illumos.tar.xz": "d84e40868ce185b39a0ad9a6dfc118b31cc0742b9e4e80b59944572043088f24", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "69cb1a75f109f1bc3ef55eacb2bf8f3ad4e4f74fbe7fd2b92ee448082b15292f", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "de2bff6b876d38a20c944b9ef1ca296061e6882080316cb6ad4f346b3f25543d", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "1e7803d70fd4965da58e0949f1de2ed9624852b48a6afc43fa7f007940e1ad61", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "cff451b8636469879061f9d0a2e2403d3bece99ea61e4ce8992095dcc5d57429", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "42654d72fc9816827ee0e0fba553f672eeacf7af2f828dcced42b3603ea7b244", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "d8b40b941b95d888af07649aece54b51fe419f129957a3c1ea00bb707092fba9", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "9e168ccc151b0320feac61a46f69e5287ebe61d5cda4fd096c2a6e4c1bc4630e", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "1fa18c0e9d352188505f1dcf21b132863cf531f3a5d1cec512baaa135dae071b", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-none.tar.gz": "221da3b26cafafb2f1db1bcb69529424df021e149983ddd07cae15f9e7bd3b05", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-none.tar.xz": "401b277ab48e8b5dd30da993a68b2318b9f5c3f6a1cd69c244dfa62212b77dc1", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-redox.tar.gz": "0a67ac955769e71b677af6647233bea61f2bc61db0eda5b3a2d70fe52c094806", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-redox.tar.xz": "96d52cf2a502adbb3cc37f1c46fba79ec7dc2ffdfaa369e58ba60a2e9b7a6efb", + "dist/2022-06-29/rustc-beta-aarch64-apple-darwin.tar.gz": "13c5bf14af21282b302efc63285b2c683f24853d510319aa43d150fd127255d1", + "dist/2022-06-29/rustc-beta-aarch64-apple-darwin.tar.xz": "3afc8778d32d04b8137552ca651237b5573149bfb7c4b3797e73746af8636612", + "dist/2022-06-29/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "84f95488f8540020efc1f59d3112805b7b16517fcf0e991fac45757f7f88d09b", + "dist/2022-06-29/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "818479235bdc06809c89728ba7c449f2187c159aeb45ffce62250a1e40202921", + "dist/2022-06-29/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "1a8acf7bd5d81b0cce741669aa76170c595525bfd981f327199a014d8f96cf29", + "dist/2022-06-29/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "eaecede917a4994772b1043c42c1a0a88bbf0efe5b9830e5be4fa039c13152a6", + "dist/2022-06-29/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "f38e0aefff50338ec442a8a915aef83bb89a445c2535840a74cc1cd3ccd0ec1a", + "dist/2022-06-29/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "f4c7ff3f19303bf82b0a7e3adff2f1d76be75487b78a53a23b5a564567c418b8", + "dist/2022-06-29/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "473936c8d1c6fb7de9da593185d6d3dcf32b3cd833e9a7b96a721ce6ad587628", + "dist/2022-06-29/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "72787fe6ae27c684c166acf178556ff570a923db89b5e4576b97b528b991b6db", + "dist/2022-06-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "f641842f5b298ba11d7143d4e24f03b8adf20363e25c459a9b98e9903fd48a16", + "dist/2022-06-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "3ef2c162e55a62024e4cbb079f03a38d40529d864ce4f8d28c12843b38568802", + "dist/2022-06-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "e3e714078092863a7cd3a6d9c8b8d8a8c05da97debff0545f45593163bd51e4e", + "dist/2022-06-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "dc9ae664ffa5b61d576182ddb79234331e1227302fe9cd6db0926011522582c8", + "dist/2022-06-29/rustc-beta-i686-pc-windows-gnu.tar.gz": "9bc6578d355c1fee74e8104331cdad4f3c9c94bf1713e989de5d52c1f5291528", + "dist/2022-06-29/rustc-beta-i686-pc-windows-gnu.tar.xz": "412a2ee2a94ecec20c1c54934b72d84b46e29f35f6520b8e654ef518b9a7e511", + "dist/2022-06-29/rustc-beta-i686-pc-windows-msvc.tar.gz": "f8fc7fbcd82398964ec562f0750f33fa1af55268e053d416d0729b466fc7fb3f", + "dist/2022-06-29/rustc-beta-i686-pc-windows-msvc.tar.xz": "eaa66c5680987aaea99d7cd38a5245c832698f4a53443eeeb06880a8ec915497", + "dist/2022-06-29/rustc-beta-i686-unknown-linux-gnu.tar.gz": "8748755c8c72ede71310f998c38ea0ba80e2065da5f53f8ac61bfe8e4c94ea1a", + "dist/2022-06-29/rustc-beta-i686-unknown-linux-gnu.tar.xz": "fac18aa72b3c801230dd3a653bab76521618be5fe48de2f79dc1890dacbc7a9c", + "dist/2022-06-29/rustc-beta-mips-unknown-linux-gnu.tar.gz": "e22c7209d77b1fdce3439225c2e7d659a61cdaced9387fccaef5370cb25baef1", + "dist/2022-06-29/rustc-beta-mips-unknown-linux-gnu.tar.xz": "cea1aa2447e02cc6a4be215f0bb4b658560f641389e314c0cc6814c2e1cb5c18", + "dist/2022-06-29/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "e57c23dd8981d77b81b27af2879c4a2bf9e6619b5a638d8ba9dac790bf9316a0", + "dist/2022-06-29/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "0dafb1d812358f5275ff272d247573ac0799dac64a446f7ad08543d6f4334088", + "dist/2022-06-29/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "bf6be111afb4ea7ecdbc611e94aedce8e5ebf255f1e52cc61da65913a6963471", + "dist/2022-06-29/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "7d169795f5ef7c09b7e3a9b40d8669c0b2fc6449247551b426286ebe3f6e258f", + "dist/2022-06-29/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "0e76f229b0dbeb14497cfda0f4d717c369b8bc59c7bce1fbad059220562c0814", + "dist/2022-06-29/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "d6870a46ab49264498b18a4cd2d2400f0df8b02514e92c1bd6396c732f869035", + "dist/2022-06-29/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "547269aa65cbfe33ef5457ac969399fcf90384f57523a91e9c61306fb9e464da", + "dist/2022-06-29/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "fe75b0ae3a9338f1e48e72e6d6f51edba25f5fd7ab0544d3feae6b69105f160c", + "dist/2022-06-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "b445b6ec414be5c580a19717125858ed4c8e0c90828e085f2ab47a3b44a0863e", + "dist/2022-06-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "a915c1da4a45cd286c0b8978999d5ef2ab96b24185793ee1dc043e094cf6c51c", + "dist/2022-06-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "72b6014c14f12f5e5848924e20342d993903d16e883ea8473ca8cf9d188f68d5", + "dist/2022-06-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "ee707cf657c9991eca8a9b722fb58b420b2c9fe9bc9e32c4042a4af2bc37e8cb", + "dist/2022-06-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "8e1fc4091115f93f13d88dd7a9b05492ffbcf72f12fc8bdeac28dd6f3c78c3ac", + "dist/2022-06-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "ae52c2a0c43871c658d63c101a192dd5fea65931e0d45855bd8dd40a58a7e688", + "dist/2022-06-29/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "fe45b4d1d509a7a0c317888b575d3dcf1dfb7c0b8306ec54e2d09245c906e276", + "dist/2022-06-29/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "0c06412d27669429ff1c0e5855c3a3ac923b40a93b2fdcb8fbccb4033476b5d1", + "dist/2022-06-29/rustc-beta-x86_64-apple-darwin.tar.gz": "a3c33e87a6b12049fcd7cbb0f53ea74c8411c91c262b6f352a1024221d3457c4", + "dist/2022-06-29/rustc-beta-x86_64-apple-darwin.tar.xz": "3256ad9fdca2506b06962b4e88c9a41daa8f094a5c1c80530fbce4dbdd6e1c32", + "dist/2022-06-29/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "e2881ef537ec43fc012307cdac5291e4733b322e92a3b056a6f2820c883653b8", + "dist/2022-06-29/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "5a8a36ca5f01ffc8a2dff21c6fbf99652444c6d3731c650fb91cce1fe79c3ebc", + "dist/2022-06-29/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "6ee9a6511fc5342b4f07102f874822553c928ed75f09c4e34952db1c248604f1", + "dist/2022-06-29/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "830d24aff7aac91a61143878969632a47eb8392c539fabdd25826792c7125509", + "dist/2022-06-29/rustc-beta-x86_64-unknown-freebsd.tar.gz": "1fb6dc34083e95e193c39bfb4edca99f42713f5cfe3bda8e368e977f61c82110", + "dist/2022-06-29/rustc-beta-x86_64-unknown-freebsd.tar.xz": "c3b9ba1586bb6152596aeb01997b40ab65ab7140525b1b0bc22f2a84baf5c44b", + "dist/2022-06-29/rustc-beta-x86_64-unknown-illumos.tar.gz": "584b8ee47755982a6b0f0d0d5a12af35ad740e2df8b1ec1d3084509ea940c2b6", + "dist/2022-06-29/rustc-beta-x86_64-unknown-illumos.tar.xz": "a4532b97743b8a90f4f492513c7cd51600426c08454be2e24a49cf867ca0e30b", + "dist/2022-06-29/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "f3fb7f949724bf9b8b77cc562d9d53eb067872bc312ceeb2b5541c6667f70da2", + "dist/2022-06-29/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "10912b2783699d9e155b4f59dd762fe012e4ea4410b56d83b36d1df769a8cd49", + "dist/2022-06-29/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "f548bad660bce1513081be0767305a523fd129a0b13aa368e8c86a36d1ec3b23", + "dist/2022-06-29/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "fd52405c614d6932d9e5948e851be7315f1f9d21bbfc3e6d142d6d3196464fe7", + "dist/2022-06-29/rustc-beta-x86_64-unknown-netbsd.tar.gz": "1b816d0bf6d4138bd557094f922e7aa9b2e7d0ea27464cadbb117eac8a42f3fc", + "dist/2022-06-29/rustc-beta-x86_64-unknown-netbsd.tar.xz": "b869ba4ab920cd08bd063cedba08614d5c6199f643d277d59f44af513925c16b", + "dist/2022-06-29/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "3ac81b63371115875eec194eb4d0c3e9aeb624c7f7ce3ee85b197b8e3f1cd599", + "dist/2022-06-29/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "8eda09837e39a0847b79803645f810d87be7208465deb7f5b0952fa7e39c2113", + "dist/2022-06-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "353d2f523a3a1bc2ca478b6facea40363d2d18ca6b48d8f4be18626c7cdb3142", + "dist/2022-06-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "ade013031c8c72eae5717c248cb20f36107d326c497b4f3c8e90dc2912d11975", + "dist/2022-06-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "64b5f8f97781bd4eca5554f28688a58831162fafaebac31b0f04610e16f09a48", + "dist/2022-06-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "feb458ae9a30773519b8be69557d0bd4c3d924aa22eb4a4fdf331e0d620f1e90", + "dist/2022-06-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "cb2698b870f2c56554996f2e651ae53b11241c06da6ebab4b40a460f6826d91f", + "dist/2022-06-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "b0be127f8c04dc4ac2d77b2f9ec7e74a793b65bcd591c0c6a7208b1f4b445df3", + "dist/2022-06-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "596b02cf564a03c69a29f61ca6bba4758152d64775eff62b767bf77cce3b00bf", + "dist/2022-06-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "f819a48640599ea06bcc4a3f3630bd0a12c9e698cf8f62f61b36813830a54d55", + "dist/2022-06-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "19df36c566a4cf5d440011a1c0e94a4cc70e5b66e29b36a268872d4e2def8e78", + "dist/2022-06-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "dade13d688c6ba9b291b403d4d61bfd8973d3284b9bc7a92ed6de47665411f07", + "dist/2022-06-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "5ba3a696872e02cb2a4b2e191262d61ecbe6f289345373ee06c542a2d2580527", + "dist/2022-06-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "8ff08027f040bdf0de0496d6a408796fcca44540b097414255f776704e6f4966", + "dist/2022-06-29/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "15a36d3a798d2fa027d05229ab42baa4cadb6faa8edfd8c13260ea4756031194", + "dist/2022-06-29/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "438ea44472607752d205d9d2f14056a4c66fd9a84f728110792aadd22929b9fd", + "dist/2022-06-29/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "734aa5ce2105134c34301e44f7d8f0ea3bc94587df3e27793530f3a722eb9b26", + "dist/2022-06-29/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "02a7401369a03caec796deb2d3a0b3c1a46bad79bbe6e654d9e721cd95bfcb0a", + "dist/2022-06-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "17a8c573eaaf5033b15ef14ff221848e3100332b6f01b30b249c9e854bcc21d9", + "dist/2022-06-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "bca6959f1e6977cccd0571bc61a37928f559eee8e10395d7eb033cec9a8e0dae", + "dist/2022-06-29/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "6a4cd4b13e877b7f8ba712cab0e804edefd432d78cd46970bd44384ce94e7faa", + "dist/2022-06-29/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "43adf44181bee2b295584c36c35041ff97465fa3fe46b358e142a1d10c224a40", + "dist/2022-06-29/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "376abf3aa462c0e1271044761af0c9f3c63442731c6d04accd32a0ca0221eee6", + "dist/2022-06-29/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "f8a5f3d01e06f46a6d85fa7f74b1a494fcb55a6d5dc8113eb96d6a46d0d37050", + "dist/2022-06-29/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "158573b8e9da4e8a464bd3c692e54084cd0b9097596d41c21646091883d15b48", + "dist/2022-06-29/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "bdae49f025be97fbf37c9ca7ef1f4331ec4ebf8a5fb429a4c20f09619069e655", + "dist/2022-06-29/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "6ed1ea2364c8b645c6d899cada76cf161222fae9b4693ee71fb98721409f73a8", + "dist/2022-06-29/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "beaa6383696385769cd885b3314ccb6f69a7a5557bb1af7214c2c8b2d03d64c7", + "dist/2022-06-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "0f0ad140d47b4477e9ff0a925468b36aaaca0063eed018022624ee15cd0fcd7e", + "dist/2022-06-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "23d3bcf9d9a22bd869b3857c7c8bbf25c168ab60677a958c8b48d8b04319beae", + "dist/2022-06-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "fbd1655d0399a3e8728710dc0c234ebca2ce8669fc42eadbbb075baabaee740f", + "dist/2022-06-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "1d0c70f5ec38542f2d5b125d59d93ffa1a984a7a2e2353503f8b8554604daa8a", + "dist/2022-06-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "34acce36d8aecd8f4414fae766c2ad7c7942eaa8b422075017ce28e84f08fb08", + "dist/2022-06-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "8984ea923bf93c394ca50b41f58df0d750bc522c481de2a0468afafef052f343", + "dist/2022-06-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "a9064c4ecfe40a2b3cdbabe12b6063f13680f2a6eb36d58f02fa6207af988a13", + "dist/2022-06-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "3576cfd24cb1b53d96145651810c532a5b1c424dfcc39b2c78d5688d7f0791ca", + "dist/2022-06-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "2b921dbf7f8c2931bc531665087ffa05efe8bb4270902a311789409994844cd0", + "dist/2022-06-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "f6a4134ffb2c4616606b5d9d3ba63b9dda1ec49c2c0af2290a915c08d80ef301", + "dist/2022-06-29/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "468bc3d0d587b37993cda14fbaf07ab4edc05627126d96d9ccaf58b1df55178f", + "dist/2022-06-29/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "e6262f053b2e456d09ce6617e8209e229d2b9ced144a9eff12de830b6f0cbcfe", + "dist/2022-06-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "34a9cf74d9076c49c6266d718fad9a78ea1ede268f9b7978b508b76a4c6e3f8c", + "dist/2022-06-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "3d0e544dbb280e4cafebc05dcc68b3cda8a742f9909f59de93c8791721c3f2c8", + "dist/2022-06-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "d7119b250b1b31fcba6b3d34cb8deafa32fe20f547ad1bc1e931c58e7059f65f", + "dist/2022-06-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "ebc31e9118112e64fced1ad94e4e903e7ac0ff8dd771d85a55c1589a6b838c38", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "a940ea208faa9882808cc56a8e96cadf79f954844ede160b2b8971238bc84f4a", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "e699ef1a7a7f5e4bd40cbb3daff754e9214cbe71c28b1436a893a5edbca8c876", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "2a53b4b5e57fd9e1d9014d46576e6b47b51d0dbaaf55c4e84964390c2b2065cf", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "e4491027e20ac563ea8a0906d8941f80274890d4d1b4b3728e26e5926f2c77cf", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "b7ba70b0ca5ece6b14cb1034e7226a83435f8b71c77a864b4ad949db11ab75b1", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "ce07cc2010a424e83672095d89b4592485a7c94a3f450e609ed62237c86909ca", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "bd653ae8f104872e5a2f937fabdff09d41691c28d512fb7f08562fb21ab64e89", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "d374ef3fcfaf21c13813cab8953c42c9c965c02549d18e95fca903b923ef5e6b", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "f0fe5175ea73034b1b789db8d31214ca561af0f4be21c52895b47baf103e5952", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "6bc6231ebba38ec47fc1de646aa7d8a9855d2dbfb61595fad299656e39acd0d5" } } diff --git a/src/test/assembly/static-relocation-model.rs b/src/test/assembly/static-relocation-model.rs index faa2e3952096d..6c41e0b78f137 100644 --- a/src/test/assembly/static-relocation-model.rs +++ b/src/test/assembly/static-relocation-model.rs @@ -36,8 +36,7 @@ extern "C" { } // CHECK-LABEL: banana: -// On the next line LLVM 14 produces a `movb`, whereas LLVM 15+ produces a `movzbl`. -// x64: {{movb|movzbl}} chaenomeles{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}} +// x64: movb chaenomeles{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}} // A64: adrp [[REG:[a-z0-9]+]], chaenomeles // A64-NEXT: ldrb {{[a-z0-9]+}}, {{\[}}[[REG]], :lo12:chaenomeles] #[no_mangle] @@ -48,7 +47,7 @@ pub fn banana() -> u8 { } // CHECK-LABEL: peach: -// x64: {{movb|movzbl}} banana{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}} +// x64: movb banana{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}} // A64: adrp [[REG2:[a-z0-9]+]], banana // A64-NEXT: ldrb {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:banana] #[no_mangle] @@ -60,7 +59,7 @@ pub fn peach() -> u8 { // CHECK-LABEL: mango: // x64: movq EXOCHORDA{{(\(%[a-z0-9]+\))?}}, %[[REG:[a-z0-9]+]] -// x64-NEXT: {{movb|movzbl}} (%[[REG]]), %{{[a-z0-9]+}} +// x64-NEXT: movb (%[[REG]]), %{{[a-z0-9]+}} // A64: adrp [[REG2:[a-z0-9]+]], EXOCHORDA // A64-NEXT: ldr {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:EXOCHORDA] #[no_mangle] diff --git a/src/test/codegen/atomic-operations-llvm-12.rs b/src/test/codegen/atomic-operations-llvm-12.rs deleted file mode 100644 index bd4c63dcff1d7..0000000000000 --- a/src/test/codegen/atomic-operations-llvm-12.rs +++ /dev/null @@ -1,84 +0,0 @@ -// Code generation of atomic operations for LLVM 12 -// ignore-llvm-version: 13 - 99 -// compile-flags: -O -#![crate_type = "lib"] - -use std::sync::atomic::{AtomicI32, Ordering::*}; - -// CHECK-LABEL: @compare_exchange -#[no_mangle] -pub fn compare_exchange(a: &AtomicI32) { - // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 10 monotonic monotonic - // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 11 acquire acquire - // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 12 seq_cst seq_cst - let _ = a.compare_exchange(0, 10, Relaxed, Relaxed); - let _ = a.compare_exchange(0, 11, Relaxed, Acquire); - let _ = a.compare_exchange(0, 12, Relaxed, SeqCst); - - // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 20 release monotonic - // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 21 acq_rel acquire - // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 22 seq_cst seq_cst - let _ = a.compare_exchange(0, 20, Release, Relaxed); - let _ = a.compare_exchange(0, 21, Release, Acquire); - let _ = a.compare_exchange(0, 22, Release, SeqCst); - - // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 30 acquire monotonic - // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 31 acquire acquire - // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 32 seq_cst seq_cst - let _ = a.compare_exchange(0, 30, Acquire, Relaxed); - let _ = a.compare_exchange(0, 31, Acquire, Acquire); - let _ = a.compare_exchange(0, 32, Acquire, SeqCst); - - // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 40 acq_rel monotonic - // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 41 acq_rel acquire - // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 42 seq_cst seq_cst - let _ = a.compare_exchange(0, 40, AcqRel, Relaxed); - let _ = a.compare_exchange(0, 41, AcqRel, Acquire); - let _ = a.compare_exchange(0, 42, AcqRel, SeqCst); - - // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 50 seq_cst monotonic - // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 51 seq_cst acquire - // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 52 seq_cst seq_cst - let _ = a.compare_exchange(0, 50, SeqCst, Relaxed); - let _ = a.compare_exchange(0, 51, SeqCst, Acquire); - let _ = a.compare_exchange(0, 52, SeqCst, SeqCst); -} - -// CHECK-LABEL: @compare_exchange_weak -#[no_mangle] -pub fn compare_exchange_weak(w: &AtomicI32) { - // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 10 monotonic monotonic - // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 11 acquire acquire - // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 12 seq_cst seq_cst - let _ = w.compare_exchange_weak(1, 10, Relaxed, Relaxed); - let _ = w.compare_exchange_weak(1, 11, Relaxed, Acquire); - let _ = w.compare_exchange_weak(1, 12, Relaxed, SeqCst); - - // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 20 release monotonic - // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 21 acq_rel acquire - // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 22 seq_cst seq_cst - let _ = w.compare_exchange_weak(1, 20, Release, Relaxed); - let _ = w.compare_exchange_weak(1, 21, Release, Acquire); - let _ = w.compare_exchange_weak(1, 22, Release, SeqCst); - - // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 30 acquire monotonic - // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 31 acquire acquire - // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 32 seq_cst seq_cst - let _ = w.compare_exchange_weak(1, 30, Acquire, Relaxed); - let _ = w.compare_exchange_weak(1, 31, Acquire, Acquire); - let _ = w.compare_exchange_weak(1, 32, Acquire, SeqCst); - - // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 40 acq_rel monotonic - // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 41 acq_rel acquire - // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 42 seq_cst seq_cst - let _ = w.compare_exchange_weak(1, 40, AcqRel, Relaxed); - let _ = w.compare_exchange_weak(1, 41, AcqRel, Acquire); - let _ = w.compare_exchange_weak(1, 42, AcqRel, SeqCst); - - // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 50 seq_cst monotonic - // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 51 seq_cst acquire - // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 52 seq_cst seq_cst - let _ = w.compare_exchange_weak(1, 50, SeqCst, Relaxed); - let _ = w.compare_exchange_weak(1, 51, SeqCst, Acquire); - let _ = w.compare_exchange_weak(1, 52, SeqCst, SeqCst); -} diff --git a/src/test/codegen/atomic-operations.rs b/src/test/codegen/atomic-operations.rs index 771cf58725aaa..a14f63726bb9a 100644 --- a/src/test/codegen/atomic-operations.rs +++ b/src/test/codegen/atomic-operations.rs @@ -1,5 +1,5 @@ // Code generation of atomic operations. -// min-llvm-version: 13.0 +// // compile-flags: -O #![crate_type = "lib"] @@ -9,32 +9,20 @@ use std::sync::atomic::{AtomicI32, Ordering::*}; #[no_mangle] pub fn compare_exchange(a: &AtomicI32) { // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 10 monotonic monotonic - // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 11 monotonic acquire - // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 12 monotonic seq_cst let _ = a.compare_exchange(0, 10, Relaxed, Relaxed); - let _ = a.compare_exchange(0, 11, Relaxed, Acquire); - let _ = a.compare_exchange(0, 12, Relaxed, SeqCst); // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 20 release monotonic - // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 21 release acquire - // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 22 release seq_cst let _ = a.compare_exchange(0, 20, Release, Relaxed); - let _ = a.compare_exchange(0, 21, Release, Acquire); - let _ = a.compare_exchange(0, 22, Release, SeqCst); // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 30 acquire monotonic // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 31 acquire acquire - // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 32 acquire seq_cst let _ = a.compare_exchange(0, 30, Acquire, Relaxed); let _ = a.compare_exchange(0, 31, Acquire, Acquire); - let _ = a.compare_exchange(0, 32, Acquire, SeqCst); // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 40 acq_rel monotonic // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 41 acq_rel acquire - // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 42 acq_rel seq_cst let _ = a.compare_exchange(0, 40, AcqRel, Relaxed); let _ = a.compare_exchange(0, 41, AcqRel, Acquire); - let _ = a.compare_exchange(0, 42, AcqRel, SeqCst); // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 50 seq_cst monotonic // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 51 seq_cst acquire @@ -48,32 +36,20 @@ pub fn compare_exchange(a: &AtomicI32) { #[no_mangle] pub fn compare_exchange_weak(w: &AtomicI32) { // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 10 monotonic monotonic - // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 11 monotonic acquire - // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 12 monotonic seq_cst let _ = w.compare_exchange_weak(1, 10, Relaxed, Relaxed); - let _ = w.compare_exchange_weak(1, 11, Relaxed, Acquire); - let _ = w.compare_exchange_weak(1, 12, Relaxed, SeqCst); // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 20 release monotonic - // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 21 release acquire - // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 22 release seq_cst let _ = w.compare_exchange_weak(1, 20, Release, Relaxed); - let _ = w.compare_exchange_weak(1, 21, Release, Acquire); - let _ = w.compare_exchange_weak(1, 22, Release, SeqCst); // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 30 acquire monotonic // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 31 acquire acquire - // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 32 acquire seq_cst let _ = w.compare_exchange_weak(1, 30, Acquire, Relaxed); let _ = w.compare_exchange_weak(1, 31, Acquire, Acquire); - let _ = w.compare_exchange_weak(1, 32, Acquire, SeqCst); // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 40 acq_rel monotonic // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 41 acq_rel acquire - // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 42 acq_rel seq_cst let _ = w.compare_exchange_weak(1, 40, AcqRel, Relaxed); let _ = w.compare_exchange_weak(1, 41, AcqRel, Acquire); - let _ = w.compare_exchange_weak(1, 42, AcqRel, SeqCst); // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 50 seq_cst monotonic // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 51 seq_cst acquire diff --git a/src/test/codegen/box-maybe-uninit-llvm14.rs b/src/test/codegen/box-maybe-uninit-llvm14.rs deleted file mode 100644 index bd1a6599c3365..0000000000000 --- a/src/test/codegen/box-maybe-uninit-llvm14.rs +++ /dev/null @@ -1,26 +0,0 @@ -// compile-flags: -O - -// Once we're done with llvm 14 and earlier, this test can be deleted. - -#![crate_type="lib"] - -use std::mem::MaybeUninit; - -// Boxing a `MaybeUninit` value should not copy junk from the stack -#[no_mangle] -pub fn box_uninitialized() -> Box> { - // CHECK-LABEL: @box_uninitialized - // CHECK-NOT: store - // CHECK-NOT: alloca - // CHECK-NOT: memcpy - // CHECK-NOT: memset - Box::new(MaybeUninit::uninit()) -} - -// FIXME: add a test for a bigger box. Currently broken, see -// https://github.com/rust-lang/rust/issues/58201. - -// Hide the LLVM 15+ `allocalign` attribute in the declaration of __rust_alloc -// from the CHECK-NOT above. We don't check the attributes here because we can't rely -// on all of them being set until LLVM 15. -// CHECK: declare noalias{{.*}} @__rust_alloc(i{{[0-9]+}}, i{{[0-9]+.*}}) diff --git a/src/test/codegen/box-maybe-uninit.rs b/src/test/codegen/box-maybe-uninit.rs index e105e26f16a23..5004f787cde19 100644 --- a/src/test/codegen/box-maybe-uninit.rs +++ b/src/test/codegen/box-maybe-uninit.rs @@ -1,5 +1,4 @@ // compile-flags: -O -// min-llvm-version: 15.0 #![crate_type="lib"] use std::mem::MaybeUninit; @@ -17,9 +16,3 @@ pub fn box_uninitialized() -> Box> { // FIXME: add a test for a bigger box. Currently broken, see // https://github.com/rust-lang/rust/issues/58201. - -// Hide the `allocalign` attribute in the declaration of __rust_alloc -// from the CHECK-NOT above, and also verify the attributes got set reasonably. -// CHECK: declare noalias ptr @__rust_alloc(i{{[0-9]+}}, i{{[0-9]+}} allocalign) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]] - -// CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} } diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index bc650ebf5eeb6..ae6abe7a184c6 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -5,7 +5,6 @@ use std::mem::MaybeUninit; use std::num::NonZeroU64; -use std::marker::PhantomPinned; pub struct S { _field: [i32; 8], @@ -15,11 +14,6 @@ pub struct UnsafeInner { _field: std::cell::UnsafeCell, } -pub struct NotUnpin { - _field: i32, - _marker: PhantomPinned, -} - pub enum MyBool { True, False, @@ -97,7 +91,7 @@ pub fn static_borrow(_: &'static i32) { pub fn named_borrow<'r>(_: &'r i32) { } -// CHECK: @unsafe_borrow({{i16\*|ptr}} noundef nonnull align 2 %_1) +// CHECK: @unsafe_borrow({{i16\*|ptr}} noundef align 2 dereferenceable(2) %_1) // unsafe interior means this isn't actually readonly and there may be aliases ... #[no_mangle] pub fn unsafe_borrow(_: &UnsafeInner) { @@ -115,18 +109,6 @@ pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) { pub fn mutable_borrow(_: &mut i32) { } -#[no_mangle] -// CHECK: @mutable_notunpin_borrow({{i32\*|ptr}} noundef align 4 dereferenceable(4) %_1) -// This one is *not* `noalias` because it might be self-referential. -pub fn mutable_notunpin_borrow(_: &mut NotUnpin) { -} - -// CHECK: @notunpin_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1) -// But `&NotUnpin` behaves perfectly normal. -#[no_mangle] -pub fn notunpin_borrow(_: &NotUnpin) { -} - // CHECK: @indirect_struct({{%S\*|ptr}} noalias nocapture noundef dereferenceable(32) %_1) #[no_mangle] pub fn indirect_struct(_: S) { @@ -233,3 +215,10 @@ pub fn enum_id_1(x: Option>) -> Option> { pub fn enum_id_2(x: Option) -> Option { x } + +// CHECK: noalias {{i8\*|ptr}} @allocator() +#[no_mangle] +#[rustc_allocator] +pub fn allocator() -> *const i8 { + std::ptr::null() +} diff --git a/src/test/codegen/repr-transparent-aggregates-2.rs b/src/test/codegen/repr-transparent-aggregates-2.rs index df7e88f08c733..b68e8e9ebe9b4 100644 --- a/src/test/codegen/repr-transparent-aggregates-2.rs +++ b/src/test/codegen/repr-transparent-aggregates-2.rs @@ -37,19 +37,19 @@ pub enum TeBigS { Variant(BigS), } -// CHECK: define void @test_BigS({{%BigS\*|ptr}} [[BIGS_RET_ATTRS1:.*]] sret(%BigS) [[BIGS_RET_ATTRS2:.*]], [16 x i32] +// CHECK: define void @test_BigS(%BigS* [[BIGS_RET_ATTRS1:.*]] sret(%BigS) [[BIGS_RET_ATTRS2:.*]], [16 x i32] #[no_mangle] pub extern fn test_BigS(_: BigS) -> BigS { loop {} } -// CHECK: define void @test_TsBigS({{%TsBigS\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%TsBigS) [[BIGS_RET_ATTRS2]], [16 x i32] +// CHECK: define void @test_TsBigS(%TsBigS* [[BIGS_RET_ATTRS1]] sret(%TsBigS) [[BIGS_RET_ATTRS2]], [16 x i32] #[no_mangle] pub extern fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} } -// CHECK: define void @test_TuBigS({{%TuBigS\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%TuBigS) [[BIGS_RET_ATTRS2]], [16 x i32] +// CHECK: define void @test_TuBigS(%TuBigS* [[BIGS_RET_ATTRS1]] sret(%TuBigS) [[BIGS_RET_ATTRS2]], [16 x i32] #[no_mangle] pub extern fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} } -// CHECK: define void @test_TeBigS({{%"TeBigS::Variant"\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%"TeBigS::Variant") [[BIGS_RET_ATTRS2]], [16 x i32] +// CHECK: define void @test_TeBigS(%"TeBigS::Variant"* [[BIGS_RET_ATTRS1]] sret(%"TeBigS::Variant") [[BIGS_RET_ATTRS2]], [16 x i32] #[no_mangle] pub extern fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} } @@ -73,18 +73,18 @@ pub enum TeBigU { Variant(BigU), } -// CHECK: define void @test_BigU({{%BigU\*|ptr}} [[BIGU_RET_ATTRS1:.*]] sret(%BigU) [[BIGU_RET_ATTRS2:.*]], [16 x i32] +// CHECK: define void @test_BigU(%BigU* [[BIGU_RET_ATTRS1:.*]] sret(%BigU) [[BIGU_RET_ATTRS2:.*]], [16 x i32] #[no_mangle] pub extern fn test_BigU(_: BigU) -> BigU { loop {} } -// CHECK: define void @test_TsBigU({{%TsBigU\*|ptr}} [[BIGU_RET_ATTRS1]] sret(%TsBigU) [[BIGU_RET_ATTRS2]], [16 x i32] +// CHECK: define void @test_TsBigU(%TsBigU* [[BIGU_RET_ATTRS1]] sret(%TsBigU) [[BIGU_RET_ATTRS2]], [16 x i32] #[no_mangle] pub extern fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} } -// CHECK: define void @test_TuBigU({{%TuBigU\*|ptr}} [[BIGU_RET_ATTRS1]] sret(%TuBigU) [[BIGU_RET_ATTRS2]], [16 x i32] +// CHECK: define void @test_TuBigU(%TuBigU* [[BIGU_RET_ATTRS1]] sret(%TuBigU) [[BIGU_RET_ATTRS2]], [16 x i32] #[no_mangle] pub extern fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} } -// CHECK: define void @test_TeBigU({{%"TeBigU::Variant"\*|ptr}} [[BIGU_RET_ATTRS1]] sret(%"TeBigU::Variant") [[BIGU_RET_ATTRS2]], [16 x i32] +// CHECK: define void @test_TeBigU(%"TeBigU::Variant"* [[BIGU_RET_ATTRS1]] sret(%"TeBigU::Variant") [[BIGU_RET_ATTRS2]], [16 x i32] #[no_mangle] pub extern fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} } diff --git a/src/test/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs b/src/test/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs deleted file mode 100644 index ece2adbdf4325..0000000000000 --- a/src/test/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs +++ /dev/null @@ -1,575 +0,0 @@ -// Verifies that type metadata identifiers for functions are emitted correctly. -// -// needs-sanitizer-cfi -// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi - -#![crate_type="lib"] -#![allow(dead_code)] -#![allow(incomplete_features)] -#![allow(unused_must_use)] -#![feature(adt_const_params, extern_types, inline_const, type_alias_impl_trait)] - -extern crate core; -use core::ffi::c_void; -use std::marker::PhantomData; - -// User-defined type (structure) -pub struct Struct1 { - member1: T, -} - -// User-defined type (enum) -pub enum Enum1 { - Variant1(T), -} - -// User-defined type (union) -pub union Union1 { - member1: std::mem::ManuallyDrop, -} - -// Extern type -extern { - pub type type1; -} - -// Trait -pub trait Trait1 { - fn foo(&self) { } -} - -// Trait implementation -impl Trait1 for i32 { - fn foo(&self) { } -} - -// Trait implementation -impl Trait1 for Struct1 { - fn foo(&self) { } -} - -// impl Trait type aliases for helping with defining other types (see below) -pub type Type1 = impl Send; -pub type Type2 = impl Send; -pub type Type3 = impl Send; -pub type Type4 = impl Send; -pub type Type5 = impl Send; -pub type Type6 = impl Send; -pub type Type7 = impl Send; -pub type Type8 = impl Send; -pub type Type9 = impl Send; -pub type Type10 = impl Send; -pub type Type11 = impl Send; - -pub fn fn1<'a>() { - // Closure - let closure1 = || { }; - let _: Type1 = closure1; - - // Constructor - pub struct Foo(i32); - let _: Type2 = Foo; - - // Type in extern path - extern { - fn foo(); - } - let _: Type3 = foo; - - // Type in closure path - || { - pub struct Foo; - let _: Type4 = Foo; - }; - - // Type in const path - const { - pub struct Foo; - fn foo() -> Type5 { Foo } - }; - - // Type in impl path - impl Struct1 { - fn foo(&self) { } - } - let _: Type6 = >::foo; - - // Trait method - let _: Type7 = >::foo; - - // Trait method - let _: Type8 = >::foo; - - // Trait method - let _: Type9 = as Trait1>::foo; - - // Const generics - pub struct Qux([T; N]); - let _: Type10 = Qux([0; 32]); - - // Lifetimes/regions - pub struct Quux<'a>(&'a i32); - pub struct Quuux<'a, 'b>(&'a i32, &'b Quux<'b>); - let _: Type11 = Quuux; -} - -// repr(transparent) user-defined type -struct Foo(i32); - -#[repr(transparent)] -pub struct Type12 { - member1: (), - member2: PhantomData, - member3: Foo, -} - -// Self-referencing repr(transparent) user-defined type -#[repr(transparent)] -pub struct Type13<'a> { - member1: (), - member2: PhantomData, - member3: &'a Type13<'a>, -} - -pub fn foo0(_: ()) { } -// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] -pub fn foo1(_: c_void, _: ()) { } -// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] -pub fn foo2(_: (), _: c_void, _: c_void) { } -// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] -pub fn foo3(_: *mut c_void) { } -// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] -pub fn foo4(_: *mut c_void, _: *mut ()) { } -// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] -pub fn foo5(_: *mut (), _: *mut c_void, _: *mut c_void) { } -// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] -pub fn foo6(_: *const c_void) { } -// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] -pub fn foo7(_: *const c_void, _: *const ()) { } -// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] -pub fn foo8(_: *const (), _: *const c_void, _: *const c_void) { } -// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] -pub fn foo9(_: bool) { } -// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] -pub fn foo10(_: bool, _: bool) { } -// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] -pub fn foo11(_: bool, _: bool, _: bool) { } -// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] -pub fn foo12(_: i8) { } -// CHECK: define{{.*}}foo12{{.*}}!type ![[TYPE12:[0-9]+]] -pub fn foo13(_: i8, _: i8) { } -// CHECK: define{{.*}}foo13{{.*}}!type ![[TYPE13:[0-9]+]] -pub fn foo14(_: i8, _: i8, _: i8) { } -// CHECK: define{{.*}}foo14{{.*}}!type ![[TYPE14:[0-9]+]] -pub fn foo15(_: i16) { } -// CHECK: define{{.*}}foo15{{.*}}!type ![[TYPE15:[0-9]+]] -pub fn foo16(_: i16, _: i16) { } -// CHECK: define{{.*}}foo16{{.*}}!type ![[TYPE16:[0-9]+]] -pub fn foo17(_: i16, _: i16, _: i16) { } -// CHECK: define{{.*}}foo17{{.*}}!type ![[TYPE17:[0-9]+]] -pub fn foo18(_: i32) { } -// CHECK: define{{.*}}foo18{{.*}}!type ![[TYPE18:[0-9]+]] -pub fn foo19(_: i32, _: i32) { } -// CHECK: define{{.*}}foo19{{.*}}!type ![[TYPE19:[0-9]+]] -pub fn foo20(_: i32, _: i32, _: i32) { } -// CHECK: define{{.*}}foo20{{.*}}!type ![[TYPE20:[0-9]+]] -pub fn foo21(_: i64) { } -// CHECK: define{{.*}}foo21{{.*}}!type ![[TYPE21:[0-9]+]] -pub fn foo22(_: i64, _: i64) { } -// CHECK: define{{.*}}foo22{{.*}}!type ![[TYPE22:[0-9]+]] -pub fn foo23(_: i64, _: i64, _: i64) { } -// CHECK: define{{.*}}foo23{{.*}}!type ![[TYPE23:[0-9]+]] -pub fn foo24(_: i128) { } -// CHECK: define{{.*}}foo24{{.*}}!type ![[TYPE24:[0-9]+]] -pub fn foo25(_: i128, _: i128) { } -// CHECK: define{{.*}}foo25{{.*}}!type ![[TYPE25:[0-9]+]] -pub fn foo26(_: i128, _: i128, _: i128) { } -// CHECK: define{{.*}}foo26{{.*}}!type ![[TYPE26:[0-9]+]] -pub fn foo27(_: isize) { } -// CHECK: define{{.*}}foo27{{.*}}!type ![[TYPE27:[0-9]+]] -pub fn foo28(_: isize, _: isize) { } -// CHECK: define{{.*}}foo28{{.*}}!type ![[TYPE28:[0-9]+]] -pub fn foo29(_: isize, _: isize, _: isize) { } -// CHECK: define{{.*}}foo29{{.*}}!type ![[TYPE29:[0-9]+]] -pub fn foo30(_: u8) { } -// CHECK: define{{.*}}foo30{{.*}}!type ![[TYPE30:[0-9]+]] -pub fn foo31(_: u8, _: u8) { } -// CHECK: define{{.*}}foo31{{.*}}!type ![[TYPE31:[0-9]+]] -pub fn foo32(_: u8, _: u8, _: u8) { } -// CHECK: define{{.*}}foo32{{.*}}!type ![[TYPE32:[0-9]+]] -pub fn foo33(_: u16) { } -// CHECK: define{{.*}}foo33{{.*}}!type ![[TYPE33:[0-9]+]] -pub fn foo34(_: u16, _: u16) { } -// CHECK: define{{.*}}foo34{{.*}}!type ![[TYPE34:[0-9]+]] -pub fn foo35(_: u16, _: u16, _: u16) { } -// CHECK: define{{.*}}foo35{{.*}}!type ![[TYPE35:[0-9]+]] -pub fn foo36(_: u32) { } -// CHECK: define{{.*}}foo36{{.*}}!type ![[TYPE36:[0-9]+]] -pub fn foo37(_: u32, _: u32) { } -// CHECK: define{{.*}}foo37{{.*}}!type ![[TYPE37:[0-9]+]] -pub fn foo38(_: u32, _: u32, _: u32) { } -// CHECK: define{{.*}}foo38{{.*}}!type ![[TYPE38:[0-9]+]] -pub fn foo39(_: u64) { } -// CHECK: define{{.*}}foo39{{.*}}!type ![[TYPE39:[0-9]+]] -pub fn foo40(_: u64, _: u64) { } -// CHECK: define{{.*}}foo40{{.*}}!type ![[TYPE40:[0-9]+]] -pub fn foo41(_: u64, _: u64, _: u64) { } -// CHECK: define{{.*}}foo41{{.*}}!type ![[TYPE41:[0-9]+]] -pub fn foo42(_: u128) { } -// CHECK: define{{.*}}foo42{{.*}}!type ![[TYPE42:[0-9]+]] -pub fn foo43(_: u128, _: u128) { } -// CHECK: define{{.*}}foo43{{.*}}!type ![[TYPE43:[0-9]+]] -pub fn foo44(_: u128, _: u128, _: u128) { } -// CHECK: define{{.*}}foo44{{.*}}!type ![[TYPE44:[0-9]+]] -pub fn foo45(_: usize) { } -// CHECK: define{{.*}}foo45{{.*}}!type ![[TYPE45:[0-9]+]] -pub fn foo46(_: usize, _: usize) { } -// CHECK: define{{.*}}foo46{{.*}}!type ![[TYPE46:[0-9]+]] -pub fn foo47(_: usize, _: usize, _: usize) { } -// CHECK: define{{.*}}foo47{{.*}}!type ![[TYPE47:[0-9]+]] -pub fn foo48(_: f32) { } -// CHECK: define{{.*}}foo48{{.*}}!type ![[TYPE48:[0-9]+]] -pub fn foo49(_: f32, _: f32) { } -// CHECK: define{{.*}}foo49{{.*}}!type ![[TYPE49:[0-9]+]] -pub fn foo50(_: f32, _: f32, _: f32) { } -// CHECK: define{{.*}}foo50{{.*}}!type ![[TYPE50:[0-9]+]] -pub fn foo51(_: f64) { } -// CHECK: define{{.*}}foo51{{.*}}!type ![[TYPE51:[0-9]+]] -pub fn foo52(_: f64, _: f64) { } -// CHECK: define{{.*}}foo52{{.*}}!type ![[TYPE52:[0-9]+]] -pub fn foo53(_: f64, _: f64, _: f64) { } -// CHECK: define{{.*}}foo53{{.*}}!type ![[TYPE53:[0-9]+]] -pub fn foo54(_: char) { } -// CHECK: define{{.*}}foo54{{.*}}!type ![[TYPE54:[0-9]+]] -pub fn foo55(_: char, _: char) { } -// CHECK: define{{.*}}foo55{{.*}}!type ![[TYPE55:[0-9]+]] -pub fn foo56(_: char, _: char, _: char) { } -// CHECK: define{{.*}}foo56{{.*}}!type ![[TYPE56:[0-9]+]] -pub fn foo57(_: &str) { } -// CHECK: define{{.*}}foo57{{.*}}!type ![[TYPE57:[0-9]+]] -pub fn foo58(_: &str, _: &str) { } -// CHECK: define{{.*}}foo58{{.*}}!type ![[TYPE58:[0-9]+]] -pub fn foo59(_: &str, _: &str, _: &str) { } -// CHECK: define{{.*}}foo59{{.*}}!type ![[TYPE59:[0-9]+]] -pub fn foo60(_: (i32, i32)) { } -// CHECK: define{{.*}}foo60{{.*}}!type ![[TYPE60:[0-9]+]] -pub fn foo61(_: (i32, i32), _: (i32, i32)) { } -// CHECK: define{{.*}}foo61{{.*}}!type ![[TYPE61:[0-9]+]] -pub fn foo62(_: (i32, i32), _: (i32, i32), _: (i32, i32)) { } -// CHECK: define{{.*}}foo62{{.*}}!type ![[TYPE62:[0-9]+]] -pub fn foo63(_: [i32; 32]) { } -// CHECK: define{{.*}}foo63{{.*}}!type ![[TYPE63:[0-9]+]] -pub fn foo64(_: [i32; 32], _: [i32; 32]) { } -// CHECK: define{{.*}}foo64{{.*}}!type ![[TYPE64:[0-9]+]] -pub fn foo65(_: [i32; 32], _: [i32; 32], _: [i32; 32]) { } -// CHECK: define{{.*}}foo65{{.*}}!type ![[TYPE65:[0-9]+]] -pub fn foo66(_: &[i32]) { } -// CHECK: define{{.*}}foo66{{.*}}!type ![[TYPE66:[0-9]+]] -pub fn foo67(_: &[i32], _: &[i32]) { } -// CHECK: define{{.*}}foo67{{.*}}!type ![[TYPE67:[0-9]+]] -pub fn foo68(_: &[i32], _: &[i32], _: &[i32]) { } -// CHECK: define{{.*}}foo68{{.*}}!type ![[TYPE68:[0-9]+]] -pub fn foo69(_: &Struct1::) { } -// CHECK: define{{.*}}foo69{{.*}}!type ![[TYPE69:[0-9]+]] -pub fn foo70(_: &Struct1::, _: &Struct1::) { } -// CHECK: define{{.*}}foo70{{.*}}!type ![[TYPE70:[0-9]+]] -pub fn foo71(_: &Struct1::, _: &Struct1::, _: &Struct1::) { } -// CHECK: define{{.*}}foo71{{.*}}!type ![[TYPE71:[0-9]+]] -pub fn foo72(_: &Enum1::) { } -// CHECK: define{{.*}}foo72{{.*}}!type ![[TYPE72:[0-9]+]] -pub fn foo73(_: &Enum1::, _: &Enum1::) { } -// CHECK: define{{.*}}foo73{{.*}}!type ![[TYPE73:[0-9]+]] -pub fn foo74(_: &Enum1::, _: &Enum1::, _: &Enum1::) { } -// CHECK: define{{.*}}foo74{{.*}}!type ![[TYPE74:[0-9]+]] -pub fn foo75(_: &Union1::) { } -// CHECK: define{{.*}}foo75{{.*}}!type ![[TYPE75:[0-9]+]] -pub fn foo76(_: &Union1::, _: &Union1::) { } -// CHECK: define{{.*}}foo76{{.*}}!type ![[TYPE76:[0-9]+]] -pub fn foo77(_: &Union1::, _: &Union1::, _: &Union1::) { } -// CHECK: define{{.*}}foo77{{.*}}!type ![[TYPE77:[0-9]+]] -pub fn foo78(_: *mut type1) { } -// CHECK: define{{.*}}foo78{{.*}}!type ![[TYPE78:[0-9]+]] -pub fn foo79(_: *mut type1, _: *mut type1) { } -// CHECK: define{{.*}}foo79{{.*}}!type ![[TYPE79:[0-9]+]] -pub fn foo80(_: *mut type1, _: *mut type1, _: *mut type1) { } -// CHECK: define{{.*}}foo80{{.*}}!type ![[TYPE80:[0-9]+]] -pub fn foo81(_: &mut i32) { } -// CHECK: define{{.*}}foo81{{.*}}!type ![[TYPE81:[0-9]+]] -pub fn foo82(_: &mut i32, _: &i32) { } -// CHECK: define{{.*}}foo82{{.*}}!type ![[TYPE82:[0-9]+]] -pub fn foo83(_: &mut i32, _: &i32, _: &i32) { } -// CHECK: define{{.*}}foo83{{.*}}!type ![[TYPE83:[0-9]+]] -pub fn foo84(_: &i32) { } -// CHECK: define{{.*}}foo84{{.*}}!type ![[TYPE84:[0-9]+]] -pub fn foo85(_: &i32, _: &mut i32) { } -// CHECK: define{{.*}}foo85{{.*}}!type ![[TYPE85:[0-9]+]] -pub fn foo86(_: &i32, _: &mut i32, _: &mut i32) { } -// CHECK: define{{.*}}foo86{{.*}}!type ![[TYPE86:[0-9]+]] -pub fn foo87(_: *mut i32) { } -// CHECK: define{{.*}}foo87{{.*}}!type ![[TYPE87:[0-9]+]] -pub fn foo88(_: *mut i32, _: *const i32) { } -// CHECK: define{{.*}}foo88{{.*}}!type ![[TYPE88:[0-9]+]] -pub fn foo89(_: *mut i32, _: *const i32, _: *const i32) { } -// CHECK: define{{.*}}foo89{{.*}}!type ![[TYPE89:[0-9]+]] -pub fn foo90(_: *const i32) { } -// CHECK: define{{.*}}foo90{{.*}}!type ![[TYPE90:[0-9]+]] -pub fn foo91(_: *const i32, _: *mut i32) { } -// CHECK: define{{.*}}foo91{{.*}}!type ![[TYPE91:[0-9]+]] -pub fn foo92(_: *const i32, _: *mut i32, _: *mut i32) { } -// CHECK: define{{.*}}foo92{{.*}}!type ![[TYPE92:[0-9]+]] -pub fn foo93(_: fn(i32) -> i32) { } -// CHECK: define{{.*}}foo93{{.*}}!type ![[TYPE93:[0-9]+]] -pub fn foo94(_: fn(i32) -> i32, _: fn(i32) -> i32) { } -// CHECK: define{{.*}}foo94{{.*}}!type ![[TYPE94:[0-9]+]] -pub fn foo95(_: fn(i32) -> i32, _: fn(i32) -> i32, _: fn(i32) -> i32) { } -// CHECK: define{{.*}}foo95{{.*}}!type ![[TYPE95:[0-9]+]] -pub fn foo96(_: &dyn Fn(i32) -> i32) { } -// CHECK: define{{.*}}foo96{{.*}}!type ![[TYPE96:[0-9]+]] -pub fn foo97(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) { } -// CHECK: define{{.*}}foo97{{.*}}!type ![[TYPE97:[0-9]+]] -pub fn foo98(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) { } -// CHECK: define{{.*}}foo98{{.*}}!type ![[TYPE98:[0-9]+]] -pub fn foo99(_: &dyn FnMut(i32) -> i32) { } -// CHECK: define{{.*}}foo99{{.*}}!type ![[TYPE99:[0-9]+]] -pub fn foo100(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) { } -// CHECK: define{{.*}}foo100{{.*}}!type ![[TYPE100:[0-9]+]] -pub fn foo101(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) { } -// CHECK: define{{.*}}foo101{{.*}}!type ![[TYPE101:[0-9]+]] -pub fn foo102(_: &dyn FnOnce(i32) -> i32) { } -// CHECK: define{{.*}}foo102{{.*}}!type ![[TYPE102:[0-9]+]] -pub fn foo103(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) { } -// CHECK: define{{.*}}foo103{{.*}}!type ![[TYPE103:[0-9]+]] -pub fn foo104(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) {} -// CHECK: define{{.*}}foo104{{.*}}!type ![[TYPE104:[0-9]+]] -pub fn foo105(_: &dyn Send) { } -// CHECK: define{{.*}}foo105{{.*}}!type ![[TYPE105:[0-9]+]] -pub fn foo106(_: &dyn Send, _: &dyn Send) { } -// CHECK: define{{.*}}foo106{{.*}}!type ![[TYPE106:[0-9]+]] -pub fn foo107(_: &dyn Send, _: &dyn Send, _: &dyn Send) { } -// CHECK: define{{.*}}foo107{{.*}}!type ![[TYPE107:[0-9]+]] -pub fn foo108(_: Type1) { } -// CHECK: define{{.*}}foo108{{.*}}!type ![[TYPE108:[0-9]+]] -pub fn foo109(_: Type1, _: Type1) { } -// CHECK: define{{.*}}foo109{{.*}}!type ![[TYPE109:[0-9]+]] -pub fn foo110(_: Type1, _: Type1, _: Type1) { } -// CHECK: define{{.*}}foo110{{.*}}!type ![[TYPE110:[0-9]+]] -pub fn foo111(_: Type2) { } -// CHECK: define{{.*}}foo111{{.*}}!type ![[TYPE111:[0-9]+]] -pub fn foo112(_: Type2, _: Type2) { } -// CHECK: define{{.*}}foo112{{.*}}!type ![[TYPE112:[0-9]+]] -pub fn foo113(_: Type2, _: Type2, _: Type2) { } -// CHECK: define{{.*}}foo113{{.*}}!type ![[TYPE113:[0-9]+]] -pub fn foo114(_: Type3) { } -// CHECK: define{{.*}}foo114{{.*}}!type ![[TYPE114:[0-9]+]] -pub fn foo115(_: Type3, _: Type3) { } -// CHECK: define{{.*}}foo115{{.*}}!type ![[TYPE115:[0-9]+]] -pub fn foo116(_: Type3, _: Type3, _: Type3) { } -// CHECK: define{{.*}}foo116{{.*}}!type ![[TYPE116:[0-9]+]] -pub fn foo117(_: Type4) { } -// CHECK: define{{.*}}foo117{{.*}}!type ![[TYPE117:[0-9]+]] -pub fn foo118(_: Type4, _: Type4) { } -// CHECK: define{{.*}}foo118{{.*}}!type ![[TYPE118:[0-9]+]] -pub fn foo119(_: Type4, _: Type4, _: Type4) { } -// CHECK: define{{.*}}foo119{{.*}}!type ![[TYPE119:[0-9]+]] -pub fn foo120(_: Type5) { } -// CHECK: define{{.*}}foo120{{.*}}!type ![[TYPE120:[0-9]+]] -pub fn foo121(_: Type5, _: Type5) { } -// CHECK: define{{.*}}foo121{{.*}}!type ![[TYPE121:[0-9]+]] -pub fn foo122(_: Type5, _: Type5, _: Type5) { } -// CHECK: define{{.*}}foo122{{.*}}!type ![[TYPE122:[0-9]+]] -pub fn foo123(_: Type6) { } -// CHECK: define{{.*}}foo123{{.*}}!type ![[TYPE123:[0-9]+]] -pub fn foo124(_: Type6, _: Type6) { } -// CHECK: define{{.*}}foo124{{.*}}!type ![[TYPE124:[0-9]+]] -pub fn foo125(_: Type6, _: Type6, _: Type6) { } -// CHECK: define{{.*}}foo125{{.*}}!type ![[TYPE125:[0-9]+]] -pub fn foo126(_: Type7) { } -// CHECK: define{{.*}}foo126{{.*}}!type ![[TYPE126:[0-9]+]] -pub fn foo127(_: Type7, _: Type7) { } -// CHECK: define{{.*}}foo127{{.*}}!type ![[TYPE127:[0-9]+]] -pub fn foo128(_: Type7, _: Type7, _: Type7) { } -// CHECK: define{{.*}}foo128{{.*}}!type ![[TYPE128:[0-9]+]] -pub fn foo129(_: Type8) { } -// CHECK: define{{.*}}foo129{{.*}}!type ![[TYPE129:[0-9]+]] -pub fn foo130(_: Type8, _: Type8) { } -// CHECK: define{{.*}}foo130{{.*}}!type ![[TYPE130:[0-9]+]] -pub fn foo131(_: Type8, _: Type8, _: Type8) { } -// CHECK: define{{.*}}foo131{{.*}}!type ![[TYPE131:[0-9]+]] -pub fn foo132(_: Type9) { } -// CHECK: define{{.*}}foo132{{.*}}!type ![[TYPE132:[0-9]+]] -pub fn foo133(_: Type9, _: Type9) { } -// CHECK: define{{.*}}foo133{{.*}}!type ![[TYPE133:[0-9]+]] -pub fn foo134(_: Type9, _: Type9, _: Type9) { } -// CHECK: define{{.*}}foo134{{.*}}!type ![[TYPE134:[0-9]+]] -pub fn foo135(_: Type10) { } -// CHECK: define{{.*}}foo135{{.*}}!type ![[TYPE135:[0-9]+]] -pub fn foo136(_: Type10, _: Type10) { } -// CHECK: define{{.*}}foo136{{.*}}!type ![[TYPE136:[0-9]+]] -pub fn foo137(_: Type10, _: Type10, _: Type10) { } -// CHECK: define{{.*}}foo137{{.*}}!type ![[TYPE137:[0-9]+]] -pub fn foo138(_: Type11) { } -// CHECK: define{{.*}}foo138{{.*}}!type ![[TYPE138:[0-9]+]] -pub fn foo139(_: Type11, _: Type11) { } -// CHECK: define{{.*}}foo139{{.*}}!type ![[TYPE139:[0-9]+]] -pub fn foo140(_: Type11, _: Type11, _: Type11) { } -// CHECK: define{{.*}}foo140{{.*}}!type ![[TYPE140:[0-9]+]] -pub fn foo141(_: Type12) { } -// CHECK: define{{.*}}foo141{{.*}}!type ![[TYPE141:[0-9]+]] -pub fn foo142(_: Type12, _: Type12) { } -// CHECK: define{{.*}}foo142{{.*}}!type ![[TYPE142:[0-9]+]] -pub fn foo143(_: Type12, _: Type12, _: Type12) { } -// CHECK: define{{.*}}foo143{{.*}}!type ![[TYPE143:[0-9]+]] -pub fn foo144(_: Type13) { } -// CHECK: define{{.*}}foo144{{.*}}!type ![[TYPE144:[0-9]+]] -pub fn foo145(_: Type13, _: Type13) { } -// CHECK: define{{.*}}foo145{{.*}}!type ![[TYPE145:[0-9]+]] -pub fn foo146(_: Type13, _: Type13, _: Type13) { } -// CHECK: define{{.*}}foo146{{.*}}!type ![[TYPE146:[0-9]+]] - -// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvvE"} -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvvvE"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvvvvE"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvPvE"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvPvS_E"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvPvS_S_E"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPKvE"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPKvS0_E"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPKvS0_S0_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvbE"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvbbE"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvbbbE"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu2i8E"} -// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu2i8S_E"} -// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu2i8S_S_E"} -// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu3i16E"} -// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3i16S_E"} -// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3i16S_S_E"} -// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3i32E"} -// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3i32S_E"} -// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3i32S_S_E"} -// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3i64E"} -// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3i64S_E"} -// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3i64S_S_E"} -// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu4i128E"} -// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu4i128S_E"} -// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu4i128S_S_E"} -// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu5isizeE"} -// CHECK: ![[TYPE28]] = !{i64 0, !"_ZTSFvu5isizeS_E"} -// CHECK: ![[TYPE29]] = !{i64 0, !"_ZTSFvu5isizeS_S_E"} -// CHECK: ![[TYPE30]] = !{i64 0, !"_ZTSFvu2u8E"} -// CHECK: ![[TYPE31]] = !{i64 0, !"_ZTSFvu2u8S_E"} -// CHECK: ![[TYPE32]] = !{i64 0, !"_ZTSFvu2u8S_S_E"} -// CHECK: ![[TYPE33]] = !{i64 0, !"_ZTSFvu3u16E"} -// CHECK: ![[TYPE34]] = !{i64 0, !"_ZTSFvu3u16S_E"} -// CHECK: ![[TYPE35]] = !{i64 0, !"_ZTSFvu3u16S_S_E"} -// CHECK: ![[TYPE36]] = !{i64 0, !"_ZTSFvu3u32E"} -// CHECK: ![[TYPE37]] = !{i64 0, !"_ZTSFvu3u32S_E"} -// CHECK: ![[TYPE38]] = !{i64 0, !"_ZTSFvu3u32S_S_E"} -// CHECK: ![[TYPE39]] = !{i64 0, !"_ZTSFvu3u64E"} -// CHECK: ![[TYPE40]] = !{i64 0, !"_ZTSFvu3u64S_E"} -// CHECK: ![[TYPE41]] = !{i64 0, !"_ZTSFvu3u64S_S_E"} -// CHECK: ![[TYPE42]] = !{i64 0, !"_ZTSFvu4u128E"} -// CHECK: ![[TYPE43]] = !{i64 0, !"_ZTSFvu4u128S_E"} -// CHECK: ![[TYPE44]] = !{i64 0, !"_ZTSFvu4u128S_S_E"} -// CHECK: ![[TYPE45]] = !{i64 0, !"_ZTSFvu5usizeE"} -// CHECK: ![[TYPE46]] = !{i64 0, !"_ZTSFvu5usizeS_E"} -// CHECK: ![[TYPE47]] = !{i64 0, !"_ZTSFvu5usizeS_S_E"} -// CHECK: ![[TYPE48]] = !{i64 0, !"_ZTSFvu3f32E"} -// CHECK: ![[TYPE49]] = !{i64 0, !"_ZTSFvu3f32S_E"} -// CHECK: ![[TYPE50]] = !{i64 0, !"_ZTSFvu3f32S_S_E"} -// CHECK: ![[TYPE51]] = !{i64 0, !"_ZTSFvu3f64E"} -// CHECK: ![[TYPE52]] = !{i64 0, !"_ZTSFvu3f64S_E"} -// CHECK: ![[TYPE53]] = !{i64 0, !"_ZTSFvu3f64S_S_E"} -// CHECK: ![[TYPE54]] = !{i64 0, !"_ZTSFvu4charE"} -// CHECK: ![[TYPE55]] = !{i64 0, !"_ZTSFvu4charS_E"} -// CHECK: ![[TYPE56]] = !{i64 0, !"_ZTSFvu4charS_S_E"} -// CHECK: ![[TYPE57]] = !{i64 0, !"_ZTSFvu3refIu3strEE"} -// CHECK: ![[TYPE58]] = !{i64 0, !"_ZTSFvu3refIu3strES0_E"} -// CHECK: ![[TYPE59]] = !{i64 0, !"_ZTSFvu3refIu3strES0_S0_E"} -// CHECK: ![[TYPE60]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_EE"} -// CHECK: ![[TYPE61]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_E"} -// CHECK: ![[TYPE62]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_S0_E"} -// CHECK: ![[TYPE63]] = !{i64 0, !"_ZTSFvA32u3i32E"} -// CHECK: ![[TYPE64]] = !{i64 0, !"_ZTSFvA32u3i32S0_E"} -// CHECK: ![[TYPE65]] = !{i64 0, !"_ZTSFvA32u3i32S0_S0_E"} -// CHECK: ![[TYPE66]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EEE"} -// CHECK: ![[TYPE67]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_E"} -// CHECK: ![[TYPE68]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_S1_E"} -// CHECK: ![[TYPE69]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EEE"} -// CHECK: ![[TYPE70]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EES1_E"} -// CHECK: ![[TYPE71]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EES1_S1_E"} -// CHECK: ![[TYPE72]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EEE"} -// CHECK: ![[TYPE73]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EES1_E"} -// CHECK: ![[TYPE74]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EES1_S1_E"} -// CHECK: ![[TYPE75]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EEE"} -// CHECK: ![[TYPE76]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EES1_E"} -// CHECK: ![[TYPE77]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EES1_S1_E"} -// CHECK: ![[TYPE78]] = !{i64 0, !"_ZTSFvP5type1E"} -// CHECK: ![[TYPE79]] = !{i64 0, !"_ZTSFvP5type1S0_E"} -// CHECK: ![[TYPE80]] = !{i64 0, !"_ZTSFvP5type1S0_S0_E"} -// CHECK: ![[TYPE81]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32EE"} -// CHECK: ![[TYPE82]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_E"} -// CHECK: ![[TYPE83]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_S0_E"} -// CHECK: ![[TYPE84]] = !{i64 0, !"_ZTSFvu3refIu3i32EE"} -// CHECK: ![[TYPE85]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_E"} -// CHECK: ![[TYPE86]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_S1_E"} -// CHECK: ![[TYPE87]] = !{i64 0, !"_ZTSFvPu3i32E"} -// CHECK: ![[TYPE88]] = !{i64 0, !"_ZTSFvPu3i32PKS_E"} -// CHECK: ![[TYPE89]] = !{i64 0, !"_ZTSFvPu3i32PKS_S2_E"} -// CHECK: ![[TYPE90]] = !{i64 0, !"_ZTSFvPKu3i32E"} -// CHECK: ![[TYPE91]] = !{i64 0, !"_ZTSFvPKu3i32PS_E"} -// CHECK: ![[TYPE92]] = !{i64 0, !"_ZTSFvPKu3i32PS_S2_E"} -// CHECK: ![[TYPE93]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"} -// CHECK: ![[TYPE94]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"} -// CHECK: ![[TYPE95]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"} -// CHECK: ![[TYPE96]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} -// CHECK: ![[TYPE97]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} -// CHECK: ![[TYPE98]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} -// CHECK: ![[TYPE99]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} -// CHECK: ![[TYPE100]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} -// CHECK: ![[TYPE101]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} -// CHECK: ![[TYPE102]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} -// CHECK: ![[TYPE103]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} -// CHECK: ![[TYPE104]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} -// CHECK: ![[TYPE105]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"} -// CHECK: ![[TYPE106]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_E"} -// CHECK: ![[TYPE107]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_S2_E"} -// CHECK: ![[TYPE108]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvEE"} -// CHECK: ![[TYPE109]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_E"} -// CHECK: ![[TYPE110]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_S1_E"} -// CHECK: ![[TYPE111]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}E"} -// CHECK: ![[TYPE112]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_E"} -// CHECK: ![[TYPE113]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_S_E"} -// CHECK: ![[TYPE114]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooE"} -// CHECK: ![[TYPE115]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_E"} -// CHECK: ![[TYPE116]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_S_E"} -// CHECK: ![[TYPE117]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooE"} -// CHECK: ![[TYPE118]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_E"} -// CHECK: ![[TYPE119]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_S_E"} -// CHECK: ![[TYPE120]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooE"} -// CHECK: ![[TYPE121]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_E"} -// CHECK: ![[TYPE122]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_S_E"} -// CHECK: ![[TYPE123]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32EE"} -// CHECK: ![[TYPE124]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_E"} -// CHECK: ![[TYPE125]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_S0_E"} -// CHECK: ![[TYPE126]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_EE"} -// CHECK: ![[TYPE127]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_ES3_E"} -// CHECK: ![[TYPE128]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_ES3_S3_E"} -// CHECK: ![[TYPE129]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_EE"} -// CHECK: ![[TYPE130]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_E"} -// CHECK: ![[TYPE131]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_S0_E"} -// CHECK: ![[TYPE132]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_EE"} -// CHECK: ![[TYPE133]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_ES1_E"} -// CHECK: ![[TYPE134]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_ES1_S1_E"} -// CHECK: ![[TYPE135]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EEE"} -// CHECK: ![[TYPE136]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EES2_E"} -// CHECK: ![[TYPE137]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EES2_S2_E"} -// CHECK: ![[TYPE138]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_EE"} -// CHECK: ![[TYPE139]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_E"} -// CHECK: ![[TYPE140]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_S0_E"} -// CHECK: ![[TYPE141]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooE"} -// CHECK: ![[TYPE142]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_E"} -// CHECK: ![[TYPE143]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_S_E"} -// CHECK: ![[TYPE144]] = !{i64 0, !"_ZTSFvu3refIu3refIvEEE"} -// CHECK: ![[TYPE145]] = !{i64 0, !"_ZTSFvu3refIu3refIvEES0_E"} -// CHECK: ![[TYPE146]] = !{i64 0, !"_ZTSFvu3refIu3refIvEES0_S0_E"} diff --git a/src/test/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs b/src/test/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs deleted file mode 100644 index bafc4c6592f52..0000000000000 --- a/src/test/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Verifies that type metadata for functions are emitted. -// -// needs-sanitizer-cfi -// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi - -#![crate_type="lib"] - -pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: define{{.*}}foo - // CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] - // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_E") - f(arg) -} - -pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { - // CHECK-LABEL: define{{.*}}bar - // CHECK-SAME: {{.*}}!type ![[TYPE2:[0-9]+]] - // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E") - f(arg1, arg2) -} - -pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { - // CHECK-LABEL: define{{.*}}baz - // CHECK-SAME: {{.*}}!type ![[TYPE3:[0-9]+]] - // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E") - f(arg1, arg2, arg3) -} - -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PFS_S_ES_E"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_ES_S_E"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_S_ES_S_S_E"} diff --git a/src/test/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs b/src/test/codegen/sanitizer_cfi_add_canonical_jump_tables_flag.rs similarity index 69% rename from src/test/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs rename to src/test/codegen/sanitizer_cfi_add_canonical_jump_tables_flag.rs index c42fbba74254a..68f81808861a8 100644 --- a/src/test/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs +++ b/src/test/codegen/sanitizer_cfi_add_canonical_jump_tables_flag.rs @@ -1,7 +1,10 @@ // Verifies that "CFI Canonical Jump Tables" module flag is added. // +// ignore-windows // needs-sanitizer-cfi -// compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi +// only-aarch64 +// only-x86_64 +// compile-flags: -Clto -Zsanitizer=cfi #![crate_type="lib"] diff --git a/src/test/codegen/sanitizer-cfi-emit-type-checks.rs b/src/test/codegen/sanitizer_cfi_emit_type_checks.rs similarity index 54% rename from src/test/codegen/sanitizer-cfi-emit-type-checks.rs rename to src/test/codegen/sanitizer_cfi_emit_type_checks.rs index 8be5186de9e77..9ed0422ceff15 100644 --- a/src/test/codegen/sanitizer-cfi-emit-type-checks.rs +++ b/src/test/codegen/sanitizer_cfi_emit_type_checks.rs @@ -1,17 +1,21 @@ // Verifies that pointer type membership tests for indirect calls are emitted. // +// ignore-windows // needs-sanitizer-cfi -// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi +// only-aarch64 +// only-x86_64 +// compile-flags: -Clto -Cno-prepopulate-passes -Zsanitizer=cfi #![crate_type="lib"] pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} // CHECK: start: - // CHECK: [[TT:%.+]] = call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"{{[[:print:]]+}}") - // CHECK-NEXT: br i1 [[TT]], label %type_test.pass, label %type_test.fail + // CHECK-NEXT: %0 = bitcast i32 (i32)* %f to i8* + // CHECK-NEXT: %1 = call i1 @llvm.type.test(i8* %0, metadata !"{{[[:print:]]+}}") + // CHECK-NEXT: br i1 %1, label %type_test.pass, label %type_test.fail // CHECK: type_test.pass: - // CHECK-NEXT: {{%.+}} = call i32 %f(i32 %arg) + // CHECK-NEXT: %2 = call i32 %f(i32 %arg) // CHECK-NEXT: br label %bb1 // CHECK: type_test.fail: // CHECK-NEXT: call void @llvm.trap() diff --git a/src/test/codegen/sanitizer_cfi_emit_type_metadata.rs b/src/test/codegen/sanitizer_cfi_emit_type_metadata.rs new file mode 100644 index 0000000000000..96fced47e786d --- /dev/null +++ b/src/test/codegen/sanitizer_cfi_emit_type_metadata.rs @@ -0,0 +1,31 @@ +// Verifies that type metadata for functions are emitted. +// +// ignore-windows +// needs-sanitizer-cfi +// only-aarch64 +// only-x86_64 +// compile-flags: -Clto -Cno-prepopulate-passes -Zsanitizer=cfi + +#![crate_type="lib"] + +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} + // CHECK: %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid1") + f(arg) +} + +pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { + // CHECK-LABEL: define{{.*}}bar{{.*}}!type !{{[0-9]+}} + // CHECK: %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid2") + f(arg1, arg2) +} + +pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { + // CHECK-LABEL: define{{.*}}baz{{.*}}!type !{{[0-9]+}} + // CHECK: %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid3") + f(arg1, arg2, arg3) +} + +// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid2"} +// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid3"} +// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid4"} diff --git a/src/test/codegen/sanitizer_scs_attr_check.rs b/src/test/codegen/sanitizer_scs_attr_check.rs deleted file mode 100644 index 0b53db3b767cd..0000000000000 --- a/src/test/codegen/sanitizer_scs_attr_check.rs +++ /dev/null @@ -1,17 +0,0 @@ -// This tests that the shadowcallstack attribute is -// applied when enabling the shadow-call-stack sanitizer. -// -// needs-sanitizer-shadow-call-stack -// compile-flags: -Zsanitizer=shadow-call-stack - -#![crate_type = "lib"] -#![feature(no_sanitize)] - -// CHECK: ; Function Attrs:{{.*}}shadowcallstack -// CHECK-NEXT: scs -pub fn scs() {} - -// CHECK-NOT: ; Function Attrs:{{.*}}shadowcallstack -// CHECK-NEXT: no_scs -#[no_sanitize(shadow_call_stack)] -pub fn no_scs() {} diff --git a/src/test/codegen/simd-wide-sum.rs b/src/test/codegen/simd-wide-sum.rs index 04314dc291a6b..015ac4fe4d1b6 100644 --- a/src/test/codegen/simd-wide-sum.rs +++ b/src/test/codegen/simd-wide-sum.rs @@ -5,7 +5,7 @@ #![crate_type = "lib"] #![feature(portable_simd)] -use std::simd::{Simd, SimdUint}; +use std::simd::Simd; const N: usize = 8; #[no_mangle] diff --git a/src/test/codegen/vec-calloc-llvm14.rs b/src/test/codegen/vec-calloc-llvm14.rs deleted file mode 100644 index 08302796c41a1..0000000000000 --- a/src/test/codegen/vec-calloc-llvm14.rs +++ /dev/null @@ -1,144 +0,0 @@ -// compile-flags: -O -// only-x86_64 -// ignore-debug - -#![crate_type = "lib"] - -// CHECK-LABEL: @vec_zero_bytes -#[no_mangle] -pub fn vec_zero_bytes(n: usize) -> Vec { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - // CHECK-NOT: call {{.*}}llvm.memset - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - // CHECK-NOT: call {{.*}}llvm.memset - - // CHECK: ret void - vec![0; n] -} - -// CHECK-LABEL: @vec_one_bytes -#[no_mangle] -pub fn vec_one_bytes(n: usize) -> Vec { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: call {{.*}}__rust_alloc( - // CHECK: call {{.*}}llvm.memset - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: ret void - vec![1; n] -} - -// CHECK-LABEL: @vec_zero_scalar -#[no_mangle] -pub fn vec_zero_scalar(n: usize) -> Vec { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void - vec![0; n] -} - -// CHECK-LABEL: @vec_one_scalar -#[no_mangle] -pub fn vec_one_scalar(n: usize) -> Vec { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: call {{.*}}__rust_alloc( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: ret void - vec![1; n] -} - -// CHECK-LABEL: @vec_zero_rgb48 -#[no_mangle] -pub fn vec_zero_rgb48(n: usize) -> Vec<[u16; 3]> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void - vec![[0, 0, 0]; n] -} - -// CHECK-LABEL: @vec_zero_array_16 -#[no_mangle] -pub fn vec_zero_array_16(n: usize) -> Vec<[i64; 16]> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void - vec![[0_i64; 16]; n] -} - -// CHECK-LABEL: @vec_zero_tuple -#[no_mangle] -pub fn vec_zero_tuple(n: usize) -> Vec<(i16, u8, char)> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void - vec![(0, 0, '\0'); n] -} - -// CHECK-LABEL: @vec_non_zero_tuple -#[no_mangle] -pub fn vec_non_zero_tuple(n: usize) -> Vec<(i16, u8, char)> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: call {{.*}}__rust_alloc( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: ret void - vec![(0, 0, 'A'); n] -} diff --git a/src/test/codegen/vec-calloc.rs b/src/test/codegen/vec-calloc.rs index 435a4ab5187f6..c616e9f1145cf 100644 --- a/src/test/codegen/vec-calloc.rs +++ b/src/test/codegen/vec-calloc.rs @@ -1,150 +1,32 @@ // compile-flags: -O // only-x86_64 // ignore-debug -// min-llvm-version: 15.0 #![crate_type = "lib"] -// CHECK-LABEL: @vec_zero_bytes -#[no_mangle] -pub fn vec_zero_bytes(n: usize) -> Vec { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - // CHECK-NOT: call {{.*}}llvm.memset - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - // CHECK-NOT: call {{.*}}llvm.memset - - // CHECK: ret void - vec![0; n] -} - -// CHECK-LABEL: @vec_one_bytes -#[no_mangle] -pub fn vec_one_bytes(n: usize) -> Vec { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: call {{.*}}__rust_alloc( - // CHECK: call {{.*}}llvm.memset - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: ret void - vec![1; n] -} - // CHECK-LABEL: @vec_zero_scalar #[no_mangle] pub fn vec_zero_scalar(n: usize) -> Vec { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void + // CHECK-NOT: __rust_alloc( + // CHECK: __rust_alloc_zeroed( + // CHECK-NOT: __rust_alloc( vec![0; n] } -// CHECK-LABEL: @vec_one_scalar -#[no_mangle] -pub fn vec_one_scalar(n: usize) -> Vec { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: call {{.*}}__rust_alloc( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: ret void - vec![1; n] -} - // CHECK-LABEL: @vec_zero_rgb48 #[no_mangle] pub fn vec_zero_rgb48(n: usize) -> Vec<[u16; 3]> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void + // CHECK-NOT: __rust_alloc( + // CHECK: __rust_alloc_zeroed( + // CHECK-NOT: __rust_alloc( vec![[0, 0, 0]; n] } -// CHECK-LABEL: @vec_zero_array_16 +// CHECK-LABEL: @vec_zero_array_32 #[no_mangle] -pub fn vec_zero_array_16(n: usize) -> Vec<[i64; 16]> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void - vec![[0_i64; 16]; n] +pub fn vec_zero_array_32(n: usize) -> Vec<[i64; 32]> { + // CHECK-NOT: __rust_alloc( + // CHECK: __rust_alloc_zeroed( + // CHECK-NOT: __rust_alloc( + vec![[0_i64; 32]; n] } - -// CHECK-LABEL: @vec_zero_tuple -#[no_mangle] -pub fn vec_zero_tuple(n: usize) -> Vec<(i16, u8, char)> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void - vec![(0, 0, '\0'); n] -} - -// CHECK-LABEL: @vec_non_zero_tuple -#[no_mangle] -pub fn vec_non_zero_tuple(n: usize) -> Vec<(i16, u8, char)> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: call {{.*}}__rust_alloc( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: ret void - vec![(0, 0, 'A'); n] -} - -// Ensure that __rust_alloc_zeroed gets the right attributes for LLVM to optimize it away. -// CHECK: declare noalias ptr @__rust_alloc_zeroed(i64, i64 allocalign) unnamed_addr [[RUST_ALLOC_ZEROED_ATTRS:#[0-9]+]] - -// CHECK-DAG: attributes [[RUST_ALLOC_ZEROED_ATTRS]] = { {{.*}} allockind("alloc,zeroed,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} } diff --git a/src/test/debuginfo/basic-types-globals-lto.rs b/src/test/debuginfo/basic-types-globals-lto.rs new file mode 100644 index 0000000000000..1adf278ad32de --- /dev/null +++ b/src/test/debuginfo/basic-types-globals-lto.rs @@ -0,0 +1,81 @@ +// Caveat - gdb doesn't know about UTF-32 character encoding and will print a +// rust char as only its numerical value. + +// min-lldb-version: 310 +// min-gdb-version: 8.0 + +// no-prefer-dynamic +// compile-flags:-g -C lto +// gdb-command:run +// gdbg-command:print 'basic_types_globals::B' +// gdbr-command:print B +// gdb-check:$1 = false +// gdbg-command:print 'basic_types_globals::I' +// gdbr-command:print I +// gdb-check:$2 = -1 +// gdbg-command:print 'basic_types_globals::C' +// gdbr-command:print/d C +// gdbg-check:$3 = 97 +// gdbr-check:$3 = 97 +// gdbg-command:print/d 'basic_types_globals::I8' +// gdbr-command:print I8 +// gdb-check:$4 = 68 +// gdbg-command:print 'basic_types_globals::I16' +// gdbr-command:print I16 +// gdb-check:$5 = -16 +// gdbg-command:print 'basic_types_globals::I32' +// gdbr-command:print I32 +// gdb-check:$6 = -32 +// gdbg-command:print 'basic_types_globals::I64' +// gdbr-command:print I64 +// gdb-check:$7 = -64 +// gdbg-command:print 'basic_types_globals::U' +// gdbr-command:print U +// gdb-check:$8 = 1 +// gdbg-command:print/d 'basic_types_globals::U8' +// gdbr-command:print U8 +// gdb-check:$9 = 100 +// gdbg-command:print 'basic_types_globals::U16' +// gdbr-command:print U16 +// gdb-check:$10 = 16 +// gdbg-command:print 'basic_types_globals::U32' +// gdbr-command:print U32 +// gdb-check:$11 = 32 +// gdbg-command:print 'basic_types_globals::U64' +// gdbr-command:print U64 +// gdb-check:$12 = 64 +// gdbg-command:print 'basic_types_globals::F32' +// gdbr-command:print F32 +// gdb-check:$13 = 2.5 +// gdbg-command:print 'basic_types_globals::F64' +// gdbr-command:print F64 +// gdb-check:$14 = 3.5 +// gdb-command:continue + +#![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] +#![omit_gdb_pretty_printer_section] + +// N.B. These are `mut` only so they don't constant fold away. +static mut B: bool = false; +static mut I: isize = -1; +static mut C: char = 'a'; +static mut I8: i8 = 68; +static mut I16: i16 = -16; +static mut I32: i32 = -32; +static mut I64: i64 = -64; +static mut U: usize = 1; +static mut U8: u8 = 100; +static mut U16: u16 = 16; +static mut U32: u32 = 32; +static mut U64: u64 = 64; +static mut F32: f32 = 2.5; +static mut F64: f64 = 3.5; + +fn main() { + _zzz(); // #break + + let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F32, F64) }; +} + +fn _zzz() {()} diff --git a/src/test/debuginfo/basic-types-globals.rs b/src/test/debuginfo/basic-types-globals.rs index 8a3df8ba2d18e..3602db39a4ec1 100644 --- a/src/test/debuginfo/basic-types-globals.rs +++ b/src/test/debuginfo/basic-types-globals.rs @@ -4,13 +4,7 @@ // min-lldb-version: 310 // min-gdb-version: 8.0 -// revisions: lto no-lto - // compile-flags:-g - -// [lto] compile-flags:-C lto -// [lto] no-prefer-dynamic - // gdb-command:run // gdbg-command:print 'basic_types_globals::B' // gdbr-command:print B diff --git a/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff b/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff index 57e298625f9a0..884275430c8b1 100644 --- a/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff +++ b/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff @@ -2,28 +2,28 @@ + // MIR for `encode` after SimplifyBranchSame fn encode(_1: Type) -> Type { - debug v => _1; // in scope 0 at $DIR/76803_regression.rs:+0:15: +0:16 - let mut _0: Type; // return place in scope 0 at $DIR/76803_regression.rs:+0:27: +0:31 - let mut _2: isize; // in scope 0 at $DIR/76803_regression.rs:+2:9: +2:16 + debug v => _1; // in scope 0 at $DIR/76803_regression.rs:10:15: 10:16 + let mut _0: Type; // return place in scope 0 at $DIR/76803_regression.rs:10:27: 10:31 + let mut _2: isize; // in scope 0 at $DIR/76803_regression.rs:12:9: 12:16 bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/76803_regression.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/76803_regression.rs:+1:5: +1:12 + _2 = discriminant(_1); // scope 0 at $DIR/76803_regression.rs:11:11: 11:12 + switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/76803_regression.rs:11:5: 11:12 } bb1: { - _0 = move _1; // scope 0 at $DIR/76803_regression.rs:+3:14: +3:15 - goto -> bb3; // scope 0 at $DIR/76803_regression.rs:+3:14: +3:15 + _0 = move _1; // scope 0 at $DIR/76803_regression.rs:13:14: 13:15 + goto -> bb3; // scope 0 at $DIR/76803_regression.rs:13:14: 13:15 } bb2: { - Deinit(_0); // scope 0 at $DIR/76803_regression.rs:+2:20: +2:27 - discriminant(_0) = 1; // scope 0 at $DIR/76803_regression.rs:+2:20: +2:27 - goto -> bb3; // scope 0 at $DIR/76803_regression.rs:+2:20: +2:27 + Deinit(_0); // scope 0 at $DIR/76803_regression.rs:12:20: 12:27 + discriminant(_0) = 1; // scope 0 at $DIR/76803_regression.rs:12:20: 12:27 + goto -> bb3; // scope 0 at $DIR/76803_regression.rs:12:20: 12:27 } bb3: { - return; // scope 0 at $DIR/76803_regression.rs:+5:2: +5:2 + return; // scope 0 at $DIR/76803_regression.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/src/test/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir index d41a66871cc43..ee8e21781480c 100644 --- a/src/test/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir @@ -33,83 +33,83 @@ | 29: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32]) }, span: $DIR/address-of.rs:36:12: 36:22, inferred_ty: *mut [i32] | fn address_of_reborrow() -> () { - let mut _0: (); // return place in scope 0 at $DIR/address-of.rs:+0:26: +0:26 - let _1: &[i32; 10]; // in scope 0 at $DIR/address-of.rs:+1:9: +1:10 - let _2: [i32; 10]; // in scope 0 at $DIR/address-of.rs:+1:14: +1:21 - let mut _4: [i32; 10]; // in scope 0 at $DIR/address-of.rs:+2:22: +2:29 - let _5: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+4:5: +4:18 - let mut _6: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+4:5: +4:18 - let _7: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+5:5: +5:26 - let _8: *const dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:+6:5: +6:25 - let mut _9: *const dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:+6:5: +6:25 - let mut _10: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+6:5: +6:6 - let _11: *const [i32]; // in scope 0 at $DIR/address-of.rs:+7:5: +7:22 - let mut _12: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+7:5: +7:6 - let _13: *const i32; // in scope 0 at $DIR/address-of.rs:+8:5: +8:20 - let mut _14: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+8:5: +8:6 - let mut _18: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+12:30: +12:31 - let mut _20: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+13:27: +13:28 - let _21: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+15:5: +15:18 - let mut _22: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+15:5: +15:18 - let _23: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+16:5: +16:26 - let _24: *const dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:+17:5: +17:25 - let mut _25: *const dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:+17:5: +17:25 - let mut _26: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+17:5: +17:6 - let _27: *const [i32]; // in scope 0 at $DIR/address-of.rs:+18:5: +18:22 - let mut _28: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+18:5: +18:6 - let mut _32: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+22:30: +22:31 - let mut _34: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+23:27: +23:28 - let _35: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:+25:5: +25:16 - let mut _36: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:+25:5: +25:16 - let _37: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:+26:5: +26:24 - let _38: *mut dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:+27:5: +27:23 - let mut _39: *mut dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:+27:5: +27:23 - let mut _40: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:+27:5: +27:6 - let _41: *mut [i32]; // in scope 0 at $DIR/address-of.rs:+28:5: +28:20 - let mut _42: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:+28:5: +28:6 - let mut _46: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:+32:28: +32:29 - let mut _48: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:+33:25: +33:26 + let mut _0: (); // return place in scope 0 at $DIR/address-of.rs:3:26: 3:26 + let _1: &[i32; 10]; // in scope 0 at $DIR/address-of.rs:4:9: 4:10 + let _2: [i32; 10]; // in scope 0 at $DIR/address-of.rs:4:14: 4:21 + let mut _4: [i32; 10]; // in scope 0 at $DIR/address-of.rs:5:22: 5:29 + let _5: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:7:5: 7:18 + let mut _6: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:7:5: 7:18 + let _7: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:8:5: 8:26 + let _8: *const dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:9:5: 9:25 + let mut _9: *const dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:9:5: 9:25 + let mut _10: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:9:5: 9:6 + let _11: *const [i32]; // in scope 0 at $DIR/address-of.rs:10:5: 10:22 + let mut _12: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:10:5: 10:6 + let _13: *const i32; // in scope 0 at $DIR/address-of.rs:11:5: 11:20 + let mut _14: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:11:5: 11:6 + let mut _18: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:15:30: 15:31 + let mut _20: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:16:27: 16:28 + let _21: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:18:5: 18:18 + let mut _22: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:18:5: 18:18 + let _23: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:19:5: 19:26 + let _24: *const dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:20:5: 20:25 + let mut _25: *const dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:20:5: 20:25 + let mut _26: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:20:5: 20:6 + let _27: *const [i32]; // in scope 0 at $DIR/address-of.rs:21:5: 21:22 + let mut _28: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:21:5: 21:6 + let mut _32: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:25:30: 25:31 + let mut _34: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:26:27: 26:28 + let _35: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:28:5: 28:16 + let mut _36: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:28:5: 28:16 + let _37: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:29:5: 29:24 + let _38: *mut dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:30:5: 30:23 + let mut _39: *mut dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:30:5: 30:23 + let mut _40: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:30:5: 30:6 + let _41: *mut [i32]; // in scope 0 at $DIR/address-of.rs:31:5: 31:20 + let mut _42: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:31:5: 31:6 + let mut _46: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:35:28: 35:29 + let mut _48: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:36:25: 36:26 scope 1 { - debug y => _1; // in scope 1 at $DIR/address-of.rs:+1:9: +1:10 - let mut _3: &mut [i32; 10]; // in scope 1 at $DIR/address-of.rs:+2:9: +2:14 + debug y => _1; // in scope 1 at $DIR/address-of.rs:4:9: 4:10 + let mut _3: &mut [i32; 10]; // in scope 1 at $DIR/address-of.rs:5:9: 5:14 scope 2 { - debug z => _3; // in scope 2 at $DIR/address-of.rs:+2:9: +2:14 - let _15: *const [i32; 10] as UserTypeProjection { base: UserType(2), projs: [] }; // in scope 2 at $DIR/address-of.rs:+10:9: +10:10 + debug z => _3; // in scope 2 at $DIR/address-of.rs:5:9: 5:14 + let _15: *const [i32; 10] as UserTypeProjection { base: UserType(2), projs: [] }; // in scope 2 at $DIR/address-of.rs:13:9: 13:10 scope 3 { - debug p => _15; // in scope 3 at $DIR/address-of.rs:+10:9: +10:10 - let _16: *const [i32; 10] as UserTypeProjection { base: UserType(4), projs: [] }; // in scope 3 at $DIR/address-of.rs:+11:9: +11:10 + debug p => _15; // in scope 3 at $DIR/address-of.rs:13:9: 13:10 + let _16: *const [i32; 10] as UserTypeProjection { base: UserType(4), projs: [] }; // in scope 3 at $DIR/address-of.rs:14:9: 14:10 scope 4 { - debug p => _16; // in scope 4 at $DIR/address-of.rs:+11:9: +11:10 - let _17: *const dyn std::marker::Send as UserTypeProjection { base: UserType(6), projs: [] }; // in scope 4 at $DIR/address-of.rs:+12:9: +12:10 + debug p => _16; // in scope 4 at $DIR/address-of.rs:14:9: 14:10 + let _17: *const dyn std::marker::Send as UserTypeProjection { base: UserType(6), projs: [] }; // in scope 4 at $DIR/address-of.rs:15:9: 15:10 scope 5 { - debug p => _17; // in scope 5 at $DIR/address-of.rs:+12:9: +12:10 - let _19: *const [i32] as UserTypeProjection { base: UserType(8), projs: [] }; // in scope 5 at $DIR/address-of.rs:+13:9: +13:10 + debug p => _17; // in scope 5 at $DIR/address-of.rs:15:9: 15:10 + let _19: *const [i32] as UserTypeProjection { base: UserType(8), projs: [] }; // in scope 5 at $DIR/address-of.rs:16:9: 16:10 scope 6 { - debug p => _19; // in scope 6 at $DIR/address-of.rs:+13:9: +13:10 - let _29: *const [i32; 10] as UserTypeProjection { base: UserType(12), projs: [] }; // in scope 6 at $DIR/address-of.rs:+20:9: +20:10 + debug p => _19; // in scope 6 at $DIR/address-of.rs:16:9: 16:10 + let _29: *const [i32; 10] as UserTypeProjection { base: UserType(12), projs: [] }; // in scope 6 at $DIR/address-of.rs:23:9: 23:10 scope 7 { - debug p => _29; // in scope 7 at $DIR/address-of.rs:+20:9: +20:10 - let _30: *const [i32; 10] as UserTypeProjection { base: UserType(14), projs: [] }; // in scope 7 at $DIR/address-of.rs:+21:9: +21:10 + debug p => _29; // in scope 7 at $DIR/address-of.rs:23:9: 23:10 + let _30: *const [i32; 10] as UserTypeProjection { base: UserType(14), projs: [] }; // in scope 7 at $DIR/address-of.rs:24:9: 24:10 scope 8 { - debug p => _30; // in scope 8 at $DIR/address-of.rs:+21:9: +21:10 - let _31: *const dyn std::marker::Send as UserTypeProjection { base: UserType(16), projs: [] }; // in scope 8 at $DIR/address-of.rs:+22:9: +22:10 + debug p => _30; // in scope 8 at $DIR/address-of.rs:24:9: 24:10 + let _31: *const dyn std::marker::Send as UserTypeProjection { base: UserType(16), projs: [] }; // in scope 8 at $DIR/address-of.rs:25:9: 25:10 scope 9 { - debug p => _31; // in scope 9 at $DIR/address-of.rs:+22:9: +22:10 - let _33: *const [i32] as UserTypeProjection { base: UserType(18), projs: [] }; // in scope 9 at $DIR/address-of.rs:+23:9: +23:10 + debug p => _31; // in scope 9 at $DIR/address-of.rs:25:9: 25:10 + let _33: *const [i32] as UserTypeProjection { base: UserType(18), projs: [] }; // in scope 9 at $DIR/address-of.rs:26:9: 26:10 scope 10 { - debug p => _33; // in scope 10 at $DIR/address-of.rs:+23:9: +23:10 - let _43: *mut [i32; 10] as UserTypeProjection { base: UserType(22), projs: [] }; // in scope 10 at $DIR/address-of.rs:+30:9: +30:10 + debug p => _33; // in scope 10 at $DIR/address-of.rs:26:9: 26:10 + let _43: *mut [i32; 10] as UserTypeProjection { base: UserType(22), projs: [] }; // in scope 10 at $DIR/address-of.rs:33:9: 33:10 scope 11 { - debug p => _43; // in scope 11 at $DIR/address-of.rs:+30:9: +30:10 - let _44: *mut [i32; 10] as UserTypeProjection { base: UserType(24), projs: [] }; // in scope 11 at $DIR/address-of.rs:+31:9: +31:10 + debug p => _43; // in scope 11 at $DIR/address-of.rs:33:9: 33:10 + let _44: *mut [i32; 10] as UserTypeProjection { base: UserType(24), projs: [] }; // in scope 11 at $DIR/address-of.rs:34:9: 34:10 scope 12 { - debug p => _44; // in scope 12 at $DIR/address-of.rs:+31:9: +31:10 - let _45: *mut dyn std::marker::Send as UserTypeProjection { base: UserType(26), projs: [] }; // in scope 12 at $DIR/address-of.rs:+32:9: +32:10 + debug p => _44; // in scope 12 at $DIR/address-of.rs:34:9: 34:10 + let _45: *mut dyn std::marker::Send as UserTypeProjection { base: UserType(26), projs: [] }; // in scope 12 at $DIR/address-of.rs:35:9: 35:10 scope 13 { - debug p => _45; // in scope 13 at $DIR/address-of.rs:+32:9: +32:10 - let _47: *mut [i32] as UserTypeProjection { base: UserType(28), projs: [] }; // in scope 13 at $DIR/address-of.rs:+33:9: +33:10 + debug p => _45; // in scope 13 at $DIR/address-of.rs:35:9: 35:10 + let _47: *mut [i32] as UserTypeProjection { base: UserType(28), projs: [] }; // in scope 13 at $DIR/address-of.rs:36:9: 36:10 scope 14 { - debug p => _47; // in scope 14 at $DIR/address-of.rs:+33:9: +33:10 + debug p => _47; // in scope 14 at $DIR/address-of.rs:36:9: 36:10 } } } @@ -126,183 +126,183 @@ fn address_of_reborrow() -> () { } bb0: { - StorageLive(_1); // scope 0 at $DIR/address-of.rs:+1:9: +1:10 - StorageLive(_2); // scope 0 at $DIR/address-of.rs:+1:14: +1:21 - _2 = [const 0_i32; 10]; // scope 0 at $DIR/address-of.rs:+1:14: +1:21 - _1 = &_2; // scope 0 at $DIR/address-of.rs:+1:13: +1:21 - FakeRead(ForLet(None), _1); // scope 0 at $DIR/address-of.rs:+1:9: +1:10 - StorageLive(_3); // scope 1 at $DIR/address-of.rs:+2:9: +2:14 - StorageLive(_4); // scope 1 at $DIR/address-of.rs:+2:22: +2:29 - _4 = [const 0_i32; 10]; // scope 1 at $DIR/address-of.rs:+2:22: +2:29 - _3 = &mut _4; // scope 1 at $DIR/address-of.rs:+2:17: +2:29 - FakeRead(ForLet(None), _3); // scope 1 at $DIR/address-of.rs:+2:9: +2:14 - StorageLive(_5); // scope 2 at $DIR/address-of.rs:+4:5: +4:18 - StorageLive(_6); // scope 2 at $DIR/address-of.rs:+4:5: +4:18 - _6 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:+4:5: +4:6 - AscribeUserType(_6, o, UserTypeProjection { base: UserType(0), projs: [] }); // scope 2 at $DIR/address-of.rs:+4:5: +4:18 - _5 = _6; // scope 2 at $DIR/address-of.rs:+4:5: +4:18 - StorageDead(_6); // scope 2 at $DIR/address-of.rs:+4:18: +4:19 - StorageDead(_5); // scope 2 at $DIR/address-of.rs:+4:18: +4:19 - StorageLive(_7); // scope 2 at $DIR/address-of.rs:+5:5: +5:26 - _7 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:+5:5: +5:6 - StorageDead(_7); // scope 2 at $DIR/address-of.rs:+5:26: +5:27 - StorageLive(_8); // scope 2 at $DIR/address-of.rs:+6:5: +6:25 - StorageLive(_9); // scope 2 at $DIR/address-of.rs:+6:5: +6:25 - StorageLive(_10); // scope 2 at $DIR/address-of.rs:+6:5: +6:6 - _10 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:+6:5: +6:6 - _9 = move _10 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 2 at $DIR/address-of.rs:+6:5: +6:6 - StorageDead(_10); // scope 2 at $DIR/address-of.rs:+6:5: +6:6 - AscribeUserType(_9, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 2 at $DIR/address-of.rs:+6:5: +6:25 - _8 = _9; // scope 2 at $DIR/address-of.rs:+6:5: +6:25 - StorageDead(_9); // scope 2 at $DIR/address-of.rs:+6:25: +6:26 - StorageDead(_8); // scope 2 at $DIR/address-of.rs:+6:25: +6:26 - StorageLive(_11); // scope 2 at $DIR/address-of.rs:+7:5: +7:22 - StorageLive(_12); // scope 2 at $DIR/address-of.rs:+7:5: +7:6 - _12 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:+7:5: +7:6 - _11 = move _12 as *const [i32] (Pointer(Unsize)); // scope 2 at $DIR/address-of.rs:+7:5: +7:6 - StorageDead(_12); // scope 2 at $DIR/address-of.rs:+7:5: +7:6 - StorageDead(_11); // scope 2 at $DIR/address-of.rs:+7:22: +7:23 - StorageLive(_13); // scope 2 at $DIR/address-of.rs:+8:5: +8:20 - StorageLive(_14); // scope 2 at $DIR/address-of.rs:+8:5: +8:6 - _14 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:+8:5: +8:6 - _13 = move _14 as *const i32 (Pointer(ArrayToPointer)); // scope 2 at $DIR/address-of.rs:+8:5: +8:20 - StorageDead(_14); // scope 2 at $DIR/address-of.rs:+8:19: +8:20 - StorageDead(_13); // scope 2 at $DIR/address-of.rs:+8:20: +8:21 - StorageLive(_15); // scope 2 at $DIR/address-of.rs:+10:9: +10:10 - _15 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:+10:23: +10:24 - FakeRead(ForLet(None), _15); // scope 2 at $DIR/address-of.rs:+10:9: +10:10 - AscribeUserType(_15, o, UserTypeProjection { base: UserType(3), projs: [] }); // scope 2 at $DIR/address-of.rs:+10:12: +10:20 - StorageLive(_16); // scope 3 at $DIR/address-of.rs:+11:9: +11:10 - _16 = &raw const (*_1); // scope 3 at $DIR/address-of.rs:+11:31: +11:32 - FakeRead(ForLet(None), _16); // scope 3 at $DIR/address-of.rs:+11:9: +11:10 - AscribeUserType(_16, o, UserTypeProjection { base: UserType(5), projs: [] }); // scope 3 at $DIR/address-of.rs:+11:12: +11:28 - StorageLive(_17); // scope 4 at $DIR/address-of.rs:+12:9: +12:10 - StorageLive(_18); // scope 4 at $DIR/address-of.rs:+12:30: +12:31 - _18 = &raw const (*_1); // scope 4 at $DIR/address-of.rs:+12:30: +12:31 - _17 = move _18 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 4 at $DIR/address-of.rs:+12:30: +12:31 - StorageDead(_18); // scope 4 at $DIR/address-of.rs:+12:30: +12:31 - FakeRead(ForLet(None), _17); // scope 4 at $DIR/address-of.rs:+12:9: +12:10 - AscribeUserType(_17, o, UserTypeProjection { base: UserType(7), projs: [] }); // scope 4 at $DIR/address-of.rs:+12:12: +12:27 - StorageLive(_19); // scope 5 at $DIR/address-of.rs:+13:9: +13:10 - StorageLive(_20); // scope 5 at $DIR/address-of.rs:+13:27: +13:28 - _20 = &raw const (*_1); // scope 5 at $DIR/address-of.rs:+13:27: +13:28 - _19 = move _20 as *const [i32] (Pointer(Unsize)); // scope 5 at $DIR/address-of.rs:+13:27: +13:28 - StorageDead(_20); // scope 5 at $DIR/address-of.rs:+13:27: +13:28 - FakeRead(ForLet(None), _19); // scope 5 at $DIR/address-of.rs:+13:9: +13:10 - AscribeUserType(_19, o, UserTypeProjection { base: UserType(9), projs: [] }); // scope 5 at $DIR/address-of.rs:+13:12: +13:24 - StorageLive(_21); // scope 6 at $DIR/address-of.rs:+15:5: +15:18 - StorageLive(_22); // scope 6 at $DIR/address-of.rs:+15:5: +15:18 - _22 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:+15:5: +15:6 - AscribeUserType(_22, o, UserTypeProjection { base: UserType(10), projs: [] }); // scope 6 at $DIR/address-of.rs:+15:5: +15:18 - _21 = _22; // scope 6 at $DIR/address-of.rs:+15:5: +15:18 - StorageDead(_22); // scope 6 at $DIR/address-of.rs:+15:18: +15:19 - StorageDead(_21); // scope 6 at $DIR/address-of.rs:+15:18: +15:19 - StorageLive(_23); // scope 6 at $DIR/address-of.rs:+16:5: +16:26 - _23 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:+16:5: +16:6 - StorageDead(_23); // scope 6 at $DIR/address-of.rs:+16:26: +16:27 - StorageLive(_24); // scope 6 at $DIR/address-of.rs:+17:5: +17:25 - StorageLive(_25); // scope 6 at $DIR/address-of.rs:+17:5: +17:25 - StorageLive(_26); // scope 6 at $DIR/address-of.rs:+17:5: +17:6 - _26 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:+17:5: +17:6 - _25 = move _26 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 6 at $DIR/address-of.rs:+17:5: +17:6 - StorageDead(_26); // scope 6 at $DIR/address-of.rs:+17:5: +17:6 - AscribeUserType(_25, o, UserTypeProjection { base: UserType(11), projs: [] }); // scope 6 at $DIR/address-of.rs:+17:5: +17:25 - _24 = _25; // scope 6 at $DIR/address-of.rs:+17:5: +17:25 - StorageDead(_25); // scope 6 at $DIR/address-of.rs:+17:25: +17:26 - StorageDead(_24); // scope 6 at $DIR/address-of.rs:+17:25: +17:26 - StorageLive(_27); // scope 6 at $DIR/address-of.rs:+18:5: +18:22 - StorageLive(_28); // scope 6 at $DIR/address-of.rs:+18:5: +18:6 - _28 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:+18:5: +18:6 - _27 = move _28 as *const [i32] (Pointer(Unsize)); // scope 6 at $DIR/address-of.rs:+18:5: +18:6 - StorageDead(_28); // scope 6 at $DIR/address-of.rs:+18:5: +18:6 - StorageDead(_27); // scope 6 at $DIR/address-of.rs:+18:22: +18:23 - StorageLive(_29); // scope 6 at $DIR/address-of.rs:+20:9: +20:10 - _29 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:+20:23: +20:24 - FakeRead(ForLet(None), _29); // scope 6 at $DIR/address-of.rs:+20:9: +20:10 - AscribeUserType(_29, o, UserTypeProjection { base: UserType(13), projs: [] }); // scope 6 at $DIR/address-of.rs:+20:12: +20:20 - StorageLive(_30); // scope 7 at $DIR/address-of.rs:+21:9: +21:10 - _30 = &raw const (*_3); // scope 7 at $DIR/address-of.rs:+21:31: +21:32 - FakeRead(ForLet(None), _30); // scope 7 at $DIR/address-of.rs:+21:9: +21:10 - AscribeUserType(_30, o, UserTypeProjection { base: UserType(15), projs: [] }); // scope 7 at $DIR/address-of.rs:+21:12: +21:28 - StorageLive(_31); // scope 8 at $DIR/address-of.rs:+22:9: +22:10 - StorageLive(_32); // scope 8 at $DIR/address-of.rs:+22:30: +22:31 - _32 = &raw const (*_3); // scope 8 at $DIR/address-of.rs:+22:30: +22:31 - _31 = move _32 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 8 at $DIR/address-of.rs:+22:30: +22:31 - StorageDead(_32); // scope 8 at $DIR/address-of.rs:+22:30: +22:31 - FakeRead(ForLet(None), _31); // scope 8 at $DIR/address-of.rs:+22:9: +22:10 - AscribeUserType(_31, o, UserTypeProjection { base: UserType(17), projs: [] }); // scope 8 at $DIR/address-of.rs:+22:12: +22:27 - StorageLive(_33); // scope 9 at $DIR/address-of.rs:+23:9: +23:10 - StorageLive(_34); // scope 9 at $DIR/address-of.rs:+23:27: +23:28 - _34 = &raw const (*_3); // scope 9 at $DIR/address-of.rs:+23:27: +23:28 - _33 = move _34 as *const [i32] (Pointer(Unsize)); // scope 9 at $DIR/address-of.rs:+23:27: +23:28 - StorageDead(_34); // scope 9 at $DIR/address-of.rs:+23:27: +23:28 - FakeRead(ForLet(None), _33); // scope 9 at $DIR/address-of.rs:+23:9: +23:10 - AscribeUserType(_33, o, UserTypeProjection { base: UserType(19), projs: [] }); // scope 9 at $DIR/address-of.rs:+23:12: +23:24 - StorageLive(_35); // scope 10 at $DIR/address-of.rs:+25:5: +25:16 - StorageLive(_36); // scope 10 at $DIR/address-of.rs:+25:5: +25:16 - _36 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:+25:5: +25:6 - AscribeUserType(_36, o, UserTypeProjection { base: UserType(20), projs: [] }); // scope 10 at $DIR/address-of.rs:+25:5: +25:16 - _35 = _36; // scope 10 at $DIR/address-of.rs:+25:5: +25:16 - StorageDead(_36); // scope 10 at $DIR/address-of.rs:+25:16: +25:17 - StorageDead(_35); // scope 10 at $DIR/address-of.rs:+25:16: +25:17 - StorageLive(_37); // scope 10 at $DIR/address-of.rs:+26:5: +26:24 - _37 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:+26:5: +26:6 - StorageDead(_37); // scope 10 at $DIR/address-of.rs:+26:24: +26:25 - StorageLive(_38); // scope 10 at $DIR/address-of.rs:+27:5: +27:23 - StorageLive(_39); // scope 10 at $DIR/address-of.rs:+27:5: +27:23 - StorageLive(_40); // scope 10 at $DIR/address-of.rs:+27:5: +27:6 - _40 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:+27:5: +27:6 - _39 = move _40 as *mut dyn std::marker::Send (Pointer(Unsize)); // scope 10 at $DIR/address-of.rs:+27:5: +27:6 - StorageDead(_40); // scope 10 at $DIR/address-of.rs:+27:5: +27:6 - AscribeUserType(_39, o, UserTypeProjection { base: UserType(21), projs: [] }); // scope 10 at $DIR/address-of.rs:+27:5: +27:23 - _38 = _39; // scope 10 at $DIR/address-of.rs:+27:5: +27:23 - StorageDead(_39); // scope 10 at $DIR/address-of.rs:+27:23: +27:24 - StorageDead(_38); // scope 10 at $DIR/address-of.rs:+27:23: +27:24 - StorageLive(_41); // scope 10 at $DIR/address-of.rs:+28:5: +28:20 - StorageLive(_42); // scope 10 at $DIR/address-of.rs:+28:5: +28:6 - _42 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:+28:5: +28:6 - _41 = move _42 as *mut [i32] (Pointer(Unsize)); // scope 10 at $DIR/address-of.rs:+28:5: +28:6 - StorageDead(_42); // scope 10 at $DIR/address-of.rs:+28:5: +28:6 - StorageDead(_41); // scope 10 at $DIR/address-of.rs:+28:20: +28:21 - StorageLive(_43); // scope 10 at $DIR/address-of.rs:+30:9: +30:10 - _43 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:+30:21: +30:22 - FakeRead(ForLet(None), _43); // scope 10 at $DIR/address-of.rs:+30:9: +30:10 - AscribeUserType(_43, o, UserTypeProjection { base: UserType(23), projs: [] }); // scope 10 at $DIR/address-of.rs:+30:12: +30:18 - StorageLive(_44); // scope 11 at $DIR/address-of.rs:+31:9: +31:10 - _44 = &raw mut (*_3); // scope 11 at $DIR/address-of.rs:+31:29: +31:30 - FakeRead(ForLet(None), _44); // scope 11 at $DIR/address-of.rs:+31:9: +31:10 - AscribeUserType(_44, o, UserTypeProjection { base: UserType(25), projs: [] }); // scope 11 at $DIR/address-of.rs:+31:12: +31:26 - StorageLive(_45); // scope 12 at $DIR/address-of.rs:+32:9: +32:10 - StorageLive(_46); // scope 12 at $DIR/address-of.rs:+32:28: +32:29 - _46 = &raw mut (*_3); // scope 12 at $DIR/address-of.rs:+32:28: +32:29 - _45 = move _46 as *mut dyn std::marker::Send (Pointer(Unsize)); // scope 12 at $DIR/address-of.rs:+32:28: +32:29 - StorageDead(_46); // scope 12 at $DIR/address-of.rs:+32:28: +32:29 - FakeRead(ForLet(None), _45); // scope 12 at $DIR/address-of.rs:+32:9: +32:10 - AscribeUserType(_45, o, UserTypeProjection { base: UserType(27), projs: [] }); // scope 12 at $DIR/address-of.rs:+32:12: +32:25 - StorageLive(_47); // scope 13 at $DIR/address-of.rs:+33:9: +33:10 - StorageLive(_48); // scope 13 at $DIR/address-of.rs:+33:25: +33:26 - _48 = &raw mut (*_3); // scope 13 at $DIR/address-of.rs:+33:25: +33:26 - _47 = move _48 as *mut [i32] (Pointer(Unsize)); // scope 13 at $DIR/address-of.rs:+33:25: +33:26 - StorageDead(_48); // scope 13 at $DIR/address-of.rs:+33:25: +33:26 - FakeRead(ForLet(None), _47); // scope 13 at $DIR/address-of.rs:+33:9: +33:10 - AscribeUserType(_47, o, UserTypeProjection { base: UserType(29), projs: [] }); // scope 13 at $DIR/address-of.rs:+33:12: +33:22 - _0 = const (); // scope 0 at $DIR/address-of.rs:+0:26: +34:2 - StorageDead(_47); // scope 13 at $DIR/address-of.rs:+34:1: +34:2 - StorageDead(_45); // scope 12 at $DIR/address-of.rs:+34:1: +34:2 - StorageDead(_44); // scope 11 at $DIR/address-of.rs:+34:1: +34:2 - StorageDead(_43); // scope 10 at $DIR/address-of.rs:+34:1: +34:2 - StorageDead(_33); // scope 9 at $DIR/address-of.rs:+34:1: +34:2 - StorageDead(_31); // scope 8 at $DIR/address-of.rs:+34:1: +34:2 - StorageDead(_30); // scope 7 at $DIR/address-of.rs:+34:1: +34:2 - StorageDead(_29); // scope 6 at $DIR/address-of.rs:+34:1: +34:2 - StorageDead(_19); // scope 5 at $DIR/address-of.rs:+34:1: +34:2 - StorageDead(_17); // scope 4 at $DIR/address-of.rs:+34:1: +34:2 - StorageDead(_16); // scope 3 at $DIR/address-of.rs:+34:1: +34:2 - StorageDead(_15); // scope 2 at $DIR/address-of.rs:+34:1: +34:2 - StorageDead(_4); // scope 1 at $DIR/address-of.rs:+34:1: +34:2 - StorageDead(_3); // scope 1 at $DIR/address-of.rs:+34:1: +34:2 - StorageDead(_2); // scope 0 at $DIR/address-of.rs:+34:1: +34:2 - StorageDead(_1); // scope 0 at $DIR/address-of.rs:+34:1: +34:2 - return; // scope 0 at $DIR/address-of.rs:+34:2: +34:2 + StorageLive(_1); // scope 0 at $DIR/address-of.rs:4:9: 4:10 + StorageLive(_2); // scope 0 at $DIR/address-of.rs:4:14: 4:21 + _2 = [const 0_i32; 10]; // scope 0 at $DIR/address-of.rs:4:14: 4:21 + _1 = &_2; // scope 0 at $DIR/address-of.rs:4:13: 4:21 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/address-of.rs:4:9: 4:10 + StorageLive(_3); // scope 1 at $DIR/address-of.rs:5:9: 5:14 + StorageLive(_4); // scope 1 at $DIR/address-of.rs:5:22: 5:29 + _4 = [const 0_i32; 10]; // scope 1 at $DIR/address-of.rs:5:22: 5:29 + _3 = &mut _4; // scope 1 at $DIR/address-of.rs:5:17: 5:29 + FakeRead(ForLet(None), _3); // scope 1 at $DIR/address-of.rs:5:9: 5:14 + StorageLive(_5); // scope 2 at $DIR/address-of.rs:7:5: 7:18 + StorageLive(_6); // scope 2 at $DIR/address-of.rs:7:5: 7:18 + _6 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:7:5: 7:6 + AscribeUserType(_6, o, UserTypeProjection { base: UserType(0), projs: [] }); // scope 2 at $DIR/address-of.rs:7:5: 7:18 + _5 = _6; // scope 2 at $DIR/address-of.rs:7:5: 7:18 + StorageDead(_6); // scope 2 at $DIR/address-of.rs:7:18: 7:19 + StorageDead(_5); // scope 2 at $DIR/address-of.rs:7:18: 7:19 + StorageLive(_7); // scope 2 at $DIR/address-of.rs:8:5: 8:26 + _7 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:8:5: 8:6 + StorageDead(_7); // scope 2 at $DIR/address-of.rs:8:26: 8:27 + StorageLive(_8); // scope 2 at $DIR/address-of.rs:9:5: 9:25 + StorageLive(_9); // scope 2 at $DIR/address-of.rs:9:5: 9:25 + StorageLive(_10); // scope 2 at $DIR/address-of.rs:9:5: 9:6 + _10 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:9:5: 9:6 + _9 = move _10 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 2 at $DIR/address-of.rs:9:5: 9:6 + StorageDead(_10); // scope 2 at $DIR/address-of.rs:9:5: 9:6 + AscribeUserType(_9, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 2 at $DIR/address-of.rs:9:5: 9:25 + _8 = _9; // scope 2 at $DIR/address-of.rs:9:5: 9:25 + StorageDead(_9); // scope 2 at $DIR/address-of.rs:9:25: 9:26 + StorageDead(_8); // scope 2 at $DIR/address-of.rs:9:25: 9:26 + StorageLive(_11); // scope 2 at $DIR/address-of.rs:10:5: 10:22 + StorageLive(_12); // scope 2 at $DIR/address-of.rs:10:5: 10:6 + _12 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:10:5: 10:6 + _11 = move _12 as *const [i32] (Pointer(Unsize)); // scope 2 at $DIR/address-of.rs:10:5: 10:6 + StorageDead(_12); // scope 2 at $DIR/address-of.rs:10:5: 10:6 + StorageDead(_11); // scope 2 at $DIR/address-of.rs:10:22: 10:23 + StorageLive(_13); // scope 2 at $DIR/address-of.rs:11:5: 11:20 + StorageLive(_14); // scope 2 at $DIR/address-of.rs:11:5: 11:6 + _14 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:11:5: 11:6 + _13 = move _14 as *const i32 (Pointer(ArrayToPointer)); // scope 2 at $DIR/address-of.rs:11:5: 11:20 + StorageDead(_14); // scope 2 at $DIR/address-of.rs:11:19: 11:20 + StorageDead(_13); // scope 2 at $DIR/address-of.rs:11:20: 11:21 + StorageLive(_15); // scope 2 at $DIR/address-of.rs:13:9: 13:10 + _15 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:13:23: 13:24 + FakeRead(ForLet(None), _15); // scope 2 at $DIR/address-of.rs:13:9: 13:10 + AscribeUserType(_15, o, UserTypeProjection { base: UserType(3), projs: [] }); // scope 2 at $DIR/address-of.rs:13:12: 13:20 + StorageLive(_16); // scope 3 at $DIR/address-of.rs:14:9: 14:10 + _16 = &raw const (*_1); // scope 3 at $DIR/address-of.rs:14:31: 14:32 + FakeRead(ForLet(None), _16); // scope 3 at $DIR/address-of.rs:14:9: 14:10 + AscribeUserType(_16, o, UserTypeProjection { base: UserType(5), projs: [] }); // scope 3 at $DIR/address-of.rs:14:12: 14:28 + StorageLive(_17); // scope 4 at $DIR/address-of.rs:15:9: 15:10 + StorageLive(_18); // scope 4 at $DIR/address-of.rs:15:30: 15:31 + _18 = &raw const (*_1); // scope 4 at $DIR/address-of.rs:15:30: 15:31 + _17 = move _18 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 4 at $DIR/address-of.rs:15:30: 15:31 + StorageDead(_18); // scope 4 at $DIR/address-of.rs:15:30: 15:31 + FakeRead(ForLet(None), _17); // scope 4 at $DIR/address-of.rs:15:9: 15:10 + AscribeUserType(_17, o, UserTypeProjection { base: UserType(7), projs: [] }); // scope 4 at $DIR/address-of.rs:15:12: 15:27 + StorageLive(_19); // scope 5 at $DIR/address-of.rs:16:9: 16:10 + StorageLive(_20); // scope 5 at $DIR/address-of.rs:16:27: 16:28 + _20 = &raw const (*_1); // scope 5 at $DIR/address-of.rs:16:27: 16:28 + _19 = move _20 as *const [i32] (Pointer(Unsize)); // scope 5 at $DIR/address-of.rs:16:27: 16:28 + StorageDead(_20); // scope 5 at $DIR/address-of.rs:16:27: 16:28 + FakeRead(ForLet(None), _19); // scope 5 at $DIR/address-of.rs:16:9: 16:10 + AscribeUserType(_19, o, UserTypeProjection { base: UserType(9), projs: [] }); // scope 5 at $DIR/address-of.rs:16:12: 16:24 + StorageLive(_21); // scope 6 at $DIR/address-of.rs:18:5: 18:18 + StorageLive(_22); // scope 6 at $DIR/address-of.rs:18:5: 18:18 + _22 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:18:5: 18:6 + AscribeUserType(_22, o, UserTypeProjection { base: UserType(10), projs: [] }); // scope 6 at $DIR/address-of.rs:18:5: 18:18 + _21 = _22; // scope 6 at $DIR/address-of.rs:18:5: 18:18 + StorageDead(_22); // scope 6 at $DIR/address-of.rs:18:18: 18:19 + StorageDead(_21); // scope 6 at $DIR/address-of.rs:18:18: 18:19 + StorageLive(_23); // scope 6 at $DIR/address-of.rs:19:5: 19:26 + _23 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:19:5: 19:6 + StorageDead(_23); // scope 6 at $DIR/address-of.rs:19:26: 19:27 + StorageLive(_24); // scope 6 at $DIR/address-of.rs:20:5: 20:25 + StorageLive(_25); // scope 6 at $DIR/address-of.rs:20:5: 20:25 + StorageLive(_26); // scope 6 at $DIR/address-of.rs:20:5: 20:6 + _26 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:20:5: 20:6 + _25 = move _26 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 6 at $DIR/address-of.rs:20:5: 20:6 + StorageDead(_26); // scope 6 at $DIR/address-of.rs:20:5: 20:6 + AscribeUserType(_25, o, UserTypeProjection { base: UserType(11), projs: [] }); // scope 6 at $DIR/address-of.rs:20:5: 20:25 + _24 = _25; // scope 6 at $DIR/address-of.rs:20:5: 20:25 + StorageDead(_25); // scope 6 at $DIR/address-of.rs:20:25: 20:26 + StorageDead(_24); // scope 6 at $DIR/address-of.rs:20:25: 20:26 + StorageLive(_27); // scope 6 at $DIR/address-of.rs:21:5: 21:22 + StorageLive(_28); // scope 6 at $DIR/address-of.rs:21:5: 21:6 + _28 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:21:5: 21:6 + _27 = move _28 as *const [i32] (Pointer(Unsize)); // scope 6 at $DIR/address-of.rs:21:5: 21:6 + StorageDead(_28); // scope 6 at $DIR/address-of.rs:21:5: 21:6 + StorageDead(_27); // scope 6 at $DIR/address-of.rs:21:22: 21:23 + StorageLive(_29); // scope 6 at $DIR/address-of.rs:23:9: 23:10 + _29 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:23:23: 23:24 + FakeRead(ForLet(None), _29); // scope 6 at $DIR/address-of.rs:23:9: 23:10 + AscribeUserType(_29, o, UserTypeProjection { base: UserType(13), projs: [] }); // scope 6 at $DIR/address-of.rs:23:12: 23:20 + StorageLive(_30); // scope 7 at $DIR/address-of.rs:24:9: 24:10 + _30 = &raw const (*_3); // scope 7 at $DIR/address-of.rs:24:31: 24:32 + FakeRead(ForLet(None), _30); // scope 7 at $DIR/address-of.rs:24:9: 24:10 + AscribeUserType(_30, o, UserTypeProjection { base: UserType(15), projs: [] }); // scope 7 at $DIR/address-of.rs:24:12: 24:28 + StorageLive(_31); // scope 8 at $DIR/address-of.rs:25:9: 25:10 + StorageLive(_32); // scope 8 at $DIR/address-of.rs:25:30: 25:31 + _32 = &raw const (*_3); // scope 8 at $DIR/address-of.rs:25:30: 25:31 + _31 = move _32 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 8 at $DIR/address-of.rs:25:30: 25:31 + StorageDead(_32); // scope 8 at $DIR/address-of.rs:25:30: 25:31 + FakeRead(ForLet(None), _31); // scope 8 at $DIR/address-of.rs:25:9: 25:10 + AscribeUserType(_31, o, UserTypeProjection { base: UserType(17), projs: [] }); // scope 8 at $DIR/address-of.rs:25:12: 25:27 + StorageLive(_33); // scope 9 at $DIR/address-of.rs:26:9: 26:10 + StorageLive(_34); // scope 9 at $DIR/address-of.rs:26:27: 26:28 + _34 = &raw const (*_3); // scope 9 at $DIR/address-of.rs:26:27: 26:28 + _33 = move _34 as *const [i32] (Pointer(Unsize)); // scope 9 at $DIR/address-of.rs:26:27: 26:28 + StorageDead(_34); // scope 9 at $DIR/address-of.rs:26:27: 26:28 + FakeRead(ForLet(None), _33); // scope 9 at $DIR/address-of.rs:26:9: 26:10 + AscribeUserType(_33, o, UserTypeProjection { base: UserType(19), projs: [] }); // scope 9 at $DIR/address-of.rs:26:12: 26:24 + StorageLive(_35); // scope 10 at $DIR/address-of.rs:28:5: 28:16 + StorageLive(_36); // scope 10 at $DIR/address-of.rs:28:5: 28:16 + _36 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:28:5: 28:6 + AscribeUserType(_36, o, UserTypeProjection { base: UserType(20), projs: [] }); // scope 10 at $DIR/address-of.rs:28:5: 28:16 + _35 = _36; // scope 10 at $DIR/address-of.rs:28:5: 28:16 + StorageDead(_36); // scope 10 at $DIR/address-of.rs:28:16: 28:17 + StorageDead(_35); // scope 10 at $DIR/address-of.rs:28:16: 28:17 + StorageLive(_37); // scope 10 at $DIR/address-of.rs:29:5: 29:24 + _37 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:29:5: 29:6 + StorageDead(_37); // scope 10 at $DIR/address-of.rs:29:24: 29:25 + StorageLive(_38); // scope 10 at $DIR/address-of.rs:30:5: 30:23 + StorageLive(_39); // scope 10 at $DIR/address-of.rs:30:5: 30:23 + StorageLive(_40); // scope 10 at $DIR/address-of.rs:30:5: 30:6 + _40 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:30:5: 30:6 + _39 = move _40 as *mut dyn std::marker::Send (Pointer(Unsize)); // scope 10 at $DIR/address-of.rs:30:5: 30:6 + StorageDead(_40); // scope 10 at $DIR/address-of.rs:30:5: 30:6 + AscribeUserType(_39, o, UserTypeProjection { base: UserType(21), projs: [] }); // scope 10 at $DIR/address-of.rs:30:5: 30:23 + _38 = _39; // scope 10 at $DIR/address-of.rs:30:5: 30:23 + StorageDead(_39); // scope 10 at $DIR/address-of.rs:30:23: 30:24 + StorageDead(_38); // scope 10 at $DIR/address-of.rs:30:23: 30:24 + StorageLive(_41); // scope 10 at $DIR/address-of.rs:31:5: 31:20 + StorageLive(_42); // scope 10 at $DIR/address-of.rs:31:5: 31:6 + _42 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:31:5: 31:6 + _41 = move _42 as *mut [i32] (Pointer(Unsize)); // scope 10 at $DIR/address-of.rs:31:5: 31:6 + StorageDead(_42); // scope 10 at $DIR/address-of.rs:31:5: 31:6 + StorageDead(_41); // scope 10 at $DIR/address-of.rs:31:20: 31:21 + StorageLive(_43); // scope 10 at $DIR/address-of.rs:33:9: 33:10 + _43 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:33:21: 33:22 + FakeRead(ForLet(None), _43); // scope 10 at $DIR/address-of.rs:33:9: 33:10 + AscribeUserType(_43, o, UserTypeProjection { base: UserType(23), projs: [] }); // scope 10 at $DIR/address-of.rs:33:12: 33:18 + StorageLive(_44); // scope 11 at $DIR/address-of.rs:34:9: 34:10 + _44 = &raw mut (*_3); // scope 11 at $DIR/address-of.rs:34:29: 34:30 + FakeRead(ForLet(None), _44); // scope 11 at $DIR/address-of.rs:34:9: 34:10 + AscribeUserType(_44, o, UserTypeProjection { base: UserType(25), projs: [] }); // scope 11 at $DIR/address-of.rs:34:12: 34:26 + StorageLive(_45); // scope 12 at $DIR/address-of.rs:35:9: 35:10 + StorageLive(_46); // scope 12 at $DIR/address-of.rs:35:28: 35:29 + _46 = &raw mut (*_3); // scope 12 at $DIR/address-of.rs:35:28: 35:29 + _45 = move _46 as *mut dyn std::marker::Send (Pointer(Unsize)); // scope 12 at $DIR/address-of.rs:35:28: 35:29 + StorageDead(_46); // scope 12 at $DIR/address-of.rs:35:28: 35:29 + FakeRead(ForLet(None), _45); // scope 12 at $DIR/address-of.rs:35:9: 35:10 + AscribeUserType(_45, o, UserTypeProjection { base: UserType(27), projs: [] }); // scope 12 at $DIR/address-of.rs:35:12: 35:25 + StorageLive(_47); // scope 13 at $DIR/address-of.rs:36:9: 36:10 + StorageLive(_48); // scope 13 at $DIR/address-of.rs:36:25: 36:26 + _48 = &raw mut (*_3); // scope 13 at $DIR/address-of.rs:36:25: 36:26 + _47 = move _48 as *mut [i32] (Pointer(Unsize)); // scope 13 at $DIR/address-of.rs:36:25: 36:26 + StorageDead(_48); // scope 13 at $DIR/address-of.rs:36:25: 36:26 + FakeRead(ForLet(None), _47); // scope 13 at $DIR/address-of.rs:36:9: 36:10 + AscribeUserType(_47, o, UserTypeProjection { base: UserType(29), projs: [] }); // scope 13 at $DIR/address-of.rs:36:12: 36:22 + _0 = const (); // scope 0 at $DIR/address-of.rs:3:26: 37:2 + StorageDead(_47); // scope 13 at $DIR/address-of.rs:37:1: 37:2 + StorageDead(_45); // scope 12 at $DIR/address-of.rs:37:1: 37:2 + StorageDead(_44); // scope 11 at $DIR/address-of.rs:37:1: 37:2 + StorageDead(_43); // scope 10 at $DIR/address-of.rs:37:1: 37:2 + StorageDead(_33); // scope 9 at $DIR/address-of.rs:37:1: 37:2 + StorageDead(_31); // scope 8 at $DIR/address-of.rs:37:1: 37:2 + StorageDead(_30); // scope 7 at $DIR/address-of.rs:37:1: 37:2 + StorageDead(_29); // scope 6 at $DIR/address-of.rs:37:1: 37:2 + StorageDead(_19); // scope 5 at $DIR/address-of.rs:37:1: 37:2 + StorageDead(_17); // scope 4 at $DIR/address-of.rs:37:1: 37:2 + StorageDead(_16); // scope 3 at $DIR/address-of.rs:37:1: 37:2 + StorageDead(_15); // scope 2 at $DIR/address-of.rs:37:1: 37:2 + StorageDead(_4); // scope 1 at $DIR/address-of.rs:37:1: 37:2 + StorageDead(_3); // scope 1 at $DIR/address-of.rs:37:1: 37:2 + StorageDead(_2); // scope 0 at $DIR/address-of.rs:37:1: 37:2 + StorageDead(_1); // scope 0 at $DIR/address-of.rs:37:1: 37:2 + return; // scope 0 at $DIR/address-of.rs:37:2: 37:2 } } diff --git a/src/test/mir-opt/address_of.borrow_and_cast.SimplifyCfg-initial.after.mir b/src/test/mir-opt/address_of.borrow_and_cast.SimplifyCfg-initial.after.mir index 060077b8adb9e..195f3e2e65c64 100644 --- a/src/test/mir-opt/address_of.borrow_and_cast.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/address_of.borrow_and_cast.SimplifyCfg-initial.after.mir @@ -1,47 +1,47 @@ // MIR for `borrow_and_cast` after SimplifyCfg-initial fn borrow_and_cast(_1: i32) -> () { - debug x => _1; // in scope 0 at $DIR/address-of.rs:+0:20: +0:25 - let mut _0: (); // return place in scope 0 at $DIR/address-of.rs:+0:32: +0:32 - let _2: *const i32; // in scope 0 at $DIR/address-of.rs:+1:9: +1:10 - let _3: &i32; // in scope 0 at $DIR/address-of.rs:+1:13: +1:15 - let _5: &mut i32; // in scope 0 at $DIR/address-of.rs:+2:13: +2:19 - let mut _7: &mut i32; // in scope 0 at $DIR/address-of.rs:+3:13: +3:19 + debug x => _1; // in scope 0 at $DIR/address-of.rs:41:20: 41:25 + let mut _0: (); // return place in scope 0 at $DIR/address-of.rs:41:32: 41:32 + let _2: *const i32; // in scope 0 at $DIR/address-of.rs:42:9: 42:10 + let _3: &i32; // in scope 0 at $DIR/address-of.rs:42:13: 42:15 + let _5: &mut i32; // in scope 0 at $DIR/address-of.rs:43:13: 43:19 + let mut _7: &mut i32; // in scope 0 at $DIR/address-of.rs:44:13: 44:19 scope 1 { - debug p => _2; // in scope 1 at $DIR/address-of.rs:+1:9: +1:10 - let _4: *const i32; // in scope 1 at $DIR/address-of.rs:+2:9: +2:10 + debug p => _2; // in scope 1 at $DIR/address-of.rs:42:9: 42:10 + let _4: *const i32; // in scope 1 at $DIR/address-of.rs:43:9: 43:10 scope 2 { - debug q => _4; // in scope 2 at $DIR/address-of.rs:+2:9: +2:10 - let _6: *mut i32; // in scope 2 at $DIR/address-of.rs:+3:9: +3:10 + debug q => _4; // in scope 2 at $DIR/address-of.rs:43:9: 43:10 + let _6: *mut i32; // in scope 2 at $DIR/address-of.rs:44:9: 44:10 scope 3 { - debug r => _6; // in scope 3 at $DIR/address-of.rs:+3:9: +3:10 + debug r => _6; // in scope 3 at $DIR/address-of.rs:44:9: 44:10 } } } bb0: { - StorageLive(_2); // scope 0 at $DIR/address-of.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/address-of.rs:+1:13: +1:15 - _3 = &_1; // scope 0 at $DIR/address-of.rs:+1:13: +1:15 - _2 = &raw const (*_3); // scope 0 at $DIR/address-of.rs:+1:13: +1:15 - FakeRead(ForLet(None), _2); // scope 0 at $DIR/address-of.rs:+1:9: +1:10 - StorageDead(_3); // scope 0 at $DIR/address-of.rs:+1:29: +1:30 - StorageLive(_4); // scope 1 at $DIR/address-of.rs:+2:9: +2:10 - StorageLive(_5); // scope 1 at $DIR/address-of.rs:+2:13: +2:19 - _5 = &mut _1; // scope 1 at $DIR/address-of.rs:+2:13: +2:19 - _4 = &raw const (*_5); // scope 1 at $DIR/address-of.rs:+2:13: +2:19 - FakeRead(ForLet(None), _4); // scope 1 at $DIR/address-of.rs:+2:9: +2:10 - StorageDead(_5); // scope 1 at $DIR/address-of.rs:+2:33: +2:34 - StorageLive(_6); // scope 2 at $DIR/address-of.rs:+3:9: +3:10 - StorageLive(_7); // scope 2 at $DIR/address-of.rs:+3:13: +3:19 - _7 = &mut _1; // scope 2 at $DIR/address-of.rs:+3:13: +3:19 - _6 = &raw mut (*_7); // scope 2 at $DIR/address-of.rs:+3:13: +3:19 - FakeRead(ForLet(None), _6); // scope 2 at $DIR/address-of.rs:+3:9: +3:10 - StorageDead(_7); // scope 2 at $DIR/address-of.rs:+3:31: +3:32 - _0 = const (); // scope 0 at $DIR/address-of.rs:+0:32: +4:2 - StorageDead(_6); // scope 2 at $DIR/address-of.rs:+4:1: +4:2 - StorageDead(_4); // scope 1 at $DIR/address-of.rs:+4:1: +4:2 - StorageDead(_2); // scope 0 at $DIR/address-of.rs:+4:1: +4:2 - return; // scope 0 at $DIR/address-of.rs:+4:2: +4:2 + StorageLive(_2); // scope 0 at $DIR/address-of.rs:42:9: 42:10 + StorageLive(_3); // scope 0 at $DIR/address-of.rs:42:13: 42:15 + _3 = &_1; // scope 0 at $DIR/address-of.rs:42:13: 42:15 + _2 = &raw const (*_3); // scope 0 at $DIR/address-of.rs:42:13: 42:15 + FakeRead(ForLet(None), _2); // scope 0 at $DIR/address-of.rs:42:9: 42:10 + StorageDead(_3); // scope 0 at $DIR/address-of.rs:42:29: 42:30 + StorageLive(_4); // scope 1 at $DIR/address-of.rs:43:9: 43:10 + StorageLive(_5); // scope 1 at $DIR/address-of.rs:43:13: 43:19 + _5 = &mut _1; // scope 1 at $DIR/address-of.rs:43:13: 43:19 + _4 = &raw const (*_5); // scope 1 at $DIR/address-of.rs:43:13: 43:19 + FakeRead(ForLet(None), _4); // scope 1 at $DIR/address-of.rs:43:9: 43:10 + StorageDead(_5); // scope 1 at $DIR/address-of.rs:43:33: 43:34 + StorageLive(_6); // scope 2 at $DIR/address-of.rs:44:9: 44:10 + StorageLive(_7); // scope 2 at $DIR/address-of.rs:44:13: 44:19 + _7 = &mut _1; // scope 2 at $DIR/address-of.rs:44:13: 44:19 + _6 = &raw mut (*_7); // scope 2 at $DIR/address-of.rs:44:13: 44:19 + FakeRead(ForLet(None), _6); // scope 2 at $DIR/address-of.rs:44:9: 44:10 + StorageDead(_7); // scope 2 at $DIR/address-of.rs:44:31: 44:32 + _0 = const (); // scope 0 at $DIR/address-of.rs:41:32: 45:2 + StorageDead(_6); // scope 2 at $DIR/address-of.rs:45:1: 45:2 + StorageDead(_4); // scope 1 at $DIR/address-of.rs:45:1: 45:2 + StorageDead(_2); // scope 0 at $DIR/address-of.rs:45:1: 45:2 + return; // scope 0 at $DIR/address-of.rs:45:2: 45:2 } } diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir index 27f883ed321ae..c8848caa02709 100644 --- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir +++ b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir @@ -1,22 +1,22 @@ // MIR for `main` after SimplifyCfg-elaborate-drops fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +0:11 - let mut _1: [u32; 3]; // in scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14 - let mut _4: &mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+3:25: +3:31 - let mut _5: u32; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:12: +4:29 - let mut _6: *mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:25: +4:26 - let _7: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:7: +4:8 - let mut _8: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9 - let mut _9: bool; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9 + let mut _0: (); // return place in scope 0 at $DIR/array-index-is-temporary.rs:12:11: 12:11 + let mut _1: [u32; 3]; // in scope 0 at $DIR/array-index-is-temporary.rs:13:9: 13:14 + let mut _4: &mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:15:25: 15:31 + let mut _5: u32; // in scope 0 at $DIR/array-index-is-temporary.rs:16:12: 16:29 + let mut _6: *mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:16:25: 16:26 + let _7: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:16:7: 16:8 + let mut _8: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:16:5: 16:9 + let mut _9: bool; // in scope 0 at $DIR/array-index-is-temporary.rs:16:5: 16:9 scope 1 { - debug x => _1; // in scope 1 at $DIR/array-index-is-temporary.rs:+1:9: +1:14 - let mut _2: usize; // in scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14 + debug x => _1; // in scope 1 at $DIR/array-index-is-temporary.rs:13:9: 13:14 + let mut _2: usize; // in scope 1 at $DIR/array-index-is-temporary.rs:14:9: 14:14 scope 2 { - debug y => _2; // in scope 2 at $DIR/array-index-is-temporary.rs:+2:9: +2:14 - let _3: *mut usize; // in scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10 + debug y => _2; // in scope 2 at $DIR/array-index-is-temporary.rs:14:9: 14:14 + let _3: *mut usize; // in scope 2 at $DIR/array-index-is-temporary.rs:15:9: 15:10 scope 3 { - debug z => _3; // in scope 3 at $DIR/array-index-is-temporary.rs:+3:9: +3:10 + debug z => _3; // in scope 3 at $DIR/array-index-is-temporary.rs:15:9: 15:10 scope 4 { } } @@ -24,41 +24,41 @@ fn main() -> () { } bb0: { - StorageLive(_1); // scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14 - _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:+1:17: +1:29 - StorageLive(_2); // scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14 - _2 = const 1_usize; // scope 1 at $DIR/array-index-is-temporary.rs:+2:17: +2:18 - StorageLive(_3); // scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10 - StorageLive(_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31 - _4 = &mut _2; // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31 - _3 = &raw mut (*_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31 - StorageDead(_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:31: +3:32 - StorageLive(_5); // scope 3 at $DIR/array-index-is-temporary.rs:+4:12: +4:29 - StorageLive(_6); // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26 - _6 = _3; // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26 - _5 = foo(move _6) -> bb1; // scope 4 at $DIR/array-index-is-temporary.rs:+4:21: +4:27 + StorageLive(_1); // scope 0 at $DIR/array-index-is-temporary.rs:13:9: 13:14 + _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:13:17: 13:29 + StorageLive(_2); // scope 1 at $DIR/array-index-is-temporary.rs:14:9: 14:14 + _2 = const 1_usize; // scope 1 at $DIR/array-index-is-temporary.rs:14:17: 14:18 + StorageLive(_3); // scope 2 at $DIR/array-index-is-temporary.rs:15:9: 15:10 + StorageLive(_4); // scope 2 at $DIR/array-index-is-temporary.rs:15:25: 15:31 + _4 = &mut _2; // scope 2 at $DIR/array-index-is-temporary.rs:15:25: 15:31 + _3 = &raw mut (*_4); // scope 2 at $DIR/array-index-is-temporary.rs:15:25: 15:31 + StorageDead(_4); // scope 2 at $DIR/array-index-is-temporary.rs:15:31: 15:32 + StorageLive(_5); // scope 3 at $DIR/array-index-is-temporary.rs:16:12: 16:29 + StorageLive(_6); // scope 4 at $DIR/array-index-is-temporary.rs:16:25: 16:26 + _6 = _3; // scope 4 at $DIR/array-index-is-temporary.rs:16:25: 16:26 + _5 = foo(move _6) -> bb1; // scope 4 at $DIR/array-index-is-temporary.rs:16:21: 16:27 // mir::Constant // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24 // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value() } } bb1: { - StorageDead(_6); // scope 4 at $DIR/array-index-is-temporary.rs:+4:26: +4:27 - StorageLive(_7); // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8 - _7 = _2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8 - _8 = Len(_1); // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9 - _9 = Lt(_7, _8); // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9 - assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9 + StorageDead(_6); // scope 4 at $DIR/array-index-is-temporary.rs:16:26: 16:27 + StorageLive(_7); // scope 3 at $DIR/array-index-is-temporary.rs:16:7: 16:8 + _7 = _2; // scope 3 at $DIR/array-index-is-temporary.rs:16:7: 16:8 + _8 = Len(_1); // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 + _9 = Lt(_7, _8); // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 } bb2: { - _1[_7] = move _5; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:29 - StorageDead(_5); // scope 3 at $DIR/array-index-is-temporary.rs:+4:28: +4:29 - StorageDead(_7); // scope 3 at $DIR/array-index-is-temporary.rs:+4:29: +4:30 - _0 = const (); // scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +5:2 - StorageDead(_3); // scope 2 at $DIR/array-index-is-temporary.rs:+5:1: +5:2 - StorageDead(_2); // scope 1 at $DIR/array-index-is-temporary.rs:+5:1: +5:2 - StorageDead(_1); // scope 0 at $DIR/array-index-is-temporary.rs:+5:1: +5:2 - return; // scope 0 at $DIR/array-index-is-temporary.rs:+5:2: +5:2 + _1[_7] = move _5; // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:29 + StorageDead(_5); // scope 3 at $DIR/array-index-is-temporary.rs:16:28: 16:29 + StorageDead(_7); // scope 3 at $DIR/array-index-is-temporary.rs:16:29: 16:30 + _0 = const (); // scope 0 at $DIR/array-index-is-temporary.rs:12:11: 17:2 + StorageDead(_3); // scope 2 at $DIR/array-index-is-temporary.rs:17:1: 17:2 + StorageDead(_2); // scope 1 at $DIR/array-index-is-temporary.rs:17:1: 17:2 + StorageDead(_1); // scope 0 at $DIR/array-index-is-temporary.rs:17:1: 17:2 + return; // scope 0 at $DIR/array-index-is-temporary.rs:17:2: 17:2 } } diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir index 27f883ed321ae..c8848caa02709 100644 --- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir +++ b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir @@ -1,22 +1,22 @@ // MIR for `main` after SimplifyCfg-elaborate-drops fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +0:11 - let mut _1: [u32; 3]; // in scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14 - let mut _4: &mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+3:25: +3:31 - let mut _5: u32; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:12: +4:29 - let mut _6: *mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:25: +4:26 - let _7: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:7: +4:8 - let mut _8: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9 - let mut _9: bool; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9 + let mut _0: (); // return place in scope 0 at $DIR/array-index-is-temporary.rs:12:11: 12:11 + let mut _1: [u32; 3]; // in scope 0 at $DIR/array-index-is-temporary.rs:13:9: 13:14 + let mut _4: &mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:15:25: 15:31 + let mut _5: u32; // in scope 0 at $DIR/array-index-is-temporary.rs:16:12: 16:29 + let mut _6: *mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:16:25: 16:26 + let _7: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:16:7: 16:8 + let mut _8: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:16:5: 16:9 + let mut _9: bool; // in scope 0 at $DIR/array-index-is-temporary.rs:16:5: 16:9 scope 1 { - debug x => _1; // in scope 1 at $DIR/array-index-is-temporary.rs:+1:9: +1:14 - let mut _2: usize; // in scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14 + debug x => _1; // in scope 1 at $DIR/array-index-is-temporary.rs:13:9: 13:14 + let mut _2: usize; // in scope 1 at $DIR/array-index-is-temporary.rs:14:9: 14:14 scope 2 { - debug y => _2; // in scope 2 at $DIR/array-index-is-temporary.rs:+2:9: +2:14 - let _3: *mut usize; // in scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10 + debug y => _2; // in scope 2 at $DIR/array-index-is-temporary.rs:14:9: 14:14 + let _3: *mut usize; // in scope 2 at $DIR/array-index-is-temporary.rs:15:9: 15:10 scope 3 { - debug z => _3; // in scope 3 at $DIR/array-index-is-temporary.rs:+3:9: +3:10 + debug z => _3; // in scope 3 at $DIR/array-index-is-temporary.rs:15:9: 15:10 scope 4 { } } @@ -24,41 +24,41 @@ fn main() -> () { } bb0: { - StorageLive(_1); // scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14 - _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:+1:17: +1:29 - StorageLive(_2); // scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14 - _2 = const 1_usize; // scope 1 at $DIR/array-index-is-temporary.rs:+2:17: +2:18 - StorageLive(_3); // scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10 - StorageLive(_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31 - _4 = &mut _2; // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31 - _3 = &raw mut (*_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31 - StorageDead(_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:31: +3:32 - StorageLive(_5); // scope 3 at $DIR/array-index-is-temporary.rs:+4:12: +4:29 - StorageLive(_6); // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26 - _6 = _3; // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26 - _5 = foo(move _6) -> bb1; // scope 4 at $DIR/array-index-is-temporary.rs:+4:21: +4:27 + StorageLive(_1); // scope 0 at $DIR/array-index-is-temporary.rs:13:9: 13:14 + _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:13:17: 13:29 + StorageLive(_2); // scope 1 at $DIR/array-index-is-temporary.rs:14:9: 14:14 + _2 = const 1_usize; // scope 1 at $DIR/array-index-is-temporary.rs:14:17: 14:18 + StorageLive(_3); // scope 2 at $DIR/array-index-is-temporary.rs:15:9: 15:10 + StorageLive(_4); // scope 2 at $DIR/array-index-is-temporary.rs:15:25: 15:31 + _4 = &mut _2; // scope 2 at $DIR/array-index-is-temporary.rs:15:25: 15:31 + _3 = &raw mut (*_4); // scope 2 at $DIR/array-index-is-temporary.rs:15:25: 15:31 + StorageDead(_4); // scope 2 at $DIR/array-index-is-temporary.rs:15:31: 15:32 + StorageLive(_5); // scope 3 at $DIR/array-index-is-temporary.rs:16:12: 16:29 + StorageLive(_6); // scope 4 at $DIR/array-index-is-temporary.rs:16:25: 16:26 + _6 = _3; // scope 4 at $DIR/array-index-is-temporary.rs:16:25: 16:26 + _5 = foo(move _6) -> bb1; // scope 4 at $DIR/array-index-is-temporary.rs:16:21: 16:27 // mir::Constant // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24 // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value() } } bb1: { - StorageDead(_6); // scope 4 at $DIR/array-index-is-temporary.rs:+4:26: +4:27 - StorageLive(_7); // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8 - _7 = _2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8 - _8 = Len(_1); // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9 - _9 = Lt(_7, _8); // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9 - assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9 + StorageDead(_6); // scope 4 at $DIR/array-index-is-temporary.rs:16:26: 16:27 + StorageLive(_7); // scope 3 at $DIR/array-index-is-temporary.rs:16:7: 16:8 + _7 = _2; // scope 3 at $DIR/array-index-is-temporary.rs:16:7: 16:8 + _8 = Len(_1); // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 + _9 = Lt(_7, _8); // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 } bb2: { - _1[_7] = move _5; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:29 - StorageDead(_5); // scope 3 at $DIR/array-index-is-temporary.rs:+4:28: +4:29 - StorageDead(_7); // scope 3 at $DIR/array-index-is-temporary.rs:+4:29: +4:30 - _0 = const (); // scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +5:2 - StorageDead(_3); // scope 2 at $DIR/array-index-is-temporary.rs:+5:1: +5:2 - StorageDead(_2); // scope 1 at $DIR/array-index-is-temporary.rs:+5:1: +5:2 - StorageDead(_1); // scope 0 at $DIR/array-index-is-temporary.rs:+5:1: +5:2 - return; // scope 0 at $DIR/array-index-is-temporary.rs:+5:2: +5:2 + _1[_7] = move _5; // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:29 + StorageDead(_5); // scope 3 at $DIR/array-index-is-temporary.rs:16:28: 16:29 + StorageDead(_7); // scope 3 at $DIR/array-index-is-temporary.rs:16:29: 16:30 + _0 = const (); // scope 0 at $DIR/array-index-is-temporary.rs:12:11: 17:2 + StorageDead(_3); // scope 2 at $DIR/array-index-is-temporary.rs:17:1: 17:2 + StorageDead(_2); // scope 1 at $DIR/array-index-is-temporary.rs:17:1: 17:2 + StorageDead(_1); // scope 0 at $DIR/array-index-is-temporary.rs:17:1: 17:2 + return; // scope 0 at $DIR/array-index-is-temporary.rs:17:2: 17:2 } } diff --git a/src/test/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir b/src/test/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir index 2487ef5c2150e..44d722d6f9bff 100644 --- a/src/test/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir +++ b/src/test/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir @@ -1,24 +1,24 @@ // MIR for `main` after AbortUnwindingCalls fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/asm_unwind_panic_abort.rs:+0:11: +0:11 - let _1: (); // in scope 0 at $DIR/asm_unwind_panic_abort.rs:+2:9: +2:49 + let mut _0: (); // return place in scope 0 at $DIR/asm_unwind_panic_abort.rs:12:11: 12:11 + let _1: (); // in scope 0 at $DIR/asm_unwind_panic_abort.rs:14:9: 14:49 scope 1 { } bb0: { - StorageLive(_1); // scope 1 at $DIR/asm_unwind_panic_abort.rs:+2:9: +2:49 - _1 = const (); // scope 1 at $DIR/asm_unwind_panic_abort.rs:+2:9: +2:49 - asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind: bb2]; // scope 1 at $DIR/asm_unwind_panic_abort.rs:+2:9: +2:49 + StorageLive(_1); // scope 1 at $DIR/asm_unwind_panic_abort.rs:14:9: 14:49 + _1 = const (); // scope 1 at $DIR/asm_unwind_panic_abort.rs:14:9: 14:49 + asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind: bb2]; // scope 1 at $DIR/asm_unwind_panic_abort.rs:14:9: 14:49 } bb1: { - StorageDead(_1); // scope 1 at $DIR/asm_unwind_panic_abort.rs:+2:48: +2:49 - _0 = const (); // scope 1 at $DIR/asm_unwind_panic_abort.rs:+1:5: +3:6 - return; // scope 0 at $DIR/asm_unwind_panic_abort.rs:+4:2: +4:2 + StorageDead(_1); // scope 1 at $DIR/asm_unwind_panic_abort.rs:14:48: 14:49 + _0 = const (); // scope 1 at $DIR/asm_unwind_panic_abort.rs:13:5: 15:6 + return; // scope 0 at $DIR/asm_unwind_panic_abort.rs:16:2: 16:2 } bb2 (cleanup): { - abort; // scope 0 at $DIR/asm_unwind_panic_abort.rs:+0:1: +4:2 + abort; // scope 0 at $DIR/asm_unwind_panic_abort.rs:12:1: 16:2 } } diff --git a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir index 1f099cd5e8370..a63a94b2ab599 100644 --- a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir @@ -5,80 +5,80 @@ | 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option>) }, span: $DIR/basic_assignment.rs:18:17: 18:33, inferred_ty: std::option::Option> | fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/basic_assignment.rs:+0:11: +0:11 - let _1: bool; // in scope 0 at $DIR/basic_assignment.rs:+1:9: +1:17 - let mut _3: bool; // in scope 0 at $DIR/basic_assignment.rs:+6:16: +6:24 - let mut _6: std::option::Option>; // in scope 0 at $DIR/basic_assignment.rs:+13:14: +13:20 + let mut _0: (); // return place in scope 0 at $DIR/basic_assignment.rs:10:11: 10:11 + let _1: bool; // in scope 0 at $DIR/basic_assignment.rs:11:9: 11:17 + let mut _3: bool; // in scope 0 at $DIR/basic_assignment.rs:16:16: 16:24 + let mut _6: std::option::Option>; // in scope 0 at $DIR/basic_assignment.rs:23:14: 23:20 scope 1 { - debug nodrop_x => _1; // in scope 1 at $DIR/basic_assignment.rs:+1:9: +1:17 - let _2: bool; // in scope 1 at $DIR/basic_assignment.rs:+2:9: +2:17 + debug nodrop_x => _1; // in scope 1 at $DIR/basic_assignment.rs:11:9: 11:17 + let _2: bool; // in scope 1 at $DIR/basic_assignment.rs:12:9: 12:17 scope 2 { - debug nodrop_y => _2; // in scope 2 at $DIR/basic_assignment.rs:+2:9: +2:17 - let _4: std::option::Option> as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 2 at $DIR/basic_assignment.rs:+8:9: +8:15 + debug nodrop_y => _2; // in scope 2 at $DIR/basic_assignment.rs:12:9: 12:17 + let _4: std::option::Option> as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 2 at $DIR/basic_assignment.rs:18:9: 18:15 scope 3 { - debug drop_x => _4; // in scope 3 at $DIR/basic_assignment.rs:+8:9: +8:15 - let _5: std::option::Option>; // in scope 3 at $DIR/basic_assignment.rs:+9:9: +9:15 + debug drop_x => _4; // in scope 3 at $DIR/basic_assignment.rs:18:9: 18:15 + let _5: std::option::Option>; // in scope 3 at $DIR/basic_assignment.rs:19:9: 19:15 scope 4 { - debug drop_y => _5; // in scope 4 at $DIR/basic_assignment.rs:+9:9: +9:15 + debug drop_y => _5; // in scope 4 at $DIR/basic_assignment.rs:19:9: 19:15 } } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/basic_assignment.rs:+1:9: +1:17 - _1 = const false; // scope 0 at $DIR/basic_assignment.rs:+1:20: +1:25 - FakeRead(ForLet(None), _1); // scope 0 at $DIR/basic_assignment.rs:+1:9: +1:17 - StorageLive(_2); // scope 1 at $DIR/basic_assignment.rs:+2:9: +2:17 - StorageLive(_3); // scope 2 at $DIR/basic_assignment.rs:+6:16: +6:24 - _3 = _1; // scope 2 at $DIR/basic_assignment.rs:+6:16: +6:24 - _2 = move _3; // scope 2 at $DIR/basic_assignment.rs:+6:5: +6:24 - StorageDead(_3); // scope 2 at $DIR/basic_assignment.rs:+6:23: +6:24 - StorageLive(_4); // scope 2 at $DIR/basic_assignment.rs:+8:9: +8:15 - _4 = Option::>::None; // scope 2 at $DIR/basic_assignment.rs:+8:36: +8:40 - FakeRead(ForLet(None), _4); // scope 2 at $DIR/basic_assignment.rs:+8:9: +8:15 - AscribeUserType(_4, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 2 at $DIR/basic_assignment.rs:+8:17: +8:33 - StorageLive(_5); // scope 3 at $DIR/basic_assignment.rs:+9:9: +9:15 - StorageLive(_6); // scope 4 at $DIR/basic_assignment.rs:+13:14: +13:20 - _6 = move _4; // scope 4 at $DIR/basic_assignment.rs:+13:14: +13:20 - replace(_5 <- move _6) -> [return: bb1, unwind: bb5]; // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11 + StorageLive(_1); // scope 0 at $DIR/basic_assignment.rs:11:9: 11:17 + _1 = const false; // scope 0 at $DIR/basic_assignment.rs:11:20: 11:25 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/basic_assignment.rs:11:9: 11:17 + StorageLive(_2); // scope 1 at $DIR/basic_assignment.rs:12:9: 12:17 + StorageLive(_3); // scope 2 at $DIR/basic_assignment.rs:16:16: 16:24 + _3 = _1; // scope 2 at $DIR/basic_assignment.rs:16:16: 16:24 + _2 = move _3; // scope 2 at $DIR/basic_assignment.rs:16:5: 16:24 + StorageDead(_3); // scope 2 at $DIR/basic_assignment.rs:16:23: 16:24 + StorageLive(_4); // scope 2 at $DIR/basic_assignment.rs:18:9: 18:15 + _4 = Option::>::None; // scope 2 at $DIR/basic_assignment.rs:18:36: 18:40 + FakeRead(ForLet(None), _4); // scope 2 at $DIR/basic_assignment.rs:18:9: 18:15 + AscribeUserType(_4, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 2 at $DIR/basic_assignment.rs:18:17: 18:33 + StorageLive(_5); // scope 3 at $DIR/basic_assignment.rs:19:9: 19:15 + StorageLive(_6); // scope 4 at $DIR/basic_assignment.rs:23:14: 23:20 + _6 = move _4; // scope 4 at $DIR/basic_assignment.rs:23:14: 23:20 + replace(_5 <- move _6) -> [return: bb1, unwind: bb5]; // scope 4 at $DIR/basic_assignment.rs:23:5: 23:11 } bb1: { - drop(_6) -> [return: bb2, unwind: bb6]; // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20 + drop(_6) -> [return: bb2, unwind: bb6]; // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20 } bb2: { - StorageDead(_6); // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20 - _0 = const (); // scope 0 at $DIR/basic_assignment.rs:+0:11: +14:2 - drop(_5) -> [return: bb3, unwind: bb7]; // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2 + StorageDead(_6); // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20 + _0 = const (); // scope 0 at $DIR/basic_assignment.rs:10:11: 24:2 + drop(_5) -> [return: bb3, unwind: bb7]; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 } bb3: { - StorageDead(_5); // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2 - drop(_4) -> [return: bb4, unwind: bb8]; // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2 + StorageDead(_5); // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 + drop(_4) -> [return: bb4, unwind: bb8]; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 } bb4: { - StorageDead(_4); // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2 - StorageDead(_2); // scope 1 at $DIR/basic_assignment.rs:+14:1: +14:2 - StorageDead(_1); // scope 0 at $DIR/basic_assignment.rs:+14:1: +14:2 - return; // scope 0 at $DIR/basic_assignment.rs:+14:2: +14:2 + StorageDead(_4); // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 + StorageDead(_2); // scope 1 at $DIR/basic_assignment.rs:24:1: 24:2 + StorageDead(_1); // scope 0 at $DIR/basic_assignment.rs:24:1: 24:2 + return; // scope 0 at $DIR/basic_assignment.rs:24:2: 24:2 } bb5 (cleanup): { - drop(_6) -> bb6; // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20 + drop(_6) -> bb6; // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20 } bb6 (cleanup): { - drop(_5) -> bb7; // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2 + drop(_5) -> bb7; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 } bb7 (cleanup): { - drop(_4) -> bb8; // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2 + drop(_4) -> bb8; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 } bb8 (cleanup): { - resume; // scope 0 at $DIR/basic_assignment.rs:+0:1: +14:2 + resume; // scope 0 at $DIR/basic_assignment.rs:10:1: 24:2 } } diff --git a/src/test/mir-opt/bool_compare.opt1.InstCombine.diff b/src/test/mir-opt/bool_compare.opt1.InstCombine.diff index 9c5a9fa9abb0e..8f57d307abf58 100644 --- a/src/test/mir-opt/bool_compare.opt1.InstCombine.diff +++ b/src/test/mir-opt/bool_compare.opt1.InstCombine.diff @@ -2,34 +2,34 @@ + // MIR for `opt1` after InstCombine fn opt1(_1: bool) -> u32 { - debug x => _1; // in scope 0 at $DIR/bool_compare.rs:+0:9: +0:10 - let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:+0:21: +0:24 - let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:+1:8: +1:17 - let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:+1:8: +1:9 + debug x => _1; // in scope 0 at $DIR/bool_compare.rs:2:9: 2:10 + let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:2:21: 2:24 + let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:3:8: 3:17 + let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:3:8: 3:9 bb0: { - StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:+1:8: +1:17 - StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:+1:8: +1:9 - _3 = _1; // scope 0 at $DIR/bool_compare.rs:+1:8: +1:9 -- _2 = Ne(move _3, const true); // scope 0 at $DIR/bool_compare.rs:+1:8: +1:17 -+ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:+1:8: +1:17 - StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:+1:16: +1:17 - switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:+1:8: +1:17 + StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:3:8: 3:17 + StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:3:8: 3:9 + _3 = _1; // scope 0 at $DIR/bool_compare.rs:3:8: 3:9 +- _2 = Ne(move _3, const true); // scope 0 at $DIR/bool_compare.rs:3:8: 3:17 ++ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:3:8: 3:17 + StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:3:16: 3:17 + switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:3:8: 3:17 } bb1: { - _0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:+1:20: +1:21 - goto -> bb3; // scope 0 at $DIR/bool_compare.rs:+1:5: +1:34 + _0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:3:20: 3:21 + goto -> bb3; // scope 0 at $DIR/bool_compare.rs:3:5: 3:34 } bb2: { - _0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:+1:31: +1:32 - goto -> bb3; // scope 0 at $DIR/bool_compare.rs:+1:5: +1:34 + _0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:3:31: 3:32 + goto -> bb3; // scope 0 at $DIR/bool_compare.rs:3:5: 3:34 } bb3: { - StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:+1:33: +1:34 - return; // scope 0 at $DIR/bool_compare.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:3:33: 3:34 + return; // scope 0 at $DIR/bool_compare.rs:4:2: 4:2 } } diff --git a/src/test/mir-opt/bool_compare.opt2.InstCombine.diff b/src/test/mir-opt/bool_compare.opt2.InstCombine.diff index 58c52c4b7d7ff..1f5738ae75837 100644 --- a/src/test/mir-opt/bool_compare.opt2.InstCombine.diff +++ b/src/test/mir-opt/bool_compare.opt2.InstCombine.diff @@ -2,34 +2,34 @@ + // MIR for `opt2` after InstCombine fn opt2(_1: bool) -> u32 { - debug x => _1; // in scope 0 at $DIR/bool_compare.rs:+0:9: +0:10 - let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:+0:21: +0:24 - let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:+1:8: +1:17 - let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:+1:16: +1:17 + debug x => _1; // in scope 0 at $DIR/bool_compare.rs:7:9: 7:10 + let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:7:21: 7:24 + let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:8:8: 8:17 + let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:8:16: 8:17 bb0: { - StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:+1:8: +1:17 - StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:+1:16: +1:17 - _3 = _1; // scope 0 at $DIR/bool_compare.rs:+1:16: +1:17 -- _2 = Ne(const true, move _3); // scope 0 at $DIR/bool_compare.rs:+1:8: +1:17 -+ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:+1:8: +1:17 - StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:+1:16: +1:17 - switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:+1:8: +1:17 + StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:8:8: 8:17 + StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:8:16: 8:17 + _3 = _1; // scope 0 at $DIR/bool_compare.rs:8:16: 8:17 +- _2 = Ne(const true, move _3); // scope 0 at $DIR/bool_compare.rs:8:8: 8:17 ++ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:8:8: 8:17 + StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:8:16: 8:17 + switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:8:8: 8:17 } bb1: { - _0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:+1:20: +1:21 - goto -> bb3; // scope 0 at $DIR/bool_compare.rs:+1:5: +1:34 + _0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:8:20: 8:21 + goto -> bb3; // scope 0 at $DIR/bool_compare.rs:8:5: 8:34 } bb2: { - _0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:+1:31: +1:32 - goto -> bb3; // scope 0 at $DIR/bool_compare.rs:+1:5: +1:34 + _0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:8:31: 8:32 + goto -> bb3; // scope 0 at $DIR/bool_compare.rs:8:5: 8:34 } bb3: { - StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:+1:33: +1:34 - return; // scope 0 at $DIR/bool_compare.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:8:33: 8:34 + return; // scope 0 at $DIR/bool_compare.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/bool_compare.opt3.InstCombine.diff b/src/test/mir-opt/bool_compare.opt3.InstCombine.diff index 676428c95c1bf..3320509a7b37a 100644 --- a/src/test/mir-opt/bool_compare.opt3.InstCombine.diff +++ b/src/test/mir-opt/bool_compare.opt3.InstCombine.diff @@ -2,34 +2,34 @@ + // MIR for `opt3` after InstCombine fn opt3(_1: bool) -> u32 { - debug x => _1; // in scope 0 at $DIR/bool_compare.rs:+0:9: +0:10 - let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:+0:21: +0:24 - let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:+1:8: +1:18 - let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:+1:8: +1:9 + debug x => _1; // in scope 0 at $DIR/bool_compare.rs:12:9: 12:10 + let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:12:21: 12:24 + let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:13:8: 13:18 + let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:13:8: 13:9 bb0: { - StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:+1:8: +1:18 - StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:+1:8: +1:9 - _3 = _1; // scope 0 at $DIR/bool_compare.rs:+1:8: +1:9 -- _2 = Eq(move _3, const false); // scope 0 at $DIR/bool_compare.rs:+1:8: +1:18 -+ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:+1:8: +1:18 - StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:+1:17: +1:18 - switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:+1:8: +1:18 + StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:13:8: 13:18 + StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:13:8: 13:9 + _3 = _1; // scope 0 at $DIR/bool_compare.rs:13:8: 13:9 +- _2 = Eq(move _3, const false); // scope 0 at $DIR/bool_compare.rs:13:8: 13:18 ++ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:13:8: 13:18 + StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:13:17: 13:18 + switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:13:8: 13:18 } bb1: { - _0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:+1:21: +1:22 - goto -> bb3; // scope 0 at $DIR/bool_compare.rs:+1:5: +1:35 + _0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:13:21: 13:22 + goto -> bb3; // scope 0 at $DIR/bool_compare.rs:13:5: 13:35 } bb2: { - _0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:+1:32: +1:33 - goto -> bb3; // scope 0 at $DIR/bool_compare.rs:+1:5: +1:35 + _0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:13:32: 13:33 + goto -> bb3; // scope 0 at $DIR/bool_compare.rs:13:5: 13:35 } bb3: { - StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:+1:34: +1:35 - return; // scope 0 at $DIR/bool_compare.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:13:34: 13:35 + return; // scope 0 at $DIR/bool_compare.rs:14:2: 14:2 } } diff --git a/src/test/mir-opt/bool_compare.opt4.InstCombine.diff b/src/test/mir-opt/bool_compare.opt4.InstCombine.diff index addfcd769a546..02049f4126da5 100644 --- a/src/test/mir-opt/bool_compare.opt4.InstCombine.diff +++ b/src/test/mir-opt/bool_compare.opt4.InstCombine.diff @@ -2,34 +2,34 @@ + // MIR for `opt4` after InstCombine fn opt4(_1: bool) -> u32 { - debug x => _1; // in scope 0 at $DIR/bool_compare.rs:+0:9: +0:10 - let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:+0:21: +0:24 - let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:+1:8: +1:18 - let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:+1:17: +1:18 + debug x => _1; // in scope 0 at $DIR/bool_compare.rs:17:9: 17:10 + let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:17:21: 17:24 + let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:18:8: 18:18 + let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:18:17: 18:18 bb0: { - StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:+1:8: +1:18 - StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:+1:17: +1:18 - _3 = _1; // scope 0 at $DIR/bool_compare.rs:+1:17: +1:18 -- _2 = Eq(const false, move _3); // scope 0 at $DIR/bool_compare.rs:+1:8: +1:18 -+ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:+1:8: +1:18 - StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:+1:17: +1:18 - switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:+1:8: +1:18 + StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:18:8: 18:18 + StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:18:17: 18:18 + _3 = _1; // scope 0 at $DIR/bool_compare.rs:18:17: 18:18 +- _2 = Eq(const false, move _3); // scope 0 at $DIR/bool_compare.rs:18:8: 18:18 ++ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:18:8: 18:18 + StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:18:17: 18:18 + switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:18:8: 18:18 } bb1: { - _0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:+1:21: +1:22 - goto -> bb3; // scope 0 at $DIR/bool_compare.rs:+1:5: +1:35 + _0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:18:21: 18:22 + goto -> bb3; // scope 0 at $DIR/bool_compare.rs:18:5: 18:35 } bb2: { - _0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:+1:32: +1:33 - goto -> bb3; // scope 0 at $DIR/bool_compare.rs:+1:5: +1:35 + _0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:18:32: 18:33 + goto -> bb3; // scope 0 at $DIR/bool_compare.rs:18:5: 18:35 } bb3: { - StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:+1:34: +1:35 - return; // scope 0 at $DIR/bool_compare.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:18:34: 18:35 + return; // scope 0 at $DIR/bool_compare.rs:19:2: 19:2 } } diff --git a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir index 49133138d45e3..9b35beccbcc5a 100644 --- a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir @@ -1,80 +1,80 @@ // MIR for `main` before ElaborateDrops fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/box_expr.rs:+0:11: +0:11 - let _1: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:+1:9: +1:10 - let mut _2: usize; // in scope 0 at $DIR/box_expr.rs:+1:13: +1:25 - let mut _3: usize; // in scope 0 at $DIR/box_expr.rs:+1:13: +1:25 - let mut _4: *mut u8; // in scope 0 at $DIR/box_expr.rs:+1:13: +1:25 - let mut _5: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:+1:13: +1:25 - let _6: (); // in scope 0 at $DIR/box_expr.rs:+2:5: +2:12 - let mut _7: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:+2:10: +2:11 + let mut _0: (); // return place in scope 0 at $DIR/box_expr.rs:6:11: 6:11 + let _1: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:7:9: 7:10 + let mut _2: usize; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 + let mut _3: usize; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 + let mut _4: *mut u8; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 + let mut _5: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 + let _6: (); // in scope 0 at $DIR/box_expr.rs:8:5: 8:12 + let mut _7: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:8:10: 8:11 scope 1 { - debug x => _1; // in scope 1 at $DIR/box_expr.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/box_expr.rs:7:9: 7:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/box_expr.rs:+1:9: +1:10 - _2 = SizeOf(S); // scope 2 at $DIR/box_expr.rs:+1:13: +1:25 - _3 = AlignOf(S); // scope 2 at $DIR/box_expr.rs:+1:13: +1:25 - _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/box_expr.rs:+1:13: +1:25 + StorageLive(_1); // scope 0 at $DIR/box_expr.rs:7:9: 7:10 + _2 = SizeOf(S); // scope 2 at $DIR/box_expr.rs:7:13: 7:25 + _3 = AlignOf(S); // scope 2 at $DIR/box_expr.rs:7:13: 7:25 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/box_expr.rs:7:13: 7:25 // mir::Constant // + span: $DIR/box_expr.rs:7:13: 7:25 // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value() } } bb1: { - StorageLive(_5); // scope 0 at $DIR/box_expr.rs:+1:13: +1:25 - _5 = ShallowInitBox(move _4, S); // scope 0 at $DIR/box_expr.rs:+1:13: +1:25 - (*_5) = S::new() -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/box_expr.rs:+1:17: +1:25 + StorageLive(_5); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 + _5 = ShallowInitBox(move _4, S); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 + (*_5) = S::new() -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 // mir::Constant // + span: $DIR/box_expr.rs:7:17: 7:23 // + literal: Const { ty: fn() -> S {S::new}, val: Value() } } bb2: { - _1 = move _5; // scope 0 at $DIR/box_expr.rs:+1:13: +1:25 - drop(_5) -> bb3; // scope 0 at $DIR/box_expr.rs:+1:24: +1:25 + _1 = move _5; // scope 0 at $DIR/box_expr.rs:7:13: 7:25 + drop(_5) -> bb3; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 } bb3: { - StorageDead(_5); // scope 0 at $DIR/box_expr.rs:+1:24: +1:25 - StorageLive(_6); // scope 1 at $DIR/box_expr.rs:+2:5: +2:12 - StorageLive(_7); // scope 1 at $DIR/box_expr.rs:+2:10: +2:11 - _7 = move _1; // scope 1 at $DIR/box_expr.rs:+2:10: +2:11 - _6 = std::mem::drop::>(move _7) -> [return: bb4, unwind: bb6]; // scope 1 at $DIR/box_expr.rs:+2:5: +2:12 + StorageDead(_5); // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + StorageLive(_6); // scope 1 at $DIR/box_expr.rs:8:5: 8:12 + StorageLive(_7); // scope 1 at $DIR/box_expr.rs:8:10: 8:11 + _7 = move _1; // scope 1 at $DIR/box_expr.rs:8:10: 8:11 + _6 = std::mem::drop::>(move _7) -> [return: bb4, unwind: bb6]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 // mir::Constant // + span: $DIR/box_expr.rs:8:5: 8:9 // + literal: Const { ty: fn(Box) {std::mem::drop::>}, val: Value() } } bb4: { - StorageDead(_7); // scope 1 at $DIR/box_expr.rs:+2:11: +2:12 - StorageDead(_6); // scope 1 at $DIR/box_expr.rs:+2:12: +2:13 - _0 = const (); // scope 0 at $DIR/box_expr.rs:+0:11: +3:2 - drop(_1) -> bb5; // scope 0 at $DIR/box_expr.rs:+3:1: +3:2 + StorageDead(_7); // scope 1 at $DIR/box_expr.rs:8:11: 8:12 + StorageDead(_6); // scope 1 at $DIR/box_expr.rs:8:12: 8:13 + _0 = const (); // scope 0 at $DIR/box_expr.rs:6:11: 9:2 + drop(_1) -> bb5; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 } bb5: { - StorageDead(_1); // scope 0 at $DIR/box_expr.rs:+3:1: +3:2 - return; // scope 0 at $DIR/box_expr.rs:+3:2: +3:2 + StorageDead(_1); // scope 0 at $DIR/box_expr.rs:9:1: 9:2 + return; // scope 0 at $DIR/box_expr.rs:9:2: 9:2 } bb6 (cleanup): { - drop(_7) -> bb7; // scope 1 at $DIR/box_expr.rs:+2:11: +2:12 + drop(_7) -> bb7; // scope 1 at $DIR/box_expr.rs:8:11: 8:12 } bb7 (cleanup): { - drop(_1) -> bb9; // scope 0 at $DIR/box_expr.rs:+3:1: +3:2 + drop(_1) -> bb9; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 } bb8 (cleanup): { - drop(_5) -> bb9; // scope 0 at $DIR/box_expr.rs:+1:24: +1:25 + drop(_5) -> bb9; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 } bb9 (cleanup): { - resume; // scope 0 at $DIR/box_expr.rs:+0:1: +3:2 + resume; // scope 0 at $DIR/box_expr.rs:6:1: 9:2 } } diff --git a/src/test/mir-opt/byte_slice.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/byte_slice.main.SimplifyCfg-elaborate-drops.after.mir index 73f5655a1e502..073cba5acf407 100644 --- a/src/test/mir-opt/byte_slice.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/byte_slice.main.SimplifyCfg-elaborate-drops.after.mir @@ -1,28 +1,28 @@ // MIR for `main` after SimplifyCfg-elaborate-drops fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/byte_slice.rs:+0:11: +0:11 - let _1: &[u8; 3]; // in scope 0 at $DIR/byte_slice.rs:+1:9: +1:10 + let mut _0: (); // return place in scope 0 at $DIR/byte_slice.rs:4:11: 4:11 + let _1: &[u8; 3]; // in scope 0 at $DIR/byte_slice.rs:5:9: 5:10 scope 1 { - debug x => _1; // in scope 1 at $DIR/byte_slice.rs:+1:9: +1:10 - let _2: [u8; 2]; // in scope 1 at $DIR/byte_slice.rs:+2:9: +2:10 + debug x => _1; // in scope 1 at $DIR/byte_slice.rs:5:9: 5:10 + let _2: [u8; 2]; // in scope 1 at $DIR/byte_slice.rs:6:9: 6:10 scope 2 { - debug y => _2; // in scope 2 at $DIR/byte_slice.rs:+2:9: +2:10 + debug y => _2; // in scope 2 at $DIR/byte_slice.rs:6:9: 6:10 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/byte_slice.rs:+1:9: +1:10 - _1 = const b"foo"; // scope 0 at $DIR/byte_slice.rs:+1:13: +1:19 + StorageLive(_1); // scope 0 at $DIR/byte_slice.rs:5:9: 5:10 + _1 = const b"foo"; // scope 0 at $DIR/byte_slice.rs:5:13: 5:19 // mir::Constant // + span: $DIR/byte_slice.rs:5:13: 5:19 // + literal: Const { ty: &[u8; 3], val: Value(Scalar(alloc1)) } - StorageLive(_2); // scope 1 at $DIR/byte_slice.rs:+2:9: +2:10 - _2 = [const 5_u8, const 120_u8]; // scope 1 at $DIR/byte_slice.rs:+2:13: +2:24 - _0 = const (); // scope 0 at $DIR/byte_slice.rs:+0:11: +3:2 - StorageDead(_2); // scope 1 at $DIR/byte_slice.rs:+3:1: +3:2 - StorageDead(_1); // scope 0 at $DIR/byte_slice.rs:+3:1: +3:2 - return; // scope 0 at $DIR/byte_slice.rs:+3:2: +3:2 + StorageLive(_2); // scope 1 at $DIR/byte_slice.rs:6:9: 6:10 + _2 = [const 5_u8, const 120_u8]; // scope 1 at $DIR/byte_slice.rs:6:13: 6:24 + _0 = const (); // scope 0 at $DIR/byte_slice.rs:4:11: 7:2 + StorageDead(_2); // scope 1 at $DIR/byte_slice.rs:7:1: 7:2 + StorageDead(_1); // scope 0 at $DIR/byte_slice.rs:7:1: 7:2 + return; // scope 0 at $DIR/byte_slice.rs:7:2: 7:2 } } diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff b/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff index c73150f947dfe..979e5bc4d2118 100644 --- a/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff +++ b/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff @@ -2,76 +2,76 @@ + // MIR for `norm2` after InstCombine fn norm2(_1: [f32; 2]) -> f32 { - debug x => _1; // in scope 0 at $DIR/combine_array_len.rs:+0:10: +0:11 - let mut _0: f32; // return place in scope 0 at $DIR/combine_array_len.rs:+0:26: +0:29 - let _2: f32; // in scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10 - let _3: usize; // in scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16 - let mut _4: usize; // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 - let mut _5: bool; // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 - let _7: usize; // in scope 0 at $DIR/combine_array_len.rs:+2:15: +2:16 - let mut _8: usize; // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17 - let mut _9: bool; // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17 - let mut _10: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:8 - let mut _11: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:6 - let mut _12: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:7: +3:8 - let mut _13: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:14 - let mut _14: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:12 - let mut _15: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:13: +3:14 + debug x => _1; // in scope 0 at $DIR/combine_array_len.rs:4:10: 4:11 + let mut _0: f32; // return place in scope 0 at $DIR/combine_array_len.rs:4:26: 4:29 + let _2: f32; // in scope 0 at $DIR/combine_array_len.rs:5:9: 5:10 + let _3: usize; // in scope 0 at $DIR/combine_array_len.rs:5:15: 5:16 + let mut _4: usize; // in scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + let mut _5: bool; // in scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + let _7: usize; // in scope 0 at $DIR/combine_array_len.rs:6:15: 6:16 + let mut _8: usize; // in scope 0 at $DIR/combine_array_len.rs:6:13: 6:17 + let mut _9: bool; // in scope 0 at $DIR/combine_array_len.rs:6:13: 6:17 + let mut _10: f32; // in scope 0 at $DIR/combine_array_len.rs:7:5: 7:8 + let mut _11: f32; // in scope 0 at $DIR/combine_array_len.rs:7:5: 7:6 + let mut _12: f32; // in scope 0 at $DIR/combine_array_len.rs:7:7: 7:8 + let mut _13: f32; // in scope 0 at $DIR/combine_array_len.rs:7:11: 7:14 + let mut _14: f32; // in scope 0 at $DIR/combine_array_len.rs:7:11: 7:12 + let mut _15: f32; // in scope 0 at $DIR/combine_array_len.rs:7:13: 7:14 scope 1 { - debug a => _2; // in scope 1 at $DIR/combine_array_len.rs:+1:9: +1:10 - let _6: f32; // in scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10 + debug a => _2; // in scope 1 at $DIR/combine_array_len.rs:5:9: 5:10 + let _6: f32; // in scope 1 at $DIR/combine_array_len.rs:6:9: 6:10 scope 2 { - debug b => _6; // in scope 2 at $DIR/combine_array_len.rs:+2:9: +2:10 + debug b => _6; // in scope 2 at $DIR/combine_array_len.rs:6:9: 6:10 } } bb0: { - StorageLive(_2); // scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16 - _3 = const 0_usize; // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16 -- _4 = Len(_1); // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 -+ _4 = const 2_usize; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 - _5 = Lt(_3, _4); // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 + StorageLive(_2); // scope 0 at $DIR/combine_array_len.rs:5:9: 5:10 + StorageLive(_3); // scope 0 at $DIR/combine_array_len.rs:5:15: 5:16 + _3 = const 0_usize; // scope 0 at $DIR/combine_array_len.rs:5:15: 5:16 +- _4 = Len(_1); // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 ++ _4 = const 2_usize; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + _5 = Lt(_3, _4); // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 } bb1: { - _2 = _1[_3]; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 - StorageDead(_3); // scope 0 at $DIR/combine_array_len.rs:+1:17: +1:18 - StorageLive(_6); // scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10 - StorageLive(_7); // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16 - _7 = const 1_usize; // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16 -- _8 = Len(_1); // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17 -+ _8 = const 2_usize; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17 - _9 = Lt(_7, _8); // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17 - assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17 + _2 = _1[_3]; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + StorageDead(_3); // scope 0 at $DIR/combine_array_len.rs:5:17: 5:18 + StorageLive(_6); // scope 1 at $DIR/combine_array_len.rs:6:9: 6:10 + StorageLive(_7); // scope 1 at $DIR/combine_array_len.rs:6:15: 6:16 + _7 = const 1_usize; // scope 1 at $DIR/combine_array_len.rs:6:15: 6:16 +- _8 = Len(_1); // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 ++ _8 = const 2_usize; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 + _9 = Lt(_7, _8); // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 } bb2: { - _6 = _1[_7]; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17 - StorageDead(_7); // scope 1 at $DIR/combine_array_len.rs:+2:17: +2:18 - StorageLive(_10); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8 - StorageLive(_11); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6 - _11 = _2; // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6 - StorageLive(_12); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8 - _12 = _2; // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8 - _10 = Mul(move _11, move _12); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8 - StorageDead(_12); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8 - StorageDead(_11); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8 - StorageLive(_13); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14 - StorageLive(_14); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12 - _14 = _6; // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12 - StorageLive(_15); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - _15 = _6; // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - _13 = Mul(move _14, move _15); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14 - StorageDead(_15); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - StorageDead(_14); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - _0 = Add(move _10, move _13); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:14 - StorageDead(_13); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - StorageDead(_10); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - StorageDead(_6); // scope 1 at $DIR/combine_array_len.rs:+4:1: +4:2 - StorageDead(_2); // scope 0 at $DIR/combine_array_len.rs:+4:1: +4:2 - return; // scope 0 at $DIR/combine_array_len.rs:+4:2: +4:2 + _6 = _1[_7]; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 + StorageDead(_7); // scope 1 at $DIR/combine_array_len.rs:6:17: 6:18 + StorageLive(_10); // scope 2 at $DIR/combine_array_len.rs:7:5: 7:8 + StorageLive(_11); // scope 2 at $DIR/combine_array_len.rs:7:5: 7:6 + _11 = _2; // scope 2 at $DIR/combine_array_len.rs:7:5: 7:6 + StorageLive(_12); // scope 2 at $DIR/combine_array_len.rs:7:7: 7:8 + _12 = _2; // scope 2 at $DIR/combine_array_len.rs:7:7: 7:8 + _10 = Mul(move _11, move _12); // scope 2 at $DIR/combine_array_len.rs:7:5: 7:8 + StorageDead(_12); // scope 2 at $DIR/combine_array_len.rs:7:7: 7:8 + StorageDead(_11); // scope 2 at $DIR/combine_array_len.rs:7:7: 7:8 + StorageLive(_13); // scope 2 at $DIR/combine_array_len.rs:7:11: 7:14 + StorageLive(_14); // scope 2 at $DIR/combine_array_len.rs:7:11: 7:12 + _14 = _6; // scope 2 at $DIR/combine_array_len.rs:7:11: 7:12 + StorageLive(_15); // scope 2 at $DIR/combine_array_len.rs:7:13: 7:14 + _15 = _6; // scope 2 at $DIR/combine_array_len.rs:7:13: 7:14 + _13 = Mul(move _14, move _15); // scope 2 at $DIR/combine_array_len.rs:7:11: 7:14 + StorageDead(_15); // scope 2 at $DIR/combine_array_len.rs:7:13: 7:14 + StorageDead(_14); // scope 2 at $DIR/combine_array_len.rs:7:13: 7:14 + _0 = Add(move _10, move _13); // scope 2 at $DIR/combine_array_len.rs:7:5: 7:14 + StorageDead(_13); // scope 2 at $DIR/combine_array_len.rs:7:13: 7:14 + StorageDead(_10); // scope 2 at $DIR/combine_array_len.rs:7:13: 7:14 + StorageDead(_6); // scope 1 at $DIR/combine_array_len.rs:8:1: 8:2 + StorageDead(_2); // scope 0 at $DIR/combine_array_len.rs:8:1: 8:2 + return; // scope 0 at $DIR/combine_array_len.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff b/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff index c73150f947dfe..979e5bc4d2118 100644 --- a/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff +++ b/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff @@ -2,76 +2,76 @@ + // MIR for `norm2` after InstCombine fn norm2(_1: [f32; 2]) -> f32 { - debug x => _1; // in scope 0 at $DIR/combine_array_len.rs:+0:10: +0:11 - let mut _0: f32; // return place in scope 0 at $DIR/combine_array_len.rs:+0:26: +0:29 - let _2: f32; // in scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10 - let _3: usize; // in scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16 - let mut _4: usize; // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 - let mut _5: bool; // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 - let _7: usize; // in scope 0 at $DIR/combine_array_len.rs:+2:15: +2:16 - let mut _8: usize; // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17 - let mut _9: bool; // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17 - let mut _10: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:8 - let mut _11: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:6 - let mut _12: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:7: +3:8 - let mut _13: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:14 - let mut _14: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:12 - let mut _15: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:13: +3:14 + debug x => _1; // in scope 0 at $DIR/combine_array_len.rs:4:10: 4:11 + let mut _0: f32; // return place in scope 0 at $DIR/combine_array_len.rs:4:26: 4:29 + let _2: f32; // in scope 0 at $DIR/combine_array_len.rs:5:9: 5:10 + let _3: usize; // in scope 0 at $DIR/combine_array_len.rs:5:15: 5:16 + let mut _4: usize; // in scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + let mut _5: bool; // in scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + let _7: usize; // in scope 0 at $DIR/combine_array_len.rs:6:15: 6:16 + let mut _8: usize; // in scope 0 at $DIR/combine_array_len.rs:6:13: 6:17 + let mut _9: bool; // in scope 0 at $DIR/combine_array_len.rs:6:13: 6:17 + let mut _10: f32; // in scope 0 at $DIR/combine_array_len.rs:7:5: 7:8 + let mut _11: f32; // in scope 0 at $DIR/combine_array_len.rs:7:5: 7:6 + let mut _12: f32; // in scope 0 at $DIR/combine_array_len.rs:7:7: 7:8 + let mut _13: f32; // in scope 0 at $DIR/combine_array_len.rs:7:11: 7:14 + let mut _14: f32; // in scope 0 at $DIR/combine_array_len.rs:7:11: 7:12 + let mut _15: f32; // in scope 0 at $DIR/combine_array_len.rs:7:13: 7:14 scope 1 { - debug a => _2; // in scope 1 at $DIR/combine_array_len.rs:+1:9: +1:10 - let _6: f32; // in scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10 + debug a => _2; // in scope 1 at $DIR/combine_array_len.rs:5:9: 5:10 + let _6: f32; // in scope 1 at $DIR/combine_array_len.rs:6:9: 6:10 scope 2 { - debug b => _6; // in scope 2 at $DIR/combine_array_len.rs:+2:9: +2:10 + debug b => _6; // in scope 2 at $DIR/combine_array_len.rs:6:9: 6:10 } } bb0: { - StorageLive(_2); // scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16 - _3 = const 0_usize; // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16 -- _4 = Len(_1); // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 -+ _4 = const 2_usize; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 - _5 = Lt(_3, _4); // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 + StorageLive(_2); // scope 0 at $DIR/combine_array_len.rs:5:9: 5:10 + StorageLive(_3); // scope 0 at $DIR/combine_array_len.rs:5:15: 5:16 + _3 = const 0_usize; // scope 0 at $DIR/combine_array_len.rs:5:15: 5:16 +- _4 = Len(_1); // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 ++ _4 = const 2_usize; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + _5 = Lt(_3, _4); // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 } bb1: { - _2 = _1[_3]; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 - StorageDead(_3); // scope 0 at $DIR/combine_array_len.rs:+1:17: +1:18 - StorageLive(_6); // scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10 - StorageLive(_7); // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16 - _7 = const 1_usize; // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16 -- _8 = Len(_1); // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17 -+ _8 = const 2_usize; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17 - _9 = Lt(_7, _8); // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17 - assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17 + _2 = _1[_3]; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + StorageDead(_3); // scope 0 at $DIR/combine_array_len.rs:5:17: 5:18 + StorageLive(_6); // scope 1 at $DIR/combine_array_len.rs:6:9: 6:10 + StorageLive(_7); // scope 1 at $DIR/combine_array_len.rs:6:15: 6:16 + _7 = const 1_usize; // scope 1 at $DIR/combine_array_len.rs:6:15: 6:16 +- _8 = Len(_1); // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 ++ _8 = const 2_usize; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 + _9 = Lt(_7, _8); // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 } bb2: { - _6 = _1[_7]; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17 - StorageDead(_7); // scope 1 at $DIR/combine_array_len.rs:+2:17: +2:18 - StorageLive(_10); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8 - StorageLive(_11); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6 - _11 = _2; // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6 - StorageLive(_12); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8 - _12 = _2; // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8 - _10 = Mul(move _11, move _12); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8 - StorageDead(_12); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8 - StorageDead(_11); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8 - StorageLive(_13); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14 - StorageLive(_14); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12 - _14 = _6; // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12 - StorageLive(_15); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - _15 = _6; // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - _13 = Mul(move _14, move _15); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14 - StorageDead(_15); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - StorageDead(_14); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - _0 = Add(move _10, move _13); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:14 - StorageDead(_13); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - StorageDead(_10); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - StorageDead(_6); // scope 1 at $DIR/combine_array_len.rs:+4:1: +4:2 - StorageDead(_2); // scope 0 at $DIR/combine_array_len.rs:+4:1: +4:2 - return; // scope 0 at $DIR/combine_array_len.rs:+4:2: +4:2 + _6 = _1[_7]; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 + StorageDead(_7); // scope 1 at $DIR/combine_array_len.rs:6:17: 6:18 + StorageLive(_10); // scope 2 at $DIR/combine_array_len.rs:7:5: 7:8 + StorageLive(_11); // scope 2 at $DIR/combine_array_len.rs:7:5: 7:6 + _11 = _2; // scope 2 at $DIR/combine_array_len.rs:7:5: 7:6 + StorageLive(_12); // scope 2 at $DIR/combine_array_len.rs:7:7: 7:8 + _12 = _2; // scope 2 at $DIR/combine_array_len.rs:7:7: 7:8 + _10 = Mul(move _11, move _12); // scope 2 at $DIR/combine_array_len.rs:7:5: 7:8 + StorageDead(_12); // scope 2 at $DIR/combine_array_len.rs:7:7: 7:8 + StorageDead(_11); // scope 2 at $DIR/combine_array_len.rs:7:7: 7:8 + StorageLive(_13); // scope 2 at $DIR/combine_array_len.rs:7:11: 7:14 + StorageLive(_14); // scope 2 at $DIR/combine_array_len.rs:7:11: 7:12 + _14 = _6; // scope 2 at $DIR/combine_array_len.rs:7:11: 7:12 + StorageLive(_15); // scope 2 at $DIR/combine_array_len.rs:7:13: 7:14 + _15 = _6; // scope 2 at $DIR/combine_array_len.rs:7:13: 7:14 + _13 = Mul(move _14, move _15); // scope 2 at $DIR/combine_array_len.rs:7:11: 7:14 + StorageDead(_15); // scope 2 at $DIR/combine_array_len.rs:7:13: 7:14 + StorageDead(_14); // scope 2 at $DIR/combine_array_len.rs:7:13: 7:14 + _0 = Add(move _10, move _13); // scope 2 at $DIR/combine_array_len.rs:7:5: 7:14 + StorageDead(_13); // scope 2 at $DIR/combine_array_len.rs:7:13: 7:14 + StorageDead(_10); // scope 2 at $DIR/combine_array_len.rs:7:13: 7:14 + StorageDead(_6); // scope 1 at $DIR/combine_array_len.rs:8:1: 8:2 + StorageDead(_2); // scope 0 at $DIR/combine_array_len.rs:8:1: 8:2 + return; // scope 0 at $DIR/combine_array_len.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff index 833d620cc6c93..7ecd67d7c679a 100644 --- a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff +++ b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff @@ -2,84 +2,84 @@ + // MIR for `::clone` after InstCombine fn ::clone(_1: &MyThing) -> MyThing { - debug self => _1; // in scope 0 at $DIR/combine_clone_of_primitives.rs:+0:10: +0:15 - let mut _0: MyThing; // return place in scope 0 at $DIR/combine_clone_of_primitives.rs:+0:10: +0:15 - let mut _2: T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:+2:5: +2:9 - let mut _3: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:+2:5: +2:9 - let _4: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:+2:5: +2:9 - let mut _5: u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:+3:5: +3:11 - let mut _6: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:+3:5: +3:11 - let _7: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:+3:5: +3:11 - let mut _8: [f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:+4:5: +4:16 - let mut _9: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:+4:5: +4:16 - let _10: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:+4:5: +4:16 + debug self => _1; // in scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 + let mut _0: MyThing; // return place in scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 + let mut _2: T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + let mut _3: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + let _4: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + let mut _5: u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + let mut _6: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + let _7: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + let mut _8: [f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 + let mut _9: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 + let _10: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 bb0: { - StorageLive(_2); // scope 0 at $DIR/combine_clone_of_primitives.rs:+2:5: +2:9 - StorageLive(_3); // scope 0 at $DIR/combine_clone_of_primitives.rs:+2:5: +2:9 - StorageLive(_4); // scope 0 at $DIR/combine_clone_of_primitives.rs:+2:5: +2:9 - _4 = &((*_1).0: T); // scope 0 at $DIR/combine_clone_of_primitives.rs:+2:5: +2:9 -- _3 = &(*_4); // scope 0 at $DIR/combine_clone_of_primitives.rs:+2:5: +2:9 -+ _3 = _4; // scope 0 at $DIR/combine_clone_of_primitives.rs:+2:5: +2:9 - _2 = ::clone(move _3) -> bb1; // scope 0 at $DIR/combine_clone_of_primitives.rs:+2:5: +2:9 + StorageLive(_2); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + StorageLive(_3); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + StorageLive(_4); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + _4 = &((*_1).0: T); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 +- _3 = &(*_4); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 ++ _3 = _4; // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + _2 = ::clone(move _3) -> bb1; // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 // mir::Constant // + span: $DIR/combine_clone_of_primitives.rs:8:5: 8:9 // + literal: Const { ty: for<'r> fn(&'r T) -> T {::clone}, val: Value() } } bb1: { - StorageDead(_3); // scope 0 at $DIR/combine_clone_of_primitives.rs:+2:8: +2:9 - StorageLive(_5); // scope 0 at $DIR/combine_clone_of_primitives.rs:+3:5: +3:11 - StorageLive(_6); // scope 0 at $DIR/combine_clone_of_primitives.rs:+3:5: +3:11 - StorageLive(_7); // scope 0 at $DIR/combine_clone_of_primitives.rs:+3:5: +3:11 - _7 = &((*_1).1: u64); // scope 0 at $DIR/combine_clone_of_primitives.rs:+3:5: +3:11 -- _6 = &(*_7); // scope 0 at $DIR/combine_clone_of_primitives.rs:+3:5: +3:11 -- _5 = ::clone(move _6) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/combine_clone_of_primitives.rs:+3:5: +3:11 + StorageDead(_3); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:8: 8:9 + StorageLive(_5); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + StorageLive(_6); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + StorageLive(_7); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + _7 = &((*_1).1: u64); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 +- _6 = &(*_7); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 +- _5 = ::clone(move _6) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 - // mir::Constant - // + span: $DIR/combine_clone_of_primitives.rs:9:5: 9:11 - // + literal: Const { ty: for<'r> fn(&'r u64) -> u64 {::clone}, val: Value() } -+ _6 = _7; // scope 0 at $DIR/combine_clone_of_primitives.rs:+3:5: +3:11 -+ _5 = (*_6); // scope 0 at $DIR/combine_clone_of_primitives.rs:+3:5: +3:11 -+ goto -> bb2; // scope 0 at $DIR/combine_clone_of_primitives.rs:+3:5: +3:11 ++ _6 = _7; // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 ++ _5 = (*_6); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 ++ goto -> bb2; // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 } bb2: { - StorageDead(_6); // scope 0 at $DIR/combine_clone_of_primitives.rs:+3:10: +3:11 - StorageLive(_8); // scope 0 at $DIR/combine_clone_of_primitives.rs:+4:5: +4:16 - StorageLive(_9); // scope 0 at $DIR/combine_clone_of_primitives.rs:+4:5: +4:16 - StorageLive(_10); // scope 0 at $DIR/combine_clone_of_primitives.rs:+4:5: +4:16 - _10 = &((*_1).2: [f32; 3]); // scope 0 at $DIR/combine_clone_of_primitives.rs:+4:5: +4:16 -- _9 = &(*_10); // scope 0 at $DIR/combine_clone_of_primitives.rs:+4:5: +4:16 -- _8 = <[f32; 3] as Clone>::clone(move _9) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/combine_clone_of_primitives.rs:+4:5: +4:16 + StorageDead(_6); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:10: 9:11 + StorageLive(_8); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 + StorageLive(_9); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 + StorageLive(_10); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 + _10 = &((*_1).2: [f32; 3]); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 +- _9 = &(*_10); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 +- _8 = <[f32; 3] as Clone>::clone(move _9) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 - // mir::Constant - // + span: $DIR/combine_clone_of_primitives.rs:10:5: 10:16 - // + literal: Const { ty: for<'r> fn(&'r [f32; 3]) -> [f32; 3] {<[f32; 3] as Clone>::clone}, val: Value() } -+ _9 = _10; // scope 0 at $DIR/combine_clone_of_primitives.rs:+4:5: +4:16 -+ _8 = (*_9); // scope 0 at $DIR/combine_clone_of_primitives.rs:+4:5: +4:16 -+ goto -> bb3; // scope 0 at $DIR/combine_clone_of_primitives.rs:+4:5: +4:16 ++ _9 = _10; // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 ++ _8 = (*_9); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 ++ goto -> bb3; // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 } bb3: { - StorageDead(_9); // scope 0 at $DIR/combine_clone_of_primitives.rs:+4:15: +4:16 - Deinit(_0); // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:10: +0:15 - (_0.0: T) = move _2; // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:10: +0:15 - (_0.1: u64) = move _5; // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:10: +0:15 - (_0.2: [f32; 3]) = move _8; // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:10: +0:15 - StorageDead(_8); // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:14: +0:15 - StorageDead(_5); // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:14: +0:15 - StorageDead(_2); // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:14: +0:15 - StorageDead(_10); // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:14: +0:15 - StorageDead(_7); // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:14: +0:15 - StorageDead(_4); // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:14: +0:15 - return; // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:15: +0:15 + StorageDead(_9); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:15: 10:16 + Deinit(_0); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 + (_0.0: T) = move _2; // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 + (_0.1: u64) = move _5; // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 + (_0.2: [f32; 3]) = move _8; // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 + StorageDead(_8); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 + StorageDead(_5); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 + StorageDead(_2); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 + StorageDead(_10); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 + StorageDead(_7); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 + StorageDead(_4); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 + return; // scope 0 at $DIR/combine_clone_of_primitives.rs:6:15: 6:15 } bb4 (cleanup): { - drop(_2) -> bb5; // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:14: +0:15 + drop(_2) -> bb5; // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 } bb5 (cleanup): { - resume; // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:10: +0:15 + resume; // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 } } diff --git a/src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir b/src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir index da5a64cac6513..f8a8afa92e0e6 100644 --- a/src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir +++ b/src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir @@ -1,22 +1,22 @@ // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/const_allocation.rs:+0:11: +0:11 - let _1: &[(std::option::Option, &[&str])]; // in scope 0 at $DIR/const_allocation.rs:+1:5: +1:8 - let mut _2: &&[(std::option::Option, &[&str])]; // in scope 0 at $DIR/const_allocation.rs:+1:5: +1:8 + let mut _0: (); // return place in scope 0 at $DIR/const_allocation.rs:7:11: 7:11 + let _1: &[(std::option::Option, &[&str])]; // in scope 0 at $DIR/const_allocation.rs:8:5: 8:8 + let mut _2: &&[(std::option::Option, &[&str])]; // in scope 0 at $DIR/const_allocation.rs:8:5: 8:8 bb0: { - StorageLive(_1); // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8 - StorageLive(_2); // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8 - _2 = const {alloc1: &&[(Option, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8 + StorageLive(_1); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 + StorageLive(_2); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 + _2 = const {alloc1: &&[(Option, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 // mir::Constant // + span: $DIR/const_allocation.rs:8:5: 8:8 // + literal: Const { ty: &&[(Option, &[&str])], val: Value(Scalar(alloc1)) } - _1 = (*_2); // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8 - StorageDead(_2); // scope 0 at $DIR/const_allocation.rs:+1:8: +1:9 - StorageDead(_1); // scope 0 at $DIR/const_allocation.rs:+1:8: +1:9 - nop; // scope 0 at $DIR/const_allocation.rs:+0:11: +2:2 - return; // scope 0 at $DIR/const_allocation.rs:+2:2: +2:2 + _1 = (*_2); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 + StorageDead(_2); // scope 0 at $DIR/const_allocation.rs:8:8: 8:9 + StorageDead(_1); // scope 0 at $DIR/const_allocation.rs:8:8: 8:9 + nop; // scope 0 at $DIR/const_allocation.rs:7:11: 9:2 + return; // scope 0 at $DIR/const_allocation.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir b/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir index febd990681e56..1f1d857425e5b 100644 --- a/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir +++ b/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir @@ -1,22 +1,22 @@ // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/const_allocation.rs:+0:11: +0:11 - let _1: &[(std::option::Option, &[&str])]; // in scope 0 at $DIR/const_allocation.rs:+1:5: +1:8 - let mut _2: &&[(std::option::Option, &[&str])]; // in scope 0 at $DIR/const_allocation.rs:+1:5: +1:8 + let mut _0: (); // return place in scope 0 at $DIR/const_allocation.rs:7:11: 7:11 + let _1: &[(std::option::Option, &[&str])]; // in scope 0 at $DIR/const_allocation.rs:8:5: 8:8 + let mut _2: &&[(std::option::Option, &[&str])]; // in scope 0 at $DIR/const_allocation.rs:8:5: 8:8 bb0: { - StorageLive(_1); // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8 - StorageLive(_2); // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8 - _2 = const {alloc1: &&[(Option, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8 + StorageLive(_1); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 + StorageLive(_2); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 + _2 = const {alloc1: &&[(Option, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 // mir::Constant // + span: $DIR/const_allocation.rs:8:5: 8:8 // + literal: Const { ty: &&[(Option, &[&str])], val: Value(Scalar(alloc1)) } - _1 = (*_2); // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8 - StorageDead(_2); // scope 0 at $DIR/const_allocation.rs:+1:8: +1:9 - StorageDead(_1); // scope 0 at $DIR/const_allocation.rs:+1:8: +1:9 - nop; // scope 0 at $DIR/const_allocation.rs:+0:11: +2:2 - return; // scope 0 at $DIR/const_allocation.rs:+2:2: +2:2 + _1 = (*_2); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 + StorageDead(_2); // scope 0 at $DIR/const_allocation.rs:8:8: 8:9 + StorageDead(_1); // scope 0 at $DIR/const_allocation.rs:8:8: 8:9 + nop; // scope 0 at $DIR/const_allocation.rs:7:11: 9:2 + return; // scope 0 at $DIR/const_allocation.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir index 389641f20f422..432aac9ccdfbb 100644 --- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir +++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir @@ -1,22 +1,22 @@ // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/const_allocation2.rs:+0:11: +0:11 - let _1: &[(std::option::Option, &[&u8])]; // in scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8 - let mut _2: &&[(std::option::Option, &[&u8])]; // in scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8 + let mut _0: (); // return place in scope 0 at $DIR/const_allocation2.rs:4:11: 4:11 + let _1: &[(std::option::Option, &[&u8])]; // in scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 + let mut _2: &&[(std::option::Option, &[&u8])]; // in scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 bb0: { - StorageLive(_1); // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8 - StorageLive(_2); // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8 - _2 = const {alloc1: &&[(Option, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8 + StorageLive(_1); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 + StorageLive(_2); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 + _2 = const {alloc1: &&[(Option, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 // mir::Constant // + span: $DIR/const_allocation2.rs:5:5: 5:8 // + literal: Const { ty: &&[(Option, &[&u8])], val: Value(Scalar(alloc1)) } - _1 = (*_2); // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8 - StorageDead(_2); // scope 0 at $DIR/const_allocation2.rs:+1:8: +1:9 - StorageDead(_1); // scope 0 at $DIR/const_allocation2.rs:+1:8: +1:9 - nop; // scope 0 at $DIR/const_allocation2.rs:+0:11: +2:2 - return; // scope 0 at $DIR/const_allocation2.rs:+2:2: +2:2 + _1 = (*_2); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 + StorageDead(_2); // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9 + StorageDead(_1); // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9 + nop; // scope 0 at $DIR/const_allocation2.rs:4:11: 6:2 + return; // scope 0 at $DIR/const_allocation2.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir index ce3848e9216c7..e2acd610b8053 100644 --- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir +++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir @@ -1,22 +1,22 @@ // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/const_allocation2.rs:+0:11: +0:11 - let _1: &[(std::option::Option, &[&u8])]; // in scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8 - let mut _2: &&[(std::option::Option, &[&u8])]; // in scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8 + let mut _0: (); // return place in scope 0 at $DIR/const_allocation2.rs:4:11: 4:11 + let _1: &[(std::option::Option, &[&u8])]; // in scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 + let mut _2: &&[(std::option::Option, &[&u8])]; // in scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 bb0: { - StorageLive(_1); // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8 - StorageLive(_2); // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8 - _2 = const {alloc1: &&[(Option, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8 + StorageLive(_1); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 + StorageLive(_2); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 + _2 = const {alloc1: &&[(Option, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 // mir::Constant // + span: $DIR/const_allocation2.rs:5:5: 5:8 // + literal: Const { ty: &&[(Option, &[&u8])], val: Value(Scalar(alloc1)) } - _1 = (*_2); // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8 - StorageDead(_2); // scope 0 at $DIR/const_allocation2.rs:+1:8: +1:9 - StorageDead(_1); // scope 0 at $DIR/const_allocation2.rs:+1:8: +1:9 - nop; // scope 0 at $DIR/const_allocation2.rs:+0:11: +2:2 - return; // scope 0 at $DIR/const_allocation2.rs:+2:2: +2:2 + _1 = (*_2); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 + StorageDead(_2); // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9 + StorageDead(_1); // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9 + nop; // scope 0 at $DIR/const_allocation2.rs:4:11: 6:2 + return; // scope 0 at $DIR/const_allocation2.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir index b72519159d758..991cf40d1b7ce 100644 --- a/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir +++ b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir @@ -1,22 +1,22 @@ // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/const_allocation3.rs:+0:11: +0:11 - let _1: &Packed; // in scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8 - let mut _2: &&Packed; // in scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8 + let mut _0: (); // return place in scope 0 at $DIR/const_allocation3.rs:4:11: 4:11 + let _1: &Packed; // in scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 + let mut _2: &&Packed; // in scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 bb0: { - StorageLive(_1); // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8 - StorageLive(_2); // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8 - _2 = const {alloc1: &&Packed}; // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8 + StorageLive(_1); // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 + StorageLive(_2); // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 + _2 = const {alloc1: &&Packed}; // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 // mir::Constant // + span: $DIR/const_allocation3.rs:5:5: 5:8 // + literal: Const { ty: &&Packed, val: Value(Scalar(alloc1)) } - _1 = (*_2); // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8 - StorageDead(_2); // scope 0 at $DIR/const_allocation3.rs:+1:8: +1:9 - StorageDead(_1); // scope 0 at $DIR/const_allocation3.rs:+1:8: +1:9 - nop; // scope 0 at $DIR/const_allocation3.rs:+0:11: +2:2 - return; // scope 0 at $DIR/const_allocation3.rs:+2:2: +2:2 + _1 = (*_2); // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 + StorageDead(_2); // scope 0 at $DIR/const_allocation3.rs:5:8: 5:9 + StorageDead(_1); // scope 0 at $DIR/const_allocation3.rs:5:8: 5:9 + nop; // scope 0 at $DIR/const_allocation3.rs:4:11: 6:2 + return; // scope 0 at $DIR/const_allocation3.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir index 6bd047c7d9fb2..fb481697aa811 100644 --- a/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir +++ b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir @@ -1,22 +1,22 @@ // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/const_allocation3.rs:+0:11: +0:11 - let _1: &Packed; // in scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8 - let mut _2: &&Packed; // in scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8 + let mut _0: (); // return place in scope 0 at $DIR/const_allocation3.rs:4:11: 4:11 + let _1: &Packed; // in scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 + let mut _2: &&Packed; // in scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 bb0: { - StorageLive(_1); // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8 - StorageLive(_2); // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8 - _2 = const {alloc1: &&Packed}; // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8 + StorageLive(_1); // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 + StorageLive(_2); // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 + _2 = const {alloc1: &&Packed}; // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 // mir::Constant // + span: $DIR/const_allocation3.rs:5:5: 5:8 // + literal: Const { ty: &&Packed, val: Value(Scalar(alloc1)) } - _1 = (*_2); // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8 - StorageDead(_2); // scope 0 at $DIR/const_allocation3.rs:+1:8: +1:9 - StorageDead(_1); // scope 0 at $DIR/const_allocation3.rs:+1:8: +1:9 - nop; // scope 0 at $DIR/const_allocation3.rs:+0:11: +2:2 - return; // scope 0 at $DIR/const_allocation3.rs:+2:2: +2:2 + _1 = (*_2); // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 + StorageDead(_2); // scope 0 at $DIR/const_allocation3.rs:5:8: 5:9 + StorageDead(_1); // scope 0 at $DIR/const_allocation3.rs:5:8: 5:9 + nop; // scope 0 at $DIR/const_allocation3.rs:4:11: 6:2 + return; // scope 0 at $DIR/const_allocation3.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff index a092f37529154..cd4b471b28cc1 100644 --- a/src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff +++ b/src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff @@ -2,46 +2,46 @@ + // MIR for `main` after ConstDebugInfo fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/const_debuginfo.rs:+0:11: +0:11 - let _1: u8; // in scope 0 at $DIR/const_debuginfo.rs:+1:9: +1:10 - let mut _5: u8; // in scope 0 at $DIR/const_debuginfo.rs:+4:15: +4:20 - let mut _6: u8; // in scope 0 at $DIR/const_debuginfo.rs:+4:15: +4:16 - let mut _7: u8; // in scope 0 at $DIR/const_debuginfo.rs:+4:19: +4:20 - let mut _8: u8; // in scope 0 at $DIR/const_debuginfo.rs:+4:23: +4:24 - let mut _14: u32; // in scope 0 at $DIR/const_debuginfo.rs:+13:13: +13:16 - let mut _15: u32; // in scope 0 at $DIR/const_debuginfo.rs:+13:19: +13:22 + let mut _0: (); // return place in scope 0 at $DIR/const_debuginfo.rs:8:11: 8:11 + let _1: u8; // in scope 0 at $DIR/const_debuginfo.rs:9:9: 9:10 + let mut _5: u8; // in scope 0 at $DIR/const_debuginfo.rs:12:15: 12:20 + let mut _6: u8; // in scope 0 at $DIR/const_debuginfo.rs:12:15: 12:16 + let mut _7: u8; // in scope 0 at $DIR/const_debuginfo.rs:12:19: 12:20 + let mut _8: u8; // in scope 0 at $DIR/const_debuginfo.rs:12:23: 12:24 + let mut _14: u32; // in scope 0 at $DIR/const_debuginfo.rs:21:13: 21:16 + let mut _15: u32; // in scope 0 at $DIR/const_debuginfo.rs:21:19: 21:22 scope 1 { -- debug x => _1; // in scope 1 at $DIR/const_debuginfo.rs:+1:9: +1:10 -+ debug x => const 1_u8; // in scope 1 at $DIR/const_debuginfo.rs:+1:9: +1:10 - let _2: u8; // in scope 1 at $DIR/const_debuginfo.rs:+2:9: +2:10 +- debug x => _1; // in scope 1 at $DIR/const_debuginfo.rs:9:9: 9:10 ++ debug x => const 1_u8; // in scope 1 at $DIR/const_debuginfo.rs:9:9: 9:10 + let _2: u8; // in scope 1 at $DIR/const_debuginfo.rs:10:9: 10:10 scope 2 { -- debug y => _2; // in scope 2 at $DIR/const_debuginfo.rs:+2:9: +2:10 -+ debug y => const 2_u8; // in scope 2 at $DIR/const_debuginfo.rs:+2:9: +2:10 - let _3: u8; // in scope 2 at $DIR/const_debuginfo.rs:+3:9: +3:10 +- debug y => _2; // in scope 2 at $DIR/const_debuginfo.rs:10:9: 10:10 ++ debug y => const 2_u8; // in scope 2 at $DIR/const_debuginfo.rs:10:9: 10:10 + let _3: u8; // in scope 2 at $DIR/const_debuginfo.rs:11:9: 11:10 scope 3 { -- debug z => _3; // in scope 3 at $DIR/const_debuginfo.rs:+3:9: +3:10 -+ debug z => const 3_u8; // in scope 3 at $DIR/const_debuginfo.rs:+3:9: +3:10 - let _4: u8; // in scope 3 at $DIR/const_debuginfo.rs:+4:9: +4:12 +- debug z => _3; // in scope 3 at $DIR/const_debuginfo.rs:11:9: 11:10 ++ debug z => const 3_u8; // in scope 3 at $DIR/const_debuginfo.rs:11:9: 11:10 + let _4: u8; // in scope 3 at $DIR/const_debuginfo.rs:12:9: 12:12 scope 4 { -- debug sum => _4; // in scope 4 at $DIR/const_debuginfo.rs:+4:9: +4:12 -+ debug sum => const 6_u8; // in scope 4 at $DIR/const_debuginfo.rs:+4:9: +4:12 - let _9: &str; // in scope 4 at $DIR/const_debuginfo.rs:+6:9: +6:10 +- debug sum => _4; // in scope 4 at $DIR/const_debuginfo.rs:12:9: 12:12 ++ debug sum => const 6_u8; // in scope 4 at $DIR/const_debuginfo.rs:12:9: 12:12 + let _9: &str; // in scope 4 at $DIR/const_debuginfo.rs:14:9: 14:10 scope 5 { -- debug s => _9; // in scope 5 at $DIR/const_debuginfo.rs:+6:9: +6:10 -+ debug s => const "hello, world!"; // in scope 5 at $DIR/const_debuginfo.rs:+6:9: +6:10 - let _10: (bool, bool, u32); // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 +- debug s => _9; // in scope 5 at $DIR/const_debuginfo.rs:14:9: 14:10 ++ debug s => const "hello, world!"; // in scope 5 at $DIR/const_debuginfo.rs:14:9: 14:10 + let _10: (bool, bool, u32); // in scope 5 at $DIR/const_debuginfo.rs:16:9: 16:10 scope 6 { - debug f => _10; // in scope 6 at $DIR/const_debuginfo.rs:+8:9: +8:10 - let _11: std::option::Option; // in scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10 + debug f => _10; // in scope 6 at $DIR/const_debuginfo.rs:16:9: 16:10 + let _11: std::option::Option; // in scope 6 at $DIR/const_debuginfo.rs:18:9: 18:10 scope 7 { - debug o => _11; // in scope 7 at $DIR/const_debuginfo.rs:+10:9: +10:10 - let _12: Point; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10 + debug o => _11; // in scope 7 at $DIR/const_debuginfo.rs:18:9: 18:10 + let _12: Point; // in scope 7 at $DIR/const_debuginfo.rs:20:9: 20:10 scope 8 { - debug p => _12; // in scope 8 at $DIR/const_debuginfo.rs:+12:9: +12:10 - let _13: u32; // in scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10 + debug p => _12; // in scope 8 at $DIR/const_debuginfo.rs:20:9: 20:10 + let _13: u32; // in scope 8 at $DIR/const_debuginfo.rs:21:9: 21:10 scope 9 { -- debug a => _13; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10 -+ debug a => const 64_u32; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10 +- debug a => _13; // in scope 9 at $DIR/const_debuginfo.rs:21:9: 21:10 ++ debug a => const 64_u32; // in scope 9 at $DIR/const_debuginfo.rs:21:9: 21:10 } } } @@ -53,63 +53,63 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/const_debuginfo.rs:+1:9: +1:10 - _1 = const 1_u8; // scope 0 at $DIR/const_debuginfo.rs:+1:13: +1:16 - StorageLive(_2); // scope 1 at $DIR/const_debuginfo.rs:+2:9: +2:10 - _2 = const 2_u8; // scope 1 at $DIR/const_debuginfo.rs:+2:13: +2:16 - StorageLive(_3); // scope 2 at $DIR/const_debuginfo.rs:+3:9: +3:10 - _3 = const 3_u8; // scope 2 at $DIR/const_debuginfo.rs:+3:13: +3:16 - StorageLive(_4); // scope 3 at $DIR/const_debuginfo.rs:+4:9: +4:12 - StorageLive(_5); // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:20 - StorageLive(_6); // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:16 - _6 = const 1_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:16 - StorageLive(_7); // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20 - _7 = const 2_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20 - _5 = const 3_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:20 - StorageDead(_7); // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20 - StorageDead(_6); // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20 - StorageLive(_8); // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24 - _8 = const 3_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24 - _4 = const 6_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:24 - StorageDead(_8); // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24 - StorageDead(_5); // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24 - StorageLive(_9); // scope 4 at $DIR/const_debuginfo.rs:+6:9: +6:10 - _9 = const "hello, world!"; // scope 4 at $DIR/const_debuginfo.rs:+6:13: +6:28 + StorageLive(_1); // scope 0 at $DIR/const_debuginfo.rs:9:9: 9:10 + _1 = const 1_u8; // scope 0 at $DIR/const_debuginfo.rs:9:13: 9:16 + StorageLive(_2); // scope 1 at $DIR/const_debuginfo.rs:10:9: 10:10 + _2 = const 2_u8; // scope 1 at $DIR/const_debuginfo.rs:10:13: 10:16 + StorageLive(_3); // scope 2 at $DIR/const_debuginfo.rs:11:9: 11:10 + _3 = const 3_u8; // scope 2 at $DIR/const_debuginfo.rs:11:13: 11:16 + StorageLive(_4); // scope 3 at $DIR/const_debuginfo.rs:12:9: 12:12 + StorageLive(_5); // scope 3 at $DIR/const_debuginfo.rs:12:15: 12:20 + StorageLive(_6); // scope 3 at $DIR/const_debuginfo.rs:12:15: 12:16 + _6 = const 1_u8; // scope 3 at $DIR/const_debuginfo.rs:12:15: 12:16 + StorageLive(_7); // scope 3 at $DIR/const_debuginfo.rs:12:19: 12:20 + _7 = const 2_u8; // scope 3 at $DIR/const_debuginfo.rs:12:19: 12:20 + _5 = const 3_u8; // scope 3 at $DIR/const_debuginfo.rs:12:15: 12:20 + StorageDead(_7); // scope 3 at $DIR/const_debuginfo.rs:12:19: 12:20 + StorageDead(_6); // scope 3 at $DIR/const_debuginfo.rs:12:19: 12:20 + StorageLive(_8); // scope 3 at $DIR/const_debuginfo.rs:12:23: 12:24 + _8 = const 3_u8; // scope 3 at $DIR/const_debuginfo.rs:12:23: 12:24 + _4 = const 6_u8; // scope 3 at $DIR/const_debuginfo.rs:12:15: 12:24 + StorageDead(_8); // scope 3 at $DIR/const_debuginfo.rs:12:23: 12:24 + StorageDead(_5); // scope 3 at $DIR/const_debuginfo.rs:12:23: 12:24 + StorageLive(_9); // scope 4 at $DIR/const_debuginfo.rs:14:9: 14:10 + _9 = const "hello, world!"; // scope 4 at $DIR/const_debuginfo.rs:14:13: 14:28 // mir::Constant // + span: $DIR/const_debuginfo.rs:14:13: 14:28 // + literal: Const { ty: &str, val: Value(Slice(..)) } - StorageLive(_10); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 - Deinit(_10); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 - (_10.0: bool) = const true; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 - (_10.1: bool) = const false; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 - (_10.2: u32) = const 123_u32; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 - StorageLive(_11); // scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10 - Deinit(_11); // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24 - ((_11 as Some).0: u16) = const 99_u16; // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24 - discriminant(_11) = 1; // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24 - StorageLive(_12); // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10 - Deinit(_12); // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 - (_12.0: u32) = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 - (_12.1: u32) = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 - StorageLive(_13); // scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10 - StorageLive(_14); // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:16 - _14 = const 32_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:16 - StorageLive(_15); // scope 8 at $DIR/const_debuginfo.rs:+13:19: +13:22 - _15 = const 32_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:19: +13:22 - _13 = const 64_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:22 - StorageDead(_15); // scope 8 at $DIR/const_debuginfo.rs:+13:21: +13:22 - StorageDead(_14); // scope 8 at $DIR/const_debuginfo.rs:+13:21: +13:22 - nop; // scope 0 at $DIR/const_debuginfo.rs:+0:11: +14:2 - StorageDead(_13); // scope 8 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_12); // scope 7 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_11); // scope 6 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_10); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_9); // scope 4 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_4); // scope 3 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_3); // scope 2 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_2); // scope 1 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_1); // scope 0 at $DIR/const_debuginfo.rs:+14:1: +14:2 - return; // scope 0 at $DIR/const_debuginfo.rs:+14:2: +14:2 + StorageLive(_10); // scope 5 at $DIR/const_debuginfo.rs:16:9: 16:10 + Deinit(_10); // scope 5 at $DIR/const_debuginfo.rs:16:13: 16:34 + (_10.0: bool) = const true; // scope 5 at $DIR/const_debuginfo.rs:16:13: 16:34 + (_10.1: bool) = const false; // scope 5 at $DIR/const_debuginfo.rs:16:13: 16:34 + (_10.2: u32) = const 123_u32; // scope 5 at $DIR/const_debuginfo.rs:16:13: 16:34 + StorageLive(_11); // scope 6 at $DIR/const_debuginfo.rs:18:9: 18:10 + Deinit(_11); // scope 6 at $DIR/const_debuginfo.rs:18:13: 18:24 + ((_11 as Some).0: u16) = const 99_u16; // scope 6 at $DIR/const_debuginfo.rs:18:13: 18:24 + discriminant(_11) = 1; // scope 6 at $DIR/const_debuginfo.rs:18:13: 18:24 + StorageLive(_12); // scope 7 at $DIR/const_debuginfo.rs:20:9: 20:10 + Deinit(_12); // scope 7 at $DIR/const_debuginfo.rs:20:13: 20:35 + (_12.0: u32) = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:20:13: 20:35 + (_12.1: u32) = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:20:13: 20:35 + StorageLive(_13); // scope 8 at $DIR/const_debuginfo.rs:21:9: 21:10 + StorageLive(_14); // scope 8 at $DIR/const_debuginfo.rs:21:13: 21:16 + _14 = const 32_u32; // scope 8 at $DIR/const_debuginfo.rs:21:13: 21:16 + StorageLive(_15); // scope 8 at $DIR/const_debuginfo.rs:21:19: 21:22 + _15 = const 32_u32; // scope 8 at $DIR/const_debuginfo.rs:21:19: 21:22 + _13 = const 64_u32; // scope 8 at $DIR/const_debuginfo.rs:21:13: 21:22 + StorageDead(_15); // scope 8 at $DIR/const_debuginfo.rs:21:21: 21:22 + StorageDead(_14); // scope 8 at $DIR/const_debuginfo.rs:21:21: 21:22 + nop; // scope 0 at $DIR/const_debuginfo.rs:8:11: 22:2 + StorageDead(_13); // scope 8 at $DIR/const_debuginfo.rs:22:1: 22:2 + StorageDead(_12); // scope 7 at $DIR/const_debuginfo.rs:22:1: 22:2 + StorageDead(_11); // scope 6 at $DIR/const_debuginfo.rs:22:1: 22:2 + StorageDead(_10); // scope 5 at $DIR/const_debuginfo.rs:22:1: 22:2 + StorageDead(_9); // scope 4 at $DIR/const_debuginfo.rs:22:1: 22:2 + StorageDead(_4); // scope 3 at $DIR/const_debuginfo.rs:22:1: 22:2 + StorageDead(_3); // scope 2 at $DIR/const_debuginfo.rs:22:1: 22:2 + StorageDead(_2); // scope 1 at $DIR/const_debuginfo.rs:22:1: 22:2 + StorageDead(_1); // scope 0 at $DIR/const_debuginfo.rs:22:1: 22:2 + return; // scope 0 at $DIR/const_debuginfo.rs:22:2: 22:2 } } diff --git a/src/test/mir-opt/const_goto.issue_77355_opt.ConstGoto.diff b/src/test/mir-opt/const_goto.issue_77355_opt.ConstGoto.diff index fade2d0bc6edf..544d16a251a82 100644 --- a/src/test/mir-opt/const_goto.issue_77355_opt.ConstGoto.diff +++ b/src/test/mir-opt/const_goto.issue_77355_opt.ConstGoto.diff @@ -2,25 +2,25 @@ + // MIR for `issue_77355_opt` after ConstGoto fn issue_77355_opt(_1: Foo) -> u64 { - debug num => _1; // in scope 0 at $DIR/const_goto.rs:+0:20: +0:23 - let mut _0: u64; // return place in scope 0 at $DIR/const_goto.rs:+0:33: +0:36 + debug num => _1; // in scope 0 at $DIR/const_goto.rs:11:20: 11:23 + let mut _0: u64; // return place in scope 0 at $DIR/const_goto.rs:11:33: 11:36 - let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -- let mut _3: isize; // in scope 0 at $DIR/const_goto.rs:+1:22: +1:28 -+ let mut _2: isize; // in scope 0 at $DIR/const_goto.rs:+1:22: +1:28 +- let mut _3: isize; // in scope 0 at $DIR/const_goto.rs:12:22: 12:28 ++ let mut _2: isize; // in scope 0 at $DIR/const_goto.rs:12:22: 12:28 bb0: { - StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -- _3 = discriminant(_1); // scope 0 at $DIR/const_goto.rs:+1:17: +1:20 +- _3 = discriminant(_1); // scope 0 at $DIR/const_goto.rs:12:17: 12:20 - switchInt(move _3) -> [1_isize: bb2, 2_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ _2 = discriminant(_1); // scope 0 at $DIR/const_goto.rs:+1:17: +1:20 ++ _2 = discriminant(_1); // scope 0 at $DIR/const_goto.rs:12:17: 12:20 + switchInt(move _2) -> [1_isize: bb2, 2_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL } bb1: { - _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ _0 = const 42_u64; // scope 0 at $DIR/const_goto.rs:+1:53: +1:55 -+ goto -> bb3; // scope 0 at $DIR/const_goto.rs:+1:5: +1:57 ++ _0 = const 42_u64; // scope 0 at $DIR/const_goto.rs:12:53: 12:55 ++ goto -> bb3; // scope 0 at $DIR/const_goto.rs:12:5: 12:57 } bb2: { @@ -33,20 +33,20 @@ - } - - bb4: { - _0 = const 23_u64; // scope 0 at $DIR/const_goto.rs:+1:41: +1:43 -- goto -> bb6; // scope 0 at $DIR/const_goto.rs:+1:5: +1:57 -+ goto -> bb3; // scope 0 at $DIR/const_goto.rs:+1:5: +1:57 + _0 = const 23_u64; // scope 0 at $DIR/const_goto.rs:12:41: 12:43 +- goto -> bb6; // scope 0 at $DIR/const_goto.rs:12:5: 12:57 ++ goto -> bb3; // scope 0 at $DIR/const_goto.rs:12:5: 12:57 } - bb5: { -- _0 = const 42_u64; // scope 0 at $DIR/const_goto.rs:+1:53: +1:55 -- goto -> bb6; // scope 0 at $DIR/const_goto.rs:+1:5: +1:57 +- _0 = const 42_u64; // scope 0 at $DIR/const_goto.rs:12:53: 12:55 +- goto -> bb6; // scope 0 at $DIR/const_goto.rs:12:5: 12:57 - } - - bb6: { -- StorageDead(_2); // scope 0 at $DIR/const_goto.rs:+1:56: +1:57 +- StorageDead(_2); // scope 0 at $DIR/const_goto.rs:12:56: 12:57 + bb3: { - return; // scope 0 at $DIR/const_goto.rs:+2:2: +2:2 + return; // scope 0 at $DIR/const_goto.rs:13:2: 13:2 } } diff --git a/src/test/mir-opt/const_goto_const_eval_fail.f.ConstGoto.diff b/src/test/mir-opt/const_goto_const_eval_fail.f.ConstGoto.diff index 623297aeba506..9ba02942b58b6 100644 --- a/src/test/mir-opt/const_goto_const_eval_fail.f.ConstGoto.diff +++ b/src/test/mir-opt/const_goto_const_eval_fail.f.ConstGoto.diff @@ -2,50 +2,50 @@ + // MIR for `f` after ConstGoto fn f() -> u64 { - let mut _0: u64; // return place in scope 0 at $DIR/const_goto_const_eval_fail.rs:+0:44: +0:47 - let mut _1: bool; // in scope 0 at $DIR/const_goto_const_eval_fail.rs:+1:11: +6:6 - let mut _2: i32; // in scope 0 at $DIR/const_goto_const_eval_fail.rs:+2:15: +2:16 + let mut _0: u64; // return place in scope 0 at $DIR/const_goto_const_eval_fail.rs:6:44: 6:47 + let mut _1: bool; // in scope 0 at $DIR/const_goto_const_eval_fail.rs:7:11: 12:6 + let mut _2: i32; // in scope 0 at $DIR/const_goto_const_eval_fail.rs:8:15: 8:16 bb0: { - StorageLive(_1); // scope 0 at $DIR/const_goto_const_eval_fail.rs:+1:11: +6:6 - StorageLive(_2); // scope 0 at $DIR/const_goto_const_eval_fail.rs:+2:15: +2:16 - _2 = const A; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+2:15: +2:16 - switchInt(_2) -> [1_i32: bb2, 2_i32: bb2, 3_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+2:9: +2:16 + StorageLive(_1); // scope 0 at $DIR/const_goto_const_eval_fail.rs:7:11: 12:6 + StorageLive(_2); // scope 0 at $DIR/const_goto_const_eval_fail.rs:8:15: 8:16 + _2 = const A; // scope 0 at $DIR/const_goto_const_eval_fail.rs:8:15: 8:16 + switchInt(_2) -> [1_i32: bb2, 2_i32: bb2, 3_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:8:9: 8:16 } bb1: { - _1 = const true; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+4:18: +4:22 - goto -> bb3; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+4:18: +4:22 + _1 = const true; // scope 0 at $DIR/const_goto_const_eval_fail.rs:10:18: 10:22 + goto -> bb3; // scope 0 at $DIR/const_goto_const_eval_fail.rs:10:18: 10:22 } bb2: { - _1 = const B; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+3:26: +3:27 -- goto -> bb3; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+3:26: +3:27 -+ switchInt(_1) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+1:5: +6:6 + _1 = const B; // scope 0 at $DIR/const_goto_const_eval_fail.rs:9:26: 9:27 +- goto -> bb3; // scope 0 at $DIR/const_goto_const_eval_fail.rs:9:26: 9:27 ++ switchInt(_1) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:7:5: 12:6 } bb3: { -- switchInt(_1) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+1:5: +6:6 +- switchInt(_1) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:7:5: 12:6 - } - - bb4: { - _0 = const 2_u64; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+8:17: +8:18 -- goto -> bb6; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+8:17: +8:18 -+ goto -> bb5; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+8:17: +8:18 + _0 = const 2_u64; // scope 0 at $DIR/const_goto_const_eval_fail.rs:14:17: 14:18 +- goto -> bb6; // scope 0 at $DIR/const_goto_const_eval_fail.rs:14:17: 14:18 ++ goto -> bb5; // scope 0 at $DIR/const_goto_const_eval_fail.rs:14:17: 14:18 } - bb5: { + bb4: { - _0 = const 1_u64; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+7:18: +7:19 -- goto -> bb6; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+7:18: +7:19 -+ goto -> bb5; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+7:18: +7:19 + _0 = const 1_u64; // scope 0 at $DIR/const_goto_const_eval_fail.rs:13:18: 13:19 +- goto -> bb6; // scope 0 at $DIR/const_goto_const_eval_fail.rs:13:18: 13:19 ++ goto -> bb5; // scope 0 at $DIR/const_goto_const_eval_fail.rs:13:18: 13:19 } - bb6: { + bb5: { - StorageDead(_2); // scope 0 at $DIR/const_goto_const_eval_fail.rs:+10:1: +10:2 - StorageDead(_1); // scope 0 at $DIR/const_goto_const_eval_fail.rs:+10:1: +10:2 - return; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+10:2: +10:2 + StorageDead(_2); // scope 0 at $DIR/const_goto_const_eval_fail.rs:16:1: 16:2 + StorageDead(_1); // scope 0 at $DIR/const_goto_const_eval_fail.rs:16:1: 16:2 + return; // scope 0 at $DIR/const_goto_const_eval_fail.rs:16:2: 16:2 } } diff --git a/src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff b/src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff index 2b09ef7866126..62a681e1c12a7 100644 --- a/src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff +++ b/src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff @@ -2,102 +2,102 @@ + // MIR for `match_nested_if` after ConstGoto fn match_nested_if() -> bool { - let mut _0: bool; // return place in scope 0 at $DIR/const_goto_storage.rs:+0:25: +0:29 - let _1: bool; // in scope 0 at $DIR/const_goto_storage.rs:+1:9: +1:12 -- let mut _2: (); // in scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23 -- let mut _3: bool; // in scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10 -- let mut _4: bool; // in scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76 -- let mut _5: bool; // in scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52 -- let mut _6: bool; // in scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 -+ let mut _2: bool; // in scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 + let mut _0: bool; // return place in scope 0 at $DIR/const_goto_storage.rs:2:25: 2:29 + let _1: bool; // in scope 0 at $DIR/const_goto_storage.rs:3:9: 3:12 +- let mut _2: (); // in scope 0 at $DIR/const_goto_storage.rs:3:21: 3:23 +- let mut _3: bool; // in scope 0 at $DIR/const_goto_storage.rs:4:15: 8:10 +- let mut _4: bool; // in scope 0 at $DIR/const_goto_storage.rs:4:18: 4:76 +- let mut _5: bool; // in scope 0 at $DIR/const_goto_storage.rs:4:21: 4:52 +- let mut _6: bool; // in scope 0 at $DIR/const_goto_storage.rs:4:24: 4:28 ++ let mut _2: bool; // in scope 0 at $DIR/const_goto_storage.rs:4:24: 4:28 scope 1 { - debug val => _1; // in scope 1 at $DIR/const_goto_storage.rs:+1:9: +1:12 + debug val => _1; // in scope 1 at $DIR/const_goto_storage.rs:3:9: 3:12 } bb0: { - StorageLive(_1); // scope 0 at $DIR/const_goto_storage.rs:+1:9: +1:12 -- StorageLive(_2); // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23 -- nop; // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23 -- StorageLive(_3); // scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10 -- StorageLive(_4); // scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76 -- StorageLive(_5); // scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52 -- StorageLive(_6); // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 -- _6 = const true; // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 -- switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 -+ StorageLive(_2); // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 -+ _2 = const true; // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 -+ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 + StorageLive(_1); // scope 0 at $DIR/const_goto_storage.rs:3:9: 3:12 +- StorageLive(_2); // scope 0 at $DIR/const_goto_storage.rs:3:21: 3:23 +- nop; // scope 0 at $DIR/const_goto_storage.rs:3:21: 3:23 +- StorageLive(_3); // scope 0 at $DIR/const_goto_storage.rs:4:15: 8:10 +- StorageLive(_4); // scope 0 at $DIR/const_goto_storage.rs:4:18: 4:76 +- StorageLive(_5); // scope 0 at $DIR/const_goto_storage.rs:4:21: 4:52 +- StorageLive(_6); // scope 0 at $DIR/const_goto_storage.rs:4:24: 4:28 +- _6 = const true; // scope 0 at $DIR/const_goto_storage.rs:4:24: 4:28 +- switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto_storage.rs:4:24: 4:28 ++ StorageLive(_2); // scope 0 at $DIR/const_goto_storage.rs:4:24: 4:28 ++ _2 = const true; // scope 0 at $DIR/const_goto_storage.rs:4:24: 4:28 ++ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto_storage.rs:4:24: 4:28 } bb1: { -- _5 = const true; // scope 0 at $DIR/const_goto_storage.rs:+2:31: +2:35 -- goto -> bb3; // scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52 +- _5 = const true; // scope 0 at $DIR/const_goto_storage.rs:4:31: 4:35 +- goto -> bb3; // scope 0 at $DIR/const_goto_storage.rs:4:21: 4:52 - } - - bb2: { -- _5 = const false; // scope 0 at $DIR/const_goto_storage.rs:+2:45: +2:50 -- goto -> bb3; // scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52 +- _5 = const false; // scope 0 at $DIR/const_goto_storage.rs:4:45: 4:50 +- goto -> bb3; // scope 0 at $DIR/const_goto_storage.rs:4:21: 4:52 - } - - bb3: { -- StorageDead(_6); // scope 0 at $DIR/const_goto_storage.rs:+2:51: +2:52 -- switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52 +- StorageDead(_6); // scope 0 at $DIR/const_goto_storage.rs:4:51: 4:52 +- switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/const_goto_storage.rs:4:21: 4:52 - } - - bb4: { -- _4 = const true; // scope 0 at $DIR/const_goto_storage.rs:+2:55: +2:59 -- goto -> bb6; // scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76 +- _4 = const true; // scope 0 at $DIR/const_goto_storage.rs:4:55: 4:59 +- goto -> bb6; // scope 0 at $DIR/const_goto_storage.rs:4:18: 4:76 - } - - bb5: { -- _4 = const false; // scope 0 at $DIR/const_goto_storage.rs:+2:69: +2:74 -- goto -> bb6; // scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76 +- _4 = const false; // scope 0 at $DIR/const_goto_storage.rs:4:69: 4:74 +- goto -> bb6; // scope 0 at $DIR/const_goto_storage.rs:4:18: 4:76 - } - - bb6: { -- StorageDead(_5); // scope 0 at $DIR/const_goto_storage.rs:+2:75: +2:76 -- switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76 +- StorageDead(_5); // scope 0 at $DIR/const_goto_storage.rs:4:75: 4:76 +- switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/const_goto_storage.rs:4:18: 4:76 - } - - bb7: { -- _3 = const true; // scope 0 at $DIR/const_goto_storage.rs:+3:13: +3:17 -- goto -> bb9; // scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10 +- _3 = const true; // scope 0 at $DIR/const_goto_storage.rs:5:13: 5:17 +- goto -> bb9; // scope 0 at $DIR/const_goto_storage.rs:4:15: 8:10 - } - - bb8: { -- _3 = const false; // scope 0 at $DIR/const_goto_storage.rs:+5:13: +5:18 -- goto -> bb9; // scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10 +- _3 = const false; // scope 0 at $DIR/const_goto_storage.rs:7:13: 7:18 +- goto -> bb9; // scope 0 at $DIR/const_goto_storage.rs:4:15: 8:10 - } - - bb9: { -- switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10 +- switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/const_goto_storage.rs:4:15: 8:10 - } - - bb10: { -- StorageDead(_4); // scope 0 at $DIR/const_goto_storage.rs:+6:9: +6:10 -- StorageDead(_3); // scope 0 at $DIR/const_goto_storage.rs:+6:9: +6:10 -+ StorageDead(_2); // scope 0 at $DIR/const_goto_storage.rs:+2:51: +2:52 - _1 = const true; // scope 0 at $DIR/const_goto_storage.rs:+8:17: +8:21 -- goto -> bb12; // scope 0 at $DIR/const_goto_storage.rs:+8:17: +8:21 -+ goto -> bb3; // scope 0 at $DIR/const_goto_storage.rs:+8:17: +8:21 +- StorageDead(_4); // scope 0 at $DIR/const_goto_storage.rs:8:9: 8:10 +- StorageDead(_3); // scope 0 at $DIR/const_goto_storage.rs:8:9: 8:10 ++ StorageDead(_2); // scope 0 at $DIR/const_goto_storage.rs:4:51: 4:52 + _1 = const true; // scope 0 at $DIR/const_goto_storage.rs:10:17: 10:21 +- goto -> bb12; // scope 0 at $DIR/const_goto_storage.rs:10:17: 10:21 ++ goto -> bb3; // scope 0 at $DIR/const_goto_storage.rs:10:17: 10:21 } - bb11: { -- StorageDead(_4); // scope 0 at $DIR/const_goto_storage.rs:+6:9: +6:10 -- StorageDead(_3); // scope 0 at $DIR/const_goto_storage.rs:+6:9: +6:10 +- StorageDead(_4); // scope 0 at $DIR/const_goto_storage.rs:8:9: 8:10 +- StorageDead(_3); // scope 0 at $DIR/const_goto_storage.rs:8:9: 8:10 + bb2: { -+ StorageDead(_2); // scope 0 at $DIR/const_goto_storage.rs:+2:51: +2:52 - _1 = const false; // scope 0 at $DIR/const_goto_storage.rs:+10:14: +10:19 -- goto -> bb12; // scope 0 at $DIR/const_goto_storage.rs:+10:14: +10:19 -+ goto -> bb3; // scope 0 at $DIR/const_goto_storage.rs:+10:14: +10:19 ++ StorageDead(_2); // scope 0 at $DIR/const_goto_storage.rs:4:51: 4:52 + _1 = const false; // scope 0 at $DIR/const_goto_storage.rs:12:14: 12:19 +- goto -> bb12; // scope 0 at $DIR/const_goto_storage.rs:12:14: 12:19 ++ goto -> bb3; // scope 0 at $DIR/const_goto_storage.rs:12:14: 12:19 } - bb12: { -- StorageDead(_2); // scope 0 at $DIR/const_goto_storage.rs:+11:6: +11:7 +- StorageDead(_2); // scope 0 at $DIR/const_goto_storage.rs:13:6: 13:7 + bb3: { - _0 = _1; // scope 1 at $DIR/const_goto_storage.rs:+12:5: +12:8 - StorageDead(_1); // scope 0 at $DIR/const_goto_storage.rs:+13:1: +13:2 - return; // scope 0 at $DIR/const_goto_storage.rs:+13:2: +13:2 + _0 = _1; // scope 1 at $DIR/const_goto_storage.rs:14:5: 14:8 + StorageDead(_1); // scope 0 at $DIR/const_goto_storage.rs:15:1: 15:2 + return; // scope 0 at $DIR/const_goto_storage.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir index 7650769de3b59..666b805e822c1 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir @@ -1,20 +1,20 @@ // MIR for `BAR::promoted[0]` after SimplifyCfg-elaborate-drops promoted[0] in BAR: &[&i32; 1] = { - let mut _0: &[&i32; 1]; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44 - let mut _1: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:35 - let mut _2: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:32: +0:34 - let mut _3: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:33: +0:34 + let mut _0: &[&i32; 1]; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 + let mut _1: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 + let mut _2: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 + let mut _3: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34 bb0: { - _3 = const {alloc1: &i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:33: +0:34 + _3 = const {alloc1: &i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34 // mir::Constant // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34 // + literal: Const { ty: &i32, val: Value(Scalar(alloc1)) } - _2 = &(*_3); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:32: +0:34 - _1 = [move _2]; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:35 - _0 = &_1; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44 - return; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44 + _2 = &(*_3); // scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 + _1 = [move _2]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 + _0 = &_1; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 + return; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 } } diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff index f58ba56b943f4..bc82222d11856 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff @@ -2,49 +2,49 @@ + // MIR for `BAR` after PromoteTemps static mut BAR: *const &i32 = { - let mut _0: *const &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:+0:17: +0:28 - let mut _1: &[&i32]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44 - let mut _2: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44 - let _3: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:35 - let mut _4: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:32: +0:34 - let _5: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:33: +0:34 -+ let mut _6: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44 + let mut _0: *const &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:9:17: 9:28 + let mut _1: &[&i32]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 + let mut _2: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 + let _3: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 + let mut _4: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 + let _5: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34 ++ let mut _6: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 bb0: { - StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44 - StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44 -- StorageLive(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:35 -- StorageLive(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:32: +0:34 -- StorageLive(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:33: +0:34 -- _5 = const {alloc1: &i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:33: +0:34 -+ _6 = const BAR::promoted[0]; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44 + StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 + StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 +- StorageLive(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 +- StorageLive(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 +- StorageLive(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34 +- _5 = const {alloc1: &i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34 ++ _6 = const BAR::promoted[0]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 // mir::Constant - // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34 - // + literal: Const { ty: &i32, val: Value(Scalar(alloc1)) } -- _4 = &(*_5); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:32: +0:34 -- _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:35 -- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44 +- _4 = &(*_5); // scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 +- _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 +- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 + // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:44 + // + literal: Const { ty: &[&i32; 1], val: Unevaluated(BAR, [], Some(promoted[0])) } -+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44 - _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44 -- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:34: +0:35 - StorageDead(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:34: +0:35 - _0 = core::slice::::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44 ++ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 + _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 +- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35 + StorageDead(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35 + _0 = core::slice::::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 // mir::Constant // + span: $DIR/const-promotion-extern-static.rs:9:36: 9:42 // + literal: Const { ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::::as_ptr}, val: Value() } } bb1: { -- StorageDead(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:43: +0:44 -- StorageDead(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:43: +0:44 - StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:43: +0:44 - return; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:1: +0:28 +- StorageDead(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:9:43: 9:44 +- StorageDead(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:9:43: 9:44 + StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:9:43: 9:44 + return; // scope 0 at $DIR/const-promotion-extern-static.rs:9:1: 9:28 } bb2 (cleanup): { - resume; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:1: +0:28 + resume; // scope 0 at $DIR/const-promotion-extern-static.rs:9:1: 9:28 } - } - diff --git a/src/test/mir-opt/const_promotion_extern_static.BOP.mir_map.0.mir b/src/test/mir-opt/const_promotion_extern_static.BOP.mir_map.0.mir index deb467977d7bf..2e63c2c25fac3 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BOP.mir_map.0.mir +++ b/src/test/mir-opt/const_promotion_extern_static.BOP.mir_map.0.mir @@ -1,17 +1,17 @@ // MIR for `BOP` 0 mir_map static BOP: &i32 = { - let mut _0: &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:+0:13: +0:17 - let _1: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:20: +0:23 - let _2: i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:21: +0:23 + let mut _0: &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:16:13: 16:17 + let _1: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:16:20: 16:23 + let _2: i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:16:21: 16:23 bb0: { - StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:20: +0:23 - StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:21: +0:23 - _2 = const 13_i32; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:21: +0:23 - _1 = &_2; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:20: +0:23 - _0 = &(*_1); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:20: +0:23 - StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:22: +0:23 - return; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:1: +0:17 + StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:16:20: 16:23 + StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:16:21: 16:23 + _2 = const 13_i32; // scope 0 at $DIR/const-promotion-extern-static.rs:16:21: 16:23 + _1 = &_2; // scope 0 at $DIR/const-promotion-extern-static.rs:16:20: 16:23 + _0 = &(*_1); // scope 0 at $DIR/const-promotion-extern-static.rs:16:20: 16:23 + StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:16:22: 16:23 + return; // scope 0 at $DIR/const-promotion-extern-static.rs:16:1: 16:17 } } diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir index 71827eab1c28b..785c8386e88b5 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir @@ -1,20 +1,20 @@ // MIR for `FOO::promoted[0]` after SimplifyCfg-elaborate-drops promoted[0] in FOO: &[&i32; 1] = { - let mut _0: &[&i32; 1]; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55 - let mut _1: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:46 - let mut _2: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:32: +0:45 - let mut _3: *const i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:42: +0:43 + let mut _0: &[&i32; 1]; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 + let mut _1: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 + let mut _2: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45 + let mut _3: *const i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 bb0: { - _3 = const {alloc3: *const i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:42: +0:43 + _3 = const {alloc3: *const i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 // mir::Constant // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43 // + literal: Const { ty: *const i32, val: Value(Scalar(alloc3)) } - _2 = &(*_3); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:41: +0:43 - _1 = [move _2]; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:46 - _0 = &_1; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55 - return; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55 + _2 = &(*_3); // scope 0 at $DIR/const-promotion-extern-static.rs:13:41: 13:43 + _1 = [move _2]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 + _0 = &_1; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 + return; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 } } diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff index 5300f555fdfb8..39dcf2f10c6f2 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff @@ -2,51 +2,51 @@ + // MIR for `FOO` after PromoteTemps static mut FOO: *const &i32 = { - let mut _0: *const &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:+0:17: +0:28 - let mut _1: &[&i32]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55 - let mut _2: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55 - let _3: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:46 - let mut _4: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:32: +0:45 - let _5: *const i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:42: +0:43 -+ let mut _6: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55 + let mut _0: *const &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:13:17: 13:28 + let mut _1: &[&i32]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 + let mut _2: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 + let _3: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 + let mut _4: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45 + let _5: *const i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 ++ let mut _6: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 scope 1 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55 - StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55 -- StorageLive(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:46 -- StorageLive(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:32: +0:45 -- StorageLive(_5); // scope 1 at $DIR/const-promotion-extern-static.rs:+0:42: +0:43 -- _5 = const {alloc3: *const i32}; // scope 1 at $DIR/const-promotion-extern-static.rs:+0:42: +0:43 -+ _6 = const FOO::promoted[0]; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55 + StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 + StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 +- StorageLive(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 +- StorageLive(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45 +- StorageLive(_5); // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 +- _5 = const {alloc3: *const i32}; // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 ++ _6 = const FOO::promoted[0]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 // mir::Constant - // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43 - // + literal: Const { ty: *const i32, val: Value(Scalar(alloc3)) } -- _4 = &(*_5); // scope 1 at $DIR/const-promotion-extern-static.rs:+0:41: +0:43 -- _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:46 -- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55 +- _4 = &(*_5); // scope 1 at $DIR/const-promotion-extern-static.rs:13:41: 13:43 +- _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 +- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 + // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:55 + // + literal: Const { ty: &[&i32; 1], val: Unevaluated(FOO, [], Some(promoted[0])) } -+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55 - _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55 -- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:45: +0:46 - StorageDead(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:45: +0:46 - _0 = core::slice::::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55 ++ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 + _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 +- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46 + StorageDead(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46 + _0 = core::slice::::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 // mir::Constant // + span: $DIR/const-promotion-extern-static.rs:13:47: 13:53 // + literal: Const { ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::::as_ptr}, val: Value() } } bb1: { -- StorageDead(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:54: +0:55 -- StorageDead(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:54: +0:55 - StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:54: +0:55 - return; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:1: +0:28 +- StorageDead(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:13:54: 13:55 +- StorageDead(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:13:54: 13:55 + StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:13:54: 13:55 + return; // scope 0 at $DIR/const-promotion-extern-static.rs:13:1: 13:28 } bb2 (cleanup): { - resume; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:1: +0:28 + resume; // scope 0 at $DIR/const-promotion-extern-static.rs:13:1: 13:28 } } - diff --git a/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff b/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff index 836443bf4d293..821075047cb87 100644 --- a/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff @@ -2,31 +2,31 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/aggregate.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/aggregate.rs:+1:9: +1:10 - let mut _2: i32; // in scope 0 at $DIR/aggregate.rs:+1:13: +1:24 - let mut _3: (i32, i32, i32); // in scope 0 at $DIR/aggregate.rs:+1:13: +1:22 + let mut _0: (); // return place in scope 0 at $DIR/aggregate.rs:4:11: 4:11 + let _1: i32; // in scope 0 at $DIR/aggregate.rs:5:9: 5:10 + let mut _2: i32; // in scope 0 at $DIR/aggregate.rs:5:13: 5:24 + let mut _3: (i32, i32, i32); // in scope 0 at $DIR/aggregate.rs:5:13: 5:22 scope 1 { - debug x => _1; // in scope 1 at $DIR/aggregate.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/aggregate.rs:5:9: 5:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/aggregate.rs:+1:9: +1:10 - StorageLive(_2); // scope 0 at $DIR/aggregate.rs:+1:13: +1:24 - StorageLive(_3); // scope 0 at $DIR/aggregate.rs:+1:13: +1:22 - Deinit(_3); // scope 0 at $DIR/aggregate.rs:+1:13: +1:22 - (_3.0: i32) = const 0_i32; // scope 0 at $DIR/aggregate.rs:+1:13: +1:22 - (_3.1: i32) = const 1_i32; // scope 0 at $DIR/aggregate.rs:+1:13: +1:22 - (_3.2: i32) = const 2_i32; // scope 0 at $DIR/aggregate.rs:+1:13: +1:22 -- _2 = (_3.1: i32); // scope 0 at $DIR/aggregate.rs:+1:13: +1:24 -- _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/aggregate.rs:+1:13: +1:28 -+ _2 = const 1_i32; // scope 0 at $DIR/aggregate.rs:+1:13: +1:24 -+ _1 = const 1_i32; // scope 0 at $DIR/aggregate.rs:+1:13: +1:28 - StorageDead(_2); // scope 0 at $DIR/aggregate.rs:+1:27: +1:28 - StorageDead(_3); // scope 0 at $DIR/aggregate.rs:+1:28: +1:29 - nop; // scope 0 at $DIR/aggregate.rs:+0:11: +2:2 - StorageDead(_1); // scope 0 at $DIR/aggregate.rs:+2:1: +2:2 - return; // scope 0 at $DIR/aggregate.rs:+2:2: +2:2 + StorageLive(_1); // scope 0 at $DIR/aggregate.rs:5:9: 5:10 + StorageLive(_2); // scope 0 at $DIR/aggregate.rs:5:13: 5:24 + StorageLive(_3); // scope 0 at $DIR/aggregate.rs:5:13: 5:22 + Deinit(_3); // scope 0 at $DIR/aggregate.rs:5:13: 5:22 + (_3.0: i32) = const 0_i32; // scope 0 at $DIR/aggregate.rs:5:13: 5:22 + (_3.1: i32) = const 1_i32; // scope 0 at $DIR/aggregate.rs:5:13: 5:22 + (_3.2: i32) = const 2_i32; // scope 0 at $DIR/aggregate.rs:5:13: 5:22 +- _2 = (_3.1: i32); // scope 0 at $DIR/aggregate.rs:5:13: 5:24 +- _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/aggregate.rs:5:13: 5:28 ++ _2 = const 1_i32; // scope 0 at $DIR/aggregate.rs:5:13: 5:24 ++ _1 = const 1_i32; // scope 0 at $DIR/aggregate.rs:5:13: 5:28 + StorageDead(_2); // scope 0 at $DIR/aggregate.rs:5:27: 5:28 + StorageDead(_3); // scope 0 at $DIR/aggregate.rs:5:28: 5:29 + nop; // scope 0 at $DIR/aggregate.rs:4:11: 6:2 + StorageDead(_1); // scope 0 at $DIR/aggregate.rs:6:1: 6:2 + return; // scope 0 at $DIR/aggregate.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff index bb9abdd10200d..e69f887cea8fa 100644 --- a/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff @@ -2,37 +2,37 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/array_index.rs:+0:11: +0:11 - let _1: u32; // in scope 0 at $DIR/array_index.rs:+1:9: +1:10 - let mut _2: [u32; 4]; // in scope 0 at $DIR/array_index.rs:+1:18: +1:30 - let _3: usize; // in scope 0 at $DIR/array_index.rs:+1:31: +1:32 - let mut _4: usize; // in scope 0 at $DIR/array_index.rs:+1:18: +1:33 - let mut _5: bool; // in scope 0 at $DIR/array_index.rs:+1:18: +1:33 + let mut _0: (); // return place in scope 0 at $DIR/array_index.rs:4:11: 4:11 + let _1: u32; // in scope 0 at $DIR/array_index.rs:5:9: 5:10 + let mut _2: [u32; 4]; // in scope 0 at $DIR/array_index.rs:5:18: 5:30 + let _3: usize; // in scope 0 at $DIR/array_index.rs:5:31: 5:32 + let mut _4: usize; // in scope 0 at $DIR/array_index.rs:5:18: 5:33 + let mut _5: bool; // in scope 0 at $DIR/array_index.rs:5:18: 5:33 scope 1 { - debug x => _1; // in scope 1 at $DIR/array_index.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/array_index.rs:5:9: 5:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/array_index.rs:+1:9: +1:10 - StorageLive(_2); // scope 0 at $DIR/array_index.rs:+1:18: +1:30 - _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; // scope 0 at $DIR/array_index.rs:+1:18: +1:30 - StorageLive(_3); // scope 0 at $DIR/array_index.rs:+1:31: +1:32 - _3 = const 2_usize; // scope 0 at $DIR/array_index.rs:+1:31: +1:32 - _4 = const 4_usize; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 -- _5 = Lt(_3, _4); // scope 0 at $DIR/array_index.rs:+1:18: +1:33 -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 -+ _5 = const true; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 + StorageLive(_1); // scope 0 at $DIR/array_index.rs:5:9: 5:10 + StorageLive(_2); // scope 0 at $DIR/array_index.rs:5:18: 5:30 + _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; // scope 0 at $DIR/array_index.rs:5:18: 5:30 + StorageLive(_3); // scope 0 at $DIR/array_index.rs:5:31: 5:32 + _3 = const 2_usize; // scope 0 at $DIR/array_index.rs:5:31: 5:32 + _4 = const 4_usize; // scope 0 at $DIR/array_index.rs:5:18: 5:33 +- _5 = Lt(_3, _4); // scope 0 at $DIR/array_index.rs:5:18: 5:33 +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 ++ _5 = const true; // scope 0 at $DIR/array_index.rs:5:18: 5:33 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 } bb1: { -- _1 = _2[_3]; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 -+ _1 = const 2_u32; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 - StorageDead(_3); // scope 0 at $DIR/array_index.rs:+1:33: +1:34 - StorageDead(_2); // scope 0 at $DIR/array_index.rs:+1:33: +1:34 - nop; // scope 0 at $DIR/array_index.rs:+0:11: +2:2 - StorageDead(_1); // scope 0 at $DIR/array_index.rs:+2:1: +2:2 - return; // scope 0 at $DIR/array_index.rs:+2:2: +2:2 +- _1 = _2[_3]; // scope 0 at $DIR/array_index.rs:5:18: 5:33 ++ _1 = const 2_u32; // scope 0 at $DIR/array_index.rs:5:18: 5:33 + StorageDead(_3); // scope 0 at $DIR/array_index.rs:5:33: 5:34 + StorageDead(_2); // scope 0 at $DIR/array_index.rs:5:33: 5:34 + nop; // scope 0 at $DIR/array_index.rs:4:11: 6:2 + StorageDead(_1); // scope 0 at $DIR/array_index.rs:6:1: 6:2 + return; // scope 0 at $DIR/array_index.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff index bb9abdd10200d..e69f887cea8fa 100644 --- a/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff @@ -2,37 +2,37 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/array_index.rs:+0:11: +0:11 - let _1: u32; // in scope 0 at $DIR/array_index.rs:+1:9: +1:10 - let mut _2: [u32; 4]; // in scope 0 at $DIR/array_index.rs:+1:18: +1:30 - let _3: usize; // in scope 0 at $DIR/array_index.rs:+1:31: +1:32 - let mut _4: usize; // in scope 0 at $DIR/array_index.rs:+1:18: +1:33 - let mut _5: bool; // in scope 0 at $DIR/array_index.rs:+1:18: +1:33 + let mut _0: (); // return place in scope 0 at $DIR/array_index.rs:4:11: 4:11 + let _1: u32; // in scope 0 at $DIR/array_index.rs:5:9: 5:10 + let mut _2: [u32; 4]; // in scope 0 at $DIR/array_index.rs:5:18: 5:30 + let _3: usize; // in scope 0 at $DIR/array_index.rs:5:31: 5:32 + let mut _4: usize; // in scope 0 at $DIR/array_index.rs:5:18: 5:33 + let mut _5: bool; // in scope 0 at $DIR/array_index.rs:5:18: 5:33 scope 1 { - debug x => _1; // in scope 1 at $DIR/array_index.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/array_index.rs:5:9: 5:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/array_index.rs:+1:9: +1:10 - StorageLive(_2); // scope 0 at $DIR/array_index.rs:+1:18: +1:30 - _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; // scope 0 at $DIR/array_index.rs:+1:18: +1:30 - StorageLive(_3); // scope 0 at $DIR/array_index.rs:+1:31: +1:32 - _3 = const 2_usize; // scope 0 at $DIR/array_index.rs:+1:31: +1:32 - _4 = const 4_usize; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 -- _5 = Lt(_3, _4); // scope 0 at $DIR/array_index.rs:+1:18: +1:33 -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 -+ _5 = const true; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 + StorageLive(_1); // scope 0 at $DIR/array_index.rs:5:9: 5:10 + StorageLive(_2); // scope 0 at $DIR/array_index.rs:5:18: 5:30 + _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; // scope 0 at $DIR/array_index.rs:5:18: 5:30 + StorageLive(_3); // scope 0 at $DIR/array_index.rs:5:31: 5:32 + _3 = const 2_usize; // scope 0 at $DIR/array_index.rs:5:31: 5:32 + _4 = const 4_usize; // scope 0 at $DIR/array_index.rs:5:18: 5:33 +- _5 = Lt(_3, _4); // scope 0 at $DIR/array_index.rs:5:18: 5:33 +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 ++ _5 = const true; // scope 0 at $DIR/array_index.rs:5:18: 5:33 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 } bb1: { -- _1 = _2[_3]; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 -+ _1 = const 2_u32; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 - StorageDead(_3); // scope 0 at $DIR/array_index.rs:+1:33: +1:34 - StorageDead(_2); // scope 0 at $DIR/array_index.rs:+1:33: +1:34 - nop; // scope 0 at $DIR/array_index.rs:+0:11: +2:2 - StorageDead(_1); // scope 0 at $DIR/array_index.rs:+2:1: +2:2 - return; // scope 0 at $DIR/array_index.rs:+2:2: +2:2 +- _1 = _2[_3]; // scope 0 at $DIR/array_index.rs:5:18: 5:33 ++ _1 = const 2_u32; // scope 0 at $DIR/array_index.rs:5:18: 5:33 + StorageDead(_3); // scope 0 at $DIR/array_index.rs:5:33: 5:34 + StorageDead(_2); // scope 0 at $DIR/array_index.rs:5:33: 5:34 + nop; // scope 0 at $DIR/array_index.rs:4:11: 6:2 + StorageDead(_1); // scope 0 at $DIR/array_index.rs:6:1: 6:2 + return; // scope 0 at $DIR/array_index.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff index 45134a3fdff3c..8d4852e3727e0 100644 --- a/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff @@ -2,53 +2,53 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/bad_op_div_by_zero.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/bad_op_div_by_zero.rs:+1:9: +1:10 - let mut _3: i32; // in scope 0 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19 - let mut _4: bool; // in scope 0 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 - let mut _5: bool; // in scope 0 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 - let mut _6: bool; // in scope 0 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 - let mut _7: bool; // in scope 0 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 + let mut _0: (); // return place in scope 0 at $DIR/bad_op_div_by_zero.rs:3:11: 3:11 + let _1: i32; // in scope 0 at $DIR/bad_op_div_by_zero.rs:4:9: 4:10 + let mut _3: i32; // in scope 0 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19 + let mut _4: bool; // in scope 0 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 + let mut _5: bool; // in scope 0 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 + let mut _6: bool; // in scope 0 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 + let mut _7: bool; // in scope 0 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 scope 1 { - debug y => _1; // in scope 1 at $DIR/bad_op_div_by_zero.rs:+1:9: +1:10 - let _2: i32; // in scope 1 at $DIR/bad_op_div_by_zero.rs:+2:9: +2:11 + debug y => _1; // in scope 1 at $DIR/bad_op_div_by_zero.rs:4:9: 4:10 + let _2: i32; // in scope 1 at $DIR/bad_op_div_by_zero.rs:5:9: 5:11 scope 2 { - debug _z => _2; // in scope 2 at $DIR/bad_op_div_by_zero.rs:+2:9: +2:11 + debug _z => _2; // in scope 2 at $DIR/bad_op_div_by_zero.rs:5:9: 5:11 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/bad_op_div_by_zero.rs:+1:9: +1:10 - _1 = const 0_i32; // scope 0 at $DIR/bad_op_div_by_zero.rs:+1:13: +1:14 - StorageLive(_2); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:9: +2:11 - StorageLive(_3); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19 -- _3 = _1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19 -- _4 = Eq(_3, const 0_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 -- assert(!move _4, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 -+ _3 = const 0_i32; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19 -+ _4 = const true; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 -+ assert(!const true, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 + StorageLive(_1); // scope 0 at $DIR/bad_op_div_by_zero.rs:4:9: 4:10 + _1 = const 0_i32; // scope 0 at $DIR/bad_op_div_by_zero.rs:4:13: 4:14 + StorageLive(_2); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:9: 5:11 + StorageLive(_3); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19 +- _3 = _1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19 +- _4 = Eq(_3, const 0_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 +- assert(!move _4, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 ++ _3 = const 0_i32; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19 ++ _4 = const true; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 ++ assert(!const true, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 } bb1: { -- _5 = Eq(_3, const -1_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 -- _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 -- _7 = BitAnd(move _5, move _6); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 -- assert(!move _7, "attempt to compute `{} / {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 -+ _5 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 -+ _6 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 -+ _7 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 -+ assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 +- _5 = Eq(_3, const -1_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 +- _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 +- _7 = BitAnd(move _5, move _6); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 +- assert(!move _7, "attempt to compute `{} / {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 ++ _5 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 ++ _6 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 ++ _7 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 ++ assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 } bb2: { -- _2 = Div(const 1_i32, move _3); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 -+ _2 = Div(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 - StorageDead(_3); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19 - nop; // scope 0 at $DIR/bad_op_div_by_zero.rs:+0:11: +3:2 - StorageDead(_2); // scope 1 at $DIR/bad_op_div_by_zero.rs:+3:1: +3:2 - StorageDead(_1); // scope 0 at $DIR/bad_op_div_by_zero.rs:+3:1: +3:2 - return; // scope 0 at $DIR/bad_op_div_by_zero.rs:+3:2: +3:2 +- _2 = Div(const 1_i32, move _3); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 ++ _2 = Div(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 + StorageDead(_3); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19 + nop; // scope 0 at $DIR/bad_op_div_by_zero.rs:3:11: 6:2 + StorageDead(_2); // scope 1 at $DIR/bad_op_div_by_zero.rs:6:1: 6:2 + StorageDead(_1); // scope 0 at $DIR/bad_op_div_by_zero.rs:6:1: 6:2 + return; // scope 0 at $DIR/bad_op_div_by_zero.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff index 22151304259bc..ae1fa64e745b4 100644 --- a/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff @@ -2,53 +2,53 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/bad_op_mod_by_zero.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:9: +1:10 - let mut _3: i32; // in scope 0 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19 - let mut _4: bool; // in scope 0 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 - let mut _5: bool; // in scope 0 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 - let mut _6: bool; // in scope 0 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 - let mut _7: bool; // in scope 0 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 + let mut _0: (); // return place in scope 0 at $DIR/bad_op_mod_by_zero.rs:3:11: 3:11 + let _1: i32; // in scope 0 at $DIR/bad_op_mod_by_zero.rs:4:9: 4:10 + let mut _3: i32; // in scope 0 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19 + let mut _4: bool; // in scope 0 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 + let mut _5: bool; // in scope 0 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 + let mut _6: bool; // in scope 0 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 + let mut _7: bool; // in scope 0 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 scope 1 { - debug y => _1; // in scope 1 at $DIR/bad_op_mod_by_zero.rs:+1:9: +1:10 - let _2: i32; // in scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:9: +2:11 + debug y => _1; // in scope 1 at $DIR/bad_op_mod_by_zero.rs:4:9: 4:10 + let _2: i32; // in scope 1 at $DIR/bad_op_mod_by_zero.rs:5:9: 5:11 scope 2 { - debug _z => _2; // in scope 2 at $DIR/bad_op_mod_by_zero.rs:+2:9: +2:11 + debug _z => _2; // in scope 2 at $DIR/bad_op_mod_by_zero.rs:5:9: 5:11 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:9: +1:10 - _1 = const 0_i32; // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:13: +1:14 - StorageLive(_2); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:9: +2:11 - StorageLive(_3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19 -- _3 = _1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19 -- _4 = Eq(_3, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -- assert(!move _4, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -+ _3 = const 0_i32; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19 -+ _4 = const true; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -+ assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 + StorageLive(_1); // scope 0 at $DIR/bad_op_mod_by_zero.rs:4:9: 4:10 + _1 = const 0_i32; // scope 0 at $DIR/bad_op_mod_by_zero.rs:4:13: 4:14 + StorageLive(_2); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:9: 5:11 + StorageLive(_3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19 +- _3 = _1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19 +- _4 = Eq(_3, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 +- assert(!move _4, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 ++ _3 = const 0_i32; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19 ++ _4 = const true; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 ++ assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 } bb1: { -- _5 = Eq(_3, const -1_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -- _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -- _7 = BitAnd(move _5, move _6); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -- assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -+ _5 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -+ _6 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -+ _7 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -+ assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 +- _5 = Eq(_3, const -1_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 +- _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 +- _7 = BitAnd(move _5, move _6); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 +- assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 ++ _5 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 ++ _6 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 ++ _7 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 ++ assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 } bb2: { -- _2 = Rem(const 1_i32, move _3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -+ _2 = Rem(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 - StorageDead(_3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19 - nop; // scope 0 at $DIR/bad_op_mod_by_zero.rs:+0:11: +3:2 - StorageDead(_2); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2 - StorageDead(_1); // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2 - return; // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:2: +3:2 +- _2 = Rem(const 1_i32, move _3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 ++ _2 = Rem(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 + StorageDead(_3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19 + nop; // scope 0 at $DIR/bad_op_mod_by_zero.rs:3:11: 6:2 + StorageDead(_2); // scope 1 at $DIR/bad_op_mod_by_zero.rs:6:1: 6:2 + StorageDead(_1); // scope 0 at $DIR/bad_op_mod_by_zero.rs:6:1: 6:2 + return; // scope 0 at $DIR/bad_op_mod_by_zero.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff index 55348883810f3..cda6e751c8ef5 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff @@ -2,55 +2,55 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+0:11: +0:11 - let _1: *const [i32]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10 - let mut _2: *const [i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - let _3: &[i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - let _4: [i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:26: +1:35 - let _6: usize; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 - let mut _7: usize; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - let mut _8: bool; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - let mut _9: &[i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 + let mut _0: (); // return place in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:4:11: 4:11 + let _1: *const [i32]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:9: 5:10 + let mut _2: *const [i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 + let _3: &[i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 + let _4: [i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:26: 5:35 + let _6: usize; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24 + let mut _7: usize; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 + let mut _8: bool; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 + let mut _9: &[i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 scope 1 { - debug a => _1; // in scope 1 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10 + debug a => _1; // in scope 1 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:9: 5:10 scope 2 { - let _5: i32; // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15 + let _5: i32; // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:13: 7:15 scope 3 { - debug _b => _5; // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15 + debug _b => _5; // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:13: 7:15 } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10 - StorageLive(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - StorageLive(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - _9 = const main::promoted[0]; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 + StorageLive(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:9: 5:10 + StorageLive(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 + StorageLive(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 + _9 = const main::promoted[0]; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) } - _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - StorageDead(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35 - StorageDead(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36 - StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15 - StorageLive(_6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 - _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 - _7 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -- _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -+ _8 = Lt(const 3_usize, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 + _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 + _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 + _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 + StorageDead(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:34: 5:35 + StorageDead(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:35: 5:36 + StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:13: 7:15 + StorageLive(_6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24 + _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24 + _7 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 +- _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 ++ _8 = Lt(const 3_usize, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 } bb1: { - _5 = (*_1)[_6]; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - StorageDead(_6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26 - nop; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+2:5: +4:6 - StorageDead(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6 - StorageDead(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:1: +5:2 - return; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:2: +5:2 + _5 = (*_1)[_6]; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 + StorageDead(_6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:25: 7:26 + nop; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:6:5: 8:6 + StorageDead(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:8:5: 8:6 + StorageDead(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:9:1: 9:2 + return; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff index 55348883810f3..cda6e751c8ef5 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff @@ -2,55 +2,55 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+0:11: +0:11 - let _1: *const [i32]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10 - let mut _2: *const [i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - let _3: &[i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - let _4: [i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:26: +1:35 - let _6: usize; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 - let mut _7: usize; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - let mut _8: bool; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - let mut _9: &[i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 + let mut _0: (); // return place in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:4:11: 4:11 + let _1: *const [i32]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:9: 5:10 + let mut _2: *const [i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 + let _3: &[i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 + let _4: [i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:26: 5:35 + let _6: usize; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24 + let mut _7: usize; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 + let mut _8: bool; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 + let mut _9: &[i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 scope 1 { - debug a => _1; // in scope 1 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10 + debug a => _1; // in scope 1 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:9: 5:10 scope 2 { - let _5: i32; // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15 + let _5: i32; // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:13: 7:15 scope 3 { - debug _b => _5; // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15 + debug _b => _5; // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:13: 7:15 } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10 - StorageLive(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - StorageLive(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - _9 = const main::promoted[0]; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 + StorageLive(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:9: 5:10 + StorageLive(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 + StorageLive(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 + _9 = const main::promoted[0]; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) } - _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - StorageDead(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35 - StorageDead(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36 - StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15 - StorageLive(_6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 - _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 - _7 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -- _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -+ _8 = Lt(const 3_usize, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 + _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 + _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 + _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 + StorageDead(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:34: 5:35 + StorageDead(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:35: 5:36 + StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:13: 7:15 + StorageLive(_6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24 + _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24 + _7 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 +- _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 ++ _8 = Lt(const 3_usize, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 } bb1: { - _5 = (*_1)[_6]; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - StorageDead(_6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26 - nop; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+2:5: +4:6 - StorageDead(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6 - StorageDead(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:1: +5:2 - return; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:2: +5:2 + _5 = (*_1)[_6]; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 + StorageDead(_6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:25: 7:26 + nop; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:6:5: 8:6 + StorageDead(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:8:5: 8:6 + StorageDead(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:9:1: 9:2 + return; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/const_prop/boolean_identities.test.ConstProp.diff b/src/test/mir-opt/const_prop/boolean_identities.test.ConstProp.diff index 0de800917534a..8a6d16a3a15c1 100644 --- a/src/test/mir-opt/const_prop/boolean_identities.test.ConstProp.diff +++ b/src/test/mir-opt/const_prop/boolean_identities.test.ConstProp.diff @@ -2,32 +2,32 @@ + // MIR for `test` after ConstProp fn test(_1: bool, _2: bool) -> bool { - debug x => _1; // in scope 0 at $DIR/boolean_identities.rs:+0:13: +0:14 - debug y => _2; // in scope 0 at $DIR/boolean_identities.rs:+0:22: +0:23 - let mut _0: bool; // return place in scope 0 at $DIR/boolean_identities.rs:+0:34: +0:38 - let mut _3: bool; // in scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15 - let mut _4: bool; // in scope 0 at $DIR/boolean_identities.rs:+1:6: +1:7 - let mut _5: bool; // in scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29 - let mut _6: bool; // in scope 0 at $DIR/boolean_identities.rs:+1:19: +1:20 + debug x => _1; // in scope 0 at $DIR/boolean_identities.rs:4:13: 4:14 + debug y => _2; // in scope 0 at $DIR/boolean_identities.rs:4:22: 4:23 + let mut _0: bool; // return place in scope 0 at $DIR/boolean_identities.rs:4:34: 4:38 + let mut _3: bool; // in scope 0 at $DIR/boolean_identities.rs:5:5: 5:15 + let mut _4: bool; // in scope 0 at $DIR/boolean_identities.rs:5:6: 5:7 + let mut _5: bool; // in scope 0 at $DIR/boolean_identities.rs:5:18: 5:29 + let mut _6: bool; // in scope 0 at $DIR/boolean_identities.rs:5:19: 5:20 bb0: { - StorageLive(_3); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15 - StorageLive(_4); // scope 0 at $DIR/boolean_identities.rs:+1:6: +1:7 - _4 = _2; // scope 0 at $DIR/boolean_identities.rs:+1:6: +1:7 -- _3 = BitOr(move _4, const true); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15 -+ _3 = const true; // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15 - StorageDead(_4); // scope 0 at $DIR/boolean_identities.rs:+1:14: +1:15 - StorageLive(_5); // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29 - StorageLive(_6); // scope 0 at $DIR/boolean_identities.rs:+1:19: +1:20 - _6 = _1; // scope 0 at $DIR/boolean_identities.rs:+1:19: +1:20 -- _5 = BitAnd(move _6, const false); // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29 -+ _5 = const false; // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29 - StorageDead(_6); // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29 -- _0 = BitAnd(move _3, move _5); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:29 -+ _0 = const false; // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:29 - StorageDead(_5); // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29 - StorageDead(_3); // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29 - return; // scope 0 at $DIR/boolean_identities.rs:+2:2: +2:2 + StorageLive(_3); // scope 0 at $DIR/boolean_identities.rs:5:5: 5:15 + StorageLive(_4); // scope 0 at $DIR/boolean_identities.rs:5:6: 5:7 + _4 = _2; // scope 0 at $DIR/boolean_identities.rs:5:6: 5:7 +- _3 = BitOr(move _4, const true); // scope 0 at $DIR/boolean_identities.rs:5:5: 5:15 ++ _3 = const true; // scope 0 at $DIR/boolean_identities.rs:5:5: 5:15 + StorageDead(_4); // scope 0 at $DIR/boolean_identities.rs:5:14: 5:15 + StorageLive(_5); // scope 0 at $DIR/boolean_identities.rs:5:18: 5:29 + StorageLive(_6); // scope 0 at $DIR/boolean_identities.rs:5:19: 5:20 + _6 = _1; // scope 0 at $DIR/boolean_identities.rs:5:19: 5:20 +- _5 = BitAnd(move _6, const false); // scope 0 at $DIR/boolean_identities.rs:5:18: 5:29 ++ _5 = const false; // scope 0 at $DIR/boolean_identities.rs:5:18: 5:29 + StorageDead(_6); // scope 0 at $DIR/boolean_identities.rs:5:28: 5:29 +- _0 = BitAnd(move _3, move _5); // scope 0 at $DIR/boolean_identities.rs:5:5: 5:29 ++ _0 = const false; // scope 0 at $DIR/boolean_identities.rs:5:5: 5:29 + StorageDead(_5); // scope 0 at $DIR/boolean_identities.rs:5:28: 5:29 + StorageDead(_3); // scope 0 at $DIR/boolean_identities.rs:5:28: 5:29 + return; // scope 0 at $DIR/boolean_identities.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff index f2d4bee1bf94d..919b909435197 100644 --- a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff @@ -2,66 +2,66 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/boxes.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/boxes.rs:+1:9: +1:10 - let mut _2: i32; // in scope 0 at $DIR/boxes.rs:+1:13: +1:22 - let mut _3: std::boxed::Box; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22 - let mut _4: usize; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22 - let mut _5: usize; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22 - let mut _6: *mut u8; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22 - let mut _7: std::boxed::Box; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22 - let mut _8: *const i32; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22 - let mut _9: *const i32; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22 - let mut _10: *const i32; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22 - let mut _11: *const i32; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22 + let mut _0: (); // return place in scope 0 at $DIR/boxes.rs:11:11: 11:11 + let _1: i32; // in scope 0 at $DIR/boxes.rs:12:9: 12:10 + let mut _2: i32; // in scope 0 at $DIR/boxes.rs:12:13: 12:22 + let mut _3: std::boxed::Box; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _4: usize; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _5: usize; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _6: *mut u8; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _7: std::boxed::Box; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _8: *const i32; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _9: *const i32; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _10: *const i32; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _11: *const i32; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 scope 1 { - debug x => _1; // in scope 1 at $DIR/boxes.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/boxes.rs:12:9: 12:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/boxes.rs:+1:9: +1:10 - StorageLive(_2); // scope 0 at $DIR/boxes.rs:+1:13: +1:22 - StorageLive(_3); // scope 0 at $DIR/boxes.rs:+1:14: +1:22 -- _4 = SizeOf(i32); // scope 2 at $DIR/boxes.rs:+1:14: +1:22 -- _5 = AlignOf(i32); // scope 2 at $DIR/boxes.rs:+1:14: +1:22 -- _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> bb1; // scope 2 at $DIR/boxes.rs:+1:14: +1:22 -+ _4 = const 4_usize; // scope 2 at $DIR/boxes.rs:+1:14: +1:22 -+ _5 = const 4_usize; // scope 2 at $DIR/boxes.rs:+1:14: +1:22 -+ _6 = alloc::alloc::exchange_malloc(const 4_usize, const 4_usize) -> bb1; // scope 2 at $DIR/boxes.rs:+1:14: +1:22 + StorageLive(_1); // scope 0 at $DIR/boxes.rs:12:9: 12:10 + StorageLive(_2); // scope 0 at $DIR/boxes.rs:12:13: 12:22 + StorageLive(_3); // scope 0 at $DIR/boxes.rs:12:14: 12:22 +- _4 = SizeOf(i32); // scope 2 at $DIR/boxes.rs:12:14: 12:22 +- _5 = AlignOf(i32); // scope 2 at $DIR/boxes.rs:12:14: 12:22 +- _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> bb1; // scope 2 at $DIR/boxes.rs:12:14: 12:22 ++ _4 = const 4_usize; // scope 2 at $DIR/boxes.rs:12:14: 12:22 ++ _5 = const 4_usize; // scope 2 at $DIR/boxes.rs:12:14: 12:22 ++ _6 = alloc::alloc::exchange_malloc(const 4_usize, const 4_usize) -> bb1; // scope 2 at $DIR/boxes.rs:12:14: 12:22 // mir::Constant // + span: $DIR/boxes.rs:12:14: 12:22 // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value() } } bb1: { - StorageLive(_7); // scope 0 at $DIR/boxes.rs:+1:14: +1:22 - _7 = ShallowInitBox(move _6, i32); // scope 0 at $DIR/boxes.rs:+1:14: +1:22 - StorageLive(_8); // scope 0 at $DIR/boxes.rs:+1:19: +1:21 - _8 = (((_7.0: std::ptr::Unique).0: std::ptr::NonNull).0: *const i32); // scope 0 at $DIR/boxes.rs:+1:19: +1:21 - (*_8) = const 42_i32; // scope 0 at $DIR/boxes.rs:+1:19: +1:21 - StorageDead(_8); // scope 0 at $DIR/boxes.rs:+1:14: +1:22 - _3 = move _7; // scope 0 at $DIR/boxes.rs:+1:14: +1:22 - StorageDead(_7); // scope 0 at $DIR/boxes.rs:+1:21: +1:22 - StorageLive(_9); // scope 0 at $DIR/boxes.rs:+1:13: +1:22 - _9 = (((_3.0: std::ptr::Unique).0: std::ptr::NonNull).0: *const i32); // scope 0 at $DIR/boxes.rs:+1:13: +1:22 - _2 = (*_9); // scope 0 at $DIR/boxes.rs:+1:13: +1:22 - StorageDead(_9); // scope 0 at $DIR/boxes.rs:+1:13: +1:26 - _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/boxes.rs:+1:13: +1:26 - StorageDead(_2); // scope 0 at $DIR/boxes.rs:+1:25: +1:26 - drop(_3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/boxes.rs:+1:26: +1:27 + StorageLive(_7); // scope 0 at $DIR/boxes.rs:12:14: 12:22 + _7 = ShallowInitBox(move _6, i32); // scope 0 at $DIR/boxes.rs:12:14: 12:22 + StorageLive(_8); // scope 0 at $DIR/boxes.rs:12:19: 12:21 + _8 = (((_7.0: std::ptr::Unique).0: std::ptr::NonNull).0: *const i32); // scope 0 at $DIR/boxes.rs:12:19: 12:21 + (*_8) = const 42_i32; // scope 0 at $DIR/boxes.rs:12:19: 12:21 + StorageDead(_8); // scope 0 at $DIR/boxes.rs:12:14: 12:22 + _3 = move _7; // scope 0 at $DIR/boxes.rs:12:14: 12:22 + StorageDead(_7); // scope 0 at $DIR/boxes.rs:12:21: 12:22 + StorageLive(_9); // scope 0 at $DIR/boxes.rs:12:13: 12:22 + _9 = (((_3.0: std::ptr::Unique).0: std::ptr::NonNull).0: *const i32); // scope 0 at $DIR/boxes.rs:12:13: 12:22 + _2 = (*_9); // scope 0 at $DIR/boxes.rs:12:13: 12:22 + StorageDead(_9); // scope 0 at $DIR/boxes.rs:12:13: 12:26 + _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/boxes.rs:12:13: 12:26 + StorageDead(_2); // scope 0 at $DIR/boxes.rs:12:25: 12:26 + drop(_3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/boxes.rs:12:26: 12:27 } bb2: { - StorageDead(_3); // scope 0 at $DIR/boxes.rs:+1:26: +1:27 - nop; // scope 0 at $DIR/boxes.rs:+0:11: +2:2 - StorageDead(_1); // scope 0 at $DIR/boxes.rs:+2:1: +2:2 - return; // scope 0 at $DIR/boxes.rs:+2:2: +2:2 + StorageDead(_3); // scope 0 at $DIR/boxes.rs:12:26: 12:27 + nop; // scope 0 at $DIR/boxes.rs:11:11: 13:2 + StorageDead(_1); // scope 0 at $DIR/boxes.rs:13:1: 13:2 + return; // scope 0 at $DIR/boxes.rs:13:2: 13:2 } bb3 (cleanup): { - resume; // scope 0 at $DIR/boxes.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/boxes.rs:11:1: 13:2 } } diff --git a/src/test/mir-opt/const_prop/cast.main.ConstProp.diff b/src/test/mir-opt/const_prop/cast.main.ConstProp.diff index 5698a612fe2d2..21326d8b1cf57 100644 --- a/src/test/mir-opt/const_prop/cast.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/cast.main.ConstProp.diff @@ -2,27 +2,27 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/cast.rs:+0:11: +0:11 - let _1: u32; // in scope 0 at $DIR/cast.rs:+1:9: +1:10 + let mut _0: (); // return place in scope 0 at $DIR/cast.rs:3:11: 3:11 + let _1: u32; // in scope 0 at $DIR/cast.rs:4:9: 4:10 scope 1 { - debug x => _1; // in scope 1 at $DIR/cast.rs:+1:9: +1:10 - let _2: u8; // in scope 1 at $DIR/cast.rs:+3:9: +3:10 + debug x => _1; // in scope 1 at $DIR/cast.rs:4:9: 4:10 + let _2: u8; // in scope 1 at $DIR/cast.rs:6:9: 6:10 scope 2 { - debug y => _2; // in scope 2 at $DIR/cast.rs:+3:9: +3:10 + debug y => _2; // in scope 2 at $DIR/cast.rs:6:9: 6:10 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/cast.rs:+1:9: +1:10 -- _1 = const 42_u8 as u32 (Misc); // scope 0 at $DIR/cast.rs:+1:13: +1:24 -+ _1 = const 42_u32; // scope 0 at $DIR/cast.rs:+1:13: +1:24 - StorageLive(_2); // scope 1 at $DIR/cast.rs:+3:9: +3:10 -- _2 = const 42_u32 as u8 (Misc); // scope 1 at $DIR/cast.rs:+3:13: +3:24 -+ _2 = const 42_u8; // scope 1 at $DIR/cast.rs:+3:13: +3:24 - nop; // scope 0 at $DIR/cast.rs:+0:11: +4:2 - StorageDead(_2); // scope 1 at $DIR/cast.rs:+4:1: +4:2 - StorageDead(_1); // scope 0 at $DIR/cast.rs:+4:1: +4:2 - return; // scope 0 at $DIR/cast.rs:+4:2: +4:2 + StorageLive(_1); // scope 0 at $DIR/cast.rs:4:9: 4:10 +- _1 = const 42_u8 as u32 (Misc); // scope 0 at $DIR/cast.rs:4:13: 4:24 ++ _1 = const 42_u32; // scope 0 at $DIR/cast.rs:4:13: 4:24 + StorageLive(_2); // scope 1 at $DIR/cast.rs:6:9: 6:10 +- _2 = const 42_u32 as u8 (Misc); // scope 1 at $DIR/cast.rs:6:13: 6:24 ++ _2 = const 42_u8; // scope 1 at $DIR/cast.rs:6:13: 6:24 + nop; // scope 0 at $DIR/cast.rs:3:11: 7:2 + StorageDead(_2); // scope 1 at $DIR/cast.rs:7:1: 7:2 + StorageDead(_1); // scope 0 at $DIR/cast.rs:7:1: 7:2 + return; // scope 0 at $DIR/cast.rs:7:2: 7:2 } } diff --git a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff index 5e33d054207b0..77ff8ef4e4952 100644 --- a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff @@ -2,27 +2,27 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/checked_add.rs:+0:11: +0:11 - let _1: u32; // in scope 0 at $DIR/checked_add.rs:+1:9: +1:10 - let mut _2: (u32, bool); // in scope 0 at $DIR/checked_add.rs:+1:18: +1:23 + let mut _0: (); // return place in scope 0 at $DIR/checked_add.rs:4:11: 4:11 + let _1: u32; // in scope 0 at $DIR/checked_add.rs:5:9: 5:10 + let mut _2: (u32, bool); // in scope 0 at $DIR/checked_add.rs:5:18: 5:23 scope 1 { - debug x => _1; // in scope 1 at $DIR/checked_add.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/checked_add.rs:5:9: 5:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/checked_add.rs:+1:9: +1:10 -- _2 = CheckedAdd(const 1_u32, const 1_u32); // scope 0 at $DIR/checked_add.rs:+1:18: +1:23 -- assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:+1:18: +1:23 -+ _2 = const (2_u32, false); // scope 0 at $DIR/checked_add.rs:+1:18: +1:23 -+ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:+1:18: +1:23 + StorageLive(_1); // scope 0 at $DIR/checked_add.rs:5:9: 5:10 +- _2 = CheckedAdd(const 1_u32, const 1_u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 +- assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 ++ _2 = const (2_u32, false); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 } bb1: { -- _1 = move (_2.0: u32); // scope 0 at $DIR/checked_add.rs:+1:18: +1:23 -+ _1 = const 2_u32; // scope 0 at $DIR/checked_add.rs:+1:18: +1:23 - nop; // scope 0 at $DIR/checked_add.rs:+0:11: +2:2 - StorageDead(_1); // scope 0 at $DIR/checked_add.rs:+2:1: +2:2 - return; // scope 0 at $DIR/checked_add.rs:+2:2: +2:2 +- _1 = move (_2.0: u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 ++ _1 = const 2_u32; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 + nop; // scope 0 at $DIR/checked_add.rs:4:11: 6:2 + StorageDead(_1); // scope 0 at $DIR/checked_add.rs:6:1: 6:2 + return; // scope 0 at $DIR/checked_add.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff index c21b24591d88e..852a2419f558d 100644 --- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff @@ -2,43 +2,43 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/const_prop_fails_gracefully.rs:+0:11: +0:11 - let _1: usize; // in scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:9: +2:10 - let mut _2: *const i32; // in scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:30 - let _3: &i32; // in scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16 - let _4: (); // in scope 0 at $DIR/const_prop_fails_gracefully.rs:+3:5: +3:12 - let mut _5: usize; // in scope 0 at $DIR/const_prop_fails_gracefully.rs:+3:10: +3:11 + let mut _0: (); // return place in scope 0 at $DIR/const_prop_fails_gracefully.rs:5:11: 5:11 + let _1: usize; // in scope 0 at $DIR/const_prop_fails_gracefully.rs:7:9: 7:10 + let mut _2: *const i32; // in scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:30 + let _3: &i32; // in scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 + let _4: (); // in scope 0 at $DIR/const_prop_fails_gracefully.rs:8:5: 8:12 + let mut _5: usize; // in scope 0 at $DIR/const_prop_fails_gracefully.rs:8:10: 8:11 scope 1 { - debug x => _1; // in scope 1 at $DIR/const_prop_fails_gracefully.rs:+2:9: +2:10 + debug x => _1; // in scope 1 at $DIR/const_prop_fails_gracefully.rs:7:9: 7:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:9: +2:10 - StorageLive(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:30 - StorageLive(_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16 - _3 = const FOO; // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16 + StorageLive(_1); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:9: 7:10 + StorageLive(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:30 + StorageLive(_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 + _3 = const FOO; // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 // mir::Constant // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 // + literal: Const { ty: &i32, val: Unevaluated(FOO, [], None) } - _2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16 - _1 = move _2 as usize (PointerExposeAddress); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:39 - StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:38: +2:39 - StorageDead(_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:39: +2:40 - StorageLive(_4); // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:5: +3:12 - StorageLive(_5); // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:10: +3:11 - _5 = _1; // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:10: +3:11 - _4 = read(move _5) -> bb1; // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:5: +3:12 + _2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 + _1 = move _2 as usize (PointerExposeAddress); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39 + StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39 + StorageDead(_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:39: 7:40 + StorageLive(_4); // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:5: 8:12 + StorageLive(_5); // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:10: 8:11 + _5 = _1; // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:10: 8:11 + _4 = read(move _5) -> bb1; // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:5: 8:12 // mir::Constant // + span: $DIR/const_prop_fails_gracefully.rs:8:5: 8:9 // + literal: Const { ty: fn(usize) {read}, val: Value() } } bb1: { - StorageDead(_5); // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:11: +3:12 - StorageDead(_4); // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:12: +3:13 - nop; // scope 0 at $DIR/const_prop_fails_gracefully.rs:+0:11: +4:2 - StorageDead(_1); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+4:1: +4:2 - return; // scope 0 at $DIR/const_prop_fails_gracefully.rs:+4:2: +4:2 + StorageDead(_5); // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:11: 8:12 + StorageDead(_4); // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:12: 8:13 + nop; // scope 0 at $DIR/const_prop_fails_gracefully.rs:5:11: 9:2 + StorageDead(_1); // scope 0 at $DIR/const_prop_fails_gracefully.rs:9:1: 9:2 + return; // scope 0 at $DIR/const_prop_fails_gracefully.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff b/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff index 5f4df0d883bca..d0287cc2b2b64 100644 --- a/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff +++ b/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff @@ -2,16 +2,16 @@ + // MIR for `hello` after ConstProp fn hello() -> () { - let mut _0: (); // return place in scope 0 at $DIR/control-flow-simplification.rs:+0:14: +0:14 - let mut _1: bool; // in scope 0 at $DIR/control-flow-simplification.rs:+1:8: +1:21 + let mut _0: (); // return place in scope 0 at $DIR/control-flow-simplification.rs:11:14: 11:14 + let mut _1: bool; // in scope 0 at $DIR/control-flow-simplification.rs:12:8: 12:21 let mut _2: !; // in scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL bb0: { - StorageLive(_1); // scope 0 at $DIR/control-flow-simplification.rs:+1:8: +1:21 -- _1 = const ::NEEDS; // scope 0 at $DIR/control-flow-simplification.rs:+1:8: +1:21 -- switchInt(move _1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/control-flow-simplification.rs:+1:8: +1:21 -+ _1 = const false; // scope 0 at $DIR/control-flow-simplification.rs:+1:8: +1:21 -+ switchInt(const false) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/control-flow-simplification.rs:+1:8: +1:21 + StorageLive(_1); // scope 0 at $DIR/control-flow-simplification.rs:12:8: 12:21 +- _1 = const ::NEEDS; // scope 0 at $DIR/control-flow-simplification.rs:12:8: 12:21 +- switchInt(move _1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/control-flow-simplification.rs:12:8: 12:21 ++ _1 = const false; // scope 0 at $DIR/control-flow-simplification.rs:12:8: 12:21 ++ switchInt(const false) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/control-flow-simplification.rs:12:8: 12:21 } bb1: { @@ -26,9 +26,9 @@ } bb2: { - nop; // scope 0 at $DIR/control-flow-simplification.rs:+3:6: +3:6 - StorageDead(_1); // scope 0 at $DIR/control-flow-simplification.rs:+3:5: +3:6 - return; // scope 0 at $DIR/control-flow-simplification.rs:+4:2: +4:2 + nop; // scope 0 at $DIR/control-flow-simplification.rs:14:6: 14:6 + StorageDead(_1); // scope 0 at $DIR/control-flow-simplification.rs:14:5: 14:6 + return; // scope 0 at $DIR/control-flow-simplification.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir b/src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir index 70f9797751131..30512d0bbe874 100644 --- a/src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir +++ b/src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir @@ -1,9 +1,9 @@ // MIR for `hello` before PreCodegen fn hello() -> () { - let mut _0: (); // return place in scope 0 at $DIR/control-flow-simplification.rs:+0:14: +0:14 + let mut _0: (); // return place in scope 0 at $DIR/control-flow-simplification.rs:11:14: 11:14 bb0: { - return; // scope 0 at $DIR/control-flow-simplification.rs:+4:2: +4:2 + return; // scope 0 at $DIR/control-flow-simplification.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff index 5b4ecaa80f1f1..047853696f228 100644 --- a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff @@ -2,51 +2,51 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/discriminant.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/discriminant.rs:+1:9: +1:10 - let mut _2: i32; // in scope 0 at $DIR/discriminant.rs:+1:13: +1:64 - let mut _3: std::option::Option; // in scope 0 at $DIR/discriminant.rs:+1:34: +1:44 - let mut _4: isize; // in scope 0 at $DIR/discriminant.rs:+1:21: +1:31 + let mut _0: (); // return place in scope 0 at $DIR/discriminant.rs:10:11: 10:11 + let _1: i32; // in scope 0 at $DIR/discriminant.rs:11:9: 11:10 + let mut _2: i32; // in scope 0 at $DIR/discriminant.rs:11:13: 11:64 + let mut _3: std::option::Option; // in scope 0 at $DIR/discriminant.rs:11:34: 11:44 + let mut _4: isize; // in scope 0 at $DIR/discriminant.rs:11:21: 11:31 scope 1 { - debug x => _1; // in scope 1 at $DIR/discriminant.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/discriminant.rs:11:9: 11:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/discriminant.rs:+1:9: +1:10 - StorageLive(_2); // scope 0 at $DIR/discriminant.rs:+1:13: +1:64 - StorageLive(_3); // scope 2 at $DIR/discriminant.rs:+1:34: +1:44 - Deinit(_3); // scope 2 at $DIR/discriminant.rs:+1:34: +1:44 - ((_3 as Some).0: bool) = const true; // scope 2 at $DIR/discriminant.rs:+1:34: +1:44 - discriminant(_3) = 1; // scope 2 at $DIR/discriminant.rs:+1:34: +1:44 -- _4 = discriminant(_3); // scope 2 at $DIR/discriminant.rs:+1:21: +1:31 -- switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31 -+ _4 = const 1_isize; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31 -+ switchInt(const 1_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31 + StorageLive(_1); // scope 0 at $DIR/discriminant.rs:11:9: 11:10 + StorageLive(_2); // scope 0 at $DIR/discriminant.rs:11:13: 11:64 + StorageLive(_3); // scope 2 at $DIR/discriminant.rs:11:34: 11:44 + Deinit(_3); // scope 2 at $DIR/discriminant.rs:11:34: 11:44 + ((_3 as Some).0: bool) = const true; // scope 2 at $DIR/discriminant.rs:11:34: 11:44 + discriminant(_3) = 1; // scope 2 at $DIR/discriminant.rs:11:34: 11:44 +- _4 = discriminant(_3); // scope 2 at $DIR/discriminant.rs:11:21: 11:31 +- switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:11:21: 11:31 ++ _4 = const 1_isize; // scope 2 at $DIR/discriminant.rs:11:21: 11:31 ++ switchInt(const 1_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:11:21: 11:31 } bb1: { - switchInt(((_3 as Some).0: bool)) -> [false: bb3, otherwise: bb2]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31 + switchInt(((_3 as Some).0: bool)) -> [false: bb3, otherwise: bb2]; // scope 2 at $DIR/discriminant.rs:11:21: 11:31 } bb2: { - _2 = const 42_i32; // scope 2 at $DIR/discriminant.rs:+1:47: +1:49 - goto -> bb4; // scope 0 at $DIR/discriminant.rs:+1:13: +1:64 + _2 = const 42_i32; // scope 2 at $DIR/discriminant.rs:11:47: 11:49 + goto -> bb4; // scope 0 at $DIR/discriminant.rs:11:13: 11:64 } bb3: { - _2 = const 10_i32; // scope 0 at $DIR/discriminant.rs:+1:59: +1:61 - goto -> bb4; // scope 0 at $DIR/discriminant.rs:+1:13: +1:64 + _2 = const 10_i32; // scope 0 at $DIR/discriminant.rs:11:59: 11:61 + goto -> bb4; // scope 0 at $DIR/discriminant.rs:11:13: 11:64 } bb4: { - _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/discriminant.rs:+1:13: +1:68 - StorageDead(_2); // scope 0 at $DIR/discriminant.rs:+1:67: +1:68 - StorageDead(_3); // scope 0 at $DIR/discriminant.rs:+1:68: +1:69 - nop; // scope 0 at $DIR/discriminant.rs:+0:11: +2:2 - StorageDead(_1); // scope 0 at $DIR/discriminant.rs:+2:1: +2:2 - return; // scope 0 at $DIR/discriminant.rs:+2:2: +2:2 + _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/discriminant.rs:11:13: 11:68 + StorageDead(_2); // scope 0 at $DIR/discriminant.rs:11:67: 11:68 + StorageDead(_3); // scope 0 at $DIR/discriminant.rs:11:68: 11:69 + nop; // scope 0 at $DIR/discriminant.rs:10:11: 12:2 + StorageDead(_1); // scope 0 at $DIR/discriminant.rs:12:1: 12:2 + return; // scope 0 at $DIR/discriminant.rs:12:2: 12:2 } } diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff index 5b4ecaa80f1f1..047853696f228 100644 --- a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff @@ -2,51 +2,51 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/discriminant.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/discriminant.rs:+1:9: +1:10 - let mut _2: i32; // in scope 0 at $DIR/discriminant.rs:+1:13: +1:64 - let mut _3: std::option::Option; // in scope 0 at $DIR/discriminant.rs:+1:34: +1:44 - let mut _4: isize; // in scope 0 at $DIR/discriminant.rs:+1:21: +1:31 + let mut _0: (); // return place in scope 0 at $DIR/discriminant.rs:10:11: 10:11 + let _1: i32; // in scope 0 at $DIR/discriminant.rs:11:9: 11:10 + let mut _2: i32; // in scope 0 at $DIR/discriminant.rs:11:13: 11:64 + let mut _3: std::option::Option; // in scope 0 at $DIR/discriminant.rs:11:34: 11:44 + let mut _4: isize; // in scope 0 at $DIR/discriminant.rs:11:21: 11:31 scope 1 { - debug x => _1; // in scope 1 at $DIR/discriminant.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/discriminant.rs:11:9: 11:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/discriminant.rs:+1:9: +1:10 - StorageLive(_2); // scope 0 at $DIR/discriminant.rs:+1:13: +1:64 - StorageLive(_3); // scope 2 at $DIR/discriminant.rs:+1:34: +1:44 - Deinit(_3); // scope 2 at $DIR/discriminant.rs:+1:34: +1:44 - ((_3 as Some).0: bool) = const true; // scope 2 at $DIR/discriminant.rs:+1:34: +1:44 - discriminant(_3) = 1; // scope 2 at $DIR/discriminant.rs:+1:34: +1:44 -- _4 = discriminant(_3); // scope 2 at $DIR/discriminant.rs:+1:21: +1:31 -- switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31 -+ _4 = const 1_isize; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31 -+ switchInt(const 1_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31 + StorageLive(_1); // scope 0 at $DIR/discriminant.rs:11:9: 11:10 + StorageLive(_2); // scope 0 at $DIR/discriminant.rs:11:13: 11:64 + StorageLive(_3); // scope 2 at $DIR/discriminant.rs:11:34: 11:44 + Deinit(_3); // scope 2 at $DIR/discriminant.rs:11:34: 11:44 + ((_3 as Some).0: bool) = const true; // scope 2 at $DIR/discriminant.rs:11:34: 11:44 + discriminant(_3) = 1; // scope 2 at $DIR/discriminant.rs:11:34: 11:44 +- _4 = discriminant(_3); // scope 2 at $DIR/discriminant.rs:11:21: 11:31 +- switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:11:21: 11:31 ++ _4 = const 1_isize; // scope 2 at $DIR/discriminant.rs:11:21: 11:31 ++ switchInt(const 1_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:11:21: 11:31 } bb1: { - switchInt(((_3 as Some).0: bool)) -> [false: bb3, otherwise: bb2]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31 + switchInt(((_3 as Some).0: bool)) -> [false: bb3, otherwise: bb2]; // scope 2 at $DIR/discriminant.rs:11:21: 11:31 } bb2: { - _2 = const 42_i32; // scope 2 at $DIR/discriminant.rs:+1:47: +1:49 - goto -> bb4; // scope 0 at $DIR/discriminant.rs:+1:13: +1:64 + _2 = const 42_i32; // scope 2 at $DIR/discriminant.rs:11:47: 11:49 + goto -> bb4; // scope 0 at $DIR/discriminant.rs:11:13: 11:64 } bb3: { - _2 = const 10_i32; // scope 0 at $DIR/discriminant.rs:+1:59: +1:61 - goto -> bb4; // scope 0 at $DIR/discriminant.rs:+1:13: +1:64 + _2 = const 10_i32; // scope 0 at $DIR/discriminant.rs:11:59: 11:61 + goto -> bb4; // scope 0 at $DIR/discriminant.rs:11:13: 11:64 } bb4: { - _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/discriminant.rs:+1:13: +1:68 - StorageDead(_2); // scope 0 at $DIR/discriminant.rs:+1:67: +1:68 - StorageDead(_3); // scope 0 at $DIR/discriminant.rs:+1:68: +1:69 - nop; // scope 0 at $DIR/discriminant.rs:+0:11: +2:2 - StorageDead(_1); // scope 0 at $DIR/discriminant.rs:+2:1: +2:2 - return; // scope 0 at $DIR/discriminant.rs:+2:2: +2:2 + _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/discriminant.rs:11:13: 11:68 + StorageDead(_2); // scope 0 at $DIR/discriminant.rs:11:67: 11:68 + StorageDead(_3); // scope 0 at $DIR/discriminant.rs:11:68: 11:69 + nop; // scope 0 at $DIR/discriminant.rs:10:11: 12:2 + StorageDead(_1); // scope 0 at $DIR/discriminant.rs:12:1: 12:2 + return; // scope 0 at $DIR/discriminant.rs:12:2: 12:2 } } diff --git a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff index 2e1e32545a286..8dd55235ef37b 100644 --- a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff @@ -2,32 +2,32 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/indirect.rs:+0:11: +0:11 - let _1: u8; // in scope 0 at $DIR/indirect.rs:+1:9: +1:10 - let mut _2: u8; // in scope 0 at $DIR/indirect.rs:+1:13: +1:25 - let mut _3: (u8, bool); // in scope 0 at $DIR/indirect.rs:+1:13: +1:29 + let mut _0: (); // return place in scope 0 at $DIR/indirect.rs:4:11: 4:11 + let _1: u8; // in scope 0 at $DIR/indirect.rs:5:9: 5:10 + let mut _2: u8; // in scope 0 at $DIR/indirect.rs:5:13: 5:25 + let mut _3: (u8, bool); // in scope 0 at $DIR/indirect.rs:5:13: 5:29 scope 1 { - debug x => _1; // in scope 1 at $DIR/indirect.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/indirect.rs:5:9: 5:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/indirect.rs:+1:9: +1:10 - StorageLive(_2); // scope 0 at $DIR/indirect.rs:+1:13: +1:25 -- _2 = const 2_u32 as u8 (Misc); // scope 0 at $DIR/indirect.rs:+1:13: +1:25 -- _3 = CheckedAdd(_2, const 1_u8); // scope 0 at $DIR/indirect.rs:+1:13: +1:29 -- assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:+1:13: +1:29 -+ _2 = const 2_u8; // scope 0 at $DIR/indirect.rs:+1:13: +1:25 -+ _3 = const (3_u8, false); // scope 0 at $DIR/indirect.rs:+1:13: +1:29 -+ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u8, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:+1:13: +1:29 + StorageLive(_1); // scope 0 at $DIR/indirect.rs:5:9: 5:10 + StorageLive(_2); // scope 0 at $DIR/indirect.rs:5:13: 5:25 +- _2 = const 2_u32 as u8 (Misc); // scope 0 at $DIR/indirect.rs:5:13: 5:25 +- _3 = CheckedAdd(_2, const 1_u8); // scope 0 at $DIR/indirect.rs:5:13: 5:29 +- assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29 ++ _2 = const 2_u8; // scope 0 at $DIR/indirect.rs:5:13: 5:25 ++ _3 = const (3_u8, false); // scope 0 at $DIR/indirect.rs:5:13: 5:29 ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u8, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29 } bb1: { -- _1 = move (_3.0: u8); // scope 0 at $DIR/indirect.rs:+1:13: +1:29 -+ _1 = const 3_u8; // scope 0 at $DIR/indirect.rs:+1:13: +1:29 - StorageDead(_2); // scope 0 at $DIR/indirect.rs:+1:28: +1:29 - nop; // scope 0 at $DIR/indirect.rs:+0:11: +2:2 - StorageDead(_1); // scope 0 at $DIR/indirect.rs:+2:1: +2:2 - return; // scope 0 at $DIR/indirect.rs:+2:2: +2:2 +- _1 = move (_3.0: u8); // scope 0 at $DIR/indirect.rs:5:13: 5:29 ++ _1 = const 3_u8; // scope 0 at $DIR/indirect.rs:5:13: 5:29 + StorageDead(_2); // scope 0 at $DIR/indirect.rs:5:28: 5:29 + nop; // scope 0 at $DIR/indirect.rs:4:11: 6:2 + StorageDead(_1); // scope 0 at $DIR/indirect.rs:6:1: 6:2 + return; // scope 0 at $DIR/indirect.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff b/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff index 67a4dc3c09269..c60cf1e481dcd 100644 --- a/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff @@ -2,24 +2,24 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/invalid_constant.rs:+0:11: +0:11 - let _1: char; // in scope 0 at $DIR/invalid_constant.rs:+6:9: +6:22 - let mut _2: main::InvalidChar; // in scope 0 at $DIR/invalid_constant.rs:+6:34: +6:63 - let mut _4: E; // in scope 0 at $DIR/invalid_constant.rs:+13:25: +13:59 - let mut _5: main::InvalidTag; // in scope 0 at $DIR/invalid_constant.rs:+13:34: +13:55 - let mut _7: Empty; // in scope 0 at $DIR/invalid_constant.rs:+20:35: +20:73 - let mut _8: main::NoVariants; // in scope 0 at $DIR/invalid_constant.rs:+20:44: +20:65 + let mut _0: (); // return place in scope 0 at $DIR/invalid_constant.rs:15:11: 15:11 + let _1: char; // in scope 0 at $DIR/invalid_constant.rs:21:9: 21:22 + let mut _2: main::InvalidChar; // in scope 0 at $DIR/invalid_constant.rs:21:34: 21:63 + let mut _4: E; // in scope 0 at $DIR/invalid_constant.rs:28:25: 28:59 + let mut _5: main::InvalidTag; // in scope 0 at $DIR/invalid_constant.rs:28:34: 28:55 + let mut _7: Empty; // in scope 0 at $DIR/invalid_constant.rs:35:35: 35:73 + let mut _8: main::NoVariants; // in scope 0 at $DIR/invalid_constant.rs:35:44: 35:65 scope 1 { - debug _invalid_char => _1; // in scope 1 at $DIR/invalid_constant.rs:+6:9: +6:22 - let _3: [E; 1]; // in scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21 + debug _invalid_char => _1; // in scope 1 at $DIR/invalid_constant.rs:21:9: 21:22 + let _3: [E; 1]; // in scope 1 at $DIR/invalid_constant.rs:28:9: 28:21 scope 3 { - debug _invalid_tag => _3; // in scope 3 at $DIR/invalid_constant.rs:+13:9: +13:21 - let _6: [Empty; 1]; // in scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31 + debug _invalid_tag => _3; // in scope 3 at $DIR/invalid_constant.rs:28:9: 28:21 + let _6: [Empty; 1]; // in scope 3 at $DIR/invalid_constant.rs:35:9: 35:31 scope 5 { - debug _enum_without_variants => _6; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31 - let _9: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22 + debug _enum_without_variants => _6; // in scope 5 at $DIR/invalid_constant.rs:35:9: 35:31 + let _9: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:39:9: 39:22 scope 7 { - debug _non_utf8_str => _9; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22 + debug _non_utf8_str => _9; // in scope 7 at $DIR/invalid_constant.rs:39:9: 39:22 } } scope 6 { @@ -32,46 +32,46 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/invalid_constant.rs:+6:9: +6:22 - StorageLive(_2); // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63 - Deinit(_2); // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63 - (_2.0: u32) = const 1114113_u32; // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63 -- _1 = (_2.1: char); // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:67 -+ _1 = const {transmute(0x00110001): char}; // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:67 - StorageDead(_2); // scope 0 at $DIR/invalid_constant.rs:+6:69: +6:70 - StorageLive(_3); // scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21 - StorageLive(_4); // scope 1 at $DIR/invalid_constant.rs:+13:25: +13:59 - StorageLive(_5); // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55 - Deinit(_5); // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55 - (_5.0: u32) = const 4_u32; // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55 -- _4 = (_5.1: E); // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:57 -- _3 = [move _4]; // scope 1 at $DIR/invalid_constant.rs:+13:24: +13:60 -+ _4 = const Scalar(0x00000004): E; // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:57 + StorageLive(_1); // scope 0 at $DIR/invalid_constant.rs:21:9: 21:22 + StorageLive(_2); // scope 2 at $DIR/invalid_constant.rs:21:34: 21:63 + Deinit(_2); // scope 2 at $DIR/invalid_constant.rs:21:34: 21:63 + (_2.0: u32) = const 1114113_u32; // scope 2 at $DIR/invalid_constant.rs:21:34: 21:63 +- _1 = (_2.1: char); // scope 2 at $DIR/invalid_constant.rs:21:34: 21:67 ++ _1 = const {transmute(0x00110001): char}; // scope 2 at $DIR/invalid_constant.rs:21:34: 21:67 + StorageDead(_2); // scope 0 at $DIR/invalid_constant.rs:21:69: 21:70 + StorageLive(_3); // scope 1 at $DIR/invalid_constant.rs:28:9: 28:21 + StorageLive(_4); // scope 1 at $DIR/invalid_constant.rs:28:25: 28:59 + StorageLive(_5); // scope 4 at $DIR/invalid_constant.rs:28:34: 28:55 + Deinit(_5); // scope 4 at $DIR/invalid_constant.rs:28:34: 28:55 + (_5.0: u32) = const 4_u32; // scope 4 at $DIR/invalid_constant.rs:28:34: 28:55 +- _4 = (_5.1: E); // scope 4 at $DIR/invalid_constant.rs:28:34: 28:57 +- _3 = [move _4]; // scope 1 at $DIR/invalid_constant.rs:28:24: 28:60 ++ _4 = const Scalar(0x00000004): E; // scope 4 at $DIR/invalid_constant.rs:28:34: 28:57 + // mir::Constant + // + span: $DIR/invalid_constant.rs:28:34: 28:57 + // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) } -+ _3 = [const Scalar(0x00000004): E]; // scope 1 at $DIR/invalid_constant.rs:+13:24: +13:60 ++ _3 = [const Scalar(0x00000004): E]; // scope 1 at $DIR/invalid_constant.rs:28:24: 28:60 + // mir::Constant + // + span: $DIR/invalid_constant.rs:28:24: 28:60 + // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) } - StorageDead(_4); // scope 1 at $DIR/invalid_constant.rs:+13:59: +13:60 - StorageDead(_5); // scope 1 at $DIR/invalid_constant.rs:+13:60: +13:61 - StorageLive(_6); // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31 - StorageLive(_7); // scope 3 at $DIR/invalid_constant.rs:+20:35: +20:73 - StorageLive(_8); // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65 - Deinit(_8); // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65 - (_8.0: u32) = const 0_u32; // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65 - nop; // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:71 - nop; // scope 3 at $DIR/invalid_constant.rs:+20:34: +20:74 - StorageDead(_7); // scope 3 at $DIR/invalid_constant.rs:+20:73: +20:74 - StorageDead(_8); // scope 3 at $DIR/invalid_constant.rs:+20:74: +20:75 - StorageLive(_9); // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22 - nop; // scope 0 at $DIR/invalid_constant.rs:+0:11: +27:2 - StorageDead(_9); // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2 - StorageDead(_6); // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2 - StorageDead(_3); // scope 1 at $DIR/invalid_constant.rs:+27:1: +27:2 - StorageDead(_1); // scope 0 at $DIR/invalid_constant.rs:+27:1: +27:2 - return; // scope 0 at $DIR/invalid_constant.rs:+27:2: +27:2 + StorageDead(_4); // scope 1 at $DIR/invalid_constant.rs:28:59: 28:60 + StorageDead(_5); // scope 1 at $DIR/invalid_constant.rs:28:60: 28:61 + StorageLive(_6); // scope 3 at $DIR/invalid_constant.rs:35:9: 35:31 + StorageLive(_7); // scope 3 at $DIR/invalid_constant.rs:35:35: 35:73 + StorageLive(_8); // scope 6 at $DIR/invalid_constant.rs:35:44: 35:65 + Deinit(_8); // scope 6 at $DIR/invalid_constant.rs:35:44: 35:65 + (_8.0: u32) = const 0_u32; // scope 6 at $DIR/invalid_constant.rs:35:44: 35:65 + nop; // scope 6 at $DIR/invalid_constant.rs:35:44: 35:71 + nop; // scope 3 at $DIR/invalid_constant.rs:35:34: 35:74 + StorageDead(_7); // scope 3 at $DIR/invalid_constant.rs:35:73: 35:74 + StorageDead(_8); // scope 3 at $DIR/invalid_constant.rs:35:74: 35:75 + StorageLive(_9); // scope 5 at $DIR/invalid_constant.rs:39:9: 39:22 + nop; // scope 0 at $DIR/invalid_constant.rs:15:11: 42:2 + StorageDead(_9); // scope 5 at $DIR/invalid_constant.rs:42:1: 42:2 + StorageDead(_6); // scope 3 at $DIR/invalid_constant.rs:42:1: 42:2 + StorageDead(_3); // scope 1 at $DIR/invalid_constant.rs:42:1: 42:2 + StorageDead(_1); // scope 0 at $DIR/invalid_constant.rs:42:1: 42:2 + return; // scope 0 at $DIR/invalid_constant.rs:42:2: 42:2 } } diff --git a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff index b3d5980aa7336..5991d7637f50f 100644 --- a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff @@ -2,32 +2,32 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-66971.rs:+0:11: +0:11 - let _1: (); // in scope 0 at $DIR/issue-66971.rs:+1:5: +1:23 - let mut _2: ((), u8, u8); // in scope 0 at $DIR/issue-66971.rs:+1:12: +1:22 - let mut _3: (); // in scope 0 at $DIR/issue-66971.rs:+1:13: +1:15 + let mut _0: (); // return place in scope 0 at $DIR/issue-66971.rs:15:11: 15:11 + let _1: (); // in scope 0 at $DIR/issue-66971.rs:16:5: 16:23 + let mut _2: ((), u8, u8); // in scope 0 at $DIR/issue-66971.rs:16:12: 16:22 + let mut _3: (); // in scope 0 at $DIR/issue-66971.rs:16:13: 16:15 bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-66971.rs:+1:5: +1:23 - StorageLive(_2); // scope 0 at $DIR/issue-66971.rs:+1:12: +1:22 - StorageLive(_3); // scope 0 at $DIR/issue-66971.rs:+1:13: +1:15 - nop; // scope 0 at $DIR/issue-66971.rs:+1:13: +1:15 - Deinit(_2); // scope 0 at $DIR/issue-66971.rs:+1:12: +1:22 - nop; // scope 0 at $DIR/issue-66971.rs:+1:12: +1:22 - (_2.1: u8) = const 0_u8; // scope 0 at $DIR/issue-66971.rs:+1:12: +1:22 - (_2.2: u8) = const 0_u8; // scope 0 at $DIR/issue-66971.rs:+1:12: +1:22 - StorageDead(_3); // scope 0 at $DIR/issue-66971.rs:+1:21: +1:22 - _1 = encode(move _2) -> bb1; // scope 0 at $DIR/issue-66971.rs:+1:5: +1:23 + StorageLive(_1); // scope 0 at $DIR/issue-66971.rs:16:5: 16:23 + StorageLive(_2); // scope 0 at $DIR/issue-66971.rs:16:12: 16:22 + StorageLive(_3); // scope 0 at $DIR/issue-66971.rs:16:13: 16:15 + nop; // scope 0 at $DIR/issue-66971.rs:16:13: 16:15 + Deinit(_2); // scope 0 at $DIR/issue-66971.rs:16:12: 16:22 + nop; // scope 0 at $DIR/issue-66971.rs:16:12: 16:22 + (_2.1: u8) = const 0_u8; // scope 0 at $DIR/issue-66971.rs:16:12: 16:22 + (_2.2: u8) = const 0_u8; // scope 0 at $DIR/issue-66971.rs:16:12: 16:22 + StorageDead(_3); // scope 0 at $DIR/issue-66971.rs:16:21: 16:22 + _1 = encode(move _2) -> bb1; // scope 0 at $DIR/issue-66971.rs:16:5: 16:23 // mir::Constant // + span: $DIR/issue-66971.rs:16:5: 16:11 // + literal: Const { ty: fn(((), u8, u8)) {encode}, val: Value() } } bb1: { - StorageDead(_2); // scope 0 at $DIR/issue-66971.rs:+1:22: +1:23 - StorageDead(_1); // scope 0 at $DIR/issue-66971.rs:+1:23: +1:24 - nop; // scope 0 at $DIR/issue-66971.rs:+0:11: +2:2 - return; // scope 0 at $DIR/issue-66971.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/issue-66971.rs:16:22: 16:23 + StorageDead(_1); // scope 0 at $DIR/issue-66971.rs:16:23: 16:24 + nop; // scope 0 at $DIR/issue-66971.rs:15:11: 17:2 + return; // scope 0 at $DIR/issue-66971.rs:17:2: 17:2 } } diff --git a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff index 8330b50529f73..149a60c0bbb54 100644 --- a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff @@ -2,33 +2,33 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-67019.rs:+0:11: +0:11 - let _1: (); // in scope 0 at $DIR/issue-67019.rs:+1:5: +1:20 - let mut _2: ((u8, u8),); // in scope 0 at $DIR/issue-67019.rs:+1:10: +1:19 - let mut _3: (u8, u8); // in scope 0 at $DIR/issue-67019.rs:+1:11: +1:17 + let mut _0: (); // return place in scope 0 at $DIR/issue-67019.rs:10:11: 10:11 + let _1: (); // in scope 0 at $DIR/issue-67019.rs:11:5: 11:20 + let mut _2: ((u8, u8),); // in scope 0 at $DIR/issue-67019.rs:11:10: 11:19 + let mut _3: (u8, u8); // in scope 0 at $DIR/issue-67019.rs:11:11: 11:17 bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-67019.rs:+1:5: +1:20 - StorageLive(_2); // scope 0 at $DIR/issue-67019.rs:+1:10: +1:19 - StorageLive(_3); // scope 0 at $DIR/issue-67019.rs:+1:11: +1:17 - Deinit(_3); // scope 0 at $DIR/issue-67019.rs:+1:11: +1:17 - (_3.0: u8) = const 1_u8; // scope 0 at $DIR/issue-67019.rs:+1:11: +1:17 - (_3.1: u8) = const 2_u8; // scope 0 at $DIR/issue-67019.rs:+1:11: +1:17 - Deinit(_2); // scope 0 at $DIR/issue-67019.rs:+1:10: +1:19 -- (_2.0: (u8, u8)) = move _3; // scope 0 at $DIR/issue-67019.rs:+1:10: +1:19 -+ (_2.0: (u8, u8)) = const (1_u8, 2_u8); // scope 0 at $DIR/issue-67019.rs:+1:10: +1:19 - StorageDead(_3); // scope 0 at $DIR/issue-67019.rs:+1:18: +1:19 - _1 = test(move _2) -> bb1; // scope 0 at $DIR/issue-67019.rs:+1:5: +1:20 + StorageLive(_1); // scope 0 at $DIR/issue-67019.rs:11:5: 11:20 + StorageLive(_2); // scope 0 at $DIR/issue-67019.rs:11:10: 11:19 + StorageLive(_3); // scope 0 at $DIR/issue-67019.rs:11:11: 11:17 + Deinit(_3); // scope 0 at $DIR/issue-67019.rs:11:11: 11:17 + (_3.0: u8) = const 1_u8; // scope 0 at $DIR/issue-67019.rs:11:11: 11:17 + (_3.1: u8) = const 2_u8; // scope 0 at $DIR/issue-67019.rs:11:11: 11:17 + Deinit(_2); // scope 0 at $DIR/issue-67019.rs:11:10: 11:19 +- (_2.0: (u8, u8)) = move _3; // scope 0 at $DIR/issue-67019.rs:11:10: 11:19 ++ (_2.0: (u8, u8)) = const (1_u8, 2_u8); // scope 0 at $DIR/issue-67019.rs:11:10: 11:19 + StorageDead(_3); // scope 0 at $DIR/issue-67019.rs:11:18: 11:19 + _1 = test(move _2) -> bb1; // scope 0 at $DIR/issue-67019.rs:11:5: 11:20 // mir::Constant // + span: $DIR/issue-67019.rs:11:5: 11:9 // + literal: Const { ty: fn(((u8, u8),)) {test}, val: Value() } } bb1: { - StorageDead(_2); // scope 0 at $DIR/issue-67019.rs:+1:19: +1:20 - StorageDead(_1); // scope 0 at $DIR/issue-67019.rs:+1:20: +1:21 - nop; // scope 0 at $DIR/issue-67019.rs:+0:11: +2:2 - return; // scope 0 at $DIR/issue-67019.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/issue-67019.rs:11:19: 11:20 + StorageDead(_1); // scope 0 at $DIR/issue-67019.rs:11:20: 11:21 + nop; // scope 0 at $DIR/issue-67019.rs:10:11: 12:2 + return; // scope 0 at $DIR/issue-67019.rs:12:2: 12:2 } } diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff index 96de39258e4dd..8276318f1ef84 100644 --- a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff @@ -2,36 +2,36 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/large_array_index.rs:+0:11: +0:11 - let _1: u8; // in scope 0 at $DIR/large_array_index.rs:+2:9: +2:10 - let mut _2: [u8; 5000]; // in scope 0 at $DIR/large_array_index.rs:+2:17: +2:29 - let _3: usize; // in scope 0 at $DIR/large_array_index.rs:+2:30: +2:31 - let mut _4: usize; // in scope 0 at $DIR/large_array_index.rs:+2:17: +2:32 - let mut _5: bool; // in scope 0 at $DIR/large_array_index.rs:+2:17: +2:32 + let mut _0: (); // return place in scope 0 at $DIR/large_array_index.rs:4:11: 4:11 + let _1: u8; // in scope 0 at $DIR/large_array_index.rs:6:9: 6:10 + let mut _2: [u8; 5000]; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:29 + let _3: usize; // in scope 0 at $DIR/large_array_index.rs:6:30: 6:31 + let mut _4: usize; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:32 + let mut _5: bool; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:32 scope 1 { - debug x => _1; // in scope 1 at $DIR/large_array_index.rs:+2:9: +2:10 + debug x => _1; // in scope 1 at $DIR/large_array_index.rs:6:9: 6:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/large_array_index.rs:+2:9: +2:10 - StorageLive(_2); // scope 0 at $DIR/large_array_index.rs:+2:17: +2:29 - _2 = [const 0_u8; 5000]; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:29 - StorageLive(_3); // scope 0 at $DIR/large_array_index.rs:+2:30: +2:31 - _3 = const 2_usize; // scope 0 at $DIR/large_array_index.rs:+2:30: +2:31 - _4 = const 5000_usize; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32 -- _5 = Lt(_3, _4); // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32 -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32 -+ _5 = const true; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32 -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32 + StorageLive(_1); // scope 0 at $DIR/large_array_index.rs:6:9: 6:10 + StorageLive(_2); // scope 0 at $DIR/large_array_index.rs:6:17: 6:29 + _2 = [const 0_u8; 5000]; // scope 0 at $DIR/large_array_index.rs:6:17: 6:29 + StorageLive(_3); // scope 0 at $DIR/large_array_index.rs:6:30: 6:31 + _3 = const 2_usize; // scope 0 at $DIR/large_array_index.rs:6:30: 6:31 + _4 = const 5000_usize; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 +- _5 = Lt(_3, _4); // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 ++ _5 = const true; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 } bb1: { - _1 = _2[_3]; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32 - StorageDead(_3); // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33 - StorageDead(_2); // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33 - nop; // scope 0 at $DIR/large_array_index.rs:+0:11: +3:2 - StorageDead(_1); // scope 0 at $DIR/large_array_index.rs:+3:1: +3:2 - return; // scope 0 at $DIR/large_array_index.rs:+3:2: +3:2 + _1 = _2[_3]; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 + StorageDead(_3); // scope 0 at $DIR/large_array_index.rs:6:32: 6:33 + StorageDead(_2); // scope 0 at $DIR/large_array_index.rs:6:32: 6:33 + nop; // scope 0 at $DIR/large_array_index.rs:4:11: 7:2 + StorageDead(_1); // scope 0 at $DIR/large_array_index.rs:7:1: 7:2 + return; // scope 0 at $DIR/large_array_index.rs:7:2: 7:2 } } diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff index 96de39258e4dd..8276318f1ef84 100644 --- a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff @@ -2,36 +2,36 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/large_array_index.rs:+0:11: +0:11 - let _1: u8; // in scope 0 at $DIR/large_array_index.rs:+2:9: +2:10 - let mut _2: [u8; 5000]; // in scope 0 at $DIR/large_array_index.rs:+2:17: +2:29 - let _3: usize; // in scope 0 at $DIR/large_array_index.rs:+2:30: +2:31 - let mut _4: usize; // in scope 0 at $DIR/large_array_index.rs:+2:17: +2:32 - let mut _5: bool; // in scope 0 at $DIR/large_array_index.rs:+2:17: +2:32 + let mut _0: (); // return place in scope 0 at $DIR/large_array_index.rs:4:11: 4:11 + let _1: u8; // in scope 0 at $DIR/large_array_index.rs:6:9: 6:10 + let mut _2: [u8; 5000]; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:29 + let _3: usize; // in scope 0 at $DIR/large_array_index.rs:6:30: 6:31 + let mut _4: usize; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:32 + let mut _5: bool; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:32 scope 1 { - debug x => _1; // in scope 1 at $DIR/large_array_index.rs:+2:9: +2:10 + debug x => _1; // in scope 1 at $DIR/large_array_index.rs:6:9: 6:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/large_array_index.rs:+2:9: +2:10 - StorageLive(_2); // scope 0 at $DIR/large_array_index.rs:+2:17: +2:29 - _2 = [const 0_u8; 5000]; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:29 - StorageLive(_3); // scope 0 at $DIR/large_array_index.rs:+2:30: +2:31 - _3 = const 2_usize; // scope 0 at $DIR/large_array_index.rs:+2:30: +2:31 - _4 = const 5000_usize; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32 -- _5 = Lt(_3, _4); // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32 -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32 -+ _5 = const true; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32 -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32 + StorageLive(_1); // scope 0 at $DIR/large_array_index.rs:6:9: 6:10 + StorageLive(_2); // scope 0 at $DIR/large_array_index.rs:6:17: 6:29 + _2 = [const 0_u8; 5000]; // scope 0 at $DIR/large_array_index.rs:6:17: 6:29 + StorageLive(_3); // scope 0 at $DIR/large_array_index.rs:6:30: 6:31 + _3 = const 2_usize; // scope 0 at $DIR/large_array_index.rs:6:30: 6:31 + _4 = const 5000_usize; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 +- _5 = Lt(_3, _4); // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 ++ _5 = const true; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 } bb1: { - _1 = _2[_3]; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32 - StorageDead(_3); // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33 - StorageDead(_2); // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33 - nop; // scope 0 at $DIR/large_array_index.rs:+0:11: +3:2 - StorageDead(_1); // scope 0 at $DIR/large_array_index.rs:+3:1: +3:2 - return; // scope 0 at $DIR/large_array_index.rs:+3:2: +3:2 + _1 = _2[_3]; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 + StorageDead(_3); // scope 0 at $DIR/large_array_index.rs:6:32: 6:33 + StorageDead(_2); // scope 0 at $DIR/large_array_index.rs:6:32: 6:33 + nop; // scope 0 at $DIR/large_array_index.rs:4:11: 7:2 + StorageDead(_1); // scope 0 at $DIR/large_array_index.rs:7:1: 7:2 + return; // scope 0 at $DIR/large_array_index.rs:7:2: 7:2 } } diff --git a/src/test/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff b/src/test/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff index 629c8e60148fd..84ae8cc7477e3 100644 --- a/src/test/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff @@ -2,17 +2,17 @@ + // MIR for `test` after ConstProp fn test(_1: i32) -> i32 { - debug x => _1; // in scope 0 at $DIR/mult_by_zero.rs:+0:9: +0:10 - let mut _0: i32; // return place in scope 0 at $DIR/mult_by_zero.rs:+0:21: +0:24 - let mut _2: i32; // in scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4 + debug x => _1; // in scope 0 at $DIR/mult_by_zero.rs:4:9: 4:10 + let mut _0: i32; // return place in scope 0 at $DIR/mult_by_zero.rs:4:21: 4:24 + let mut _2: i32; // in scope 0 at $DIR/mult_by_zero.rs:5:3: 5:4 bb0: { - StorageLive(_2); // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4 - _2 = _1; // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4 -- _0 = Mul(move _2, const 0_i32); // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8 -+ _0 = const 0_i32; // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8 - StorageDead(_2); // scope 0 at $DIR/mult_by_zero.rs:+1:7: +1:8 - return; // scope 0 at $DIR/mult_by_zero.rs:+2:2: +2:2 + StorageLive(_2); // scope 0 at $DIR/mult_by_zero.rs:5:3: 5:4 + _2 = _1; // scope 0 at $DIR/mult_by_zero.rs:5:3: 5:4 +- _0 = Mul(move _2, const 0_i32); // scope 0 at $DIR/mult_by_zero.rs:5:3: 5:8 ++ _0 = const 0_i32; // scope 0 at $DIR/mult_by_zero.rs:5:3: 5:8 + StorageDead(_2); // scope 0 at $DIR/mult_by_zero.rs:5:7: 5:8 + return; // scope 0 at $DIR/mult_by_zero.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/mutable_variable.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable.main.ConstProp.diff index 3bbd6a87f9714..f159cfa025cc8 100644 --- a/src/test/mir-opt/const_prop/mutable_variable.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable.main.ConstProp.diff @@ -2,27 +2,27 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/mutable_variable.rs:+0:11: +0:11 - let mut _1: i32; // in scope 0 at $DIR/mutable_variable.rs:+1:9: +1:14 + let mut _0: (); // return place in scope 0 at $DIR/mutable_variable.rs:4:11: 4:11 + let mut _1: i32; // in scope 0 at $DIR/mutable_variable.rs:5:9: 5:14 scope 1 { - debug x => _1; // in scope 1 at $DIR/mutable_variable.rs:+1:9: +1:14 - let _2: i32; // in scope 1 at $DIR/mutable_variable.rs:+3:9: +3:10 + debug x => _1; // in scope 1 at $DIR/mutable_variable.rs:5:9: 5:14 + let _2: i32; // in scope 1 at $DIR/mutable_variable.rs:7:9: 7:10 scope 2 { - debug y => _2; // in scope 2 at $DIR/mutable_variable.rs:+3:9: +3:10 + debug y => _2; // in scope 2 at $DIR/mutable_variable.rs:7:9: 7:10 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/mutable_variable.rs:+1:9: +1:14 - _1 = const 42_i32; // scope 0 at $DIR/mutable_variable.rs:+1:17: +1:19 - _1 = const 99_i32; // scope 1 at $DIR/mutable_variable.rs:+2:5: +2:11 - StorageLive(_2); // scope 1 at $DIR/mutable_variable.rs:+3:9: +3:10 -- _2 = _1; // scope 1 at $DIR/mutable_variable.rs:+3:13: +3:14 -+ _2 = const 99_i32; // scope 1 at $DIR/mutable_variable.rs:+3:13: +3:14 - nop; // scope 0 at $DIR/mutable_variable.rs:+0:11: +4:2 - StorageDead(_2); // scope 1 at $DIR/mutable_variable.rs:+4:1: +4:2 - StorageDead(_1); // scope 0 at $DIR/mutable_variable.rs:+4:1: +4:2 - return; // scope 0 at $DIR/mutable_variable.rs:+4:2: +4:2 + StorageLive(_1); // scope 0 at $DIR/mutable_variable.rs:5:9: 5:14 + _1 = const 42_i32; // scope 0 at $DIR/mutable_variable.rs:5:17: 5:19 + _1 = const 99_i32; // scope 1 at $DIR/mutable_variable.rs:6:5: 6:11 + StorageLive(_2); // scope 1 at $DIR/mutable_variable.rs:7:9: 7:10 +- _2 = _1; // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14 ++ _2 = const 99_i32; // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14 + nop; // scope 0 at $DIR/mutable_variable.rs:4:11: 8:2 + StorageDead(_2); // scope 1 at $DIR/mutable_variable.rs:8:1: 8:2 + StorageDead(_1); // scope 0 at $DIR/mutable_variable.rs:8:1: 8:2 + return; // scope 0 at $DIR/mutable_variable.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff index fed6a98b9f364..b1deebe40fac0 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff @@ -2,29 +2,29 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/mutable_variable_aggregate.rs:+0:11: +0:11 - let mut _1: (i32, i32); // in scope 0 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14 + let mut _0: (); // return place in scope 0 at $DIR/mutable_variable_aggregate.rs:4:11: 4:11 + let mut _1: (i32, i32); // in scope 0 at $DIR/mutable_variable_aggregate.rs:5:9: 5:14 scope 1 { - debug x => _1; // in scope 1 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14 - let _2: (i32, i32); // in scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 + debug x => _1; // in scope 1 at $DIR/mutable_variable_aggregate.rs:5:9: 5:14 + let _2: (i32, i32); // in scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10 scope 2 { - debug y => _2; // in scope 2 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 + debug y => _2; // in scope 2 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14 - Deinit(_1); // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:17: +1:25 - (_1.0: i32) = const 42_i32; // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:17: +1:25 - (_1.1: i32) = const 43_i32; // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:17: +1:25 - (_1.1: i32) = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate.rs:+2:5: +2:13 - StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 -- _2 = _1; // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14 -+ _2 = const (42_i32, 99_i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14 - nop; // scope 0 at $DIR/mutable_variable_aggregate.rs:+0:11: +4:2 - StorageDead(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:+4:1: +4:2 - StorageDead(_1); // scope 0 at $DIR/mutable_variable_aggregate.rs:+4:1: +4:2 - return; // scope 0 at $DIR/mutable_variable_aggregate.rs:+4:2: +4:2 + StorageLive(_1); // scope 0 at $DIR/mutable_variable_aggregate.rs:5:9: 5:14 + Deinit(_1); // scope 0 at $DIR/mutable_variable_aggregate.rs:5:17: 5:25 + (_1.0: i32) = const 42_i32; // scope 0 at $DIR/mutable_variable_aggregate.rs:5:17: 5:25 + (_1.1: i32) = const 43_i32; // scope 0 at $DIR/mutable_variable_aggregate.rs:5:17: 5:25 + (_1.1: i32) = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate.rs:6:5: 6:13 + StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10 +- _2 = _1; // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14 ++ _2 = const (42_i32, 99_i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14 + nop; // scope 0 at $DIR/mutable_variable_aggregate.rs:4:11: 8:2 + StorageDead(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:8:1: 8:2 + StorageDead(_1); // scope 0 at $DIR/mutable_variable_aggregate.rs:8:1: 8:2 + return; // scope 0 at $DIR/mutable_variable_aggregate.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff index 90eebd8feac60..07208ad0d2b58 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff @@ -2,35 +2,35 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+0:11: +0:11 - let mut _1: (i32, i32); // in scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+1:9: +1:14 + let mut _0: (); // return place in scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:4:11: 4:11 + let mut _1: (i32, i32); // in scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:9: 5:14 scope 1 { - debug x => _1; // in scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:+1:9: +1:14 - let _2: &mut (i32, i32); // in scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:+2:9: +2:10 + debug x => _1; // in scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:9: 5:14 + let _2: &mut (i32, i32); // in scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:9: 6:10 scope 2 { - debug z => _2; // in scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+2:9: +2:10 - let _3: (i32, i32); // in scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10 + debug z => _2; // in scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:9: 6:10 + let _3: (i32, i32); // in scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:8:9: 8:10 scope 3 { - debug y => _3; // in scope 3 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10 + debug y => _3; // in scope 3 at $DIR/mutable_variable_aggregate_mut_ref.rs:8:9: 8:10 } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+1:9: +1:14 - Deinit(_1); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+1:17: +1:25 - (_1.0: i32) = const 42_i32; // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+1:17: +1:25 - (_1.1: i32) = const 43_i32; // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+1:17: +1:25 - StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:+2:9: +2:10 - _2 = &mut _1; // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:+2:13: +2:19 - ((*_2).1: i32) = const 99_i32; // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+3:5: +3:13 - StorageLive(_3); // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10 - _3 = _1; // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:13: +4:14 - nop; // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+0:11: +5:2 - StorageDead(_3); // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:1: +5:2 - StorageDead(_2); // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:1: +5:2 - StorageDead(_1); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:1: +5:2 - return; // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:2: +5:2 + StorageLive(_1); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:9: 5:14 + Deinit(_1); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25 + (_1.0: i32) = const 42_i32; // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25 + (_1.1: i32) = const 43_i32; // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25 + StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:9: 6:10 + _2 = &mut _1; // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:13: 6:19 + ((*_2).1: i32) = const 99_i32; // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:7:5: 7:13 + StorageLive(_3); // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:8:9: 8:10 + _3 = _1; // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:8:13: 8:14 + nop; // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:4:11: 9:2 + StorageDead(_3); // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:9:1: 9:2 + StorageDead(_2); // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:9:1: 9:2 + StorageDead(_1); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:9:1: 9:2 + return; // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff index c678f7b032763..724cf096f5946 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff @@ -2,34 +2,34 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+0:11: +0:11 - let mut _1: (i32, i32); // in scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+1:9: +1:14 + let mut _0: (); // return place in scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:4:11: 4:11 + let mut _1: (i32, i32); // in scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:5:9: 5:14 scope 1 { - debug x => _1; // in scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:+1:9: +1:14 - let _2: i32; // in scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:+4:9: +4:10 + debug x => _1; // in scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:5:9: 5:14 + let _2: i32; // in scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:9: 8:10 scope 2 { - debug y => _2; // in scope 2 at $DIR/mutable_variable_aggregate_partial_read.rs:+4:9: +4:10 + debug y => _2; // in scope 2 at $DIR/mutable_variable_aggregate_partial_read.rs:8:9: 8:10 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+1:9: +1:14 - _1 = foo() -> bb1; // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+1:29: +1:34 + StorageLive(_1); // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:5:9: 5:14 + _1 = foo() -> bb1; // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:5:29: 5:34 // mir::Constant // + span: $DIR/mutable_variable_aggregate_partial_read.rs:5:29: 5:32 // + literal: Const { ty: fn() -> (i32, i32) {foo}, val: Value() } } bb1: { - (_1.1: i32) = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:+2:5: +2:13 - (_1.0: i32) = const 42_i32; // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:+3:5: +3:13 - StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:+4:9: +4:10 -- _2 = (_1.1: i32); // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:+4:13: +4:16 -+ _2 = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:+4:13: +4:16 - nop; // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+0:11: +5:2 - StorageDead(_2); // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:+5:1: +5:2 - StorageDead(_1); // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+5:1: +5:2 - return; // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+5:2: +5:2 + (_1.1: i32) = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:6:5: 6:13 + (_1.0: i32) = const 42_i32; // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:7:5: 7:13 + StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:9: 8:10 +- _2 = (_1.1: i32); // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:13: 8:16 ++ _2 = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:13: 8:16 + nop; // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:4:11: 9:2 + StorageDead(_2); // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:9:1: 9:2 + StorageDead(_1); // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:9:1: 9:2 + return; // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff index 4c2ba9a099815..1fd92ddd46190 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff @@ -2,43 +2,43 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/mutable_variable_no_prop.rs:+0:11: +0:11 - let mut _1: u32; // in scope 0 at $DIR/mutable_variable_no_prop.rs:+1:9: +1:14 - let _2: (); // in scope 0 at $DIR/mutable_variable_no_prop.rs:+2:5: +4:6 - let mut _3: u32; // in scope 0 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19 - let mut _4: *mut u32; // in scope 0 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19 + let mut _0: (); // return place in scope 0 at $DIR/mutable_variable_no_prop.rs:6:11: 6:11 + let mut _1: u32; // in scope 0 at $DIR/mutable_variable_no_prop.rs:7:9: 7:14 + let _2: (); // in scope 0 at $DIR/mutable_variable_no_prop.rs:8:5: 10:6 + let mut _3: u32; // in scope 0 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19 + let mut _4: *mut u32; // in scope 0 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19 scope 1 { - debug x => _1; // in scope 1 at $DIR/mutable_variable_no_prop.rs:+1:9: +1:14 - let _5: u32; // in scope 1 at $DIR/mutable_variable_no_prop.rs:+5:9: +5:10 + debug x => _1; // in scope 1 at $DIR/mutable_variable_no_prop.rs:7:9: 7:14 + let _5: u32; // in scope 1 at $DIR/mutable_variable_no_prop.rs:11:9: 11:10 scope 2 { } scope 3 { - debug y => _5; // in scope 3 at $DIR/mutable_variable_no_prop.rs:+5:9: +5:10 + debug y => _5; // in scope 3 at $DIR/mutable_variable_no_prop.rs:11:9: 11:10 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/mutable_variable_no_prop.rs:+1:9: +1:14 - _1 = const 42_u32; // scope 0 at $DIR/mutable_variable_no_prop.rs:+1:17: +1:19 - StorageLive(_2); // scope 1 at $DIR/mutable_variable_no_prop.rs:+2:5: +4:6 - StorageLive(_3); // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19 - StorageLive(_4); // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19 - _4 = const {alloc1: *mut u32}; // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19 + StorageLive(_1); // scope 0 at $DIR/mutable_variable_no_prop.rs:7:9: 7:14 + _1 = const 42_u32; // scope 0 at $DIR/mutable_variable_no_prop.rs:7:17: 7:19 + StorageLive(_2); // scope 1 at $DIR/mutable_variable_no_prop.rs:8:5: 10:6 + StorageLive(_3); // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19 + StorageLive(_4); // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19 + _4 = const {alloc1: *mut u32}; // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19 // mir::Constant // + span: $DIR/mutable_variable_no_prop.rs:9:13: 9:19 // + literal: Const { ty: *mut u32, val: Value(Scalar(alloc1)) } - _3 = (*_4); // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19 - _1 = move _3; // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:9: +3:19 - StorageDead(_3); // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:18: +3:19 - StorageDead(_4); // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:19: +3:20 - nop; // scope 2 at $DIR/mutable_variable_no_prop.rs:+2:5: +4:6 - StorageDead(_2); // scope 1 at $DIR/mutable_variable_no_prop.rs:+4:5: +4:6 - StorageLive(_5); // scope 1 at $DIR/mutable_variable_no_prop.rs:+5:9: +5:10 - _5 = _1; // scope 1 at $DIR/mutable_variable_no_prop.rs:+5:13: +5:14 - nop; // scope 0 at $DIR/mutable_variable_no_prop.rs:+0:11: +6:2 - StorageDead(_5); // scope 1 at $DIR/mutable_variable_no_prop.rs:+6:1: +6:2 - StorageDead(_1); // scope 0 at $DIR/mutable_variable_no_prop.rs:+6:1: +6:2 - return; // scope 0 at $DIR/mutable_variable_no_prop.rs:+6:2: +6:2 + _3 = (*_4); // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19 + _1 = move _3; // scope 2 at $DIR/mutable_variable_no_prop.rs:9:9: 9:19 + StorageDead(_3); // scope 2 at $DIR/mutable_variable_no_prop.rs:9:18: 9:19 + StorageDead(_4); // scope 2 at $DIR/mutable_variable_no_prop.rs:9:19: 9:20 + nop; // scope 2 at $DIR/mutable_variable_no_prop.rs:8:5: 10:6 + StorageDead(_2); // scope 1 at $DIR/mutable_variable_no_prop.rs:10:5: 10:6 + StorageLive(_5); // scope 1 at $DIR/mutable_variable_no_prop.rs:11:9: 11:10 + _5 = _1; // scope 1 at $DIR/mutable_variable_no_prop.rs:11:13: 11:14 + nop; // scope 0 at $DIR/mutable_variable_no_prop.rs:6:11: 12:2 + StorageDead(_5); // scope 1 at $DIR/mutable_variable_no_prop.rs:12:1: 12:2 + StorageDead(_1); // scope 0 at $DIR/mutable_variable_no_prop.rs:12:1: 12:2 + return; // scope 0 at $DIR/mutable_variable_no_prop.rs:12:2: 12:2 } } diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff index 5328792b32388..a22efa7eaf50a 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff @@ -2,52 +2,52 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/mutable_variable_unprop_assign.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/mutable_variable_unprop_assign.rs:+1:9: +1:10 - let mut _3: i32; // in scope 0 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 + let mut _0: (); // return place in scope 0 at $DIR/mutable_variable_unprop_assign.rs:4:11: 4:11 + let _1: i32; // in scope 0 at $DIR/mutable_variable_unprop_assign.rs:5:9: 5:10 + let mut _3: i32; // in scope 0 at $DIR/mutable_variable_unprop_assign.rs:7:11: 7:12 scope 1 { - debug a => _1; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+1:9: +1:10 - let mut _2: (i32, i32); // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 + debug a => _1; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:5:9: 5:10 + let mut _2: (i32, i32); // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:9: 6:14 scope 2 { - debug x => _2; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 - let _4: i32; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10 + debug x => _2; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:6:9: 6:14 + let _4: i32; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:8:9: 8:10 scope 3 { - debug y => _4; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10 - let _5: i32; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10 + debug y => _4; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:8:9: 8:10 + let _5: i32; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:9:9: 9:10 scope 4 { - debug z => _5; // in scope 4 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10 + debug z => _5; // in scope 4 at $DIR/mutable_variable_unprop_assign.rs:9:9: 9:10 } } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+1:9: +1:10 - _1 = foo() -> bb1; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+1:13: +1:18 + StorageLive(_1); // scope 0 at $DIR/mutable_variable_unprop_assign.rs:5:9: 5:10 + _1 = foo() -> bb1; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:5:13: 5:18 // mir::Constant // + span: $DIR/mutable_variable_unprop_assign.rs:5:13: 5:16 // + literal: Const { ty: fn() -> i32 {foo}, val: Value() } } bb1: { - StorageLive(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 - Deinit(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 - (_2.0: i32) = const 1_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 - (_2.1: i32) = const 2_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 - StorageLive(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 - _3 = _1; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 - (_2.1: i32) = move _3; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:5: +3:12 - StorageDead(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 - StorageLive(_4); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10 - _4 = (_2.1: i32); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:13: +4:16 - StorageLive(_5); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10 - _5 = (_2.0: i32); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16 - nop; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+0:11: +6:2 - StorageDead(_5); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 - StorageDead(_4); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 - StorageDead(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 - StorageDead(_1); // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 - return; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+6:2: +6:2 + StorageLive(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:9: 6:14 + Deinit(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:29: 6:35 + (_2.0: i32) = const 1_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:29: 6:35 + (_2.1: i32) = const 2_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:29: 6:35 + StorageLive(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:7:11: 7:12 + _3 = _1; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:7:11: 7:12 + (_2.1: i32) = move _3; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:7:5: 7:12 + StorageDead(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:7:11: 7:12 + StorageLive(_4); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:8:9: 8:10 + _4 = (_2.1: i32); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:8:13: 8:16 + StorageLive(_5); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:9:9: 9:10 + _5 = (_2.0: i32); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:9:13: 9:16 + nop; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:4:11: 10:2 + StorageDead(_5); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:10:1: 10:2 + StorageDead(_4); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:10:1: 10:2 + StorageDead(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:10:1: 10:2 + StorageDead(_1); // scope 0 at $DIR/mutable_variable_unprop_assign.rs:10:1: 10:2 + return; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff index 94aadfaf8d57b..72a613b26b6a3 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff @@ -2,67 +2,67 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 - let mut _2: (i32, bool); // in scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 - let mut _4: [i32; 6]; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:31 - let _5: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:32: +2:33 - let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 - let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 - let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:11:11: 11:11 + let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 + let mut _2: (i32, bool); // in scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + let mut _4: [i32; 6]; // in scope 0 at $DIR/optimizes_into_variable.rs:13:13: 13:31 + let _5: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:13:32: 13:33 + let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:14:13: 14:36 scope 1 { - debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 - let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 + debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:12:9: 12:10 + let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 scope 2 { - debug y => _3; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 - let _8: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + debug y => _3; // in scope 2 at $DIR/optimizes_into_variable.rs:13:9: 13:10 + let _8: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 scope 3 { - debug z => _8; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + debug z => _8; // in scope 3 at $DIR/optimizes_into_variable.rs:14:9: 14:10 } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 -- _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 -- assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 -+ _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 -+ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 + StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 +- _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 +- assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 ++ _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 } bb1: { -- _1 = move (_2.0: i32); // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 -+ _1 = const 4_i32; // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 - StorageLive(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 - StorageLive(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:31 - _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:31 - StorageLive(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:32: +2:33 - _5 = const 3_usize; // scope 1 at $DIR/optimizes_into_variable.rs:+2:32: +2:33 - _6 = const 6_usize; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 -- _7 = Lt(_5, _6); // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 -- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 -+ _7 = const true; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 +- _1 = move (_2.0: i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 ++ _1 = const 4_i32; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + StorageLive(_3); // scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 + StorageLive(_4); // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31 + _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31 + StorageLive(_5); // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33 + _5 = const 3_usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33 + _6 = const 6_usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 +- _7 = Lt(_5, _6); // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 +- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 ++ _7 = const true; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 } bb2: { -- _3 = _4[_5]; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 -+ _3 = const 3_i32; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 - StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 - StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 - StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 - StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - Deinit(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - (_9.0: u32) = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - (_9.1: u32) = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 -- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 -+ _8 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 - StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 - nop; // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2 - StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 - StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 - StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 - return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2 +- _3 = _4[_5]; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 ++ _3 = const 3_i32; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:13:34: 13:35 + StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:13:34: 13:35 + StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36 + Deinit(_9); // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36 + (_9.0: u32) = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36 + (_9.1: u32) = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36 +- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38 ++ _8 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38 + StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:14:38: 14:39 + nop; // scope 0 at $DIR/optimizes_into_variable.rs:11:11: 15:2 + StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + return; // scope 0 at $DIR/optimizes_into_variable.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff index 94aadfaf8d57b..72a613b26b6a3 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff @@ -2,67 +2,67 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 - let mut _2: (i32, bool); // in scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 - let mut _4: [i32; 6]; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:31 - let _5: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:32: +2:33 - let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 - let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 - let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:11:11: 11:11 + let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 + let mut _2: (i32, bool); // in scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + let mut _4: [i32; 6]; // in scope 0 at $DIR/optimizes_into_variable.rs:13:13: 13:31 + let _5: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:13:32: 13:33 + let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:14:13: 14:36 scope 1 { - debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 - let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 + debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:12:9: 12:10 + let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 scope 2 { - debug y => _3; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 - let _8: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + debug y => _3; // in scope 2 at $DIR/optimizes_into_variable.rs:13:9: 13:10 + let _8: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 scope 3 { - debug z => _8; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + debug z => _8; // in scope 3 at $DIR/optimizes_into_variable.rs:14:9: 14:10 } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 -- _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 -- assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 -+ _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 -+ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 + StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 +- _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 +- assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 ++ _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 } bb1: { -- _1 = move (_2.0: i32); // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 -+ _1 = const 4_i32; // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 - StorageLive(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 - StorageLive(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:31 - _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:31 - StorageLive(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:32: +2:33 - _5 = const 3_usize; // scope 1 at $DIR/optimizes_into_variable.rs:+2:32: +2:33 - _6 = const 6_usize; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 -- _7 = Lt(_5, _6); // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 -- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 -+ _7 = const true; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 +- _1 = move (_2.0: i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 ++ _1 = const 4_i32; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + StorageLive(_3); // scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 + StorageLive(_4); // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31 + _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31 + StorageLive(_5); // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33 + _5 = const 3_usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33 + _6 = const 6_usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 +- _7 = Lt(_5, _6); // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 +- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 ++ _7 = const true; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 } bb2: { -- _3 = _4[_5]; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 -+ _3 = const 3_i32; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 - StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 - StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 - StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 - StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - Deinit(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - (_9.0: u32) = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - (_9.1: u32) = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 -- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 -+ _8 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 - StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 - nop; // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2 - StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 - StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 - StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 - return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2 +- _3 = _4[_5]; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 ++ _3 = const 3_i32; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:13:34: 13:35 + StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:13:34: 13:35 + StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36 + Deinit(_9); // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36 + (_9.0: u32) = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36 + (_9.1: u32) = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36 +- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38 ++ _8 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38 + StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:14:38: 14:39 + nop; // scope 0 at $DIR/optimizes_into_variable.rs:11:11: 15:2 + StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + return; // scope 0 at $DIR/optimizes_into_variable.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir index 75cea8ad2cebf..6d11d02d67928 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir @@ -1,27 +1,27 @@ // MIR for `main` after SimplifyLocals fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:11:11: 11:11 + let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 scope 1 { - debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 - let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 + debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:12:9: 12:10 + let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 scope 2 { - debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 - let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:13:9: 13:10 + let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 scope 3 { - debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:14:9: 14:10 } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 - StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 - StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 - StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 - StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 - StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 - return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2 + StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 + StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 + StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + return; // scope 0 at $DIR/optimizes_into_variable.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir index 75cea8ad2cebf..6d11d02d67928 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir @@ -1,27 +1,27 @@ // MIR for `main` after SimplifyLocals fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:11:11: 11:11 + let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 scope 1 { - debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 - let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 + debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:12:9: 12:10 + let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 scope 2 { - debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 - let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:13:9: 13:10 + let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 scope 3 { - debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:14:9: 14:10 } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 - StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 - StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 - StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 - StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 - StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 - return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2 + StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 + StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 + StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + return; // scope 0 at $DIR/optimizes_into_variable.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff b/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff index 89f43d7513815..15b3e07664258 100644 --- a/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff @@ -2,43 +2,43 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/read_immutable_static.rs:+0:11: +0:11 - let _1: u8; // in scope 0 at $DIR/read_immutable_static.rs:+1:9: +1:10 - let mut _2: u8; // in scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16 - let mut _3: &u8; // in scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16 - let mut _4: u8; // in scope 0 at $DIR/read_immutable_static.rs:+1:19: +1:22 - let mut _5: &u8; // in scope 0 at $DIR/read_immutable_static.rs:+1:19: +1:22 + let mut _0: (); // return place in scope 0 at $DIR/read_immutable_static.rs:6:11: 6:11 + let _1: u8; // in scope 0 at $DIR/read_immutable_static.rs:7:9: 7:10 + let mut _2: u8; // in scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16 + let mut _3: &u8; // in scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16 + let mut _4: u8; // in scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22 + let mut _5: &u8; // in scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22 scope 1 { - debug x => _1; // in scope 1 at $DIR/read_immutable_static.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/read_immutable_static.rs:7:9: 7:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/read_immutable_static.rs:+1:9: +1:10 - StorageLive(_2); // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16 - StorageLive(_3); // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16 - _3 = const {alloc1: &u8}; // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16 + StorageLive(_1); // scope 0 at $DIR/read_immutable_static.rs:7:9: 7:10 + StorageLive(_2); // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16 + StorageLive(_3); // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16 + _3 = const {alloc1: &u8}; // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16 // mir::Constant // + span: $DIR/read_immutable_static.rs:7:13: 7:16 // + literal: Const { ty: &u8, val: Value(Scalar(alloc1)) } -- _2 = (*_3); // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16 -+ _2 = const 2_u8; // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16 - StorageLive(_4); // scope 0 at $DIR/read_immutable_static.rs:+1:19: +1:22 - StorageLive(_5); // scope 0 at $DIR/read_immutable_static.rs:+1:19: +1:22 - _5 = const {alloc1: &u8}; // scope 0 at $DIR/read_immutable_static.rs:+1:19: +1:22 +- _2 = (*_3); // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16 ++ _2 = const 2_u8; // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16 + StorageLive(_4); // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22 + StorageLive(_5); // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22 + _5 = const {alloc1: &u8}; // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22 // mir::Constant // + span: $DIR/read_immutable_static.rs:7:19: 7:22 // + literal: Const { ty: &u8, val: Value(Scalar(alloc1)) } -- _4 = (*_5); // scope 0 at $DIR/read_immutable_static.rs:+1:19: +1:22 -- _1 = Add(move _2, move _4); // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:22 -+ _4 = const 2_u8; // scope 0 at $DIR/read_immutable_static.rs:+1:19: +1:22 -+ _1 = const 4_u8; // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:22 - StorageDead(_4); // scope 0 at $DIR/read_immutable_static.rs:+1:21: +1:22 - StorageDead(_2); // scope 0 at $DIR/read_immutable_static.rs:+1:21: +1:22 - StorageDead(_5); // scope 0 at $DIR/read_immutable_static.rs:+1:22: +1:23 - StorageDead(_3); // scope 0 at $DIR/read_immutable_static.rs:+1:22: +1:23 - nop; // scope 0 at $DIR/read_immutable_static.rs:+0:11: +2:2 - StorageDead(_1); // scope 0 at $DIR/read_immutable_static.rs:+2:1: +2:2 - return; // scope 0 at $DIR/read_immutable_static.rs:+2:2: +2:2 +- _4 = (*_5); // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22 +- _1 = Add(move _2, move _4); // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:22 ++ _4 = const 2_u8; // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22 ++ _1 = const 4_u8; // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:22 + StorageDead(_4); // scope 0 at $DIR/read_immutable_static.rs:7:21: 7:22 + StorageDead(_2); // scope 0 at $DIR/read_immutable_static.rs:7:21: 7:22 + StorageDead(_5); // scope 0 at $DIR/read_immutable_static.rs:7:22: 7:23 + StorageDead(_3); // scope 0 at $DIR/read_immutable_static.rs:7:22: 7:23 + nop; // scope 0 at $DIR/read_immutable_static.rs:6:11: 8:2 + StorageDead(_1); // scope 0 at $DIR/read_immutable_static.rs:8:1: 8:2 + return; // scope 0 at $DIR/read_immutable_static.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff index c8b09220f1e44..07ace0d6b576d 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff @@ -2,26 +2,26 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/ref_deref.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 - let mut _2: &i32; // in scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 - let _3: i32; // in scope 0 at $DIR/ref_deref.rs:+1:8: +1:9 - let mut _4: &i32; // in scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 + let mut _0: (); // return place in scope 0 at $DIR/ref_deref.rs:4:11: 4:11 + let _1: i32; // in scope 0 at $DIR/ref_deref.rs:5:5: 5:10 + let mut _2: &i32; // in scope 0 at $DIR/ref_deref.rs:5:6: 5:10 + let _3: i32; // in scope 0 at $DIR/ref_deref.rs:5:8: 5:9 + let mut _4: &i32; // in scope 0 at $DIR/ref_deref.rs:5:6: 5:10 bb0: { - StorageLive(_1); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 - StorageLive(_2); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 - _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 + StorageLive(_1); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 + StorageLive(_2); // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 + _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 // mir::Constant // + span: $DIR/ref_deref.rs:5:6: 5:10 // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) } - _2 = _4; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 -- _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 -+ _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 - StorageDead(_2); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11 - StorageDead(_1); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11 - nop; // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2 - return; // scope 0 at $DIR/ref_deref.rs:+2:2: +2:2 + _2 = _4; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 +- _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 ++ _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 + StorageDead(_2); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 + StorageDead(_1); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 + nop; // scope 0 at $DIR/ref_deref.rs:4:11: 6:2 + return; // scope 0 at $DIR/ref_deref.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff index d141d2cf87bb7..aed13d8ec02ec 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff @@ -2,29 +2,29 @@ + // MIR for `main` after PromoteTemps fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/ref_deref.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 - let mut _2: &i32; // in scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 - let _3: i32; // in scope 0 at $DIR/ref_deref.rs:+1:8: +1:9 -+ let mut _4: &i32; // in scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 + let mut _0: (); // return place in scope 0 at $DIR/ref_deref.rs:4:11: 4:11 + let _1: i32; // in scope 0 at $DIR/ref_deref.rs:5:5: 5:10 + let mut _2: &i32; // in scope 0 at $DIR/ref_deref.rs:5:6: 5:10 + let _3: i32; // in scope 0 at $DIR/ref_deref.rs:5:8: 5:9 ++ let mut _4: &i32; // in scope 0 at $DIR/ref_deref.rs:5:6: 5:10 bb0: { - StorageLive(_1); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 - StorageLive(_2); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 -- StorageLive(_3); // scope 0 at $DIR/ref_deref.rs:+1:8: +1:9 -- _3 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:+1:8: +1:9 -- _2 = &_3; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 -+ _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 + StorageLive(_1); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 + StorageLive(_2); // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 +- StorageLive(_3); // scope 0 at $DIR/ref_deref.rs:5:8: 5:9 +- _3 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:5:8: 5:9 +- _2 = &_3; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 ++ _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 + // mir::Constant + // + span: $DIR/ref_deref.rs:5:6: 5:10 + // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) } -+ _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 - _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 -- StorageDead(_3); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11 - StorageDead(_2); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11 - StorageDead(_1); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11 - _0 = const (); // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2 - return; // scope 0 at $DIR/ref_deref.rs:+2:2: +2:2 ++ _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 + _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 +- StorageDead(_3); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 + StorageDead(_2); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 + StorageDead(_1); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 + _0 = const (); // scope 0 at $DIR/ref_deref.rs:4:11: 6:2 + return; // scope 0 at $DIR/ref_deref.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff index f0c89caeac645..bbd0ec1a33687 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff @@ -2,25 +2,25 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/ref_deref_project.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17 - let mut _2: &i32; // in scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 - let _3: (i32, i32); // in scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14 - let mut _4: &(i32, i32); // in scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 + let mut _0: (); // return place in scope 0 at $DIR/ref_deref_project.rs:4:11: 4:11 + let _1: i32; // in scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 + let mut _2: &i32; // in scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 + let _3: (i32, i32); // in scope 0 at $DIR/ref_deref_project.rs:5:8: 5:14 + let mut _4: &(i32, i32); // in scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 bb0: { - StorageLive(_1); // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17 - StorageLive(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 - _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 + StorageLive(_1); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 + StorageLive(_2); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 + _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 // mir::Constant // + span: $DIR/ref_deref_project.rs:5:6: 5:17 // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) } - _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 - _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17 - StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18 - StorageDead(_1); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18 - nop; // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2 - return; // scope 0 at $DIR/ref_deref_project.rs:+2:2: +2:2 + _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 + _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 + StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 + StorageDead(_1); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 + nop; // scope 0 at $DIR/ref_deref_project.rs:4:11: 6:2 + return; // scope 0 at $DIR/ref_deref_project.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff index d2554028792c1..2df963556a9ee 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff @@ -2,29 +2,29 @@ + // MIR for `main` after PromoteTemps fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/ref_deref_project.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17 - let mut _2: &i32; // in scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 - let _3: (i32, i32); // in scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14 -+ let mut _4: &(i32, i32); // in scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 + let mut _0: (); // return place in scope 0 at $DIR/ref_deref_project.rs:4:11: 4:11 + let _1: i32; // in scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 + let mut _2: &i32; // in scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 + let _3: (i32, i32); // in scope 0 at $DIR/ref_deref_project.rs:5:8: 5:14 ++ let mut _4: &(i32, i32); // in scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 bb0: { - StorageLive(_1); // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17 - StorageLive(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 -- StorageLive(_3); // scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14 -- _3 = (const 4_i32, const 5_i32); // scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14 -- _2 = &(_3.1: i32); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 -+ _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 + StorageLive(_1); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 + StorageLive(_2); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 +- StorageLive(_3); // scope 0 at $DIR/ref_deref_project.rs:5:8: 5:14 +- _3 = (const 4_i32, const 5_i32); // scope 0 at $DIR/ref_deref_project.rs:5:8: 5:14 +- _2 = &(_3.1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 ++ _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 + // mir::Constant + // + span: $DIR/ref_deref_project.rs:5:6: 5:17 + // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) } -+ _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 - _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17 -- StorageDead(_3); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18 - StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18 - StorageDead(_1); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18 - _0 = const (); // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2 - return; // scope 0 at $DIR/ref_deref_project.rs:+2:2: +2:2 ++ _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 + _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 +- StorageDead(_3); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 + StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 + StorageDead(_1); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 + _0 = const (); // scope 0 at $DIR/ref_deref_project.rs:4:11: 6:2 + return; // scope 0 at $DIR/ref_deref_project.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff b/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff index 237a6f94aa7fd..80f461a4c02cf 100644 --- a/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff @@ -2,28 +2,28 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/reify_fn_ptr.rs:+0:11: +0:11 - let mut _1: *const fn(); // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:41 - let mut _2: usize; // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26 - let mut _3: fn(); // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17 + let mut _0: (); // return place in scope 0 at $DIR/reify_fn_ptr.rs:3:11: 3:11 + let mut _1: *const fn(); // in scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:41 + let mut _2: usize; // in scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26 + let mut _3: fn(); // in scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:17 scope 1 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:41 - StorageLive(_2); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26 - StorageLive(_3); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17 - _3 = main as fn() (Pointer(ReifyFnPointer)); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17 + StorageLive(_1); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:41 + StorageLive(_2); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26 + StorageLive(_3); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:17 + _3 = main as fn() (Pointer(ReifyFnPointer)); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:17 // mir::Constant // + span: $DIR/reify_fn_ptr.rs:4:13: 4:17 // + literal: Const { ty: fn() {main}, val: Value() } - _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26 - StorageDead(_3); // scope 0 at $DIR/reify_fn_ptr.rs:+1:25: +1:26 - _1 = move _2 as *const fn() (PointerFromExposedAddress); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:41 - StorageDead(_2); // scope 0 at $DIR/reify_fn_ptr.rs:+1:40: +1:41 - StorageDead(_1); // scope 0 at $DIR/reify_fn_ptr.rs:+1:41: +1:42 - nop; // scope 0 at $DIR/reify_fn_ptr.rs:+0:11: +2:2 - return; // scope 0 at $DIR/reify_fn_ptr.rs:+2:2: +2:2 + _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26 + StorageDead(_3); // scope 0 at $DIR/reify_fn_ptr.rs:4:25: 4:26 + _1 = move _2 as *const fn() (PointerFromExposedAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:41 + StorageDead(_2); // scope 0 at $DIR/reify_fn_ptr.rs:4:40: 4:41 + StorageDead(_1); // scope 0 at $DIR/reify_fn_ptr.rs:4:41: 4:42 + nop; // scope 0 at $DIR/reify_fn_ptr.rs:3:11: 5:2 + return; // scope 0 at $DIR/reify_fn_ptr.rs:5:2: 5:2 } } diff --git a/src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff index 7c4977996917e..1d9e4712d5a22 100644 --- a/src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff @@ -2,42 +2,42 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/repeat.rs:+0:11: +0:11 - let _1: u32; // in scope 0 at $DIR/repeat.rs:+1:9: +1:10 - let mut _2: u32; // in scope 0 at $DIR/repeat.rs:+1:18: +1:28 - let mut _3: [u32; 8]; // in scope 0 at $DIR/repeat.rs:+1:18: +1:25 - let _4: usize; // in scope 0 at $DIR/repeat.rs:+1:26: +1:27 - let mut _5: usize; // in scope 0 at $DIR/repeat.rs:+1:18: +1:28 - let mut _6: bool; // in scope 0 at $DIR/repeat.rs:+1:18: +1:28 + let mut _0: (); // return place in scope 0 at $DIR/repeat.rs:5:11: 5:11 + let _1: u32; // in scope 0 at $DIR/repeat.rs:6:9: 6:10 + let mut _2: u32; // in scope 0 at $DIR/repeat.rs:6:18: 6:28 + let mut _3: [u32; 8]; // in scope 0 at $DIR/repeat.rs:6:18: 6:25 + let _4: usize; // in scope 0 at $DIR/repeat.rs:6:26: 6:27 + let mut _5: usize; // in scope 0 at $DIR/repeat.rs:6:18: 6:28 + let mut _6: bool; // in scope 0 at $DIR/repeat.rs:6:18: 6:28 scope 1 { - debug x => _1; // in scope 1 at $DIR/repeat.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/repeat.rs:6:9: 6:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/repeat.rs:+1:9: +1:10 - StorageLive(_2); // scope 0 at $DIR/repeat.rs:+1:18: +1:28 - StorageLive(_3); // scope 0 at $DIR/repeat.rs:+1:18: +1:25 - _3 = [const 42_u32; 8]; // scope 0 at $DIR/repeat.rs:+1:18: +1:25 - StorageLive(_4); // scope 0 at $DIR/repeat.rs:+1:26: +1:27 - _4 = const 2_usize; // scope 0 at $DIR/repeat.rs:+1:26: +1:27 - _5 = const 8_usize; // scope 0 at $DIR/repeat.rs:+1:18: +1:28 -- _6 = Lt(_4, _5); // scope 0 at $DIR/repeat.rs:+1:18: +1:28 -- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:+1:18: +1:28 -+ _6 = const true; // scope 0 at $DIR/repeat.rs:+1:18: +1:28 -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:+1:18: +1:28 + StorageLive(_1); // scope 0 at $DIR/repeat.rs:6:9: 6:10 + StorageLive(_2); // scope 0 at $DIR/repeat.rs:6:18: 6:28 + StorageLive(_3); // scope 0 at $DIR/repeat.rs:6:18: 6:25 + _3 = [const 42_u32; 8]; // scope 0 at $DIR/repeat.rs:6:18: 6:25 + StorageLive(_4); // scope 0 at $DIR/repeat.rs:6:26: 6:27 + _4 = const 2_usize; // scope 0 at $DIR/repeat.rs:6:26: 6:27 + _5 = const 8_usize; // scope 0 at $DIR/repeat.rs:6:18: 6:28 +- _6 = Lt(_4, _5); // scope 0 at $DIR/repeat.rs:6:18: 6:28 +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 ++ _6 = const true; // scope 0 at $DIR/repeat.rs:6:18: 6:28 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 } bb1: { -- _2 = _3[_4]; // scope 0 at $DIR/repeat.rs:+1:18: +1:28 -- _1 = Add(move _2, const 0_u32); // scope 0 at $DIR/repeat.rs:+1:18: +1:32 -+ _2 = const 42_u32; // scope 0 at $DIR/repeat.rs:+1:18: +1:28 -+ _1 = const 42_u32; // scope 0 at $DIR/repeat.rs:+1:18: +1:32 - StorageDead(_2); // scope 0 at $DIR/repeat.rs:+1:31: +1:32 - StorageDead(_4); // scope 0 at $DIR/repeat.rs:+1:32: +1:33 - StorageDead(_3); // scope 0 at $DIR/repeat.rs:+1:32: +1:33 - nop; // scope 0 at $DIR/repeat.rs:+0:11: +2:2 - StorageDead(_1); // scope 0 at $DIR/repeat.rs:+2:1: +2:2 - return; // scope 0 at $DIR/repeat.rs:+2:2: +2:2 +- _2 = _3[_4]; // scope 0 at $DIR/repeat.rs:6:18: 6:28 +- _1 = Add(move _2, const 0_u32); // scope 0 at $DIR/repeat.rs:6:18: 6:32 ++ _2 = const 42_u32; // scope 0 at $DIR/repeat.rs:6:18: 6:28 ++ _1 = const 42_u32; // scope 0 at $DIR/repeat.rs:6:18: 6:32 + StorageDead(_2); // scope 0 at $DIR/repeat.rs:6:31: 6:32 + StorageDead(_4); // scope 0 at $DIR/repeat.rs:6:32: 6:33 + StorageDead(_3); // scope 0 at $DIR/repeat.rs:6:32: 6:33 + nop; // scope 0 at $DIR/repeat.rs:5:11: 7:2 + StorageDead(_1); // scope 0 at $DIR/repeat.rs:7:1: 7:2 + return; // scope 0 at $DIR/repeat.rs:7:2: 7:2 } } diff --git a/src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff index 7c4977996917e..1d9e4712d5a22 100644 --- a/src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff @@ -2,42 +2,42 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/repeat.rs:+0:11: +0:11 - let _1: u32; // in scope 0 at $DIR/repeat.rs:+1:9: +1:10 - let mut _2: u32; // in scope 0 at $DIR/repeat.rs:+1:18: +1:28 - let mut _3: [u32; 8]; // in scope 0 at $DIR/repeat.rs:+1:18: +1:25 - let _4: usize; // in scope 0 at $DIR/repeat.rs:+1:26: +1:27 - let mut _5: usize; // in scope 0 at $DIR/repeat.rs:+1:18: +1:28 - let mut _6: bool; // in scope 0 at $DIR/repeat.rs:+1:18: +1:28 + let mut _0: (); // return place in scope 0 at $DIR/repeat.rs:5:11: 5:11 + let _1: u32; // in scope 0 at $DIR/repeat.rs:6:9: 6:10 + let mut _2: u32; // in scope 0 at $DIR/repeat.rs:6:18: 6:28 + let mut _3: [u32; 8]; // in scope 0 at $DIR/repeat.rs:6:18: 6:25 + let _4: usize; // in scope 0 at $DIR/repeat.rs:6:26: 6:27 + let mut _5: usize; // in scope 0 at $DIR/repeat.rs:6:18: 6:28 + let mut _6: bool; // in scope 0 at $DIR/repeat.rs:6:18: 6:28 scope 1 { - debug x => _1; // in scope 1 at $DIR/repeat.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/repeat.rs:6:9: 6:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/repeat.rs:+1:9: +1:10 - StorageLive(_2); // scope 0 at $DIR/repeat.rs:+1:18: +1:28 - StorageLive(_3); // scope 0 at $DIR/repeat.rs:+1:18: +1:25 - _3 = [const 42_u32; 8]; // scope 0 at $DIR/repeat.rs:+1:18: +1:25 - StorageLive(_4); // scope 0 at $DIR/repeat.rs:+1:26: +1:27 - _4 = const 2_usize; // scope 0 at $DIR/repeat.rs:+1:26: +1:27 - _5 = const 8_usize; // scope 0 at $DIR/repeat.rs:+1:18: +1:28 -- _6 = Lt(_4, _5); // scope 0 at $DIR/repeat.rs:+1:18: +1:28 -- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:+1:18: +1:28 -+ _6 = const true; // scope 0 at $DIR/repeat.rs:+1:18: +1:28 -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:+1:18: +1:28 + StorageLive(_1); // scope 0 at $DIR/repeat.rs:6:9: 6:10 + StorageLive(_2); // scope 0 at $DIR/repeat.rs:6:18: 6:28 + StorageLive(_3); // scope 0 at $DIR/repeat.rs:6:18: 6:25 + _3 = [const 42_u32; 8]; // scope 0 at $DIR/repeat.rs:6:18: 6:25 + StorageLive(_4); // scope 0 at $DIR/repeat.rs:6:26: 6:27 + _4 = const 2_usize; // scope 0 at $DIR/repeat.rs:6:26: 6:27 + _5 = const 8_usize; // scope 0 at $DIR/repeat.rs:6:18: 6:28 +- _6 = Lt(_4, _5); // scope 0 at $DIR/repeat.rs:6:18: 6:28 +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 ++ _6 = const true; // scope 0 at $DIR/repeat.rs:6:18: 6:28 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 } bb1: { -- _2 = _3[_4]; // scope 0 at $DIR/repeat.rs:+1:18: +1:28 -- _1 = Add(move _2, const 0_u32); // scope 0 at $DIR/repeat.rs:+1:18: +1:32 -+ _2 = const 42_u32; // scope 0 at $DIR/repeat.rs:+1:18: +1:28 -+ _1 = const 42_u32; // scope 0 at $DIR/repeat.rs:+1:18: +1:32 - StorageDead(_2); // scope 0 at $DIR/repeat.rs:+1:31: +1:32 - StorageDead(_4); // scope 0 at $DIR/repeat.rs:+1:32: +1:33 - StorageDead(_3); // scope 0 at $DIR/repeat.rs:+1:32: +1:33 - nop; // scope 0 at $DIR/repeat.rs:+0:11: +2:2 - StorageDead(_1); // scope 0 at $DIR/repeat.rs:+2:1: +2:2 - return; // scope 0 at $DIR/repeat.rs:+2:2: +2:2 +- _2 = _3[_4]; // scope 0 at $DIR/repeat.rs:6:18: 6:28 +- _1 = Add(move _2, const 0_u32); // scope 0 at $DIR/repeat.rs:6:18: 6:32 ++ _2 = const 42_u32; // scope 0 at $DIR/repeat.rs:6:18: 6:28 ++ _1 = const 42_u32; // scope 0 at $DIR/repeat.rs:6:18: 6:32 + StorageDead(_2); // scope 0 at $DIR/repeat.rs:6:31: 6:32 + StorageDead(_4); // scope 0 at $DIR/repeat.rs:6:32: 6:33 + StorageDead(_3); // scope 0 at $DIR/repeat.rs:6:32: 6:33 + nop; // scope 0 at $DIR/repeat.rs:5:11: 7:2 + StorageDead(_1); // scope 0 at $DIR/repeat.rs:7:1: 7:2 + return; // scope 0 at $DIR/repeat.rs:7:2: 7:2 } } diff --git a/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff b/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff index 5ebd8a52079d7..c6ac8d6fb139d 100644 --- a/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff +++ b/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff @@ -2,20 +2,20 @@ + // MIR for `add` after ConstProp fn add() -> u32 { - let mut _0: u32; // return place in scope 0 at $DIR/return_place.rs:+0:13: +0:16 - let mut _1: (u32, bool); // in scope 0 at $DIR/return_place.rs:+1:5: +1:10 + let mut _0: u32; // return place in scope 0 at $DIR/return_place.rs:5:13: 5:16 + let mut _1: (u32, bool); // in scope 0 at $DIR/return_place.rs:6:5: 6:10 bb0: { -- _1 = CheckedAdd(const 2_u32, const 2_u32); // scope 0 at $DIR/return_place.rs:+1:5: +1:10 -- assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:+1:5: +1:10 -+ _1 = const (4_u32, false); // scope 0 at $DIR/return_place.rs:+1:5: +1:10 -+ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:+1:5: +1:10 +- _1 = CheckedAdd(const 2_u32, const 2_u32); // scope 0 at $DIR/return_place.rs:6:5: 6:10 +- assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10 ++ _1 = const (4_u32, false); // scope 0 at $DIR/return_place.rs:6:5: 6:10 ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10 } bb1: { -- _0 = move (_1.0: u32); // scope 0 at $DIR/return_place.rs:+1:5: +1:10 -+ _0 = const 4_u32; // scope 0 at $DIR/return_place.rs:+1:5: +1:10 - return; // scope 0 at $DIR/return_place.rs:+2:2: +2:2 +- _0 = move (_1.0: u32); // scope 0 at $DIR/return_place.rs:6:5: 6:10 ++ _0 = const 4_u32; // scope 0 at $DIR/return_place.rs:6:5: 6:10 + return; // scope 0 at $DIR/return_place.rs:7:2: 7:2 } } diff --git a/src/test/mir-opt/const_prop/return_place.add.PreCodegen.before.mir b/src/test/mir-opt/const_prop/return_place.add.PreCodegen.before.mir index ececd9942838d..e6dd096e1c0e3 100644 --- a/src/test/mir-opt/const_prop/return_place.add.PreCodegen.before.mir +++ b/src/test/mir-opt/const_prop/return_place.add.PreCodegen.before.mir @@ -1,10 +1,10 @@ // MIR for `add` before PreCodegen fn add() -> u32 { - let mut _0: u32; // return place in scope 0 at $DIR/return_place.rs:+0:13: +0:16 + let mut _0: u32; // return place in scope 0 at $DIR/return_place.rs:5:13: 5:16 bb0: { - _0 = const 4_u32; // scope 0 at $DIR/return_place.rs:+1:5: +1:10 - return; // scope 0 at $DIR/return_place.rs:+2:2: +2:2 + _0 = const 4_u32; // scope 0 at $DIR/return_place.rs:6:5: 6:10 + return; // scope 0 at $DIR/return_place.rs:7:2: 7:2 } } diff --git a/src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff b/src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff index 5920937e0fd4f..6343ee80a2562 100644 --- a/src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff @@ -2,34 +2,34 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/scalar_literal_propagation.rs:+0:11: +0:11 - let _1: u32; // in scope 0 at $DIR/scalar_literal_propagation.rs:+1:9: +1:10 - let _2: (); // in scope 0 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15 - let mut _3: u32; // in scope 0 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14 + let mut _0: (); // return place in scope 0 at $DIR/scalar_literal_propagation.rs:2:11: 2:11 + let _1: u32; // in scope 0 at $DIR/scalar_literal_propagation.rs:3:9: 3:10 + let _2: (); // in scope 0 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 + let mut _3: u32; // in scope 0 at $DIR/scalar_literal_propagation.rs:4:13: 4:14 scope 1 { - debug x => _1; // in scope 1 at $DIR/scalar_literal_propagation.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/scalar_literal_propagation.rs:3:9: 3:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/scalar_literal_propagation.rs:+1:9: +1:10 - _1 = const 1_u32; // scope 0 at $DIR/scalar_literal_propagation.rs:+1:13: +1:14 - StorageLive(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15 - StorageLive(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14 -- _3 = _1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14 -- _2 = consume(move _3) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15 -+ _3 = const 1_u32; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14 -+ _2 = consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15 + StorageLive(_1); // scope 0 at $DIR/scalar_literal_propagation.rs:3:9: 3:10 + _1 = const 1_u32; // scope 0 at $DIR/scalar_literal_propagation.rs:3:13: 3:14 + StorageLive(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 + StorageLive(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14 +- _3 = _1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14 +- _2 = consume(move _3) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 ++ _3 = const 1_u32; // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14 ++ _2 = consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 // mir::Constant // + span: $DIR/scalar_literal_propagation.rs:4:5: 4:12 // + literal: Const { ty: fn(u32) {consume}, val: Value() } } bb1: { - StorageDead(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:14: +2:15 - StorageDead(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:15: +2:16 - nop; // scope 0 at $DIR/scalar_literal_propagation.rs:+0:11: +3:2 - StorageDead(_1); // scope 0 at $DIR/scalar_literal_propagation.rs:+3:1: +3:2 - return; // scope 0 at $DIR/scalar_literal_propagation.rs:+3:2: +3:2 + StorageDead(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:4:14: 4:15 + StorageDead(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:4:15: 4:16 + nop; // scope 0 at $DIR/scalar_literal_propagation.rs:2:11: 5:2 + StorageDead(_1); // scope 0 at $DIR/scalar_literal_propagation.rs:5:1: 5:2 + return; // scope 0 at $DIR/scalar_literal_propagation.rs:5:2: 5:2 } } diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff index 0ebfbca21391f..5366d233505d2 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff @@ -2,52 +2,52 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/slice_len.rs:+0:11: +0:11 - let _1: u32; // in scope 0 at $DIR/slice_len.rs:+1:5: +1:33 - let mut _2: &[u32]; // in scope 0 at $DIR/slice_len.rs:+1:5: +1:30 - let mut _3: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - let _4: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - let _5: [u32; 3]; // in scope 0 at $DIR/slice_len.rs:+1:7: +1:19 - let _6: usize; // in scope 0 at $DIR/slice_len.rs:+1:31: +1:32 - let mut _7: usize; // in scope 0 at $DIR/slice_len.rs:+1:5: +1:33 - let mut _8: bool; // in scope 0 at $DIR/slice_len.rs:+1:5: +1:33 - let mut _9: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - let mut _10: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:+1:6: +1:19 + let mut _0: (); // return place in scope 0 at $DIR/slice_len.rs:4:11: 4:11 + let _1: u32; // in scope 0 at $DIR/slice_len.rs:5:5: 5:33 + let mut _2: &[u32]; // in scope 0 at $DIR/slice_len.rs:5:5: 5:30 + let mut _3: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:6: 5:19 + let _4: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:6: 5:19 + let _5: [u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:7: 5:19 + let _6: usize; // in scope 0 at $DIR/slice_len.rs:5:31: 5:32 + let mut _7: usize; // in scope 0 at $DIR/slice_len.rs:5:5: 5:33 + let mut _8: bool; // in scope 0 at $DIR/slice_len.rs:5:5: 5:33 + let mut _9: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:6: 5:19 + let mut _10: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:6: 5:19 bb0: { - StorageLive(_1); // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 - StorageLive(_2); // scope 0 at $DIR/slice_len.rs:+1:5: +1:30 - StorageLive(_3); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - StorageLive(_4); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - _9 = const main::promoted[0]; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 + StorageLive(_1); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + StorageLive(_2); // scope 0 at $DIR/slice_len.rs:5:5: 5:30 + StorageLive(_3); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + StorageLive(_4); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + _9 = const main::promoted[0]; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 // mir::Constant // + span: $DIR/slice_len.rs:5:6: 5:19 // + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) } - _4 = _9; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - _3 = _4; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - StorageLive(_10); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - _10 = _3; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - StorageDead(_3); // scope 0 at $DIR/slice_len.rs:+1:18: +1:19 - StorageLive(_6); // scope 0 at $DIR/slice_len.rs:+1:31: +1:32 - _6 = const 1_usize; // scope 0 at $DIR/slice_len.rs:+1:31: +1:32 - _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 - StorageDead(_10); // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 -- _8 = Lt(_6, _7); // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 -- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 -+ _8 = const true; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 + _4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + _3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + StorageLive(_10); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + _10 = _3; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + StorageDead(_3); // scope 0 at $DIR/slice_len.rs:5:18: 5:19 + StorageLive(_6); // scope 0 at $DIR/slice_len.rs:5:31: 5:32 + _6 = const 1_usize; // scope 0 at $DIR/slice_len.rs:5:31: 5:32 + _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + StorageDead(_10); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 +- _8 = Lt(_6, _7); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 ++ _8 = const true; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 } bb1: { -- _1 = (*_2)[_6]; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 -+ _1 = const 2_u32; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 - StorageDead(_6); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 - StorageDead(_4); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 - StorageDead(_2); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 - StorageDead(_1); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 - nop; // scope 0 at $DIR/slice_len.rs:+0:11: +2:2 - return; // scope 0 at $DIR/slice_len.rs:+2:2: +2:2 +- _1 = (*_2)[_6]; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 ++ _1 = const 2_u32; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + StorageDead(_6); // scope 0 at $DIR/slice_len.rs:5:33: 5:34 + StorageDead(_4); // scope 0 at $DIR/slice_len.rs:5:33: 5:34 + StorageDead(_2); // scope 0 at $DIR/slice_len.rs:5:33: 5:34 + StorageDead(_1); // scope 0 at $DIR/slice_len.rs:5:33: 5:34 + nop; // scope 0 at $DIR/slice_len.rs:4:11: 6:2 + return; // scope 0 at $DIR/slice_len.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff index 0ebfbca21391f..5366d233505d2 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff @@ -2,52 +2,52 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/slice_len.rs:+0:11: +0:11 - let _1: u32; // in scope 0 at $DIR/slice_len.rs:+1:5: +1:33 - let mut _2: &[u32]; // in scope 0 at $DIR/slice_len.rs:+1:5: +1:30 - let mut _3: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - let _4: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - let _5: [u32; 3]; // in scope 0 at $DIR/slice_len.rs:+1:7: +1:19 - let _6: usize; // in scope 0 at $DIR/slice_len.rs:+1:31: +1:32 - let mut _7: usize; // in scope 0 at $DIR/slice_len.rs:+1:5: +1:33 - let mut _8: bool; // in scope 0 at $DIR/slice_len.rs:+1:5: +1:33 - let mut _9: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - let mut _10: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:+1:6: +1:19 + let mut _0: (); // return place in scope 0 at $DIR/slice_len.rs:4:11: 4:11 + let _1: u32; // in scope 0 at $DIR/slice_len.rs:5:5: 5:33 + let mut _2: &[u32]; // in scope 0 at $DIR/slice_len.rs:5:5: 5:30 + let mut _3: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:6: 5:19 + let _4: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:6: 5:19 + let _5: [u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:7: 5:19 + let _6: usize; // in scope 0 at $DIR/slice_len.rs:5:31: 5:32 + let mut _7: usize; // in scope 0 at $DIR/slice_len.rs:5:5: 5:33 + let mut _8: bool; // in scope 0 at $DIR/slice_len.rs:5:5: 5:33 + let mut _9: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:6: 5:19 + let mut _10: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:6: 5:19 bb0: { - StorageLive(_1); // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 - StorageLive(_2); // scope 0 at $DIR/slice_len.rs:+1:5: +1:30 - StorageLive(_3); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - StorageLive(_4); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - _9 = const main::promoted[0]; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 + StorageLive(_1); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + StorageLive(_2); // scope 0 at $DIR/slice_len.rs:5:5: 5:30 + StorageLive(_3); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + StorageLive(_4); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + _9 = const main::promoted[0]; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 // mir::Constant // + span: $DIR/slice_len.rs:5:6: 5:19 // + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) } - _4 = _9; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - _3 = _4; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - StorageLive(_10); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - _10 = _3; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 - StorageDead(_3); // scope 0 at $DIR/slice_len.rs:+1:18: +1:19 - StorageLive(_6); // scope 0 at $DIR/slice_len.rs:+1:31: +1:32 - _6 = const 1_usize; // scope 0 at $DIR/slice_len.rs:+1:31: +1:32 - _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 - StorageDead(_10); // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 -- _8 = Lt(_6, _7); // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 -- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 -+ _8 = const true; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 + _4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + _3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + StorageLive(_10); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + _10 = _3; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + StorageDead(_3); // scope 0 at $DIR/slice_len.rs:5:18: 5:19 + StorageLive(_6); // scope 0 at $DIR/slice_len.rs:5:31: 5:32 + _6 = const 1_usize; // scope 0 at $DIR/slice_len.rs:5:31: 5:32 + _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + StorageDead(_10); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 +- _8 = Lt(_6, _7); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 ++ _8 = const true; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 } bb1: { -- _1 = (*_2)[_6]; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 -+ _1 = const 2_u32; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 - StorageDead(_6); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 - StorageDead(_4); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 - StorageDead(_2); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 - StorageDead(_1); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 - nop; // scope 0 at $DIR/slice_len.rs:+0:11: +2:2 - return; // scope 0 at $DIR/slice_len.rs:+2:2: +2:2 +- _1 = (*_2)[_6]; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 ++ _1 = const 2_u32; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + StorageDead(_6); // scope 0 at $DIR/slice_len.rs:5:33: 5:34 + StorageDead(_4); // scope 0 at $DIR/slice_len.rs:5:33: 5:34 + StorageDead(_2); // scope 0 at $DIR/slice_len.rs:5:33: 5:34 + StorageDead(_1); // scope 0 at $DIR/slice_len.rs:5:33: 5:34 + nop; // scope 0 at $DIR/slice_len.rs:4:11: 6:2 + return; // scope 0 at $DIR/slice_len.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff b/src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff index 9d7c2784d8b2c..5dfa05a46d377 100644 --- a/src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff @@ -2,33 +2,33 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/switch_int.rs:+0:11: +0:11 - let mut _1: i32; // in scope 0 at $DIR/switch_int.rs:+1:11: +1:12 + let mut _0: (); // return place in scope 0 at $DIR/switch_int.rs:6:11: 6:11 + let mut _1: i32; // in scope 0 at $DIR/switch_int.rs:7:11: 7:12 bb0: { - StorageLive(_1); // scope 0 at $DIR/switch_int.rs:+1:11: +1:12 - _1 = const 1_i32; // scope 0 at $DIR/switch_int.rs:+1:11: +1:12 -- switchInt(_1) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:+1:5: +1:12 -+ switchInt(const 1_i32) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:+1:5: +1:12 + StorageLive(_1); // scope 0 at $DIR/switch_int.rs:7:11: 7:12 + _1 = const 1_i32; // scope 0 at $DIR/switch_int.rs:7:11: 7:12 +- switchInt(_1) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:7:5: 7:12 ++ switchInt(const 1_i32) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:7:5: 7:12 } bb1: { - _0 = foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:+3:14: +3:21 + _0 = foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21 // mir::Constant // + span: $DIR/switch_int.rs:9:14: 9:17 // + literal: Const { ty: fn(i32) {foo}, val: Value() } } bb2: { - _0 = foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:+2:14: +2:20 + _0 = foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20 // mir::Constant // + span: $DIR/switch_int.rs:8:14: 8:17 // + literal: Const { ty: fn(i32) {foo}, val: Value() } } bb3: { - StorageDead(_1); // scope 0 at $DIR/switch_int.rs:+5:1: +5:2 - return; // scope 0 at $DIR/switch_int.rs:+5:2: +5:2 + StorageDead(_1); // scope 0 at $DIR/switch_int.rs:11:1: 11:2 + return; // scope 0 at $DIR/switch_int.rs:11:2: 11:2 } } diff --git a/src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff b/src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff index 74f9eafe42061..704b4bbe018d5 100644 --- a/src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff +++ b/src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff @@ -2,33 +2,33 @@ + // MIR for `main` after SimplifyConstCondition-after-const-prop fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/switch_int.rs:+0:11: +0:11 - let mut _1: i32; // in scope 0 at $DIR/switch_int.rs:+1:11: +1:12 + let mut _0: (); // return place in scope 0 at $DIR/switch_int.rs:6:11: 6:11 + let mut _1: i32; // in scope 0 at $DIR/switch_int.rs:7:11: 7:12 bb0: { - StorageLive(_1); // scope 0 at $DIR/switch_int.rs:+1:11: +1:12 - _1 = const 1_i32; // scope 0 at $DIR/switch_int.rs:+1:11: +1:12 -- switchInt(const 1_i32) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:+1:5: +1:12 -+ goto -> bb2; // scope 0 at $DIR/switch_int.rs:+1:5: +1:12 + StorageLive(_1); // scope 0 at $DIR/switch_int.rs:7:11: 7:12 + _1 = const 1_i32; // scope 0 at $DIR/switch_int.rs:7:11: 7:12 +- switchInt(const 1_i32) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:7:5: 7:12 ++ goto -> bb2; // scope 0 at $DIR/switch_int.rs:7:5: 7:12 } bb1: { - _0 = foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:+3:14: +3:21 + _0 = foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21 // mir::Constant // + span: $DIR/switch_int.rs:9:14: 9:17 // + literal: Const { ty: fn(i32) {foo}, val: Value() } } bb2: { - _0 = foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:+2:14: +2:20 + _0 = foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20 // mir::Constant // + span: $DIR/switch_int.rs:8:14: 8:17 // + literal: Const { ty: fn(i32) {foo}, val: Value() } } bb3: { - StorageDead(_1); // scope 0 at $DIR/switch_int.rs:+5:1: +5:2 - return; // scope 0 at $DIR/switch_int.rs:+5:2: +5:2 + StorageDead(_1); // scope 0 at $DIR/switch_int.rs:11:1: 11:2 + return; // scope 0 at $DIR/switch_int.rs:11:2: 11:2 } } diff --git a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff index a0603c60dc79c..adb182314ac5e 100644 --- a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff @@ -2,35 +2,35 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/tuple_literal_propagation.rs:+0:11: +0:11 - let _1: (u32, u32); // in scope 0 at $DIR/tuple_literal_propagation.rs:+1:9: +1:10 - let _2: (); // in scope 0 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15 - let mut _3: (u32, u32); // in scope 0 at $DIR/tuple_literal_propagation.rs:+3:13: +3:14 + let mut _0: (); // return place in scope 0 at $DIR/tuple_literal_propagation.rs:2:11: 2:11 + let _1: (u32, u32); // in scope 0 at $DIR/tuple_literal_propagation.rs:3:9: 3:10 + let _2: (); // in scope 0 at $DIR/tuple_literal_propagation.rs:5:5: 5:15 + let mut _3: (u32, u32); // in scope 0 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 scope 1 { - debug x => _1; // in scope 1 at $DIR/tuple_literal_propagation.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/tuple_literal_propagation.rs:3:9: 3:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/tuple_literal_propagation.rs:+1:9: +1:10 - Deinit(_1); // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19 - (_1.0: u32) = const 1_u32; // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19 - (_1.1: u32) = const 2_u32; // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19 - StorageLive(_2); // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15 - StorageLive(_3); // scope 1 at $DIR/tuple_literal_propagation.rs:+3:13: +3:14 -- _3 = _1; // scope 1 at $DIR/tuple_literal_propagation.rs:+3:13: +3:14 -+ _3 = const (1_u32, 2_u32); // scope 1 at $DIR/tuple_literal_propagation.rs:+3:13: +3:14 - _2 = consume(move _3) -> bb1; // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15 + StorageLive(_1); // scope 0 at $DIR/tuple_literal_propagation.rs:3:9: 3:10 + Deinit(_1); // scope 0 at $DIR/tuple_literal_propagation.rs:3:13: 3:19 + (_1.0: u32) = const 1_u32; // scope 0 at $DIR/tuple_literal_propagation.rs:3:13: 3:19 + (_1.1: u32) = const 2_u32; // scope 0 at $DIR/tuple_literal_propagation.rs:3:13: 3:19 + StorageLive(_2); // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15 + StorageLive(_3); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 +- _3 = _1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 ++ _3 = const (1_u32, 2_u32); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 + _2 = consume(move _3) -> bb1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15 // mir::Constant // + span: $DIR/tuple_literal_propagation.rs:5:5: 5:12 // + literal: Const { ty: fn((u32, u32)) {consume}, val: Value() } } bb1: { - StorageDead(_3); // scope 1 at $DIR/tuple_literal_propagation.rs:+3:14: +3:15 - StorageDead(_2); // scope 1 at $DIR/tuple_literal_propagation.rs:+3:15: +3:16 - nop; // scope 0 at $DIR/tuple_literal_propagation.rs:+0:11: +4:2 - StorageDead(_1); // scope 0 at $DIR/tuple_literal_propagation.rs:+4:1: +4:2 - return; // scope 0 at $DIR/tuple_literal_propagation.rs:+4:2: +4:2 + StorageDead(_3); // scope 1 at $DIR/tuple_literal_propagation.rs:5:14: 5:15 + StorageDead(_2); // scope 1 at $DIR/tuple_literal_propagation.rs:5:15: 5:16 + nop; // scope 0 at $DIR/tuple_literal_propagation.rs:2:11: 6:2 + StorageDead(_1); // scope 0 at $DIR/tuple_literal_propagation.rs:6:1: 6:2 + return; // scope 0 at $DIR/tuple_literal_propagation.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff b/src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff index 459da2e335851..dcc4368694c9f 100644 --- a/src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff +++ b/src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff @@ -2,41 +2,41 @@ + // MIR for `bar` after ConstProp fn bar() -> () { - let mut _0: (); // return place in scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +0:10 - let mut _1: (i32,); // in scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14 - let _2: (); // in scope 0 at $DIR/const_prop_miscompile.rs:+2:5: +4:6 - let mut _3: *mut i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+3:10: +3:22 - let mut _5: i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+5:13: +5:20 + let mut _0: (); // return place in scope 0 at $DIR/const_prop_miscompile.rs:11:10: 11:10 + let mut _1: (i32,); // in scope 0 at $DIR/const_prop_miscompile.rs:12:9: 12:14 + let _2: (); // in scope 0 at $DIR/const_prop_miscompile.rs:13:5: 15:6 + let mut _3: *mut i32; // in scope 0 at $DIR/const_prop_miscompile.rs:14:10: 14:22 + let mut _5: i32; // in scope 0 at $DIR/const_prop_miscompile.rs:16:13: 16:20 scope 1 { - debug v => _1; // in scope 1 at $DIR/const_prop_miscompile.rs:+1:9: +1:14 - let _4: bool; // in scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10 + debug v => _1; // in scope 1 at $DIR/const_prop_miscompile.rs:12:9: 12:14 + let _4: bool; // in scope 1 at $DIR/const_prop_miscompile.rs:16:9: 16:10 scope 2 { } scope 3 { - debug y => _4; // in scope 3 at $DIR/const_prop_miscompile.rs:+5:9: +5:10 + debug y => _4; // in scope 3 at $DIR/const_prop_miscompile.rs:16:9: 16:10 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14 - Deinit(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21 - (_1.0: i32) = const 1_i32; // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21 - StorageLive(_2); // scope 1 at $DIR/const_prop_miscompile.rs:+2:5: +4:6 - StorageLive(_3); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22 - _3 = &raw mut (_1.0: i32); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22 - (*_3) = const 5_i32; // scope 2 at $DIR/const_prop_miscompile.rs:+3:9: +3:26 - StorageDead(_3); // scope 2 at $DIR/const_prop_miscompile.rs:+3:26: +3:27 - nop; // scope 2 at $DIR/const_prop_miscompile.rs:+2:5: +4:6 - StorageDead(_2); // scope 1 at $DIR/const_prop_miscompile.rs:+4:5: +4:6 - StorageLive(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10 - StorageLive(_5); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:20 - _5 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:15: +5:18 - _4 = Eq(move _5, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:25 - StorageDead(_5); // scope 1 at $DIR/const_prop_miscompile.rs:+5:24: +5:25 - nop; // scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +6:2 - StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+6:1: +6:2 - StorageDead(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+6:1: +6:2 - return; // scope 0 at $DIR/const_prop_miscompile.rs:+6:2: +6:2 + StorageLive(_1); // scope 0 at $DIR/const_prop_miscompile.rs:12:9: 12:14 + Deinit(_1); // scope 0 at $DIR/const_prop_miscompile.rs:12:17: 12:21 + (_1.0: i32) = const 1_i32; // scope 0 at $DIR/const_prop_miscompile.rs:12:17: 12:21 + StorageLive(_2); // scope 1 at $DIR/const_prop_miscompile.rs:13:5: 15:6 + StorageLive(_3); // scope 2 at $DIR/const_prop_miscompile.rs:14:10: 14:22 + _3 = &raw mut (_1.0: i32); // scope 2 at $DIR/const_prop_miscompile.rs:14:10: 14:22 + (*_3) = const 5_i32; // scope 2 at $DIR/const_prop_miscompile.rs:14:9: 14:26 + StorageDead(_3); // scope 2 at $DIR/const_prop_miscompile.rs:14:26: 14:27 + nop; // scope 2 at $DIR/const_prop_miscompile.rs:13:5: 15:6 + StorageDead(_2); // scope 1 at $DIR/const_prop_miscompile.rs:15:5: 15:6 + StorageLive(_4); // scope 1 at $DIR/const_prop_miscompile.rs:16:9: 16:10 + StorageLive(_5); // scope 1 at $DIR/const_prop_miscompile.rs:16:13: 16:20 + _5 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:16:15: 16:18 + _4 = Eq(move _5, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:16:13: 16:25 + StorageDead(_5); // scope 1 at $DIR/const_prop_miscompile.rs:16:24: 16:25 + nop; // scope 0 at $DIR/const_prop_miscompile.rs:11:10: 17:2 + StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:17:1: 17:2 + StorageDead(_1); // scope 0 at $DIR/const_prop_miscompile.rs:17:1: 17:2 + return; // scope 0 at $DIR/const_prop_miscompile.rs:17:2: 17:2 } } diff --git a/src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff b/src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff index e8bd98cf8cba1..08730da2f3d12 100644 --- a/src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff +++ b/src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff @@ -2,35 +2,35 @@ + // MIR for `foo` after ConstProp fn foo() -> () { - let mut _0: (); // return place in scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +0:10 - let mut _1: (i32,); // in scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14 - let mut _2: &mut i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+2:6: +2:14 - let mut _4: i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+3:13: +3:20 + let mut _0: (); // return place in scope 0 at $DIR/const_prop_miscompile.rs:4:10: 4:10 + let mut _1: (i32,); // in scope 0 at $DIR/const_prop_miscompile.rs:5:9: 5:14 + let mut _2: &mut i32; // in scope 0 at $DIR/const_prop_miscompile.rs:6:6: 6:14 + let mut _4: i32; // in scope 0 at $DIR/const_prop_miscompile.rs:7:13: 7:20 scope 1 { - debug u => _1; // in scope 1 at $DIR/const_prop_miscompile.rs:+1:9: +1:14 - let _3: bool; // in scope 1 at $DIR/const_prop_miscompile.rs:+3:9: +3:10 + debug u => _1; // in scope 1 at $DIR/const_prop_miscompile.rs:5:9: 5:14 + let _3: bool; // in scope 1 at $DIR/const_prop_miscompile.rs:7:9: 7:10 scope 2 { - debug y => _3; // in scope 2 at $DIR/const_prop_miscompile.rs:+3:9: +3:10 + debug y => _3; // in scope 2 at $DIR/const_prop_miscompile.rs:7:9: 7:10 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14 - Deinit(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21 - (_1.0: i32) = const 1_i32; // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21 - StorageLive(_2); // scope 1 at $DIR/const_prop_miscompile.rs:+2:6: +2:14 - _2 = &mut (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:+2:6: +2:14 - (*_2) = const 5_i32; // scope 1 at $DIR/const_prop_miscompile.rs:+2:5: +2:18 - StorageDead(_2); // scope 1 at $DIR/const_prop_miscompile.rs:+2:18: +2:19 - StorageLive(_3); // scope 1 at $DIR/const_prop_miscompile.rs:+3:9: +3:10 - StorageLive(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+3:13: +3:20 - _4 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:+3:15: +3:18 - _3 = Eq(move _4, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:+3:13: +3:25 - StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+3:24: +3:25 - nop; // scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +4:2 - StorageDead(_3); // scope 1 at $DIR/const_prop_miscompile.rs:+4:1: +4:2 - StorageDead(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+4:1: +4:2 - return; // scope 0 at $DIR/const_prop_miscompile.rs:+4:2: +4:2 + StorageLive(_1); // scope 0 at $DIR/const_prop_miscompile.rs:5:9: 5:14 + Deinit(_1); // scope 0 at $DIR/const_prop_miscompile.rs:5:17: 5:21 + (_1.0: i32) = const 1_i32; // scope 0 at $DIR/const_prop_miscompile.rs:5:17: 5:21 + StorageLive(_2); // scope 1 at $DIR/const_prop_miscompile.rs:6:6: 6:14 + _2 = &mut (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:6:6: 6:14 + (*_2) = const 5_i32; // scope 1 at $DIR/const_prop_miscompile.rs:6:5: 6:18 + StorageDead(_2); // scope 1 at $DIR/const_prop_miscompile.rs:6:18: 6:19 + StorageLive(_3); // scope 1 at $DIR/const_prop_miscompile.rs:7:9: 7:10 + StorageLive(_4); // scope 1 at $DIR/const_prop_miscompile.rs:7:13: 7:20 + _4 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:7:15: 7:18 + _3 = Eq(move _4, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:7:13: 7:25 + StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:7:24: 7:25 + nop; // scope 0 at $DIR/const_prop_miscompile.rs:4:10: 8:2 + StorageDead(_3); // scope 1 at $DIR/const_prop_miscompile.rs:8:1: 8:2 + StorageDead(_1); // scope 0 at $DIR/const_prop_miscompile.rs:8:1: 8:2 + return; // scope 0 at $DIR/const_prop_miscompile.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff b/src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff index 58dd788b6afca..5f8019ac975a3 100644 --- a/src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff +++ b/src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff @@ -2,74 +2,74 @@ + // MIR for `cycle` after DeadStoreElimination fn cycle(_1: i32, _2: i32, _3: i32) -> () { - debug x => _1; // in scope 0 at $DIR/cycle.rs:+0:10: +0:15 - debug y => _2; // in scope 0 at $DIR/cycle.rs:+0:22: +0:27 - debug z => _3; // in scope 0 at $DIR/cycle.rs:+0:34: +0:39 - let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:+0:46: +0:46 - let mut _4: (); // in scope 0 at $DIR/cycle.rs:+0:1: +9:2 - let mut _5: bool; // in scope 0 at $DIR/cycle.rs:+3:11: +3:17 - let _6: i32; // in scope 0 at $DIR/cycle.rs:+4:13: +4:17 - let mut _7: i32; // in scope 0 at $DIR/cycle.rs:+5:13: +5:14 - let mut _8: i32; // in scope 0 at $DIR/cycle.rs:+6:13: +6:14 - let mut _9: i32; // in scope 0 at $DIR/cycle.rs:+7:13: +7:17 - let mut _10: !; // in scope 0 at $DIR/cycle.rs:+3:5: +8:6 - let _11: (); // in scope 0 at $DIR/cycle.rs:+3:5: +8:6 - let mut _12: !; // in scope 0 at $DIR/cycle.rs:+3:5: +8:6 + debug x => _1; // in scope 0 at $DIR/cycle.rs:9:10: 9:15 + debug y => _2; // in scope 0 at $DIR/cycle.rs:9:22: 9:27 + debug z => _3; // in scope 0 at $DIR/cycle.rs:9:34: 9:39 + let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:9:46: 9:46 + let mut _4: (); // in scope 0 at $DIR/cycle.rs:9:1: 18:2 + let mut _5: bool; // in scope 0 at $DIR/cycle.rs:12:11: 12:17 + let _6: i32; // in scope 0 at $DIR/cycle.rs:13:13: 13:17 + let mut _7: i32; // in scope 0 at $DIR/cycle.rs:14:13: 14:14 + let mut _8: i32; // in scope 0 at $DIR/cycle.rs:15:13: 15:14 + let mut _9: i32; // in scope 0 at $DIR/cycle.rs:16:13: 16:17 + let mut _10: !; // in scope 0 at $DIR/cycle.rs:12:5: 17:6 + let _11: (); // in scope 0 at $DIR/cycle.rs:12:5: 17:6 + let mut _12: !; // in scope 0 at $DIR/cycle.rs:12:5: 17:6 scope 1 { - debug temp => _6; // in scope 1 at $DIR/cycle.rs:+4:13: +4:17 + debug temp => _6; // in scope 1 at $DIR/cycle.rs:13:13: 13:17 } bb0: { - goto -> bb1; // scope 0 at $DIR/cycle.rs:+3:5: +8:6 + goto -> bb1; // scope 0 at $DIR/cycle.rs:12:5: 17:6 } bb1: { - StorageLive(_5); // scope 0 at $DIR/cycle.rs:+3:11: +3:17 - _5 = cond() -> bb2; // scope 0 at $DIR/cycle.rs:+3:11: +3:17 + StorageLive(_5); // scope 0 at $DIR/cycle.rs:12:11: 12:17 + _5 = cond() -> bb2; // scope 0 at $DIR/cycle.rs:12:11: 12:17 // mir::Constant // + span: $DIR/cycle.rs:12:11: 12:15 // + literal: Const { ty: fn() -> bool {cond}, val: Value() } } bb2: { - switchInt(move _5) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/cycle.rs:+3:11: +3:17 + switchInt(move _5) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/cycle.rs:12:11: 12:17 } bb3: { - StorageLive(_6); // scope 0 at $DIR/cycle.rs:+4:13: +4:17 -- _6 = _3; // scope 0 at $DIR/cycle.rs:+4:20: +4:21 -+ nop; // scope 0 at $DIR/cycle.rs:+4:20: +4:21 - StorageLive(_7); // scope 1 at $DIR/cycle.rs:+5:13: +5:14 -- _7 = _2; // scope 1 at $DIR/cycle.rs:+5:13: +5:14 -- _3 = move _7; // scope 1 at $DIR/cycle.rs:+5:9: +5:14 -+ nop; // scope 1 at $DIR/cycle.rs:+5:13: +5:14 -+ nop; // scope 1 at $DIR/cycle.rs:+5:9: +5:14 - StorageDead(_7); // scope 1 at $DIR/cycle.rs:+5:13: +5:14 - StorageLive(_8); // scope 1 at $DIR/cycle.rs:+6:13: +6:14 -- _8 = _1; // scope 1 at $DIR/cycle.rs:+6:13: +6:14 -- _2 = move _8; // scope 1 at $DIR/cycle.rs:+6:9: +6:14 -+ nop; // scope 1 at $DIR/cycle.rs:+6:13: +6:14 -+ nop; // scope 1 at $DIR/cycle.rs:+6:9: +6:14 - StorageDead(_8); // scope 1 at $DIR/cycle.rs:+6:13: +6:14 - StorageLive(_9); // scope 1 at $DIR/cycle.rs:+7:13: +7:17 -- _9 = _6; // scope 1 at $DIR/cycle.rs:+7:13: +7:17 -- _1 = move _9; // scope 1 at $DIR/cycle.rs:+7:9: +7:17 -+ nop; // scope 1 at $DIR/cycle.rs:+7:13: +7:17 -+ nop; // scope 1 at $DIR/cycle.rs:+7:9: +7:17 - StorageDead(_9); // scope 1 at $DIR/cycle.rs:+7:16: +7:17 -- _4 = const (); // scope 0 at $DIR/cycle.rs:+3:18: +8:6 -+ nop; // scope 0 at $DIR/cycle.rs:+3:18: +8:6 - StorageDead(_6); // scope 0 at $DIR/cycle.rs:+8:5: +8:6 - StorageDead(_5); // scope 0 at $DIR/cycle.rs:+8:5: +8:6 - goto -> bb1; // scope 0 at $DIR/cycle.rs:+3:5: +8:6 + StorageLive(_6); // scope 0 at $DIR/cycle.rs:13:13: 13:17 +- _6 = _3; // scope 0 at $DIR/cycle.rs:13:20: 13:21 ++ nop; // scope 0 at $DIR/cycle.rs:13:20: 13:21 + StorageLive(_7); // scope 1 at $DIR/cycle.rs:14:13: 14:14 +- _7 = _2; // scope 1 at $DIR/cycle.rs:14:13: 14:14 +- _3 = move _7; // scope 1 at $DIR/cycle.rs:14:9: 14:14 ++ nop; // scope 1 at $DIR/cycle.rs:14:13: 14:14 ++ nop; // scope 1 at $DIR/cycle.rs:14:9: 14:14 + StorageDead(_7); // scope 1 at $DIR/cycle.rs:14:13: 14:14 + StorageLive(_8); // scope 1 at $DIR/cycle.rs:15:13: 15:14 +- _8 = _1; // scope 1 at $DIR/cycle.rs:15:13: 15:14 +- _2 = move _8; // scope 1 at $DIR/cycle.rs:15:9: 15:14 ++ nop; // scope 1 at $DIR/cycle.rs:15:13: 15:14 ++ nop; // scope 1 at $DIR/cycle.rs:15:9: 15:14 + StorageDead(_8); // scope 1 at $DIR/cycle.rs:15:13: 15:14 + StorageLive(_9); // scope 1 at $DIR/cycle.rs:16:13: 16:17 +- _9 = _6; // scope 1 at $DIR/cycle.rs:16:13: 16:17 +- _1 = move _9; // scope 1 at $DIR/cycle.rs:16:9: 16:17 ++ nop; // scope 1 at $DIR/cycle.rs:16:13: 16:17 ++ nop; // scope 1 at $DIR/cycle.rs:16:9: 16:17 + StorageDead(_9); // scope 1 at $DIR/cycle.rs:16:16: 16:17 +- _4 = const (); // scope 0 at $DIR/cycle.rs:12:18: 17:6 ++ nop; // scope 0 at $DIR/cycle.rs:12:18: 17:6 + StorageDead(_6); // scope 0 at $DIR/cycle.rs:17:5: 17:6 + StorageDead(_5); // scope 0 at $DIR/cycle.rs:17:5: 17:6 + goto -> bb1; // scope 0 at $DIR/cycle.rs:12:5: 17:6 } bb4: { - StorageLive(_11); // scope 0 at $DIR/cycle.rs:+3:5: +8:6 - _0 = const (); // scope 0 at $DIR/cycle.rs:+3:5: +8:6 - StorageDead(_11); // scope 0 at $DIR/cycle.rs:+8:5: +8:6 - StorageDead(_5); // scope 0 at $DIR/cycle.rs:+8:5: +8:6 - return; // scope 0 at $DIR/cycle.rs:+9:2: +9:2 + StorageLive(_11); // scope 0 at $DIR/cycle.rs:12:5: 17:6 + _0 = const (); // scope 0 at $DIR/cycle.rs:12:5: 17:6 + StorageDead(_11); // scope 0 at $DIR/cycle.rs:17:5: 17:6 + StorageDead(_5); // scope 0 at $DIR/cycle.rs:17:5: 17:6 + return; // scope 0 at $DIR/cycle.rs:18:2: 18:2 } } diff --git a/src/test/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff b/src/test/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff index 89f1846b45de8..2331f63ecdd42 100644 --- a/src/test/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff +++ b/src/test/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff @@ -2,34 +2,34 @@ + // MIR for `pointer_to_int` after DeadStoreElimination fn pointer_to_int(_1: *mut i32) -> () { - debug p => _1; // in scope 0 at $DIR/provenance_soundness.rs:+0:19: +0:20 - let mut _0: (); // return place in scope 0 at $DIR/provenance_soundness.rs:+0:32: +0:32 - let _2: usize; // in scope 0 at $DIR/provenance_soundness.rs:+1:9: +1:11 - let mut _3: *mut i32; // in scope 0 at $DIR/provenance_soundness.rs:+1:14: +1:15 - let mut _5: *mut i32; // in scope 0 at $DIR/provenance_soundness.rs:+2:14: +2:15 + debug p => _1; // in scope 0 at $DIR/provenance_soundness.rs:7:19: 7:20 + let mut _0: (); // return place in scope 0 at $DIR/provenance_soundness.rs:7:32: 7:32 + let _2: usize; // in scope 0 at $DIR/provenance_soundness.rs:8:9: 8:11 + let mut _3: *mut i32; // in scope 0 at $DIR/provenance_soundness.rs:8:14: 8:15 + let mut _5: *mut i32; // in scope 0 at $DIR/provenance_soundness.rs:9:14: 9:15 scope 1 { - debug _x => _2; // in scope 1 at $DIR/provenance_soundness.rs:+1:9: +1:11 - let _4: isize; // in scope 1 at $DIR/provenance_soundness.rs:+2:9: +2:11 + debug _x => _2; // in scope 1 at $DIR/provenance_soundness.rs:8:9: 8:11 + let _4: isize; // in scope 1 at $DIR/provenance_soundness.rs:9:9: 9:11 scope 2 { - debug _y => _4; // in scope 2 at $DIR/provenance_soundness.rs:+2:9: +2:11 + debug _y => _4; // in scope 2 at $DIR/provenance_soundness.rs:9:9: 9:11 } } bb0: { - StorageLive(_2); // scope 0 at $DIR/provenance_soundness.rs:+1:9: +1:11 - StorageLive(_3); // scope 0 at $DIR/provenance_soundness.rs:+1:14: +1:15 - _3 = _1; // scope 0 at $DIR/provenance_soundness.rs:+1:14: +1:15 - _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/provenance_soundness.rs:+1:14: +1:24 - StorageDead(_3); // scope 0 at $DIR/provenance_soundness.rs:+1:23: +1:24 - StorageLive(_4); // scope 1 at $DIR/provenance_soundness.rs:+2:9: +2:11 - StorageLive(_5); // scope 1 at $DIR/provenance_soundness.rs:+2:14: +2:15 - _5 = _1; // scope 1 at $DIR/provenance_soundness.rs:+2:14: +2:15 - _4 = move _5 as isize (PointerExposeAddress); // scope 1 at $DIR/provenance_soundness.rs:+2:14: +2:24 - StorageDead(_5); // scope 1 at $DIR/provenance_soundness.rs:+2:23: +2:24 - _0 = const (); // scope 0 at $DIR/provenance_soundness.rs:+0:32: +3:2 - StorageDead(_4); // scope 1 at $DIR/provenance_soundness.rs:+3:1: +3:2 - StorageDead(_2); // scope 0 at $DIR/provenance_soundness.rs:+3:1: +3:2 - return; // scope 0 at $DIR/provenance_soundness.rs:+3:2: +3:2 + StorageLive(_2); // scope 0 at $DIR/provenance_soundness.rs:8:9: 8:11 + StorageLive(_3); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:15 + _3 = _1; // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:15 + _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:24 + StorageDead(_3); // scope 0 at $DIR/provenance_soundness.rs:8:23: 8:24 + StorageLive(_4); // scope 1 at $DIR/provenance_soundness.rs:9:9: 9:11 + StorageLive(_5); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:15 + _5 = _1; // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:15 + _4 = move _5 as isize (PointerExposeAddress); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:24 + StorageDead(_5); // scope 1 at $DIR/provenance_soundness.rs:9:23: 9:24 + _0 = const (); // scope 0 at $DIR/provenance_soundness.rs:7:32: 10:2 + StorageDead(_4); // scope 1 at $DIR/provenance_soundness.rs:10:1: 10:2 + StorageDead(_2); // scope 0 at $DIR/provenance_soundness.rs:10:1: 10:2 + return; // scope 0 at $DIR/provenance_soundness.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/dead-store-elimination/provenance_soundness.retags.DeadStoreElimination.diff b/src/test/mir-opt/dead-store-elimination/provenance_soundness.retags.DeadStoreElimination.diff index 300f0d5dcaa98..0bfffb6dca3dc 100644 --- a/src/test/mir-opt/dead-store-elimination/provenance_soundness.retags.DeadStoreElimination.diff +++ b/src/test/mir-opt/dead-store-elimination/provenance_soundness.retags.DeadStoreElimination.diff @@ -2,13 +2,13 @@ + // MIR for `retags` after DeadStoreElimination fn retags(_1: &mut i32) -> () { - debug _r => _1; // in scope 0 at $DIR/provenance_soundness.rs:+0:11: +0:13 - let mut _0: (); // return place in scope 0 at $DIR/provenance_soundness.rs:+0:25: +0:25 + debug _r => _1; // in scope 0 at $DIR/provenance_soundness.rs:13:11: 13:13 + let mut _0: (); // return place in scope 0 at $DIR/provenance_soundness.rs:13:25: 13:25 bb0: { - Retag([fn entry] _1); // scope 0 at $DIR/provenance_soundness.rs:+0:1: +0:27 - _0 = const (); // scope 0 at $DIR/provenance_soundness.rs:+0:25: +0:27 - return; // scope 0 at $DIR/provenance_soundness.rs:+0:27: +0:27 + Retag([fn entry] _1); // scope 0 at $DIR/provenance_soundness.rs:13:1: 13:27 + _0 = const (); // scope 0 at $DIR/provenance_soundness.rs:13:25: 13:27 + return; // scope 0 at $DIR/provenance_soundness.rs:13:27: 13:27 } } diff --git a/src/test/mir-opt/deaggregator_test.bar.Deaggregator.diff b/src/test/mir-opt/deaggregator_test.bar.Deaggregator.diff index db136485a2115..69de05b309f84 100644 --- a/src/test/mir-opt/deaggregator_test.bar.Deaggregator.diff +++ b/src/test/mir-opt/deaggregator_test.bar.Deaggregator.diff @@ -2,20 +2,20 @@ + // MIR for `bar` after Deaggregator fn bar(_1: usize) -> Baz { - debug a => _1; // in scope 0 at $DIR/deaggregator_test.rs:+0:8: +0:9 - let mut _0: Baz; // return place in scope 0 at $DIR/deaggregator_test.rs:+0:21: +0:24 - let mut _2: usize; // in scope 0 at $DIR/deaggregator_test.rs:+1:14: +1:15 + debug a => _1; // in scope 0 at $DIR/deaggregator_test.rs:8:8: 8:9 + let mut _0: Baz; // return place in scope 0 at $DIR/deaggregator_test.rs:8:21: 8:24 + let mut _2: usize; // in scope 0 at $DIR/deaggregator_test.rs:9:14: 9:15 bb0: { - StorageLive(_2); // scope 0 at $DIR/deaggregator_test.rs:+1:14: +1:15 - _2 = _1; // scope 0 at $DIR/deaggregator_test.rs:+1:14: +1:15 -- _0 = Baz { x: move _2, y: const 0f32, z: const false }; // scope 0 at $DIR/deaggregator_test.rs:+1:5: +1:35 -+ Deinit(_0); // scope 0 at $DIR/deaggregator_test.rs:+1:5: +1:35 -+ (_0.0: usize) = move _2; // scope 0 at $DIR/deaggregator_test.rs:+1:5: +1:35 -+ (_0.1: f32) = const 0f32; // scope 0 at $DIR/deaggregator_test.rs:+1:5: +1:35 -+ (_0.2: bool) = const false; // scope 0 at $DIR/deaggregator_test.rs:+1:5: +1:35 - StorageDead(_2); // scope 0 at $DIR/deaggregator_test.rs:+1:34: +1:35 - return; // scope 0 at $DIR/deaggregator_test.rs:+2:2: +2:2 + StorageLive(_2); // scope 0 at $DIR/deaggregator_test.rs:9:14: 9:15 + _2 = _1; // scope 0 at $DIR/deaggregator_test.rs:9:14: 9:15 +- _0 = Baz { x: move _2, y: const 0f32, z: const false }; // scope 0 at $DIR/deaggregator_test.rs:9:5: 9:35 ++ Deinit(_0); // scope 0 at $DIR/deaggregator_test.rs:9:5: 9:35 ++ (_0.0: usize) = move _2; // scope 0 at $DIR/deaggregator_test.rs:9:5: 9:35 ++ (_0.1: f32) = const 0f32; // scope 0 at $DIR/deaggregator_test.rs:9:5: 9:35 ++ (_0.2: bool) = const false; // scope 0 at $DIR/deaggregator_test.rs:9:5: 9:35 + StorageDead(_2); // scope 0 at $DIR/deaggregator_test.rs:9:34: 9:35 + return; // scope 0 at $DIR/deaggregator_test.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/deaggregator_test_enum.bar.Deaggregator.diff b/src/test/mir-opt/deaggregator_test_enum.bar.Deaggregator.diff index f28c2b482af2d..b28f506a694c9 100644 --- a/src/test/mir-opt/deaggregator_test_enum.bar.Deaggregator.diff +++ b/src/test/mir-opt/deaggregator_test_enum.bar.Deaggregator.diff @@ -2,19 +2,19 @@ + // MIR for `bar` after Deaggregator fn bar(_1: usize) -> Baz { - debug a => _1; // in scope 0 at $DIR/deaggregator_test_enum.rs:+0:8: +0:9 - let mut _0: Baz; // return place in scope 0 at $DIR/deaggregator_test_enum.rs:+0:21: +0:24 - let mut _2: usize; // in scope 0 at $DIR/deaggregator_test_enum.rs:+1:19: +1:20 + debug a => _1; // in scope 0 at $DIR/deaggregator_test_enum.rs:7:8: 7:9 + let mut _0: Baz; // return place in scope 0 at $DIR/deaggregator_test_enum.rs:7:21: 7:24 + let mut _2: usize; // in scope 0 at $DIR/deaggregator_test_enum.rs:8:19: 8:20 bb0: { - StorageLive(_2); // scope 0 at $DIR/deaggregator_test_enum.rs:+1:19: +1:20 - _2 = _1; // scope 0 at $DIR/deaggregator_test_enum.rs:+1:19: +1:20 -- _0 = Baz::Foo { x: move _2 }; // scope 0 at $DIR/deaggregator_test_enum.rs:+1:5: +1:22 -+ Deinit(_0); // scope 0 at $DIR/deaggregator_test_enum.rs:+1:5: +1:22 -+ ((_0 as Foo).0: usize) = move _2; // scope 0 at $DIR/deaggregator_test_enum.rs:+1:5: +1:22 -+ discriminant(_0) = 1; // scope 0 at $DIR/deaggregator_test_enum.rs:+1:5: +1:22 - StorageDead(_2); // scope 0 at $DIR/deaggregator_test_enum.rs:+1:21: +1:22 - return; // scope 0 at $DIR/deaggregator_test_enum.rs:+2:2: +2:2 + StorageLive(_2); // scope 0 at $DIR/deaggregator_test_enum.rs:8:19: 8:20 + _2 = _1; // scope 0 at $DIR/deaggregator_test_enum.rs:8:19: 8:20 +- _0 = Baz::Foo { x: move _2 }; // scope 0 at $DIR/deaggregator_test_enum.rs:8:5: 8:22 ++ Deinit(_0); // scope 0 at $DIR/deaggregator_test_enum.rs:8:5: 8:22 ++ ((_0 as Foo).0: usize) = move _2; // scope 0 at $DIR/deaggregator_test_enum.rs:8:5: 8:22 ++ discriminant(_0) = 1; // scope 0 at $DIR/deaggregator_test_enum.rs:8:5: 8:22 + StorageDead(_2); // scope 0 at $DIR/deaggregator_test_enum.rs:8:21: 8:22 + return; // scope 0 at $DIR/deaggregator_test_enum.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/deaggregator_test_enum_2.test1.Deaggregator.diff b/src/test/mir-opt/deaggregator_test_enum_2.test1.Deaggregator.diff index fb18089e040f0..5cfcef849e9db 100644 --- a/src/test/mir-opt/deaggregator_test_enum_2.test1.Deaggregator.diff +++ b/src/test/mir-opt/deaggregator_test_enum_2.test1.Deaggregator.diff @@ -2,44 +2,44 @@ + // MIR for `test1` after Deaggregator fn test1(_1: bool, _2: i32) -> Foo { - debug x => _1; // in scope 0 at $DIR/deaggregator_test_enum_2.rs:+0:10: +0:11 - debug y => _2; // in scope 0 at $DIR/deaggregator_test_enum_2.rs:+0:19: +0:20 - let mut _0: Foo; // return place in scope 0 at $DIR/deaggregator_test_enum_2.rs:+0:30: +0:33 - let mut _3: bool; // in scope 0 at $DIR/deaggregator_test_enum_2.rs:+1:8: +1:9 - let mut _4: i32; // in scope 0 at $DIR/deaggregator_test_enum_2.rs:+2:16: +2:17 - let mut _5: i32; // in scope 0 at $DIR/deaggregator_test_enum_2.rs:+4:16: +4:17 + debug x => _1; // in scope 0 at $DIR/deaggregator_test_enum_2.rs:9:10: 9:11 + debug y => _2; // in scope 0 at $DIR/deaggregator_test_enum_2.rs:9:19: 9:20 + let mut _0: Foo; // return place in scope 0 at $DIR/deaggregator_test_enum_2.rs:9:30: 9:33 + let mut _3: bool; // in scope 0 at $DIR/deaggregator_test_enum_2.rs:10:8: 10:9 + let mut _4: i32; // in scope 0 at $DIR/deaggregator_test_enum_2.rs:11:16: 11:17 + let mut _5: i32; // in scope 0 at $DIR/deaggregator_test_enum_2.rs:13:16: 13:17 bb0: { - StorageLive(_3); // scope 0 at $DIR/deaggregator_test_enum_2.rs:+1:8: +1:9 - _3 = _1; // scope 0 at $DIR/deaggregator_test_enum_2.rs:+1:8: +1:9 - switchInt(move _3) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/deaggregator_test_enum_2.rs:+1:8: +1:9 + StorageLive(_3); // scope 0 at $DIR/deaggregator_test_enum_2.rs:10:8: 10:9 + _3 = _1; // scope 0 at $DIR/deaggregator_test_enum_2.rs:10:8: 10:9 + switchInt(move _3) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/deaggregator_test_enum_2.rs:10:8: 10:9 } bb1: { - StorageLive(_4); // scope 0 at $DIR/deaggregator_test_enum_2.rs:+2:16: +2:17 - _4 = _2; // scope 0 at $DIR/deaggregator_test_enum_2.rs:+2:16: +2:17 -- _0 = Foo::A(move _4); // scope 0 at $DIR/deaggregator_test_enum_2.rs:+2:9: +2:18 -+ Deinit(_0); // scope 0 at $DIR/deaggregator_test_enum_2.rs:+2:9: +2:18 -+ ((_0 as A).0: i32) = move _4; // scope 0 at $DIR/deaggregator_test_enum_2.rs:+2:9: +2:18 -+ discriminant(_0) = 0; // scope 0 at $DIR/deaggregator_test_enum_2.rs:+2:9: +2:18 - StorageDead(_4); // scope 0 at $DIR/deaggregator_test_enum_2.rs:+2:17: +2:18 - goto -> bb3; // scope 0 at $DIR/deaggregator_test_enum_2.rs:+1:5: +5:6 + StorageLive(_4); // scope 0 at $DIR/deaggregator_test_enum_2.rs:11:16: 11:17 + _4 = _2; // scope 0 at $DIR/deaggregator_test_enum_2.rs:11:16: 11:17 +- _0 = Foo::A(move _4); // scope 0 at $DIR/deaggregator_test_enum_2.rs:11:9: 11:18 ++ Deinit(_0); // scope 0 at $DIR/deaggregator_test_enum_2.rs:11:9: 11:18 ++ ((_0 as A).0: i32) = move _4; // scope 0 at $DIR/deaggregator_test_enum_2.rs:11:9: 11:18 ++ discriminant(_0) = 0; // scope 0 at $DIR/deaggregator_test_enum_2.rs:11:9: 11:18 + StorageDead(_4); // scope 0 at $DIR/deaggregator_test_enum_2.rs:11:17: 11:18 + goto -> bb3; // scope 0 at $DIR/deaggregator_test_enum_2.rs:10:5: 14:6 } bb2: { - StorageLive(_5); // scope 0 at $DIR/deaggregator_test_enum_2.rs:+4:16: +4:17 - _5 = _2; // scope 0 at $DIR/deaggregator_test_enum_2.rs:+4:16: +4:17 -- _0 = Foo::B(move _5); // scope 0 at $DIR/deaggregator_test_enum_2.rs:+4:9: +4:18 -+ Deinit(_0); // scope 0 at $DIR/deaggregator_test_enum_2.rs:+4:9: +4:18 -+ ((_0 as B).0: i32) = move _5; // scope 0 at $DIR/deaggregator_test_enum_2.rs:+4:9: +4:18 -+ discriminant(_0) = 1; // scope 0 at $DIR/deaggregator_test_enum_2.rs:+4:9: +4:18 - StorageDead(_5); // scope 0 at $DIR/deaggregator_test_enum_2.rs:+4:17: +4:18 - goto -> bb3; // scope 0 at $DIR/deaggregator_test_enum_2.rs:+1:5: +5:6 + StorageLive(_5); // scope 0 at $DIR/deaggregator_test_enum_2.rs:13:16: 13:17 + _5 = _2; // scope 0 at $DIR/deaggregator_test_enum_2.rs:13:16: 13:17 +- _0 = Foo::B(move _5); // scope 0 at $DIR/deaggregator_test_enum_2.rs:13:9: 13:18 ++ Deinit(_0); // scope 0 at $DIR/deaggregator_test_enum_2.rs:13:9: 13:18 ++ ((_0 as B).0: i32) = move _5; // scope 0 at $DIR/deaggregator_test_enum_2.rs:13:9: 13:18 ++ discriminant(_0) = 1; // scope 0 at $DIR/deaggregator_test_enum_2.rs:13:9: 13:18 + StorageDead(_5); // scope 0 at $DIR/deaggregator_test_enum_2.rs:13:17: 13:18 + goto -> bb3; // scope 0 at $DIR/deaggregator_test_enum_2.rs:10:5: 14:6 } bb3: { - StorageDead(_3); // scope 0 at $DIR/deaggregator_test_enum_2.rs:+5:5: +5:6 - return; // scope 0 at $DIR/deaggregator_test_enum_2.rs:+6:2: +6:2 + StorageDead(_3); // scope 0 at $DIR/deaggregator_test_enum_2.rs:14:5: 14:6 + return; // scope 0 at $DIR/deaggregator_test_enum_2.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/deaggregator_test_multiple.test.Deaggregator.diff b/src/test/mir-opt/deaggregator_test_multiple.test.Deaggregator.diff index cf5da273c2894..c346f551a1ab8 100644 --- a/src/test/mir-opt/deaggregator_test_multiple.test.Deaggregator.diff +++ b/src/test/mir-opt/deaggregator_test_multiple.test.Deaggregator.diff @@ -2,34 +2,34 @@ + // MIR for `test` after Deaggregator fn test(_1: i32) -> [Foo; 2] { - debug x => _1; // in scope 0 at $DIR/deaggregator_test_multiple.rs:+0:9: +0:10 - let mut _0: [Foo; 2]; // return place in scope 0 at $DIR/deaggregator_test_multiple.rs:+0:20: +0:28 - let mut _2: Foo; // in scope 0 at $DIR/deaggregator_test_multiple.rs:+1:6: +1:15 - let mut _3: i32; // in scope 0 at $DIR/deaggregator_test_multiple.rs:+1:13: +1:14 - let mut _4: Foo; // in scope 0 at $DIR/deaggregator_test_multiple.rs:+1:17: +1:26 - let mut _5: i32; // in scope 0 at $DIR/deaggregator_test_multiple.rs:+1:24: +1:25 + debug x => _1; // in scope 0 at $DIR/deaggregator_test_multiple.rs:9:9: 9:10 + let mut _0: [Foo; 2]; // return place in scope 0 at $DIR/deaggregator_test_multiple.rs:9:20: 9:28 + let mut _2: Foo; // in scope 0 at $DIR/deaggregator_test_multiple.rs:10:6: 10:15 + let mut _3: i32; // in scope 0 at $DIR/deaggregator_test_multiple.rs:10:13: 10:14 + let mut _4: Foo; // in scope 0 at $DIR/deaggregator_test_multiple.rs:10:17: 10:26 + let mut _5: i32; // in scope 0 at $DIR/deaggregator_test_multiple.rs:10:24: 10:25 bb0: { - StorageLive(_2); // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:6: +1:15 - StorageLive(_3); // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:13: +1:14 - _3 = _1; // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:13: +1:14 -- _2 = Foo::A(move _3); // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:6: +1:15 -+ Deinit(_2); // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:6: +1:15 -+ ((_2 as A).0: i32) = move _3; // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:6: +1:15 -+ discriminant(_2) = 0; // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:6: +1:15 - StorageDead(_3); // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:14: +1:15 - StorageLive(_4); // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:17: +1:26 - StorageLive(_5); // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:24: +1:25 - _5 = _1; // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:24: +1:25 -- _4 = Foo::A(move _5); // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:17: +1:26 -+ Deinit(_4); // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:17: +1:26 -+ ((_4 as A).0: i32) = move _5; // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:17: +1:26 -+ discriminant(_4) = 0; // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:17: +1:26 - StorageDead(_5); // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:25: +1:26 - _0 = [move _2, move _4]; // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:5: +1:27 - StorageDead(_4); // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:26: +1:27 - StorageDead(_2); // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:26: +1:27 - return; // scope 0 at $DIR/deaggregator_test_multiple.rs:+2:2: +2:2 + StorageLive(_2); // scope 0 at $DIR/deaggregator_test_multiple.rs:10:6: 10:15 + StorageLive(_3); // scope 0 at $DIR/deaggregator_test_multiple.rs:10:13: 10:14 + _3 = _1; // scope 0 at $DIR/deaggregator_test_multiple.rs:10:13: 10:14 +- _2 = Foo::A(move _3); // scope 0 at $DIR/deaggregator_test_multiple.rs:10:6: 10:15 ++ Deinit(_2); // scope 0 at $DIR/deaggregator_test_multiple.rs:10:6: 10:15 ++ ((_2 as A).0: i32) = move _3; // scope 0 at $DIR/deaggregator_test_multiple.rs:10:6: 10:15 ++ discriminant(_2) = 0; // scope 0 at $DIR/deaggregator_test_multiple.rs:10:6: 10:15 + StorageDead(_3); // scope 0 at $DIR/deaggregator_test_multiple.rs:10:14: 10:15 + StorageLive(_4); // scope 0 at $DIR/deaggregator_test_multiple.rs:10:17: 10:26 + StorageLive(_5); // scope 0 at $DIR/deaggregator_test_multiple.rs:10:24: 10:25 + _5 = _1; // scope 0 at $DIR/deaggregator_test_multiple.rs:10:24: 10:25 +- _4 = Foo::A(move _5); // scope 0 at $DIR/deaggregator_test_multiple.rs:10:17: 10:26 ++ Deinit(_4); // scope 0 at $DIR/deaggregator_test_multiple.rs:10:17: 10:26 ++ ((_4 as A).0: i32) = move _5; // scope 0 at $DIR/deaggregator_test_multiple.rs:10:17: 10:26 ++ discriminant(_4) = 0; // scope 0 at $DIR/deaggregator_test_multiple.rs:10:17: 10:26 + StorageDead(_5); // scope 0 at $DIR/deaggregator_test_multiple.rs:10:25: 10:26 + _0 = [move _2, move _4]; // scope 0 at $DIR/deaggregator_test_multiple.rs:10:5: 10:27 + StorageDead(_4); // scope 0 at $DIR/deaggregator_test_multiple.rs:10:26: 10:27 + StorageDead(_2); // scope 0 at $DIR/deaggregator_test_multiple.rs:10:26: 10:27 + return; // scope 0 at $DIR/deaggregator_test_multiple.rs:11:2: 11:2 } } diff --git a/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff index 01864ba24ac08..688015f68d37e 100644 --- a/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff +++ b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff @@ -2,14 +2,14 @@ + // MIR for `is_line_doc_comment_2` after DeduplicateBlocks fn is_line_doc_comment_2(_1: &str) -> bool { - debug s => _1; // in scope 0 at $DIR/deduplicate_blocks.rs:+0:36: +0:37 - let mut _0: bool; // return place in scope 0 at $DIR/deduplicate_blocks.rs:+0:48: +0:52 - let mut _2: &[u8]; // in scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23 - let mut _3: &str; // in scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23 - let mut _4: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31 - let mut _5: bool; // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31 - let mut _6: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 - let mut _7: bool; // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 + debug s => _1; // in scope 0 at $DIR/deduplicate_blocks.rs:2:36: 2:37 + let mut _0: bool; // return place in scope 0 at $DIR/deduplicate_blocks.rs:2:48: 2:52 + let mut _2: &[u8]; // in scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 + let mut _3: &str; // in scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 + let mut _4: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31 + let mut _5: bool; // in scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31 + let mut _6: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37 + let mut _7: bool; // in scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37 scope 1 (inlined core::str::::as_bytes) { // at $DIR/deduplicate_blocks.rs:3:11: 3:23 debug self => _3; // in scope 1 at $SRC_DIR/core/src/str/mod.rs:LL:COL let mut _8: &str; // in scope 1 at $SRC_DIR/core/src/str/mod.rs:LL:COL @@ -18,9 +18,9 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23 - StorageLive(_3); // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23 - _3 = _1; // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23 + StorageLive(_2); // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 + StorageLive(_3); // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 + _3 = _1; // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 StorageLive(_8); // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL _8 = _3; // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL - _2 = transmute::<&str, &[u8]>(move _8) -> bb14; // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL @@ -31,77 +31,77 @@ } bb1: { - switchInt((*_2)[0 of 4]) -> [47_u8: bb2, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 + switchInt((*_2)[0 of 4]) -> [47_u8: bb2, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 3:23 } bb2: { - switchInt((*_2)[1 of 4]) -> [47_u8: bb3, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 + switchInt((*_2)[1 of 4]) -> [47_u8: bb3, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 3:23 } bb3: { - switchInt((*_2)[2 of 4]) -> [47_u8: bb4, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 + switchInt((*_2)[2 of 4]) -> [47_u8: bb4, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 3:23 } bb4: { -- switchInt((*_2)[3 of 4]) -> [47_u8: bb10, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 -+ switchInt((*_2)[3 of 4]) -> [47_u8: bb9, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 +- switchInt((*_2)[3 of 4]) -> [47_u8: bb10, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 3:23 ++ switchInt((*_2)[3 of 4]) -> [47_u8: bb9, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 3:23 } bb5: { - _4 = Len((*_2)); // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31 - _5 = Ge(move _4, const 3_usize); // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31 - switchInt(move _5) -> [false: bb9, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31 + _4 = Len((*_2)); // scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31 + _5 = Ge(move _4, const 3_usize); // scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31 + switchInt(move _5) -> [false: bb9, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31 } bb6: { - switchInt((*_2)[0 of 3]) -> [47_u8: bb7, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 + switchInt((*_2)[0 of 3]) -> [47_u8: bb7, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 3:23 } bb7: { - switchInt((*_2)[1 of 3]) -> [47_u8: bb8, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 + switchInt((*_2)[1 of 3]) -> [47_u8: bb8, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 3:23 } bb8: { -- switchInt((*_2)[2 of 3]) -> [47_u8: bb11, 33_u8: bb12, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 -+ switchInt((*_2)[2 of 3]) -> [47_u8: bb10, 33_u8: bb10, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 +- switchInt((*_2)[2 of 3]) -> [47_u8: bb11, 33_u8: bb12, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 3:23 ++ switchInt((*_2)[2 of 3]) -> [47_u8: bb10, 33_u8: bb10, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 3:23 } bb9: { -- _0 = const false; // scope 0 at $DIR/deduplicate_blocks.rs:+5:14: +5:19 -- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:+5:14: +5:19 +- _0 = const false; // scope 0 at $DIR/deduplicate_blocks.rs:7:14: 7:19 +- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:7:14: 7:19 - } - - bb10: { - _0 = const false; // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46 -- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46 -+ goto -> bb11; // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46 + _0 = const false; // scope 0 at $DIR/deduplicate_blocks.rs:4:41: 4:46 +- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:4:41: 4:46 ++ goto -> bb11; // scope 0 at $DIR/deduplicate_blocks.rs:4:41: 4:46 } - bb11: { -- _0 = const true; // scope 0 at $DIR/deduplicate_blocks.rs:+3:35: +3:39 -- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:+3:35: +3:39 +- _0 = const true; // scope 0 at $DIR/deduplicate_blocks.rs:5:35: 5:39 +- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:5:35: 5:39 - } - - bb12: { + bb10: { - _0 = const true; // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39 -- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39 -+ goto -> bb11; // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39 + _0 = const true; // scope 0 at $DIR/deduplicate_blocks.rs:6:35: 6:39 +- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:6:35: 6:39 ++ goto -> bb11; // scope 0 at $DIR/deduplicate_blocks.rs:6:35: 6:39 } - bb13: { + bb11: { - StorageDead(_2); // scope 0 at $DIR/deduplicate_blocks.rs:+7:1: +7:2 - return; // scope 0 at $DIR/deduplicate_blocks.rs:+7:2: +7:2 + StorageDead(_2); // scope 0 at $DIR/deduplicate_blocks.rs:9:1: 9:2 + return; // scope 0 at $DIR/deduplicate_blocks.rs:9:2: 9:2 } - bb14: { + bb12: { StorageDead(_8); // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL - StorageDead(_3); // scope 0 at $DIR/deduplicate_blocks.rs:+1:22: +1:23 - _6 = Len((*_2)); // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 - _7 = Ge(move _6, const 4_usize); // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 - switchInt(move _7) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 + StorageDead(_3); // scope 0 at $DIR/deduplicate_blocks.rs:3:22: 3:23 + _6 = Len((*_2)); // scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37 + _7 = Ge(move _6, const 4_usize); // scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37 + switchInt(move _7) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37 } } diff --git a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff index 548b94d17f566..9affe5a50061d 100644 --- a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff +++ b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff @@ -2,110 +2,110 @@ + // MIR for `main` after Derefer fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/derefer_complex_case.rs:+0:11: +0:11 - let mut _1: std::slice::Iter; // in scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - let mut _2: &[i32; 2]; // in scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - let _3: [i32; 2]; // in scope 0 at $DIR/derefer_complex_case.rs:+1:18: +1:26 - let mut _4: std::slice::Iter; // in scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - let mut _5: (); // in scope 0 at $DIR/derefer_complex_case.rs:+0:1: +2:2 - let _6: (); // in scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - let mut _7: std::option::Option<&i32>; // in scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - let mut _8: &mut std::slice::Iter; // in scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - let mut _9: &mut std::slice::Iter; // in scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - let mut _10: isize; // in scope 0 at $DIR/derefer_complex_case.rs:+1:5: +1:40 - let mut _11: !; // in scope 0 at $DIR/derefer_complex_case.rs:+1:5: +1:40 - let mut _13: i32; // in scope 0 at $DIR/derefer_complex_case.rs:+1:34: +1:37 - let mut _14: &[i32; 2]; // in scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 -+ let mut _15: &i32; // in scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 + let mut _0: (); // return place in scope 0 at $DIR/derefer_complex_case.rs:4:11: 4:11 + let mut _1: std::slice::Iter; // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + let mut _2: &[i32; 2]; // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + let _3: [i32; 2]; // in scope 0 at $DIR/derefer_complex_case.rs:5:18: 5:26 + let mut _4: std::slice::Iter; // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + let mut _5: (); // in scope 0 at $DIR/derefer_complex_case.rs:4:1: 6:2 + let _6: (); // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + let mut _7: std::option::Option<&i32>; // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + let mut _8: &mut std::slice::Iter; // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + let mut _9: &mut std::slice::Iter; // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + let mut _10: isize; // in scope 0 at $DIR/derefer_complex_case.rs:5:5: 5:40 + let mut _11: !; // in scope 0 at $DIR/derefer_complex_case.rs:5:5: 5:40 + let mut _13: i32; // in scope 0 at $DIR/derefer_complex_case.rs:5:34: 5:37 + let mut _14: &[i32; 2]; // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 ++ let mut _15: &i32; // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 scope 1 { - debug iter => _4; // in scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - let _12: i32; // in scope 1 at $DIR/derefer_complex_case.rs:+1:10: +1:13 + debug iter => _4; // in scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 + let _12: i32; // in scope 1 at $DIR/derefer_complex_case.rs:5:10: 5:13 scope 2 { - debug foo => _12; // in scope 2 at $DIR/derefer_complex_case.rs:+1:10: +1:13 + debug foo => _12; // in scope 2 at $DIR/derefer_complex_case.rs:5:10: 5:13 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - StorageLive(_2); // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - _14 = const main::promoted[0]; // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 + StorageLive(_1); // scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + StorageLive(_2); // scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + _14 = const main::promoted[0]; // scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 // mir::Constant // + span: $DIR/derefer_complex_case.rs:5:17: 5:26 // + literal: Const { ty: &[i32; 2], val: Unevaluated(main, [], Some(promoted[0])) } - _2 = &(*_14); // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - _1 = <&[i32; 2] as IntoIterator>::into_iter(move _2) -> bb1; // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 + _2 = &(*_14); // scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + _1 = <&[i32; 2] as IntoIterator>::into_iter(move _2) -> bb1; // scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 // mir::Constant // + span: $DIR/derefer_complex_case.rs:5:17: 5:26 // + literal: Const { ty: fn(&[i32; 2]) -> <&[i32; 2] as IntoIterator>::IntoIter {<&[i32; 2] as IntoIterator>::into_iter}, val: Value() } } bb1: { - StorageDead(_2); // scope 0 at $DIR/derefer_complex_case.rs:+1:25: +1:26 - StorageLive(_4); // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - _4 = move _1; // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - goto -> bb2; // scope 1 at $DIR/derefer_complex_case.rs:+1:5: +1:40 + StorageDead(_2); // scope 0 at $DIR/derefer_complex_case.rs:5:25: 5:26 + StorageLive(_4); // scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + _4 = move _1; // scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + goto -> bb2; // scope 1 at $DIR/derefer_complex_case.rs:5:5: 5:40 } bb2: { - StorageLive(_6); // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - StorageLive(_7); // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - StorageLive(_8); // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - StorageLive(_9); // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - _9 = &mut _4; // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - _8 = &mut (*_9); // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - _7 = as Iterator>::next(move _8) -> bb3; // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26 + StorageLive(_6); // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 + StorageLive(_7); // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 + StorageLive(_8); // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 + StorageLive(_9); // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 + _9 = &mut _4; // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 + _8 = &mut (*_9); // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 + _7 = as Iterator>::next(move _8) -> bb3; // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 // mir::Constant // + span: $DIR/derefer_complex_case.rs:5:17: 5:26 // + literal: Const { ty: for<'r> fn(&'r mut std::slice::Iter) -> Option< as Iterator>::Item> { as Iterator>::next}, val: Value() } } bb3: { - StorageDead(_8); // scope 1 at $DIR/derefer_complex_case.rs:+1:25: +1:26 - _10 = discriminant(_7); // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26 - switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26 + StorageDead(_8); // scope 1 at $DIR/derefer_complex_case.rs:5:25: 5:26 + _10 = discriminant(_7); // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 + switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 } bb4: { - StorageLive(_12); // scope 1 at $DIR/derefer_complex_case.rs:+1:10: +1:13 -- _12 = (*((_7 as Some).0: &i32)); // scope 1 at $DIR/derefer_complex_case.rs:+1:10: +1:13 -+ StorageLive(_15); // scope 1 at $DIR/derefer_complex_case.rs:+1:10: +1:13 -+ _15 = deref_copy ((_7 as Some).0: &i32); // scope 1 at $DIR/derefer_complex_case.rs:+1:10: +1:13 -+ _12 = (*_15); // scope 1 at $DIR/derefer_complex_case.rs:+1:10: +1:13 -+ StorageDead(_15); // scope 2 at $DIR/derefer_complex_case.rs:+1:34: +1:37 - StorageLive(_13); // scope 2 at $DIR/derefer_complex_case.rs:+1:34: +1:37 - _13 = _12; // scope 2 at $DIR/derefer_complex_case.rs:+1:34: +1:37 - _6 = std::mem::drop::(move _13) -> bb7; // scope 2 at $DIR/derefer_complex_case.rs:+1:29: +1:38 + StorageLive(_12); // scope 1 at $DIR/derefer_complex_case.rs:5:10: 5:13 +- _12 = (*((_7 as Some).0: &i32)); // scope 1 at $DIR/derefer_complex_case.rs:5:10: 5:13 ++ StorageLive(_15); // scope 1 at $DIR/derefer_complex_case.rs:5:10: 5:13 ++ _15 = deref_copy ((_7 as Some).0: &i32); // scope 1 at $DIR/derefer_complex_case.rs:5:10: 5:13 ++ _12 = (*_15); // scope 1 at $DIR/derefer_complex_case.rs:5:10: 5:13 ++ StorageDead(_15); // scope 2 at $DIR/derefer_complex_case.rs:5:34: 5:37 + StorageLive(_13); // scope 2 at $DIR/derefer_complex_case.rs:5:34: 5:37 + _13 = _12; // scope 2 at $DIR/derefer_complex_case.rs:5:34: 5:37 + _6 = std::mem::drop::(move _13) -> bb7; // scope 2 at $DIR/derefer_complex_case.rs:5:29: 5:38 // mir::Constant // + span: $DIR/derefer_complex_case.rs:5:29: 5:33 // + literal: Const { ty: fn(i32) {std::mem::drop::}, val: Value() } } bb5: { - unreachable; // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26 + unreachable; // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 } bb6: { - _0 = const (); // scope 1 at $DIR/derefer_complex_case.rs:+1:5: +1:40 - StorageDead(_9); // scope 1 at $DIR/derefer_complex_case.rs:+1:39: +1:40 - StorageDead(_7); // scope 1 at $DIR/derefer_complex_case.rs:+1:39: +1:40 - StorageDead(_6); // scope 1 at $DIR/derefer_complex_case.rs:+1:39: +1:40 - StorageDead(_4); // scope 0 at $DIR/derefer_complex_case.rs:+1:39: +1:40 - StorageDead(_1); // scope 0 at $DIR/derefer_complex_case.rs:+1:39: +1:40 - return; // scope 0 at $DIR/derefer_complex_case.rs:+2:2: +2:2 + _0 = const (); // scope 1 at $DIR/derefer_complex_case.rs:5:5: 5:40 + StorageDead(_9); // scope 1 at $DIR/derefer_complex_case.rs:5:39: 5:40 + StorageDead(_7); // scope 1 at $DIR/derefer_complex_case.rs:5:39: 5:40 + StorageDead(_6); // scope 1 at $DIR/derefer_complex_case.rs:5:39: 5:40 + StorageDead(_4); // scope 0 at $DIR/derefer_complex_case.rs:5:39: 5:40 + StorageDead(_1); // scope 0 at $DIR/derefer_complex_case.rs:5:39: 5:40 + return; // scope 0 at $DIR/derefer_complex_case.rs:6:2: 6:2 } bb7: { - StorageDead(_13); // scope 2 at $DIR/derefer_complex_case.rs:+1:37: +1:38 - StorageDead(_12); // scope 1 at $DIR/derefer_complex_case.rs:+1:39: +1:40 - StorageDead(_9); // scope 1 at $DIR/derefer_complex_case.rs:+1:39: +1:40 - StorageDead(_7); // scope 1 at $DIR/derefer_complex_case.rs:+1:39: +1:40 - StorageDead(_6); // scope 1 at $DIR/derefer_complex_case.rs:+1:39: +1:40 - _5 = const (); // scope 1 at $DIR/derefer_complex_case.rs:+1:5: +1:40 - goto -> bb2; // scope 1 at $DIR/derefer_complex_case.rs:+1:5: +1:40 + StorageDead(_13); // scope 2 at $DIR/derefer_complex_case.rs:5:37: 5:38 + StorageDead(_12); // scope 1 at $DIR/derefer_complex_case.rs:5:39: 5:40 + StorageDead(_9); // scope 1 at $DIR/derefer_complex_case.rs:5:39: 5:40 + StorageDead(_7); // scope 1 at $DIR/derefer_complex_case.rs:5:39: 5:40 + StorageDead(_6); // scope 1 at $DIR/derefer_complex_case.rs:5:39: 5:40 + _5 = const (); // scope 1 at $DIR/derefer_complex_case.rs:5:5: 5:40 + goto -> bb2; // scope 1 at $DIR/derefer_complex_case.rs:5:5: 5:40 + } + + bb8 (cleanup): { -+ resume; // scope 0 at $DIR/derefer_complex_case.rs:+0:1: +2:2 ++ resume; // scope 0 at $DIR/derefer_complex_case.rs:4:1: 6:2 } } diff --git a/src/test/mir-opt/derefer_inline_test.main.Derefer.diff b/src/test/mir-opt/derefer_inline_test.main.Derefer.diff index ce6ffaa56413c..fe64156f42f84 100644 --- a/src/test/mir-opt/derefer_inline_test.main.Derefer.diff +++ b/src/test/mir-opt/derefer_inline_test.main.Derefer.diff @@ -2,60 +2,60 @@ + // MIR for `main` after Derefer fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/derefer_inline_test.rs:+0:11: +0:11 - let _1: std::boxed::Box>; // in scope 0 at $DIR/derefer_inline_test.rs:+1:5: +1:12 - let mut _2: usize; // in scope 0 at $DIR/derefer_inline_test.rs:+1:5: +1:12 - let mut _3: usize; // in scope 0 at $DIR/derefer_inline_test.rs:+1:5: +1:12 - let mut _4: *mut u8; // in scope 0 at $DIR/derefer_inline_test.rs:+1:5: +1:12 - let mut _5: std::boxed::Box>; // in scope 0 at $DIR/derefer_inline_test.rs:+1:5: +1:12 + let mut _0: (); // return place in scope 0 at $DIR/derefer_inline_test.rs:9:11: 9:11 + let _1: std::boxed::Box>; // in scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 + let mut _2: usize; // in scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 + let mut _3: usize; // in scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 + let mut _4: *mut u8; // in scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 + let mut _5: std::boxed::Box>; // in scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 scope 1 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/derefer_inline_test.rs:+1:5: +1:12 - _2 = SizeOf(std::boxed::Box); // scope 1 at $DIR/derefer_inline_test.rs:+1:5: +1:12 - _3 = AlignOf(std::boxed::Box); // scope 1 at $DIR/derefer_inline_test.rs:+1:5: +1:12 - _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/derefer_inline_test.rs:+1:5: +1:12 + StorageLive(_1); // scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 + _2 = SizeOf(std::boxed::Box); // scope 1 at $DIR/derefer_inline_test.rs:10:5: 10:12 + _3 = AlignOf(std::boxed::Box); // scope 1 at $DIR/derefer_inline_test.rs:10:5: 10:12 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/derefer_inline_test.rs:10:5: 10:12 // mir::Constant // + span: $DIR/derefer_inline_test.rs:10:5: 10:12 // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value() } } bb1: { - StorageLive(_5); // scope 0 at $DIR/derefer_inline_test.rs:+1:5: +1:12 - _5 = ShallowInitBox(move _4, std::boxed::Box); // scope 0 at $DIR/derefer_inline_test.rs:+1:5: +1:12 - (*_5) = f() -> [return: bb2, unwind: bb6]; // scope 0 at $DIR/derefer_inline_test.rs:+1:9: +1:12 + StorageLive(_5); // scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 + _5 = ShallowInitBox(move _4, std::boxed::Box); // scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 + (*_5) = f() -> [return: bb2, unwind: bb6]; // scope 0 at $DIR/derefer_inline_test.rs:10:9: 10:12 // mir::Constant // + span: $DIR/derefer_inline_test.rs:10:9: 10:10 // + literal: Const { ty: fn() -> Box {f}, val: Value() } } bb2: { - _1 = move _5; // scope 0 at $DIR/derefer_inline_test.rs:+1:5: +1:12 - drop(_5) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/derefer_inline_test.rs:+1:11: +1:12 + _1 = move _5; // scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 + drop(_5) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 } bb3: { - StorageDead(_5); // scope 0 at $DIR/derefer_inline_test.rs:+1:11: +1:12 - drop(_1) -> bb4; // scope 0 at $DIR/derefer_inline_test.rs:+1:12: +1:13 + StorageDead(_5); // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 + drop(_1) -> bb4; // scope 0 at $DIR/derefer_inline_test.rs:10:12: 10:13 } bb4: { - StorageDead(_1); // scope 0 at $DIR/derefer_inline_test.rs:+1:12: +1:13 - _0 = const (); // scope 0 at $DIR/derefer_inline_test.rs:+0:11: +2:2 - return; // scope 0 at $DIR/derefer_inline_test.rs:+2:2: +2:2 + StorageDead(_1); // scope 0 at $DIR/derefer_inline_test.rs:10:12: 10:13 + _0 = const (); // scope 0 at $DIR/derefer_inline_test.rs:9:11: 11:2 + return; // scope 0 at $DIR/derefer_inline_test.rs:11:2: 11:2 } bb5 (cleanup): { - drop(_1) -> bb7; // scope 0 at $DIR/derefer_inline_test.rs:+1:12: +1:13 + drop(_1) -> bb7; // scope 0 at $DIR/derefer_inline_test.rs:10:12: 10:13 } bb6 (cleanup): { - drop(_5) -> bb7; // scope 0 at $DIR/derefer_inline_test.rs:+1:11: +1:12 + drop(_5) -> bb7; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 } bb7 (cleanup): { - resume; // scope 0 at $DIR/derefer_inline_test.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/derefer_inline_test.rs:9:1: 11:2 } } diff --git a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff index 51df13bdfd01d..003803fbd5ca9 100644 --- a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff +++ b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff @@ -2,102 +2,102 @@ + // MIR for `main` after Derefer fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/derefer_terminator_test.rs:+0:11: +0:11 - let _1: bool; // in scope 0 at $DIR/derefer_terminator_test.rs:+1:9: +1:10 - let _3: (); // in scope 0 at $DIR/derefer_terminator_test.rs:+3:5: +6:6 - let mut _4: &&&&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:+3:15: +3:22 - let _5: &&&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:+3:17: +3:21 - let _6: &&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:+3:18: +3:21 - let _7: &bool; // in scope 0 at $DIR/derefer_terminator_test.rs:+3:19: +3:21 -+ let mut _10: &&&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:+3:15: +3:22 -+ let mut _11: &&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:+3:15: +3:22 -+ let mut _12: &bool; // in scope 0 at $DIR/derefer_terminator_test.rs:+3:15: +3:22 + let mut _0: (); // return place in scope 0 at $DIR/derefer_terminator_test.rs:4:11: 4:11 + let _1: bool; // in scope 0 at $DIR/derefer_terminator_test.rs:5:9: 5:10 + let _3: (); // in scope 0 at $DIR/derefer_terminator_test.rs:7:5: 10:6 + let mut _4: &&&&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:7:15: 7:22 + let _5: &&&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:7:17: 7:21 + let _6: &&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:7:18: 7:21 + let _7: &bool; // in scope 0 at $DIR/derefer_terminator_test.rs:7:19: 7:21 ++ let mut _10: &&&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:7:15: 7:22 ++ let mut _11: &&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:7:15: 7:22 ++ let mut _12: &bool; // in scope 0 at $DIR/derefer_terminator_test.rs:7:15: 7:22 scope 1 { - debug b => _1; // in scope 1 at $DIR/derefer_terminator_test.rs:+1:9: +1:10 - let _2: bool; // in scope 1 at $DIR/derefer_terminator_test.rs:+2:9: +2:10 + debug b => _1; // in scope 1 at $DIR/derefer_terminator_test.rs:5:9: 5:10 + let _2: bool; // in scope 1 at $DIR/derefer_terminator_test.rs:6:9: 6:10 scope 2 { - debug d => _2; // in scope 2 at $DIR/derefer_terminator_test.rs:+2:9: +2:10 - let _8: i32; // in scope 2 at $DIR/derefer_terminator_test.rs:+4:22: +4:23 - let _9: i32; // in scope 2 at $DIR/derefer_terminator_test.rs:+7:9: +7:10 + debug d => _2; // in scope 2 at $DIR/derefer_terminator_test.rs:6:9: 6:10 + let _8: i32; // in scope 2 at $DIR/derefer_terminator_test.rs:8:22: 8:23 + let _9: i32; // in scope 2 at $DIR/derefer_terminator_test.rs:11:9: 11:10 scope 3 { - debug x => _8; // in scope 3 at $DIR/derefer_terminator_test.rs:+4:22: +4:23 + debug x => _8; // in scope 3 at $DIR/derefer_terminator_test.rs:8:22: 8:23 } scope 4 { - debug y => _9; // in scope 4 at $DIR/derefer_terminator_test.rs:+7:9: +7:10 + debug y => _9; // in scope 4 at $DIR/derefer_terminator_test.rs:11:9: 11:10 } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/derefer_terminator_test.rs:+1:9: +1:10 - _1 = foo() -> bb1; // scope 0 at $DIR/derefer_terminator_test.rs:+1:13: +1:18 + StorageLive(_1); // scope 0 at $DIR/derefer_terminator_test.rs:5:9: 5:10 + _1 = foo() -> bb1; // scope 0 at $DIR/derefer_terminator_test.rs:5:13: 5:18 // mir::Constant // + span: $DIR/derefer_terminator_test.rs:5:13: 5:16 // + literal: Const { ty: fn() -> bool {foo}, val: Value() } } bb1: { - StorageLive(_2); // scope 1 at $DIR/derefer_terminator_test.rs:+2:9: +2:10 - _2 = foo() -> bb2; // scope 1 at $DIR/derefer_terminator_test.rs:+2:13: +2:18 + StorageLive(_2); // scope 1 at $DIR/derefer_terminator_test.rs:6:9: 6:10 + _2 = foo() -> bb2; // scope 1 at $DIR/derefer_terminator_test.rs:6:13: 6:18 // mir::Constant // + span: $DIR/derefer_terminator_test.rs:6:13: 6:16 // + literal: Const { ty: fn() -> bool {foo}, val: Value() } } bb2: { - StorageLive(_3); // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +6:6 - StorageLive(_4); // scope 2 at $DIR/derefer_terminator_test.rs:+3:15: +3:22 - StorageLive(_5); // scope 2 at $DIR/derefer_terminator_test.rs:+3:17: +3:21 - StorageLive(_6); // scope 2 at $DIR/derefer_terminator_test.rs:+3:18: +3:21 - StorageLive(_7); // scope 2 at $DIR/derefer_terminator_test.rs:+3:19: +3:21 - _7 = &_1; // scope 2 at $DIR/derefer_terminator_test.rs:+3:19: +3:21 - _6 = &_7; // scope 2 at $DIR/derefer_terminator_test.rs:+3:18: +3:21 - _5 = &_6; // scope 2 at $DIR/derefer_terminator_test.rs:+3:17: +3:21 - _4 = &_5; // scope 2 at $DIR/derefer_terminator_test.rs:+3:15: +3:22 -- switchInt((*(*(*(*_4))))) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22 -+ StorageLive(_10); // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22 -+ _10 = deref_copy (*_4); // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22 -+ StorageLive(_11); // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22 -+ _11 = deref_copy (*_10); // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22 -+ StorageDead(_10); // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22 -+ StorageLive(_12); // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22 -+ _12 = deref_copy (*_11); // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22 -+ StorageDead(_11); // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22 -+ switchInt((*_12)) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22 + StorageLive(_3); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 10:6 + StorageLive(_4); // scope 2 at $DIR/derefer_terminator_test.rs:7:15: 7:22 + StorageLive(_5); // scope 2 at $DIR/derefer_terminator_test.rs:7:17: 7:21 + StorageLive(_6); // scope 2 at $DIR/derefer_terminator_test.rs:7:18: 7:21 + StorageLive(_7); // scope 2 at $DIR/derefer_terminator_test.rs:7:19: 7:21 + _7 = &_1; // scope 2 at $DIR/derefer_terminator_test.rs:7:19: 7:21 + _6 = &_7; // scope 2 at $DIR/derefer_terminator_test.rs:7:18: 7:21 + _5 = &_6; // scope 2 at $DIR/derefer_terminator_test.rs:7:17: 7:21 + _4 = &_5; // scope 2 at $DIR/derefer_terminator_test.rs:7:15: 7:22 +- switchInt((*(*(*(*_4))))) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ StorageLive(_10); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ _10 = deref_copy (*_4); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ StorageLive(_11); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ _11 = deref_copy (*_10); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ StorageDead(_10); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ StorageLive(_12); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ _12 = deref_copy (*_11); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ StorageDead(_11); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ switchInt((*_12)) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 } bb3: { -+ StorageDead(_12); // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22 - _3 = const (); // scope 2 at $DIR/derefer_terminator_test.rs:+5:18: +5:20 - goto -> bb5; // scope 2 at $DIR/derefer_terminator_test.rs:+5:18: +5:20 ++ StorageDead(_12); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 + _3 = const (); // scope 2 at $DIR/derefer_terminator_test.rs:9:18: 9:20 + goto -> bb5; // scope 2 at $DIR/derefer_terminator_test.rs:9:18: 9:20 } bb4: { -+ StorageDead(_12); // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22 - StorageLive(_8); // scope 2 at $DIR/derefer_terminator_test.rs:+4:22: +4:23 - _8 = const 5_i32; // scope 2 at $DIR/derefer_terminator_test.rs:+4:26: +4:27 - _3 = const (); // scope 2 at $DIR/derefer_terminator_test.rs:+4:17: +4:29 - StorageDead(_8); // scope 2 at $DIR/derefer_terminator_test.rs:+4:28: +4:29 - goto -> bb5; // scope 2 at $DIR/derefer_terminator_test.rs:+4:28: +4:29 ++ StorageDead(_12); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 + StorageLive(_8); // scope 2 at $DIR/derefer_terminator_test.rs:8:22: 8:23 + _8 = const 5_i32; // scope 2 at $DIR/derefer_terminator_test.rs:8:26: 8:27 + _3 = const (); // scope 2 at $DIR/derefer_terminator_test.rs:8:17: 8:29 + StorageDead(_8); // scope 2 at $DIR/derefer_terminator_test.rs:8:28: 8:29 + goto -> bb5; // scope 2 at $DIR/derefer_terminator_test.rs:8:28: 8:29 } bb5: { - StorageDead(_7); // scope 2 at $DIR/derefer_terminator_test.rs:+6:5: +6:6 - StorageDead(_6); // scope 2 at $DIR/derefer_terminator_test.rs:+6:5: +6:6 - StorageDead(_5); // scope 2 at $DIR/derefer_terminator_test.rs:+6:5: +6:6 - StorageDead(_4); // scope 2 at $DIR/derefer_terminator_test.rs:+6:5: +6:6 - StorageDead(_3); // scope 2 at $DIR/derefer_terminator_test.rs:+6:5: +6:6 - StorageLive(_9); // scope 2 at $DIR/derefer_terminator_test.rs:+7:9: +7:10 - _9 = const 42_i32; // scope 2 at $DIR/derefer_terminator_test.rs:+7:13: +7:15 - _0 = const (); // scope 0 at $DIR/derefer_terminator_test.rs:+0:11: +8:2 - StorageDead(_9); // scope 2 at $DIR/derefer_terminator_test.rs:+8:1: +8:2 - StorageDead(_2); // scope 1 at $DIR/derefer_terminator_test.rs:+8:1: +8:2 - StorageDead(_1); // scope 0 at $DIR/derefer_terminator_test.rs:+8:1: +8:2 - return; // scope 0 at $DIR/derefer_terminator_test.rs:+8:2: +8:2 + StorageDead(_7); // scope 2 at $DIR/derefer_terminator_test.rs:10:5: 10:6 + StorageDead(_6); // scope 2 at $DIR/derefer_terminator_test.rs:10:5: 10:6 + StorageDead(_5); // scope 2 at $DIR/derefer_terminator_test.rs:10:5: 10:6 + StorageDead(_4); // scope 2 at $DIR/derefer_terminator_test.rs:10:5: 10:6 + StorageDead(_3); // scope 2 at $DIR/derefer_terminator_test.rs:10:5: 10:6 + StorageLive(_9); // scope 2 at $DIR/derefer_terminator_test.rs:11:9: 11:10 + _9 = const 42_i32; // scope 2 at $DIR/derefer_terminator_test.rs:11:13: 11:15 + _0 = const (); // scope 0 at $DIR/derefer_terminator_test.rs:4:11: 12:2 + StorageDead(_9); // scope 2 at $DIR/derefer_terminator_test.rs:12:1: 12:2 + StorageDead(_2); // scope 1 at $DIR/derefer_terminator_test.rs:12:1: 12:2 + StorageDead(_1); // scope 0 at $DIR/derefer_terminator_test.rs:12:1: 12:2 + return; // scope 0 at $DIR/derefer_terminator_test.rs:12:2: 12:2 + } + + bb6 (cleanup): { -+ resume; // scope 0 at $DIR/derefer_terminator_test.rs:+0:1: +8:2 ++ resume; // scope 0 at $DIR/derefer_terminator_test.rs:4:1: 12:2 } } diff --git a/src/test/mir-opt/derefer_test.main.Derefer.diff b/src/test/mir-opt/derefer_test.main.Derefer.diff index cf8211c1ed089..df76b3ebc2deb 100644 --- a/src/test/mir-opt/derefer_test.main.Derefer.diff +++ b/src/test/mir-opt/derefer_test.main.Derefer.diff @@ -2,57 +2,57 @@ + // MIR for `main` after Derefer fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/derefer_test.rs:+0:11: +0:11 - let mut _1: (i32, i32); // in scope 0 at $DIR/derefer_test.rs:+1:9: +1:14 - let mut _3: &mut (i32, i32); // in scope 0 at $DIR/derefer_test.rs:+2:22: +2:28 -+ let mut _6: &mut (i32, i32); // in scope 0 at $DIR/derefer_test.rs:+2:9: +2:14 -+ let mut _7: &mut (i32, i32); // in scope 0 at $DIR/derefer_test.rs:+2:9: +2:14 + let mut _0: (); // return place in scope 0 at $DIR/derefer_test.rs:2:11: 2:11 + let mut _1: (i32, i32); // in scope 0 at $DIR/derefer_test.rs:3:9: 3:14 + let mut _3: &mut (i32, i32); // in scope 0 at $DIR/derefer_test.rs:4:22: 4:28 ++ let mut _6: &mut (i32, i32); // in scope 0 at $DIR/derefer_test.rs:4:9: 4:14 ++ let mut _7: &mut (i32, i32); // in scope 0 at $DIR/derefer_test.rs:4:9: 4:14 scope 1 { - debug a => _1; // in scope 1 at $DIR/derefer_test.rs:+1:9: +1:14 - let mut _2: (i32, &mut (i32, i32)); // in scope 1 at $DIR/derefer_test.rs:+2:9: +2:14 + debug a => _1; // in scope 1 at $DIR/derefer_test.rs:3:9: 3:14 + let mut _2: (i32, &mut (i32, i32)); // in scope 1 at $DIR/derefer_test.rs:4:9: 4:14 scope 2 { - debug b => _2; // in scope 2 at $DIR/derefer_test.rs:+2:9: +2:14 - let _4: &mut i32; // in scope 2 at $DIR/derefer_test.rs:+3:9: +3:10 + debug b => _2; // in scope 2 at $DIR/derefer_test.rs:4:9: 4:14 + let _4: &mut i32; // in scope 2 at $DIR/derefer_test.rs:5:9: 5:10 scope 3 { - debug x => _4; // in scope 3 at $DIR/derefer_test.rs:+3:9: +3:10 - let _5: &mut i32; // in scope 3 at $DIR/derefer_test.rs:+4:9: +4:10 + debug x => _4; // in scope 3 at $DIR/derefer_test.rs:5:9: 5:10 + let _5: &mut i32; // in scope 3 at $DIR/derefer_test.rs:6:9: 6:10 scope 4 { - debug y => _5; // in scope 4 at $DIR/derefer_test.rs:+4:9: +4:10 + debug y => _5; // in scope 4 at $DIR/derefer_test.rs:6:9: 6:10 } } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/derefer_test.rs:+1:9: +1:14 - _1 = (const 42_i32, const 43_i32); // scope 0 at $DIR/derefer_test.rs:+1:17: +1:24 - StorageLive(_2); // scope 1 at $DIR/derefer_test.rs:+2:9: +2:14 - StorageLive(_3); // scope 1 at $DIR/derefer_test.rs:+2:22: +2:28 - _3 = &mut _1; // scope 1 at $DIR/derefer_test.rs:+2:22: +2:28 - _2 = (const 99_i32, move _3); // scope 1 at $DIR/derefer_test.rs:+2:17: +2:29 - StorageDead(_3); // scope 1 at $DIR/derefer_test.rs:+2:28: +2:29 - StorageLive(_4); // scope 2 at $DIR/derefer_test.rs:+3:9: +3:10 -- _4 = &mut ((*(_2.1: &mut (i32, i32))).0: i32); // scope 2 at $DIR/derefer_test.rs:+3:13: +3:26 -+ StorageLive(_6); // scope 2 at $DIR/derefer_test.rs:+3:13: +3:26 -+ _6 = deref_copy (_2.1: &mut (i32, i32)); // scope 2 at $DIR/derefer_test.rs:+3:13: +3:26 -+ _4 = &mut ((*_6).0: i32); // scope 2 at $DIR/derefer_test.rs:+3:13: +3:26 -+ StorageDead(_6); // scope 3 at $DIR/derefer_test.rs:+4:9: +4:10 - StorageLive(_5); // scope 3 at $DIR/derefer_test.rs:+4:9: +4:10 -- _5 = &mut ((*(_2.1: &mut (i32, i32))).1: i32); // scope 3 at $DIR/derefer_test.rs:+4:13: +4:26 -+ StorageLive(_7); // scope 3 at $DIR/derefer_test.rs:+4:13: +4:26 -+ _7 = deref_copy (_2.1: &mut (i32, i32)); // scope 3 at $DIR/derefer_test.rs:+4:13: +4:26 -+ _5 = &mut ((*_7).1: i32); // scope 3 at $DIR/derefer_test.rs:+4:13: +4:26 -+ StorageDead(_7); // scope 0 at $DIR/derefer_test.rs:+0:11: +5:2 - _0 = const (); // scope 0 at $DIR/derefer_test.rs:+0:11: +5:2 - StorageDead(_5); // scope 3 at $DIR/derefer_test.rs:+5:1: +5:2 - StorageDead(_4); // scope 2 at $DIR/derefer_test.rs:+5:1: +5:2 - StorageDead(_2); // scope 1 at $DIR/derefer_test.rs:+5:1: +5:2 - StorageDead(_1); // scope 0 at $DIR/derefer_test.rs:+5:1: +5:2 - return; // scope 0 at $DIR/derefer_test.rs:+5:2: +5:2 + StorageLive(_1); // scope 0 at $DIR/derefer_test.rs:3:9: 3:14 + _1 = (const 42_i32, const 43_i32); // scope 0 at $DIR/derefer_test.rs:3:17: 3:24 + StorageLive(_2); // scope 1 at $DIR/derefer_test.rs:4:9: 4:14 + StorageLive(_3); // scope 1 at $DIR/derefer_test.rs:4:22: 4:28 + _3 = &mut _1; // scope 1 at $DIR/derefer_test.rs:4:22: 4:28 + _2 = (const 99_i32, move _3); // scope 1 at $DIR/derefer_test.rs:4:17: 4:29 + StorageDead(_3); // scope 1 at $DIR/derefer_test.rs:4:28: 4:29 + StorageLive(_4); // scope 2 at $DIR/derefer_test.rs:5:9: 5:10 +- _4 = &mut ((*(_2.1: &mut (i32, i32))).0: i32); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 ++ StorageLive(_6); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 ++ _6 = deref_copy (_2.1: &mut (i32, i32)); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 ++ _4 = &mut ((*_6).0: i32); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 ++ StorageDead(_6); // scope 3 at $DIR/derefer_test.rs:6:9: 6:10 + StorageLive(_5); // scope 3 at $DIR/derefer_test.rs:6:9: 6:10 +- _5 = &mut ((*(_2.1: &mut (i32, i32))).1: i32); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 ++ StorageLive(_7); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 ++ _7 = deref_copy (_2.1: &mut (i32, i32)); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 ++ _5 = &mut ((*_7).1: i32); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 ++ StorageDead(_7); // scope 0 at $DIR/derefer_test.rs:2:11: 7:2 + _0 = const (); // scope 0 at $DIR/derefer_test.rs:2:11: 7:2 + StorageDead(_5); // scope 3 at $DIR/derefer_test.rs:7:1: 7:2 + StorageDead(_4); // scope 2 at $DIR/derefer_test.rs:7:1: 7:2 + StorageDead(_2); // scope 1 at $DIR/derefer_test.rs:7:1: 7:2 + StorageDead(_1); // scope 0 at $DIR/derefer_test.rs:7:1: 7:2 + return; // scope 0 at $DIR/derefer_test.rs:7:2: 7:2 + } + + bb1 (cleanup): { -+ resume; // scope 0 at $DIR/derefer_test.rs:+0:1: +5:2 ++ resume; // scope 0 at $DIR/derefer_test.rs:2:1: 7:2 } } diff --git a/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff index 91c9d5512243c..044c92a2f4325 100644 --- a/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff +++ b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff @@ -2,34 +2,34 @@ + // MIR for `main` after Derefer fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/derefer_test_multiple.rs:+0:12: +0:12 - let mut _1: (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:+1:9: +1:14 - let mut _3: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:+2:22: +2:28 - let mut _5: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:+3:22: +3:28 - let mut _7: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:+4:22: +4:28 -+ let mut _10: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:+4:9: +4:14 -+ let mut _11: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:+4:9: +4:14 -+ let mut _12: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:+4:9: +4:14 -+ let mut _13: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:+4:9: +4:14 -+ let mut _14: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:+4:9: +4:14 -+ let mut _15: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:+4:9: +4:14 + let mut _0: (); // return place in scope 0 at $DIR/derefer_test_multiple.rs:2:12: 2:12 + let mut _1: (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:3:9: 3:14 + let mut _3: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:4:22: 4:28 + let mut _5: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:5:22: 5:28 + let mut _7: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:6:22: 6:28 ++ let mut _10: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14 ++ let mut _11: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14 ++ let mut _12: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14 ++ let mut _13: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14 ++ let mut _14: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14 ++ let mut _15: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:6:9: 6:14 scope 1 { - debug a => _1; // in scope 1 at $DIR/derefer_test_multiple.rs:+1:9: +1:14 - let mut _2: (i32, &mut (i32, i32)); // in scope 1 at $DIR/derefer_test_multiple.rs:+2:9: +2:14 + debug a => _1; // in scope 1 at $DIR/derefer_test_multiple.rs:3:9: 3:14 + let mut _2: (i32, &mut (i32, i32)); // in scope 1 at $DIR/derefer_test_multiple.rs:4:9: 4:14 scope 2 { - debug b => _2; // in scope 2 at $DIR/derefer_test_multiple.rs:+2:9: +2:14 - let mut _4: (i32, &mut (i32, &mut (i32, i32))); // in scope 2 at $DIR/derefer_test_multiple.rs:+3:9: +3:14 + debug b => _2; // in scope 2 at $DIR/derefer_test_multiple.rs:4:9: 4:14 + let mut _4: (i32, &mut (i32, &mut (i32, i32))); // in scope 2 at $DIR/derefer_test_multiple.rs:5:9: 5:14 scope 3 { - debug c => _4; // in scope 3 at $DIR/derefer_test_multiple.rs:+3:9: +3:14 - let mut _6: (i32, &mut (i32, &mut (i32, &mut (i32, i32)))); // in scope 3 at $DIR/derefer_test_multiple.rs:+4:9: +4:14 + debug c => _4; // in scope 3 at $DIR/derefer_test_multiple.rs:5:9: 5:14 + let mut _6: (i32, &mut (i32, &mut (i32, &mut (i32, i32)))); // in scope 3 at $DIR/derefer_test_multiple.rs:6:9: 6:14 scope 4 { - debug d => _6; // in scope 4 at $DIR/derefer_test_multiple.rs:+4:9: +4:14 - let _8: &mut i32; // in scope 4 at $DIR/derefer_test_multiple.rs:+5:9: +5:10 + debug d => _6; // in scope 4 at $DIR/derefer_test_multiple.rs:6:9: 6:14 + let _8: &mut i32; // in scope 4 at $DIR/derefer_test_multiple.rs:7:9: 7:10 scope 5 { - debug x => _8; // in scope 5 at $DIR/derefer_test_multiple.rs:+5:9: +5:10 - let _9: &mut i32; // in scope 5 at $DIR/derefer_test_multiple.rs:+6:9: +6:10 + debug x => _8; // in scope 5 at $DIR/derefer_test_multiple.rs:7:9: 7:10 + let _9: &mut i32; // in scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 scope 6 { - debug y => _9; // in scope 6 at $DIR/derefer_test_multiple.rs:+6:9: +6:10 + debug y => _9; // in scope 6 at $DIR/derefer_test_multiple.rs:8:9: 8:10 } } } @@ -38,59 +38,59 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/derefer_test_multiple.rs:+1:9: +1:14 - _1 = (const 42_i32, const 43_i32); // scope 0 at $DIR/derefer_test_multiple.rs:+1:17: +1:25 - StorageLive(_2); // scope 1 at $DIR/derefer_test_multiple.rs:+2:9: +2:14 - StorageLive(_3); // scope 1 at $DIR/derefer_test_multiple.rs:+2:22: +2:28 - _3 = &mut _1; // scope 1 at $DIR/derefer_test_multiple.rs:+2:22: +2:28 - _2 = (const 99_i32, move _3); // scope 1 at $DIR/derefer_test_multiple.rs:+2:17: +2:29 - StorageDead(_3); // scope 1 at $DIR/derefer_test_multiple.rs:+2:28: +2:29 - StorageLive(_4); // scope 2 at $DIR/derefer_test_multiple.rs:+3:9: +3:14 - StorageLive(_5); // scope 2 at $DIR/derefer_test_multiple.rs:+3:22: +3:28 - _5 = &mut _2; // scope 2 at $DIR/derefer_test_multiple.rs:+3:22: +3:28 - _4 = (const 11_i32, move _5); // scope 2 at $DIR/derefer_test_multiple.rs:+3:17: +3:29 - StorageDead(_5); // scope 2 at $DIR/derefer_test_multiple.rs:+3:28: +3:29 - StorageLive(_6); // scope 3 at $DIR/derefer_test_multiple.rs:+4:9: +4:14 - StorageLive(_7); // scope 3 at $DIR/derefer_test_multiple.rs:+4:22: +4:28 - _7 = &mut _4; // scope 3 at $DIR/derefer_test_multiple.rs:+4:22: +4:28 - _6 = (const 13_i32, move _7); // scope 3 at $DIR/derefer_test_multiple.rs:+4:17: +4:29 - StorageDead(_7); // scope 3 at $DIR/derefer_test_multiple.rs:+4:28: +4:29 - StorageLive(_8); // scope 4 at $DIR/derefer_test_multiple.rs:+5:9: +5:10 -- _8 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:+5:13: +5:30 -+ StorageLive(_10); // scope 4 at $DIR/derefer_test_multiple.rs:+5:13: +5:30 -+ _10 = deref_copy (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 4 at $DIR/derefer_test_multiple.rs:+5:13: +5:30 -+ StorageLive(_11); // scope 4 at $DIR/derefer_test_multiple.rs:+5:13: +5:30 -+ _11 = deref_copy ((*_10).1: &mut (i32, &mut (i32, i32))); // scope 4 at $DIR/derefer_test_multiple.rs:+5:13: +5:30 -+ StorageDead(_10); // scope 4 at $DIR/derefer_test_multiple.rs:+5:13: +5:30 -+ StorageLive(_12); // scope 4 at $DIR/derefer_test_multiple.rs:+5:13: +5:30 -+ _12 = deref_copy ((*_11).1: &mut (i32, i32)); // scope 4 at $DIR/derefer_test_multiple.rs:+5:13: +5:30 -+ StorageDead(_11); // scope 4 at $DIR/derefer_test_multiple.rs:+5:13: +5:30 -+ _8 = &mut ((*_12).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:+5:13: +5:30 -+ StorageDead(_12); // scope 5 at $DIR/derefer_test_multiple.rs:+6:9: +6:10 - StorageLive(_9); // scope 5 at $DIR/derefer_test_multiple.rs:+6:9: +6:10 -- _9 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:+6:13: +6:30 -+ StorageLive(_13); // scope 5 at $DIR/derefer_test_multiple.rs:+6:13: +6:30 -+ _13 = deref_copy (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 5 at $DIR/derefer_test_multiple.rs:+6:13: +6:30 -+ StorageLive(_14); // scope 5 at $DIR/derefer_test_multiple.rs:+6:13: +6:30 -+ _14 = deref_copy ((*_13).1: &mut (i32, &mut (i32, i32))); // scope 5 at $DIR/derefer_test_multiple.rs:+6:13: +6:30 -+ StorageDead(_13); // scope 5 at $DIR/derefer_test_multiple.rs:+6:13: +6:30 -+ StorageLive(_15); // scope 5 at $DIR/derefer_test_multiple.rs:+6:13: +6:30 -+ _15 = deref_copy ((*_14).1: &mut (i32, i32)); // scope 5 at $DIR/derefer_test_multiple.rs:+6:13: +6:30 -+ StorageDead(_14); // scope 5 at $DIR/derefer_test_multiple.rs:+6:13: +6:30 -+ _9 = &mut ((*_15).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:+6:13: +6:30 -+ StorageDead(_15); // scope 0 at $DIR/derefer_test_multiple.rs:+0:12: +7:2 - _0 = const (); // scope 0 at $DIR/derefer_test_multiple.rs:+0:12: +7:2 - StorageDead(_9); // scope 5 at $DIR/derefer_test_multiple.rs:+7:1: +7:2 - StorageDead(_8); // scope 4 at $DIR/derefer_test_multiple.rs:+7:1: +7:2 - StorageDead(_6); // scope 3 at $DIR/derefer_test_multiple.rs:+7:1: +7:2 - StorageDead(_4); // scope 2 at $DIR/derefer_test_multiple.rs:+7:1: +7:2 - StorageDead(_2); // scope 1 at $DIR/derefer_test_multiple.rs:+7:1: +7:2 - StorageDead(_1); // scope 0 at $DIR/derefer_test_multiple.rs:+7:1: +7:2 - return; // scope 0 at $DIR/derefer_test_multiple.rs:+7:2: +7:2 + StorageLive(_1); // scope 0 at $DIR/derefer_test_multiple.rs:3:9: 3:14 + _1 = (const 42_i32, const 43_i32); // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25 + StorageLive(_2); // scope 1 at $DIR/derefer_test_multiple.rs:4:9: 4:14 + StorageLive(_3); // scope 1 at $DIR/derefer_test_multiple.rs:4:22: 4:28 + _3 = &mut _1; // scope 1 at $DIR/derefer_test_multiple.rs:4:22: 4:28 + _2 = (const 99_i32, move _3); // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29 + StorageDead(_3); // scope 1 at $DIR/derefer_test_multiple.rs:4:28: 4:29 + StorageLive(_4); // scope 2 at $DIR/derefer_test_multiple.rs:5:9: 5:14 + StorageLive(_5); // scope 2 at $DIR/derefer_test_multiple.rs:5:22: 5:28 + _5 = &mut _2; // scope 2 at $DIR/derefer_test_multiple.rs:5:22: 5:28 + _4 = (const 11_i32, move _5); // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29 + StorageDead(_5); // scope 2 at $DIR/derefer_test_multiple.rs:5:28: 5:29 + StorageLive(_6); // scope 3 at $DIR/derefer_test_multiple.rs:6:9: 6:14 + StorageLive(_7); // scope 3 at $DIR/derefer_test_multiple.rs:6:22: 6:28 + _7 = &mut _4; // scope 3 at $DIR/derefer_test_multiple.rs:6:22: 6:28 + _6 = (const 13_i32, move _7); // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29 + StorageDead(_7); // scope 3 at $DIR/derefer_test_multiple.rs:6:28: 6:29 + StorageLive(_8); // scope 4 at $DIR/derefer_test_multiple.rs:7:9: 7:10 +- _8 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ StorageLive(_10); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _10 = deref_copy (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ StorageLive(_11); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _11 = deref_copy ((*_10).1: &mut (i32, &mut (i32, i32))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ StorageDead(_10); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ StorageLive(_12); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _12 = deref_copy ((*_11).1: &mut (i32, i32)); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ StorageDead(_11); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _8 = &mut ((*_12).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ StorageDead(_12); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 + StorageLive(_9); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 +- _9 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ StorageLive(_13); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _13 = deref_copy (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ StorageLive(_14); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _14 = deref_copy ((*_13).1: &mut (i32, &mut (i32, i32))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ StorageDead(_13); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ StorageLive(_15); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _15 = deref_copy ((*_14).1: &mut (i32, i32)); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ StorageDead(_14); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _9 = &mut ((*_15).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ StorageDead(_15); // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2 + _0 = const (); // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2 + StorageDead(_9); // scope 5 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + StorageDead(_8); // scope 4 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + StorageDead(_6); // scope 3 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + StorageDead(_4); // scope 2 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + StorageDead(_2); // scope 1 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + StorageDead(_1); // scope 0 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + return; // scope 0 at $DIR/derefer_test_multiple.rs:9:2: 9:2 + } + + bb1 (cleanup): { -+ resume; // scope 0 at $DIR/derefer_test_multiple.rs:+0:1: +7:2 ++ resume; // scope 0 at $DIR/derefer_test_multiple.rs:2:1: 9:2 } } diff --git a/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff index 8929f2cc779a7..97fb7fce14e40 100644 --- a/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff @@ -2,64 +2,64 @@ + // MIR for `main` after DestinationPropagation fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/branch.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/branch.rs:+1:9: +1:10 - let mut _3: bool; // in scope 0 at $DIR/branch.rs:+3:16: +3:22 - let _4: i32; // in scope 0 at $DIR/branch.rs:+6:9: +6:14 + let mut _0: (); // return place in scope 0 at $DIR/branch.rs:12:11: 12:11 + let _1: i32; // in scope 0 at $DIR/branch.rs:13:9: 13:10 + let mut _3: bool; // in scope 0 at $DIR/branch.rs:15:16: 15:22 + let _4: i32; // in scope 0 at $DIR/branch.rs:18:9: 18:14 scope 1 { - debug x => _1; // in scope 1 at $DIR/branch.rs:+1:9: +1:10 - let _2: i32; // in scope 1 at $DIR/branch.rs:+3:9: +3:10 + debug x => _1; // in scope 1 at $DIR/branch.rs:13:9: 13:10 + let _2: i32; // in scope 1 at $DIR/branch.rs:15:9: 15:10 scope 2 { - debug y => _2; // in scope 2 at $DIR/branch.rs:+3:9: +3:10 + debug y => _2; // in scope 2 at $DIR/branch.rs:15:9: 15:10 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/branch.rs:+1:9: +1:10 - _1 = val() -> bb1; // scope 0 at $DIR/branch.rs:+1:13: +1:18 + StorageLive(_1); // scope 0 at $DIR/branch.rs:13:9: 13:10 + _1 = val() -> bb1; // scope 0 at $DIR/branch.rs:13:13: 13:18 // mir::Constant // + span: $DIR/branch.rs:13:13: 13:16 // + literal: Const { ty: fn() -> i32 {val}, val: Value() } } bb1: { - StorageLive(_2); // scope 1 at $DIR/branch.rs:+3:9: +3:10 - StorageLive(_3); // scope 1 at $DIR/branch.rs:+3:16: +3:22 - _3 = cond() -> bb2; // scope 1 at $DIR/branch.rs:+3:16: +3:22 + StorageLive(_2); // scope 1 at $DIR/branch.rs:15:9: 15:10 + StorageLive(_3); // scope 1 at $DIR/branch.rs:15:16: 15:22 + _3 = cond() -> bb2; // scope 1 at $DIR/branch.rs:15:16: 15:22 // mir::Constant // + span: $DIR/branch.rs:15:16: 15:20 // + literal: Const { ty: fn() -> bool {cond}, val: Value() } } bb2: { - switchInt(move _3) -> [false: bb4, otherwise: bb3]; // scope 1 at $DIR/branch.rs:+3:16: +3:22 + switchInt(move _3) -> [false: bb4, otherwise: bb3]; // scope 1 at $DIR/branch.rs:15:16: 15:22 } bb3: { - nop; // scope 1 at $DIR/branch.rs:+4:9: +4:10 - goto -> bb6; // scope 1 at $DIR/branch.rs:+3:13: +8:6 + nop; // scope 1 at $DIR/branch.rs:16:9: 16:10 + goto -> bb6; // scope 1 at $DIR/branch.rs:15:13: 20:6 } bb4: { - StorageLive(_4); // scope 1 at $DIR/branch.rs:+6:9: +6:14 - _4 = val() -> bb5; // scope 1 at $DIR/branch.rs:+6:9: +6:14 + StorageLive(_4); // scope 1 at $DIR/branch.rs:18:9: 18:14 + _4 = val() -> bb5; // scope 1 at $DIR/branch.rs:18:9: 18:14 // mir::Constant // + span: $DIR/branch.rs:18:9: 18:12 // + literal: Const { ty: fn() -> i32 {val}, val: Value() } } bb5: { - StorageDead(_4); // scope 1 at $DIR/branch.rs:+6:14: +6:15 - nop; // scope 1 at $DIR/branch.rs:+7:9: +7:10 - goto -> bb6; // scope 1 at $DIR/branch.rs:+3:13: +8:6 + StorageDead(_4); // scope 1 at $DIR/branch.rs:18:14: 18:15 + nop; // scope 1 at $DIR/branch.rs:19:9: 19:10 + goto -> bb6; // scope 1 at $DIR/branch.rs:15:13: 20:6 } bb6: { - StorageDead(_3); // scope 1 at $DIR/branch.rs:+8:5: +8:6 - nop; // scope 0 at $DIR/branch.rs:+0:11: +9:2 - StorageDead(_2); // scope 1 at $DIR/branch.rs:+9:1: +9:2 - StorageDead(_1); // scope 0 at $DIR/branch.rs:+9:1: +9:2 - return; // scope 0 at $DIR/branch.rs:+9:2: +9:2 + StorageDead(_3); // scope 1 at $DIR/branch.rs:20:5: 20:6 + nop; // scope 0 at $DIR/branch.rs:12:11: 21:2 + StorageDead(_2); // scope 1 at $DIR/branch.rs:21:1: 21:2 + StorageDead(_1); // scope 0 at $DIR/branch.rs:21:1: 21:2 + return; // scope 0 at $DIR/branch.rs:21:2: 21:2 } } diff --git a/src/test/mir-opt/dest-prop/copy_propagation_arg.arg_src.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/copy_propagation_arg.arg_src.DestinationPropagation.diff index f28bc72df58cb..8919703647d6d 100644 --- a/src/test/mir-opt/dest-prop/copy_propagation_arg.arg_src.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.arg_src.DestinationPropagation.diff @@ -2,25 +2,25 @@ + // MIR for `arg_src` after DestinationPropagation fn arg_src(_1: i32) -> i32 { - debug x => const 123_i32; // in scope 0 at $DIR/copy_propagation_arg.rs:+0:12: +0:17 - let mut _0: i32; // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:27: +0:30 - let _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 + debug x => const 123_i32; // in scope 0 at $DIR/copy_propagation_arg.rs:27:12: 27:17 + let mut _0: i32; // return place in scope 0 at $DIR/copy_propagation_arg.rs:27:27: 27:30 + let _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 scope 1 { -- debug y => _2; // in scope 1 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 -+ debug y => _0; // in scope 1 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 +- debug y => _2; // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10 ++ debug y => _0; // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10 } bb0: { -- StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 -- _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+1:13: +1:14 -+ nop; // scope 0 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 -+ _0 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+1:13: +1:14 - nop; // scope 1 at $DIR/copy_propagation_arg.rs:+2:5: +2:12 -- _0 = _2; // scope 1 at $DIR/copy_propagation_arg.rs:+3:5: +3:6 -- StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+4:1: +4:2 -+ nop; // scope 1 at $DIR/copy_propagation_arg.rs:+3:5: +3:6 -+ nop; // scope 0 at $DIR/copy_propagation_arg.rs:+4:1: +4:2 - return; // scope 0 at $DIR/copy_propagation_arg.rs:+4:2: +4:2 +- StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 +- _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14 ++ nop; // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 ++ _0 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14 + nop; // scope 1 at $DIR/copy_propagation_arg.rs:29:5: 29:12 +- _0 = _2; // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6 +- StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2 ++ nop; // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6 ++ nop; // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2 + return; // scope 0 at $DIR/copy_propagation_arg.rs:31:2: 31:2 } } diff --git a/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff index a8a7e9ab6d44d..11a0d1f609f72 100644 --- a/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff @@ -2,27 +2,27 @@ + // MIR for `bar` after DestinationPropagation fn bar(_1: u8) -> () { - debug x => const 5_u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13 - let mut _0: (); // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +0:19 - let _2: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13 - let mut _3: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12 + debug x => const 5_u8; // in scope 0 at $DIR/copy_propagation_arg.rs:15:8: 15:13 + let mut _0: (); // return place in scope 0 at $DIR/copy_propagation_arg.rs:15:19: 15:19 + let _2: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13 + let mut _3: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:16:11: 16:12 bb0: { - StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13 - StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12 - _3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12 - _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13 + StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13 + StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:16:11: 16:12 + _3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:16:11: 16:12 + _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13 // mir::Constant // + span: $DIR/copy_propagation_arg.rs:16:5: 16:10 // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value() } } bb1: { - StorageDead(_3); // scope 0 at $DIR/copy_propagation_arg.rs:+1:12: +1:13 - StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+1:13: +1:14 - nop; // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:10 - nop; // scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +3:2 - return; // scope 0 at $DIR/copy_propagation_arg.rs:+3:2: +3:2 + StorageDead(_3); // scope 0 at $DIR/copy_propagation_arg.rs:16:12: 16:13 + StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:16:13: 16:14 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:17:5: 17:10 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:15:19: 18:2 + return; // scope 0 at $DIR/copy_propagation_arg.rs:18:2: 18:2 } } diff --git a/src/test/mir-opt/dest-prop/copy_propagation_arg.baz.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/copy_propagation_arg.baz.DestinationPropagation.diff index ce9be4c27183d..67ce87e842d04 100644 --- a/src/test/mir-opt/dest-prop/copy_propagation_arg.baz.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.baz.DestinationPropagation.diff @@ -2,17 +2,17 @@ + // MIR for `baz` after DestinationPropagation fn baz(_1: i32) -> () { - debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13 - let mut _0: (); // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:20: +0:20 - let mut _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10 + debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:21:8: 21:13 + let mut _0: (); // return place in scope 0 at $DIR/copy_propagation_arg.rs:21:20: 21:20 + let mut _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 bb0: { - StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10 - nop; // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10 - nop; // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:10 - StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10 - nop; // scope 0 at $DIR/copy_propagation_arg.rs:+0:20: +3:2 - return; // scope 0 at $DIR/copy_propagation_arg.rs:+3:2: +3:2 + StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10 + StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:21:20: 24:2 + return; // scope 0 at $DIR/copy_propagation_arg.rs:24:2: 24:2 } } diff --git a/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff index d7a0b950fc227..1346a04938a20 100644 --- a/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff @@ -2,27 +2,27 @@ + // MIR for `foo` after DestinationPropagation fn foo(_1: u8) -> () { - debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13 - let mut _0: (); // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +0:19 - let mut _2: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17 - let mut _3: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16 + debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:9:8: 9:13 + let mut _0: (); // return place in scope 0 at $DIR/copy_propagation_arg.rs:9:19: 9:19 + let mut _2: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 + let mut _3: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 bb0: { - StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17 - StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16 - _3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16 - _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17 + StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 + StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 + _3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 + _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 // mir::Constant // + span: $DIR/copy_propagation_arg.rs:11:9: 11:14 // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value() } } bb1: { - StorageDead(_3); // scope 0 at $DIR/copy_propagation_arg.rs:+2:16: +2:17 - nop; // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:17 - StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+2:16: +2:17 - nop; // scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +3:2 - return; // scope 0 at $DIR/copy_propagation_arg.rs:+3:2: +3:2 + StorageDead(_3); // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17 + StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:9:19: 12:2 + return; // scope 0 at $DIR/copy_propagation_arg.rs:12:2: 12:2 } } diff --git a/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff index 8eeb0d354c698..516180fbec68d 100644 --- a/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff @@ -2,19 +2,19 @@ + // MIR for `main` after DestinationPropagation fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:+0:11: +0:11 - let mut _1: i32; // in scope 0 at $DIR/cycle.rs:+1:9: +1:14 - let mut _4: i32; // in scope 0 at $DIR/cycle.rs:+4:9: +4:10 - let _5: (); // in scope 0 at $DIR/cycle.rs:+6:5: +6:12 - let mut _6: i32; // in scope 0 at $DIR/cycle.rs:+6:10: +6:11 + let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:8:11: 8:11 + let mut _1: i32; // in scope 0 at $DIR/cycle.rs:9:9: 9:14 + let mut _4: i32; // in scope 0 at $DIR/cycle.rs:12:9: 12:10 + let _5: (); // in scope 0 at $DIR/cycle.rs:14:5: 14:12 + let mut _6: i32; // in scope 0 at $DIR/cycle.rs:14:10: 14:11 scope 1 { - debug x => _1; // in scope 1 at $DIR/cycle.rs:+1:9: +1:14 - let _2: i32; // in scope 1 at $DIR/cycle.rs:+2:9: +2:10 + debug x => _1; // in scope 1 at $DIR/cycle.rs:9:9: 9:14 + let _2: i32; // in scope 1 at $DIR/cycle.rs:10:9: 10:10 scope 2 { - debug y => _2; // in scope 2 at $DIR/cycle.rs:+2:9: +2:10 - let _3: i32; // in scope 2 at $DIR/cycle.rs:+3:9: +3:10 + debug y => _2; // in scope 2 at $DIR/cycle.rs:10:9: 10:10 + let _3: i32; // in scope 2 at $DIR/cycle.rs:11:9: 11:10 scope 3 { - debug z => _3; // in scope 3 at $DIR/cycle.rs:+3:9: +3:10 + debug z => _3; // in scope 3 at $DIR/cycle.rs:11:9: 11:10 scope 4 (inlined std::mem::drop::) { // at $DIR/cycle.rs:14:5: 14:12 debug _x => _6; // in scope 4 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } @@ -23,31 +23,31 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/cycle.rs:+1:9: +1:14 - _1 = val() -> bb1; // scope 0 at $DIR/cycle.rs:+1:17: +1:22 + StorageLive(_1); // scope 0 at $DIR/cycle.rs:9:9: 9:14 + _1 = val() -> bb1; // scope 0 at $DIR/cycle.rs:9:17: 9:22 // mir::Constant // + span: $DIR/cycle.rs:9:17: 9:20 // + literal: Const { ty: fn() -> i32 {val}, val: Value() } } bb1: { - StorageLive(_2); // scope 1 at $DIR/cycle.rs:+2:9: +2:10 - nop; // scope 1 at $DIR/cycle.rs:+2:13: +2:14 - StorageLive(_3); // scope 2 at $DIR/cycle.rs:+3:9: +3:10 - nop; // scope 2 at $DIR/cycle.rs:+3:13: +3:14 - StorageLive(_4); // scope 3 at $DIR/cycle.rs:+4:9: +4:10 - nop; // scope 3 at $DIR/cycle.rs:+4:9: +4:10 - nop; // scope 3 at $DIR/cycle.rs:+4:5: +4:10 - StorageDead(_4); // scope 3 at $DIR/cycle.rs:+4:9: +4:10 - StorageLive(_5); // scope 3 at $DIR/cycle.rs:+6:5: +6:12 - StorageLive(_6); // scope 3 at $DIR/cycle.rs:+6:10: +6:11 - nop; // scope 3 at $DIR/cycle.rs:+6:10: +6:11 - StorageDead(_6); // scope 3 at $DIR/cycle.rs:+6:11: +6:12 - StorageDead(_5); // scope 3 at $DIR/cycle.rs:+6:12: +6:13 - StorageDead(_3); // scope 2 at $DIR/cycle.rs:+7:1: +7:2 - StorageDead(_2); // scope 1 at $DIR/cycle.rs:+7:1: +7:2 - StorageDead(_1); // scope 0 at $DIR/cycle.rs:+7:1: +7:2 - return; // scope 0 at $DIR/cycle.rs:+7:2: +7:2 + StorageLive(_2); // scope 1 at $DIR/cycle.rs:10:9: 10:10 + nop; // scope 1 at $DIR/cycle.rs:10:13: 10:14 + StorageLive(_3); // scope 2 at $DIR/cycle.rs:11:9: 11:10 + nop; // scope 2 at $DIR/cycle.rs:11:13: 11:14 + StorageLive(_4); // scope 3 at $DIR/cycle.rs:12:9: 12:10 + nop; // scope 3 at $DIR/cycle.rs:12:9: 12:10 + nop; // scope 3 at $DIR/cycle.rs:12:5: 12:10 + StorageDead(_4); // scope 3 at $DIR/cycle.rs:12:9: 12:10 + StorageLive(_5); // scope 3 at $DIR/cycle.rs:14:5: 14:12 + StorageLive(_6); // scope 3 at $DIR/cycle.rs:14:10: 14:11 + nop; // scope 3 at $DIR/cycle.rs:14:10: 14:11 + StorageDead(_6); // scope 3 at $DIR/cycle.rs:14:11: 14:12 + StorageDead(_5); // scope 3 at $DIR/cycle.rs:14:12: 14:13 + StorageDead(_3); // scope 2 at $DIR/cycle.rs:15:1: 15:2 + StorageDead(_2); // scope 1 at $DIR/cycle.rs:15:1: 15:2 + StorageDead(_1); // scope 0 at $DIR/cycle.rs:15:1: 15:2 + return; // scope 0 at $DIR/cycle.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff index a20a172af1bbc..3475d41b50fbd 100644 --- a/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff @@ -2,38 +2,38 @@ + // MIR for `nrvo` after DestinationPropagation fn nrvo(_1: for<'r> fn(&'r mut [u8; 1024])) -> [u8; 1024] { - debug init => _1; // in scope 0 at $DIR/simple.rs:+0:9: +0:13 - let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/simple.rs:+0:39: +0:49 - let mut _2: [u8; 1024]; // in scope 0 at $DIR/simple.rs:+1:9: +1:16 - let _3: (); // in scope 0 at $DIR/simple.rs:+2:5: +2:19 - let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/simple.rs:+2:5: +2:9 - let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/simple.rs:+2:10: +2:18 - let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/simple.rs:+2:10: +2:18 + debug init => _1; // in scope 0 at $DIR/simple.rs:4:9: 4:13 + let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/simple.rs:4:39: 4:49 + let mut _2: [u8; 1024]; // in scope 0 at $DIR/simple.rs:5:9: 5:16 + let _3: (); // in scope 0 at $DIR/simple.rs:6:5: 6:19 + let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/simple.rs:6:5: 6:9 + let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/simple.rs:6:10: 6:18 + let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/simple.rs:6:10: 6:18 scope 1 { - debug buf => _2; // in scope 1 at $DIR/simple.rs:+1:9: +1:16 + debug buf => _2; // in scope 1 at $DIR/simple.rs:5:9: 5:16 } bb0: { - StorageLive(_2); // scope 0 at $DIR/simple.rs:+1:9: +1:16 - _2 = [const 0_u8; 1024]; // scope 0 at $DIR/simple.rs:+1:19: +1:28 - StorageLive(_3); // scope 1 at $DIR/simple.rs:+2:5: +2:19 - StorageLive(_4); // scope 1 at $DIR/simple.rs:+2:5: +2:9 - _4 = _1; // scope 1 at $DIR/simple.rs:+2:5: +2:9 - StorageLive(_5); // scope 1 at $DIR/simple.rs:+2:10: +2:18 - StorageLive(_6); // scope 1 at $DIR/simple.rs:+2:10: +2:18 - _6 = &mut _2; // scope 1 at $DIR/simple.rs:+2:10: +2:18 - _5 = &mut (*_6); // scope 1 at $DIR/simple.rs:+2:10: +2:18 - _3 = move _4(move _5) -> bb1; // scope 1 at $DIR/simple.rs:+2:5: +2:19 + StorageLive(_2); // scope 0 at $DIR/simple.rs:5:9: 5:16 + _2 = [const 0_u8; 1024]; // scope 0 at $DIR/simple.rs:5:19: 5:28 + StorageLive(_3); // scope 1 at $DIR/simple.rs:6:5: 6:19 + StorageLive(_4); // scope 1 at $DIR/simple.rs:6:5: 6:9 + _4 = _1; // scope 1 at $DIR/simple.rs:6:5: 6:9 + StorageLive(_5); // scope 1 at $DIR/simple.rs:6:10: 6:18 + StorageLive(_6); // scope 1 at $DIR/simple.rs:6:10: 6:18 + _6 = &mut _2; // scope 1 at $DIR/simple.rs:6:10: 6:18 + _5 = &mut (*_6); // scope 1 at $DIR/simple.rs:6:10: 6:18 + _3 = move _4(move _5) -> bb1; // scope 1 at $DIR/simple.rs:6:5: 6:19 } bb1: { - StorageDead(_5); // scope 1 at $DIR/simple.rs:+2:18: +2:19 - StorageDead(_4); // scope 1 at $DIR/simple.rs:+2:18: +2:19 - StorageDead(_6); // scope 1 at $DIR/simple.rs:+2:19: +2:20 - StorageDead(_3); // scope 1 at $DIR/simple.rs:+2:19: +2:20 - _0 = _2; // scope 1 at $DIR/simple.rs:+3:5: +3:8 - StorageDead(_2); // scope 0 at $DIR/simple.rs:+4:1: +4:2 - return; // scope 0 at $DIR/simple.rs:+4:2: +4:2 + StorageDead(_5); // scope 1 at $DIR/simple.rs:6:18: 6:19 + StorageDead(_4); // scope 1 at $DIR/simple.rs:6:18: 6:19 + StorageDead(_6); // scope 1 at $DIR/simple.rs:6:19: 6:20 + StorageDead(_3); // scope 1 at $DIR/simple.rs:6:19: 6:20 + _0 = _2; // scope 1 at $DIR/simple.rs:7:5: 7:8 + StorageDead(_2); // scope 0 at $DIR/simple.rs:8:1: 8:2 + return; // scope 0 at $DIR/simple.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff index accdb00852ede..acfd3c18fc930 100644 --- a/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff @@ -2,13 +2,13 @@ + // MIR for `main` after DestinationPropagation fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/union.rs:+0:11: +0:11 - let _1: main::Un; // in scope 0 at $DIR/union.rs:+5:9: +5:11 - let mut _2: u32; // in scope 0 at $DIR/union.rs:+5:23: +5:28 - let _3: (); // in scope 0 at $DIR/union.rs:+7:5: +7:27 - let mut _4: u32; // in scope 0 at $DIR/union.rs:+7:10: +7:26 + let mut _0: (); // return place in scope 0 at $DIR/union.rs:8:11: 8:11 + let _1: main::Un; // in scope 0 at $DIR/union.rs:13:9: 13:11 + let mut _2: u32; // in scope 0 at $DIR/union.rs:13:23: 13:28 + let _3: (); // in scope 0 at $DIR/union.rs:15:5: 15:27 + let mut _4: u32; // in scope 0 at $DIR/union.rs:15:10: 15:26 scope 1 { - debug un => _1; // in scope 1 at $DIR/union.rs:+5:9: +5:11 + debug un => _1; // in scope 1 at $DIR/union.rs:13:9: 13:11 scope 2 { } scope 3 (inlined std::mem::drop::) { // at $DIR/union.rs:15:5: 15:27 @@ -17,25 +17,25 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/union.rs:+5:9: +5:11 - StorageLive(_2); // scope 0 at $DIR/union.rs:+5:23: +5:28 - _2 = val() -> bb1; // scope 0 at $DIR/union.rs:+5:23: +5:28 + StorageLive(_1); // scope 0 at $DIR/union.rs:13:9: 13:11 + StorageLive(_2); // scope 0 at $DIR/union.rs:13:23: 13:28 + _2 = val() -> bb1; // scope 0 at $DIR/union.rs:13:23: 13:28 // mir::Constant // + span: $DIR/union.rs:13:23: 13:26 // + literal: Const { ty: fn() -> u32 {val}, val: Value() } } bb1: { - nop; // scope 0 at $DIR/union.rs:+5:14: +5:30 - nop; // scope 0 at $DIR/union.rs:+5:14: +5:30 - StorageDead(_2); // scope 0 at $DIR/union.rs:+5:29: +5:30 - StorageLive(_3); // scope 1 at $DIR/union.rs:+7:5: +7:27 - StorageLive(_4); // scope 1 at $DIR/union.rs:+7:10: +7:26 - nop; // scope 2 at $DIR/union.rs:+7:19: +7:24 - StorageDead(_4); // scope 1 at $DIR/union.rs:+7:26: +7:27 - StorageDead(_3); // scope 1 at $DIR/union.rs:+7:27: +7:28 - StorageDead(_1); // scope 0 at $DIR/union.rs:+8:1: +8:2 - return; // scope 0 at $DIR/union.rs:+8:2: +8:2 + nop; // scope 0 at $DIR/union.rs:13:14: 13:30 + nop; // scope 0 at $DIR/union.rs:13:14: 13:30 + StorageDead(_2); // scope 0 at $DIR/union.rs:13:29: 13:30 + StorageLive(_3); // scope 1 at $DIR/union.rs:15:5: 15:27 + StorageLive(_4); // scope 1 at $DIR/union.rs:15:10: 15:26 + nop; // scope 2 at $DIR/union.rs:15:19: 15:24 + StorageDead(_4); // scope 1 at $DIR/union.rs:15:26: 15:27 + StorageDead(_3); // scope 1 at $DIR/union.rs:15:27: 15:28 + StorageDead(_1); // scope 0 at $DIR/union.rs:16:1: 16:2 + return; // scope 0 at $DIR/union.rs:16:2: 16:2 } } diff --git a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff index 89d8106ae3ce7..e40274dc39340 100644 --- a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff @@ -2,77 +2,77 @@ + // MIR for `opt1` after EarlyOtherwiseBranch fn opt1(_1: Option, _2: Option) -> u32 { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:+0:9: +0:10 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:+0:25: +0:26 - let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch.rs:+0:44: +0:47 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:+1:12: +1:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:+1:15: +1:16 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:+2:19: +2:26 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:+2:10: +2:17 - let _8: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:+2:15: +2:16 - let _9: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:+2:24: +2:25 -+ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:3:9: 3:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:3:25: 3:26 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch.rs:3:44: 3:47 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:4:12: 4:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:4:15: 4:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 + let _8: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + let _9: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:5:24: 5:25 ++ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 ++ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 scope 1 { - debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:+2:15: +2:16 - debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:+2:24: +2:25 + debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:5:24: 5:25 } bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:+1:12: +1:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:+1:12: +1:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:+1:15: +1:16 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:+1:15: +1:16 - Deinit(_3); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17 - _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 -- switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ _10 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ _11 = Ne(_7, move _10); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ switchInt(move _11) -> [false: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:4:12: 4:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:4:12: 4:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:4:15: 4:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:4:15: 4:16 + Deinit(_3); // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:4:16: 4:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:4:16: 4:17 + _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 +- switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 ++ StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 ++ _10 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 ++ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 ++ _11 = Ne(_7, move _10); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 ++ StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 ++ switchInt(move _11) -> [false: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 } bb1: { -+ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:+3:14: +3:15 - _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:+3:14: +3:15 -- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:+3:14: +3:15 -+ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:+3:14: +3:15 ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 +- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 ++ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 } bb2: { -- _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 -- switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 +- _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 +- switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 - } - - bb3: { - StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:+2:15: +2:16 - _8 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:+2:15: +2:16 - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:+2:24: +2:25 - _9 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:+2:24: +2:25 - _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:+2:31: +2:32 - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:+2:31: +2:32 - StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:+2:31: +2:32 -- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:+2:31: +2:32 -+ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:+2:31: +2:32 + StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + _8 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:5:24: 5:25 + _9 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:5:24: 5:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:5:31: 5:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:5:31: 5:32 + StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:5:31: 5:32 +- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:5:31: 5:32 ++ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:5:31: 5:32 } - bb4: { + bb3: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:+5:1: +5:2 - return; // scope 0 at $DIR/early_otherwise_branch.rs:+5:2: +5:2 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:8:1: 8:2 + return; // scope 0 at $DIR/early_otherwise_branch.rs:8:2: 8:2 + } + + bb4: { -+ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 ++ switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 } } diff --git a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff index 1a9efa930036c..1cdd97ab283bc 100644 --- a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff @@ -2,91 +2,91 @@ + // MIR for `opt2` after EarlyOtherwiseBranch fn opt2(_1: Option, _2: Option) -> u32 { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:+0:9: +0:10 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:+0:25: +0:26 - let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch.rs:+0:44: +0:47 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:+1:12: +1:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:+1:15: +1:16 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:+3:16: +3:20 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:+2:19: +2:26 - let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:+2:10: +2:17 - let _9: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:+2:15: +2:16 - let _10: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:+2:24: +2:25 -+ let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ let mut _12: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:11:9: 11:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:11:25: 11:26 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch.rs:11:44: 11:47 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:12:12: 12:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:12:15: 12:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:13:19: 13:26 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 + let _9: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + let _10: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:13:24: 13:25 ++ let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 ++ let mut _12: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 scope 1 { - debug a => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:+2:15: +2:16 - debug b => _10; // in scope 1 at $DIR/early_otherwise_branch.rs:+2:24: +2:25 + debug a => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + debug b => _10; // in scope 1 at $DIR/early_otherwise_branch.rs:13:24: 13:25 } bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:+1:12: +1:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:+1:12: +1:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:+1:15: +1:16 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:+1:15: +1:16 - Deinit(_3); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17 - _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 -- switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ _11 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ _12 = Ne(_8, move _11); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ switchInt(move _12) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:12:12: 12:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:12:12: 12:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:12:15: 12:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:12:15: 12:16 + Deinit(_3); // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17 + _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 +- switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 ++ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 ++ _11 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 ++ StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 ++ _12 = Ne(_8, move _11); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 ++ switchInt(move _12) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 } bb1: { -- _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 -- switchInt(move _6) -> [0_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 +- _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 +- switchInt(move _6) -> [0_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 - } - - bb2: { -+ StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:+4:14: +4:15 - _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:+4:14: +4:15 -- goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:+4:14: +4:15 -+ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:+4:14: +4:15 ++ StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15 + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15 +- goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15 } - bb3: { -- _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 -- switchInt(move _7) -> [1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 +- _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 +- switchInt(move _7) -> [1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 - } - - bb4: { + bb2: { - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:+2:15: +2:16 - _9 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:+2:15: +2:16 - StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:+2:24: +2:25 - _10 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:+2:24: +2:25 - _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:+2:31: +2:32 - StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:+2:31: +2:32 - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:+2:31: +2:32 -- goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:+2:31: +2:32 -+ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:+2:31: +2:32 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + _9 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:13:24: 13:25 + _10 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:13:24: 13:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:13:31: 13:32 + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:13:31: 13:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:13:31: 13:32 +- goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:13:31: 13:32 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:13:31: 13:32 } - bb5: { + bb3: { - _0 = const 0_u32; // scope 0 at $DIR/early_otherwise_branch.rs:+3:25: +3:26 -- goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:+3:25: +3:26 -+ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:+3:25: +3:26 + _0 = const 0_u32; // scope 0 at $DIR/early_otherwise_branch.rs:14:25: 14:26 +- goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:14:25: 14:26 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:14:25: 14:26 } - bb6: { + bb4: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:+6:1: +6:2 - return; // scope 0 at $DIR/early_otherwise_branch.rs:+6:2: +6:2 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:17:1: 17:2 + return; // scope 0 at $DIR/early_otherwise_branch.rs:17:2: 17:2 + } + + bb5: { -+ StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 ++ StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 ++ switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 } } diff --git a/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff index 309a72ae58b68..96c7e46853f14 100644 --- a/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff @@ -2,77 +2,77 @@ + // MIR for `opt3` after EarlyOtherwiseBranch fn opt3(_1: Option, _2: Option) -> u32 { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:+0:9: +0:10 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:+0:25: +0:26 - let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch.rs:+0:45: +0:48 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:+1:12: +1:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:+1:15: +1:16 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:+2:19: +2:26 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:+2:10: +2:17 - let _8: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:+2:15: +2:16 - let _9: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:+2:24: +2:25 -+ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:21:9: 21:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:21:25: 21:26 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch.rs:21:45: 21:48 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:22:12: 22:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:22:15: 22:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:23:19: 23:26 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:23:10: 23:17 + let _8: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:23:15: 23:16 + let _9: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:23:24: 23:25 ++ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 ++ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 scope 1 { - debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:+2:15: +2:16 - debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:+2:24: +2:25 + debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:23:15: 23:16 + debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:23:24: 23:25 } bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:+1:12: +1:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:+1:12: +1:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:+1:15: +1:16 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:+1:15: +1:16 - Deinit(_3); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17 - _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 -- switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ _10 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ _11 = Ne(_7, move _10); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ switchInt(move _11) -> [false: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:22:12: 22:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:22:12: 22:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:22:15: 22:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:22:15: 22:16 + Deinit(_3); // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:22:16: 22:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:22:16: 22:17 + _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 +- switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 ++ StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 ++ _10 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 ++ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 ++ _11 = Ne(_7, move _10); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 ++ StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 ++ switchInt(move _11) -> [false: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 } bb1: { -+ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:+3:14: +3:15 - _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:+3:14: +3:15 -- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:+3:14: +3:15 -+ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:+3:14: +3:15 ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:24:14: 24:15 + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:24:14: 24:15 +- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:24:14: 24:15 ++ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:24:14: 24:15 } bb2: { -- _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17 -- switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 +- _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 +- switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 - } - - bb3: { - StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:+2:15: +2:16 - _8 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:+2:15: +2:16 - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:+2:24: +2:25 - _9 = (((_3.1: std::option::Option) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch.rs:+2:24: +2:25 - _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:+2:31: +2:32 - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:+2:31: +2:32 - StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:+2:31: +2:32 -- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:+2:31: +2:32 -+ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:+2:31: +2:32 + StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:23:15: 23:16 + _8 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:23:15: 23:16 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:23:24: 23:25 + _9 = (((_3.1: std::option::Option) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch.rs:23:24: 23:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:23:31: 23:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:23:31: 23:32 + StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:23:31: 23:32 +- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:23:31: 23:32 ++ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:23:31: 23:32 } - bb4: { + bb3: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:+5:1: +5:2 - return; // scope 0 at $DIR/early_otherwise_branch.rs:+5:2: +5:2 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:26:1: 26:2 + return; // scope 0 at $DIR/early_otherwise_branch.rs:26:2: 26:2 + } + + bb4: { -+ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 -+ switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17 ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 ++ switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 } } diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff index 9574f32f7f06b..379d0e9ea48b3 100644 --- a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff @@ -2,99 +2,99 @@ + // MIR for `opt1` after EarlyOtherwiseBranch fn opt1(_1: Option, _2: Option, _3: Option) -> u32 { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+0:9: +0:10 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+0:25: +0:26 - debug z => _3; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+0:41: +0:42 - let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+0:60: +0:63 - let mut _4: (std::option::Option, std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:12: +1:13 - let mut _6: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:15: +1:16 - let mut _7: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:18: +1:19 - let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:28: +2:35 - let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:19: +2:26 - let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:10: +2:17 - let _11: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:15: +2:16 - let _12: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:24: +2:25 - let _13: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:33: +2:34 -+ let mut _14: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20 -+ let mut _15: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20 -+ let mut _16: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20 -+ let mut _17: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20 + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:9: 4:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:25: 4:26 + debug z => _3; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:41: 4:42 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:60: 4:63 + let mut _4: (std::option::Option, std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:12: 5:13 + let mut _6: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:15: 5:16 + let mut _7: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:18: 5:19 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 + let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 + let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 + let _11: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 + let _12: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 + let _13: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 ++ let mut _14: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ let mut _15: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ let mut _16: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ let mut _17: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 scope 1 { - debug a => _11; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:15: +2:16 - debug b => _12; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:24: +2:25 - debug c => _13; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:33: +2:34 + debug a => _11; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 + debug b => _12; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 + debug c => _13; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 } bb0: { - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:12: +1:13 - _5 = _1; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:12: +1:13 - StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:15: +1:16 - _6 = _2; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:15: +1:16 - StorageLive(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:18: +1:19 - _7 = _3; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:18: +1:19 - Deinit(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20 - (_4.0: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20 - (_4.1: std::option::Option) = move _6; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20 - (_4.2: std::option::Option) = move _7; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20 - StorageDead(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:19: +1:20 - StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:19: +1:20 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:19: +1:20 - _10 = discriminant((_4.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20 -- switchInt(move _10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20 -+ StorageLive(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20 -+ _14 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20 -+ StorageLive(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20 -+ _15 = Ne(_10, move _14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20 -+ StorageDead(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20 -+ switchInt(move _15) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:12: 5:13 + _5 = _1; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:12: 5:13 + StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:15: 5:16 + _6 = _2; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:15: 5:16 + StorageLive(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:18: 5:19 + _7 = _3; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:18: 5:19 + Deinit(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + (_4.0: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + (_4.1: std::option::Option) = move _6; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + (_4.2: std::option::Option) = move _7; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + StorageDead(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:19: 5:20 + StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:19: 5:20 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:19: 5:20 + _10 = discriminant((_4.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 +- switchInt(move _10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ StorageLive(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ _14 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ StorageLive(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ _15 = Ne(_10, move _14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ StorageDead(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ switchInt(move _15) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 } bb1: { -+ StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+3:14: +3:15 -+ StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+3:14: +3:15 - _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+3:14: +3:15 -- goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+3:14: +3:15 -+ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+3:14: +3:15 ++ StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 ++ StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 +- goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 } bb2: { -- _9 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20 -- switchInt(move _9) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20 +- _9 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 +- switchInt(move _9) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 - } - - bb3: { - _8 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20 -- switchInt(move _8) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20 -+ switchInt(move _8) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20 + _8 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 +- switchInt(move _8) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ switchInt(move _8) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 } - bb4: { + bb3: { - StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:15: +2:16 - _11 = (((_4.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:15: +2:16 - StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:24: +2:25 - _12 = (((_4.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:24: +2:25 - StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:33: +2:34 - _13 = (((_4.2: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:33: +2:34 - _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:40: +2:41 - StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:40: +2:41 - StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:40: +2:41 - StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:40: +2:41 -- goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:40: +2:41 -+ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+2:40: +2:41 + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 + _11 = (((_4.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 + _12 = (((_4.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 + StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 + _13 = (((_4.2: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 + StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 +- goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 } - bb5: { + bb4: { - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+5:1: +5:2 - return; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+5:2: +5:2 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:1: 9:2 + return; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:2: 9:2 + } + + bb5: { -+ StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20 -+ switchInt(_10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20 ++ StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ switchInt(_10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 } } diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff index 4e6852ad7b6a5..988694000ee99 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff @@ -2,343 +2,343 @@ + // MIR for `try_sum` after SimplifyConstCondition-final fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> Result { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+1:5: +1:6 - debug other => _2; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+2:5: +2:10 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:+3:6: +3:42 - let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +11:6 - let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16 - let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:21: +6:30 - let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:21: +7:30 - let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:23: +8:34 - let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:23: +9:34 - let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:11: +6:18 - let _12: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 - let _13: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 - let mut _14: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49 - let mut _15: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41 - let mut _16: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49 - let _17: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 - let _18: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 - let mut _19: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49 - let mut _20: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41 - let mut _21: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49 - let _22: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 - let _23: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 - let mut _24: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55 - let mut _25: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47 - let mut _26: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55 - let _27: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 - let _28: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 - let mut _29: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55 - let mut _30: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47 - let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55 - let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:14: +10:28 - let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27 - let mut _34: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _35: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _36: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _37: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _38: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _39: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _40: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _41: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _42: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _43: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _44: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _45: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _46: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:17:5: 17:6 + debug other => _2; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:18:5: 18:10 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:6: 19:42 + let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 27:6 + let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16 + let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:18: 21:23 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:23: 24:34 + let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 + let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:11: 22:18 + let _12: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + let _13: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + let mut _14: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49 + let mut _15: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41 + let mut _16: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49 + let _17: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + let _18: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + let mut _19: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + let mut _20: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 + let mut _21: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 + let _22: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + let _23: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + let mut _24: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55 + let mut _25: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47 + let mut _26: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55 + let _27: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + let _28: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + let mut _29: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + let mut _30: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 + let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 + let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:14: 26:28 + let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27 + let mut _34: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _35: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _36: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _37: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _38: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _39: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _40: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _41: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _42: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _43: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _44: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _45: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _46: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 scope 1 { -- debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 -- debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 -+ debug one => _15; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 -+ debug other => _16; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 +- debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 +- debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 ++ debug one => _15; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 ++ debug other => _16; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 } scope 2 { -- debug one => _17; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 -- debug other => _18; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 -+ debug one => _20; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 -+ debug other => _21; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 +- debug one => _17; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 +- debug other => _18; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 ++ debug one => _20; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 ++ debug other => _21; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 } scope 3 { -- debug one => _22; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 -- debug other => _23; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 -+ debug one => _25; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 -+ debug other => _26; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 +- debug one => _22; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 +- debug other => _23; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 ++ debug one => _25; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 ++ debug other => _26; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 } scope 4 { -- debug one => _27; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 -- debug other => _28; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 -+ debug one => _30; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 -+ debug other => _31; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 +- debug one => _27; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 +- debug other => _28; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 ++ debug one => _30; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 ++ debug other => _31; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 } bb0: { -- StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +11:6 -- StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 -- StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16 -- _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +11:6 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16 -+ (_4.0: &ViewportPercentageLength) = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16 - StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23 - _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23 - Deinit(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 -- (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24 -- StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24 - StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _34 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _11 = discriminant((*_34)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 - switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 +- StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 27:6 +- StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 +- StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16 +- _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 27:6 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16 ++ (_4.0: &ViewportPercentageLength) = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16 + StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:18: 21:23 + _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:18: 21:23 + Deinit(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 +- (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24 +- StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24 + StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _34 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _11 = discriminant((*_34)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 } bb1: { - StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _35 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _7 = discriminant((*_35)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 - switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 + StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _35 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _7 = discriminant((*_35)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 } bb2: { - StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27 - nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27 - Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28 - nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28 - discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28 - StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:27: +10:28 -- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7 -- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2 - return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2 + StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27 + Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28 + discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28 + StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:27: 26:28 +- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7 +- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2 + return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2 } bb3: { - StorageLive(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _36 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _8 = discriminant((*_36)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - StorageDead(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 - switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 + StorageLive(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _36 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _8 = discriminant((*_36)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + StorageDead(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 } bb4: { - StorageLive(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _37 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _9 = discriminant((*_37)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - StorageDead(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 - switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 + StorageLive(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _37 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _9 = discriminant((*_37)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + StorageDead(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 } bb5: { - StorageLive(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _38 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _10 = discriminant((*_38)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - StorageDead(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 - switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 + StorageLive(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _38 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _10 = discriminant((*_38)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + StorageDead(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 } bb6: { -- StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 - StorageLive(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 - _39 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 -- _12 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 -+ _15 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 - StorageDead(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 -- StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 - StorageLive(_40); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 - _40 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 -- _13 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 -+ _16 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 - StorageDead(_40); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49 -- StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49 -- StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41 -- _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41 -- StorageLive(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49 -- _16 = _13; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49 -- _14 = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49 -- StorageDead(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49 -- StorageDead(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49 -- Deinit(_3); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50 -- ((_3 as Vw).0: f32) = move _14; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50 -- discriminant(_3) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50 -- StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 -- StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 -- StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49 -+ ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49 -+ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50 -+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 - goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 +- StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + StorageLive(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + _39 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 +- _12 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 ++ _15 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + StorageDead(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 +- StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + StorageLive(_40); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + _40 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 +- _13 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 ++ _16 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + StorageDead(_40); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49 +- StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49 +- StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41 +- _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41 +- StorageLive(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49 +- _16 = _13; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49 +- _14 = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49 +- StorageDead(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49 +- StorageDead(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49 +- Deinit(_3); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50 +- ((_3 as Vw).0: f32) = move _14; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50 +- discriminant(_3) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50 +- StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50 +- StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50 +- StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49 ++ ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49 ++ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50 ++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50 + goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50 } bb7: { -- StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 - StorageLive(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 - _41 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 -- _17 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 -+ _20 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 - StorageDead(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 -- StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 - StorageLive(_42); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 - _42 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 -- _18 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 -+ _21 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 - StorageDead(_42); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49 -- StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49 -- StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41 -- _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41 -- StorageLive(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49 -- _21 = _18; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49 -- _19 = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49 -- StorageDead(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49 -- StorageDead(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49 -- Deinit(_3); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50 -- ((_3 as Vh).0: f32) = move _19; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50 -- discriminant(_3) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50 -- StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 -- StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 -- StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49 -+ ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49 -+ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50 -+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 - goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 +- StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + StorageLive(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + _41 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 +- _17 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 ++ _20 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + StorageDead(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 +- StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + StorageLive(_42); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + _42 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 +- _18 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 ++ _21 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + StorageDead(_42); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 +- StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 +- StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 +- _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 +- StorageLive(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 +- _21 = _18; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 +- _19 = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 +- StorageDead(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 +- StorageDead(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 +- Deinit(_3); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 +- ((_3 as Vh).0: f32) = move _19; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 +- discriminant(_3) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 +- StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 +- StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 +- StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 ++ ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 ++ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 ++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 + goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 } bb8: { -- StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 - StorageLive(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 - _43 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 -- _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 -+ _25 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 - StorageDead(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 -- StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 - StorageLive(_44); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 - _44 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 -- _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 -+ _26 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 - StorageDead(_44); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55 -- StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55 -- StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47 -- _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47 -- StorageLive(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55 -- _26 = _23; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55 -- _24 = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55 -- StorageDead(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55 -- StorageDead(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55 -- Deinit(_3); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56 -- ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56 -- discriminant(_3) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56 -- StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 -- StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 -- StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55 -+ ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55 -+ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56 -+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 - goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 +- StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + StorageLive(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + _43 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 +- _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 ++ _25 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + StorageDead(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 +- StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + StorageLive(_44); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + _44 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 +- _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 ++ _26 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + StorageDead(_44); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55 +- StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55 +- StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47 +- _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47 +- StorageLive(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55 +- _26 = _23; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55 +- _24 = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55 +- StorageDead(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55 +- StorageDead(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55 +- Deinit(_3); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56 +- ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56 +- discriminant(_3) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56 +- StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56 +- StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56 +- StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55 ++ ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55 ++ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56 ++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56 + goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56 } bb9: { -- StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 - StorageLive(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 - _45 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 -- _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 -+ _30 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 - StorageDead(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 -- StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 - StorageLive(_46); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 - _46 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 -- _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 -+ _31 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 - StorageDead(_46); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55 -- StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55 -- StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47 -- _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47 -- StorageLive(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55 -- _31 = _28; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55 -- _29 = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55 -- StorageDead(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55 -- StorageDead(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55 -- Deinit(_3); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56 -- ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56 -- discriminant(_3) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56 -- StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 -- StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 -- StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55 -+ ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55 -+ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56 -+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 - goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 +- StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + StorageLive(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + _45 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 +- _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 ++ _30 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + StorageDead(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 +- StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + StorageLive(_46); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + _46 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 +- _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 ++ _31 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + StorageDead(_46); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 +- StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 +- StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 +- _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 +- StorageLive(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 +- _31 = _28; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 +- _29 = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 +- StorageDead(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 +- StorageDead(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 +- Deinit(_3); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 +- ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 +- discriminant(_3) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 +- StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 +- StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 +- StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 ++ ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 ++ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 ++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 + goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 } bb10: { - Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7 -- ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7 - discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7 -- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7 -- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2 - return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2 + Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7 +- ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7 + discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7 +- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7 +- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2 + return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2 } } diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff index 2519f79f8254e..1b090a33ffcd7 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -2,252 +2,252 @@ + // MIR for `try_sum` after EarlyOtherwiseBranch fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> Result { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+1:5: +1:6 - debug other => _2; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+2:5: +2:10 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:+3:6: +3:42 - let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +11:6 - let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16 - let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:21: +6:30 - let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:21: +7:30 - let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:23: +8:34 - let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:23: +9:34 - let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:11: +6:18 - let _12: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 - let _13: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 - let mut _14: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49 - let mut _15: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41 - let mut _16: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49 - let _17: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 - let _18: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 - let mut _19: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49 - let mut _20: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41 - let mut _21: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49 - let _22: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 - let _23: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 - let mut _24: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55 - let mut _25: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47 - let mut _26: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55 - let _27: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 - let _28: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 - let mut _29: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55 - let mut _30: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47 - let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55 - let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:14: +10:28 - let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27 - let mut _34: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _35: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _36: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _37: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _38: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _39: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _40: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _41: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _42: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _43: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _44: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _45: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _46: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:17:5: 17:6 + debug other => _2; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:18:5: 18:10 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:6: 19:42 + let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 27:6 + let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16 + let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:18: 21:23 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:23: 24:34 + let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 + let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:11: 22:18 + let _12: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + let _13: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + let mut _14: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49 + let mut _15: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41 + let mut _16: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49 + let _17: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + let _18: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + let mut _19: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + let mut _20: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 + let mut _21: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 + let _22: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + let _23: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + let mut _24: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55 + let mut _25: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47 + let mut _26: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55 + let _27: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + let _28: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + let mut _29: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + let mut _30: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 + let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 + let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:14: 26:28 + let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27 + let mut _34: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _35: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _36: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _37: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _38: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _39: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _40: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _41: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _42: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _43: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _44: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _45: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + let mut _46: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 scope 1 { - debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 - debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 + debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 } scope 2 { - debug one => _17; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 - debug other => _18; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 + debug one => _17; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + debug other => _18; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 } scope 3 { - debug one => _22; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 - debug other => _23; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 + debug one => _22; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + debug other => _23; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 } scope 4 { - debug one => _27; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 - debug other => _28; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 + debug one => _27; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + debug other => _28; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 } bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +11:6 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16 - _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16 - StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23 - _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23 - Deinit(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24 - StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _34 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _11 = discriminant((*_34)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 - switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 27:6 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16 + _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16 + StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:18: 21:23 + _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:18: 21:23 + Deinit(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24 + StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _34 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _11 = discriminant((*_34)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 } bb1: { - StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _35 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _7 = discriminant((*_35)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 - switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 + StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _35 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _7 = discriminant((*_35)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 } bb2: { - StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27 - nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27 - Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28 - nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28 - discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28 - StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:27: +10:28 - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2 - return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2 + StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27 + Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28 + discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28 + StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:27: 26:28 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2 + return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2 } bb3: { - StorageLive(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _36 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _8 = discriminant((*_36)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - StorageDead(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 - switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 + StorageLive(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _36 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _8 = discriminant((*_36)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + StorageDead(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 } bb4: { - StorageLive(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _37 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _9 = discriminant((*_37)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - StorageDead(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 - switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 + StorageLive(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _37 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _9 = discriminant((*_37)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + StorageDead(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 } bb5: { - StorageLive(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _38 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _10 = discriminant((*_38)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - StorageDead(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 - switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 + StorageLive(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _38 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _10 = discriminant((*_38)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + StorageDead(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 } bb6: { - StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 - StorageLive(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 - _39 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 - _12 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 - StorageDead(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 - StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 - StorageLive(_40); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 - _40 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 - _13 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 - StorageDead(_40); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49 - StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49 - StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41 - _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41 - StorageLive(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49 - _16 = _13; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49 - _14 = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49 - StorageDead(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49 - StorageDead(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49 - Deinit(_3); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50 - ((_3 as Vw).0: f32) = move _14; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50 - discriminant(_3) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50 - StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 - StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 - StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 - goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + StorageLive(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + _39 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + _12 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + StorageDead(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + StorageLive(_40); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + _40 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + _13 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + StorageDead(_40); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49 + StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49 + StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41 + _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41 + StorageLive(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49 + _16 = _13; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49 + _14 = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49 + StorageDead(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49 + StorageDead(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49 + Deinit(_3); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50 + ((_3 as Vw).0: f32) = move _14; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50 + discriminant(_3) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50 + StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50 + StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50 + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50 + goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50 } bb7: { - StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 - StorageLive(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 - _41 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 - _17 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 - StorageDead(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 - StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 - StorageLive(_42); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 - _42 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 - _18 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 - StorageDead(_42); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49 - StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49 - StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41 - _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41 - StorageLive(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49 - _21 = _18; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49 - _19 = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49 - StorageDead(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49 - StorageDead(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49 - Deinit(_3); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50 - ((_3 as Vh).0: f32) = move _19; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50 - discriminant(_3) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50 - StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 - StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 - StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 - goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 + StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + StorageLive(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + _41 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + _17 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + StorageDead(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + StorageLive(_42); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + _42 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + _18 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + StorageDead(_42); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 + _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 + StorageLive(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 + _21 = _18; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 + _19 = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + StorageDead(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 + StorageDead(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 + Deinit(_3); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 + ((_3 as Vh).0: f32) = move _19; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 + discriminant(_3) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 + StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 + StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 + StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 + goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 } bb8: { - StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 - StorageLive(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 - _43 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 - _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 - StorageDead(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 - StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 - StorageLive(_44); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 - _44 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 - _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 - StorageDead(_44); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55 - StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55 - StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47 - _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47 - StorageLive(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55 - _26 = _23; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55 - _24 = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55 - StorageDead(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55 - StorageDead(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55 - Deinit(_3); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56 - ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56 - discriminant(_3) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56 - StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 - StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 - StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 - goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 + StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + StorageLive(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + _43 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + StorageDead(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + StorageLive(_44); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + _44 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + StorageDead(_44); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55 + StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55 + StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47 + _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47 + StorageLive(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55 + _26 = _23; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55 + _24 = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55 + StorageDead(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55 + StorageDead(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55 + Deinit(_3); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56 + ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56 + discriminant(_3) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56 + StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56 + StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56 + StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56 + goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56 } bb9: { - StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 - StorageLive(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 - _45 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 - _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 - StorageDead(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 - StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 - StorageLive(_46); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 - _46 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 - _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 - StorageDead(_46); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55 - StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55 - StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47 - _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47 - StorageLive(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55 - _31 = _28; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55 - _29 = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55 - StorageDead(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55 - StorageDead(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55 - Deinit(_3); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56 - ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56 - discriminant(_3) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56 - StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 - StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 - StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 - goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 + StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + StorageLive(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + _45 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + StorageDead(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + StorageLive(_46); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + _46 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + StorageDead(_46); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 + _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 + StorageLive(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 + _31 = _28; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 + _29 = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + StorageDead(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 + StorageDead(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 + Deinit(_3); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 + ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 + discriminant(_3) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 + StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 + StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 + StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 + goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 } bb10: { - Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7 - ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7 - discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7 - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2 - return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2 + Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7 + ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7 + discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2 + return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2 } } diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff index 321f57951b465..848f2feb32125 100644 --- a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff @@ -2,94 +2,94 @@ + // MIR for `noopt1` after EarlyOtherwiseBranch fn noopt1(_1: Option, _2: Option) -> u32 { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:+0:11: +0:12 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:+0:27: +0:28 - let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:+0:46: +0:49 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:12: +1:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:15: +1:16 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:+4:16: +4:23 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:+2:19: +2:26 - let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:+2:10: +2:17 - let _9: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:+2:15: +2:16 - let _10: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:+2:24: +2:25 - let _11: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:+3:15: +3:16 - let _12: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:+4:21: +4:22 + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:7:11: 7:12 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:7:27: 7:28 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:7:46: 7:49 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:12: 8:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:15: 8:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:16: 11:23 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:19: 9:26 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:10: 9:17 + let _9: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + let _10: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25 + let _11: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + let _12: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22 scope 1 { - debug a => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:+2:15: +2:16 - debug b => _10; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:+2:24: +2:25 + debug a => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + debug b => _10; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25 } scope 2 { - debug a => _11; // in scope 2 at $DIR/early_otherwise_branch_noopt.rs:+3:15: +3:16 + debug a => _11; // in scope 2 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 } scope 3 { - debug b => _12; // in scope 3 at $DIR/early_otherwise_branch_noopt.rs:+4:21: +4:22 + debug b => _12; // in scope 3 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22 } bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:12: +1:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:12: +1:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:15: +1:16 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:15: +1:16 - Deinit(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:16: +1:17 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:16: +1:17 - _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17 - switchInt(move _8) -> [0_isize: bb1, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:5: +1:17 + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:12: 8:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:12: 8:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:15: 8:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:15: 8:16 + Deinit(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17 + _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + switchInt(move _8) -> [0_isize: bb1, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17 } bb1: { - _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17 - switchInt(move _6) -> [0_isize: bb2, 1_isize: bb7, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:5: +1:17 + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + switchInt(move _6) -> [0_isize: bb2, 1_isize: bb7, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17 } bb2: { - _0 = const 3_u32; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+5:25: +5:26 - goto -> bb8; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+5:25: +5:26 + _0 = const 3_u32; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:25: 12:26 + goto -> bb8; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:25: 12:26 } bb3: { - unreachable; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17 + unreachable; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 } bb4: { - _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17 - switchInt(move _7) -> [0_isize: bb6, 1_isize: bb5, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:5: +1:17 + _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + switchInt(move _7) -> [0_isize: bb6, 1_isize: bb5, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17 } bb5: { - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+2:15: +2:16 - _9 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+2:15: +2:16 - StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+2:24: +2:25 - _10 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+2:24: +2:25 - _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:+2:31: +2:32 - StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+2:31: +2:32 - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+2:31: +2:32 - goto -> bb8; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+2:31: +2:32 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + _9 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25 + _10 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32 + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32 + goto -> bb8; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32 } bb6: { - StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+3:15: +3:16 - _11 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+3:15: +3:16 - _0 = const 1_u32; // scope 2 at $DIR/early_otherwise_branch_noopt.rs:+3:28: +3:29 - StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+3:28: +3:29 - goto -> bb8; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+3:28: +3:29 + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + _11 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + _0 = const 1_u32; // scope 2 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29 + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29 + goto -> bb8; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29 } bb7: { - StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+4:21: +4:22 - _12 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+4:21: +4:22 - _0 = const 2_u32; // scope 3 at $DIR/early_otherwise_branch_noopt.rs:+4:28: +4:29 - StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+4:28: +4:29 - goto -> bb8; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+4:28: +4:29 + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22 + _12 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22 + _0 = const 2_u32; // scope 3 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + goto -> bb8; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 } bb8: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+7:1: +7:2 - return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+7:2: +7:2 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:1: 14:2 + return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:2: 14:2 } } diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff index 8b556acb2c452..7d42c772f160a 100644 --- a/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff @@ -2,46 +2,46 @@ + // MIR for `no_deref_ptr` after EarlyOtherwiseBranch fn no_deref_ptr(_1: Option, _2: *const Option) -> i32 { - debug a => _1; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:+0:24: +0:25 - debug b => _2; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:+0:40: +0:41 - let mut _0: i32; // return place in scope 0 at $DIR/early_otherwise_branch_soundness.rs:+0:66: +0:69 - let mut _3: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:+3:9: +3:16 - let mut _4: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:+4:13: +4:20 - let _5: i32; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:+4:18: +4:19 + debug a => _1; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:18:24: 18:25 + debug b => _2; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:18:40: 18:41 + let mut _0: i32; // return place in scope 0 at $DIR/early_otherwise_branch_soundness.rs:18:66: 18:69 + let mut _3: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:21:9: 21:16 + let mut _4: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:13: 22:20 + let _5: i32; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19 scope 1 { - debug v => _5; // in scope 1 at $DIR/early_otherwise_branch_soundness.rs:+4:18: +4:19 + debug v => _5; // in scope 1 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19 } bb0: { - _3 = discriminant(_1); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+1:11: +1:12 - switchInt(move _3) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+1:5: +1:12 + _3 = discriminant(_1); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:19:11: 19:12 + switchInt(move _3) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:19:5: 19:12 } bb1: { - _0 = const 0_i32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+7:14: +7:15 - goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+7:14: +7:15 + _0 = const 0_i32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15 + goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15 } bb2: { - _4 = discriminant((*_2)); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+3:26: +3:28 - switchInt(move _4) -> [1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+3:20: +3:28 + _4 = discriminant((*_2)); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:21:26: 21:28 + switchInt(move _4) -> [1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:21:20: 21:28 } bb3: { - _0 = const 0_i32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+5:18: +5:19 - goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+5:18: +5:19 + _0 = const 0_i32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19 + goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19 } bb4: { - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+4:18: +4:19 - _5 = (((*_2) as Some).0: i32); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+4:18: +4:19 - _0 = _5; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:+4:24: +4:25 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+4:24: +4:25 - goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+4:24: +4:25 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19 + _5 = (((*_2) as Some).0: i32); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19 + _0 = _5; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25 + goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25 } bb5: { - return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+9:2: +9:2 + return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:27:2: 27:2 } } diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff index 3d7b3f75a8bf0..2ee7374250217 100644 --- a/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff @@ -2,39 +2,39 @@ + // MIR for `no_downcast` after EarlyOtherwiseBranch fn no_downcast(_1: &E) -> u32 { - debug e => _1; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:+0:16: +0:17 - let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_soundness.rs:+0:26: +0:29 - let mut _2: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:+1:20: +1:30 - let mut _3: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:+1:12: +1:31 - let mut _4: &E; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:+0:16: +0:17 + debug e => _1; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:16: 12:17 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:26: 12:29 + let mut _2: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:20: 13:30 + let mut _3: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 + let mut _4: &E; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:16: 12:17 scope 1 { } bb0: { - _3 = discriminant((*_1)); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:+1:12: +1:31 - switchInt(move _3) -> [1_isize: bb1, otherwise: bb3]; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:+1:12: +1:31 + _3 = discriminant((*_1)); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 + switchInt(move _3) -> [1_isize: bb1, otherwise: bb3]; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 } bb1: { - StorageLive(_4); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:+1:12: +1:31 - _4 = deref_copy (((*_1) as Some).0: &E); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:+1:12: +1:31 - _2 = discriminant((*_4)); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:+1:12: +1:31 - StorageDead(_4); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:+1:12: +1:31 - switchInt(move _2) -> [1_isize: bb2, otherwise: bb3]; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:+1:12: +1:31 + StorageLive(_4); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 + _4 = deref_copy (((*_1) as Some).0: &E); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 + _2 = discriminant((*_4)); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 + StorageDead(_4); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 + switchInt(move _2) -> [1_isize: bb2, otherwise: bb3]; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 } bb2: { - _0 = const 1_u32; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:+1:38: +1:39 - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+1:5: +1:52 + _0 = const 1_u32; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:38: 13:39 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52 } bb3: { - _0 = const 2_u32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+1:49: +1:50 - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+1:5: +1:52 + _0 = const 2_u32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:49: 13:50 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52 } bb4: { - return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+2:2: +2:2 + return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:14:2: 14:2 } } diff --git a/src/test/mir-opt/enum_cast.bar.mir_map.0.mir b/src/test/mir-opt/enum_cast.bar.mir_map.0.mir index afca2fd296075..1b4a469135cb6 100644 --- a/src/test/mir-opt/enum_cast.bar.mir_map.0.mir +++ b/src/test/mir-opt/enum_cast.bar.mir_map.0.mir @@ -1,13 +1,13 @@ // MIR for `bar` 0 mir_map fn bar(_1: Bar) -> usize { - debug bar => _1; // in scope 0 at $DIR/enum_cast.rs:+0:8: +0:11 - let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26 - let mut _2: isize; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8 + debug bar => _1; // in scope 0 at $DIR/enum_cast.rs:22:8: 22:11 + let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:22:21: 22:26 + let mut _2: isize; // in scope 0 at $DIR/enum_cast.rs:23:5: 23:8 bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 - _0 = move _2 as usize (Misc); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 - return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2 + _2 = discriminant(_1); // scope 0 at $DIR/enum_cast.rs:23:5: 23:17 + _0 = move _2 as usize (Misc); // scope 0 at $DIR/enum_cast.rs:23:5: 23:17 + return; // scope 0 at $DIR/enum_cast.rs:24:2: 24:2 } } diff --git a/src/test/mir-opt/enum_cast.boo.mir_map.0.mir b/src/test/mir-opt/enum_cast.boo.mir_map.0.mir index c79596d789953..7724e89a22854 100644 --- a/src/test/mir-opt/enum_cast.boo.mir_map.0.mir +++ b/src/test/mir-opt/enum_cast.boo.mir_map.0.mir @@ -1,13 +1,13 @@ // MIR for `boo` 0 mir_map fn boo(_1: Boo) -> usize { - debug boo => _1; // in scope 0 at $DIR/enum_cast.rs:+0:8: +0:11 - let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26 - let mut _2: u8; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8 + debug boo => _1; // in scope 0 at $DIR/enum_cast.rs:26:8: 26:11 + let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:26:21: 26:26 + let mut _2: u8; // in scope 0 at $DIR/enum_cast.rs:27:5: 27:8 bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 - _0 = move _2 as usize (Misc); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 - return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2 + _2 = discriminant(_1); // scope 0 at $DIR/enum_cast.rs:27:5: 27:17 + _0 = move _2 as usize (Misc); // scope 0 at $DIR/enum_cast.rs:27:5: 27:17 + return; // scope 0 at $DIR/enum_cast.rs:28:2: 28:2 } } diff --git a/src/test/mir-opt/enum_cast.droppy.mir_map.0.mir b/src/test/mir-opt/enum_cast.droppy.mir_map.0.mir index 8ced136db842a..a9dcfadae75c7 100644 --- a/src/test/mir-opt/enum_cast.droppy.mir_map.0.mir +++ b/src/test/mir-opt/enum_cast.droppy.mir_map.0.mir @@ -1,54 +1,54 @@ // MIR for `droppy` 0 mir_map fn droppy() -> () { - let mut _0: (); // return place in scope 0 at $DIR/enum_cast.rs:+0:13: +0:13 - let _1: (); // in scope 0 at $DIR/enum_cast.rs:+1:5: +6:6 - let _2: Droppy; // in scope 0 at $DIR/enum_cast.rs:+2:13: +2:14 - let mut _4: isize; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:18 - let _5: Droppy; // in scope 0 at $DIR/enum_cast.rs:+7:9: +7:10 + let mut _0: (); // return place in scope 0 at $DIR/enum_cast.rs:39:13: 39:13 + let _1: (); // in scope 0 at $DIR/enum_cast.rs:40:5: 45:6 + let _2: Droppy; // in scope 0 at $DIR/enum_cast.rs:41:13: 41:14 + let mut _4: isize; // in scope 0 at $DIR/enum_cast.rs:44:17: 44:18 + let _5: Droppy; // in scope 0 at $DIR/enum_cast.rs:46:9: 46:10 scope 1 { - debug x => _2; // in scope 1 at $DIR/enum_cast.rs:+2:13: +2:14 + debug x => _2; // in scope 1 at $DIR/enum_cast.rs:41:13: 41:14 scope 2 { - debug y => _3; // in scope 2 at $DIR/enum_cast.rs:+5:13: +5:14 + debug y => _3; // in scope 2 at $DIR/enum_cast.rs:44:13: 44:14 } scope 3 { - let _3: usize; // in scope 3 at $DIR/enum_cast.rs:+5:13: +5:14 + let _3: usize; // in scope 3 at $DIR/enum_cast.rs:44:13: 44:14 } } scope 4 { - debug z => _5; // in scope 4 at $DIR/enum_cast.rs:+7:9: +7:10 + debug z => _5; // in scope 4 at $DIR/enum_cast.rs:46:9: 46:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/enum_cast.rs:+1:5: +6:6 - StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+2:13: +2:14 - _2 = Droppy::C; // scope 0 at $DIR/enum_cast.rs:+2:17: +2:26 - FakeRead(ForLet(None), _2); // scope 0 at $DIR/enum_cast.rs:+2:13: +2:14 - StorageLive(_3); // scope 3 at $DIR/enum_cast.rs:+5:13: +5:14 - _4 = discriminant(_2); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27 - _3 = move _4 as usize (Misc); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27 - FakeRead(ForLet(None), _3); // scope 3 at $DIR/enum_cast.rs:+5:13: +5:14 - _1 = const (); // scope 0 at $DIR/enum_cast.rs:+1:5: +6:6 - StorageDead(_3); // scope 1 at $DIR/enum_cast.rs:+6:5: +6:6 - drop(_2) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/enum_cast.rs:+6:5: +6:6 + StorageLive(_1); // scope 0 at $DIR/enum_cast.rs:40:5: 45:6 + StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:41:13: 41:14 + _2 = Droppy::C; // scope 0 at $DIR/enum_cast.rs:41:17: 41:26 + FakeRead(ForLet(None), _2); // scope 0 at $DIR/enum_cast.rs:41:13: 41:14 + StorageLive(_3); // scope 3 at $DIR/enum_cast.rs:44:13: 44:14 + _4 = discriminant(_2); // scope 3 at $DIR/enum_cast.rs:44:17: 44:27 + _3 = move _4 as usize (Misc); // scope 3 at $DIR/enum_cast.rs:44:17: 44:27 + FakeRead(ForLet(None), _3); // scope 3 at $DIR/enum_cast.rs:44:13: 44:14 + _1 = const (); // scope 0 at $DIR/enum_cast.rs:40:5: 45:6 + StorageDead(_3); // scope 1 at $DIR/enum_cast.rs:45:5: 45:6 + drop(_2) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/enum_cast.rs:45:5: 45:6 } bb1: { - StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+6:5: +6:6 - StorageDead(_1); // scope 0 at $DIR/enum_cast.rs:+6:5: +6:6 - StorageLive(_5); // scope 0 at $DIR/enum_cast.rs:+7:9: +7:10 - _5 = Droppy::B; // scope 0 at $DIR/enum_cast.rs:+7:13: +7:22 - FakeRead(ForLet(None), _5); // scope 0 at $DIR/enum_cast.rs:+7:9: +7:10 - _0 = const (); // scope 0 at $DIR/enum_cast.rs:+0:13: +8:2 - drop(_5) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/enum_cast.rs:+8:1: +8:2 + StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:45:5: 45:6 + StorageDead(_1); // scope 0 at $DIR/enum_cast.rs:45:5: 45:6 + StorageLive(_5); // scope 0 at $DIR/enum_cast.rs:46:9: 46:10 + _5 = Droppy::B; // scope 0 at $DIR/enum_cast.rs:46:13: 46:22 + FakeRead(ForLet(None), _5); // scope 0 at $DIR/enum_cast.rs:46:9: 46:10 + _0 = const (); // scope 0 at $DIR/enum_cast.rs:39:13: 47:2 + drop(_5) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/enum_cast.rs:47:1: 47:2 } bb2: { - StorageDead(_5); // scope 0 at $DIR/enum_cast.rs:+8:1: +8:2 - return; // scope 0 at $DIR/enum_cast.rs:+8:2: +8:2 + StorageDead(_5); // scope 0 at $DIR/enum_cast.rs:47:1: 47:2 + return; // scope 0 at $DIR/enum_cast.rs:47:2: 47:2 } bb3 (cleanup): { - resume; // scope 0 at $DIR/enum_cast.rs:+0:1: +8:2 + resume; // scope 0 at $DIR/enum_cast.rs:39:1: 47:2 } } diff --git a/src/test/mir-opt/enum_cast.foo.mir_map.0.mir b/src/test/mir-opt/enum_cast.foo.mir_map.0.mir index 39d6adeba33e9..d89dc9519239b 100644 --- a/src/test/mir-opt/enum_cast.foo.mir_map.0.mir +++ b/src/test/mir-opt/enum_cast.foo.mir_map.0.mir @@ -1,13 +1,13 @@ // MIR for `foo` 0 mir_map fn foo(_1: Foo) -> usize { - debug foo => _1; // in scope 0 at $DIR/enum_cast.rs:+0:8: +0:11 - let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26 - let mut _2: isize; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8 + debug foo => _1; // in scope 0 at $DIR/enum_cast.rs:18:8: 18:11 + let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:18:21: 18:26 + let mut _2: isize; // in scope 0 at $DIR/enum_cast.rs:19:5: 19:8 bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 - _0 = move _2 as usize (Misc); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17 - return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2 + _2 = discriminant(_1); // scope 0 at $DIR/enum_cast.rs:19:5: 19:17 + _0 = move _2 as usize (Misc); // scope 0 at $DIR/enum_cast.rs:19:5: 19:17 + return; // scope 0 at $DIR/enum_cast.rs:20:2: 20:2 } } diff --git a/src/test/mir-opt/equal_true.opt.InstCombine.diff b/src/test/mir-opt/equal_true.opt.InstCombine.diff index 89982308e7161..174095888b48a 100644 --- a/src/test/mir-opt/equal_true.opt.InstCombine.diff +++ b/src/test/mir-opt/equal_true.opt.InstCombine.diff @@ -2,34 +2,34 @@ + // MIR for `opt` after InstCombine fn opt(_1: bool) -> i32 { - debug x => _1; // in scope 0 at $DIR/equal_true.rs:+0:8: +0:9 - let mut _0: i32; // return place in scope 0 at $DIR/equal_true.rs:+0:20: +0:23 - let mut _2: bool; // in scope 0 at $DIR/equal_true.rs:+1:8: +1:17 - let mut _3: bool; // in scope 0 at $DIR/equal_true.rs:+1:8: +1:9 + debug x => _1; // in scope 0 at $DIR/equal_true.rs:3:8: 3:9 + let mut _0: i32; // return place in scope 0 at $DIR/equal_true.rs:3:20: 3:23 + let mut _2: bool; // in scope 0 at $DIR/equal_true.rs:4:8: 4:17 + let mut _3: bool; // in scope 0 at $DIR/equal_true.rs:4:8: 4:9 bb0: { - StorageLive(_2); // scope 0 at $DIR/equal_true.rs:+1:8: +1:17 - StorageLive(_3); // scope 0 at $DIR/equal_true.rs:+1:8: +1:9 - _3 = _1; // scope 0 at $DIR/equal_true.rs:+1:8: +1:9 -- _2 = Eq(move _3, const true); // scope 0 at $DIR/equal_true.rs:+1:8: +1:17 -+ _2 = move _3; // scope 0 at $DIR/equal_true.rs:+1:8: +1:17 - StorageDead(_3); // scope 0 at $DIR/equal_true.rs:+1:16: +1:17 - switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/equal_true.rs:+1:8: +1:17 + StorageLive(_2); // scope 0 at $DIR/equal_true.rs:4:8: 4:17 + StorageLive(_3); // scope 0 at $DIR/equal_true.rs:4:8: 4:9 + _3 = _1; // scope 0 at $DIR/equal_true.rs:4:8: 4:9 +- _2 = Eq(move _3, const true); // scope 0 at $DIR/equal_true.rs:4:8: 4:17 ++ _2 = move _3; // scope 0 at $DIR/equal_true.rs:4:8: 4:17 + StorageDead(_3); // scope 0 at $DIR/equal_true.rs:4:16: 4:17 + switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/equal_true.rs:4:8: 4:17 } bb1: { - _0 = const 0_i32; // scope 0 at $DIR/equal_true.rs:+1:20: +1:21 - goto -> bb3; // scope 0 at $DIR/equal_true.rs:+1:5: +1:34 + _0 = const 0_i32; // scope 0 at $DIR/equal_true.rs:4:20: 4:21 + goto -> bb3; // scope 0 at $DIR/equal_true.rs:4:5: 4:34 } bb2: { - _0 = const 1_i32; // scope 0 at $DIR/equal_true.rs:+1:31: +1:32 - goto -> bb3; // scope 0 at $DIR/equal_true.rs:+1:5: +1:34 + _0 = const 1_i32; // scope 0 at $DIR/equal_true.rs:4:31: 4:32 + goto -> bb3; // scope 0 at $DIR/equal_true.rs:4:5: 4:34 } bb3: { - StorageDead(_2); // scope 0 at $DIR/equal_true.rs:+1:33: +1:34 - return; // scope 0 at $DIR/equal_true.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/equal_true.rs:4:33: 4:34 + return; // scope 0 at $DIR/equal_true.rs:5:2: 5:2 } } diff --git a/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir b/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir index d39145973624f..6b7b3db05419e 100644 --- a/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir @@ -1,83 +1,83 @@ // MIR for `match_tuple` after SimplifyCfg-initial fn match_tuple(_1: (u32, bool, Option, u32)) -> u32 { - debug x => _1; // in scope 0 at $DIR/exponential-or.rs:+0:16: +0:17 - let mut _0: u32; // return place in scope 0 at $DIR/exponential-or.rs:+0:53: +0:56 - let mut _2: isize; // in scope 0 at $DIR/exponential-or.rs:+2:37: +2:48 - let mut _3: bool; // in scope 0 at $DIR/exponential-or.rs:+2:70: +2:77 - let mut _4: bool; // in scope 0 at $DIR/exponential-or.rs:+2:70: +2:77 - let mut _5: bool; // in scope 0 at $DIR/exponential-or.rs:+2:62: +2:67 - let mut _6: bool; // in scope 0 at $DIR/exponential-or.rs:+2:62: +2:67 - let _7: u32; // in scope 0 at $DIR/exponential-or.rs:+2:10: +2:21 - let _8: u32; // in scope 0 at $DIR/exponential-or.rs:+2:57: +2:78 - let mut _9: u32; // in scope 0 at $DIR/exponential-or.rs:+2:83: +2:84 - let mut _10: u32; // in scope 0 at $DIR/exponential-or.rs:+2:87: +2:88 + debug x => _1; // in scope 0 at $DIR/exponential-or.rs:4:16: 4:17 + let mut _0: u32; // return place in scope 0 at $DIR/exponential-or.rs:4:53: 4:56 + let mut _2: isize; // in scope 0 at $DIR/exponential-or.rs:6:37: 6:48 + let mut _3: bool; // in scope 0 at $DIR/exponential-or.rs:6:70: 6:77 + let mut _4: bool; // in scope 0 at $DIR/exponential-or.rs:6:70: 6:77 + let mut _5: bool; // in scope 0 at $DIR/exponential-or.rs:6:62: 6:67 + let mut _6: bool; // in scope 0 at $DIR/exponential-or.rs:6:62: 6:67 + let _7: u32; // in scope 0 at $DIR/exponential-or.rs:6:10: 6:21 + let _8: u32; // in scope 0 at $DIR/exponential-or.rs:6:57: 6:78 + let mut _9: u32; // in scope 0 at $DIR/exponential-or.rs:6:83: 6:84 + let mut _10: u32; // in scope 0 at $DIR/exponential-or.rs:6:87: 6:88 scope 1 { - debug y => _7; // in scope 1 at $DIR/exponential-or.rs:+2:10: +2:21 - debug z => _8; // in scope 1 at $DIR/exponential-or.rs:+2:57: +2:78 + debug y => _7; // in scope 1 at $DIR/exponential-or.rs:6:10: 6:21 + debug z => _8; // in scope 1 at $DIR/exponential-or.rs:6:57: 6:78 } bb0: { - FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/exponential-or.rs:+1:11: +1:12 - switchInt((_1.0: u32)) -> [1_u32: bb2, 4_u32: bb2, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:+2:15: +2:20 + FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/exponential-or.rs:5:11: 5:12 + switchInt((_1.0: u32)) -> [1_u32: bb2, 4_u32: bb2, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:6:15: 6:20 } bb1: { - _0 = const 0_u32; // scope 0 at $DIR/exponential-or.rs:+3:14: +3:15 - goto -> bb10; // scope 0 at $DIR/exponential-or.rs:+3:14: +3:15 + _0 = const 0_u32; // scope 0 at $DIR/exponential-or.rs:7:14: 7:15 + goto -> bb10; // scope 0 at $DIR/exponential-or.rs:7:14: 7:15 } bb2: { - _2 = discriminant((_1.2: std::option::Option)); // scope 0 at $DIR/exponential-or.rs:+2:37: +2:55 - switchInt(move _2) -> [0_isize: bb4, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:+2:37: +2:55 + _2 = discriminant((_1.2: std::option::Option)); // scope 0 at $DIR/exponential-or.rs:6:37: 6:55 + switchInt(move _2) -> [0_isize: bb4, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:6:37: 6:55 } bb3: { - switchInt((((_1.2: std::option::Option) as Some).0: i32)) -> [1_i32: bb4, 8_i32: bb4, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:+2:37: +2:55 + switchInt((((_1.2: std::option::Option) as Some).0: i32)) -> [1_i32: bb4, 8_i32: bb4, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:6:37: 6:55 } bb4: { - _5 = Le(const 6_u32, (_1.3: u32)); // scope 0 at $DIR/exponential-or.rs:+2:62: +2:67 - switchInt(move _5) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/exponential-or.rs:+2:62: +2:67 + _5 = Le(const 6_u32, (_1.3: u32)); // scope 0 at $DIR/exponential-or.rs:6:62: 6:67 + switchInt(move _5) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/exponential-or.rs:6:62: 6:67 } bb5: { - _6 = Le((_1.3: u32), const 9_u32); // scope 0 at $DIR/exponential-or.rs:+2:62: +2:67 - switchInt(move _6) -> [false: bb6, otherwise: bb8]; // scope 0 at $DIR/exponential-or.rs:+2:62: +2:67 + _6 = Le((_1.3: u32), const 9_u32); // scope 0 at $DIR/exponential-or.rs:6:62: 6:67 + switchInt(move _6) -> [false: bb6, otherwise: bb8]; // scope 0 at $DIR/exponential-or.rs:6:62: 6:67 } bb6: { - _3 = Le(const 13_u32, (_1.3: u32)); // scope 0 at $DIR/exponential-or.rs:+2:70: +2:77 - switchInt(move _3) -> [false: bb1, otherwise: bb7]; // scope 0 at $DIR/exponential-or.rs:+2:70: +2:77 + _3 = Le(const 13_u32, (_1.3: u32)); // scope 0 at $DIR/exponential-or.rs:6:70: 6:77 + switchInt(move _3) -> [false: bb1, otherwise: bb7]; // scope 0 at $DIR/exponential-or.rs:6:70: 6:77 } bb7: { - _4 = Le((_1.3: u32), const 16_u32); // scope 0 at $DIR/exponential-or.rs:+2:70: +2:77 - switchInt(move _4) -> [false: bb1, otherwise: bb8]; // scope 0 at $DIR/exponential-or.rs:+2:70: +2:77 + _4 = Le((_1.3: u32), const 16_u32); // scope 0 at $DIR/exponential-or.rs:6:70: 6:77 + switchInt(move _4) -> [false: bb1, otherwise: bb8]; // scope 0 at $DIR/exponential-or.rs:6:70: 6:77 } bb8: { - falseEdge -> [real: bb9, imaginary: bb1]; // scope 0 at $DIR/exponential-or.rs:+2:9: +2:79 + falseEdge -> [real: bb9, imaginary: bb1]; // scope 0 at $DIR/exponential-or.rs:6:9: 6:79 } bb9: { - StorageLive(_7); // scope 0 at $DIR/exponential-or.rs:+2:10: +2:21 - _7 = (_1.0: u32); // scope 0 at $DIR/exponential-or.rs:+2:10: +2:21 - StorageLive(_8); // scope 0 at $DIR/exponential-or.rs:+2:57: +2:78 - _8 = (_1.3: u32); // scope 0 at $DIR/exponential-or.rs:+2:57: +2:78 - StorageLive(_9); // scope 1 at $DIR/exponential-or.rs:+2:83: +2:84 - _9 = _7; // scope 1 at $DIR/exponential-or.rs:+2:83: +2:84 - StorageLive(_10); // scope 1 at $DIR/exponential-or.rs:+2:87: +2:88 - _10 = _8; // scope 1 at $DIR/exponential-or.rs:+2:87: +2:88 - _0 = BitXor(move _9, move _10); // scope 1 at $DIR/exponential-or.rs:+2:83: +2:88 - StorageDead(_10); // scope 1 at $DIR/exponential-or.rs:+2:87: +2:88 - StorageDead(_9); // scope 1 at $DIR/exponential-or.rs:+2:87: +2:88 - StorageDead(_8); // scope 0 at $DIR/exponential-or.rs:+2:87: +2:88 - StorageDead(_7); // scope 0 at $DIR/exponential-or.rs:+2:87: +2:88 - goto -> bb10; // scope 0 at $DIR/exponential-or.rs:+2:87: +2:88 + StorageLive(_7); // scope 0 at $DIR/exponential-or.rs:6:10: 6:21 + _7 = (_1.0: u32); // scope 0 at $DIR/exponential-or.rs:6:10: 6:21 + StorageLive(_8); // scope 0 at $DIR/exponential-or.rs:6:57: 6:78 + _8 = (_1.3: u32); // scope 0 at $DIR/exponential-or.rs:6:57: 6:78 + StorageLive(_9); // scope 1 at $DIR/exponential-or.rs:6:83: 6:84 + _9 = _7; // scope 1 at $DIR/exponential-or.rs:6:83: 6:84 + StorageLive(_10); // scope 1 at $DIR/exponential-or.rs:6:87: 6:88 + _10 = _8; // scope 1 at $DIR/exponential-or.rs:6:87: 6:88 + _0 = BitXor(move _9, move _10); // scope 1 at $DIR/exponential-or.rs:6:83: 6:88 + StorageDead(_10); // scope 1 at $DIR/exponential-or.rs:6:87: 6:88 + StorageDead(_9); // scope 1 at $DIR/exponential-or.rs:6:87: 6:88 + StorageDead(_8); // scope 0 at $DIR/exponential-or.rs:6:87: 6:88 + StorageDead(_7); // scope 0 at $DIR/exponential-or.rs:6:87: 6:88 + goto -> bb10; // scope 0 at $DIR/exponential-or.rs:6:87: 6:88 } bb10: { - return; // scope 0 at $DIR/exponential-or.rs:+5:2: +5:2 + return; // scope 0 at $DIR/exponential-or.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir b/src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir index c63433d36203d..bcc6042f2fb62 100644 --- a/src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir +++ b/src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir @@ -1,13 +1,13 @@ // MIR for `std::ops::Fn::call` before AddMovesForPackedDrops fn std::ops::Fn::call(_1: *const fn(), _2: ()) -> >::Output { - let mut _0: >::Output; // return place in scope 0 at $SRC_DIR/core/src/ops/function.rs:+0:5: +0:67 + let mut _0: >::Output; // return place in scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL bb0: { - _0 = move (*_1)() -> bb1; // scope 0 at $SRC_DIR/core/src/ops/function.rs:+0:5: +0:67 + _0 = move (*_1)() -> bb1; // scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL } bb1: { - return; // scope 0 at $SRC_DIR/core/src/ops/function.rs:+0:5: +0:67 + return; // scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL } } diff --git a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff index dca36b1a76d0f..a930d83b9e798 100644 --- a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff +++ b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff @@ -2,145 +2,145 @@ + // MIR for `float_to_exponential_common` after ConstProp fn float_to_exponential_common(_1: &mut Formatter, _2: &T, _3: bool) -> Result<(), std::fmt::Error> { - debug fmt => _1; // in scope 0 at $DIR/funky_arms.rs:+0:35: +0:38 - debug num => _2; // in scope 0 at $DIR/funky_arms.rs:+0:60: +0:63 - debug upper => _3; // in scope 0 at $DIR/funky_arms.rs:+0:69: +0:74 - let mut _0: std::result::Result<(), std::fmt::Error>; // return place in scope 0 at $DIR/funky_arms.rs:+0:85: +0:91 - let _4: bool; // in scope 0 at $DIR/funky_arms.rs:+4:9: +4:19 - let mut _5: &std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:+4:22: +4:37 - let mut _7: std::option::Option; // in scope 0 at $DIR/funky_arms.rs:+13:30: +13:45 - let mut _8: &std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:+13:30: +13:45 - let mut _9: isize; // in scope 0 at $DIR/funky_arms.rs:+13:12: +13:27 - let mut _11: &mut std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:+15:43: +15:46 - let mut _12: &T; // in scope 0 at $DIR/funky_arms.rs:+15:48: +15:51 - let mut _13: core::num::flt2dec::Sign; // in scope 0 at $DIR/funky_arms.rs:+15:53: +15:57 - let mut _14: u32; // in scope 0 at $DIR/funky_arms.rs:+15:59: +15:79 - let mut _15: u32; // in scope 0 at $DIR/funky_arms.rs:+15:59: +15:75 - let mut _16: usize; // in scope 0 at $DIR/funky_arms.rs:+15:59: +15:68 - let mut _17: bool; // in scope 0 at $DIR/funky_arms.rs:+15:81: +15:86 - let mut _18: &mut std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:+17:46: +17:49 - let mut _19: &T; // in scope 0 at $DIR/funky_arms.rs:+17:51: +17:54 - let mut _20: core::num::flt2dec::Sign; // in scope 0 at $DIR/funky_arms.rs:+17:56: +17:60 - let mut _21: bool; // in scope 0 at $DIR/funky_arms.rs:+17:62: +17:67 + debug fmt => _1; // in scope 0 at $DIR/funky_arms.rs:11:35: 11:38 + debug num => _2; // in scope 0 at $DIR/funky_arms.rs:11:60: 11:63 + debug upper => _3; // in scope 0 at $DIR/funky_arms.rs:11:69: 11:74 + let mut _0: std::result::Result<(), std::fmt::Error>; // return place in scope 0 at $DIR/funky_arms.rs:11:85: 11:91 + let _4: bool; // in scope 0 at $DIR/funky_arms.rs:15:9: 15:19 + let mut _5: &std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:15:22: 15:37 + let mut _7: std::option::Option; // in scope 0 at $DIR/funky_arms.rs:24:30: 24:45 + let mut _8: &std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:24:30: 24:45 + let mut _9: isize; // in scope 0 at $DIR/funky_arms.rs:24:12: 24:27 + let mut _11: &mut std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:26:43: 26:46 + let mut _12: &T; // in scope 0 at $DIR/funky_arms.rs:26:48: 26:51 + let mut _13: core::num::flt2dec::Sign; // in scope 0 at $DIR/funky_arms.rs:26:53: 26:57 + let mut _14: u32; // in scope 0 at $DIR/funky_arms.rs:26:59: 26:79 + let mut _15: u32; // in scope 0 at $DIR/funky_arms.rs:26:59: 26:75 + let mut _16: usize; // in scope 0 at $DIR/funky_arms.rs:26:59: 26:68 + let mut _17: bool; // in scope 0 at $DIR/funky_arms.rs:26:81: 26:86 + let mut _18: &mut std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:28:46: 28:49 + let mut _19: &T; // in scope 0 at $DIR/funky_arms.rs:28:51: 28:54 + let mut _20: core::num::flt2dec::Sign; // in scope 0 at $DIR/funky_arms.rs:28:56: 28:60 + let mut _21: bool; // in scope 0 at $DIR/funky_arms.rs:28:62: 28:67 scope 1 { - debug force_sign => _4; // in scope 1 at $DIR/funky_arms.rs:+4:9: +4:19 - let _6: core::num::flt2dec::Sign; // in scope 1 at $DIR/funky_arms.rs:+8:9: +8:13 + debug force_sign => _4; // in scope 1 at $DIR/funky_arms.rs:15:9: 15:19 + let _6: core::num::flt2dec::Sign; // in scope 1 at $DIR/funky_arms.rs:19:9: 19:13 scope 2 { - debug sign => _6; // in scope 2 at $DIR/funky_arms.rs:+8:9: +8:13 + debug sign => _6; // in scope 2 at $DIR/funky_arms.rs:19:9: 19:13 scope 3 { - debug precision => _10; // in scope 3 at $DIR/funky_arms.rs:+13:17: +13:26 - let _10: usize; // in scope 3 at $DIR/funky_arms.rs:+13:17: +13:26 + debug precision => _10; // in scope 3 at $DIR/funky_arms.rs:24:17: 24:26 + let _10: usize; // in scope 3 at $DIR/funky_arms.rs:24:17: 24:26 } } } bb0: { - StorageLive(_4); // scope 0 at $DIR/funky_arms.rs:+4:9: +4:19 - StorageLive(_5); // scope 0 at $DIR/funky_arms.rs:+4:22: +4:37 - _5 = &(*_1); // scope 0 at $DIR/funky_arms.rs:+4:22: +4:37 - _4 = Formatter::sign_plus(move _5) -> bb1; // scope 0 at $DIR/funky_arms.rs:+4:22: +4:37 + StorageLive(_4); // scope 0 at $DIR/funky_arms.rs:15:9: 15:19 + StorageLive(_5); // scope 0 at $DIR/funky_arms.rs:15:22: 15:37 + _5 = &(*_1); // scope 0 at $DIR/funky_arms.rs:15:22: 15:37 + _4 = Formatter::sign_plus(move _5) -> bb1; // scope 0 at $DIR/funky_arms.rs:15:22: 15:37 // mir::Constant // + span: $DIR/funky_arms.rs:15:26: 15:35 // + literal: Const { ty: for<'r> fn(&'r Formatter) -> bool {Formatter::sign_plus}, val: Value() } } bb1: { - StorageDead(_5); // scope 0 at $DIR/funky_arms.rs:+4:36: +4:37 - StorageLive(_6); // scope 1 at $DIR/funky_arms.rs:+8:9: +8:13 - switchInt(_4) -> [false: bb3, otherwise: bb2]; // scope 1 at $DIR/funky_arms.rs:+8:16: +8:32 + StorageDead(_5); // scope 0 at $DIR/funky_arms.rs:15:36: 15:37 + StorageLive(_6); // scope 1 at $DIR/funky_arms.rs:19:9: 19:13 + switchInt(_4) -> [false: bb3, otherwise: bb2]; // scope 1 at $DIR/funky_arms.rs:19:16: 19:32 } bb2: { - Deinit(_6); // scope 1 at $DIR/funky_arms.rs:+10:17: +10:41 - discriminant(_6) = 1; // scope 1 at $DIR/funky_arms.rs:+10:17: +10:41 - goto -> bb4; // scope 1 at $DIR/funky_arms.rs:+10:17: +10:41 + Deinit(_6); // scope 1 at $DIR/funky_arms.rs:21:17: 21:41 + discriminant(_6) = 1; // scope 1 at $DIR/funky_arms.rs:21:17: 21:41 + goto -> bb4; // scope 1 at $DIR/funky_arms.rs:21:17: 21:41 } bb3: { - Deinit(_6); // scope 1 at $DIR/funky_arms.rs:+9:18: +9:38 - discriminant(_6) = 0; // scope 1 at $DIR/funky_arms.rs:+9:18: +9:38 - goto -> bb4; // scope 1 at $DIR/funky_arms.rs:+9:18: +9:38 + Deinit(_6); // scope 1 at $DIR/funky_arms.rs:20:18: 20:38 + discriminant(_6) = 0; // scope 1 at $DIR/funky_arms.rs:20:18: 20:38 + goto -> bb4; // scope 1 at $DIR/funky_arms.rs:20:18: 20:38 } bb4: { - StorageLive(_7); // scope 3 at $DIR/funky_arms.rs:+13:30: +13:45 - StorageLive(_8); // scope 3 at $DIR/funky_arms.rs:+13:30: +13:45 - _8 = &(*_1); // scope 3 at $DIR/funky_arms.rs:+13:30: +13:45 - _7 = Formatter::precision(move _8) -> bb5; // scope 3 at $DIR/funky_arms.rs:+13:30: +13:45 + StorageLive(_7); // scope 3 at $DIR/funky_arms.rs:24:30: 24:45 + StorageLive(_8); // scope 3 at $DIR/funky_arms.rs:24:30: 24:45 + _8 = &(*_1); // scope 3 at $DIR/funky_arms.rs:24:30: 24:45 + _7 = Formatter::precision(move _8) -> bb5; // scope 3 at $DIR/funky_arms.rs:24:30: 24:45 // mir::Constant // + span: $DIR/funky_arms.rs:24:34: 24:43 // + literal: Const { ty: for<'r> fn(&'r Formatter) -> Option {Formatter::precision}, val: Value() } } bb5: { - StorageDead(_8); // scope 3 at $DIR/funky_arms.rs:+13:44: +13:45 - _9 = discriminant(_7); // scope 3 at $DIR/funky_arms.rs:+13:12: +13:27 - switchInt(move _9) -> [1_isize: bb6, otherwise: bb8]; // scope 3 at $DIR/funky_arms.rs:+13:12: +13:27 + StorageDead(_8); // scope 3 at $DIR/funky_arms.rs:24:44: 24:45 + _9 = discriminant(_7); // scope 3 at $DIR/funky_arms.rs:24:12: 24:27 + switchInt(move _9) -> [1_isize: bb6, otherwise: bb8]; // scope 3 at $DIR/funky_arms.rs:24:12: 24:27 } bb6: { - StorageLive(_10); // scope 3 at $DIR/funky_arms.rs:+13:17: +13:26 - _10 = ((_7 as Some).0: usize); // scope 3 at $DIR/funky_arms.rs:+13:17: +13:26 - StorageLive(_11); // scope 3 at $DIR/funky_arms.rs:+15:43: +15:46 - _11 = &mut (*_1); // scope 3 at $DIR/funky_arms.rs:+15:43: +15:46 - StorageLive(_12); // scope 3 at $DIR/funky_arms.rs:+15:48: +15:51 - _12 = _2; // scope 3 at $DIR/funky_arms.rs:+15:48: +15:51 - StorageLive(_13); // scope 3 at $DIR/funky_arms.rs:+15:53: +15:57 - _13 = _6; // scope 3 at $DIR/funky_arms.rs:+15:53: +15:57 - StorageLive(_14); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:79 - StorageLive(_15); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75 - StorageLive(_16); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:68 - _16 = _10; // scope 3 at $DIR/funky_arms.rs:+15:59: +15:68 - _15 = move _16 as u32 (Misc); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75 - StorageDead(_16); // scope 3 at $DIR/funky_arms.rs:+15:74: +15:75 - _14 = Add(move _15, const 1_u32); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:79 - StorageDead(_15); // scope 3 at $DIR/funky_arms.rs:+15:78: +15:79 - StorageLive(_17); // scope 3 at $DIR/funky_arms.rs:+15:81: +15:86 - _17 = _3; // scope 3 at $DIR/funky_arms.rs:+15:81: +15:86 - _0 = float_to_exponential_common_exact::(move _11, move _12, move _13, move _14, move _17) -> bb7; // scope 3 at $DIR/funky_arms.rs:+15:9: +15:87 + StorageLive(_10); // scope 3 at $DIR/funky_arms.rs:24:17: 24:26 + _10 = ((_7 as Some).0: usize); // scope 3 at $DIR/funky_arms.rs:24:17: 24:26 + StorageLive(_11); // scope 3 at $DIR/funky_arms.rs:26:43: 26:46 + _11 = &mut (*_1); // scope 3 at $DIR/funky_arms.rs:26:43: 26:46 + StorageLive(_12); // scope 3 at $DIR/funky_arms.rs:26:48: 26:51 + _12 = _2; // scope 3 at $DIR/funky_arms.rs:26:48: 26:51 + StorageLive(_13); // scope 3 at $DIR/funky_arms.rs:26:53: 26:57 + _13 = _6; // scope 3 at $DIR/funky_arms.rs:26:53: 26:57 + StorageLive(_14); // scope 3 at $DIR/funky_arms.rs:26:59: 26:79 + StorageLive(_15); // scope 3 at $DIR/funky_arms.rs:26:59: 26:75 + StorageLive(_16); // scope 3 at $DIR/funky_arms.rs:26:59: 26:68 + _16 = _10; // scope 3 at $DIR/funky_arms.rs:26:59: 26:68 + _15 = move _16 as u32 (Misc); // scope 3 at $DIR/funky_arms.rs:26:59: 26:75 + StorageDead(_16); // scope 3 at $DIR/funky_arms.rs:26:74: 26:75 + _14 = Add(move _15, const 1_u32); // scope 3 at $DIR/funky_arms.rs:26:59: 26:79 + StorageDead(_15); // scope 3 at $DIR/funky_arms.rs:26:78: 26:79 + StorageLive(_17); // scope 3 at $DIR/funky_arms.rs:26:81: 26:86 + _17 = _3; // scope 3 at $DIR/funky_arms.rs:26:81: 26:86 + _0 = float_to_exponential_common_exact::(move _11, move _12, move _13, move _14, move _17) -> bb7; // scope 3 at $DIR/funky_arms.rs:26:9: 26:87 // mir::Constant // + span: $DIR/funky_arms.rs:26:9: 26:42 // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut Formatter<'s>, &'t0 T, Sign, u32, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_exact::}, val: Value() } } bb7: { - StorageDead(_17); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 - StorageDead(_14); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 - StorageDead(_13); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 - StorageDead(_12); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 - StorageDead(_11); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 - StorageDead(_10); // scope 2 at $DIR/funky_arms.rs:+16:5: +16:6 - goto -> bb10; // scope 2 at $DIR/funky_arms.rs:+13:5: +18:6 + StorageDead(_17); // scope 3 at $DIR/funky_arms.rs:26:86: 26:87 + StorageDead(_14); // scope 3 at $DIR/funky_arms.rs:26:86: 26:87 + StorageDead(_13); // scope 3 at $DIR/funky_arms.rs:26:86: 26:87 + StorageDead(_12); // scope 3 at $DIR/funky_arms.rs:26:86: 26:87 + StorageDead(_11); // scope 3 at $DIR/funky_arms.rs:26:86: 26:87 + StorageDead(_10); // scope 2 at $DIR/funky_arms.rs:27:5: 27:6 + goto -> bb10; // scope 2 at $DIR/funky_arms.rs:24:5: 29:6 } bb8: { - StorageLive(_18); // scope 2 at $DIR/funky_arms.rs:+17:46: +17:49 - _18 = &mut (*_1); // scope 2 at $DIR/funky_arms.rs:+17:46: +17:49 - StorageLive(_19); // scope 2 at $DIR/funky_arms.rs:+17:51: +17:54 - _19 = _2; // scope 2 at $DIR/funky_arms.rs:+17:51: +17:54 - StorageLive(_20); // scope 2 at $DIR/funky_arms.rs:+17:56: +17:60 - _20 = _6; // scope 2 at $DIR/funky_arms.rs:+17:56: +17:60 - StorageLive(_21); // scope 2 at $DIR/funky_arms.rs:+17:62: +17:67 - _21 = _3; // scope 2 at $DIR/funky_arms.rs:+17:62: +17:67 - _0 = float_to_exponential_common_shortest::(move _18, move _19, move _20, move _21) -> bb9; // scope 2 at $DIR/funky_arms.rs:+17:9: +17:68 + StorageLive(_18); // scope 2 at $DIR/funky_arms.rs:28:46: 28:49 + _18 = &mut (*_1); // scope 2 at $DIR/funky_arms.rs:28:46: 28:49 + StorageLive(_19); // scope 2 at $DIR/funky_arms.rs:28:51: 28:54 + _19 = _2; // scope 2 at $DIR/funky_arms.rs:28:51: 28:54 + StorageLive(_20); // scope 2 at $DIR/funky_arms.rs:28:56: 28:60 + _20 = _6; // scope 2 at $DIR/funky_arms.rs:28:56: 28:60 + StorageLive(_21); // scope 2 at $DIR/funky_arms.rs:28:62: 28:67 + _21 = _3; // scope 2 at $DIR/funky_arms.rs:28:62: 28:67 + _0 = float_to_exponential_common_shortest::(move _18, move _19, move _20, move _21) -> bb9; // scope 2 at $DIR/funky_arms.rs:28:9: 28:68 // mir::Constant // + span: $DIR/funky_arms.rs:28:9: 28:45 // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut Formatter<'s>, &'t0 T, Sign, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_shortest::}, val: Value() } } bb9: { - StorageDead(_21); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68 - StorageDead(_20); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68 - StorageDead(_19); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68 - StorageDead(_18); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68 - goto -> bb10; // scope 2 at $DIR/funky_arms.rs:+13:5: +18:6 + StorageDead(_21); // scope 2 at $DIR/funky_arms.rs:28:67: 28:68 + StorageDead(_20); // scope 2 at $DIR/funky_arms.rs:28:67: 28:68 + StorageDead(_19); // scope 2 at $DIR/funky_arms.rs:28:67: 28:68 + StorageDead(_18); // scope 2 at $DIR/funky_arms.rs:28:67: 28:68 + goto -> bb10; // scope 2 at $DIR/funky_arms.rs:24:5: 29:6 } bb10: { - StorageDead(_6); // scope 1 at $DIR/funky_arms.rs:+19:1: +19:2 - StorageDead(_4); // scope 0 at $DIR/funky_arms.rs:+19:1: +19:2 - StorageDead(_7); // scope 0 at $DIR/funky_arms.rs:+19:1: +19:2 - return; // scope 0 at $DIR/funky_arms.rs:+19:2: +19:2 + StorageDead(_6); // scope 1 at $DIR/funky_arms.rs:30:1: 30:2 + StorageDead(_4); // scope 0 at $DIR/funky_arms.rs:30:1: 30:2 + StorageDead(_7); // scope 0 at $DIR/funky_arms.rs:30:1: 30:2 + return; // scope 0 at $DIR/funky_arms.rs:30:2: 30:2 } } diff --git a/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir index 09765c7b9974b..c78c345dec224 100644 --- a/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir +++ b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir @@ -15,70 +15,70 @@ } */ fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 10:17]) -> () { - let mut _0: (); // return place in scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +0:17 - let mut _2: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +0:17 - let _3: std::string::String; // in scope 0 at $DIR/generator-drop-cleanup.rs:+1:13: +1:15 - let _4: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:+2:9: +2:14 - let mut _5: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:+2:9: +2:14 - let mut _6: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:+0:18: +0:18 - let mut _7: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +0:17 - let mut _8: u32; // in scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +0:17 + let mut _0: (); // return place in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 + let mut _2: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 + let _3: std::string::String; // in scope 0 at $DIR/generator-drop-cleanup.rs:11:13: 11:15 + let _4: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:12:9: 12:14 + let mut _5: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:12:9: 12:14 + let mut _6: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:18: 10:18 + let mut _7: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 + let mut _8: u32; // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 scope 1 { - debug _s => (((*_1) as variant#3).0: std::string::String); // in scope 1 at $DIR/generator-drop-cleanup.rs:+1:13: +1:15 + debug _s => (((*_1) as variant#3).0: std::string::String); // in scope 1 at $DIR/generator-drop-cleanup.rs:11:13: 11:15 } bb0: { - _8 = discriminant((*_1)); // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +0:17 - switchInt(move _8) -> [0_u32: bb7, 3_u32: bb10, otherwise: bb11]; // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +0:17 + _8 = discriminant((*_1)); // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 + switchInt(move _8) -> [0_u32: bb7, 3_u32: bb10, otherwise: bb11]; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 } bb1: { - StorageDead(_5); // scope 1 at $DIR/generator-drop-cleanup.rs:+2:13: +2:14 - StorageDead(_4); // scope 1 at $DIR/generator-drop-cleanup.rs:+2:14: +2:15 - drop((((*_1) as variant#3).0: std::string::String)) -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/generator-drop-cleanup.rs:+3:5: +3:6 + StorageDead(_5); // scope 1 at $DIR/generator-drop-cleanup.rs:12:13: 12:14 + StorageDead(_4); // scope 1 at $DIR/generator-drop-cleanup.rs:12:14: 12:15 + drop((((*_1) as variant#3).0: std::string::String)) -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6 } bb2: { - nop; // scope 0 at $DIR/generator-drop-cleanup.rs:+3:5: +3:6 - goto -> bb8; // scope 0 at $DIR/generator-drop-cleanup.rs:+3:5: +3:6 + nop; // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6 + goto -> bb8; // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6 } bb3: { - return; // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +0:17 + return; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 } bb4 (cleanup): { - resume; // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +0:17 + resume; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 } bb5 (cleanup): { - nop; // scope 0 at $DIR/generator-drop-cleanup.rs:+3:5: +3:6 - goto -> bb4; // scope 0 at $DIR/generator-drop-cleanup.rs:+3:5: +3:6 + nop; // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6 + goto -> bb4; // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6 } bb6: { - return; // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +0:17 + return; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 } bb7: { - goto -> bb9; // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +0:17 + goto -> bb9; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 } bb8: { - goto -> bb3; // scope 0 at $DIR/generator-drop-cleanup.rs:+3:5: +3:6 + goto -> bb3; // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6 } bb9: { - goto -> bb6; // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +0:17 + goto -> bb6; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 } bb10: { - StorageLive(_4); // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +0:17 - StorageLive(_5); // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +0:17 - goto -> bb1; // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +0:17 + StorageLive(_4); // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 + StorageLive(_5); // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 + goto -> bb1; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 } bb11: { - return; // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +0:17 + return; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 } } diff --git a/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir b/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir index cb6ed33212ec4..af4ed32c50889 100644 --- a/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir +++ b/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir @@ -3,112 +3,112 @@ fn main::{closure#0}(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 22:18], _2: ()) -> () yields () { - let mut _0: (); // return place in scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:19: +0:19 - let _3: Foo; // in scope 0 at $DIR/generator-storage-dead-unwind.rs:+1:13: +1:14 - let _5: (); // in scope 0 at $DIR/generator-storage-dead-unwind.rs:+3:9: +3:14 - let mut _6: (); // in scope 0 at $DIR/generator-storage-dead-unwind.rs:+3:9: +3:14 - let _7: (); // in scope 0 at $DIR/generator-storage-dead-unwind.rs:+4:9: +4:16 - let mut _8: Foo; // in scope 0 at $DIR/generator-storage-dead-unwind.rs:+4:14: +4:15 - let _9: (); // in scope 0 at $DIR/generator-storage-dead-unwind.rs:+5:9: +5:16 - let mut _10: Bar; // in scope 0 at $DIR/generator-storage-dead-unwind.rs:+5:14: +5:15 + let mut _0: (); // return place in scope 0 at $DIR/generator-storage-dead-unwind.rs:22:19: 22:19 + let _3: Foo; // in scope 0 at $DIR/generator-storage-dead-unwind.rs:23:13: 23:14 + let _5: (); // in scope 0 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14 + let mut _6: (); // in scope 0 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14 + let _7: (); // in scope 0 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16 + let mut _8: Foo; // in scope 0 at $DIR/generator-storage-dead-unwind.rs:26:14: 26:15 + let _9: (); // in scope 0 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16 + let mut _10: Bar; // in scope 0 at $DIR/generator-storage-dead-unwind.rs:27:14: 27:15 scope 1 { - debug a => _3; // in scope 1 at $DIR/generator-storage-dead-unwind.rs:+1:13: +1:14 - let _4: Bar; // in scope 1 at $DIR/generator-storage-dead-unwind.rs:+2:13: +2:14 + debug a => _3; // in scope 1 at $DIR/generator-storage-dead-unwind.rs:23:13: 23:14 + let _4: Bar; // in scope 1 at $DIR/generator-storage-dead-unwind.rs:24:13: 24:14 scope 2 { - debug b => _4; // in scope 2 at $DIR/generator-storage-dead-unwind.rs:+2:13: +2:14 + debug b => _4; // in scope 2 at $DIR/generator-storage-dead-unwind.rs:24:13: 24:14 } } bb0: { - StorageLive(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:+1:13: +1:14 - Deinit(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:+1:17: +1:23 - (_3.0: i32) = const 5_i32; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+1:17: +1:23 - StorageLive(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:+2:13: +2:14 - Deinit(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:+2:17: +2:23 - (_4.0: i32) = const 6_i32; // scope 1 at $DIR/generator-storage-dead-unwind.rs:+2:17: +2:23 - StorageLive(_5); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+3:9: +3:14 - StorageLive(_6); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+3:9: +3:14 - Deinit(_6); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+3:9: +3:14 - _5 = yield(move _6) -> [resume: bb1, drop: bb5]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:+3:9: +3:14 + StorageLive(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:13: 23:14 + Deinit(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23 + (_3.0: i32) = const 5_i32; // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23 + StorageLive(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:13: 24:14 + Deinit(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23 + (_4.0: i32) = const 6_i32; // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23 + StorageLive(_5); // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14 + StorageLive(_6); // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14 + Deinit(_6); // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14 + _5 = yield(move _6) -> [resume: bb1, drop: bb5]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14 } bb1: { - StorageDead(_6); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+3:13: +3:14 - StorageDead(_5); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+3:14: +3:15 - StorageLive(_7); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:9: +4:16 - StorageLive(_8); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:14: +4:15 - _8 = move _3; // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:14: +4:15 - _7 = take::(move _8) -> [return: bb2, unwind: bb9]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:9: +4:16 + StorageDead(_6); // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:13: 25:14 + StorageDead(_5); // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:14: 25:15 + StorageLive(_7); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16 + StorageLive(_8); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:14: 26:15 + _8 = move _3; // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:14: 26:15 + _7 = take::(move _8) -> [return: bb2, unwind: bb9]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16 // mir::Constant // + span: $DIR/generator-storage-dead-unwind.rs:26:9: 26:13 // + literal: Const { ty: fn(Foo) {take::}, val: Value() } } bb2: { - StorageDead(_8); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:15: +4:16 - StorageDead(_7); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:16: +4:17 - StorageLive(_9); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+5:9: +5:16 - StorageLive(_10); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+5:14: +5:15 - _10 = move _4; // scope 2 at $DIR/generator-storage-dead-unwind.rs:+5:14: +5:15 - _9 = take::(move _10) -> [return: bb3, unwind: bb8]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:+5:9: +5:16 + StorageDead(_8); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:15: 26:16 + StorageDead(_7); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:16: 26:17 + StorageLive(_9); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16 + StorageLive(_10); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:14: 27:15 + _10 = move _4; // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:14: 27:15 + _9 = take::(move _10) -> [return: bb3, unwind: bb8]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16 // mir::Constant // + span: $DIR/generator-storage-dead-unwind.rs:27:9: 27:13 // + literal: Const { ty: fn(Bar) {take::}, val: Value() } } bb3: { - StorageDead(_10); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+5:15: +5:16 - StorageDead(_9); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+5:16: +5:17 - _0 = const (); // scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:19: +6:6 - StorageDead(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6 - StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6 - drop(_1) -> [return: bb4, unwind: bb11]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6 + StorageDead(_10); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:15: 27:16 + StorageDead(_9); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:16: 27:17 + _0 = const (); // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:19: 28:6 + StorageDead(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6 + StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6 + drop(_1) -> [return: bb4, unwind: bb11]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6 } bb4: { - return; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:18: +0:18 + return; // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:18: 22:18 } bb5: { - StorageDead(_6); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+3:13: +3:14 - StorageDead(_5); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+3:14: +3:15 - StorageDead(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6 - drop(_3) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6 + StorageDead(_6); // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:13: 25:14 + StorageDead(_5); // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:14: 25:15 + StorageDead(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6 + drop(_3) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6 } bb6: { - StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6 - drop(_1) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6 + StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6 + drop(_1) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6 } bb7: { - generator_drop; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:16: +0:18 + generator_drop; // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:16: 22:18 } bb8 (cleanup): { - StorageDead(_10); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+5:15: +5:16 - StorageDead(_9); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+5:16: +5:17 + StorageDead(_10); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:15: 27:16 + StorageDead(_9); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:16: 27:17 goto -> bb10; // scope 2 at no-location } bb9 (cleanup): { - StorageDead(_8); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:15: +4:16 - StorageDead(_7); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:16: +4:17 + StorageDead(_8); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:15: 26:16 + StorageDead(_7); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:16: 26:17 goto -> bb10; // scope 2 at no-location } bb10 (cleanup): { - StorageDead(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6 - StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6 - drop(_1) -> bb11; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6 + StorageDead(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6 + StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6 + drop(_1) -> bb11; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6 } bb11 (cleanup): { - resume; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:16: +0:18 + resume; // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:16: 22:18 } bb12 (cleanup): { - StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6 - drop(_1) -> bb11; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6 + StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6 + drop(_1) -> bb11; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6 } } diff --git a/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir index 62e7d7b2da7e8..16fa432dc3ad3 100644 --- a/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir +++ b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir @@ -15,70 +15,70 @@ } */ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 19:24]>, _2: u8) -> GeneratorState<(), ()> { - debug _x => _10; // in scope 0 at $DIR/generator-tiny.rs:+0:17: +0:19 - let mut _0: std::ops::GeneratorState<(), ()>; // return place in scope 0 at $DIR/generator-tiny.rs:+0:16: +0:24 - let _3: HasDrop; // in scope 0 at $DIR/generator-tiny.rs:+1:13: +1:15 - let mut _4: !; // in scope 0 at $DIR/generator-tiny.rs:+2:9: +5:10 - let mut _5: (); // in scope 0 at $DIR/generator-tiny.rs:+0:16: +0:24 - let _6: u8; // in scope 0 at $DIR/generator-tiny.rs:+3:13: +3:18 - let mut _7: (); // in scope 0 at $DIR/generator-tiny.rs:+3:13: +3:18 - let _8: (); // in scope 0 at $DIR/generator-tiny.rs:+4:13: +4:21 - let mut _9: (); // in scope 0 at $DIR/generator-tiny.rs:+0:25: +0:25 - let _10: u8; // in scope 0 at $DIR/generator-tiny.rs:+0:17: +0:19 - let mut _11: u32; // in scope 0 at $DIR/generator-tiny.rs:+0:16: +0:24 + debug _x => _10; // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19 + let mut _0: std::ops::GeneratorState<(), ()>; // return place in scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 + let _3: HasDrop; // in scope 0 at $DIR/generator-tiny.rs:20:13: 20:15 + let mut _4: !; // in scope 0 at $DIR/generator-tiny.rs:21:9: 24:10 + let mut _5: (); // in scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 + let _6: u8; // in scope 0 at $DIR/generator-tiny.rs:22:13: 22:18 + let mut _7: (); // in scope 0 at $DIR/generator-tiny.rs:22:13: 22:18 + let _8: (); // in scope 0 at $DIR/generator-tiny.rs:23:13: 23:21 + let mut _9: (); // in scope 0 at $DIR/generator-tiny.rs:19:25: 19:25 + let _10: u8; // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19 + let mut _11: u32; // in scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 scope 1 { - debug _d => (((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24])) as variant#3).0: HasDrop); // in scope 1 at $DIR/generator-tiny.rs:+1:13: +1:15 + debug _d => (((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24])) as variant#3).0: HasDrop); // in scope 1 at $DIR/generator-tiny.rs:20:13: 20:15 } bb0: { - _11 = discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24]))); // scope 0 at $DIR/generator-tiny.rs:+0:16: +0:24 - switchInt(move _11) -> [0_u32: bb1, 3_u32: bb5, otherwise: bb6]; // scope 0 at $DIR/generator-tiny.rs:+0:16: +0:24 + _11 = discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24]))); // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 + switchInt(move _11) -> [0_u32: bb1, 3_u32: bb5, otherwise: bb6]; // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 } bb1: { - _10 = move _2; // scope 0 at $DIR/generator-tiny.rs:+0:16: +0:24 - nop; // scope 0 at $DIR/generator-tiny.rs:+1:13: +1:15 - Deinit((((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24])) as variant#3).0: HasDrop)); // scope 0 at $DIR/generator-tiny.rs:+1:18: +1:25 - StorageLive(_4); // scope 1 at $DIR/generator-tiny.rs:+2:9: +5:10 - goto -> bb2; // scope 1 at $DIR/generator-tiny.rs:+2:9: +5:10 + _10 = move _2; // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 + nop; // scope 0 at $DIR/generator-tiny.rs:20:13: 20:15 + Deinit((((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24])) as variant#3).0: HasDrop)); // scope 0 at $DIR/generator-tiny.rs:20:18: 20:25 + StorageLive(_4); // scope 1 at $DIR/generator-tiny.rs:21:9: 24:10 + goto -> bb2; // scope 1 at $DIR/generator-tiny.rs:21:9: 24:10 } bb2: { - StorageLive(_6); // scope 1 at $DIR/generator-tiny.rs:+3:13: +3:18 - StorageLive(_7); // scope 1 at $DIR/generator-tiny.rs:+3:13: +3:18 - Deinit(_7); // scope 1 at $DIR/generator-tiny.rs:+3:13: +3:18 - Deinit(_0); // scope 1 at $DIR/generator-tiny.rs:+3:13: +3:18 - ((_0 as Yielded).0: ()) = move _7; // scope 1 at $DIR/generator-tiny.rs:+3:13: +3:18 - discriminant(_0) = 0; // scope 1 at $DIR/generator-tiny.rs:+3:13: +3:18 - discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24]))) = 3; // scope 1 at $DIR/generator-tiny.rs:+3:13: +3:18 - return; // scope 1 at $DIR/generator-tiny.rs:+3:13: +3:18 + StorageLive(_6); // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 + StorageLive(_7); // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 + Deinit(_7); // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 + Deinit(_0); // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 + ((_0 as Yielded).0: ()) = move _7; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 + discriminant(_0) = 0; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 + discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24]))) = 3; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 + return; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 } bb3: { - StorageDead(_7); // scope 1 at $DIR/generator-tiny.rs:+3:17: +3:18 - StorageDead(_6); // scope 1 at $DIR/generator-tiny.rs:+3:18: +3:19 - StorageLive(_8); // scope 1 at $DIR/generator-tiny.rs:+4:13: +4:21 - _8 = callee() -> bb4; // scope 1 at $DIR/generator-tiny.rs:+4:13: +4:21 + StorageDead(_7); // scope 1 at $DIR/generator-tiny.rs:22:17: 22:18 + StorageDead(_6); // scope 1 at $DIR/generator-tiny.rs:22:18: 22:19 + StorageLive(_8); // scope 1 at $DIR/generator-tiny.rs:23:13: 23:21 + _8 = callee() -> bb4; // scope 1 at $DIR/generator-tiny.rs:23:13: 23:21 // mir::Constant // + span: $DIR/generator-tiny.rs:23:13: 23:19 // + literal: Const { ty: fn() {callee}, val: Value() } } bb4: { - StorageDead(_8); // scope 1 at $DIR/generator-tiny.rs:+4:21: +4:22 - _5 = const (); // scope 1 at $DIR/generator-tiny.rs:+2:14: +5:10 - goto -> bb2; // scope 1 at $DIR/generator-tiny.rs:+2:9: +5:10 + StorageDead(_8); // scope 1 at $DIR/generator-tiny.rs:23:21: 23:22 + _5 = const (); // scope 1 at $DIR/generator-tiny.rs:21:14: 24:10 + goto -> bb2; // scope 1 at $DIR/generator-tiny.rs:21:9: 24:10 } bb5: { - StorageLive(_4); // scope 0 at $DIR/generator-tiny.rs:+0:16: +0:24 - StorageLive(_6); // scope 0 at $DIR/generator-tiny.rs:+0:16: +0:24 - StorageLive(_7); // scope 0 at $DIR/generator-tiny.rs:+0:16: +0:24 - _6 = move _2; // scope 0 at $DIR/generator-tiny.rs:+0:16: +0:24 - goto -> bb3; // scope 0 at $DIR/generator-tiny.rs:+0:16: +0:24 + StorageLive(_4); // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 + StorageLive(_6); // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 + StorageLive(_7); // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 + _6 = move _2; // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 + goto -> bb3; // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 } bb6: { - unreachable; // scope 0 at $DIR/generator-tiny.rs:+0:16: +0:24 + unreachable; // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 } } diff --git a/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff index 19b5ab44156f4..dddb7acae2b2c 100644 --- a/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff +++ b/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff @@ -2,29 +2,29 @@ + // MIR for `dont_opt_bool` after SimplifyComparisonIntegral fn dont_opt_bool(_1: bool) -> u32 { - debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:+0:18: +0:19 - let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:+0:30: +0:33 - let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:16:18: 16:19 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:16:30: 16:33 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:17:8: 17:9 bb0: { - StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 - _2 = _1; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 - switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:17:8: 17:9 + _2 = _1; // scope 0 at $DIR/if-condition-int.rs:17:8: 17:9 + switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:17:8: 17:9 } bb1: { - _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:+1:12: +1:13 - goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:26 + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:17:12: 17:13 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:17:5: 17:26 } bb2: { - _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:+1:23: +1:24 - goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:26 + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:17:23: 17:24 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:17:5: 17:26 } bb3: { - StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:+1:25: +1:26 - return; // scope 0 at $DIR/if-condition-int.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:17:25: 17:26 + return; // scope 0 at $DIR/if-condition-int.rs:18:2: 18:2 } } diff --git a/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff index 256af7b94be2c..2ff8386b205bd 100644 --- a/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff +++ b/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff @@ -2,33 +2,33 @@ + // MIR for `dont_opt_floats` after SimplifyComparisonIntegral fn dont_opt_floats(_1: f32) -> i32 { - debug a => _1; // in scope 0 at $DIR/if-condition-int.rs:+0:20: +0:21 - let mut _0: i32; // return place in scope 0 at $DIR/if-condition-int.rs:+0:31: +0:34 - let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:18 - let mut _3: f32; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 + debug a => _1; // in scope 0 at $DIR/if-condition-int.rs:52:20: 52:21 + let mut _0: i32; // return place in scope 0 at $DIR/if-condition-int.rs:52:31: 52:34 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:53:8: 53:18 + let mut _3: f32; // in scope 0 at $DIR/if-condition-int.rs:53:8: 53:9 bb0: { - StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:18 - StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 - _3 = _1; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 - _2 = Eq(move _3, const -42f32); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:18 - StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:17: +1:18 - switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:18 + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:53:8: 53:18 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:53:8: 53:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:53:8: 53:9 + _2 = Eq(move _3, const -42f32); // scope 0 at $DIR/if-condition-int.rs:53:8: 53:18 + StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:53:17: 53:18 + switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:53:8: 53:18 } bb1: { - _0 = const 0_i32; // scope 0 at $DIR/if-condition-int.rs:+1:21: +1:22 - goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:35 + _0 = const 0_i32; // scope 0 at $DIR/if-condition-int.rs:53:21: 53:22 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:53:5: 53:35 } bb2: { - _0 = const 1_i32; // scope 0 at $DIR/if-condition-int.rs:+1:32: +1:33 - goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:35 + _0 = const 1_i32; // scope 0 at $DIR/if-condition-int.rs:53:32: 53:33 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:53:5: 53:35 } bb3: { - StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:+1:34: +1:35 - return; // scope 0 at $DIR/if-condition-int.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:53:34: 53:35 + return; // scope 0 at $DIR/if-condition-int.rs:54:2: 54:2 } } diff --git a/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff index 3f612e03f58e2..fd4dcb2265e61 100644 --- a/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff +++ b/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff @@ -2,57 +2,57 @@ + // MIR for `dont_remove_comparison` after SimplifyComparisonIntegral fn dont_remove_comparison(_1: i8) -> i32 { - debug a => _1; // in scope 0 at $DIR/if-condition-int.rs:+0:27: +0:28 - let mut _0: i32; // return place in scope 0 at $DIR/if-condition-int.rs:+0:37: +0:40 - let _2: bool; // in scope 0 at $DIR/if-condition-int.rs:+1:9: +1:10 - let mut _3: i8; // in scope 0 at $DIR/if-condition-int.rs:+1:13: +1:14 - let mut _4: i32; // in scope 0 at $DIR/if-condition-int.rs:+3:23: +3:31 - let mut _5: bool; // in scope 0 at $DIR/if-condition-int.rs:+3:23: +3:24 - let mut _6: i32; // in scope 0 at $DIR/if-condition-int.rs:+4:23: +4:31 - let mut _7: bool; // in scope 0 at $DIR/if-condition-int.rs:+4:23: +4:24 + debug a => _1; // in scope 0 at $DIR/if-condition-int.rs:43:27: 43:28 + let mut _0: i32; // return place in scope 0 at $DIR/if-condition-int.rs:43:37: 43:40 + let _2: bool; // in scope 0 at $DIR/if-condition-int.rs:44:9: 44:10 + let mut _3: i8; // in scope 0 at $DIR/if-condition-int.rs:44:13: 44:14 + let mut _4: i32; // in scope 0 at $DIR/if-condition-int.rs:46:23: 46:31 + let mut _5: bool; // in scope 0 at $DIR/if-condition-int.rs:46:23: 46:24 + let mut _6: i32; // in scope 0 at $DIR/if-condition-int.rs:47:23: 47:31 + let mut _7: bool; // in scope 0 at $DIR/if-condition-int.rs:47:23: 47:24 scope 1 { - debug b => _2; // in scope 1 at $DIR/if-condition-int.rs:+1:9: +1:10 + debug b => _2; // in scope 1 at $DIR/if-condition-int.rs:44:9: 44:10 } bb0: { - StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:+1:13: +1:14 - _3 = _1; // scope 0 at $DIR/if-condition-int.rs:+1:13: +1:14 -- _2 = Eq(move _3, const 17_i8); // scope 0 at $DIR/if-condition-int.rs:+1:13: +1:20 -- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:19: +1:20 -- switchInt(_2) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if-condition-int.rs:+2:5: +2:12 -+ _2 = Eq(_3, const 17_i8); // scope 0 at $DIR/if-condition-int.rs:+1:13: +1:20 -+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:19: +1:20 -+ switchInt(move _3) -> [17_i8: bb1, otherwise: bb2]; // scope 1 at $DIR/if-condition-int.rs:+2:5: +2:12 + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:44:9: 44:10 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:44:13: 44:14 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:44:13: 44:14 +- _2 = Eq(move _3, const 17_i8); // scope 0 at $DIR/if-condition-int.rs:44:13: 44:20 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:44:19: 44:20 +- switchInt(_2) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if-condition-int.rs:45:5: 45:12 ++ _2 = Eq(_3, const 17_i8); // scope 0 at $DIR/if-condition-int.rs:44:13: 44:20 ++ nop; // scope 0 at $DIR/if-condition-int.rs:44:19: 44:20 ++ switchInt(move _3) -> [17_i8: bb1, otherwise: bb2]; // scope 1 at $DIR/if-condition-int.rs:45:5: 45:12 } bb1: { -+ StorageDead(_3); // scope 1 at $DIR/if-condition-int.rs:+2:5: +2:12 - StorageLive(_6); // scope 1 at $DIR/if-condition-int.rs:+4:23: +4:31 - StorageLive(_7); // scope 1 at $DIR/if-condition-int.rs:+4:23: +4:24 - _7 = _2; // scope 1 at $DIR/if-condition-int.rs:+4:23: +4:24 - _6 = move _7 as i32 (Misc); // scope 1 at $DIR/if-condition-int.rs:+4:23: +4:31 - StorageDead(_7); // scope 1 at $DIR/if-condition-int.rs:+4:30: +4:31 - _0 = Add(const 100_i32, move _6); // scope 1 at $DIR/if-condition-int.rs:+4:17: +4:31 - StorageDead(_6); // scope 1 at $DIR/if-condition-int.rs:+4:30: +4:31 - goto -> bb3; // scope 1 at $DIR/if-condition-int.rs:+4:30: +4:31 ++ StorageDead(_3); // scope 1 at $DIR/if-condition-int.rs:45:5: 45:12 + StorageLive(_6); // scope 1 at $DIR/if-condition-int.rs:47:23: 47:31 + StorageLive(_7); // scope 1 at $DIR/if-condition-int.rs:47:23: 47:24 + _7 = _2; // scope 1 at $DIR/if-condition-int.rs:47:23: 47:24 + _6 = move _7 as i32 (Misc); // scope 1 at $DIR/if-condition-int.rs:47:23: 47:31 + StorageDead(_7); // scope 1 at $DIR/if-condition-int.rs:47:30: 47:31 + _0 = Add(const 100_i32, move _6); // scope 1 at $DIR/if-condition-int.rs:47:17: 47:31 + StorageDead(_6); // scope 1 at $DIR/if-condition-int.rs:47:30: 47:31 + goto -> bb3; // scope 1 at $DIR/if-condition-int.rs:47:30: 47:31 } bb2: { -+ StorageDead(_3); // scope 1 at $DIR/if-condition-int.rs:+2:5: +2:12 - StorageLive(_4); // scope 1 at $DIR/if-condition-int.rs:+3:23: +3:31 - StorageLive(_5); // scope 1 at $DIR/if-condition-int.rs:+3:23: +3:24 - _5 = _2; // scope 1 at $DIR/if-condition-int.rs:+3:23: +3:24 - _4 = move _5 as i32 (Misc); // scope 1 at $DIR/if-condition-int.rs:+3:23: +3:31 - StorageDead(_5); // scope 1 at $DIR/if-condition-int.rs:+3:30: +3:31 - _0 = Add(const 10_i32, move _4); // scope 1 at $DIR/if-condition-int.rs:+3:18: +3:31 - StorageDead(_4); // scope 1 at $DIR/if-condition-int.rs:+3:30: +3:31 - goto -> bb3; // scope 1 at $DIR/if-condition-int.rs:+3:30: +3:31 ++ StorageDead(_3); // scope 1 at $DIR/if-condition-int.rs:45:5: 45:12 + StorageLive(_4); // scope 1 at $DIR/if-condition-int.rs:46:23: 46:31 + StorageLive(_5); // scope 1 at $DIR/if-condition-int.rs:46:23: 46:24 + _5 = _2; // scope 1 at $DIR/if-condition-int.rs:46:23: 46:24 + _4 = move _5 as i32 (Misc); // scope 1 at $DIR/if-condition-int.rs:46:23: 46:31 + StorageDead(_5); // scope 1 at $DIR/if-condition-int.rs:46:30: 46:31 + _0 = Add(const 10_i32, move _4); // scope 1 at $DIR/if-condition-int.rs:46:18: 46:31 + StorageDead(_4); // scope 1 at $DIR/if-condition-int.rs:46:30: 46:31 + goto -> bb3; // scope 1 at $DIR/if-condition-int.rs:46:30: 46:31 } bb3: { - StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:+6:1: +6:2 - return; // scope 0 at $DIR/if-condition-int.rs:+6:2: +6:2 + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:49:1: 49:2 + return; // scope 0 at $DIR/if-condition-int.rs:49:2: 49:2 } } diff --git a/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff index 9b64c379fee77..40de48385f02e 100644 --- a/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff +++ b/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff @@ -2,38 +2,38 @@ + // MIR for `opt_char` after SimplifyComparisonIntegral fn opt_char(_1: char) -> u32 { - debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:+0:13: +0:14 - let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:+0:25: +0:28 - let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16 - let mut _3: char; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:20:13: 20:14 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:20:25: 20:28 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:21:8: 21:16 + let mut _3: char; // in scope 0 at $DIR/if-condition-int.rs:21:8: 21:9 bb0: { - StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16 - StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 - _3 = _1; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 -- _2 = Eq(move _3, const 'x'); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16 -- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:15: +1:16 -- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16 -+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16 -+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:15: +1:16 -+ switchInt(move _3) -> ['x': bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16 + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:16 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:21:8: 21:9 +- _2 = Eq(move _3, const 'x'); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:16 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:21:15: 21:16 +- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:21:8: 21:16 ++ nop; // scope 0 at $DIR/if-condition-int.rs:21:8: 21:16 ++ nop; // scope 0 at $DIR/if-condition-int.rs:21:15: 21:16 ++ switchInt(move _3) -> ['x': bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:21:8: 21:16 } bb1: { -+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16 - _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:+1:19: +1:20 - goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:33 ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:16 + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:21:19: 21:20 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33 } bb2: { -+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16 - _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:+1:30: +1:31 - goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:33 ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:16 + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:21:30: 21:31 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33 } bb3: { - StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:+1:32: +1:33 - return; // scope 0 at $DIR/if-condition-int.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:21:32: 21:33 + return; // scope 0 at $DIR/if-condition-int.rs:22:2: 22:2 } } diff --git a/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff index 8042d63bb34dd..28c36aed84c38 100644 --- a/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff +++ b/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff @@ -2,38 +2,38 @@ + // MIR for `opt_i8` after SimplifyComparisonIntegral fn opt_i8(_1: i8) -> u32 { - debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:+0:11: +0:12 - let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:+0:21: +0:24 - let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 - let mut _3: i8; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:24:11: 24:12 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:24:21: 24:24 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:25:8: 25:15 + let mut _3: i8; // in scope 0 at $DIR/if-condition-int.rs:25:8: 25:9 bb0: { - StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 - StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 - _3 = _1; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 -- _2 = Eq(move _3, const 42_i8); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 -- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:14: +1:15 -- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 -+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 -+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:14: +1:15 -+ switchInt(move _3) -> [42_i8: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:15 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:25:8: 25:9 +- _2 = Eq(move _3, const 42_i8); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:15 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:25:14: 25:15 +- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:25:8: 25:15 ++ nop; // scope 0 at $DIR/if-condition-int.rs:25:8: 25:15 ++ nop; // scope 0 at $DIR/if-condition-int.rs:25:14: 25:15 ++ switchInt(move _3) -> [42_i8: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:25:8: 25:15 } bb1: { -+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 - _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:+1:18: +1:19 - goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:32 ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:15 + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:25:18: 25:19 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32 } bb2: { -+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 - _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:+1:29: +1:30 - goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:32 ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:15 + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:25:29: 25:30 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32 } bb3: { - StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:+1:31: +1:32 - return; // scope 0 at $DIR/if-condition-int.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:25:31: 25:32 + return; // scope 0 at $DIR/if-condition-int.rs:26:2: 26:2 } } diff --git a/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff index a408de1ef3e97..55932fee9600c 100644 --- a/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff +++ b/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff @@ -2,64 +2,64 @@ + // MIR for `opt_multiple_ifs` after SimplifyComparisonIntegral fn opt_multiple_ifs(_1: u32) -> u32 { - debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:+0:21: +0:22 - let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:+0:32: +0:35 - let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 - let mut _3: u32; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 - let mut _4: bool; // in scope 0 at $DIR/if-condition-int.rs:+3:15: +3:22 - let mut _5: u32; // in scope 0 at $DIR/if-condition-int.rs:+3:15: +3:16 + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:32:21: 32:22 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:32:32: 32:35 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:33:8: 33:15 + let mut _3: u32; // in scope 0 at $DIR/if-condition-int.rs:33:8: 33:9 + let mut _4: bool; // in scope 0 at $DIR/if-condition-int.rs:35:15: 35:22 + let mut _5: u32; // in scope 0 at $DIR/if-condition-int.rs:35:15: 35:16 bb0: { - StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 - StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 - _3 = _1; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 -- _2 = Eq(move _3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 -- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:14: +1:15 -- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 -+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 -+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:14: +1:15 -+ switchInt(move _3) -> [42_u32: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:15 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:33:8: 33:9 +- _2 = Eq(move _3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:15 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:33:14: 33:15 +- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:33:8: 33:15 ++ nop; // scope 0 at $DIR/if-condition-int.rs:33:8: 33:15 ++ nop; // scope 0 at $DIR/if-condition-int.rs:33:14: 33:15 ++ switchInt(move _3) -> [42_u32: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:33:8: 33:15 } bb1: { -+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 - _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:+2:9: +2:10 - goto -> bb6; // scope 0 at $DIR/if-condition-int.rs:+1:5: +7:6 ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:15 + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:34:9: 34:10 + goto -> bb6; // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6 } bb2: { -+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 - StorageLive(_4); // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:22 - StorageLive(_5); // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:16 - _5 = _1; // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:16 -- _4 = Ne(move _5, const 21_u32); // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:22 -- StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:+3:21: +3:22 -- switchInt(move _4) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:22 -+ nop; // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:22 -+ nop; // scope 0 at $DIR/if-condition-int.rs:+3:21: +3:22 -+ switchInt(move _5) -> [21_u32: bb4, otherwise: bb3]; // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:22 ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:15 + StorageLive(_4); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:22 + StorageLive(_5); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:16 + _5 = _1; // scope 0 at $DIR/if-condition-int.rs:35:15: 35:16 +- _4 = Ne(move _5, const 21_u32); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:22 +- StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:35:21: 35:22 +- switchInt(move _4) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/if-condition-int.rs:35:15: 35:22 ++ nop; // scope 0 at $DIR/if-condition-int.rs:35:15: 35:22 ++ nop; // scope 0 at $DIR/if-condition-int.rs:35:21: 35:22 ++ switchInt(move _5) -> [21_u32: bb4, otherwise: bb3]; // scope 0 at $DIR/if-condition-int.rs:35:15: 35:22 } bb3: { -+ StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:22 - _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:+4:9: +4:10 - goto -> bb5; // scope 0 at $DIR/if-condition-int.rs:+3:12: +7:6 ++ StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:22 + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:36:9: 36:10 + goto -> bb5; // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6 } bb4: { -+ StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:22 - _0 = const 2_u32; // scope 0 at $DIR/if-condition-int.rs:+6:9: +6:10 - goto -> bb5; // scope 0 at $DIR/if-condition-int.rs:+3:12: +7:6 ++ StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:22 + _0 = const 2_u32; // scope 0 at $DIR/if-condition-int.rs:38:9: 38:10 + goto -> bb5; // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6 } bb5: { - StorageDead(_4); // scope 0 at $DIR/if-condition-int.rs:+7:5: +7:6 - goto -> bb6; // scope 0 at $DIR/if-condition-int.rs:+1:5: +7:6 + StorageDead(_4); // scope 0 at $DIR/if-condition-int.rs:39:5: 39:6 + goto -> bb6; // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6 } bb6: { - StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:+7:5: +7:6 - return; // scope 0 at $DIR/if-condition-int.rs:+8:2: +8:2 + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:39:5: 39:6 + return; // scope 0 at $DIR/if-condition-int.rs:40:2: 40:2 } } diff --git a/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff index 6802f89d9278b..c4574b32a5999 100644 --- a/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff +++ b/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff @@ -2,38 +2,38 @@ + // MIR for `opt_negative` after SimplifyComparisonIntegral fn opt_negative(_1: i32) -> u32 { - debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:+0:17: +0:18 - let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:+0:28: +0:31 - let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16 - let mut _3: i32; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:28:17: 28:18 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:28:28: 28:31 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:29:8: 29:16 + let mut _3: i32; // in scope 0 at $DIR/if-condition-int.rs:29:8: 29:9 bb0: { - StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16 - StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 - _3 = _1; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 -- _2 = Eq(move _3, const -42_i32); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16 -- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:15: +1:16 -- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16 -+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16 -+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:15: +1:16 -+ switchInt(move _3) -> [-42_i32: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16 + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:16 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:29:8: 29:9 +- _2 = Eq(move _3, const -42_i32); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:16 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:29:15: 29:16 +- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:29:8: 29:16 ++ nop; // scope 0 at $DIR/if-condition-int.rs:29:8: 29:16 ++ nop; // scope 0 at $DIR/if-condition-int.rs:29:15: 29:16 ++ switchInt(move _3) -> [-42_i32: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:29:8: 29:16 } bb1: { -+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16 - _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:+1:19: +1:20 - goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:33 ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:16 + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:29:19: 29:20 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33 } bb2: { -+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16 - _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:+1:30: +1:31 - goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:33 ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:16 + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:29:30: 29:31 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33 } bb3: { - StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:+1:32: +1:33 - return; // scope 0 at $DIR/if-condition-int.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:29:32: 29:33 + return; // scope 0 at $DIR/if-condition-int.rs:30:2: 30:2 } } diff --git a/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff index 96387771d06f1..88d9d5622b8ec 100644 --- a/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff +++ b/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff @@ -2,38 +2,38 @@ + // MIR for `opt_u32` after SimplifyComparisonIntegral fn opt_u32(_1: u32) -> u32 { - debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:+0:12: +0:13 - let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:+0:23: +0:26 - let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 - let mut _3: u32; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:11:12: 11:13 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:11:23: 11:26 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:12:8: 12:15 + let mut _3: u32; // in scope 0 at $DIR/if-condition-int.rs:12:8: 12:9 bb0: { - StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 - StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 - _3 = _1; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9 -- _2 = Eq(move _3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 -- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:14: +1:15 -- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 -+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 -+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:14: +1:15 -+ switchInt(move _3) -> [42_u32: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:15 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:12:8: 12:9 +- _2 = Eq(move _3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:15 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:12:14: 12:15 +- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:12:8: 12:15 ++ nop; // scope 0 at $DIR/if-condition-int.rs:12:8: 12:15 ++ nop; // scope 0 at $DIR/if-condition-int.rs:12:14: 12:15 ++ switchInt(move _3) -> [42_u32: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:12:8: 12:15 } bb1: { -+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 - _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:+1:18: +1:19 - goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:32 ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:15 + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:12:18: 12:19 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32 } bb2: { -+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15 - _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:+1:29: +1:30 - goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:32 ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:15 + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:12:29: 12:30 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32 } bb3: { - StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:+1:31: +1:32 - return; // scope 0 at $DIR/if-condition-int.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:12:31: 12:32 + return; // scope 0 at $DIR/if-condition-int.rs:13:2: 13:2 } } diff --git a/src/test/mir-opt/inline/caller_with_trivial_bound.foo.Inline.diff b/src/test/mir-opt/inline/caller_with_trivial_bound.foo.Inline.diff index d7deb9c66cfa0..d30c74897b342 100644 --- a/src/test/mir-opt/inline/caller_with_trivial_bound.foo.Inline.diff +++ b/src/test/mir-opt/inline/caller_with_trivial_bound.foo.Inline.diff @@ -2,32 +2,32 @@ + // MIR for `foo` after Inline fn foo() -> () { - let mut _0: (); // return place in scope 0 at $DIR/caller-with-trivial-bound.rs:+1:1: +1:1 - let mut _1: >::Item; // in scope 0 at $DIR/caller-with-trivial-bound.rs:+4:9: +4:14 + let mut _0: (); // return place in scope 0 at $DIR/caller-with-trivial-bound.rs:17:1: 17:1 + let mut _1: >::Item; // in scope 0 at $DIR/caller-with-trivial-bound.rs:20:9: 20:14 scope 1 { - debug x => _1; // in scope 1 at $DIR/caller-with-trivial-bound.rs:+4:9: +4:14 + debug x => _1; // in scope 1 at $DIR/caller-with-trivial-bound.rs:20:9: 20:14 } bb0: { - StorageLive(_1); // scope 0 at $DIR/caller-with-trivial-bound.rs:+4:9: +4:14 - _1 = bar::() -> bb1; // scope 0 at $DIR/caller-with-trivial-bound.rs:+4:51: +4:61 + StorageLive(_1); // scope 0 at $DIR/caller-with-trivial-bound.rs:20:9: 20:14 + _1 = bar::() -> bb1; // scope 0 at $DIR/caller-with-trivial-bound.rs:20:51: 20:61 // mir::Constant // + span: $DIR/caller-with-trivial-bound.rs:20:51: 20:59 // + literal: Const { ty: fn() -> >::Item {bar::}, val: Value() } } bb1: { - _0 = const (); // scope 0 at $DIR/caller-with-trivial-bound.rs:+3:1: +5:2 - drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/caller-with-trivial-bound.rs:+5:1: +5:2 + _0 = const (); // scope 0 at $DIR/caller-with-trivial-bound.rs:19:1: 21:2 + drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/caller-with-trivial-bound.rs:21:1: 21:2 } bb2: { - StorageDead(_1); // scope 0 at $DIR/caller-with-trivial-bound.rs:+5:1: +5:2 - return; // scope 0 at $DIR/caller-with-trivial-bound.rs:+5:2: +5:2 + StorageDead(_1); // scope 0 at $DIR/caller-with-trivial-bound.rs:21:1: 21:2 + return; // scope 0 at $DIR/caller-with-trivial-bound.rs:21:2: 21:2 } bb3 (cleanup): { - resume; // scope 0 at $DIR/caller-with-trivial-bound.rs:+0:1: +5:2 + resume; // scope 0 at $DIR/caller-with-trivial-bound.rs:16:1: 21:2 } } diff --git a/src/test/mir-opt/inline/cycle.f.Inline.diff b/src/test/mir-opt/inline/cycle.f.Inline.diff index 40fdd1cdb19c9..1376ba99d992c 100644 --- a/src/test/mir-opt/inline/cycle.f.Inline.diff +++ b/src/test/mir-opt/inline/cycle.f.Inline.diff @@ -2,42 +2,42 @@ + // MIR for `f` after Inline fn f(_1: impl Fn()) -> () { - debug g => _1; // in scope 0 at $DIR/cycle.rs:+0:6: +0:7 - let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:+0:20: +0:20 - let _2: (); // in scope 0 at $DIR/cycle.rs:+1:5: +1:8 - let mut _3: &impl Fn(); // in scope 0 at $DIR/cycle.rs:+1:5: +1:6 - let mut _4: (); // in scope 0 at $DIR/cycle.rs:+1:5: +1:8 + debug g => _1; // in scope 0 at $DIR/cycle.rs:5:6: 5:7 + let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:5:20: 5:20 + let _2: (); // in scope 0 at $DIR/cycle.rs:6:5: 6:8 + let mut _3: &impl Fn(); // in scope 0 at $DIR/cycle.rs:6:5: 6:6 + let mut _4: (); // in scope 0 at $DIR/cycle.rs:6:5: 6:8 bb0: { - StorageLive(_2); // scope 0 at $DIR/cycle.rs:+1:5: +1:8 - StorageLive(_3); // scope 0 at $DIR/cycle.rs:+1:5: +1:6 - _3 = &_1; // scope 0 at $DIR/cycle.rs:+1:5: +1:6 - StorageLive(_4); // scope 0 at $DIR/cycle.rs:+1:5: +1:8 - Deinit(_4); // scope 0 at $DIR/cycle.rs:+1:5: +1:8 - _2 = >::call(move _3, move _4) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/cycle.rs:+1:5: +1:8 + StorageLive(_2); // scope 0 at $DIR/cycle.rs:6:5: 6:8 + StorageLive(_3); // scope 0 at $DIR/cycle.rs:6:5: 6:6 + _3 = &_1; // scope 0 at $DIR/cycle.rs:6:5: 6:6 + StorageLive(_4); // scope 0 at $DIR/cycle.rs:6:5: 6:8 + Deinit(_4); // scope 0 at $DIR/cycle.rs:6:5: 6:8 + _2 = >::call(move _3, move _4) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/cycle.rs:6:5: 6:8 // mir::Constant // + span: $DIR/cycle.rs:6:5: 6:6 // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> >::Output {>::call}, val: Value() } } bb1: { - StorageDead(_4); // scope 0 at $DIR/cycle.rs:+1:7: +1:8 - StorageDead(_3); // scope 0 at $DIR/cycle.rs:+1:7: +1:8 - StorageDead(_2); // scope 0 at $DIR/cycle.rs:+1:8: +1:9 - _0 = const (); // scope 0 at $DIR/cycle.rs:+0:20: +2:2 - drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/cycle.rs:+2:1: +2:2 + StorageDead(_4); // scope 0 at $DIR/cycle.rs:6:7: 6:8 + StorageDead(_3); // scope 0 at $DIR/cycle.rs:6:7: 6:8 + StorageDead(_2); // scope 0 at $DIR/cycle.rs:6:8: 6:9 + _0 = const (); // scope 0 at $DIR/cycle.rs:5:20: 7:2 + drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/cycle.rs:7:1: 7:2 } bb2: { - return; // scope 0 at $DIR/cycle.rs:+2:2: +2:2 + return; // scope 0 at $DIR/cycle.rs:7:2: 7:2 } bb3 (cleanup): { - drop(_1) -> bb4; // scope 0 at $DIR/cycle.rs:+2:1: +2:2 + drop(_1) -> bb4; // scope 0 at $DIR/cycle.rs:7:1: 7:2 } bb4 (cleanup): { - resume; // scope 0 at $DIR/cycle.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/cycle.rs:5:1: 7:2 } } diff --git a/src/test/mir-opt/inline/cycle.g.Inline.diff b/src/test/mir-opt/inline/cycle.g.Inline.diff index 59f34d379ec20..5a8c147a32723 100644 --- a/src/test/mir-opt/inline/cycle.g.Inline.diff +++ b/src/test/mir-opt/inline/cycle.g.Inline.diff @@ -2,56 +2,56 @@ + // MIR for `g` after Inline fn g() -> () { - let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:+0:8: +0:8 - let _1: (); // in scope 0 at $DIR/cycle.rs:+1:5: +1:12 -+ let mut _2: fn() {main}; // in scope 0 at $DIR/cycle.rs:+1:5: +1:12 + let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:11:8: 11:8 + let _1: (); // in scope 0 at $DIR/cycle.rs:12:5: 12:12 ++ let mut _2: fn() {main}; // in scope 0 at $DIR/cycle.rs:12:5: 12:12 + scope 1 (inlined f::) { // at $DIR/cycle.rs:12:5: 12:12 -+ debug g => _2; // in scope 1 at $DIR/cycle.rs:+0:6: +0:7 -+ let _3: (); // in scope 1 at $DIR/cycle.rs:+0:5: +0:8 -+ let mut _4: &fn() {main}; // in scope 1 at $DIR/cycle.rs:+0:5: +0:6 -+ let mut _5: (); // in scope 1 at $DIR/cycle.rs:+0:5: +0:8 ++ debug g => _2; // in scope 1 at $DIR/cycle.rs:5:6: 5:7 ++ let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ let mut _4: &fn() {main}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ let mut _5: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 + scope 2 (inlined >::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8 + } + } bb0: { - StorageLive(_1); // scope 0 at $DIR/cycle.rs:+1:5: +1:12 -- _1 = f::(main) -> bb1; // scope 0 at $DIR/cycle.rs:+1:5: +1:12 -+ StorageLive(_2); // scope 0 at $DIR/cycle.rs:+1:5: +1:12 -+ _2 = main; // scope 0 at $DIR/cycle.rs:+1:5: +1:12 + StorageLive(_1); // scope 0 at $DIR/cycle.rs:12:5: 12:12 +- _1 = f::(main) -> bb1; // scope 0 at $DIR/cycle.rs:12:5: 12:12 ++ StorageLive(_2); // scope 0 at $DIR/cycle.rs:12:5: 12:12 ++ _2 = main; // scope 0 at $DIR/cycle.rs:12:5: 12:12 // mir::Constant - // + span: $DIR/cycle.rs:12:5: 12:6 - // + literal: Const { ty: fn(fn() {main}) {f::}, val: Value() } - // mir::Constant // + span: $DIR/cycle.rs:12:7: 12:11 // + literal: Const { ty: fn() {main}, val: Value() } -+ StorageLive(_3); // scope 1 at $DIR/cycle.rs:+0:5: +0:8 -+ StorageLive(_4); // scope 1 at $DIR/cycle.rs:+0:5: +0:6 -+ _4 = &_2; // scope 1 at $DIR/cycle.rs:+0:5: +0:6 -+ StorageLive(_5); // scope 1 at $DIR/cycle.rs:+0:5: +0:8 ++ StorageLive(_3); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 + _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL } bb1: { -+ StorageDead(_2); // scope 0 at $DIR/cycle.rs:+1:5: +1:12 - StorageDead(_1); // scope 0 at $DIR/cycle.rs:+1:12: +1:13 - _0 = const (); // scope 0 at $DIR/cycle.rs:+0:8: +2:2 - return; // scope 0 at $DIR/cycle.rs:+2:2: +2:2 ++ StorageDead(_2); // scope 0 at $DIR/cycle.rs:12:5: 12:12 + StorageDead(_1); // scope 0 at $DIR/cycle.rs:12:12: 12:13 + _0 = const (); // scope 0 at $DIR/cycle.rs:11:8: 13:2 + return; // scope 0 at $DIR/cycle.rs:13:2: 13:2 + } + + bb2 (cleanup): { -+ drop(_2) -> bb3; // scope 1 at $DIR/cycle.rs:+0:1: +0:2 ++ drop(_2) -> bb3; // scope 1 at $DIR/cycle.rs:7:1: 7:2 + } + + bb3 (cleanup): { -+ resume; // scope 1 at $DIR/cycle.rs:+0:1: +0:2 ++ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2 + } + + bb4: { -+ StorageDead(_5); // scope 1 at $DIR/cycle.rs:+0:7: +0:8 -+ StorageDead(_4); // scope 1 at $DIR/cycle.rs:+0:7: +0:8 -+ StorageDead(_3); // scope 1 at $DIR/cycle.rs:+0:8: +0:9 -+ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:+0:1: +0:2 ++ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9 ++ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2 } } diff --git a/src/test/mir-opt/inline/cycle.main.Inline.diff b/src/test/mir-opt/inline/cycle.main.Inline.diff index 6def7c3ee3e00..e102c65090587 100644 --- a/src/test/mir-opt/inline/cycle.main.Inline.diff +++ b/src/test/mir-opt/inline/cycle.main.Inline.diff @@ -2,21 +2,21 @@ + // MIR for `main` after Inline fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:+0:11: +0:11 - let _1: (); // in scope 0 at $DIR/cycle.rs:+1:5: +1:9 -+ let mut _2: fn() {g}; // in scope 0 at $DIR/cycle.rs:+1:5: +1:9 + let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:16:11: 16:11 + let _1: (); // in scope 0 at $DIR/cycle.rs:17:5: 17:9 ++ let mut _2: fn() {g}; // in scope 0 at $DIR/cycle.rs:17:5: 17:9 + scope 1 (inlined f::) { // at $DIR/cycle.rs:17:5: 17:9 -+ debug g => _2; // in scope 1 at $DIR/cycle.rs:+0:6: +0:7 -+ let _3: (); // in scope 1 at $DIR/cycle.rs:+0:5: +0:8 -+ let mut _4: &fn() {g}; // in scope 1 at $DIR/cycle.rs:+0:5: +0:6 -+ let mut _5: (); // in scope 1 at $DIR/cycle.rs:+0:5: +0:8 ++ debug g => _2; // in scope 1 at $DIR/cycle.rs:5:6: 5:7 ++ let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ let mut _4: &fn() {g}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ let mut _5: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 + scope 2 (inlined >::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8 + scope 3 (inlined g) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL -+ let mut _6: fn() {main}; // in scope 3 at $DIR/cycle.rs:+0:5: +0:12 ++ let mut _6: fn() {main}; // in scope 3 at $DIR/cycle.rs:12:5: 12:12 + scope 4 (inlined f::) { // at $DIR/cycle.rs:12:5: 12:12 -+ debug g => _6; // in scope 4 at $DIR/cycle.rs:+0:6: +0:7 -+ let _7: (); // in scope 4 at $DIR/cycle.rs:+0:5: +0:8 -+ let mut _8: &fn() {main}; // in scope 4 at $DIR/cycle.rs:+0:5: +0:6 ++ debug g => _6; // in scope 4 at $DIR/cycle.rs:5:6: 5:7 ++ let _7: (); // in scope 4 at $DIR/cycle.rs:6:5: 6:8 ++ let mut _8: &fn() {main}; // in scope 4 at $DIR/cycle.rs:6:5: 6:6 + scope 5 (inlined >::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8 + } + } @@ -25,50 +25,50 @@ + } bb0: { - StorageLive(_1); // scope 0 at $DIR/cycle.rs:+1:5: +1:9 -- _1 = f::(g) -> bb1; // scope 0 at $DIR/cycle.rs:+1:5: +1:9 -+ StorageLive(_2); // scope 0 at $DIR/cycle.rs:+1:5: +1:9 -+ _2 = g; // scope 0 at $DIR/cycle.rs:+1:5: +1:9 + StorageLive(_1); // scope 0 at $DIR/cycle.rs:17:5: 17:9 +- _1 = f::(g) -> bb1; // scope 0 at $DIR/cycle.rs:17:5: 17:9 ++ StorageLive(_2); // scope 0 at $DIR/cycle.rs:17:5: 17:9 ++ _2 = g; // scope 0 at $DIR/cycle.rs:17:5: 17:9 // mir::Constant - // + span: $DIR/cycle.rs:17:5: 17:6 - // + literal: Const { ty: fn(fn() {g}) {f::}, val: Value() } - // mir::Constant // + span: $DIR/cycle.rs:17:7: 17:8 // + literal: Const { ty: fn() {g}, val: Value() } -+ StorageLive(_3); // scope 1 at $DIR/cycle.rs:+0:5: +0:8 -+ StorageLive(_4); // scope 1 at $DIR/cycle.rs:+0:5: +0:6 -+ _4 = &_2; // scope 1 at $DIR/cycle.rs:+0:5: +0:6 -+ StorageLive(_5); // scope 1 at $DIR/cycle.rs:+0:5: +0:8 -+ StorageLive(_6); // scope 3 at $DIR/cycle.rs:+0:5: +0:12 -+ StorageLive(_7); // scope 4 at $DIR/cycle.rs:+0:5: +0:8 -+ StorageLive(_8); // scope 4 at $DIR/cycle.rs:+0:5: +0:6 -+ _8 = &_6; // scope 4 at $DIR/cycle.rs:+0:5: +0:6 ++ StorageLive(_3); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ StorageLive(_6); // scope 3 at $DIR/cycle.rs:12:5: 12:12 ++ StorageLive(_7); // scope 4 at $DIR/cycle.rs:6:5: 6:8 ++ StorageLive(_8); // scope 4 at $DIR/cycle.rs:6:5: 6:6 ++ _8 = &_6; // scope 4 at $DIR/cycle.rs:6:5: 6:6 + _7 = move (*_8)() -> [return: bb4, unwind: bb2]; // scope 5 at $SRC_DIR/core/src/ops/function.rs:LL:COL } bb1: { -+ StorageDead(_2); // scope 0 at $DIR/cycle.rs:+1:5: +1:9 - StorageDead(_1); // scope 0 at $DIR/cycle.rs:+1:9: +1:10 - _0 = const (); // scope 0 at $DIR/cycle.rs:+0:11: +2:2 - return; // scope 0 at $DIR/cycle.rs:+2:2: +2:2 ++ StorageDead(_2); // scope 0 at $DIR/cycle.rs:17:5: 17:9 + StorageDead(_1); // scope 0 at $DIR/cycle.rs:17:9: 17:10 + _0 = const (); // scope 0 at $DIR/cycle.rs:16:11: 18:2 + return; // scope 0 at $DIR/cycle.rs:18:2: 18:2 + } + + bb2 (cleanup): { -+ drop(_2) -> bb3; // scope 1 at $DIR/cycle.rs:+0:1: +0:2 ++ drop(_2) -> bb3; // scope 1 at $DIR/cycle.rs:7:1: 7:2 + } + + bb3 (cleanup): { -+ resume; // scope 1 at $DIR/cycle.rs:+0:1: +0:2 ++ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2 + } + + bb4: { -+ StorageDead(_8); // scope 4 at $DIR/cycle.rs:+0:7: +0:8 -+ StorageDead(_7); // scope 4 at $DIR/cycle.rs:+0:8: +0:9 -+ StorageDead(_6); // scope 3 at $DIR/cycle.rs:+0:5: +0:12 -+ StorageDead(_5); // scope 1 at $DIR/cycle.rs:+0:7: +0:8 -+ StorageDead(_4); // scope 1 at $DIR/cycle.rs:+0:7: +0:8 -+ StorageDead(_3); // scope 1 at $DIR/cycle.rs:+0:8: +0:9 -+ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:+0:1: +0:2 ++ StorageDead(_8); // scope 4 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_7); // scope 4 at $DIR/cycle.rs:6:8: 6:9 ++ StorageDead(_6); // scope 3 at $DIR/cycle.rs:12:5: 12:12 ++ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9 ++ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2 } } diff --git a/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff b/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff index 49c91e956e72d..7b306dd9482ca 100644 --- a/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff +++ b/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff @@ -2,29 +2,29 @@ + // MIR for `get_query` after Inline fn get_query(_1: &T) -> () { - debug t => _1; // in scope 0 at $DIR/dyn-trait.rs:+0:31: +0:32 - let mut _0: (); // return place in scope 0 at $DIR/dyn-trait.rs:+0:38: +0:38 - let _2: &::C; // in scope 0 at $DIR/dyn-trait.rs:+1:9: +1:10 - let mut _3: &T; // in scope 0 at $DIR/dyn-trait.rs:+1:22: +1:23 - let mut _4: &::C; // in scope 0 at $DIR/dyn-trait.rs:+2:23: +2:24 + debug t => _1; // in scope 0 at $DIR/dyn-trait.rs:32:31: 32:32 + let mut _0: (); // return place in scope 0 at $DIR/dyn-trait.rs:32:38: 32:38 + let _2: &::C; // in scope 0 at $DIR/dyn-trait.rs:33:9: 33:10 + let mut _3: &T; // in scope 0 at $DIR/dyn-trait.rs:33:22: 33:23 + let mut _4: &::C; // in scope 0 at $DIR/dyn-trait.rs:34:23: 34:24 scope 1 { - debug c => _2; // in scope 1 at $DIR/dyn-trait.rs:+1:9: +1:10 + debug c => _2; // in scope 1 at $DIR/dyn-trait.rs:33:9: 33:10 + scope 2 (inlined try_execute_query::<::C>) { // at $DIR/dyn-trait.rs:34:5: 34:25 -+ debug c => _4; // in scope 2 at $DIR/dyn-trait.rs:+0:36: +0:37 -+ let mut _5: &dyn Cache::V>; // in scope 2 at $DIR/dyn-trait.rs:+0:14: +0:15 -+ let mut _6: &::C; // in scope 2 at $DIR/dyn-trait.rs:+0:14: +0:15 ++ debug c => _4; // in scope 2 at $DIR/dyn-trait.rs:26:36: 26:37 ++ let mut _5: &dyn Cache::V>; // in scope 2 at $DIR/dyn-trait.rs:27:14: 27:15 ++ let mut _6: &::C; // in scope 2 at $DIR/dyn-trait.rs:27:14: 27:15 + scope 3 (inlined mk_cycle::<::V>) { // at $DIR/dyn-trait.rs:27:5: 27:16 -+ debug c => _5; // in scope 3 at $DIR/dyn-trait.rs:+0:27: +0:28 -+ let mut _7: &dyn Cache::V>; // in scope 3 at $DIR/dyn-trait.rs:+0:5: +0:22 ++ debug c => _5; // in scope 3 at $DIR/dyn-trait.rs:20:27: 20:28 ++ let mut _7: &dyn Cache::V>; // in scope 3 at $DIR/dyn-trait.rs:21:5: 21:22 + } + } } bb0: { - StorageLive(_2); // scope 0 at $DIR/dyn-trait.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/dyn-trait.rs:+1:22: +1:23 - _3 = &(*_1); // scope 0 at $DIR/dyn-trait.rs:+1:22: +1:23 - _2 = ::cache::(move _3) -> bb1; // scope 0 at $DIR/dyn-trait.rs:+1:13: +1:24 + StorageLive(_2); // scope 0 at $DIR/dyn-trait.rs:33:9: 33:10 + StorageLive(_3); // scope 0 at $DIR/dyn-trait.rs:33:22: 33:23 + _3 = &(*_1); // scope 0 at $DIR/dyn-trait.rs:33:22: 33:23 + _2 = ::cache::(move _3) -> bb1; // scope 0 at $DIR/dyn-trait.rs:33:13: 33:24 // mir::Constant // + span: $DIR/dyn-trait.rs:33:13: 33:21 // + user_ty: UserType(0) @@ -32,18 +32,18 @@ } bb1: { - StorageDead(_3); // scope 0 at $DIR/dyn-trait.rs:+1:23: +1:24 - StorageLive(_4); // scope 1 at $DIR/dyn-trait.rs:+2:23: +2:24 - _4 = &(*_2); // scope 1 at $DIR/dyn-trait.rs:+2:23: +2:24 -- _0 = try_execute_query::<::C>(move _4) -> bb2; // scope 1 at $DIR/dyn-trait.rs:+2:5: +2:25 -+ StorageLive(_5); // scope 2 at $DIR/dyn-trait.rs:+0:14: +0:15 -+ StorageLive(_6); // scope 2 at $DIR/dyn-trait.rs:+0:14: +0:15 -+ _6 = _4; // scope 2 at $DIR/dyn-trait.rs:+0:14: +0:15 -+ _5 = move _6 as &dyn Cache::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn-trait.rs:+0:14: +0:15 -+ StorageDead(_6); // scope 2 at $DIR/dyn-trait.rs:+0:14: +0:15 -+ StorageLive(_7); // scope 3 at $DIR/dyn-trait.rs:+0:5: +0:22 -+ _7 = _5; // scope 3 at $DIR/dyn-trait.rs:+0:5: +0:22 -+ _0 = ::V> as Cache>::store_nocache(move _7) -> bb2; // scope 3 at $DIR/dyn-trait.rs:+0:5: +0:22 + StorageDead(_3); // scope 0 at $DIR/dyn-trait.rs:33:23: 33:24 + StorageLive(_4); // scope 1 at $DIR/dyn-trait.rs:34:23: 34:24 + _4 = &(*_2); // scope 1 at $DIR/dyn-trait.rs:34:23: 34:24 +- _0 = try_execute_query::<::C>(move _4) -> bb2; // scope 1 at $DIR/dyn-trait.rs:34:5: 34:25 ++ StorageLive(_5); // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15 ++ StorageLive(_6); // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15 ++ _6 = _4; // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15 ++ _5 = move _6 as &dyn Cache::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15 ++ StorageDead(_6); // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15 ++ StorageLive(_7); // scope 3 at $DIR/dyn-trait.rs:21:5: 21:22 ++ _7 = _5; // scope 3 at $DIR/dyn-trait.rs:21:5: 21:22 ++ _0 = ::V> as Cache>::store_nocache(move _7) -> bb2; // scope 3 at $DIR/dyn-trait.rs:21:5: 21:22 // mir::Constant - // + span: $DIR/dyn-trait.rs:34:5: 34:22 - // + literal: Const { ty: for<'r> fn(&'r ::C) {try_execute_query::<::C>}, val: Value() } @@ -52,15 +52,15 @@ } bb2: { -+ StorageDead(_7); // scope 3 at $DIR/dyn-trait.rs:+0:21: +0:22 -+ StorageDead(_5); // scope 2 at $DIR/dyn-trait.rs:+0:15: +0:16 - StorageDead(_4); // scope 1 at $DIR/dyn-trait.rs:+2:24: +2:25 - StorageDead(_2); // scope 0 at $DIR/dyn-trait.rs:+3:1: +3:2 - return; // scope 0 at $DIR/dyn-trait.rs:+3:2: +3:2 ++ StorageDead(_7); // scope 3 at $DIR/dyn-trait.rs:21:21: 21:22 ++ StorageDead(_5); // scope 2 at $DIR/dyn-trait.rs:27:15: 27:16 + StorageDead(_4); // scope 1 at $DIR/dyn-trait.rs:34:24: 34:25 + StorageDead(_2); // scope 0 at $DIR/dyn-trait.rs:35:1: 35:2 + return; // scope 0 at $DIR/dyn-trait.rs:35:2: 35:2 + } + + bb3 (cleanup): { -+ resume; // scope 0 at $DIR/dyn-trait.rs:+0:1: +3:2 ++ resume; // scope 0 at $DIR/dyn-trait.rs:32:1: 35:2 } } diff --git a/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff b/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff index 994930ef4cf6f..2a909702a6dc0 100644 --- a/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff +++ b/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff @@ -2,22 +2,22 @@ + // MIR for `mk_cycle` after Inline fn mk_cycle(_1: &dyn Cache) -> () { - debug c => _1; // in scope 0 at $DIR/dyn-trait.rs:+0:27: +0:28 - let mut _0: (); // return place in scope 0 at $DIR/dyn-trait.rs:+0:49: +0:49 - let mut _2: &dyn Cache; // in scope 0 at $DIR/dyn-trait.rs:+1:5: +1:22 + debug c => _1; // in scope 0 at $DIR/dyn-trait.rs:20:27: 20:28 + let mut _0: (); // return place in scope 0 at $DIR/dyn-trait.rs:20:49: 20:49 + let mut _2: &dyn Cache; // in scope 0 at $DIR/dyn-trait.rs:21:5: 21:22 bb0: { - StorageLive(_2); // scope 0 at $DIR/dyn-trait.rs:+1:5: +1:22 - _2 = &(*_1); // scope 0 at $DIR/dyn-trait.rs:+1:5: +1:22 - _0 = as Cache>::store_nocache(move _2) -> bb1; // scope 0 at $DIR/dyn-trait.rs:+1:5: +1:22 + StorageLive(_2); // scope 0 at $DIR/dyn-trait.rs:21:5: 21:22 + _2 = &(*_1); // scope 0 at $DIR/dyn-trait.rs:21:5: 21:22 + _0 = as Cache>::store_nocache(move _2) -> bb1; // scope 0 at $DIR/dyn-trait.rs:21:5: 21:22 // mir::Constant // + span: $DIR/dyn-trait.rs:21:7: 21:20 // + literal: Const { ty: for<'r> fn(&'r dyn Cache) { as Cache>::store_nocache}, val: Value() } } bb1: { - StorageDead(_2); // scope 0 at $DIR/dyn-trait.rs:+1:21: +1:22 - return; // scope 0 at $DIR/dyn-trait.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/dyn-trait.rs:21:21: 21:22 + return; // scope 0 at $DIR/dyn-trait.rs:22:2: 22:2 } } diff --git a/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff b/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff index 805354d2804a6..01ebc999cb3ec 100644 --- a/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff +++ b/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff @@ -2,25 +2,25 @@ + // MIR for `try_execute_query` after Inline fn try_execute_query(_1: &C) -> () { - debug c => _1; // in scope 0 at $DIR/dyn-trait.rs:+0:36: +0:37 - let mut _0: (); // return place in scope 0 at $DIR/dyn-trait.rs:+0:43: +0:43 - let mut _2: &dyn Cache::V>; // in scope 0 at $DIR/dyn-trait.rs:+1:14: +1:15 - let mut _3: &C; // in scope 0 at $DIR/dyn-trait.rs:+1:14: +1:15 + debug c => _1; // in scope 0 at $DIR/dyn-trait.rs:26:36: 26:37 + let mut _0: (); // return place in scope 0 at $DIR/dyn-trait.rs:26:43: 26:43 + let mut _2: &dyn Cache::V>; // in scope 0 at $DIR/dyn-trait.rs:27:14: 27:15 + let mut _3: &C; // in scope 0 at $DIR/dyn-trait.rs:27:14: 27:15 + scope 1 (inlined mk_cycle::<::V>) { // at $DIR/dyn-trait.rs:27:5: 27:16 -+ debug c => _2; // in scope 1 at $DIR/dyn-trait.rs:+0:27: +0:28 -+ let mut _4: &dyn Cache::V>; // in scope 1 at $DIR/dyn-trait.rs:+0:5: +0:22 ++ debug c => _2; // in scope 1 at $DIR/dyn-trait.rs:20:27: 20:28 ++ let mut _4: &dyn Cache::V>; // in scope 1 at $DIR/dyn-trait.rs:21:5: 21:22 + } bb0: { - StorageLive(_2); // scope 0 at $DIR/dyn-trait.rs:+1:14: +1:15 - StorageLive(_3); // scope 0 at $DIR/dyn-trait.rs:+1:14: +1:15 - _3 = &(*_1); // scope 0 at $DIR/dyn-trait.rs:+1:14: +1:15 - _2 = move _3 as &dyn Cache::V> (Pointer(Unsize)); // scope 0 at $DIR/dyn-trait.rs:+1:14: +1:15 - StorageDead(_3); // scope 0 at $DIR/dyn-trait.rs:+1:14: +1:15 -- _0 = mk_cycle::<::V>(move _2) -> bb1; // scope 0 at $DIR/dyn-trait.rs:+1:5: +1:16 -+ StorageLive(_4); // scope 1 at $DIR/dyn-trait.rs:+0:5: +0:22 -+ _4 = _2; // scope 1 at $DIR/dyn-trait.rs:+0:5: +0:22 -+ _0 = ::V> as Cache>::store_nocache(move _4) -> bb1; // scope 1 at $DIR/dyn-trait.rs:+0:5: +0:22 + StorageLive(_2); // scope 0 at $DIR/dyn-trait.rs:27:14: 27:15 + StorageLive(_3); // scope 0 at $DIR/dyn-trait.rs:27:14: 27:15 + _3 = &(*_1); // scope 0 at $DIR/dyn-trait.rs:27:14: 27:15 + _2 = move _3 as &dyn Cache::V> (Pointer(Unsize)); // scope 0 at $DIR/dyn-trait.rs:27:14: 27:15 + StorageDead(_3); // scope 0 at $DIR/dyn-trait.rs:27:14: 27:15 +- _0 = mk_cycle::<::V>(move _2) -> bb1; // scope 0 at $DIR/dyn-trait.rs:27:5: 27:16 ++ StorageLive(_4); // scope 1 at $DIR/dyn-trait.rs:21:5: 21:22 ++ _4 = _2; // scope 1 at $DIR/dyn-trait.rs:21:5: 21:22 ++ _0 = ::V> as Cache>::store_nocache(move _4) -> bb1; // scope 1 at $DIR/dyn-trait.rs:21:5: 21:22 // mir::Constant - // + span: $DIR/dyn-trait.rs:27:5: 27:13 - // + literal: Const { ty: for<'r> fn(&'r (dyn Cache::V> + 'r)) {mk_cycle::<::V>}, val: Value() } @@ -29,13 +29,13 @@ } bb1: { -+ StorageDead(_4); // scope 1 at $DIR/dyn-trait.rs:+0:21: +0:22 - StorageDead(_2); // scope 0 at $DIR/dyn-trait.rs:+1:15: +1:16 - return; // scope 0 at $DIR/dyn-trait.rs:+2:2: +2:2 ++ StorageDead(_4); // scope 1 at $DIR/dyn-trait.rs:21:21: 21:22 + StorageDead(_2); // scope 0 at $DIR/dyn-trait.rs:27:15: 27:16 + return; // scope 0 at $DIR/dyn-trait.rs:28:2: 28:2 + } + + bb2 (cleanup): { -+ resume; // scope 0 at $DIR/dyn-trait.rs:+0:1: +2:2 ++ resume; // scope 0 at $DIR/dyn-trait.rs:26:1: 28:2 } } diff --git a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir index 77b5df943a353..ff338ae58cd87 100644 --- a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir @@ -1,48 +1,48 @@ // MIR for `bar` after Inline fn bar() -> bool { - let mut _0: bool; // return place in scope 0 at $DIR/inline-any-operand.rs:+0:13: +0:17 - let _1: fn(i32, i32) -> bool {foo}; // in scope 0 at $DIR/inline-any-operand.rs:+1:9: +1:10 - let mut _2: fn(i32, i32) -> bool {foo}; // in scope 0 at $DIR/inline-any-operand.rs:+2:5: +2:6 - let mut _3: i32; // in scope 0 at $DIR/inline-any-operand.rs:+2:5: +2:13 - let mut _4: i32; // in scope 0 at $DIR/inline-any-operand.rs:+2:5: +2:13 + let mut _0: bool; // return place in scope 0 at $DIR/inline-any-operand.rs:10:13: 10:17 + let _1: fn(i32, i32) -> bool {foo}; // in scope 0 at $DIR/inline-any-operand.rs:11:9: 11:10 + let mut _2: fn(i32, i32) -> bool {foo}; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:6 + let mut _3: i32; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13 + let mut _4: i32; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13 scope 1 { - debug f => _1; // in scope 1 at $DIR/inline-any-operand.rs:+1:9: +1:10 + debug f => _1; // in scope 1 at $DIR/inline-any-operand.rs:11:9: 11:10 scope 2 (inlined foo) { // at $DIR/inline-any-operand.rs:12:5: 12:13 - debug x => _3; // in scope 2 at $DIR/inline-any-operand.rs:+6:8: +6:9 - debug y => _4; // in scope 2 at $DIR/inline-any-operand.rs:+6:16: +6:17 - let mut _5: i32; // in scope 2 at $DIR/inline-any-operand.rs:+7:5: +7:6 - let mut _6: i32; // in scope 2 at $DIR/inline-any-operand.rs:+7:10: +7:11 + debug x => _3; // in scope 2 at $DIR/inline-any-operand.rs:16:8: 16:9 + debug y => _4; // in scope 2 at $DIR/inline-any-operand.rs:16:16: 16:17 + let mut _5: i32; // in scope 2 at $DIR/inline-any-operand.rs:17:5: 17:6 + let mut _6: i32; // in scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-any-operand.rs:+1:9: +1:10 - _1 = foo; // scope 0 at $DIR/inline-any-operand.rs:+1:13: +1:16 + StorageLive(_1); // scope 0 at $DIR/inline-any-operand.rs:11:9: 11:10 + _1 = foo; // scope 0 at $DIR/inline-any-operand.rs:11:13: 11:16 // mir::Constant // + span: $DIR/inline-any-operand.rs:11:13: 11:16 // + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value() } - StorageLive(_2); // scope 1 at $DIR/inline-any-operand.rs:+2:5: +2:6 - _2 = _1; // scope 1 at $DIR/inline-any-operand.rs:+2:5: +2:6 - StorageLive(_3); // scope 1 at $DIR/inline-any-operand.rs:+2:5: +2:13 - _3 = const 1_i32; // scope 1 at $DIR/inline-any-operand.rs:+2:5: +2:13 - StorageLive(_4); // scope 1 at $DIR/inline-any-operand.rs:+2:5: +2:13 - _4 = const -1_i32; // scope 1 at $DIR/inline-any-operand.rs:+2:5: +2:13 - StorageLive(_5); // scope 2 at $DIR/inline-any-operand.rs:+7:5: +7:6 - _5 = _3; // scope 2 at $DIR/inline-any-operand.rs:+7:5: +7:6 - StorageLive(_6); // scope 2 at $DIR/inline-any-operand.rs:+7:10: +7:11 - _6 = _4; // scope 2 at $DIR/inline-any-operand.rs:+7:10: +7:11 - _0 = Eq(move _5, move _6); // scope 2 at $DIR/inline-any-operand.rs:+7:5: +7:11 - StorageDead(_6); // scope 2 at $DIR/inline-any-operand.rs:+7:10: +7:11 - StorageDead(_5); // scope 2 at $DIR/inline-any-operand.rs:+7:10: +7:11 - StorageDead(_4); // scope 1 at $DIR/inline-any-operand.rs:+2:5: +2:13 - StorageDead(_3); // scope 1 at $DIR/inline-any-operand.rs:+2:5: +2:13 - StorageDead(_2); // scope 1 at $DIR/inline-any-operand.rs:+2:12: +2:13 - StorageDead(_1); // scope 0 at $DIR/inline-any-operand.rs:+3:1: +3:2 - return; // scope 0 at $DIR/inline-any-operand.rs:+3:2: +3:2 + StorageLive(_2); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6 + _2 = _1; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6 + StorageLive(_3); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + _3 = const 1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageLive(_4); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + _4 = const -1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageLive(_5); // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:6 + _5 = _3; // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:6 + StorageLive(_6); // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 + _6 = _4; // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 + _0 = Eq(move _5, move _6); // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:11 + StorageDead(_6); // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 + StorageDead(_5); // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 + StorageDead(_4); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageDead(_3); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageDead(_2); // scope 1 at $DIR/inline-any-operand.rs:12:12: 12:13 + StorageDead(_1); // scope 0 at $DIR/inline-any-operand.rs:13:1: 13:2 + return; // scope 0 at $DIR/inline-any-operand.rs:13:2: 13:2 } bb1 (cleanup): { - resume; // scope 0 at $DIR/inline-any-operand.rs:+0:1: +3:2 + resume; // scope 0 at $DIR/inline-any-operand.rs:10:1: 13:2 } } diff --git a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir index d746e1a093a92..66fc5fa80ea26 100644 --- a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir @@ -1,53 +1,53 @@ // MIR for `foo` after Inline fn foo(_1: T, _2: i32) -> i32 { - debug _t => _1; // in scope 0 at $DIR/inline-closure.rs:+0:17: +0:19 - debug q => _2; // in scope 0 at $DIR/inline-closure.rs:+0:24: +0:25 - let mut _0: i32; // return place in scope 0 at $DIR/inline-closure.rs:+0:35: +0:38 - let _3: [closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure.rs:+1:9: +1:10 - let mut _4: &[closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure.rs:+2:5: +2:6 - let mut _5: (i32, i32); // in scope 0 at $DIR/inline-closure.rs:+2:5: +2:12 - let mut _6: i32; // in scope 0 at $DIR/inline-closure.rs:+2:7: +2:8 - let mut _7: i32; // in scope 0 at $DIR/inline-closure.rs:+2:10: +2:11 - let mut _8: i32; // in scope 0 at $DIR/inline-closure.rs:+2:5: +2:12 - let mut _9: i32; // in scope 0 at $DIR/inline-closure.rs:+2:5: +2:12 + debug _t => _1; // in scope 0 at $DIR/inline-closure.rs:10:17: 10:19 + debug q => _2; // in scope 0 at $DIR/inline-closure.rs:10:24: 10:25 + let mut _0: i32; // return place in scope 0 at $DIR/inline-closure.rs:10:35: 10:38 + let _3: [closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure.rs:11:9: 11:10 + let mut _4: &[closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure.rs:12:5: 12:6 + let mut _5: (i32, i32); // in scope 0 at $DIR/inline-closure.rs:12:5: 12:12 + let mut _6: i32; // in scope 0 at $DIR/inline-closure.rs:12:7: 12:8 + let mut _7: i32; // in scope 0 at $DIR/inline-closure.rs:12:10: 12:11 + let mut _8: i32; // in scope 0 at $DIR/inline-closure.rs:12:5: 12:12 + let mut _9: i32; // in scope 0 at $DIR/inline-closure.rs:12:5: 12:12 scope 1 { - debug x => _3; // in scope 1 at $DIR/inline-closure.rs:+1:9: +1:10 + debug x => _3; // in scope 1 at $DIR/inline-closure.rs:11:9: 11:10 scope 2 (inlined foo::::{closure#0}) { // at $DIR/inline-closure.rs:12:5: 12:12 - debug _t => _8; // in scope 2 at $DIR/inline-closure.rs:+1:14: +1:16 - debug _q => _9; // in scope 2 at $DIR/inline-closure.rs:+1:18: +1:20 + debug _t => _8; // in scope 2 at $DIR/inline-closure.rs:11:14: 11:16 + debug _q => _9; // in scope 2 at $DIR/inline-closure.rs:11:18: 11:20 } } bb0: { - StorageLive(_3); // scope 0 at $DIR/inline-closure.rs:+1:9: +1:10 - Deinit(_3); // scope 0 at $DIR/inline-closure.rs:+1:13: +1:24 - StorageLive(_4); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:6 - _4 = &_3; // scope 1 at $DIR/inline-closure.rs:+2:5: +2:6 - StorageLive(_5); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12 - StorageLive(_6); // scope 1 at $DIR/inline-closure.rs:+2:7: +2:8 - _6 = _2; // scope 1 at $DIR/inline-closure.rs:+2:7: +2:8 - StorageLive(_7); // scope 1 at $DIR/inline-closure.rs:+2:10: +2:11 - _7 = _2; // scope 1 at $DIR/inline-closure.rs:+2:10: +2:11 - Deinit(_5); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12 - (_5.0: i32) = move _6; // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12 - (_5.1: i32) = move _7; // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12 - StorageLive(_8); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12 - _8 = move (_5.0: i32); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12 - StorageLive(_9); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12 - _9 = move (_5.1: i32); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12 - _0 = _8; // scope 2 at $DIR/inline-closure.rs:+1:22: +1:24 - StorageDead(_9); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12 - StorageDead(_8); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12 - StorageDead(_7); // scope 1 at $DIR/inline-closure.rs:+2:11: +2:12 - StorageDead(_6); // scope 1 at $DIR/inline-closure.rs:+2:11: +2:12 - StorageDead(_5); // scope 1 at $DIR/inline-closure.rs:+2:11: +2:12 - StorageDead(_4); // scope 1 at $DIR/inline-closure.rs:+2:11: +2:12 - StorageDead(_3); // scope 0 at $DIR/inline-closure.rs:+3:1: +3:2 - return; // scope 0 at $DIR/inline-closure.rs:+3:2: +3:2 + StorageLive(_3); // scope 0 at $DIR/inline-closure.rs:11:9: 11:10 + Deinit(_3); // scope 0 at $DIR/inline-closure.rs:11:13: 11:24 + StorageLive(_4); // scope 1 at $DIR/inline-closure.rs:12:5: 12:6 + _4 = &_3; // scope 1 at $DIR/inline-closure.rs:12:5: 12:6 + StorageLive(_5); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + StorageLive(_6); // scope 1 at $DIR/inline-closure.rs:12:7: 12:8 + _6 = _2; // scope 1 at $DIR/inline-closure.rs:12:7: 12:8 + StorageLive(_7); // scope 1 at $DIR/inline-closure.rs:12:10: 12:11 + _7 = _2; // scope 1 at $DIR/inline-closure.rs:12:10: 12:11 + Deinit(_5); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + (_5.0: i32) = move _6; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + (_5.1: i32) = move _7; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + StorageLive(_8); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + _8 = move (_5.0: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + StorageLive(_9); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + _9 = move (_5.1: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + _0 = _8; // scope 2 at $DIR/inline-closure.rs:11:22: 11:24 + StorageDead(_9); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + StorageDead(_8); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + StorageDead(_7); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12 + StorageDead(_6); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12 + StorageDead(_5); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12 + StorageDead(_4); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12 + StorageDead(_3); // scope 0 at $DIR/inline-closure.rs:13:1: 13:2 + return; // scope 0 at $DIR/inline-closure.rs:13:2: 13:2 } bb1 (cleanup): { - resume; // scope 0 at $DIR/inline-closure.rs:+0:1: +3:2 + resume; // scope 0 at $DIR/inline-closure.rs:10:1: 13:2 } } diff --git a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir index 84b3fb92cd535..7bb17dab061ad 100644 --- a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir @@ -1,60 +1,60 @@ // MIR for `foo` after Inline fn foo(_1: T, _2: &i32) -> i32 { - debug _t => _1; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+0:17: +0:19 - debug q => _2; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+0:24: +0:25 - let mut _0: i32; // return place in scope 0 at $DIR/inline-closure-borrows-arg.rs:+0:36: +0:39 - let _3: [closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+1:9: +1:10 - let mut _4: &[closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:6 - let mut _5: (&i32, &i32); // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12 - let mut _6: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+5:7: +5:8 - let mut _7: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+5:10: +5:11 - let mut _8: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12 - let mut _9: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12 + debug _t => _1; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:11:17: 11:19 + debug q => _2; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:11:24: 11:25 + let mut _0: i32; // return place in scope 0 at $DIR/inline-closure-borrows-arg.rs:11:36: 11:39 + let _3: [closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:12:9: 12:10 + let mut _4: &[closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:6 + let mut _5: (&i32, &i32); // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + let mut _6: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:7: 16:8 + let mut _7: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11 + let mut _8: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + let mut _9: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 scope 1 { - debug x => _3; // in scope 1 at $DIR/inline-closure-borrows-arg.rs:+1:9: +1:10 + debug x => _3; // in scope 1 at $DIR/inline-closure-borrows-arg.rs:12:9: 12:10 scope 2 (inlined foo::::{closure#0}) { // at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 - debug r => _8; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:+1:14: +1:15 - debug _s => _9; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:+1:23: +1:25 - let _10: &i32; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:+2:13: +2:21 + debug r => _8; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:12:14: 12:15 + debug _s => _9; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:12:23: 12:25 + let _10: &i32; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:13:13: 13:21 scope 3 { - debug variable => _10; // in scope 3 at $DIR/inline-closure-borrows-arg.rs:+2:13: +2:21 + debug variable => _10; // in scope 3 at $DIR/inline-closure-borrows-arg.rs:13:13: 13:21 } } } bb0: { - StorageLive(_3); // scope 0 at $DIR/inline-closure-borrows-arg.rs:+1:9: +1:10 - Deinit(_3); // scope 0 at $DIR/inline-closure-borrows-arg.rs:+1:13: +4:6 - StorageLive(_4); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:6 - _4 = &_3; // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:6 - StorageLive(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12 - StorageLive(_6); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:7: +5:8 - _6 = &(*_2); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:7: +5:8 - StorageLive(_7); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:10: +5:11 - _7 = &(*_2); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:10: +5:11 - Deinit(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12 - (_5.0: &i32) = move _6; // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12 - (_5.1: &i32) = move _7; // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12 - StorageLive(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12 - _8 = move (_5.0: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12 - StorageLive(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12 - _9 = move (_5.1: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12 - StorageLive(_10); // scope 2 at $DIR/inline-closure-borrows-arg.rs:+2:13: +2:21 - _10 = _8; // scope 2 at $DIR/inline-closure-borrows-arg.rs:+2:24: +2:27 - _0 = (*_10); // scope 3 at $DIR/inline-closure-borrows-arg.rs:+3:9: +3:18 - StorageDead(_10); // scope 2 at $DIR/inline-closure-borrows-arg.rs:+4:5: +4:6 - StorageDead(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12 - StorageDead(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12 - StorageDead(_7); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:11: +5:12 - StorageDead(_6); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:11: +5:12 - StorageDead(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:11: +5:12 - StorageDead(_4); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:11: +5:12 - StorageDead(_3); // scope 0 at $DIR/inline-closure-borrows-arg.rs:+6:1: +6:2 - return; // scope 0 at $DIR/inline-closure-borrows-arg.rs:+6:2: +6:2 + StorageLive(_3); // scope 0 at $DIR/inline-closure-borrows-arg.rs:12:9: 12:10 + Deinit(_3); // scope 0 at $DIR/inline-closure-borrows-arg.rs:12:13: 15:6 + StorageLive(_4); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:6 + _4 = &_3; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:6 + StorageLive(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageLive(_6); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:7: 16:8 + _6 = &(*_2); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:7: 16:8 + StorageLive(_7); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11 + _7 = &(*_2); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11 + Deinit(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + (_5.0: &i32) = move _6; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + (_5.1: &i32) = move _7; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageLive(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + _8 = move (_5.0: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageLive(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + _9 = move (_5.1: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageLive(_10); // scope 2 at $DIR/inline-closure-borrows-arg.rs:13:13: 13:21 + _10 = _8; // scope 2 at $DIR/inline-closure-borrows-arg.rs:13:24: 13:27 + _0 = (*_10); // scope 3 at $DIR/inline-closure-borrows-arg.rs:14:9: 14:18 + StorageDead(_10); // scope 2 at $DIR/inline-closure-borrows-arg.rs:15:5: 15:6 + StorageDead(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageDead(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageDead(_7); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 + StorageDead(_6); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 + StorageDead(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 + StorageDead(_4); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 + StorageDead(_3); // scope 0 at $DIR/inline-closure-borrows-arg.rs:17:1: 17:2 + return; // scope 0 at $DIR/inline-closure-borrows-arg.rs:17:2: 17:2 } bb1 (cleanup): { - resume; // scope 0 at $DIR/inline-closure-borrows-arg.rs:+0:1: +6:2 + resume; // scope 0 at $DIR/inline-closure-borrows-arg.rs:11:1: 17:2 } } diff --git a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir index 75693dc384b13..0e6ae6578e2a3 100644 --- a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir @@ -1,73 +1,73 @@ // MIR for `foo` after Inline fn foo(_1: T, _2: i32) -> (i32, T) { - debug t => _1; // in scope 0 at $DIR/inline-closure-captures.rs:+0:17: +0:18 - debug q => _2; // in scope 0 at $DIR/inline-closure-captures.rs:+0:23: +0:24 - let mut _0: (i32, T); // return place in scope 0 at $DIR/inline-closure-captures.rs:+0:34: +0:42 - let _3: [closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-captures.rs:+1:9: +1:10 - let mut _4: &i32; // in scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24 - let mut _5: &T; // in scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24 - let mut _6: &[closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-captures.rs:+2:5: +2:6 - let mut _7: (i32,); // in scope 0 at $DIR/inline-closure-captures.rs:+2:5: +2:9 - let mut _8: i32; // in scope 0 at $DIR/inline-closure-captures.rs:+2:7: +2:8 - let mut _9: i32; // in scope 0 at $DIR/inline-closure-captures.rs:+2:5: +2:9 + debug t => _1; // in scope 0 at $DIR/inline-closure-captures.rs:10:17: 10:18 + debug q => _2; // in scope 0 at $DIR/inline-closure-captures.rs:10:23: 10:24 + let mut _0: (i32, T); // return place in scope 0 at $DIR/inline-closure-captures.rs:10:34: 10:42 + let _3: [closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-captures.rs:11:9: 11:10 + let mut _4: &i32; // in scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 + let mut _5: &T; // in scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 + let mut _6: &[closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:6 + let mut _7: (i32,); // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9 + let mut _8: i32; // in scope 0 at $DIR/inline-closure-captures.rs:12:7: 12:8 + let mut _9: i32; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9 scope 1 { - debug x => _3; // in scope 1 at $DIR/inline-closure-captures.rs:+1:9: +1:10 + debug x => _3; // in scope 1 at $DIR/inline-closure-captures.rs:11:9: 11:10 scope 2 (inlined foo::::{closure#0}) { // at $DIR/inline-closure-captures.rs:12:5: 12:9 - debug _q => _9; // in scope 2 at $DIR/inline-closure-captures.rs:+1:14: +1:16 - debug q => (*((*_6).0: &i32)); // in scope 2 at $DIR/inline-closure-captures.rs:+0:23: +0:24 - debug t => (*((*_6).1: &T)); // in scope 2 at $DIR/inline-closure-captures.rs:+0:17: +0:18 - let mut _10: i32; // in scope 2 at $DIR/inline-closure-captures.rs:+1:19: +1:20 - let mut _11: T; // in scope 2 at $DIR/inline-closure-captures.rs:+1:22: +1:23 - let mut _12: &i32; // in scope 2 at $DIR/inline-closure-captures.rs:+1:13: +1:17 - let mut _13: &T; // in scope 2 at $DIR/inline-closure-captures.rs:+1:13: +1:17 + debug _q => _9; // in scope 2 at $DIR/inline-closure-captures.rs:11:14: 11:16 + debug q => (*((*_6).0: &i32)); // in scope 2 at $DIR/inline-closure-captures.rs:10:23: 10:24 + debug t => (*((*_6).1: &T)); // in scope 2 at $DIR/inline-closure-captures.rs:10:17: 10:18 + let mut _10: i32; // in scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 + let mut _11: T; // in scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 + let mut _12: &i32; // in scope 2 at $DIR/inline-closure-captures.rs:11:13: 11:17 + let mut _13: &T; // in scope 2 at $DIR/inline-closure-captures.rs:11:13: 11:17 } } bb0: { - StorageLive(_3); // scope 0 at $DIR/inline-closure-captures.rs:+1:9: +1:10 - StorageLive(_4); // scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24 - _4 = &_2; // scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24 - StorageLive(_5); // scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24 - _5 = &_1; // scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24 - Deinit(_3); // scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24 - (_3.0: &i32) = move _4; // scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24 - (_3.1: &T) = move _5; // scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24 - StorageDead(_5); // scope 0 at $DIR/inline-closure-captures.rs:+1:16: +1:17 - StorageDead(_4); // scope 0 at $DIR/inline-closure-captures.rs:+1:16: +1:17 - StorageLive(_6); // scope 1 at $DIR/inline-closure-captures.rs:+2:5: +2:6 - _6 = &_3; // scope 1 at $DIR/inline-closure-captures.rs:+2:5: +2:6 - StorageLive(_7); // scope 1 at $DIR/inline-closure-captures.rs:+2:5: +2:9 - StorageLive(_8); // scope 1 at $DIR/inline-closure-captures.rs:+2:7: +2:8 - _8 = _2; // scope 1 at $DIR/inline-closure-captures.rs:+2:7: +2:8 - Deinit(_7); // scope 1 at $DIR/inline-closure-captures.rs:+2:5: +2:9 - (_7.0: i32) = move _8; // scope 1 at $DIR/inline-closure-captures.rs:+2:5: +2:9 - StorageLive(_9); // scope 1 at $DIR/inline-closure-captures.rs:+2:5: +2:9 - _9 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:+2:5: +2:9 - StorageLive(_10); // scope 2 at $DIR/inline-closure-captures.rs:+1:19: +1:20 - StorageLive(_12); // scope 2 at $DIR/inline-closure-captures.rs:+1:19: +1:20 - _12 = deref_copy ((*_6).0: &i32); // scope 2 at $DIR/inline-closure-captures.rs:+1:19: +1:20 - _10 = (*_12); // scope 2 at $DIR/inline-closure-captures.rs:+1:19: +1:20 - StorageDead(_12); // scope 2 at $DIR/inline-closure-captures.rs:+1:22: +1:23 - StorageLive(_11); // scope 2 at $DIR/inline-closure-captures.rs:+1:22: +1:23 - StorageLive(_13); // scope 2 at $DIR/inline-closure-captures.rs:+1:22: +1:23 - _13 = deref_copy ((*_6).1: &T); // scope 2 at $DIR/inline-closure-captures.rs:+1:22: +1:23 - _11 = (*_13); // scope 2 at $DIR/inline-closure-captures.rs:+1:22: +1:23 - StorageDead(_13); // scope 2 at $DIR/inline-closure-captures.rs:+1:18: +1:24 - Deinit(_0); // scope 2 at $DIR/inline-closure-captures.rs:+1:18: +1:24 - (_0.0: i32) = move _10; // scope 2 at $DIR/inline-closure-captures.rs:+1:18: +1:24 - (_0.1: T) = move _11; // scope 2 at $DIR/inline-closure-captures.rs:+1:18: +1:24 - StorageDead(_11); // scope 2 at $DIR/inline-closure-captures.rs:+1:23: +1:24 - StorageDead(_10); // scope 2 at $DIR/inline-closure-captures.rs:+1:23: +1:24 - StorageDead(_9); // scope 1 at $DIR/inline-closure-captures.rs:+2:5: +2:9 - StorageDead(_8); // scope 1 at $DIR/inline-closure-captures.rs:+2:8: +2:9 - StorageDead(_7); // scope 1 at $DIR/inline-closure-captures.rs:+2:8: +2:9 - StorageDead(_6); // scope 1 at $DIR/inline-closure-captures.rs:+2:8: +2:9 - StorageDead(_3); // scope 0 at $DIR/inline-closure-captures.rs:+3:1: +3:2 - return; // scope 0 at $DIR/inline-closure-captures.rs:+3:2: +3:2 + StorageLive(_3); // scope 0 at $DIR/inline-closure-captures.rs:11:9: 11:10 + StorageLive(_4); // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 + _4 = &_2; // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 + StorageLive(_5); // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 + _5 = &_1; // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 + Deinit(_3); // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 + (_3.0: &i32) = move _4; // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 + (_3.1: &T) = move _5; // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 + StorageDead(_5); // scope 0 at $DIR/inline-closure-captures.rs:11:16: 11:17 + StorageDead(_4); // scope 0 at $DIR/inline-closure-captures.rs:11:16: 11:17 + StorageLive(_6); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:6 + _6 = &_3; // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:6 + StorageLive(_7); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 + StorageLive(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8 + _8 = _2; // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8 + Deinit(_7); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 + (_7.0: i32) = move _8; // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 + StorageLive(_9); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 + _9 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 + StorageLive(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 + StorageLive(_12); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 + _12 = deref_copy ((*_6).0: &i32); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 + _10 = (*_12); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 + StorageDead(_12); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 + StorageLive(_11); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 + StorageLive(_13); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 + _13 = deref_copy ((*_6).1: &T); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 + _11 = (*_13); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 + StorageDead(_13); // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 + Deinit(_0); // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 + (_0.0: i32) = move _10; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 + (_0.1: T) = move _11; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 + StorageDead(_11); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24 + StorageDead(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24 + StorageDead(_9); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 + StorageDead(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 + StorageDead(_7); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 + StorageDead(_6); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 + StorageDead(_3); // scope 0 at $DIR/inline-closure-captures.rs:13:1: 13:2 + return; // scope 0 at $DIR/inline-closure-captures.rs:13:2: 13:2 } bb1 (cleanup): { - resume; // scope 0 at $DIR/inline-closure-captures.rs:+0:1: +3:2 + resume; // scope 0 at $DIR/inline-closure-captures.rs:10:1: 13:2 } } diff --git a/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff index 556d587a47276..34762b97c3b2f 100644 --- a/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff +++ b/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff @@ -2,27 +2,27 @@ + // MIR for `inlined_no_sanitize` after Inline fn inlined_no_sanitize() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:+0:37: +0:37 - let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:18 + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:23:37: 23:37 + let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:24:5: 24:18 + scope 1 (inlined no_sanitize) { // at $DIR/inline-compatibility.rs:24:5: 24:18 + } bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:18 -- _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:18 + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:24:5: 24:18 +- _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:24:5: 24:18 - // mir::Constant - // + span: $DIR/inline-compatibility.rs:24:5: 24:16 - // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value() } - } - - bb1: { - StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:18: +1:19 - _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:+0:37: +2:2 - return; // scope 0 at $DIR/inline-compatibility.rs:+2:2: +2:2 + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:24:18: 24:19 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:23:37: 25:2 + return; // scope 0 at $DIR/inline-compatibility.rs:25:2: 25:2 + } + + bb1 (cleanup): { -+ resume; // scope 0 at $DIR/inline-compatibility.rs:+0:1: +2:2 ++ resume; // scope 0 at $DIR/inline-compatibility.rs:23:1: 25:2 } } diff --git a/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff index b1ee4307358c4..fd1e1983d1e0d 100644 --- a/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff +++ b/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff @@ -2,27 +2,27 @@ + // MIR for `inlined_target_feature` after Inline fn inlined_target_feature() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:+0:40: +0:40 - let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:21 + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:12:40: 12:40 + let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:13:5: 13:21 + scope 1 (inlined target_feature) { // at $DIR/inline-compatibility.rs:13:5: 13:21 + } bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:21 -- _1 = target_feature() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:21 + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:13:5: 13:21 +- _1 = target_feature() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:13:5: 13:21 - // mir::Constant - // + span: $DIR/inline-compatibility.rs:13:5: 13:19 - // + literal: Const { ty: unsafe fn() {target_feature}, val: Value() } - } - - bb1: { - StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:21: +1:22 - _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:+0:40: +2:2 - return; // scope 0 at $DIR/inline-compatibility.rs:+2:2: +2:2 + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:13:21: 13:22 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:12:40: 14:2 + return; // scope 0 at $DIR/inline-compatibility.rs:14:2: 14:2 + } + + bb1 (cleanup): { -+ resume; // scope 0 at $DIR/inline-compatibility.rs:+0:1: +2:2 ++ resume; // scope 0 at $DIR/inline-compatibility.rs:12:1: 14:2 } } diff --git a/src/test/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff index 49aea431e46dd..bced3f6fe56a7 100644 --- a/src/test/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff +++ b/src/test/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff @@ -2,24 +2,24 @@ + // MIR for `not_inlined_c_variadic` after Inline fn not_inlined_c_variadic() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:+0:40: +0:40 - let _1: u32; // in scope 0 at $DIR/inline-compatibility.rs:+1:9: +1:10 + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:41:40: 41:40 + let _1: u32; // in scope 0 at $DIR/inline-compatibility.rs:42:9: 42:10 scope 1 { - debug s => _1; // in scope 1 at $DIR/inline-compatibility.rs:+1:9: +1:10 + debug s => _1; // in scope 1 at $DIR/inline-compatibility.rs:42:9: 42:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:9: +1:10 - _1 = sum(const 4_u32, const 4_u32, const 30_u32, const 200_u32, const 1000_u32) -> bb1; // scope 0 at $DIR/inline-compatibility.rs:+1:13: +1:52 + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:42:9: 42:10 + _1 = sum(const 4_u32, const 4_u32, const 30_u32, const 200_u32, const 1000_u32) -> bb1; // scope 0 at $DIR/inline-compatibility.rs:42:13: 42:52 // mir::Constant // + span: $DIR/inline-compatibility.rs:42:13: 42:16 // + literal: Const { ty: unsafe extern "C" fn(u32, ...) -> u32 {sum}, val: Value() } } bb1: { - _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:+0:40: +2:2 - StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:+2:1: +2:2 - return; // scope 0 at $DIR/inline-compatibility.rs:+2:2: +2:2 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:41:40: 43:2 + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:43:1: 43:2 + return; // scope 0 at $DIR/inline-compatibility.rs:43:2: 43:2 } } diff --git a/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff index 94ce574a94dc2..a4989cbfa096d 100644 --- a/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff +++ b/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff @@ -2,21 +2,21 @@ + // MIR for `not_inlined_no_sanitize` after Inline fn not_inlined_no_sanitize() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:+0:41: +0:41 - let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:18 + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:28:41: 28:41 + let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:29:5: 29:18 bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:18 - _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:18 + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:29:5: 29:18 + _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:29:5: 29:18 // mir::Constant // + span: $DIR/inline-compatibility.rs:29:5: 29:16 // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value() } } bb1: { - StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:18: +1:19 - _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:+0:41: +2:2 - return; // scope 0 at $DIR/inline-compatibility.rs:+2:2: +2:2 + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:29:18: 29:19 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:28:41: 30:2 + return; // scope 0 at $DIR/inline-compatibility.rs:30:2: 30:2 } } diff --git a/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff index 8506e257b3fe9..49dd90c971cb4 100644 --- a/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff +++ b/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff @@ -2,21 +2,21 @@ + // MIR for `not_inlined_target_feature` after Inline fn not_inlined_target_feature() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:+0:44: +0:44 - let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:21 + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:17:44: 17:44 + let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:18:5: 18:21 bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:21 - _1 = target_feature() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:21 + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:18:5: 18:21 + _1 = target_feature() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:18:5: 18:21 // mir::Constant // + span: $DIR/inline-compatibility.rs:18:5: 18:19 // + literal: Const { ty: unsafe fn() {target_feature}, val: Value() } } bb1: { - StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:21: +1:22 - _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:+0:44: +2:2 - return; // scope 0 at $DIR/inline-compatibility.rs:+2:2: +2:2 + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:18:21: 18:22 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:17:44: 19:2 + return; // scope 0 at $DIR/inline-compatibility.rs:19:2: 19:2 } } diff --git a/src/test/mir-opt/inline/inline_cycle.one.Inline.diff b/src/test/mir-opt/inline/inline_cycle.one.Inline.diff index a6d65928da708..8128797d27eae 100644 --- a/src/test/mir-opt/inline/inline_cycle.one.Inline.diff +++ b/src/test/mir-opt/inline/inline_cycle.one.Inline.diff @@ -2,8 +2,8 @@ + // MIR for `one` after Inline fn one() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-cycle.rs:+0:10: +0:10 - let _1: (); // in scope 0 at $DIR/inline-cycle.rs:+1:5: +1:24 + let mut _0: (); // return place in scope 0 at $DIR/inline-cycle.rs:13:10: 13:10 + let _1: (); // in scope 0 at $DIR/inline-cycle.rs:14:5: 14:24 + scope 1 (inlined ::call) { // at $DIR/inline-cycle.rs:14:5: 14:24 + scope 2 (inlined as Call>::call) { // at $DIR/inline-cycle.rs:43:9: 43:23 + scope 3 (inlined as Call>::call) { // at $DIR/inline-cycle.rs:28:9: 28:31 @@ -12,9 +12,9 @@ + } bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-cycle.rs:+1:5: +1:24 -- _1 = ::call() -> bb1; // scope 0 at $DIR/inline-cycle.rs:+1:5: +1:24 -+ _1 = ::call() -> bb1; // scope 3 at $DIR/inline-cycle.rs:+23:9: +23:28 + StorageLive(_1); // scope 0 at $DIR/inline-cycle.rs:14:5: 14:24 +- _1 = ::call() -> bb1; // scope 0 at $DIR/inline-cycle.rs:14:5: 14:24 ++ _1 = ::call() -> bb1; // scope 3 at $DIR/inline-cycle.rs:36:9: 36:28 // mir::Constant - // + span: $DIR/inline-cycle.rs:14:5: 14:22 + // + span: $DIR/inline-cycle.rs:36:9: 36:26 @@ -22,13 +22,13 @@ } bb1: { - StorageDead(_1); // scope 0 at $DIR/inline-cycle.rs:+1:24: +1:25 - _0 = const (); // scope 0 at $DIR/inline-cycle.rs:+0:10: +2:2 - return; // scope 0 at $DIR/inline-cycle.rs:+2:2: +2:2 + StorageDead(_1); // scope 0 at $DIR/inline-cycle.rs:14:24: 14:25 + _0 = const (); // scope 0 at $DIR/inline-cycle.rs:13:10: 15:2 + return; // scope 0 at $DIR/inline-cycle.rs:15:2: 15:2 + } + + bb2 (cleanup): { -+ resume; // scope 0 at $DIR/inline-cycle.rs:+0:1: +2:2 ++ resume; // scope 0 at $DIR/inline-cycle.rs:13:1: 15:2 } } diff --git a/src/test/mir-opt/inline/inline_cycle.two.Inline.diff b/src/test/mir-opt/inline/inline_cycle.two.Inline.diff index 0fea4121f8dae..29c793d7bd8cd 100644 --- a/src/test/mir-opt/inline/inline_cycle.two.Inline.diff +++ b/src/test/mir-opt/inline/inline_cycle.two.Inline.diff @@ -2,36 +2,36 @@ + // MIR for `two` after Inline fn two() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-cycle.rs:+0:10: +0:10 - let _1: (); // in scope 0 at $DIR/inline-cycle.rs:+1:5: +1:12 -+ let mut _2: fn() {f}; // in scope 0 at $DIR/inline-cycle.rs:+1:5: +1:12 + let mut _0: (); // return place in scope 0 at $DIR/inline-cycle.rs:48:10: 48:10 + let _1: (); // in scope 0 at $DIR/inline-cycle.rs:49:5: 49:12 ++ let mut _2: fn() {f}; // in scope 0 at $DIR/inline-cycle.rs:49:5: 49:12 + scope 1 (inlined call::) { // at $DIR/inline-cycle.rs:49:5: 49:12 -+ debug f => _2; // in scope 1 at $DIR/inline-cycle.rs:+5:22: +5:23 -+ let _3: (); // in scope 1 at $DIR/inline-cycle.rs:+6:5: +6:8 -+ let mut _4: fn() {f}; // in scope 1 at $DIR/inline-cycle.rs:+6:5: +6:6 -+ let mut _5: (); // in scope 1 at $DIR/inline-cycle.rs:+6:5: +6:8 ++ debug f => _2; // in scope 1 at $DIR/inline-cycle.rs:53:22: 53:23 ++ let _3: (); // in scope 1 at $DIR/inline-cycle.rs:54:5: 54:8 ++ let mut _4: fn() {f}; // in scope 1 at $DIR/inline-cycle.rs:54:5: 54:6 ++ let mut _5: (); // in scope 1 at $DIR/inline-cycle.rs:54:5: 54:8 + scope 2 (inlined >::call_once - shim(fn() {f})) { // at $DIR/inline-cycle.rs:54:5: 54:8 + scope 3 (inlined f) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL -+ let _6: (); // in scope 3 at $DIR/inline-cycle.rs:+11:5: +11:12 ++ let _6: (); // in scope 3 at $DIR/inline-cycle.rs:59:5: 59:12 + } + } + } bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-cycle.rs:+1:5: +1:12 -- _1 = call::(f) -> bb1; // scope 0 at $DIR/inline-cycle.rs:+1:5: +1:12 -+ StorageLive(_2); // scope 0 at $DIR/inline-cycle.rs:+1:5: +1:12 -+ _2 = f; // scope 0 at $DIR/inline-cycle.rs:+1:5: +1:12 + StorageLive(_1); // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12 +- _1 = call::(f) -> bb1; // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12 ++ StorageLive(_2); // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12 ++ _2 = f; // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12 // mir::Constant - // + span: $DIR/inline-cycle.rs:49:5: 49:9 + // + span: $DIR/inline-cycle.rs:49:10: 49:11 + // + literal: Const { ty: fn() {f}, val: Value() } -+ StorageLive(_3); // scope 1 at $DIR/inline-cycle.rs:+6:5: +6:8 -+ StorageLive(_4); // scope 1 at $DIR/inline-cycle.rs:+6:5: +6:6 -+ _4 = move _2; // scope 1 at $DIR/inline-cycle.rs:+6:5: +6:6 -+ StorageLive(_5); // scope 1 at $DIR/inline-cycle.rs:+6:5: +6:8 -+ StorageLive(_6); // scope 3 at $DIR/inline-cycle.rs:+11:5: +11:12 -+ _6 = call::(f) -> bb1; // scope 3 at $DIR/inline-cycle.rs:+11:5: +11:12 ++ StorageLive(_3); // scope 1 at $DIR/inline-cycle.rs:54:5: 54:8 ++ StorageLive(_4); // scope 1 at $DIR/inline-cycle.rs:54:5: 54:6 ++ _4 = move _2; // scope 1 at $DIR/inline-cycle.rs:54:5: 54:6 ++ StorageLive(_5); // scope 1 at $DIR/inline-cycle.rs:54:5: 54:8 ++ StorageLive(_6); // scope 3 at $DIR/inline-cycle.rs:59:5: 59:12 ++ _6 = call::(f) -> bb1; // scope 3 at $DIR/inline-cycle.rs:59:5: 59:12 + // mir::Constant + // + span: $DIR/inline-cycle.rs:59:5: 59:9 // + literal: Const { ty: fn(fn() {f}) {call::}, val: Value() } @@ -42,18 +42,18 @@ } bb1: { -+ StorageDead(_6); // scope 3 at $DIR/inline-cycle.rs:+11:12: +11:13 -+ StorageDead(_5); // scope 1 at $DIR/inline-cycle.rs:+6:7: +6:8 -+ StorageDead(_4); // scope 1 at $DIR/inline-cycle.rs:+6:7: +6:8 -+ StorageDead(_3); // scope 1 at $DIR/inline-cycle.rs:+6:8: +6:9 -+ StorageDead(_2); // scope 0 at $DIR/inline-cycle.rs:+1:5: +1:12 - StorageDead(_1); // scope 0 at $DIR/inline-cycle.rs:+1:12: +1:13 - _0 = const (); // scope 0 at $DIR/inline-cycle.rs:+0:10: +2:2 - return; // scope 0 at $DIR/inline-cycle.rs:+2:2: +2:2 ++ StorageDead(_6); // scope 3 at $DIR/inline-cycle.rs:59:12: 59:13 ++ StorageDead(_5); // scope 1 at $DIR/inline-cycle.rs:54:7: 54:8 ++ StorageDead(_4); // scope 1 at $DIR/inline-cycle.rs:54:7: 54:8 ++ StorageDead(_3); // scope 1 at $DIR/inline-cycle.rs:54:8: 54:9 ++ StorageDead(_2); // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12 + StorageDead(_1); // scope 0 at $DIR/inline-cycle.rs:49:12: 49:13 + _0 = const (); // scope 0 at $DIR/inline-cycle.rs:48:10: 50:2 + return; // scope 0 at $DIR/inline-cycle.rs:50:2: 50:2 + } + + bb2 (cleanup): { -+ resume; // scope 0 at $DIR/inline-cycle.rs:+0:1: +2:2 ++ resume; // scope 0 at $DIR/inline-cycle.rs:48:1: 50:2 } } diff --git a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff b/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff index d5709f1b47a40..2ccd39e7931ed 100644 --- a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff +++ b/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff @@ -2,8 +2,8 @@ + // MIR for `main` after Inline fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-cycle-generic.rs:+0:11: +0:11 - let _1: (); // in scope 0 at $DIR/inline-cycle-generic.rs:+1:5: +1:24 + let mut _0: (); // return place in scope 0 at $DIR/inline-cycle-generic.rs:8:11: 8:11 + let _1: (); // in scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24 + scope 1 (inlined ::call) { // at $DIR/inline-cycle-generic.rs:9:5: 9:24 + scope 2 (inlined as Call>::call) { // at $DIR/inline-cycle-generic.rs:38:9: 38:31 + scope 3 (inlined ::call) { // at $DIR/inline-cycle-generic.rs:31:9: 31:28 @@ -14,9 +14,9 @@ + } bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-cycle-generic.rs:+1:5: +1:24 -- _1 = ::call() -> bb1; // scope 0 at $DIR/inline-cycle-generic.rs:+1:5: +1:24 -+ _1 = ::call() -> bb1; // scope 4 at $DIR/inline-cycle-generic.rs:+23:9: +23:28 + StorageLive(_1); // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24 +- _1 = ::call() -> bb1; // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24 ++ _1 = ::call() -> bb1; // scope 4 at $DIR/inline-cycle-generic.rs:31:9: 31:28 // mir::Constant - // + span: $DIR/inline-cycle-generic.rs:9:5: 9:22 + // + span: $DIR/inline-cycle-generic.rs:31:9: 31:26 @@ -24,13 +24,13 @@ } bb1: { - StorageDead(_1); // scope 0 at $DIR/inline-cycle-generic.rs:+1:24: +1:25 - _0 = const (); // scope 0 at $DIR/inline-cycle-generic.rs:+0:11: +2:2 - return; // scope 0 at $DIR/inline-cycle-generic.rs:+2:2: +2:2 + StorageDead(_1); // scope 0 at $DIR/inline-cycle-generic.rs:9:24: 9:25 + _0 = const (); // scope 0 at $DIR/inline-cycle-generic.rs:8:11: 10:2 + return; // scope 0 at $DIR/inline-cycle-generic.rs:10:2: 10:2 + } + + bb2 (cleanup): { -+ resume; // scope 0 at $DIR/inline-cycle-generic.rs:+0:1: +2:2 ++ resume; // scope 0 at $DIR/inline-cycle-generic.rs:8:1: 10:2 } } diff --git a/src/test/mir-opt/inline/inline_diverging.f.Inline.diff b/src/test/mir-opt/inline/inline_diverging.f.Inline.diff index 7ebc2ff5c4531..7cdc1a6b546a2 100644 --- a/src/test/mir-opt/inline/inline_diverging.f.Inline.diff +++ b/src/test/mir-opt/inline/inline_diverging.f.Inline.diff @@ -2,27 +2,27 @@ + // MIR for `f` after Inline fn f() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-diverging.rs:+0:12: +0:12 - let mut _1: !; // in scope 0 at $DIR/inline-diverging.rs:+0:12: +2:2 - let _2: !; // in scope 0 at $DIR/inline-diverging.rs:+1:5: +1:12 + let mut _0: (); // return place in scope 0 at $DIR/inline-diverging.rs:7:12: 7:12 + let mut _1: !; // in scope 0 at $DIR/inline-diverging.rs:7:12: 9:2 + let _2: !; // in scope 0 at $DIR/inline-diverging.rs:8:5: 8:12 + scope 1 (inlined sleep) { // at $DIR/inline-diverging.rs:8:5: 8:12 + } bb0: { - StorageLive(_2); // scope 0 at $DIR/inline-diverging.rs:+1:5: +1:12 -- _2 = sleep(); // scope 0 at $DIR/inline-diverging.rs:+1:5: +1:12 + StorageLive(_2); // scope 0 at $DIR/inline-diverging.rs:8:5: 8:12 +- _2 = sleep(); // scope 0 at $DIR/inline-diverging.rs:8:5: 8:12 - // mir::Constant - // + span: $DIR/inline-diverging.rs:8:5: 8:10 - // + literal: Const { ty: fn() -> ! {sleep}, val: Value() } -+ goto -> bb1; // scope 0 at $DIR/inline-diverging.rs:+1:5: +1:12 ++ goto -> bb1; // scope 0 at $DIR/inline-diverging.rs:8:5: 8:12 + } + + bb1: { -+ goto -> bb1; // scope 1 at $DIR/inline-diverging.rs:+32:5: +32:12 ++ goto -> bb1; // scope 1 at $DIR/inline-diverging.rs:39:5: 39:12 + } + + bb2 (cleanup): { -+ resume; // scope 0 at $DIR/inline-diverging.rs:+0:1: +2:2 ++ resume; // scope 0 at $DIR/inline-diverging.rs:7:1: 9:2 } } diff --git a/src/test/mir-opt/inline/inline_diverging.g.Inline.diff b/src/test/mir-opt/inline/inline_diverging.g.Inline.diff index acdd0f87901d5..595df0aed5ff8 100644 --- a/src/test/mir-opt/inline/inline_diverging.g.Inline.diff +++ b/src/test/mir-opt/inline/inline_diverging.g.Inline.diff @@ -2,38 +2,38 @@ + // MIR for `g` after Inline fn g(_1: i32) -> u32 { - debug i => _1; // in scope 0 at $DIR/inline-diverging.rs:+0:10: +0:11 - let mut _0: u32; // return place in scope 0 at $DIR/inline-diverging.rs:+0:21: +0:24 - let mut _2: bool; // in scope 0 at $DIR/inline-diverging.rs:+1:8: +1:13 - let mut _3: i32; // in scope 0 at $DIR/inline-diverging.rs:+1:8: +1:9 - let mut _4: i32; // in scope 0 at $DIR/inline-diverging.rs:+2:9: +2:10 - let mut _5: !; // in scope 0 at $DIR/inline-diverging.rs:+3:12: +5:6 - let _6: !; // in scope 0 at $DIR/inline-diverging.rs:+4:9: +4:16 + debug i => _1; // in scope 0 at $DIR/inline-diverging.rs:12:10: 12:11 + let mut _0: u32; // return place in scope 0 at $DIR/inline-diverging.rs:12:21: 12:24 + let mut _2: bool; // in scope 0 at $DIR/inline-diverging.rs:13:8: 13:13 + let mut _3: i32; // in scope 0 at $DIR/inline-diverging.rs:13:8: 13:9 + let mut _4: i32; // in scope 0 at $DIR/inline-diverging.rs:14:9: 14:10 + let mut _5: !; // in scope 0 at $DIR/inline-diverging.rs:15:12: 17:6 + let _6: !; // in scope 0 at $DIR/inline-diverging.rs:16:9: 16:16 + scope 1 (inlined panic) { // at $DIR/inline-diverging.rs:16:9: 16:16 + let mut _7: !; // in scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL + } bb0: { - StorageLive(_2); // scope 0 at $DIR/inline-diverging.rs:+1:8: +1:13 - StorageLive(_3); // scope 0 at $DIR/inline-diverging.rs:+1:8: +1:9 - _3 = _1; // scope 0 at $DIR/inline-diverging.rs:+1:8: +1:9 - _2 = Gt(move _3, const 0_i32); // scope 0 at $DIR/inline-diverging.rs:+1:8: +1:13 - StorageDead(_3); // scope 0 at $DIR/inline-diverging.rs:+1:12: +1:13 - switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/inline-diverging.rs:+1:8: +1:13 + StorageLive(_2); // scope 0 at $DIR/inline-diverging.rs:13:8: 13:13 + StorageLive(_3); // scope 0 at $DIR/inline-diverging.rs:13:8: 13:9 + _3 = _1; // scope 0 at $DIR/inline-diverging.rs:13:8: 13:9 + _2 = Gt(move _3, const 0_i32); // scope 0 at $DIR/inline-diverging.rs:13:8: 13:13 + StorageDead(_3); // scope 0 at $DIR/inline-diverging.rs:13:12: 13:13 + switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/inline-diverging.rs:13:8: 13:13 } bb1: { - StorageLive(_4); // scope 0 at $DIR/inline-diverging.rs:+2:9: +2:10 - _4 = _1; // scope 0 at $DIR/inline-diverging.rs:+2:9: +2:10 - _0 = move _4 as u32 (Misc); // scope 0 at $DIR/inline-diverging.rs:+2:9: +2:17 - StorageDead(_4); // scope 0 at $DIR/inline-diverging.rs:+2:16: +2:17 - StorageDead(_2); // scope 0 at $DIR/inline-diverging.rs:+5:5: +5:6 - return; // scope 0 at $DIR/inline-diverging.rs:+6:2: +6:2 + StorageLive(_4); // scope 0 at $DIR/inline-diverging.rs:14:9: 14:10 + _4 = _1; // scope 0 at $DIR/inline-diverging.rs:14:9: 14:10 + _0 = move _4 as u32 (Misc); // scope 0 at $DIR/inline-diverging.rs:14:9: 14:17 + StorageDead(_4); // scope 0 at $DIR/inline-diverging.rs:14:16: 14:17 + StorageDead(_2); // scope 0 at $DIR/inline-diverging.rs:17:5: 17:6 + return; // scope 0 at $DIR/inline-diverging.rs:18:2: 18:2 } bb2: { - StorageLive(_6); // scope 0 at $DIR/inline-diverging.rs:+4:9: +4:16 -- _6 = panic(); // scope 0 at $DIR/inline-diverging.rs:+4:9: +4:16 + StorageLive(_6); // scope 0 at $DIR/inline-diverging.rs:16:9: 16:16 +- _6 = panic(); // scope 0 at $DIR/inline-diverging.rs:16:9: 16:16 + StorageLive(_7); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL + _7 = begin_panic::<&str>(const "explicit panic"); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL // mir::Constant @@ -47,7 +47,7 @@ + } + + bb3 (cleanup): { -+ resume; // scope 0 at $DIR/inline-diverging.rs:+0:1: +6:2 ++ resume; // scope 0 at $DIR/inline-diverging.rs:12:1: 18:2 } } diff --git a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff index 8fda8673c9535..32066cf2e3e73 100644 --- a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff +++ b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff @@ -2,23 +2,23 @@ + // MIR for `h` after Inline fn h() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-diverging.rs:+0:12: +0:12 - let _1: (!, !); // in scope 0 at $DIR/inline-diverging.rs:+1:5: +1:22 -+ let mut _2: fn() -> ! {sleep}; // in scope 0 at $DIR/inline-diverging.rs:+1:5: +1:22 + let mut _0: (); // return place in scope 0 at $DIR/inline-diverging.rs:21:12: 21:12 + let _1: (!, !); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 ++ let mut _2: fn() -> ! {sleep}; // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 + scope 1 (inlined call_twice:: ! {sleep}>) { // at $DIR/inline-diverging.rs:22:5: 22:22 -+ debug f => _2; // in scope 1 at $DIR/inline-diverging.rs:+5:36: +5:37 -+ let _3: !; // in scope 1 at $DIR/inline-diverging.rs:+6:9: +6:10 -+ let mut _4: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:+6:13: +6:14 -+ let mut _5: (); // in scope 1 at $DIR/inline-diverging.rs:+6:13: +6:16 -+ let mut _7: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:+7:13: +7:14 -+ let mut _8: (); // in scope 1 at $DIR/inline-diverging.rs:+7:13: +7:16 -+ let mut _9: !; // in scope 1 at $DIR/inline-diverging.rs:+8:6: +8:7 -+ let mut _10: !; // in scope 1 at $DIR/inline-diverging.rs:+8:9: +8:10 ++ debug f => _2; // in scope 1 at $DIR/inline-diverging.rs:26:36: 26:37 ++ let _3: !; // in scope 1 at $DIR/inline-diverging.rs:27:9: 27:10 ++ let mut _4: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:14 ++ let mut _5: (); // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:16 ++ let mut _7: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14 ++ let mut _8: (); // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:16 ++ let mut _9: !; // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7 ++ let mut _10: !; // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10 + scope 2 { -+ debug a => _3; // in scope 2 at $DIR/inline-diverging.rs:+6:9: +6:10 -+ let _6: !; // in scope 2 at $DIR/inline-diverging.rs:+7:9: +7:10 ++ debug a => _3; // in scope 2 at $DIR/inline-diverging.rs:27:9: 27:10 ++ let _6: !; // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10 + scope 3 { -+ debug b => _6; // in scope 3 at $DIR/inline-diverging.rs:+7:9: +7:10 ++ debug b => _6; // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10 + } + scope 6 (inlined ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline-diverging.rs:28:13: 28:16 + scope 7 (inlined sleep) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -32,29 +32,29 @@ + } bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-diverging.rs:+1:5: +1:22 -- _1 = call_twice:: ! {sleep}>(sleep); // scope 0 at $DIR/inline-diverging.rs:+1:5: +1:22 -+ StorageLive(_2); // scope 0 at $DIR/inline-diverging.rs:+1:5: +1:22 -+ _2 = sleep; // scope 0 at $DIR/inline-diverging.rs:+1:5: +1:22 + StorageLive(_1); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 +- _1 = call_twice:: ! {sleep}>(sleep); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 ++ StorageLive(_2); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 ++ _2 = sleep; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 // mir::Constant - // + span: $DIR/inline-diverging.rs:22:5: 22:15 - // + literal: Const { ty: fn(fn() -> ! {sleep}) -> (!, !) {call_twice:: ! {sleep}>}, val: Value() } - // mir::Constant // + span: $DIR/inline-diverging.rs:22:16: 22:21 // + literal: Const { ty: fn() -> ! {sleep}, val: Value() } -+ StorageLive(_3); // scope 1 at $DIR/inline-diverging.rs:+6:9: +6:10 -+ StorageLive(_4); // scope 1 at $DIR/inline-diverging.rs:+6:13: +6:14 -+ _4 = &_2; // scope 1 at $DIR/inline-diverging.rs:+6:13: +6:14 -+ StorageLive(_5); // scope 1 at $DIR/inline-diverging.rs:+6:13: +6:16 -+ goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:+18:5: +18:12 ++ StorageLive(_3); // scope 1 at $DIR/inline-diverging.rs:27:9: 27:10 ++ StorageLive(_4); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14 ++ _4 = &_2; // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14 ++ StorageLive(_5); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16 ++ goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12 + } + + bb1: { -+ goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:+18:5: +18:12 ++ goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12 + } + + bb2 (cleanup): { -+ resume; // scope 0 at $DIR/inline-diverging.rs:+0:1: +2:2 ++ resume; // scope 0 at $DIR/inline-diverging.rs:21:1: 23:2 } } diff --git a/src/test/mir-opt/inline/inline_generator.main.Inline.diff b/src/test/mir-opt/inline/inline_generator.main.Inline.diff index c7c2759cc6579..b4f0abd1af54b 100644 --- a/src/test/mir-opt/inline/inline_generator.main.Inline.diff +++ b/src/test/mir-opt/inline/inline_generator.main.Inline.diff @@ -2,14 +2,14 @@ + // MIR for `main` after Inline fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-generator.rs:+0:11: +0:11 - let _1: std::ops::GeneratorState; // in scope 0 at $DIR/inline-generator.rs:+1:9: +1:11 - let mut _2: std::pin::Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>; // in scope 0 at $DIR/inline-generator.rs:+1:14: +1:32 - let mut _3: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 0 at $DIR/inline-generator.rs:+1:23: +1:31 - let mut _4: [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 0 at $DIR/inline-generator.rs:+1:28: +1:31 -+ let mut _7: bool; // in scope 0 at $DIR/inline-generator.rs:+1:14: +1:46 + let mut _0: (); // return place in scope 0 at $DIR/inline-generator.rs:8:11: 8:11 + let _1: std::ops::GeneratorState; // in scope 0 at $DIR/inline-generator.rs:9:9: 9:11 + let mut _2: std::pin::Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:32 + let mut _3: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 0 at $DIR/inline-generator.rs:9:23: 9:31 + let mut _4: [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 0 at $DIR/inline-generator.rs:9:28: 9:31 ++ let mut _7: bool; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:46 scope 1 { - debug _r => _1; // in scope 1 at $DIR/inline-generator.rs:+1:9: +1:11 + debug _r => _1; // in scope 1 at $DIR/inline-generator.rs:9:9: 9:11 } + scope 2 (inlined g) { // at $DIR/inline-generator.rs:9:28: 9:31 + } @@ -24,33 +24,33 @@ + } + } + scope 6 (inlined g::{closure#0}) { // at $DIR/inline-generator.rs:9:14: 9:46 -+ debug a => _11; // in scope 6 at $DIR/inline-generator.rs:+7:6: +7:7 -+ let mut _8: i32; // in scope 6 at $DIR/inline-generator.rs:+7:17: +7:39 -+ let mut _9: bool; // in scope 6 at $DIR/inline-generator.rs:+7:20: +7:21 -+ let mut _10: bool; // in scope 6 at $DIR/inline-generator.rs:+7:9: +7:9 -+ let _11: bool; // in scope 6 at $DIR/inline-generator.rs:+7:6: +7:7 -+ let mut _12: u32; // in scope 6 at $DIR/inline-generator.rs:+7:5: +7:8 -+ let mut _13: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline-generator.rs:+7:5: +7:8 -+ let mut _14: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline-generator.rs:+7:5: +7:8 -+ let mut _15: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline-generator.rs:+7:5: +7:8 ++ debug a => _11; // in scope 6 at $DIR/inline-generator.rs:15:6: 15:7 ++ let mut _8: i32; // in scope 6 at $DIR/inline-generator.rs:15:17: 15:39 ++ let mut _9: bool; // in scope 6 at $DIR/inline-generator.rs:15:20: 15:21 ++ let mut _10: bool; // in scope 6 at $DIR/inline-generator.rs:15:9: 15:9 ++ let _11: bool; // in scope 6 at $DIR/inline-generator.rs:15:6: 15:7 ++ let mut _12: u32; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ let mut _13: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ let mut _14: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ let mut _15: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:8 + } bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-generator.rs:+1:9: +1:11 - StorageLive(_2); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:32 - StorageLive(_3); // scope 0 at $DIR/inline-generator.rs:+1:23: +1:31 - StorageLive(_4); // scope 0 at $DIR/inline-generator.rs:+1:28: +1:31 -- _4 = g() -> bb1; // scope 0 at $DIR/inline-generator.rs:+1:28: +1:31 + StorageLive(_1); // scope 0 at $DIR/inline-generator.rs:9:9: 9:11 + StorageLive(_2); // scope 0 at $DIR/inline-generator.rs:9:14: 9:32 + StorageLive(_3); // scope 0 at $DIR/inline-generator.rs:9:23: 9:31 + StorageLive(_4); // scope 0 at $DIR/inline-generator.rs:9:28: 9:31 +- _4 = g() -> bb1; // scope 0 at $DIR/inline-generator.rs:9:28: 9:31 - // mir::Constant - // + span: $DIR/inline-generator.rs:9:28: 9:29 - // + literal: Const { ty: fn() -> impl Generator {g}, val: Value() } - } - - bb1: { -+ Deinit(_4); // scope 2 at $DIR/inline-generator.rs:+7:5: +7:41 -+ discriminant(_4) = 0; // scope 2 at $DIR/inline-generator.rs:+7:5: +7:41 - _3 = &mut _4; // scope 0 at $DIR/inline-generator.rs:+1:23: +1:31 -- _2 = Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:+1:14: +1:32 ++ Deinit(_4); // scope 2 at $DIR/inline-generator.rs:15:5: 15:41 ++ discriminant(_4) = 0; // scope 2 at $DIR/inline-generator.rs:15:5: 15:41 + _3 = &mut _4; // scope 0 at $DIR/inline-generator.rs:9:23: 9:31 +- _2 = Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:32 - // mir::Constant - // + span: $DIR/inline-generator.rs:9:14: 9:22 - // + user_ty: UserType(0) @@ -66,91 +66,91 @@ + (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]) = move _6; // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL + StorageDead(_6); // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL + StorageDead(_5); // scope 4 at $SRC_DIR/core/src/pin.rs:LL:COL - StorageDead(_3); // scope 0 at $DIR/inline-generator.rs:+1:31: +1:32 -- _1 = <[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46 + StorageDead(_3); // scope 0 at $DIR/inline-generator.rs:9:31: 9:32 +- _1 = <[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 - // mir::Constant - // + span: $DIR/inline-generator.rs:9:33: 9:39 - // + literal: Const { ty: for<'r> fn(Pin<&'r mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>, bool) -> GeneratorState<<[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator>::Yield, <[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator>::Return> {<[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator>::resume}, val: Value() } -+ StorageLive(_7); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46 -+ _7 = const false; // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46 -+ StorageLive(_10); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46 -+ StorageLive(_11); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46 -+ StorageLive(_12); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46 -+ StorageLive(_13); // scope 6 at $DIR/inline-generator.rs:+7:5: +7:8 -+ _13 = deref_copy (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline-generator.rs:+7:5: +7:8 -+ _12 = discriminant((*_13)); // scope 6 at $DIR/inline-generator.rs:+7:5: +7:8 -+ StorageDead(_13); // scope 6 at $DIR/inline-generator.rs:+7:5: +7:8 -+ switchInt(move _12) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline-generator.rs:+7:5: +7:8 ++ StorageLive(_7); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 ++ _7 = const false; // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 ++ StorageLive(_10); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 ++ StorageLive(_11); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 ++ StorageLive(_12); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 ++ StorageLive(_13); // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ _13 = deref_copy (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ _12 = discriminant((*_13)); // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ StorageDead(_13); // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ switchInt(move _12) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 } - bb3: { + bb1: { -+ StorageDead(_12); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46 -+ StorageDead(_11); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46 -+ StorageDead(_10); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46 -+ StorageDead(_7); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46 - StorageDead(_2); // scope 0 at $DIR/inline-generator.rs:+1:45: +1:46 - StorageDead(_4); // scope 0 at $DIR/inline-generator.rs:+1:46: +1:47 - _0 = const (); // scope 0 at $DIR/inline-generator.rs:+0:11: +2:2 - StorageDead(_1); // scope 0 at $DIR/inline-generator.rs:+2:1: +2:2 - return; // scope 0 at $DIR/inline-generator.rs:+2:2: +2:2 ++ StorageDead(_12); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 ++ StorageDead(_11); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 ++ StorageDead(_10); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 ++ StorageDead(_7); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 + StorageDead(_2); // scope 0 at $DIR/inline-generator.rs:9:45: 9:46 + StorageDead(_4); // scope 0 at $DIR/inline-generator.rs:9:46: 9:47 + _0 = const (); // scope 0 at $DIR/inline-generator.rs:8:11: 10:2 + StorageDead(_1); // scope 0 at $DIR/inline-generator.rs:10:1: 10:2 + return; // scope 0 at $DIR/inline-generator.rs:10:2: 10:2 } - bb4 (cleanup): { + bb2 (cleanup): { - resume; // scope 0 at $DIR/inline-generator.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/inline-generator.rs:8:1: 10:2 + } + + bb3: { -+ _11 = move _7; // scope 6 at $DIR/inline-generator.rs:+7:5: +7:8 -+ StorageLive(_8); // scope 6 at $DIR/inline-generator.rs:+7:17: +7:39 -+ StorageLive(_9); // scope 6 at $DIR/inline-generator.rs:+7:20: +7:21 -+ _9 = _11; // scope 6 at $DIR/inline-generator.rs:+7:20: +7:21 -+ switchInt(move _9) -> [false: bb5, otherwise: bb4]; // scope 6 at $DIR/inline-generator.rs:+7:20: +7:21 ++ _11 = move _7; // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ StorageLive(_8); // scope 6 at $DIR/inline-generator.rs:15:17: 15:39 ++ StorageLive(_9); // scope 6 at $DIR/inline-generator.rs:15:20: 15:21 ++ _9 = _11; // scope 6 at $DIR/inline-generator.rs:15:20: 15:21 ++ switchInt(move _9) -> [false: bb5, otherwise: bb4]; // scope 6 at $DIR/inline-generator.rs:15:20: 15:21 + } + + bb4: { -+ _8 = const 7_i32; // scope 6 at $DIR/inline-generator.rs:+7:24: +7:25 -+ goto -> bb6; // scope 6 at $DIR/inline-generator.rs:+7:17: +7:39 ++ _8 = const 7_i32; // scope 6 at $DIR/inline-generator.rs:15:24: 15:25 ++ goto -> bb6; // scope 6 at $DIR/inline-generator.rs:15:17: 15:39 + } + + bb5: { -+ _8 = const 13_i32; // scope 6 at $DIR/inline-generator.rs:+7:35: +7:37 -+ goto -> bb6; // scope 6 at $DIR/inline-generator.rs:+7:17: +7:39 ++ _8 = const 13_i32; // scope 6 at $DIR/inline-generator.rs:15:35: 15:37 ++ goto -> bb6; // scope 6 at $DIR/inline-generator.rs:15:17: 15:39 + } + + bb6: { -+ StorageDead(_9); // scope 6 at $DIR/inline-generator.rs:+7:38: +7:39 -+ Deinit(_1); // scope 6 at $DIR/inline-generator.rs:+7:11: +7:39 -+ ((_1 as Yielded).0: i32) = move _8; // scope 6 at $DIR/inline-generator.rs:+7:11: +7:39 -+ discriminant(_1) = 0; // scope 6 at $DIR/inline-generator.rs:+7:11: +7:39 -+ StorageLive(_14); // scope 6 at $DIR/inline-generator.rs:+7:11: +7:39 -+ _14 = deref_copy (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline-generator.rs:+7:11: +7:39 -+ discriminant((*_14)) = 3; // scope 6 at $DIR/inline-generator.rs:+7:11: +7:39 -+ StorageDead(_14); // scope 6 at $DIR/inline-generator.rs:+7:11: +7:39 -+ goto -> bb1; // scope 0 at $DIR/inline-generator.rs:+7:11: +7:39 ++ StorageDead(_9); // scope 6 at $DIR/inline-generator.rs:15:38: 15:39 ++ Deinit(_1); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 ++ ((_1 as Yielded).0: i32) = move _8; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 ++ discriminant(_1) = 0; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 ++ StorageLive(_14); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 ++ _14 = deref_copy (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 ++ discriminant((*_14)) = 3; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 ++ StorageDead(_14); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 ++ goto -> bb1; // scope 0 at $DIR/inline-generator.rs:15:11: 15:39 + } + + bb7: { -+ StorageLive(_8); // scope 6 at $DIR/inline-generator.rs:+7:5: +7:8 -+ _10 = move _7; // scope 6 at $DIR/inline-generator.rs:+7:5: +7:8 -+ StorageDead(_8); // scope 6 at $DIR/inline-generator.rs:+7:38: +7:39 -+ Deinit(_1); // scope 6 at $DIR/inline-generator.rs:+7:8: +7:8 -+ ((_1 as Complete).0: bool) = move _10; // scope 6 at $DIR/inline-generator.rs:+7:8: +7:8 -+ discriminant(_1) = 1; // scope 6 at $DIR/inline-generator.rs:+7:8: +7:8 -+ StorageLive(_15); // scope 6 at $DIR/inline-generator.rs:+7:8: +7:8 -+ _15 = deref_copy (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline-generator.rs:+7:8: +7:8 -+ discriminant((*_15)) = 1; // scope 6 at $DIR/inline-generator.rs:+7:8: +7:8 -+ StorageDead(_15); // scope 6 at $DIR/inline-generator.rs:+7:8: +7:8 -+ goto -> bb1; // scope 0 at $DIR/inline-generator.rs:+7:8: +7:8 ++ StorageLive(_8); // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ _10 = move _7; // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ StorageDead(_8); // scope 6 at $DIR/inline-generator.rs:15:38: 15:39 ++ Deinit(_1); // scope 6 at $DIR/inline-generator.rs:15:8: 15:8 ++ ((_1 as Complete).0: bool) = move _10; // scope 6 at $DIR/inline-generator.rs:15:8: 15:8 ++ discriminant(_1) = 1; // scope 6 at $DIR/inline-generator.rs:15:8: 15:8 ++ StorageLive(_15); // scope 6 at $DIR/inline-generator.rs:15:8: 15:8 ++ _15 = deref_copy (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline-generator.rs:15:8: 15:8 ++ discriminant((*_15)) = 1; // scope 6 at $DIR/inline-generator.rs:15:8: 15:8 ++ StorageDead(_15); // scope 6 at $DIR/inline-generator.rs:15:8: 15:8 ++ goto -> bb1; // scope 0 at $DIR/inline-generator.rs:15:8: 15:8 + } + + bb8: { -+ assert(const false, "generator resumed after completion") -> [success: bb8, unwind: bb2]; // scope 6 at $DIR/inline-generator.rs:+7:5: +7:8 ++ assert(const false, "generator resumed after completion") -> [success: bb8, unwind: bb2]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 + } + + bb9: { -+ unreachable; // scope 6 at $DIR/inline-generator.rs:+7:5: +7:8 ++ unreachable; // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 } } diff --git a/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff b/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff index e3375e9e15cb3..05bd99b62cd1f 100644 --- a/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff +++ b/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff @@ -2,47 +2,47 @@ + // MIR for `default` after Inline fn default() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-instruction-set.rs:+0:18: +0:18 - let _1: (); // in scope 0 at $DIR/inline-instruction-set.rs:+1:5: +1:26 - let _2: (); // in scope 0 at $DIR/inline-instruction-set.rs:+2:5: +2:26 - let _3: (); // in scope 0 at $DIR/inline-instruction-set.rs:+3:5: +3:30 + let mut _0: (); // return place in scope 0 at $DIR/inline-instruction-set.rs:50:18: 50:18 + let _1: (); // in scope 0 at $DIR/inline-instruction-set.rs:51:5: 51:26 + let _2: (); // in scope 0 at $DIR/inline-instruction-set.rs:52:5: 52:26 + let _3: (); // in scope 0 at $DIR/inline-instruction-set.rs:53:5: 53:30 + scope 1 (inlined instruction_set_default) { // at $DIR/inline-instruction-set.rs:53:5: 53:30 + } bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-instruction-set.rs:+1:5: +1:26 - _1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline-instruction-set.rs:+1:5: +1:26 + StorageLive(_1); // scope 0 at $DIR/inline-instruction-set.rs:51:5: 51:26 + _1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline-instruction-set.rs:51:5: 51:26 // mir::Constant // + span: $DIR/inline-instruction-set.rs:51:5: 51:24 // + literal: Const { ty: fn() {instruction_set_a32}, val: Value() } } bb1: { - StorageDead(_1); // scope 0 at $DIR/inline-instruction-set.rs:+1:26: +1:27 - StorageLive(_2); // scope 0 at $DIR/inline-instruction-set.rs:+2:5: +2:26 - _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:+2:5: +2:26 + StorageDead(_1); // scope 0 at $DIR/inline-instruction-set.rs:51:26: 51:27 + StorageLive(_2); // scope 0 at $DIR/inline-instruction-set.rs:52:5: 52:26 + _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:52:5: 52:26 // mir::Constant // + span: $DIR/inline-instruction-set.rs:52:5: 52:24 // + literal: Const { ty: fn() {instruction_set_t32}, val: Value() } } bb2: { - StorageDead(_2); // scope 0 at $DIR/inline-instruction-set.rs:+2:26: +2:27 - StorageLive(_3); // scope 0 at $DIR/inline-instruction-set.rs:+3:5: +3:30 -- _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline-instruction-set.rs:+3:5: +3:30 + StorageDead(_2); // scope 0 at $DIR/inline-instruction-set.rs:52:26: 52:27 + StorageLive(_3); // scope 0 at $DIR/inline-instruction-set.rs:53:5: 53:30 +- _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline-instruction-set.rs:53:5: 53:30 - // mir::Constant - // + span: $DIR/inline-instruction-set.rs:53:5: 53:28 - // + literal: Const { ty: fn() {instruction_set_default}, val: Value() } - } - - bb3: { - StorageDead(_3); // scope 0 at $DIR/inline-instruction-set.rs:+3:30: +3:31 - _0 = const (); // scope 0 at $DIR/inline-instruction-set.rs:+0:18: +4:2 - return; // scope 0 at $DIR/inline-instruction-set.rs:+4:2: +4:2 + StorageDead(_3); // scope 0 at $DIR/inline-instruction-set.rs:53:30: 53:31 + _0 = const (); // scope 0 at $DIR/inline-instruction-set.rs:50:18: 54:2 + return; // scope 0 at $DIR/inline-instruction-set.rs:54:2: 54:2 + } + + bb3 (cleanup): { -+ resume; // scope 0 at $DIR/inline-instruction-set.rs:+0:1: +4:2 ++ resume; // scope 0 at $DIR/inline-instruction-set.rs:50:1: 54:2 } } diff --git a/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff b/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff index ce294db02fdd5..cb0d01428c946 100644 --- a/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff +++ b/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff @@ -2,35 +2,35 @@ + // MIR for `t32` after Inline fn t32() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-instruction-set.rs:+0:14: +0:14 - let _1: (); // in scope 0 at $DIR/inline-instruction-set.rs:+1:5: +1:26 - let _2: (); // in scope 0 at $DIR/inline-instruction-set.rs:+2:5: +2:26 - let _3: (); // in scope 0 at $DIR/inline-instruction-set.rs:+5:5: +5:30 + let mut _0: (); // return place in scope 0 at $DIR/inline-instruction-set.rs:41:14: 41:14 + let _1: (); // in scope 0 at $DIR/inline-instruction-set.rs:42:5: 42:26 + let _2: (); // in scope 0 at $DIR/inline-instruction-set.rs:43:5: 43:26 + let _3: (); // in scope 0 at $DIR/inline-instruction-set.rs:46:5: 46:30 + scope 1 (inlined instruction_set_t32) { // at $DIR/inline-instruction-set.rs:43:5: 43:26 + } bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-instruction-set.rs:+1:5: +1:26 - _1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline-instruction-set.rs:+1:5: +1:26 + StorageLive(_1); // scope 0 at $DIR/inline-instruction-set.rs:42:5: 42:26 + _1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline-instruction-set.rs:42:5: 42:26 // mir::Constant // + span: $DIR/inline-instruction-set.rs:42:5: 42:24 // + literal: Const { ty: fn() {instruction_set_a32}, val: Value() } } bb1: { - StorageDead(_1); // scope 0 at $DIR/inline-instruction-set.rs:+1:26: +1:27 - StorageLive(_2); // scope 0 at $DIR/inline-instruction-set.rs:+2:5: +2:26 -- _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:+2:5: +2:26 + StorageDead(_1); // scope 0 at $DIR/inline-instruction-set.rs:42:26: 42:27 + StorageLive(_2); // scope 0 at $DIR/inline-instruction-set.rs:43:5: 43:26 +- _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:43:5: 43:26 - // mir::Constant - // + span: $DIR/inline-instruction-set.rs:43:5: 43:24 - // + literal: Const { ty: fn() {instruction_set_t32}, val: Value() } - } - - bb2: { - StorageDead(_2); // scope 0 at $DIR/inline-instruction-set.rs:+2:26: +2:27 - StorageLive(_3); // scope 0 at $DIR/inline-instruction-set.rs:+5:5: +5:30 -- _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline-instruction-set.rs:+5:5: +5:30 -+ _3 = instruction_set_default() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:+5:5: +5:30 + StorageDead(_2); // scope 0 at $DIR/inline-instruction-set.rs:43:26: 43:27 + StorageLive(_3); // scope 0 at $DIR/inline-instruction-set.rs:46:5: 46:30 +- _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline-instruction-set.rs:46:5: 46:30 ++ _3 = instruction_set_default() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:46:5: 46:30 // mir::Constant // + span: $DIR/inline-instruction-set.rs:46:5: 46:28 // + literal: Const { ty: fn() {instruction_set_default}, val: Value() } @@ -38,13 +38,13 @@ - bb3: { + bb2: { - StorageDead(_3); // scope 0 at $DIR/inline-instruction-set.rs:+5:30: +5:31 - _0 = const (); // scope 0 at $DIR/inline-instruction-set.rs:+0:14: +6:2 - return; // scope 0 at $DIR/inline-instruction-set.rs:+6:2: +6:2 + StorageDead(_3); // scope 0 at $DIR/inline-instruction-set.rs:46:30: 46:31 + _0 = const (); // scope 0 at $DIR/inline-instruction-set.rs:41:14: 47:2 + return; // scope 0 at $DIR/inline-instruction-set.rs:47:2: 47:2 + } + + bb3 (cleanup): { -+ resume; // scope 0 at $DIR/inline-instruction-set.rs:+0:1: +6:2 ++ resume; // scope 0 at $DIR/inline-instruction-set.rs:41:1: 47:2 } } diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff index deaba70e082ed..17050f184cb48 100644 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff +++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff @@ -2,18 +2,18 @@ + // MIR for `main` after Inline fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:+0:11: +0:11 - let _1: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11 - let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - let mut _5: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43 - let mut _7: *const std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - let mut _8: *const std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 -+ let mut _9: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 + let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:7:11: 7:11 + let _1: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 + let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _5: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 + let mut _7: *const std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _8: *const std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 ++ let mut _9: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 scope 1 { - debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11 + debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:8:9: 8:11 } scope 2 { } @@ -22,23 +22,23 @@ + } bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11 - _2 = SizeOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - _3 = AlignOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43 + StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 + _2 = SizeOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _3 = AlignOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 // mir::Constant // + span: $DIR/inline-into-box-place.rs:8:29: 8:43 // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value() } } bb1: { - StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - _5 = ShallowInitBox(move _4, std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 - _7 = (((_5.0: std::ptr::Unique>).0: std::ptr::NonNull>).0: *const std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -- (*_7) = Vec::::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -+ StorageLive(_9); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -+ _9 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 + StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _5 = ShallowInitBox(move _4, std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _7 = (((_5.0: std::ptr::Unique>).0: std::ptr::NonNull>).0: *const std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 +- (*_7) = Vec::::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ StorageLive(_9); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ _9 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + StorageLive(_10); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + _10 = const alloc::raw_vec::RawVec::::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL // mir::Constant @@ -55,24 +55,24 @@ + ((*_9).0: alloc::raw_vec::RawVec) = move _10; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + ((*_9).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + StorageDead(_10); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ StorageDead(_9); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 - StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 - _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43 - _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:+0:11: +2:2 -- drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2 -+ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2 ++ StorageDead(_9); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 + _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2 +- drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 ++ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 } - bb3: { + bb2: { - StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2 - return; // scope 0 at $DIR/inline-into-box-place.rs:+2:2: +2:2 + StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 + return; // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2 } - bb4 (cleanup): { -- StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -- _6 = alloc::alloc::box_free::, std::alloc::Global>(move (_5.0: std::ptr::Unique>), move (_5.1: std::alloc::Global)) -> bb5; // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43 +- StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 +- _6 = alloc::alloc::box_free::, std::alloc::Global>(move (_5.0: std::ptr::Unique>), move (_5.1: std::alloc::Global)) -> bb5; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:42: 8:43 - // + literal: Const { ty: unsafe fn(Unique>, std::alloc::Global) {alloc::alloc::box_free::, std::alloc::Global>}, val: Value() } @@ -80,7 +80,7 @@ - - bb5 (cleanup): { + bb3 (cleanup): { - resume; // scope 0 at $DIR/inline-into-box-place.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2 } } diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff index deaba70e082ed..17050f184cb48 100644 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff +++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff @@ -2,18 +2,18 @@ + // MIR for `main` after Inline fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:+0:11: +0:11 - let _1: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11 - let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - let mut _5: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43 - let mut _7: *const std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - let mut _8: *const std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 -+ let mut _9: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 + let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:7:11: 7:11 + let _1: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 + let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _5: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 + let mut _7: *const std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _8: *const std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 ++ let mut _9: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 scope 1 { - debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11 + debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:8:9: 8:11 } scope 2 { } @@ -22,23 +22,23 @@ + } bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11 - _2 = SizeOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - _3 = AlignOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43 + StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 + _2 = SizeOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _3 = AlignOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 // mir::Constant // + span: $DIR/inline-into-box-place.rs:8:29: 8:43 // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value() } } bb1: { - StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - _5 = ShallowInitBox(move _4, std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 - _7 = (((_5.0: std::ptr::Unique>).0: std::ptr::NonNull>).0: *const std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -- (*_7) = Vec::::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -+ StorageLive(_9); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -+ _9 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 + StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _5 = ShallowInitBox(move _4, std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _7 = (((_5.0: std::ptr::Unique>).0: std::ptr::NonNull>).0: *const std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 +- (*_7) = Vec::::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ StorageLive(_9); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ _9 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + StorageLive(_10); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + _10 = const alloc::raw_vec::RawVec::::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL // mir::Constant @@ -55,24 +55,24 @@ + ((*_9).0: alloc::raw_vec::RawVec) = move _10; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + ((*_9).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + StorageDead(_10); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ StorageDead(_9); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 - StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 - _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43 - _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:+0:11: +2:2 -- drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2 -+ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2 ++ StorageDead(_9); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 + _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2 +- drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 ++ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 } - bb3: { + bb2: { - StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2 - return; // scope 0 at $DIR/inline-into-box-place.rs:+2:2: +2:2 + StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 + return; // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2 } - bb4 (cleanup): { -- StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -- _6 = alloc::alloc::box_free::, std::alloc::Global>(move (_5.0: std::ptr::Unique>), move (_5.1: std::alloc::Global)) -> bb5; // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43 +- StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 +- _6 = alloc::alloc::box_free::, std::alloc::Global>(move (_5.0: std::ptr::Unique>), move (_5.1: std::alloc::Global)) -> bb5; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:42: 8:43 - // + literal: Const { ty: unsafe fn(Unique>, std::alloc::Global) {alloc::alloc::box_free::, std::alloc::Global>}, val: Value() } @@ -80,7 +80,7 @@ - - bb5 (cleanup): { + bb3 (cleanup): { - resume; // scope 0 at $DIR/inline-into-box-place.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2 } } diff --git a/src/test/mir-opt/inline/inline_options.main.Inline.after.mir b/src/test/mir-opt/inline/inline_options.main.Inline.after.mir index 49c72b7196c41..45023083be668 100644 --- a/src/test/mir-opt/inline/inline_options.main.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_options.main.Inline.after.mir @@ -1,59 +1,59 @@ // MIR for `main` after Inline fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-options.rs:+0:11: +0:11 - let _1: (); // in scope 0 at $DIR/inline-options.rs:+1:5: +1:18 - let _2: (); // in scope 0 at $DIR/inline-options.rs:+2:5: +2:21 + let mut _0: (); // return place in scope 0 at $DIR/inline-options.rs:8:11: 8:11 + let _1: (); // in scope 0 at $DIR/inline-options.rs:9:5: 9:18 + let _2: (); // in scope 0 at $DIR/inline-options.rs:10:5: 10:21 scope 1 (inlined inlined::) { // at $DIR/inline-options.rs:10:5: 10:21 - let _3: (); // in scope 1 at $DIR/inline-options.rs:+8:23: +8:26 - let _4: (); // in scope 1 at $DIR/inline-options.rs:+8:28: +8:31 - let _5: (); // in scope 1 at $DIR/inline-options.rs:+8:33: +8:36 + let _3: (); // in scope 1 at $DIR/inline-options.rs:16:23: 16:26 + let _4: (); // in scope 1 at $DIR/inline-options.rs:16:28: 16:31 + let _5: (); // in scope 1 at $DIR/inline-options.rs:16:33: 16:36 } bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-options.rs:+1:5: +1:18 - _1 = not_inlined() -> bb1; // scope 0 at $DIR/inline-options.rs:+1:5: +1:18 + StorageLive(_1); // scope 0 at $DIR/inline-options.rs:9:5: 9:18 + _1 = not_inlined() -> bb1; // scope 0 at $DIR/inline-options.rs:9:5: 9:18 // mir::Constant // + span: $DIR/inline-options.rs:9:5: 9:16 // + literal: Const { ty: fn() {not_inlined}, val: Value() } } bb1: { - StorageDead(_1); // scope 0 at $DIR/inline-options.rs:+1:18: +1:19 - StorageLive(_2); // scope 0 at $DIR/inline-options.rs:+2:5: +2:21 - StorageLive(_3); // scope 1 at $DIR/inline-options.rs:+8:23: +8:26 - _3 = g() -> bb2; // scope 1 at $DIR/inline-options.rs:+8:23: +8:26 + StorageDead(_1); // scope 0 at $DIR/inline-options.rs:9:18: 9:19 + StorageLive(_2); // scope 0 at $DIR/inline-options.rs:10:5: 10:21 + StorageLive(_3); // scope 1 at $DIR/inline-options.rs:16:23: 16:26 + _3 = g() -> bb2; // scope 1 at $DIR/inline-options.rs:16:23: 16:26 // mir::Constant // + span: $DIR/inline-options.rs:16:23: 16:24 // + literal: Const { ty: fn() {g}, val: Value() } } bb2: { - StorageDead(_3); // scope 1 at $DIR/inline-options.rs:+8:26: +8:27 - StorageLive(_4); // scope 1 at $DIR/inline-options.rs:+8:28: +8:31 - _4 = g() -> bb3; // scope 1 at $DIR/inline-options.rs:+8:28: +8:31 + StorageDead(_3); // scope 1 at $DIR/inline-options.rs:16:26: 16:27 + StorageLive(_4); // scope 1 at $DIR/inline-options.rs:16:28: 16:31 + _4 = g() -> bb3; // scope 1 at $DIR/inline-options.rs:16:28: 16:31 // mir::Constant // + span: $DIR/inline-options.rs:16:28: 16:29 // + literal: Const { ty: fn() {g}, val: Value() } } bb3: { - StorageDead(_4); // scope 1 at $DIR/inline-options.rs:+8:31: +8:32 - StorageLive(_5); // scope 1 at $DIR/inline-options.rs:+8:33: +8:36 - _5 = g() -> bb4; // scope 1 at $DIR/inline-options.rs:+8:33: +8:36 + StorageDead(_4); // scope 1 at $DIR/inline-options.rs:16:31: 16:32 + StorageLive(_5); // scope 1 at $DIR/inline-options.rs:16:33: 16:36 + _5 = g() -> bb4; // scope 1 at $DIR/inline-options.rs:16:33: 16:36 // mir::Constant // + span: $DIR/inline-options.rs:16:33: 16:34 // + literal: Const { ty: fn() {g}, val: Value() } } bb4: { - StorageDead(_5); // scope 1 at $DIR/inline-options.rs:+8:36: +8:37 - StorageDead(_2); // scope 0 at $DIR/inline-options.rs:+2:21: +2:22 - _0 = const (); // scope 0 at $DIR/inline-options.rs:+0:11: +3:2 - return; // scope 0 at $DIR/inline-options.rs:+3:2: +3:2 + StorageDead(_5); // scope 1 at $DIR/inline-options.rs:16:36: 16:37 + StorageDead(_2); // scope 0 at $DIR/inline-options.rs:10:21: 10:22 + _0 = const (); // scope 0 at $DIR/inline-options.rs:8:11: 11:2 + return; // scope 0 at $DIR/inline-options.rs:11:2: 11:2 } bb5 (cleanup): { - resume; // scope 0 at $DIR/inline-options.rs:+0:1: +3:2 + resume; // scope 0 at $DIR/inline-options.rs:8:1: 11:2 } } diff --git a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir index 0ea8823156c12..fcc1767578eb2 100644 --- a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir @@ -1,76 +1,76 @@ // MIR for `bar` after Inline fn bar() -> bool { - let mut _0: bool; // return place in scope 0 at $DIR/inline-retag.rs:+0:13: +0:17 - let _1: for<'r, 's> fn(&'r i32, &'s i32) -> bool {foo}; // in scope 0 at $DIR/inline-retag.rs:+1:9: +1:10 - let mut _2: for<'r, 's> fn(&'r i32, &'s i32) -> bool {foo}; // in scope 0 at $DIR/inline-retag.rs:+2:5: +2:6 - let mut _3: &i32; // in scope 0 at $DIR/inline-retag.rs:+2:7: +2:9 - let _4: &i32; // in scope 0 at $DIR/inline-retag.rs:+2:7: +2:9 - let _5: i32; // in scope 0 at $DIR/inline-retag.rs:+2:8: +2:9 - let mut _6: &i32; // in scope 0 at $DIR/inline-retag.rs:+2:11: +2:14 - let _7: &i32; // in scope 0 at $DIR/inline-retag.rs:+2:11: +2:14 - let _8: i32; // in scope 0 at $DIR/inline-retag.rs:+2:12: +2:14 + let mut _0: bool; // return place in scope 0 at $DIR/inline-retag.rs:10:13: 10:17 + let _1: for<'r, 's> fn(&'r i32, &'s i32) -> bool {foo}; // in scope 0 at $DIR/inline-retag.rs:11:9: 11:10 + let mut _2: for<'r, 's> fn(&'r i32, &'s i32) -> bool {foo}; // in scope 0 at $DIR/inline-retag.rs:12:5: 12:6 + let mut _3: &i32; // in scope 0 at $DIR/inline-retag.rs:12:7: 12:9 + let _4: &i32; // in scope 0 at $DIR/inline-retag.rs:12:7: 12:9 + let _5: i32; // in scope 0 at $DIR/inline-retag.rs:12:8: 12:9 + let mut _6: &i32; // in scope 0 at $DIR/inline-retag.rs:12:11: 12:14 + let _7: &i32; // in scope 0 at $DIR/inline-retag.rs:12:11: 12:14 + let _8: i32; // in scope 0 at $DIR/inline-retag.rs:12:12: 12:14 scope 1 { - debug f => _1; // in scope 1 at $DIR/inline-retag.rs:+1:9: +1:10 - let mut _9: &i32; // in scope 1 at $DIR/inline-retag.rs:+2:11: +2:14 - let mut _10: &i32; // in scope 1 at $DIR/inline-retag.rs:+2:7: +2:9 + debug f => _1; // in scope 1 at $DIR/inline-retag.rs:11:9: 11:10 + let mut _9: &i32; // in scope 1 at $DIR/inline-retag.rs:12:11: 12:14 + let mut _10: &i32; // in scope 1 at $DIR/inline-retag.rs:12:7: 12:9 scope 2 (inlined foo) { // at $DIR/inline-retag.rs:12:5: 12:15 - debug x => _3; // in scope 2 at $DIR/inline-retag.rs:+6:8: +6:9 - debug y => _6; // in scope 2 at $DIR/inline-retag.rs:+6:17: +6:18 - let mut _11: i32; // in scope 2 at $DIR/inline-retag.rs:+7:5: +7:7 - let mut _12: i32; // in scope 2 at $DIR/inline-retag.rs:+7:11: +7:13 + debug x => _3; // in scope 2 at $DIR/inline-retag.rs:16:8: 16:9 + debug y => _6; // in scope 2 at $DIR/inline-retag.rs:16:17: 16:18 + let mut _11: i32; // in scope 2 at $DIR/inline-retag.rs:17:5: 17:7 + let mut _12: i32; // in scope 2 at $DIR/inline-retag.rs:17:11: 17:13 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-retag.rs:+1:9: +1:10 - _1 = foo; // scope 0 at $DIR/inline-retag.rs:+1:13: +1:16 + StorageLive(_1); // scope 0 at $DIR/inline-retag.rs:11:9: 11:10 + _1 = foo; // scope 0 at $DIR/inline-retag.rs:11:13: 11:16 // mir::Constant // + span: $DIR/inline-retag.rs:11:13: 11:16 // + literal: Const { ty: for<'r, 's> fn(&'r i32, &'s i32) -> bool {foo}, val: Value() } - StorageLive(_2); // scope 1 at $DIR/inline-retag.rs:+2:5: +2:6 - _2 = _1; // scope 1 at $DIR/inline-retag.rs:+2:5: +2:6 - StorageLive(_3); // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9 - StorageLive(_4); // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9 - _10 = const bar::promoted[1]; // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9 + StorageLive(_2); // scope 1 at $DIR/inline-retag.rs:12:5: 12:6 + _2 = _1; // scope 1 at $DIR/inline-retag.rs:12:5: 12:6 + StorageLive(_3); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 + StorageLive(_4); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 + _10 = const bar::promoted[1]; // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 // mir::Constant // + span: $DIR/inline-retag.rs:12:7: 12:9 // + literal: Const { ty: &i32, val: Unevaluated(bar, [], Some(promoted[1])) } - Retag(_10); // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9 - _4 = &(*_10); // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9 - Retag(_4); // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9 - _3 = &(*_4); // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9 - Retag(_3); // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9 - StorageLive(_6); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14 - StorageLive(_7); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14 - _9 = const bar::promoted[0]; // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14 + Retag(_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 + _4 = &(*_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 + Retag(_4); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 + _3 = &(*_4); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 + Retag(_3); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 + StorageLive(_6); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 + StorageLive(_7); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 + _9 = const bar::promoted[0]; // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 // mir::Constant // + span: $DIR/inline-retag.rs:12:11: 12:14 // + literal: Const { ty: &i32, val: Unevaluated(bar, [], Some(promoted[0])) } - Retag(_9); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14 - _7 = &(*_9); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14 - Retag(_7); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14 - _6 = &(*_7); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14 - Retag(_6); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14 - Retag(_3); // scope 2 at $DIR/inline-retag.rs:+6:1: +8:2 - Retag(_6); // scope 2 at $DIR/inline-retag.rs:+6:1: +8:2 - StorageLive(_11); // scope 2 at $DIR/inline-retag.rs:+7:5: +7:7 - _11 = (*_3); // scope 2 at $DIR/inline-retag.rs:+7:5: +7:7 - StorageLive(_12); // scope 2 at $DIR/inline-retag.rs:+7:11: +7:13 - _12 = (*_6); // scope 2 at $DIR/inline-retag.rs:+7:11: +7:13 - _0 = Eq(move _11, move _12); // scope 2 at $DIR/inline-retag.rs:+7:5: +7:13 - StorageDead(_12); // scope 2 at $DIR/inline-retag.rs:+7:12: +7:13 - StorageDead(_11); // scope 2 at $DIR/inline-retag.rs:+7:12: +7:13 - StorageDead(_6); // scope 1 at $DIR/inline-retag.rs:+2:14: +2:15 - StorageDead(_3); // scope 1 at $DIR/inline-retag.rs:+2:14: +2:15 - StorageDead(_2); // scope 1 at $DIR/inline-retag.rs:+2:14: +2:15 - StorageDead(_1); // scope 0 at $DIR/inline-retag.rs:+3:1: +3:2 - StorageDead(_7); // scope 0 at $DIR/inline-retag.rs:+3:1: +3:2 - StorageDead(_4); // scope 0 at $DIR/inline-retag.rs:+3:1: +3:2 - return; // scope 0 at $DIR/inline-retag.rs:+3:2: +3:2 + Retag(_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 + _7 = &(*_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 + Retag(_7); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 + _6 = &(*_7); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 + Retag(_6); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 + Retag(_3); // scope 2 at $DIR/inline-retag.rs:16:1: 18:2 + Retag(_6); // scope 2 at $DIR/inline-retag.rs:16:1: 18:2 + StorageLive(_11); // scope 2 at $DIR/inline-retag.rs:17:5: 17:7 + _11 = (*_3); // scope 2 at $DIR/inline-retag.rs:17:5: 17:7 + StorageLive(_12); // scope 2 at $DIR/inline-retag.rs:17:11: 17:13 + _12 = (*_6); // scope 2 at $DIR/inline-retag.rs:17:11: 17:13 + _0 = Eq(move _11, move _12); // scope 2 at $DIR/inline-retag.rs:17:5: 17:13 + StorageDead(_12); // scope 2 at $DIR/inline-retag.rs:17:12: 17:13 + StorageDead(_11); // scope 2 at $DIR/inline-retag.rs:17:12: 17:13 + StorageDead(_6); // scope 1 at $DIR/inline-retag.rs:12:14: 12:15 + StorageDead(_3); // scope 1 at $DIR/inline-retag.rs:12:14: 12:15 + StorageDead(_2); // scope 1 at $DIR/inline-retag.rs:12:14: 12:15 + StorageDead(_1); // scope 0 at $DIR/inline-retag.rs:13:1: 13:2 + StorageDead(_7); // scope 0 at $DIR/inline-retag.rs:13:1: 13:2 + StorageDead(_4); // scope 0 at $DIR/inline-retag.rs:13:1: 13:2 + return; // scope 0 at $DIR/inline-retag.rs:13:2: 13:2 } bb1 (cleanup): { - resume; // scope 0 at $DIR/inline-retag.rs:+0:1: +3:2 + resume; // scope 0 at $DIR/inline-retag.rs:10:1: 13:2 } } diff --git a/src/test/mir-opt/inline/inline_shims.clone.Inline.diff b/src/test/mir-opt/inline/inline_shims.clone.Inline.diff index e69af79162264..d67b07b0181b4 100644 --- a/src/test/mir-opt/inline/inline_shims.clone.Inline.diff +++ b/src/test/mir-opt/inline/inline_shims.clone.Inline.diff @@ -2,16 +2,16 @@ + // MIR for `clone` after Inline fn clone(_1: fn(A, B)) -> fn(A, B) { - debug f => _1; // in scope 0 at $DIR/inline-shims.rs:+0:20: +0:21 - let mut _0: fn(A, B); // return place in scope 0 at $DIR/inline-shims.rs:+0:36: +0:44 - let mut _2: &fn(A, B); // in scope 0 at $DIR/inline-shims.rs:+1:5: +1:14 + debug f => _1; // in scope 0 at $DIR/inline-shims.rs:5:20: 5:21 + let mut _0: fn(A, B); // return place in scope 0 at $DIR/inline-shims.rs:5:36: 5:44 + let mut _2: &fn(A, B); // in scope 0 at $DIR/inline-shims.rs:6:5: 6:14 + scope 1 (inlined ::clone - shim(fn(A, B))) { // at $DIR/inline-shims.rs:6:5: 6:14 + } bb0: { - StorageLive(_2); // scope 0 at $DIR/inline-shims.rs:+1:5: +1:14 - _2 = &_1; // scope 0 at $DIR/inline-shims.rs:+1:5: +1:14 -- _0 = ::clone(move _2) -> bb1; // scope 0 at $DIR/inline-shims.rs:+1:5: +1:14 + StorageLive(_2); // scope 0 at $DIR/inline-shims.rs:6:5: 6:14 + _2 = &_1; // scope 0 at $DIR/inline-shims.rs:6:5: 6:14 +- _0 = ::clone(move _2) -> bb1; // scope 0 at $DIR/inline-shims.rs:6:5: 6:14 - // mir::Constant - // + span: $DIR/inline-shims.rs:6:7: 6:12 - // + literal: Const { ty: for<'r> fn(&'r fn(A, B)) -> fn(A, B) {::clone}, val: Value() } @@ -19,12 +19,12 @@ - - bb1: { + _0 = (*_2); // scope 1 at $SRC_DIR/core/src/clone.rs:LL:COL - StorageDead(_2); // scope 0 at $DIR/inline-shims.rs:+1:13: +1:14 - return; // scope 0 at $DIR/inline-shims.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/inline-shims.rs:6:13: 6:14 + return; // scope 0 at $DIR/inline-shims.rs:7:2: 7:2 + } + + bb1 (cleanup): { -+ resume; // scope 0 at $DIR/inline-shims.rs:+0:1: +2:2 ++ resume; // scope 0 at $DIR/inline-shims.rs:5:1: 7:2 } } diff --git a/src/test/mir-opt/inline/inline_shims.drop.Inline.diff b/src/test/mir-opt/inline/inline_shims.drop.Inline.diff index 8c1c383ee25dc..5c7cbc9b41900 100644 --- a/src/test/mir-opt/inline/inline_shims.drop.Inline.diff +++ b/src/test/mir-opt/inline/inline_shims.drop.Inline.diff @@ -2,12 +2,12 @@ + // MIR for `drop` after Inline fn drop(_1: *mut Vec, _2: *mut Option) -> () { - debug a => _1; // in scope 0 at $DIR/inline-shims.rs:+0:19: +0:20 - debug b => _2; // in scope 0 at $DIR/inline-shims.rs:+0:35: +0:36 - let mut _0: (); // return place in scope 0 at $DIR/inline-shims.rs:+0:54: +0:54 - let _3: (); // in scope 0 at $DIR/inline-shims.rs:+1:14: +1:40 - let mut _4: *mut std::vec::Vec; // in scope 0 at $DIR/inline-shims.rs:+1:38: +1:39 - let mut _5: *mut std::option::Option; // in scope 0 at $DIR/inline-shims.rs:+2:38: +2:39 + debug a => _1; // in scope 0 at $DIR/inline-shims.rs:10:19: 10:20 + debug b => _2; // in scope 0 at $DIR/inline-shims.rs:10:35: 10:36 + let mut _0: (); // return place in scope 0 at $DIR/inline-shims.rs:10:54: 10:54 + let _3: (); // in scope 0 at $DIR/inline-shims.rs:11:14: 11:40 + let mut _4: *mut std::vec::Vec; // in scope 0 at $DIR/inline-shims.rs:11:38: 11:39 + let mut _5: *mut std::option::Option; // in scope 0 at $DIR/inline-shims.rs:12:38: 12:39 scope 1 { } scope 2 { @@ -18,35 +18,35 @@ } bb0: { - StorageLive(_3); // scope 0 at $DIR/inline-shims.rs:+1:5: +1:42 - StorageLive(_4); // scope 1 at $DIR/inline-shims.rs:+1:38: +1:39 - _4 = _1; // scope 1 at $DIR/inline-shims.rs:+1:38: +1:39 - _3 = std::ptr::drop_in_place::>(move _4) -> bb1; // scope 1 at $DIR/inline-shims.rs:+1:14: +1:40 + StorageLive(_3); // scope 0 at $DIR/inline-shims.rs:11:5: 11:42 + StorageLive(_4); // scope 1 at $DIR/inline-shims.rs:11:38: 11:39 + _4 = _1; // scope 1 at $DIR/inline-shims.rs:11:38: 11:39 + _3 = std::ptr::drop_in_place::>(move _4) -> bb1; // scope 1 at $DIR/inline-shims.rs:11:14: 11:40 // mir::Constant // + span: $DIR/inline-shims.rs:11:14: 11:37 // + literal: Const { ty: unsafe fn(*mut Vec) {std::ptr::drop_in_place::>}, val: Value() } } bb1: { - StorageDead(_4); // scope 1 at $DIR/inline-shims.rs:+1:39: +1:40 - StorageDead(_3); // scope 0 at $DIR/inline-shims.rs:+1:41: +1:42 - StorageLive(_5); // scope 2 at $DIR/inline-shims.rs:+2:38: +2:39 - _5 = _2; // scope 2 at $DIR/inline-shims.rs:+2:38: +2:39 -- _0 = std::ptr::drop_in_place::>(move _5) -> bb2; // scope 2 at $DIR/inline-shims.rs:+2:14: +2:40 + StorageDead(_4); // scope 1 at $DIR/inline-shims.rs:11:39: 11:40 + StorageDead(_3); // scope 0 at $DIR/inline-shims.rs:11:41: 11:42 + StorageLive(_5); // scope 2 at $DIR/inline-shims.rs:12:38: 12:39 + _5 = _2; // scope 2 at $DIR/inline-shims.rs:12:38: 12:39 +- _0 = std::ptr::drop_in_place::>(move _5) -> bb2; // scope 2 at $DIR/inline-shims.rs:12:14: 12:40 - // mir::Constant - // + span: $DIR/inline-shims.rs:12:14: 12:37 - // + literal: Const { ty: unsafe fn(*mut Option) {std::ptr::drop_in_place::>}, val: Value() } -+ StorageLive(_6); // scope 2 at $DIR/inline-shims.rs:+2:14: +2:40 -+ StorageLive(_7); // scope 2 at $DIR/inline-shims.rs:+2:14: +2:40 ++ StorageLive(_6); // scope 2 at $DIR/inline-shims.rs:12:14: 12:40 ++ StorageLive(_7); // scope 2 at $DIR/inline-shims.rs:12:14: 12:40 + _6 = discriminant((*_5)); // scope 3 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + switchInt(move _6) -> [0_isize: bb2, otherwise: bb3]; // scope 3 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb2: { -+ StorageDead(_7); // scope 2 at $DIR/inline-shims.rs:+2:14: +2:40 -+ StorageDead(_6); // scope 2 at $DIR/inline-shims.rs:+2:14: +2:40 - StorageDead(_5); // scope 2 at $DIR/inline-shims.rs:+2:39: +2:40 - return; // scope 0 at $DIR/inline-shims.rs:+3:2: +3:2 ++ StorageDead(_7); // scope 2 at $DIR/inline-shims.rs:12:14: 12:40 ++ StorageDead(_6); // scope 2 at $DIR/inline-shims.rs:12:14: 12:40 + StorageDead(_5); // scope 2 at $DIR/inline-shims.rs:12:39: 12:40 + return; // scope 0 at $DIR/inline-shims.rs:13:2: 13:2 + } + + bb3: { @@ -54,7 +54,7 @@ + } + + bb4 (cleanup): { -+ resume; // scope 0 at $DIR/inline-shims.rs:+0:1: +3:2 ++ resume; // scope 0 at $DIR/inline-shims.rs:10:1: 13:2 } } diff --git a/src/test/mir-opt/inline/inline_specialization.main.Inline.diff b/src/test/mir-opt/inline/inline_specialization.main.Inline.diff index 6c71311c7d434..747eeb9845073 100644 --- a/src/test/mir-opt/inline/inline_specialization.main.Inline.diff +++ b/src/test/mir-opt/inline/inline_specialization.main.Inline.diff @@ -2,31 +2,31 @@ + // MIR for `main` after Inline fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-specialization.rs:+0:11: +0:11 - let _1: u32; // in scope 0 at $DIR/inline-specialization.rs:+1:9: +1:10 + let mut _0: (); // return place in scope 0 at $DIR/inline-specialization.rs:4:11: 4:11 + let _1: u32; // in scope 0 at $DIR/inline-specialization.rs:5:9: 5:10 scope 1 { - debug x => _1; // in scope 1 at $DIR/inline-specialization.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/inline-specialization.rs:5:9: 5:10 } + scope 2 (inlined as Foo>::bar) { // at $DIR/inline-specialization.rs:5:13: 5:38 + } bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-specialization.rs:+1:9: +1:10 -- _1 = as Foo>::bar() -> bb1; // scope 0 at $DIR/inline-specialization.rs:+1:13: +1:38 + StorageLive(_1); // scope 0 at $DIR/inline-specialization.rs:5:9: 5:10 +- _1 = as Foo>::bar() -> bb1; // scope 0 at $DIR/inline-specialization.rs:5:13: 5:38 - // mir::Constant - // + span: $DIR/inline-specialization.rs:5:13: 5:36 - // + literal: Const { ty: fn() -> u32 { as Foo>::bar}, val: Value() } - } - - bb1: { -+ _1 = const 123_u32; // scope 2 at $DIR/inline-specialization.rs:+10:31: +10:34 - _0 = const (); // scope 0 at $DIR/inline-specialization.rs:+0:11: +2:2 - StorageDead(_1); // scope 0 at $DIR/inline-specialization.rs:+2:1: +2:2 - return; // scope 0 at $DIR/inline-specialization.rs:+2:2: +2:2 ++ _1 = const 123_u32; // scope 2 at $DIR/inline-specialization.rs:14:31: 14:34 + _0 = const (); // scope 0 at $DIR/inline-specialization.rs:4:11: 6:2 + StorageDead(_1); // scope 0 at $DIR/inline-specialization.rs:6:1: 6:2 + return; // scope 0 at $DIR/inline-specialization.rs:6:2: 6:2 + } + + bb1 (cleanup): { -+ resume; // scope 0 at $DIR/inline-specialization.rs:+0:1: +2:2 ++ resume; // scope 0 at $DIR/inline-specialization.rs:4:1: 6:2 } } diff --git a/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir b/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir index ed95edd16ce79..1646de9289a81 100644 --- a/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir @@ -1,21 +1,21 @@ // MIR for `test` after Inline fn test(_1: &dyn X) -> u32 { - debug x => _1; // in scope 0 at $DIR/inline-trait-method.rs:+0:9: +0:10 - let mut _0: u32; // return place in scope 0 at $DIR/inline-trait-method.rs:+0:23: +0:26 - let mut _2: &dyn X; // in scope 0 at $DIR/inline-trait-method.rs:+1:5: +1:10 + debug x => _1; // in scope 0 at $DIR/inline-trait-method.rs:8:9: 8:10 + let mut _0: u32; // return place in scope 0 at $DIR/inline-trait-method.rs:8:23: 8:26 + let mut _2: &dyn X; // in scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10 bb0: { - StorageLive(_2); // scope 0 at $DIR/inline-trait-method.rs:+1:5: +1:10 - _2 = &(*_1); // scope 0 at $DIR/inline-trait-method.rs:+1:5: +1:10 - _0 = ::y(move _2) -> bb1; // scope 0 at $DIR/inline-trait-method.rs:+1:5: +1:10 + StorageLive(_2); // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10 + _2 = &(*_1); // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10 + _0 = ::y(move _2) -> bb1; // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10 // mir::Constant // + span: $DIR/inline-trait-method.rs:9:7: 9:8 // + literal: Const { ty: for<'r> fn(&'r dyn X) -> u32 {::y}, val: Value() } } bb1: { - StorageDead(_2); // scope 0 at $DIR/inline-trait-method.rs:+1:9: +1:10 - return; // scope 0 at $DIR/inline-trait-method.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/inline-trait-method.rs:9:9: 9:10 + return; // scope 0 at $DIR/inline-trait-method.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir index 36875d07ca429..eb6c09c1cd798 100644 --- a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir @@ -1,36 +1,36 @@ // MIR for `test2` after Inline fn test2(_1: &dyn X) -> bool { - debug x => _1; // in scope 0 at $DIR/inline-trait-method_2.rs:+0:10: +0:11 - let mut _0: bool; // return place in scope 0 at $DIR/inline-trait-method_2.rs:+0:24: +0:28 - let mut _2: &dyn X; // in scope 0 at $DIR/inline-trait-method_2.rs:+1:10: +1:11 - let mut _3: &dyn X; // in scope 0 at $DIR/inline-trait-method_2.rs:+1:10: +1:11 + debug x => _1; // in scope 0 at $DIR/inline-trait-method_2.rs:4:10: 4:11 + let mut _0: bool; // return place in scope 0 at $DIR/inline-trait-method_2.rs:4:24: 4:28 + let mut _2: &dyn X; // in scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 + let mut _3: &dyn X; // in scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 scope 1 (inlined test) { // at $DIR/inline-trait-method_2.rs:5:5: 5:12 - debug x => _2; // in scope 1 at $DIR/inline-trait-method_2.rs:+5:9: +5:10 - let mut _4: &dyn X; // in scope 1 at $DIR/inline-trait-method_2.rs:+6:5: +6:10 + debug x => _2; // in scope 1 at $DIR/inline-trait-method_2.rs:9:9: 9:10 + let mut _4: &dyn X; // in scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10 } bb0: { - StorageLive(_2); // scope 0 at $DIR/inline-trait-method_2.rs:+1:10: +1:11 - StorageLive(_3); // scope 0 at $DIR/inline-trait-method_2.rs:+1:10: +1:11 - _3 = &(*_1); // scope 0 at $DIR/inline-trait-method_2.rs:+1:10: +1:11 - _2 = move _3 as &dyn X (Pointer(Unsize)); // scope 0 at $DIR/inline-trait-method_2.rs:+1:10: +1:11 - StorageDead(_3); // scope 0 at $DIR/inline-trait-method_2.rs:+1:10: +1:11 - StorageLive(_4); // scope 1 at $DIR/inline-trait-method_2.rs:+6:5: +6:10 - _4 = _2; // scope 1 at $DIR/inline-trait-method_2.rs:+6:5: +6:10 - _0 = ::y(move _4) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:+6:5: +6:10 + StorageLive(_2); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 + StorageLive(_3); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 + _3 = &(*_1); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 + _2 = move _3 as &dyn X (Pointer(Unsize)); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 + StorageDead(_3); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 + StorageLive(_4); // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10 + _4 = _2; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10 + _0 = ::y(move _4) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10 // mir::Constant // + span: $DIR/inline-trait-method_2.rs:10:7: 10:8 // + literal: Const { ty: for<'r> fn(&'r dyn X) -> bool {::y}, val: Value() } } bb1: { - StorageDead(_4); // scope 1 at $DIR/inline-trait-method_2.rs:+6:9: +6:10 - StorageDead(_2); // scope 0 at $DIR/inline-trait-method_2.rs:+1:11: +1:12 - return; // scope 0 at $DIR/inline-trait-method_2.rs:+2:2: +2:2 + StorageDead(_4); // scope 1 at $DIR/inline-trait-method_2.rs:10:9: 10:10 + StorageDead(_2); // scope 0 at $DIR/inline-trait-method_2.rs:5:11: 5:12 + return; // scope 0 at $DIR/inline-trait-method_2.rs:6:2: 6:2 } bb2 (cleanup): { - resume; // scope 0 at $DIR/inline-trait-method_2.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/inline-trait-method_2.rs:4:1: 6:2 } } diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir index e715ff83598f3..56a23cde0c7e1 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir @@ -1,34 +1,34 @@ // MIR for `a` after Inline fn a(_1: &mut [T]) -> &mut [T] { - debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:13: +0:14 - let mut _0: &mut [T]; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:29: +0:37 - let mut _2: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - let mut _3: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - let mut _4: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 + debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:2:13: 2:14 + let mut _0: &mut [T]; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:2:29: 2:37 + let mut _2: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 + let mut _3: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 + let mut _4: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 scope 1 (inlined <[T] as AsMut<[T]>>::as_mut) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 debug self => _4; // in scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL let mut _5: &mut [T]; // in scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 + StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 + StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 + StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 + _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 StorageLive(_5); // scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL _5 = &mut (*_4); // scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL _3 = &mut (*_5); // scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL StorageDead(_5); // scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - _2 = &mut (*_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - StorageDead(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:14: +1:15 - _0 = &mut (*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2 - StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2 - return; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2 + _2 = &mut (*_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 + StorageDead(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:14: 3:15 + _0 = &mut (*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 + StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:4:1: 4:2 + StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:4:1: 4:2 + return; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:4:2: 4:2 } bb1 (cleanup): { - resume; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:2:1: 4:2 } } diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir index 8bacced23bd6b..b45dfb17bfe82 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir @@ -1,11 +1,11 @@ // MIR for `b` after Inline fn b(_1: &mut Box) -> &mut T { - debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:13: +0:14 - let mut _0: &mut T; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:32: +0:38 - let mut _2: &mut T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - let mut _3: &mut T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - let mut _4: &mut std::boxed::Box; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 + debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:7:13: 7:14 + let mut _0: &mut T; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:7:32: 7:38 + let mut _2: &mut T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 + let mut _3: &mut T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 + let mut _4: &mut std::boxed::Box; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 scope 1 (inlined as AsMut>::as_mut) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 debug self => _4; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL let mut _5: &mut T; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL @@ -15,10 +15,10 @@ fn b(_1: &mut Box) -> &mut T { } bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 + StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 + StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 + StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 + _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 StorageLive(_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageLive(_6); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageLive(_7); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL @@ -32,15 +32,15 @@ fn b(_1: &mut Box) -> &mut T { _3 = &mut (*_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageDead(_6); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageDead(_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - _2 = &mut (*_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - StorageDead(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:14: +1:15 - _0 = &mut (*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2 - StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2 - return; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2 + _2 = &mut (*_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 + StorageDead(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:14: 8:15 + _0 = &mut (*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 + StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:9:1: 9:2 + StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:9:1: 9:2 + return; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:9:2: 9:2 } bb1 (cleanup): { - resume; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:7:1: 9:2 } } diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir index 233a1788288fa..326b2ad71c0e5 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir @@ -1,26 +1,26 @@ // MIR for `c` after Inline fn c(_1: &[T]) -> &[T] { - debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:13: +0:14 - let mut _0: &[T]; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:25: +0:29 - let _2: &[T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - let mut _3: &[T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 + debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:12:13: 12:14 + let mut _0: &[T]; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:12:25: 12:29 + let _2: &[T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 + let mut _3: &[T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 scope 1 (inlined <[T] as AsRef<[T]>>::as_ref) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 debug self => _3; // in scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 + StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 + StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 + _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 _2 = _3; // scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - _0 = &(*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:14: +1:15 - StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2 - return; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2 + _0 = &(*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 + StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:14: 13:15 + StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:14:1: 14:2 + return; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:14:2: 14:2 } bb1 (cleanup): { - resume; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:12:1: 14:2 } } diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir index 5b4aeee9e2b5c..4e8547419ae1f 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir @@ -1,10 +1,10 @@ // MIR for `d` after Inline fn d(_1: &Box) -> &T { - debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:13: +0:14 - let mut _0: &T; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:28: +0:30 - let _2: &T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - let mut _3: &std::boxed::Box; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 + debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:17:13: 17:14 + let mut _0: &T; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:17:28: 17:30 + let _2: &T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 + let mut _3: &std::boxed::Box; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 scope 1 (inlined as AsRef>::as_ref) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 debug self => _3; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL let mut _4: std::boxed::Box; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL @@ -12,9 +12,9 @@ fn d(_1: &Box) -> &T { } bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 + StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 + StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 + _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 StorageLive(_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL _4 = deref_copy (*_3); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageLive(_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL @@ -22,13 +22,13 @@ fn d(_1: &Box) -> &T { _2 = &(*_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageDead(_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageDead(_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - _0 = &(*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15 - StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:14: +1:15 - StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2 - return; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2 + _0 = &(*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 + StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:14: 18:15 + StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:19:1: 19:2 + return; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:19:2: 19:2 } bb1 (cleanup): { - resume; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:17:1: 19:2 } } diff --git a/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir b/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir index 769ff89fdb7ad..242073574f2b2 100644 --- a/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir @@ -1,46 +1,46 @@ // MIR for `main` after Inline fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+0:11: +0:11 - let _1: [closure@$DIR/issue-76997-inline-scopes-parenting.rs:5:13: 5:16]; // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:9: +1:10 - let mut _2: &[closure@$DIR/issue-76997-inline-scopes-parenting.rs:5:13: 5:16]; // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:6 - let mut _3: ((),); // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:10 - let mut _4: (); // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:7: +2:9 - let mut _5: (); // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:10 + let mut _0: (); // return place in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:4:11: 4:11 + let _1: [closure@$DIR/issue-76997-inline-scopes-parenting.rs:5:13: 5:16]; // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:5:9: 5:10 + let mut _2: &[closure@$DIR/issue-76997-inline-scopes-parenting.rs:5:13: 5:16]; // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:6 + let mut _3: ((),); // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 + let mut _4: (); // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:6:7: 6:9 + let mut _5: (); // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 scope 1 { - debug f => _1; // in scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:9: +1:10 + debug f => _1; // in scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:5:9: 5:10 scope 2 (inlined main::{closure#0}) { // at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 - debug x => _5; // in scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:14: +1:15 - let _6: (); // in scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:23: +1:24 + debug x => _5; // in scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:5:14: 5:15 + let _6: (); // in scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:5:23: 5:24 scope 3 { - debug y => _6; // in scope 3 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:23: +1:24 + debug y => _6; // in scope 3 at $DIR/issue-76997-inline-scopes-parenting.rs:5:23: 5:24 } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:9: +1:10 - Deinit(_1); // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:13: +1:33 - StorageLive(_2); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:6 - _2 = &_1; // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:6 - StorageLive(_3); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:10 - StorageLive(_4); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:7: +2:9 - Deinit(_4); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:7: +2:9 - Deinit(_3); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:10 - (_3.0: ()) = move _4; // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:10 - StorageLive(_5); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:10 - _5 = move (_3.0: ()); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:10 - StorageLive(_6); // scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:23: +1:24 - StorageDead(_6); // scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:32: +1:33 - StorageDead(_5); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:10 - StorageDead(_4); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:9: +2:10 - StorageDead(_3); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:9: +2:10 - StorageDead(_2); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:9: +2:10 - StorageDead(_1); // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+3:1: +3:2 - return; // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+3:2: +3:2 + StorageLive(_1); // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:5:9: 5:10 + Deinit(_1); // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:5:13: 5:33 + StorageLive(_2); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:6 + _2 = &_1; // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:6 + StorageLive(_3); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 + StorageLive(_4); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:7: 6:9 + Deinit(_4); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:7: 6:9 + Deinit(_3); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 + (_3.0: ()) = move _4; // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 + StorageLive(_5); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 + _5 = move (_3.0: ()); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 + StorageLive(_6); // scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:5:23: 5:24 + StorageDead(_6); // scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:5:32: 5:33 + StorageDead(_5); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 + StorageDead(_4); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:9: 6:10 + StorageDead(_3); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:9: 6:10 + StorageDead(_2); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:9: 6:10 + StorageDead(_1); // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:7:1: 7:2 + return; // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:7:2: 7:2 } bb1 (cleanup): { - resume; // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+0:1: +3:2 + resume; // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:4:1: 7:2 } } diff --git a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff index c16dfdf395ecc..f91d352622626 100644 --- a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff +++ b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff @@ -2,31 +2,31 @@ + // MIR for `bar` after Inline fn bar(_1: P) -> () { - debug _baz => _1; // in scope 0 at $DIR/issue-78442.rs:+2:5: +2:9 - let mut _0: (); // return place in scope 0 at $DIR/issue-78442.rs:+3:3: +3:3 - let _2: (); // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 - let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 - let _4: fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 - let mut _5: (); // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 + debug _baz => _1; // in scope 0 at $DIR/issue-78442.rs:9:5: 9:9 + let mut _0: (); // return place in scope 0 at $DIR/issue-78442.rs:10:3: 10:3 + let _2: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17 + let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + let _4: fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + let mut _5: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17 + scope 1 (inlined >::call - shim(fn() {foo})) { // at $DIR/issue-78442.rs:11:5: 11:17 + } bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 - StorageLive(_3); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 - StorageLive(_4); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 -- _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 -+ _4 = hide_foo() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 + StorageLive(_2); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 + StorageLive(_3); // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + StorageLive(_4); // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 +- _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 ++ _4 = hide_foo() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 // mir::Constant // + span: $DIR/issue-78442.rs:11:5: 11:13 // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value() } } bb1: { - _3 = &_4; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 - StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 - Deinit(_5); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 -- _2 = >::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 + _3 = &_4; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 + Deinit(_5); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 +- _2 = >::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 - // mir::Constant - // + span: $DIR/issue-78442.rs:11:5: 11:15 - // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> >::Output {>::call}, val: Value() } @@ -34,35 +34,35 @@ } bb2: { -- StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17 -- StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17 -- StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 -- StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 -- _0 = const (); // scope 0 at $DIR/issue-78442.rs:+3:3: +5:2 -- drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 -+ return; // scope 0 at $DIR/issue-78442.rs:+5:2: +5:2 +- StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17 +- StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17 +- StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18 +- StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18 +- _0 = const (); // scope 0 at $DIR/issue-78442.rs:10:3: 12:2 +- drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2 ++ return; // scope 0 at $DIR/issue-78442.rs:12:2: 12:2 } - bb3: { -- return; // scope 0 at $DIR/issue-78442.rs:+5:2: +5:2 +- return; // scope 0 at $DIR/issue-78442.rs:12:2: 12:2 + bb3 (cleanup): { -+ drop(_1) -> bb4; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 ++ drop(_1) -> bb4; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2 } bb4 (cleanup): { -- drop(_1) -> bb5; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 -+ resume; // scope 0 at $DIR/issue-78442.rs:+0:1: +5:2 +- drop(_1) -> bb5; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2 ++ resume; // scope 0 at $DIR/issue-78442.rs:7:1: 12:2 } - bb5 (cleanup): { -- resume; // scope 0 at $DIR/issue-78442.rs:+0:1: +5:2 +- resume; // scope 0 at $DIR/issue-78442.rs:7:1: 12:2 + bb5: { -+ StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17 -+ StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17 -+ StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 -+ StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 -+ _0 = const (); // scope 0 at $DIR/issue-78442.rs:+3:3: +5:2 -+ drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 ++ StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17 ++ StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17 ++ StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18 ++ StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18 ++ _0 = const (); // scope 0 at $DIR/issue-78442.rs:10:3: 12:2 ++ drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2 } } diff --git a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff index 0faa522cbaa9c..4446280e72004 100644 --- a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff +++ b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff @@ -2,31 +2,31 @@ + // MIR for `bar` after RevealAll fn bar(_1: P) -> () { - debug _baz => _1; // in scope 0 at $DIR/issue-78442.rs:+2:5: +2:9 - let mut _0: (); // return place in scope 0 at $DIR/issue-78442.rs:+3:3: +3:3 - let _2: (); // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 -- let mut _3: &impl Fn(); // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 -- let _4: impl Fn(); // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 -+ let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 -+ let _4: fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 - let mut _5: (); // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 + debug _baz => _1; // in scope 0 at $DIR/issue-78442.rs:9:5: 9:9 + let mut _0: (); // return place in scope 0 at $DIR/issue-78442.rs:10:3: 10:3 + let _2: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17 +- let mut _3: &impl Fn(); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15 +- let _4: impl Fn(); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15 ++ let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15 ++ let _4: fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + let mut _5: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17 bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 - StorageLive(_3); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 - StorageLive(_4); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 - _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 + StorageLive(_2); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 + StorageLive(_3); // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + StorageLive(_4); // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 // mir::Constant // + span: $DIR/issue-78442.rs:11:5: 11:13 // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value() } } bb1: { - _3 = &_4; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 - StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 - Deinit(_5); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 -- _2 = >::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 -+ _2 = >::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 + _3 = &_4; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 + Deinit(_5); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 +- _2 = >::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 ++ _2 = >::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 // mir::Constant // + span: $DIR/issue-78442.rs:11:5: 11:15 - // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> >::Output {>::call}, val: Value() } @@ -34,24 +34,24 @@ } bb2: { - StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17 - StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17 - StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 - StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 - _0 = const (); // scope 0 at $DIR/issue-78442.rs:+3:3: +5:2 - drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 + StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17 + StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17 + StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18 + StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18 + _0 = const (); // scope 0 at $DIR/issue-78442.rs:10:3: 12:2 + drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2 } bb3: { - return; // scope 0 at $DIR/issue-78442.rs:+5:2: +5:2 + return; // scope 0 at $DIR/issue-78442.rs:12:2: 12:2 } bb4 (cleanup): { - drop(_1) -> bb5; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 + drop(_1) -> bb5; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2 } bb5 (cleanup): { - resume; // scope 0 at $DIR/issue-78442.rs:+0:1: +5:2 + resume; // scope 0 at $DIR/issue-78442.rs:7:1: 12:2 } } diff --git a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff index b78ef36eadd98..fef696df770b6 100644 --- a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff @@ -2,12 +2,12 @@ + // MIR for `bar` after InstrumentCoverage fn bar() -> bool { - let mut _0: bool; // return place in scope 0 at /the/src/instrument_coverage.rs:+0:13: +0:17 + let mut _0: bool; // return place in scope 0 at /the/src/instrument_coverage.rs:19:13: 19:17 bb0: { -+ Coverage::Counter(1) for /the/src/instrument_coverage.rs:19:1 - 21:2; // scope 0 at /the/src/instrument_coverage.rs:+2:2: +2:2 - _0 = const true; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +1:9 - return; // scope 0 at /the/src/instrument_coverage.rs:+2:2: +2:2 ++ Coverage::Counter(1) for /the/src/instrument_coverage.rs:19:1 - 21:2; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 + _0 = const true; // scope 0 at /the/src/instrument_coverage.rs:20:5: 20:9 + return; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 } } diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff index 0490c0df2e605..9384ce52cc825 100644 --- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff @@ -2,50 +2,50 @@ + // MIR for `main` after InstrumentCoverage fn main() -> () { - let mut _0: (); // return place in scope 0 at /the/src/instrument_coverage.rs:+0:11: +0:11 - let mut _1: (); // in scope 0 at /the/src/instrument_coverage.rs:+0:1: +6:2 - let mut _2: bool; // in scope 0 at /the/src/instrument_coverage.rs:+2:12: +2:17 - let mut _3: !; // in scope 0 at /the/src/instrument_coverage.rs:+2:18: +4:10 + let mut _0: (); // return place in scope 0 at /the/src/instrument_coverage.rs:10:11: 10:11 + let mut _1: (); // in scope 0 at /the/src/instrument_coverage.rs:10:1: 16:2 + let mut _2: bool; // in scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 + let mut _3: !; // in scope 0 at /the/src/instrument_coverage.rs:12:18: 14:10 bb0: { -+ Coverage::Counter(1) for /the/src/instrument_coverage.rs:10:1 - 10:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6 - goto -> bb1; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6 ++ Coverage::Counter(1) for /the/src/instrument_coverage.rs:10:1 - 10:11; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 + goto -> bb1; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 } bb1: { -+ Coverage::Expression(4294967295) = 1 + 2 for /the/src/instrument_coverage.rs:11:5 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6 - falseUnwind -> [real: bb2, cleanup: bb6]; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6 ++ Coverage::Expression(4294967295) = 1 + 2 for /the/src/instrument_coverage.rs:11:5 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 + falseUnwind -> [real: bb2, cleanup: bb6]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 } bb2: { - StorageLive(_2); // scope 0 at /the/src/instrument_coverage.rs:+2:12: +2:17 - _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at /the/src/instrument_coverage.rs:+2:12: +2:17 + StorageLive(_2); // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 + _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 // mir::Constant // + span: /the/src/instrument_coverage.rs:12:12: 12:15 // + literal: Const { ty: fn() -> bool {bar}, val: Value() } } bb3: { - switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at /the/src/instrument_coverage.rs:+2:12: +2:17 + switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 } bb4: { -+ Coverage::Expression(4294967293) = 4294967294 + 0 for /the/src/instrument_coverage.rs:16:1 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2 -+ Coverage::Expression(4294967294) = 4294967295 - 2 for /the/src/instrument_coverage.rs:13:13 - 13:18; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2 - _0 = const (); // scope 0 at /the/src/instrument_coverage.rs:+3:13: +3:18 - StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:+4:9: +4:10 - return; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2 ++ Coverage::Expression(4294967293) = 4294967294 + 0 for /the/src/instrument_coverage.rs:16:1 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2 ++ Coverage::Expression(4294967294) = 4294967295 - 2 for /the/src/instrument_coverage.rs:13:13 - 13:18; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2 + _0 = const (); // scope 0 at /the/src/instrument_coverage.rs:13:13: 13:18 + StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:14:9: 14:10 + return; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2 } bb5: { -+ Coverage::Counter(2) for /the/src/instrument_coverage.rs:14:10 - 14:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6 - _1 = const (); // scope 0 at /the/src/instrument_coverage.rs:+4:10: +4:10 - StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:+4:9: +4:10 - goto -> bb1; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6 ++ Coverage::Counter(2) for /the/src/instrument_coverage.rs:14:10 - 14:11; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 + _1 = const (); // scope 0 at /the/src/instrument_coverage.rs:14:10: 14:10 + StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:14:9: 14:10 + goto -> bb1; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 } bb6 (cleanup): { - resume; // scope 0 at /the/src/instrument_coverage.rs:+0:1: +6:2 + resume; // scope 0 at /the/src/instrument_coverage.rs:10:1: 16:2 } } diff --git a/src/test/mir-opt/issue-99325.rs b/src/test/mir-opt/issue-99325.rs deleted file mode 100644 index b79946ea8b56c..0000000000000 --- a/src/test/mir-opt/issue-99325.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![feature(adt_const_params)] -#![allow(incomplete_features)] - -pub fn function_with_bytes() -> &'static [u8] { - BYTES -} - -// EMIT_MIR issue_99325.main.mir_map.0.mir -pub fn main() { - assert_eq!(function_with_bytes::(), &[0x41, 0x41, 0x41, 0x41]); - assert_eq!(function_with_bytes::<{ &[0x41, 0x41, 0x41, 0x41] }>(), b"AAAA"); -} diff --git a/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir index b13987f7360e6..a2471e4308b01 100644 --- a/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir @@ -1,52 +1,52 @@ // MIR for `main` after SimplifyCfg-initial fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-38669.rs:+0:11: +0:11 - let mut _1: bool; // in scope 0 at $DIR/issue-38669.rs:+1:9: +1:25 - let mut _2: (); // in scope 0 at $DIR/issue-38669.rs:+0:1: +8:2 - let _3: (); // in scope 0 at $DIR/issue-38669.rs:+3:9: +5:10 - let mut _4: bool; // in scope 0 at $DIR/issue-38669.rs:+3:12: +3:24 - let mut _5: !; // in scope 0 at $DIR/issue-38669.rs:+3:25: +5:10 + let mut _0: (); // return place in scope 0 at $DIR/issue-38669.rs:4:11: 4:11 + let mut _1: bool; // in scope 0 at $DIR/issue-38669.rs:5:9: 5:25 + let mut _2: (); // in scope 0 at $DIR/issue-38669.rs:4:1: 12:2 + let _3: (); // in scope 0 at $DIR/issue-38669.rs:7:9: 9:10 + let mut _4: bool; // in scope 0 at $DIR/issue-38669.rs:7:12: 7:24 + let mut _5: !; // in scope 0 at $DIR/issue-38669.rs:7:25: 9:10 scope 1 { - debug should_break => _1; // in scope 1 at $DIR/issue-38669.rs:+1:9: +1:25 + debug should_break => _1; // in scope 1 at $DIR/issue-38669.rs:5:9: 5:25 } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-38669.rs:+1:9: +1:25 - _1 = const false; // scope 0 at $DIR/issue-38669.rs:+1:28: +1:33 - FakeRead(ForLet(None), _1); // scope 0 at $DIR/issue-38669.rs:+1:9: +1:25 - goto -> bb1; // scope 1 at $DIR/issue-38669.rs:+2:5: +7:6 + StorageLive(_1); // scope 0 at $DIR/issue-38669.rs:5:9: 5:25 + _1 = const false; // scope 0 at $DIR/issue-38669.rs:5:28: 5:33 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/issue-38669.rs:5:9: 5:25 + goto -> bb1; // scope 1 at $DIR/issue-38669.rs:6:5: 11:6 } bb1: { - falseUnwind -> [real: bb2, cleanup: bb5]; // scope 1 at $DIR/issue-38669.rs:+2:5: +7:6 + falseUnwind -> [real: bb2, cleanup: bb5]; // scope 1 at $DIR/issue-38669.rs:6:5: 11:6 } bb2: { - StorageLive(_3); // scope 1 at $DIR/issue-38669.rs:+3:9: +5:10 - StorageLive(_4); // scope 1 at $DIR/issue-38669.rs:+3:12: +3:24 - _4 = _1; // scope 1 at $DIR/issue-38669.rs:+3:12: +3:24 - switchInt(move _4) -> [false: bb4, otherwise: bb3]; // scope 1 at $DIR/issue-38669.rs:+3:12: +3:24 + StorageLive(_3); // scope 1 at $DIR/issue-38669.rs:7:9: 9:10 + StorageLive(_4); // scope 1 at $DIR/issue-38669.rs:7:12: 7:24 + _4 = _1; // scope 1 at $DIR/issue-38669.rs:7:12: 7:24 + switchInt(move _4) -> [false: bb4, otherwise: bb3]; // scope 1 at $DIR/issue-38669.rs:7:12: 7:24 } bb3: { - _0 = const (); // scope 1 at $DIR/issue-38669.rs:+4:13: +4:18 - StorageDead(_4); // scope 1 at $DIR/issue-38669.rs:+5:9: +5:10 - StorageDead(_3); // scope 1 at $DIR/issue-38669.rs:+5:9: +5:10 - StorageDead(_1); // scope 0 at $DIR/issue-38669.rs:+8:1: +8:2 - return; // scope 0 at $DIR/issue-38669.rs:+8:2: +8:2 + _0 = const (); // scope 1 at $DIR/issue-38669.rs:8:13: 8:18 + StorageDead(_4); // scope 1 at $DIR/issue-38669.rs:9:9: 9:10 + StorageDead(_3); // scope 1 at $DIR/issue-38669.rs:9:9: 9:10 + StorageDead(_1); // scope 0 at $DIR/issue-38669.rs:12:1: 12:2 + return; // scope 0 at $DIR/issue-38669.rs:12:2: 12:2 } bb4: { - _3 = const (); // scope 1 at $DIR/issue-38669.rs:+5:10: +5:10 - StorageDead(_4); // scope 1 at $DIR/issue-38669.rs:+5:9: +5:10 - StorageDead(_3); // scope 1 at $DIR/issue-38669.rs:+5:9: +5:10 - _1 = const true; // scope 1 at $DIR/issue-38669.rs:+6:9: +6:28 - _2 = const (); // scope 1 at $DIR/issue-38669.rs:+2:10: +7:6 - goto -> bb1; // scope 1 at $DIR/issue-38669.rs:+2:5: +7:6 + _3 = const (); // scope 1 at $DIR/issue-38669.rs:9:10: 9:10 + StorageDead(_4); // scope 1 at $DIR/issue-38669.rs:9:9: 9:10 + StorageDead(_3); // scope 1 at $DIR/issue-38669.rs:9:9: 9:10 + _1 = const true; // scope 1 at $DIR/issue-38669.rs:10:9: 10:28 + _2 = const (); // scope 1 at $DIR/issue-38669.rs:6:10: 11:6 + goto -> bb1; // scope 1 at $DIR/issue-38669.rs:6:5: 11:6 } bb5 (cleanup): { - resume; // scope 0 at $DIR/issue-38669.rs:+0:1: +8:2 + resume; // scope 0 at $DIR/issue-38669.rs:4:1: 12:2 } } diff --git a/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir index 1d7cb91d6a7e8..19110894dc720 100644 --- a/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir @@ -1,70 +1,70 @@ // MIR for `main` after ElaborateDrops fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-41110.rs:+0:11: +0:11 - let _1: (); // in scope 0 at $DIR/issue-41110.rs:+1:9: +1:10 - let mut _2: S; // in scope 0 at $DIR/issue-41110.rs:+1:13: +1:14 - let mut _3: S; // in scope 0 at $DIR/issue-41110.rs:+1:21: +1:27 - let mut _4: S; // in scope 0 at $DIR/issue-41110.rs:+1:21: +1:22 - let mut _5: bool; // in scope 0 at $DIR/issue-41110.rs:+1:27: +1:28 + let mut _0: (); // return place in scope 0 at $DIR/issue-41110.rs:7:11: 7:11 + let _1: (); // in scope 0 at $DIR/issue-41110.rs:8:9: 8:10 + let mut _2: S; // in scope 0 at $DIR/issue-41110.rs:8:13: 8:14 + let mut _3: S; // in scope 0 at $DIR/issue-41110.rs:8:21: 8:27 + let mut _4: S; // in scope 0 at $DIR/issue-41110.rs:8:21: 8:22 + let mut _5: bool; // in scope 0 at $DIR/issue-41110.rs:8:27: 8:28 scope 1 { - debug x => _1; // in scope 1 at $DIR/issue-41110.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/issue-41110.rs:8:9: 8:10 } bb0: { - _5 = const false; // scope 0 at $DIR/issue-41110.rs:+1:9: +1:10 - StorageLive(_1); // scope 0 at $DIR/issue-41110.rs:+1:9: +1:10 - StorageLive(_2); // scope 0 at $DIR/issue-41110.rs:+1:13: +1:14 - _5 = const true; // scope 0 at $DIR/issue-41110.rs:+1:13: +1:14 - _2 = S; // scope 0 at $DIR/issue-41110.rs:+1:13: +1:14 - StorageLive(_3); // scope 0 at $DIR/issue-41110.rs:+1:21: +1:27 - StorageLive(_4); // scope 0 at $DIR/issue-41110.rs:+1:21: +1:22 - _4 = S; // scope 0 at $DIR/issue-41110.rs:+1:21: +1:22 - _3 = S::id(move _4) -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-41110.rs:+1:21: +1:27 + _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:9: 8:10 + StorageLive(_1); // scope 0 at $DIR/issue-41110.rs:8:9: 8:10 + StorageLive(_2); // scope 0 at $DIR/issue-41110.rs:8:13: 8:14 + _5 = const true; // scope 0 at $DIR/issue-41110.rs:8:13: 8:14 + _2 = S; // scope 0 at $DIR/issue-41110.rs:8:13: 8:14 + StorageLive(_3); // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 + StorageLive(_4); // scope 0 at $DIR/issue-41110.rs:8:21: 8:22 + _4 = S; // scope 0 at $DIR/issue-41110.rs:8:21: 8:22 + _3 = S::id(move _4) -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 // mir::Constant // + span: $DIR/issue-41110.rs:8:23: 8:25 // + literal: Const { ty: fn(S) -> S {S::id}, val: Value() } } bb1: { - StorageDead(_4); // scope 0 at $DIR/issue-41110.rs:+1:26: +1:27 - _5 = const false; // scope 0 at $DIR/issue-41110.rs:+1:13: +1:28 - _1 = S::other(move _2, move _3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-41110.rs:+1:13: +1:28 + StorageDead(_4); // scope 0 at $DIR/issue-41110.rs:8:26: 8:27 + _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 + _1 = S::other(move _2, move _3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 // mir::Constant // + span: $DIR/issue-41110.rs:8:15: 8:20 // + literal: Const { ty: fn(S, S) {S::other}, val: Value() } } bb2: { - StorageDead(_3); // scope 0 at $DIR/issue-41110.rs:+1:27: +1:28 - _5 = const false; // scope 0 at $DIR/issue-41110.rs:+1:27: +1:28 - StorageDead(_2); // scope 0 at $DIR/issue-41110.rs:+1:27: +1:28 - _0 = const (); // scope 0 at $DIR/issue-41110.rs:+0:11: +2:2 - StorageDead(_1); // scope 0 at $DIR/issue-41110.rs:+2:1: +2:2 - return; // scope 0 at $DIR/issue-41110.rs:+2:2: +2:2 + StorageDead(_3); // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 + _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 + StorageDead(_2); // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 + _0 = const (); // scope 0 at $DIR/issue-41110.rs:7:11: 9:2 + StorageDead(_1); // scope 0 at $DIR/issue-41110.rs:9:1: 9:2 + return; // scope 0 at $DIR/issue-41110.rs:9:2: 9:2 } bb3 (cleanup): { - goto -> bb5; // scope 0 at $DIR/issue-41110.rs:+1:27: +1:28 + goto -> bb5; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 } bb4 (cleanup): { - goto -> bb5; // scope 0 at $DIR/issue-41110.rs:+1:26: +1:27 + goto -> bb5; // scope 0 at $DIR/issue-41110.rs:8:26: 8:27 } bb5 (cleanup): { - goto -> bb8; // scope 0 at $DIR/issue-41110.rs:+1:27: +1:28 + goto -> bb8; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 } bb6 (cleanup): { - resume; // scope 0 at $DIR/issue-41110.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/issue-41110.rs:7:1: 9:2 } bb7 (cleanup): { - drop(_2) -> bb6; // scope 0 at $DIR/issue-41110.rs:+1:27: +1:28 + drop(_2) -> bb6; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 } bb8 (cleanup): { - switchInt(_5) -> [false: bb6, otherwise: bb7]; // scope 0 at $DIR/issue-41110.rs:+1:27: +1:28 + switchInt(_5) -> [false: bb6, otherwise: bb7]; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 } } diff --git a/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir index b0e3496b2c8eb..1901ea1747ed2 100644 --- a/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir @@ -1,101 +1,101 @@ // MIR for `test` after ElaborateDrops fn test() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-41110.rs:+0:15: +0:15 - let _1: S; // in scope 0 at $DIR/issue-41110.rs:+1:9: +1:10 - let _3: (); // in scope 0 at $DIR/issue-41110.rs:+3:5: +3:12 - let mut _4: S; // in scope 0 at $DIR/issue-41110.rs:+3:10: +3:11 - let mut _5: S; // in scope 0 at $DIR/issue-41110.rs:+4:9: +4:10 - let mut _6: bool; // in scope 0 at $DIR/issue-41110.rs:+5:1: +5:2 + let mut _0: (); // return place in scope 0 at $DIR/issue-41110.rs:14:15: 14:15 + let _1: S; // in scope 0 at $DIR/issue-41110.rs:15:9: 15:10 + let _3: (); // in scope 0 at $DIR/issue-41110.rs:17:5: 17:12 + let mut _4: S; // in scope 0 at $DIR/issue-41110.rs:17:10: 17:11 + let mut _5: S; // in scope 0 at $DIR/issue-41110.rs:18:9: 18:10 + let mut _6: bool; // in scope 0 at $DIR/issue-41110.rs:19:1: 19:2 scope 1 { - debug u => _1; // in scope 1 at $DIR/issue-41110.rs:+1:9: +1:10 - let mut _2: S; // in scope 1 at $DIR/issue-41110.rs:+2:9: +2:14 + debug u => _1; // in scope 1 at $DIR/issue-41110.rs:15:9: 15:10 + let mut _2: S; // in scope 1 at $DIR/issue-41110.rs:16:9: 16:14 scope 2 { - debug v => _2; // in scope 2 at $DIR/issue-41110.rs:+2:9: +2:14 + debug v => _2; // in scope 2 at $DIR/issue-41110.rs:16:9: 16:14 } } bb0: { - _6 = const false; // scope 0 at $DIR/issue-41110.rs:+1:9: +1:10 - StorageLive(_1); // scope 0 at $DIR/issue-41110.rs:+1:9: +1:10 - _6 = const true; // scope 0 at $DIR/issue-41110.rs:+1:13: +1:14 - _1 = S; // scope 0 at $DIR/issue-41110.rs:+1:13: +1:14 - StorageLive(_2); // scope 1 at $DIR/issue-41110.rs:+2:9: +2:14 - _2 = S; // scope 1 at $DIR/issue-41110.rs:+2:17: +2:18 - StorageLive(_3); // scope 2 at $DIR/issue-41110.rs:+3:5: +3:12 - StorageLive(_4); // scope 2 at $DIR/issue-41110.rs:+3:10: +3:11 - _4 = move _2; // scope 2 at $DIR/issue-41110.rs:+3:10: +3:11 - _3 = std::mem::drop::(move _4) -> [return: bb1, unwind: bb7]; // scope 2 at $DIR/issue-41110.rs:+3:5: +3:12 + _6 = const false; // scope 0 at $DIR/issue-41110.rs:15:9: 15:10 + StorageLive(_1); // scope 0 at $DIR/issue-41110.rs:15:9: 15:10 + _6 = const true; // scope 0 at $DIR/issue-41110.rs:15:13: 15:14 + _1 = S; // scope 0 at $DIR/issue-41110.rs:15:13: 15:14 + StorageLive(_2); // scope 1 at $DIR/issue-41110.rs:16:9: 16:14 + _2 = S; // scope 1 at $DIR/issue-41110.rs:16:17: 16:18 + StorageLive(_3); // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 + StorageLive(_4); // scope 2 at $DIR/issue-41110.rs:17:10: 17:11 + _4 = move _2; // scope 2 at $DIR/issue-41110.rs:17:10: 17:11 + _3 = std::mem::drop::(move _4) -> [return: bb1, unwind: bb7]; // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 // mir::Constant // + span: $DIR/issue-41110.rs:17:5: 17:9 // + literal: Const { ty: fn(S) {std::mem::drop::}, val: Value() } } bb1: { - StorageDead(_4); // scope 2 at $DIR/issue-41110.rs:+3:11: +3:12 - StorageDead(_3); // scope 2 at $DIR/issue-41110.rs:+3:12: +3:13 - StorageLive(_5); // scope 2 at $DIR/issue-41110.rs:+4:9: +4:10 - _6 = const false; // scope 2 at $DIR/issue-41110.rs:+4:9: +4:10 - _5 = move _1; // scope 2 at $DIR/issue-41110.rs:+4:9: +4:10 - goto -> bb12; // scope 2 at $DIR/issue-41110.rs:+4:5: +4:6 + StorageDead(_4); // scope 2 at $DIR/issue-41110.rs:17:11: 17:12 + StorageDead(_3); // scope 2 at $DIR/issue-41110.rs:17:12: 17:13 + StorageLive(_5); // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 + _6 = const false; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 + _5 = move _1; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 + goto -> bb12; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 } bb2: { - goto -> bb3; // scope 2 at $DIR/issue-41110.rs:+4:9: +4:10 + goto -> bb3; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 } bb3: { - StorageDead(_5); // scope 2 at $DIR/issue-41110.rs:+4:9: +4:10 - _0 = const (); // scope 0 at $DIR/issue-41110.rs:+0:15: +5:2 - drop(_2) -> [return: bb4, unwind: bb9]; // scope 1 at $DIR/issue-41110.rs:+5:1: +5:2 + StorageDead(_5); // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 + _0 = const (); // scope 0 at $DIR/issue-41110.rs:14:15: 19:2 + drop(_2) -> [return: bb4, unwind: bb9]; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 } bb4: { - StorageDead(_2); // scope 1 at $DIR/issue-41110.rs:+5:1: +5:2 - goto -> bb5; // scope 0 at $DIR/issue-41110.rs:+5:1: +5:2 + StorageDead(_2); // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 + goto -> bb5; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } bb5: { - _6 = const false; // scope 0 at $DIR/issue-41110.rs:+5:1: +5:2 - StorageDead(_1); // scope 0 at $DIR/issue-41110.rs:+5:1: +5:2 - return; // scope 0 at $DIR/issue-41110.rs:+5:2: +5:2 + _6 = const false; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + StorageDead(_1); // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + return; // scope 0 at $DIR/issue-41110.rs:19:2: 19:2 } bb6 (cleanup): { - goto -> bb8; // scope 2 at $DIR/issue-41110.rs:+4:9: +4:10 + goto -> bb8; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 } bb7 (cleanup): { - goto -> bb8; // scope 2 at $DIR/issue-41110.rs:+3:11: +3:12 + goto -> bb8; // scope 2 at $DIR/issue-41110.rs:17:11: 17:12 } bb8 (cleanup): { - goto -> bb9; // scope 1 at $DIR/issue-41110.rs:+5:1: +5:2 + goto -> bb9; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 } bb9 (cleanup): { - goto -> bb14; // scope 0 at $DIR/issue-41110.rs:+5:1: +5:2 + goto -> bb14; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } bb10 (cleanup): { - resume; // scope 0 at $DIR/issue-41110.rs:+0:1: +5:2 + resume; // scope 0 at $DIR/issue-41110.rs:14:1: 19:2 } bb11 (cleanup): { - _2 = move _5; // scope 2 at $DIR/issue-41110.rs:+4:5: +4:6 - goto -> bb6; // scope 2 at $DIR/issue-41110.rs:+4:5: +4:6 + _2 = move _5; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 + goto -> bb6; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 } bb12: { - _2 = move _5; // scope 2 at $DIR/issue-41110.rs:+4:5: +4:6 - goto -> bb2; // scope 2 at $DIR/issue-41110.rs:+4:5: +4:6 + _2 = move _5; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 + goto -> bb2; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 } bb13 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/issue-41110.rs:+5:1: +5:2 + drop(_1) -> bb10; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } bb14 (cleanup): { - switchInt(_6) -> [false: bb10, otherwise: bb13]; // scope 0 at $DIR/issue-41110.rs:+5:1: +5:2 + switchInt(_6) -> [false: bb10, otherwise: bb13]; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } } diff --git a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir index 047b24db46643..701e291f46ecf 100644 --- a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir +++ b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir @@ -1,20 +1,20 @@ // MIR for `::{constant#0}` after SimplifyCfg-promote-consts ::{constant#0}: usize = { - let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 - let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 + let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 + let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 bb0: { - _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 - assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 + _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 + assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 } bb1: { - _0 = move (_1.0: usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 - return; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 + _0 = move (_1.0: usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 + return; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 } bb2 (cleanup): { - resume; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 + resume; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 } } diff --git a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir index 047b24db46643..701e291f46ecf 100644 --- a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir +++ b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir @@ -1,20 +1,20 @@ // MIR for `::{constant#0}` after SimplifyCfg-promote-consts ::{constant#0}: usize = { - let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 - let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 + let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 + let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 bb0: { - _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 - assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 + _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 + assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 } bb1: { - _0 = move (_1.0: usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 - return; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 + _0 = move (_1.0: usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 + return; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 } bb2 (cleanup): { - resume; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 + resume; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 } } diff --git a/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir index f95a0a1c013bc..a4ff718f42258 100644 --- a/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir @@ -1,152 +1,152 @@ // MIR for `main` after ElaborateDrops fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-41888.rs:+0:11: +0:11 - let _1: E; // in scope 0 at $DIR/issue-41888.rs:+1:9: +1:10 - let mut _2: bool; // in scope 0 at $DIR/issue-41888.rs:+2:8: +2:14 - let mut _3: E; // in scope 0 at $DIR/issue-41888.rs:+3:13: +3:20 - let mut _4: K; // in scope 0 at $DIR/issue-41888.rs:+3:18: +3:19 - let mut _5: isize; // in scope 0 at $DIR/issue-41888.rs:+4:16: +4:24 - let mut _7: bool; // in scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 - let mut _8: bool; // in scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 - let mut _9: bool; // in scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 - let mut _10: isize; // in scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 - let mut _11: isize; // in scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 + let mut _0: (); // return place in scope 0 at $DIR/issue-41888.rs:6:11: 6:11 + let _1: E; // in scope 0 at $DIR/issue-41888.rs:7:9: 7:10 + let mut _2: bool; // in scope 0 at $DIR/issue-41888.rs:8:8: 8:14 + let mut _3: E; // in scope 0 at $DIR/issue-41888.rs:9:13: 9:20 + let mut _4: K; // in scope 0 at $DIR/issue-41888.rs:9:18: 9:19 + let mut _5: isize; // in scope 0 at $DIR/issue-41888.rs:10:16: 10:24 + let mut _7: bool; // in scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + let mut _8: bool; // in scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + let mut _9: bool; // in scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + let mut _10: isize; // in scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + let mut _11: isize; // in scope 0 at $DIR/issue-41888.rs:15:1: 15:2 scope 1 { - debug e => _1; // in scope 1 at $DIR/issue-41888.rs:+1:9: +1:10 + debug e => _1; // in scope 1 at $DIR/issue-41888.rs:7:9: 7:10 scope 2 { - debug _k => _6; // in scope 2 at $DIR/issue-41888.rs:+4:21: +4:23 - let _6: K; // in scope 2 at $DIR/issue-41888.rs:+4:21: +4:23 + debug _k => _6; // in scope 2 at $DIR/issue-41888.rs:10:21: 10:23 + let _6: K; // in scope 2 at $DIR/issue-41888.rs:10:21: 10:23 } } bb0: { - _9 = const false; // scope 0 at $DIR/issue-41888.rs:+1:9: +1:10 - _7 = const false; // scope 0 at $DIR/issue-41888.rs:+1:9: +1:10 - _8 = const false; // scope 0 at $DIR/issue-41888.rs:+1:9: +1:10 - StorageLive(_1); // scope 0 at $DIR/issue-41888.rs:+1:9: +1:10 - StorageLive(_2); // scope 1 at $DIR/issue-41888.rs:+2:8: +2:14 - _2 = cond() -> [return: bb1, unwind: bb11]; // scope 1 at $DIR/issue-41888.rs:+2:8: +2:14 + _9 = const false; // scope 0 at $DIR/issue-41888.rs:7:9: 7:10 + _7 = const false; // scope 0 at $DIR/issue-41888.rs:7:9: 7:10 + _8 = const false; // scope 0 at $DIR/issue-41888.rs:7:9: 7:10 + StorageLive(_1); // scope 0 at $DIR/issue-41888.rs:7:9: 7:10 + StorageLive(_2); // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 + _2 = cond() -> [return: bb1, unwind: bb11]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 // mir::Constant // + span: $DIR/issue-41888.rs:8:8: 8:12 // + literal: Const { ty: fn() -> bool {cond}, val: Value() } } bb1: { - switchInt(move _2) -> [false: bb7, otherwise: bb2]; // scope 1 at $DIR/issue-41888.rs:+2:8: +2:14 + switchInt(move _2) -> [false: bb7, otherwise: bb2]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 } bb2: { - StorageLive(_3); // scope 1 at $DIR/issue-41888.rs:+3:13: +3:20 - StorageLive(_4); // scope 1 at $DIR/issue-41888.rs:+3:18: +3:19 - _4 = K; // scope 1 at $DIR/issue-41888.rs:+3:18: +3:19 - _3 = E::F(move _4); // scope 1 at $DIR/issue-41888.rs:+3:13: +3:20 - StorageDead(_4); // scope 1 at $DIR/issue-41888.rs:+3:19: +3:20 - goto -> bb14; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10 + StorageLive(_3); // scope 1 at $DIR/issue-41888.rs:9:13: 9:20 + StorageLive(_4); // scope 1 at $DIR/issue-41888.rs:9:18: 9:19 + _4 = K; // scope 1 at $DIR/issue-41888.rs:9:18: 9:19 + _3 = E::F(move _4); // scope 1 at $DIR/issue-41888.rs:9:13: 9:20 + StorageDead(_4); // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 + goto -> bb14; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 } bb3: { - goto -> bb4; // scope 1 at $DIR/issue-41888.rs:+3:19: +3:20 + goto -> bb4; // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 } bb4: { - StorageDead(_3); // scope 1 at $DIR/issue-41888.rs:+3:19: +3:20 - _5 = discriminant(_1); // scope 2 at $DIR/issue-41888.rs:+4:16: +4:24 - switchInt(move _5) -> [0_isize: bb5, otherwise: bb6]; // scope 2 at $DIR/issue-41888.rs:+4:16: +4:24 + StorageDead(_3); // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 + _5 = discriminant(_1); // scope 2 at $DIR/issue-41888.rs:10:16: 10:24 + switchInt(move _5) -> [0_isize: bb5, otherwise: bb6]; // scope 2 at $DIR/issue-41888.rs:10:16: 10:24 } bb5: { - StorageLive(_6); // scope 2 at $DIR/issue-41888.rs:+4:21: +4:23 - _9 = const false; // scope 2 at $DIR/issue-41888.rs:+4:21: +4:23 - _6 = move ((_1 as F).0: K); // scope 2 at $DIR/issue-41888.rs:+4:21: +4:23 - _0 = const (); // scope 2 at $DIR/issue-41888.rs:+4:29: +7:10 - StorageDead(_6); // scope 1 at $DIR/issue-41888.rs:+7:9: +7:10 - goto -> bb8; // scope 1 at $DIR/issue-41888.rs:+4:9: +7:10 + StorageLive(_6); // scope 2 at $DIR/issue-41888.rs:10:21: 10:23 + _9 = const false; // scope 2 at $DIR/issue-41888.rs:10:21: 10:23 + _6 = move ((_1 as F).0: K); // scope 2 at $DIR/issue-41888.rs:10:21: 10:23 + _0 = const (); // scope 2 at $DIR/issue-41888.rs:10:29: 13:10 + StorageDead(_6); // scope 1 at $DIR/issue-41888.rs:13:9: 13:10 + goto -> bb8; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 } bb6: { - _0 = const (); // scope 1 at $DIR/issue-41888.rs:+7:10: +7:10 - goto -> bb8; // scope 1 at $DIR/issue-41888.rs:+4:9: +7:10 + _0 = const (); // scope 1 at $DIR/issue-41888.rs:13:10: 13:10 + goto -> bb8; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 } bb7: { - _0 = const (); // scope 1 at $DIR/issue-41888.rs:+8:6: +8:6 - goto -> bb8; // scope 1 at $DIR/issue-41888.rs:+2:5: +8:6 + _0 = const (); // scope 1 at $DIR/issue-41888.rs:14:6: 14:6 + goto -> bb8; // scope 1 at $DIR/issue-41888.rs:8:5: 14:6 } bb8: { - StorageDead(_2); // scope 1 at $DIR/issue-41888.rs:+8:5: +8:6 - goto -> bb20; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 + StorageDead(_2); // scope 1 at $DIR/issue-41888.rs:14:5: 14:6 + goto -> bb20; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } bb9: { - _7 = const false; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 - _8 = const false; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 - _9 = const false; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 - StorageDead(_1); // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 - return; // scope 0 at $DIR/issue-41888.rs:+9:2: +9:2 + _7 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + _8 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + _9 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + StorageDead(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + return; // scope 0 at $DIR/issue-41888.rs:15:2: 15:2 } bb10 (cleanup): { - goto -> bb11; // scope 1 at $DIR/issue-41888.rs:+3:19: +3:20 + goto -> bb11; // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 } bb11 (cleanup): { - goto -> bb12; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 + goto -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } bb12 (cleanup): { - resume; // scope 0 at $DIR/issue-41888.rs:+0:1: +9:2 + resume; // scope 0 at $DIR/issue-41888.rs:6:1: 15:2 } bb13 (cleanup): { - _7 = const true; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10 - _8 = const true; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10 - _9 = const true; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10 - _1 = move _3; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10 - goto -> bb10; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10 + _7 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 + _8 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 + _9 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 + _1 = move _3; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 + goto -> bb10; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 } bb14: { - _7 = const true; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10 - _8 = const true; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10 - _9 = const true; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10 - _1 = move _3; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10 - goto -> bb3; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10 + _7 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 + _8 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 + _9 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 + _1 = move _3; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 + goto -> bb3; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 } bb15: { - _7 = const false; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 - goto -> bb9; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 + _7 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + goto -> bb9; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } bb16 (cleanup): { - goto -> bb12; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 + goto -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } bb17: { - drop(_1) -> [return: bb15, unwind: bb12]; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 + drop(_1) -> [return: bb15, unwind: bb12]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } bb18 (cleanup): { - drop(_1) -> bb12; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 + drop(_1) -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } bb19: { - _10 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 - switchInt(move _10) -> [0_isize: bb15, otherwise: bb17]; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 + _10 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + switchInt(move _10) -> [0_isize: bb15, otherwise: bb17]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } bb20: { - switchInt(_7) -> [false: bb15, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 + switchInt(_7) -> [false: bb15, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } bb21 (cleanup): { - _11 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 - switchInt(move _11) -> [0_isize: bb16, otherwise: bb18]; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 + _11 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + switchInt(move _11) -> [0_isize: bb16, otherwise: bb18]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } bb22 (cleanup): { - switchInt(_7) -> [false: bb12, otherwise: bb21]; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2 + switchInt(_7) -> [false: bb12, otherwise: bb21]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } } diff --git a/src/test/mir-opt/issue_49232.main.mir_map.0.mir b/src/test/mir-opt/issue_49232.main.mir_map.0.mir index 821323b5e2426..6301763449b90 100644 --- a/src/test/mir-opt/issue_49232.main.mir_map.0.mir +++ b/src/test/mir-opt/issue_49232.main.mir_map.0.mir @@ -1,82 +1,82 @@ // MIR for `main` 0 mir_map fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-49232.rs:+0:11: +0:11 - let mut _1: (); // in scope 0 at $DIR/issue-49232.rs:+0:1: +10:2 - let _2: i32; // in scope 0 at $DIR/issue-49232.rs:+2:13: +2:19 - let mut _3: bool; // in scope 0 at $DIR/issue-49232.rs:+3:19: +3:23 - let mut _4: !; // in scope 0 at $DIR/issue-49232.rs:+5:25: +5:30 - let _5: (); // in scope 0 at $DIR/issue-49232.rs:+8:9: +8:22 - let mut _6: &i32; // in scope 0 at $DIR/issue-49232.rs:+8:14: +8:21 + let mut _0: (); // return place in scope 0 at $DIR/issue-49232.rs:5:11: 5:11 + let mut _1: (); // in scope 0 at $DIR/issue-49232.rs:5:1: 15:2 + let _2: i32; // in scope 0 at $DIR/issue-49232.rs:7:13: 7:19 + let mut _3: bool; // in scope 0 at $DIR/issue-49232.rs:8:19: 8:23 + let mut _4: !; // in scope 0 at $DIR/issue-49232.rs:10:25: 10:30 + let _5: (); // in scope 0 at $DIR/issue-49232.rs:13:9: 13:22 + let mut _6: &i32; // in scope 0 at $DIR/issue-49232.rs:13:14: 13:21 scope 1 { - debug beacon => _2; // in scope 1 at $DIR/issue-49232.rs:+2:13: +2:19 + debug beacon => _2; // in scope 1 at $DIR/issue-49232.rs:7:13: 7:19 } bb0: { - goto -> bb1; // scope 0 at $DIR/issue-49232.rs:+1:5: +9:6 + goto -> bb1; // scope 0 at $DIR/issue-49232.rs:6:5: 14:6 } bb1: { - falseUnwind -> [real: bb2, cleanup: bb11]; // scope 0 at $DIR/issue-49232.rs:+1:5: +9:6 + falseUnwind -> [real: bb2, cleanup: bb11]; // scope 0 at $DIR/issue-49232.rs:6:5: 14:6 } bb2: { - StorageLive(_2); // scope 0 at $DIR/issue-49232.rs:+2:13: +2:19 - StorageLive(_3); // scope 0 at $DIR/issue-49232.rs:+3:19: +3:23 - _3 = const true; // scope 0 at $DIR/issue-49232.rs:+3:19: +3:23 - FakeRead(ForMatchedPlace(None), _3); // scope 0 at $DIR/issue-49232.rs:+3:19: +3:23 - switchInt(_3) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/issue-49232.rs:+3:13: +3:23 + StorageLive(_2); // scope 0 at $DIR/issue-49232.rs:7:13: 7:19 + StorageLive(_3); // scope 0 at $DIR/issue-49232.rs:8:19: 8:23 + _3 = const true; // scope 0 at $DIR/issue-49232.rs:8:19: 8:23 + FakeRead(ForMatchedPlace(None), _3); // scope 0 at $DIR/issue-49232.rs:8:19: 8:23 + switchInt(_3) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/issue-49232.rs:8:13: 8:23 } bb3: { - falseEdge -> [real: bb5, imaginary: bb4]; // scope 0 at $DIR/issue-49232.rs:+4:17: +4:22 + falseEdge -> [real: bb5, imaginary: bb4]; // scope 0 at $DIR/issue-49232.rs:9:17: 9:22 } bb4: { - _0 = const (); // scope 0 at $DIR/issue-49232.rs:+5:25: +5:30 - goto -> bb10; // scope 0 at $DIR/issue-49232.rs:+5:25: +5:30 + _0 = const (); // scope 0 at $DIR/issue-49232.rs:10:25: 10:30 + goto -> bb10; // scope 0 at $DIR/issue-49232.rs:10:25: 10:30 } bb5: { - _2 = const 4_i32; // scope 0 at $DIR/issue-49232.rs:+4:26: +4:27 - goto -> bb8; // scope 0 at $DIR/issue-49232.rs:+4:26: +4:27 + _2 = const 4_i32; // scope 0 at $DIR/issue-49232.rs:9:26: 9:27 + goto -> bb8; // scope 0 at $DIR/issue-49232.rs:9:26: 9:27 } bb6: { - unreachable; // scope 0 at $DIR/issue-49232.rs:+5:25: +5:30 + unreachable; // scope 0 at $DIR/issue-49232.rs:10:25: 10:30 } bb7: { - goto -> bb8; // scope 0 at $DIR/issue-49232.rs:+6:13: +6:14 + goto -> bb8; // scope 0 at $DIR/issue-49232.rs:11:13: 11:14 } bb8: { - FakeRead(ForLet(None), _2); // scope 0 at $DIR/issue-49232.rs:+2:13: +2:19 - StorageDead(_3); // scope 0 at $DIR/issue-49232.rs:+7:10: +7:11 - StorageLive(_5); // scope 1 at $DIR/issue-49232.rs:+8:9: +8:22 - StorageLive(_6); // scope 1 at $DIR/issue-49232.rs:+8:14: +8:21 - _6 = &_2; // scope 1 at $DIR/issue-49232.rs:+8:14: +8:21 - _5 = std::mem::drop::<&i32>(move _6) -> [return: bb9, unwind: bb11]; // scope 1 at $DIR/issue-49232.rs:+8:9: +8:22 + FakeRead(ForLet(None), _2); // scope 0 at $DIR/issue-49232.rs:7:13: 7:19 + StorageDead(_3); // scope 0 at $DIR/issue-49232.rs:12:10: 12:11 + StorageLive(_5); // scope 1 at $DIR/issue-49232.rs:13:9: 13:22 + StorageLive(_6); // scope 1 at $DIR/issue-49232.rs:13:14: 13:21 + _6 = &_2; // scope 1 at $DIR/issue-49232.rs:13:14: 13:21 + _5 = std::mem::drop::<&i32>(move _6) -> [return: bb9, unwind: bb11]; // scope 1 at $DIR/issue-49232.rs:13:9: 13:22 // mir::Constant // + span: $DIR/issue-49232.rs:13:9: 13:13 // + literal: Const { ty: fn(&i32) {std::mem::drop::<&i32>}, val: Value() } } bb9: { - StorageDead(_6); // scope 1 at $DIR/issue-49232.rs:+8:21: +8:22 - StorageDead(_5); // scope 1 at $DIR/issue-49232.rs:+8:22: +8:23 - _1 = const (); // scope 0 at $DIR/issue-49232.rs:+1:10: +9:6 - StorageDead(_2); // scope 0 at $DIR/issue-49232.rs:+9:5: +9:6 - goto -> bb1; // scope 0 at $DIR/issue-49232.rs:+1:5: +9:6 + StorageDead(_6); // scope 1 at $DIR/issue-49232.rs:13:21: 13:22 + StorageDead(_5); // scope 1 at $DIR/issue-49232.rs:13:22: 13:23 + _1 = const (); // scope 0 at $DIR/issue-49232.rs:6:10: 14:6 + StorageDead(_2); // scope 0 at $DIR/issue-49232.rs:14:5: 14:6 + goto -> bb1; // scope 0 at $DIR/issue-49232.rs:6:5: 14:6 } bb10: { - StorageDead(_3); // scope 0 at $DIR/issue-49232.rs:+7:10: +7:11 - StorageDead(_2); // scope 0 at $DIR/issue-49232.rs:+9:5: +9:6 - return; // scope 0 at $DIR/issue-49232.rs:+10:2: +10:2 + StorageDead(_3); // scope 0 at $DIR/issue-49232.rs:12:10: 12:11 + StorageDead(_2); // scope 0 at $DIR/issue-49232.rs:14:5: 14:6 + return; // scope 0 at $DIR/issue-49232.rs:15:2: 15:2 } bb11 (cleanup): { - resume; // scope 0 at $DIR/issue-49232.rs:+0:1: +10:2 + resume; // scope 0 at $DIR/issue-49232.rs:5:1: 15:2 } } diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir index 72603dc5dbea2..f21e9bbd270a2 100644 --- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir +++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir @@ -1,122 +1,122 @@ // MIR for `test` before ElaborateDrops fn test() -> Option> { - let mut _0: std::option::Option>; // return place in scope 0 at $DIR/issue-62289.rs:+0:14: +0:30 - let mut _1: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:+1:10: +1:21 - let mut _2: usize; // in scope 0 at $DIR/issue-62289.rs:+1:10: +1:21 - let mut _3: usize; // in scope 0 at $DIR/issue-62289.rs:+1:10: +1:21 - let mut _4: *mut u8; // in scope 0 at $DIR/issue-62289.rs:+1:10: +1:21 - let mut _5: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:+1:10: +1:21 - let mut _6: std::ops::ControlFlow, u32>; // in scope 0 at $DIR/issue-62289.rs:+1:15: +1:20 - let mut _7: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:+1:15: +1:19 - let mut _8: isize; // in scope 0 at $DIR/issue-62289.rs:+1:19: +1:20 - let _9: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:+1:19: +1:20 - let mut _10: !; // in scope 0 at $DIR/issue-62289.rs:+1:19: +1:20 - let mut _11: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:+1:19: +1:20 - let _12: u32; // in scope 0 at $DIR/issue-62289.rs:+1:15: +1:20 + let mut _0: std::option::Option>; // return place in scope 0 at $DIR/issue-62289.rs:8:14: 8:30 + let mut _1: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _2: usize; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _3: usize; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _4: *mut u8; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _5: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _6: std::ops::ControlFlow, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + let mut _7: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:19 + let mut _8: isize; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let _9: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let mut _10: !; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let mut _11: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let _12: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 scope 1 { } scope 2 { - debug residual => _9; // in scope 2 at $DIR/issue-62289.rs:+1:19: +1:20 + debug residual => _9; // in scope 2 at $DIR/issue-62289.rs:9:19: 9:20 scope 3 { } } scope 4 { - debug val => _12; // in scope 4 at $DIR/issue-62289.rs:+1:15: +1:20 + debug val => _12; // in scope 4 at $DIR/issue-62289.rs:9:15: 9:20 scope 5 { } } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-62289.rs:+1:10: +1:21 - _2 = SizeOf(u32); // scope 1 at $DIR/issue-62289.rs:+1:10: +1:21 - _3 = AlignOf(u32); // scope 1 at $DIR/issue-62289.rs:+1:10: +1:21 - _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/issue-62289.rs:+1:10: +1:21 + StorageLive(_1); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + _2 = SizeOf(u32); // scope 1 at $DIR/issue-62289.rs:9:10: 9:21 + _3 = AlignOf(u32); // scope 1 at $DIR/issue-62289.rs:9:10: 9:21 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/issue-62289.rs:9:10: 9:21 // mir::Constant // + span: $DIR/issue-62289.rs:9:10: 9:21 // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value() } } bb1: { - StorageLive(_5); // scope 0 at $DIR/issue-62289.rs:+1:10: +1:21 - _5 = ShallowInitBox(move _4, u32); // scope 0 at $DIR/issue-62289.rs:+1:10: +1:21 - StorageLive(_6); // scope 0 at $DIR/issue-62289.rs:+1:15: +1:20 - StorageLive(_7); // scope 0 at $DIR/issue-62289.rs:+1:15: +1:19 - _7 = Option::::None; // scope 0 at $DIR/issue-62289.rs:+1:15: +1:19 - _6 = as Try>::branch(move _7) -> [return: bb2, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:+1:15: +1:20 + StorageLive(_5); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + _5 = ShallowInitBox(move _4, u32); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + StorageLive(_6); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + StorageLive(_7); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 + _7 = Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 + _6 = as Try>::branch(move _7) -> [return: bb2, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 // + literal: Const { ty: fn(Option) -> ControlFlow< as Try>::Residual, as Try>::Output> { as Try>::branch}, val: Value() } } bb2: { - StorageDead(_7); // scope 0 at $DIR/issue-62289.rs:+1:19: +1:20 - _8 = discriminant(_6); // scope 0 at $DIR/issue-62289.rs:+1:15: +1:20 - switchInt(move _8) -> [0_isize: bb3, 1_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/issue-62289.rs:+1:15: +1:20 + StorageDead(_7); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + _8 = discriminant(_6); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + switchInt(move _8) -> [0_isize: bb3, 1_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 } bb3: { - StorageLive(_12); // scope 0 at $DIR/issue-62289.rs:+1:15: +1:20 - _12 = ((_6 as Continue).0: u32); // scope 0 at $DIR/issue-62289.rs:+1:15: +1:20 - (*_5) = _12; // scope 5 at $DIR/issue-62289.rs:+1:15: +1:20 - StorageDead(_12); // scope 0 at $DIR/issue-62289.rs:+1:19: +1:20 - _1 = move _5; // scope 0 at $DIR/issue-62289.rs:+1:10: +1:21 - drop(_5) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:+1:20: +1:21 + StorageLive(_12); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _12 = ((_6 as Continue).0: u32); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + (*_5) = _12; // scope 5 at $DIR/issue-62289.rs:9:15: 9:20 + StorageDead(_12); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + _1 = move _5; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + drop(_5) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb4: { - unreachable; // scope 0 at $DIR/issue-62289.rs:+1:15: +1:20 + unreachable; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 } bb5: { - StorageLive(_9); // scope 0 at $DIR/issue-62289.rs:+1:19: +1:20 - _9 = ((_6 as Break).0: std::option::Option); // scope 0 at $DIR/issue-62289.rs:+1:19: +1:20 - StorageLive(_11); // scope 3 at $DIR/issue-62289.rs:+1:19: +1:20 - _11 = _9; // scope 3 at $DIR/issue-62289.rs:+1:19: +1:20 - _0 = > as FromResidual>>::from_residual(move _11) -> [return: bb6, unwind: bb12]; // scope 3 at $DIR/issue-62289.rs:+1:15: +1:20 + StorageLive(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + _9 = ((_6 as Break).0: std::option::Option); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + StorageLive(_11); // scope 3 at $DIR/issue-62289.rs:9:19: 9:20 + _11 = _9; // scope 3 at $DIR/issue-62289.rs:9:19: 9:20 + _0 = > as FromResidual>>::from_residual(move _11) -> [return: bb6, unwind: bb12]; // scope 3 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:19: 9:20 // + literal: Const { ty: fn(Option) -> Option> {> as FromResidual>>::from_residual}, val: Value() } } bb6: { - StorageDead(_11); // scope 3 at $DIR/issue-62289.rs:+1:19: +1:20 - StorageDead(_9); // scope 0 at $DIR/issue-62289.rs:+1:19: +1:20 - drop(_5) -> bb9; // scope 0 at $DIR/issue-62289.rs:+1:20: +1:21 + StorageDead(_11); // scope 3 at $DIR/issue-62289.rs:9:19: 9:20 + StorageDead(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + drop(_5) -> bb9; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb7: { - StorageDead(_5); // scope 0 at $DIR/issue-62289.rs:+1:20: +1:21 - _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:+1:5: +1:22 - drop(_1) -> bb8; // scope 0 at $DIR/issue-62289.rs:+1:21: +1:22 + StorageDead(_5); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 + drop(_1) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } bb8: { - StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:+1:21: +1:22 - StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:+2:1: +2:2 - goto -> bb10; // scope 0 at $DIR/issue-62289.rs:+2:2: +2:2 + StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 + goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } bb9: { - StorageDead(_5); // scope 0 at $DIR/issue-62289.rs:+1:20: +1:21 - StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:+1:21: +1:22 - StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:+2:1: +2:2 - goto -> bb10; // scope 0 at $DIR/issue-62289.rs:+2:2: +2:2 + StorageDead(_5); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 + goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } bb10: { - return; // scope 0 at $DIR/issue-62289.rs:+2:2: +2:2 + return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } bb11 (cleanup): { - drop(_1) -> bb13; // scope 0 at $DIR/issue-62289.rs:+1:21: +1:22 + drop(_1) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } bb12 (cleanup): { - drop(_5) -> bb13; // scope 0 at $DIR/issue-62289.rs:+1:20: +1:21 + drop(_5) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb13 (cleanup): { - resume; // scope 0 at $DIR/issue-62289.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/issue-62289.rs:8:1: 10:2 } } diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir index 972ce1d507854..e19cd74527985 100644 --- a/src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir +++ b/src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir @@ -1,17 +1,17 @@ // MIR for `bar` 0 mir_map fn bar(_1: [(Never, u32); 1]) -> u32 { - let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:+0:40: +0:43 - let _2: u32; // in scope 0 at $DIR/issue-72181.rs:+0:13: +0:14 + let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:19:40: 19:43 + let _2: u32; // in scope 0 at $DIR/issue-72181.rs:19:13: 19:14 scope 1 { - debug x => _2; // in scope 1 at $DIR/issue-72181.rs:+0:13: +0:14 + debug x => _2; // in scope 1 at $DIR/issue-72181.rs:19:13: 19:14 } bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14 - _2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14 - _0 = _2; // scope 1 at $DIR/issue-72181.rs:+0:46: +0:47 - StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49 - return; // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49 + StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:19:13: 19:14 + _2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:19:13: 19:14 + _0 = _2; // scope 1 at $DIR/issue-72181.rs:19:46: 19:47 + StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:19:48: 19:49 + return; // scope 0 at $DIR/issue-72181.rs:19:49: 19:49 } } diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir index 972ce1d507854..e19cd74527985 100644 --- a/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir +++ b/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir @@ -1,17 +1,17 @@ // MIR for `bar` 0 mir_map fn bar(_1: [(Never, u32); 1]) -> u32 { - let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:+0:40: +0:43 - let _2: u32; // in scope 0 at $DIR/issue-72181.rs:+0:13: +0:14 + let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:19:40: 19:43 + let _2: u32; // in scope 0 at $DIR/issue-72181.rs:19:13: 19:14 scope 1 { - debug x => _2; // in scope 1 at $DIR/issue-72181.rs:+0:13: +0:14 + debug x => _2; // in scope 1 at $DIR/issue-72181.rs:19:13: 19:14 } bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14 - _2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14 - _0 = _2; // scope 1 at $DIR/issue-72181.rs:+0:46: +0:47 - StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49 - return; // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49 + StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:19:13: 19:14 + _2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:19:13: 19:14 + _0 = _2; // scope 1 at $DIR/issue-72181.rs:19:46: 19:47 + StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:19:48: 19:49 + return; // scope 0 at $DIR/issue-72181.rs:19:49: 19:49 } } diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir index 534f131ea936b..c9a2b9c0d83a3 100644 --- a/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir +++ b/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir @@ -1,27 +1,27 @@ // MIR for `foo` 0 mir_map fn foo(_1: [(Never, u32); 1]) -> u32 { - debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:+0:8: +0:10 - let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:+0:34: +0:37 - let _2: usize; // in scope 0 at $DIR/issue-72181.rs:+0:43: +0:44 - let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45 - let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45 + debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:16:8: 16:10 + let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:16:34: 16:37 + let _2: usize; // in scope 0 at $DIR/issue-72181.rs:16:43: 16:44 + let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45 bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44 - _2 = const 0_usize; // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44 - _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45 - _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45 - assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45 + StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:16:43: 16:44 + _2 = const 0_usize; // scope 0 at $DIR/issue-72181.rs:16:43: 16:44 + _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 } bb1: { - _0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:47 - StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49 - return; // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49 + _0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:16:40: 16:47 + StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:16:48: 16:49 + return; // scope 0 at $DIR/issue-72181.rs:16:49: 16:49 } bb2 (cleanup): { - resume; // scope 0 at $DIR/issue-72181.rs:+0:1: +0:49 + resume; // scope 0 at $DIR/issue-72181.rs:16:1: 16:49 } } diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir index 534f131ea936b..c9a2b9c0d83a3 100644 --- a/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir +++ b/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir @@ -1,27 +1,27 @@ // MIR for `foo` 0 mir_map fn foo(_1: [(Never, u32); 1]) -> u32 { - debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:+0:8: +0:10 - let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:+0:34: +0:37 - let _2: usize; // in scope 0 at $DIR/issue-72181.rs:+0:43: +0:44 - let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45 - let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45 + debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:16:8: 16:10 + let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:16:34: 16:37 + let _2: usize; // in scope 0 at $DIR/issue-72181.rs:16:43: 16:44 + let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45 bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44 - _2 = const 0_usize; // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44 - _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45 - _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45 - assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45 + StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:16:43: 16:44 + _2 = const 0_usize; // scope 0 at $DIR/issue-72181.rs:16:43: 16:44 + _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 } bb1: { - _0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:47 - StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49 - return; // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49 + _0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:16:40: 16:47 + StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:16:48: 16:49 + return; // scope 0 at $DIR/issue-72181.rs:16:49: 16:49 } bb2 (cleanup): { - resume; // scope 0 at $DIR/issue-72181.rs:+0:1: +0:49 + resume; // scope 0 at $DIR/issue-72181.rs:16:1: 16:49 } } diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir index 425906f84fcd6..f4602d147c947 100644 --- a/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir +++ b/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir @@ -1,18 +1,18 @@ // MIR for `main` 0 mir_map fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:+0:11: +0:11 - let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:+1:13: +1:34 - let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:+3:14: +3:27 - let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:+3:29: +3:42 - let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:+4:13: +4:30 - let _6: usize; // in scope 0 at $DIR/issue-72181.rs:+4:24: +4:25 - let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26 - let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26 + let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:23:11: 23:11 + let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:24:13: 24:34 + let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:26:14: 26:27 + let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:26:29: 26:42 + let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:27:13: 27:30 + let _6: usize; // in scope 0 at $DIR/issue-72181.rs:27:24: 27:25 + let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26 + let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26 scope 1 { - let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:+3:9: +3:10 + let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:26:9: 26:10 scope 2 { - debug f => _2; // in scope 2 at $DIR/issue-72181.rs:+3:9: +3:10 + debug f => _2; // in scope 2 at $DIR/issue-72181.rs:26:9: 26:10 scope 3 { } scope 4 { @@ -21,42 +21,42 @@ fn main() -> () { } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34 - _1 = std::mem::size_of::() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34 + StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:24:13: 24:34 + _1 = std::mem::size_of::() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34 // mir::Constant // + span: $DIR/issue-72181.rs:24:13: 24:32 // + literal: Const { ty: fn() -> usize {std::mem::size_of::}, val: Value() } } bb1: { - StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:+1:34: +1:35 - StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10 - StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27 - _3 = Foo { a: const 42_u64 }; // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27 - StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42 - _4 = Foo { a: const 10_u64 }; // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42 - _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:+3:13: +3:43 - StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43 - StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43 - FakeRead(ForLet(None), _2); // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10 - StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:+4:13: +4:30 - StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25 - _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25 - _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26 - _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26 - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26 + StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:24:34: 24:35 + StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10 + StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:26:14: 26:27 + _3 = Foo { a: const 42_u64 }; // scope 1 at $DIR/issue-72181.rs:26:14: 26:27 + StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:26:29: 26:42 + _4 = Foo { a: const 10_u64 }; // scope 1 at $DIR/issue-72181.rs:26:29: 26:42 + _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:26:13: 26:43 + StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43 + StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43 + FakeRead(ForLet(None), _2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10 + StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:27:13: 27:30 + StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:27:24: 27:25 + _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:27:24: 27:25 + _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 + _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 + assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 } bb2: { - _5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:28 - StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31 - StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31 - _0 = const (); // scope 0 at $DIR/issue-72181.rs:+0:11: +5:2 - StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:+5:1: +5:2 - return; // scope 0 at $DIR/issue-72181.rs:+5:2: +5:2 + _5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:27:22: 27:28 + StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31 + StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31 + _0 = const (); // scope 0 at $DIR/issue-72181.rs:23:11: 28:2 + StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:28:1: 28:2 + return; // scope 0 at $DIR/issue-72181.rs:28:2: 28:2 } bb3 (cleanup): { - resume; // scope 0 at $DIR/issue-72181.rs:+0:1: +5:2 + resume; // scope 0 at $DIR/issue-72181.rs:23:1: 28:2 } } diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir index 425906f84fcd6..f4602d147c947 100644 --- a/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir +++ b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir @@ -1,18 +1,18 @@ // MIR for `main` 0 mir_map fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:+0:11: +0:11 - let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:+1:13: +1:34 - let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:+3:14: +3:27 - let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:+3:29: +3:42 - let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:+4:13: +4:30 - let _6: usize; // in scope 0 at $DIR/issue-72181.rs:+4:24: +4:25 - let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26 - let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26 + let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:23:11: 23:11 + let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:24:13: 24:34 + let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:26:14: 26:27 + let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:26:29: 26:42 + let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:27:13: 27:30 + let _6: usize; // in scope 0 at $DIR/issue-72181.rs:27:24: 27:25 + let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26 + let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26 scope 1 { - let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:+3:9: +3:10 + let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:26:9: 26:10 scope 2 { - debug f => _2; // in scope 2 at $DIR/issue-72181.rs:+3:9: +3:10 + debug f => _2; // in scope 2 at $DIR/issue-72181.rs:26:9: 26:10 scope 3 { } scope 4 { @@ -21,42 +21,42 @@ fn main() -> () { } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34 - _1 = std::mem::size_of::() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34 + StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:24:13: 24:34 + _1 = std::mem::size_of::() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34 // mir::Constant // + span: $DIR/issue-72181.rs:24:13: 24:32 // + literal: Const { ty: fn() -> usize {std::mem::size_of::}, val: Value() } } bb1: { - StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:+1:34: +1:35 - StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10 - StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27 - _3 = Foo { a: const 42_u64 }; // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27 - StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42 - _4 = Foo { a: const 10_u64 }; // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42 - _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:+3:13: +3:43 - StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43 - StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43 - FakeRead(ForLet(None), _2); // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10 - StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:+4:13: +4:30 - StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25 - _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25 - _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26 - _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26 - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26 + StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:24:34: 24:35 + StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10 + StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:26:14: 26:27 + _3 = Foo { a: const 42_u64 }; // scope 1 at $DIR/issue-72181.rs:26:14: 26:27 + StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:26:29: 26:42 + _4 = Foo { a: const 10_u64 }; // scope 1 at $DIR/issue-72181.rs:26:29: 26:42 + _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:26:13: 26:43 + StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43 + StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43 + FakeRead(ForLet(None), _2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10 + StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:27:13: 27:30 + StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:27:24: 27:25 + _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:27:24: 27:25 + _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 + _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 + assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 } bb2: { - _5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:28 - StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31 - StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31 - _0 = const (); // scope 0 at $DIR/issue-72181.rs:+0:11: +5:2 - StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:+5:1: +5:2 - return; // scope 0 at $DIR/issue-72181.rs:+5:2: +5:2 + _5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:27:22: 27:28 + StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31 + StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31 + _0 = const (); // scope 0 at $DIR/issue-72181.rs:23:11: 28:2 + StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:28:1: 28:2 + return; // scope 0 at $DIR/issue-72181.rs:28:2: 28:2 } bb3 (cleanup): { - resume; // scope 0 at $DIR/issue-72181.rs:+0:1: +5:2 + resume; // scope 0 at $DIR/issue-72181.rs:23:1: 28:2 } } diff --git a/src/test/mir-opt/issue_72181_1.f.mir_map.0.mir b/src/test/mir-opt/issue_72181_1.f.mir_map.0.mir index e1a35d88bf1d9..7def08ece220b 100644 --- a/src/test/mir-opt/issue_72181_1.f.mir_map.0.mir +++ b/src/test/mir-opt/issue_72181_1.f.mir_map.0.mir @@ -1,29 +1,29 @@ // MIR for `f` 0 mir_map fn f(_1: Void) -> ! { - debug v => _1; // in scope 0 at $DIR/issue-72181-1.rs:+0:6: +0:7 - let mut _0: !; // return place in scope 0 at $DIR/issue-72181-1.rs:+0:18: +0:19 - let mut _2: !; // in scope 0 at $DIR/issue-72181-1.rs:+0:20: +2:2 - let mut _3: !; // in scope 0 at $DIR/issue-72181-1.rs:+1:5: +1:15 + debug v => _1; // in scope 0 at $DIR/issue-72181-1.rs:10:6: 10:7 + let mut _0: !; // return place in scope 0 at $DIR/issue-72181-1.rs:10:18: 10:19 + let mut _2: !; // in scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2 + let mut _3: !; // in scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15 bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:+0:20: +2:2 - StorageLive(_3); // scope 0 at $DIR/issue-72181-1.rs:+1:5: +1:15 - FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/issue-72181-1.rs:+1:11: +1:12 - unreachable; // scope 0 at $DIR/issue-72181-1.rs:+1:11: +1:12 + StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2 + StorageLive(_3); // scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15 + FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12 + unreachable; // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12 } bb1: { - unreachable; // scope 0 at $DIR/issue-72181-1.rs:+1:5: +1:15 + unreachable; // scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15 } bb2: { - StorageDead(_3); // scope 0 at $DIR/issue-72181-1.rs:+1:14: +1:15 - unreachable; // scope 0 at $DIR/issue-72181-1.rs:+0:20: +2:2 + StorageDead(_3); // scope 0 at $DIR/issue-72181-1.rs:11:14: 11:15 + unreachable; // scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2 } bb3: { - StorageDead(_2); // scope 0 at $DIR/issue-72181-1.rs:+2:1: +2:2 - return; // scope 0 at $DIR/issue-72181-1.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/issue-72181-1.rs:12:1: 12:2 + return; // scope 0 at $DIR/issue-72181-1.rs:12:2: 12:2 } } diff --git a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir index 336693337fb57..9842e26ab6993 100644 --- a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir +++ b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir @@ -5,53 +5,53 @@ | 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(Void) }, span: $DIR/issue-72181-1.rs:16:12: 16:16, inferred_ty: Void | fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-72181-1.rs:+0:11: +0:11 - let mut _1: !; // in scope 0 at $DIR/issue-72181-1.rs:+0:11: +6:2 - let _2: Void as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/issue-72181-1.rs:+1:9: +1:10 - let mut _3: (); // in scope 0 at $DIR/issue-72181-1.rs:+2:41: +2:43 - let _4: !; // in scope 0 at $DIR/issue-72181-1.rs:+5:5: +5:9 - let mut _5: Void; // in scope 0 at $DIR/issue-72181-1.rs:+5:7: +5:8 + let mut _0: (); // return place in scope 0 at $DIR/issue-72181-1.rs:15:11: 15:11 + let mut _1: !; // in scope 0 at $DIR/issue-72181-1.rs:15:11: 21:2 + let _2: Void as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10 + let mut _3: (); // in scope 0 at $DIR/issue-72181-1.rs:17:41: 17:43 + let _4: !; // in scope 0 at $DIR/issue-72181-1.rs:20:5: 20:9 + let mut _5: Void; // in scope 0 at $DIR/issue-72181-1.rs:20:7: 20:8 scope 1 { - debug v => _2; // in scope 1 at $DIR/issue-72181-1.rs:+1:9: +1:10 + debug v => _2; // in scope 1 at $DIR/issue-72181-1.rs:16:9: 16:10 } scope 2 { } bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:+1:9: +1:10 - StorageLive(_3); // scope 2 at $DIR/issue-72181-1.rs:+2:41: +2:43 - _3 = (); // scope 2 at $DIR/issue-72181-1.rs:+2:41: +2:43 - _2 = transmute::<(), Void>(move _3) -> bb4; // scope 2 at $DIR/issue-72181-1.rs:+2:9: +2:44 + StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10 + StorageLive(_3); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43 + _3 = (); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43 + _2 = transmute::<(), Void>(move _3) -> bb4; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44 // mir::Constant // + span: $DIR/issue-72181-1.rs:17:9: 17:40 // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {transmute::<(), Void>}, val: Value() } } bb1: { - StorageDead(_3); // scope 2 at $DIR/issue-72181-1.rs:+2:43: +2:44 - FakeRead(ForLet(None), _2); // scope 0 at $DIR/issue-72181-1.rs:+1:9: +1:10 - AscribeUserType(_2, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/issue-72181-1.rs:+1:12: +1:16 - StorageLive(_4); // scope 1 at $DIR/issue-72181-1.rs:+5:5: +5:9 - StorageLive(_5); // scope 1 at $DIR/issue-72181-1.rs:+5:7: +5:8 - _5 = move _2; // scope 1 at $DIR/issue-72181-1.rs:+5:7: +5:8 - _4 = f(move _5) -> bb4; // scope 1 at $DIR/issue-72181-1.rs:+5:5: +5:9 + StorageDead(_3); // scope 2 at $DIR/issue-72181-1.rs:17:43: 17:44 + FakeRead(ForLet(None), _2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10 + AscribeUserType(_2, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/issue-72181-1.rs:16:12: 16:16 + StorageLive(_4); // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9 + StorageLive(_5); // scope 1 at $DIR/issue-72181-1.rs:20:7: 20:8 + _5 = move _2; // scope 1 at $DIR/issue-72181-1.rs:20:7: 20:8 + _4 = f(move _5) -> bb4; // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9 // mir::Constant // + span: $DIR/issue-72181-1.rs:20:5: 20:6 // + literal: Const { ty: fn(Void) -> ! {f}, val: Value() } } bb2: { - StorageDead(_5); // scope 1 at $DIR/issue-72181-1.rs:+5:8: +5:9 - StorageDead(_4); // scope 1 at $DIR/issue-72181-1.rs:+5:9: +5:10 - StorageDead(_2); // scope 0 at $DIR/issue-72181-1.rs:+6:1: +6:2 - unreachable; // scope 0 at $DIR/issue-72181-1.rs:+0:11: +6:2 + StorageDead(_5); // scope 1 at $DIR/issue-72181-1.rs:20:8: 20:9 + StorageDead(_4); // scope 1 at $DIR/issue-72181-1.rs:20:9: 20:10 + StorageDead(_2); // scope 0 at $DIR/issue-72181-1.rs:21:1: 21:2 + unreachable; // scope 0 at $DIR/issue-72181-1.rs:15:11: 21:2 } bb3: { - return; // scope 0 at $DIR/issue-72181-1.rs:+6:2: +6:2 + return; // scope 0 at $DIR/issue-72181-1.rs:21:2: 21:2 } bb4 (cleanup): { - resume; // scope 0 at $DIR/issue-72181-1.rs:+0:1: +6:2 + resume; // scope 0 at $DIR/issue-72181-1.rs:15:1: 21:2 } } diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff index be8e86a832cb6..9295265154424 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff @@ -2,10 +2,10 @@ + // MIR for `main` after PreCodegen fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14 - let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - let _3: i32; // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 + let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11 + let _1: i32; // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + let _3: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 let mut _5: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _6: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _7: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -19,10 +19,10 @@ let _18: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _19: std::option::Option; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 1 { - debug split => _1; // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14 - let _4: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14 + debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 + let _4: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 scope 3 { - debug _prev => _4; // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14 + debug _prev => _4; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 let _8: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let _9: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _20: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -37,21 +37,21 @@ } } scope 2 { - debug v => _3; // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15 + debug v => _3; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14 - StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - Deinit(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - StorageLive(_3); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - _3 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - _1 = _3; // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21 - StorageDead(_3); // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21 - StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7 - StorageLive(_4); // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14 + StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + Deinit(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + StorageLive(_3); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _3 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _1 = _3; // scope 2 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_3); // scope 0 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 + StorageLive(_4); // scope 1 at $DIR/issue-73223.rs:7:9: 7:14 StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _6 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -109,9 +109,9 @@ StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_4); // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2 - return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2 + StorageDead(_4); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 + StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 + return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff index be8e86a832cb6..9295265154424 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff @@ -2,10 +2,10 @@ + // MIR for `main` after PreCodegen fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14 - let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - let _3: i32; // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 + let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11 + let _1: i32; // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + let _3: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 let mut _5: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _6: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _7: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -19,10 +19,10 @@ let _18: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _19: std::option::Option; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 1 { - debug split => _1; // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14 - let _4: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14 + debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 + let _4: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 scope 3 { - debug _prev => _4; // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14 + debug _prev => _4; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 let _8: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let _9: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _20: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -37,21 +37,21 @@ } } scope 2 { - debug v => _3; // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15 + debug v => _3; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14 - StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - Deinit(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - StorageLive(_3); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - _3 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - _1 = _3; // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21 - StorageDead(_3); // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21 - StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7 - StorageLive(_4); // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14 + StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + Deinit(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + StorageLive(_3); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _3 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _1 = _3; // scope 2 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_3); // scope 0 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 + StorageLive(_4); // scope 1 at $DIR/issue-73223.rs:7:9: 7:14 StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _6 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -109,9 +109,9 @@ StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_4); // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2 - return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2 + StorageDead(_4); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 + StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 + return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff index 50948180fc46e..f52b1a953c120 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff @@ -2,18 +2,18 @@ + // MIR for `main` after SimplifyArmIdentity fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14 - let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - let mut _3: isize; // in scope 0 at $DIR/issue-73223.rs:+2:9: +2:16 - let _4: i32; // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - let mut _5: !; // in scope 0 at $DIR/issue-73223.rs:+3:17: +3:23 - let mut _7: i32; // in scope 0 at $DIR/issue-73223.rs:+6:22: +6:27 + let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11 + let _1: i32; // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + let mut _3: isize; // in scope 0 at $DIR/issue-73223.rs:3:9: 3:16 + let _4: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + let mut _5: !; // in scope 0 at $DIR/issue-73223.rs:4:17: 4:23 + let mut _7: i32; // in scope 0 at $DIR/issue-73223.rs:7:22: 7:27 let _8: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _9: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _10: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _11: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _12: i32; // in scope 0 at $DIR/issue-73223.rs:+7:23: +7:24 + let _12: i32; // in scope 0 at $DIR/issue-73223.rs:8:23: 8:24 let mut _15: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _16: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _17: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -27,10 +27,10 @@ let _26: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _27: std::option::Option; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 1 { - debug split => _1; // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14 - let _6: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14 + debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 + let _6: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 scope 3 { - debug _prev => _6; // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14 + debug _prev => _6; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 let _13: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let _14: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _28: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -45,39 +45,39 @@ } } scope 2 { - debug v => _4; // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15 + debug v => _4; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14 - StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - Deinit(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - _3 = const 1_isize; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - goto -> bb2; // scope 0 at $DIR/issue-73223.rs:+1:17: +1:30 + StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + Deinit(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + _3 = const 1_isize; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + goto -> bb2; // scope 0 at $DIR/issue-73223.rs:2:17: 2:30 } bb1: { - nop; // scope 0 at $DIR/issue-73223.rs:+3:17: +3:23 - StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2 - return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2 + nop; // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 + StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 + StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 + return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } bb2: { - StorageLive(_4); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - _4 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - _1 = _4; // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21 - StorageDead(_4); // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21 - StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7 - StorageLive(_6); // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14 - StorageLive(_7); // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27 - _7 = _1; // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27 - Deinit(_6); // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28 - ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28 - discriminant(_6) = 1; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28 - StorageDead(_7); // scope 1 at $DIR/issue-73223.rs:+6:27: +6:28 + StorageLive(_4); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _4 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _1 = _4; // scope 2 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_4); // scope 0 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 + StorageLive(_6); // scope 1 at $DIR/issue-73223.rs:7:9: 7:14 + StorageLive(_7); // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 + _7 = _1; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 + Deinit(_6); // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 + ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 + discriminant(_6) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 + StorageDead(_7); // scope 1 at $DIR/issue-73223.rs:7:27: 7:28 StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -148,10 +148,10 @@ StorageDead(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - nop; // scope 0 at $DIR/issue-73223.rs:+0:11: +8:2 - StorageDead(_6); // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2 - return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2 + nop; // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 + StorageDead(_6); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 + StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 + return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff index 50948180fc46e..f52b1a953c120 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff @@ -2,18 +2,18 @@ + // MIR for `main` after SimplifyArmIdentity fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14 - let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - let mut _3: isize; // in scope 0 at $DIR/issue-73223.rs:+2:9: +2:16 - let _4: i32; // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - let mut _5: !; // in scope 0 at $DIR/issue-73223.rs:+3:17: +3:23 - let mut _7: i32; // in scope 0 at $DIR/issue-73223.rs:+6:22: +6:27 + let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11 + let _1: i32; // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + let mut _3: isize; // in scope 0 at $DIR/issue-73223.rs:3:9: 3:16 + let _4: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + let mut _5: !; // in scope 0 at $DIR/issue-73223.rs:4:17: 4:23 + let mut _7: i32; // in scope 0 at $DIR/issue-73223.rs:7:22: 7:27 let _8: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _9: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _10: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _11: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _12: i32; // in scope 0 at $DIR/issue-73223.rs:+7:23: +7:24 + let _12: i32; // in scope 0 at $DIR/issue-73223.rs:8:23: 8:24 let mut _15: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _16: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _17: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -27,10 +27,10 @@ let _26: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _27: std::option::Option; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 1 { - debug split => _1; // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14 - let _6: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14 + debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 + let _6: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 scope 3 { - debug _prev => _6; // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14 + debug _prev => _6; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 let _13: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let _14: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _28: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -45,39 +45,39 @@ } } scope 2 { - debug v => _4; // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15 + debug v => _4; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14 - StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - Deinit(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - _3 = const 1_isize; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - goto -> bb2; // scope 0 at $DIR/issue-73223.rs:+1:17: +1:30 + StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + Deinit(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + _3 = const 1_isize; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + goto -> bb2; // scope 0 at $DIR/issue-73223.rs:2:17: 2:30 } bb1: { - nop; // scope 0 at $DIR/issue-73223.rs:+3:17: +3:23 - StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2 - return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2 + nop; // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 + StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 + StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 + return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } bb2: { - StorageLive(_4); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - _4 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - _1 = _4; // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21 - StorageDead(_4); // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21 - StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7 - StorageLive(_6); // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14 - StorageLive(_7); // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27 - _7 = _1; // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27 - Deinit(_6); // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28 - ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28 - discriminant(_6) = 1; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28 - StorageDead(_7); // scope 1 at $DIR/issue-73223.rs:+6:27: +6:28 + StorageLive(_4); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _4 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _1 = _4; // scope 2 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_4); // scope 0 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 + StorageLive(_6); // scope 1 at $DIR/issue-73223.rs:7:9: 7:14 + StorageLive(_7); // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 + _7 = _1; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 + Deinit(_6); // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 + ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 + discriminant(_6) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 + StorageDead(_7); // scope 1 at $DIR/issue-73223.rs:7:27: 7:28 StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -148,10 +148,10 @@ StorageDead(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - nop; // scope 0 at $DIR/issue-73223.rs:+0:11: +8:2 - StorageDead(_6); // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2 - return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2 + nop; // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 + StorageDead(_6); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 + StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 + return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff b/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff index 2368c021eda57..14bb66910fe3c 100644 --- a/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff +++ b/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff @@ -2,67 +2,67 @@ + // MIR for `test` after SimplifyComparisonIntegral fn test(_1: T) -> () { - debug x => _1; // in scope 0 at $DIR/issue_76432.rs:+0:38: +0:39 - let mut _0: (); // return place in scope 0 at $DIR/issue_76432.rs:+0:44: +0:44 - let _2: &[T]; // in scope 0 at $DIR/issue_76432.rs:+1:9: +1:10 - let mut _3: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 - let _4: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 - let _5: [T; 3]; // in scope 0 at $DIR/issue_76432.rs:+1:20: +1:29 - let mut _6: T; // in scope 0 at $DIR/issue_76432.rs:+1:21: +1:22 - let mut _7: T; // in scope 0 at $DIR/issue_76432.rs:+1:24: +1:25 - let mut _8: T; // in scope 0 at $DIR/issue_76432.rs:+1:27: +1:28 - let _9: [*const T; 3]; // in scope 0 at $DIR/issue_76432.rs:+2:5: +5:6 - let mut _10: usize; // in scope 0 at $DIR/issue_76432.rs:+3:9: +3:33 - let mut _11: usize; // in scope 0 at $DIR/issue_76432.rs:+3:9: +3:33 - let mut _12: bool; // in scope 0 at $DIR/issue_76432.rs:+3:9: +3:33 - let mut _16: *const T; // in scope 0 at $DIR/issue_76432.rs:+3:38: +3:52 - let mut _17: *const T; // in scope 0 at $DIR/issue_76432.rs:+3:38: +3:52 - let mut _18: *const T; // in scope 0 at $DIR/issue_76432.rs:+3:54: +3:68 - let mut _19: *const T; // in scope 0 at $DIR/issue_76432.rs:+3:54: +3:68 - let mut _20: *const T; // in scope 0 at $DIR/issue_76432.rs:+3:70: +3:84 - let mut _21: *const T; // in scope 0 at $DIR/issue_76432.rs:+3:70: +3:84 + debug x => _1; // in scope 0 at $DIR/issue_76432.rs:6:38: 6:39 + let mut _0: (); // return place in scope 0 at $DIR/issue_76432.rs:6:44: 6:44 + let _2: &[T]; // in scope 0 at $DIR/issue_76432.rs:7:9: 7:10 + let mut _3: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + let _4: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + let _5: [T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:20: 7:29 + let mut _6: T; // in scope 0 at $DIR/issue_76432.rs:7:21: 7:22 + let mut _7: T; // in scope 0 at $DIR/issue_76432.rs:7:24: 7:25 + let mut _8: T; // in scope 0 at $DIR/issue_76432.rs:7:27: 7:28 + let _9: [*const T; 3]; // in scope 0 at $DIR/issue_76432.rs:8:5: 11:6 + let mut _10: usize; // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 + let mut _11: usize; // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 + let mut _12: bool; // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 + let mut _16: *const T; // in scope 0 at $DIR/issue_76432.rs:9:38: 9:52 + let mut _17: *const T; // in scope 0 at $DIR/issue_76432.rs:9:38: 9:52 + let mut _18: *const T; // in scope 0 at $DIR/issue_76432.rs:9:54: 9:68 + let mut _19: *const T; // in scope 0 at $DIR/issue_76432.rs:9:54: 9:68 + let mut _20: *const T; // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84 + let mut _21: *const T; // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84 let mut _22: !; // in scope 0 at $SRC_DIR/core/src/panic.rs:LL:COL - let mut _23: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 + let mut _23: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29 scope 1 { - debug v => _2; // in scope 1 at $DIR/issue_76432.rs:+1:9: +1:10 - let _13: &T; // in scope 1 at $DIR/issue_76432.rs:+3:10: +3:16 - let _14: &T; // in scope 1 at $DIR/issue_76432.rs:+3:18: +3:24 - let _15: &T; // in scope 1 at $DIR/issue_76432.rs:+3:26: +3:32 + debug v => _2; // in scope 1 at $DIR/issue_76432.rs:7:9: 7:10 + let _13: &T; // in scope 1 at $DIR/issue_76432.rs:9:10: 9:16 + let _14: &T; // in scope 1 at $DIR/issue_76432.rs:9:18: 9:24 + let _15: &T; // in scope 1 at $DIR/issue_76432.rs:9:26: 9:32 scope 2 { - debug v1 => _13; // in scope 2 at $DIR/issue_76432.rs:+3:10: +3:16 - debug v2 => _14; // in scope 2 at $DIR/issue_76432.rs:+3:18: +3:24 - debug v3 => _15; // in scope 2 at $DIR/issue_76432.rs:+3:26: +3:32 + debug v1 => _13; // in scope 2 at $DIR/issue_76432.rs:9:10: 9:16 + debug v2 => _14; // in scope 2 at $DIR/issue_76432.rs:9:18: 9:24 + debug v3 => _15; // in scope 2 at $DIR/issue_76432.rs:9:26: 9:32 } } bb0: { - StorageLive(_2); // scope 0 at $DIR/issue_76432.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 - StorageLive(_4); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 - StorageLive(_5); // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29 - StorageLive(_6); // scope 0 at $DIR/issue_76432.rs:+1:21: +1:22 - _6 = _1; // scope 0 at $DIR/issue_76432.rs:+1:21: +1:22 - StorageLive(_7); // scope 0 at $DIR/issue_76432.rs:+1:24: +1:25 - _7 = _1; // scope 0 at $DIR/issue_76432.rs:+1:24: +1:25 - StorageLive(_8); // scope 0 at $DIR/issue_76432.rs:+1:27: +1:28 - _8 = _1; // scope 0 at $DIR/issue_76432.rs:+1:27: +1:28 - _5 = [move _6, move _7, move _8]; // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29 - StorageDead(_8); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29 - StorageDead(_7); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29 - StorageDead(_6); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29 - _4 = &_5; // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 - _3 = _4; // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 - StorageLive(_23); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 - _23 = _3; // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 - _2 = move _3 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 - StorageDead(_3); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29 - StorageDead(_4); // scope 0 at $DIR/issue_76432.rs:+1:29: +1:30 - StorageLive(_9); // scope 1 at $DIR/issue_76432.rs:+2:5: +5:6 - _10 = const 3_usize; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33 - StorageDead(_23); // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33 - _11 = const 3_usize; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33 - _12 = const true; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33 - goto -> bb2; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33 + StorageLive(_2); // scope 0 at $DIR/issue_76432.rs:7:9: 7:10 + StorageLive(_3); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageLive(_4); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageLive(_5); // scope 0 at $DIR/issue_76432.rs:7:20: 7:29 + StorageLive(_6); // scope 0 at $DIR/issue_76432.rs:7:21: 7:22 + _6 = _1; // scope 0 at $DIR/issue_76432.rs:7:21: 7:22 + StorageLive(_7); // scope 0 at $DIR/issue_76432.rs:7:24: 7:25 + _7 = _1; // scope 0 at $DIR/issue_76432.rs:7:24: 7:25 + StorageLive(_8); // scope 0 at $DIR/issue_76432.rs:7:27: 7:28 + _8 = _1; // scope 0 at $DIR/issue_76432.rs:7:27: 7:28 + _5 = [move _6, move _7, move _8]; // scope 0 at $DIR/issue_76432.rs:7:20: 7:29 + StorageDead(_8); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + StorageDead(_7); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + StorageDead(_6); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + _4 = &_5; // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + _3 = _4; // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageLive(_23); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + _23 = _3; // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + _2 = move _3 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageDead(_3); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + StorageDead(_4); // scope 0 at $DIR/issue_76432.rs:7:29: 7:30 + StorageLive(_9); // scope 1 at $DIR/issue_76432.rs:8:5: 11:6 + _10 = const 3_usize; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + StorageDead(_23); // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + _11 = const 3_usize; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + _12 = const true; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + goto -> bb2; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 } bb1: { @@ -77,39 +77,39 @@ } bb2: { - StorageLive(_13); // scope 1 at $DIR/issue_76432.rs:+3:10: +3:16 - _13 = &(*_2)[0 of 3]; // scope 1 at $DIR/issue_76432.rs:+3:10: +3:16 - StorageLive(_14); // scope 1 at $DIR/issue_76432.rs:+3:18: +3:24 - _14 = &(*_2)[1 of 3]; // scope 1 at $DIR/issue_76432.rs:+3:18: +3:24 - StorageLive(_15); // scope 1 at $DIR/issue_76432.rs:+3:26: +3:32 - _15 = &(*_2)[2 of 3]; // scope 1 at $DIR/issue_76432.rs:+3:26: +3:32 - StorageLive(_16); // scope 2 at $DIR/issue_76432.rs:+3:38: +3:52 - StorageLive(_17); // scope 2 at $DIR/issue_76432.rs:+3:38: +3:52 - _17 = &raw const (*_13); // scope 2 at $DIR/issue_76432.rs:+3:38: +3:40 - _16 = _17; // scope 2 at $DIR/issue_76432.rs:+3:38: +3:52 - StorageLive(_18); // scope 2 at $DIR/issue_76432.rs:+3:54: +3:68 - StorageLive(_19); // scope 2 at $DIR/issue_76432.rs:+3:54: +3:68 - _19 = &raw const (*_14); // scope 2 at $DIR/issue_76432.rs:+3:54: +3:56 - _18 = _19; // scope 2 at $DIR/issue_76432.rs:+3:54: +3:68 - StorageLive(_20); // scope 2 at $DIR/issue_76432.rs:+3:70: +3:84 - StorageLive(_21); // scope 2 at $DIR/issue_76432.rs:+3:70: +3:84 - _21 = &raw const (*_15); // scope 2 at $DIR/issue_76432.rs:+3:70: +3:72 - _20 = _21; // scope 2 at $DIR/issue_76432.rs:+3:70: +3:84 - _9 = [move _16, move _18, move _20]; // scope 2 at $DIR/issue_76432.rs:+3:37: +3:85 - StorageDead(_21); // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85 - StorageDead(_20); // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85 - StorageDead(_19); // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85 - StorageDead(_18); // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85 - StorageDead(_17); // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85 - StorageDead(_16); // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85 - StorageDead(_15); // scope 1 at $DIR/issue_76432.rs:+3:84: +3:85 - StorageDead(_14); // scope 1 at $DIR/issue_76432.rs:+3:84: +3:85 - StorageDead(_13); // scope 1 at $DIR/issue_76432.rs:+3:84: +3:85 - StorageDead(_9); // scope 1 at $DIR/issue_76432.rs:+5:6: +5:7 - nop; // scope 0 at $DIR/issue_76432.rs:+0:44: +6:2 - StorageDead(_5); // scope 0 at $DIR/issue_76432.rs:+6:1: +6:2 - StorageDead(_2); // scope 0 at $DIR/issue_76432.rs:+6:1: +6:2 - return; // scope 0 at $DIR/issue_76432.rs:+6:2: +6:2 + StorageLive(_13); // scope 1 at $DIR/issue_76432.rs:9:10: 9:16 + _13 = &(*_2)[0 of 3]; // scope 1 at $DIR/issue_76432.rs:9:10: 9:16 + StorageLive(_14); // scope 1 at $DIR/issue_76432.rs:9:18: 9:24 + _14 = &(*_2)[1 of 3]; // scope 1 at $DIR/issue_76432.rs:9:18: 9:24 + StorageLive(_15); // scope 1 at $DIR/issue_76432.rs:9:26: 9:32 + _15 = &(*_2)[2 of 3]; // scope 1 at $DIR/issue_76432.rs:9:26: 9:32 + StorageLive(_16); // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 + StorageLive(_17); // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 + _17 = &raw const (*_13); // scope 2 at $DIR/issue_76432.rs:9:38: 9:40 + _16 = _17; // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 + StorageLive(_18); // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 + StorageLive(_19); // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 + _19 = &raw const (*_14); // scope 2 at $DIR/issue_76432.rs:9:54: 9:56 + _18 = _19; // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 + StorageLive(_20); // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 + StorageLive(_21); // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 + _21 = &raw const (*_15); // scope 2 at $DIR/issue_76432.rs:9:70: 9:72 + _20 = _21; // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 + _9 = [move _16, move _18, move _20]; // scope 2 at $DIR/issue_76432.rs:9:37: 9:85 + StorageDead(_21); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_20); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_19); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_18); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_17); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_16); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_15); // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_14); // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_13); // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_9); // scope 1 at $DIR/issue_76432.rs:11:6: 11:7 + nop; // scope 0 at $DIR/issue_76432.rs:6:44: 12:2 + StorageDead(_5); // scope 0 at $DIR/issue_76432.rs:12:1: 12:2 + StorageDead(_2); // scope 0 at $DIR/issue_76432.rs:12:1: 12:2 + return; // scope 0 at $DIR/issue_76432.rs:12:2: 12:2 } } diff --git a/src/test/mir-opt/issue_78192.f.InstCombine.diff b/src/test/mir-opt/issue_78192.f.InstCombine.diff index 8ec94d65fda52..ec3be78525802 100644 --- a/src/test/mir-opt/issue_78192.f.InstCombine.diff +++ b/src/test/mir-opt/issue_78192.f.InstCombine.diff @@ -2,28 +2,28 @@ + // MIR for `f` after InstCombine fn f(_1: &T) -> *const T { - debug a => _1; // in scope 0 at $DIR/issue-78192.rs:+0:13: +0:14 - let mut _0: *const T; // return place in scope 0 at $DIR/issue-78192.rs:+0:23: +0:31 - let _2: &*const T; // in scope 0 at $DIR/issue-78192.rs:+1:9: +1:10 - let _3: &*const T; // in scope 0 at $DIR/issue-78192.rs:+1:24: +1:40 - let _4: *const T; // in scope 0 at $DIR/issue-78192.rs:+1:25: +1:40 + debug a => _1; // in scope 0 at $DIR/issue-78192.rs:2:13: 2:14 + let mut _0: *const T; // return place in scope 0 at $DIR/issue-78192.rs:2:23: 2:31 + let _2: &*const T; // in scope 0 at $DIR/issue-78192.rs:3:9: 3:10 + let _3: &*const T; // in scope 0 at $DIR/issue-78192.rs:3:24: 3:40 + let _4: *const T; // in scope 0 at $DIR/issue-78192.rs:3:25: 3:40 scope 1 { - debug b => _2; // in scope 1 at $DIR/issue-78192.rs:+1:9: +1:10 + debug b => _2; // in scope 1 at $DIR/issue-78192.rs:3:9: 3:10 } bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-78192.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/issue-78192.rs:+1:24: +1:40 - StorageLive(_4); // scope 0 at $DIR/issue-78192.rs:+1:25: +1:40 - _4 = &raw const (*_1); // scope 0 at $DIR/issue-78192.rs:+1:26: +1:27 - _3 = &_4; // scope 0 at $DIR/issue-78192.rs:+1:24: +1:40 -- _2 = &(*_3); // scope 0 at $DIR/issue-78192.rs:+1:24: +1:40 -+ _2 = _3; // scope 0 at $DIR/issue-78192.rs:+1:24: +1:40 - StorageDead(_3); // scope 0 at $DIR/issue-78192.rs:+1:40: +1:41 - _0 = (*_2); // scope 1 at $DIR/issue-78192.rs:+2:5: +2:7 - StorageDead(_4); // scope 0 at $DIR/issue-78192.rs:+3:1: +3:2 - StorageDead(_2); // scope 0 at $DIR/issue-78192.rs:+3:1: +3:2 - return; // scope 0 at $DIR/issue-78192.rs:+3:2: +3:2 + StorageLive(_2); // scope 0 at $DIR/issue-78192.rs:3:9: 3:10 + StorageLive(_3); // scope 0 at $DIR/issue-78192.rs:3:24: 3:40 + StorageLive(_4); // scope 0 at $DIR/issue-78192.rs:3:25: 3:40 + _4 = &raw const (*_1); // scope 0 at $DIR/issue-78192.rs:3:26: 3:27 + _3 = &_4; // scope 0 at $DIR/issue-78192.rs:3:24: 3:40 +- _2 = &(*_3); // scope 0 at $DIR/issue-78192.rs:3:24: 3:40 ++ _2 = _3; // scope 0 at $DIR/issue-78192.rs:3:24: 3:40 + StorageDead(_3); // scope 0 at $DIR/issue-78192.rs:3:40: 3:41 + _0 = (*_2); // scope 1 at $DIR/issue-78192.rs:4:5: 4:7 + StorageDead(_4); // scope 0 at $DIR/issue-78192.rs:5:1: 5:2 + StorageDead(_2); // scope 0 at $DIR/issue-78192.rs:5:1: 5:2 + return; // scope 0 at $DIR/issue-78192.rs:5:2: 5:2 } } diff --git a/src/test/mir-opt/issue_99325.main.mir_map.0.mir b/src/test/mir-opt/issue_99325.main.mir_map.0.mir deleted file mode 100644 index 5bca9f0ea9893..0000000000000 --- a/src/test/mir-opt/issue_99325.main.mir_map.0.mir +++ /dev/null @@ -1,295 +0,0 @@ -// MIR for `main` 0 mir_map - -| User Type Annotations -| 0: user_ty: Canonical { max_universe: U0, variables: [], value: TypeOf(DefId(0:3 ~ issue_99325[8f58]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Value(Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)])) }], user_self_ty: None }) }, span: $DIR/issue-99325.rs:10:16: 10:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { max_universe: U0, variables: [], value: TypeOf(DefId(0:3 ~ issue_99325[8f58]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:8 ~ issue_99325[8f58]::main::{constant#1}), const_param_did: Some(DefId(0:4 ~ issue_99325[8f58]::function_with_bytes::BYTES)) }, substs: [], promoted: None }) }], user_self_ty: None }) }, span: $DIR/issue-99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| -fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-99325.rs:+0:15: +0:15 - let _1: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _2: (&&[u8], &&[u8; 4]); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _3: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _4: &[u8]; // in scope 0 at $DIR/issue-99325.rs:+1:16: +1:48 - let mut _5: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _6: &[u8; 4]; // in scope 0 at $DIR/issue-99325.rs:+1:50: +1:75 - let _7: [u8; 4]; // in scope 0 at $DIR/issue-99325.rs:+1:51: +1:75 - let _8: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _9: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _10: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _11: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _12: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _13: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _14: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _16: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _17: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _18: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _19: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _20: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _21: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _22: std::option::Option; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _23: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _24: (&&[u8], &&[u8; 4]); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _25: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _26: &[u8]; // in scope 0 at $DIR/issue-99325.rs:+2:16: +2:70 - let mut _27: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _28: &[u8; 4]; // in scope 0 at $DIR/issue-99325.rs:+2:72: +2:79 - let _29: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _30: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _31: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _32: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _33: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _34: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _35: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _37: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _38: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _39: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _40: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _41: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _42: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _43: std::option::Option; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - scope 1 { - debug left_val => _8; // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - debug right_val => _9; // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _15: core::panicking::AssertKind; // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - scope 2 { - debug kind => _15; // in scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - } - scope 3 { - debug left_val => _29; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - debug right_val => _30; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _36: core::panicking::AssertKind; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - scope 4 { - debug kind => _36; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - } - - bb0: { - StorageLive(_1); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_4); // scope 0 at $DIR/issue-99325.rs:+1:16: +1:48 - _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb19]; // scope 0 at $DIR/issue-99325.rs:+1:16: +1:48 - // mir::Constant - // + span: $DIR/issue-99325.rs:10:16: 10:46 - // + user_ty: UserType(0) - // + literal: Const { ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}, val: Value() } - } - - bb1: { - _3 = &_4; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_5); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_6); // scope 0 at $DIR/issue-99325.rs:+1:50: +1:75 - StorageLive(_7); // scope 0 at $DIR/issue-99325.rs:+1:51: +1:75 - _7 = [const 65_u8, const 65_u8, const 65_u8, const 65_u8]; // scope 0 at $DIR/issue-99325.rs:+1:51: +1:75 - _6 = &_7; // scope 0 at $DIR/issue-99325.rs:+1:50: +1:75 - _5 = &_6; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _2 = (move _3, move _5); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_5); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - FakeRead(ForMatchedPlace(None), _2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_8); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _8 = (_2.0: &&[u8]); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_9); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _9 = (_2.1: &&[u8; 4]); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_10); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_11); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_12); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _12 = &(*_8); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_13); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _13 = &(*_9); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _11 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _12, move _13) -> [return: bb2, unwind: bb19]; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: for<'r, 's> fn(&'r &[u8], &'s &[u8; 4]) -> bool {<&[u8] as PartialEq<&[u8; 4]>>::eq}, val: Value() } - } - - bb2: { - StorageDead(_13); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_12); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _10 = Not(move _11); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_11); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - switchInt(move _10) -> [false: bb4, otherwise: bb3]; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb3: { - StorageLive(_15); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _15 = core::panicking::AssertKind::Eq; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - FakeRead(ForLet(None), _15); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_16); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_17); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _17 = move _15; // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_18); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_19); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _19 = &(*_8); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _18 = &(*_19); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_20); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_21); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _21 = &(*_9); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _20 = &(*_21); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_22); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _22 = Option::::None; // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _16 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _17, move _18, move _20, move _22) -> bb19; // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r &[u8], &'s &[u8; 4], Option>) -> ! {core::panicking::assert_failed::<&[u8], &[u8; 4]>}, val: Value() } - } - - bb4: { - goto -> bb7; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb5: { - StorageDead(_22); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_20); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_18); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_17); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_21); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_19); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_16); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_15); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - unreachable; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb6: { - goto -> bb8; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb7: { - _1 = const (); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - goto -> bb8; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb8: { - StorageDead(_10); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_9); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_8); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - goto -> bb9; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb9: { - StorageDead(_7); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_6); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_1); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_23); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_24); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_25); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_26); // scope 0 at $DIR/issue-99325.rs:+2:16: +2:70 - _26 = function_with_bytes::<&*b"AAAA">() -> [return: bb10, unwind: bb19]; // scope 0 at $DIR/issue-99325.rs:+2:16: +2:70 - // mir::Constant - // + span: $DIR/issue-99325.rs:11:16: 11:68 - // + user_ty: UserType(1) - // + literal: Const { ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}, val: Value() } - } - - bb10: { - _25 = &_26; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_27); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_28); // scope 0 at $DIR/issue-99325.rs:+2:72: +2:79 - _28 = const b"AAAA"; // scope 0 at $DIR/issue-99325.rs:+2:72: +2:79 - // mir::Constant - // + span: $DIR/issue-99325.rs:11:72: 11:79 - // + literal: Const { ty: &[u8; 4], val: Value(Scalar(alloc4)) } - _27 = &_28; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _24 = (move _25, move _27); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_27); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_25); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - FakeRead(ForMatchedPlace(None), _24); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_29); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _29 = (_24.0: &&[u8]); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_30); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _30 = (_24.1: &&[u8; 4]); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_31); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_33); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _33 = &(*_29); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_34); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _34 = &(*_30); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _32 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _33, move _34) -> [return: bb11, unwind: bb19]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: for<'r, 's> fn(&'r &[u8], &'s &[u8; 4]) -> bool {<&[u8] as PartialEq<&[u8; 4]>>::eq}, val: Value() } - } - - bb11: { - StorageDead(_34); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_33); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _31 = Not(move _32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - switchInt(move _31) -> [false: bb13, otherwise: bb12]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb12: { - StorageLive(_36); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _36 = core::panicking::AssertKind::Eq; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - FakeRead(ForLet(None), _36); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_37); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_38); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _38 = move _36; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_39); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_40); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _40 = &(*_29); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _39 = &(*_40); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_41); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_42); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _42 = &(*_30); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _41 = &(*_42); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_43); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _43 = Option::::None; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _37 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _38, move _39, move _41, move _43) -> bb19; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r &[u8], &'s &[u8; 4], Option>) -> ! {core::panicking::assert_failed::<&[u8], &[u8; 4]>}, val: Value() } - } - - bb13: { - goto -> bb16; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb14: { - StorageDead(_43); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_41); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_39); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_38); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_42); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_40); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_37); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_36); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - unreachable; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb15: { - goto -> bb17; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb16: { - _23 = const (); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - goto -> bb17; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb17: { - StorageDead(_31); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_30); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_29); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - goto -> bb18; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb18: { - StorageDead(_28); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_26); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_24); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_23); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _0 = const (); // scope 0 at $DIR/issue-99325.rs:+0:15: +3:2 - return; // scope 0 at $DIR/issue-99325.rs:+3:2: +3:2 - } - - bb19 (cleanup): { - resume; // scope 0 at $DIR/issue-99325.rs:+0:1: +3:2 - } -} - -alloc4 (size: 4, align: 1) { - 41 41 41 41 │ AAAA -} diff --git a/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir b/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir index 86b38d4b70adc..dd85434d879c3 100644 --- a/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir +++ b/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir @@ -1,12 +1,12 @@ // MIR for `num_to_digit` after PreCodegen fn num_to_digit(_1: char) -> u32 { - debug num => _1; // in scope 0 at $DIR/issue-59352.rs:+0:21: +0:24 - let mut _0: u32; // return place in scope 0 at $DIR/issue-59352.rs:+0:35: +0:38 - let mut _2: char; // in scope 0 at $DIR/issue-59352.rs:+2:8: +2:11 - let mut _3: std::option::Option; // in scope 0 at $DIR/issue-59352.rs:+2:26: +2:41 - let mut _4: char; // in scope 0 at $DIR/issue-59352.rs:+2:26: +2:29 - let mut _5: u32; // in scope 0 at $DIR/issue-59352.rs:+2:8: +2:23 + debug num => _1; // in scope 0 at $DIR/issue-59352.rs:12:21: 12:24 + let mut _0: u32; // return place in scope 0 at $DIR/issue-59352.rs:12:35: 12:38 + let mut _2: char; // in scope 0 at $DIR/issue-59352.rs:14:8: 14:11 + let mut _3: std::option::Option; // in scope 0 at $DIR/issue-59352.rs:14:26: 14:41 + let mut _4: char; // in scope 0 at $DIR/issue-59352.rs:14:26: 14:29 + let mut _5: u32; // in scope 0 at $DIR/issue-59352.rs:14:8: 14:23 let mut _12: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 1 (inlined char::methods::::is_digit) { // at $DIR/issue-59352.rs:14:8: 14:23 debug self => _2; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL @@ -29,9 +29,9 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-59352.rs:+2:8: +2:11 - _2 = _1; // scope 0 at $DIR/issue-59352.rs:+2:8: +2:11 - StorageLive(_5); // scope 0 at $DIR/issue-59352.rs:+2:8: +2:23 + StorageLive(_2); // scope 0 at $DIR/issue-59352.rs:14:8: 14:11 + _2 = _1; // scope 0 at $DIR/issue-59352.rs:14:8: 14:11 + StorageLive(_5); // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 StorageLive(_6); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL StorageLive(_7); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL StorageLive(_8); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL @@ -43,31 +43,31 @@ fn num_to_digit(_1: char) -> u32 { } bb1: { - StorageDead(_12); // scope 0 at $DIR/issue-59352.rs:+2:8: +2:23 - StorageLive(_3); // scope 0 at $DIR/issue-59352.rs:+2:26: +2:41 - StorageLive(_4); // scope 0 at $DIR/issue-59352.rs:+2:26: +2:29 - _4 = _1; // scope 0 at $DIR/issue-59352.rs:+2:26: +2:29 - _3 = char::methods::::to_digit(move _4, const 8_u32) -> bb2; // scope 0 at $DIR/issue-59352.rs:+2:26: +2:41 + StorageDead(_12); // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 + StorageLive(_3); // scope 0 at $DIR/issue-59352.rs:14:26: 14:41 + StorageLive(_4); // scope 0 at $DIR/issue-59352.rs:14:26: 14:29 + _4 = _1; // scope 0 at $DIR/issue-59352.rs:14:26: 14:29 + _3 = char::methods::::to_digit(move _4, const 8_u32) -> bb2; // scope 0 at $DIR/issue-59352.rs:14:26: 14:41 // mir::Constant // + span: $DIR/issue-59352.rs:14:30: 14:38 // + literal: Const { ty: fn(char, u32) -> Option {char::methods::::to_digit}, val: Value() } } bb2: { - StorageDead(_4); // scope 0 at $DIR/issue-59352.rs:+2:40: +2:41 - StorageLive(_10); // scope 0 at $DIR/issue-59352.rs:+2:26: +2:50 + StorageDead(_4); // scope 0 at $DIR/issue-59352.rs:14:40: 14:41 + StorageLive(_10); // scope 0 at $DIR/issue-59352.rs:14:26: 14:50 _10 = discriminant(_3); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL switchInt(move _10) -> [0_isize: bb6, 1_isize: bb8, otherwise: bb7]; // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL } bb3: { - StorageDead(_12); // scope 0 at $DIR/issue-59352.rs:+2:8: +2:23 - _0 = const 0_u32; // scope 0 at $DIR/issue-59352.rs:+2:60: +2:61 - goto -> bb4; // scope 0 at $DIR/issue-59352.rs:+2:5: +2:63 + StorageDead(_12); // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 + _0 = const 0_u32; // scope 0 at $DIR/issue-59352.rs:14:60: 14:61 + goto -> bb4; // scope 0 at $DIR/issue-59352.rs:14:5: 14:63 } bb4: { - return; // scope 0 at $DIR/issue-59352.rs:+3:2: +3:2 + return; // scope 0 at $DIR/issue-59352.rs:15:2: 15:2 } bb5: { @@ -80,9 +80,9 @@ fn num_to_digit(_1: char) -> u32 { StorageDead(_9); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL StorageDead(_6); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL StorageDead(_7); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - StorageDead(_5); // scope 0 at $DIR/issue-59352.rs:+2:8: +2:23 - StorageDead(_2); // scope 0 at $DIR/issue-59352.rs:+2:22: +2:23 - switchInt(move _12) -> [1_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/issue-59352.rs:+2:8: +2:23 + StorageDead(_5); // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 + StorageDead(_2); // scope 0 at $DIR/issue-59352.rs:14:22: 14:23 + switchInt(move _12) -> [1_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 } bb6: { @@ -102,8 +102,8 @@ fn num_to_digit(_1: char) -> u32 { bb8: { _0 = move ((_3 as Some).0: u32); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL - StorageDead(_10); // scope 0 at $DIR/issue-59352.rs:+2:26: +2:50 - StorageDead(_3); // scope 0 at $DIR/issue-59352.rs:+2:49: +2:50 - goto -> bb4; // scope 0 at $DIR/issue-59352.rs:+2:5: +2:63 + StorageDead(_10); // scope 0 at $DIR/issue-59352.rs:14:26: 14:50 + StorageDead(_3); // scope 0 at $DIR/issue-59352.rs:14:49: 14:50 + goto -> bb4; // scope 0 at $DIR/issue-59352.rs:14:5: 14:63 } } diff --git a/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff index 2ee4332ad3827..08ff3b67655ce 100644 --- a/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff +++ b/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff @@ -2,17 +2,17 @@ + // MIR for `foo` after MatchBranchSimplification fn foo(_1: [u8; 16]) -> Option<[u8; 4]> { - debug bytes => _1; // in scope 0 at $DIR/issue-75439.rs:+0:12: +0:17 - let mut _0: std::option::Option<[u8; 4]>; // return place in scope 0 at $DIR/issue-75439.rs:+0:32: +0:47 - let _2: [u32; 4]; // in scope 0 at $DIR/issue-75439.rs:+2:9: +2:15 - let mut _3: [u8; 16]; // in scope 0 at $DIR/issue-75439.rs:+2:47: +2:52 - let mut _5: [u8; 4]; // in scope 0 at $DIR/issue-75439.rs:+5:14: +5:38 - let mut _6: u32; // in scope 0 at $DIR/issue-75439.rs:+5:33: +5:35 + debug bytes => _1; // in scope 0 at $DIR/issue-75439.rs:5:12: 5:17 + let mut _0: std::option::Option<[u8; 4]>; // return place in scope 0 at $DIR/issue-75439.rs:5:32: 5:47 + let _2: [u32; 4]; // in scope 0 at $DIR/issue-75439.rs:7:9: 7:15 + let mut _3: [u8; 16]; // in scope 0 at $DIR/issue-75439.rs:7:47: 7:52 + let mut _5: [u8; 4]; // in scope 0 at $DIR/issue-75439.rs:10:14: 10:38 + let mut _6: u32; // in scope 0 at $DIR/issue-75439.rs:10:33: 10:35 scope 1 { - debug dwords => _2; // in scope 1 at $DIR/issue-75439.rs:+2:9: +2:15 + debug dwords => _2; // in scope 1 at $DIR/issue-75439.rs:7:9: 7:15 scope 3 { - debug ip => _4; // in scope 3 at $DIR/issue-75439.rs:+4:27: +4:29 - let _4: u32; // in scope 3 at $DIR/issue-75439.rs:+4:27: +4:29 + debug ip => _4; // in scope 3 at $DIR/issue-75439.rs:9:27: 9:29 + let _4: u32; // in scope 3 at $DIR/issue-75439.rs:9:27: 9:29 scope 4 { } } @@ -21,69 +21,69 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-75439.rs:+2:9: +2:15 - StorageLive(_3); // scope 2 at $DIR/issue-75439.rs:+2:47: +2:52 - _3 = _1; // scope 2 at $DIR/issue-75439.rs:+2:47: +2:52 - _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue-75439.rs:+2:37: +2:53 + StorageLive(_2); // scope 0 at $DIR/issue-75439.rs:7:9: 7:15 + StorageLive(_3); // scope 2 at $DIR/issue-75439.rs:7:47: 7:52 + _3 = _1; // scope 2 at $DIR/issue-75439.rs:7:47: 7:52 + _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue-75439.rs:7:37: 7:53 // mir::Constant // + span: $DIR/issue-75439.rs:7:37: 7:46 // + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value() } } bb1: { - StorageDead(_3); // scope 2 at $DIR/issue-75439.rs:+2:52: +2:53 - switchInt(_2[0 of 4]) -> [0_u32: bb2, otherwise: bb8]; // scope 3 at $DIR/issue-75439.rs:+4:12: +4:30 + StorageDead(_3); // scope 2 at $DIR/issue-75439.rs:7:52: 7:53 + switchInt(_2[0 of 4]) -> [0_u32: bb2, otherwise: bb8]; // scope 3 at $DIR/issue-75439.rs:9:12: 9:30 } bb2: { - switchInt(_2[1 of 4]) -> [0_u32: bb3, otherwise: bb8]; // scope 3 at $DIR/issue-75439.rs:+4:12: +4:30 + switchInt(_2[1 of 4]) -> [0_u32: bb3, otherwise: bb8]; // scope 3 at $DIR/issue-75439.rs:9:12: 9:30 } bb3: { - switchInt(_2[2 of 4]) -> [0_u32: bb5, 4294901760_u32: bb6, otherwise: bb8]; // scope 3 at $DIR/issue-75439.rs:+4:12: +4:30 + switchInt(_2[2 of 4]) -> [0_u32: bb5, 4294901760_u32: bb6, otherwise: bb8]; // scope 3 at $DIR/issue-75439.rs:9:12: 9:30 } bb4: { - StorageLive(_5); // scope 3 at $DIR/issue-75439.rs:+5:14: +5:38 - StorageLive(_6); // scope 4 at $DIR/issue-75439.rs:+5:33: +5:35 - _6 = _4; // scope 4 at $DIR/issue-75439.rs:+5:33: +5:35 - _5 = transmute::(move _6) -> bb7; // scope 4 at $DIR/issue-75439.rs:+5:23: +5:36 + StorageLive(_5); // scope 3 at $DIR/issue-75439.rs:10:14: 10:38 + StorageLive(_6); // scope 4 at $DIR/issue-75439.rs:10:33: 10:35 + _6 = _4; // scope 4 at $DIR/issue-75439.rs:10:33: 10:35 + _5 = transmute::(move _6) -> bb7; // scope 4 at $DIR/issue-75439.rs:10:23: 10:36 // mir::Constant // + span: $DIR/issue-75439.rs:10:23: 10:32 // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::}, val: Value() } } bb5: { - StorageLive(_4); // scope 3 at $DIR/issue-75439.rs:+4:27: +4:29 - _4 = _2[3 of 4]; // scope 3 at $DIR/issue-75439.rs:+4:27: +4:29 - goto -> bb4; // scope 3 at $DIR/issue-75439.rs:+4:12: +4:30 + StorageLive(_4); // scope 3 at $DIR/issue-75439.rs:9:27: 9:29 + _4 = _2[3 of 4]; // scope 3 at $DIR/issue-75439.rs:9:27: 9:29 + goto -> bb4; // scope 3 at $DIR/issue-75439.rs:9:12: 9:30 } bb6: { - StorageLive(_4); // scope 3 at $DIR/issue-75439.rs:+4:27: +4:29 - _4 = _2[3 of 4]; // scope 3 at $DIR/issue-75439.rs:+4:27: +4:29 - goto -> bb4; // scope 3 at $DIR/issue-75439.rs:+4:12: +4:30 + StorageLive(_4); // scope 3 at $DIR/issue-75439.rs:9:27: 9:29 + _4 = _2[3 of 4]; // scope 3 at $DIR/issue-75439.rs:9:27: 9:29 + goto -> bb4; // scope 3 at $DIR/issue-75439.rs:9:12: 9:30 } bb7: { - StorageDead(_6); // scope 4 at $DIR/issue-75439.rs:+5:35: +5:36 - Deinit(_0); // scope 3 at $DIR/issue-75439.rs:+5:9: +5:39 - ((_0 as Some).0: [u8; 4]) = move _5; // scope 3 at $DIR/issue-75439.rs:+5:9: +5:39 - discriminant(_0) = 1; // scope 3 at $DIR/issue-75439.rs:+5:9: +5:39 - StorageDead(_5); // scope 3 at $DIR/issue-75439.rs:+5:38: +5:39 - StorageDead(_4); // scope 1 at $DIR/issue-75439.rs:+6:5: +6:6 - goto -> bb9; // scope 1 at $DIR/issue-75439.rs:+4:5: +8:6 + StorageDead(_6); // scope 4 at $DIR/issue-75439.rs:10:35: 10:36 + Deinit(_0); // scope 3 at $DIR/issue-75439.rs:10:9: 10:39 + ((_0 as Some).0: [u8; 4]) = move _5; // scope 3 at $DIR/issue-75439.rs:10:9: 10:39 + discriminant(_0) = 1; // scope 3 at $DIR/issue-75439.rs:10:9: 10:39 + StorageDead(_5); // scope 3 at $DIR/issue-75439.rs:10:38: 10:39 + StorageDead(_4); // scope 1 at $DIR/issue-75439.rs:11:5: 11:6 + goto -> bb9; // scope 1 at $DIR/issue-75439.rs:9:5: 13:6 } bb8: { - Deinit(_0); // scope 1 at $DIR/issue-75439.rs:+7:9: +7:13 - discriminant(_0) = 0; // scope 1 at $DIR/issue-75439.rs:+7:9: +7:13 - goto -> bb9; // scope 1 at $DIR/issue-75439.rs:+4:5: +8:6 + Deinit(_0); // scope 1 at $DIR/issue-75439.rs:12:9: 12:13 + discriminant(_0) = 0; // scope 1 at $DIR/issue-75439.rs:12:9: 12:13 + goto -> bb9; // scope 1 at $DIR/issue-75439.rs:9:5: 13:6 } bb9: { - StorageDead(_2); // scope 0 at $DIR/issue-75439.rs:+9:1: +9:2 - return; // scope 0 at $DIR/issue-75439.rs:+9:2: +9:2 + StorageDead(_2); // scope 0 at $DIR/issue-75439.rs:14:1: 14:2 + return; // scope 0 at $DIR/issue-75439.rs:14:2: 14:2 } } diff --git a/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir b/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir index 5981ab885f90c..9e91603cee943 100644 --- a/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir +++ b/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir @@ -1,52 +1,52 @@ // MIR for `main` after SimplifyCfg-promote-consts fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/loop_test.rs:+0:11: +0:11 - let _1: (); // in scope 0 at $DIR/loop_test.rs:+4:5: +6:6 - let mut _2: bool; // in scope 0 at $DIR/loop_test.rs:+4:8: +4:12 - let mut _3: !; // in scope 0 at $DIR/loop_test.rs:+4:13: +6:6 - let mut _4: !; // in scope 0 at $DIR/loop_test.rs:+7:5: +10:6 - let mut _5: (); // in scope 0 at $DIR/loop_test.rs:+0:1: +11:2 - let _6: i32; // in scope 0 at $DIR/loop_test.rs:+8:13: +8:14 + let mut _0: (); // return place in scope 0 at $DIR/loop_test.rs:6:11: 6:11 + let _1: (); // in scope 0 at $DIR/loop_test.rs:10:5: 12:6 + let mut _2: bool; // in scope 0 at $DIR/loop_test.rs:10:8: 10:12 + let mut _3: !; // in scope 0 at $DIR/loop_test.rs:10:13: 12:6 + let mut _4: !; // in scope 0 at $DIR/loop_test.rs:13:5: 16:6 + let mut _5: (); // in scope 0 at $DIR/loop_test.rs:6:1: 17:2 + let _6: i32; // in scope 0 at $DIR/loop_test.rs:14:13: 14:14 scope 1 { - debug x => _6; // in scope 1 at $DIR/loop_test.rs:+8:13: +8:14 + debug x => _6; // in scope 1 at $DIR/loop_test.rs:14:13: 14:14 } bb0: { - StorageLive(_1); // scope 0 at $DIR/loop_test.rs:+4:5: +6:6 - StorageLive(_2); // scope 0 at $DIR/loop_test.rs:+4:8: +4:12 - _2 = const true; // scope 0 at $DIR/loop_test.rs:+4:8: +4:12 - switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/loop_test.rs:+4:8: +4:12 + StorageLive(_1); // scope 0 at $DIR/loop_test.rs:10:5: 12:6 + StorageLive(_2); // scope 0 at $DIR/loop_test.rs:10:8: 10:12 + _2 = const true; // scope 0 at $DIR/loop_test.rs:10:8: 10:12 + switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/loop_test.rs:10:8: 10:12 } bb1: { - _0 = const (); // scope 0 at $DIR/loop_test.rs:+5:9: +5:15 - StorageDead(_2); // scope 0 at $DIR/loop_test.rs:+6:5: +6:6 - StorageDead(_1); // scope 0 at $DIR/loop_test.rs:+6:5: +6:6 - return; // scope 0 at $DIR/loop_test.rs:+11:2: +11:2 + _0 = const (); // scope 0 at $DIR/loop_test.rs:11:9: 11:15 + StorageDead(_2); // scope 0 at $DIR/loop_test.rs:12:5: 12:6 + StorageDead(_1); // scope 0 at $DIR/loop_test.rs:12:5: 12:6 + return; // scope 0 at $DIR/loop_test.rs:17:2: 17:2 } bb2: { - _1 = const (); // scope 0 at $DIR/loop_test.rs:+6:6: +6:6 - StorageDead(_2); // scope 0 at $DIR/loop_test.rs:+6:5: +6:6 - StorageDead(_1); // scope 0 at $DIR/loop_test.rs:+6:5: +6:6 - StorageLive(_4); // scope 0 at $DIR/loop_test.rs:+7:5: +10:6 - goto -> bb3; // scope 0 at $DIR/loop_test.rs:+7:5: +10:6 + _1 = const (); // scope 0 at $DIR/loop_test.rs:12:6: 12:6 + StorageDead(_2); // scope 0 at $DIR/loop_test.rs:12:5: 12:6 + StorageDead(_1); // scope 0 at $DIR/loop_test.rs:12:5: 12:6 + StorageLive(_4); // scope 0 at $DIR/loop_test.rs:13:5: 16:6 + goto -> bb3; // scope 0 at $DIR/loop_test.rs:13:5: 16:6 } bb3: { - falseUnwind -> [real: bb4, cleanup: bb5]; // scope 0 at $DIR/loop_test.rs:+7:5: +10:6 + falseUnwind -> [real: bb4, cleanup: bb5]; // scope 0 at $DIR/loop_test.rs:13:5: 16:6 } bb4: { - StorageLive(_6); // scope 0 at $DIR/loop_test.rs:+8:13: +8:14 - _6 = const 1_i32; // scope 0 at $DIR/loop_test.rs:+8:17: +8:18 - FakeRead(ForLet(None), _6); // scope 0 at $DIR/loop_test.rs:+8:13: +8:14 - StorageDead(_6); // scope 0 at $DIR/loop_test.rs:+10:5: +10:6 + StorageLive(_6); // scope 0 at $DIR/loop_test.rs:14:13: 14:14 + _6 = const 1_i32; // scope 0 at $DIR/loop_test.rs:14:17: 14:18 + FakeRead(ForLet(None), _6); // scope 0 at $DIR/loop_test.rs:14:13: 14:14 + StorageDead(_6); // scope 0 at $DIR/loop_test.rs:16:5: 16:6 goto -> bb3; // scope 0 at no-location } bb5 (cleanup): { - resume; // scope 0 at $DIR/loop_test.rs:+0:1: +11:2 + resume; // scope 0 at $DIR/loop_test.rs:6:1: 17:2 } } diff --git a/src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff b/src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff index 2589c9f282f33..c7226573d75c5 100644 --- a/src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff +++ b/src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff @@ -2,65 +2,65 @@ + // MIR for `array_bound` after InstCombine fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:36: +0:41 - debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:+0:50: +0:55 - let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:+0:70: +0:72 - let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 - let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:6:36: 6:41 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:6:50: 6:55 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:6:70: 6:72 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 + let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - _4 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _7 = _2; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - _11 = _7; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21 -- _5 = Len((*_11)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ _7 = _2; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + _11 = _7; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:7:20: 7:21 +- _5 = Len((*_11)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 } bb1: { - StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 - _8 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -- _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ _9 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 + StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 + _8 = _1; // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 +- _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ _9 = const N; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 } bb2: { - _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6 - goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6 + _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:9:5: 9:6 + goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 } bb3: { - _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:11 - goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6 + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:10:9: 10:11 + goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 } bb4: { - StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+5:5: +5:6 - return; // scope 0 at $DIR/lower_array_len.rs:+6:2: +6:2 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:11:5: 11:6 + return; // scope 0 at $DIR/lower_array_len.rs:12:2: 12:2 } } diff --git a/src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff b/src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff index 049bbeac867f9..d6c1c92cd9177 100644 --- a/src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff +++ b/src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff @@ -2,67 +2,67 @@ + // MIR for `array_bound` after NormalizeArrayLen fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:36: +0:41 - debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:+0:50: +0:55 - let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:+0:70: +0:72 - let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 - let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:6:36: 6:41 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:6:50: 6:55 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:6:70: 6:72 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 + let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - _4 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _11 = _7; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21 -- _5 = Len((*_6)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _5 = Len((*_11)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ _11 = _7; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:7:20: 7:21 +- _5 = Len((*_6)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ _5 = Len((*_11)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 } bb1: { - StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - switchInt(move _3) -> [false: bb4, otherwise: bb2]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 + StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + switchInt(move _3) -> [false: bb4, otherwise: bb2]; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 } bb2: { - StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 - _8 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 - _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb3; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 + StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 + _8 = _1; // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 + _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb3; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 } bb3: { - _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6 - goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6 + _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:9:5: 9:6 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 } bb4: { - _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:11 - goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6 + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:10:9: 10:11 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 } bb5: { - StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+5:5: +5:6 - return; // scope 0 at $DIR/lower_array_len.rs:+6:2: +6:2 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:11:5: 11:6 + return; // scope 0 at $DIR/lower_array_len.rs:12:2: 12:2 } } diff --git a/src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff b/src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff index 8312db6b37b35..887c7b01f4327 100644 --- a/src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff +++ b/src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff @@ -2,69 +2,69 @@ + // MIR for `array_bound` after SimplifyLocals fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:36: +0:41 - debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:+0:50: +0:55 - let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:+0:70: +0:72 - let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -- let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ let _6: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -+ let mut _7: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ let mut _8: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:6:36: 6:41 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:6:50: 6:55 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:6:70: 6:72 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 +- let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 +- let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 +- let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ let _6: usize; // in scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 ++ let mut _7: usize; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ let mut _8: bool; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - _4 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21 - _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:7:20: 7:21 + _5 = const N; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 } bb1: { -- StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -- _8 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -- _9 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -+ _6 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -+ _7 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ _8 = Lt(_6, _7); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 +- StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 +- _8 = _1; // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 +- _9 = const N; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 +- _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 +- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 ++ _6 = _1; // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 ++ _7 = const N; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ _8 = Lt(_6, _7); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 } bb2: { -- _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6 -+ _0 = (*_2)[_6]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6 - goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6 +- _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 +- StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:9:5: 9:6 ++ _0 = (*_2)[_6]; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:9:5: 9:6 + goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 } bb3: { - _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:11 - goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6 + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:10:9: 10:11 + goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 } bb4: { - StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+5:5: +5:6 - return; // scope 0 at $DIR/lower_array_len.rs:+6:2: +6:2 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:11:5: 11:6 + return; // scope 0 at $DIR/lower_array_len.rs:12:2: 12:2 } } diff --git a/src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff b/src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff index 401d4bac61e00..5622d48453213 100644 --- a/src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff +++ b/src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff @@ -2,78 +2,78 @@ + // MIR for `array_bound_mut` after InstCombine fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:40: +0:45 - debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:+0:54: +0:59 - let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:+0:78: +0:80 - let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 - let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 - let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 - let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 - let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:17:40: 17:45 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:17:54: 17:59 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:17:78: 17:80 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 + let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 + let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - _4 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - _14 = _7; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21 -- _5 = Len((*_14)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + _14 = _7; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:18:20: 18:21 +- _5 = Len((*_14)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 } bb1: { - StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 - _8 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -- _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ _9 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 + StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 + _8 = _1; // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 +- _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ _9 = const N; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 } bb2: { - _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6 - goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6 + _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:20:5: 20:6 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 } bb3: { - StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 - _11 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 -- _12 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -+ _12 = const N; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 - _13 = Lt(_11, _12); // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 - assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> bb4; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 + StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 + _11 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 +- _12 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ _12 = const N; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + _13 = Lt(_11, _12); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> bb4; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 } bb4: { - (*_2)[_11] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:22 - StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+4:22: +4:23 - _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+6:9: +6:11 - goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6 + (*_2)[_11] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:22 + StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:21:22: 21:23 + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:23:9: 23:11 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 } bb5: { - StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+7:5: +7:6 - return; // scope 0 at $DIR/lower_array_len.rs:+8:2: +8:2 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:24:5: 24:6 + return; // scope 0 at $DIR/lower_array_len.rs:25:2: 25:2 } } diff --git a/src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff b/src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff index 40ec01eeb41a6..11fc20aa693c7 100644 --- a/src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff +++ b/src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff @@ -2,80 +2,80 @@ + // MIR for `array_bound_mut` after NormalizeArrayLen fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:40: +0:45 - debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:+0:54: +0:59 - let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:+0:78: +0:80 - let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 - let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 - let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 - let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -+ let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:17:40: 17:45 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:17:54: 17:59 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:17:78: 17:80 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 + let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 + let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - _4 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _14 = _7; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21 -- _5 = Len((*_6)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _5 = Len((*_14)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ _14 = _7; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:18:20: 18:21 +- _5 = Len((*_6)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ _5 = Len((*_14)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 } bb1: { - StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - switchInt(move _3) -> [false: bb4, otherwise: bb2]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 + StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + switchInt(move _3) -> [false: bb4, otherwise: bb2]; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 } bb2: { - StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 - _8 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 - _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb3; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 + StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 + _8 = _1; // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 + _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb3; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 } bb3: { - _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6 - goto -> bb6; // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6 + _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:20:5: 20:6 + goto -> bb6; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 } bb4: { - StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 - _11 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 - _12 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 - _13 = Lt(_11, _12); // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 - assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> bb5; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 + StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 + _11 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 + _12 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + _13 = Lt(_11, _12); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> bb5; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 } bb5: { - (*_2)[_11] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:22 - StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+4:22: +4:23 - _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+6:9: +6:11 - goto -> bb6; // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6 + (*_2)[_11] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:22 + StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:21:22: 21:23 + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:23:9: 23:11 + goto -> bb6; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 } bb6: { - StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+7:5: +7:6 - return; // scope 0 at $DIR/lower_array_len.rs:+8:2: +8:2 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:24:5: 24:6 + return; // scope 0 at $DIR/lower_array_len.rs:25:2: 25:2 } } diff --git a/src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff b/src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff index 4f241d7c9064b..51d5f1acdab83 100644 --- a/src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff +++ b/src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff @@ -2,92 +2,92 @@ + // MIR for `array_bound_mut` after SimplifyLocals fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:40: +0:45 - debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:+0:54: +0:59 - let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:+0:78: +0:80 - let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -- let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 -- let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -- let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -- let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ let _6: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -+ let mut _7: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ let mut _8: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ let _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 -+ let mut _10: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -+ let mut _11: bool; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:17:40: 17:45 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:17:54: 17:59 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:17:78: 17:80 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 +- let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 +- let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 +- let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 +- let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 +- let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 +- let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ let _6: usize; // in scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 ++ let mut _7: usize; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ let mut _8: bool; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ let _9: usize; // in scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 ++ let mut _10: usize; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ let mut _11: bool; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - _4 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21 - _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:18:20: 18:21 + _5 = const N; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 } bb1: { -- StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -- _8 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -- _9 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -+ _6 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -+ _7 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ _8 = Lt(_6, _7); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 +- StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 +- _8 = _1; // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 +- _9 = const N; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 +- _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 +- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 ++ _6 = _1; // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 ++ _7 = const N; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ _8 = Lt(_6, _7); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 } bb2: { -- _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6 -+ _0 = (*_2)[_6]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6 - goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6 +- _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 +- StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:20:5: 20:6 ++ _0 = (*_2)[_6]; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:20:5: 20:6 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 } bb3: { -- StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 -- _11 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 -- _12 = const N; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -- _13 = Lt(const 0_usize, _12); // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -+ StorageLive(_9); // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 -+ _9 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 -+ _10 = const N; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -+ _11 = Lt(const 0_usize, _10); // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -+ assert(move _11, "index out of bounds: the length is {} but the index is {}", move _10, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 +- StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 +- _11 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 +- _12 = const N; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 +- _13 = Lt(const 0_usize, _12); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ StorageLive(_9); // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 ++ _9 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 ++ _10 = const N; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ _11 = Lt(const 0_usize, _10); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ assert(move _11, "index out of bounds: the length is {} but the index is {}", move _10, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 } bb4: { -- (*_2)[_11] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:22 -- StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+4:22: +4:23 -+ (*_2)[_9] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:22 -+ StorageDead(_9); // scope 0 at $DIR/lower_array_len.rs:+4:22: +4:23 - _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+6:9: +6:11 - goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6 +- (*_2)[_11] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:22 +- StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:21:22: 21:23 ++ (*_2)[_9] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:22 ++ StorageDead(_9); // scope 0 at $DIR/lower_array_len.rs:21:22: 21:23 + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:23:9: 23:11 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 } bb5: { - StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+7:5: +7:6 - return; // scope 0 at $DIR/lower_array_len.rs:+8:2: +8:2 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:24:5: 24:6 + return; // scope 0 at $DIR/lower_array_len.rs:25:2: 25:2 } } diff --git a/src/test/mir-opt/lower_array_len.array_len.InstCombine.diff b/src/test/mir-opt/lower_array_len.array_len.InstCombine.diff index 26f45be17be6f..a818de39bcc84 100644 --- a/src/test/mir-opt/lower_array_len.array_len.InstCombine.diff +++ b/src/test/mir-opt/lower_array_len.array_len.InstCombine.diff @@ -2,26 +2,26 @@ + // MIR for `array_len` after InstCombine fn array_len(_1: &[u8; N]) -> usize { - debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:34: +0:37 - let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:52: +0:57 - let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:30:34: 30:37 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:30:52: 30:57 + let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 bb0: { - StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- _3 = &(*_1); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _3 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - _4 = _3; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8 -- _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14 - return; // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2 + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- _3 = &(*_1); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ _3 = _1; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + _4 = _3; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:31:7: 31:8 +- _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:31:13: 31:14 + return; // scope 0 at $DIR/lower_array_len.rs:32:2: 32:2 } } diff --git a/src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff b/src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff index 3ed68f5f72568..892fdda818ebd 100644 --- a/src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff +++ b/src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff @@ -2,29 +2,29 @@ + // MIR for `array_len` after NormalizeArrayLen fn array_len(_1: &[u8; N]) -> usize { - debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:34: +0:37 - let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:52: +0:57 - let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:30:34: 30:37 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:30:52: 30:57 + let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 bb0: { - StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - _3 = &(*_1); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _4 = _3; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8 -- _0 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + _3 = &(*_1); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ _4 = _3; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:31:7: 31:8 +- _0 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 } bb1: { - StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14 - return; // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:31:13: 31:14 + return; // scope 0 at $DIR/lower_array_len.rs:32:2: 32:2 } } diff --git a/src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff b/src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff index 09d571d20a369..3c26cf32a76c7 100644 --- a/src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff +++ b/src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff @@ -2,21 +2,21 @@ + // MIR for `array_len` after SimplifyLocals fn array_len(_1: &[u8; N]) -> usize { - debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:34: +0:37 - let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:52: +0:57 -- let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:30:34: 30:37 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:30:52: 30:57 +- let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 bb0: { -- StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8 - _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14 - return; // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2 +- StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:31:7: 31:8 + _0 = const N; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:31:13: 31:14 + return; // scope 0 at $DIR/lower_array_len.rs:32:2: 32:2 } } diff --git a/src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff b/src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff index 843da758deb1c..ce12531e84bbf 100644 --- a/src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff +++ b/src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff @@ -2,25 +2,25 @@ + // MIR for `array_len_by_value` after InstCombine fn array_len_by_value(_1: [u8; N]) -> usize { - debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:43: +0:46 - let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:60: +0:65 - let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:37:43: 37:46 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:37:60: 37:65 + let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 bb0: { - StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - _3 = &_1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - _4 = _3; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8 -- _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14 - return; // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2 + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + _3 = &_1; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + _4 = _3; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:38:7: 38:8 +- _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:38:13: 38:14 + return; // scope 0 at $DIR/lower_array_len.rs:39:2: 39:2 } } diff --git a/src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff b/src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff index f0e0cdcfdc0e4..201fffbf0d45a 100644 --- a/src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff +++ b/src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff @@ -2,29 +2,29 @@ + // MIR for `array_len_by_value` after NormalizeArrayLen fn array_len_by_value(_1: [u8; N]) -> usize { - debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:43: +0:46 - let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:60: +0:65 - let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:37:43: 37:46 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:37:60: 37:65 + let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 bb0: { - StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - _3 = &_1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _4 = _3; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8 -- _0 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + _3 = &_1; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ _4 = _3; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:38:7: 38:8 +- _0 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 } bb1: { - StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14 - return; // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:38:13: 38:14 + return; // scope 0 at $DIR/lower_array_len.rs:39:2: 39:2 } } diff --git a/src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff b/src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff index dc1c00b69c138..7a94217fa8b09 100644 --- a/src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff +++ b/src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff @@ -2,21 +2,21 @@ + // MIR for `array_len_by_value` after SimplifyLocals fn array_len_by_value(_1: [u8; N]) -> usize { - debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:43: +0:46 - let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:60: +0:65 -- let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:37:43: 37:46 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:37:60: 37:65 +- let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 bb0: { -- StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8 - _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14 - return; // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2 +- StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:38:7: 38:8 + _0 = const N; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:38:13: 38:14 + return; // scope 0 at $DIR/lower_array_len.rs:39:2: 39:2 } } diff --git a/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff index 6866bcf9b8a7f..1b9e46c6a6d0a 100644 --- a/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff @@ -2,23 +2,23 @@ + // MIR for `align_of` after LowerIntrinsics fn align_of() -> usize { - let mut _0: usize; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:25: +0:30 + let mut _0: usize; // return place in scope 0 at $DIR/lower_intrinsics.rs:18:25: 18:30 bb0: { -- _0 = std::intrinsics::min_align_of::() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42 +- _0 = std::intrinsics::min_align_of::() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:42 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:19:5: 19:40 - // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::min_align_of::}, val: Value() } -+ _0 = AlignOf(T); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42 -+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42 ++ _0 = AlignOf(T); // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:42 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:42 } bb1: { - return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2 + return; // scope 0 at $DIR/lower_intrinsics.rs:20:2: 20:2 } bb2 (cleanup): { - resume; // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/lower_intrinsics.rs:18:1: 20:2 } } diff --git a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff index 032a6a01b7fe2..9bda88ce2c7e8 100644 --- a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff @@ -2,118 +2,118 @@ + // MIR for `discriminant` after LowerIntrinsics fn discriminant(_1: T) -> () { - debug t => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:24: +0:25 - let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:30: +0:30 - let _2: ::Discriminant; // in scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 - let mut _3: &T; // in scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44 - let _4: &T; // in scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44 - let _5: u8; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 - let mut _6: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 - let _7: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 - let _8: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+2:43: +2:44 - let _9: u8; // in scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 - let mut _10: &(); // in scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 - let _11: &(); // in scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 - let _12: (); // in scope 0 at $DIR/lower_intrinsics.rs:+3:43: +3:45 - let _13: isize; // in scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 - let mut _14: &E; // in scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 - let _15: &E; // in scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 - let _16: E; // in scope 0 at $DIR/lower_intrinsics.rs:+4:43: +4:47 - let mut _17: &E; // in scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 - let mut _18: &(); // in scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 - let mut _19: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 + debug t => _1; // in scope 0 at $DIR/lower_intrinsics.rs:73:24: 73:25 + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:73:30: 73:30 + let _2: ::Discriminant; // in scope 0 at $DIR/lower_intrinsics.rs:74:5: 74:45 + let mut _3: &T; // in scope 0 at $DIR/lower_intrinsics.rs:74:42: 74:44 + let _4: &T; // in scope 0 at $DIR/lower_intrinsics.rs:74:42: 74:44 + let _5: u8; // in scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45 + let mut _6: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 + let _7: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 + let _8: i32; // in scope 0 at $DIR/lower_intrinsics.rs:75:43: 75:44 + let _9: u8; // in scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46 + let mut _10: &(); // in scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 + let _11: &(); // in scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 + let _12: (); // in scope 0 at $DIR/lower_intrinsics.rs:76:43: 76:45 + let _13: isize; // in scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48 + let mut _14: &E; // in scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 + let _15: &E; // in scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 + let _16: E; // in scope 0 at $DIR/lower_intrinsics.rs:77:43: 77:47 + let mut _17: &E; // in scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 + let mut _18: &(); // in scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 + let mut _19: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 bb0: { - StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 - StorageLive(_3); // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44 - StorageLive(_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44 - _4 = &_1; // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44 - _3 = &(*_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44 -- _2 = discriminant_value::(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 + StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:74:5: 74:45 + StorageLive(_3); // scope 0 at $DIR/lower_intrinsics.rs:74:42: 74:44 + StorageLive(_4); // scope 0 at $DIR/lower_intrinsics.rs:74:42: 74:44 + _4 = &_1; // scope 0 at $DIR/lower_intrinsics.rs:74:42: 74:44 + _3 = &(*_4); // scope 0 at $DIR/lower_intrinsics.rs:74:42: 74:44 +- _2 = discriminant_value::(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:74:5: 74:45 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:74:5: 74:41 - // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r T) -> ::Discriminant {discriminant_value::}, val: Value() } -+ _2 = discriminant((*_3)); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 -+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 ++ _2 = discriminant((*_3)); // scope 0 at $DIR/lower_intrinsics.rs:74:5: 74:45 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:74:5: 74:45 } bb1: { - StorageDead(_3); // scope 0 at $DIR/lower_intrinsics.rs:+1:44: +1:45 - StorageDead(_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:45: +1:46 - StorageDead(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:45: +1:46 - StorageLive(_5); // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 - StorageLive(_6); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 - StorageLive(_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 - _19 = const discriminant::::promoted[2]; // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 + StorageDead(_3); // scope 0 at $DIR/lower_intrinsics.rs:74:44: 74:45 + StorageDead(_4); // scope 0 at $DIR/lower_intrinsics.rs:74:45: 74:46 + StorageDead(_2); // scope 0 at $DIR/lower_intrinsics.rs:74:45: 74:46 + StorageLive(_5); // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45 + StorageLive(_6); // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 + StorageLive(_7); // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 + _19 = const discriminant::::promoted[2]; // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 // mir::Constant // + span: $DIR/lower_intrinsics.rs:75:42: 75:44 // + literal: Const { ty: &i32, val: Unevaluated(discriminant, [T], Some(promoted[2])) } - _7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 - _6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 -- _5 = discriminant_value::(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 + _7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 + _6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 +- _5 = discriminant_value::(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:75:5: 75:41 - // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r i32) -> ::Discriminant {discriminant_value::}, val: Value() } -+ _5 = discriminant((*_6)); // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 -+ goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 ++ _5 = discriminant((*_6)); // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45 ++ goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45 } bb2: { - StorageDead(_6); // scope 0 at $DIR/lower_intrinsics.rs:+2:44: +2:45 - StorageDead(_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:45: +2:46 - StorageDead(_5); // scope 0 at $DIR/lower_intrinsics.rs:+2:45: +2:46 - StorageLive(_9); // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 - StorageLive(_10); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 - StorageLive(_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 - _18 = const discriminant::::promoted[1]; // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 + StorageDead(_6); // scope 0 at $DIR/lower_intrinsics.rs:75:44: 75:45 + StorageDead(_7); // scope 0 at $DIR/lower_intrinsics.rs:75:45: 75:46 + StorageDead(_5); // scope 0 at $DIR/lower_intrinsics.rs:75:45: 75:46 + StorageLive(_9); // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46 + StorageLive(_10); // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 + StorageLive(_11); // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 + _18 = const discriminant::::promoted[1]; // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 // mir::Constant // + span: $DIR/lower_intrinsics.rs:76:42: 76:45 // + literal: Const { ty: &(), val: Unevaluated(discriminant, [T], Some(promoted[1])) } - _11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 - _10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 -- _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 + _11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 + _10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 +- _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:76:5: 76:41 - // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value() } -+ _9 = discriminant((*_10)); // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 -+ goto -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 ++ _9 = discriminant((*_10)); // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46 ++ goto -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46 } bb3: { - StorageDead(_10); // scope 0 at $DIR/lower_intrinsics.rs:+3:45: +3:46 - StorageDead(_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:46: +3:47 - StorageDead(_9); // scope 0 at $DIR/lower_intrinsics.rs:+3:46: +3:47 - StorageLive(_13); // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 - StorageLive(_14); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 - StorageLive(_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 - _17 = const discriminant::::promoted[0]; // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 + StorageDead(_10); // scope 0 at $DIR/lower_intrinsics.rs:76:45: 76:46 + StorageDead(_11); // scope 0 at $DIR/lower_intrinsics.rs:76:46: 76:47 + StorageDead(_9); // scope 0 at $DIR/lower_intrinsics.rs:76:46: 76:47 + StorageLive(_13); // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48 + StorageLive(_14); // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 + StorageLive(_15); // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 + _17 = const discriminant::::promoted[0]; // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 // mir::Constant // + span: $DIR/lower_intrinsics.rs:77:42: 77:47 // + literal: Const { ty: &E, val: Unevaluated(discriminant, [T], Some(promoted[0])) } - _15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 - _14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 -- _13 = discriminant_value::(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 + _15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 + _14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 +- _13 = discriminant_value::(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:77:5: 77:41 - // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r E) -> ::Discriminant {discriminant_value::}, val: Value() } -+ _13 = discriminant((*_14)); // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 -+ goto -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 ++ _13 = discriminant((*_14)); // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48 ++ goto -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48 } bb4: { - StorageDead(_14); // scope 0 at $DIR/lower_intrinsics.rs:+4:47: +4:48 - StorageDead(_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:48: +4:49 - StorageDead(_13); // scope 0 at $DIR/lower_intrinsics.rs:+4:48: +4:49 - _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:+0:30: +5:2 - drop(_1) -> bb5; // scope 0 at $DIR/lower_intrinsics.rs:+5:1: +5:2 + StorageDead(_14); // scope 0 at $DIR/lower_intrinsics.rs:77:47: 77:48 + StorageDead(_15); // scope 0 at $DIR/lower_intrinsics.rs:77:48: 77:49 + StorageDead(_13); // scope 0 at $DIR/lower_intrinsics.rs:77:48: 77:49 + _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:73:30: 78:2 + drop(_1) -> bb5; // scope 0 at $DIR/lower_intrinsics.rs:78:1: 78:2 } bb5: { - return; // scope 0 at $DIR/lower_intrinsics.rs:+5:2: +5:2 + return; // scope 0 at $DIR/lower_intrinsics.rs:78:2: 78:2 } bb6 (cleanup): { - resume; // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +5:2 + resume; // scope 0 at $DIR/lower_intrinsics.rs:73:1: 78:2 } } diff --git a/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir b/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir index 9e4de2ac068e5..a12aa1d6686a9 100644 --- a/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir +++ b/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir @@ -1,32 +1,32 @@ // MIR for `f_u64` before PreCodegen fn f_u64() -> () { - let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:16: +0:16 - let mut _1: u64; // in scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:21 + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:39:16: 39:16 + let mut _1: u64; // in scope 0 at $DIR/lower_intrinsics.rs:40:5: 40:21 scope 1 (inlined f_dispatch::) { // at $DIR/lower_intrinsics.rs:40:5: 40:21 - debug t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:+5:22: +5:23 - let _2: (); // in scope 1 at $DIR/lower_intrinsics.rs:+9:9: +9:21 - let mut _3: u64; // in scope 1 at $DIR/lower_intrinsics.rs:+9:19: +9:20 + debug t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:44:22: 44:23 + let _2: (); // in scope 1 at $DIR/lower_intrinsics.rs:48:9: 48:21 + let mut _3: u64; // in scope 1 at $DIR/lower_intrinsics.rs:48:19: 48:20 scope 2 (inlined std::mem::size_of::) { // at $DIR/lower_intrinsics.rs:45:8: 45:32 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:21 - _1 = const 0_u64; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:21 - StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+9:9: +9:21 - StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+9:19: +9:20 - _3 = move _1; // scope 1 at $DIR/lower_intrinsics.rs:+9:19: +9:20 - _2 = f_non_zst::(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+9:9: +9:21 + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:40:5: 40:21 + _1 = const 0_u64; // scope 0 at $DIR/lower_intrinsics.rs:40:5: 40:21 + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:48:9: 48:21 + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:48:19: 48:20 + _3 = move _1; // scope 1 at $DIR/lower_intrinsics.rs:48:19: 48:20 + _2 = f_non_zst::(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:48:9: 48:21 // mir::Constant // + span: $DIR/lower_intrinsics.rs:48:9: 48:18 // + literal: Const { ty: fn(u64) {f_non_zst::}, val: Value() } } bb1: { - StorageDead(_3); // scope 1 at $DIR/lower_intrinsics.rs:+9:20: +9:21 - StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:+9:21: +9:22 - StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:21 - return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2 + StorageDead(_3); // scope 1 at $DIR/lower_intrinsics.rs:48:20: 48:21 + StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:48:21: 48:22 + StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:40:5: 40:21 + return; // scope 0 at $DIR/lower_intrinsics.rs:41:2: 41:2 } } diff --git a/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir b/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir index 9a6c0457f92c9..49e3b9144a59a 100644 --- a/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir +++ b/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir @@ -1,30 +1,30 @@ // MIR for `f_unit` before PreCodegen fn f_unit() -> () { - let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:17: +0:17 - let mut _1: (); // in scope 0 at $DIR/lower_intrinsics.rs:+1:16: +1:18 + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:33:17: 33:17 + let mut _1: (); // in scope 0 at $DIR/lower_intrinsics.rs:34:16: 34:18 scope 1 (inlined f_dispatch::<()>) { // at $DIR/lower_intrinsics.rs:34:5: 34:19 - debug t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:+11:22: +11:23 - let _2: (); // in scope 1 at $DIR/lower_intrinsics.rs:+13:9: +13:17 - let mut _3: (); // in scope 1 at $DIR/lower_intrinsics.rs:+13:15: +13:16 + debug t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:44:22: 44:23 + let _2: (); // in scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17 + let mut _3: (); // in scope 1 at $DIR/lower_intrinsics.rs:46:15: 46:16 scope 2 (inlined std::mem::size_of::<()>) { // at $DIR/lower_intrinsics.rs:45:8: 45:32 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:16: +1:18 - StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+13:9: +13:17 - StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+13:15: +13:16 - _2 = f_zst::<()>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+13:9: +13:17 + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:34:16: 34:18 + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17 + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:46:15: 46:16 + _2 = f_zst::<()>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17 // mir::Constant // + span: $DIR/lower_intrinsics.rs:46:9: 46:14 // + literal: Const { ty: fn(()) {f_zst::<()>}, val: Value() } } bb1: { - StorageDead(_3); // scope 1 at $DIR/lower_intrinsics.rs:+13:16: +13:17 - StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:+13:17: +13:18 - StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:18: +1:19 - return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2 + StorageDead(_3); // scope 1 at $DIR/lower_intrinsics.rs:46:16: 46:17 + StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:46:17: 46:18 + StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:34:18: 34:19 + return; // scope 0 at $DIR/lower_intrinsics.rs:35:2: 35:2 } } diff --git a/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff index 50c86e61949dd..6c99e1b7ca6cb 100644 --- a/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff @@ -2,32 +2,32 @@ + // MIR for `forget` after LowerIntrinsics fn forget(_1: T) -> () { - debug t => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:18: +0:19 - let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:24: +0:24 - let mut _2: T; // in scope 0 at $DIR/lower_intrinsics.rs:+1:30: +1:31 + debug t => _1; // in scope 0 at $DIR/lower_intrinsics.rs:23:18: 23:19 + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:23:24: 23:24 + let mut _2: T; // in scope 0 at $DIR/lower_intrinsics.rs:24:30: 24:31 bb0: { - StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:30: +1:31 - _2 = move _1; // scope 0 at $DIR/lower_intrinsics.rs:+1:30: +1:31 -- _0 = std::intrinsics::forget::(move _2) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32 + StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:24:30: 24:31 + _2 = move _1; // scope 0 at $DIR/lower_intrinsics.rs:24:30: 24:31 +- _0 = std::intrinsics::forget::(move _2) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:24:5: 24:32 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:24:5: 24:29 - // + literal: Const { ty: extern "rust-intrinsic" fn(T) {std::intrinsics::forget::}, val: Value() } -+ _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32 -+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32 ++ _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:24:5: 24:32 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:24:5: 24:32 } bb1: { - StorageDead(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:31: +1:32 - goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:1: +2:2 + StorageDead(_2); // scope 0 at $DIR/lower_intrinsics.rs:24:31: 24:32 + goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:25:1: 25:2 } bb2: { - return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2 + return; // scope 0 at $DIR/lower_intrinsics.rs:25:2: 25:2 } bb3 (cleanup): { - resume; // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/lower_intrinsics.rs:23:1: 25:2 } } diff --git a/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff index 01591e17624d7..41dac17dcb640 100644 --- a/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff @@ -2,34 +2,34 @@ + // MIR for `non_const` after LowerIntrinsics fn non_const() -> usize { - let mut _0: usize; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:26: +0:31 - let _1: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}; // in scope 0 at $DIR/lower_intrinsics.rs:+2:9: +2:18 - let mut _2: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}; // in scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:14 + let mut _0: usize; // return place in scope 0 at $DIR/lower_intrinsics.rs:60:26: 60:31 + let _1: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}; // in scope 0 at $DIR/lower_intrinsics.rs:62:9: 62:18 + let mut _2: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}; // in scope 0 at $DIR/lower_intrinsics.rs:63:5: 63:14 scope 1 { - debug size_of_t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:18 + debug size_of_t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:62:9: 62:18 } bb0: { - StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+2:9: +2:18 - _1 = std::intrinsics::size_of::; // scope 0 at $DIR/lower_intrinsics.rs:+2:21: +2:51 + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:62:9: 62:18 + _1 = std::intrinsics::size_of::; // scope 0 at $DIR/lower_intrinsics.rs:62:21: 62:51 // mir::Constant // + span: $DIR/lower_intrinsics.rs:62:21: 62:51 // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}, val: Value() } - StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:14 - _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:14 -- _0 = move _2() -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:16 -+ _0 = SizeOf(T); // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:16 -+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:16 + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:63:5: 63:14 + _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:63:5: 63:14 +- _0 = move _2() -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:63:5: 63:16 ++ _0 = SizeOf(T); // scope 1 at $DIR/lower_intrinsics.rs:63:5: 63:16 ++ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:63:5: 63:16 } bb1: { - StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:+3:15: +3:16 - StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:+4:1: +4:2 - return; // scope 0 at $DIR/lower_intrinsics.rs:+4:2: +4:2 + StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:63:15: 63:16 + StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:64:1: 64:2 + return; // scope 0 at $DIR/lower_intrinsics.rs:64:2: 64:2 } bb2 (cleanup): { - resume; // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +4:2 + resume; // scope 0 at $DIR/lower_intrinsics.rs:60:1: 64:2 } } diff --git a/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff index 7bc24fe7d673f..cd6da6f1dc745 100644 --- a/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff @@ -2,23 +2,23 @@ + // MIR for `size_of` after LowerIntrinsics fn size_of() -> usize { - let mut _0: usize; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:24: +0:29 + let mut _0: usize; // return place in scope 0 at $DIR/lower_intrinsics.rs:13:24: 13:29 bb0: { -- _0 = std::intrinsics::size_of::() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37 +- _0 = std::intrinsics::size_of::() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:14:5: 14:37 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:14:5: 14:35 - // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}, val: Value() } -+ _0 = SizeOf(T); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37 -+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37 ++ _0 = SizeOf(T); // scope 0 at $DIR/lower_intrinsics.rs:14:5: 14:37 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:14:5: 14:37 } bb1: { - return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2 + return; // scope 0 at $DIR/lower_intrinsics.rs:15:2: 15:2 } bb2 (cleanup): { - resume; // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/lower_intrinsics.rs:13:1: 15:2 } } diff --git a/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff index 581926ab163e8..0ce8d85070c70 100644 --- a/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff @@ -2,25 +2,25 @@ + // MIR for `unreachable` after LowerIntrinsics fn unreachable() -> ! { - let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:25: +0:26 - let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:27: +2:2 - let _2: (); // in scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:45 - let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:45 + let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:28:25: 28:26 + let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:28:27: 30:2 + let _2: (); // in scope 0 at $DIR/lower_intrinsics.rs:29:14: 29:45 + let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:29:14: 29:45 scope 1 { } bb0: { - StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:47 - StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 -- _3 = std::intrinsics::unreachable(); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 + StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:29:5: 29:47 + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:29:14: 29:45 +- _3 = std::intrinsics::unreachable(); // scope 1 at $DIR/lower_intrinsics.rs:29:14: 29:45 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:29:14: 29:43 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value() } -+ unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 ++ unreachable; // scope 1 at $DIR/lower_intrinsics.rs:29:14: 29:45 } bb1 (cleanup): { - resume; // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/lower_intrinsics.rs:28:1: 30:2 } } diff --git a/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff index b0fa55bdd4c6d..ebe240121cc5f 100644 --- a/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff @@ -2,86 +2,86 @@ + // MIR for `wrapping` after LowerIntrinsics fn wrapping(_1: i32, _2: i32) -> () { - debug a => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:17: +0:18 - debug b => _2; // in scope 0 at $DIR/lower_intrinsics.rs:+0:25: +0:26 - let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:33: +0:33 - let _3: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:11 - let mut _4: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+1:45: +1:46 - let mut _5: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+1:48: +1:49 - let mut _7: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+2:45: +2:46 - let mut _8: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+2:48: +2:49 - let mut _10: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+3:45: +3:46 - let mut _11: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+3:48: +3:49 + debug a => _1; // in scope 0 at $DIR/lower_intrinsics.rs:6:17: 6:18 + debug b => _2; // in scope 0 at $DIR/lower_intrinsics.rs:6:25: 6:26 + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:6:33: 6:33 + let _3: i32; // in scope 0 at $DIR/lower_intrinsics.rs:7:9: 7:11 + let mut _4: i32; // in scope 0 at $DIR/lower_intrinsics.rs:7:45: 7:46 + let mut _5: i32; // in scope 0 at $DIR/lower_intrinsics.rs:7:48: 7:49 + let mut _7: i32; // in scope 0 at $DIR/lower_intrinsics.rs:8:45: 8:46 + let mut _8: i32; // in scope 0 at $DIR/lower_intrinsics.rs:8:48: 8:49 + let mut _10: i32; // in scope 0 at $DIR/lower_intrinsics.rs:9:45: 9:46 + let mut _11: i32; // in scope 0 at $DIR/lower_intrinsics.rs:9:48: 9:49 scope 1 { - debug _x => _3; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:11 - let _6: i32; // in scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:11 + debug _x => _3; // in scope 1 at $DIR/lower_intrinsics.rs:7:9: 7:11 + let _6: i32; // in scope 1 at $DIR/lower_intrinsics.rs:8:9: 8:11 scope 2 { - debug _y => _6; // in scope 2 at $DIR/lower_intrinsics.rs:+2:9: +2:11 - let _9: i32; // in scope 2 at $DIR/lower_intrinsics.rs:+3:9: +3:11 + debug _y => _6; // in scope 2 at $DIR/lower_intrinsics.rs:8:9: 8:11 + let _9: i32; // in scope 2 at $DIR/lower_intrinsics.rs:9:9: 9:11 scope 3 { - debug _z => _9; // in scope 3 at $DIR/lower_intrinsics.rs:+3:9: +3:11 + debug _z => _9; // in scope 3 at $DIR/lower_intrinsics.rs:9:9: 9:11 } } } bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:11 - StorageLive(_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:45: +1:46 - _4 = _1; // scope 0 at $DIR/lower_intrinsics.rs:+1:45: +1:46 - StorageLive(_5); // scope 0 at $DIR/lower_intrinsics.rs:+1:48: +1:49 - _5 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:48: +1:49 -- _3 = wrapping_add::(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:50 + StorageLive(_3); // scope 0 at $DIR/lower_intrinsics.rs:7:9: 7:11 + StorageLive(_4); // scope 0 at $DIR/lower_intrinsics.rs:7:45: 7:46 + _4 = _1; // scope 0 at $DIR/lower_intrinsics.rs:7:45: 7:46 + StorageLive(_5); // scope 0 at $DIR/lower_intrinsics.rs:7:48: 7:49 + _5 = _2; // scope 0 at $DIR/lower_intrinsics.rs:7:48: 7:49 +- _3 = wrapping_add::(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:7:14: 7:44 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_add::}, val: Value() } -+ _3 = Add(move _4, move _5); // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:50 -+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:50 ++ _3 = Add(move _4, move _5); // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50 } bb1: { - StorageDead(_5); // scope 0 at $DIR/lower_intrinsics.rs:+1:49: +1:50 - StorageDead(_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:49: +1:50 - StorageLive(_6); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:11 - StorageLive(_7); // scope 1 at $DIR/lower_intrinsics.rs:+2:45: +2:46 - _7 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+2:45: +2:46 - StorageLive(_8); // scope 1 at $DIR/lower_intrinsics.rs:+2:48: +2:49 - _8 = _2; // scope 1 at $DIR/lower_intrinsics.rs:+2:48: +2:49 -- _6 = wrapping_sub::(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:50 + StorageDead(_5); // scope 0 at $DIR/lower_intrinsics.rs:7:49: 7:50 + StorageDead(_4); // scope 0 at $DIR/lower_intrinsics.rs:7:49: 7:50 + StorageLive(_6); // scope 1 at $DIR/lower_intrinsics.rs:8:9: 8:11 + StorageLive(_7); // scope 1 at $DIR/lower_intrinsics.rs:8:45: 8:46 + _7 = _1; // scope 1 at $DIR/lower_intrinsics.rs:8:45: 8:46 + StorageLive(_8); // scope 1 at $DIR/lower_intrinsics.rs:8:48: 8:49 + _8 = _2; // scope 1 at $DIR/lower_intrinsics.rs:8:48: 8:49 +- _6 = wrapping_sub::(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:8:14: 8:44 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_sub::}, val: Value() } -+ _6 = Sub(move _7, move _8); // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:50 -+ goto -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:50 ++ _6 = Sub(move _7, move _8); // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50 ++ goto -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50 } bb2: { - StorageDead(_8); // scope 1 at $DIR/lower_intrinsics.rs:+2:49: +2:50 - StorageDead(_7); // scope 1 at $DIR/lower_intrinsics.rs:+2:49: +2:50 - StorageLive(_9); // scope 2 at $DIR/lower_intrinsics.rs:+3:9: +3:11 - StorageLive(_10); // scope 2 at $DIR/lower_intrinsics.rs:+3:45: +3:46 - _10 = _1; // scope 2 at $DIR/lower_intrinsics.rs:+3:45: +3:46 - StorageLive(_11); // scope 2 at $DIR/lower_intrinsics.rs:+3:48: +3:49 - _11 = _2; // scope 2 at $DIR/lower_intrinsics.rs:+3:48: +3:49 -- _9 = wrapping_mul::(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:50 + StorageDead(_8); // scope 1 at $DIR/lower_intrinsics.rs:8:49: 8:50 + StorageDead(_7); // scope 1 at $DIR/lower_intrinsics.rs:8:49: 8:50 + StorageLive(_9); // scope 2 at $DIR/lower_intrinsics.rs:9:9: 9:11 + StorageLive(_10); // scope 2 at $DIR/lower_intrinsics.rs:9:45: 9:46 + _10 = _1; // scope 2 at $DIR/lower_intrinsics.rs:9:45: 9:46 + StorageLive(_11); // scope 2 at $DIR/lower_intrinsics.rs:9:48: 9:49 + _11 = _2; // scope 2 at $DIR/lower_intrinsics.rs:9:48: 9:49 +- _9 = wrapping_mul::(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:9:14: 9:44 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_mul::}, val: Value() } -+ _9 = Mul(move _10, move _11); // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:50 -+ goto -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:50 ++ _9 = Mul(move _10, move _11); // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50 ++ goto -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50 } bb3: { - StorageDead(_11); // scope 2 at $DIR/lower_intrinsics.rs:+3:49: +3:50 - StorageDead(_10); // scope 2 at $DIR/lower_intrinsics.rs:+3:49: +3:50 - _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:+0:33: +4:2 - StorageDead(_9); // scope 2 at $DIR/lower_intrinsics.rs:+4:1: +4:2 - StorageDead(_6); // scope 1 at $DIR/lower_intrinsics.rs:+4:1: +4:2 - StorageDead(_3); // scope 0 at $DIR/lower_intrinsics.rs:+4:1: +4:2 - return; // scope 0 at $DIR/lower_intrinsics.rs:+4:2: +4:2 + StorageDead(_11); // scope 2 at $DIR/lower_intrinsics.rs:9:49: 9:50 + StorageDead(_10); // scope 2 at $DIR/lower_intrinsics.rs:9:49: 9:50 + _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:6:33: 10:2 + StorageDead(_9); // scope 2 at $DIR/lower_intrinsics.rs:10:1: 10:2 + StorageDead(_6); // scope 1 at $DIR/lower_intrinsics.rs:10:1: 10:2 + StorageDead(_3); // scope 0 at $DIR/lower_intrinsics.rs:10:1: 10:2 + return; // scope 0 at $DIR/lower_intrinsics.rs:10:2: 10:2 } bb4 (cleanup): { - resume; // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +4:2 + resume; // scope 0 at $DIR/lower_intrinsics.rs:6:1: 10:2 } } diff --git a/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff b/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff index 46fccba56f7c8..96404f0506cf2 100644 --- a/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff +++ b/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff @@ -2,62 +2,62 @@ + // MIR for `bound` after LowerSliceLenCalls fn bound(_1: usize, _2: &[u8]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_slice_len.rs:+0:14: +0:19 - debug slice => _2; // in scope 0 at $DIR/lower_slice_len.rs:+0:28: +0:33 - let mut _0: u8; // return place in scope 0 at $DIR/lower_slice_len.rs:+0:45: +0:47 - let mut _3: bool; // in scope 0 at $DIR/lower_slice_len.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_slice_len.rs:+1:8: +1:13 - let mut _5: usize; // in scope 0 at $DIR/lower_slice_len.rs:+1:16: +1:27 - let mut _6: &[u8]; // in scope 0 at $DIR/lower_slice_len.rs:+1:16: +1:27 - let _7: usize; // in scope 0 at $DIR/lower_slice_len.rs:+2:15: +2:20 - let mut _8: usize; // in scope 0 at $DIR/lower_slice_len.rs:+2:9: +2:21 - let mut _9: bool; // in scope 0 at $DIR/lower_slice_len.rs:+2:9: +2:21 + debug index => _1; // in scope 0 at $DIR/lower_slice_len.rs:4:14: 4:19 + debug slice => _2; // in scope 0 at $DIR/lower_slice_len.rs:4:28: 4:33 + let mut _0: u8; // return place in scope 0 at $DIR/lower_slice_len.rs:4:45: 4:47 + let mut _3: bool; // in scope 0 at $DIR/lower_slice_len.rs:5:8: 5:27 + let mut _4: usize; // in scope 0 at $DIR/lower_slice_len.rs:5:8: 5:13 + let mut _5: usize; // in scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 + let _7: usize; // in scope 0 at $DIR/lower_slice_len.rs:6:15: 6:20 + let mut _8: usize; // in scope 0 at $DIR/lower_slice_len.rs:6:9: 6:21 + let mut _9: bool; // in scope 0 at $DIR/lower_slice_len.rs:6:9: 6:21 bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_slice_len.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_slice_len.rs:+1:8: +1:13 - _4 = _1; // scope 0 at $DIR/lower_slice_len.rs:+1:8: +1:13 - StorageLive(_5); // scope 0 at $DIR/lower_slice_len.rs:+1:16: +1:27 - StorageLive(_6); // scope 0 at $DIR/lower_slice_len.rs:+1:16: +1:27 - _6 = &(*_2); // scope 0 at $DIR/lower_slice_len.rs:+1:16: +1:27 -- _5 = core::slice::::len(move _6) -> bb1; // scope 0 at $DIR/lower_slice_len.rs:+1:16: +1:27 + StorageLive(_3); // scope 0 at $DIR/lower_slice_len.rs:5:8: 5:27 + StorageLive(_4); // scope 0 at $DIR/lower_slice_len.rs:5:8: 5:13 + _4 = _1; // scope 0 at $DIR/lower_slice_len.rs:5:8: 5:13 + StorageLive(_5); // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 + StorageLive(_6); // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 + _6 = &(*_2); // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 +- _5 = core::slice::::len(move _6) -> bb1; // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 - // mir::Constant - // + span: $DIR/lower_slice_len.rs:5:22: 5:25 - // + literal: Const { ty: for<'r> fn(&'r [u8]) -> usize {core::slice::::len}, val: Value() } -+ _5 = Len((*_6)); // scope 0 at $DIR/lower_slice_len.rs:+1:16: +1:27 -+ goto -> bb1; // scope 0 at $DIR/lower_slice_len.rs:+1:16: +1:27 ++ _5 = Len((*_6)); // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 ++ goto -> bb1; // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 } bb1: { - StorageDead(_6); // scope 0 at $DIR/lower_slice_len.rs:+1:26: +1:27 - _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_slice_len.rs:+1:8: +1:27 - StorageDead(_5); // scope 0 at $DIR/lower_slice_len.rs:+1:26: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_slice_len.rs:+1:26: +1:27 - switchInt(move _3) -> [false: bb4, otherwise: bb2]; // scope 0 at $DIR/lower_slice_len.rs:+1:8: +1:27 + StorageDead(_6); // scope 0 at $DIR/lower_slice_len.rs:5:26: 5:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_slice_len.rs:5:8: 5:27 + StorageDead(_5); // scope 0 at $DIR/lower_slice_len.rs:5:26: 5:27 + StorageDead(_4); // scope 0 at $DIR/lower_slice_len.rs:5:26: 5:27 + switchInt(move _3) -> [false: bb4, otherwise: bb2]; // scope 0 at $DIR/lower_slice_len.rs:5:8: 5:27 } bb2: { - StorageLive(_7); // scope 0 at $DIR/lower_slice_len.rs:+2:15: +2:20 - _7 = _1; // scope 0 at $DIR/lower_slice_len.rs:+2:15: +2:20 - _8 = Len((*_2)); // scope 0 at $DIR/lower_slice_len.rs:+2:9: +2:21 - _9 = Lt(_7, _8); // scope 0 at $DIR/lower_slice_len.rs:+2:9: +2:21 - assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb3; // scope 0 at $DIR/lower_slice_len.rs:+2:9: +2:21 + StorageLive(_7); // scope 0 at $DIR/lower_slice_len.rs:6:15: 6:20 + _7 = _1; // scope 0 at $DIR/lower_slice_len.rs:6:15: 6:20 + _8 = Len((*_2)); // scope 0 at $DIR/lower_slice_len.rs:6:9: 6:21 + _9 = Lt(_7, _8); // scope 0 at $DIR/lower_slice_len.rs:6:9: 6:21 + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb3; // scope 0 at $DIR/lower_slice_len.rs:6:9: 6:21 } bb3: { - _0 = (*_2)[_7]; // scope 0 at $DIR/lower_slice_len.rs:+2:9: +2:21 - StorageDead(_7); // scope 0 at $DIR/lower_slice_len.rs:+3:5: +3:6 - goto -> bb5; // scope 0 at $DIR/lower_slice_len.rs:+1:5: +5:6 + _0 = (*_2)[_7]; // scope 0 at $DIR/lower_slice_len.rs:6:9: 6:21 + StorageDead(_7); // scope 0 at $DIR/lower_slice_len.rs:7:5: 7:6 + goto -> bb5; // scope 0 at $DIR/lower_slice_len.rs:5:5: 9:6 } bb4: { - _0 = const 42_u8; // scope 0 at $DIR/lower_slice_len.rs:+4:9: +4:11 - goto -> bb5; // scope 0 at $DIR/lower_slice_len.rs:+1:5: +5:6 + _0 = const 42_u8; // scope 0 at $DIR/lower_slice_len.rs:8:9: 8:11 + goto -> bb5; // scope 0 at $DIR/lower_slice_len.rs:5:5: 9:6 } bb5: { - StorageDead(_3); // scope 0 at $DIR/lower_slice_len.rs:+5:5: +5:6 - return; // scope 0 at $DIR/lower_slice_len.rs:+6:2: +6:2 + StorageDead(_3); // scope 0 at $DIR/lower_slice_len.rs:9:5: 9:6 + return; // scope 0 at $DIR/lower_slice_len.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 25ab0c9f7f4c0..c2e422f800250 100644 --- a/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -2,271 +2,271 @@ + // MIR for `complicated_match` after ElaborateDrops fn complicated_match(_1: bool, _2: (bool, bool, String)) -> i32 { - debug cond => _1; // in scope 0 at $DIR/match-arm-scopes.rs:+0:22: +0:26 - debug items => _2; // in scope 0 at $DIR/match-arm-scopes.rs:+0:34: +0:39 - let mut _0: i32; // return place in scope 0 at $DIR/match-arm-scopes.rs:+0:66: +0:69 - let mut _3: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:+1:11: +1:16 - let mut _4: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:+1:11: +1:16 - let _5: bool; // in scope 0 at $DIR/match-arm-scopes.rs:+2:17: +2:18 - let _6: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:+2:17: +2:18 - let _7: std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:+2:20: +2:21 - let _8: &std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:+2:20: +2:21 - let mut _9: bool; // in scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73 - let mut _10: bool; // in scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49 - let mut _11: !; // in scope 0 at $DIR/match-arm-scopes.rs:+2:52: +2:60 - let mut _12: bool; // in scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73 - let mut _13: bool; // in scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49 - let mut _14: !; // in scope 0 at $DIR/match-arm-scopes.rs:+2:52: +2:60 - let _15: bool; // in scope 0 at $DIR/match-arm-scopes.rs:+3:16: +3:17 - let _16: std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:+3:19: +3:20 + debug cond => _1; // in scope 0 at $DIR/match-arm-scopes.rs:13:22: 13:26 + debug items => _2; // in scope 0 at $DIR/match-arm-scopes.rs:13:34: 13:39 + let mut _0: i32; // return place in scope 0 at $DIR/match-arm-scopes.rs:13:66: 13:69 + let mut _3: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16 + let mut _4: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16 + let _5: bool; // in scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18 + let _6: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18 + let _7: std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21 + let _8: &std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21 + let mut _9: bool; // in scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73 + let mut _10: bool; // in scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49 + let mut _11: !; // in scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60 + let mut _12: bool; // in scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73 + let mut _13: bool; // in scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49 + let mut _14: !; // in scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60 + let _15: bool; // in scope 0 at $DIR/match-arm-scopes.rs:16:16: 16:17 + let _16: std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:16:19: 16:20 scope 1 { - debug a => _5; // in scope 1 at $DIR/match-arm-scopes.rs:+2:17: +2:18 - debug a => _6; // in scope 1 at $DIR/match-arm-scopes.rs:+2:17: +2:18 - debug s => _7; // in scope 1 at $DIR/match-arm-scopes.rs:+2:20: +2:21 - debug s => _8; // in scope 1 at $DIR/match-arm-scopes.rs:+2:20: +2:21 + debug a => _5; // in scope 1 at $DIR/match-arm-scopes.rs:15:17: 15:18 + debug a => _6; // in scope 1 at $DIR/match-arm-scopes.rs:15:17: 15:18 + debug s => _7; // in scope 1 at $DIR/match-arm-scopes.rs:15:20: 15:21 + debug s => _8; // in scope 1 at $DIR/match-arm-scopes.rs:15:20: 15:21 } scope 2 { - debug b => _15; // in scope 2 at $DIR/match-arm-scopes.rs:+3:16: +3:17 - debug t => _16; // in scope 2 at $DIR/match-arm-scopes.rs:+3:19: +3:20 + debug b => _15; // in scope 2 at $DIR/match-arm-scopes.rs:16:16: 16:17 + debug t => _16; // in scope 2 at $DIR/match-arm-scopes.rs:16:19: 16:20 } bb0: { -- FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match-arm-scopes.rs:+1:11: +1:16 -- switchInt((_2.0: bool)) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +1:16 -+ switchInt((_2.0: bool)) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +1:16 +- FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16 +- switchInt((_2.0: bool)) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 14:16 ++ switchInt((_2.0: bool)) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 14:16 } bb1: { -- falseEdge -> [real: bb8, imaginary: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:+2:9: +2:22 -+ switchInt((_2.1: bool)) -> [false: bb10, otherwise: bb2]; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +1:16 +- falseEdge -> [real: bb8, imaginary: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:15:9: 15:22 ++ switchInt((_2.1: bool)) -> [false: bb10, otherwise: bb2]; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 14:16 } bb2: { -- switchInt((_2.1: bool)) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +1:16 -+ switchInt((_2.0: bool)) -> [false: bb3, otherwise: bb17]; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +1:16 +- switchInt((_2.1: bool)) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 14:16 ++ switchInt((_2.0: bool)) -> [false: bb3, otherwise: bb17]; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 14:16 } bb3: { -- falseEdge -> [real: bb13, imaginary: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:+2:25: +2:38 +- falseEdge -> [real: bb13, imaginary: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:15:25: 15:38 - } - - bb4: { -- switchInt((_2.0: bool)) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +1:16 +- switchInt((_2.0: bool)) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 14:16 - } - - bb5: { -- falseEdge -> [real: bb20, imaginary: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:+3:9: +3:21 +- falseEdge -> [real: bb20, imaginary: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:16:9: 16:21 - } - - bb6: { - StorageLive(_15); // scope 0 at $DIR/match-arm-scopes.rs:+3:32: +3:33 - _15 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:+3:32: +3:33 - StorageLive(_16); // scope 0 at $DIR/match-arm-scopes.rs:+3:35: +3:36 - _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:+3:35: +3:36 -- goto -> bb19; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +4:6 -+ goto -> bb16; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +4:6 + StorageLive(_15); // scope 0 at $DIR/match-arm-scopes.rs:16:32: 16:33 + _15 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:16:32: 16:33 + StorageLive(_16); // scope 0 at $DIR/match-arm-scopes.rs:16:35: 16:36 + _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:35: 16:36 +- goto -> bb19; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6 ++ goto -> bb16; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6 } - bb7: { + bb4: { - _0 = const 1_i32; // scope 1 at $DIR/match-arm-scopes.rs:+2:77: +2:78 -- drop(_7) -> [return: bb18, unwind: bb25]; // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78 -+ drop(_7) -> [return: bb15, unwind: bb22]; // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78 + _0 = const 1_i32; // scope 1 at $DIR/match-arm-scopes.rs:15:77: 15:78 +- drop(_7) -> [return: bb18, unwind: bb25]; // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78 ++ drop(_7) -> [return: bb15, unwind: bb22]; // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78 } - bb8: { + bb5: { - StorageLive(_6); // scope 0 at $DIR/match-arm-scopes.rs:+2:17: +2:18 - _6 = &(_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:+2:17: +2:18 - StorageLive(_8); // scope 0 at $DIR/match-arm-scopes.rs:+2:20: +2:21 - _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:+2:20: +2:21 -- _3 = &shallow (_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:+1:11: +1:16 -- _4 = &shallow (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:+1:11: +1:16 - StorageLive(_9); // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73 - StorageLive(_10); // scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49 - _10 = _1; // scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49 -- switchInt(move _10) -> [false: bb10, otherwise: bb9]; // scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49 -+ switchInt(move _10) -> [false: bb7, otherwise: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49 + StorageLive(_6); // scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18 + _6 = &(_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18 + StorageLive(_8); // scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21 + _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21 +- _3 = &shallow (_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16 +- _4 = &shallow (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16 + StorageLive(_9); // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73 + StorageLive(_10); // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49 + _10 = _1; // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49 +- switchInt(move _10) -> [false: bb10, otherwise: bb9]; // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49 ++ switchInt(move _10) -> [false: bb7, otherwise: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49 } - bb9: { + bb6: { - _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:+2:59: +2:60 - StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 - StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 + _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:15:59: 15:60 + StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 + StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 - goto -> bb23; // scope 0 at no-location + goto -> bb20; // scope 0 at no-location } - bb10: { + bb7: { - _9 = (*_6); // scope 0 at $DIR/match-arm-scopes.rs:+2:70: +2:71 -- switchInt(move _9) -> [false: bb12, otherwise: bb11]; // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73 -+ switchInt(move _9) -> [false: bb9, otherwise: bb8]; // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73 + _9 = (*_6); // scope 0 at $DIR/match-arm-scopes.rs:15:70: 15:71 +- switchInt(move _9) -> [false: bb12, otherwise: bb11]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73 ++ switchInt(move _9) -> [false: bb9, otherwise: bb8]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73 } - bb11: { + bb8: { - StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 - StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 -- FakeRead(ForMatchGuard, _3); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 -- FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 -- FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 -- FakeRead(ForGuardBinding, _8); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 - StorageLive(_5); // scope 0 at $DIR/match-arm-scopes.rs:+2:17: +2:18 - _5 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:+2:17: +2:18 - StorageLive(_7); // scope 0 at $DIR/match-arm-scopes.rs:+2:20: +2:21 - _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:+2:20: +2:21 -- goto -> bb7; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +4:6 -+ goto -> bb4; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +4:6 + StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 + StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 +- FakeRead(ForMatchGuard, _3); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 +- FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 +- FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 +- FakeRead(ForGuardBinding, _8); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 + StorageLive(_5); // scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18 + _5 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18 + StorageLive(_7); // scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21 + _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21 +- goto -> bb7; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6 ++ goto -> bb4; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6 } - bb12: { + bb9: { - StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 - StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 - StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78 - StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78 -- falseEdge -> [real: bb2, imaginary: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73 -+ goto -> bb1; // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73 + StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 + StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 + StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78 + StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78 +- falseEdge -> [real: bb2, imaginary: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73 ++ goto -> bb1; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73 } - bb13: { + bb10: { - StorageLive(_6); // scope 0 at $DIR/match-arm-scopes.rs:+2:26: +2:27 - _6 = &(_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:+2:26: +2:27 - StorageLive(_8); // scope 0 at $DIR/match-arm-scopes.rs:+2:36: +2:37 - _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:+2:36: +2:37 -- _3 = &shallow (_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:+1:11: +1:16 -- _4 = &shallow (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:+1:11: +1:16 - StorageLive(_12); // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73 - StorageLive(_13); // scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49 - _13 = _1; // scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49 -- switchInt(move _13) -> [false: bb15, otherwise: bb14]; // scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49 -+ switchInt(move _13) -> [false: bb12, otherwise: bb11]; // scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49 + StorageLive(_6); // scope 0 at $DIR/match-arm-scopes.rs:15:26: 15:27 + _6 = &(_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:15:26: 15:27 + StorageLive(_8); // scope 0 at $DIR/match-arm-scopes.rs:15:36: 15:37 + _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:15:36: 15:37 +- _3 = &shallow (_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16 +- _4 = &shallow (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16 + StorageLive(_12); // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73 + StorageLive(_13); // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49 + _13 = _1; // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49 +- switchInt(move _13) -> [false: bb15, otherwise: bb14]; // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49 ++ switchInt(move _13) -> [false: bb12, otherwise: bb11]; // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49 } - bb14: { + bb11: { - _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:+2:59: +2:60 - StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 - StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 + _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:15:59: 15:60 + StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 + StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 - goto -> bb23; // scope 0 at no-location + goto -> bb20; // scope 0 at no-location } - bb15: { + bb12: { - _12 = (*_6); // scope 0 at $DIR/match-arm-scopes.rs:+2:70: +2:71 -- switchInt(move _12) -> [false: bb17, otherwise: bb16]; // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73 -+ switchInt(move _12) -> [false: bb14, otherwise: bb13]; // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73 + _12 = (*_6); // scope 0 at $DIR/match-arm-scopes.rs:15:70: 15:71 +- switchInt(move _12) -> [false: bb17, otherwise: bb16]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73 ++ switchInt(move _12) -> [false: bb14, otherwise: bb13]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73 } - bb16: { + bb13: { - StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 - StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 -- FakeRead(ForMatchGuard, _3); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 -- FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 -- FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 -- FakeRead(ForGuardBinding, _8); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 - StorageLive(_5); // scope 0 at $DIR/match-arm-scopes.rs:+2:26: +2:27 - _5 = (_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:+2:26: +2:27 - StorageLive(_7); // scope 0 at $DIR/match-arm-scopes.rs:+2:36: +2:37 - _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:+2:36: +2:37 -- goto -> bb7; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +4:6 -+ goto -> bb4; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +4:6 + StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 + StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 +- FakeRead(ForMatchGuard, _3); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 +- FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 +- FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 +- FakeRead(ForGuardBinding, _8); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 + StorageLive(_5); // scope 0 at $DIR/match-arm-scopes.rs:15:26: 15:27 + _5 = (_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:15:26: 15:27 + StorageLive(_7); // scope 0 at $DIR/match-arm-scopes.rs:15:36: 15:37 + _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:15:36: 15:37 +- goto -> bb7; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6 ++ goto -> bb4; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6 } - bb17: { + bb14: { - StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 - StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73 - StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78 - StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78 -- falseEdge -> [real: bb4, imaginary: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73 -+ goto -> bb2; // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73 + StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 + StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 + StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78 + StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78 +- falseEdge -> [real: bb4, imaginary: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73 ++ goto -> bb2; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73 } - bb18: { + bb15: { - StorageDead(_7); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78 - StorageDead(_5); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78 - StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78 - StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78 -- goto -> bb22; // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78 -+ goto -> bb19; // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78 + StorageDead(_7); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78 + StorageDead(_5); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78 + StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78 + StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78 +- goto -> bb22; // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78 ++ goto -> bb19; // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78 } - bb19: { + bb16: { - _0 = const 2_i32; // scope 2 at $DIR/match-arm-scopes.rs:+3:41: +3:42 -- drop(_16) -> [return: bb21, unwind: bb25]; // scope 0 at $DIR/match-arm-scopes.rs:+3:41: +3:42 -+ drop(_16) -> [return: bb18, unwind: bb22]; // scope 0 at $DIR/match-arm-scopes.rs:+3:41: +3:42 + _0 = const 2_i32; // scope 2 at $DIR/match-arm-scopes.rs:16:41: 16:42 +- drop(_16) -> [return: bb21, unwind: bb25]; // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42 ++ drop(_16) -> [return: bb18, unwind: bb22]; // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42 } - bb20: { + bb17: { - StorageLive(_15); // scope 0 at $DIR/match-arm-scopes.rs:+3:16: +3:17 - _15 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:+3:16: +3:17 - StorageLive(_16); // scope 0 at $DIR/match-arm-scopes.rs:+3:19: +3:20 - _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:+3:19: +3:20 -- goto -> bb19; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +4:6 -+ goto -> bb16; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +4:6 + StorageLive(_15); // scope 0 at $DIR/match-arm-scopes.rs:16:16: 16:17 + _15 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:16:16: 16:17 + StorageLive(_16); // scope 0 at $DIR/match-arm-scopes.rs:16:19: 16:20 + _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:19: 16:20 +- goto -> bb19; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6 ++ goto -> bb16; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6 } - bb21: { + bb18: { - StorageDead(_16); // scope 0 at $DIR/match-arm-scopes.rs:+3:41: +3:42 - StorageDead(_15); // scope 0 at $DIR/match-arm-scopes.rs:+3:41: +3:42 -- goto -> bb22; // scope 0 at $DIR/match-arm-scopes.rs:+3:41: +3:42 -+ goto -> bb19; // scope 0 at $DIR/match-arm-scopes.rs:+3:41: +3:42 + StorageDead(_16); // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42 + StorageDead(_15); // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42 +- goto -> bb22; // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42 ++ goto -> bb19; // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42 } - bb22: { -- drop(_2) -> [return: bb24, unwind: bb26]; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2 +- drop(_2) -> [return: bb24, unwind: bb26]; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2 + bb19: { -+ goto -> bb26; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2 ++ goto -> bb26; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2 } - bb23: { + bb20: { - StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78 - StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78 -- drop(_2) -> [return: bb24, unwind: bb26]; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2 -+ drop(_2) -> [return: bb21, unwind: bb23]; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2 + StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78 + StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78 +- drop(_2) -> [return: bb24, unwind: bb26]; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2 ++ drop(_2) -> [return: bb21, unwind: bb23]; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2 } - bb24: { + bb21: { - return; // scope 0 at $DIR/match-arm-scopes.rs:+5:2: +5:2 + return; // scope 0 at $DIR/match-arm-scopes.rs:18:2: 18:2 } - bb25 (cleanup): { -- drop(_2) -> bb26; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2 +- drop(_2) -> bb26; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2 + bb22 (cleanup): { -+ goto -> bb27; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2 ++ goto -> bb27; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2 } - bb26 (cleanup): { + bb23 (cleanup): { - resume; // scope 0 at $DIR/match-arm-scopes.rs:+0:1: +5:2 + resume; // scope 0 at $DIR/match-arm-scopes.rs:13:1: 18:2 + } + + bb24: { -+ goto -> bb21; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2 ++ goto -> bb21; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2 + } + + bb25 (cleanup): { -+ goto -> bb23; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2 ++ goto -> bb23; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2 + } + + bb26: { -+ goto -> bb24; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2 ++ goto -> bb24; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2 + } + + bb27 (cleanup): { -+ goto -> bb23; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2 ++ goto -> bb23; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2 } } diff --git a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir index c05ed00f7539b..722097630f79b 100644 --- a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir +++ b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir @@ -1,113 +1,113 @@ // MIR for `full_tested_match` after PromoteTemps fn full_tested_match() -> () { - let mut _0: (); // return place in scope 0 at $DIR/match_false_edges.rs:+0:28: +0:28 - let mut _1: (i32, i32); // in scope 0 at $DIR/match_false_edges.rs:+1:13: +5:6 - let mut _2: std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27 - let mut _3: isize; // in scope 0 at $DIR/match_false_edges.rs:+2:9: +2:16 - let mut _4: &std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27 - let _5: i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15 - let _6: &i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15 - let mut _7: bool; // in scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27 - let mut _8: i32; // in scope 0 at $DIR/match_false_edges.rs:+2:35: +2:36 - let _9: i32; // in scope 0 at $DIR/match_false_edges.rs:+3:14: +3:15 - let mut _10: i32; // in scope 0 at $DIR/match_false_edges.rs:+3:24: +3:25 - let mut _11: &std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15 + let mut _0: (); // return place in scope 0 at $DIR/match_false_edges.rs:12:28: 12:28 + let mut _1: (i32, i32); // in scope 0 at $DIR/match_false_edges.rs:13:13: 17:6 + let mut _2: std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:13:19: 13:27 + let mut _3: isize; // in scope 0 at $DIR/match_false_edges.rs:14:9: 14:16 + let mut _4: &std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:13:19: 13:27 + let _5: i32; // in scope 0 at $DIR/match_false_edges.rs:14:14: 14:15 + let _6: &i32; // in scope 0 at $DIR/match_false_edges.rs:14:14: 14:15 + let mut _7: bool; // in scope 0 at $DIR/match_false_edges.rs:14:20: 14:27 + let mut _8: i32; // in scope 0 at $DIR/match_false_edges.rs:14:35: 14:36 + let _9: i32; // in scope 0 at $DIR/match_false_edges.rs:15:14: 15:15 + let mut _10: i32; // in scope 0 at $DIR/match_false_edges.rs:15:24: 15:25 + let mut _11: &std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:14:14: 14:15 scope 1 { } scope 2 { - debug x => _5; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:15 - debug x => _6; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:15 + debug x => _5; // in scope 2 at $DIR/match_false_edges.rs:14:14: 14:15 + debug x => _6; // in scope 2 at $DIR/match_false_edges.rs:14:14: 14:15 } scope 3 { - debug y => _9; // in scope 3 at $DIR/match_false_edges.rs:+3:14: +3:15 + debug y => _9; // in scope 3 at $DIR/match_false_edges.rs:15:14: 15:15 } bb0: { - StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:+1:13: +5:6 - StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27 - _2 = Option::::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27 - FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27 - _3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27 - switchInt(move _3) -> [0_isize: bb1, 1_isize: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:27 + StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:13:13: 17:6 + StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:13:19: 13:27 + _2 = Option::::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:13:19: 13:27 + FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:13:19: 13:27 + _3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:13:19: 13:27 + switchInt(move _3) -> [0_isize: bb1, 1_isize: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:13:13: 13:27 } bb1: { - _1 = (const 3_i32, const 3_i32); // scope 0 at $DIR/match_false_edges.rs:+4:17: +4:23 - goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:+4:17: +4:23 + _1 = (const 3_i32, const 3_i32); // scope 0 at $DIR/match_false_edges.rs:16:17: 16:23 + goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:16:17: 16:23 } bb2: { - falseEdge -> [real: bb5, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:+2:9: +2:16 + falseEdge -> [real: bb5, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:14:9: 14:16 } bb3: { - falseEdge -> [real: bb9, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:+3:9: +3:16 + falseEdge -> [real: bb9, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:15:9: 15:16 } bb4: { - unreachable; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27 + unreachable; // scope 0 at $DIR/match_false_edges.rs:13:19: 13:27 } bb5: { - StorageLive(_6); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15 - _11 = const full_tested_match::promoted[0]; // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15 + StorageLive(_6); // scope 0 at $DIR/match_false_edges.rs:14:14: 14:15 + _11 = const full_tested_match::promoted[0]; // scope 0 at $DIR/match_false_edges.rs:14:14: 14:15 // mir::Constant // + span: $DIR/match_false_edges.rs:14:14: 14:15 // + literal: Const { ty: &Option, val: Unevaluated(full_tested_match, [], Some(promoted[0])) } - _6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15 - _4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27 - StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27 - _7 = guard() -> [return: bb6, unwind: bb11]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27 + _6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:14:14: 14:15 + _4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:13:19: 13:27 + StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:14:20: 14:27 + _7 = guard() -> [return: bb6, unwind: bb11]; // scope 0 at $DIR/match_false_edges.rs:14:20: 14:27 // mir::Constant // + span: $DIR/match_false_edges.rs:14:20: 14:25 // + literal: Const { ty: fn() -> bool {guard}, val: Value() } } bb6: { - switchInt(move _7) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27 + switchInt(move _7) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:14:20: 14:27 } bb7: { - StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27 - FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27 - FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27 - StorageLive(_5); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15 - _5 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15 - StorageLive(_8); // scope 2 at $DIR/match_false_edges.rs:+2:35: +2:36 - _8 = _5; // scope 2 at $DIR/match_false_edges.rs:+2:35: +2:36 - _1 = (const 1_i32, move _8); // scope 2 at $DIR/match_false_edges.rs:+2:31: +2:37 - StorageDead(_8); // scope 2 at $DIR/match_false_edges.rs:+2:36: +2:37 - StorageDead(_5); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37 - StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37 - goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37 + StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:14:26: 14:27 + FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match_false_edges.rs:14:26: 14:27 + FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match_false_edges.rs:14:26: 14:27 + StorageLive(_5); // scope 0 at $DIR/match_false_edges.rs:14:14: 14:15 + _5 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:14:14: 14:15 + StorageLive(_8); // scope 2 at $DIR/match_false_edges.rs:14:35: 14:36 + _8 = _5; // scope 2 at $DIR/match_false_edges.rs:14:35: 14:36 + _1 = (const 1_i32, move _8); // scope 2 at $DIR/match_false_edges.rs:14:31: 14:37 + StorageDead(_8); // scope 2 at $DIR/match_false_edges.rs:14:36: 14:37 + StorageDead(_5); // scope 0 at $DIR/match_false_edges.rs:14:36: 14:37 + StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:14:36: 14:37 + goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:14:36: 14:37 } bb8: { - StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27 - StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37 - goto -> bb3; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27 + StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:14:26: 14:27 + StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:14:36: 14:37 + goto -> bb3; // scope 0 at $DIR/match_false_edges.rs:14:20: 14:27 } bb9: { - StorageLive(_9); // scope 0 at $DIR/match_false_edges.rs:+3:14: +3:15 - _9 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+3:14: +3:15 - StorageLive(_10); // scope 3 at $DIR/match_false_edges.rs:+3:24: +3:25 - _10 = _9; // scope 3 at $DIR/match_false_edges.rs:+3:24: +3:25 - _1 = (const 2_i32, move _10); // scope 3 at $DIR/match_false_edges.rs:+3:20: +3:26 - StorageDead(_10); // scope 3 at $DIR/match_false_edges.rs:+3:25: +3:26 - StorageDead(_9); // scope 0 at $DIR/match_false_edges.rs:+3:25: +3:26 - goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:+3:25: +3:26 + StorageLive(_9); // scope 0 at $DIR/match_false_edges.rs:15:14: 15:15 + _9 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:15:14: 15:15 + StorageLive(_10); // scope 3 at $DIR/match_false_edges.rs:15:24: 15:25 + _10 = _9; // scope 3 at $DIR/match_false_edges.rs:15:24: 15:25 + _1 = (const 2_i32, move _10); // scope 3 at $DIR/match_false_edges.rs:15:20: 15:26 + StorageDead(_10); // scope 3 at $DIR/match_false_edges.rs:15:25: 15:26 + StorageDead(_9); // scope 0 at $DIR/match_false_edges.rs:15:25: 15:26 + goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:15:25: 15:26 } bb10: { - StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:+5:6: +5:7 - StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:+5:6: +5:7 - _0 = const (); // scope 0 at $DIR/match_false_edges.rs:+0:28: +6:2 - return; // scope 0 at $DIR/match_false_edges.rs:+6:2: +6:2 + StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:17:6: 17:7 + StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:17:6: 17:7 + _0 = const (); // scope 0 at $DIR/match_false_edges.rs:12:28: 18:2 + return; // scope 0 at $DIR/match_false_edges.rs:18:2: 18:2 } bb11 (cleanup): { - resume; // scope 0 at $DIR/match_false_edges.rs:+0:1: +6:2 + resume; // scope 0 at $DIR/match_false_edges.rs:12:1: 18:2 } } diff --git a/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir b/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir index 145ed878fc9e4..df052e32157db 100644 --- a/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir +++ b/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir @@ -1,108 +1,108 @@ // MIR for `full_tested_match2` before PromoteTemps fn full_tested_match2() -> () { - let mut _0: (); // return place in scope 0 at $DIR/match_false_edges.rs:+0:29: +0:29 - let mut _1: (i32, i32); // in scope 0 at $DIR/match_false_edges.rs:+1:13: +5:6 - let mut _2: std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27 - let mut _3: isize; // in scope 0 at $DIR/match_false_edges.rs:+2:9: +2:16 - let mut _4: &std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27 - let _5: i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15 - let _6: &i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15 - let mut _7: bool; // in scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27 - let mut _8: i32; // in scope 0 at $DIR/match_false_edges.rs:+2:35: +2:36 - let _9: i32; // in scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15 - let mut _10: i32; // in scope 0 at $DIR/match_false_edges.rs:+4:24: +4:25 + let mut _0: (); // return place in scope 0 at $DIR/match_false_edges.rs:23:29: 23:29 + let mut _1: (i32, i32); // in scope 0 at $DIR/match_false_edges.rs:24:13: 28:6 + let mut _2: std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:24:19: 24:27 + let mut _3: isize; // in scope 0 at $DIR/match_false_edges.rs:25:9: 25:16 + let mut _4: &std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:24:19: 24:27 + let _5: i32; // in scope 0 at $DIR/match_false_edges.rs:25:14: 25:15 + let _6: &i32; // in scope 0 at $DIR/match_false_edges.rs:25:14: 25:15 + let mut _7: bool; // in scope 0 at $DIR/match_false_edges.rs:25:20: 25:27 + let mut _8: i32; // in scope 0 at $DIR/match_false_edges.rs:25:35: 25:36 + let _9: i32; // in scope 0 at $DIR/match_false_edges.rs:27:14: 27:15 + let mut _10: i32; // in scope 0 at $DIR/match_false_edges.rs:27:24: 27:25 scope 1 { } scope 2 { - debug x => _5; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:15 - debug x => _6; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:15 + debug x => _5; // in scope 2 at $DIR/match_false_edges.rs:25:14: 25:15 + debug x => _6; // in scope 2 at $DIR/match_false_edges.rs:25:14: 25:15 } scope 3 { - debug y => _9; // in scope 3 at $DIR/match_false_edges.rs:+4:14: +4:15 + debug y => _9; // in scope 3 at $DIR/match_false_edges.rs:27:14: 27:15 } bb0: { - StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:+1:13: +5:6 - StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27 - _2 = Option::::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27 - FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27 - _3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27 - switchInt(move _3) -> [0_isize: bb1, 1_isize: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:27 + StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:24:13: 28:6 + StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:24:19: 24:27 + _2 = Option::::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:24:19: 24:27 + FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:24:19: 24:27 + _3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:24:19: 24:27 + switchInt(move _3) -> [0_isize: bb1, 1_isize: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:24:13: 24:27 } bb1: { - falseEdge -> [real: bb9, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:+3:9: +3:13 + falseEdge -> [real: bb9, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:26:9: 26:13 } bb2: { - falseEdge -> [real: bb5, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:+2:9: +2:16 + falseEdge -> [real: bb5, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:25:9: 25:16 } bb3: { - StorageLive(_9); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15 - _9 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15 - StorageLive(_10); // scope 3 at $DIR/match_false_edges.rs:+4:24: +4:25 - _10 = _9; // scope 3 at $DIR/match_false_edges.rs:+4:24: +4:25 - _1 = (const 2_i32, move _10); // scope 3 at $DIR/match_false_edges.rs:+4:20: +4:26 - StorageDead(_10); // scope 3 at $DIR/match_false_edges.rs:+4:25: +4:26 - StorageDead(_9); // scope 0 at $DIR/match_false_edges.rs:+4:25: +4:26 - goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:+4:25: +4:26 + StorageLive(_9); // scope 0 at $DIR/match_false_edges.rs:27:14: 27:15 + _9 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:27:14: 27:15 + StorageLive(_10); // scope 3 at $DIR/match_false_edges.rs:27:24: 27:25 + _10 = _9; // scope 3 at $DIR/match_false_edges.rs:27:24: 27:25 + _1 = (const 2_i32, move _10); // scope 3 at $DIR/match_false_edges.rs:27:20: 27:26 + StorageDead(_10); // scope 3 at $DIR/match_false_edges.rs:27:25: 27:26 + StorageDead(_9); // scope 0 at $DIR/match_false_edges.rs:27:25: 27:26 + goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:27:25: 27:26 } bb4: { - unreachable; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27 + unreachable; // scope 0 at $DIR/match_false_edges.rs:24:19: 24:27 } bb5: { - StorageLive(_6); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15 - _6 = &((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15 - _4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27 - StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27 - _7 = guard() -> [return: bb6, unwind: bb11]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27 + StorageLive(_6); // scope 0 at $DIR/match_false_edges.rs:25:14: 25:15 + _6 = &((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:25:14: 25:15 + _4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:24:19: 24:27 + StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:25:20: 25:27 + _7 = guard() -> [return: bb6, unwind: bb11]; // scope 0 at $DIR/match_false_edges.rs:25:20: 25:27 // mir::Constant // + span: $DIR/match_false_edges.rs:25:20: 25:25 // + literal: Const { ty: fn() -> bool {guard}, val: Value() } } bb6: { - switchInt(move _7) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27 + switchInt(move _7) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:25:20: 25:27 } bb7: { - StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27 - FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27 - FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27 - StorageLive(_5); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15 - _5 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15 - StorageLive(_8); // scope 2 at $DIR/match_false_edges.rs:+2:35: +2:36 - _8 = _5; // scope 2 at $DIR/match_false_edges.rs:+2:35: +2:36 - _1 = (const 1_i32, move _8); // scope 2 at $DIR/match_false_edges.rs:+2:31: +2:37 - StorageDead(_8); // scope 2 at $DIR/match_false_edges.rs:+2:36: +2:37 - StorageDead(_5); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37 - StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37 - goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37 + StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:25:26: 25:27 + FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match_false_edges.rs:25:26: 25:27 + FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match_false_edges.rs:25:26: 25:27 + StorageLive(_5); // scope 0 at $DIR/match_false_edges.rs:25:14: 25:15 + _5 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:25:14: 25:15 + StorageLive(_8); // scope 2 at $DIR/match_false_edges.rs:25:35: 25:36 + _8 = _5; // scope 2 at $DIR/match_false_edges.rs:25:35: 25:36 + _1 = (const 1_i32, move _8); // scope 2 at $DIR/match_false_edges.rs:25:31: 25:37 + StorageDead(_8); // scope 2 at $DIR/match_false_edges.rs:25:36: 25:37 + StorageDead(_5); // scope 0 at $DIR/match_false_edges.rs:25:36: 25:37 + StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:25:36: 25:37 + goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:25:36: 25:37 } bb8: { - StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27 - StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37 - falseEdge -> [real: bb3, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27 + StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:25:26: 25:27 + StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:25:36: 25:37 + falseEdge -> [real: bb3, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:25:20: 25:27 } bb9: { - _1 = (const 3_i32, const 3_i32); // scope 0 at $DIR/match_false_edges.rs:+3:17: +3:23 - goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:+3:17: +3:23 + _1 = (const 3_i32, const 3_i32); // scope 0 at $DIR/match_false_edges.rs:26:17: 26:23 + goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:26:17: 26:23 } bb10: { - StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:+5:6: +5:7 - StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:+5:6: +5:7 - _0 = const (); // scope 0 at $DIR/match_false_edges.rs:+0:29: +6:2 - return; // scope 0 at $DIR/match_false_edges.rs:+6:2: +6:2 + StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:28:6: 28:7 + StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:28:6: 28:7 + _0 = const (); // scope 0 at $DIR/match_false_edges.rs:23:29: 29:2 + return; // scope 0 at $DIR/match_false_edges.rs:29:2: 29:2 } bb11 (cleanup): { - resume; // scope 0 at $DIR/match_false_edges.rs:+0:1: +6:2 + resume; // scope 0 at $DIR/match_false_edges.rs:23:1: 29:2 } } diff --git a/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir b/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir index 8f40e8a887f2d..fc50db397fdcf 100644 --- a/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir +++ b/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir @@ -1,153 +1,153 @@ // MIR for `main` before PromoteTemps fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/match_false_edges.rs:+0:11: +0:11 - let mut _1: i32; // in scope 0 at $DIR/match_false_edges.rs:+1:13: +6:6 - let mut _2: std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26 - let mut _3: isize; // in scope 0 at $DIR/match_false_edges.rs:+4:9: +4:16 - let mut _4: isize; // in scope 0 at $DIR/match_false_edges.rs:+2:9: +2:17 - let mut _5: &std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26 - let _6: i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16 - let _7: &i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16 - let mut _8: bool; // in scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28 - let _9: std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:+3:9: +3:11 - let _10: i32; // in scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15 - let _11: &i32; // in scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15 - let mut _12: bool; // in scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29 - let mut _13: i32; // in scope 0 at $DIR/match_false_edges.rs:+4:27: +4:28 - let _14: std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:+5:9: +5:11 + let mut _0: (); // return place in scope 0 at $DIR/match_false_edges.rs:32:11: 32:11 + let mut _1: i32; // in scope 0 at $DIR/match_false_edges.rs:33:13: 38:6 + let mut _2: std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:33:19: 33:26 + let mut _3: isize; // in scope 0 at $DIR/match_false_edges.rs:36:9: 36:16 + let mut _4: isize; // in scope 0 at $DIR/match_false_edges.rs:34:9: 34:17 + let mut _5: &std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:33:19: 33:26 + let _6: i32; // in scope 0 at $DIR/match_false_edges.rs:34:14: 34:16 + let _7: &i32; // in scope 0 at $DIR/match_false_edges.rs:34:14: 34:16 + let mut _8: bool; // in scope 0 at $DIR/match_false_edges.rs:34:21: 34:28 + let _9: std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:35:9: 35:11 + let _10: i32; // in scope 0 at $DIR/match_false_edges.rs:36:14: 36:15 + let _11: &i32; // in scope 0 at $DIR/match_false_edges.rs:36:14: 36:15 + let mut _12: bool; // in scope 0 at $DIR/match_false_edges.rs:36:20: 36:29 + let mut _13: i32; // in scope 0 at $DIR/match_false_edges.rs:36:27: 36:28 + let _14: std::option::Option; // in scope 0 at $DIR/match_false_edges.rs:37:9: 37:11 scope 1 { } scope 2 { - debug _w => _6; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:16 - debug _w => _7; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:16 + debug _w => _6; // in scope 2 at $DIR/match_false_edges.rs:34:14: 34:16 + debug _w => _7; // in scope 2 at $DIR/match_false_edges.rs:34:14: 34:16 } scope 3 { - debug _x => _9; // in scope 3 at $DIR/match_false_edges.rs:+3:9: +3:11 + debug _x => _9; // in scope 3 at $DIR/match_false_edges.rs:35:9: 35:11 } scope 4 { - debug y => _10; // in scope 4 at $DIR/match_false_edges.rs:+4:14: +4:15 - debug y => _11; // in scope 4 at $DIR/match_false_edges.rs:+4:14: +4:15 + debug y => _10; // in scope 4 at $DIR/match_false_edges.rs:36:14: 36:15 + debug y => _11; // in scope 4 at $DIR/match_false_edges.rs:36:14: 36:15 } scope 5 { - debug _z => _14; // in scope 5 at $DIR/match_false_edges.rs:+5:9: +5:11 + debug _z => _14; // in scope 5 at $DIR/match_false_edges.rs:37:9: 37:11 } bb0: { - StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:+1:13: +6:6 - StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26 - _2 = Option::::Some(const 1_i32); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26 - FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26 - _4 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26 - switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:26 + StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:33:13: 38:6 + StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:33:19: 33:26 + _2 = Option::::Some(const 1_i32); // scope 0 at $DIR/match_false_edges.rs:33:19: 33:26 + FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:33:19: 33:26 + _4 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:33:19: 33:26 + switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/match_false_edges.rs:33:13: 33:26 } bb1: { - falseEdge -> [real: bb9, imaginary: bb4]; // scope 0 at $DIR/match_false_edges.rs:+3:9: +3:11 + falseEdge -> [real: bb9, imaginary: bb4]; // scope 0 at $DIR/match_false_edges.rs:35:9: 35:11 } bb2: { - falseEdge -> [real: bb5, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:+2:9: +2:17 + falseEdge -> [real: bb5, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:34:9: 34:17 } bb3: { - StorageLive(_14); // scope 0 at $DIR/match_false_edges.rs:+5:9: +5:11 - _14 = _2; // scope 0 at $DIR/match_false_edges.rs:+5:9: +5:11 - _1 = const 4_i32; // scope 5 at $DIR/match_false_edges.rs:+5:15: +5:16 - StorageDead(_14); // scope 0 at $DIR/match_false_edges.rs:+5:15: +5:16 - goto -> bb14; // scope 0 at $DIR/match_false_edges.rs:+5:15: +5:16 + StorageLive(_14); // scope 0 at $DIR/match_false_edges.rs:37:9: 37:11 + _14 = _2; // scope 0 at $DIR/match_false_edges.rs:37:9: 37:11 + _1 = const 4_i32; // scope 5 at $DIR/match_false_edges.rs:37:15: 37:16 + StorageDead(_14); // scope 0 at $DIR/match_false_edges.rs:37:15: 37:16 + goto -> bb14; // scope 0 at $DIR/match_false_edges.rs:37:15: 37:16 } bb4: { - falseEdge -> [real: bb10, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:+4:9: +4:16 + falseEdge -> [real: bb10, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:36:9: 36:16 } bb5: { - StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16 - _7 = &((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16 - _5 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26 - StorageLive(_8); // scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28 - _8 = guard() -> [return: bb6, unwind: bb15]; // scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28 + StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:34:14: 34:16 + _7 = &((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:34:14: 34:16 + _5 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:33:19: 33:26 + StorageLive(_8); // scope 0 at $DIR/match_false_edges.rs:34:21: 34:28 + _8 = guard() -> [return: bb6, unwind: bb15]; // scope 0 at $DIR/match_false_edges.rs:34:21: 34:28 // mir::Constant // + span: $DIR/match_false_edges.rs:34:21: 34:26 // + literal: Const { ty: fn() -> bool {guard}, val: Value() } } bb6: { - switchInt(move _8) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28 + switchInt(move _8) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:34:21: 34:28 } bb7: { - StorageDead(_8); // scope 0 at $DIR/match_false_edges.rs:+2:27: +2:28 - FakeRead(ForMatchGuard, _5); // scope 0 at $DIR/match_false_edges.rs:+2:27: +2:28 - FakeRead(ForGuardBinding, _7); // scope 0 at $DIR/match_false_edges.rs:+2:27: +2:28 - StorageLive(_6); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16 - _6 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16 - _1 = const 1_i32; // scope 2 at $DIR/match_false_edges.rs:+2:32: +2:33 - StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:+2:32: +2:33 - StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:32: +2:33 - goto -> bb14; // scope 0 at $DIR/match_false_edges.rs:+2:32: +2:33 + StorageDead(_8); // scope 0 at $DIR/match_false_edges.rs:34:27: 34:28 + FakeRead(ForMatchGuard, _5); // scope 0 at $DIR/match_false_edges.rs:34:27: 34:28 + FakeRead(ForGuardBinding, _7); // scope 0 at $DIR/match_false_edges.rs:34:27: 34:28 + StorageLive(_6); // scope 0 at $DIR/match_false_edges.rs:34:14: 34:16 + _6 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:34:14: 34:16 + _1 = const 1_i32; // scope 2 at $DIR/match_false_edges.rs:34:32: 34:33 + StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:34:32: 34:33 + StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:34:32: 34:33 + goto -> bb14; // scope 0 at $DIR/match_false_edges.rs:34:32: 34:33 } bb8: { - StorageDead(_8); // scope 0 at $DIR/match_false_edges.rs:+2:27: +2:28 - StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:32: +2:33 - falseEdge -> [real: bb1, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28 + StorageDead(_8); // scope 0 at $DIR/match_false_edges.rs:34:27: 34:28 + StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:34:32: 34:33 + falseEdge -> [real: bb1, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:34:21: 34:28 } bb9: { - StorageLive(_9); // scope 0 at $DIR/match_false_edges.rs:+3:9: +3:11 - _9 = _2; // scope 0 at $DIR/match_false_edges.rs:+3:9: +3:11 - _1 = const 2_i32; // scope 3 at $DIR/match_false_edges.rs:+3:15: +3:16 - StorageDead(_9); // scope 0 at $DIR/match_false_edges.rs:+3:15: +3:16 - goto -> bb14; // scope 0 at $DIR/match_false_edges.rs:+3:15: +3:16 + StorageLive(_9); // scope 0 at $DIR/match_false_edges.rs:35:9: 35:11 + _9 = _2; // scope 0 at $DIR/match_false_edges.rs:35:9: 35:11 + _1 = const 2_i32; // scope 3 at $DIR/match_false_edges.rs:35:15: 35:16 + StorageDead(_9); // scope 0 at $DIR/match_false_edges.rs:35:15: 35:16 + goto -> bb14; // scope 0 at $DIR/match_false_edges.rs:35:15: 35:16 } bb10: { - StorageLive(_11); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15 - _11 = &((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15 - _5 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26 - StorageLive(_12); // scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29 - StorageLive(_13); // scope 0 at $DIR/match_false_edges.rs:+4:27: +4:28 - _13 = (*_11); // scope 0 at $DIR/match_false_edges.rs:+4:27: +4:28 - _12 = guard2(move _13) -> [return: bb11, unwind: bb15]; // scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29 + StorageLive(_11); // scope 0 at $DIR/match_false_edges.rs:36:14: 36:15 + _11 = &((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:36:14: 36:15 + _5 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:33:19: 33:26 + StorageLive(_12); // scope 0 at $DIR/match_false_edges.rs:36:20: 36:29 + StorageLive(_13); // scope 0 at $DIR/match_false_edges.rs:36:27: 36:28 + _13 = (*_11); // scope 0 at $DIR/match_false_edges.rs:36:27: 36:28 + _12 = guard2(move _13) -> [return: bb11, unwind: bb15]; // scope 0 at $DIR/match_false_edges.rs:36:20: 36:29 // mir::Constant // + span: $DIR/match_false_edges.rs:36:20: 36:26 // + literal: Const { ty: fn(i32) -> bool {guard2}, val: Value() } } bb11: { - switchInt(move _12) -> [false: bb13, otherwise: bb12]; // scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29 + switchInt(move _12) -> [false: bb13, otherwise: bb12]; // scope 0 at $DIR/match_false_edges.rs:36:20: 36:29 } bb12: { - StorageDead(_13); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29 - StorageDead(_12); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29 - FakeRead(ForMatchGuard, _5); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29 - FakeRead(ForGuardBinding, _11); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29 - StorageLive(_10); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15 - _10 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15 - _1 = const 3_i32; // scope 4 at $DIR/match_false_edges.rs:+4:33: +4:34 - StorageDead(_10); // scope 0 at $DIR/match_false_edges.rs:+4:33: +4:34 - StorageDead(_11); // scope 0 at $DIR/match_false_edges.rs:+4:33: +4:34 - goto -> bb14; // scope 0 at $DIR/match_false_edges.rs:+4:33: +4:34 + StorageDead(_13); // scope 0 at $DIR/match_false_edges.rs:36:28: 36:29 + StorageDead(_12); // scope 0 at $DIR/match_false_edges.rs:36:28: 36:29 + FakeRead(ForMatchGuard, _5); // scope 0 at $DIR/match_false_edges.rs:36:28: 36:29 + FakeRead(ForGuardBinding, _11); // scope 0 at $DIR/match_false_edges.rs:36:28: 36:29 + StorageLive(_10); // scope 0 at $DIR/match_false_edges.rs:36:14: 36:15 + _10 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:36:14: 36:15 + _1 = const 3_i32; // scope 4 at $DIR/match_false_edges.rs:36:33: 36:34 + StorageDead(_10); // scope 0 at $DIR/match_false_edges.rs:36:33: 36:34 + StorageDead(_11); // scope 0 at $DIR/match_false_edges.rs:36:33: 36:34 + goto -> bb14; // scope 0 at $DIR/match_false_edges.rs:36:33: 36:34 } bb13: { - StorageDead(_13); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29 - StorageDead(_12); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29 - StorageDead(_11); // scope 0 at $DIR/match_false_edges.rs:+4:33: +4:34 - falseEdge -> [real: bb3, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29 + StorageDead(_13); // scope 0 at $DIR/match_false_edges.rs:36:28: 36:29 + StorageDead(_12); // scope 0 at $DIR/match_false_edges.rs:36:28: 36:29 + StorageDead(_11); // scope 0 at $DIR/match_false_edges.rs:36:33: 36:34 + falseEdge -> [real: bb3, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:36:20: 36:29 } bb14: { - StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:+6:6: +6:7 - StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:+6:6: +6:7 - _0 = const (); // scope 0 at $DIR/match_false_edges.rs:+0:11: +7:2 - return; // scope 0 at $DIR/match_false_edges.rs:+7:2: +7:2 + StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:38:6: 38:7 + StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:38:6: 38:7 + _0 = const (); // scope 0 at $DIR/match_false_edges.rs:32:11: 39:2 + return; // scope 0 at $DIR/match_false_edges.rs:39:2: 39:2 } bb15 (cleanup): { - resume; // scope 0 at $DIR/match_false_edges.rs:+0:1: +7:2 + resume; // scope 0 at $DIR/match_false_edges.rs:32:1: 39:2 } } diff --git a/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir index b184ffc404e6b..89eefa69019a2 100644 --- a/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir @@ -1,106 +1,106 @@ // MIR for `main` after SimplifyCfg-initial fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/match_test.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/match_test.rs:+1:9: +1:10 - let _3: i32; // in scope 0 at $DIR/match_test.rs:+6:5: +11:6 - let mut _4: bool; // in scope 0 at $DIR/match_test.rs:+8:9: +8:16 - let mut _5: bool; // in scope 0 at $DIR/match_test.rs:+8:9: +8:16 - let mut _6: bool; // in scope 0 at $DIR/match_test.rs:+7:9: +7:14 - let mut _7: bool; // in scope 0 at $DIR/match_test.rs:+7:9: +7:14 - let mut _8: &i32; // in scope 0 at $DIR/match_test.rs:+6:11: +6:12 - let mut _9: bool; // in scope 0 at $DIR/match_test.rs:+7:18: +7:19 + let mut _0: (); // return place in scope 0 at $DIR/match_test.rs:6:11: 6:11 + let _1: i32; // in scope 0 at $DIR/match_test.rs:7:9: 7:10 + let _3: i32; // in scope 0 at $DIR/match_test.rs:12:5: 17:6 + let mut _4: bool; // in scope 0 at $DIR/match_test.rs:14:9: 14:16 + let mut _5: bool; // in scope 0 at $DIR/match_test.rs:14:9: 14:16 + let mut _6: bool; // in scope 0 at $DIR/match_test.rs:13:9: 13:14 + let mut _7: bool; // in scope 0 at $DIR/match_test.rs:13:9: 13:14 + let mut _8: &i32; // in scope 0 at $DIR/match_test.rs:12:11: 12:12 + let mut _9: bool; // in scope 0 at $DIR/match_test.rs:13:18: 13:19 scope 1 { - debug x => _1; // in scope 1 at $DIR/match_test.rs:+1:9: +1:10 - let _2: bool; // in scope 1 at $DIR/match_test.rs:+2:9: +2:10 + debug x => _1; // in scope 1 at $DIR/match_test.rs:7:9: 7:10 + let _2: bool; // in scope 1 at $DIR/match_test.rs:8:9: 8:10 scope 2 { - debug b => _2; // in scope 2 at $DIR/match_test.rs:+2:9: +2:10 + debug b => _2; // in scope 2 at $DIR/match_test.rs:8:9: 8:10 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/match_test.rs:+1:9: +1:10 - _1 = const 3_i32; // scope 0 at $DIR/match_test.rs:+1:13: +1:14 - FakeRead(ForLet(None), _1); // scope 0 at $DIR/match_test.rs:+1:9: +1:10 - StorageLive(_2); // scope 1 at $DIR/match_test.rs:+2:9: +2:10 - _2 = const true; // scope 1 at $DIR/match_test.rs:+2:13: +2:17 - FakeRead(ForLet(None), _2); // scope 1 at $DIR/match_test.rs:+2:9: +2:10 - StorageLive(_3); // scope 2 at $DIR/match_test.rs:+6:5: +11:6 - FakeRead(ForMatchedPlace(None), _1); // scope 2 at $DIR/match_test.rs:+6:11: +6:12 - _6 = Le(const 0_i32, _1); // scope 2 at $DIR/match_test.rs:+7:9: +7:14 - switchInt(move _6) -> [false: bb4, otherwise: bb1]; // scope 2 at $DIR/match_test.rs:+7:9: +7:14 + StorageLive(_1); // scope 0 at $DIR/match_test.rs:7:9: 7:10 + _1 = const 3_i32; // scope 0 at $DIR/match_test.rs:7:13: 7:14 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/match_test.rs:7:9: 7:10 + StorageLive(_2); // scope 1 at $DIR/match_test.rs:8:9: 8:10 + _2 = const true; // scope 1 at $DIR/match_test.rs:8:13: 8:17 + FakeRead(ForLet(None), _2); // scope 1 at $DIR/match_test.rs:8:9: 8:10 + StorageLive(_3); // scope 2 at $DIR/match_test.rs:12:5: 17:6 + FakeRead(ForMatchedPlace(None), _1); // scope 2 at $DIR/match_test.rs:12:11: 12:12 + _6 = Le(const 0_i32, _1); // scope 2 at $DIR/match_test.rs:13:9: 13:14 + switchInt(move _6) -> [false: bb4, otherwise: bb1]; // scope 2 at $DIR/match_test.rs:13:9: 13:14 } bb1: { - _7 = Lt(_1, const 10_i32); // scope 2 at $DIR/match_test.rs:+7:9: +7:14 - switchInt(move _7) -> [false: bb4, otherwise: bb2]; // scope 2 at $DIR/match_test.rs:+7:9: +7:14 + _7 = Lt(_1, const 10_i32); // scope 2 at $DIR/match_test.rs:13:9: 13:14 + switchInt(move _7) -> [false: bb4, otherwise: bb2]; // scope 2 at $DIR/match_test.rs:13:9: 13:14 } bb2: { - falseEdge -> [real: bb9, imaginary: bb6]; // scope 2 at $DIR/match_test.rs:+7:9: +7:14 + falseEdge -> [real: bb9, imaginary: bb6]; // scope 2 at $DIR/match_test.rs:13:9: 13:14 } bb3: { - _3 = const 3_i32; // scope 2 at $DIR/match_test.rs:+10:14: +10:15 - goto -> bb14; // scope 2 at $DIR/match_test.rs:+10:14: +10:15 + _3 = const 3_i32; // scope 2 at $DIR/match_test.rs:16:14: 16:15 + goto -> bb14; // scope 2 at $DIR/match_test.rs:16:14: 16:15 } bb4: { - _4 = Le(const 10_i32, _1); // scope 2 at $DIR/match_test.rs:+8:9: +8:16 - switchInt(move _4) -> [false: bb7, otherwise: bb5]; // scope 2 at $DIR/match_test.rs:+8:9: +8:16 + _4 = Le(const 10_i32, _1); // scope 2 at $DIR/match_test.rs:14:9: 14:16 + switchInt(move _4) -> [false: bb7, otherwise: bb5]; // scope 2 at $DIR/match_test.rs:14:9: 14:16 } bb5: { - _5 = Le(_1, const 20_i32); // scope 2 at $DIR/match_test.rs:+8:9: +8:16 - switchInt(move _5) -> [false: bb7, otherwise: bb6]; // scope 2 at $DIR/match_test.rs:+8:9: +8:16 + _5 = Le(_1, const 20_i32); // scope 2 at $DIR/match_test.rs:14:9: 14:16 + switchInt(move _5) -> [false: bb7, otherwise: bb6]; // scope 2 at $DIR/match_test.rs:14:9: 14:16 } bb6: { - falseEdge -> [real: bb12, imaginary: bb8]; // scope 2 at $DIR/match_test.rs:+8:9: +8:16 + falseEdge -> [real: bb12, imaginary: bb8]; // scope 2 at $DIR/match_test.rs:14:9: 14:16 } bb7: { - switchInt(_1) -> [-1_i32: bb8, otherwise: bb3]; // scope 2 at $DIR/match_test.rs:+6:5: +6:12 + switchInt(_1) -> [-1_i32: bb8, otherwise: bb3]; // scope 2 at $DIR/match_test.rs:12:5: 12:12 } bb8: { - falseEdge -> [real: bb13, imaginary: bb3]; // scope 2 at $DIR/match_test.rs:+9:9: +9:11 + falseEdge -> [real: bb13, imaginary: bb3]; // scope 2 at $DIR/match_test.rs:15:9: 15:11 } bb9: { - _8 = &shallow _1; // scope 2 at $DIR/match_test.rs:+6:11: +6:12 - StorageLive(_9); // scope 2 at $DIR/match_test.rs:+7:18: +7:19 - _9 = _2; // scope 2 at $DIR/match_test.rs:+7:18: +7:19 - switchInt(move _9) -> [false: bb11, otherwise: bb10]; // scope 2 at $DIR/match_test.rs:+7:18: +7:19 + _8 = &shallow _1; // scope 2 at $DIR/match_test.rs:12:11: 12:12 + StorageLive(_9); // scope 2 at $DIR/match_test.rs:13:18: 13:19 + _9 = _2; // scope 2 at $DIR/match_test.rs:13:18: 13:19 + switchInt(move _9) -> [false: bb11, otherwise: bb10]; // scope 2 at $DIR/match_test.rs:13:18: 13:19 } bb10: { - StorageDead(_9); // scope 2 at $DIR/match_test.rs:+7:18: +7:19 - FakeRead(ForMatchGuard, _8); // scope 2 at $DIR/match_test.rs:+7:18: +7:19 - _3 = const 0_i32; // scope 2 at $DIR/match_test.rs:+7:23: +7:24 - goto -> bb14; // scope 2 at $DIR/match_test.rs:+7:23: +7:24 + StorageDead(_9); // scope 2 at $DIR/match_test.rs:13:18: 13:19 + FakeRead(ForMatchGuard, _8); // scope 2 at $DIR/match_test.rs:13:18: 13:19 + _3 = const 0_i32; // scope 2 at $DIR/match_test.rs:13:23: 13:24 + goto -> bb14; // scope 2 at $DIR/match_test.rs:13:23: 13:24 } bb11: { - StorageDead(_9); // scope 2 at $DIR/match_test.rs:+7:18: +7:19 - falseEdge -> [real: bb3, imaginary: bb6]; // scope 2 at $DIR/match_test.rs:+7:18: +7:19 + StorageDead(_9); // scope 2 at $DIR/match_test.rs:13:18: 13:19 + falseEdge -> [real: bb3, imaginary: bb6]; // scope 2 at $DIR/match_test.rs:13:18: 13:19 } bb12: { - _3 = const 1_i32; // scope 2 at $DIR/match_test.rs:+8:20: +8:21 - goto -> bb14; // scope 2 at $DIR/match_test.rs:+8:20: +8:21 + _3 = const 1_i32; // scope 2 at $DIR/match_test.rs:14:20: 14:21 + goto -> bb14; // scope 2 at $DIR/match_test.rs:14:20: 14:21 } bb13: { - _3 = const 2_i32; // scope 2 at $DIR/match_test.rs:+9:15: +9:16 - goto -> bb14; // scope 2 at $DIR/match_test.rs:+9:15: +9:16 + _3 = const 2_i32; // scope 2 at $DIR/match_test.rs:15:15: 15:16 + goto -> bb14; // scope 2 at $DIR/match_test.rs:15:15: 15:16 } bb14: { - StorageDead(_3); // scope 2 at $DIR/match_test.rs:+11:6: +11:7 - _0 = const (); // scope 0 at $DIR/match_test.rs:+0:11: +12:2 - StorageDead(_2); // scope 1 at $DIR/match_test.rs:+12:1: +12:2 - StorageDead(_1); // scope 0 at $DIR/match_test.rs:+12:1: +12:2 - return; // scope 0 at $DIR/match_test.rs:+12:2: +12:2 + StorageDead(_3); // scope 2 at $DIR/match_test.rs:17:6: 17:7 + _0 = const (); // scope 0 at $DIR/match_test.rs:6:11: 18:2 + StorageDead(_2); // scope 1 at $DIR/match_test.rs:18:1: 18:2 + StorageDead(_1); // scope 0 at $DIR/match_test.rs:18:1: 18:2 + return; // scope 0 at $DIR/match_test.rs:18:2: 18:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff index 2005c10efa93b..e63148a8312da 100644 --- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff @@ -2,87 +2,87 @@ + // MIR for `bar` after MatchBranchSimplification fn bar(_1: i32) -> (bool, bool, bool, bool) { - debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:9 - let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:19: +0:43 - let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10 - let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +21:6 - let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:6: +23:7 - let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:9: +23:10 - let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:12: +23:13 - let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:15: +23:16 -+ let mut _11: i32; // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +6:12 + debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:13:8: 13:9 + let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:13:19: 13:43 + let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:19:5: 34:6 + let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:36:6: 36:7 + let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:36:9: 36:10 + let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:36:12: 36:13 + let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:36:15: 36:16 ++ let mut _11: i32; // in scope 0 at $DIR/matches_reduce_branches.rs:19:5: 19:12 scope 1 { - debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:10 - let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10 + debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:15:9: 15:10 scope 2 { - debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:+2:9: +2:10 - let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10 + debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:16:9: 16:10 scope 3 { - debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:+3:9: +3:10 - let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10 + debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10 + let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:17:9: 17:10 scope 4 { - debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:+4:9: +4:10 + debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:17:9: 17:10 } } } } bb0: { - StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10 - StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10 - StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10 - StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10 - StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +21:6 -- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12 + StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:16:9: 16:10 + StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:17:9: 17:10 + StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:19:5: 34:6 +- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:19:5: 19:12 - } - - bb1: { -- _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+15:13: +15:21 -- _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+16:13: +16:22 -- _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+17:13: +17:22 -- _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+18:13: +18:21 -- nop; // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15 -- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15 +- _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:21 +- _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:22 +- _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:30:13: 30:22 +- _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:31:13: 31:21 +- nop; // scope 4 at $DIR/matches_reduce_branches.rs:32:13: 32:15 +- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:32:13: 32:15 - } - - bb2: { -- _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22 -- _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21 -+ StorageLive(_11); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12 -+ _11 = _1; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12 -+ _2 = Ne(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22 -+ _3 = Eq(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21 - _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+10:13: +10:22 - _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+11:13: +11:21 -- nop; // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15 -- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15 +- _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22 +- _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21 ++ StorageLive(_11); // scope 4 at $DIR/matches_reduce_branches.rs:19:5: 19:12 ++ _11 = _1; // scope 4 at $DIR/matches_reduce_branches.rs:19:5: 19:12 ++ _2 = Ne(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22 ++ _3 = Eq(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21 + _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:22 + _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:24:13: 24:21 +- nop; // scope 4 at $DIR/matches_reduce_branches.rs:25:13: 25:15 +- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:25:13: 25:15 - } - - bb3: { -+ StorageDead(_11); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12 - StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+21:6: +21:7 - StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7 - _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7 - StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10 - _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10 - StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13 - _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13 - StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16 - _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16 - Deinit(_0); // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17 - (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17 - (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17 - (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17 - (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17 - StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17 - StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17 - StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17 - StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17 - StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:+24:1: +24:2 - StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:+24:1: +24:2 - StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:+24:1: +24:2 - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+24:1: +24:2 - return; // scope 0 at $DIR/matches_reduce_branches.rs:+24:2: +24:2 ++ StorageDead(_11); // scope 4 at $DIR/matches_reduce_branches.rs:19:5: 19:12 + StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7 + StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:36:6: 36:7 + _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:36:6: 36:7 + StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:36:9: 36:10 + _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:36:9: 36:10 + StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:36:12: 36:13 + _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:36:12: 36:13 + StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:36:15: 36:16 + _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:36:15: 36:16 + Deinit(_0); // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17 + (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17 + (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17 + (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17 + (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17 + StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:36:16: 36:17 + StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:36:16: 36:17 + StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:36:16: 36:17 + StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:36:16: 36:17 + StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:37:1: 37:2 + StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:37:1: 37:2 + StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:37:1: 37:2 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:37:1: 37:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:37:2: 37:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff index 2005c10efa93b..e63148a8312da 100644 --- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff @@ -2,87 +2,87 @@ + // MIR for `bar` after MatchBranchSimplification fn bar(_1: i32) -> (bool, bool, bool, bool) { - debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:9 - let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:19: +0:43 - let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10 - let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +21:6 - let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:6: +23:7 - let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:9: +23:10 - let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:12: +23:13 - let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:15: +23:16 -+ let mut _11: i32; // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +6:12 + debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:13:8: 13:9 + let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:13:19: 13:43 + let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:19:5: 34:6 + let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:36:6: 36:7 + let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:36:9: 36:10 + let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:36:12: 36:13 + let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:36:15: 36:16 ++ let mut _11: i32; // in scope 0 at $DIR/matches_reduce_branches.rs:19:5: 19:12 scope 1 { - debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:10 - let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10 + debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:15:9: 15:10 scope 2 { - debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:+2:9: +2:10 - let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10 + debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:16:9: 16:10 scope 3 { - debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:+3:9: +3:10 - let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10 + debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10 + let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:17:9: 17:10 scope 4 { - debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:+4:9: +4:10 + debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:17:9: 17:10 } } } } bb0: { - StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10 - StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10 - StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10 - StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10 - StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +21:6 -- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12 + StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:16:9: 16:10 + StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:17:9: 17:10 + StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:19:5: 34:6 +- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:19:5: 19:12 - } - - bb1: { -- _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+15:13: +15:21 -- _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+16:13: +16:22 -- _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+17:13: +17:22 -- _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+18:13: +18:21 -- nop; // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15 -- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15 +- _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:21 +- _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:22 +- _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:30:13: 30:22 +- _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:31:13: 31:21 +- nop; // scope 4 at $DIR/matches_reduce_branches.rs:32:13: 32:15 +- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:32:13: 32:15 - } - - bb2: { -- _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22 -- _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21 -+ StorageLive(_11); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12 -+ _11 = _1; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12 -+ _2 = Ne(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22 -+ _3 = Eq(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21 - _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+10:13: +10:22 - _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+11:13: +11:21 -- nop; // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15 -- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15 +- _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22 +- _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21 ++ StorageLive(_11); // scope 4 at $DIR/matches_reduce_branches.rs:19:5: 19:12 ++ _11 = _1; // scope 4 at $DIR/matches_reduce_branches.rs:19:5: 19:12 ++ _2 = Ne(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22 ++ _3 = Eq(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21 + _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:22 + _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:24:13: 24:21 +- nop; // scope 4 at $DIR/matches_reduce_branches.rs:25:13: 25:15 +- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:25:13: 25:15 - } - - bb3: { -+ StorageDead(_11); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12 - StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+21:6: +21:7 - StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7 - _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7 - StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10 - _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10 - StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13 - _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13 - StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16 - _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16 - Deinit(_0); // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17 - (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17 - (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17 - (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17 - (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17 - StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17 - StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17 - StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17 - StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17 - StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:+24:1: +24:2 - StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:+24:1: +24:2 - StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:+24:1: +24:2 - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+24:1: +24:2 - return; // scope 0 at $DIR/matches_reduce_branches.rs:+24:2: +24:2 ++ StorageDead(_11); // scope 4 at $DIR/matches_reduce_branches.rs:19:5: 19:12 + StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7 + StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:36:6: 36:7 + _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:36:6: 36:7 + StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:36:9: 36:10 + _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:36:9: 36:10 + StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:36:12: 36:13 + _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:36:12: 36:13 + StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:36:15: 36:16 + _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:36:15: 36:16 + Deinit(_0); // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17 + (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17 + (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17 + (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17 + (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17 + StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:36:16: 36:17 + StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:36:16: 36:17 + StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:36:16: 36:17 + StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:36:16: 36:17 + StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:37:1: 37:2 + StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:37:1: 37:2 + StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:37:1: 37:2 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:37:1: 37:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:37:2: 37:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff index b7862e5678f23..29f66ceac981e 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff @@ -2,13 +2,13 @@ + // MIR for `foo` after MatchBranchSimplification fn foo(_1: Option<()>) -> () { - debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11 - let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25 - let mut _2: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26 + debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:7:8: 7:11 + let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:7:25: 7:25 + let mut _2: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:8:22: 8:26 + let mut _3: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20 + _2 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:8:17: 8:20 - switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - @@ -24,7 +24,7 @@ + StorageLive(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _3 = move _2; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - return; // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:11:2: 11:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff index b7862e5678f23..29f66ceac981e 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff @@ -2,13 +2,13 @@ + // MIR for `foo` after MatchBranchSimplification fn foo(_1: Option<()>) -> () { - debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11 - let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25 - let mut _2: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26 + debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:7:8: 7:11 + let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:7:25: 7:25 + let mut _2: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:8:22: 8:26 + let mut _3: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20 + _2 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:8:17: 8:20 - switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - @@ -24,7 +24,7 @@ + StorageLive(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _3 = move _2; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - return; // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:11:2: 11:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.32bit.mir b/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.32bit.mir index a36ec8de4a391..e3b318c949fc6 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.32bit.mir +++ b/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.32bit.mir @@ -1,10 +1,10 @@ // MIR for `foo` before PreCodegen fn foo(_1: Option<()>) -> () { - debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11 - let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25 + debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:7:8: 7:11 + let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:7:25: 7:25 bb0: { - return; // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:11:2: 11:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.64bit.mir b/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.64bit.mir index a36ec8de4a391..e3b318c949fc6 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.64bit.mir +++ b/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.64bit.mir @@ -1,10 +1,10 @@ // MIR for `foo` before PreCodegen fn foo(_1: Option<()>) -> () { - debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11 - let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25 + debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:7:8: 7:11 + let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:7:25: 7:25 bb0: { - return; // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:11:2: 11:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff index 672c6b34e94b6..2dfb2e1af0d63 100644 --- a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff @@ -2,41 +2,41 @@ + // MIR for `match_nested_if` after MatchBranchSimplification fn match_nested_if() -> bool { - let mut _0: bool; // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:29 - let _1: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12 - let mut _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -+ let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 + let mut _0: bool; // return place in scope 0 at $DIR/matches_reduce_branches.rs:39:25: 39:29 + let _1: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:9: 40:12 + let mut _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:41:24: 41:28 ++ let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:41:24: 41:28 scope 1 { - debug val => _1; // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:12 + debug val => _1; // in scope 1 at $DIR/matches_reduce_branches.rs:40:9: 40:12 } bb0: { - StorageLive(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12 - StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 - _2 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 + StorageLive(_1); // scope 0 at $DIR/matches_reduce_branches.rs:40:9: 40:12 + StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:41:24: 41:28 + _2 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:41:24: 41:28 +- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:41:24: 41:28 - } - - bb1: { -+ StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -+ _3 = move _2; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52 -- _1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17 -- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17 ++ StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:41:24: 41:28 ++ _3 = move _2; // scope 0 at $DIR/matches_reduce_branches.rs:41:24: 41:28 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:41:51: 41:52 +- _1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:47:13: 47:17 +- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:47:13: 47:17 - } - - bb2: { -- StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52 -- _1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 -- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 +- StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:41:51: 41:52 +- _1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:49:14: 49:19 +- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:49:14: 49:19 - } - - bb3: { -+ _1 = Ne(_3, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 -+ StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 - _0 = _1; // scope 1 at $DIR/matches_reduce_branches.rs:+12:5: +12:8 - StorageDead(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+13:1: +13:2 - return; // scope 0 at $DIR/matches_reduce_branches.rs:+13:2: +13:2 ++ _1 = Ne(_3, const false); // scope 0 at $DIR/matches_reduce_branches.rs:49:14: 49:19 ++ StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:41:24: 41:28 + _0 = _1; // scope 1 at $DIR/matches_reduce_branches.rs:51:5: 51:8 + StorageDead(_1); // scope 0 at $DIR/matches_reduce_branches.rs:52:1: 52:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:52:2: 52:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff index 672c6b34e94b6..2dfb2e1af0d63 100644 --- a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff @@ -2,41 +2,41 @@ + // MIR for `match_nested_if` after MatchBranchSimplification fn match_nested_if() -> bool { - let mut _0: bool; // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:29 - let _1: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12 - let mut _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -+ let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 + let mut _0: bool; // return place in scope 0 at $DIR/matches_reduce_branches.rs:39:25: 39:29 + let _1: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:9: 40:12 + let mut _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:41:24: 41:28 ++ let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:41:24: 41:28 scope 1 { - debug val => _1; // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:12 + debug val => _1; // in scope 1 at $DIR/matches_reduce_branches.rs:40:9: 40:12 } bb0: { - StorageLive(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12 - StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 - _2 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 + StorageLive(_1); // scope 0 at $DIR/matches_reduce_branches.rs:40:9: 40:12 + StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:41:24: 41:28 + _2 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:41:24: 41:28 +- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:41:24: 41:28 - } - - bb1: { -+ StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -+ _3 = move _2; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52 -- _1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17 -- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17 ++ StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:41:24: 41:28 ++ _3 = move _2; // scope 0 at $DIR/matches_reduce_branches.rs:41:24: 41:28 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:41:51: 41:52 +- _1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:47:13: 47:17 +- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:47:13: 47:17 - } - - bb2: { -- StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52 -- _1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 -- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 +- StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:41:51: 41:52 +- _1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:49:14: 49:19 +- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:49:14: 49:19 - } - - bb3: { -+ _1 = Ne(_3, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 -+ StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 - _0 = _1; // scope 1 at $DIR/matches_reduce_branches.rs:+12:5: +12:8 - StorageDead(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+13:1: +13:2 - return; // scope 0 at $DIR/matches_reduce_branches.rs:+13:2: +13:2 ++ _1 = Ne(_3, const false); // scope 0 at $DIR/matches_reduce_branches.rs:49:14: 49:19 ++ StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:41:24: 41:28 + _0 = _1; // scope 1 at $DIR/matches_reduce_branches.rs:51:5: 51:8 + StorageDead(_1); // scope 0 at $DIR/matches_reduce_branches.rs:52:1: 52:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:52:2: 52:2 } } diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff index c42657b385577..711cc31f49f98 100644 --- a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff +++ b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff @@ -2,27 +2,27 @@ + // MIR for `exhaustive_match` after MatchBranchSimplification fn exhaustive_match(_1: E) -> u8 { - debug e => _1; // in scope 0 at $DIR/matches_u8.rs:+0:25: +0:26 - let mut _0: u8; // return place in scope 0 at $DIR/matches_u8.rs:+0:34: +0:36 - let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13 + debug e => _1; // in scope 0 at $DIR/matches_u8.rs:11:25: 11:26 + let mut _0: u8; // return place in scope 0 at $DIR/matches_u8.rs:11:34: 11:36 + let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:13:9: 13:13 bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12 + _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:12:11: 12:12 + switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:12:5: 12:12 } bb1: { - _0 = const 1_u8; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18 - goto -> bb3; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18 + _0 = const 1_u8; // scope 0 at $DIR/matches_u8.rs:14:17: 14:18 + goto -> bb3; // scope 0 at $DIR/matches_u8.rs:14:17: 14:18 } bb2: { - _0 = const 0_u8; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18 - goto -> bb3; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18 + _0 = const 0_u8; // scope 0 at $DIR/matches_u8.rs:13:17: 13:18 + goto -> bb3; // scope 0 at $DIR/matches_u8.rs:13:17: 13:18 } bb3: { - return; // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2 + return; // scope 0 at $DIR/matches_u8.rs:16:2: 16:2 } } diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff index c42657b385577..711cc31f49f98 100644 --- a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff +++ b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff @@ -2,27 +2,27 @@ + // MIR for `exhaustive_match` after MatchBranchSimplification fn exhaustive_match(_1: E) -> u8 { - debug e => _1; // in scope 0 at $DIR/matches_u8.rs:+0:25: +0:26 - let mut _0: u8; // return place in scope 0 at $DIR/matches_u8.rs:+0:34: +0:36 - let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13 + debug e => _1; // in scope 0 at $DIR/matches_u8.rs:11:25: 11:26 + let mut _0: u8; // return place in scope 0 at $DIR/matches_u8.rs:11:34: 11:36 + let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:13:9: 13:13 bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12 + _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:12:11: 12:12 + switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:12:5: 12:12 } bb1: { - _0 = const 1_u8; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18 - goto -> bb3; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18 + _0 = const 1_u8; // scope 0 at $DIR/matches_u8.rs:14:17: 14:18 + goto -> bb3; // scope 0 at $DIR/matches_u8.rs:14:17: 14:18 } bb2: { - _0 = const 0_u8; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18 - goto -> bb3; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18 + _0 = const 0_u8; // scope 0 at $DIR/matches_u8.rs:13:17: 13:18 + goto -> bb3; // scope 0 at $DIR/matches_u8.rs:13:17: 13:18 } bb3: { - return; // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2 + return; // scope 0 at $DIR/matches_u8.rs:16:2: 16:2 } } diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff index a4ff2e437db24..6bdeccbf913e6 100644 --- a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff +++ b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff @@ -2,27 +2,27 @@ + // MIR for `exhaustive_match_i8` after MatchBranchSimplification fn exhaustive_match_i8(_1: E) -> i8 { - debug e => _1; // in scope 0 at $DIR/matches_u8.rs:+0:28: +0:29 - let mut _0: i8; // return place in scope 0 at $DIR/matches_u8.rs:+0:37: +0:39 - let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13 + debug e => _1; // in scope 0 at $DIR/matches_u8.rs:19:28: 19:29 + let mut _0: i8; // return place in scope 0 at $DIR/matches_u8.rs:19:37: 19:39 + let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:21:9: 21:13 bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12 + _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:20:11: 20:12 + switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:20:5: 20:12 } bb1: { - _0 = const 1_i8; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18 - goto -> bb3; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18 + _0 = const 1_i8; // scope 0 at $DIR/matches_u8.rs:22:17: 22:18 + goto -> bb3; // scope 0 at $DIR/matches_u8.rs:22:17: 22:18 } bb2: { - _0 = const 0_i8; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18 - goto -> bb3; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18 + _0 = const 0_i8; // scope 0 at $DIR/matches_u8.rs:21:17: 21:18 + goto -> bb3; // scope 0 at $DIR/matches_u8.rs:21:17: 21:18 } bb3: { - return; // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2 + return; // scope 0 at $DIR/matches_u8.rs:24:2: 24:2 } } diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff index a4ff2e437db24..6bdeccbf913e6 100644 --- a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff +++ b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff @@ -2,27 +2,27 @@ + // MIR for `exhaustive_match_i8` after MatchBranchSimplification fn exhaustive_match_i8(_1: E) -> i8 { - debug e => _1; // in scope 0 at $DIR/matches_u8.rs:+0:28: +0:29 - let mut _0: i8; // return place in scope 0 at $DIR/matches_u8.rs:+0:37: +0:39 - let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13 + debug e => _1; // in scope 0 at $DIR/matches_u8.rs:19:28: 19:29 + let mut _0: i8; // return place in scope 0 at $DIR/matches_u8.rs:19:37: 19:39 + let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:21:9: 21:13 bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12 + _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:20:11: 20:12 + switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:20:5: 20:12 } bb1: { - _0 = const 1_i8; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18 - goto -> bb3; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18 + _0 = const 1_i8; // scope 0 at $DIR/matches_u8.rs:22:17: 22:18 + goto -> bb3; // scope 0 at $DIR/matches_u8.rs:22:17: 22:18 } bb2: { - _0 = const 0_i8; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18 - goto -> bb3; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18 + _0 = const 0_i8; // scope 0 at $DIR/matches_u8.rs:21:17: 21:18 + goto -> bb3; // scope 0 at $DIR/matches_u8.rs:21:17: 21:18 } bb3: { - return; // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2 + return; // scope 0 at $DIR/matches_u8.rs:24:2: 24:2 } } diff --git a/src/test/mir-opt/multiple_return_terminators.test.MultipleReturnTerminators.diff b/src/test/mir-opt/multiple_return_terminators.test.MultipleReturnTerminators.diff index 48a11c950639a..dbcb8813d5458 100644 --- a/src/test/mir-opt/multiple_return_terminators.test.MultipleReturnTerminators.diff +++ b/src/test/mir-opt/multiple_return_terminators.test.MultipleReturnTerminators.diff @@ -2,11 +2,11 @@ + // MIR for `test` after MultipleReturnTerminators fn test(_1: bool) -> () { - debug x => _1; // in scope 0 at $DIR/multiple_return_terminators.rs:+0:9: +0:10 - let mut _0: (); // return place in scope 0 at $DIR/multiple_return_terminators.rs:+0:18: +0:18 + debug x => _1; // in scope 0 at $DIR/multiple_return_terminators.rs:4:9: 4:10 + let mut _0: (); // return place in scope 0 at $DIR/multiple_return_terminators.rs:4:18: 4:18 bb0: { - return; // scope 0 at $DIR/multiple_return_terminators.rs:+6:2: +6:2 + return; // scope 0 at $DIR/multiple_return_terminators.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir b/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir index cbfdf8c5d5639..8423128123ab7 100644 --- a/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir +++ b/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir @@ -35,14 +35,14 @@ | '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0) | fn use_x(_1: &'_#6r mut i32, _2: &'_#7r u32, _3: &'_#8r u32, _4: &'_#9r u32) -> bool { - debug w => _1; // in scope 0 at $DIR/named-lifetimes-basic.rs:+0:26: +0:27 - debug x => _2; // in scope 0 at $DIR/named-lifetimes-basic.rs:+0:42: +0:43 - debug y => _3; // in scope 0 at $DIR/named-lifetimes-basic.rs:+0:54: +0:55 - debug z => _4; // in scope 0 at $DIR/named-lifetimes-basic.rs:+0:66: +0:67 - let mut _0: bool; // return place in scope 0 at $DIR/named-lifetimes-basic.rs:+0:81: +0:85 + debug w => _1; // in scope 0 at $DIR/named-lifetimes-basic.rs:12:26: 12:27 + debug x => _2; // in scope 0 at $DIR/named-lifetimes-basic.rs:12:42: 12:43 + debug y => _3; // in scope 0 at $DIR/named-lifetimes-basic.rs:12:54: 12:55 + debug z => _4; // in scope 0 at $DIR/named-lifetimes-basic.rs:12:66: 12:67 + let mut _0: bool; // return place in scope 0 at $DIR/named-lifetimes-basic.rs:12:81: 12:85 bb0: { - _0 = const ConstValue(Scalar(0x01): bool); // bb0[0]: scope 0 at $DIR/named-lifetimes-basic.rs:+0:88: +0:92 - return; // bb0[1]: scope 0 at $DIR/named-lifetimes-basic.rs:+0:94: +0:94 + _0 = const ConstValue(Scalar(0x01): bool); // bb0[0]: scope 0 at $DIR/named-lifetimes-basic.rs:12:88: 12:92 + return; // bb0[1]: scope 0 at $DIR/named-lifetimes-basic.rs:12:94: 12:94 } } diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir index 55e7faf9ee47b..e1d870ef9a4e9 100644 --- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir +++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir @@ -22,91 +22,91 @@ | '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0) | fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:+0:11: +0:11 - let mut _1: [usize; Const { ty: usize, kind: Value(Leaf(0x00000003)) }]; // in scope 0 at $DIR/region-subtyping-basic.rs:+1:9: +1:14 - let _3: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:+2:16: +2:17 - let mut _4: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:+2:14: +2:18 - let mut _5: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:+2:14: +2:18 - let mut _7: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:+4:8: +4:12 - let _8: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:+5:9: +5:18 - let mut _9: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:+5:15: +5:17 - let _10: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:+7:9: +7:18 + let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11 + let mut _1: [usize; Const { ty: usize, kind: Value(Leaf(0x00000003)) }]; // in scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + let _3: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:18:16: 18:17 + let mut _4: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + let mut _5: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + let mut _7: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:20:8: 20:12 + let _8: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:21:9: 21:18 + let mut _9: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:21:15: 21:17 + let _10: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:23:9: 23:18 scope 1 { - debug v => _1; // in scope 1 at $DIR/region-subtyping-basic.rs:+1:9: +1:14 - let _2: &'_#4r usize; // in scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10 + debug v => _1; // in scope 1 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + let _2: &'_#4r usize; // in scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 scope 2 { - debug p => _2; // in scope 2 at $DIR/region-subtyping-basic.rs:+2:9: +2:10 - let _6: &'_#5r usize; // in scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10 + debug p => _2; // in scope 2 at $DIR/region-subtyping-basic.rs:18:9: 18:10 + let _6: &'_#5r usize; // in scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 scope 3 { - debug q => _6; // in scope 3 at $DIR/region-subtyping-basic.rs:+3:9: +3:10 + debug q => _6; // in scope 3 at $DIR/region-subtyping-basic.rs:19:9: 19:10 } } } bb0: { - StorageLive(_1); // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:+1:9: +1:14 - _1 = [const ConstValue(Scalar(0x00000001): usize), const ConstValue(Scalar(0x00000002): usize), const ConstValue(Scalar(0x00000003): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:+1:17: +1:26 - FakeRead(ForLet(None), _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:+1:9: +1:14 - StorageLive(_2); // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10 - StorageLive(_3); // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:+2:16: +2:17 - _3 = const ConstValue(Scalar(0x00000000): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:+2:16: +2:17 - _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:+2:14: +2:18 - _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:+2:14: +2:18 - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb7]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:+2:14: +2:18 + StorageLive(_1); // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + _1 = [const ConstValue(Scalar(0x00000001): usize), const ConstValue(Scalar(0x00000002): usize), const ConstValue(Scalar(0x00000003): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26 + FakeRead(ForLet(None), _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + StorageLive(_2); // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 + StorageLive(_3); // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17 + _3 = const ConstValue(Scalar(0x00000000): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17 + _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb7]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 } bb1: { - _2 = &'_#3r _1[_3]; // bb1[0]: scope 1 at $DIR/region-subtyping-basic.rs:+2:13: +2:18 - FakeRead(ForLet(None), _2); // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10 - StorageLive(_6); // bb1[2]: scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10 - _6 = _2; // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:+3:13: +3:14 - FakeRead(ForLet(None), _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10 - StorageLive(_7); // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:+4:8: +4:12 - _7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:+4:8: +4:12 - switchInt(move _7) -> [ConstValue(Scalar(0x00): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:+4:8: +4:12 + _2 = &'_#3r _1[_3]; // bb1[0]: scope 1 at $DIR/region-subtyping-basic.rs:18:13: 18:18 + FakeRead(ForLet(None), _2); // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 + StorageLive(_6); // bb1[2]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 + _6 = _2; // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14 + FakeRead(ForLet(None), _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 + StorageLive(_7); // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12 + _7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12 + switchInt(move _7) -> [ConstValue(Scalar(0x00): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12 } bb2: { - StorageLive(_8); // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:+5:9: +5:18 - StorageLive(_9); // bb2[1]: scope 3 at $DIR/region-subtyping-basic.rs:+5:15: +5:17 - _9 = (*_6); // bb2[2]: scope 3 at $DIR/region-subtyping-basic.rs:+5:15: +5:17 - _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:+5:9: +5:18 + StorageLive(_8); // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 + StorageLive(_9); // bb2[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17 + _9 = (*_6); // bb2[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17 + _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 // mir::Constant // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14 // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value() } } bb3: { - StorageDead(_9); // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:+5:17: +5:18 - StorageDead(_8); // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:+5:18: +5:19 - _0 = const ConstValue(ZeroSized: ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:+4:13: +6:6 - goto -> bb6; // bb3[3]: scope 3 at $DIR/region-subtyping-basic.rs:+4:5: +8:6 + StorageDead(_9); // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18 + StorageDead(_8); // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19 + _0 = const ConstValue(ZeroSized: ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6 + goto -> bb6; // bb3[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } bb4: { - StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:+7:9: +7:18 - _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:+7:9: +7:18 + StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 + _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 // mir::Constant // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14 // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value() } } bb5: { - StorageDead(_10); // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:+7:18: +7:19 - _0 = const ConstValue(ZeroSized: ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:+6:12: +8:6 - goto -> bb6; // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:+4:5: +8:6 + StorageDead(_10); // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19 + _0 = const ConstValue(ZeroSized: ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6 + goto -> bb6; // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } bb6: { - StorageDead(_7); // bb6[0]: scope 3 at $DIR/region-subtyping-basic.rs:+8:5: +8:6 - StorageDead(_6); // bb6[1]: scope 2 at $DIR/region-subtyping-basic.rs:+9:1: +9:2 - StorageDead(_3); // bb6[2]: scope 1 at $DIR/region-subtyping-basic.rs:+9:1: +9:2 - StorageDead(_2); // bb6[3]: scope 1 at $DIR/region-subtyping-basic.rs:+9:1: +9:2 - StorageDead(_1); // bb6[4]: scope 0 at $DIR/region-subtyping-basic.rs:+9:1: +9:2 - return; // bb6[5]: scope 0 at $DIR/region-subtyping-basic.rs:+9:2: +9:2 + StorageDead(_7); // bb6[0]: scope 3 at $DIR/region-subtyping-basic.rs:24:5: 24:6 + StorageDead(_6); // bb6[1]: scope 2 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + StorageDead(_3); // bb6[2]: scope 1 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + StorageDead(_2); // bb6[3]: scope 1 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + StorageDead(_1); // bb6[4]: scope 0 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + return; // bb6[5]: scope 0 at $DIR/region-subtyping-basic.rs:25:2: 25:2 } bb7 (cleanup): { - resume; // bb7[0]: scope 0 at $DIR/region-subtyping-basic.rs:+0:1: +9:2 + resume; // bb7[0]: scope 0 at $DIR/region-subtyping-basic.rs:16:1: 25:2 } } diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir index 2647c94335f87..2f9dff00b631b 100644 --- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir +++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir @@ -22,91 +22,91 @@ | '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0) | fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:+0:11: +0:11 - let mut _1: [usize; Const { ty: usize, kind: Value(Leaf(0x0000000000000003)) }]; // in scope 0 at $DIR/region-subtyping-basic.rs:+1:9: +1:14 - let _3: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:+2:16: +2:17 - let mut _4: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:+2:14: +2:18 - let mut _5: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:+2:14: +2:18 - let mut _7: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:+4:8: +4:12 - let _8: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:+5:9: +5:18 - let mut _9: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:+5:15: +5:17 - let _10: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:+7:9: +7:18 + let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11 + let mut _1: [usize; Const { ty: usize, kind: Value(Leaf(0x0000000000000003)) }]; // in scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + let _3: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:18:16: 18:17 + let mut _4: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + let mut _5: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + let mut _7: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:20:8: 20:12 + let _8: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:21:9: 21:18 + let mut _9: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:21:15: 21:17 + let _10: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:23:9: 23:18 scope 1 { - debug v => _1; // in scope 1 at $DIR/region-subtyping-basic.rs:+1:9: +1:14 - let _2: &'_#4r usize; // in scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10 + debug v => _1; // in scope 1 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + let _2: &'_#4r usize; // in scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 scope 2 { - debug p => _2; // in scope 2 at $DIR/region-subtyping-basic.rs:+2:9: +2:10 - let _6: &'_#5r usize; // in scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10 + debug p => _2; // in scope 2 at $DIR/region-subtyping-basic.rs:18:9: 18:10 + let _6: &'_#5r usize; // in scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 scope 3 { - debug q => _6; // in scope 3 at $DIR/region-subtyping-basic.rs:+3:9: +3:10 + debug q => _6; // in scope 3 at $DIR/region-subtyping-basic.rs:19:9: 19:10 } } } bb0: { - StorageLive(_1); // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:+1:9: +1:14 - _1 = [const ConstValue(Scalar(0x0000000000000001): usize), const ConstValue(Scalar(0x0000000000000002): usize), const ConstValue(Scalar(0x0000000000000003): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:+1:17: +1:26 - FakeRead(ForLet(None), _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:+1:9: +1:14 - StorageLive(_2); // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10 - StorageLive(_3); // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:+2:16: +2:17 - _3 = const ConstValue(Scalar(0x0000000000000000): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:+2:16: +2:17 - _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:+2:14: +2:18 - _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:+2:14: +2:18 - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb7]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:+2:14: +2:18 + StorageLive(_1); // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + _1 = [const ConstValue(Scalar(0x0000000000000001): usize), const ConstValue(Scalar(0x0000000000000002): usize), const ConstValue(Scalar(0x0000000000000003): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26 + FakeRead(ForLet(None), _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + StorageLive(_2); // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 + StorageLive(_3); // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17 + _3 = const ConstValue(Scalar(0x0000000000000000): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17 + _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb7]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 } bb1: { - _2 = &'_#3r _1[_3]; // bb1[0]: scope 1 at $DIR/region-subtyping-basic.rs:+2:13: +2:18 - FakeRead(ForLet(None), _2); // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10 - StorageLive(_6); // bb1[2]: scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10 - _6 = _2; // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:+3:13: +3:14 - FakeRead(ForLet(None), _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10 - StorageLive(_7); // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:+4:8: +4:12 - _7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:+4:8: +4:12 - switchInt(move _7) -> [ConstValue(Scalar(0x00): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:+4:8: +4:12 + _2 = &'_#3r _1[_3]; // bb1[0]: scope 1 at $DIR/region-subtyping-basic.rs:18:13: 18:18 + FakeRead(ForLet(None), _2); // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 + StorageLive(_6); // bb1[2]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 + _6 = _2; // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14 + FakeRead(ForLet(None), _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 + StorageLive(_7); // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12 + _7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12 + switchInt(move _7) -> [ConstValue(Scalar(0x00): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12 } bb2: { - StorageLive(_8); // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:+5:9: +5:18 - StorageLive(_9); // bb2[1]: scope 3 at $DIR/region-subtyping-basic.rs:+5:15: +5:17 - _9 = (*_6); // bb2[2]: scope 3 at $DIR/region-subtyping-basic.rs:+5:15: +5:17 - _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:+5:9: +5:18 + StorageLive(_8); // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 + StorageLive(_9); // bb2[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17 + _9 = (*_6); // bb2[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17 + _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 // mir::Constant // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14 // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value() } } bb3: { - StorageDead(_9); // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:+5:17: +5:18 - StorageDead(_8); // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:+5:18: +5:19 - _0 = const ConstValue(ZeroSized: ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:+4:13: +6:6 - goto -> bb6; // bb3[3]: scope 3 at $DIR/region-subtyping-basic.rs:+4:5: +8:6 + StorageDead(_9); // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18 + StorageDead(_8); // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19 + _0 = const ConstValue(ZeroSized: ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6 + goto -> bb6; // bb3[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } bb4: { - StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:+7:9: +7:18 - _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:+7:9: +7:18 + StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 + _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 // mir::Constant // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14 // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value() } } bb5: { - StorageDead(_10); // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:+7:18: +7:19 - _0 = const ConstValue(ZeroSized: ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:+6:12: +8:6 - goto -> bb6; // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:+4:5: +8:6 + StorageDead(_10); // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19 + _0 = const ConstValue(ZeroSized: ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6 + goto -> bb6; // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } bb6: { - StorageDead(_7); // bb6[0]: scope 3 at $DIR/region-subtyping-basic.rs:+8:5: +8:6 - StorageDead(_6); // bb6[1]: scope 2 at $DIR/region-subtyping-basic.rs:+9:1: +9:2 - StorageDead(_3); // bb6[2]: scope 1 at $DIR/region-subtyping-basic.rs:+9:1: +9:2 - StorageDead(_2); // bb6[3]: scope 1 at $DIR/region-subtyping-basic.rs:+9:1: +9:2 - StorageDead(_1); // bb6[4]: scope 0 at $DIR/region-subtyping-basic.rs:+9:1: +9:2 - return; // bb6[5]: scope 0 at $DIR/region-subtyping-basic.rs:+9:2: +9:2 + StorageDead(_7); // bb6[0]: scope 3 at $DIR/region-subtyping-basic.rs:24:5: 24:6 + StorageDead(_6); // bb6[1]: scope 2 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + StorageDead(_3); // bb6[2]: scope 1 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + StorageDead(_2); // bb6[3]: scope 1 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + StorageDead(_1); // bb6[4]: scope 0 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + return; // bb6[5]: scope 0 at $DIR/region-subtyping-basic.rs:25:2: 25:2 } bb7 (cleanup): { - resume; // bb7[0]: scope 0 at $DIR/region-subtyping-basic.rs:+0:1: +9:2 + resume; // bb7[0]: scope 0 at $DIR/region-subtyping-basic.rs:16:1: 25:2 } } diff --git a/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir index 50fd98ff13a62..fda6cd6120771 100644 --- a/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir @@ -1,21 +1,21 @@ // MIR for `unwrap` after SimplifyCfg-elaborate-drops fn unwrap(_1: Option) -> T { - debug opt => _1; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:+0:14: +0:17 - let mut _0: T; // return place in scope 0 at $DIR/no-drop-for-inactive-variant.rs:+0:33: +0:34 - let mut _2: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:+2:9: +2:16 - let _3: T; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:+2:14: +2:15 + debug opt => _1; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:7:14: 7:17 + let mut _0: T; // return place in scope 0 at $DIR/no-drop-for-inactive-variant.rs:7:33: 7:34 + let mut _2: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:9: 9:16 + let _3: T; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:14: 9:15 let mut _4: !; // in scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL - let mut _5: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:+5:1: +5:2 - let mut _6: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:+5:1: +5:2 - let mut _7: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:+5:1: +5:2 + let mut _5: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:1: 12:2 + let mut _6: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:1: 12:2 + let mut _7: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:1: 12:2 scope 1 { - debug x => _3; // in scope 1 at $DIR/no-drop-for-inactive-variant.rs:+2:14: +2:15 + debug x => _3; // in scope 1 at $DIR/no-drop-for-inactive-variant.rs:9:14: 9:15 } bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+1:11: +1:14 - switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+1:5: +1:14 + _2 = discriminant(_1); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:8:11: 8:14 + switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:8:5: 8:14 } bb1: { @@ -30,20 +30,20 @@ fn unwrap(_1: Option) -> T { } bb2: { - unreachable; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+1:11: +1:14 + unreachable; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:8:11: 8:14 } bb3: { - StorageLive(_3); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+2:14: +2:15 - _3 = move ((_1 as Some).0: T); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+2:14: +2:15 - _0 = move _3; // scope 1 at $DIR/no-drop-for-inactive-variant.rs:+2:20: +2:21 - StorageDead(_3); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+2:20: +2:21 - _5 = discriminant(_1); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+5:1: +5:2 - return; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+5:2: +5:2 + StorageLive(_3); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:14: 9:15 + _3 = move ((_1 as Some).0: T); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:14: 9:15 + _0 = move _3; // scope 1 at $DIR/no-drop-for-inactive-variant.rs:9:20: 9:21 + StorageDead(_3); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:20: 9:21 + _5 = discriminant(_1); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:1: 12:2 + return; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:2: 12:2 } bb4 (cleanup): { - _7 = discriminant(_1); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+5:1: +5:2 - resume; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+0:1: +5:2 + _7 = discriminant(_1); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:1: 12:2 + resume; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:7:1: 12:2 } } diff --git a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir index 25c6e3060069d..0c814fd9d8dda 100644 --- a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir @@ -1,49 +1,49 @@ // MIR for `main` before ElaborateDrops fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/no-spurious-drop-after-call.rs:+0:11: +0:11 - let _1: (); // in scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:5: +1:35 - let mut _2: std::string::String; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:34 - let mut _3: &str; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:34 - let _4: &str; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:22 + let mut _0: (); // return place in scope 0 at $DIR/no-spurious-drop-after-call.rs:8:11: 8:11 + let _1: (); // in scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 + let mut _2: std::string::String; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 + let mut _3: &str; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 + let _4: &str; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 bb0: { - StorageLive(_1); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:5: +1:35 - StorageLive(_2); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:34 - StorageLive(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:34 - StorageLive(_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:22 - _4 = const ""; // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:22 + StorageLive(_1); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 + StorageLive(_2); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 + StorageLive(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 + StorageLive(_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 + _4 = const ""; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 // + literal: Const { ty: &str, val: Value(Slice(..)) } - _3 = &(*_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:34 - _2 = ::to_string(move _3) -> bb1; // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:34 + _3 = &(*_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 + _2 = ::to_string(move _3) -> bb1; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:23: 9:32 // + literal: Const { ty: for<'r> fn(&'r str) -> String {::to_string}, val: Value() } } bb1: { - StorageDead(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:33: +1:34 - _1 = std::mem::drop::(move _2) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:5: +1:35 + StorageDead(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:33: 9:34 + _1 = std::mem::drop::(move _2) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:5: 9:19 // + literal: Const { ty: fn(String) {std::mem::drop::}, val: Value() } } bb2: { - StorageDead(_2); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:34: +1:35 - StorageDead(_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:35: +1:36 - StorageDead(_1); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:35: +1:36 - _0 = const (); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+0:11: +2:2 - return; // scope 0 at $DIR/no-spurious-drop-after-call.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:34: 9:35 + StorageDead(_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:35: 9:36 + StorageDead(_1); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:35: 9:36 + _0 = const (); // scope 0 at $DIR/no-spurious-drop-after-call.rs:8:11: 10:2 + return; // scope 0 at $DIR/no-spurious-drop-after-call.rs:10:2: 10:2 } bb3 (cleanup): { - drop(_2) -> bb4; // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:34: +1:35 + drop(_2) -> bb4; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:34: 9:35 } bb4 (cleanup): { - resume; // scope 0 at $DIR/no-spurious-drop-after-call.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/no-spurious-drop-after-call.rs:8:1: 10:2 } } diff --git a/src/test/mir-opt/not_equal_false.opt.InstCombine.diff b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff index 5009d090668f0..249db1c8a5ab2 100644 --- a/src/test/mir-opt/not_equal_false.opt.InstCombine.diff +++ b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff @@ -2,34 +2,34 @@ + // MIR for `opt` after InstCombine fn opt(_1: bool) -> u32 { - debug x => _1; // in scope 0 at $DIR/not_equal_false.rs:+0:8: +0:9 - let mut _0: u32; // return place in scope 0 at $DIR/not_equal_false.rs:+0:20: +0:23 - let mut _2: bool; // in scope 0 at $DIR/not_equal_false.rs:+1:8: +1:18 - let mut _3: bool; // in scope 0 at $DIR/not_equal_false.rs:+1:8: +1:9 + debug x => _1; // in scope 0 at $DIR/not_equal_false.rs:3:8: 3:9 + let mut _0: u32; // return place in scope 0 at $DIR/not_equal_false.rs:3:20: 3:23 + let mut _2: bool; // in scope 0 at $DIR/not_equal_false.rs:4:8: 4:18 + let mut _3: bool; // in scope 0 at $DIR/not_equal_false.rs:4:8: 4:9 bb0: { - StorageLive(_2); // scope 0 at $DIR/not_equal_false.rs:+1:8: +1:18 - StorageLive(_3); // scope 0 at $DIR/not_equal_false.rs:+1:8: +1:9 - _3 = _1; // scope 0 at $DIR/not_equal_false.rs:+1:8: +1:9 -- _2 = Ne(move _3, const false); // scope 0 at $DIR/not_equal_false.rs:+1:8: +1:18 -+ _2 = move _3; // scope 0 at $DIR/not_equal_false.rs:+1:8: +1:18 - StorageDead(_3); // scope 0 at $DIR/not_equal_false.rs:+1:17: +1:18 - switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:+1:8: +1:18 + StorageLive(_2); // scope 0 at $DIR/not_equal_false.rs:4:8: 4:18 + StorageLive(_3); // scope 0 at $DIR/not_equal_false.rs:4:8: 4:9 + _3 = _1; // scope 0 at $DIR/not_equal_false.rs:4:8: 4:9 +- _2 = Ne(move _3, const false); // scope 0 at $DIR/not_equal_false.rs:4:8: 4:18 ++ _2 = move _3; // scope 0 at $DIR/not_equal_false.rs:4:8: 4:18 + StorageDead(_3); // scope 0 at $DIR/not_equal_false.rs:4:17: 4:18 + switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:8: 4:18 } bb1: { - _0 = const 0_u32; // scope 0 at $DIR/not_equal_false.rs:+1:21: +1:22 - goto -> bb3; // scope 0 at $DIR/not_equal_false.rs:+1:5: +1:35 + _0 = const 0_u32; // scope 0 at $DIR/not_equal_false.rs:4:21: 4:22 + goto -> bb3; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:35 } bb2: { - _0 = const 1_u32; // scope 0 at $DIR/not_equal_false.rs:+1:32: +1:33 - goto -> bb3; // scope 0 at $DIR/not_equal_false.rs:+1:5: +1:35 + _0 = const 1_u32; // scope 0 at $DIR/not_equal_false.rs:4:32: 4:33 + goto -> bb3; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:35 } bb3: { - StorageDead(_2); // scope 0 at $DIR/not_equal_false.rs:+1:34: +1:35 - return; // scope 0 at $DIR/not_equal_false.rs:+2:2: +2:2 + StorageDead(_2); // scope 0 at $DIR/not_equal_false.rs:4:34: 4:35 + return; // scope 0 at $DIR/not_equal_false.rs:5:2: 5:2 } } diff --git a/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff b/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff index 9e89bd9fb9631..f438eaa002780 100644 --- a/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff +++ b/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff @@ -2,42 +2,42 @@ + // MIR for `nrvo` after RenameReturnPlace fn nrvo(_1: for<'r> fn(&'r mut [u8; 1024])) -> [u8; 1024] { - debug init => _1; // in scope 0 at $DIR/nrvo-simple.rs:+0:9: +0:13 -- let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:+0:39: +0:49 -+ let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:+1:9: +1:16 - let mut _2: [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:+1:9: +1:16 - let _3: (); // in scope 0 at $DIR/nrvo-simple.rs:+2:5: +2:19 - let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/nrvo-simple.rs:+2:5: +2:9 - let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:+2:10: +2:18 - let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:+2:10: +2:18 + debug init => _1; // in scope 0 at $DIR/nrvo-simple.rs:4:9: 4:13 +- let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:4:39: 4:49 ++ let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:5:9: 5:16 + let mut _2: [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:5:9: 5:16 + let _3: (); // in scope 0 at $DIR/nrvo-simple.rs:6:5: 6:19 + let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/nrvo-simple.rs:6:5: 6:9 + let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:6:10: 6:18 + let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:6:10: 6:18 scope 1 { -- debug buf => _2; // in scope 1 at $DIR/nrvo-simple.rs:+1:9: +1:16 -+ debug buf => _0; // in scope 1 at $DIR/nrvo-simple.rs:+1:9: +1:16 +- debug buf => _2; // in scope 1 at $DIR/nrvo-simple.rs:5:9: 5:16 ++ debug buf => _0; // in scope 1 at $DIR/nrvo-simple.rs:5:9: 5:16 } bb0: { -- StorageLive(_2); // scope 0 at $DIR/nrvo-simple.rs:+1:9: +1:16 -- _2 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:+1:19: +1:28 -+ _0 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:+1:19: +1:28 - StorageLive(_3); // scope 1 at $DIR/nrvo-simple.rs:+2:5: +2:19 - StorageLive(_4); // scope 1 at $DIR/nrvo-simple.rs:+2:5: +2:9 - _4 = _1; // scope 1 at $DIR/nrvo-simple.rs:+2:5: +2:9 - StorageLive(_5); // scope 1 at $DIR/nrvo-simple.rs:+2:10: +2:18 - StorageLive(_6); // scope 1 at $DIR/nrvo-simple.rs:+2:10: +2:18 -- _6 = &mut _2; // scope 1 at $DIR/nrvo-simple.rs:+2:10: +2:18 -+ _6 = &mut _0; // scope 1 at $DIR/nrvo-simple.rs:+2:10: +2:18 - _5 = &mut (*_6); // scope 1 at $DIR/nrvo-simple.rs:+2:10: +2:18 - _3 = move _4(move _5) -> bb1; // scope 1 at $DIR/nrvo-simple.rs:+2:5: +2:19 +- StorageLive(_2); // scope 0 at $DIR/nrvo-simple.rs:5:9: 5:16 +- _2 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:5:19: 5:28 ++ _0 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:5:19: 5:28 + StorageLive(_3); // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:19 + StorageLive(_4); // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:9 + _4 = _1; // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:9 + StorageLive(_5); // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 + StorageLive(_6); // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 +- _6 = &mut _2; // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 ++ _6 = &mut _0; // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 + _5 = &mut (*_6); // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 + _3 = move _4(move _5) -> bb1; // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:19 } bb1: { - StorageDead(_5); // scope 1 at $DIR/nrvo-simple.rs:+2:18: +2:19 - StorageDead(_4); // scope 1 at $DIR/nrvo-simple.rs:+2:18: +2:19 - StorageDead(_6); // scope 1 at $DIR/nrvo-simple.rs:+2:19: +2:20 - StorageDead(_3); // scope 1 at $DIR/nrvo-simple.rs:+2:19: +2:20 -- _0 = _2; // scope 1 at $DIR/nrvo-simple.rs:+3:5: +3:8 -- StorageDead(_2); // scope 0 at $DIR/nrvo-simple.rs:+4:1: +4:2 - return; // scope 0 at $DIR/nrvo-simple.rs:+4:2: +4:2 + StorageDead(_5); // scope 1 at $DIR/nrvo-simple.rs:6:18: 6:19 + StorageDead(_4); // scope 1 at $DIR/nrvo-simple.rs:6:18: 6:19 + StorageDead(_6); // scope 1 at $DIR/nrvo-simple.rs:6:19: 6:20 + StorageDead(_3); // scope 1 at $DIR/nrvo-simple.rs:6:19: 6:20 +- _0 = _2; // scope 1 at $DIR/nrvo-simple.rs:7:5: 7:8 +- StorageDead(_2); // scope 0 at $DIR/nrvo-simple.rs:8:1: 8:2 + return; // scope 0 at $DIR/nrvo-simple.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir index c3874d3b39d38..81f428d607177 100644 --- a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir +++ b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir @@ -1,55 +1,55 @@ // MIR for `main` after SimplifyCfg-elaborate-drops fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +0:11 - let mut _1: Packed; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14 - let mut _2: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42 - let mut _3: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41 - let mut _4: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29 - let mut _5: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28 - let mut _6: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 + let mut _0: (); // return place in scope 0 at $DIR/packed-struct-drop-aligned.rs:5:11: 5:11 + let mut _1: Packed; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:6:9: 6:14 + let mut _2: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:6:24: 6:42 + let mut _3: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41 + let mut _4: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:7:11: 7:29 + let mut _5: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28 + let mut _6: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8 scope 1 { - debug x => _1; // in scope 1 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14 + debug x => _1; // in scope 1 at $DIR/packed-struct-drop-aligned.rs:6:9: 6:14 } bb0: { - StorageLive(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14 - StorageLive(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42 - StorageLive(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41 - _3 = Droppy(const 0_usize); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41 - _2 = Aligned(move _3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42 - StorageDead(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:41: +1:42 - _1 = Packed(move _2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43 - StorageDead(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:42: +1:43 - StorageLive(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29 - StorageLive(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28 - _5 = Droppy(const 0_usize); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28 - _4 = Aligned(move _5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29 - StorageDead(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29 - StorageLive(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - _6 = move (_1.0: Aligned); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 + StorageLive(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:9: 6:14 + StorageLive(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:24: 6:42 + StorageLive(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41 + _3 = Droppy(const 0_usize); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41 + _2 = Aligned(move _3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:24: 6:42 + StorageDead(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:41: 6:42 + _1 = Packed(move _2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:17: 6:43 + StorageDead(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:42: 6:43 + StorageLive(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:11: 7:29 + StorageLive(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28 + _5 = Droppy(const 0_usize); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28 + _4 = Aligned(move _5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:11: 7:29 + StorageDead(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:28: 7:29 + StorageLive(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8 + _6 = move (_1.0: Aligned); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8 + drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8 } bb1: { - StorageDead(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2 - return; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:2: +3:2 + StorageDead(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2 + return; // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:2: 8:2 } bb2 (cleanup): { - resume; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:1: +3:2 + resume; // scope 0 at $DIR/packed-struct-drop-aligned.rs:5:1: 8:2 } bb3 (cleanup): { - (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - drop(_1) -> bb2; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2 + (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8 + drop(_1) -> bb2; // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2 } bb4: { - StorageDead(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - StorageDead(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29 - _0 = const (); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +3:2 - drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2 + StorageDead(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8 + (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8 + StorageDead(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:28: 7:29 + _0 = const (); // scope 0 at $DIR/packed-struct-drop-aligned.rs:5:11: 8:2 + drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2 } } diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir index c3874d3b39d38..81f428d607177 100644 --- a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir +++ b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir @@ -1,55 +1,55 @@ // MIR for `main` after SimplifyCfg-elaborate-drops fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +0:11 - let mut _1: Packed; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14 - let mut _2: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42 - let mut _3: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41 - let mut _4: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29 - let mut _5: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28 - let mut _6: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 + let mut _0: (); // return place in scope 0 at $DIR/packed-struct-drop-aligned.rs:5:11: 5:11 + let mut _1: Packed; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:6:9: 6:14 + let mut _2: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:6:24: 6:42 + let mut _3: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41 + let mut _4: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:7:11: 7:29 + let mut _5: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28 + let mut _6: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8 scope 1 { - debug x => _1; // in scope 1 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14 + debug x => _1; // in scope 1 at $DIR/packed-struct-drop-aligned.rs:6:9: 6:14 } bb0: { - StorageLive(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14 - StorageLive(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42 - StorageLive(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41 - _3 = Droppy(const 0_usize); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41 - _2 = Aligned(move _3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42 - StorageDead(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:41: +1:42 - _1 = Packed(move _2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43 - StorageDead(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:42: +1:43 - StorageLive(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29 - StorageLive(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28 - _5 = Droppy(const 0_usize); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28 - _4 = Aligned(move _5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29 - StorageDead(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29 - StorageLive(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - _6 = move (_1.0: Aligned); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 + StorageLive(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:9: 6:14 + StorageLive(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:24: 6:42 + StorageLive(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41 + _3 = Droppy(const 0_usize); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41 + _2 = Aligned(move _3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:24: 6:42 + StorageDead(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:41: 6:42 + _1 = Packed(move _2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:17: 6:43 + StorageDead(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:42: 6:43 + StorageLive(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:11: 7:29 + StorageLive(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28 + _5 = Droppy(const 0_usize); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28 + _4 = Aligned(move _5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:11: 7:29 + StorageDead(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:28: 7:29 + StorageLive(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8 + _6 = move (_1.0: Aligned); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8 + drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8 } bb1: { - StorageDead(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2 - return; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:2: +3:2 + StorageDead(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2 + return; // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:2: 8:2 } bb2 (cleanup): { - resume; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:1: +3:2 + resume; // scope 0 at $DIR/packed-struct-drop-aligned.rs:5:1: 8:2 } bb3 (cleanup): { - (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - drop(_1) -> bb2; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2 + (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8 + drop(_1) -> bb2; // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2 } bb4: { - StorageDead(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - StorageDead(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29 - _0 = const (); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +3:2 - drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2 + StorageDead(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8 + (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8 + StorageDead(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:28: 7:29 + _0 = const (); // scope 0 at $DIR/packed-struct-drop-aligned.rs:5:11: 8:2 + drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2 } } diff --git a/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir b/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir index 45797ec0607c8..8ee81e679ec47 100644 --- a/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir +++ b/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir @@ -7,90 +7,90 @@ | 3: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }], value: Ty(&&&&*mut Test) }, span: $DIR/receiver-ptr-mutability.rs:18:18: 18:31, inferred_ty: &&&&*mut Test | fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/receiver-ptr-mutability.rs:+0:11: +0:11 - let _1: *mut Test as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+1:9: +1:12 - let _2: (); // in scope 0 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:12 - let mut _3: *const Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:12 - let mut _4: *mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:8 - let _6: &&&&*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+5:34: +5:41 - let _7: &&&*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+5:35: +5:41 - let _8: &&*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+5:36: +5:41 - let _9: &*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+5:37: +5:41 - let _10: (); // in scope 0 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16 - let mut _11: *const Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16 - let mut _12: *mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16 + let mut _0: (); // return place in scope 0 at $DIR/receiver-ptr-mutability.rs:13:11: 13:11 + let _1: *mut Test as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/receiver-ptr-mutability.rs:14:9: 14:12 + let _2: (); // in scope 0 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 + let mut _3: *const Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 + let mut _4: *mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8 + let _6: &&&&*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:18:34: 18:41 + let _7: &&&*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:18:35: 18:41 + let _8: &&*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:18:36: 18:41 + let _9: &*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:18:37: 18:41 + let _10: (); // in scope 0 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 + let mut _11: *const Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 + let mut _12: *mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 scope 1 { - debug ptr => _1; // in scope 1 at $DIR/receiver-ptr-mutability.rs:+1:9: +1:12 - let _5: &&&&*mut Test as UserTypeProjection { base: UserType(2), projs: [] }; // in scope 1 at $DIR/receiver-ptr-mutability.rs:+5:9: +5:16 + debug ptr => _1; // in scope 1 at $DIR/receiver-ptr-mutability.rs:14:9: 14:12 + let _5: &&&&*mut Test as UserTypeProjection { base: UserType(2), projs: [] }; // in scope 1 at $DIR/receiver-ptr-mutability.rs:18:9: 18:16 scope 2 { - debug ptr_ref => _5; // in scope 2 at $DIR/receiver-ptr-mutability.rs:+5:9: +5:16 + debug ptr_ref => _5; // in scope 2 at $DIR/receiver-ptr-mutability.rs:18:9: 18:16 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/receiver-ptr-mutability.rs:+1:9: +1:12 - _1 = null_mut::() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/receiver-ptr-mutability.rs:+1:26: +1:46 + StorageLive(_1); // scope 0 at $DIR/receiver-ptr-mutability.rs:14:9: 14:12 + _1 = null_mut::() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/receiver-ptr-mutability.rs:14:26: 14:46 // mir::Constant // + span: $DIR/receiver-ptr-mutability.rs:14:26: 14:44 // + literal: Const { ty: fn() -> *mut Test {null_mut::}, val: Value() } } bb1: { - FakeRead(ForLet(None), _1); // scope 0 at $DIR/receiver-ptr-mutability.rs:+1:9: +1:12 - AscribeUserType(_1, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/receiver-ptr-mutability.rs:+1:14: +1:23 - StorageLive(_2); // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:12 - StorageLive(_3); // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:12 - StorageLive(_4); // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:8 - _4 = _1; // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:8 - _3 = move _4 as *const Test (Pointer(MutToConstPointer)); // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:12 - StorageDead(_4); // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:7: +2:8 - _2 = Test::x(move _3) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:12 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/receiver-ptr-mutability.rs:14:9: 14:12 + AscribeUserType(_1, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/receiver-ptr-mutability.rs:14:14: 14:23 + StorageLive(_2); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 + StorageLive(_3); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 + StorageLive(_4); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8 + _4 = _1; // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8 + _3 = move _4 as *const Test (Pointer(MutToConstPointer)); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 + StorageDead(_4); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:7: 15:8 + _2 = Test::x(move _3) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 // mir::Constant // + span: $DIR/receiver-ptr-mutability.rs:15:9: 15:10 // + literal: Const { ty: fn(*const Test) {Test::x}, val: Value() } } bb2: { - StorageDead(_3); // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:11: +2:12 - StorageDead(_2); // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:12: +2:13 - StorageLive(_5); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:9: +5:16 - StorageLive(_6); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:34: +5:41 - StorageLive(_7); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:35: +5:41 - StorageLive(_8); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:36: +5:41 - StorageLive(_9); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:37: +5:41 - _9 = &_1; // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:37: +5:41 - _8 = &_9; // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:36: +5:41 - _7 = &_8; // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:35: +5:41 - _6 = &_7; // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:34: +5:41 - _5 = &(*_6); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:34: +5:41 - FakeRead(ForLet(None), _5); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:9: +5:16 - AscribeUserType(_5, o, UserTypeProjection { base: UserType(3), projs: [] }); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:18: +5:31 - StorageDead(_6); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:41: +5:42 - StorageLive(_10); // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16 - StorageLive(_11); // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16 - StorageLive(_12); // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16 - _12 = (*(*(*(*_5)))); // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16 - _11 = move _12 as *const Test (Pointer(MutToConstPointer)); // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16 - StorageDead(_12); // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:11: +6:12 - _10 = Test::x(move _11) -> [return: bb3, unwind: bb4]; // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16 + StorageDead(_3); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:11: 15:12 + StorageDead(_2); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:12: 15:13 + StorageLive(_5); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:9: 18:16 + StorageLive(_6); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:34: 18:41 + StorageLive(_7); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:35: 18:41 + StorageLive(_8); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:36: 18:41 + StorageLive(_9); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:37: 18:41 + _9 = &_1; // scope 1 at $DIR/receiver-ptr-mutability.rs:18:37: 18:41 + _8 = &_9; // scope 1 at $DIR/receiver-ptr-mutability.rs:18:36: 18:41 + _7 = &_8; // scope 1 at $DIR/receiver-ptr-mutability.rs:18:35: 18:41 + _6 = &_7; // scope 1 at $DIR/receiver-ptr-mutability.rs:18:34: 18:41 + _5 = &(*_6); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:34: 18:41 + FakeRead(ForLet(None), _5); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:9: 18:16 + AscribeUserType(_5, o, UserTypeProjection { base: UserType(3), projs: [] }); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:18: 18:31 + StorageDead(_6); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:41: 18:42 + StorageLive(_10); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 + StorageLive(_11); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 + StorageLive(_12); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 + _12 = (*(*(*(*_5)))); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 + _11 = move _12 as *const Test (Pointer(MutToConstPointer)); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 + StorageDead(_12); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:11: 19:12 + _10 = Test::x(move _11) -> [return: bb3, unwind: bb4]; // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 // mir::Constant // + span: $DIR/receiver-ptr-mutability.rs:19:13: 19:14 // + literal: Const { ty: fn(*const Test) {Test::x}, val: Value() } } bb3: { - StorageDead(_11); // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:15: +6:16 - StorageDead(_10); // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:16: +6:17 - _0 = const (); // scope 0 at $DIR/receiver-ptr-mutability.rs:+0:11: +7:2 - StorageDead(_9); // scope 1 at $DIR/receiver-ptr-mutability.rs:+7:1: +7:2 - StorageDead(_8); // scope 1 at $DIR/receiver-ptr-mutability.rs:+7:1: +7:2 - StorageDead(_7); // scope 1 at $DIR/receiver-ptr-mutability.rs:+7:1: +7:2 - StorageDead(_5); // scope 1 at $DIR/receiver-ptr-mutability.rs:+7:1: +7:2 - StorageDead(_1); // scope 0 at $DIR/receiver-ptr-mutability.rs:+7:1: +7:2 - return; // scope 0 at $DIR/receiver-ptr-mutability.rs:+7:2: +7:2 + StorageDead(_11); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:15: 19:16 + StorageDead(_10); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:16: 19:17 + _0 = const (); // scope 0 at $DIR/receiver-ptr-mutability.rs:13:11: 20:2 + StorageDead(_9); // scope 1 at $DIR/receiver-ptr-mutability.rs:20:1: 20:2 + StorageDead(_8); // scope 1 at $DIR/receiver-ptr-mutability.rs:20:1: 20:2 + StorageDead(_7); // scope 1 at $DIR/receiver-ptr-mutability.rs:20:1: 20:2 + StorageDead(_5); // scope 1 at $DIR/receiver-ptr-mutability.rs:20:1: 20:2 + StorageDead(_1); // scope 0 at $DIR/receiver-ptr-mutability.rs:20:1: 20:2 + return; // scope 0 at $DIR/receiver-ptr-mutability.rs:20:2: 20:2 } bb4 (cleanup): { - resume; // scope 0 at $DIR/receiver-ptr-mutability.rs:+0:1: +7:2 + resume; // scope 0 at $DIR/receiver-ptr-mutability.rs:13:1: 20:2 } } diff --git a/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff b/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff index 243a54b6a8454..7b6146d4bc14d 100644 --- a/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff +++ b/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff @@ -2,75 +2,75 @@ + // MIR for `match_guard` after CleanupNonCodegenStatements fn match_guard(_1: Option<&&i32>, _2: bool) -> i32 { - debug x => _1; // in scope 0 at $DIR/remove_fake_borrows.rs:+0:16: +0:17 - debug c => _2; // in scope 0 at $DIR/remove_fake_borrows.rs:+0:34: +0:35 - let mut _0: i32; // return place in scope 0 at $DIR/remove_fake_borrows.rs:+0:46: +0:49 - let mut _3: isize; // in scope 0 at $DIR/remove_fake_borrows.rs:+2:9: +2:16 - let mut _4: &std::option::Option<&&i32>; // in scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12 - let mut _5: &&i32; // in scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12 - let mut _6: &&&i32; // in scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12 - let mut _7: &i32; // in scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12 - let mut _8: bool; // in scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21 + debug x => _1; // in scope 0 at $DIR/remove_fake_borrows.rs:6:16: 6:17 + debug c => _2; // in scope 0 at $DIR/remove_fake_borrows.rs:6:34: 6:35 + let mut _0: i32; // return place in scope 0 at $DIR/remove_fake_borrows.rs:6:46: 6:49 + let mut _3: isize; // in scope 0 at $DIR/remove_fake_borrows.rs:8:9: 8:16 + let mut _4: &std::option::Option<&&i32>; // in scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 + let mut _5: &&i32; // in scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 + let mut _6: &&&i32; // in scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 + let mut _7: &i32; // in scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 + let mut _8: bool; // in scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21 bb0: { -- FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12 -+ nop; // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12 - _3 = discriminant(_1); // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12 - switchInt(move _3) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:+1:5: +1:12 +- FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 ++ nop; // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 + _3 = discriminant(_1); // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 + switchInt(move _3) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:7:5: 7:12 } bb1: { - _0 = const 1_i32; // scope 0 at $DIR/remove_fake_borrows.rs:+3:14: +3:15 - goto -> bb7; // scope 0 at $DIR/remove_fake_borrows.rs:+3:14: +3:15 + _0 = const 1_i32; // scope 0 at $DIR/remove_fake_borrows.rs:9:14: 9:15 + goto -> bb7; // scope 0 at $DIR/remove_fake_borrows.rs:9:14: 9:15 } bb2: { - switchInt((*(*((_1 as Some).0: &&i32)))) -> [0_i32: bb3, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:+1:5: +1:12 + switchInt((*(*((_1 as Some).0: &&i32)))) -> [0_i32: bb3, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:7:5: 7:12 } bb3: { - goto -> bb4; // scope 0 at $DIR/remove_fake_borrows.rs:+2:9: +2:16 + goto -> bb4; // scope 0 at $DIR/remove_fake_borrows.rs:8:9: 8:16 } bb4: { -- _4 = &shallow _1; // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12 -- _5 = &shallow (*((_1 as Some).0: &&i32)); // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12 -- _6 = &shallow ((_1 as Some).0: &&i32); // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12 -- _7 = &shallow (*(*((_1 as Some).0: &&i32))); // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12 -+ nop; // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12 -+ nop; // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12 -+ nop; // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12 -+ nop; // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12 - StorageLive(_8); // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21 - _8 = _2; // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21 - switchInt(move _8) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21 +- _4 = &shallow _1; // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 +- _5 = &shallow (*((_1 as Some).0: &&i32)); // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 +- _6 = &shallow ((_1 as Some).0: &&i32); // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 +- _7 = &shallow (*(*((_1 as Some).0: &&i32))); // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 ++ nop; // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 ++ nop; // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 ++ nop; // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 ++ nop; // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 + StorageLive(_8); // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21 + _8 = _2; // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21 + switchInt(move _8) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21 } bb5: { - StorageDead(_8); // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21 -- FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21 -- FakeRead(ForMatchGuard, _5); // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21 -- FakeRead(ForMatchGuard, _6); // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21 -- FakeRead(ForMatchGuard, _7); // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21 -+ nop; // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21 -+ nop; // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21 -+ nop; // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21 -+ nop; // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21 - _0 = const 0_i32; // scope 0 at $DIR/remove_fake_borrows.rs:+2:25: +2:26 - goto -> bb7; // scope 0 at $DIR/remove_fake_borrows.rs:+2:25: +2:26 + StorageDead(_8); // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21 +- FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21 +- FakeRead(ForMatchGuard, _5); // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21 +- FakeRead(ForMatchGuard, _6); // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21 +- FakeRead(ForMatchGuard, _7); // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21 ++ nop; // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21 ++ nop; // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21 ++ nop; // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21 ++ nop; // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21 + _0 = const 0_i32; // scope 0 at $DIR/remove_fake_borrows.rs:8:25: 8:26 + goto -> bb7; // scope 0 at $DIR/remove_fake_borrows.rs:8:25: 8:26 } bb6: { - StorageDead(_8); // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21 - goto -> bb1; // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21 + StorageDead(_8); // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21 + goto -> bb1; // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21 } bb7: { - return; // scope 0 at $DIR/remove_fake_borrows.rs:+5:2: +5:2 + return; // scope 0 at $DIR/remove_fake_borrows.rs:11:2: 11:2 } bb8 (cleanup): { - resume; // scope 0 at $DIR/remove_fake_borrows.rs:+0:1: +5:2 + resume; // scope 0 at $DIR/remove_fake_borrows.rs:6:1: 11:2 } } diff --git a/src/test/mir-opt/remove_never_const.no_codegen.PreCodegen.after.mir b/src/test/mir-opt/remove_never_const.no_codegen.PreCodegen.after.mir index 76bdd23be1684..bf62c8441fd11 100644 --- a/src/test/mir-opt/remove_never_const.no_codegen.PreCodegen.after.mir +++ b/src/test/mir-opt/remove_never_const.no_codegen.PreCodegen.after.mir @@ -1,11 +1,11 @@ // MIR for `no_codegen` after PreCodegen fn no_codegen() -> () { - let mut _0: (); // return place in scope 0 at $DIR/remove-never-const.rs:+0:20: +0:20 + let mut _0: (); // return place in scope 0 at $DIR/remove-never-const.rs:18:20: 18:20 scope 1 { } bb0: { - unreachable; // scope 0 at $DIR/remove-never-const.rs:+1:13: +1:33 + unreachable; // scope 0 at $DIR/remove-never-const.rs:19:13: 19:33 } } diff --git a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff index a17a0776437d4..b2bfe4280b0af 100644 --- a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff +++ b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff @@ -2,26 +2,26 @@ + // MIR for `main` after RemoveStorageMarkers fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/remove_storage_markers.rs:+0:11: +0:11 - let mut _1: i32; // in scope 0 at $DIR/remove_storage_markers.rs:+1:9: +1:16 - let mut _2: std::ops::Range; // in scope 0 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - let mut _3: std::ops::Range; // in scope 0 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - let mut _5: (); // in scope 0 at $DIR/remove_storage_markers.rs:+0:1: +5:2 - let _6: (); // in scope 0 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - let mut _7: std::option::Option; // in scope 0 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - let mut _8: &mut std::ops::Range; // in scope 0 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - let mut _9: &mut std::ops::Range; // in scope 0 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - let mut _10: isize; // in scope 0 at $DIR/remove_storage_markers.rs:+2:5: +4:6 - let mut _11: !; // in scope 0 at $DIR/remove_storage_markers.rs:+2:5: +4:6 - let mut _13: i32; // in scope 0 at $DIR/remove_storage_markers.rs:+3:16: +3:17 + let mut _0: (); // return place in scope 0 at $DIR/remove_storage_markers.rs:6:11: 6:11 + let mut _1: i32; // in scope 0 at $DIR/remove_storage_markers.rs:7:9: 7:16 + let mut _2: std::ops::Range; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let mut _3: std::ops::Range; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let mut _5: (); // in scope 0 at $DIR/remove_storage_markers.rs:6:1: 11:2 + let _6: (); // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let mut _7: std::option::Option; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let mut _8: &mut std::ops::Range; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let mut _9: &mut std::ops::Range; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let mut _10: isize; // in scope 0 at $DIR/remove_storage_markers.rs:8:5: 10:6 + let mut _11: !; // in scope 0 at $DIR/remove_storage_markers.rs:8:5: 10:6 + let mut _13: i32; // in scope 0 at $DIR/remove_storage_markers.rs:9:16: 9:17 scope 1 { - debug sum => _1; // in scope 1 at $DIR/remove_storage_markers.rs:+1:9: +1:16 - let mut _4: std::ops::Range; // in scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19 + debug sum => _1; // in scope 1 at $DIR/remove_storage_markers.rs:7:9: 7:16 + let mut _4: std::ops::Range; // in scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 scope 2 { - debug iter => _4; // in scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - let _12: i32; // in scope 2 at $DIR/remove_storage_markers.rs:+2:9: +2:10 + debug iter => _4; // in scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let _12: i32; // in scope 2 at $DIR/remove_storage_markers.rs:8:9: 8:10 scope 3 { - debug i => _12; // in scope 3 at $DIR/remove_storage_markers.rs:+2:9: +2:10 + debug i => _12; // in scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10 } scope 5 (inlined iter::range::>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19 debug self => _8; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL @@ -34,27 +34,27 @@ } bb0: { -- StorageLive(_1); // scope 0 at $DIR/remove_storage_markers.rs:+1:9: +1:16 - _1 = const 0_i32; // scope 0 at $DIR/remove_storage_markers.rs:+1:19: +1:20 -- StorageLive(_2); // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19 -- StorageLive(_3); // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - Deinit(_3); // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - (_3.0: i32) = const 0_i32; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - (_3.1: i32) = const 10_i32; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19 +- StorageLive(_1); // scope 0 at $DIR/remove_storage_markers.rs:7:9: 7:16 + _1 = const 0_i32; // scope 0 at $DIR/remove_storage_markers.rs:7:19: 7:20 +- StorageLive(_2); // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 +- StorageLive(_3); // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 + Deinit(_3); // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 + (_3.0: i32) = const 0_i32; // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 + (_3.1: i32) = const 10_i32; // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 _2 = move _3; // scope 4 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL -- StorageDead(_3); // scope 1 at $DIR/remove_storage_markers.rs:+2:18: +2:19 -- StorageLive(_4); // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - _4 = move _2; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - goto -> bb1; // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6 +- StorageDead(_3); // scope 1 at $DIR/remove_storage_markers.rs:8:18: 8:19 +- StorageLive(_4); // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 + _4 = move _2; // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 + goto -> bb1; // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6 } bb1: { -- StorageLive(_6); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 -- StorageLive(_7); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 -- StorageLive(_8); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 -- StorageLive(_9); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - _9 = &mut _4; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - _8 = &mut (*_9); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 +- StorageLive(_6); // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 +- StorageLive(_7); // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 +- StorageLive(_8); // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 +- StorageLive(_9); // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 + _9 = &mut _4; // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 + _8 = &mut (*_9); // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 - StorageLive(_14); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL _14 = &mut (*_8); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL _7 = as iter::range::RangeIteratorImpl>::spec_next(move _14) -> bb4; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL @@ -64,41 +64,41 @@ } bb2: { -- StorageLive(_12); // scope 2 at $DIR/remove_storage_markers.rs:+2:9: +2:10 - _12 = ((_7 as Some).0: i32); // scope 2 at $DIR/remove_storage_markers.rs:+2:9: +2:10 -- StorageLive(_13); // scope 3 at $DIR/remove_storage_markers.rs:+3:16: +3:17 - _13 = _12; // scope 3 at $DIR/remove_storage_markers.rs:+3:16: +3:17 - _1 = Add(_1, move _13); // scope 3 at $DIR/remove_storage_markers.rs:+3:9: +3:17 -- StorageDead(_13); // scope 3 at $DIR/remove_storage_markers.rs:+3:16: +3:17 - _6 = const (); // scope 3 at $DIR/remove_storage_markers.rs:+2:20: +4:6 -- StorageDead(_12); // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6 -- StorageDead(_9); // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6 -- StorageDead(_7); // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6 -- StorageDead(_6); // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6 - _5 = const (); // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6 - goto -> bb1; // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6 +- StorageLive(_12); // scope 2 at $DIR/remove_storage_markers.rs:8:9: 8:10 + _12 = ((_7 as Some).0: i32); // scope 2 at $DIR/remove_storage_markers.rs:8:9: 8:10 +- StorageLive(_13); // scope 3 at $DIR/remove_storage_markers.rs:9:16: 9:17 + _13 = _12; // scope 3 at $DIR/remove_storage_markers.rs:9:16: 9:17 + _1 = Add(_1, move _13); // scope 3 at $DIR/remove_storage_markers.rs:9:9: 9:17 +- StorageDead(_13); // scope 3 at $DIR/remove_storage_markers.rs:9:16: 9:17 + _6 = const (); // scope 3 at $DIR/remove_storage_markers.rs:8:20: 10:6 +- StorageDead(_12); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 +- StorageDead(_9); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 +- StorageDead(_7); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 +- StorageDead(_6); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 + _5 = const (); // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6 + goto -> bb1; // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6 } bb3: { - _0 = const (); // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6 -- StorageDead(_9); // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6 -- StorageDead(_7); // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6 -- StorageDead(_6); // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6 -- StorageDead(_4); // scope 1 at $DIR/remove_storage_markers.rs:+4:5: +4:6 -- StorageDead(_2); // scope 1 at $DIR/remove_storage_markers.rs:+4:5: +4:6 -- StorageDead(_1); // scope 0 at $DIR/remove_storage_markers.rs:+5:1: +5:2 - return; // scope 0 at $DIR/remove_storage_markers.rs:+5:2: +5:2 + _0 = const (); // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6 +- StorageDead(_9); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 +- StorageDead(_7); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 +- StorageDead(_6); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 +- StorageDead(_4); // scope 1 at $DIR/remove_storage_markers.rs:10:5: 10:6 +- StorageDead(_2); // scope 1 at $DIR/remove_storage_markers.rs:10:5: 10:6 +- StorageDead(_1); // scope 0 at $DIR/remove_storage_markers.rs:11:1: 11:2 + return; // scope 0 at $DIR/remove_storage_markers.rs:11:2: 11:2 } bb4: { - StorageDead(_14); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL -- StorageDead(_8); // scope 2 at $DIR/remove_storage_markers.rs:+2:18: +2:19 - _10 = discriminant(_7); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - switchInt(move _10) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 +- StorageDead(_8); // scope 2 at $DIR/remove_storage_markers.rs:8:18: 8:19 + _10 = discriminant(_7); // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 + switchInt(move _10) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 } bb5 (cleanup): { - resume; // scope 0 at $DIR/remove_storage_markers.rs:+0:1: +5:2 + resume; // scope 0 at $DIR/remove_storage_markers.rs:6:1: 11:2 } } diff --git a/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff index 07e4dd4181324..8b321130236f8 100644 --- a/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff +++ b/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff @@ -2,30 +2,30 @@ + // MIR for `cannot_opt_generic` after RemoveUnneededDrops fn cannot_opt_generic(_1: T) -> () { - debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:+0:26: +0:27 - let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:+0:32: +0:32 - let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12 - let mut _3: T; // in scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:20:26: 20:27 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:20:32: 20:32 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:21:5: 21:12 + let mut _3: T; // in scope 0 at $DIR/remove_unneeded_drops.rs:21:10: 21:11 scope 1 (inlined std::mem::drop::) { // at $DIR/remove_unneeded_drops.rs:21:5: 21:12 debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } bb0: { - StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12 - StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 - _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:21:5: 21:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:21:10: 21:11 + _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:21:10: 21:11 drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } bb1 (cleanup): { - resume; // scope 0 at $DIR/remove_unneeded_drops.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/remove_unneeded_drops.rs:20:1: 22:2 } bb2: { - StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:11: +1:12 - StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13 - nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+0:32: +2:2 - return; // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2 + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:21:11: 21:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:21:12: 21:13 + nop; // scope 0 at $DIR/remove_unneeded_drops.rs:20:32: 22:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:22:2: 22:2 } } diff --git a/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff index e809ca4e90066..a0c8565134cd9 100644 --- a/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff +++ b/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff @@ -2,30 +2,30 @@ + // MIR for `dont_opt` after RemoveUnneededDrops fn dont_opt(_1: Vec) -> () { - debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:+0:13: +0:14 - let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:+0:27: +0:27 - let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12 - let mut _3: std::vec::Vec; // in scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:8:13: 8:14 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:8:27: 8:27 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:9:5: 9:12 + let mut _3: std::vec::Vec; // in scope 0 at $DIR/remove_unneeded_drops.rs:9:10: 9:11 scope 1 (inlined std::mem::drop::>) { // at $DIR/remove_unneeded_drops.rs:9:5: 9:12 debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } bb0: { - StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12 - StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 - _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:9:5: 9:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:9:10: 9:11 + _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:9:10: 9:11 drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } bb1 (cleanup): { - resume; // scope 0 at $DIR/remove_unneeded_drops.rs:+0:1: +2:2 + resume; // scope 0 at $DIR/remove_unneeded_drops.rs:8:1: 10:2 } bb2: { - StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:11: +1:12 - StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13 - nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+0:27: +2:2 - return; // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2 + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:9:11: 9:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:9:12: 9:13 + nop; // scope 0 at $DIR/remove_unneeded_drops.rs:8:27: 10:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff index b29b08f836d33..44eda308bdf90 100644 --- a/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff +++ b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff @@ -2,30 +2,30 @@ + // MIR for `opt` after RemoveUnneededDrops fn opt(_1: bool) -> () { - debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:+0:8: +0:9 - let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:+0:17: +0:17 - let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12 - let mut _3: bool; // in scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:3:8: 3:9 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:3:17: 3:17 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:4:5: 4:12 + let mut _3: bool; // in scope 0 at $DIR/remove_unneeded_drops.rs:4:10: 4:11 scope 1 (inlined std::mem::drop::) { // at $DIR/remove_unneeded_drops.rs:4:5: 4:12 debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } bb0: { - StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12 - StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 - _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:4:5: 4:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:4:10: 4:11 + _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:4:10: 4:11 - drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - } - - bb1: { - StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:11: +1:12 - StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13 -- nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+0:17: +2:2 - return; // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2 + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:4:11: 4:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:4:12: 4:13 +- nop; // scope 0 at $DIR/remove_unneeded_drops.rs:3:17: 5:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:5:2: 5:2 - } - - bb2 (cleanup): { -- resume; // scope 0 at $DIR/remove_unneeded_drops.rs:+0:1: +2:2 +- resume; // scope 0 at $DIR/remove_unneeded_drops.rs:3:1: 5:2 } } diff --git a/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff index 9058ddbd7ec79..85de00e7001a7 100644 --- a/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff +++ b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff @@ -2,30 +2,30 @@ + // MIR for `opt_generic_copy` after RemoveUnneededDrops fn opt_generic_copy(_1: T) -> () { - debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:+0:30: +0:31 - let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:+0:36: +0:36 - let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12 - let mut _3: T; // in scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:13:30: 13:31 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:13:36: 13:36 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:14:5: 14:12 + let mut _3: T; // in scope 0 at $DIR/remove_unneeded_drops.rs:14:10: 14:11 scope 1 (inlined std::mem::drop::) { // at $DIR/remove_unneeded_drops.rs:14:5: 14:12 debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } bb0: { - StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12 - StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 - _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:14:5: 14:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:14:10: 14:11 + _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:14:10: 14:11 - drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - } - - bb1: { - StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:11: +1:12 - StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13 -- nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+0:36: +2:2 - return; // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2 + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:14:11: 14:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:14:12: 14:13 +- nop; // scope 0 at $DIR/remove_unneeded_drops.rs:13:36: 15:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:15:2: 15:2 - } - - bb2 (cleanup): { -- resume; // scope 0 at $DIR/remove_unneeded_drops.rs:+0:1: +2:2 +- resume; // scope 0 at $DIR/remove_unneeded_drops.rs:13:1: 15:2 } } diff --git a/src/test/mir-opt/remove_zsts_dont_touch_unions.get_union.RemoveZsts.after.mir b/src/test/mir-opt/remove_zsts_dont_touch_unions.get_union.RemoveZsts.after.mir index 7d9e6046202ca..ad8f0acc763a6 100644 --- a/src/test/mir-opt/remove_zsts_dont_touch_unions.get_union.RemoveZsts.after.mir +++ b/src/test/mir-opt/remove_zsts_dont_touch_unions.get_union.RemoveZsts.after.mir @@ -1,15 +1,15 @@ // MIR for `get_union` after RemoveZsts fn get_union() -> Foo { - let mut _0: Foo; // return place in scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:+0:19: +0:22 - let mut _1: (); // in scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:+1:14: +1:16 + let mut _0: Foo; // return place in scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:12:19: 12:22 + let mut _1: (); // in scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:13:14: 13:16 bb0: { - StorageLive(_1); // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:+1:14: +1:16 - nop; // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:+1:14: +1:16 - Deinit(_0); // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:+1:5: +1:18 - (_0.0: ()) = move _1; // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:+1:5: +1:18 - StorageDead(_1); // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:+1:17: +1:18 - return; // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:+2:2: +2:2 + StorageLive(_1); // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:13:14: 13:16 + nop; // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:13:14: 13:16 + Deinit(_0); // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:13:5: 13:18 + (_0.0: ()) = move _1; // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:13:5: 13:18 + StorageDead(_1); // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:13:17: 13:18 + return; // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:14:2: 14:2 } } diff --git a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir index 451d0fe4c02dc..05e83b13a50c4 100644 --- a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir @@ -1,23 +1,23 @@ // MIR for `array_casts` after SimplifyCfg-elaborate-drops fn array_casts() -> () { - let mut _0: (); // return place in scope 0 at $DIR/retag.rs:+0:18: +0:18 - let mut _1: [usize; 2]; // in scope 0 at $DIR/retag.rs:+1:9: +1:14 - let mut _3: *mut [usize; 2]; // in scope 0 at $DIR/retag.rs:+2:13: +2:19 - let mut _4: &mut [usize; 2]; // in scope 0 at $DIR/retag.rs:+2:13: +2:19 - let _5: (); // in scope 0 at $DIR/retag.rs:+3:5: +3:30 - let mut _6: *mut usize; // in scope 0 at $DIR/retag.rs:+3:15: +3:23 - let mut _7: *mut usize; // in scope 0 at $DIR/retag.rs:+3:15: +3:16 - let mut _10: *const [usize; 2]; // in scope 0 at $DIR/retag.rs:+6:13: +6:15 - let _11: &[usize; 2]; // in scope 0 at $DIR/retag.rs:+6:13: +6:15 + let mut _0: (); // return place in scope 0 at $DIR/retag.rs:57:18: 57:18 + let mut _1: [usize; 2]; // in scope 0 at $DIR/retag.rs:58:9: 58:14 + let mut _3: *mut [usize; 2]; // in scope 0 at $DIR/retag.rs:59:13: 59:19 + let mut _4: &mut [usize; 2]; // in scope 0 at $DIR/retag.rs:59:13: 59:19 + let _5: (); // in scope 0 at $DIR/retag.rs:60:5: 60:30 + let mut _6: *mut usize; // in scope 0 at $DIR/retag.rs:60:15: 60:23 + let mut _7: *mut usize; // in scope 0 at $DIR/retag.rs:60:15: 60:16 + let mut _10: *const [usize; 2]; // in scope 0 at $DIR/retag.rs:63:13: 63:15 + let _11: &[usize; 2]; // in scope 0 at $DIR/retag.rs:63:13: 63:15 let _12: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _13: (&usize, &usize); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _14: &usize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _15: usize; // in scope 0 at $DIR/retag.rs:+7:16: +7:36 - let mut _16: *const usize; // in scope 0 at $DIR/retag.rs:+7:26: +7:34 - let mut _17: *const usize; // in scope 0 at $DIR/retag.rs:+7:26: +7:27 + let _15: usize; // in scope 0 at $DIR/retag.rs:64:16: 64:36 + let mut _16: *const usize; // in scope 0 at $DIR/retag.rs:64:26: 64:34 + let mut _17: *const usize; // in scope 0 at $DIR/retag.rs:64:26: 64:27 let mut _18: &usize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _19: usize; // in scope 0 at $DIR/retag.rs:+7:38: +7:39 + let _19: usize; // in scope 0 at $DIR/retag.rs:64:38: 64:39 let mut _22: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _23: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _24: usize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -31,18 +31,18 @@ fn array_casts() -> () { let _33: &usize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _34: std::option::Option; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 1 { - debug x => _1; // in scope 1 at $DIR/retag.rs:+1:9: +1:14 - let _2: *mut usize; // in scope 1 at $DIR/retag.rs:+2:9: +2:10 + debug x => _1; // in scope 1 at $DIR/retag.rs:58:9: 58:14 + let _2: *mut usize; // in scope 1 at $DIR/retag.rs:59:9: 59:10 scope 2 { - debug p => _2; // in scope 2 at $DIR/retag.rs:+2:9: +2:10 - let _8: [usize; 2]; // in scope 2 at $DIR/retag.rs:+5:9: +5:10 + debug p => _2; // in scope 2 at $DIR/retag.rs:59:9: 59:10 + let _8: [usize; 2]; // in scope 2 at $DIR/retag.rs:62:9: 62:10 scope 3 { } scope 4 { - debug x => _8; // in scope 4 at $DIR/retag.rs:+5:9: +5:10 - let _9: *const usize; // in scope 4 at $DIR/retag.rs:+6:9: +6:10 + debug x => _8; // in scope 4 at $DIR/retag.rs:62:9: 62:10 + let _9: *const usize; // in scope 4 at $DIR/retag.rs:63:9: 63:10 scope 5 { - debug p => _9; // in scope 5 at $DIR/retag.rs:+6:9: +6:10 + debug p => _9; // in scope 5 at $DIR/retag.rs:63:9: 63:10 let _20: &usize; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let _21: &usize; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _35: &usize; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -62,62 +62,62 @@ fn array_casts() -> () { } bb0: { - StorageLive(_1); // scope 0 at $DIR/retag.rs:+1:9: +1:14 - _1 = [const 0_usize, const 0_usize]; // scope 0 at $DIR/retag.rs:+1:29: +1:35 - StorageLive(_2); // scope 1 at $DIR/retag.rs:+2:9: +2:10 - StorageLive(_3); // scope 1 at $DIR/retag.rs:+2:13: +2:19 - StorageLive(_4); // scope 1 at $DIR/retag.rs:+2:13: +2:19 - _4 = &mut _1; // scope 1 at $DIR/retag.rs:+2:13: +2:19 - Retag(_4); // scope 1 at $DIR/retag.rs:+2:13: +2:19 - _3 = &raw mut (*_4); // scope 1 at $DIR/retag.rs:+2:13: +2:19 - Retag([raw] _3); // scope 1 at $DIR/retag.rs:+2:13: +2:19 - _2 = move _3 as *mut usize (Pointer(ArrayToPointer)); // scope 1 at $DIR/retag.rs:+2:13: +2:33 - StorageDead(_3); // scope 1 at $DIR/retag.rs:+2:32: +2:33 - StorageDead(_4); // scope 1 at $DIR/retag.rs:+2:33: +2:34 - StorageLive(_5); // scope 2 at $DIR/retag.rs:+3:5: +3:30 - StorageLive(_6); // scope 3 at $DIR/retag.rs:+3:15: +3:23 - StorageLive(_7); // scope 3 at $DIR/retag.rs:+3:15: +3:16 - _7 = _2; // scope 3 at $DIR/retag.rs:+3:15: +3:16 - _6 = ptr::mut_ptr::::add(move _7, const 1_usize) -> bb1; // scope 3 at $DIR/retag.rs:+3:15: +3:23 + StorageLive(_1); // scope 0 at $DIR/retag.rs:58:9: 58:14 + _1 = [const 0_usize, const 0_usize]; // scope 0 at $DIR/retag.rs:58:29: 58:35 + StorageLive(_2); // scope 1 at $DIR/retag.rs:59:9: 59:10 + StorageLive(_3); // scope 1 at $DIR/retag.rs:59:13: 59:19 + StorageLive(_4); // scope 1 at $DIR/retag.rs:59:13: 59:19 + _4 = &mut _1; // scope 1 at $DIR/retag.rs:59:13: 59:19 + Retag(_4); // scope 1 at $DIR/retag.rs:59:13: 59:19 + _3 = &raw mut (*_4); // scope 1 at $DIR/retag.rs:59:13: 59:19 + Retag([raw] _3); // scope 1 at $DIR/retag.rs:59:13: 59:19 + _2 = move _3 as *mut usize (Pointer(ArrayToPointer)); // scope 1 at $DIR/retag.rs:59:13: 59:33 + StorageDead(_3); // scope 1 at $DIR/retag.rs:59:32: 59:33 + StorageDead(_4); // scope 1 at $DIR/retag.rs:59:33: 59:34 + StorageLive(_5); // scope 2 at $DIR/retag.rs:60:5: 60:30 + StorageLive(_6); // scope 3 at $DIR/retag.rs:60:15: 60:23 + StorageLive(_7); // scope 3 at $DIR/retag.rs:60:15: 60:16 + _7 = _2; // scope 3 at $DIR/retag.rs:60:15: 60:16 + _6 = ptr::mut_ptr::::add(move _7, const 1_usize) -> bb1; // scope 3 at $DIR/retag.rs:60:15: 60:23 // mir::Constant // + span: $DIR/retag.rs:60:17: 60:20 // + literal: Const { ty: unsafe fn(*mut usize, usize) -> *mut usize {ptr::mut_ptr::::add}, val: Value() } } bb1: { - StorageDead(_7); // scope 3 at $DIR/retag.rs:+3:22: +3:23 - (*_6) = const 1_usize; // scope 3 at $DIR/retag.rs:+3:14: +3:27 - StorageDead(_6); // scope 3 at $DIR/retag.rs:+3:27: +3:28 - _5 = const (); // scope 3 at $DIR/retag.rs:+3:5: +3:30 - StorageDead(_5); // scope 2 at $DIR/retag.rs:+3:29: +3:30 - StorageLive(_8); // scope 2 at $DIR/retag.rs:+5:9: +5:10 - _8 = [const 0_usize, const 1_usize]; // scope 2 at $DIR/retag.rs:+5:25: +5:31 - StorageLive(_9); // scope 4 at $DIR/retag.rs:+6:9: +6:10 - StorageLive(_10); // scope 4 at $DIR/retag.rs:+6:13: +6:15 - StorageLive(_11); // scope 4 at $DIR/retag.rs:+6:13: +6:15 - _11 = &_8; // scope 4 at $DIR/retag.rs:+6:13: +6:15 - Retag(_11); // scope 4 at $DIR/retag.rs:+6:13: +6:15 - _10 = &raw const (*_11); // scope 4 at $DIR/retag.rs:+6:13: +6:15 - Retag([raw] _10); // scope 4 at $DIR/retag.rs:+6:13: +6:15 - _9 = move _10 as *const usize (Pointer(ArrayToPointer)); // scope 4 at $DIR/retag.rs:+6:13: +6:31 - StorageDead(_10); // scope 4 at $DIR/retag.rs:+6:30: +6:31 - StorageDead(_11); // scope 4 at $DIR/retag.rs:+6:31: +6:32 + StorageDead(_7); // scope 3 at $DIR/retag.rs:60:22: 60:23 + (*_6) = const 1_usize; // scope 3 at $DIR/retag.rs:60:14: 60:27 + StorageDead(_6); // scope 3 at $DIR/retag.rs:60:27: 60:28 + _5 = const (); // scope 3 at $DIR/retag.rs:60:5: 60:30 + StorageDead(_5); // scope 2 at $DIR/retag.rs:60:29: 60:30 + StorageLive(_8); // scope 2 at $DIR/retag.rs:62:9: 62:10 + _8 = [const 0_usize, const 1_usize]; // scope 2 at $DIR/retag.rs:62:25: 62:31 + StorageLive(_9); // scope 4 at $DIR/retag.rs:63:9: 63:10 + StorageLive(_10); // scope 4 at $DIR/retag.rs:63:13: 63:15 + StorageLive(_11); // scope 4 at $DIR/retag.rs:63:13: 63:15 + _11 = &_8; // scope 4 at $DIR/retag.rs:63:13: 63:15 + Retag(_11); // scope 4 at $DIR/retag.rs:63:13: 63:15 + _10 = &raw const (*_11); // scope 4 at $DIR/retag.rs:63:13: 63:15 + Retag([raw] _10); // scope 4 at $DIR/retag.rs:63:13: 63:15 + _9 = move _10 as *const usize (Pointer(ArrayToPointer)); // scope 4 at $DIR/retag.rs:63:13: 63:31 + StorageDead(_10); // scope 4 at $DIR/retag.rs:63:30: 63:31 + StorageDead(_11); // scope 4 at $DIR/retag.rs:63:31: 63:32 StorageLive(_12); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_13); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_14); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_15); // scope 5 at $DIR/retag.rs:+7:16: +7:36 - StorageLive(_16); // scope 6 at $DIR/retag.rs:+7:26: +7:34 - StorageLive(_17); // scope 6 at $DIR/retag.rs:+7:26: +7:27 - _17 = _9; // scope 6 at $DIR/retag.rs:+7:26: +7:27 - _16 = ptr::const_ptr::::add(move _17, const 1_usize) -> bb2; // scope 6 at $DIR/retag.rs:+7:26: +7:34 + StorageLive(_15); // scope 5 at $DIR/retag.rs:64:16: 64:36 + StorageLive(_16); // scope 6 at $DIR/retag.rs:64:26: 64:34 + StorageLive(_17); // scope 6 at $DIR/retag.rs:64:26: 64:27 + _17 = _9; // scope 6 at $DIR/retag.rs:64:26: 64:27 + _16 = ptr::const_ptr::::add(move _17, const 1_usize) -> bb2; // scope 6 at $DIR/retag.rs:64:26: 64:34 // mir::Constant // + span: $DIR/retag.rs:64:28: 64:31 // + literal: Const { ty: unsafe fn(*const usize, usize) -> *const usize {ptr::const_ptr::::add}, val: Value() } } bb2: { - StorageDead(_17); // scope 6 at $DIR/retag.rs:+7:33: +7:34 - _15 = (*_16); // scope 6 at $DIR/retag.rs:+7:25: +7:34 + StorageDead(_17); // scope 6 at $DIR/retag.rs:64:33: 64:34 + _15 = (*_16); // scope 6 at $DIR/retag.rs:64:25: 64:34 _14 = &_15; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL Retag(_14); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -188,11 +188,11 @@ fn array_casts() -> () { StorageDead(_15); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_13); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_12); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _0 = const (); // scope 0 at $DIR/retag.rs:+0:18: +8:2 - StorageDead(_9); // scope 4 at $DIR/retag.rs:+8:1: +8:2 - StorageDead(_8); // scope 2 at $DIR/retag.rs:+8:1: +8:2 - StorageDead(_2); // scope 1 at $DIR/retag.rs:+8:1: +8:2 - StorageDead(_1); // scope 0 at $DIR/retag.rs:+8:1: +8:2 - return; // scope 0 at $DIR/retag.rs:+8:2: +8:2 + _0 = const (); // scope 0 at $DIR/retag.rs:57:18: 65:2 + StorageDead(_9); // scope 4 at $DIR/retag.rs:65:1: 65:2 + StorageDead(_8); // scope 2 at $DIR/retag.rs:65:1: 65:2 + StorageDead(_2); // scope 1 at $DIR/retag.rs:65:1: 65:2 + StorageDead(_1); // scope 0 at $DIR/retag.rs:65:1: 65:2 + return; // scope 0 at $DIR/retag.rs:65:2: 65:2 } } diff --git a/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir b/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir index 84f674db2d154..8057aa13a9ffb 100644 --- a/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir +++ b/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir @@ -1,20 +1,20 @@ // MIR for `std::ptr::drop_in_place` after SimplifyCfg-make_shim fn std::ptr::drop_in_place(_1: *mut Test) -> () { - let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _2: &mut Test; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _2: &mut Test; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL bb0: { - Retag([raw] _1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _3 = ::drop(move _2) -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + Retag([raw] _1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _3 = ::drop(move _2) -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL // + literal: Const { ty: for<'r> fn(&'r mut Test) {::drop}, val: Value() } } bb1: { - return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } } diff --git a/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir index 60c0f336e74c6..5808c60775252 100644 --- a/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir @@ -1,22 +1,22 @@ // MIR for `main::{closure#0}` after SimplifyCfg-elaborate-drops fn main::{closure#0}(_1: &[closure@main::{closure#0}], _2: &i32) -> &i32 { - debug x => _2; // in scope 0 at $DIR/retag.rs:+0:32: +0:33 - let mut _0: &i32; // return place in scope 0 at $DIR/retag.rs:+0:44: +0:48 - let _3: &i32; // in scope 0 at $DIR/retag.rs:+1:13: +1:15 + debug x => _2; // in scope 0 at $DIR/retag.rs:40:32: 40:33 + let mut _0: &i32; // return place in scope 0 at $DIR/retag.rs:40:44: 40:48 + let _3: &i32; // in scope 0 at $DIR/retag.rs:41:13: 41:15 scope 1 { - debug _y => _3; // in scope 1 at $DIR/retag.rs:+1:13: +1:15 + debug _y => _3; // in scope 1 at $DIR/retag.rs:41:13: 41:15 } bb0: { - Retag([fn entry] _1); // scope 0 at $DIR/retag.rs:+0:31: +0:48 - Retag([fn entry] _2); // scope 0 at $DIR/retag.rs:+0:31: +0:48 - StorageLive(_3); // scope 0 at $DIR/retag.rs:+1:13: +1:15 - _3 = _2; // scope 0 at $DIR/retag.rs:+1:18: +1:19 - Retag(_3); // scope 0 at $DIR/retag.rs:+1:18: +1:19 - _0 = _2; // scope 1 at $DIR/retag.rs:+2:9: +2:10 - Retag(_0); // scope 1 at $DIR/retag.rs:+2:9: +2:10 - StorageDead(_3); // scope 0 at $DIR/retag.rs:+3:5: +3:6 - return; // scope 0 at $DIR/retag.rs:+0:48: +0:48 + Retag([fn entry] _1); // scope 0 at $DIR/retag.rs:40:31: 40:48 + Retag([fn entry] _2); // scope 0 at $DIR/retag.rs:40:31: 40:48 + StorageLive(_3); // scope 0 at $DIR/retag.rs:41:13: 41:15 + _3 = _2; // scope 0 at $DIR/retag.rs:41:18: 41:19 + Retag(_3); // scope 0 at $DIR/retag.rs:41:18: 41:19 + _0 = _2; // scope 1 at $DIR/retag.rs:42:9: 42:10 + Retag(_0); // scope 1 at $DIR/retag.rs:42:9: 42:10 + StorageDead(_3); // scope 0 at $DIR/retag.rs:43:5: 43:6 + return; // scope 0 at $DIR/retag.rs:40:48: 40:48 } } diff --git a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir index ae6b5cfe21ebb..a3490d460ec54 100644 --- a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir @@ -1,117 +1,117 @@ // MIR for `main` after SimplifyCfg-elaborate-drops fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/retag.rs:+0:11: +0:11 - let mut _1: i32; // in scope 0 at $DIR/retag.rs:+1:9: +1:14 - let _2: (); // in scope 0 at $DIR/retag.rs:+2:5: +8:6 - let mut _4: &Test; // in scope 0 at $DIR/retag.rs:+3:17: +3:36 - let _5: Test; // in scope 0 at $DIR/retag.rs:+3:17: +3:24 - let mut _6: &mut i32; // in scope 0 at $DIR/retag.rs:+3:29: +3:35 - let mut _7: &mut i32; // in scope 0 at $DIR/retag.rs:+3:29: +3:35 - let mut _9: &mut i32; // in scope 0 at $DIR/retag.rs:+4:19: +4:20 - let mut _12: *mut i32; // in scope 0 at $DIR/retag.rs:+7:18: +7:29 - let mut _14: [closure@main::{closure#0}]; // in scope 0 at $DIR/retag.rs:+11:31: +14:6 - let mut _16: for<'r> fn(&'r i32) -> &'r i32; // in scope 0 at $DIR/retag.rs:+15:14: +15:15 - let mut _17: &i32; // in scope 0 at $DIR/retag.rs:+15:16: +15:18 - let _18: &i32; // in scope 0 at $DIR/retag.rs:+15:16: +15:18 - let _19: &i32; // in scope 0 at $DIR/retag.rs:+18:5: +18:24 - let mut _20: &Test; // in scope 0 at $DIR/retag.rs:+18:5: +18:24 - let _21: Test; // in scope 0 at $DIR/retag.rs:+18:5: +18:12 - let mut _22: &i32; // in scope 0 at $DIR/retag.rs:+18:21: +18:23 - let _23: &i32; // in scope 0 at $DIR/retag.rs:+18:21: +18:23 - let _24: i32; // in scope 0 at $DIR/retag.rs:+18:22: +18:23 - let mut _26: *const i32; // in scope 0 at $DIR/retag.rs:+21:14: +21:28 - let _27: (); // in scope 0 at $DIR/retag.rs:+23:5: +23:18 + let mut _0: (); // return place in scope 0 at $DIR/retag.rs:29:11: 29:11 + let mut _1: i32; // in scope 0 at $DIR/retag.rs:30:9: 30:14 + let _2: (); // in scope 0 at $DIR/retag.rs:31:5: 37:6 + let mut _4: &Test; // in scope 0 at $DIR/retag.rs:32:17: 32:36 + let _5: Test; // in scope 0 at $DIR/retag.rs:32:17: 32:24 + let mut _6: &mut i32; // in scope 0 at $DIR/retag.rs:32:29: 32:35 + let mut _7: &mut i32; // in scope 0 at $DIR/retag.rs:32:29: 32:35 + let mut _9: &mut i32; // in scope 0 at $DIR/retag.rs:33:19: 33:20 + let mut _12: *mut i32; // in scope 0 at $DIR/retag.rs:36:18: 36:29 + let mut _14: [closure@main::{closure#0}]; // in scope 0 at $DIR/retag.rs:40:31: 43:6 + let mut _16: for<'r> fn(&'r i32) -> &'r i32; // in scope 0 at $DIR/retag.rs:44:14: 44:15 + let mut _17: &i32; // in scope 0 at $DIR/retag.rs:44:16: 44:18 + let _18: &i32; // in scope 0 at $DIR/retag.rs:44:16: 44:18 + let _19: &i32; // in scope 0 at $DIR/retag.rs:47:5: 47:24 + let mut _20: &Test; // in scope 0 at $DIR/retag.rs:47:5: 47:24 + let _21: Test; // in scope 0 at $DIR/retag.rs:47:5: 47:12 + let mut _22: &i32; // in scope 0 at $DIR/retag.rs:47:21: 47:23 + let _23: &i32; // in scope 0 at $DIR/retag.rs:47:21: 47:23 + let _24: i32; // in scope 0 at $DIR/retag.rs:47:22: 47:23 + let mut _26: *const i32; // in scope 0 at $DIR/retag.rs:50:14: 50:28 + let _27: (); // in scope 0 at $DIR/retag.rs:52:5: 52:18 scope 1 { - debug x => _1; // in scope 1 at $DIR/retag.rs:+1:9: +1:14 - let _3: &mut i32; // in scope 1 at $DIR/retag.rs:+3:13: +3:14 - let _13: for<'r> fn(&'r i32) -> &'r i32; // in scope 1 at $DIR/retag.rs:+11:9: +11:10 + debug x => _1; // in scope 1 at $DIR/retag.rs:30:9: 30:14 + let _3: &mut i32; // in scope 1 at $DIR/retag.rs:32:13: 32:14 + let _13: for<'r> fn(&'r i32) -> &'r i32; // in scope 1 at $DIR/retag.rs:40:9: 40:10 scope 2 { - debug v => _3; // in scope 2 at $DIR/retag.rs:+3:13: +3:14 - let _8: &mut i32; // in scope 2 at $DIR/retag.rs:+4:13: +4:14 + debug v => _3; // in scope 2 at $DIR/retag.rs:32:13: 32:14 + let _8: &mut i32; // in scope 2 at $DIR/retag.rs:33:13: 33:14 scope 3 { - debug w => _8; // in scope 3 at $DIR/retag.rs:+4:13: +4:14 - let _10: &mut i32; // in scope 3 at $DIR/retag.rs:+5:13: +5:14 + debug w => _8; // in scope 3 at $DIR/retag.rs:33:13: 33:14 + let _10: &mut i32; // in scope 3 at $DIR/retag.rs:34:13: 34:14 scope 4 { - debug w => _10; // in scope 4 at $DIR/retag.rs:+5:13: +5:14 - let _11: *mut i32; // in scope 4 at $DIR/retag.rs:+7:13: +7:15 + debug w => _10; // in scope 4 at $DIR/retag.rs:34:13: 34:14 + let _11: *mut i32; // in scope 4 at $DIR/retag.rs:36:13: 36:15 scope 5 { - debug _w => _11; // in scope 5 at $DIR/retag.rs:+7:13: +7:15 + debug _w => _11; // in scope 5 at $DIR/retag.rs:36:13: 36:15 } } } } scope 6 { - debug c => _13; // in scope 6 at $DIR/retag.rs:+11:9: +11:10 - let _15: &i32; // in scope 6 at $DIR/retag.rs:+15:9: +15:11 + debug c => _13; // in scope 6 at $DIR/retag.rs:40:9: 40:10 + let _15: &i32; // in scope 6 at $DIR/retag.rs:44:9: 44:11 scope 7 { - debug _w => _15; // in scope 7 at $DIR/retag.rs:+15:9: +15:11 - let _25: *const i32; // in scope 7 at $DIR/retag.rs:+21:9: +21:11 - let mut _28: &i32; // in scope 7 at $DIR/retag.rs:+18:21: +18:23 + debug _w => _15; // in scope 7 at $DIR/retag.rs:44:9: 44:11 + let _25: *const i32; // in scope 7 at $DIR/retag.rs:50:9: 50:11 + let mut _28: &i32; // in scope 7 at $DIR/retag.rs:47:21: 47:23 scope 8 { - debug _w => _25; // in scope 8 at $DIR/retag.rs:+21:9: +21:11 + debug _w => _25; // in scope 8 at $DIR/retag.rs:50:9: 50:11 } } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/retag.rs:+1:9: +1:14 - _1 = const 0_i32; // scope 0 at $DIR/retag.rs:+1:17: +1:18 - StorageLive(_2); // scope 1 at $DIR/retag.rs:+2:5: +8:6 - StorageLive(_3); // scope 1 at $DIR/retag.rs:+3:13: +3:14 - StorageLive(_4); // scope 1 at $DIR/retag.rs:+3:17: +3:36 - StorageLive(_5); // scope 1 at $DIR/retag.rs:+3:17: +3:24 - _5 = Test(const 0_i32); // scope 1 at $DIR/retag.rs:+3:17: +3:24 - _4 = &_5; // scope 1 at $DIR/retag.rs:+3:17: +3:36 - Retag(_4); // scope 1 at $DIR/retag.rs:+3:17: +3:36 - StorageLive(_6); // scope 1 at $DIR/retag.rs:+3:29: +3:35 - StorageLive(_7); // scope 1 at $DIR/retag.rs:+3:29: +3:35 - _7 = &mut _1; // scope 1 at $DIR/retag.rs:+3:29: +3:35 - Retag(_7); // scope 1 at $DIR/retag.rs:+3:29: +3:35 - _6 = &mut (*_7); // scope 1 at $DIR/retag.rs:+3:29: +3:35 - Retag([2phase] _6); // scope 1 at $DIR/retag.rs:+3:29: +3:35 - _3 = Test::foo(move _4, move _6) -> [return: bb1, unwind: bb8]; // scope 1 at $DIR/retag.rs:+3:17: +3:36 + StorageLive(_1); // scope 0 at $DIR/retag.rs:30:9: 30:14 + _1 = const 0_i32; // scope 0 at $DIR/retag.rs:30:17: 30:18 + StorageLive(_2); // scope 1 at $DIR/retag.rs:31:5: 37:6 + StorageLive(_3); // scope 1 at $DIR/retag.rs:32:13: 32:14 + StorageLive(_4); // scope 1 at $DIR/retag.rs:32:17: 32:36 + StorageLive(_5); // scope 1 at $DIR/retag.rs:32:17: 32:24 + _5 = Test(const 0_i32); // scope 1 at $DIR/retag.rs:32:17: 32:24 + _4 = &_5; // scope 1 at $DIR/retag.rs:32:17: 32:36 + Retag(_4); // scope 1 at $DIR/retag.rs:32:17: 32:36 + StorageLive(_6); // scope 1 at $DIR/retag.rs:32:29: 32:35 + StorageLive(_7); // scope 1 at $DIR/retag.rs:32:29: 32:35 + _7 = &mut _1; // scope 1 at $DIR/retag.rs:32:29: 32:35 + Retag(_7); // scope 1 at $DIR/retag.rs:32:29: 32:35 + _6 = &mut (*_7); // scope 1 at $DIR/retag.rs:32:29: 32:35 + Retag([2phase] _6); // scope 1 at $DIR/retag.rs:32:29: 32:35 + _3 = Test::foo(move _4, move _6) -> [return: bb1, unwind: bb8]; // scope 1 at $DIR/retag.rs:32:17: 32:36 // mir::Constant // + span: $DIR/retag.rs:32:25: 32:28 // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x mut i32) -> &'x mut i32 {Test::foo}, val: Value() } } bb1: { - Retag(_3); // scope 1 at $DIR/retag.rs:+3:17: +3:36 - StorageDead(_6); // scope 1 at $DIR/retag.rs:+3:35: +3:36 - StorageDead(_4); // scope 1 at $DIR/retag.rs:+3:35: +3:36 - StorageDead(_7); // scope 1 at $DIR/retag.rs:+3:36: +3:37 - drop(_5) -> [return: bb2, unwind: bb9]; // scope 1 at $DIR/retag.rs:+3:36: +3:37 + Retag(_3); // scope 1 at $DIR/retag.rs:32:17: 32:36 + StorageDead(_6); // scope 1 at $DIR/retag.rs:32:35: 32:36 + StorageDead(_4); // scope 1 at $DIR/retag.rs:32:35: 32:36 + StorageDead(_7); // scope 1 at $DIR/retag.rs:32:36: 32:37 + drop(_5) -> [return: bb2, unwind: bb9]; // scope 1 at $DIR/retag.rs:32:36: 32:37 } bb2: { - StorageDead(_5); // scope 1 at $DIR/retag.rs:+3:36: +3:37 - StorageLive(_8); // scope 2 at $DIR/retag.rs:+4:13: +4:14 - StorageLive(_9); // scope 2 at $DIR/retag.rs:+4:19: +4:20 - _9 = move _3; // scope 2 at $DIR/retag.rs:+4:19: +4:20 - Retag(_9); // scope 2 at $DIR/retag.rs:+4:19: +4:20 - _8 = &mut (*_9); // scope 2 at $DIR/retag.rs:+4:19: +4:20 - Retag(_8); // scope 2 at $DIR/retag.rs:+4:19: +4:20 - StorageDead(_9); // scope 2 at $DIR/retag.rs:+4:22: +4:23 - StorageLive(_10); // scope 3 at $DIR/retag.rs:+5:13: +5:14 - _10 = move _8; // scope 3 at $DIR/retag.rs:+5:17: +5:18 - Retag(_10); // scope 3 at $DIR/retag.rs:+5:17: +5:18 - StorageLive(_11); // scope 4 at $DIR/retag.rs:+7:13: +7:15 - StorageLive(_12); // scope 4 at $DIR/retag.rs:+7:18: +7:29 - _12 = &raw mut (*_10); // scope 4 at $DIR/retag.rs:+7:18: +7:19 - Retag([raw] _12); // scope 4 at $DIR/retag.rs:+7:18: +7:19 - _11 = _12; // scope 4 at $DIR/retag.rs:+7:18: +7:29 - StorageDead(_12); // scope 4 at $DIR/retag.rs:+7:29: +7:30 - _2 = const (); // scope 1 at $DIR/retag.rs:+2:5: +8:6 - StorageDead(_11); // scope 4 at $DIR/retag.rs:+8:5: +8:6 - StorageDead(_10); // scope 3 at $DIR/retag.rs:+8:5: +8:6 - StorageDead(_8); // scope 2 at $DIR/retag.rs:+8:5: +8:6 - StorageDead(_3); // scope 1 at $DIR/retag.rs:+8:5: +8:6 - StorageDead(_2); // scope 1 at $DIR/retag.rs:+8:5: +8:6 - StorageLive(_13); // scope 1 at $DIR/retag.rs:+11:9: +11:10 - StorageLive(_14); // scope 1 at $DIR/retag.rs:+11:31: +14:6 - _14 = [closure@main::{closure#0}]; // scope 1 at $DIR/retag.rs:+11:31: +14:6 + StorageDead(_5); // scope 1 at $DIR/retag.rs:32:36: 32:37 + StorageLive(_8); // scope 2 at $DIR/retag.rs:33:13: 33:14 + StorageLive(_9); // scope 2 at $DIR/retag.rs:33:19: 33:20 + _9 = move _3; // scope 2 at $DIR/retag.rs:33:19: 33:20 + Retag(_9); // scope 2 at $DIR/retag.rs:33:19: 33:20 + _8 = &mut (*_9); // scope 2 at $DIR/retag.rs:33:19: 33:20 + Retag(_8); // scope 2 at $DIR/retag.rs:33:19: 33:20 + StorageDead(_9); // scope 2 at $DIR/retag.rs:33:22: 33:23 + StorageLive(_10); // scope 3 at $DIR/retag.rs:34:13: 34:14 + _10 = move _8; // scope 3 at $DIR/retag.rs:34:17: 34:18 + Retag(_10); // scope 3 at $DIR/retag.rs:34:17: 34:18 + StorageLive(_11); // scope 4 at $DIR/retag.rs:36:13: 36:15 + StorageLive(_12); // scope 4 at $DIR/retag.rs:36:18: 36:29 + _12 = &raw mut (*_10); // scope 4 at $DIR/retag.rs:36:18: 36:19 + Retag([raw] _12); // scope 4 at $DIR/retag.rs:36:18: 36:19 + _11 = _12; // scope 4 at $DIR/retag.rs:36:18: 36:29 + StorageDead(_12); // scope 4 at $DIR/retag.rs:36:29: 36:30 + _2 = const (); // scope 1 at $DIR/retag.rs:31:5: 37:6 + StorageDead(_11); // scope 4 at $DIR/retag.rs:37:5: 37:6 + StorageDead(_10); // scope 3 at $DIR/retag.rs:37:5: 37:6 + StorageDead(_8); // scope 2 at $DIR/retag.rs:37:5: 37:6 + StorageDead(_3); // scope 1 at $DIR/retag.rs:37:5: 37:6 + StorageDead(_2); // scope 1 at $DIR/retag.rs:37:5: 37:6 + StorageLive(_13); // scope 1 at $DIR/retag.rs:40:9: 40:10 + StorageLive(_14); // scope 1 at $DIR/retag.rs:40:31: 43:6 + _14 = [closure@main::{closure#0}]; // scope 1 at $DIR/retag.rs:40:31: 43:6 // closure // + def_id: DefId(0:14 ~ retag[4622]::main::{closure#0}) // + substs: [ @@ -119,92 +119,92 @@ fn main() -> () { // for<'r> extern "rust-call" fn((&'r i32,)) -> &'r i32, // (), // ] - Retag(_14); // scope 1 at $DIR/retag.rs:+11:31: +14:6 - _13 = move _14 as for<'r> fn(&'r i32) -> &'r i32 (Pointer(ClosureFnPointer(Normal))); // scope 1 at $DIR/retag.rs:+11:31: +14:6 - StorageDead(_14); // scope 1 at $DIR/retag.rs:+11:47: +11:48 - StorageLive(_15); // scope 6 at $DIR/retag.rs:+15:9: +15:11 - StorageLive(_16); // scope 6 at $DIR/retag.rs:+15:14: +15:15 - _16 = _13; // scope 6 at $DIR/retag.rs:+15:14: +15:15 - StorageLive(_17); // scope 6 at $DIR/retag.rs:+15:16: +15:18 - StorageLive(_18); // scope 6 at $DIR/retag.rs:+15:16: +15:18 - _18 = &_1; // scope 6 at $DIR/retag.rs:+15:16: +15:18 - Retag(_18); // scope 6 at $DIR/retag.rs:+15:16: +15:18 - _17 = &(*_18); // scope 6 at $DIR/retag.rs:+15:16: +15:18 - Retag(_17); // scope 6 at $DIR/retag.rs:+15:16: +15:18 - _15 = move _16(move _17) -> bb3; // scope 6 at $DIR/retag.rs:+15:14: +15:19 + Retag(_14); // scope 1 at $DIR/retag.rs:40:31: 43:6 + _13 = move _14 as for<'r> fn(&'r i32) -> &'r i32 (Pointer(ClosureFnPointer(Normal))); // scope 1 at $DIR/retag.rs:40:31: 43:6 + StorageDead(_14); // scope 1 at $DIR/retag.rs:40:47: 40:48 + StorageLive(_15); // scope 6 at $DIR/retag.rs:44:9: 44:11 + StorageLive(_16); // scope 6 at $DIR/retag.rs:44:14: 44:15 + _16 = _13; // scope 6 at $DIR/retag.rs:44:14: 44:15 + StorageLive(_17); // scope 6 at $DIR/retag.rs:44:16: 44:18 + StorageLive(_18); // scope 6 at $DIR/retag.rs:44:16: 44:18 + _18 = &_1; // scope 6 at $DIR/retag.rs:44:16: 44:18 + Retag(_18); // scope 6 at $DIR/retag.rs:44:16: 44:18 + _17 = &(*_18); // scope 6 at $DIR/retag.rs:44:16: 44:18 + Retag(_17); // scope 6 at $DIR/retag.rs:44:16: 44:18 + _15 = move _16(move _17) -> bb3; // scope 6 at $DIR/retag.rs:44:14: 44:19 } bb3: { - Retag(_15); // scope 6 at $DIR/retag.rs:+15:14: +15:19 - StorageDead(_17); // scope 6 at $DIR/retag.rs:+15:18: +15:19 - StorageDead(_16); // scope 6 at $DIR/retag.rs:+15:18: +15:19 - StorageDead(_18); // scope 6 at $DIR/retag.rs:+15:19: +15:20 - StorageLive(_19); // scope 7 at $DIR/retag.rs:+18:5: +18:24 - StorageLive(_20); // scope 7 at $DIR/retag.rs:+18:5: +18:24 - StorageLive(_21); // scope 7 at $DIR/retag.rs:+18:5: +18:12 - _21 = Test(const 0_i32); // scope 7 at $DIR/retag.rs:+18:5: +18:12 - _20 = &_21; // scope 7 at $DIR/retag.rs:+18:5: +18:24 - Retag(_20); // scope 7 at $DIR/retag.rs:+18:5: +18:24 - StorageLive(_22); // scope 7 at $DIR/retag.rs:+18:21: +18:23 - StorageLive(_23); // scope 7 at $DIR/retag.rs:+18:21: +18:23 - _28 = const main::promoted[0]; // scope 7 at $DIR/retag.rs:+18:21: +18:23 + Retag(_15); // scope 6 at $DIR/retag.rs:44:14: 44:19 + StorageDead(_17); // scope 6 at $DIR/retag.rs:44:18: 44:19 + StorageDead(_16); // scope 6 at $DIR/retag.rs:44:18: 44:19 + StorageDead(_18); // scope 6 at $DIR/retag.rs:44:19: 44:20 + StorageLive(_19); // scope 7 at $DIR/retag.rs:47:5: 47:24 + StorageLive(_20); // scope 7 at $DIR/retag.rs:47:5: 47:24 + StorageLive(_21); // scope 7 at $DIR/retag.rs:47:5: 47:12 + _21 = Test(const 0_i32); // scope 7 at $DIR/retag.rs:47:5: 47:12 + _20 = &_21; // scope 7 at $DIR/retag.rs:47:5: 47:24 + Retag(_20); // scope 7 at $DIR/retag.rs:47:5: 47:24 + StorageLive(_22); // scope 7 at $DIR/retag.rs:47:21: 47:23 + StorageLive(_23); // scope 7 at $DIR/retag.rs:47:21: 47:23 + _28 = const main::promoted[0]; // scope 7 at $DIR/retag.rs:47:21: 47:23 // mir::Constant // + span: $DIR/retag.rs:47:21: 47:23 // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) } - Retag(_28); // scope 7 at $DIR/retag.rs:+18:21: +18:23 - _23 = &(*_28); // scope 7 at $DIR/retag.rs:+18:21: +18:23 - Retag(_23); // scope 7 at $DIR/retag.rs:+18:21: +18:23 - _22 = &(*_23); // scope 7 at $DIR/retag.rs:+18:21: +18:23 - Retag(_22); // scope 7 at $DIR/retag.rs:+18:21: +18:23 - _19 = Test::foo_shr(move _20, move _22) -> [return: bb4, unwind: bb7]; // scope 7 at $DIR/retag.rs:+18:5: +18:24 + Retag(_28); // scope 7 at $DIR/retag.rs:47:21: 47:23 + _23 = &(*_28); // scope 7 at $DIR/retag.rs:47:21: 47:23 + Retag(_23); // scope 7 at $DIR/retag.rs:47:21: 47:23 + _22 = &(*_23); // scope 7 at $DIR/retag.rs:47:21: 47:23 + Retag(_22); // scope 7 at $DIR/retag.rs:47:21: 47:23 + _19 = Test::foo_shr(move _20, move _22) -> [return: bb4, unwind: bb7]; // scope 7 at $DIR/retag.rs:47:5: 47:24 // mir::Constant // + span: $DIR/retag.rs:47:13: 47:20 // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x i32) -> &'x i32 {Test::foo_shr}, val: Value() } } bb4: { - Retag(_19); // scope 7 at $DIR/retag.rs:+18:5: +18:24 - StorageDead(_22); // scope 7 at $DIR/retag.rs:+18:23: +18:24 - StorageDead(_20); // scope 7 at $DIR/retag.rs:+18:23: +18:24 - StorageDead(_23); // scope 7 at $DIR/retag.rs:+18:24: +18:25 - drop(_21) -> [return: bb5, unwind: bb9]; // scope 7 at $DIR/retag.rs:+18:24: +18:25 + Retag(_19); // scope 7 at $DIR/retag.rs:47:5: 47:24 + StorageDead(_22); // scope 7 at $DIR/retag.rs:47:23: 47:24 + StorageDead(_20); // scope 7 at $DIR/retag.rs:47:23: 47:24 + StorageDead(_23); // scope 7 at $DIR/retag.rs:47:24: 47:25 + drop(_21) -> [return: bb5, unwind: bb9]; // scope 7 at $DIR/retag.rs:47:24: 47:25 } bb5: { - StorageDead(_21); // scope 7 at $DIR/retag.rs:+18:24: +18:25 - StorageDead(_19); // scope 7 at $DIR/retag.rs:+18:24: +18:25 - StorageLive(_25); // scope 7 at $DIR/retag.rs:+21:9: +21:11 - StorageLive(_26); // scope 7 at $DIR/retag.rs:+21:14: +21:28 - _26 = &raw const (*_15); // scope 7 at $DIR/retag.rs:+21:14: +21:16 - Retag([raw] _26); // scope 7 at $DIR/retag.rs:+21:14: +21:16 - _25 = _26; // scope 7 at $DIR/retag.rs:+21:14: +21:28 - StorageDead(_26); // scope 7 at $DIR/retag.rs:+21:28: +21:29 - StorageLive(_27); // scope 8 at $DIR/retag.rs:+23:5: +23:18 - _27 = array_casts() -> bb6; // scope 8 at $DIR/retag.rs:+23:5: +23:18 + StorageDead(_21); // scope 7 at $DIR/retag.rs:47:24: 47:25 + StorageDead(_19); // scope 7 at $DIR/retag.rs:47:24: 47:25 + StorageLive(_25); // scope 7 at $DIR/retag.rs:50:9: 50:11 + StorageLive(_26); // scope 7 at $DIR/retag.rs:50:14: 50:28 + _26 = &raw const (*_15); // scope 7 at $DIR/retag.rs:50:14: 50:16 + Retag([raw] _26); // scope 7 at $DIR/retag.rs:50:14: 50:16 + _25 = _26; // scope 7 at $DIR/retag.rs:50:14: 50:28 + StorageDead(_26); // scope 7 at $DIR/retag.rs:50:28: 50:29 + StorageLive(_27); // scope 8 at $DIR/retag.rs:52:5: 52:18 + _27 = array_casts() -> bb6; // scope 8 at $DIR/retag.rs:52:5: 52:18 // mir::Constant // + span: $DIR/retag.rs:52:5: 52:16 // + literal: Const { ty: fn() {array_casts}, val: Value() } } bb6: { - StorageDead(_27); // scope 8 at $DIR/retag.rs:+23:18: +23:19 - _0 = const (); // scope 0 at $DIR/retag.rs:+0:11: +24:2 - StorageDead(_25); // scope 7 at $DIR/retag.rs:+24:1: +24:2 - StorageDead(_15); // scope 6 at $DIR/retag.rs:+24:1: +24:2 - StorageDead(_13); // scope 1 at $DIR/retag.rs:+24:1: +24:2 - StorageDead(_1); // scope 0 at $DIR/retag.rs:+24:1: +24:2 - return; // scope 0 at $DIR/retag.rs:+24:2: +24:2 + StorageDead(_27); // scope 8 at $DIR/retag.rs:52:18: 52:19 + _0 = const (); // scope 0 at $DIR/retag.rs:29:11: 53:2 + StorageDead(_25); // scope 7 at $DIR/retag.rs:53:1: 53:2 + StorageDead(_15); // scope 6 at $DIR/retag.rs:53:1: 53:2 + StorageDead(_13); // scope 1 at $DIR/retag.rs:53:1: 53:2 + StorageDead(_1); // scope 0 at $DIR/retag.rs:53:1: 53:2 + return; // scope 0 at $DIR/retag.rs:53:2: 53:2 } bb7 (cleanup): { - drop(_21) -> bb9; // scope 7 at $DIR/retag.rs:+18:24: +18:25 + drop(_21) -> bb9; // scope 7 at $DIR/retag.rs:47:24: 47:25 } bb8 (cleanup): { - drop(_5) -> bb9; // scope 1 at $DIR/retag.rs:+3:36: +3:37 + drop(_5) -> bb9; // scope 1 at $DIR/retag.rs:32:36: 32:37 } bb9 (cleanup): { - resume; // scope 0 at $DIR/retag.rs:+0:1: +24:2 + resume; // scope 0 at $DIR/retag.rs:29:1: 53:2 } } diff --git a/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir index e395fdb274f37..980f07d5f1096 100644 --- a/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir @@ -1,20 +1,20 @@ // MIR for `::foo` after SimplifyCfg-elaborate-drops fn ::foo(_1: &Test, _2: &mut i32) -> &mut i32 { - debug self => _1; // in scope 0 at $DIR/retag.rs:+0:16: +0:21 - debug x => _2; // in scope 0 at $DIR/retag.rs:+0:23: +0:24 - let mut _0: &mut i32; // return place in scope 0 at $DIR/retag.rs:+0:42: +0:53 - let mut _3: &mut i32; // in scope 0 at $DIR/retag.rs:+1:9: +1:10 + debug self => _1; // in scope 0 at $DIR/retag.rs:13:16: 13:21 + debug x => _2; // in scope 0 at $DIR/retag.rs:13:23: 13:24 + let mut _0: &mut i32; // return place in scope 0 at $DIR/retag.rs:13:42: 13:53 + let mut _3: &mut i32; // in scope 0 at $DIR/retag.rs:14:9: 14:10 bb0: { - Retag([fn entry] _1); // scope 0 at $DIR/retag.rs:+0:5: +2:6 - Retag([fn entry] _2); // scope 0 at $DIR/retag.rs:+0:5: +2:6 - StorageLive(_3); // scope 0 at $DIR/retag.rs:+1:9: +1:10 - _3 = &mut (*_2); // scope 0 at $DIR/retag.rs:+1:9: +1:10 - Retag(_3); // scope 0 at $DIR/retag.rs:+1:9: +1:10 - _0 = &mut (*_3); // scope 0 at $DIR/retag.rs:+1:9: +1:10 - Retag(_0); // scope 0 at $DIR/retag.rs:+1:9: +1:10 - StorageDead(_3); // scope 0 at $DIR/retag.rs:+2:5: +2:6 - return; // scope 0 at $DIR/retag.rs:+2:6: +2:6 + Retag([fn entry] _1); // scope 0 at $DIR/retag.rs:13:5: 15:6 + Retag([fn entry] _2); // scope 0 at $DIR/retag.rs:13:5: 15:6 + StorageLive(_3); // scope 0 at $DIR/retag.rs:14:9: 14:10 + _3 = &mut (*_2); // scope 0 at $DIR/retag.rs:14:9: 14:10 + Retag(_3); // scope 0 at $DIR/retag.rs:14:9: 14:10 + _0 = &mut (*_3); // scope 0 at $DIR/retag.rs:14:9: 14:10 + Retag(_0); // scope 0 at $DIR/retag.rs:14:9: 14:10 + StorageDead(_3); // scope 0 at $DIR/retag.rs:15:5: 15:6 + return; // scope 0 at $DIR/retag.rs:15:6: 15:6 } } diff --git a/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir index e609166dec892..9c252d63fc72c 100644 --- a/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir @@ -1,15 +1,15 @@ // MIR for `::foo_shr` after SimplifyCfg-elaborate-drops fn ::foo_shr(_1: &Test, _2: &i32) -> &i32 { - debug self => _1; // in scope 0 at $DIR/retag.rs:+0:20: +0:25 - debug x => _2; // in scope 0 at $DIR/retag.rs:+0:27: +0:28 - let mut _0: &i32; // return place in scope 0 at $DIR/retag.rs:+0:42: +0:49 + debug self => _1; // in scope 0 at $DIR/retag.rs:16:20: 16:25 + debug x => _2; // in scope 0 at $DIR/retag.rs:16:27: 16:28 + let mut _0: &i32; // return place in scope 0 at $DIR/retag.rs:16:42: 16:49 bb0: { - Retag([fn entry] _1); // scope 0 at $DIR/retag.rs:+0:5: +2:6 - Retag([fn entry] _2); // scope 0 at $DIR/retag.rs:+0:5: +2:6 - _0 = _2; // scope 0 at $DIR/retag.rs:+1:9: +1:10 - Retag(_0); // scope 0 at $DIR/retag.rs:+1:9: +1:10 - return; // scope 0 at $DIR/retag.rs:+2:6: +2:6 + Retag([fn entry] _1); // scope 0 at $DIR/retag.rs:16:5: 18:6 + Retag([fn entry] _2); // scope 0 at $DIR/retag.rs:16:5: 18:6 + _0 = _2; // scope 0 at $DIR/retag.rs:17:9: 17:10 + Retag(_0); // scope 0 at $DIR/retag.rs:17:9: 17:10 + return; // scope 0 at $DIR/retag.rs:18:6: 18:6 } } diff --git a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff b/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff index 3a11e45cacde5..4cdbaec7d2a2a 100644 --- a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff +++ b/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff @@ -2,18 +2,18 @@ + // MIR for `identity` after ConstProp fn identity(_1: Result) -> Result { - debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53 - let mut _2: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - let mut _3: std::ops::ControlFlow, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - let mut _4: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - let mut _5: isize; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let _6: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let mut _7: !; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let mut _8: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 + debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:28:13: 28:14 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/separate_const_switch.rs:28:37: 28:53 + let mut _2: i32; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + let mut _3: std::ops::ControlFlow, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + let mut _4: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9 + let mut _5: isize; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + let _6: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + let mut _7: !; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + let mut _8: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 scope 1 { - debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10 + debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:29:9: 29:10 scope 2 { scope 8 (inlined #[track_caller] as FromResidual>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10 debug residual => _8; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL @@ -30,7 +30,7 @@ } } scope 3 { - debug val => _9; // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10 + debug val => _9; // in scope 3 at $DIR/separate_const_switch.rs:29:8: 29:10 scope 4 { } } @@ -51,33 +51,33 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageLive(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - _4 = _1; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - StorageLive(_10); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 + StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + StorageLive(_3); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9 + _4 = _1; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9 + StorageLive(_10); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 _10 = discriminant(_4); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL switchInt(move _10) -> [0_isize: bb5, 1_isize: bb3, otherwise: bb4]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL } bb1: { - StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - _9 = ((_3 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - _2 = _9; // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - Deinit(_0); // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - ((_0 as Ok).0: i32) = move _2; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - discriminant(_0) = 0; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11 - StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2 + StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + _9 = ((_3 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + _2 = _9; // scope 4 at $DIR/separate_const_switch.rs:29:8: 29:10 + StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + Deinit(_0); // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11 + ((_0 as Ok).0: i32) = move _2; // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11 + discriminant(_0) = 0; // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11 + StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:29:10: 29:11 + StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:30:1: 30:2 + return; // scope 0 at $DIR/separate_const_switch.rs:30:2: 30:2 } bb2: { - StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - _6 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - _8 = _6; // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 + StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + _6 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + StorageLive(_8); // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10 + _8 = _6; // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10 StorageLive(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL _16 = move ((_8 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL StorageLive(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL @@ -90,11 +90,11 @@ discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11 - StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2 + StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10 + StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:29:10: 29:11 + StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:30:1: 30:2 + return; // scope 0 at $DIR/separate_const_switch.rs:30:2: 30:2 } bb3: { @@ -112,12 +112,12 @@ discriminant(_3) = 1; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_14); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_13); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 -- _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -- switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -+ _5 = const 1_isize; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -+ switchInt(const 1_isize) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 + StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 +- _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 +- switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 ++ _5 = const 1_isize; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 ++ switchInt(const 1_isize) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 } bb4: { @@ -134,12 +134,12 @@ discriminant(_3) = 0; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_12); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_11); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 -- _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -- switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -+ _5 = const 0_isize; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -+ switchInt(const 0_isize) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 + StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 +- _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 +- switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 ++ _5 = const 0_isize; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 ++ switchInt(const 0_isize) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 } } diff --git a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir index 952ef22d41001..f4c526c6b1979 100644 --- a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir +++ b/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir @@ -1,16 +1,16 @@ // MIR for `identity` after PreCodegen fn identity(_1: Result) -> Result { - debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53 - let mut _2: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - let mut _3: std::ops::ControlFlow, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - let mut _4: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - let _5: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let mut _6: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let _7: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 + debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:28:13: 28:14 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/separate_const_switch.rs:28:37: 28:53 + let mut _2: i32; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + let mut _3: std::ops::ControlFlow, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + let mut _4: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9 + let _5: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + let mut _6: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + let _7: i32; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 scope 1 { - debug residual => _5; // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10 + debug residual => _5; // in scope 1 at $DIR/separate_const_switch.rs:29:9: 29:10 scope 2 { scope 8 (inlined #[track_caller] as FromResidual>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10 debug residual => _6; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL @@ -27,7 +27,7 @@ fn identity(_1: Result) -> Result { } } scope 3 { - debug val => _7; // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10 + debug val => _7; // in scope 3 at $DIR/separate_const_switch.rs:29:8: 29:10 scope 4 { } } @@ -48,11 +48,11 @@ fn identity(_1: Result) -> Result { } bb0: { - StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageLive(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - _4 = _1; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - StorageLive(_8); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 + StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + StorageLive(_3); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9 + _4 = _1; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9 + StorageLive(_8); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 _8 = discriminant(_4); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL switchInt(move _8) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL } @@ -72,12 +72,12 @@ fn identity(_1: Result) -> Result { discriminant(_3) = 1; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_12); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_11); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_8); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_5); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - _5 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_6); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - _6 = _5; // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 + StorageDead(_8); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + StorageLive(_5); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + _5 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + StorageLive(_6); // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10 + _6 = _5; // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10 StorageLive(_14); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL _14 = move ((_6 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL StorageLive(_15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL @@ -90,11 +90,11 @@ fn identity(_1: Result) -> Result { discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_14); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_6); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageDead(_5); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11 - StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2 + StorageDead(_6); // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10 + StorageDead(_5); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:29:10: 29:11 + StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:30:1: 30:2 + return; // scope 0 at $DIR/separate_const_switch.rs:30:2: 30:2 } bb2: { @@ -111,17 +111,17 @@ fn identity(_1: Result) -> Result { discriminant(_3) = 0; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_10); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_9); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_8); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_7); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - _7 = ((_3 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - _2 = _7; // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageDead(_7); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - Deinit(_0); // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - ((_0 as Ok).0: i32) = move _2; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - discriminant(_0) = 0; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11 - StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2 + StorageDead(_8); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + StorageLive(_7); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + _7 = ((_3 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + _2 = _7; // scope 4 at $DIR/separate_const_switch.rs:29:8: 29:10 + StorageDead(_7); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + Deinit(_0); // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11 + ((_0 as Ok).0: i32) = move _2; // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11 + discriminant(_0) = 0; // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11 + StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:29:10: 29:11 + StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:30:1: 30:2 + return; // scope 0 at $DIR/separate_const_switch.rs:30:2: 30:2 } } diff --git a/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff b/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff index 8453d534150b3..d94967072ba75 100644 --- a/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff +++ b/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff @@ -2,18 +2,18 @@ + // MIR for `identity` after SeparateConstSwitch fn identity(_1: Result) -> Result { - debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53 - let mut _2: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - let mut _3: std::ops::ControlFlow, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - let mut _4: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - let mut _5: isize; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let _6: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let mut _7: !; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let mut _8: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 + debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:28:13: 28:14 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/separate_const_switch.rs:28:37: 28:53 + let mut _2: i32; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + let mut _3: std::ops::ControlFlow, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + let mut _4: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9 + let mut _5: isize; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + let _6: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + let mut _7: !; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + let mut _8: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 scope 1 { - debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10 + debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:29:9: 29:10 scope 2 { scope 8 (inlined #[track_caller] as FromResidual>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10 debug residual => _8; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL @@ -30,7 +30,7 @@ } } scope 3 { - debug val => _9; // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10 + debug val => _9; // in scope 3 at $DIR/separate_const_switch.rs:29:8: 29:10 scope 4 { } } @@ -51,42 +51,42 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageLive(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - _4 = _1; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - StorageLive(_10); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 + StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + StorageLive(_3); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9 + _4 = _1; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9 + StorageLive(_10); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 _10 = discriminant(_4); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL + switchInt(move _10) -> [0_isize: bb5, 1_isize: bb3, otherwise: bb4]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL } bb1: { -- StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -- StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 -- _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -- switchInt(move _5) -> [0_isize: bb2, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 +- StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 +- StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 +- _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 +- switchInt(move _5) -> [0_isize: bb2, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 - } - - bb2: { - StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - _9 = ((_3 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - _2 = _9; // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - Deinit(_0); // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - ((_0 as Ok).0: i32) = move _2; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - discriminant(_0) = 0; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11 - StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2 + StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + _9 = ((_3 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + _2 = _9; // scope 4 at $DIR/separate_const_switch.rs:29:8: 29:10 + StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + Deinit(_0); // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11 + ((_0 as Ok).0: i32) = move _2; // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11 + discriminant(_0) = 0; // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11 + StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:29:10: 29:11 + StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:30:1: 30:2 + return; // scope 0 at $DIR/separate_const_switch.rs:30:2: 30:2 } - bb3: { + bb2: { - StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - _6 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - _8 = _6; // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 + StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + _6 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + StorageLive(_8); // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10 + _8 = _6; // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10 StorageLive(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL _16 = move ((_8 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL StorageLive(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL @@ -99,11 +99,11 @@ discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11 - StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2 + StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10 + StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:29:10: 29:11 + StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:30:1: 30:2 + return; // scope 0 at $DIR/separate_const_switch.rs:30:2: 30:2 } - bb4: { @@ -123,10 +123,10 @@ StorageDead(_14); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_13); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - goto -> bb1; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL -+ StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -+ StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 -+ _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -+ switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 ++ StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 ++ StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 ++ _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 ++ switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 } - bb5: { @@ -146,10 +146,10 @@ StorageDead(_12); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_11); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - goto -> bb1; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL -+ StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -+ StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 -+ _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -+ switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 ++ StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 ++ StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 ++ _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 ++ switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 } } diff --git a/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff b/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff index de9f45c3d4690..ea549a76f5810 100644 --- a/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff +++ b/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff @@ -2,94 +2,94 @@ + // MIR for `too_complex` after ConstProp fn too_complex(_1: Result) -> Option { - debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17 - let mut _0: std::option::Option; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53 - let mut _2: std::ops::ControlFlow; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 - let mut _3: isize; // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18 - let _4: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - let mut _5: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45 - let _6: usize; // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - let mut _7: usize; // in scope 0 at $DIR/separate_const_switch.rs:+8:42: +8:43 - let mut _8: isize; // in scope 0 at $DIR/separate_const_switch.rs:+11:9: +11:33 - let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - let mut _10: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43 - let _11: usize; // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 + debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:9:16: 9:17 + let mut _0: std::option::Option; // return place in scope 0 at $DIR/separate_const_switch.rs:9:42: 9:53 + let mut _2: std::ops::ControlFlow; // in scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6 + let mut _3: isize; // in scope 0 at $DIR/separate_const_switch.rs:16:13: 16:18 + let _4: i32; // in scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17 + let mut _5: i32; // in scope 0 at $DIR/separate_const_switch.rs:16:44: 16:45 + let _6: usize; // in scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18 + let mut _7: usize; // in scope 0 at $DIR/separate_const_switch.rs:17:42: 17:43 + let mut _8: isize; // in scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33 + let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32 + let mut _10: i32; // in scope 0 at $DIR/separate_const_switch.rs:20:42: 20:43 + let _11: usize; // in scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29 scope 1 { - debug v => _4; // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17 + debug v => _4; // in scope 1 at $DIR/separate_const_switch.rs:16:16: 16:17 } scope 2 { - debug r => _6; // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18 + debug r => _6; // in scope 2 at $DIR/separate_const_switch.rs:17:17: 17:18 } scope 3 { - debug v => _9; // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32 + debug v => _9; // in scope 3 at $DIR/separate_const_switch.rs:20:31: 20:32 } scope 4 { - debug r => _11; // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29 + debug r => _11; // in scope 4 at $DIR/separate_const_switch.rs:21:28: 21:29 } bb0: { - StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 - _3 = discriminant(_1); // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16 - switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16 + StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6 + _3 = discriminant(_1); // scope 0 at $DIR/separate_const_switch.rs:15:15: 15:16 + switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/separate_const_switch.rs:15:9: 15:16 } bb1: { - StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - _6 = ((_1 as Err).0: usize); // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - StorageLive(_7); // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43 - _7 = _6; // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43 - Deinit(_2); // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44 - ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44 - discriminant(_2) = 1; // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44 - StorageDead(_7); // scope 2 at $DIR/separate_const_switch.rs:+8:43: +8:44 - StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44 -- _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 -- switchInt(move _8) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6 -+ _8 = const 1_isize; // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 -+ switchInt(const 1_isize) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6 + StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18 + _6 = ((_1 as Err).0: usize); // scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18 + StorageLive(_7); // scope 2 at $DIR/separate_const_switch.rs:17:42: 17:43 + _7 = _6; // scope 2 at $DIR/separate_const_switch.rs:17:42: 17:43 + Deinit(_2); // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44 + ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44 + discriminant(_2) = 1; // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44 + StorageDead(_7); // scope 2 at $DIR/separate_const_switch.rs:17:43: 17:44 + StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:17:43: 17:44 +- _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6 +- switchInt(move _8) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:14:5: 19:6 ++ _8 = const 1_isize; // scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6 ++ switchInt(const 1_isize) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:14:5: 19:6 } bb2: { - StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - _4 = ((_1 as Ok).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - StorageLive(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45 - _5 = _4; // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45 - Deinit(_2); // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - discriminant(_2) = 0; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - StorageDead(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46 - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46 -- _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 -- switchInt(move _8) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6 -+ _8 = const 0_isize; // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 -+ switchInt(const 0_isize) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6 + StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17 + _4 = ((_1 as Ok).0: i32); // scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17 + StorageLive(_5); // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45 + _5 = _4; // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45 + Deinit(_2); // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46 + ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46 + discriminant(_2) = 0; // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46 + StorageDead(_5); // scope 1 at $DIR/separate_const_switch.rs:16:45: 16:46 + StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:16:45: 16:46 +- _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6 +- switchInt(move _8) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:14:5: 19:6 ++ _8 = const 0_isize; // scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6 ++ switchInt(const 0_isize) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:14:5: 19:6 } bb3: { - StorageLive(_11); // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 - _11 = ((_2 as Break).0: usize); // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 - Deinit(_0); // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38 - discriminant(_0) = 0; // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38 - StorageDead(_11); // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38 - goto -> bb5; // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38 + StorageLive(_11); // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29 + _11 = ((_2 as Break).0: usize); // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29 + Deinit(_0); // scope 4 at $DIR/separate_const_switch.rs:21:34: 21:38 + discriminant(_0) = 0; // scope 4 at $DIR/separate_const_switch.rs:21:34: 21:38 + StorageDead(_11); // scope 0 at $DIR/separate_const_switch.rs:21:37: 21:38 + goto -> bb5; // scope 0 at $DIR/separate_const_switch.rs:21:37: 21:38 } bb4: { - StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - _9 = ((_2 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - StorageLive(_10); // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43 - _10 = _9; // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43 - Deinit(_0); // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - ((_0 as Some).0: i32) = move _10; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - discriminant(_0) = 1; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - StorageDead(_10); // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44 - StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44 - goto -> bb5; // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44 + StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32 + _9 = ((_2 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32 + StorageLive(_10); // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43 + _10 = _9; // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43 + Deinit(_0); // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44 + ((_0 as Some).0: i32) = move _10; // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44 + discriminant(_0) = 1; // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44 + StorageDead(_10); // scope 3 at $DIR/separate_const_switch.rs:20:43: 20:44 + StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:20:43: 20:44 + goto -> bb5; // scope 0 at $DIR/separate_const_switch.rs:20:43: 20:44 } bb5: { - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2 + StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:23:1: 23:2 + return; // scope 0 at $DIR/separate_const_switch.rs:23:2: 23:2 } } diff --git a/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir index 1009225b733f9..39100316597e3 100644 --- a/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir +++ b/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir @@ -1,69 +1,69 @@ // MIR for `too_complex` after PreCodegen fn too_complex(_1: Result) -> Option { - debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17 - let mut _0: std::option::Option; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53 - let mut _2: std::ops::ControlFlow; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 - let mut _3: isize; // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18 - let _4: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - let mut _5: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45 - let _6: usize; // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - let _7: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - let mut _8: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43 - let _9: usize; // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 + debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:9:16: 9:17 + let mut _0: std::option::Option; // return place in scope 0 at $DIR/separate_const_switch.rs:9:42: 9:53 + let mut _2: std::ops::ControlFlow; // in scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6 + let mut _3: isize; // in scope 0 at $DIR/separate_const_switch.rs:16:13: 16:18 + let _4: i32; // in scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17 + let mut _5: i32; // in scope 0 at $DIR/separate_const_switch.rs:16:44: 16:45 + let _6: usize; // in scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18 + let _7: i32; // in scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32 + let mut _8: i32; // in scope 0 at $DIR/separate_const_switch.rs:20:42: 20:43 + let _9: usize; // in scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29 scope 1 { - debug v => _4; // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17 + debug v => _4; // in scope 1 at $DIR/separate_const_switch.rs:16:16: 16:17 } scope 2 { - debug r => _6; // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18 + debug r => _6; // in scope 2 at $DIR/separate_const_switch.rs:17:17: 17:18 } scope 3 { - debug v => _7; // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32 + debug v => _7; // in scope 3 at $DIR/separate_const_switch.rs:20:31: 20:32 } scope 4 { - debug r => _9; // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29 + debug r => _9; // in scope 4 at $DIR/separate_const_switch.rs:21:28: 21:29 } bb0: { - StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 - _3 = discriminant(_1); // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16 - switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16 + StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6 + _3 = discriminant(_1); // scope 0 at $DIR/separate_const_switch.rs:15:15: 15:16 + switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/separate_const_switch.rs:15:9: 15:16 } bb1: { - StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44 - StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 - Deinit(_0); // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38 - discriminant(_0) = 0; // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38 - StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38 - goto -> bb3; // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38 + StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18 + StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:17:43: 17:44 + StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29 + Deinit(_0); // scope 4 at $DIR/separate_const_switch.rs:21:34: 21:38 + discriminant(_0) = 0; // scope 4 at $DIR/separate_const_switch.rs:21:34: 21:38 + StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:21:37: 21:38 + goto -> bb3; // scope 0 at $DIR/separate_const_switch.rs:21:37: 21:38 } bb2: { - StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - _4 = ((_1 as Ok).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - StorageLive(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45 - _5 = _4; // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45 - Deinit(_2); // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - discriminant(_2) = 0; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - StorageDead(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46 - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46 - StorageLive(_7); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - _7 = ((_2 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - StorageLive(_8); // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43 - _8 = _7; // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43 - Deinit(_0); // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - ((_0 as Some).0: i32) = move _8; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - discriminant(_0) = 1; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - StorageDead(_8); // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44 - StorageDead(_7); // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44 - goto -> bb3; // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44 + StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17 + _4 = ((_1 as Ok).0: i32); // scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17 + StorageLive(_5); // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45 + _5 = _4; // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45 + Deinit(_2); // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46 + ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46 + discriminant(_2) = 0; // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46 + StorageDead(_5); // scope 1 at $DIR/separate_const_switch.rs:16:45: 16:46 + StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:16:45: 16:46 + StorageLive(_7); // scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32 + _7 = ((_2 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32 + StorageLive(_8); // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43 + _8 = _7; // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43 + Deinit(_0); // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44 + ((_0 as Some).0: i32) = move _8; // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44 + discriminant(_0) = 1; // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44 + StorageDead(_8); // scope 3 at $DIR/separate_const_switch.rs:20:43: 20:44 + StorageDead(_7); // scope 0 at $DIR/separate_const_switch.rs:20:43: 20:44 + goto -> bb3; // scope 0 at $DIR/separate_const_switch.rs:20:43: 20:44 } bb3: { - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2 + StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:23:1: 23:2 + return; // scope 0 at $DIR/separate_const_switch.rs:23:2: 23:2 } } diff --git a/src/test/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff b/src/test/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff index 3ab1c572aa1a3..11f8d509281ea 100644 --- a/src/test/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff +++ b/src/test/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff @@ -2,101 +2,101 @@ + // MIR for `too_complex` after SeparateConstSwitch fn too_complex(_1: Result) -> Option { - debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17 - let mut _0: std::option::Option; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53 - let mut _2: std::ops::ControlFlow; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 - let mut _3: isize; // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18 - let _4: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - let mut _5: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45 - let _6: usize; // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - let mut _7: usize; // in scope 0 at $DIR/separate_const_switch.rs:+8:42: +8:43 - let mut _8: isize; // in scope 0 at $DIR/separate_const_switch.rs:+11:9: +11:33 - let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - let mut _10: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43 - let _11: usize; // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 + debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:9:16: 9:17 + let mut _0: std::option::Option; // return place in scope 0 at $DIR/separate_const_switch.rs:9:42: 9:53 + let mut _2: std::ops::ControlFlow; // in scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6 + let mut _3: isize; // in scope 0 at $DIR/separate_const_switch.rs:16:13: 16:18 + let _4: i32; // in scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17 + let mut _5: i32; // in scope 0 at $DIR/separate_const_switch.rs:16:44: 16:45 + let _6: usize; // in scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18 + let mut _7: usize; // in scope 0 at $DIR/separate_const_switch.rs:17:42: 17:43 + let mut _8: isize; // in scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33 + let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32 + let mut _10: i32; // in scope 0 at $DIR/separate_const_switch.rs:20:42: 20:43 + let _11: usize; // in scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29 scope 1 { - debug v => _4; // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17 + debug v => _4; // in scope 1 at $DIR/separate_const_switch.rs:16:16: 16:17 } scope 2 { - debug r => _6; // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18 + debug r => _6; // in scope 2 at $DIR/separate_const_switch.rs:17:17: 17:18 } scope 3 { - debug v => _9; // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32 + debug v => _9; // in scope 3 at $DIR/separate_const_switch.rs:20:31: 20:32 } scope 4 { - debug r => _11; // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29 + debug r => _11; // in scope 4 at $DIR/separate_const_switch.rs:21:28: 21:29 } bb0: { - StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 - _3 = discriminant(_1); // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16 - switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16 + StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6 + _3 = discriminant(_1); // scope 0 at $DIR/separate_const_switch.rs:15:15: 15:16 + switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/separate_const_switch.rs:15:9: 15:16 } bb1: { - StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - _6 = ((_1 as Err).0: usize); // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - StorageLive(_7); // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43 - _7 = _6; // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43 - Deinit(_2); // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44 - ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44 - discriminant(_2) = 1; // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44 - StorageDead(_7); // scope 2 at $DIR/separate_const_switch.rs:+8:43: +8:44 - StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44 -- goto -> bb3; // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44 -+ _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 -+ switchInt(move _8) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6 + StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18 + _6 = ((_1 as Err).0: usize); // scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18 + StorageLive(_7); // scope 2 at $DIR/separate_const_switch.rs:17:42: 17:43 + _7 = _6; // scope 2 at $DIR/separate_const_switch.rs:17:42: 17:43 + Deinit(_2); // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44 + ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44 + discriminant(_2) = 1; // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44 + StorageDead(_7); // scope 2 at $DIR/separate_const_switch.rs:17:43: 17:44 + StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:17:43: 17:44 +- goto -> bb3; // scope 0 at $DIR/separate_const_switch.rs:17:43: 17:44 ++ _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6 ++ switchInt(move _8) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:14:5: 19:6 } bb2: { - StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - _4 = ((_1 as Ok).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - StorageLive(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45 - _5 = _4; // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45 - Deinit(_2); // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - discriminant(_2) = 0; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - StorageDead(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46 - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46 -- goto -> bb3; // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46 + StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17 + _4 = ((_1 as Ok).0: i32); // scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17 + StorageLive(_5); // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45 + _5 = _4; // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45 + Deinit(_2); // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46 + ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46 + discriminant(_2) = 0; // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46 + StorageDead(_5); // scope 1 at $DIR/separate_const_switch.rs:16:45: 16:46 + StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:16:45: 16:46 +- goto -> bb3; // scope 0 at $DIR/separate_const_switch.rs:16:45: 16:46 - } - - bb3: { - _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 -- switchInt(move _8) -> [0_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6 -+ switchInt(move _8) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6 + _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6 +- switchInt(move _8) -> [0_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/separate_const_switch.rs:14:5: 19:6 ++ switchInt(move _8) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:14:5: 19:6 } - bb4: { + bb3: { - StorageLive(_11); // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 - _11 = ((_2 as Break).0: usize); // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 - Deinit(_0); // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38 - discriminant(_0) = 0; // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38 - StorageDead(_11); // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38 -- goto -> bb6; // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38 -+ goto -> bb5; // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38 + StorageLive(_11); // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29 + _11 = ((_2 as Break).0: usize); // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29 + Deinit(_0); // scope 4 at $DIR/separate_const_switch.rs:21:34: 21:38 + discriminant(_0) = 0; // scope 4 at $DIR/separate_const_switch.rs:21:34: 21:38 + StorageDead(_11); // scope 0 at $DIR/separate_const_switch.rs:21:37: 21:38 +- goto -> bb6; // scope 0 at $DIR/separate_const_switch.rs:21:37: 21:38 ++ goto -> bb5; // scope 0 at $DIR/separate_const_switch.rs:21:37: 21:38 } - bb5: { + bb4: { - StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - _9 = ((_2 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - StorageLive(_10); // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43 - _10 = _9; // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43 - Deinit(_0); // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - ((_0 as Some).0: i32) = move _10; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - discriminant(_0) = 1; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - StorageDead(_10); // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44 - StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44 -- goto -> bb6; // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44 -+ goto -> bb5; // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44 + StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32 + _9 = ((_2 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32 + StorageLive(_10); // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43 + _10 = _9; // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43 + Deinit(_0); // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44 + ((_0 as Some).0: i32) = move _10; // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44 + discriminant(_0) = 1; // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44 + StorageDead(_10); // scope 3 at $DIR/separate_const_switch.rs:20:43: 20:44 + StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:20:43: 20:44 +- goto -> bb6; // scope 0 at $DIR/separate_const_switch.rs:20:43: 20:44 ++ goto -> bb5; // scope 0 at $DIR/separate_const_switch.rs:20:43: 20:44 } - bb6: { + bb5: { - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2 + StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:23:1: 23:2 + return; // scope 0 at $DIR/separate_const_switch.rs:23:2: 23:2 } } diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir b/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir index 3bef6aa0579a7..c189c18d2d0e7 100644 --- a/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir +++ b/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir @@ -1,29 +1,29 @@ // MIR for `match_bool` 0 mir_map fn match_bool(_1: bool) -> usize { - debug x => _1; // in scope 0 at $DIR/simple-match.rs:+0:15: +0:16 - let mut _0: usize; // return place in scope 0 at $DIR/simple-match.rs:+0:27: +0:32 + debug x => _1; // in scope 0 at $DIR/simple-match.rs:5:15: 5:16 + let mut _0: usize; // return place in scope 0 at $DIR/simple-match.rs:5:27: 5:32 bb0: { - FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:+1:11: +1:12 - switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:+1:5: +1:12 + FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:6:11: 6:12 + switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:6:5: 6:12 } bb1: { - falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/simple-match.rs:+2:9: +2:13 + falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/simple-match.rs:7:9: 7:13 } bb2: { - _0 = const 20_usize; // scope 0 at $DIR/simple-match.rs:+3:14: +3:16 - goto -> bb4; // scope 0 at $DIR/simple-match.rs:+3:14: +3:16 + _0 = const 20_usize; // scope 0 at $DIR/simple-match.rs:8:14: 8:16 + goto -> bb4; // scope 0 at $DIR/simple-match.rs:8:14: 8:16 } bb3: { - _0 = const 10_usize; // scope 0 at $DIR/simple-match.rs:+2:17: +2:19 - goto -> bb4; // scope 0 at $DIR/simple-match.rs:+2:17: +2:19 + _0 = const 10_usize; // scope 0 at $DIR/simple-match.rs:7:17: 7:19 + goto -> bb4; // scope 0 at $DIR/simple-match.rs:7:17: 7:19 } bb4: { - return; // scope 0 at $DIR/simple-match.rs:+5:2: +5:2 + return; // scope 0 at $DIR/simple-match.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir b/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir index 3bef6aa0579a7..c189c18d2d0e7 100644 --- a/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir +++ b/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir @@ -1,29 +1,29 @@ // MIR for `match_bool` 0 mir_map fn match_bool(_1: bool) -> usize { - debug x => _1; // in scope 0 at $DIR/simple-match.rs:+0:15: +0:16 - let mut _0: usize; // return place in scope 0 at $DIR/simple-match.rs:+0:27: +0:32 + debug x => _1; // in scope 0 at $DIR/simple-match.rs:5:15: 5:16 + let mut _0: usize; // return place in scope 0 at $DIR/simple-match.rs:5:27: 5:32 bb0: { - FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:+1:11: +1:12 - switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:+1:5: +1:12 + FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:6:11: 6:12 + switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:6:5: 6:12 } bb1: { - falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/simple-match.rs:+2:9: +2:13 + falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/simple-match.rs:7:9: 7:13 } bb2: { - _0 = const 20_usize; // scope 0 at $DIR/simple-match.rs:+3:14: +3:16 - goto -> bb4; // scope 0 at $DIR/simple-match.rs:+3:14: +3:16 + _0 = const 20_usize; // scope 0 at $DIR/simple-match.rs:8:14: 8:16 + goto -> bb4; // scope 0 at $DIR/simple-match.rs:8:14: 8:16 } bb3: { - _0 = const 10_usize; // scope 0 at $DIR/simple-match.rs:+2:17: +2:19 - goto -> bb4; // scope 0 at $DIR/simple-match.rs:+2:17: +2:19 + _0 = const 10_usize; // scope 0 at $DIR/simple-match.rs:7:17: 7:19 + goto -> bb4; // scope 0 at $DIR/simple-match.rs:7:17: 7:19 } bb4: { - return; // scope 0 at $DIR/simple-match.rs:+5:2: +5:2 + return; // scope 0 at $DIR/simple-match.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff index 9c3ad4b4df912..389dbd27b5d1b 100644 --- a/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff @@ -2,45 +2,45 @@ + // MIR for `id` after SimplifyArmIdentity fn id(_1: Option) -> Option { - debug o => _1; // in scope 0 at $DIR/simplify-arm.rs:+0:7: +0:8 - let mut _0: std::option::Option; // return place in scope 0 at $DIR/simplify-arm.rs:+0:25: +0:35 - let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:16 - let _3: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15 - let mut _4: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:25: +2:26 + debug o => _1; // in scope 0 at $DIR/simplify-arm.rs:9:7: 9:8 + let mut _0: std::option::Option; // return place in scope 0 at $DIR/simplify-arm.rs:9:25: 9:35 + let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 + let _3: u8; // in scope 0 at $DIR/simplify-arm.rs:11:14: 11:15 + let mut _4: u8; // in scope 0 at $DIR/simplify-arm.rs:11:25: 11:26 scope 1 { - debug v => _3; // in scope 1 at $DIR/simplify-arm.rs:+2:14: +2:15 + debug v => _3; // in scope 1 at $DIR/simplify-arm.rs:11:14: 11:15 } bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:5: +1:12 + _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12 + switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:10:5: 10:12 } bb1: { - Deinit(_0); // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21 - discriminant(_0) = 0; // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21 + Deinit(_0); // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21 + discriminant(_0) = 0; // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21 } bb2: { - unreachable; // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12 + unreachable; // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12 } bb3: { - StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15 - _3 = ((_1 as Some).0: u8); // scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15 - StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:+2:25: +2:26 - _4 = _3; // scope 1 at $DIR/simplify-arm.rs:+2:25: +2:26 - Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27 - ((_0 as Some).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27 - discriminant(_0) = 1; // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27 - StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:+2:26: +2:27 - StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:+2:26: +2:27 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+2:26: +2:27 + StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15 + _3 = ((_1 as Some).0: u8); // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15 + StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26 + _4 = _3; // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26 + Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 + ((_0 as Some).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 + discriminant(_0) = 1; // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 + StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:11:26: 11:27 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:11:26: 11:27 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:11:26: 11:27 } bb4: { - return; // scope 0 at $DIR/simplify-arm.rs:+5:2: +5:2 + return; // scope 0 at $DIR/simplify-arm.rs:14:2: 14:2 } } diff --git a/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff index 7b3a699365773..32b7b9aa55553 100644 --- a/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff +++ b/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff @@ -2,45 +2,45 @@ + // MIR for `id` after SimplifyBranchSame fn id(_1: Option) -> Option { - debug o => _1; // in scope 0 at $DIR/simplify-arm.rs:+0:7: +0:8 - let mut _0: std::option::Option; // return place in scope 0 at $DIR/simplify-arm.rs:+0:25: +0:35 - let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:16 - let _3: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15 - let mut _4: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:25: +2:26 + debug o => _1; // in scope 0 at $DIR/simplify-arm.rs:9:7: 9:8 + let mut _0: std::option::Option; // return place in scope 0 at $DIR/simplify-arm.rs:9:25: 9:35 + let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 + let _3: u8; // in scope 0 at $DIR/simplify-arm.rs:11:14: 11:15 + let mut _4: u8; // in scope 0 at $DIR/simplify-arm.rs:11:25: 11:26 scope 1 { - debug v => _3; // in scope 1 at $DIR/simplify-arm.rs:+2:14: +2:15 + debug v => _3; // in scope 1 at $DIR/simplify-arm.rs:11:14: 11:15 } bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:5: +1:12 + _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12 + switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:10:5: 10:12 } bb1: { - Deinit(_0); // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21 - discriminant(_0) = 0; // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21 + Deinit(_0); // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21 + discriminant(_0) = 0; // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21 } bb2: { - unreachable; // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12 + unreachable; // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12 } bb3: { - StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15 - _3 = ((_1 as Some).0: u8); // scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15 - StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:+2:25: +2:26 - _4 = _3; // scope 1 at $DIR/simplify-arm.rs:+2:25: +2:26 - Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27 - ((_0 as Some).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27 - discriminant(_0) = 1; // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27 - StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:+2:26: +2:27 - StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:+2:26: +2:27 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+2:26: +2:27 + StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15 + _3 = ((_1 as Some).0: u8); // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15 + StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26 + _4 = _3; // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26 + Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 + ((_0 as Some).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 + discriminant(_0) = 1; // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 + StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:11:26: 11:27 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:11:26: 11:27 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:11:26: 11:27 } bb4: { - return; // scope 0 at $DIR/simplify-arm.rs:+5:2: +5:2 + return; // scope 0 at $DIR/simplify-arm.rs:14:2: 14:2 } } diff --git a/src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff index 31d8453cec015..60d421a2e1ab3 100644 --- a/src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff @@ -2,57 +2,57 @@ + // MIR for `id_result` after SimplifyArmIdentity fn id_result(_1: Result) -> Result { - debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:+0:14: +0:15 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify-arm.rs:+0:37: +0:52 - let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:14 - let _3: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13 - let mut _4: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:21: +2:22 - let _5: i32; // in scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14 - let mut _6: i32; // in scope 0 at $DIR/simplify-arm.rs:+3:23: +3:24 + debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:16:14: 16:15 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify-arm.rs:16:37: 16:52 + let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:18:9: 18:14 + let _3: u8; // in scope 0 at $DIR/simplify-arm.rs:18:12: 18:13 + let mut _4: u8; // in scope 0 at $DIR/simplify-arm.rs:18:21: 18:22 + let _5: i32; // in scope 0 at $DIR/simplify-arm.rs:19:13: 19:14 + let mut _6: i32; // in scope 0 at $DIR/simplify-arm.rs:19:23: 19:24 scope 1 { - debug x => _3; // in scope 1 at $DIR/simplify-arm.rs:+2:12: +2:13 + debug x => _3; // in scope 1 at $DIR/simplify-arm.rs:18:12: 18:13 } scope 2 { - debug y => _5; // in scope 2 at $DIR/simplify-arm.rs:+3:13: +3:14 + debug y => _5; // in scope 2 at $DIR/simplify-arm.rs:19:13: 19:14 } bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:5: +1:12 + _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:17:11: 17:12 + switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:17:5: 17:12 } bb1: { - StorageLive(_5); // scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14 - _5 = ((_1 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14 - StorageLive(_6); // scope 2 at $DIR/simplify-arm.rs:+3:23: +3:24 - _6 = _5; // scope 2 at $DIR/simplify-arm.rs:+3:23: +3:24 - Deinit(_0); // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25 - ((_0 as Err).0: i32) = move _6; // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25 - discriminant(_0) = 1; // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25 - StorageDead(_6); // scope 2 at $DIR/simplify-arm.rs:+3:24: +3:25 - StorageDead(_5); // scope 0 at $DIR/simplify-arm.rs:+3:24: +3:25 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+3:24: +3:25 + StorageLive(_5); // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14 + _5 = ((_1 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14 + StorageLive(_6); // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24 + _6 = _5; // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24 + Deinit(_0); // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25 + ((_0 as Err).0: i32) = move _6; // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25 + discriminant(_0) = 1; // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25 + StorageDead(_6); // scope 2 at $DIR/simplify-arm.rs:19:24: 19:25 + StorageDead(_5); // scope 0 at $DIR/simplify-arm.rs:19:24: 19:25 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:19:24: 19:25 } bb2: { - unreachable; // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12 + unreachable; // scope 0 at $DIR/simplify-arm.rs:17:11: 17:12 } bb3: { - StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13 - _3 = ((_1 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13 - StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:+2:21: +2:22 - _4 = _3; // scope 1 at $DIR/simplify-arm.rs:+2:21: +2:22 - Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23 - ((_0 as Ok).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23 - discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23 - StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:+2:22: +2:23 - StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:+2:22: +2:23 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+2:22: +2:23 + StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13 + _3 = ((_1 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13 + StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22 + _4 = _3; // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22 + Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23 + ((_0 as Ok).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23 + discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23 + StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:18:22: 18:23 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:18:22: 18:23 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:18:22: 18:23 } bb4: { - return; // scope 0 at $DIR/simplify-arm.rs:+5:2: +5:2 + return; // scope 0 at $DIR/simplify-arm.rs:21:2: 21:2 } } diff --git a/src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff index 3692ebf747bd2..52adf11d0f528 100644 --- a/src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff +++ b/src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff @@ -2,57 +2,57 @@ + // MIR for `id_result` after SimplifyBranchSame fn id_result(_1: Result) -> Result { - debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:+0:14: +0:15 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify-arm.rs:+0:37: +0:52 - let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:14 - let _3: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13 - let mut _4: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:21: +2:22 - let _5: i32; // in scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14 - let mut _6: i32; // in scope 0 at $DIR/simplify-arm.rs:+3:23: +3:24 + debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:16:14: 16:15 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify-arm.rs:16:37: 16:52 + let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:18:9: 18:14 + let _3: u8; // in scope 0 at $DIR/simplify-arm.rs:18:12: 18:13 + let mut _4: u8; // in scope 0 at $DIR/simplify-arm.rs:18:21: 18:22 + let _5: i32; // in scope 0 at $DIR/simplify-arm.rs:19:13: 19:14 + let mut _6: i32; // in scope 0 at $DIR/simplify-arm.rs:19:23: 19:24 scope 1 { - debug x => _3; // in scope 1 at $DIR/simplify-arm.rs:+2:12: +2:13 + debug x => _3; // in scope 1 at $DIR/simplify-arm.rs:18:12: 18:13 } scope 2 { - debug y => _5; // in scope 2 at $DIR/simplify-arm.rs:+3:13: +3:14 + debug y => _5; // in scope 2 at $DIR/simplify-arm.rs:19:13: 19:14 } bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:5: +1:12 + _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:17:11: 17:12 + switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:17:5: 17:12 } bb1: { - StorageLive(_5); // scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14 - _5 = ((_1 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14 - StorageLive(_6); // scope 2 at $DIR/simplify-arm.rs:+3:23: +3:24 - _6 = _5; // scope 2 at $DIR/simplify-arm.rs:+3:23: +3:24 - Deinit(_0); // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25 - ((_0 as Err).0: i32) = move _6; // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25 - discriminant(_0) = 1; // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25 - StorageDead(_6); // scope 2 at $DIR/simplify-arm.rs:+3:24: +3:25 - StorageDead(_5); // scope 0 at $DIR/simplify-arm.rs:+3:24: +3:25 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+3:24: +3:25 + StorageLive(_5); // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14 + _5 = ((_1 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14 + StorageLive(_6); // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24 + _6 = _5; // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24 + Deinit(_0); // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25 + ((_0 as Err).0: i32) = move _6; // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25 + discriminant(_0) = 1; // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25 + StorageDead(_6); // scope 2 at $DIR/simplify-arm.rs:19:24: 19:25 + StorageDead(_5); // scope 0 at $DIR/simplify-arm.rs:19:24: 19:25 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:19:24: 19:25 } bb2: { - unreachable; // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12 + unreachable; // scope 0 at $DIR/simplify-arm.rs:17:11: 17:12 } bb3: { - StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13 - _3 = ((_1 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13 - StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:+2:21: +2:22 - _4 = _3; // scope 1 at $DIR/simplify-arm.rs:+2:21: +2:22 - Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23 - ((_0 as Ok).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23 - discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23 - StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:+2:22: +2:23 - StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:+2:22: +2:23 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+2:22: +2:23 + StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13 + _3 = ((_1 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13 + StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22 + _4 = _3; // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22 + Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23 + ((_0 as Ok).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23 + discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23 + StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:18:22: 18:23 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:18:22: 18:23 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:18:22: 18:23 } bb4: { - return; // scope 0 at $DIR/simplify-arm.rs:+5:2: +5:2 + return; // scope 0 at $DIR/simplify-arm.rs:21:2: 21:2 } } diff --git a/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff index 229046b51fcd5..d2dbfbe1093a8 100644 --- a/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff @@ -2,92 +2,92 @@ + // MIR for `id_try` after SimplifyArmIdentity fn id_try(_1: Result) -> Result { - debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:+0:11: +0:12 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify-arm.rs:+0:34: +0:49 - let _2: u8; // in scope 0 at $DIR/simplify-arm.rs:+1:9: +1:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:+1:19: +1:33 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:+1:31: +1:32 - let mut _5: isize; // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:15 - let _6: i32; // in scope 0 at $DIR/simplify-arm.rs:+2:13: +2:14 - let mut _7: !; // in scope 0 at $DIR/simplify-arm.rs:+2:19: +2:51 - let mut _8: i32; // in scope 0 at $DIR/simplify-arm.rs:+2:37: +2:50 - let mut _9: i32; // in scope 0 at $DIR/simplify-arm.rs:+2:48: +2:49 - let _10: u8; // in scope 0 at $DIR/simplify-arm.rs:+3:12: +3:13 - let mut _11: u8; // in scope 0 at $DIR/simplify-arm.rs:+5:8: +5:9 + debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:35:11: 35:12 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify-arm.rs:35:34: 35:49 + let _2: u8; // in scope 0 at $DIR/simplify-arm.rs:36:9: 36:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + let mut _5: isize; // in scope 0 at $DIR/simplify-arm.rs:37:9: 37:15 + let _6: i32; // in scope 0 at $DIR/simplify-arm.rs:37:13: 37:14 + let mut _7: !; // in scope 0 at $DIR/simplify-arm.rs:37:19: 37:51 + let mut _8: i32; // in scope 0 at $DIR/simplify-arm.rs:37:37: 37:50 + let mut _9: i32; // in scope 0 at $DIR/simplify-arm.rs:37:48: 37:49 + let _10: u8; // in scope 0 at $DIR/simplify-arm.rs:38:12: 38:13 + let mut _11: u8; // in scope 0 at $DIR/simplify-arm.rs:40:8: 40:9 scope 1 { - debug x => _2; // in scope 1 at $DIR/simplify-arm.rs:+1:9: +1:10 + debug x => _2; // in scope 1 at $DIR/simplify-arm.rs:36:9: 36:10 } scope 2 { - debug e => _6; // in scope 2 at $DIR/simplify-arm.rs:+2:13: +2:14 + debug e => _6; // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14 scope 5 (inlined >::from) { // at $DIR/simplify-arm.rs:37:37: 37:50 debug t => _9; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } scope 6 (inlined from_error::) { // at $DIR/simplify-arm.rs:37:26: 37:51 - debug e => _8; // in scope 6 at $DIR/simplify-arm.rs:+0:21: +0:22 + debug e => _8; // in scope 6 at $DIR/simplify-arm.rs:27:21: 27:22 } } scope 3 { - debug v => _10; // in scope 3 at $DIR/simplify-arm.rs:+3:12: +3:13 + debug v => _10; // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13 } scope 4 (inlined into_result::) { // at $DIR/simplify-arm.rs:36:19: 36:33 - debug r => _4; // in scope 4 at $DIR/simplify-arm.rs:+0:22: +0:23 + debug r => _4; // in scope 4 at $DIR/simplify-arm.rs:23:22: 23:23 } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify-arm.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:+1:19: +1:33 - StorageLive(_4); // scope 0 at $DIR/simplify-arm.rs:+1:31: +1:32 - _4 = _1; // scope 0 at $DIR/simplify-arm.rs:+1:31: +1:32 - _3 = move _4; // scope 4 at $DIR/simplify-arm.rs:+0:5: +0:6 - StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:+1:32: +1:33 - _5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:+1:19: +1:33 - switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:13: +1:33 + StorageLive(_2); // scope 0 at $DIR/simplify-arm.rs:36:9: 36:10 + StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 + StorageLive(_4); // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + _4 = _1; // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + _3 = move _4; // scope 4 at $DIR/simplify-arm.rs:24:5: 24:6 + StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:36:32: 36:33 + _5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 + switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:36:13: 36:33 } bb1: { - StorageLive(_10); // scope 0 at $DIR/simplify-arm.rs:+3:12: +3:13 - _10 = ((_3 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:+3:12: +3:13 - _2 = _10; // scope 3 at $DIR/simplify-arm.rs:+3:18: +3:19 - StorageDead(_10); // scope 0 at $DIR/simplify-arm.rs:+3:18: +3:19 - StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:+4:6: +4:7 - StorageLive(_11); // scope 1 at $DIR/simplify-arm.rs:+5:8: +5:9 - _11 = _2; // scope 1 at $DIR/simplify-arm.rs:+5:8: +5:9 - Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:+5:5: +5:10 - ((_0 as Ok).0: u8) = move _11; // scope 1 at $DIR/simplify-arm.rs:+5:5: +5:10 - discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:+5:5: +5:10 - StorageDead(_11); // scope 1 at $DIR/simplify-arm.rs:+5:9: +5:10 - StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:+6:1: +6:2 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+6:2: +6:2 + StorageLive(_10); // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13 + _10 = ((_3 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13 + _2 = _10; // scope 3 at $DIR/simplify-arm.rs:38:18: 38:19 + StorageDead(_10); // scope 0 at $DIR/simplify-arm.rs:38:18: 38:19 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7 + StorageLive(_11); // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9 + _11 = _2; // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9 + Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10 + ((_0 as Ok).0: u8) = move _11; // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10 + discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10 + StorageDead(_11); // scope 1 at $DIR/simplify-arm.rs:40:9: 40:10 + StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 } bb2: { - unreachable; // scope 0 at $DIR/simplify-arm.rs:+1:19: +1:33 + unreachable; // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 } bb3: { - StorageLive(_6); // scope 0 at $DIR/simplify-arm.rs:+2:13: +2:14 - _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:+2:13: +2:14 - StorageLive(_8); // scope 2 at $DIR/simplify-arm.rs:+2:37: +2:50 - StorageLive(_9); // scope 2 at $DIR/simplify-arm.rs:+2:48: +2:49 - _9 = _6; // scope 2 at $DIR/simplify-arm.rs:+2:48: +2:49 + StorageLive(_6); // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14 + _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14 + StorageLive(_8); // scope 2 at $DIR/simplify-arm.rs:37:37: 37:50 + StorageLive(_9); // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49 + _9 = _6; // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49 _8 = move _9; // scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - StorageDead(_9); // scope 2 at $DIR/simplify-arm.rs:+2:49: +2:50 - ((_0 as Err).0: i32) = move _8; // scope 6 at $DIR/simplify-arm.rs:+0:9: +0:10 - Deinit(_0); // scope 6 at $DIR/simplify-arm.rs:+0:5: +0:11 - discriminant(_0) = 1; // scope 6 at $DIR/simplify-arm.rs:+0:5: +0:11 - StorageDead(_8); // scope 2 at $DIR/simplify-arm.rs:+2:50: +2:51 - StorageDead(_6); // scope 0 at $DIR/simplify-arm.rs:+2:50: +2:51 - StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:+4:6: +4:7 - StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:+6:1: +6:2 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+6:2: +6:2 + StorageDead(_9); // scope 2 at $DIR/simplify-arm.rs:37:49: 37:50 + ((_0 as Err).0: i32) = move _8; // scope 6 at $DIR/simplify-arm.rs:28:9: 28:10 + Deinit(_0); // scope 6 at $DIR/simplify-arm.rs:28:5: 28:11 + discriminant(_0) = 1; // scope 6 at $DIR/simplify-arm.rs:28:5: 28:11 + StorageDead(_8); // scope 2 at $DIR/simplify-arm.rs:37:50: 37:51 + StorageDead(_6); // scope 0 at $DIR/simplify-arm.rs:37:50: 37:51 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7 + StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 } bb4: { - return; // scope 0 at $DIR/simplify-arm.rs:+6:2: +6:2 + return; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 } bb5 (cleanup): { - resume; // scope 0 at $DIR/simplify-arm.rs:+0:1: +6:2 + resume; // scope 0 at $DIR/simplify-arm.rs:35:1: 41:2 } } diff --git a/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff index 22a2f85c09ae5..a993ea73665c4 100644 --- a/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff +++ b/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff @@ -2,92 +2,92 @@ + // MIR for `id_try` after SimplifyBranchSame fn id_try(_1: Result) -> Result { - debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:+0:11: +0:12 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify-arm.rs:+0:34: +0:49 - let _2: u8; // in scope 0 at $DIR/simplify-arm.rs:+1:9: +1:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:+1:19: +1:33 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:+1:31: +1:32 - let mut _5: isize; // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:15 - let _6: i32; // in scope 0 at $DIR/simplify-arm.rs:+2:13: +2:14 - let mut _7: !; // in scope 0 at $DIR/simplify-arm.rs:+2:19: +2:51 - let mut _8: i32; // in scope 0 at $DIR/simplify-arm.rs:+2:37: +2:50 - let mut _9: i32; // in scope 0 at $DIR/simplify-arm.rs:+2:48: +2:49 - let _10: u8; // in scope 0 at $DIR/simplify-arm.rs:+3:12: +3:13 - let mut _11: u8; // in scope 0 at $DIR/simplify-arm.rs:+5:8: +5:9 + debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:35:11: 35:12 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify-arm.rs:35:34: 35:49 + let _2: u8; // in scope 0 at $DIR/simplify-arm.rs:36:9: 36:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + let mut _5: isize; // in scope 0 at $DIR/simplify-arm.rs:37:9: 37:15 + let _6: i32; // in scope 0 at $DIR/simplify-arm.rs:37:13: 37:14 + let mut _7: !; // in scope 0 at $DIR/simplify-arm.rs:37:19: 37:51 + let mut _8: i32; // in scope 0 at $DIR/simplify-arm.rs:37:37: 37:50 + let mut _9: i32; // in scope 0 at $DIR/simplify-arm.rs:37:48: 37:49 + let _10: u8; // in scope 0 at $DIR/simplify-arm.rs:38:12: 38:13 + let mut _11: u8; // in scope 0 at $DIR/simplify-arm.rs:40:8: 40:9 scope 1 { - debug x => _2; // in scope 1 at $DIR/simplify-arm.rs:+1:9: +1:10 + debug x => _2; // in scope 1 at $DIR/simplify-arm.rs:36:9: 36:10 } scope 2 { - debug e => _6; // in scope 2 at $DIR/simplify-arm.rs:+2:13: +2:14 + debug e => _6; // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14 scope 5 (inlined >::from) { // at $DIR/simplify-arm.rs:37:37: 37:50 debug t => _9; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } scope 6 (inlined from_error::) { // at $DIR/simplify-arm.rs:37:26: 37:51 - debug e => _8; // in scope 6 at $DIR/simplify-arm.rs:+0:21: +0:22 + debug e => _8; // in scope 6 at $DIR/simplify-arm.rs:27:21: 27:22 } } scope 3 { - debug v => _10; // in scope 3 at $DIR/simplify-arm.rs:+3:12: +3:13 + debug v => _10; // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13 } scope 4 (inlined into_result::) { // at $DIR/simplify-arm.rs:36:19: 36:33 - debug r => _4; // in scope 4 at $DIR/simplify-arm.rs:+0:22: +0:23 + debug r => _4; // in scope 4 at $DIR/simplify-arm.rs:23:22: 23:23 } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify-arm.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:+1:19: +1:33 - StorageLive(_4); // scope 0 at $DIR/simplify-arm.rs:+1:31: +1:32 - _4 = _1; // scope 0 at $DIR/simplify-arm.rs:+1:31: +1:32 - _3 = move _4; // scope 4 at $DIR/simplify-arm.rs:+0:5: +0:6 - StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:+1:32: +1:33 - _5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:+1:19: +1:33 - switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:13: +1:33 + StorageLive(_2); // scope 0 at $DIR/simplify-arm.rs:36:9: 36:10 + StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 + StorageLive(_4); // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + _4 = _1; // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + _3 = move _4; // scope 4 at $DIR/simplify-arm.rs:24:5: 24:6 + StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:36:32: 36:33 + _5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 + switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:36:13: 36:33 } bb1: { - StorageLive(_10); // scope 0 at $DIR/simplify-arm.rs:+3:12: +3:13 - _10 = ((_3 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:+3:12: +3:13 - _2 = _10; // scope 3 at $DIR/simplify-arm.rs:+3:18: +3:19 - StorageDead(_10); // scope 0 at $DIR/simplify-arm.rs:+3:18: +3:19 - StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:+4:6: +4:7 - StorageLive(_11); // scope 1 at $DIR/simplify-arm.rs:+5:8: +5:9 - _11 = _2; // scope 1 at $DIR/simplify-arm.rs:+5:8: +5:9 - Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:+5:5: +5:10 - ((_0 as Ok).0: u8) = move _11; // scope 1 at $DIR/simplify-arm.rs:+5:5: +5:10 - discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:+5:5: +5:10 - StorageDead(_11); // scope 1 at $DIR/simplify-arm.rs:+5:9: +5:10 - StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:+6:1: +6:2 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+6:2: +6:2 + StorageLive(_10); // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13 + _10 = ((_3 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13 + _2 = _10; // scope 3 at $DIR/simplify-arm.rs:38:18: 38:19 + StorageDead(_10); // scope 0 at $DIR/simplify-arm.rs:38:18: 38:19 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7 + StorageLive(_11); // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9 + _11 = _2; // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9 + Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10 + ((_0 as Ok).0: u8) = move _11; // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10 + discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10 + StorageDead(_11); // scope 1 at $DIR/simplify-arm.rs:40:9: 40:10 + StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 } bb2: { - unreachable; // scope 0 at $DIR/simplify-arm.rs:+1:19: +1:33 + unreachable; // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 } bb3: { - StorageLive(_6); // scope 0 at $DIR/simplify-arm.rs:+2:13: +2:14 - _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:+2:13: +2:14 - StorageLive(_8); // scope 2 at $DIR/simplify-arm.rs:+2:37: +2:50 - StorageLive(_9); // scope 2 at $DIR/simplify-arm.rs:+2:48: +2:49 - _9 = _6; // scope 2 at $DIR/simplify-arm.rs:+2:48: +2:49 + StorageLive(_6); // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14 + _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14 + StorageLive(_8); // scope 2 at $DIR/simplify-arm.rs:37:37: 37:50 + StorageLive(_9); // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49 + _9 = _6; // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49 _8 = move _9; // scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - StorageDead(_9); // scope 2 at $DIR/simplify-arm.rs:+2:49: +2:50 - ((_0 as Err).0: i32) = move _8; // scope 6 at $DIR/simplify-arm.rs:+0:9: +0:10 - Deinit(_0); // scope 6 at $DIR/simplify-arm.rs:+0:5: +0:11 - discriminant(_0) = 1; // scope 6 at $DIR/simplify-arm.rs:+0:5: +0:11 - StorageDead(_8); // scope 2 at $DIR/simplify-arm.rs:+2:50: +2:51 - StorageDead(_6); // scope 0 at $DIR/simplify-arm.rs:+2:50: +2:51 - StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:+4:6: +4:7 - StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:+6:1: +6:2 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+6:2: +6:2 + StorageDead(_9); // scope 2 at $DIR/simplify-arm.rs:37:49: 37:50 + ((_0 as Err).0: i32) = move _8; // scope 6 at $DIR/simplify-arm.rs:28:9: 28:10 + Deinit(_0); // scope 6 at $DIR/simplify-arm.rs:28:5: 28:11 + discriminant(_0) = 1; // scope 6 at $DIR/simplify-arm.rs:28:5: 28:11 + StorageDead(_8); // scope 2 at $DIR/simplify-arm.rs:37:50: 37:51 + StorageDead(_6); // scope 0 at $DIR/simplify-arm.rs:37:50: 37:51 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7 + StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 } bb4: { - return; // scope 0 at $DIR/simplify-arm.rs:+6:2: +6:2 + return; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 } bb5 (cleanup): { - resume; // scope 0 at $DIR/simplify-arm.rs:+0:1: +6:2 + resume; // scope 0 at $DIR/simplify-arm.rs:35:1: 41:2 } } diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff index 118f5dd0abb43..474d2df7aadb8 100644 --- a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff +++ b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff @@ -2,60 +2,60 @@ + // MIR for `main` after SimplifyArmIdentity fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify-arm-identity.rs:+0:11: +0:11 - let _1: Src; // in scope 0 at $DIR/simplify-arm-identity.rs:+1:9: +1:10 - let mut _2: Dst; // in scope 0 at $DIR/simplify-arm-identity.rs:+2:18: +5:6 - let mut _3: isize; // in scope 0 at $DIR/simplify-arm-identity.rs:+3:9: +3:20 - let mut _5: u8; // in scope 0 at $DIR/simplify-arm-identity.rs:+3:33: +3:34 + let mut _0: (); // return place in scope 0 at $DIR/simplify-arm-identity.rs:17:11: 17:11 + let _1: Src; // in scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10 + let mut _2: Dst; // in scope 0 at $DIR/simplify-arm-identity.rs:19:18: 22:6 + let mut _3: isize; // in scope 0 at $DIR/simplify-arm-identity.rs:20:9: 20:20 + let mut _5: u8; // in scope 0 at $DIR/simplify-arm-identity.rs:20:33: 20:34 scope 1 { - debug e => _1; // in scope 1 at $DIR/simplify-arm-identity.rs:+1:9: +1:10 - let _4: u8; // in scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19 + debug e => _1; // in scope 1 at $DIR/simplify-arm-identity.rs:18:9: 18:10 + let _4: u8; // in scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19 scope 2 { } scope 3 { - debug x => _4; // in scope 3 at $DIR/simplify-arm-identity.rs:+3:18: +3:19 + debug x => _4; // in scope 3 at $DIR/simplify-arm-identity.rs:20:18: 20:19 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+1:9: +1:10 - Deinit(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29 - ((_1 as Foo).0: u8) = const 0_u8; // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29 - discriminant(_1) = 0; // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29 - StorageLive(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+2:18: +5:6 - _3 = const 0_isize; // scope 1 at $DIR/simplify-arm-identity.rs:+2:24: +2:25 - goto -> bb3; // scope 1 at $DIR/simplify-arm-identity.rs:+2:18: +2:25 + StorageLive(_1); // scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10 + Deinit(_1); // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29 + ((_1 as Foo).0: u8) = const 0_u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29 + discriminant(_1) = 0; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29 + StorageLive(_2); // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6 + _3 = const 0_isize; // scope 1 at $DIR/simplify-arm-identity.rs:19:24: 19:25 + goto -> bb3; // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 19:25 } bb1: { - Deinit(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32 - ((_2 as Foo).0: u8) = const 0_u8; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32 - discriminant(_2) = 0; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32 - goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32 + Deinit(_2); // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32 + ((_2 as Foo).0: u8) = const 0_u8; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32 + discriminant(_2) = 0; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32 + goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32 } bb2: { - unreachable; // scope 1 at $DIR/simplify-arm-identity.rs:+2:24: +2:25 + unreachable; // scope 1 at $DIR/simplify-arm-identity.rs:19:24: 19:25 } bb3: { - StorageLive(_4); // scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19 - _4 = ((_1 as Foo).0: u8); // scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19 - StorageLive(_5); // scope 3 at $DIR/simplify-arm-identity.rs:+3:33: +3:34 - _5 = _4; // scope 3 at $DIR/simplify-arm-identity.rs:+3:33: +3:34 - Deinit(_2); // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35 - ((_2 as Foo).0: u8) = move _5; // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35 - discriminant(_2) = 0; // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35 - StorageDead(_5); // scope 3 at $DIR/simplify-arm-identity.rs:+3:34: +3:35 - StorageDead(_4); // scope 1 at $DIR/simplify-arm-identity.rs:+3:34: +3:35 - goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:+3:34: +3:35 + StorageLive(_4); // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19 + _4 = ((_1 as Foo).0: u8); // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19 + StorageLive(_5); // scope 3 at $DIR/simplify-arm-identity.rs:20:33: 20:34 + _5 = _4; // scope 3 at $DIR/simplify-arm-identity.rs:20:33: 20:34 + Deinit(_2); // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35 + ((_2 as Foo).0: u8) = move _5; // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35 + discriminant(_2) = 0; // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35 + StorageDead(_5); // scope 3 at $DIR/simplify-arm-identity.rs:20:34: 20:35 + StorageDead(_4); // scope 1 at $DIR/simplify-arm-identity.rs:20:34: 20:35 + goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:20:34: 20:35 } bb4: { - StorageDead(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+5:6: +5:7 - nop; // scope 0 at $DIR/simplify-arm-identity.rs:+0:11: +6:2 - StorageDead(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+6:1: +6:2 - return; // scope 0 at $DIR/simplify-arm-identity.rs:+6:2: +6:2 + StorageDead(_2); // scope 1 at $DIR/simplify-arm-identity.rs:22:6: 22:7 + nop; // scope 0 at $DIR/simplify-arm-identity.rs:17:11: 23:2 + StorageDead(_1); // scope 0 at $DIR/simplify-arm-identity.rs:23:1: 23:2 + return; // scope 0 at $DIR/simplify-arm-identity.rs:23:2: 23:2 } } diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff index 118f5dd0abb43..474d2df7aadb8 100644 --- a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff +++ b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff @@ -2,60 +2,60 @@ + // MIR for `main` after SimplifyArmIdentity fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify-arm-identity.rs:+0:11: +0:11 - let _1: Src; // in scope 0 at $DIR/simplify-arm-identity.rs:+1:9: +1:10 - let mut _2: Dst; // in scope 0 at $DIR/simplify-arm-identity.rs:+2:18: +5:6 - let mut _3: isize; // in scope 0 at $DIR/simplify-arm-identity.rs:+3:9: +3:20 - let mut _5: u8; // in scope 0 at $DIR/simplify-arm-identity.rs:+3:33: +3:34 + let mut _0: (); // return place in scope 0 at $DIR/simplify-arm-identity.rs:17:11: 17:11 + let _1: Src; // in scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10 + let mut _2: Dst; // in scope 0 at $DIR/simplify-arm-identity.rs:19:18: 22:6 + let mut _3: isize; // in scope 0 at $DIR/simplify-arm-identity.rs:20:9: 20:20 + let mut _5: u8; // in scope 0 at $DIR/simplify-arm-identity.rs:20:33: 20:34 scope 1 { - debug e => _1; // in scope 1 at $DIR/simplify-arm-identity.rs:+1:9: +1:10 - let _4: u8; // in scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19 + debug e => _1; // in scope 1 at $DIR/simplify-arm-identity.rs:18:9: 18:10 + let _4: u8; // in scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19 scope 2 { } scope 3 { - debug x => _4; // in scope 3 at $DIR/simplify-arm-identity.rs:+3:18: +3:19 + debug x => _4; // in scope 3 at $DIR/simplify-arm-identity.rs:20:18: 20:19 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+1:9: +1:10 - Deinit(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29 - ((_1 as Foo).0: u8) = const 0_u8; // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29 - discriminant(_1) = 0; // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29 - StorageLive(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+2:18: +5:6 - _3 = const 0_isize; // scope 1 at $DIR/simplify-arm-identity.rs:+2:24: +2:25 - goto -> bb3; // scope 1 at $DIR/simplify-arm-identity.rs:+2:18: +2:25 + StorageLive(_1); // scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10 + Deinit(_1); // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29 + ((_1 as Foo).0: u8) = const 0_u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29 + discriminant(_1) = 0; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29 + StorageLive(_2); // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6 + _3 = const 0_isize; // scope 1 at $DIR/simplify-arm-identity.rs:19:24: 19:25 + goto -> bb3; // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 19:25 } bb1: { - Deinit(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32 - ((_2 as Foo).0: u8) = const 0_u8; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32 - discriminant(_2) = 0; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32 - goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32 + Deinit(_2); // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32 + ((_2 as Foo).0: u8) = const 0_u8; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32 + discriminant(_2) = 0; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32 + goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32 } bb2: { - unreachable; // scope 1 at $DIR/simplify-arm-identity.rs:+2:24: +2:25 + unreachable; // scope 1 at $DIR/simplify-arm-identity.rs:19:24: 19:25 } bb3: { - StorageLive(_4); // scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19 - _4 = ((_1 as Foo).0: u8); // scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19 - StorageLive(_5); // scope 3 at $DIR/simplify-arm-identity.rs:+3:33: +3:34 - _5 = _4; // scope 3 at $DIR/simplify-arm-identity.rs:+3:33: +3:34 - Deinit(_2); // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35 - ((_2 as Foo).0: u8) = move _5; // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35 - discriminant(_2) = 0; // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35 - StorageDead(_5); // scope 3 at $DIR/simplify-arm-identity.rs:+3:34: +3:35 - StorageDead(_4); // scope 1 at $DIR/simplify-arm-identity.rs:+3:34: +3:35 - goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:+3:34: +3:35 + StorageLive(_4); // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19 + _4 = ((_1 as Foo).0: u8); // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19 + StorageLive(_5); // scope 3 at $DIR/simplify-arm-identity.rs:20:33: 20:34 + _5 = _4; // scope 3 at $DIR/simplify-arm-identity.rs:20:33: 20:34 + Deinit(_2); // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35 + ((_2 as Foo).0: u8) = move _5; // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35 + discriminant(_2) = 0; // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35 + StorageDead(_5); // scope 3 at $DIR/simplify-arm-identity.rs:20:34: 20:35 + StorageDead(_4); // scope 1 at $DIR/simplify-arm-identity.rs:20:34: 20:35 + goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:20:34: 20:35 } bb4: { - StorageDead(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+5:6: +5:7 - nop; // scope 0 at $DIR/simplify-arm-identity.rs:+0:11: +6:2 - StorageDead(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+6:1: +6:2 - return; // scope 0 at $DIR/simplify-arm-identity.rs:+6:2: +6:2 + StorageDead(_2); // scope 1 at $DIR/simplify-arm-identity.rs:22:6: 22:7 + nop; // scope 0 at $DIR/simplify-arm-identity.rs:17:11: 23:2 + StorageDead(_1); // scope 0 at $DIR/simplify-arm-identity.rs:23:1: 23:2 + return; // scope 0 at $DIR/simplify-arm-identity.rs:23:2: 23:2 } } diff --git a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff index e068b81bc3bc2..6d41d5b7437f5 100644 --- a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff +++ b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff @@ -2,51 +2,51 @@ + // MIR for `main` after SimplifyCfg-early-opt fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify_cfg.rs:+0:11: +0:11 - let mut _1: (); // in scope 0 at $DIR/simplify_cfg.rs:+0:1: +6:2 - let mut _2: bool; // in scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17 - let mut _3: !; // in scope 0 at $DIR/simplify_cfg.rs:+2:18: +4:10 + let mut _0: (); // return place in scope 0 at $DIR/simplify_cfg.rs:7:11: 7:11 + let mut _1: (); // in scope 0 at $DIR/simplify_cfg.rs:7:1: 13:2 + let mut _2: bool; // in scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 + let mut _3: !; // in scope 0 at $DIR/simplify_cfg.rs:9:18: 11:10 bb0: { - goto -> bb1; // scope 0 at $DIR/simplify_cfg.rs:+1:5: +5:6 + goto -> bb1; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 } bb1: { -- goto -> bb2; // scope 0 at $DIR/simplify_cfg.rs:+1:5: +5:6 +- goto -> bb2; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 - } - - bb2: { - StorageLive(_2); // scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17 -- _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17 -+ _2 = bar() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17 + StorageLive(_2); // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 +- _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 ++ _2 = bar() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 // mir::Constant // + span: $DIR/simplify_cfg.rs:9:12: 9:15 // + literal: Const { ty: fn() -> bool {bar}, val: Value() } } - bb3: { -- switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17 +- switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 + bb2: { -+ switchInt(move _2) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17 ++ switchInt(move _2) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 } - bb4: { + bb3: { - _0 = const (); // scope 0 at $DIR/simplify_cfg.rs:+3:13: +3:18 - StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:+4:9: +4:10 - return; // scope 0 at $DIR/simplify_cfg.rs:+6:2: +6:2 + _0 = const (); // scope 0 at $DIR/simplify_cfg.rs:10:13: 10:18 + StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10 + return; // scope 0 at $DIR/simplify_cfg.rs:13:2: 13:2 } - bb5: { + bb4: { - _1 = const (); // scope 0 at $DIR/simplify_cfg.rs:+4:10: +4:10 - StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:+4:9: +4:10 - goto -> bb1; // scope 0 at $DIR/simplify_cfg.rs:+1:5: +5:6 + _1 = const (); // scope 0 at $DIR/simplify_cfg.rs:11:10: 11:10 + StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10 + goto -> bb1; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 } - bb6 (cleanup): { + bb5 (cleanup): { - resume; // scope 0 at $DIR/simplify_cfg.rs:+0:1: +6:2 + resume; // scope 0 at $DIR/simplify_cfg.rs:7:1: 13:2 } } diff --git a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff index f693798eb942d..78841d28b85b1 100644 --- a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff +++ b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff @@ -2,70 +2,70 @@ + // MIR for `main` after SimplifyCfg-initial fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify_cfg.rs:+0:11: +0:11 - let mut _1: (); // in scope 0 at $DIR/simplify_cfg.rs:+0:1: +6:2 - let mut _2: bool; // in scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17 - let mut _3: !; // in scope 0 at $DIR/simplify_cfg.rs:+2:18: +4:10 + let mut _0: (); // return place in scope 0 at $DIR/simplify_cfg.rs:7:11: 7:11 + let mut _1: (); // in scope 0 at $DIR/simplify_cfg.rs:7:1: 13:2 + let mut _2: bool; // in scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 + let mut _3: !; // in scope 0 at $DIR/simplify_cfg.rs:9:18: 11:10 bb0: { - goto -> bb1; // scope 0 at $DIR/simplify_cfg.rs:+1:5: +5:6 + goto -> bb1; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 } bb1: { -- falseUnwind -> [real: bb2, cleanup: bb11]; // scope 0 at $DIR/simplify_cfg.rs:+1:5: +5:6 -+ falseUnwind -> [real: bb2, cleanup: bb6]; // scope 0 at $DIR/simplify_cfg.rs:+1:5: +5:6 +- falseUnwind -> [real: bb2, cleanup: bb11]; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 ++ falseUnwind -> [real: bb2, cleanup: bb6]; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 } bb2: { - StorageLive(_2); // scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17 -- _2 = bar() -> [return: bb3, unwind: bb11]; // scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17 -+ _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17 + StorageLive(_2); // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 +- _2 = bar() -> [return: bb3, unwind: bb11]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 ++ _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 // mir::Constant // + span: $DIR/simplify_cfg.rs:9:12: 9:15 // + literal: Const { ty: fn() -> bool {bar}, val: Value() } } bb3: { - switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17 + switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 } bb4: { - _0 = const (); // scope 0 at $DIR/simplify_cfg.rs:+3:13: +3:18 -- goto -> bb10; // scope 0 at $DIR/simplify_cfg.rs:+3:13: +3:18 -+ StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:+4:9: +4:10 -+ return; // scope 0 at $DIR/simplify_cfg.rs:+6:2: +6:2 + _0 = const (); // scope 0 at $DIR/simplify_cfg.rs:10:13: 10:18 +- goto -> bb10; // scope 0 at $DIR/simplify_cfg.rs:10:13: 10:18 ++ StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10 ++ return; // scope 0 at $DIR/simplify_cfg.rs:13:2: 13:2 } bb5: { -- goto -> bb8; // scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17 +- goto -> bb8; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 - } - - bb6: { -- unreachable; // scope 0 at $DIR/simplify_cfg.rs:+2:18: +4:10 +- unreachable; // scope 0 at $DIR/simplify_cfg.rs:9:18: 11:10 - } - - bb7: { -- goto -> bb9; // scope 0 at $DIR/simplify_cfg.rs:+2:9: +4:10 +- goto -> bb9; // scope 0 at $DIR/simplify_cfg.rs:9:9: 11:10 - } - - bb8: { - _1 = const (); // scope 0 at $DIR/simplify_cfg.rs:+4:10: +4:10 -- goto -> bb9; // scope 0 at $DIR/simplify_cfg.rs:+2:9: +4:10 + _1 = const (); // scope 0 at $DIR/simplify_cfg.rs:11:10: 11:10 +- goto -> bb9; // scope 0 at $DIR/simplify_cfg.rs:9:9: 11:10 - } - - bb9: { - StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:+4:9: +4:10 - goto -> bb1; // scope 0 at $DIR/simplify_cfg.rs:+1:5: +5:6 + StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10 + goto -> bb1; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 } - bb10: { -- StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:+4:9: +4:10 -- return; // scope 0 at $DIR/simplify_cfg.rs:+6:2: +6:2 +- StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10 +- return; // scope 0 at $DIR/simplify_cfg.rs:13:2: 13:2 - } - - bb11 (cleanup): { + bb6 (cleanup): { - resume; // scope 0 at $DIR/simplify_cfg.rs:+0:1: +6:2 + resume; // scope 0 at $DIR/simplify_cfg.rs:7:1: 13:2 } } diff --git a/src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff b/src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff index 9b1bea2704b77..f729b53b20410 100644 --- a/src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff +++ b/src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff @@ -2,39 +2,39 @@ + // MIR for `main` after SimplifyConstCondition-after-const-prop fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify_if.rs:+0:11: +0:11 - let mut _1: bool; // in scope 0 at $DIR/simplify_if.rs:+1:8: +1:13 - let _2: (); // in scope 0 at $DIR/simplify_if.rs:+2:9: +2:15 + let mut _0: (); // return place in scope 0 at $DIR/simplify_if.rs:5:11: 5:11 + let mut _1: bool; // in scope 0 at $DIR/simplify_if.rs:6:8: 6:13 + let _2: (); // in scope 0 at $DIR/simplify_if.rs:7:9: 7:15 bb0: { - StorageLive(_1); // scope 0 at $DIR/simplify_if.rs:+1:8: +1:13 - _1 = const false; // scope 0 at $DIR/simplify_if.rs:+1:8: +1:13 -- switchInt(const false) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/simplify_if.rs:+1:8: +1:13 -+ goto -> bb3; // scope 0 at $DIR/simplify_if.rs:+1:8: +1:13 + StorageLive(_1); // scope 0 at $DIR/simplify_if.rs:6:8: 6:13 + _1 = const false; // scope 0 at $DIR/simplify_if.rs:6:8: 6:13 +- switchInt(const false) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/simplify_if.rs:6:8: 6:13 ++ goto -> bb3; // scope 0 at $DIR/simplify_if.rs:6:8: 6:13 } bb1: { - StorageLive(_2); // scope 0 at $DIR/simplify_if.rs:+2:9: +2:15 - _2 = noop() -> bb2; // scope 0 at $DIR/simplify_if.rs:+2:9: +2:15 + StorageLive(_2); // scope 0 at $DIR/simplify_if.rs:7:9: 7:15 + _2 = noop() -> bb2; // scope 0 at $DIR/simplify_if.rs:7:9: 7:15 // mir::Constant // + span: $DIR/simplify_if.rs:7:9: 7:13 // + literal: Const { ty: fn() {noop}, val: Value() } } bb2: { - StorageDead(_2); // scope 0 at $DIR/simplify_if.rs:+2:15: +2:16 - nop; // scope 0 at $DIR/simplify_if.rs:+1:14: +3:6 - goto -> bb4; // scope 0 at $DIR/simplify_if.rs:+1:5: +3:6 + StorageDead(_2); // scope 0 at $DIR/simplify_if.rs:7:15: 7:16 + nop; // scope 0 at $DIR/simplify_if.rs:6:14: 8:6 + goto -> bb4; // scope 0 at $DIR/simplify_if.rs:6:5: 8:6 } bb3: { - nop; // scope 0 at $DIR/simplify_if.rs:+3:6: +3:6 - goto -> bb4; // scope 0 at $DIR/simplify_if.rs:+1:5: +3:6 + nop; // scope 0 at $DIR/simplify_if.rs:8:6: 8:6 + goto -> bb4; // scope 0 at $DIR/simplify_if.rs:6:5: 8:6 } bb4: { - StorageDead(_1); // scope 0 at $DIR/simplify_if.rs:+3:5: +3:6 - return; // scope 0 at $DIR/simplify_if.rs:+4:2: +4:2 + StorageDead(_1); // scope 0 at $DIR/simplify_if.rs:8:5: 8:6 + return; // scope 0 at $DIR/simplify_if.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/simplify_locals.c.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.c.SimplifyLocals.diff index 5d7517e4eb43c..dd2d795496123 100644 --- a/src/test/mir-opt/simplify_locals.c.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals.c.SimplifyLocals.diff @@ -2,32 +2,32 @@ + // MIR for `c` after SimplifyLocals fn c() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:+0:8: +0:8 - let _1: [u8; 10]; // in scope 0 at $DIR/simplify-locals.rs:+1:9: +1:14 -- let mut _2: &[u8]; // in scope 0 at $DIR/simplify-locals.rs:+3:20: +3:26 -- let mut _3: &[u8; 10]; // in scope 0 at $DIR/simplify-locals.rs:+3:20: +3:26 -- let _4: &[u8; 10]; // in scope 0 at $DIR/simplify-locals.rs:+3:20: +3:26 + let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:13:8: 13:8 + let _1: [u8; 10]; // in scope 0 at $DIR/simplify-locals.rs:14:9: 14:14 +- let mut _2: &[u8]; // in scope 0 at $DIR/simplify-locals.rs:16:20: 16:26 +- let mut _3: &[u8; 10]; // in scope 0 at $DIR/simplify-locals.rs:16:20: 16:26 +- let _4: &[u8; 10]; // in scope 0 at $DIR/simplify-locals.rs:16:20: 16:26 scope 1 { - debug bytes => _1; // in scope 1 at $DIR/simplify-locals.rs:+1:9: +1:14 + debug bytes => _1; // in scope 1 at $DIR/simplify-locals.rs:14:9: 14:14 scope 2 { } } bb0: { - StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:+1:9: +1:14 - _1 = [const 0_u8; 10]; // scope 0 at $DIR/simplify-locals.rs:+1:17: +1:26 -- StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:+3:20: +3:26 -- StorageLive(_3); // scope 1 at $DIR/simplify-locals.rs:+3:20: +3:26 -- StorageLive(_4); // scope 1 at $DIR/simplify-locals.rs:+3:20: +3:26 -- _4 = &_1; // scope 1 at $DIR/simplify-locals.rs:+3:20: +3:26 -- _3 = &(*_4); // scope 1 at $DIR/simplify-locals.rs:+3:20: +3:26 -- _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 1 at $DIR/simplify-locals.rs:+3:20: +3:26 -- StorageDead(_3); // scope 1 at $DIR/simplify-locals.rs:+3:25: +3:26 -- StorageDead(_4); // scope 1 at $DIR/simplify-locals.rs:+3:26: +3:27 -- StorageDead(_2); // scope 1 at $DIR/simplify-locals.rs:+3:26: +3:27 - _0 = const (); // scope 0 at $DIR/simplify-locals.rs:+0:8: +4:2 - StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:+4:1: +4:2 - return; // scope 0 at $DIR/simplify-locals.rs:+4:2: +4:2 + StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:14:9: 14:14 + _1 = [const 0_u8; 10]; // scope 0 at $DIR/simplify-locals.rs:14:17: 14:26 +- StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:16:20: 16:26 +- StorageLive(_3); // scope 1 at $DIR/simplify-locals.rs:16:20: 16:26 +- StorageLive(_4); // scope 1 at $DIR/simplify-locals.rs:16:20: 16:26 +- _4 = &_1; // scope 1 at $DIR/simplify-locals.rs:16:20: 16:26 +- _3 = &(*_4); // scope 1 at $DIR/simplify-locals.rs:16:20: 16:26 +- _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 1 at $DIR/simplify-locals.rs:16:20: 16:26 +- StorageDead(_3); // scope 1 at $DIR/simplify-locals.rs:16:25: 16:26 +- StorageDead(_4); // scope 1 at $DIR/simplify-locals.rs:16:26: 16:27 +- StorageDead(_2); // scope 1 at $DIR/simplify-locals.rs:16:26: 16:27 + _0 = const (); // scope 0 at $DIR/simplify-locals.rs:13:8: 17:2 + StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:17:1: 17:2 + return; // scope 0 at $DIR/simplify-locals.rs:17:2: 17:2 } } diff --git a/src/test/mir-opt/simplify_locals.d1.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.d1.SimplifyLocals.diff index a9ea8869a9698..3be73ecfcb812 100644 --- a/src/test/mir-opt/simplify_locals.d1.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals.d1.SimplifyLocals.diff @@ -2,18 +2,18 @@ + // MIR for `d1` after SimplifyLocals fn d1() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:+0:9: +0:9 -- let mut _1: E; // in scope 0 at $DIR/simplify-locals.rs:+2:13: +2:17 + let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:20:9: 20:9 +- let mut _1: E; // in scope 0 at $DIR/simplify-locals.rs:22:13: 22:17 scope 1 { } bb0: { -- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:+2:13: +2:17 -- Deinit(_1); // scope 0 at $DIR/simplify-locals.rs:+2:13: +2:17 -- discriminant(_1) = 0; // scope 0 at $DIR/simplify-locals.rs:+2:13: +2:17 -- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:+2:17: +2:18 - _0 = const (); // scope 0 at $DIR/simplify-locals.rs:+0:9: +3:2 - return; // scope 0 at $DIR/simplify-locals.rs:+3:2: +3:2 +- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:22:13: 22:17 +- Deinit(_1); // scope 0 at $DIR/simplify-locals.rs:22:13: 22:17 +- discriminant(_1) = 0; // scope 0 at $DIR/simplify-locals.rs:22:13: 22:17 +- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:22:17: 22:18 + _0 = const (); // scope 0 at $DIR/simplify-locals.rs:20:9: 23:2 + return; // scope 0 at $DIR/simplify-locals.rs:23:2: 23:2 } } diff --git a/src/test/mir-opt/simplify_locals.d2.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.d2.SimplifyLocals.diff index 6a89e45843b9b..641f64fd9b7cd 100644 --- a/src/test/mir-opt/simplify_locals.d2.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals.d2.SimplifyLocals.diff @@ -2,28 +2,28 @@ + // MIR for `d2` after SimplifyLocals fn d2() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:+0:9: +0:9 -- let mut _1: E; // in scope 0 at $DIR/simplify-locals.rs:+2:22: +2:26 -- let mut _2: (i32, E); // in scope 0 at $DIR/simplify-locals.rs:+2:5: +2:17 -- let mut _3: E; // in scope 0 at $DIR/simplify-locals.rs:+2:11: +2:15 + let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:26:9: 26:9 +- let mut _1: E; // in scope 0 at $DIR/simplify-locals.rs:28:22: 28:26 +- let mut _2: (i32, E); // in scope 0 at $DIR/simplify-locals.rs:28:5: 28:17 +- let mut _3: E; // in scope 0 at $DIR/simplify-locals.rs:28:11: 28:15 bb0: { -- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:+2:22: +2:26 -- Deinit(_1); // scope 0 at $DIR/simplify-locals.rs:+2:22: +2:26 -- discriminant(_1) = 1; // scope 0 at $DIR/simplify-locals.rs:+2:22: +2:26 -- StorageLive(_2); // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:17 -- StorageLive(_3); // scope 0 at $DIR/simplify-locals.rs:+2:11: +2:15 -- Deinit(_3); // scope 0 at $DIR/simplify-locals.rs:+2:11: +2:15 -- discriminant(_3) = 0; // scope 0 at $DIR/simplify-locals.rs:+2:11: +2:15 -- Deinit(_2); // scope 0 at $DIR/simplify-locals.rs:+2:6: +2:16 -- (_2.0: i32) = const 10_i32; // scope 0 at $DIR/simplify-locals.rs:+2:6: +2:16 -- (_2.1: E) = move _3; // scope 0 at $DIR/simplify-locals.rs:+2:6: +2:16 -- StorageDead(_3); // scope 0 at $DIR/simplify-locals.rs:+2:15: +2:16 -- (_2.1: E) = move _1; // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:26 -- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:+2:25: +2:26 -- StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:+2:26: +2:27 - _0 = const (); // scope 0 at $DIR/simplify-locals.rs:+0:9: +3:2 - return; // scope 0 at $DIR/simplify-locals.rs:+3:2: +3:2 +- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:28:22: 28:26 +- Deinit(_1); // scope 0 at $DIR/simplify-locals.rs:28:22: 28:26 +- discriminant(_1) = 1; // scope 0 at $DIR/simplify-locals.rs:28:22: 28:26 +- StorageLive(_2); // scope 0 at $DIR/simplify-locals.rs:28:5: 28:17 +- StorageLive(_3); // scope 0 at $DIR/simplify-locals.rs:28:11: 28:15 +- Deinit(_3); // scope 0 at $DIR/simplify-locals.rs:28:11: 28:15 +- discriminant(_3) = 0; // scope 0 at $DIR/simplify-locals.rs:28:11: 28:15 +- Deinit(_2); // scope 0 at $DIR/simplify-locals.rs:28:6: 28:16 +- (_2.0: i32) = const 10_i32; // scope 0 at $DIR/simplify-locals.rs:28:6: 28:16 +- (_2.1: E) = move _3; // scope 0 at $DIR/simplify-locals.rs:28:6: 28:16 +- StorageDead(_3); // scope 0 at $DIR/simplify-locals.rs:28:15: 28:16 +- (_2.1: E) = move _1; // scope 0 at $DIR/simplify-locals.rs:28:5: 28:26 +- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:28:25: 28:26 +- StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:28:26: 28:27 + _0 = const (); // scope 0 at $DIR/simplify-locals.rs:26:9: 29:2 + return; // scope 0 at $DIR/simplify-locals.rs:29:2: 29:2 } } diff --git a/src/test/mir-opt/simplify_locals.expose_addr.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.expose_addr.SimplifyLocals.diff index 204a1bffc81ab..93d77ad40aa4b 100644 --- a/src/test/mir-opt/simplify_locals.expose_addr.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals.expose_addr.SimplifyLocals.diff @@ -2,20 +2,20 @@ + // MIR for `expose_addr` after SimplifyLocals fn expose_addr(_1: *const usize) -> () { - debug p => _1; // in scope 0 at $DIR/simplify-locals.rs:+0:16: +0:17 - let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:+0:33: +0:33 - let _2: usize; // in scope 0 at $DIR/simplify-locals.rs:+2:5: +2:15 - let mut _3: *const usize; // in scope 0 at $DIR/simplify-locals.rs:+2:5: +2:6 + debug p => _1; // in scope 0 at $DIR/simplify-locals.rs:66:16: 66:17 + let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:66:33: 66:33 + let _2: usize; // in scope 0 at $DIR/simplify-locals.rs:68:5: 68:15 + let mut _3: *const usize; // in scope 0 at $DIR/simplify-locals.rs:68:5: 68:6 bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:15 - StorageLive(_3); // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:6 - _3 = _1; // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:6 - _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:15 - StorageDead(_3); // scope 0 at $DIR/simplify-locals.rs:+2:14: +2:15 - StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:+2:15: +2:16 - _0 = const (); // scope 0 at $DIR/simplify-locals.rs:+0:33: +3:2 - return; // scope 0 at $DIR/simplify-locals.rs:+3:2: +3:2 + StorageLive(_2); // scope 0 at $DIR/simplify-locals.rs:68:5: 68:15 + StorageLive(_3); // scope 0 at $DIR/simplify-locals.rs:68:5: 68:6 + _3 = _1; // scope 0 at $DIR/simplify-locals.rs:68:5: 68:6 + _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/simplify-locals.rs:68:5: 68:15 + StorageDead(_3); // scope 0 at $DIR/simplify-locals.rs:68:14: 68:15 + StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:68:15: 68:16 + _0 = const (); // scope 0 at $DIR/simplify-locals.rs:66:33: 69:2 + return; // scope 0 at $DIR/simplify-locals.rs:69:2: 69:2 } } diff --git a/src/test/mir-opt/simplify_locals.r.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.r.SimplifyLocals.diff index 329e2a65a0d0f..85cf398d31693 100644 --- a/src/test/mir-opt/simplify_locals.r.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals.r.SimplifyLocals.diff @@ -2,12 +2,12 @@ + // MIR for `r` after SimplifyLocals fn r() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:+0:8: +0:8 - let mut _1: i32; // in scope 0 at $DIR/simplify-locals.rs:+1:9: +1:14 -- let mut _2: &i32; // in scope 0 at $DIR/simplify-locals.rs:+3:13: +3:15 -- let mut _3: &mut i32; // in scope 0 at $DIR/simplify-locals.rs:+4:13: +4:19 + let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:32:8: 32:8 + let mut _1: i32; // in scope 0 at $DIR/simplify-locals.rs:33:9: 33:14 +- let mut _2: &i32; // in scope 0 at $DIR/simplify-locals.rs:35:13: 35:15 +- let mut _3: &mut i32; // in scope 0 at $DIR/simplify-locals.rs:36:13: 36:19 scope 1 { - debug a => _1; // in scope 1 at $DIR/simplify-locals.rs:+1:9: +1:14 + debug a => _1; // in scope 1 at $DIR/simplify-locals.rs:33:9: 33:14 scope 2 { scope 3 { } @@ -15,17 +15,17 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:+1:9: +1:14 - _1 = const 1_i32; // scope 0 at $DIR/simplify-locals.rs:+1:17: +1:18 -- StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:+3:13: +3:15 -- _2 = &_1; // scope 1 at $DIR/simplify-locals.rs:+3:13: +3:15 -- StorageDead(_2); // scope 1 at $DIR/simplify-locals.rs:+3:15: +3:16 -- StorageLive(_3); // scope 2 at $DIR/simplify-locals.rs:+4:13: +4:19 -- _3 = &mut _1; // scope 2 at $DIR/simplify-locals.rs:+4:13: +4:19 -- StorageDead(_3); // scope 2 at $DIR/simplify-locals.rs:+4:19: +4:20 - _0 = const (); // scope 0 at $DIR/simplify-locals.rs:+0:8: +5:2 - StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:+5:1: +5:2 - return; // scope 0 at $DIR/simplify-locals.rs:+5:2: +5:2 + StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:33:9: 33:14 + _1 = const 1_i32; // scope 0 at $DIR/simplify-locals.rs:33:17: 33:18 +- StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:35:13: 35:15 +- _2 = &_1; // scope 1 at $DIR/simplify-locals.rs:35:13: 35:15 +- StorageDead(_2); // scope 1 at $DIR/simplify-locals.rs:35:15: 35:16 +- StorageLive(_3); // scope 2 at $DIR/simplify-locals.rs:36:13: 36:19 +- _3 = &mut _1; // scope 2 at $DIR/simplify-locals.rs:36:13: 36:19 +- StorageDead(_3); // scope 2 at $DIR/simplify-locals.rs:36:19: 36:20 + _0 = const (); // scope 0 at $DIR/simplify-locals.rs:32:8: 37:2 + StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:37:1: 37:2 + return; // scope 0 at $DIR/simplify-locals.rs:37:2: 37:2 } } diff --git a/src/test/mir-opt/simplify_locals.t1.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.t1.SimplifyLocals.diff index b31156ad6977e..991a0721cca30 100644 --- a/src/test/mir-opt/simplify_locals.t1.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals.t1.SimplifyLocals.diff @@ -2,21 +2,21 @@ + // MIR for `t1` after SimplifyLocals fn t1() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:+0:9: +0:9 -- let _1: u32; // in scope 0 at $DIR/simplify-locals.rs:+2:14: +2:15 -- let mut _2: *mut u32; // in scope 0 at $DIR/simplify-locals.rs:+2:14: +2:15 + let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:42:9: 42:9 +- let _1: u32; // in scope 0 at $DIR/simplify-locals.rs:44:14: 44:15 +- let mut _2: *mut u32; // in scope 0 at $DIR/simplify-locals.rs:44:14: 44:15 scope 1 { } bb0: { -- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:17 -- StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:15 -- _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:15 -- _1 = (*_2); // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:15 -- StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:+2:17: +2:18 -- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:+2:17: +2:18 - _0 = const (); // scope 0 at $DIR/simplify-locals.rs:+0:9: +3:2 - return; // scope 0 at $DIR/simplify-locals.rs:+3:2: +3:2 +- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:44:5: 44:17 +- StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:44:14: 44:15 +- _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify-locals.rs:44:14: 44:15 +- _1 = (*_2); // scope 1 at $DIR/simplify-locals.rs:44:14: 44:15 +- StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:44:17: 44:18 +- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:44:17: 44:18 + _0 = const (); // scope 0 at $DIR/simplify-locals.rs:42:9: 45:2 + return; // scope 0 at $DIR/simplify-locals.rs:45:2: 45:2 } } diff --git a/src/test/mir-opt/simplify_locals.t2.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.t2.SimplifyLocals.diff index 66b6d8d648647..6c9ed96e78ffe 100644 --- a/src/test/mir-opt/simplify_locals.t2.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals.t2.SimplifyLocals.diff @@ -2,21 +2,21 @@ + // MIR for `t2` after SimplifyLocals fn t2() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:+0:9: +0:9 -- let _1: &mut u32; // in scope 0 at $DIR/simplify-locals.rs:+2:14: +2:20 -- let mut _2: *mut u32; // in scope 0 at $DIR/simplify-locals.rs:+2:19: +2:20 + let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:48:9: 48:9 +- let _1: &mut u32; // in scope 0 at $DIR/simplify-locals.rs:50:14: 50:20 +- let mut _2: *mut u32; // in scope 0 at $DIR/simplify-locals.rs:50:19: 50:20 scope 1 { } bb0: { -- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:22 -- StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:+2:19: +2:20 -- _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify-locals.rs:+2:19: +2:20 -- _1 = &mut (*_2); // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:20 -- StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:+2:22: +2:23 -- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:+2:22: +2:23 - _0 = const (); // scope 0 at $DIR/simplify-locals.rs:+0:9: +3:2 - return; // scope 0 at $DIR/simplify-locals.rs:+3:2: +3:2 +- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:50:5: 50:22 +- StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:50:19: 50:20 +- _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify-locals.rs:50:19: 50:20 +- _1 = &mut (*_2); // scope 1 at $DIR/simplify-locals.rs:50:14: 50:20 +- StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:50:22: 50:23 +- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:50:22: 50:23 + _0 = const (); // scope 0 at $DIR/simplify-locals.rs:48:9: 51:2 + return; // scope 0 at $DIR/simplify-locals.rs:51:2: 51:2 } } diff --git a/src/test/mir-opt/simplify_locals.t3.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.t3.SimplifyLocals.diff index f6b6b78cdfbeb..2d5fb352f8be3 100644 --- a/src/test/mir-opt/simplify_locals.t3.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals.t3.SimplifyLocals.diff @@ -2,25 +2,25 @@ + // MIR for `t3` after SimplifyLocals fn t3() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:+0:9: +0:9 -- let _1: u32; // in scope 0 at $DIR/simplify-locals.rs:+2:14: +2:21 -- let mut _2: &mut u32; // in scope 0 at $DIR/simplify-locals.rs:+2:15: +2:21 -- let mut _3: *mut u32; // in scope 0 at $DIR/simplify-locals.rs:+2:20: +2:21 + let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:54:9: 54:9 +- let _1: u32; // in scope 0 at $DIR/simplify-locals.rs:56:14: 56:21 +- let mut _2: &mut u32; // in scope 0 at $DIR/simplify-locals.rs:56:15: 56:21 +- let mut _3: *mut u32; // in scope 0 at $DIR/simplify-locals.rs:56:20: 56:21 scope 1 { } bb0: { -- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:23 -- StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:+2:15: +2:21 -- StorageLive(_3); // scope 1 at $DIR/simplify-locals.rs:+2:20: +2:21 -- _3 = &/*tls*/ mut X; // scope 1 at $DIR/simplify-locals.rs:+2:20: +2:21 -- _2 = &mut (*_3); // scope 1 at $DIR/simplify-locals.rs:+2:15: +2:21 -- _1 = (*_2); // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:21 -- StorageDead(_3); // scope 0 at $DIR/simplify-locals.rs:+2:23: +2:24 -- StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:+2:23: +2:24 -- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:+2:23: +2:24 - _0 = const (); // scope 0 at $DIR/simplify-locals.rs:+0:9: +3:2 - return; // scope 0 at $DIR/simplify-locals.rs:+3:2: +3:2 +- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:56:5: 56:23 +- StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:56:15: 56:21 +- StorageLive(_3); // scope 1 at $DIR/simplify-locals.rs:56:20: 56:21 +- _3 = &/*tls*/ mut X; // scope 1 at $DIR/simplify-locals.rs:56:20: 56:21 +- _2 = &mut (*_3); // scope 1 at $DIR/simplify-locals.rs:56:15: 56:21 +- _1 = (*_2); // scope 1 at $DIR/simplify-locals.rs:56:14: 56:21 +- StorageDead(_3); // scope 0 at $DIR/simplify-locals.rs:56:23: 56:24 +- StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:56:23: 56:24 +- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:56:23: 56:24 + _0 = const (); // scope 0 at $DIR/simplify-locals.rs:54:9: 57:2 + return; // scope 0 at $DIR/simplify-locals.rs:57:2: 57:2 } } diff --git a/src/test/mir-opt/simplify_locals.t4.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.t4.SimplifyLocals.diff index 1c1da29aa678f..e0e9b3ef4062a 100644 --- a/src/test/mir-opt/simplify_locals.t4.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals.t4.SimplifyLocals.diff @@ -2,21 +2,21 @@ + // MIR for `t4` after SimplifyLocals fn t4() -> u32 { - let mut _0: u32; // return place in scope 0 at $DIR/simplify-locals.rs:+0:12: +0:15 - let mut _1: u32; // in scope 0 at $DIR/simplify-locals.rs:+2:14: +2:15 - let mut _2: *mut u32; // in scope 0 at $DIR/simplify-locals.rs:+2:14: +2:15 + let mut _0: u32; // return place in scope 0 at $DIR/simplify-locals.rs:60:12: 60:15 + let mut _1: u32; // in scope 0 at $DIR/simplify-locals.rs:62:14: 62:15 + let mut _2: *mut u32; // in scope 0 at $DIR/simplify-locals.rs:62:14: 62:15 scope 1 { } bb0: { - StorageLive(_1); // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:15 - StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:15 - _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:15 - _1 = (*_2); // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:15 - _0 = Add(move _1, const 1_u32); // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:19 - StorageDead(_1); // scope 1 at $DIR/simplify-locals.rs:+2:18: +2:19 - StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:+3:1: +3:2 - return; // scope 0 at $DIR/simplify-locals.rs:+3:2: +3:2 + StorageLive(_1); // scope 1 at $DIR/simplify-locals.rs:62:14: 62:15 + StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:62:14: 62:15 + _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify-locals.rs:62:14: 62:15 + _1 = (*_2); // scope 1 at $DIR/simplify-locals.rs:62:14: 62:15 + _0 = Add(move _1, const 1_u32); // scope 1 at $DIR/simplify-locals.rs:62:14: 62:19 + StorageDead(_1); // scope 1 at $DIR/simplify-locals.rs:62:18: 62:19 + StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:63:1: 63:2 + return; // scope 0 at $DIR/simplify-locals.rs:63:2: 63:2 } } diff --git a/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff index ac7a47ba58f7b..075fe8d090829 100644 --- a/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff @@ -2,61 +2,61 @@ + // MIR for `foo` after SimplifyLocals fn foo() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify-locals-fixedpoint.rs:+0:13: +0:13 - let mut _1: (std::option::Option, std::option::Option); // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:+1:30: +1:69 - let mut _2: std::option::Option; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:+1:31: +1:49 - let mut _3: std::option::Option; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:+1:51: +1:68 - let mut _4: isize; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:+1:22: +1:26 - let mut _5: isize; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:+1:13: +1:20 -- let mut _7: bool; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:+2:12: +2:20 -- let mut _8: u8; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:+2:12: +2:13 + let mut _0: (); // return place in scope 0 at $DIR/simplify-locals-fixedpoint.rs:3:13: 3:13 + let mut _1: (std::option::Option, std::option::Option); // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:30: 4:69 + let mut _2: std::option::Option; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:31: 4:49 + let mut _3: std::option::Option; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:51: 4:68 + let mut _4: isize; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26 + let mut _5: isize; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20 +- let mut _7: bool; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20 +- let mut _8: u8; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13 scope 1 { - debug a => _6; // in scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:18: +1:19 - let _6: u8; // in scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:18: +1:19 + debug a => _6; // in scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19 + let _6: u8; // in scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19 } bb0: { - StorageLive(_1); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:30: +1:69 - StorageLive(_2); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:31: +1:49 - Deinit(_2); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:31: +1:49 - discriminant(_2) = 0; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:31: +1:49 - StorageLive(_3); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:51: +1:68 - Deinit(_3); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:51: +1:68 - discriminant(_3) = 0; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:51: +1:68 - Deinit(_1); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:30: +1:69 - (_1.0: std::option::Option) = move _2; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:30: +1:69 - (_1.1: std::option::Option) = move _3; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:30: +1:69 - StorageDead(_3); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:68: +1:69 - StorageDead(_2); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:68: +1:69 - _5 = discriminant((_1.0: std::option::Option)); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:12: +1:27 - switchInt(move _5) -> [1_isize: bb1, otherwise: bb3]; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:12: +1:27 + StorageLive(_1); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:30: 4:69 + StorageLive(_2); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:31: 4:49 + Deinit(_2); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:31: 4:49 + discriminant(_2) = 0; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:31: 4:49 + StorageLive(_3); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:51: 4:68 + Deinit(_3); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:51: 4:68 + discriminant(_3) = 0; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:51: 4:68 + Deinit(_1); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:30: 4:69 + (_1.0: std::option::Option) = move _2; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:30: 4:69 + (_1.1: std::option::Option) = move _3; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:30: 4:69 + StorageDead(_3); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:68: 4:69 + StorageDead(_2); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:68: 4:69 + _5 = discriminant((_1.0: std::option::Option)); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:12: 4:27 + switchInt(move _5) -> [1_isize: bb1, otherwise: bb3]; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:12: 4:27 } bb1: { - _4 = discriminant((_1.1: std::option::Option)); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:12: +1:27 - switchInt(move _4) -> [0_isize: bb2, otherwise: bb3]; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:12: +1:27 + _4 = discriminant((_1.1: std::option::Option)); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:12: 4:27 + switchInt(move _4) -> [0_isize: bb2, otherwise: bb3]; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:12: 4:27 } bb2: { - StorageLive(_6); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:18: +1:19 - _6 = (((_1.0: std::option::Option) as Some).0: u8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:18: +1:19 -- StorageLive(_7); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+2:12: +2:20 -- StorageLive(_8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+2:12: +2:13 -- _8 = _6; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+2:12: +2:13 -- _7 = Gt(move _8, const 42_u8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+2:12: +2:20 -- StorageDead(_8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+2:19: +2:20 -- StorageDead(_7); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+4:9: +4:10 - StorageDead(_6); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:+5:5: +5:6 - goto -> bb3; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:+1:5: +5:6 + StorageLive(_6); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19 + _6 = (((_1.0: std::option::Option) as Some).0: u8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19 +- StorageLive(_7); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20 +- StorageLive(_8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13 +- _8 = _6; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13 +- _7 = Gt(move _8, const 42_u8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20 +- StorageDead(_8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:19: 5:20 +- StorageDead(_7); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:7:9: 7:10 + StorageDead(_6); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:8:5: 8:6 + goto -> bb3; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:5: 8:6 } bb3: { - drop(_1) -> bb4; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:+6:1: +6:2 + drop(_1) -> bb4; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:1: 9:2 } bb4: { - StorageDead(_1); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:+6:1: +6:2 - return; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:+6:2: +6:2 + StorageDead(_1); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:1: 9:2 + return; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff index da2f6fc440aa2..f4f1b9d4eb87e 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff @@ -2,70 +2,70 @@ + // MIR for `main` after SimplifyLocals fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+0:11: +0:11 -- let mut _1: ((), ()); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28 -- let mut _2: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:21: +1:23 -- let mut _3: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:25: +1:27 -- let _4: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22 -- let mut _5: ((), ()); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21 -- let mut _6: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16 -- let mut _7: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20 -- let _8: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35 -- let mut _9: u8; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34 -- let mut _10: u8; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30 -- let mut _11: Temp; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28 -+ let _1: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22 -+ let mut _2: ((), ()); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21 -+ let _3: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35 + let mut _0: (); // return place in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:12:11: 12:11 +- let mut _1: ((), ()); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:20: 13:28 +- let mut _2: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:21: 13:23 +- let mut _3: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:25: 13:27 +- let _4: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 +- let mut _5: ((), ()); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 +- let mut _6: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:14:14: 14:16 +- let mut _7: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:14:18: 14:20 +- let _8: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 +- let mut _9: u8; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34 +- let mut _10: u8; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30 +- let mut _11: Temp; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28 ++ let _1: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 ++ let mut _2: ((), ()); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 ++ let _3: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 scope 1 { } bb0: { -- StorageLive(_1); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28 -- StorageLive(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:21: +1:23 -- StorageLive(_3); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:25: +1:27 -- StorageDead(_3); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:27: +1:28 -- StorageDead(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:27: +1:28 -- StorageDead(_1); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:28: +1:29 -- StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22 -- StorageLive(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21 -- StorageLive(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16 -- StorageLive(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20 -- StorageDead(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21 -- StorageDead(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21 -- _4 = use_zst(move _5) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22 -+ StorageLive(_1); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22 -+ StorageLive(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21 -+ _1 = use_zst(move _2) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22 +- StorageLive(_1); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:20: 13:28 +- StorageLive(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:21: 13:23 +- StorageLive(_3); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:25: 13:27 +- StorageDead(_3); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:27: 13:28 +- StorageDead(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:27: 13:28 +- StorageDead(_1); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:28: 13:29 +- StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 +- StorageLive(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 +- StorageLive(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:14: 14:16 +- StorageLive(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:18: 14:20 +- StorageDead(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:20: 14:21 +- StorageDead(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:20: 14:21 +- _4 = use_zst(move _5) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 ++ StorageLive(_1); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 ++ StorageLive(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 ++ _1 = use_zst(move _2) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 // mir::Constant // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:12 // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value() } } bb1: { -- StorageDead(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:21: +2:22 -- StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:22: +2:23 -- StorageLive(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35 -- StorageLive(_9); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34 -- StorageLive(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30 -- StorageLive(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28 -- StorageDead(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:33: +4:34 -- _8 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35 -+ StorageDead(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:21: +2:22 -+ StorageDead(_1); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:22: +2:23 -+ StorageLive(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35 -+ _3 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35 +- StorageDead(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:21: 14:22 +- StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:22: 14:23 +- StorageLive(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 +- StorageLive(_9); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34 +- StorageLive(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30 +- StorageLive(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28 +- StorageDead(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:33: 16:34 +- _8 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 ++ StorageDead(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:21: 14:22 ++ StorageDead(_1); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:22: 14:23 ++ StorageLive(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 ++ _3 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 // mir::Constant // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:11 // + literal: Const { ty: fn(u8) {use_u8}, val: Value() } } bb2: { -- StorageDead(_9); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:34: +4:35 -- StorageDead(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36 -- StorageDead(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36 -+ StorageDead(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36 - return; // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+5:2: +5:2 +- StorageDead(_9); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:34: 16:35 +- StorageDead(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36 +- StorageDead(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36 ++ StorageDead(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36 + return; // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:17:2: 17:2 } } diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff index c6895fa41bf65..fc1726f98cb1d 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff +++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff @@ -2,38 +2,38 @@ + // MIR for `map` after SimplifyLocals fn map(_1: Option>) -> Option> { - debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:8: +0:9 - let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:31: +0:46 - let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:9: +2:13 -- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 -- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26 -- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 -- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 -- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 + debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:8: 3:9 + let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:31: 3:46 + let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 +- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:25: 6:26 +- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 +- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 +- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 scope 1 { - debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 + debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 } bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:5: +1:12 + _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:11: 4:12 + switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:5: 4:12 } bb1: { - ((_0 as Some).0: std::boxed::Box<()>) = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 - Deinit(_0); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27 - discriminant(_0) = 1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27 - goto -> bb3; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27 + ((_0 as Some).0: std::boxed::Box<()>) = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 + Deinit(_0); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27 + discriminant(_0) = 1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27 + goto -> bb3; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:26: 6:27 } bb2: { - Deinit(_0); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21 - discriminant(_0) = 0; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21 - goto -> bb3; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21 + Deinit(_0); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:17: 5:21 + discriminant(_0) = 0; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:17: 5:21 + goto -> bb3; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:17: 5:21 } bb3: { - return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:2: +5:2 + return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff index c6895fa41bf65..fc1726f98cb1d 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff +++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff @@ -2,38 +2,38 @@ + // MIR for `map` after SimplifyLocals fn map(_1: Option>) -> Option> { - debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:8: +0:9 - let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:31: +0:46 - let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:9: +2:13 -- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 -- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26 -- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 -- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 -- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 + debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:8: 3:9 + let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:31: 3:46 + let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 +- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:25: 6:26 +- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 +- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 +- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 scope 1 { - debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 + debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 } bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:5: +1:12 + _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:11: 4:12 + switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:5: 4:12 } bb1: { - ((_0 as Some).0: std::boxed::Box<()>) = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 - Deinit(_0); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27 - discriminant(_0) = 1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27 - goto -> bb3; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27 + ((_0 as Some).0: std::boxed::Box<()>) = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 + Deinit(_0); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27 + discriminant(_0) = 1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27 + goto -> bb3; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:26: 6:27 } bb2: { - Deinit(_0); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21 - discriminant(_0) = 0; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21 - goto -> bb3; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21 + Deinit(_0); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:17: 5:21 + discriminant(_0) = 0; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:17: 5:21 + goto -> bb3; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:17: 5:21 } bb3: { - return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:2: +5:2 + return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/simplify_match.main.ConstProp.diff b/src/test/mir-opt/simplify_match.main.ConstProp.diff index e4f9a4c12d9cb..6314abe6f39db 100644 --- a/src/test/mir-opt/simplify_match.main.ConstProp.diff +++ b/src/test/mir-opt/simplify_match.main.ConstProp.diff @@ -2,39 +2,39 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify_match.rs:+0:11: +0:11 - let mut _1: bool; // in scope 0 at $DIR/simplify_match.rs:+1:11: +1:31 - let _2: bool; // in scope 0 at $DIR/simplify_match.rs:+1:17: +1:18 + let mut _0: (); // return place in scope 0 at $DIR/simplify_match.rs:5:11: 5:11 + let mut _1: bool; // in scope 0 at $DIR/simplify_match.rs:6:11: 6:31 + let _2: bool; // in scope 0 at $DIR/simplify_match.rs:6:17: 6:18 scope 1 { - debug x => _2; // in scope 1 at $DIR/simplify_match.rs:+1:17: +1:18 + debug x => _2; // in scope 1 at $DIR/simplify_match.rs:6:17: 6:18 } bb0: { - StorageLive(_1); // scope 0 at $DIR/simplify_match.rs:+1:11: +1:31 - StorageLive(_2); // scope 0 at $DIR/simplify_match.rs:+1:17: +1:18 - _2 = const false; // scope 0 at $DIR/simplify_match.rs:+1:21: +1:26 -- _1 = _2; // scope 1 at $DIR/simplify_match.rs:+1:28: +1:29 -+ _1 = const false; // scope 1 at $DIR/simplify_match.rs:+1:28: +1:29 - StorageDead(_2); // scope 0 at $DIR/simplify_match.rs:+1:30: +1:31 -- switchInt(_1) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31 -+ switchInt(const false) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31 + StorageLive(_1); // scope 0 at $DIR/simplify_match.rs:6:11: 6:31 + StorageLive(_2); // scope 0 at $DIR/simplify_match.rs:6:17: 6:18 + _2 = const false; // scope 0 at $DIR/simplify_match.rs:6:21: 6:26 +- _1 = _2; // scope 1 at $DIR/simplify_match.rs:6:28: 6:29 ++ _1 = const false; // scope 1 at $DIR/simplify_match.rs:6:28: 6:29 + StorageDead(_2); // scope 0 at $DIR/simplify_match.rs:6:30: 6:31 +- switchInt(_1) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:6:5: 6:31 ++ switchInt(const false) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:6:5: 6:31 } bb1: { - nop; // scope 0 at $DIR/simplify_match.rs:+3:18: +3:20 - goto -> bb3; // scope 0 at $DIR/simplify_match.rs:+3:18: +3:20 + nop; // scope 0 at $DIR/simplify_match.rs:8:18: 8:20 + goto -> bb3; // scope 0 at $DIR/simplify_match.rs:8:18: 8:20 } bb2: { - _0 = noop() -> bb3; // scope 0 at $DIR/simplify_match.rs:+2:17: +2:23 + _0 = noop() -> bb3; // scope 0 at $DIR/simplify_match.rs:7:17: 7:23 // mir::Constant // + span: $DIR/simplify_match.rs:7:17: 7:21 // + literal: Const { ty: fn() {noop}, val: Value() } } bb3: { - StorageDead(_1); // scope 0 at $DIR/simplify_match.rs:+5:1: +5:2 - return; // scope 0 at $DIR/simplify_match.rs:+5:2: +5:2 + StorageDead(_1); // scope 0 at $DIR/simplify_match.rs:10:1: 10:2 + return; // scope 0 at $DIR/simplify_match.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff index d81d23c1c4c1e..15de0839c22fa 100644 --- a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff +++ b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff @@ -2,101 +2,101 @@ + // MIR for `try_identity` after DestinationPropagation fn try_identity(_1: Result) -> Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:+0:17: +0:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:+0:41: +0:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:+1:9: +1:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:+1:19: +1:33 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:+1:31: +1:32 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:+2:9: +2:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:+2:13: +2:14 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:+2:19: +2:51 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:+2:37: +2:50 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:+2:48: +2:49 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:+3:12: +3:13 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:+5:8: +5:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:21:9: 21:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:22:9: 22:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:22:19: 22:51 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:22:37: 22:50 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:22:48: 22:49 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:23:12: 23:13 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9 scope 1 { -- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:+1:9: +1:10 -+ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:+1:9: +1:10 +- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10 ++ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10 } scope 2 { - debug e => _6; // in scope 2 at $DIR/simplify_try.rs:+2:13: +2:14 + debug e => _6; // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14 scope 5 (inlined >::from) { // at $DIR/simplify_try.rs:22:37: 22:50 debug t => _9; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } scope 6 (inlined from_error::) { // at $DIR/simplify_try.rs:22:26: 22:51 - debug e => _8; // in scope 6 at $DIR/simplify_try.rs:+0:21: +0:22 + debug e => _8; // in scope 6 at $DIR/simplify_try.rs:12:21: 12:22 } } scope 3 { -- debug v => _10; // in scope 3 at $DIR/simplify_try.rs:+3:12: +3:13 -+ debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:+3:12: +3:13 +- debug v => _10; // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13 ++ debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13 } scope 4 (inlined into_result::) { // at $DIR/simplify_try.rs:21:19: 21:33 -- debug r => _4; // in scope 4 at $DIR/simplify_try.rs:+0:22: +0:23 -+ debug r => _3; // in scope 4 at $DIR/simplify_try.rs:+0:22: +0:23 +- debug r => _4; // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23 ++ debug r => _3; // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23 } bb0: { -- StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:+1:9: +1:10 -- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33 -- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32 -- _4 = _1; // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32 -- _3 = move _4; // scope 4 at $DIR/simplify_try.rs:+0:5: +0:6 -- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:+1:32: +1:33 -+ nop; // scope 0 at $DIR/simplify_try.rs:+1:9: +1:10 -+ nop; // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33 -+ nop; // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32 -+ _3 = _1; // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32 -+ nop; // scope 4 at $DIR/simplify_try.rs:+0:5: +0:6 -+ nop; // scope 0 at $DIR/simplify_try.rs:+1:32: +1:33 - _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33 - switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:+1:13: +1:33 +- StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:21:9: 21:10 +- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:21:19: 21:33 +- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 +- _4 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 +- _3 = move _4; // scope 4 at $DIR/simplify_try.rs:9:5: 9:6 +- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:21:32: 21:33 ++ nop; // scope 0 at $DIR/simplify_try.rs:21:9: 21:10 ++ nop; // scope 0 at $DIR/simplify_try.rs:21:19: 21:33 ++ nop; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 ++ _3 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 ++ nop; // scope 4 at $DIR/simplify_try.rs:9:5: 9:6 ++ nop; // scope 0 at $DIR/simplify_try.rs:21:32: 21:33 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:21:13: 21:33 } bb1: { -- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13 -- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13 -- _2 = _10; // scope 3 at $DIR/simplify_try.rs:+3:18: +3:19 -- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:+3:18: +3:19 -- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:+4:6: +4:7 -- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:+5:8: +5:9 -- _11 = _2; // scope 1 at $DIR/simplify_try.rs:+5:8: +5:9 -+ nop; // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13 -+ ((_0 as Ok).0: u32) = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13 -+ nop; // scope 3 at $DIR/simplify_try.rs:+3:18: +3:19 -+ nop; // scope 0 at $DIR/simplify_try.rs:+3:18: +3:19 -+ nop; // scope 0 at $DIR/simplify_try.rs:+4:6: +4:7 -+ nop; // scope 1 at $DIR/simplify_try.rs:+5:8: +5:9 -+ nop; // scope 1 at $DIR/simplify_try.rs:+5:8: +5:9 - Deinit(_0); // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10 -- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10 -+ nop; // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10 - discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10 -- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:+5:9: +5:10 -- StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:+6:1: +6:2 -+ nop; // scope 1 at $DIR/simplify_try.rs:+5:9: +5:10 -+ nop; // scope 0 at $DIR/simplify_try.rs:+6:1: +6:2 - return; // scope 0 at $DIR/simplify_try.rs:+6:2: +6:2 +- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:23:12: 23:13 +- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:23:12: 23:13 +- _2 = _10; // scope 3 at $DIR/simplify_try.rs:23:18: 23:19 +- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:23:18: 23:19 +- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 +- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:25:8: 25:9 +- _11 = _2; // scope 1 at $DIR/simplify_try.rs:25:8: 25:9 ++ nop; // scope 0 at $DIR/simplify_try.rs:23:12: 23:13 ++ ((_0 as Ok).0: u32) = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:23:12: 23:13 ++ nop; // scope 3 at $DIR/simplify_try.rs:23:18: 23:19 ++ nop; // scope 0 at $DIR/simplify_try.rs:23:18: 23:19 ++ nop; // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 ++ nop; // scope 1 at $DIR/simplify_try.rs:25:8: 25:9 ++ nop; // scope 1 at $DIR/simplify_try.rs:25:8: 25:9 + Deinit(_0); // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 +- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 ++ nop; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 + discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 +- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:25:9: 25:10 +- StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2 ++ nop; // scope 1 at $DIR/simplify_try.rs:25:9: 25:10 ++ nop; // scope 0 at $DIR/simplify_try.rs:26:1: 26:2 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } bb2: { - StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:+2:13: +2:14 - nop; // scope 0 at $DIR/simplify_try.rs:+2:13: +2:14 - StorageLive(_8); // scope 2 at $DIR/simplify_try.rs:+2:37: +2:50 - StorageLive(_9); // scope 2 at $DIR/simplify_try.rs:+2:48: +2:49 - nop; // scope 2 at $DIR/simplify_try.rs:+2:48: +2:49 + StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + nop; // scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + StorageLive(_8); // scope 2 at $DIR/simplify_try.rs:22:37: 22:50 + StorageLive(_9); // scope 2 at $DIR/simplify_try.rs:22:48: 22:49 + nop; // scope 2 at $DIR/simplify_try.rs:22:48: 22:49 nop; // scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - StorageDead(_9); // scope 2 at $DIR/simplify_try.rs:+2:49: +2:50 - nop; // scope 6 at $DIR/simplify_try.rs:+0:9: +0:10 - Deinit(_0); // scope 6 at $DIR/simplify_try.rs:+0:5: +0:11 - discriminant(_0) = 1; // scope 6 at $DIR/simplify_try.rs:+0:5: +0:11 - StorageDead(_8); // scope 2 at $DIR/simplify_try.rs:+2:50: +2:51 - StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:+2:50: +2:51 -- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:+4:6: +4:7 -- StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:+6:1: +6:2 -+ nop; // scope 0 at $DIR/simplify_try.rs:+4:6: +4:7 -+ nop; // scope 0 at $DIR/simplify_try.rs:+6:1: +6:2 - return; // scope 0 at $DIR/simplify_try.rs:+6:2: +6:2 + StorageDead(_9); // scope 2 at $DIR/simplify_try.rs:22:49: 22:50 + nop; // scope 6 at $DIR/simplify_try.rs:13:9: 13:10 + Deinit(_0); // scope 6 at $DIR/simplify_try.rs:13:5: 13:11 + discriminant(_0) = 1; // scope 6 at $DIR/simplify_try.rs:13:5: 13:11 + StorageDead(_8); // scope 2 at $DIR/simplify_try.rs:22:50: 22:51 + StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:22:50: 22:51 +- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 +- StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2 ++ nop; // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 ++ nop; // scope 0 at $DIR/simplify_try.rs:26:1: 26:2 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff index 853b95cc669aa..01e76109ada59 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff @@ -2,80 +2,80 @@ + // MIR for `try_identity` after SimplifyArmIdentity fn try_identity(_1: Result) -> Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:+0:17: +0:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:+0:41: +0:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:+1:9: +1:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:+1:19: +1:33 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:+1:31: +1:32 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:+2:9: +2:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:+2:13: +2:14 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:+2:19: +2:51 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:+2:37: +2:50 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:+2:48: +2:49 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:+3:12: +3:13 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:+5:8: +5:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:21:9: 21:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:22:9: 22:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:22:19: 22:51 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:22:37: 22:50 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:22:48: 22:49 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:23:12: 23:13 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9 scope 1 { - debug y => _2; // in scope 1 at $DIR/simplify_try.rs:+1:9: +1:10 + debug y => _2; // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10 } scope 2 { - debug e => _6; // in scope 2 at $DIR/simplify_try.rs:+2:13: +2:14 + debug e => _6; // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14 scope 5 (inlined >::from) { // at $DIR/simplify_try.rs:22:37: 22:50 debug t => _9; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } scope 6 (inlined from_error::) { // at $DIR/simplify_try.rs:22:26: 22:51 - debug e => _8; // in scope 6 at $DIR/simplify_try.rs:+0:21: +0:22 + debug e => _8; // in scope 6 at $DIR/simplify_try.rs:12:21: 12:22 } } scope 3 { - debug v => _10; // in scope 3 at $DIR/simplify_try.rs:+3:12: +3:13 + debug v => _10; // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13 } scope 4 (inlined into_result::) { // at $DIR/simplify_try.rs:21:19: 21:33 - debug r => _4; // in scope 4 at $DIR/simplify_try.rs:+0:22: +0:23 + debug r => _4; // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23 } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33 - StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32 - _4 = _1; // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32 - _3 = move _4; // scope 4 at $DIR/simplify_try.rs:+0:5: +0:6 - StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:+1:32: +1:33 - _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33 - switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:+1:13: +1:33 + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:21:9: 21:10 + StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + _4 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + _3 = move _4; // scope 4 at $DIR/simplify_try.rs:9:5: 9:6 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:21:32: 21:33 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:21:13: 21:33 } bb1: { - StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13 - _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13 - _2 = _10; // scope 3 at $DIR/simplify_try.rs:+3:18: +3:19 - StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:+3:18: +3:19 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:+4:6: +4:7 - StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:+5:8: +5:9 - _11 = _2; // scope 1 at $DIR/simplify_try.rs:+5:8: +5:9 - Deinit(_0); // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10 - ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10 - discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10 - StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:+5:9: +5:10 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:+6:1: +6:2 - return; // scope 0 at $DIR/simplify_try.rs:+6:2: +6:2 + StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:23:12: 23:13 + _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:23:12: 23:13 + _2 = _10; // scope 3 at $DIR/simplify_try.rs:23:18: 23:19 + StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:23:18: 23:19 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 + StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:25:8: 25:9 + _11 = _2; // scope 1 at $DIR/simplify_try.rs:25:8: 25:9 + Deinit(_0); // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 + ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 + discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 + StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:25:9: 25:10 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } bb2: { - StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:+2:13: +2:14 - _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:+2:13: +2:14 - StorageLive(_8); // scope 2 at $DIR/simplify_try.rs:+2:37: +2:50 - StorageLive(_9); // scope 2 at $DIR/simplify_try.rs:+2:48: +2:49 - _9 = _6; // scope 2 at $DIR/simplify_try.rs:+2:48: +2:49 + StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + StorageLive(_8); // scope 2 at $DIR/simplify_try.rs:22:37: 22:50 + StorageLive(_9); // scope 2 at $DIR/simplify_try.rs:22:48: 22:49 + _9 = _6; // scope 2 at $DIR/simplify_try.rs:22:48: 22:49 _8 = move _9; // scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - StorageDead(_9); // scope 2 at $DIR/simplify_try.rs:+2:49: +2:50 - ((_0 as Err).0: i32) = move _8; // scope 6 at $DIR/simplify_try.rs:+0:9: +0:10 - Deinit(_0); // scope 6 at $DIR/simplify_try.rs:+0:5: +0:11 - discriminant(_0) = 1; // scope 6 at $DIR/simplify_try.rs:+0:5: +0:11 - StorageDead(_8); // scope 2 at $DIR/simplify_try.rs:+2:50: +2:51 - StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:+2:50: +2:51 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:+4:6: +4:7 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:+6:1: +6:2 - return; // scope 0 at $DIR/simplify_try.rs:+6:2: +6:2 + StorageDead(_9); // scope 2 at $DIR/simplify_try.rs:22:49: 22:50 + ((_0 as Err).0: i32) = move _8; // scope 6 at $DIR/simplify_try.rs:13:9: 13:10 + Deinit(_0); // scope 6 at $DIR/simplify_try.rs:13:5: 13:11 + discriminant(_0) = 1; // scope 6 at $DIR/simplify_try.rs:13:5: 13:11 + StorageDead(_8); // scope 2 at $DIR/simplify_try.rs:22:50: 22:51 + StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:22:50: 22:51 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir index 10799cd92ddb9..56af6730966f7 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir @@ -1,79 +1,79 @@ // MIR for `try_identity` after SimplifyBranchSame fn try_identity(_1: Result) -> Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:+0:17: +0:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:+0:41: +0:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:+1:9: +1:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:+1:19: +1:33 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:+1:31: +1:32 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:+2:9: +2:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:+2:13: +2:14 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:+2:19: +2:51 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:+2:37: +2:50 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:+2:48: +2:49 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:+3:12: +3:13 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:+5:8: +5:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:21:9: 21:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:22:9: 22:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:22:19: 22:51 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:22:37: 22:50 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:22:48: 22:49 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:23:12: 23:13 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9 scope 1 { - debug y => _2; // in scope 1 at $DIR/simplify_try.rs:+1:9: +1:10 + debug y => _2; // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10 } scope 2 { - debug e => _6; // in scope 2 at $DIR/simplify_try.rs:+2:13: +2:14 + debug e => _6; // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14 scope 5 (inlined >::from) { // at $DIR/simplify_try.rs:22:37: 22:50 debug t => _9; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } scope 6 (inlined from_error::) { // at $DIR/simplify_try.rs:22:26: 22:51 - debug e => _8; // in scope 6 at $DIR/simplify_try.rs:+0:21: +0:22 + debug e => _8; // in scope 6 at $DIR/simplify_try.rs:12:21: 12:22 } } scope 3 { - debug v => _10; // in scope 3 at $DIR/simplify_try.rs:+3:12: +3:13 + debug v => _10; // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13 } scope 4 (inlined into_result::) { // at $DIR/simplify_try.rs:21:19: 21:33 - debug r => _4; // in scope 4 at $DIR/simplify_try.rs:+0:22: +0:23 + debug r => _4; // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23 } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33 - StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32 - _4 = _1; // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32 - _3 = move _4; // scope 4 at $DIR/simplify_try.rs:+0:5: +0:6 - StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:+1:32: +1:33 - _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33 - switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:+1:13: +1:33 + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:21:9: 21:10 + StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + _4 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + _3 = move _4; // scope 4 at $DIR/simplify_try.rs:9:5: 9:6 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:21:32: 21:33 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:21:13: 21:33 } bb1: { - StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13 - _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13 - _2 = _10; // scope 3 at $DIR/simplify_try.rs:+3:18: +3:19 - StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:+3:18: +3:19 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:+4:6: +4:7 - StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:+5:8: +5:9 - _11 = _2; // scope 1 at $DIR/simplify_try.rs:+5:8: +5:9 - Deinit(_0); // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10 - ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10 - discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10 - StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:+5:9: +5:10 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:+6:1: +6:2 - return; // scope 0 at $DIR/simplify_try.rs:+6:2: +6:2 + StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:23:12: 23:13 + _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:23:12: 23:13 + _2 = _10; // scope 3 at $DIR/simplify_try.rs:23:18: 23:19 + StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:23:18: 23:19 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 + StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:25:8: 25:9 + _11 = _2; // scope 1 at $DIR/simplify_try.rs:25:8: 25:9 + Deinit(_0); // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 + ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 + discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 + StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:25:9: 25:10 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } bb2: { - StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:+2:13: +2:14 - _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:+2:13: +2:14 - StorageLive(_8); // scope 2 at $DIR/simplify_try.rs:+2:37: +2:50 - StorageLive(_9); // scope 2 at $DIR/simplify_try.rs:+2:48: +2:49 - _9 = _6; // scope 2 at $DIR/simplify_try.rs:+2:48: +2:49 + StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + StorageLive(_8); // scope 2 at $DIR/simplify_try.rs:22:37: 22:50 + StorageLive(_9); // scope 2 at $DIR/simplify_try.rs:22:48: 22:49 + _9 = _6; // scope 2 at $DIR/simplify_try.rs:22:48: 22:49 _8 = move _9; // scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - StorageDead(_9); // scope 2 at $DIR/simplify_try.rs:+2:49: +2:50 - ((_0 as Err).0: i32) = move _8; // scope 6 at $DIR/simplify_try.rs:+0:9: +0:10 - Deinit(_0); // scope 6 at $DIR/simplify_try.rs:+0:5: +0:11 - discriminant(_0) = 1; // scope 6 at $DIR/simplify_try.rs:+0:5: +0:11 - StorageDead(_8); // scope 2 at $DIR/simplify_try.rs:+2:50: +2:51 - StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:+2:50: +2:51 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:+4:6: +4:7 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:+6:1: +6:2 - return; // scope 0 at $DIR/simplify_try.rs:+6:2: +6:2 + StorageDead(_9); // scope 2 at $DIR/simplify_try.rs:22:49: 22:50 + ((_0 as Err).0: i32) = move _8; // scope 6 at $DIR/simplify_try.rs:13:9: 13:10 + Deinit(_0); // scope 6 at $DIR/simplify_try.rs:13:5: 13:11 + discriminant(_0) = 1; // scope 6 at $DIR/simplify_try.rs:13:5: 13:11 + StorageDead(_8); // scope 2 at $DIR/simplify_try.rs:22:50: 22:51 + StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:22:50: 22:51 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir index f8c9034f77ca2..b9252df6f3e2e 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir @@ -1,54 +1,54 @@ // MIR for `try_identity` after SimplifyLocals fn try_identity(_1: Result) -> Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:+0:17: +0:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:+0:41: +0:57 - let mut _2: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:+1:19: +1:33 - let mut _3: isize; // in scope 0 at $DIR/simplify_try.rs:+2:9: +2:15 - let _4: i32; // in scope 0 at $DIR/simplify_try.rs:+2:13: +2:14 - let mut _5: i32; // in scope 0 at $DIR/simplify_try.rs:+2:37: +2:50 - let mut _6: i32; // in scope 0 at $DIR/simplify_try.rs:+2:48: +2:49 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57 + let mut _2: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + let mut _3: isize; // in scope 0 at $DIR/simplify_try.rs:22:9: 22:15 + let _4: i32; // in scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + let mut _5: i32; // in scope 0 at $DIR/simplify_try.rs:22:37: 22:50 + let mut _6: i32; // in scope 0 at $DIR/simplify_try.rs:22:48: 22:49 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:+1:9: +1:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10 } scope 2 { - debug e => _4; // in scope 2 at $DIR/simplify_try.rs:+2:13: +2:14 + debug e => _4; // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14 scope 5 (inlined >::from) { // at $DIR/simplify_try.rs:22:37: 22:50 debug t => _6; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } scope 6 (inlined from_error::) { // at $DIR/simplify_try.rs:22:26: 22:51 - debug e => _5; // in scope 6 at $DIR/simplify_try.rs:+0:21: +0:22 + debug e => _5; // in scope 6 at $DIR/simplify_try.rs:12:21: 12:22 } } scope 3 { - debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:+3:12: +3:13 + debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13 } scope 4 (inlined into_result::) { // at $DIR/simplify_try.rs:21:19: 21:33 - debug r => _2; // in scope 4 at $DIR/simplify_try.rs:+0:22: +0:23 + debug r => _2; // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23 } bb0: { - _2 = _1; // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32 - _3 = discriminant(_2); // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33 - switchInt(move _3) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:+1:13: +1:33 + _2 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + _3 = discriminant(_2); // scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + switchInt(move _3) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:21:13: 21:33 } bb1: { - ((_0 as Ok).0: u32) = ((_2 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13 - Deinit(_0); // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10 - discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10 - return; // scope 0 at $DIR/simplify_try.rs:+6:2: +6:2 + ((_0 as Ok).0: u32) = ((_2 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:23:12: 23:13 + Deinit(_0); // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 + discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } bb2: { - StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:+2:13: +2:14 - StorageLive(_5); // scope 2 at $DIR/simplify_try.rs:+2:37: +2:50 - StorageLive(_6); // scope 2 at $DIR/simplify_try.rs:+2:48: +2:49 - StorageDead(_6); // scope 2 at $DIR/simplify_try.rs:+2:49: +2:50 - Deinit(_0); // scope 6 at $DIR/simplify_try.rs:+0:5: +0:11 - discriminant(_0) = 1; // scope 6 at $DIR/simplify_try.rs:+0:5: +0:11 - StorageDead(_5); // scope 2 at $DIR/simplify_try.rs:+2:50: +2:51 - StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:+2:50: +2:51 - return; // scope 0 at $DIR/simplify_try.rs:+6:2: +6:2 + StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + StorageLive(_5); // scope 2 at $DIR/simplify_try.rs:22:37: 22:50 + StorageLive(_6); // scope 2 at $DIR/simplify_try.rs:22:48: 22:49 + StorageDead(_6); // scope 2 at $DIR/simplify_try.rs:22:49: 22:50 + Deinit(_0); // scope 6 at $DIR/simplify_try.rs:13:5: 13:11 + discriminant(_0) = 1; // scope 6 at $DIR/simplify_try.rs:13:5: 13:11 + StorageDead(_5); // scope 2 at $DIR/simplify_try.rs:22:50: 22:51 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:22:50: 22:51 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } } diff --git a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir index b4b317e84afb7..54ca9dc6682bc 100644 --- a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir +++ b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir @@ -1,101 +1,101 @@ // MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops fn std::ptr::drop_in_place(_1: *mut [String]) -> () { - let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _2: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _3: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _4: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _5: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _6: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _7: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _8: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _9: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _10: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _11: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _12: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _13: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _14: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _15: *mut [std::string::String]; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _2: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _3: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _4: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _5: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _6: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _7: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _8: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _9: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _10: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _11: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _12: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _13: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _14: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _15: *mut [std::string::String]; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL bb0: { - goto -> bb15; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + goto -> bb15; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb1: { - return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb2 (cleanup): { - resume; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + resume; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb3 (cleanup): { - _5 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_5)) -> bb4; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _5 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + drop((*_5)) -> bb4; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb4 (cleanup): { - _6 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _6) -> [false: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _6 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + switchInt(move _6) -> [false: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb5: { - _7 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_7)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _7 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + drop((*_7)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb6: { - _8 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _8) -> [false: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _8 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + switchInt(move _8) -> [false: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb7: { - _4 = const 0_usize; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _4 = const 0_usize; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb8: { - goto -> bb7; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + goto -> bb7; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb9 (cleanup): { - _11 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_11)) -> bb10; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _11 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + drop((*_11)) -> bb10; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb10 (cleanup): { - _12 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _12) -> [false: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _12 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + switchInt(move _12) -> [false: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb11: { - _13 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_13)) -> [return: bb12, unwind: bb10]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _13 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + drop((*_13)) -> [return: bb12, unwind: bb10]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb12: { - _14 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _14) -> [false: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _14 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + switchInt(move _14) -> [false: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb13: { - _15 = &raw mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _9 = move _15 as *mut std::string::String (Misc); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _10 = Offset(_9, move _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - goto -> bb12; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _15 = &raw mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _9 = move _15 as *mut std::string::String (Misc); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _10 = Offset(_9, move _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + goto -> bb12; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb14: { - goto -> bb13; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + goto -> bb13; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb15: { - _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _3 = Len((*_1)); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _3 = Len((*_1)); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } } diff --git a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir index b4b317e84afb7..54ca9dc6682bc 100644 --- a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir +++ b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir @@ -1,101 +1,101 @@ // MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops fn std::ptr::drop_in_place(_1: *mut [String]) -> () { - let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _2: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _3: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _4: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _5: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _6: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _7: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _8: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _9: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _10: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _11: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _12: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _13: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _14: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _15: *mut [std::string::String]; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _2: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _3: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _4: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _5: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _6: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _7: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _8: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _9: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _10: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _11: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _12: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _13: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _14: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _15: *mut [std::string::String]; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL bb0: { - goto -> bb15; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + goto -> bb15; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb1: { - return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb2 (cleanup): { - resume; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + resume; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb3 (cleanup): { - _5 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_5)) -> bb4; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _5 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + drop((*_5)) -> bb4; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb4 (cleanup): { - _6 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _6) -> [false: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _6 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + switchInt(move _6) -> [false: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb5: { - _7 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_7)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _7 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + drop((*_7)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb6: { - _8 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _8) -> [false: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _8 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + switchInt(move _8) -> [false: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb7: { - _4 = const 0_usize; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _4 = const 0_usize; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb8: { - goto -> bb7; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + goto -> bb7; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb9 (cleanup): { - _11 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_11)) -> bb10; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _11 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + drop((*_11)) -> bb10; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb10 (cleanup): { - _12 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _12) -> [false: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _12 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + switchInt(move _12) -> [false: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb11: { - _13 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_13)) -> [return: bb12, unwind: bb10]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _13 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + drop((*_13)) -> [return: bb12, unwind: bb10]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb12: { - _14 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _14) -> [false: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _14 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + switchInt(move _14) -> [false: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb13: { - _15 = &raw mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _9 = move _15 as *mut std::string::String (Misc); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _10 = Offset(_9, move _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - goto -> bb12; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _15 = &raw mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _9 = move _15 as *mut std::string::String (Misc); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _10 = Offset(_9, move _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + goto -> bb12; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb14: { - goto -> bb13; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + goto -> bb13; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb15: { - _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _3 = Len((*_1)); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _3 = Len((*_1)); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } } diff --git a/src/test/mir-opt/storage_live_dead_in_statics.XXX.mir_map.0.mir b/src/test/mir-opt/storage_live_dead_in_statics.XXX.mir_map.0.mir index bc9e91420714e..2c4738aa86618 100644 --- a/src/test/mir-opt/storage_live_dead_in_statics.XXX.mir_map.0.mir +++ b/src/test/mir-opt/storage_live_dead_in_statics.XXX.mir_map.0.mir @@ -1,203 +1,203 @@ // MIR for `XXX` 0 mir_map static XXX: &Foo = { - let mut _0: &Foo; // return place in scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:13: +0:25 - let _1: &Foo; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:28: +18:2 - let _2: Foo; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:29: +18:2 - let mut _3: &[(u32, u32)]; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6 - let mut _4: &[(u32, u32); 42]; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6 - let _5: &[(u32, u32); 42]; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6 - let _6: [(u32, u32); 42]; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:12: +17:6 - let mut _7: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:9: +3:15 - let mut _8: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:17: +3:23 - let mut _9: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:25: +3:31 - let mut _10: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:9: +4:15 - let mut _11: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:17: +4:23 - let mut _12: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:25: +4:31 - let mut _13: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:9: +5:15 - let mut _14: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:17: +5:23 - let mut _15: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:25: +5:31 - let mut _16: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:9: +6:15 - let mut _17: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:17: +6:23 - let mut _18: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:25: +6:31 - let mut _19: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:9: +7:15 - let mut _20: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:17: +7:23 - let mut _21: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:25: +7:31 - let mut _22: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:9: +8:15 - let mut _23: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:17: +8:23 - let mut _24: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:25: +8:31 - let mut _25: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:9: +9:15 - let mut _26: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:17: +9:23 - let mut _27: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:25: +9:31 - let mut _28: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:9: +10:15 - let mut _29: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:17: +10:23 - let mut _30: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:25: +10:31 - let mut _31: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:9: +11:15 - let mut _32: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:17: +11:23 - let mut _33: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:25: +11:31 - let mut _34: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:9: +12:15 - let mut _35: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:17: +12:23 - let mut _36: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:25: +12:31 - let mut _37: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:9: +13:15 - let mut _38: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:17: +13:23 - let mut _39: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:25: +13:31 - let mut _40: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:9: +14:15 - let mut _41: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:17: +14:23 - let mut _42: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:25: +14:31 - let mut _43: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:9: +15:15 - let mut _44: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:17: +15:23 - let mut _45: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:25: +15:31 - let mut _46: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:9: +16:15 - let mut _47: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:17: +16:23 - let mut _48: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:25: +16:31 + let mut _0: &Foo; // return place in scope 0 at $DIR/storage_live_dead_in_statics.rs:5:13: 5:25 + let _1: &Foo; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:5:28: 23:2 + let _2: Foo; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:5:29: 23:2 + let mut _3: &[(u32, u32)]; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6 + let mut _4: &[(u32, u32); 42]; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6 + let _5: &[(u32, u32); 42]; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6 + let _6: [(u32, u32); 42]; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:7:12: 22:6 + let mut _7: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:8:9: 8:15 + let mut _8: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:8:17: 8:23 + let mut _9: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:8:25: 8:31 + let mut _10: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:9:9: 9:15 + let mut _11: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:9:17: 9:23 + let mut _12: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:9:25: 9:31 + let mut _13: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:10:9: 10:15 + let mut _14: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:10:17: 10:23 + let mut _15: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:10:25: 10:31 + let mut _16: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:11:9: 11:15 + let mut _17: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:11:17: 11:23 + let mut _18: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:11:25: 11:31 + let mut _19: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:12:9: 12:15 + let mut _20: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:12:17: 12:23 + let mut _21: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:12:25: 12:31 + let mut _22: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:13:9: 13:15 + let mut _23: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:13:17: 13:23 + let mut _24: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:13:25: 13:31 + let mut _25: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:14:9: 14:15 + let mut _26: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:14:17: 14:23 + let mut _27: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:14:25: 14:31 + let mut _28: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:15:9: 15:15 + let mut _29: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:15:17: 15:23 + let mut _30: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:15:25: 15:31 + let mut _31: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:16:9: 16:15 + let mut _32: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:16:17: 16:23 + let mut _33: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:16:25: 16:31 + let mut _34: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:17:9: 17:15 + let mut _35: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:17:17: 17:23 + let mut _36: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:17:25: 17:31 + let mut _37: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:18:9: 18:15 + let mut _38: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:18:17: 18:23 + let mut _39: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:18:25: 18:31 + let mut _40: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:19:9: 19:15 + let mut _41: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:19:17: 19:23 + let mut _42: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:19:25: 19:31 + let mut _43: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:20:9: 20:15 + let mut _44: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:20:17: 20:23 + let mut _45: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:20:25: 20:31 + let mut _46: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:21:9: 21:15 + let mut _47: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:21:17: 21:23 + let mut _48: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:21:25: 21:31 bb0: { - StorageLive(_1); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:28: +18:2 - StorageLive(_2); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:29: +18:2 - StorageLive(_3); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6 - StorageLive(_4); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6 - StorageLive(_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6 - StorageLive(_6); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:12: +17:6 - StorageLive(_7); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:9: +3:15 - _7 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:9: +3:15 - StorageLive(_8); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:17: +3:23 - _8 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:17: +3:23 - StorageLive(_9); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:25: +3:31 - _9 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:25: +3:31 - StorageLive(_10); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:9: +4:15 - _10 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:9: +4:15 - StorageLive(_11); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:17: +4:23 - _11 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:17: +4:23 - StorageLive(_12); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:25: +4:31 - _12 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:25: +4:31 - StorageLive(_13); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:9: +5:15 - _13 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:9: +5:15 - StorageLive(_14); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:17: +5:23 - _14 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:17: +5:23 - StorageLive(_15); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:25: +5:31 - _15 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:25: +5:31 - StorageLive(_16); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:9: +6:15 - _16 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:9: +6:15 - StorageLive(_17); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:17: +6:23 - _17 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:17: +6:23 - StorageLive(_18); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:25: +6:31 - _18 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:25: +6:31 - StorageLive(_19); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:9: +7:15 - _19 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:9: +7:15 - StorageLive(_20); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:17: +7:23 - _20 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:17: +7:23 - StorageLive(_21); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:25: +7:31 - _21 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:25: +7:31 - StorageLive(_22); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:9: +8:15 - _22 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:9: +8:15 - StorageLive(_23); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:17: +8:23 - _23 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:17: +8:23 - StorageLive(_24); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:25: +8:31 - _24 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:25: +8:31 - StorageLive(_25); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:9: +9:15 - _25 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:9: +9:15 - StorageLive(_26); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:17: +9:23 - _26 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:17: +9:23 - StorageLive(_27); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:25: +9:31 - _27 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:25: +9:31 - StorageLive(_28); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:9: +10:15 - _28 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:9: +10:15 - StorageLive(_29); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:17: +10:23 - _29 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:17: +10:23 - StorageLive(_30); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:25: +10:31 - _30 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:25: +10:31 - StorageLive(_31); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:9: +11:15 - _31 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:9: +11:15 - StorageLive(_32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:17: +11:23 - _32 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:17: +11:23 - StorageLive(_33); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:25: +11:31 - _33 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:25: +11:31 - StorageLive(_34); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:9: +12:15 - _34 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:9: +12:15 - StorageLive(_35); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:17: +12:23 - _35 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:17: +12:23 - StorageLive(_36); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:25: +12:31 - _36 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:25: +12:31 - StorageLive(_37); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:9: +13:15 - _37 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:9: +13:15 - StorageLive(_38); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:17: +13:23 - _38 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:17: +13:23 - StorageLive(_39); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:25: +13:31 - _39 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:25: +13:31 - StorageLive(_40); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:9: +14:15 - _40 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:9: +14:15 - StorageLive(_41); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:17: +14:23 - _41 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:17: +14:23 - StorageLive(_42); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:25: +14:31 - _42 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:25: +14:31 - StorageLive(_43); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:9: +15:15 - _43 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:9: +15:15 - StorageLive(_44); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:17: +15:23 - _44 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:17: +15:23 - StorageLive(_45); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:25: +15:31 - _45 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:25: +15:31 - StorageLive(_46); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:9: +16:15 - _46 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:9: +16:15 - StorageLive(_47); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:17: +16:23 - _47 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:17: +16:23 - StorageLive(_48); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:25: +16:31 - _48 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:25: +16:31 - _6 = [move _7, move _8, move _9, move _10, move _11, move _12, move _13, move _14, move _15, move _16, move _17, move _18, move _19, move _20, move _21, move _22, move _23, move _24, move _25, move _26, move _27, move _28, move _29, move _30, move _31, move _32, move _33, move _34, move _35, move _36, move _37, move _38, move _39, move _40, move _41, move _42, move _43, move _44, move _45, move _46, move _47, move _48]; // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:12: +17:6 - StorageDead(_48); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_47); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_46); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_45); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_44); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_43); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_42); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_41); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_40); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_39); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_38); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_37); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_36); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_35); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_34); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_33); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_31); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_30); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_29); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_28); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_27); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_26); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_25); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_24); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_23); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_22); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_21); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_20); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_19); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_18); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_17); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_16); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_15); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_14); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_13); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_12); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_11); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_10); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_9); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_8); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - StorageDead(_7); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - _5 = &_6; // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6 - _4 = &(*_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6 - _3 = move _4 as &[(u32, u32)] (Pointer(Unsize)); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6 - StorageDead(_4); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6 - _2 = Foo { tup: const "hi", data: move _3 }; // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:29: +18:2 + StorageLive(_1); // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:28: 23:2 + StorageLive(_2); // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:29: 23:2 + StorageLive(_3); // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6 + StorageLive(_4); // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6 + StorageLive(_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6 + StorageLive(_6); // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:12: 22:6 + StorageLive(_7); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:9: 8:15 + _7 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:9: 8:15 + StorageLive(_8); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:17: 8:23 + _8 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:17: 8:23 + StorageLive(_9); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:25: 8:31 + _9 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:25: 8:31 + StorageLive(_10); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:9: 9:15 + _10 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:9: 9:15 + StorageLive(_11); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:17: 9:23 + _11 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:17: 9:23 + StorageLive(_12); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:25: 9:31 + _12 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:25: 9:31 + StorageLive(_13); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:9: 10:15 + _13 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:9: 10:15 + StorageLive(_14); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:17: 10:23 + _14 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:17: 10:23 + StorageLive(_15); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:25: 10:31 + _15 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:25: 10:31 + StorageLive(_16); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:9: 11:15 + _16 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:9: 11:15 + StorageLive(_17); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:17: 11:23 + _17 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:17: 11:23 + StorageLive(_18); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:25: 11:31 + _18 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:25: 11:31 + StorageLive(_19); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:9: 12:15 + _19 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:9: 12:15 + StorageLive(_20); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:17: 12:23 + _20 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:17: 12:23 + StorageLive(_21); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:25: 12:31 + _21 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:25: 12:31 + StorageLive(_22); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:9: 13:15 + _22 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:9: 13:15 + StorageLive(_23); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:17: 13:23 + _23 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:17: 13:23 + StorageLive(_24); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:25: 13:31 + _24 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:25: 13:31 + StorageLive(_25); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:9: 14:15 + _25 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:9: 14:15 + StorageLive(_26); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:17: 14:23 + _26 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:17: 14:23 + StorageLive(_27); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:25: 14:31 + _27 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:25: 14:31 + StorageLive(_28); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:9: 15:15 + _28 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:9: 15:15 + StorageLive(_29); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:17: 15:23 + _29 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:17: 15:23 + StorageLive(_30); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:25: 15:31 + _30 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:25: 15:31 + StorageLive(_31); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:9: 16:15 + _31 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:9: 16:15 + StorageLive(_32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:17: 16:23 + _32 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:17: 16:23 + StorageLive(_33); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:25: 16:31 + _33 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:25: 16:31 + StorageLive(_34); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:9: 17:15 + _34 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:9: 17:15 + StorageLive(_35); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:17: 17:23 + _35 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:17: 17:23 + StorageLive(_36); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:25: 17:31 + _36 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:25: 17:31 + StorageLive(_37); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:9: 18:15 + _37 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:9: 18:15 + StorageLive(_38); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:17: 18:23 + _38 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:17: 18:23 + StorageLive(_39); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:25: 18:31 + _39 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:25: 18:31 + StorageLive(_40); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:9: 19:15 + _40 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:9: 19:15 + StorageLive(_41); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:17: 19:23 + _41 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:17: 19:23 + StorageLive(_42); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:25: 19:31 + _42 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:25: 19:31 + StorageLive(_43); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:9: 20:15 + _43 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:9: 20:15 + StorageLive(_44); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:17: 20:23 + _44 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:17: 20:23 + StorageLive(_45); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:25: 20:31 + _45 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:25: 20:31 + StorageLive(_46); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:9: 21:15 + _46 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:9: 21:15 + StorageLive(_47); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:17: 21:23 + _47 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:17: 21:23 + StorageLive(_48); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:25: 21:31 + _48 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:25: 21:31 + _6 = [move _7, move _8, move _9, move _10, move _11, move _12, move _13, move _14, move _15, move _16, move _17, move _18, move _19, move _20, move _21, move _22, move _23, move _24, move _25, move _26, move _27, move _28, move _29, move _30, move _31, move _32, move _33, move _34, move _35, move _36, move _37, move _38, move _39, move _40, move _41, move _42, move _43, move _44, move _45, move _46, move _47, move _48]; // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:12: 22:6 + StorageDead(_48); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_47); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_46); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_45); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_44); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_43); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_42); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_41); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_40); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_39); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_38); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_37); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_36); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_35); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_34); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_33); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_31); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_30); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_29); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_28); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_27); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_26); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_25); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_24); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_23); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_22); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_21); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_20); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_19); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_18); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_17); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_16); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_15); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_14); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_13); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_12); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_11); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_10); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_9); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_8); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_7); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + _5 = &_6; // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6 + _4 = &(*_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6 + _3 = move _4 as &[(u32, u32)] (Pointer(Unsize)); // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6 + StorageDead(_4); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + _2 = Foo { tup: const "hi", data: move _3 }; // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:29: 23:2 // mir::Constant // + span: $DIR/storage_live_dead_in_statics.rs:6:10: 6:14 // + literal: Const { ty: &str, val: Value(Slice(..)) } - StorageDead(_3); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+18:1: +18:2 - _1 = &_2; // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:28: +18:2 - _0 = &(*_1); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:28: +18:2 - StorageDead(_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+18:1: +18:2 - StorageDead(_1); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+18:1: +18:2 - return; // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:1: +0:25 + StorageDead(_3); // scope 0 at $DIR/storage_live_dead_in_statics.rs:23:1: 23:2 + _1 = &_2; // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:28: 23:2 + _0 = &(*_1); // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:28: 23:2 + StorageDead(_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:23:1: 23:2 + StorageDead(_1); // scope 0 at $DIR/storage_live_dead_in_statics.rs:23:1: 23:2 + return; // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:1: 5:25 } } diff --git a/src/test/mir-opt/storage_ranges.main.nll.0.mir b/src/test/mir-opt/storage_ranges.main.nll.0.mir index 812eb3b82a6d0..b383c5ec9dc60 100644 --- a/src/test/mir-opt/storage_ranges.main.nll.0.mir +++ b/src/test/mir-opt/storage_ranges.main.nll.0.mir @@ -19,46 +19,46 @@ | '_#3r: '_#4r due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:6:17: 6:25 (#0) | fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/storage_ranges.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/storage_ranges.rs:+1:9: +1:10 - let _2: (); // in scope 0 at $DIR/storage_ranges.rs:+2:5: +4:6 - let _4: std::option::Option; // in scope 0 at $DIR/storage_ranges.rs:+3:18: +3:25 - let mut _5: i32; // in scope 0 at $DIR/storage_ranges.rs:+3:23: +3:24 + let mut _0: (); // return place in scope 0 at $DIR/storage_ranges.rs:3:11: 3:11 + let _1: i32; // in scope 0 at $DIR/storage_ranges.rs:4:9: 4:10 + let _2: (); // in scope 0 at $DIR/storage_ranges.rs:5:5: 7:6 + let _4: std::option::Option; // in scope 0 at $DIR/storage_ranges.rs:6:18: 6:25 + let mut _5: i32; // in scope 0 at $DIR/storage_ranges.rs:6:23: 6:24 scope 1 { - debug a => _1; // in scope 1 at $DIR/storage_ranges.rs:+1:9: +1:10 - let _3: &std::option::Option; // in scope 1 at $DIR/storage_ranges.rs:+3:13: +3:14 - let _6: i32; // in scope 1 at $DIR/storage_ranges.rs:+5:9: +5:10 + debug a => _1; // in scope 1 at $DIR/storage_ranges.rs:4:9: 4:10 + let _3: &std::option::Option; // in scope 1 at $DIR/storage_ranges.rs:6:13: 6:14 + let _6: i32; // in scope 1 at $DIR/storage_ranges.rs:8:9: 8:10 scope 2 { - debug b => _3; // in scope 2 at $DIR/storage_ranges.rs:+3:13: +3:14 + debug b => _3; // in scope 2 at $DIR/storage_ranges.rs:6:13: 6:14 } scope 3 { - debug c => _6; // in scope 3 at $DIR/storage_ranges.rs:+5:9: +5:10 + debug c => _6; // in scope 3 at $DIR/storage_ranges.rs:8:9: 8:10 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/storage_ranges.rs:+1:9: +1:10 - _1 = const 0_i32; // scope 0 at $DIR/storage_ranges.rs:+1:13: +1:14 - FakeRead(ForLet(None), _1); // scope 0 at $DIR/storage_ranges.rs:+1:9: +1:10 - StorageLive(_2); // scope 1 at $DIR/storage_ranges.rs:+2:5: +4:6 - StorageLive(_3); // scope 1 at $DIR/storage_ranges.rs:+3:13: +3:14 - StorageLive(_4); // scope 1 at $DIR/storage_ranges.rs:+3:18: +3:25 - StorageLive(_5); // scope 1 at $DIR/storage_ranges.rs:+3:23: +3:24 - _5 = _1; // scope 1 at $DIR/storage_ranges.rs:+3:23: +3:24 - _4 = Option::::Some(move _5); // scope 1 at $DIR/storage_ranges.rs:+3:18: +3:25 - StorageDead(_5); // scope 1 at $DIR/storage_ranges.rs:+3:24: +3:25 - _3 = &_4; // scope 1 at $DIR/storage_ranges.rs:+3:17: +3:25 - FakeRead(ForLet(None), _3); // scope 1 at $DIR/storage_ranges.rs:+3:13: +3:14 - _2 = const (); // scope 1 at $DIR/storage_ranges.rs:+2:5: +4:6 - StorageDead(_4); // scope 1 at $DIR/storage_ranges.rs:+4:5: +4:6 - StorageDead(_3); // scope 1 at $DIR/storage_ranges.rs:+4:5: +4:6 - StorageDead(_2); // scope 1 at $DIR/storage_ranges.rs:+4:5: +4:6 - StorageLive(_6); // scope 1 at $DIR/storage_ranges.rs:+5:9: +5:10 - _6 = const 1_i32; // scope 1 at $DIR/storage_ranges.rs:+5:13: +5:14 - FakeRead(ForLet(None), _6); // scope 1 at $DIR/storage_ranges.rs:+5:9: +5:10 - _0 = const (); // scope 0 at $DIR/storage_ranges.rs:+0:11: +6:2 - StorageDead(_6); // scope 1 at $DIR/storage_ranges.rs:+6:1: +6:2 - StorageDead(_1); // scope 0 at $DIR/storage_ranges.rs:+6:1: +6:2 - return; // scope 0 at $DIR/storage_ranges.rs:+6:2: +6:2 + StorageLive(_1); // scope 0 at $DIR/storage_ranges.rs:4:9: 4:10 + _1 = const 0_i32; // scope 0 at $DIR/storage_ranges.rs:4:13: 4:14 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/storage_ranges.rs:4:9: 4:10 + StorageLive(_2); // scope 1 at $DIR/storage_ranges.rs:5:5: 7:6 + StorageLive(_3); // scope 1 at $DIR/storage_ranges.rs:6:13: 6:14 + StorageLive(_4); // scope 1 at $DIR/storage_ranges.rs:6:18: 6:25 + StorageLive(_5); // scope 1 at $DIR/storage_ranges.rs:6:23: 6:24 + _5 = _1; // scope 1 at $DIR/storage_ranges.rs:6:23: 6:24 + _4 = Option::::Some(move _5); // scope 1 at $DIR/storage_ranges.rs:6:18: 6:25 + StorageDead(_5); // scope 1 at $DIR/storage_ranges.rs:6:24: 6:25 + _3 = &_4; // scope 1 at $DIR/storage_ranges.rs:6:17: 6:25 + FakeRead(ForLet(None), _3); // scope 1 at $DIR/storage_ranges.rs:6:13: 6:14 + _2 = const (); // scope 1 at $DIR/storage_ranges.rs:5:5: 7:6 + StorageDead(_4); // scope 1 at $DIR/storage_ranges.rs:7:5: 7:6 + StorageDead(_3); // scope 1 at $DIR/storage_ranges.rs:7:5: 7:6 + StorageDead(_2); // scope 1 at $DIR/storage_ranges.rs:7:5: 7:6 + StorageLive(_6); // scope 1 at $DIR/storage_ranges.rs:8:9: 8:10 + _6 = const 1_i32; // scope 1 at $DIR/storage_ranges.rs:8:13: 8:14 + FakeRead(ForLet(None), _6); // scope 1 at $DIR/storage_ranges.rs:8:9: 8:10 + _0 = const (); // scope 0 at $DIR/storage_ranges.rs:3:11: 9:2 + StorageDead(_6); // scope 1 at $DIR/storage_ranges.rs:9:1: 9:2 + StorageDead(_1); // scope 0 at $DIR/storage_ranges.rs:9:1: 9:2 + return; // scope 0 at $DIR/storage_ranges.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/tls_access.main.PreCodegen.after.mir b/src/test/mir-opt/tls_access.main.PreCodegen.after.mir index b6c36be2bbe4c..baa77497e3862 100644 --- a/src/test/mir-opt/tls_access.main.PreCodegen.after.mir +++ b/src/test/mir-opt/tls_access.main.PreCodegen.after.mir @@ -1,28 +1,28 @@ // MIR for `main` after PreCodegen fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/tls-access.rs:+0:11: +0:11 - let _2: *mut u8; // in scope 0 at $DIR/tls-access.rs:+2:18: +2:21 - let mut _3: *mut u8; // in scope 0 at $DIR/tls-access.rs:+3:9: +3:12 + let mut _0: (); // return place in scope 0 at $DIR/tls-access.rs:9:11: 9:11 + let _2: *mut u8; // in scope 0 at $DIR/tls-access.rs:11:18: 11:21 + let mut _3: *mut u8; // in scope 0 at $DIR/tls-access.rs:12:9: 12:12 scope 1 { - let _1: &u8; // in scope 1 at $DIR/tls-access.rs:+2:13: +2:14 + let _1: &u8; // in scope 1 at $DIR/tls-access.rs:11:13: 11:14 scope 2 { - debug a => _1; // in scope 2 at $DIR/tls-access.rs:+2:13: +2:14 + debug a => _1; // in scope 2 at $DIR/tls-access.rs:11:13: 11:14 } } bb0: { - StorageLive(_1); // scope 1 at $DIR/tls-access.rs:+2:13: +2:14 - StorageLive(_2); // scope 1 at $DIR/tls-access.rs:+2:18: +2:21 - _2 = &/*tls*/ mut FOO; // scope 1 at $DIR/tls-access.rs:+2:18: +2:21 - _1 = &(*_2); // scope 1 at $DIR/tls-access.rs:+2:17: +2:21 - StorageLive(_3); // scope 2 at $DIR/tls-access.rs:+3:9: +3:12 - _3 = &/*tls*/ mut FOO; // scope 2 at $DIR/tls-access.rs:+3:9: +3:12 - (*_3) = const 42_u8; // scope 2 at $DIR/tls-access.rs:+3:9: +3:17 - StorageDead(_3); // scope 2 at $DIR/tls-access.rs:+3:17: +3:18 - _0 = const (); // scope 1 at $DIR/tls-access.rs:+1:5: +4:6 - StorageDead(_2); // scope 1 at $DIR/tls-access.rs:+4:5: +4:6 - StorageDead(_1); // scope 1 at $DIR/tls-access.rs:+4:5: +4:6 - return; // scope 0 at $DIR/tls-access.rs:+5:2: +5:2 + StorageLive(_1); // scope 1 at $DIR/tls-access.rs:11:13: 11:14 + StorageLive(_2); // scope 1 at $DIR/tls-access.rs:11:18: 11:21 + _2 = &/*tls*/ mut FOO; // scope 1 at $DIR/tls-access.rs:11:18: 11:21 + _1 = &(*_2); // scope 1 at $DIR/tls-access.rs:11:17: 11:21 + StorageLive(_3); // scope 2 at $DIR/tls-access.rs:12:9: 12:12 + _3 = &/*tls*/ mut FOO; // scope 2 at $DIR/tls-access.rs:12:9: 12:12 + (*_3) = const 42_u8; // scope 2 at $DIR/tls-access.rs:12:9: 12:17 + StorageDead(_3); // scope 2 at $DIR/tls-access.rs:12:17: 12:18 + _0 = const (); // scope 1 at $DIR/tls-access.rs:10:5: 13:6 + StorageDead(_2); // scope 1 at $DIR/tls-access.rs:13:5: 13:6 + StorageDead(_1); // scope 1 at $DIR/tls-access.rs:13:5: 13:6 + return; // scope 0 at $DIR/tls-access.rs:14:2: 14:2 } } diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir index 6e9a8b4d975fa..d36d369003a63 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir @@ -1,23 +1,23 @@ // MIR for `move_out_by_subslice` 0 mir_map fn move_out_by_subslice() -> () { - let mut _0: (); // return place in scope 0 at $DIR/uniform_array_move_out.rs:+0:27: +0:27 - let _1: [std::boxed::Box; 2]; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10 - let mut _2: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - let mut _3: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - let mut _4: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - let mut _5: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - let mut _6: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - let mut _7: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - let mut _8: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - let mut _9: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - let mut _10: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - let mut _11: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 + let mut _0: (); // return place in scope 0 at $DIR/uniform_array_move_out.rs:10:27: 10:27 + let _1: [std::boxed::Box; 2]; // in scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 + let mut _2: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _3: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _4: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _5: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _6: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _7: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _8: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _9: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _10: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _11: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 scope 1 { - debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:+1:9: +1:10 - let _12: [std::boxed::Box; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:17 + debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:11:9: 11:10 + let _12: [std::boxed::Box; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 scope 4 { - debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:+2:10: +2:17 + debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:12:10: 12:17 } } scope 2 { @@ -26,86 +26,86 @@ fn move_out_by_subslice() -> () { } bb0: { - StorageLive(_1); // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10 - StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - _3 = SizeOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - _4 = AlignOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 + StorageLive(_1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 + StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + _3 = SizeOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + _4 = AlignOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19 // mir::Constant // + span: $DIR/uniform_array_move_out.rs:11:14: 11:19 // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value() } } bb1: { - StorageLive(_6); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - (*_6) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19 - _2 = move _6; // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19 + StorageLive(_6); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + (*_6) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 + _2 = move _6; // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 } bb2: { - StorageDead(_6); // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19 - StorageLive(_7); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - _8 = SizeOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - _9 = AlignOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 + StorageDead(_6); // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 + StorageLive(_7); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + _8 = SizeOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + _9 = AlignOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26 // mir::Constant // + span: $DIR/uniform_array_move_out.rs:11:21: 11:26 // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value() } } bb3: { - StorageLive(_11); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - (*_11) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26 - _7 = move _11; // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26 + StorageLive(_11); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + (*_11) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 + _7 = move _11; // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 } bb4: { - StorageDead(_11); // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26 - _1 = [move _2, move _7]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:13: +1:27 - drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27 + StorageDead(_11); // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 + _1 = [move _2, move _7]; // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27 + drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 } bb5: { - StorageDead(_7); // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27 - drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27 + StorageDead(_7); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 } bb6: { - StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27 - FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10 - StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:17 - _12 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:17 - _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:+0:27: +3:2 - drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:+3:1: +3:2 + StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 + StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 + _12 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 + _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:10:27: 13:2 + drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } bb7: { - StorageDead(_12); // scope 1 at $DIR/uniform_array_move_out.rs:+3:1: +3:2 - drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2 + StorageDead(_12); // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } bb8: { - StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2 - return; // scope 0 at $DIR/uniform_array_move_out.rs:+3:2: +3:2 + StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + return; // scope 0 at $DIR/uniform_array_move_out.rs:13:2: 13:2 } bb9 (cleanup): { - drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2 + drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } bb10 (cleanup): { - drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27 + drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 } bb11 (cleanup): { - drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27 + drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 } bb12 (cleanup): { - resume; // scope 0 at $DIR/uniform_array_move_out.rs:+0:1: +3:2 + resume; // scope 0 at $DIR/uniform_array_move_out.rs:10:1: 13:2 } } diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir index 23a50b22ad141..e6c8b66c25af0 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir @@ -1,23 +1,23 @@ // MIR for `move_out_from_end` 0 mir_map fn move_out_from_end() -> () { - let mut _0: (); // return place in scope 0 at $DIR/uniform_array_move_out.rs:+0:24: +0:24 - let _1: [std::boxed::Box; 2]; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10 - let mut _2: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - let mut _3: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - let mut _4: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - let mut _5: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - let mut _6: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - let mut _7: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - let mut _8: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - let mut _9: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - let mut _10: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - let mut _11: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 + let mut _0: (); // return place in scope 0 at $DIR/uniform_array_move_out.rs:4:24: 4:24 + let _1: [std::boxed::Box; 2]; // in scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 + let mut _2: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _3: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _4: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _5: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _6: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _7: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _8: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _9: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _10: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _11: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 scope 1 { - debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:+1:9: +1:10 - let _12: std::boxed::Box; // in scope 1 at $DIR/uniform_array_move_out.rs:+2:14: +2:16 + debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:5:9: 5:10 + let _12: std::boxed::Box; // in scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 scope 4 { - debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:+2:14: +2:16 + debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:6:14: 6:16 } } scope 2 { @@ -26,86 +26,86 @@ fn move_out_from_end() -> () { } bb0: { - StorageLive(_1); // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10 - StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - _3 = SizeOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - _4 = AlignOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 + StorageLive(_1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 + StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + _3 = SizeOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + _4 = AlignOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19 // mir::Constant // + span: $DIR/uniform_array_move_out.rs:5:14: 5:19 // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value() } } bb1: { - StorageLive(_6); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - (*_6) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19 - _2 = move _6; // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19 - drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19 + StorageLive(_6); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + (*_6) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 + _2 = move _6; // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 } bb2: { - StorageDead(_6); // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19 - StorageLive(_7); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - _8 = SizeOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - _9 = AlignOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 + StorageDead(_6); // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 + StorageLive(_7); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + _8 = SizeOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + _9 = AlignOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26 // mir::Constant // + span: $DIR/uniform_array_move_out.rs:5:21: 5:26 // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value() } } bb3: { - StorageLive(_11); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - (*_11) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26 - _7 = move _11; // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 - drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26 + StorageLive(_11); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + (*_11) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 + _7 = move _11; // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 } bb4: { - StorageDead(_11); // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26 - _1 = [move _2, move _7]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:13: +1:27 - drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27 + StorageDead(_11); // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 + _1 = [move _2, move _7]; // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27 + drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 } bb5: { - StorageDead(_7); // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27 - drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27 + StorageDead(_7); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 } bb6: { - StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27 - FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10 - StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:+2:14: +2:16 - _12 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:+2:14: +2:16 - _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:+0:24: +3:2 - drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:+3:1: +3:2 + StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 + StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 + _12 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 + _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:4:24: 7:2 + drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } bb7: { - StorageDead(_12); // scope 1 at $DIR/uniform_array_move_out.rs:+3:1: +3:2 - drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2 + StorageDead(_12); // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } bb8: { - StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2 - return; // scope 0 at $DIR/uniform_array_move_out.rs:+3:2: +3:2 + StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + return; // scope 0 at $DIR/uniform_array_move_out.rs:7:2: 7:2 } bb9 (cleanup): { - drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2 + drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } bb10 (cleanup): { - drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27 + drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 } bb11 (cleanup): { - drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27 + drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 } bb12 (cleanup): { - resume; // scope 0 at $DIR/uniform_array_move_out.rs:+0:1: +3:2 + resume; // scope 0 at $DIR/uniform_array_move_out.rs:4:1: 7:2 } } diff --git a/src/test/mir-opt/uninhabited_enum.process_never.SimplifyLocals.after.mir b/src/test/mir-opt/uninhabited_enum.process_never.SimplifyLocals.after.mir index 34c38d24c541e..aa6a4cac350b5 100644 --- a/src/test/mir-opt/uninhabited_enum.process_never.SimplifyLocals.after.mir +++ b/src/test/mir-opt/uninhabited_enum.process_never.SimplifyLocals.after.mir @@ -1,18 +1,18 @@ // MIR for `process_never` after SimplifyLocals fn process_never(_1: *const !) -> () { - debug input => _1; // in scope 0 at $DIR/uninhabited-enum.rs:+0:22: +0:27 - let mut _0: (); // return place in scope 0 at $DIR/uninhabited-enum.rs:+0:39: +0:39 - let _2: &!; // in scope 0 at $DIR/uninhabited-enum.rs:+1:8: +1:14 + debug input => _1; // in scope 0 at $DIR/uninhabited-enum.rs:7:22: 7:27 + let mut _0: (); // return place in scope 0 at $DIR/uninhabited-enum.rs:7:39: 7:39 + let _2: &!; // in scope 0 at $DIR/uninhabited-enum.rs:8:8: 8:14 scope 1 { - debug _input => _2; // in scope 1 at $DIR/uninhabited-enum.rs:+1:8: +1:14 + debug _input => _2; // in scope 1 at $DIR/uninhabited-enum.rs:8:8: 8:14 } scope 2 { } bb0: { - StorageLive(_2); // scope 0 at $DIR/uninhabited-enum.rs:+1:8: +1:14 - StorageDead(_2); // scope 0 at $DIR/uninhabited-enum.rs:+2:1: +2:2 - unreachable; // scope 0 at $DIR/uninhabited-enum.rs:+0:39: +2:2 + StorageLive(_2); // scope 0 at $DIR/uninhabited-enum.rs:8:8: 8:14 + StorageDead(_2); // scope 0 at $DIR/uninhabited-enum.rs:9:1: 9:2 + unreachable; // scope 0 at $DIR/uninhabited-enum.rs:7:39: 9:2 } } diff --git a/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals.after.mir b/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals.after.mir index bbb81724ccfd8..9fd4b1b54e73d 100644 --- a/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals.after.mir +++ b/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals.after.mir @@ -1,18 +1,18 @@ // MIR for `process_void` after SimplifyLocals fn process_void(_1: *const Void) -> () { - debug input => _1; // in scope 0 at $DIR/uninhabited-enum.rs:+0:21: +0:26 - let mut _0: (); // return place in scope 0 at $DIR/uninhabited-enum.rs:+0:41: +0:41 - let _2: &Void; // in scope 0 at $DIR/uninhabited-enum.rs:+1:8: +1:14 + debug input => _1; // in scope 0 at $DIR/uninhabited-enum.rs:13:21: 13:26 + let mut _0: (); // return place in scope 0 at $DIR/uninhabited-enum.rs:13:41: 13:41 + let _2: &Void; // in scope 0 at $DIR/uninhabited-enum.rs:14:8: 14:14 scope 1 { - debug _input => _2; // in scope 1 at $DIR/uninhabited-enum.rs:+1:8: +1:14 + debug _input => _2; // in scope 1 at $DIR/uninhabited-enum.rs:14:8: 14:14 } scope 2 { } bb0: { - StorageLive(_2); // scope 0 at $DIR/uninhabited-enum.rs:+1:8: +1:14 - StorageDead(_2); // scope 0 at $DIR/uninhabited-enum.rs:+4:1: +4:2 - return; // scope 0 at $DIR/uninhabited-enum.rs:+4:2: +4:2 + StorageLive(_2); // scope 0 at $DIR/uninhabited-enum.rs:14:8: 14:14 + StorageDead(_2); // scope 0 at $DIR/uninhabited-enum.rs:17:1: 17:2 + return; // scope 0 at $DIR/uninhabited-enum.rs:17:2: 17:2 } } diff --git a/src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir b/src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir index 3d860dac36105..16fd328b6f966 100644 --- a/src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir +++ b/src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir @@ -1,63 +1,63 @@ // MIR for `main` after SimplifyCfg-after-uninhabited-enum-branching fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/uninhabited_enum_branching.rs:+0:11: +0:11 - let _1: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +5:6 - let mut _2: Test1; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19 - let mut _3: isize; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+2:9: +2:20 - let _4: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+3:24: +3:34 - let _5: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+4:21: +4:24 - let _6: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+7:5: +10:6 - let mut _7: Test2; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19 - let mut _8: isize; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+8:9: +8:17 - let _9: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+9:21: +9:24 + let mut _0: (); // return place in scope 0 at $DIR/uninhabited_enum_branching.rs:19:11: 19:11 + let _1: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:20:5: 24:6 + let mut _2: Test1; // in scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19 + let mut _3: isize; // in scope 0 at $DIR/uninhabited_enum_branching.rs:21:9: 21:20 + let _4: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:22:24: 22:34 + let _5: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:23:21: 23:24 + let _6: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:26:5: 29:6 + let mut _7: Test2; // in scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19 + let mut _8: isize; // in scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17 + let _9: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:28:21: 28:24 bb0: { - StorageLive(_1); // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +5:6 - StorageLive(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19 - Deinit(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19 - discriminant(_2) = 2; // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19 - _3 = discriminant(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19 - StorageLive(_5); // scope 0 at $DIR/uninhabited_enum_branching.rs:+4:21: +4:24 - _5 = const "C"; // scope 0 at $DIR/uninhabited_enum_branching.rs:+4:21: +4:24 + StorageLive(_1); // scope 0 at $DIR/uninhabited_enum_branching.rs:20:5: 24:6 + StorageLive(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19 + Deinit(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19 + discriminant(_2) = 2; // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19 + _3 = discriminant(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19 + StorageLive(_5); // scope 0 at $DIR/uninhabited_enum_branching.rs:23:21: 23:24 + _5 = const "C"; // scope 0 at $DIR/uninhabited_enum_branching.rs:23:21: 23:24 // mir::Constant // + span: $DIR/uninhabited_enum_branching.rs:23:21: 23:24 // + literal: Const { ty: &str, val: Value(Slice(..)) } - _1 = &(*_5); // scope 0 at $DIR/uninhabited_enum_branching.rs:+4:21: +4:24 - StorageDead(_5); // scope 0 at $DIR/uninhabited_enum_branching.rs:+4:23: +4:24 - StorageDead(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:+5:6: +5:7 - StorageDead(_1); // scope 0 at $DIR/uninhabited_enum_branching.rs:+5:6: +5:7 - StorageLive(_6); // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:5: +10:6 - StorageLive(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19 - Deinit(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19 - discriminant(_7) = 0; // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19 - _8 = discriminant(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19 - switchInt(move _8) -> [4_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:5: +7:19 + _1 = &(*_5); // scope 0 at $DIR/uninhabited_enum_branching.rs:23:21: 23:24 + StorageDead(_5); // scope 0 at $DIR/uninhabited_enum_branching.rs:23:23: 23:24 + StorageDead(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:24:6: 24:7 + StorageDead(_1); // scope 0 at $DIR/uninhabited_enum_branching.rs:24:6: 24:7 + StorageLive(_6); // scope 0 at $DIR/uninhabited_enum_branching.rs:26:5: 29:6 + StorageLive(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19 + Deinit(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19 + discriminant(_7) = 0; // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19 + _8 = discriminant(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19 + switchInt(move _8) -> [4_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/uninhabited_enum_branching.rs:26:5: 26:19 } bb1: { - StorageLive(_9); // scope 0 at $DIR/uninhabited_enum_branching.rs:+9:21: +9:24 - _9 = const "E"; // scope 0 at $DIR/uninhabited_enum_branching.rs:+9:21: +9:24 + StorageLive(_9); // scope 0 at $DIR/uninhabited_enum_branching.rs:28:21: 28:24 + _9 = const "E"; // scope 0 at $DIR/uninhabited_enum_branching.rs:28:21: 28:24 // mir::Constant // + span: $DIR/uninhabited_enum_branching.rs:28:21: 28:24 // + literal: Const { ty: &str, val: Value(Slice(..)) } - _6 = &(*_9); // scope 0 at $DIR/uninhabited_enum_branching.rs:+9:21: +9:24 - StorageDead(_9); // scope 0 at $DIR/uninhabited_enum_branching.rs:+9:23: +9:24 - goto -> bb3; // scope 0 at $DIR/uninhabited_enum_branching.rs:+9:23: +9:24 + _6 = &(*_9); // scope 0 at $DIR/uninhabited_enum_branching.rs:28:21: 28:24 + StorageDead(_9); // scope 0 at $DIR/uninhabited_enum_branching.rs:28:23: 28:24 + goto -> bb3; // scope 0 at $DIR/uninhabited_enum_branching.rs:28:23: 28:24 } bb2: { - _6 = const "D"; // scope 0 at $DIR/uninhabited_enum_branching.rs:+8:21: +8:24 + _6 = const "D"; // scope 0 at $DIR/uninhabited_enum_branching.rs:27:21: 27:24 // mir::Constant // + span: $DIR/uninhabited_enum_branching.rs:27:21: 27:24 // + literal: Const { ty: &str, val: Value(Slice(..)) } - goto -> bb3; // scope 0 at $DIR/uninhabited_enum_branching.rs:+8:21: +8:24 + goto -> bb3; // scope 0 at $DIR/uninhabited_enum_branching.rs:27:21: 27:24 } bb3: { - StorageDead(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:+10:6: +10:7 - StorageDead(_6); // scope 0 at $DIR/uninhabited_enum_branching.rs:+10:6: +10:7 - _0 = const (); // scope 0 at $DIR/uninhabited_enum_branching.rs:+0:11: +11:2 - return; // scope 0 at $DIR/uninhabited_enum_branching.rs:+11:2: +11:2 + StorageDead(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:29:6: 29:7 + StorageDead(_6); // scope 0 at $DIR/uninhabited_enum_branching.rs:29:6: 29:7 + _0 = const (); // scope 0 at $DIR/uninhabited_enum_branching.rs:19:11: 30:2 + return; // scope 0 at $DIR/uninhabited_enum_branching.rs:30:2: 30:2 } } diff --git a/src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff b/src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff index 023f6ae32b009..c499e5c59dbeb 100644 --- a/src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff +++ b/src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff @@ -2,92 +2,92 @@ + // MIR for `main` after UninhabitedEnumBranching fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/uninhabited_enum_branching.rs:+0:11: +0:11 - let _1: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +5:6 - let mut _2: Test1; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19 - let mut _3: isize; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+2:9: +2:20 - let _4: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+3:24: +3:34 - let _5: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+4:21: +4:24 - let _6: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+7:5: +10:6 - let mut _7: Test2; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19 - let mut _8: isize; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+8:9: +8:17 - let _9: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:+9:21: +9:24 + let mut _0: (); // return place in scope 0 at $DIR/uninhabited_enum_branching.rs:19:11: 19:11 + let _1: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:20:5: 24:6 + let mut _2: Test1; // in scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19 + let mut _3: isize; // in scope 0 at $DIR/uninhabited_enum_branching.rs:21:9: 21:20 + let _4: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:22:24: 22:34 + let _5: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:23:21: 23:24 + let _6: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:26:5: 29:6 + let mut _7: Test2; // in scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19 + let mut _8: isize; // in scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17 + let _9: &str; // in scope 0 at $DIR/uninhabited_enum_branching.rs:28:21: 28:24 bb0: { - StorageLive(_1); // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +5:6 - StorageLive(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19 - Deinit(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19 - discriminant(_2) = 2; // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19 - _3 = discriminant(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19 -- switchInt(move _3) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +1:19 -+ switchInt(move _3) -> bb1; // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +1:19 + StorageLive(_1); // scope 0 at $DIR/uninhabited_enum_branching.rs:20:5: 24:6 + StorageLive(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19 + Deinit(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19 + discriminant(_2) = 2; // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19 + _3 = discriminant(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19 +- switchInt(move _3) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_enum_branching.rs:20:5: 20:19 ++ switchInt(move _3) -> bb1; // scope 0 at $DIR/uninhabited_enum_branching.rs:20:5: 20:19 } bb1: { - StorageLive(_5); // scope 0 at $DIR/uninhabited_enum_branching.rs:+4:21: +4:24 - _5 = const "C"; // scope 0 at $DIR/uninhabited_enum_branching.rs:+4:21: +4:24 + StorageLive(_5); // scope 0 at $DIR/uninhabited_enum_branching.rs:23:21: 23:24 + _5 = const "C"; // scope 0 at $DIR/uninhabited_enum_branching.rs:23:21: 23:24 // mir::Constant // + span: $DIR/uninhabited_enum_branching.rs:23:21: 23:24 // + literal: Const { ty: &str, val: Value(Slice(..)) } - _1 = &(*_5); // scope 0 at $DIR/uninhabited_enum_branching.rs:+4:21: +4:24 - StorageDead(_5); // scope 0 at $DIR/uninhabited_enum_branching.rs:+4:23: +4:24 - goto -> bb4; // scope 0 at $DIR/uninhabited_enum_branching.rs:+4:23: +4:24 + _1 = &(*_5); // scope 0 at $DIR/uninhabited_enum_branching.rs:23:21: 23:24 + StorageDead(_5); // scope 0 at $DIR/uninhabited_enum_branching.rs:23:23: 23:24 + goto -> bb4; // scope 0 at $DIR/uninhabited_enum_branching.rs:23:23: 23:24 } bb2: { - _1 = const "A(Empty)"; // scope 0 at $DIR/uninhabited_enum_branching.rs:+2:24: +2:34 + _1 = const "A(Empty)"; // scope 0 at $DIR/uninhabited_enum_branching.rs:21:24: 21:34 // mir::Constant // + span: $DIR/uninhabited_enum_branching.rs:21:24: 21:34 // + literal: Const { ty: &str, val: Value(Slice(..)) } - goto -> bb4; // scope 0 at $DIR/uninhabited_enum_branching.rs:+2:24: +2:34 + goto -> bb4; // scope 0 at $DIR/uninhabited_enum_branching.rs:21:24: 21:34 } bb3: { - StorageLive(_4); // scope 0 at $DIR/uninhabited_enum_branching.rs:+3:24: +3:34 - _4 = const "B(Empty)"; // scope 0 at $DIR/uninhabited_enum_branching.rs:+3:24: +3:34 + StorageLive(_4); // scope 0 at $DIR/uninhabited_enum_branching.rs:22:24: 22:34 + _4 = const "B(Empty)"; // scope 0 at $DIR/uninhabited_enum_branching.rs:22:24: 22:34 // mir::Constant // + span: $DIR/uninhabited_enum_branching.rs:22:24: 22:34 // + literal: Const { ty: &str, val: Value(Slice(..)) } - _1 = &(*_4); // scope 0 at $DIR/uninhabited_enum_branching.rs:+3:24: +3:34 - StorageDead(_4); // scope 0 at $DIR/uninhabited_enum_branching.rs:+3:33: +3:34 - goto -> bb4; // scope 0 at $DIR/uninhabited_enum_branching.rs:+3:33: +3:34 + _1 = &(*_4); // scope 0 at $DIR/uninhabited_enum_branching.rs:22:24: 22:34 + StorageDead(_4); // scope 0 at $DIR/uninhabited_enum_branching.rs:22:33: 22:34 + goto -> bb4; // scope 0 at $DIR/uninhabited_enum_branching.rs:22:33: 22:34 } bb4: { - StorageDead(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:+5:6: +5:7 - StorageDead(_1); // scope 0 at $DIR/uninhabited_enum_branching.rs:+5:6: +5:7 - StorageLive(_6); // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:5: +10:6 - StorageLive(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19 - Deinit(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19 - discriminant(_7) = 0; // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19 - _8 = discriminant(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19 - switchInt(move _8) -> [4_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:5: +7:19 + StorageDead(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:24:6: 24:7 + StorageDead(_1); // scope 0 at $DIR/uninhabited_enum_branching.rs:24:6: 24:7 + StorageLive(_6); // scope 0 at $DIR/uninhabited_enum_branching.rs:26:5: 29:6 + StorageLive(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19 + Deinit(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19 + discriminant(_7) = 0; // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19 + _8 = discriminant(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19 + switchInt(move _8) -> [4_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/uninhabited_enum_branching.rs:26:5: 26:19 } bb5: { - StorageLive(_9); // scope 0 at $DIR/uninhabited_enum_branching.rs:+9:21: +9:24 - _9 = const "E"; // scope 0 at $DIR/uninhabited_enum_branching.rs:+9:21: +9:24 + StorageLive(_9); // scope 0 at $DIR/uninhabited_enum_branching.rs:28:21: 28:24 + _9 = const "E"; // scope 0 at $DIR/uninhabited_enum_branching.rs:28:21: 28:24 // mir::Constant // + span: $DIR/uninhabited_enum_branching.rs:28:21: 28:24 // + literal: Const { ty: &str, val: Value(Slice(..)) } - _6 = &(*_9); // scope 0 at $DIR/uninhabited_enum_branching.rs:+9:21: +9:24 - StorageDead(_9); // scope 0 at $DIR/uninhabited_enum_branching.rs:+9:23: +9:24 - goto -> bb7; // scope 0 at $DIR/uninhabited_enum_branching.rs:+9:23: +9:24 + _6 = &(*_9); // scope 0 at $DIR/uninhabited_enum_branching.rs:28:21: 28:24 + StorageDead(_9); // scope 0 at $DIR/uninhabited_enum_branching.rs:28:23: 28:24 + goto -> bb7; // scope 0 at $DIR/uninhabited_enum_branching.rs:28:23: 28:24 } bb6: { - _6 = const "D"; // scope 0 at $DIR/uninhabited_enum_branching.rs:+8:21: +8:24 + _6 = const "D"; // scope 0 at $DIR/uninhabited_enum_branching.rs:27:21: 27:24 // mir::Constant // + span: $DIR/uninhabited_enum_branching.rs:27:21: 27:24 // + literal: Const { ty: &str, val: Value(Slice(..)) } - goto -> bb7; // scope 0 at $DIR/uninhabited_enum_branching.rs:+8:21: +8:24 + goto -> bb7; // scope 0 at $DIR/uninhabited_enum_branching.rs:27:21: 27:24 } bb7: { - StorageDead(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:+10:6: +10:7 - StorageDead(_6); // scope 0 at $DIR/uninhabited_enum_branching.rs:+10:6: +10:7 - _0 = const (); // scope 0 at $DIR/uninhabited_enum_branching.rs:+0:11: +11:2 - return; // scope 0 at $DIR/uninhabited_enum_branching.rs:+11:2: +11:2 + StorageDead(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:29:6: 29:7 + StorageDead(_6); // scope 0 at $DIR/uninhabited_enum_branching.rs:29:6: 29:7 + _0 = const (); // scope 0 at $DIR/uninhabited_enum_branching.rs:19:11: 30:2 + return; // scope 0 at $DIR/uninhabited_enum_branching.rs:30:2: 30:2 } } diff --git a/src/test/mir-opt/uninhabited_enum_branching2.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir b/src/test/mir-opt/uninhabited_enum_branching2.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir index a5e7f526928ac..77951bc8d7b67 100644 --- a/src/test/mir-opt/uninhabited_enum_branching2.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir +++ b/src/test/mir-opt/uninhabited_enum_branching2.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir @@ -1,96 +1,96 @@ // MIR for `main` after SimplifyCfg-after-uninhabited-enum-branching fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/uninhabited_enum_branching2.rs:+0:11: +0:11 - let _1: Plop; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:9: +1:13 - let mut _2: Test1; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:38: +1:46 - let _3: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+3:5: +8:6 - let mut _4: &Test1; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+3:11: +3:22 - let mut _5: isize; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+4:9: +4:20 - let _6: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+5:24: +5:34 - let _7: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+6:21: +6:24 - let _8: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+7:21: +7:24 - let _9: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+10:5: +15:6 - let mut _10: isize; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+11:9: +11:20 - let _11: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+12:24: +12:34 - let _12: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+13:21: +13:24 - let _13: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+14:21: +14:24 + let mut _0: (); // return place in scope 0 at $DIR/uninhabited_enum_branching2.rs:18:11: 18:11 + let _1: Plop; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:19:9: 19:13 + let mut _2: Test1; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:19:38: 19:46 + let _3: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:21:5: 26:6 + let mut _4: &Test1; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:21:11: 21:22 + let mut _5: isize; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:22:9: 22:20 + let _6: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:23:24: 23:34 + let _7: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:24:21: 24:24 + let _8: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:25:21: 25:24 + let _9: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:28:5: 33:6 + let mut _10: isize; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:29:9: 29:20 + let _11: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:30:24: 30:34 + let _12: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:31:21: 31:24 + let _13: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:32:21: 32:24 scope 1 { - debug plop => _1; // in scope 1 at $DIR/uninhabited_enum_branching2.rs:+1:9: +1:13 + debug plop => _1; // in scope 1 at $DIR/uninhabited_enum_branching2.rs:19:9: 19:13 } bb0: { - StorageLive(_1); // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:9: +1:13 - StorageLive(_2); // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:38: +1:46 - Deinit(_2); // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:38: +1:46 - discriminant(_2) = 2; // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:38: +1:46 - Deinit(_1); // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:16: +1:48 - (_1.0: u32) = const 51_u32; // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:16: +1:48 - (_1.1: Test1) = move _2; // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:16: +1:48 - StorageDead(_2); // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:47: +1:48 - StorageLive(_3); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:5: +8:6 - StorageLive(_4); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:11: +3:22 - _4 = &(_1.1: Test1); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:11: +3:22 - _5 = discriminant((*_4)); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:11: +3:22 - switchInt(move _5) -> [2_isize: bb2, otherwise: bb1]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:5: +3:22 + StorageLive(_1); // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:9: 19:13 + StorageLive(_2); // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:38: 19:46 + Deinit(_2); // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:38: 19:46 + discriminant(_2) = 2; // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:38: 19:46 + Deinit(_1); // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:16: 19:48 + (_1.0: u32) = const 51_u32; // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:16: 19:48 + (_1.1: Test1) = move _2; // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:16: 19:48 + StorageDead(_2); // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:47: 19:48 + StorageLive(_3); // scope 1 at $DIR/uninhabited_enum_branching2.rs:21:5: 26:6 + StorageLive(_4); // scope 1 at $DIR/uninhabited_enum_branching2.rs:21:11: 21:22 + _4 = &(_1.1: Test1); // scope 1 at $DIR/uninhabited_enum_branching2.rs:21:11: 21:22 + _5 = discriminant((*_4)); // scope 1 at $DIR/uninhabited_enum_branching2.rs:21:11: 21:22 + switchInt(move _5) -> [2_isize: bb2, otherwise: bb1]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:21:5: 21:22 } bb1: { - StorageLive(_8); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+7:21: +7:24 - _8 = const "D"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+7:21: +7:24 + StorageLive(_8); // scope 1 at $DIR/uninhabited_enum_branching2.rs:25:21: 25:24 + _8 = const "D"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:25:21: 25:24 // mir::Constant // + span: $DIR/uninhabited_enum_branching2.rs:25:21: 25:24 // + literal: Const { ty: &str, val: Value(Slice(..)) } - _3 = &(*_8); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+7:21: +7:24 - StorageDead(_8); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+7:23: +7:24 - goto -> bb3; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+7:23: +7:24 + _3 = &(*_8); // scope 1 at $DIR/uninhabited_enum_branching2.rs:25:21: 25:24 + StorageDead(_8); // scope 1 at $DIR/uninhabited_enum_branching2.rs:25:23: 25:24 + goto -> bb3; // scope 1 at $DIR/uninhabited_enum_branching2.rs:25:23: 25:24 } bb2: { - StorageLive(_7); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+6:21: +6:24 - _7 = const "C"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+6:21: +6:24 + StorageLive(_7); // scope 1 at $DIR/uninhabited_enum_branching2.rs:24:21: 24:24 + _7 = const "C"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:24:21: 24:24 // mir::Constant // + span: $DIR/uninhabited_enum_branching2.rs:24:21: 24:24 // + literal: Const { ty: &str, val: Value(Slice(..)) } - _3 = &(*_7); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+6:21: +6:24 - StorageDead(_7); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+6:23: +6:24 - goto -> bb3; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+6:23: +6:24 + _3 = &(*_7); // scope 1 at $DIR/uninhabited_enum_branching2.rs:24:21: 24:24 + StorageDead(_7); // scope 1 at $DIR/uninhabited_enum_branching2.rs:24:23: 24:24 + goto -> bb3; // scope 1 at $DIR/uninhabited_enum_branching2.rs:24:23: 24:24 } bb3: { - StorageDead(_4); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+8:6: +8:7 - StorageDead(_3); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+8:6: +8:7 - StorageLive(_9); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:5: +15:6 - _10 = discriminant((_1.1: Test1)); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:11: +10:21 - switchInt(move _10) -> [2_isize: bb5, otherwise: bb4]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:5: +10:21 + StorageDead(_4); // scope 1 at $DIR/uninhabited_enum_branching2.rs:26:6: 26:7 + StorageDead(_3); // scope 1 at $DIR/uninhabited_enum_branching2.rs:26:6: 26:7 + StorageLive(_9); // scope 1 at $DIR/uninhabited_enum_branching2.rs:28:5: 33:6 + _10 = discriminant((_1.1: Test1)); // scope 1 at $DIR/uninhabited_enum_branching2.rs:28:11: 28:21 + switchInt(move _10) -> [2_isize: bb5, otherwise: bb4]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:28:5: 28:21 } bb4: { - StorageLive(_13); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+14:21: +14:24 - _13 = const "D"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+14:21: +14:24 + StorageLive(_13); // scope 1 at $DIR/uninhabited_enum_branching2.rs:32:21: 32:24 + _13 = const "D"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:32:21: 32:24 // mir::Constant // + span: $DIR/uninhabited_enum_branching2.rs:32:21: 32:24 // + literal: Const { ty: &str, val: Value(Slice(..)) } - _9 = &(*_13); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+14:21: +14:24 - StorageDead(_13); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+14:23: +14:24 - goto -> bb6; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+14:23: +14:24 + _9 = &(*_13); // scope 1 at $DIR/uninhabited_enum_branching2.rs:32:21: 32:24 + StorageDead(_13); // scope 1 at $DIR/uninhabited_enum_branching2.rs:32:23: 32:24 + goto -> bb6; // scope 1 at $DIR/uninhabited_enum_branching2.rs:32:23: 32:24 } bb5: { - StorageLive(_12); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+13:21: +13:24 - _12 = const "C"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+13:21: +13:24 + StorageLive(_12); // scope 1 at $DIR/uninhabited_enum_branching2.rs:31:21: 31:24 + _12 = const "C"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:31:21: 31:24 // mir::Constant // + span: $DIR/uninhabited_enum_branching2.rs:31:21: 31:24 // + literal: Const { ty: &str, val: Value(Slice(..)) } - _9 = &(*_12); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+13:21: +13:24 - StorageDead(_12); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+13:23: +13:24 - goto -> bb6; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+13:23: +13:24 + _9 = &(*_12); // scope 1 at $DIR/uninhabited_enum_branching2.rs:31:21: 31:24 + StorageDead(_12); // scope 1 at $DIR/uninhabited_enum_branching2.rs:31:23: 31:24 + goto -> bb6; // scope 1 at $DIR/uninhabited_enum_branching2.rs:31:23: 31:24 } bb6: { - StorageDead(_9); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+15:6: +15:7 - _0 = const (); // scope 0 at $DIR/uninhabited_enum_branching2.rs:+0:11: +16:2 - StorageDead(_1); // scope 0 at $DIR/uninhabited_enum_branching2.rs:+16:1: +16:2 - return; // scope 0 at $DIR/uninhabited_enum_branching2.rs:+16:2: +16:2 + StorageDead(_9); // scope 1 at $DIR/uninhabited_enum_branching2.rs:33:6: 33:7 + _0 = const (); // scope 0 at $DIR/uninhabited_enum_branching2.rs:18:11: 34:2 + StorageDead(_1); // scope 0 at $DIR/uninhabited_enum_branching2.rs:34:1: 34:2 + return; // scope 0 at $DIR/uninhabited_enum_branching2.rs:34:2: 34:2 } } diff --git a/src/test/mir-opt/uninhabited_enum_branching2.main.UninhabitedEnumBranching.diff b/src/test/mir-opt/uninhabited_enum_branching2.main.UninhabitedEnumBranching.diff index 157518491f19a..1b06c730cdab6 100644 --- a/src/test/mir-opt/uninhabited_enum_branching2.main.UninhabitedEnumBranching.diff +++ b/src/test/mir-opt/uninhabited_enum_branching2.main.UninhabitedEnumBranching.diff @@ -2,137 +2,137 @@ + // MIR for `main` after UninhabitedEnumBranching fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/uninhabited_enum_branching2.rs:+0:11: +0:11 - let _1: Plop; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:9: +1:13 - let mut _2: Test1; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:38: +1:46 - let _3: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+3:5: +8:6 - let mut _4: &Test1; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+3:11: +3:22 - let mut _5: isize; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+4:9: +4:20 - let _6: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+5:24: +5:34 - let _7: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+6:21: +6:24 - let _8: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+7:21: +7:24 - let _9: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+10:5: +15:6 - let mut _10: isize; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+11:9: +11:20 - let _11: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+12:24: +12:34 - let _12: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+13:21: +13:24 - let _13: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:+14:21: +14:24 + let mut _0: (); // return place in scope 0 at $DIR/uninhabited_enum_branching2.rs:18:11: 18:11 + let _1: Plop; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:19:9: 19:13 + let mut _2: Test1; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:19:38: 19:46 + let _3: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:21:5: 26:6 + let mut _4: &Test1; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:21:11: 21:22 + let mut _5: isize; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:22:9: 22:20 + let _6: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:23:24: 23:34 + let _7: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:24:21: 24:24 + let _8: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:25:21: 25:24 + let _9: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:28:5: 33:6 + let mut _10: isize; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:29:9: 29:20 + let _11: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:30:24: 30:34 + let _12: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:31:21: 31:24 + let _13: &str; // in scope 0 at $DIR/uninhabited_enum_branching2.rs:32:21: 32:24 scope 1 { - debug plop => _1; // in scope 1 at $DIR/uninhabited_enum_branching2.rs:+1:9: +1:13 + debug plop => _1; // in scope 1 at $DIR/uninhabited_enum_branching2.rs:19:9: 19:13 } bb0: { - StorageLive(_1); // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:9: +1:13 - StorageLive(_2); // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:38: +1:46 - Deinit(_2); // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:38: +1:46 - discriminant(_2) = 2; // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:38: +1:46 - Deinit(_1); // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:16: +1:48 - (_1.0: u32) = const 51_u32; // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:16: +1:48 - (_1.1: Test1) = move _2; // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:16: +1:48 - StorageDead(_2); // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:47: +1:48 - StorageLive(_3); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:5: +8:6 - StorageLive(_4); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:11: +3:22 - _4 = &(_1.1: Test1); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:11: +3:22 - _5 = discriminant((*_4)); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:11: +3:22 -- switchInt(move _5) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, otherwise: bb1]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:5: +3:22 -+ switchInt(move _5) -> [2_isize: bb4, otherwise: bb1]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:5: +3:22 + StorageLive(_1); // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:9: 19:13 + StorageLive(_2); // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:38: 19:46 + Deinit(_2); // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:38: 19:46 + discriminant(_2) = 2; // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:38: 19:46 + Deinit(_1); // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:16: 19:48 + (_1.0: u32) = const 51_u32; // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:16: 19:48 + (_1.1: Test1) = move _2; // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:16: 19:48 + StorageDead(_2); // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:47: 19:48 + StorageLive(_3); // scope 1 at $DIR/uninhabited_enum_branching2.rs:21:5: 26:6 + StorageLive(_4); // scope 1 at $DIR/uninhabited_enum_branching2.rs:21:11: 21:22 + _4 = &(_1.1: Test1); // scope 1 at $DIR/uninhabited_enum_branching2.rs:21:11: 21:22 + _5 = discriminant((*_4)); // scope 1 at $DIR/uninhabited_enum_branching2.rs:21:11: 21:22 +- switchInt(move _5) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, otherwise: bb1]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:21:5: 21:22 ++ switchInt(move _5) -> [2_isize: bb4, otherwise: bb1]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:21:5: 21:22 } bb1: { - StorageLive(_8); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+7:21: +7:24 - _8 = const "D"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+7:21: +7:24 + StorageLive(_8); // scope 1 at $DIR/uninhabited_enum_branching2.rs:25:21: 25:24 + _8 = const "D"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:25:21: 25:24 // mir::Constant // + span: $DIR/uninhabited_enum_branching2.rs:25:21: 25:24 // + literal: Const { ty: &str, val: Value(Slice(..)) } - _3 = &(*_8); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+7:21: +7:24 - StorageDead(_8); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+7:23: +7:24 - goto -> bb5; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+7:23: +7:24 + _3 = &(*_8); // scope 1 at $DIR/uninhabited_enum_branching2.rs:25:21: 25:24 + StorageDead(_8); // scope 1 at $DIR/uninhabited_enum_branching2.rs:25:23: 25:24 + goto -> bb5; // scope 1 at $DIR/uninhabited_enum_branching2.rs:25:23: 25:24 } bb2: { - _3 = const "A(Empty)"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+4:24: +4:34 + _3 = const "A(Empty)"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:22:24: 22:34 // mir::Constant // + span: $DIR/uninhabited_enum_branching2.rs:22:24: 22:34 // + literal: Const { ty: &str, val: Value(Slice(..)) } - goto -> bb5; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+4:24: +4:34 + goto -> bb5; // scope 1 at $DIR/uninhabited_enum_branching2.rs:22:24: 22:34 } bb3: { - StorageLive(_6); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+5:24: +5:34 - _6 = const "B(Empty)"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+5:24: +5:34 + StorageLive(_6); // scope 1 at $DIR/uninhabited_enum_branching2.rs:23:24: 23:34 + _6 = const "B(Empty)"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:23:24: 23:34 // mir::Constant // + span: $DIR/uninhabited_enum_branching2.rs:23:24: 23:34 // + literal: Const { ty: &str, val: Value(Slice(..)) } - _3 = &(*_6); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+5:24: +5:34 - StorageDead(_6); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+5:33: +5:34 - goto -> bb5; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+5:33: +5:34 + _3 = &(*_6); // scope 1 at $DIR/uninhabited_enum_branching2.rs:23:24: 23:34 + StorageDead(_6); // scope 1 at $DIR/uninhabited_enum_branching2.rs:23:33: 23:34 + goto -> bb5; // scope 1 at $DIR/uninhabited_enum_branching2.rs:23:33: 23:34 } bb4: { - StorageLive(_7); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+6:21: +6:24 - _7 = const "C"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+6:21: +6:24 + StorageLive(_7); // scope 1 at $DIR/uninhabited_enum_branching2.rs:24:21: 24:24 + _7 = const "C"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:24:21: 24:24 // mir::Constant // + span: $DIR/uninhabited_enum_branching2.rs:24:21: 24:24 // + literal: Const { ty: &str, val: Value(Slice(..)) } - _3 = &(*_7); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+6:21: +6:24 - StorageDead(_7); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+6:23: +6:24 - goto -> bb5; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+6:23: +6:24 + _3 = &(*_7); // scope 1 at $DIR/uninhabited_enum_branching2.rs:24:21: 24:24 + StorageDead(_7); // scope 1 at $DIR/uninhabited_enum_branching2.rs:24:23: 24:24 + goto -> bb5; // scope 1 at $DIR/uninhabited_enum_branching2.rs:24:23: 24:24 } bb5: { - StorageDead(_4); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+8:6: +8:7 - StorageDead(_3); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+8:6: +8:7 - StorageLive(_9); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:5: +15:6 - _10 = discriminant((_1.1: Test1)); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:11: +10:21 -- switchInt(move _10) -> [0_isize: bb7, 1_isize: bb8, 2_isize: bb9, otherwise: bb6]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:5: +10:21 -+ switchInt(move _10) -> [2_isize: bb9, otherwise: bb6]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:5: +10:21 + StorageDead(_4); // scope 1 at $DIR/uninhabited_enum_branching2.rs:26:6: 26:7 + StorageDead(_3); // scope 1 at $DIR/uninhabited_enum_branching2.rs:26:6: 26:7 + StorageLive(_9); // scope 1 at $DIR/uninhabited_enum_branching2.rs:28:5: 33:6 + _10 = discriminant((_1.1: Test1)); // scope 1 at $DIR/uninhabited_enum_branching2.rs:28:11: 28:21 +- switchInt(move _10) -> [0_isize: bb7, 1_isize: bb8, 2_isize: bb9, otherwise: bb6]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:28:5: 28:21 ++ switchInt(move _10) -> [2_isize: bb9, otherwise: bb6]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:28:5: 28:21 } bb6: { - StorageLive(_13); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+14:21: +14:24 - _13 = const "D"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+14:21: +14:24 + StorageLive(_13); // scope 1 at $DIR/uninhabited_enum_branching2.rs:32:21: 32:24 + _13 = const "D"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:32:21: 32:24 // mir::Constant // + span: $DIR/uninhabited_enum_branching2.rs:32:21: 32:24 // + literal: Const { ty: &str, val: Value(Slice(..)) } - _9 = &(*_13); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+14:21: +14:24 - StorageDead(_13); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+14:23: +14:24 - goto -> bb10; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+14:23: +14:24 + _9 = &(*_13); // scope 1 at $DIR/uninhabited_enum_branching2.rs:32:21: 32:24 + StorageDead(_13); // scope 1 at $DIR/uninhabited_enum_branching2.rs:32:23: 32:24 + goto -> bb10; // scope 1 at $DIR/uninhabited_enum_branching2.rs:32:23: 32:24 } bb7: { - _9 = const "A(Empty)"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+11:24: +11:34 + _9 = const "A(Empty)"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:29:24: 29:34 // mir::Constant // + span: $DIR/uninhabited_enum_branching2.rs:29:24: 29:34 // + literal: Const { ty: &str, val: Value(Slice(..)) } - goto -> bb10; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+11:24: +11:34 + goto -> bb10; // scope 1 at $DIR/uninhabited_enum_branching2.rs:29:24: 29:34 } bb8: { - StorageLive(_11); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+12:24: +12:34 - _11 = const "B(Empty)"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+12:24: +12:34 + StorageLive(_11); // scope 1 at $DIR/uninhabited_enum_branching2.rs:30:24: 30:34 + _11 = const "B(Empty)"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:30:24: 30:34 // mir::Constant // + span: $DIR/uninhabited_enum_branching2.rs:30:24: 30:34 // + literal: Const { ty: &str, val: Value(Slice(..)) } - _9 = &(*_11); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+12:24: +12:34 - StorageDead(_11); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+12:33: +12:34 - goto -> bb10; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+12:33: +12:34 + _9 = &(*_11); // scope 1 at $DIR/uninhabited_enum_branching2.rs:30:24: 30:34 + StorageDead(_11); // scope 1 at $DIR/uninhabited_enum_branching2.rs:30:33: 30:34 + goto -> bb10; // scope 1 at $DIR/uninhabited_enum_branching2.rs:30:33: 30:34 } bb9: { - StorageLive(_12); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+13:21: +13:24 - _12 = const "C"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+13:21: +13:24 + StorageLive(_12); // scope 1 at $DIR/uninhabited_enum_branching2.rs:31:21: 31:24 + _12 = const "C"; // scope 1 at $DIR/uninhabited_enum_branching2.rs:31:21: 31:24 // mir::Constant // + span: $DIR/uninhabited_enum_branching2.rs:31:21: 31:24 // + literal: Const { ty: &str, val: Value(Slice(..)) } - _9 = &(*_12); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+13:21: +13:24 - StorageDead(_12); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+13:23: +13:24 - goto -> bb10; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+13:23: +13:24 + _9 = &(*_12); // scope 1 at $DIR/uninhabited_enum_branching2.rs:31:21: 31:24 + StorageDead(_12); // scope 1 at $DIR/uninhabited_enum_branching2.rs:31:23: 31:24 + goto -> bb10; // scope 1 at $DIR/uninhabited_enum_branching2.rs:31:23: 31:24 } bb10: { - StorageDead(_9); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+15:6: +15:7 - _0 = const (); // scope 0 at $DIR/uninhabited_enum_branching2.rs:+0:11: +16:2 - StorageDead(_1); // scope 0 at $DIR/uninhabited_enum_branching2.rs:+16:1: +16:2 - return; // scope 0 at $DIR/uninhabited_enum_branching2.rs:+16:2: +16:2 + StorageDead(_9); // scope 1 at $DIR/uninhabited_enum_branching2.rs:33:6: 33:7 + _0 = const (); // scope 0 at $DIR/uninhabited_enum_branching2.rs:18:11: 34:2 + StorageDead(_1); // scope 0 at $DIR/uninhabited_enum_branching2.rs:34:1: 34:2 + return; // scope 0 at $DIR/uninhabited_enum_branching2.rs:34:2: 34:2 } } diff --git a/src/test/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff b/src/test/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff index 11d93fca7e086..7e843b65e88fc 100644 --- a/src/test/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff +++ b/src/test/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff @@ -2,37 +2,37 @@ + // MIR for `eliminate_fallthrough` after UninhabitedEnumBranching fn eliminate_fallthrough(_1: S) -> u32 { - debug s => _1; // in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+0:26: +0:27 - let mut _0: u32; // return place in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+0:35: +0:38 - let mut _2: isize; // in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+2:9: +2:10 + debug s => _1; // in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:21:26: 21:27 + let mut _0: u32; // return place in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:21:35: 21:38 + let mut _2: isize; // in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:23:9: 23:10 bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+1:11: +1:12 -- switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+1:5: +1:12 -+ switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb5]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+1:5: +1:12 + _2 = discriminant(_1); // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:11: 22:12 +- switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:5: 22:12 ++ switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb5]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:5: 22:12 } bb1: { - _0 = const 3_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+4:14: +4:15 - goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+4:14: +4:15 + _0 = const 3_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:25:14: 25:15 + goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:25:14: 25:15 } bb2: { - _0 = const 1_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+2:14: +2:15 - goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+2:14: +2:15 + _0 = const 1_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:23:14: 23:15 + goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:23:14: 23:15 } bb3: { - _0 = const 2_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+3:14: +3:15 - goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+3:14: +3:15 + _0 = const 2_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:24:14: 24:15 + goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:24:14: 24:15 } bb4: { - return; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+6:2: +6:2 + return; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:27:2: 27:2 + } + + bb5: { -+ unreachable; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+4:14: +4:15 ++ unreachable; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:25:14: 25:15 } } diff --git a/src/test/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff b/src/test/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff index a7f8321ae34ba..5da011d427a2c 100644 --- a/src/test/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff +++ b/src/test/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff @@ -2,33 +2,33 @@ + // MIR for `keep_fallthrough` after UninhabitedEnumBranching fn keep_fallthrough(_1: S) -> u32 { - debug s => _1; // in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+0:21: +0:22 - let mut _0: u32; // return place in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+0:30: +0:33 - let mut _2: isize; // in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+2:9: +2:13 + debug s => _1; // in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:12:21: 12:22 + let mut _0: u32; // return place in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:12:30: 12:33 + let mut _2: isize; // in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:14:9: 14:13 bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+1:11: +1:12 -- switchInt(move _2) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+1:5: +1:12 -+ switchInt(move _2) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+1:5: +1:12 + _2 = discriminant(_1); // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:13:11: 13:12 +- switchInt(move _2) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:13:5: 13:12 ++ switchInt(move _2) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:13:5: 13:12 } bb1: { - _0 = const 3_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+4:14: +4:15 - goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+4:14: +4:15 + _0 = const 3_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:16:14: 16:15 + goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:16:14: 16:15 } bb2: { - _0 = const 1_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+2:17: +2:18 - goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+2:17: +2:18 + _0 = const 1_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:14:17: 14:18 + goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:14:17: 14:18 } bb3: { - _0 = const 2_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+3:14: +3:15 - goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+3:14: +3:15 + _0 = const 2_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:15:14: 15:15 + goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:15:14: 15:15 } bb4: { - return; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+6:2: +6:2 + return; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:18:2: 18:2 } } diff --git a/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff index 52d9543e97807..5aa4f1b343249 100644 --- a/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff +++ b/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff @@ -2,68 +2,68 @@ + // MIR for `main` after UnreachablePropagation fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/unreachable.rs:+0:11: +0:11 - let mut _1: std::option::Option; // in scope 0 at $DIR/unreachable.rs:+1:23: +1:30 - let mut _2: isize; // in scope 0 at $DIR/unreachable.rs:+1:12: +1:20 - let _5: (); // in scope 0 at $DIR/unreachable.rs:+4:9: +8:10 - let mut _6: bool; // in scope 0 at $DIR/unreachable.rs:+4:12: +4:16 - let mut _7: !; // in scope 0 at $DIR/unreachable.rs:+10:9: +10:21 + let mut _0: (); // return place in scope 0 at $DIR/unreachable.rs:8:11: 8:11 + let mut _1: std::option::Option; // in scope 0 at $DIR/unreachable.rs:9:23: 9:30 + let mut _2: isize; // in scope 0 at $DIR/unreachable.rs:9:12: 9:20 + let _5: (); // in scope 0 at $DIR/unreachable.rs:12:9: 16:10 + let mut _6: bool; // in scope 0 at $DIR/unreachable.rs:12:12: 12:16 + let mut _7: !; // in scope 0 at $DIR/unreachable.rs:18:9: 18:21 scope 1 { - debug _x => _3; // in scope 1 at $DIR/unreachable.rs:+1:17: +1:19 - let _3: Empty; // in scope 1 at $DIR/unreachable.rs:+1:17: +1:19 - let mut _4: i32; // in scope 1 at $DIR/unreachable.rs:+2:13: +2:19 + debug _x => _3; // in scope 1 at $DIR/unreachable.rs:9:17: 9:19 + let _3: Empty; // in scope 1 at $DIR/unreachable.rs:9:17: 9:19 + let mut _4: i32; // in scope 1 at $DIR/unreachable.rs:10:13: 10:19 scope 2 { - debug _y => _4; // in scope 2 at $DIR/unreachable.rs:+2:13: +2:19 + debug _y => _4; // in scope 2 at $DIR/unreachable.rs:10:13: 10:19 } } bb0: { - StorageLive(_1); // scope 1 at $DIR/unreachable.rs:+1:23: +1:30 - _1 = empty() -> bb1; // scope 1 at $DIR/unreachable.rs:+1:23: +1:30 + StorageLive(_1); // scope 1 at $DIR/unreachable.rs:9:23: 9:30 + _1 = empty() -> bb1; // scope 1 at $DIR/unreachable.rs:9:23: 9:30 // mir::Constant // + span: $DIR/unreachable.rs:9:23: 9:28 // + literal: Const { ty: fn() -> Option {empty}, val: Value() } } bb1: { - _2 = discriminant(_1); // scope 1 at $DIR/unreachable.rs:+1:12: +1:20 -- switchInt(move _2) -> [1_isize: bb2, otherwise: bb6]; // scope 1 at $DIR/unreachable.rs:+1:12: +1:20 -+ goto -> bb2; // scope 1 at $DIR/unreachable.rs:+1:12: +1:20 + _2 = discriminant(_1); // scope 1 at $DIR/unreachable.rs:9:12: 9:20 +- switchInt(move _2) -> [1_isize: bb2, otherwise: bb6]; // scope 1 at $DIR/unreachable.rs:9:12: 9:20 ++ goto -> bb2; // scope 1 at $DIR/unreachable.rs:9:12: 9:20 } bb2: { -- StorageLive(_3); // scope 1 at $DIR/unreachable.rs:+1:17: +1:19 -- _3 = move ((_1 as Some).0: Empty); // scope 1 at $DIR/unreachable.rs:+1:17: +1:19 -- StorageLive(_4); // scope 1 at $DIR/unreachable.rs:+2:13: +2:19 -- StorageLive(_5); // scope 2 at $DIR/unreachable.rs:+4:9: +8:10 -- StorageLive(_6); // scope 2 at $DIR/unreachable.rs:+4:12: +4:16 -- _6 = const true; // scope 2 at $DIR/unreachable.rs:+4:12: +4:16 -- switchInt(move _6) -> [false: bb4, otherwise: bb3]; // scope 2 at $DIR/unreachable.rs:+4:12: +4:16 +- StorageLive(_3); // scope 1 at $DIR/unreachable.rs:9:17: 9:19 +- _3 = move ((_1 as Some).0: Empty); // scope 1 at $DIR/unreachable.rs:9:17: 9:19 +- StorageLive(_4); // scope 1 at $DIR/unreachable.rs:10:13: 10:19 +- StorageLive(_5); // scope 2 at $DIR/unreachable.rs:12:9: 16:10 +- StorageLive(_6); // scope 2 at $DIR/unreachable.rs:12:12: 12:16 +- _6 = const true; // scope 2 at $DIR/unreachable.rs:12:12: 12:16 +- switchInt(move _6) -> [false: bb4, otherwise: bb3]; // scope 2 at $DIR/unreachable.rs:12:12: 12:16 - } - - bb3: { -- _4 = const 21_i32; // scope 2 at $DIR/unreachable.rs:+5:13: +5:20 -- _5 = const (); // scope 2 at $DIR/unreachable.rs:+4:17: +6:10 -- goto -> bb5; // scope 2 at $DIR/unreachable.rs:+4:9: +8:10 +- _4 = const 21_i32; // scope 2 at $DIR/unreachable.rs:13:13: 13:20 +- _5 = const (); // scope 2 at $DIR/unreachable.rs:12:17: 14:10 +- goto -> bb5; // scope 2 at $DIR/unreachable.rs:12:9: 16:10 - } - - bb4: { -- _4 = const 42_i32; // scope 2 at $DIR/unreachable.rs:+7:13: +7:20 -- _5 = const (); // scope 2 at $DIR/unreachable.rs:+6:16: +8:10 -- goto -> bb5; // scope 2 at $DIR/unreachable.rs:+4:9: +8:10 +- _4 = const 42_i32; // scope 2 at $DIR/unreachable.rs:15:13: 15:20 +- _5 = const (); // scope 2 at $DIR/unreachable.rs:14:16: 16:10 +- goto -> bb5; // scope 2 at $DIR/unreachable.rs:12:9: 16:10 - } - - bb5: { -- StorageDead(_6); // scope 2 at $DIR/unreachable.rs:+8:9: +8:10 -- StorageDead(_5); // scope 2 at $DIR/unreachable.rs:+8:9: +8:10 -- StorageLive(_7); // scope 2 at $DIR/unreachable.rs:+10:9: +10:21 -- unreachable; // scope 2 at $DIR/unreachable.rs:+10:15: +10:17 +- StorageDead(_6); // scope 2 at $DIR/unreachable.rs:16:9: 16:10 +- StorageDead(_5); // scope 2 at $DIR/unreachable.rs:16:9: 16:10 +- StorageLive(_7); // scope 2 at $DIR/unreachable.rs:18:9: 18:21 +- unreachable; // scope 2 at $DIR/unreachable.rs:18:15: 18:17 - } - - bb6: { - _0 = const (); // scope 0 at $DIR/unreachable.rs:+11:6: +11:6 - StorageDead(_1); // scope 0 at $DIR/unreachable.rs:+12:1: +12:2 - return; // scope 0 at $DIR/unreachable.rs:+12:2: +12:2 + _0 = const (); // scope 0 at $DIR/unreachable.rs:19:6: 19:6 + StorageDead(_1); // scope 0 at $DIR/unreachable.rs:20:1: 20:2 + return; // scope 0 at $DIR/unreachable.rs:20:2: 20:2 } } diff --git a/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff index 3d31553c44a5c..b95ab881ef05d 100644 --- a/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff +++ b/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff @@ -2,73 +2,73 @@ + // MIR for `main` after UnreachablePropagation fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/unreachable_diverging.rs:+0:11: +0:11 - let _1: bool; // in scope 0 at $DIR/unreachable_diverging.rs:+1:9: +1:10 - let mut _2: std::option::Option; // in scope 0 at $DIR/unreachable_diverging.rs:+2:25: +2:32 - let mut _3: isize; // in scope 0 at $DIR/unreachable_diverging.rs:+2:12: +2:22 - let _5: (); // in scope 0 at $DIR/unreachable_diverging.rs:+3:9: +5:10 - let mut _6: bool; // in scope 0 at $DIR/unreachable_diverging.rs:+3:12: +3:13 - let mut _7: !; // in scope 0 at $DIR/unreachable_diverging.rs:+6:9: +6:22 + let mut _0: (); // return place in scope 0 at $DIR/unreachable_diverging.rs:12:11: 12:11 + let _1: bool; // in scope 0 at $DIR/unreachable_diverging.rs:13:9: 13:10 + let mut _2: std::option::Option; // in scope 0 at $DIR/unreachable_diverging.rs:14:25: 14:32 + let mut _3: isize; // in scope 0 at $DIR/unreachable_diverging.rs:14:12: 14:22 + let _5: (); // in scope 0 at $DIR/unreachable_diverging.rs:15:9: 17:10 + let mut _6: bool; // in scope 0 at $DIR/unreachable_diverging.rs:15:12: 15:13 + let mut _7: !; // in scope 0 at $DIR/unreachable_diverging.rs:18:9: 18:22 scope 1 { - debug x => _1; // in scope 1 at $DIR/unreachable_diverging.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/unreachable_diverging.rs:13:9: 13:10 scope 2 { - debug bomb => _4; // in scope 2 at $DIR/unreachable_diverging.rs:+2:17: +2:21 - let _4: Empty; // in scope 2 at $DIR/unreachable_diverging.rs:+2:17: +2:21 + debug bomb => _4; // in scope 2 at $DIR/unreachable_diverging.rs:14:17: 14:21 + let _4: Empty; // in scope 2 at $DIR/unreachable_diverging.rs:14:17: 14:21 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/unreachable_diverging.rs:+1:9: +1:10 - _1 = const true; // scope 0 at $DIR/unreachable_diverging.rs:+1:13: +1:17 - StorageLive(_2); // scope 2 at $DIR/unreachable_diverging.rs:+2:25: +2:32 - _2 = empty() -> bb1; // scope 2 at $DIR/unreachable_diverging.rs:+2:25: +2:32 + StorageLive(_1); // scope 0 at $DIR/unreachable_diverging.rs:13:9: 13:10 + _1 = const true; // scope 0 at $DIR/unreachable_diverging.rs:13:13: 13:17 + StorageLive(_2); // scope 2 at $DIR/unreachable_diverging.rs:14:25: 14:32 + _2 = empty() -> bb1; // scope 2 at $DIR/unreachable_diverging.rs:14:25: 14:32 // mir::Constant // + span: $DIR/unreachable_diverging.rs:14:25: 14:30 // + literal: Const { ty: fn() -> Option {empty}, val: Value() } } bb1: { - _3 = discriminant(_2); // scope 2 at $DIR/unreachable_diverging.rs:+2:12: +2:22 -- switchInt(move _3) -> [1_isize: bb2, otherwise: bb6]; // scope 2 at $DIR/unreachable_diverging.rs:+2:12: +2:22 -+ switchInt(move _3) -> [1_isize: bb2, otherwise: bb5]; // scope 2 at $DIR/unreachable_diverging.rs:+2:12: +2:22 + _3 = discriminant(_2); // scope 2 at $DIR/unreachable_diverging.rs:14:12: 14:22 +- switchInt(move _3) -> [1_isize: bb2, otherwise: bb6]; // scope 2 at $DIR/unreachable_diverging.rs:14:12: 14:22 ++ switchInt(move _3) -> [1_isize: bb2, otherwise: bb5]; // scope 2 at $DIR/unreachable_diverging.rs:14:12: 14:22 } bb2: { - StorageLive(_4); // scope 2 at $DIR/unreachable_diverging.rs:+2:17: +2:21 - _4 = move ((_2 as Some).0: Empty); // scope 2 at $DIR/unreachable_diverging.rs:+2:17: +2:21 - StorageLive(_5); // scope 2 at $DIR/unreachable_diverging.rs:+3:9: +5:10 - StorageLive(_6); // scope 2 at $DIR/unreachable_diverging.rs:+3:12: +3:13 - _6 = _1; // scope 2 at $DIR/unreachable_diverging.rs:+3:12: +3:13 -- switchInt(move _6) -> [false: bb4, otherwise: bb3]; // scope 2 at $DIR/unreachable_diverging.rs:+3:12: +3:13 -+ goto -> bb3; // scope 2 at $DIR/unreachable_diverging.rs:+3:12: +3:13 + StorageLive(_4); // scope 2 at $DIR/unreachable_diverging.rs:14:17: 14:21 + _4 = move ((_2 as Some).0: Empty); // scope 2 at $DIR/unreachable_diverging.rs:14:17: 14:21 + StorageLive(_5); // scope 2 at $DIR/unreachable_diverging.rs:15:9: 17:10 + StorageLive(_6); // scope 2 at $DIR/unreachable_diverging.rs:15:12: 15:13 + _6 = _1; // scope 2 at $DIR/unreachable_diverging.rs:15:12: 15:13 +- switchInt(move _6) -> [false: bb4, otherwise: bb3]; // scope 2 at $DIR/unreachable_diverging.rs:15:12: 15:13 ++ goto -> bb3; // scope 2 at $DIR/unreachable_diverging.rs:15:12: 15:13 } bb3: { -- _5 = loop_forever() -> bb5; // scope 2 at $DIR/unreachable_diverging.rs:+4:13: +4:27 -+ _5 = loop_forever() -> bb4; // scope 2 at $DIR/unreachable_diverging.rs:+4:13: +4:27 +- _5 = loop_forever() -> bb5; // scope 2 at $DIR/unreachable_diverging.rs:16:13: 16:27 ++ _5 = loop_forever() -> bb4; // scope 2 at $DIR/unreachable_diverging.rs:16:13: 16:27 // mir::Constant // + span: $DIR/unreachable_diverging.rs:16:13: 16:25 // + literal: Const { ty: fn() {loop_forever}, val: Value() } } bb4: { -- _5 = const (); // scope 2 at $DIR/unreachable_diverging.rs:+5:10: +5:10 -- goto -> bb5; // scope 2 at $DIR/unreachable_diverging.rs:+3:9: +5:10 +- _5 = const (); // scope 2 at $DIR/unreachable_diverging.rs:17:10: 17:10 +- goto -> bb5; // scope 2 at $DIR/unreachable_diverging.rs:15:9: 17:10 - } - - bb5: { - StorageDead(_6); // scope 2 at $DIR/unreachable_diverging.rs:+5:9: +5:10 - StorageDead(_5); // scope 2 at $DIR/unreachable_diverging.rs:+5:9: +5:10 - StorageLive(_7); // scope 2 at $DIR/unreachable_diverging.rs:+6:9: +6:22 - unreachable; // scope 2 at $DIR/unreachable_diverging.rs:+6:15: +6:19 + StorageDead(_6); // scope 2 at $DIR/unreachable_diverging.rs:17:9: 17:10 + StorageDead(_5); // scope 2 at $DIR/unreachable_diverging.rs:17:9: 17:10 + StorageLive(_7); // scope 2 at $DIR/unreachable_diverging.rs:18:9: 18:22 + unreachable; // scope 2 at $DIR/unreachable_diverging.rs:18:15: 18:19 } - bb6: { + bb5: { - _0 = const (); // scope 1 at $DIR/unreachable_diverging.rs:+7:6: +7:6 - StorageDead(_1); // scope 0 at $DIR/unreachable_diverging.rs:+8:1: +8:2 - StorageDead(_2); // scope 0 at $DIR/unreachable_diverging.rs:+8:1: +8:2 - return; // scope 0 at $DIR/unreachable_diverging.rs:+8:2: +8:2 + _0 = const (); // scope 1 at $DIR/unreachable_diverging.rs:19:6: 19:6 + StorageDead(_1); // scope 0 at $DIR/unreachable_diverging.rs:20:1: 20:2 + StorageDead(_2); // scope 0 at $DIR/unreachable_diverging.rs:20:1: 20:2 + return; // scope 0 at $DIR/unreachable_diverging.rs:20:2: 20:2 } } diff --git a/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir index a72e00ecde75f..7c7f03ea6ad3c 100644 --- a/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir +++ b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir @@ -1,10 +1,10 @@ // MIR for `E::V::{constant#0}` 0 mir_map E::V::{constant#0}: isize = { - let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10 + let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10 bb0: { - _0 = const 5_isize; // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10 - return; // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10 + _0 = const 5_isize; // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10 + return; // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10 } } diff --git a/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir index a72e00ecde75f..7c7f03ea6ad3c 100644 --- a/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir +++ b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir @@ -1,10 +1,10 @@ // MIR for `E::V::{constant#0}` 0 mir_map E::V::{constant#0}: isize = { - let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10 + let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10 bb0: { - _0 = const 5_isize; // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10 - return; // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10 + _0 = const 5_isize; // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10 + return; // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10 } } diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir index 0686af46ed58e..028281ba4501c 100644 --- a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir +++ b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir @@ -1,12 +1,12 @@ // MIR for `Test::X` 0 mir_map fn Test::X(_1: usize) -> Test { - let mut _0: Test; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6 + let mut _0: Test; // return place in scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 bb0: { - Deinit(_0); // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6 - ((_0 as X).0: usize) = move _1; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6 - discriminant(_0) = 0; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6 - return; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6 + Deinit(_0); // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 + ((_0 as X).0: usize) = move _1; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 + discriminant(_0) = 0; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 + return; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 } } diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir index 0686af46ed58e..028281ba4501c 100644 --- a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir +++ b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir @@ -1,12 +1,12 @@ // MIR for `Test::X` 0 mir_map fn Test::X(_1: usize) -> Test { - let mut _0: Test; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6 + let mut _0: Test; // return place in scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 bb0: { - Deinit(_0); // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6 - ((_0 as X).0: usize) = move _1; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6 - discriminant(_0) = 0; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6 - return; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6 + Deinit(_0); // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 + ((_0 as X).0: usize) = move _1; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 + discriminant(_0) = 0; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 + return; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 } } diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir index 7ffd242e0dc3b..54ecaccdb4fb8 100644 --- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir +++ b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir @@ -1,37 +1,37 @@ // MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops fn std::ptr::drop_in_place(_1: *mut Vec) -> () { - let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _2: &mut std::vec::Vec; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _2: &mut std::vec::Vec; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL bb0: { - goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb1: { - return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb2 (cleanup): { - resume; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + resume; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb3: { - goto -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + goto -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb4 (cleanup): { - drop(((*_1).0: alloc::raw_vec::RawVec)) -> bb2; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + drop(((*_1).0: alloc::raw_vec::RawVec)) -> bb2; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb5: { - drop(((*_1).0: alloc::raw_vec::RawVec)) -> [return: bb3, unwind: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + drop(((*_1).0: alloc::raw_vec::RawVec)) -> [return: bb3, unwind: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb6: { - _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _3 = as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _3 = as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL // + literal: Const { ty: for<'r> fn(&'r mut Vec) { as Drop>::drop}, val: Value() } diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir index 7ffd242e0dc3b..54ecaccdb4fb8 100644 --- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir +++ b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir @@ -1,37 +1,37 @@ // MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops fn std::ptr::drop_in_place(_1: *mut Vec) -> () { - let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _2: &mut std::vec::Vec; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _2: &mut std::vec::Vec; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL bb0: { - goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb1: { - return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb2 (cleanup): { - resume; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + resume; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb3: { - goto -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + goto -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb4 (cleanup): { - drop(((*_1).0: alloc::raw_vec::RawVec)) -> bb2; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + drop(((*_1).0: alloc::raw_vec::RawVec)) -> bb2; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb5: { - drop(((*_1).0: alloc::raw_vec::RawVec)) -> [return: bb3, unwind: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + drop(((*_1).0: alloc::raw_vec::RawVec)) -> [return: bb3, unwind: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL } bb6: { - _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _3 = as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _3 = as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL // + literal: Const { ty: for<'r> fn(&'r mut Vec) { as Drop>::drop}, val: Value() } diff --git a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir index f7bc8d58f480f..c41fe61d48bf1 100644 --- a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir +++ b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir @@ -1,10 +1,10 @@ // MIR for `::ASSOCIATED_CONSTANT` 0 mir_map const ::ASSOCIATED_CONSTANT: i32 = { - let mut _0: i32; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:32: +0:35 + let mut _0: i32; // return place in scope 0 at $DIR/unusual-item-types.rs:10:32: 10:35 bb0: { - _0 = const 2_i32; // scope 0 at $DIR/unusual-item-types.rs:+0:38: +0:39 - return; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:35 + _0 = const 2_i32; // scope 0 at $DIR/unusual-item-types.rs:10:38: 10:39 + return; // scope 0 at $DIR/unusual-item-types.rs:10:5: 10:35 } } diff --git a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir index f7bc8d58f480f..c41fe61d48bf1 100644 --- a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir +++ b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir @@ -1,10 +1,10 @@ // MIR for `::ASSOCIATED_CONSTANT` 0 mir_map const ::ASSOCIATED_CONSTANT: i32 = { - let mut _0: i32; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:32: +0:35 + let mut _0: i32; // return place in scope 0 at $DIR/unusual-item-types.rs:10:32: 10:35 bb0: { - _0 = const 2_i32; // scope 0 at $DIR/unusual-item-types.rs:+0:38: +0:39 - return; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:35 + _0 = const 2_i32; // scope 0 at $DIR/unusual-item-types.rs:10:38: 10:39 + return; // scope 0 at $DIR/unusual-item-types.rs:10:5: 10:35 } } diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff index eef7011149d3e..f8b41d7b4c5df 100644 --- a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff +++ b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff @@ -2,54 +2,54 @@ + // MIR for `change_loop_body` after ConstProp fn change_loop_body() -> () { - let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27 - let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15 - let mut _2: (); // in scope 0 at $DIR/while_let_loops.rs:+0:1: +6:2 - let mut _3: std::option::Option; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32 - let mut _4: isize; // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25 - let mut _5: !; // in scope 0 at $DIR/while_let_loops.rs:+2:33: +5:6 - let mut _6: !; // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6 - let _7: (); // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6 - let mut _8: !; // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6 + let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:5:27: 5:27 + let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:6:9: 6:15 + let mut _2: (); // in scope 0 at $DIR/while_let_loops.rs:5:1: 11:2 + let mut _3: std::option::Option; // in scope 0 at $DIR/while_let_loops.rs:7:28: 7:32 + let mut _4: isize; // in scope 0 at $DIR/while_let_loops.rs:7:15: 7:25 + let mut _5: !; // in scope 0 at $DIR/while_let_loops.rs:7:33: 10:6 + let mut _6: !; // in scope 0 at $DIR/while_let_loops.rs:7:5: 10:6 + let _7: (); // in scope 0 at $DIR/while_let_loops.rs:7:5: 10:6 + let mut _8: !; // in scope 0 at $DIR/while_let_loops.rs:7:5: 10:6 scope 1 { - debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15 + debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15 scope 2 { } } bb0: { - StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15 - _1 = const 0_i32; // scope 0 at $DIR/while_let_loops.rs:+1:18: +1:19 - StorageLive(_3); // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32 - Deinit(_3); // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32 - discriminant(_3) = 0; // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32 -- _4 = discriminant(_3); // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25 -- switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25 -+ _4 = const 0_isize; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25 -+ switchInt(const 0_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25 + StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:6:9: 6:15 + _1 = const 0_i32; // scope 0 at $DIR/while_let_loops.rs:6:18: 6:19 + StorageLive(_3); // scope 2 at $DIR/while_let_loops.rs:7:28: 7:32 + Deinit(_3); // scope 2 at $DIR/while_let_loops.rs:7:28: 7:32 + discriminant(_3) = 0; // scope 2 at $DIR/while_let_loops.rs:7:28: 7:32 +- _4 = discriminant(_3); // scope 2 at $DIR/while_let_loops.rs:7:15: 7:25 +- switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:7:15: 7:25 ++ _4 = const 0_isize; // scope 2 at $DIR/while_let_loops.rs:7:15: 7:25 ++ switchInt(const 0_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:7:15: 7:25 } bb1: { - switchInt(((_3 as Some).0: u32)) -> [0_u32: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25 + switchInt(((_3 as Some).0: u32)) -> [0_u32: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:7:15: 7:25 } bb2: { - _1 = const 1_i32; // scope 2 at $DIR/while_let_loops.rs:+3:9: +3:15 - nop; // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14 - goto -> bb4; // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14 + _1 = const 1_i32; // scope 2 at $DIR/while_let_loops.rs:8:9: 8:15 + nop; // scope 2 at $DIR/while_let_loops.rs:9:9: 9:14 + goto -> bb4; // scope 2 at $DIR/while_let_loops.rs:9:9: 9:14 } bb3: { - StorageLive(_7); // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6 - nop; // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6 - StorageDead(_7); // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6 + StorageLive(_7); // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6 + nop; // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6 + StorageDead(_7); // scope 1 at $DIR/while_let_loops.rs:10:5: 10:6 goto -> bb4; // scope 1 at no-location } bb4: { - StorageDead(_3); // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6 - StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2 - return; // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2 + StorageDead(_3); // scope 1 at $DIR/while_let_loops.rs:10:5: 10:6 + StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:11:1: 11:2 + return; // scope 0 at $DIR/while_let_loops.rs:11:2: 11:2 } } diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff index eef7011149d3e..f8b41d7b4c5df 100644 --- a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff +++ b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff @@ -2,54 +2,54 @@ + // MIR for `change_loop_body` after ConstProp fn change_loop_body() -> () { - let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27 - let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15 - let mut _2: (); // in scope 0 at $DIR/while_let_loops.rs:+0:1: +6:2 - let mut _3: std::option::Option; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32 - let mut _4: isize; // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25 - let mut _5: !; // in scope 0 at $DIR/while_let_loops.rs:+2:33: +5:6 - let mut _6: !; // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6 - let _7: (); // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6 - let mut _8: !; // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6 + let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:5:27: 5:27 + let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:6:9: 6:15 + let mut _2: (); // in scope 0 at $DIR/while_let_loops.rs:5:1: 11:2 + let mut _3: std::option::Option; // in scope 0 at $DIR/while_let_loops.rs:7:28: 7:32 + let mut _4: isize; // in scope 0 at $DIR/while_let_loops.rs:7:15: 7:25 + let mut _5: !; // in scope 0 at $DIR/while_let_loops.rs:7:33: 10:6 + let mut _6: !; // in scope 0 at $DIR/while_let_loops.rs:7:5: 10:6 + let _7: (); // in scope 0 at $DIR/while_let_loops.rs:7:5: 10:6 + let mut _8: !; // in scope 0 at $DIR/while_let_loops.rs:7:5: 10:6 scope 1 { - debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15 + debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15 scope 2 { } } bb0: { - StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15 - _1 = const 0_i32; // scope 0 at $DIR/while_let_loops.rs:+1:18: +1:19 - StorageLive(_3); // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32 - Deinit(_3); // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32 - discriminant(_3) = 0; // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32 -- _4 = discriminant(_3); // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25 -- switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25 -+ _4 = const 0_isize; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25 -+ switchInt(const 0_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25 + StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:6:9: 6:15 + _1 = const 0_i32; // scope 0 at $DIR/while_let_loops.rs:6:18: 6:19 + StorageLive(_3); // scope 2 at $DIR/while_let_loops.rs:7:28: 7:32 + Deinit(_3); // scope 2 at $DIR/while_let_loops.rs:7:28: 7:32 + discriminant(_3) = 0; // scope 2 at $DIR/while_let_loops.rs:7:28: 7:32 +- _4 = discriminant(_3); // scope 2 at $DIR/while_let_loops.rs:7:15: 7:25 +- switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:7:15: 7:25 ++ _4 = const 0_isize; // scope 2 at $DIR/while_let_loops.rs:7:15: 7:25 ++ switchInt(const 0_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:7:15: 7:25 } bb1: { - switchInt(((_3 as Some).0: u32)) -> [0_u32: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25 + switchInt(((_3 as Some).0: u32)) -> [0_u32: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:7:15: 7:25 } bb2: { - _1 = const 1_i32; // scope 2 at $DIR/while_let_loops.rs:+3:9: +3:15 - nop; // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14 - goto -> bb4; // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14 + _1 = const 1_i32; // scope 2 at $DIR/while_let_loops.rs:8:9: 8:15 + nop; // scope 2 at $DIR/while_let_loops.rs:9:9: 9:14 + goto -> bb4; // scope 2 at $DIR/while_let_loops.rs:9:9: 9:14 } bb3: { - StorageLive(_7); // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6 - nop; // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6 - StorageDead(_7); // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6 + StorageLive(_7); // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6 + nop; // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6 + StorageDead(_7); // scope 1 at $DIR/while_let_loops.rs:10:5: 10:6 goto -> bb4; // scope 1 at no-location } bb4: { - StorageDead(_3); // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6 - StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2 - return; // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2 + StorageDead(_3); // scope 1 at $DIR/while_let_loops.rs:10:5: 10:6 + StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:11:1: 11:2 + return; // scope 0 at $DIR/while_let_loops.rs:11:2: 11:2 } } diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir index 15b0aece8f54b..5657f9413a1b4 100644 --- a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir +++ b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir @@ -1,17 +1,17 @@ // MIR for `change_loop_body` after PreCodegen fn change_loop_body() -> () { - let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27 - let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15 + let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:5:27: 5:27 + let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:6:9: 6:15 scope 1 { - debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15 + debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15 scope 2 { } } bb0: { - StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15 - StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2 - return; // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2 + StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:6:9: 6:15 + StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:11:1: 11:2 + return; // scope 0 at $DIR/while_let_loops.rs:11:2: 11:2 } } diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir index 15b0aece8f54b..5657f9413a1b4 100644 --- a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir +++ b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir @@ -1,17 +1,17 @@ // MIR for `change_loop_body` after PreCodegen fn change_loop_body() -> () { - let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27 - let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15 + let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:5:27: 5:27 + let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:6:9: 6:15 scope 1 { - debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15 + debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15 scope 2 { } } bb0: { - StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15 - StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2 - return; // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2 + StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:6:9: 6:15 + StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:11:1: 11:2 + return; // scope 0 at $DIR/while_let_loops.rs:11:2: 11:2 } } diff --git a/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir b/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir index a5e7d6afdf36d..f1c5d95df1903 100644 --- a/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir +++ b/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir @@ -1,56 +1,56 @@ // MIR for `while_loop` after PreCodegen fn while_loop(_1: bool) -> () { - debug c => _1; // in scope 0 at $DIR/while-storage.rs:+0:15: +0:16 - let mut _0: (); // return place in scope 0 at $DIR/while-storage.rs:+0:24: +0:24 - let mut _2: bool; // in scope 0 at $DIR/while-storage.rs:+1:11: +1:22 - let mut _3: bool; // in scope 0 at $DIR/while-storage.rs:+1:20: +1:21 - let mut _4: bool; // in scope 0 at $DIR/while-storage.rs:+2:12: +2:23 - let mut _5: bool; // in scope 0 at $DIR/while-storage.rs:+2:21: +2:22 + debug c => _1; // in scope 0 at $DIR/while-storage.rs:9:15: 9:16 + let mut _0: (); // return place in scope 0 at $DIR/while-storage.rs:9:24: 9:24 + let mut _2: bool; // in scope 0 at $DIR/while-storage.rs:10:11: 10:22 + let mut _3: bool; // in scope 0 at $DIR/while-storage.rs:10:20: 10:21 + let mut _4: bool; // in scope 0 at $DIR/while-storage.rs:11:12: 11:23 + let mut _5: bool; // in scope 0 at $DIR/while-storage.rs:11:21: 11:22 bb0: { - goto -> bb1; // scope 0 at $DIR/while-storage.rs:+1:5: +5:6 + goto -> bb1; // scope 0 at $DIR/while-storage.rs:10:5: 14:6 } bb1: { - StorageLive(_2); // scope 0 at $DIR/while-storage.rs:+1:11: +1:22 - StorageLive(_3); // scope 0 at $DIR/while-storage.rs:+1:20: +1:21 - _3 = _1; // scope 0 at $DIR/while-storage.rs:+1:20: +1:21 - _2 = get_bool(move _3) -> bb2; // scope 0 at $DIR/while-storage.rs:+1:11: +1:22 + StorageLive(_2); // scope 0 at $DIR/while-storage.rs:10:11: 10:22 + StorageLive(_3); // scope 0 at $DIR/while-storage.rs:10:20: 10:21 + _3 = _1; // scope 0 at $DIR/while-storage.rs:10:20: 10:21 + _2 = get_bool(move _3) -> bb2; // scope 0 at $DIR/while-storage.rs:10:11: 10:22 // mir::Constant // + span: $DIR/while-storage.rs:10:11: 10:19 // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value() } } bb2: { - StorageDead(_3); // scope 0 at $DIR/while-storage.rs:+1:21: +1:22 - switchInt(move _2) -> [false: bb7, otherwise: bb3]; // scope 0 at $DIR/while-storage.rs:+1:11: +1:22 + StorageDead(_3); // scope 0 at $DIR/while-storage.rs:10:21: 10:22 + switchInt(move _2) -> [false: bb7, otherwise: bb3]; // scope 0 at $DIR/while-storage.rs:10:11: 10:22 } bb3: { - StorageLive(_4); // scope 0 at $DIR/while-storage.rs:+2:12: +2:23 - StorageLive(_5); // scope 0 at $DIR/while-storage.rs:+2:21: +2:22 - _5 = _1; // scope 0 at $DIR/while-storage.rs:+2:21: +2:22 - _4 = get_bool(move _5) -> bb4; // scope 0 at $DIR/while-storage.rs:+2:12: +2:23 + StorageLive(_4); // scope 0 at $DIR/while-storage.rs:11:12: 11:23 + StorageLive(_5); // scope 0 at $DIR/while-storage.rs:11:21: 11:22 + _5 = _1; // scope 0 at $DIR/while-storage.rs:11:21: 11:22 + _4 = get_bool(move _5) -> bb4; // scope 0 at $DIR/while-storage.rs:11:12: 11:23 // mir::Constant // + span: $DIR/while-storage.rs:11:12: 11:20 // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value() } } bb4: { - StorageDead(_5); // scope 0 at $DIR/while-storage.rs:+2:22: +2:23 - switchInt(move _4) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/while-storage.rs:+2:12: +2:23 + StorageDead(_5); // scope 0 at $DIR/while-storage.rs:11:22: 11:23 + switchInt(move _4) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/while-storage.rs:11:12: 11:23 } bb5: { - StorageDead(_4); // scope 0 at $DIR/while-storage.rs:+4:9: +4:10 + StorageDead(_4); // scope 0 at $DIR/while-storage.rs:13:9: 13:10 goto -> bb8; // scope 0 at no-location } bb6: { - StorageDead(_4); // scope 0 at $DIR/while-storage.rs:+4:9: +4:10 - StorageDead(_2); // scope 0 at $DIR/while-storage.rs:+5:5: +5:6 - goto -> bb1; // scope 0 at $DIR/while-storage.rs:+1:5: +5:6 + StorageDead(_4); // scope 0 at $DIR/while-storage.rs:13:9: 13:10 + StorageDead(_2); // scope 0 at $DIR/while-storage.rs:14:5: 14:6 + goto -> bb1; // scope 0 at $DIR/while-storage.rs:10:5: 14:6 } bb7: { @@ -58,7 +58,7 @@ fn while_loop(_1: bool) -> () { } bb8: { - StorageDead(_2); // scope 0 at $DIR/while-storage.rs:+5:5: +5:6 - return; // scope 0 at $DIR/while-storage.rs:+6:2: +6:2 + StorageDead(_2); // scope 0 at $DIR/while-storage.rs:14:5: 14:6 + return; // scope 0 at $DIR/while-storage.rs:15:2: 15:2 } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline-dead.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline-dead.txt deleted file mode 100644 index effdef80e8eb6..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline-dead.txt +++ /dev/null @@ -1,28 +0,0 @@ - 1| |// Regression test for issue #98833. - 2| |// compile-flags: -Zinline-mir -Cdebug-assertions=off - 3| | - 4| 1|fn main() { - 5| 1| println!("{}", live::()); - 6| 1| - 7| 1| let f = |x: bool| { - 8| | debug_assert!( - 9| | x - 10| | ); - 11| 1| }; - 12| 1| f(false); - 13| 1|} - 14| | - 15| |#[inline] - 16| 1|fn live() -> u32 { - 17| 1| if B { - 18| 0| dead() - 19| | } else { - 20| 1| 0 - 21| | } - 22| 1|} - 23| | - 24| |#[inline] - 25| 0|fn dead() -> u32 { - 26| 0| 42 - 27| 0|} - diff --git a/src/test/run-make-fulldeps/coverage/inline-dead.rs b/src/test/run-make-fulldeps/coverage/inline-dead.rs deleted file mode 100644 index 854fa06296752..0000000000000 --- a/src/test/run-make-fulldeps/coverage/inline-dead.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Regression test for issue #98833. -// compile-flags: -Zinline-mir -Cdebug-assertions=off - -fn main() { - println!("{}", live::()); - - let f = |x: bool| { - debug_assert!( - x - ); - }; - f(false); -} - -#[inline] -fn live() -> u32 { - if B { - dead() - } else { - 0 - } -} - -#[inline] -fn dead() -> u32 { - 42 -} diff --git a/src/test/run-make-fulldeps/issue-84395-lto-embed-bitcode/Makefile b/src/test/run-make-fulldeps/issue-84395-lto-embed-bitcode/Makefile deleted file mode 100644 index 157edb20c30a5..0000000000000 --- a/src/test/run-make-fulldeps/issue-84395-lto-embed-bitcode/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# needs-matching-clang - -# This test makes sure the embed bitcode in elf created with -# lto-embed-bitcode=optimized is valid llvm BC module. - --include ../../run-make-fulldeps/tools.mk - -all: - $(RUSTC) test.rs --target $(TARGET) -Clink-arg=-fuse-ld=lld -Clinker-plugin-lto -Clinker=$(CLANG) -Clink-arg=-Wl,--plugin-opt=-lto-embed-bitcode=optimized -Zemit-thin-lto=no - $(LLVM_BIN_DIR)/objcopy --dump-section .llvmbc=$(TMPDIR)/test.bc $(TMPDIR)/test - $(LLVM_BIN_DIR)/llvm-dis $(TMPDIR)/test.bc diff --git a/src/test/run-make-fulldeps/issue-84395-lto-embed-bitcode/test.rs b/src/test/run-make-fulldeps/issue-84395-lto-embed-bitcode/test.rs deleted file mode 100644 index 47ad8c634112b..0000000000000 --- a/src/test/run-make-fulldeps/issue-84395-lto-embed-bitcode/test.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello World!"); -} diff --git a/src/test/run-make-fulldeps/tools.mk b/src/test/run-make-fulldeps/tools.mk index 33bf95ac1657e..a14f6e3ab95a5 100644 --- a/src/test/run-make-fulldeps/tools.mk +++ b/src/test/run-make-fulldeps/tools.mk @@ -90,7 +90,7 @@ NATIVE_STATICLIB = $(TMPDIR)/$(call NATIVE_STATICLIB_FILE,$(1)) OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \ -Fo:`cygpath -w $(TMPDIR)/$(1).obj` else -COMPILE_OBJ = $(CC) -v -c -o $(1) $(2) +COMPILE_OBJ = $(CC) -c -o $(1) $(2) COMPILE_OBJ_CXX = $(CXX) -c -o $(1) $(2) NATIVE_STATICLIB_FILE = lib$(1).a NATIVE_STATICLIB = $(call STATICLIB,$(1)) diff --git a/src/test/run-make-fulldeps/used-cdylib-macos/Makefile b/src/test/run-make-fulldeps/used-cdylib-macos/Makefile deleted file mode 100644 index 4828d9c8aad2c..0000000000000 --- a/src/test/run-make-fulldeps/used-cdylib-macos/Makefile +++ /dev/null @@ -1,11 +0,0 @@ --include ../tools.mk - -# only-macos -# -# This checks that `#[used]` passes through to the linker on -# darwin. This is subject to change in the future, see -# https://github.com/rust-lang/rust/pull/93718 for discussion - -all: - $(RUSTC) -Copt-level=3 dylib_used.rs - nm $(TMPDIR)/libdylib_used.dylib | $(CGREP) VERY_IMPORTANT_SYMBOL diff --git a/src/test/run-make-fulldeps/used-cdylib-macos/dylib_used.rs b/src/test/run-make-fulldeps/used-cdylib-macos/dylib_used.rs deleted file mode 100644 index 85f0ff92fe730..0000000000000 --- a/src/test/run-make-fulldeps/used-cdylib-macos/dylib_used.rs +++ /dev/null @@ -1,4 +0,0 @@ -#![crate_type = "cdylib"] - -#[used] -static VERY_IMPORTANT_SYMBOL: u32 = 12345; diff --git a/src/test/run-make/export-executable-symbols/Makefile b/src/test/run-make/export-executable-symbols/Makefile deleted file mode 100644 index 5006f9cb8cfea..0000000000000 --- a/src/test/run-make/export-executable-symbols/Makefile +++ /dev/null @@ -1,11 +0,0 @@ --include ../../run-make-fulldeps/tools.mk - -# ignore-wasm32 -# ignore-wasm64 -# ignore-none no-std is not supported -# only-linux - -all: - $(RUSTC) -Zexport-executable-symbols main.rs --target $(TARGET) --crate-type=bin - nm $(TMPDIR)/main | $(CGREP) exported_symbol - diff --git a/src/test/run-make/export-executable-symbols/main.rs b/src/test/run-make/export-executable-symbols/main.rs deleted file mode 100644 index c498381a33f64..0000000000000 --- a/src/test/run-make/export-executable-symbols/main.rs +++ /dev/null @@ -1,8 +0,0 @@ -// edition:2018 - -fn main() {} - -#[no_mangle] -pub fn exported_symbol() -> i8 { - 42 -} diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/Makefile b/src/test/run-make/raw-dylib-alt-calling-convention/Makefile index 1badde541128d..4af8b43ea848d 100644 --- a/src/test/run-make/raw-dylib-alt-calling-convention/Makefile +++ b/src/test/run-make/raw-dylib-alt-calling-convention/Makefile @@ -6,14 +6,14 @@ -include ../../run-make-fulldeps/tools.mk all: - $(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs - $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" $(call COMPILE_OBJ,"$(TMPDIR)"/extern.obj,extern.c) ifdef IS_MSVC - $(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll -noimplib + $(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll else $(CC) "$(TMPDIR)"/extern.obj -shared -o "$(TMPDIR)"/extern.dll endif + $(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs + $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt ifdef RUSTC_BLESS_TEST diff --git a/src/test/run-make/raw-dylib-c/Makefile b/src/test/run-make/raw-dylib-c/Makefile index 713f665078e57..166305672e6f2 100644 --- a/src/test/run-make/raw-dylib-c/Makefile +++ b/src/test/run-make/raw-dylib-c/Makefile @@ -5,24 +5,21 @@ -include ../../run-make-fulldeps/tools.mk all: - $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs - $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" - $(RUSTC) --crate-type bin --crate-name raw_dylib_test_bin lib.rs $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c) $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c) ifdef IS_MSVC - $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll -noimplib - $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll -noimplib + $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll + $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll else $(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll $(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll endif + $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs + $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt - "$(TMPDIR)"/raw_dylib_test_bin > "$(TMPDIR)"/output_bin.txt ifdef RUSTC_BLESS_TEST cp "$(TMPDIR)"/output.txt output.txt else $(DIFF) output.txt "$(TMPDIR)"/output.txt - $(DIFF) output.txt "$(TMPDIR)"/output_bin.txt endif diff --git a/src/test/run-make/raw-dylib-c/lib.rs b/src/test/run-make/raw-dylib-c/lib.rs index 58f7ccb38ce4a..e185c4aec12b0 100644 --- a/src/test/run-make/raw-dylib-c/lib.rs +++ b/src/test/run-make/raw-dylib-c/lib.rs @@ -20,7 +20,3 @@ pub fn library_function() { extern_fn_3(); } } - -fn main() { - library_function(); -} diff --git a/src/test/run-make/raw-dylib-link-ordinal/Makefile b/src/test/run-make/raw-dylib-link-ordinal/Makefile index c9baa3c1ec9ac..0e84a749b0578 100644 --- a/src/test/run-make/raw-dylib-link-ordinal/Makefile +++ b/src/test/run-make/raw-dylib-link-ordinal/Makefile @@ -5,14 +5,14 @@ -include ../../run-make-fulldeps/tools.mk all: - $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs - $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" $(call COMPILE_OBJ,"$(TMPDIR)"/exporter.obj,exporter.c) ifdef IS_MSVC - $(CC) "$(TMPDIR)"/exporter.obj exporter.def -link -dll -out:"$(TMPDIR)"/exporter.dll -noimplib + $(CC) "$(TMPDIR)"/exporter.obj exporter.def -link -dll -out:"$(TMPDIR)"/exporter.dll else $(CC) "$(TMPDIR)"/exporter.obj exporter.def -shared -o "$(TMPDIR)"/exporter.dll endif + $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs + $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt ifdef RUSTC_BLESS_TEST diff --git a/src/test/run-make/raw-dylib-stdcall-ordinal/Makefile b/src/test/run-make/raw-dylib-stdcall-ordinal/Makefile index 3360a97b5ff0e..69f62669d6291 100644 --- a/src/test/run-make/raw-dylib-stdcall-ordinal/Makefile +++ b/src/test/run-make/raw-dylib-stdcall-ordinal/Makefile @@ -6,14 +6,14 @@ -include ../../run-make-fulldeps/tools.mk all: - $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs - $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" $(call COMPILE_OBJ,"$(TMPDIR)"/exporter.obj,exporter.c) ifdef IS_MSVC - $(CC) "$(TMPDIR)"/exporter.obj exporter-msvc.def -link -dll -out:"$(TMPDIR)"/exporter.dll -noimplib + $(CC) "$(TMPDIR)"/exporter.obj exporter-msvc.def -link -dll -out:"$(TMPDIR)"/exporter.dll else $(CC) "$(TMPDIR)"/exporter.obj exporter-gnu.def -shared -o "$(TMPDIR)"/exporter.dll endif + $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs + $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" "$(TMPDIR)"/driver > "$(TMPDIR)"/actual_output.txt ifdef RUSTC_BLESS_TEST diff --git a/src/test/rustdoc-gui/docblock-details.goml b/src/test/rustdoc-gui/docblock-details.goml index f6287ade2f295..2edbf1e4e2d8c 100644 --- a/src/test/rustdoc-gui/docblock-details.goml +++ b/src/test/rustdoc-gui/docblock-details.goml @@ -9,12 +9,12 @@ reload: assert-text: (".top-doc .docblock > h3", "Hello") assert-css: ( ".top-doc .docblock > h3", - {"border-bottom": "1px solid rgb(210, 210, 210)"}, + {"border-bottom": "1px solid rgb(221, 221, 221)"}, ) // We now check that the `` doesn't have a bottom border and has the correct display. assert-css: ( ".top-doc .docblock summary h4", - {"border-bottom": "0px none rgb(210, 210, 210)"}, + {"border-bottom": "0px none rgb(221, 221, 221)"}, ) // This allows to ensure that summary is on one line only! assert-property: (".top-doc .docblock summary h4", {"offsetHeight": "33"}) diff --git a/src/test/rustdoc-gui/headings.goml b/src/test/rustdoc-gui/headings.goml index 8c2c3df1588f5..cc3dd61e99a7a 100644 --- a/src/test/rustdoc-gui/headings.goml +++ b/src/test/rustdoc-gui/headings.goml @@ -150,109 +150,15 @@ assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"}) assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "20px"}) assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"}) -// Checking colors now. +goto: file://|DOC_PATH|/staged_api/struct.Foo.html show-text: true local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} -goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html -assert-css: ( - ".top-doc .docblock h2", - {"color": "rgb(0, 0, 0)", "border-bottom": "1px solid rgb(221, 221, 221)"}, -) -assert-css: ( - ".top-doc .docblock h3", - {"color": "rgb(0, 0, 0)", "border-bottom": "1px solid rgb(221, 221, 221)"}, -) -assert-css: ( - ".top-doc .docblock h4", - {"color": "rgb(0, 0, 0)", "border-bottom": "1px solid rgb(221, 221, 221)"}, -) -assert-css: ( - ".top-doc .docblock h5", - {"color": "rgb(0, 0, 0)", "border-bottom": "0px none rgb(221, 221, 221)"}, -) -assert-css: ( - "#implementations-list .docblock h4", - {"color": "rgb(0, 0, 0)", "border-bottom": "0px none rgb(221, 221, 221)"}, -) -assert-css: ( - "#implementations-list .docblock h5", - {"color": "rgb(0, 0, 0)", "border-bottom": "0px none rgb(221, 221, 221)"}, -) -assert-css: ( - "#implementations-list .docblock h6", - {"color": "rgb(0, 0, 0)", "border-bottom": "0px none rgb(221, 221, 221)"}, -) - -local-storage: {"rustdoc-theme": "dark"} -reload: -assert-css: ( - ".top-doc .docblock h2", - {"color": "rgb(221, 221, 221)", "border-bottom": "1px solid rgb(210, 210, 210)"}, -) -assert-css: ( - ".top-doc .docblock h3", - {"color": "rgb(221, 221, 221)", "border-bottom": "1px solid rgb(210, 210, 210)"}, -) -assert-css: ( - ".top-doc .docblock h4", - {"color": "rgb(221, 221, 221)", "border-bottom": "1px solid rgb(210, 210, 210)"}, -) -assert-css: ( - ".top-doc .docblock h5", - {"color": "rgb(221, 221, 221)", "border-bottom": "0px none rgb(210, 210, 210)"}, -) -assert-css: ( - "#implementations-list .docblock h4", - {"color": "rgb(221, 221, 221)", "border-bottom": "0px none rgb(210, 210, 210)"}, -) -assert-css: ( - "#implementations-list .docblock h5", - {"color": "rgb(221, 221, 221)", "border-bottom": "0px none rgb(210, 210, 210)"}, -) -assert-css: ( - "#implementations-list .docblock h6", - {"color": "rgb(221, 221, 221)", "border-bottom": "0px none rgb(210, 210, 210)"}, -) - -local-storage: {"rustdoc-theme": "ayu"} -reload: -assert-css: ( - ".top-doc .docblock h2", - {"color": "rgb(255, 255, 255)", "border-bottom": "1px solid rgb(92, 103, 115)"}, -) -assert-css: ( - ".top-doc .docblock h2", - {"color": "rgb(255, 255, 255)", "border-bottom": "1px solid rgb(92, 103, 115)"}, -) -assert-css: ( - ".top-doc .docblock h4", - {"color": "rgb(255, 255, 255)", "border-bottom": "1px solid rgb(92, 103, 115)"}, -) -assert-css: ( - ".top-doc .docblock h5", - {"color": "rgb(197, 197, 197)", "border-bottom": "0px none rgb(92, 103, 115)"}, -) -assert-css: ( - "#implementations-list .docblock h4", - {"color": "rgb(255, 255, 255)", "border-bottom": "0px none rgb(92, 103, 115)"}, -) -assert-css: ( - "#implementations-list .docblock h5", - {"color": "rgb(197, 197, 197)", "border-bottom": "0px none rgb(92, 103, 115)"}, -) -assert-css: ( - "#implementations-list .docblock h6", - {"color": "rgb(197, 197, 197)", "border-bottom": "0px none rgb(92, 103, 115)"}, -) - -local-storage: {"rustdoc-theme": "light"} -goto: file://|DOC_PATH|/staged_api/struct.Foo.html assert-css: (".since", {"color": "rgb(128, 128, 128)"}) -local-storage: {"rustdoc-theme": "dark"} +local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} reload: assert-css: (".since", {"color": "rgb(128, 128, 128)"}) -local-storage: {"rustdoc-theme": "ayu"} +local-storage: {"rustdoc-theme": "ayu", "rustdoc-use-system-theme": "false"} reload: assert-css: (".since", {"color": "rgb(128, 128, 128)"}) diff --git a/src/test/rustdoc-gui/search-input.goml b/src/test/rustdoc-gui/search-input.goml deleted file mode 100644 index 44123b702df8a..0000000000000 --- a/src/test/rustdoc-gui/search-input.goml +++ /dev/null @@ -1,23 +0,0 @@ -// Ensures that the search input border color changes on focus. -goto: file://|DOC_PATH|/test_docs/index.html -local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"} -reload: - -assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"}) -click: ".search-input" -focus: ".search-input" -assert-css: (".search-input", {"border-color": "rgb(0, 141, 253)"}) - -local-storage: {"rustdoc-theme": "light"} -reload: - -assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"}) -click: ".search-input" -assert-css: (".search-input", {"border-color": "rgb(102, 175, 233)"}) - -local-storage: {"rustdoc-theme": "ayu"} -reload: - -assert-css: (".search-input", {"border-color": "rgb(66, 76, 87)"}) -click: ".search-input" -assert-css: (".search-input", {"border-color": "rgb(66, 76, 87)"}) diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml index 8464ba7c23cfe..6295d7fae8907 100644 --- a/src/test/rustdoc-gui/search-result-display.goml +++ b/src/test/rustdoc-gui/search-result-display.goml @@ -18,7 +18,7 @@ assert-css: (".search-results div.desc", {"width": "570px"}) size: (900, 900) // First we check the current width and position. -assert-css: ("#crate-search", {"width": "218px"}) +assert-css: ("#crate-search", {"width": "222px"}) compare-elements-position-near: ( "#crate-search", "#search-settings .search-results-title", diff --git a/src/test/rustdoc-gui/settings.goml b/src/test/rustdoc-gui/settings.goml index d9cf5ee66140f..8a3365d3cc25e 100644 --- a/src/test/rustdoc-gui/settings.goml +++ b/src/test/rustdoc-gui/settings.goml @@ -147,12 +147,3 @@ assert-false: "noscript section" javascript: false reload: assert-css: ("noscript section", {"display": "block"}) -javascript: true - -// Check for the display on small screen -show-text: true -reload: -size: (300, 1000) -click: "#settings-menu" -wait-for: "#settings" -assert-css: ("#settings .slider", {"width": "45px"}, ALL) diff --git a/src/test/rustdoc-gui/sidebar-mobile.goml b/src/test/rustdoc-gui/sidebar-mobile.goml index 033c65783498f..79f18db8fc7cd 100644 --- a/src/test/rustdoc-gui/sidebar-mobile.goml +++ b/src/test/rustdoc-gui/sidebar-mobile.goml @@ -40,25 +40,3 @@ assert-position: ("#method\.must_use", {"y": 45}) click: ".sidebar-menu-toggle" scroll-to: ".block.keyword li:nth-child(1)" compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 543}) - -// Now checking the background color of the sidebar. -local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"} -reload: - -// Open the sidebar menu. -click: ".sidebar-menu-toggle" -assert-css: (".sidebar", {"background-color": "rgb(80, 80, 80)"}) - -local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "ayu"} -reload: - -// Open the sidebar menu. -click: ".sidebar-menu-toggle" -assert-css: (".sidebar", {"background-color": "rgb(20, 25, 31)"}) - -local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "light"} -reload: - -// Open the sidebar menu. -click: ".sidebar-menu-toggle" -assert-css: (".sidebar", {"background-color": "rgb(245, 245, 245)"}) diff --git a/src/test/rustdoc-gui/src/test_docs/lib.rs b/src/test/rustdoc-gui/src/test_docs/lib.rs index 1b26aaecb5ef3..aa2f78289bea2 100644 --- a/src/test/rustdoc-gui/src/test_docs/lib.rs +++ b/src/test/rustdoc-gui/src/test_docs/lib.rs @@ -146,10 +146,6 @@ pub use crate::repro as repro2; /// ### Top-doc Prose sub-sub-heading /// /// Text below sub-sub-heading -/// -/// #### You know the drill. -/// -/// More text. pub struct HeavilyDocumentedStruct { /// # Title for field /// ## Sub-heading for field diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout index 780c0032b6d15..6f5248f5b18ce 100644 --- a/src/test/rustdoc-ui/z-help.stdout +++ b/src/test/rustdoc-ui/z-help.stdout @@ -36,8 +36,6 @@ -Z dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans. -Z dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform) -Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no) - -Z emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes) - -Z export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries -Z fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no) -Z force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no) -Z fuel=val -- set the optimization fuel quota for a crate @@ -76,7 +74,6 @@ -Z meta-stats=val -- gather metadata statistics (default: no) -Z mir-emit-retag=val -- emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 (default: no) -Z mir-enable-passes=val -- use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be enabled, overriding all other checks. Passes that are not specified are enabled or disabled by other flags as usual. - -Z mir-pretty-relative-line-numbers=val -- use line numbers relative to the function in mir pretty printing -Z mir-opt-level=val -- MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds) -Z move-size-limit=val -- the size at which the `large_assignments` lint starts to be emitted -Z mutable-noalias=val -- emit noalias metadata for mutable references (default: yes) diff --git a/src/test/rustdoc/const-generics/add-impl.rs b/src/test/rustdoc/const-generics/add-impl.rs index 591139523456e..e54f9a57ae4ee 100644 --- a/src/test/rustdoc/const-generics/add-impl.rs +++ b/src/test/rustdoc/const-generics/add-impl.rs @@ -7,7 +7,7 @@ pub struct Simd { inner: T, } -// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl Add> for Simd' +// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl Add> for Simd' impl Add for Simd { type Output = Self; diff --git a/src/test/rustdoc/const-generics/const-generic-defaults.rs b/src/test/rustdoc/const-generics/const-generic-defaults.rs index 2693d9b596993..8035f826775ef 100644 --- a/src/test/rustdoc/const-generics/const-generic-defaults.rs +++ b/src/test/rustdoc/const-generics/const-generic-defaults.rs @@ -1,5 +1,5 @@ #![crate_name = "foo"] // @has foo/struct.Foo.html '//pre[@class="rust struct"]' \ -// 'pub struct Foo(_);' +// 'pub struct Foo(_);' pub struct Foo(T); diff --git a/src/test/rustdoc/const-generics/const-generics-docs.rs b/src/test/rustdoc/const-generics/const-generics-docs.rs index 352a8e646bb49..61af7de4794a6 100644 --- a/src/test/rustdoc/const-generics/const-generics-docs.rs +++ b/src/test/rustdoc/const-generics/const-generics-docs.rs @@ -19,8 +19,8 @@ pub use extern_crate::WTrait; // @has foo/trait.Trait.html '//pre[@class="rust trait"]' \ // 'pub trait Trait' -// @has - '//*[@id="impl-Trait%3C1%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<1> for u8' -// @has - '//*[@id="impl-Trait%3C2%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<2> for u8' +// @has - '//*[@id="impl-Trait%3C1_usize%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<1_usize> for u8' +// @has - '//*[@id="impl-Trait%3C2_usize%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<2_usize> for u8' // @has - '//*[@id="impl-Trait%3C{1%20+%202}%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<{1 + 2}> for u8' // @has - '//*[@id="impl-Trait%3CN%3E-for-%5Bu8%3B%20N%5D"]//h3[@class="code-header in-band"]' \ // 'impl Trait for [u8; N]' diff --git a/src/test/rustdoc/must_implement_one_of.rs b/src/test/rustdoc/must_implement_one_of.rs deleted file mode 100644 index 1f1dd5d5796ee..0000000000000 --- a/src/test/rustdoc/must_implement_one_of.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![crate_name = "c"] -#![feature(rustc_attrs)] - -#[rustc_must_implement_one_of(a, b)] -// @matches c/trait.Trait.html '//*[@class="stab must_implement"]' \ -// 'At least one of the `a`, `b` methods is required.$' -pub trait Trait { - fn a() {} - fn b() {} -} diff --git a/src/test/rustdoc/type-layout.rs b/src/test/rustdoc/type-layout.rs index e5c6e9dc3f9ed..4eea9809ac58f 100644 --- a/src/test/rustdoc/type-layout.rs +++ b/src/test/rustdoc/type-layout.rs @@ -2,7 +2,6 @@ // @has type_layout/struct.Foo.html 'Size: ' // @has - ' bytes' -// @has - '//*[@id="layout"]/a[@href="#layout"]' '' pub struct Foo { pub a: usize, b: Vec, diff --git a/src/test/ui-fulldeps/gated-plugin.rs b/src/test/ui-fulldeps/gated-plugin.rs index 85eaf53364315..445469f8733fb 100644 --- a/src/test/ui-fulldeps/gated-plugin.rs +++ b/src/test/ui-fulldeps/gated-plugin.rs @@ -1,5 +1,4 @@ // aux-build:empty-plugin.rs -// ignore-stage1 #![plugin(empty_plugin)] //~^ ERROR compiler plugins are deprecated diff --git a/src/test/ui-fulldeps/gated-plugin.stderr b/src/test/ui-fulldeps/gated-plugin.stderr index f48f1eab60b95..b8b7dd23c1cd3 100644 --- a/src/test/ui-fulldeps/gated-plugin.stderr +++ b/src/test/ui-fulldeps/gated-plugin.stderr @@ -1,5 +1,5 @@ error[E0658]: compiler plugins are deprecated - --> $DIR/gated-plugin.rs:4:1 + --> $DIR/gated-plugin.rs:3:1 | LL | #![plugin(empty_plugin)] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![plugin(empty_plugin)] = help: add `#![feature(plugin)]` to the crate attributes to enable warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/gated-plugin.rs:4:1 + --> $DIR/gated-plugin.rs:3:1 | LL | #![plugin(empty_plugin)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version diff --git a/src/test/ui-fulldeps/internal-lints/bad_opt_access.rs b/src/test/ui-fulldeps/internal-lints/bad_opt_access.rs deleted file mode 100644 index d6bd6945e150a..0000000000000 --- a/src/test/ui-fulldeps/internal-lints/bad_opt_access.rs +++ /dev/null @@ -1,22 +0,0 @@ -// compile-flags: -Z unstable-options - -// Test that accessing command line options by field access triggers a lint for those fields -// that have wrapper functions which should be used. - -#![crate_type = "lib"] -#![feature(rustc_private)] -#![deny(rustc::bad_opt_access)] - -extern crate rustc_session; -use rustc_session::Session; - -pub fn access_bad_option(sess: Session) { - let _ = sess.opts.cg.split_debuginfo; - //~^ ERROR use `Session::split_debuginfo` instead of this field - - let _ = sess.opts.crate_types; - //~^ ERROR use `Session::crate_types` instead of this field - - let _ = sess.opts.crate_name; - // okay! -} diff --git a/src/test/ui-fulldeps/internal-lints/bad_opt_access.stderr b/src/test/ui-fulldeps/internal-lints/bad_opt_access.stderr deleted file mode 100644 index e4145bff8bee9..0000000000000 --- a/src/test/ui-fulldeps/internal-lints/bad_opt_access.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: use `Session::split_debuginfo` instead of this field - --> $DIR/bad_opt_access.rs:14:13 - | -LL | let _ = sess.opts.cg.split_debuginfo; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/bad_opt_access.rs:8:9 - | -LL | #![deny(rustc::bad_opt_access)] - | ^^^^^^^^^^^^^^^^^^^^^ - -error: use `Session::crate_types` instead of this field - --> $DIR/bad_opt_access.rs:17:13 - | -LL | let _ = sess.opts.crate_types; - | ^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics_incorrect.stderr b/src/test/ui-fulldeps/internal-lints/diagnostics_incorrect.stderr index e849ca2829e43..46c206f3bf9fb 100644 --- a/src/test/ui-fulldeps/internal-lints/diagnostics_incorrect.stderr +++ b/src/test/ui-fulldeps/internal-lints/diagnostics_incorrect.stderr @@ -4,14 +4,14 @@ error: malformed `rustc_lint_diagnostics` attribute input LL | #[rustc_lint_diagnostics(a)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_lint_diagnostics]` -error: attribute should be applied to a function definition +error: attribute should be applied to a function --> $DIR/diagnostics_incorrect.rs:5:1 | LL | #[rustc_lint_diagnostics] | ^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | struct Foo; - | ----------- not a function definition + | ----------- not a function error: aborting due to 2 previous errors diff --git a/src/test/ui-fulldeps/internal-lints/query_stability_incorrect.stderr b/src/test/ui-fulldeps/internal-lints/query_stability_incorrect.stderr index 3f78b39edd96a..b5156f2ac5905 100644 --- a/src/test/ui-fulldeps/internal-lints/query_stability_incorrect.stderr +++ b/src/test/ui-fulldeps/internal-lints/query_stability_incorrect.stderr @@ -4,14 +4,14 @@ error: malformed `rustc_lint_query_instability` attribute input LL | #[rustc_lint_query_instability(a)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_lint_query_instability]` -error: attribute should be applied to a function definition +error: attribute should be applied to a function --> $DIR/query_stability_incorrect.rs:5:1 | LL | #[rustc_lint_query_instability] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | struct Foo; - | ----------- not a function definition + | ----------- not a function error: aborting due to 2 previous errors diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs index 6ce67dcaf1d9b..2868517774d46 100644 --- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs @@ -44,11 +44,11 @@ struct WithParameters { } impl WithParameters { - fn with_ref(&self) {} //~ ERROR passing `WithParameters` by reference + fn with_ref(&self) {} //~ ERROR passing `WithParameters` by reference } impl WithParameters { - fn with_ref(&self) {} //~ ERROR passing `WithParameters` by reference + fn with_ref(&self) {} //~ ERROR passing `WithParameters` by reference } fn main() {} diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr index fb39ed60b8235..54a7cf7cab757 100644 --- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr @@ -22,17 +22,17 @@ error: passing `Foo` by reference LL | fn with_ref(&self) {} | ^^^^^ help: try passing by value: `Foo` -error: passing `WithParameters` by reference +error: passing `WithParameters` by reference --> $DIR/rustc_pass_by_value_self.rs:47:17 | LL | fn with_ref(&self) {} - | ^^^^^ help: try passing by value: `WithParameters` + | ^^^^^ help: try passing by value: `WithParameters` -error: passing `WithParameters` by reference +error: passing `WithParameters` by reference --> $DIR/rustc_pass_by_value_self.rs:51:17 | LL | fn with_ref(&self) {} - | ^^^^^ help: try passing by value: `WithParameters` + | ^^^^^ help: try passing by value: `WithParameters` error: aborting due to 5 previous errors diff --git a/src/test/ui-fulldeps/multiple-plugins.rs b/src/test/ui-fulldeps/multiple-plugins.rs index 9af3ebd570cca..25d2c8bc1235b 100644 --- a/src/test/ui-fulldeps/multiple-plugins.rs +++ b/src/test/ui-fulldeps/multiple-plugins.rs @@ -1,7 +1,6 @@ // run-pass // aux-build:multiple-plugins-1.rs // aux-build:multiple-plugins-2.rs -// ignore-stage1 // Check that the plugin registrar of multiple plugins doesn't conflict diff --git a/src/test/ui-fulldeps/multiple-plugins.stderr b/src/test/ui-fulldeps/multiple-plugins.stderr index 878ffabfc7fc2..99151933c4b58 100644 --- a/src/test/ui-fulldeps/multiple-plugins.stderr +++ b/src/test/ui-fulldeps/multiple-plugins.stderr @@ -1,5 +1,5 @@ warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/multiple-plugins.rs:9:1 + --> $DIR/multiple-plugins.rs:8:1 | LL | #![plugin(multiple_plugins_1)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version @@ -7,7 +7,7 @@ LL | #![plugin(multiple_plugins_1)] = note: `#[warn(deprecated)]` on by default warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/multiple-plugins.rs:10:1 + --> $DIR/multiple-plugins.rs:9:1 | LL | #![plugin(multiple_plugins_2)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version diff --git a/src/test/ui/argument-suggestions/issue-98894.rs b/src/test/ui/argument-suggestions/issue-98894.rs deleted file mode 100644 index c2618a96716a5..0000000000000 --- a/src/test/ui/argument-suggestions/issue-98894.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - (|_, ()| ())(if true {} else {return;}); - //~^ ERROR this function takes 2 arguments but 1 argument was supplied -} diff --git a/src/test/ui/argument-suggestions/issue-98894.stderr b/src/test/ui/argument-suggestions/issue-98894.stderr deleted file mode 100644 index 0c8b94901e16f..0000000000000 --- a/src/test/ui/argument-suggestions/issue-98894.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0057]: this function takes 2 arguments but 1 argument was supplied - --> $DIR/issue-98894.rs:2:5 - | -LL | (|_, ()| ())(if true {} else {return;}); - | ^^^^^^^^^^^^--------------------------- an argument of type `()` is missing - | -note: closure defined here - --> $DIR/issue-98894.rs:2:6 - | -LL | (|_, ()| ())(if true {} else {return;}); - | ^^^^^^^ -help: provide the argument - | -LL | (|_, ()| ())(if true {} else {return;}, ()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0057`. diff --git a/src/test/ui/argument-suggestions/issue-98897.rs b/src/test/ui/argument-suggestions/issue-98897.rs deleted file mode 100644 index c55f495d69862..0000000000000 --- a/src/test/ui/argument-suggestions/issue-98897.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - (|_, ()| ())([return, ()]); - //~^ ERROR this function takes 2 arguments but 1 argument was supplied -} diff --git a/src/test/ui/argument-suggestions/issue-98897.stderr b/src/test/ui/argument-suggestions/issue-98897.stderr deleted file mode 100644 index 8f0d98d09e89e..0000000000000 --- a/src/test/ui/argument-suggestions/issue-98897.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0057]: this function takes 2 arguments but 1 argument was supplied - --> $DIR/issue-98897.rs:2:5 - | -LL | (|_, ()| ())([return, ()]); - | ^^^^^^^^^^^^-------------- an argument of type `()` is missing - | -note: closure defined here - --> $DIR/issue-98897.rs:2:6 - | -LL | (|_, ()| ())([return, ()]); - | ^^^^^^^ -help: provide the argument - | -LL | (|_, ()| ())([return, ()], ()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0057`. diff --git a/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr b/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr index 5e531a993c62c..1a14ab40b1f86 100644 --- a/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr +++ b/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/match_arr_unknown_len.rs:3:9 | LL | [1, 2] => true, - | ^^^^^^ expected `2`, found `N` + | ^^^^^^ expected `2_usize`, found `N` | = note: expected array `[u32; 2]` found array `[u32; N]` diff --git a/src/test/ui/asm/x86_64/issue-96797.rs b/src/test/ui/asm/x86_64/issue-96797.rs deleted file mode 100644 index d3e0906f37aff..0000000000000 --- a/src/test/ui/asm/x86_64/issue-96797.rs +++ /dev/null @@ -1,26 +0,0 @@ -// build-pass -// compile-flags: -O -// min-llvm-version: 14.0.5 -// needs-asm-support -// only-x86_64 -// only-linux - -// regression test for #96797 - -#![feature(asm_sym)] - -use std::arch::global_asm; - -#[no_mangle] -fn my_func() {} - -global_asm!("call_foobar: jmp {}", sym foobar); - -fn foobar() {} - -fn main() { - extern "Rust" { - fn call_foobar(); - } - unsafe { call_foobar() }; -} diff --git a/src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.rs b/src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.rs index 63bac96135b42..08260ec8f4d63 100644 --- a/src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.rs +++ b/src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.rs @@ -5,7 +5,7 @@ trait Foo { impl<'a> Foo for &'a () { const NAME: &'a str = "unit"; - //~^ ERROR const not compatible with trait + //~^ ERROR mismatched types [E0308] } fn main() {} diff --git a/src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.stderr b/src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.stderr index de1d9589e9961..f71fb2ee18aa1 100644 --- a/src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.stderr +++ b/src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.stderr @@ -1,4 +1,4 @@ -error[E0308]: const not compatible with trait +error[E0308]: mismatched types --> $DIR/associated-const-impl-wrong-lifetime.rs:7:5 | LL | const NAME: &'a str = "unit"; diff --git a/src/test/ui/associated-type-bounds/elision.rs b/src/test/ui/associated-type-bounds/elision.rs deleted file mode 100644 index 4a533939931b2..0000000000000 --- a/src/test/ui/associated-type-bounds/elision.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(associated_type_bounds)] -#![feature(anonymous_lifetime_in_impl_trait)] - -// The same thing should happen for constaints in dyn trait. -fn f(x: &mut dyn Iterator>) -> Option<&'_ ()> { x.next() } -//~^ ERROR missing lifetime specifier -//~| ERROR mismatched types - -fn main() {} diff --git a/src/test/ui/associated-type-bounds/elision.stderr b/src/test/ui/associated-type-bounds/elision.stderr deleted file mode 100644 index ea30246274965..0000000000000 --- a/src/test/ui/associated-type-bounds/elision.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error[E0106]: missing lifetime specifier - --> $DIR/elision.rs:5:70 - | -LL | fn f(x: &mut dyn Iterator>) -> Option<&'_ ()> { x.next() } - | ------------------------------------------------ ^^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `x`'s 2 lifetimes it is borrowed from -help: consider introducing a named lifetime parameter - | -LL | fn f<'a>(x: &'a mut dyn Iterator>) -> Option<&'a ()> { x.next() } - | ++++ ++ ~~ ~~ - -error[E0308]: mismatched types - --> $DIR/elision.rs:5:79 - | -LL | fn f(x: &mut dyn Iterator>) -> Option<&'_ ()> { x.next() } - | ----------------------------- -------------- ^^^^^^^^ expected `&()`, found type parameter `impl Iterator` - | | | - | | expected `Option<&'static ()>` because of return type - | this type parameter - | - = note: expected enum `Option<&'static ()>` - found enum `Option>` - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0106, E0308. -For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr b/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr index 4de4afb6e9246..e8e07997c721d 100644 --- a/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr +++ b/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr @@ -5,10 +5,15 @@ LL | fn elision &i32>() { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | fn elision Fn() -> &'a i32>() { + | +++++++ ~~~ help: consider using the `'static` lifetime | LL | fn elision &'static i32>() { - | +++++++ + | ~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr b/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr index 7753d186504f8..c75e732b7ca4c 100644 --- a/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr +++ b/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr @@ -5,10 +5,15 @@ LL | fn elision(_: fn() -> &i32) { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | fn elision(_: for<'a> fn() -> &'a i32) { + | +++++++ ~~~ help: consider using the `'static` lifetime | LL | fn elision(_: fn() -> &'static i32) { - | +++++++ + | ~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr index e5887689690e7..ada6e357aea5e 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -18,6 +18,14 @@ LL | | break 0u8; LL | | }; | |_________- enclosing `async` block +error[E0271]: type mismatch resolving ` as Future>::Output == ()` + --> $DIR/async-block-control-flow-static-semantics.rs:26:39 + | +LL | let _: &dyn Future = █ + | ^^^^^^ expected `()`, found `u8` + | + = note: required for the cast from `impl Future` to the object type `dyn Future` + error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:21:58 | @@ -32,7 +40,7 @@ LL | | } | |_^ expected `u8`, found `()` error[E0271]: type mismatch resolving ` as Future>::Output == ()` - --> $DIR/async-block-control-flow-static-semantics.rs:26:39 + --> $DIR/async-block-control-flow-static-semantics.rs:17:39 | LL | let _: &dyn Future = █ | ^^^^^^ expected `()`, found `u8` @@ -47,14 +55,6 @@ LL | fn return_targets_async_block_not_fn() -> u8 { | | | implicitly returns `()` as its body has no tail or `return` expression -error[E0271]: type mismatch resolving ` as Future>::Output == ()` - --> $DIR/async-block-control-flow-static-semantics.rs:17:39 - | -LL | let _: &dyn Future = █ - | ^^^^^^ expected `()`, found `u8` - | - = note: required for the cast from `impl Future` to the object type `dyn Future` - error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:47:44 | diff --git a/src/test/ui/async-await/issues/issue-63388-2.rs b/src/test/ui/async-await/issues/issue-63388-2.rs index 90b59f96e5f55..458bc9faeaf27 100644 --- a/src/test/ui/async-await/issues/issue-63388-2.rs +++ b/src/test/ui/async-await/issues/issue-63388-2.rs @@ -11,7 +11,6 @@ impl Xyz { foo: &dyn Foo, bar: &'a dyn Foo ) -> &dyn Foo //~ ERROR missing lifetime specifier { - //~^ ERROR explicit lifetime required in the type of `foo` [E0621] foo } } diff --git a/src/test/ui/async-await/issues/issue-63388-2.stderr b/src/test/ui/async-await/issues/issue-63388-2.stderr index e515f227c7ef6..24fd3845b4e04 100644 --- a/src/test/ui/async-await/issues/issue-63388-2.stderr +++ b/src/test/ui/async-await/issues/issue-63388-2.stderr @@ -10,21 +10,8 @@ LL | ) -> &dyn Foo help: consider using the `'a` lifetime | LL | ) -> &'a dyn Foo - | ++ + | ~~~ -error[E0621]: explicit lifetime required in the type of `foo` - --> $DIR/issue-63388-2.rs:13:5 - | -LL | foo: &dyn Foo, bar: &'a dyn Foo - | -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)` -LL | ) -> &dyn Foo -LL | / { -LL | | -LL | | foo -LL | | } - | |_____^ lifetime `'a` required - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0106, E0621. -For more information about an error, try `rustc --explain E0106`. +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr index 3128b4df4e2d1..cdb141c0e3ea2 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr @@ -13,7 +13,7 @@ LL | | } | = help: consider adding the following bound: `'a: 'b` -error[E0700]: hidden type for `impl Trait<'a>` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/ret-impl-trait-one.rs:16:80 | LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> { diff --git a/src/test/ui/btreemap/btreemap_dropck.rs b/src/test/ui/btreemap/btreemap_dropck.rs deleted file mode 100644 index c58727df30cae..0000000000000 --- a/src/test/ui/btreemap/btreemap_dropck.rs +++ /dev/null @@ -1,16 +0,0 @@ -struct PrintOnDrop<'a>(&'a str); - -impl Drop for PrintOnDrop<'_> { - fn drop(&mut self) { - println!("printint: {}", self.0); - } -} - -use std::collections::BTreeMap; -use std::iter::FromIterator; - -fn main() { - let s = String::from("Hello World!"); - let _map = BTreeMap::from_iter([((), PrintOnDrop(&s))]); - drop(s); //~ ERROR cannot move out of `s` because it is borrowed -} diff --git a/src/test/ui/btreemap/btreemap_dropck.stderr b/src/test/ui/btreemap/btreemap_dropck.stderr deleted file mode 100644 index e953e7ae82bb8..0000000000000 --- a/src/test/ui/btreemap/btreemap_dropck.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0505]: cannot move out of `s` because it is borrowed - --> $DIR/btreemap_dropck.rs:15:10 - | -LL | let _map = BTreeMap::from_iter([((), PrintOnDrop(&s))]); - | -- borrow of `s` occurs here -LL | drop(s); - | ^ move out of `s` occurs here -LL | } - | - borrow might be used here, when `_map` is dropped and runs the `Drop` code for type `BTreeMap` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/c-variadic/variadic-ffi-6.stderr b/src/test/ui/c-variadic/variadic-ffi-6.stderr index 4c7792d965019..bb15cc000a46b 100644 --- a/src/test/ui/c-variadic/variadic-ffi-6.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-6.stderr @@ -4,11 +4,11 @@ error[E0106]: missing lifetime specifier LL | ) -> &usize { | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments help: consider using the `'static` lifetime | LL | ) -> &'static usize { - | +++++++ + | ~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/closures/issue-99565.rs b/src/test/ui/closures/issue-99565.rs deleted file mode 100644 index 3a30d2ee03499..0000000000000 --- a/src/test/ui/closures/issue-99565.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![crate_type = "lib"] - -fn foo(_: U) {} - -fn bar() { - foo(|| {}); //~ ERROR type annotations needed -} diff --git a/src/test/ui/closures/issue-99565.stderr b/src/test/ui/closures/issue-99565.stderr deleted file mode 100644 index 0d940aa9a2f5f..0000000000000 --- a/src/test/ui/closures/issue-99565.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0282]: type annotations needed - --> $DIR/issue-99565.rs:6:5 - | -LL | foo(|| {}); - | ^^^ cannot infer type of the type parameter `T` declared on the function `foo` - | -help: consider specifying the generic arguments - | -LL | foo::(|| {}); - | ++++++++ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/coherence/issue-99663-2.rs b/src/test/ui/coherence/issue-99663-2.rs deleted file mode 100644 index 10a0a568849bf..0000000000000 --- a/src/test/ui/coherence/issue-99663-2.rs +++ /dev/null @@ -1,22 +0,0 @@ -// check-pass - -#![feature(type_alias_impl_trait)] - -struct Outer { - i: InnerSend, -} - -type InnerSend = impl Send; - -fn constrain() -> InnerSend { - () -} - -trait SendMustNotImplDrop {} - -#[allow(drop_bounds)] -impl SendMustNotImplDrop for T {} - -impl SendMustNotImplDrop for Outer {} - -fn main() {} diff --git a/src/test/ui/coherence/issue-99663.rs b/src/test/ui/coherence/issue-99663.rs deleted file mode 100644 index a2d4d398ce1d5..0000000000000 --- a/src/test/ui/coherence/issue-99663.rs +++ /dev/null @@ -1,22 +0,0 @@ -// check-pass - -#![feature(type_alias_impl_trait)] - -struct Send { - i: InnerSend, -} - -type InnerSend = impl Sized; - -fn constrain() -> InnerSend { - () -} - -trait SendMustNotImplDrop {} - -#[allow(drop_bounds)] -impl SendMustNotImplDrop for T {} - -impl SendMustNotImplDrop for Send {} - -fn main() {} diff --git a/src/test/ui/const-generics/associated-type-bound-fail.stderr b/src/test/ui/const-generics/associated-type-bound-fail.stderr index e5e7ee26e44bc..da2558229a758 100644 --- a/src/test/ui/const-generics/associated-type-bound-fail.stderr +++ b/src/test/ui/const-generics/associated-type-bound-fail.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `u16: Bar` is not satisfied LL | type Assoc = u16; | ^^^ the trait `Bar` is not implemented for `u16` | - = help: the trait `Bar<3>` is implemented for `u16` + = help: the trait `Bar<3_usize>` is implemented for `u16` note: required by a bound in `Foo::Assoc` --> $DIR/associated-type-bound-fail.rs:4:17 | diff --git a/src/test/ui/const-generics/defaults/generic-expr-default-concrete.stderr b/src/test/ui/const-generics/defaults/generic-expr-default-concrete.stderr index e8826ce4335e7..905a285370a0d 100644 --- a/src/test/ui/const-generics/defaults/generic-expr-default-concrete.stderr +++ b/src/test/ui/const-generics/defaults/generic-expr-default-concrete.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/generic-expr-default-concrete.rs:10:5 | LL | Foo::<10, 12> - | ^^^^^^^^^^^^^ expected `11`, found `12` + | ^^^^^^^^^^^^^ expected `11_usize`, found `12_usize` | - = note: expected type `11` - found type `12` + = note: expected type `11_usize` + found type `12_usize` error: aborting due to previous error diff --git a/src/test/ui/const-generics/defaults/mismatch.rs b/src/test/ui/const-generics/defaults/mismatch.rs index ec131505ed755..fce4ec4edda08 100644 --- a/src/test/ui/const-generics/defaults/mismatch.rs +++ b/src/test/ui/const-generics/defaults/mismatch.rs @@ -1,22 +1,22 @@ -pub struct Example; -pub struct Example2(T); -pub struct Example3(T); -pub struct Example4; +pub struct Example; +pub struct Example2(T); +pub struct Example3(T); +pub struct Example4; fn main() { - let e: Example<13> = (); + let e: Example::<13> = (); //~^ Error: mismatched types //~| expected struct `Example` - let e: Example2 = (); + let e: Example2:: = (); //~^ Error: mismatched types //~| expected struct `Example2` - let e: Example3<13, u32> = (); + let e: Example3::<13, u32> = (); //~^ Error: mismatched types //~| expected struct `Example3` - let e: Example3<7> = (); + let e: Example3::<7> = (); //~^ Error: mismatched types - //~| expected struct `Example3<7>` - let e: Example4<7> = (); + //~| expected struct `Example3<7_usize>` + let e: Example4::<7> = (); //~^ Error: mismatched types - //~| expected struct `Example4<7>` + //~| expected struct `Example4<7_usize>` } diff --git a/src/test/ui/const-generics/defaults/mismatch.stderr b/src/test/ui/const-generics/defaults/mismatch.stderr index 52c54aace5f16..369768191951b 100644 --- a/src/test/ui/const-generics/defaults/mismatch.stderr +++ b/src/test/ui/const-generics/defaults/mismatch.stderr @@ -1,8 +1,8 @@ error[E0308]: mismatched types - --> $DIR/mismatch.rs:7:26 + --> $DIR/mismatch.rs:7:28 | -LL | let e: Example<13> = (); - | ----------- ^^ expected struct `Example`, found `()` +LL | let e: Example::<13> = (); + | ------------- ^^ expected struct `Example`, found `()` | | | expected due to this | @@ -10,10 +10,10 @@ LL | let e: Example<13> = (); found unit type `()` error[E0308]: mismatched types - --> $DIR/mismatch.rs:10:32 + --> $DIR/mismatch.rs:10:34 | -LL | let e: Example2 = (); - | ----------------- ^^ expected struct `Example2`, found `()` +LL | let e: Example2:: = (); + | ------------------- ^^ expected struct `Example2`, found `()` | | | expected due to this | @@ -21,10 +21,10 @@ LL | let e: Example2 = (); found unit type `()` error[E0308]: mismatched types - --> $DIR/mismatch.rs:13:32 + --> $DIR/mismatch.rs:13:34 | -LL | let e: Example3<13, u32> = (); - | ----------------- ^^ expected struct `Example3`, found `()` +LL | let e: Example3::<13, u32> = (); + | ------------------- ^^ expected struct `Example3`, found `()` | | | expected due to this | @@ -32,25 +32,25 @@ LL | let e: Example3<13, u32> = (); found unit type `()` error[E0308]: mismatched types - --> $DIR/mismatch.rs:16:26 + --> $DIR/mismatch.rs:16:28 | -LL | let e: Example3<7> = (); - | ----------- ^^ expected struct `Example3`, found `()` +LL | let e: Example3::<7> = (); + | ------------- ^^ expected struct `Example3`, found `()` | | | expected due to this | - = note: expected struct `Example3<7>` + = note: expected struct `Example3<7_usize>` found unit type `()` error[E0308]: mismatched types - --> $DIR/mismatch.rs:19:26 + --> $DIR/mismatch.rs:19:28 | -LL | let e: Example4<7> = (); - | ----------- ^^ expected struct `Example4`, found `()` +LL | let e: Example4::<7> = (); + | ------------- ^^ expected struct `Example4`, found `()` | | | expected due to this | - = note: expected struct `Example4<7>` + = note: expected struct `Example4<7_usize>` found unit type `()` error: aborting due to 5 previous errors diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs index 80013e7b4b230..f633e56b0ec1d 100644 --- a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs +++ b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs @@ -4,15 +4,16 @@ trait Trait {} impl Trait for Uwu {} fn rawr() -> impl Trait { - //~^ error: the trait bound `Uwu<10, 12>: Trait` is not satisfied + //~^ error: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied Uwu::<10, 12> } -trait Traitor {} +trait Traitor { } impl Traitor for u32 {} impl Traitor<1, 2> for u64 {} + fn uwu() -> impl Traitor { //~^ error: the trait bound `u32: Traitor` is not satisfied 1_u32 diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr index f2e7777ce6814..cbc7b93f3a925 100644 --- a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr +++ b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Uwu<10, 12>: Trait` is not satisfied +error[E0277]: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied --> $DIR/rp_impl_trait_fail.rs:6:14 | LL | fn rawr() -> impl Trait { - | ^^^^^^^^^^ the trait `Trait` is not implemented for `Uwu<10, 12>` + | ^^^^^^^^^^ the trait `Trait` is not implemented for `Uwu<10_u32, 12_u32>` LL | LL | Uwu::<10, 12> - | ------------- return type was inferred to be `Uwu<10, 12>` here + | ------------- return type was inferred to be `Uwu<10_u32, 12_u32>` here | = help: the trait `Trait` is implemented for `Uwu` error[E0277]: the trait bound `u32: Traitor` is not satisfied - --> $DIR/rp_impl_trait_fail.rs:16:26 + --> $DIR/rp_impl_trait_fail.rs:17:26 | LL | fn uwu() -> impl Traitor { | ^^^^^^^^^^^^^^^ the trait `Traitor` is not implemented for `u32` @@ -19,11 +19,11 @@ LL | 1_u32 | ----- return type was inferred to be `u32` here | = help: the following other types implement trait `Traitor`: - > - > + > + > error[E0277]: the trait bound `u64: Traitor` is not satisfied - --> $DIR/rp_impl_trait_fail.rs:21:13 + --> $DIR/rp_impl_trait_fail.rs:22:13 | LL | fn owo() -> impl Traitor { | ^^^^^^^^^^^^ the trait `Traitor` is not implemented for `u64` @@ -32,8 +32,8 @@ LL | 1_u64 | ----- return type was inferred to be `u64` here | = help: the following other types implement trait `Traitor`: - > - > + > + > error: aborting due to 3 previous errors diff --git a/src/test/ui/const-generics/defaults/trait_objects_fail.rs b/src/test/ui/const-generics/defaults/trait_objects_fail.rs index 6ab803f990920..5e779d2e8de59 100644 --- a/src/test/ui/const-generics/defaults/trait_objects_fail.rs +++ b/src/test/ui/const-generics/defaults/trait_objects_fail.rs @@ -16,7 +16,7 @@ trait Traitor { } } -impl Traitor<2, 3> for bool {} +impl Traitor<2, 3> for bool { } fn bar(arg: &dyn Traitor) -> u8 { arg.owo() @@ -26,5 +26,5 @@ fn main() { foo(&10_u32); //~^ error: the trait bound `u32: Trait` is not satisfied bar(&true); - //~^ error: the trait bound `bool: Traitor<_>` is not satisfied + //~^ error: the trait bound `bool: Traitor<{_: u8}>` is not satisfied } diff --git a/src/test/ui/const-generics/defaults/trait_objects_fail.stderr b/src/test/ui/const-generics/defaults/trait_objects_fail.stderr index a9c185e5fcbd1..da85b2059f0a3 100644 --- a/src/test/ui/const-generics/defaults/trait_objects_fail.stderr +++ b/src/test/ui/const-generics/defaults/trait_objects_fail.stderr @@ -6,19 +6,19 @@ LL | foo(&10_u32); | | | required by a bound introduced by this call | - = help: the trait `Trait<2>` is implemented for `u32` + = help: the trait `Trait<2_u8>` is implemented for `u32` = note: required for the cast from `u32` to the object type `dyn Trait` -error[E0277]: the trait bound `bool: Traitor<_>` is not satisfied +error[E0277]: the trait bound `bool: Traitor<{_: u8}>` is not satisfied --> $DIR/trait_objects_fail.rs:28:9 | LL | bar(&true); - | --- ^^^^^ the trait `Traitor<_>` is not implemented for `bool` + | --- ^^^^^ the trait `Traitor<{_: u8}>` is not implemented for `bool` | | | required by a bound introduced by this call | - = help: the trait `Traitor<2, 3>` is implemented for `bool` - = note: required for the cast from `bool` to the object type `dyn Traitor<_>` + = help: the trait `Traitor<2_u8, 3_u8>` is implemented for `bool` + = note: required for the cast from `bool` to the object type `dyn Traitor<{_: u8}>` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/defaults/wfness.rs b/src/test/ui/const-generics/defaults/wfness.rs index a93f670815a03..d366040ba3ea6 100644 --- a/src/test/ui/const-generics/defaults/wfness.rs +++ b/src/test/ui/const-generics/defaults/wfness.rs @@ -3,20 +3,16 @@ struct Ooopsies; trait Trait {} impl Trait<3> for () {} -struct WhereClause -where - (): Trait; -//~^ error: the trait bound `(): Trait<2>` is not satisfied +struct WhereClause where (): Trait; +//~^ error: the trait bound `(): Trait<2_u8>` is not satisfied trait Traitor {} -struct WhereClauseTooGeneric(T) -where - (): Traitor; +struct WhereClauseTooGeneric(T) where (): Traitor; // no error on struct def struct DependentDefaultWfness>(T); fn foo() -> DependentDefaultWfness { - //~^ error: the trait bound `(): Trait<1>` is not satisfied + //~^ error: the trait bound `(): Trait<1_u8>` is not satisfied loop {} } diff --git a/src/test/ui/const-generics/defaults/wfness.stderr b/src/test/ui/const-generics/defaults/wfness.stderr index 25038f830befc..8b405d6753e56 100644 --- a/src/test/ui/const-generics/defaults/wfness.stderr +++ b/src/test/ui/const-generics/defaults/wfness.stderr @@ -4,29 +4,26 @@ error[E0080]: evaluation of constant value failed LL | struct Ooopsies; | ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow -error[E0277]: the trait bound `(): Trait<2>` is not satisfied - --> $DIR/wfness.rs:8:9 +error[E0277]: the trait bound `(): Trait<2_u8>` is not satisfied + --> $DIR/wfness.rs:6:47 | -LL | (): Trait; - | ^^^^^^^^ the trait `Trait<2>` is not implemented for `()` +LL | struct WhereClause where (): Trait; + | ^^^^^^^^ the trait `Trait<2_u8>` is not implemented for `()` | - = help: the trait `Trait<3>` is implemented for `()` + = help: the trait `Trait<3_u8>` is implemented for `()` -error[E0277]: the trait bound `(): Trait<1>` is not satisfied - --> $DIR/wfness.rs:18:13 +error[E0277]: the trait bound `(): Trait<1_u8>` is not satisfied + --> $DIR/wfness.rs:14:13 | LL | fn foo() -> DependentDefaultWfness { - | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<1>` is not implemented for `()` + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<1_u8>` is not implemented for `()` | - = help: the trait `Trait<3>` is implemented for `()` + = help: the trait `Trait<3_u8>` is implemented for `()` note: required by a bound in `WhereClause` - --> $DIR/wfness.rs:8:9 + --> $DIR/wfness.rs:6:47 | -LL | struct WhereClause - | ----------- required by a bound in this -LL | where -LL | (): Trait; - | ^^^^^^^^ required by this bound in `WhereClause` +LL | struct WhereClause where (): Trait; + | ^^^^^^^^ required by this bound in `WhereClause` error: aborting due to 3 previous errors diff --git a/src/test/ui/const-generics/different_generic_args.full.stderr b/src/test/ui/const-generics/different_generic_args.full.stderr index eba1768f7dda3..a2dcc033627c6 100644 --- a/src/test/ui/const-generics/different_generic_args.full.stderr +++ b/src/test/ui/const-generics/different_generic_args.full.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/different_generic_args.rs:11:9 | LL | u = ConstUsize::<4> {}; - | ^^^^^^^^^^^^^^^^^^ expected `3`, found `4` + | ^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize` | - = note: expected struct `ConstUsize<3>` - found struct `ConstUsize<4>` + = note: expected struct `ConstUsize<3_usize>` + found struct `ConstUsize<4_usize>` error: aborting due to previous error diff --git a/src/test/ui/const-generics/different_generic_args.min.stderr b/src/test/ui/const-generics/different_generic_args.min.stderr index eba1768f7dda3..a2dcc033627c6 100644 --- a/src/test/ui/const-generics/different_generic_args.min.stderr +++ b/src/test/ui/const-generics/different_generic_args.min.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/different_generic_args.rs:11:9 | LL | u = ConstUsize::<4> {}; - | ^^^^^^^^^^^^^^^^^^ expected `3`, found `4` + | ^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize` | - = note: expected struct `ConstUsize<3>` - found struct `ConstUsize<4>` + = note: expected struct `ConstUsize<3_usize>` + found struct `ConstUsize<4_usize>` error: aborting due to previous error diff --git a/src/test/ui/const-generics/different_generic_args_array.stderr b/src/test/ui/const-generics/different_generic_args_array.stderr index 4c5b5ada4f132..f0b9035357d82 100644 --- a/src/test/ui/const-generics/different_generic_args_array.stderr +++ b/src/test/ui/const-generics/different_generic_args_array.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/different_generic_args_array.rs:9:9 | LL | x = Const::<{ [4] }> {}; - | ^^^^^^^^^^^^^^^^^^^ expected `[3]`, found `[4]` + | ^^^^^^^^^^^^^^^^^^^ expected `[3_usize]`, found `[4_usize]` | - = note: expected struct `Const<[3]>` - found struct `Const<[4]>` + = note: expected struct `Const<[3_usize]>` + found struct `Const<[4_usize]>` error: aborting due to previous error diff --git a/src/test/ui/const-generics/exhaustive-value.stderr b/src/test/ui/const-generics/exhaustive-value.stderr index 76a83ba67ce79..9c1b086f4da9a 100644 --- a/src/test/ui/const-generics/exhaustive-value.stderr +++ b/src/test/ui/const-generics/exhaustive-value.stderr @@ -5,14 +5,14 @@ LL | <() as Foo>::test() | ^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()` | = help: the following other types implement trait `Foo`: - <() as Foo<0>> - <() as Foo<100>> - <() as Foo<101>> - <() as Foo<102>> - <() as Foo<103>> - <() as Foo<104>> - <() as Foo<105>> - <() as Foo<106>> + <() as Foo<0_u8>> + <() as Foo<100_u8>> + <() as Foo<101_u8>> + <() as Foo<102_u8>> + <() as Foo<103_u8>> + <() as Foo<104_u8>> + <() as Foo<105_u8>> + <() as Foo<106_u8>> and 248 others error: aborting due to previous error diff --git a/src/test/ui/const-generics/fn-const-param-call.full.stderr b/src/test/ui/const-generics/fn-const-param-call.full.stderr index b55c2449858c9..d984449e6ca6e 100644 --- a/src/test/ui/const-generics/fn-const-param-call.full.stderr +++ b/src/test/ui/const-generics/fn-const-param-call.full.stderr @@ -1,10 +1,10 @@ -error[E0741]: using function pointers as const generic parameters is forbidden +error: using function pointers as const generic parameters is forbidden --> $DIR/fn-const-param-call.rs:11:25 | LL | struct Wrapper u32>; | ^^^^^^^^^^^ -error[E0741]: using function pointers as const generic parameters is forbidden +error: using function pointers as const generic parameters is forbidden --> $DIR/fn-const-param-call.rs:13:15 | LL | impl u32> Wrapper { @@ -12,4 +12,3 @@ LL | impl u32> Wrapper { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/fn-const-param-infer.full.stderr b/src/test/ui/const-generics/fn-const-param-infer.full.stderr index 2d66a19233269..f0767a10994a5 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.full.stderr +++ b/src/test/ui/const-generics/fn-const-param-infer.full.stderr @@ -1,4 +1,4 @@ -error[E0741]: using function pointers as const generic parameters is forbidden +error: using function pointers as const generic parameters is forbidden --> $DIR/fn-const-param-infer.rs:6:25 | LL | struct Checked bool>; @@ -6,4 +6,3 @@ LL | struct Checked bool>; error: aborting due to previous error -For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/generic_arg_infer/in-signature.stderr b/src/test/ui/const-generics/generic_arg_infer/in-signature.stderr index 52d1b29f93222..7581cf4120ecf 100644 --- a/src/test/ui/const-generics/generic_arg_infer/in-signature.stderr +++ b/src/test/ui/const-generics/generic_arg_infer/in-signature.stderr @@ -14,7 +14,7 @@ LL | fn ty_fn() -> Bar { | ---------^- | | | | | not allowed in type signatures - | help: replace with the correct return type: `Bar` + | help: replace with the correct return type: `Bar` error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/in-signature.rs:17:25 @@ -24,7 +24,7 @@ LL | fn ty_fn_mixed() -> Bar<_, _> { | | | | | | | not allowed in type signatures | | not allowed in type signatures - | help: replace with the correct return type: `Bar` + | help: replace with the correct return type: `Bar` error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/in-signature.rs:22:15 @@ -45,7 +45,7 @@ LL | const TY_CT: Bar = Bar::(0); | ^^^^^^^^^^^ | | | not allowed in type signatures - | help: replace with the correct type: `Bar` + | help: replace with the correct type: `Bar` error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables --> $DIR/in-signature.rs:28:19 @@ -54,7 +54,7 @@ LL | static TY_STATIC: Bar = Bar::(0); | ^^^^^^^^^^^ | | | not allowed in type signatures - | help: replace with the correct type: `Bar` + | help: replace with the correct type: `Bar` error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/in-signature.rs:30:20 @@ -63,7 +63,7 @@ LL | const TY_CT_MIXED: Bar<_, _> = Bar::(0); | ^^^^^^^^^ | | | not allowed in type signatures - | help: replace with the correct type: `Bar` + | help: replace with the correct type: `Bar` error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables --> $DIR/in-signature.rs:32:25 @@ -72,7 +72,7 @@ LL | static TY_STATIC_MIXED: Bar<_, _> = Bar::(0); | ^^^^^^^^^ | | | not allowed in type signatures - | help: replace with the correct type: `Bar` + | help: replace with the correct type: `Bar` error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/in-signature.rs:35:21 diff --git a/src/test/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.stderr b/src/test/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.stderr index ababb27a869d6..f235eb443b829 100644 --- a/src/test/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.stderr @@ -56,19 +56,19 @@ error[E0308]: mismatched types --> $DIR/abstract-const-as-cast-3.rs:23:5 | LL | assert_impl::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12`, found `13` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12_u128`, found `13_u128` | - = note: expected type `12` - found type `13` + = note: expected type `12_u128` + found type `13_u128` error[E0308]: mismatched types --> $DIR/abstract-const-as-cast-3.rs:25:5 | LL | assert_impl::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13`, found `14` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13_u128`, found `14_u128` | - = note: expected type `13` - found type `14` + = note: expected type `13_u128` + found type `14_u128` error: unconstrained generic constant --> $DIR/abstract-const-as-cast-3.rs:35:5 @@ -128,19 +128,19 @@ error[E0308]: mismatched types --> $DIR/abstract-const-as-cast-3.rs:41:5 | LL | assert_impl::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12`, found `13` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12_u128`, found `13_u128` | - = note: expected type `12` - found type `13` + = note: expected type `12_u128` + found type `13_u128` error[E0308]: mismatched types --> $DIR/abstract-const-as-cast-3.rs:43:5 | LL | assert_impl::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13`, found `14` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13_u128`, found `14_u128` | - = note: expected type `13` - found type `14` + = note: expected type `13_u128` + found type `14_u128` error: aborting due to 12 previous errors diff --git a/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs index 5874625adff61..18f33acaabbba 100644 --- a/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs +++ b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs @@ -1,5 +1,3 @@ -// check-pass - #![feature(generic_const_exprs)] #![allow(incomplete_features)] @@ -23,6 +21,11 @@ where } fn main() { + // FIXME(generic_const_exprs): We can't correctly infer `T` which requires + // evaluating `{ N + 1 }` which has substs containing an inference var let mut _q = Default::default(); + //~^ ERROR type annotations needed + _q = foo::<_, 2>(_q); + //~^ ERROR type annotations needed } diff --git a/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr new file mode 100644 index 0000000000000..9e8328d37017e --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr @@ -0,0 +1,38 @@ +error[E0282]: type annotations needed + --> $DIR/const_eval_resolve_canonical.rs:26:9 + | +LL | let mut _q = Default::default(); + | ^^^^^^ + | +help: consider giving `_q` an explicit type + | +LL | let mut _q: _ = Default::default(); + | +++ + +error[E0283]: type annotations needed + --> $DIR/const_eval_resolve_canonical.rs:29:10 + | +LL | _q = foo::<_, 2>(_q); + | ^^^^^^^^^^^ cannot infer the value of the constant `{ N + 1 }` + | +note: multiple `impl`s satisfying `(): Foo<{ N + 1 }>` found + --> $DIR/const_eval_resolve_canonical.rs:8:1 + | +LL | impl Foo<0> for () { + | ^^^^^^^^^^^^^^^^^^ +... +LL | impl Foo<3> for () { + | ^^^^^^^^^^^^^^^^^^ +note: required by a bound in `foo` + --> $DIR/const_eval_resolve_canonical.rs:18:9 + | +LL | fn foo(_: T) -> <() as Foo<{ N + 1 }>>::Assoc + | --- required by a bound in this +LL | where +LL | (): Foo<{ N + 1 }>, + | ^^^^^^^^^^^^^^ required by this bound in `foo` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0282, E0283. +For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.rs b/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.rs index b8f9827ec9187..90953145944fe 100644 --- a/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.rs +++ b/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.rs @@ -2,7 +2,7 @@ #![allow(incomplete_features)] fn test() -> [u8; N - 1] { - //~^ ERROR evaluation of `test::<0>::{constant#0}` failed + //~^ ERROR evaluation of `test::<0_usize>::{constant#0}` failed todo!() } diff --git a/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.stderr b/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.stderr index bd71b49ee238b..31ccf97969472 100644 --- a/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.stderr @@ -1,4 +1,4 @@ -error[E0080]: evaluation of `test::<0>::{constant#0}` failed +error[E0080]: evaluation of `test::<0_usize>::{constant#0}` failed --> $DIR/from-sig-fail.rs:4:35 | LL | fn test() -> [u8; N - 1] { diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr index 7a083733a2cd1..77a3b77ad428b 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr @@ -4,14 +4,14 @@ error[E0423]: expected value, found type parameter `T` LL | impl Bar for [u8; T] {} | ^ not a value -error[E0599]: the function or associated item `foo` exists for struct `Foo<_>`, but its trait bounds were not satisfied +error[E0599]: the function or associated item `foo` exists for struct `Foo<{_: usize}>`, but its trait bounds were not satisfied --> $DIR/issue-69654.rs:17:10 | LL | struct Foo {} | -------------------------- function or associated item `foo` not found for this struct ... LL | Foo::foo(); - | ^^^ function or associated item cannot be called on `Foo<_>` due to unsatisfied trait bounds + | ^^^ function or associated item cannot be called on `Foo<{_: usize}>` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `[u8; _]: Bar<[(); _]>` diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr index 4d0d0253f1b6d..41afaec86b6e4 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr @@ -34,21 +34,21 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = help: const parameters may only be used as standalone arguments, i.e. `J` = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions -error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual: True` +error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual: True` --> $DIR/issue-72787.rs:21:26 | LL | IsLessOrEqual: True, | ^^^^ | - = note: cannot satisfy `IsLessOrEqual: True` + = note: cannot satisfy `IsLessOrEqual: True` -error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual: True` +error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual: True` --> $DIR/issue-72787.rs:21:26 | LL | IsLessOrEqual: True, | ^^^^ | - = note: cannot satisfy `IsLessOrEqual: True` + = note: cannot satisfy `IsLessOrEqual: True` error: aborting due to 6 previous errors diff --git a/src/test/ui/const-generics/generic_const_exprs/simple_fail.rs b/src/test/ui/const-generics/generic_const_exprs/simple_fail.rs index cae54df4c1210..c47a350c7fb43 100644 --- a/src/test/ui/const-generics/generic_const_exprs/simple_fail.rs +++ b/src/test/ui/const-generics/generic_const_exprs/simple_fail.rs @@ -2,13 +2,10 @@ #![allow(incomplete_features)] type Arr = [u8; N - 1]; -//~^ ERROR evaluation of `Arr::<0>::{constant#0}` failed +//~^ ERROR evaluation of `Arr::<0_usize>::{constant#0}` failed -fn test() -> Arr -where - [u8; N - 1]: Sized, - //~^ ERROR evaluation of `test::<0>::{constant#0}` failed -{ +fn test() -> Arr where [u8; N - 1]: Sized { +//~^ ERROR evaluation of `test::<0_usize>::{constant#0}` failed todo!() } diff --git a/src/test/ui/const-generics/generic_const_exprs/simple_fail.stderr b/src/test/ui/const-generics/generic_const_exprs/simple_fail.stderr index a25fa56b7d498..99fc92fb4f0ad 100644 --- a/src/test/ui/const-generics/generic_const_exprs/simple_fail.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/simple_fail.stderr @@ -1,10 +1,10 @@ -error[E0080]: evaluation of `test::<0>::{constant#0}` failed - --> $DIR/simple_fail.rs:9:10 +error[E0080]: evaluation of `test::<0_usize>::{constant#0}` failed + --> $DIR/simple_fail.rs:7:48 | -LL | [u8; N - 1]: Sized, - | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow +LL | fn test() -> Arr where [u8; N - 1]: Sized { + | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow -error[E0080]: evaluation of `Arr::<0>::{constant#0}` failed +error[E0080]: evaluation of `Arr::<0_usize>::{constant#0}` failed --> $DIR/simple_fail.rs:4:33 | LL | type Arr = [u8; N - 1]; diff --git a/src/test/ui/const-generics/infer/one-param-uninferred.stderr b/src/test/ui/const-generics/infer/one-param-uninferred.stderr index cf70c21813950..98ea8df825265 100644 --- a/src/test/ui/const-generics/infer/one-param-uninferred.stderr +++ b/src/test/ui/const-generics/infer/one-param-uninferred.stderr @@ -6,8 +6,8 @@ LL | let _: [u8; 17] = foo(); | help: consider specifying the generic arguments | -LL | let _: [u8; 17] = foo::<17, M>(); - | +++++++++ +LL | let _: [u8; 17] = foo::<17_usize, M>(); + | +++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/const-generics/issue-66451.stderr b/src/test/ui/const-generics/issue-66451.stderr index e0cb0b661ff65..b691eac4f2d0e 100644 --- a/src/test/ui/const-generics/issue-66451.stderr +++ b/src/test/ui/const-generics/issue-66451.stderr @@ -8,12 +8,12 @@ LL | | value: 3, LL | | nested: &Bar(5), LL | | } LL | | }> = x; - | | - ^ expected `Foo { value: 3, nested: &Bar::(5) }`, found `Foo { value: 3, nested: &Bar::(4) }` + | | - ^ expected `Foo { value: 3_i32, nested: &Bar::(5_i32) }`, found `Foo { value: 3_i32, nested: &Bar::(4_i32) }` | |______| | expected due to this | - = note: expected struct `Test(5) }>` - found struct `Test(4) }>` + = note: expected struct `Test(5_i32) }>` + found struct `Test(4_i32) }>` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-71381.full.stderr b/src/test/ui/const-generics/issues/issue-71381.full.stderr index e17cf96aa3e3d..3950317b37053 100644 --- a/src/test/ui/const-generics/issues/issue-71381.full.stderr +++ b/src/test/ui/const-generics/issues/issue-71381.full.stderr @@ -10,13 +10,13 @@ error[E0770]: the type of const parameters must not depend on other generic para LL | const FN: unsafe extern "C" fn(Args), | ^^^^ the type must not depend on the parameter `Args` -error[E0741]: using function pointers as const generic parameters is forbidden +error: using function pointers as const generic parameters is forbidden --> $DIR/issue-71381.rs:14:61 | LL | pub fn call_me(&self) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0741]: using function pointers as const generic parameters is forbidden +error: using function pointers as const generic parameters is forbidden --> $DIR/issue-71381.rs:23:19 | LL | const FN: unsafe extern "C" fn(Args), @@ -24,5 +24,4 @@ LL | const FN: unsafe extern "C" fn(Args), error: aborting due to 4 previous errors -Some errors have detailed explanations: E0741, E0770. -For more information about an error, try `rustc --explain E0741`. +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-71382.full.stderr b/src/test/ui/const-generics/issues/issue-71382.full.stderr index ab2a4e64a8389..715037bd5f1e8 100644 --- a/src/test/ui/const-generics/issues/issue-71382.full.stderr +++ b/src/test/ui/const-generics/issues/issue-71382.full.stderr @@ -1,4 +1,4 @@ -error[E0741]: using function pointers as const generic parameters is forbidden +error: using function pointers as const generic parameters is forbidden --> $DIR/issue-71382.rs:16:23 | LL | fn test(&self) { @@ -6,4 +6,3 @@ LL | fn test(&self) { error: aborting due to previous error -For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/issues/issue-71611.full.stderr b/src/test/ui/const-generics/issues/issue-71611.full.stderr index 656aa29e19b25..01a85b745ce39 100644 --- a/src/test/ui/const-generics/issues/issue-71611.full.stderr +++ b/src/test/ui/const-generics/issues/issue-71611.full.stderr @@ -4,7 +4,7 @@ error[E0770]: the type of const parameters must not depend on other generic para LL | fn func(outer: A) { | ^ the type must not depend on the parameter `A` -error[E0741]: using function pointers as const generic parameters is forbidden +error: using function pointers as const generic parameters is forbidden --> $DIR/issue-71611.rs:5:21 | LL | fn func(outer: A) { @@ -12,5 +12,4 @@ LL | fn func(outer: A) { error: aborting due to 2 previous errors -Some errors have detailed explanations: E0741, E0770. -For more information about an error, try `rustc --explain E0741`. +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-72352.full.stderr b/src/test/ui/const-generics/issues/issue-72352.full.stderr index 92580b33685d1..eedd73c4dcc0a 100644 --- a/src/test/ui/const-generics/issues/issue-72352.full.stderr +++ b/src/test/ui/const-generics/issues/issue-72352.full.stderr @@ -1,4 +1,4 @@ -error[E0741]: using function pointers as const generic parameters is forbidden +error: using function pointers as const generic parameters is forbidden --> $DIR/issue-72352.rs:7:42 | LL | unsafe fn unsafely_do_the_thing usize>(ptr: *const i8) -> usize { @@ -6,4 +6,3 @@ LL | unsafe fn unsafely_do_the_thing usize>(ptr: *const i8 error: aborting due to previous error -For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/issues/issue-86530.rs b/src/test/ui/const-generics/issues/issue-86530.rs index b024decd4e11c..4a6ffd1f3008e 100644 --- a/src/test/ui/const-generics/issues/issue-86530.rs +++ b/src/test/ui/const-generics/issues/issue-86530.rs @@ -15,6 +15,7 @@ where fn unit_literals() { z(" "); //~^ ERROR: the trait bound `&str: X` is not satisfied + //~| ERROR: unconstrained generic constant } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-86530.stderr b/src/test/ui/const-generics/issues/issue-86530.stderr index c63857b2314e9..c688f838dab47 100644 --- a/src/test/ui/const-generics/issues/issue-86530.stderr +++ b/src/test/ui/const-generics/issues/issue-86530.stderr @@ -15,6 +15,22 @@ LL | where LL | T: X, | ^ required by this bound in `z` -error: aborting due to previous error +error: unconstrained generic constant + --> $DIR/issue-86530.rs:16:5 + | +LL | z(" "); + | ^ + | + = help: try adding a `where` bound using this expression: `where [(); T::Y]:` +note: required by a bound in `z` + --> $DIR/issue-86530.rs:11:10 + | +LL | fn z(t: T) + | - required by a bound in this +... +LL | [(); T::Y]: , + | ^^^^ required by this bound in `z` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-90318.rs b/src/test/ui/const-generics/issues/issue-90318.rs index d6c48e63bb3ce..bebd0c6ac1202 100644 --- a/src/test/ui/const-generics/issues/issue-90318.rs +++ b/src/test/ui/const-generics/issues/issue-90318.rs @@ -12,14 +12,16 @@ impl True for If {} fn consume(_val: T) where If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - //~^ ERROR: can't compare + //~^ ERROR: overly complex generic constant + //~| ERROR: cannot call non-const operator in constants { } fn test() where If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - //~^ ERROR: can't compare + //~^ ERROR: overly complex generic constant + //~| ERROR: cannot call non-const operator in constants { } diff --git a/src/test/ui/const-generics/issues/issue-90318.stderr b/src/test/ui/const-generics/issues/issue-90318.stderr index aba4b5c1a8d8d..c8690ecd0da7e 100644 --- a/src/test/ui/const-generics/issues/issue-90318.stderr +++ b/src/test/ui/const-generics/issues/issue-90318.stderr @@ -1,29 +1,53 @@ -error[E0277]: can't compare `TypeId` with `_` in const contexts - --> $DIR/issue-90318.rs:14:28 +error: overly complex generic constant + --> $DIR/issue-90318.rs:14:8 | LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^ no implementation for `TypeId == _` + | ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | borrowing is not supported in generic constants | - = help: the trait `~const PartialEq<_>` is not implemented for `TypeId` -note: the trait `PartialEq<_>` is implemented for `TypeId`, but that implementation is not `const` - --> $DIR/issue-90318.rs:14:28 + = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future + +error[E0015]: cannot call non-const operator in constants + --> $DIR/issue-90318.rs:14:10 | LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/any.rs:LL:COL + | +LL | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] + | ^^^^^^^^^ + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: can't compare `TypeId` with `_` in const contexts - --> $DIR/issue-90318.rs:21:28 +error: overly complex generic constant + --> $DIR/issue-90318.rs:22:8 | LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^ no implementation for `TypeId == _` + | ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | borrowing is not supported in generic constants | - = help: the trait `~const PartialEq<_>` is not implemented for `TypeId` -note: the trait `PartialEq<_>` is implemented for `TypeId`, but that implementation is not `const` - --> $DIR/issue-90318.rs:21:28 + = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future + +error[E0015]: cannot call non-const operator in constants + --> $DIR/issue-90318.rs:22:10 | LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/any.rs:LL:COL + | +LL | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] + | ^^^^^^^^^ + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/const-generics/issues/issue-98629.rs b/src/test/ui/const-generics/issues/issue-98629.rs deleted file mode 100644 index fc8666bbcdb79..0000000000000 --- a/src/test/ui/const-generics/issues/issue-98629.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(const_trait_impl)] - -trait Trait { - const N: usize; -} - -impl const Trait for i32 {} -//~^ ERROR not all trait items implemented, missing: `N` - -fn f() -where - [(); ::N]:, -{} - -fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-98629.stderr b/src/test/ui/const-generics/issues/issue-98629.stderr deleted file mode 100644 index 53570220882c3..0000000000000 --- a/src/test/ui/const-generics/issues/issue-98629.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0046]: not all trait items implemented, missing: `N` - --> $DIR/issue-98629.rs:7:1 - | -LL | const N: usize; - | -------------- `N` from trait -... -LL | impl const Trait for i32 {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ missing `N` in implementation - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0046`. diff --git a/src/test/ui/const-generics/issues/issue-99641.rs b/src/test/ui/const-generics/issues/issue-99641.rs deleted file mode 100644 index fae6d3fc41fb8..0000000000000 --- a/src/test/ui/const-generics/issues/issue-99641.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![feature(adt_const_params)] -#![allow(incomplete_features)] - -fn main() { - pub struct Color; - //~^ ERROR using function pointers - - impl Color { - //~^ ERROR using function pointers - pub fn new() -> Self { - Color:: - } - } - - pub const D65: (fn(),) = (|| {},); - - Color::::new(); -} diff --git a/src/test/ui/const-generics/issues/issue-99641.stderr b/src/test/ui/const-generics/issues/issue-99641.stderr deleted file mode 100644 index 349ebba08d53f..0000000000000 --- a/src/test/ui/const-generics/issues/issue-99641.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0741]: using function pointers as const generic parameters is forbidden - --> $DIR/issue-99641.rs:5:35 - | -LL | pub struct Color; - | ^^^^^^^ - -error[E0741]: using function pointers as const generic parameters is forbidden - --> $DIR/issue-99641.rs:8:23 - | -LL | impl Color { - | ^^^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/nested-type.full.stderr b/src/test/ui/const-generics/nested-type.full.stderr index 6d9f4406504ee..52f1c58825823 100644 --- a/src/test/ui/const-generics/nested-type.full.stderr +++ b/src/test/ui/const-generics/nested-type.full.stderr @@ -1,4 +1,4 @@ -error[E0015]: cannot call non-const fn `Foo::{constant#0}::Foo::<17>::value` in constants +error[E0015]: cannot call non-const fn `Foo::{constant#0}::Foo::<17_usize>::value` in constants --> $DIR/nested-type.rs:15:5 | LL | Foo::<17>::value() diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr b/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr index a3c011d927b5a..48e12e903b86a 100644 --- a/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr +++ b/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `A<_>: Bar<_>` is not satisfied +error[E0277]: the trait bound `A<{_: usize}>: Bar<{_: usize}>` is not satisfied --> $DIR/unused-substs-1.rs:12:13 | LL | let _ = A; - | ^ the trait `Bar<_>` is not implemented for `A<_>` + | ^ the trait `Bar<{_: usize}>` is not implemented for `A<{_: usize}>` | - = help: the trait `Bar` is implemented for `A<7>` + = help: the trait `Bar` is implemented for `A<7_usize>` note: required by a bound in `A` --> $DIR/unused-substs-1.rs:9:11 | diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.full.stderr b/src/test/ui/const-generics/raw-ptr-const-param-deref.full.stderr index 657eee2be2443..04bc46cb4ab12 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param-deref.full.stderr +++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.full.stderr @@ -1,10 +1,10 @@ -error[E0741]: using raw pointers as const generic parameters is forbidden +error: using raw pointers as const generic parameters is forbidden --> $DIR/raw-ptr-const-param-deref.rs:9:23 | LL | struct Const; | ^^^^^^^^^^ -error[E0741]: using raw pointers as const generic parameters is forbidden +error: using raw pointers as const generic parameters is forbidden --> $DIR/raw-ptr-const-param-deref.rs:11:15 | LL | impl Const

{ @@ -12,4 +12,3 @@ LL | impl Const

{ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/raw-ptr-const-param.full.stderr b/src/test/ui/const-generics/raw-ptr-const-param.full.stderr index 69f1aae5681a4..310422aafcd35 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param.full.stderr +++ b/src/test/ui/const-generics/raw-ptr-const-param.full.stderr @@ -1,4 +1,4 @@ -error[E0741]: using raw pointers as const generic parameters is forbidden +error: using raw pointers as const generic parameters is forbidden --> $DIR/raw-ptr-const-param.rs:6:23 | LL | struct Const; @@ -6,4 +6,3 @@ LL | struct Const; error: aborting due to previous error -For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/types-mismatch-const-args.full.stderr b/src/test/ui/const-generics/types-mismatch-const-args.full.stderr index 486506239ddfd..4d6b752867f1b 100644 --- a/src/test/ui/const-generics/types-mismatch-const-args.full.stderr +++ b/src/test/ui/const-generics/types-mismatch-const-args.full.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/types-mismatch-const-args.rs:14:41 | LL | let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {2u32 + 2u32}, {3u32}> { data: PhantomData }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2`, found `4` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2_u32`, found `4_u32` | - = note: expected type `2` - found type `4` + = note: expected type `2_u32` + found type `4_u32` error[E0308]: mismatched types --> $DIR/types-mismatch-const-args.rs:16:41 @@ -26,8 +26,8 @@ LL | let _: A<'a, u16, {4u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data | | | expected due to this | - = note: expected struct `A<'a, u16, 4, _>` - found struct `A<'b, u32, 2, _>` + = note: expected struct `A<'a, u16, 4_u32, _>` + found struct `A<'b, u32, 2_u32, _>` error: aborting due to 3 previous errors diff --git a/src/test/ui/const-generics/types-mismatch-const-args.min.stderr b/src/test/ui/const-generics/types-mismatch-const-args.min.stderr index 6ac93a08d5d68..8b60238cb0c03 100644 --- a/src/test/ui/const-generics/types-mismatch-const-args.min.stderr +++ b/src/test/ui/const-generics/types-mismatch-const-args.min.stderr @@ -2,12 +2,12 @@ error[E0308]: mismatched types --> $DIR/types-mismatch-const-args.rs:14:41 | LL | let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {2u32 + 2u32}, {3u32}> { data: PhantomData }; - | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2`, found `4` + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2_u32`, found `4_u32` | | | expected due to this | - = note: expected struct `A<'_, _, 2, _>` - found struct `A<'_, _, 4, _>` + = note: expected struct `A<'_, _, 2_u32, _>` + found struct `A<'_, _, 4_u32, _>` error[E0308]: mismatched types --> $DIR/types-mismatch-const-args.rs:16:41 @@ -28,8 +28,8 @@ LL | let _: A<'a, u16, {4u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data | | | expected due to this | - = note: expected struct `A<'a, u16, 4, _>` - found struct `A<'b, u32, 2, _>` + = note: expected struct `A<'a, u16, 4_u32, _>` + found struct `A<'b, u32, 2_u32, _>` error: aborting due to 3 previous errors diff --git a/src/test/ui/const-ptr/forbidden_slices.32bit.stderr b/src/test/ui/const-ptr/forbidden_slices.32bit.stderr index f3bf9c496da7b..c2d22ca4917db 100644 --- a/src/test/ui/const-ptr/forbidden_slices.32bit.stderr +++ b/src/test/ui/const-ptr/forbidden_slices.32bit.stderr @@ -222,7 +222,7 @@ error[E0080]: could not evaluate static initializer LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | `ptr_offset_from_unsigned` called on pointers into different allocations + | ptr_offset_from_unsigned called on pointers into different allocations | inside `ptr::const_ptr::::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL @@ -241,7 +241,7 @@ error[E0080]: could not evaluate static initializer LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | `ptr_offset_from_unsigned` called on pointers into different allocations + | ptr_offset_from_unsigned called on pointers into different allocations | inside `ptr::const_ptr::::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL diff --git a/src/test/ui/const-ptr/forbidden_slices.64bit.stderr b/src/test/ui/const-ptr/forbidden_slices.64bit.stderr index 5f2821a91937b..da9df1c63a4cb 100644 --- a/src/test/ui/const-ptr/forbidden_slices.64bit.stderr +++ b/src/test/ui/const-ptr/forbidden_slices.64bit.stderr @@ -222,7 +222,7 @@ error[E0080]: could not evaluate static initializer LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | `ptr_offset_from_unsigned` called on pointers into different allocations + | ptr_offset_from_unsigned called on pointers into different allocations | inside `ptr::const_ptr::::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL @@ -241,7 +241,7 @@ error[E0080]: could not evaluate static initializer LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | `ptr_offset_from_unsigned` called on pointers into different allocations + | ptr_offset_from_unsigned called on pointers into different allocations | inside `ptr::const_ptr::::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs index cd7c980077533..e238e13b8e2da 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs @@ -1,6 +1,6 @@ fn main() {} // unconst and bad, will thus error in miri -const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR can't compare +const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be reliably // unconst and bad, will thus error in miri -const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR can't compare +const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be reliably diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr index 168fa0ad0f0ed..1f5bca273d3b0 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr @@ -1,49 +1,18 @@ -error[E0277]: can't compare `*const i32` with `_` in const contexts - --> $DIR/const_raw_ptr_ops.rs:4:43 +error: pointers cannot be reliably compared during const eval + --> $DIR/const_raw_ptr_ops.rs:4:26 | LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; - | ^^ no implementation for `*const i32 == _` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: the trait `~const PartialEq<_>` is not implemented for `*const i32` -note: the trait `PartialEq<_>` is implemented for `*const i32`, but that implementation is not `const` - --> $DIR/const_raw_ptr_ops.rs:4:43 - | -LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; - | ^^ - = help: the following other types implement trait `PartialEq`: - f32 - f64 - i128 - i16 - i32 - i64 - i8 - isize - and 6 others + = note: see issue #53020 for more information -error[E0277]: can't compare `*const i32` with `_` in const contexts - --> $DIR/const_raw_ptr_ops.rs:6:44 +error: pointers cannot be reliably compared during const eval + --> $DIR/const_raw_ptr_ops.rs:6:27 | LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; - | ^^ no implementation for `*const i32 == _` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: the trait `~const PartialEq<_>` is not implemented for `*const i32` -note: the trait `PartialEq<_>` is implemented for `*const i32`, but that implementation is not `const` - --> $DIR/const_raw_ptr_ops.rs:6:44 - | -LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; - | ^^ - = help: the following other types implement trait `PartialEq`: - f32 - f64 - i128 - i16 - i32 - i64 - i8 - isize - and 6 others + = note: see issue #53020 for more information error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/consts/const-eval/const_transmute.rs b/src/test/ui/consts/const-eval/const_transmute.rs new file mode 100644 index 0000000000000..90a454c75a1ce --- /dev/null +++ b/src/test/ui/consts/const-eval/const_transmute.rs @@ -0,0 +1,54 @@ +// run-pass + +#![allow(dead_code)] + +#[repr(C)] +union Transmute { + t: T, + u: U, +} + +trait Bar { + fn bar(&self) -> u32; +} + +struct Foo { + foo: u32, + bar: bool, +} + +impl Bar for Foo { + fn bar(&self) -> u32 { + self.foo + } +} + +impl Drop for Foo { + fn drop(&mut self) { + assert!(!self.bar); + self.bar = true; + println!("dropping Foo"); + } +} + +#[derive(Copy, Clone)] +struct Fat<'a>(&'a Foo, &'static VTable); + +struct VTable { + drop: Option fn(&'a mut Foo)>, + size: usize, + align: usize, + bar: for<'a> fn(&'a Foo) -> u32, +} + +const FOO: &dyn Bar = &Foo { foo: 128, bar: false }; +const G: Fat = unsafe { Transmute { t: FOO }.u }; +const F: Option fn(&'a mut Foo)> = G.1.drop; +const H: for<'a> fn(&'a Foo) -> u32 = G.1.bar; + +fn main() { + let mut foo = Foo { foo: 99, bar: false }; + (F.unwrap())(&mut foo); + std::mem::forget(foo); // already ran the drop impl + assert_eq!(H(&Foo { foo: 42, bar: false }), 42); +} diff --git a/src/test/ui/consts/const-eval/issue-85155.stderr b/src/test/ui/consts/const-eval/issue-85155.stderr index 3d2c76b7ed040..c36d7c1721526 100644 --- a/src/test/ui/consts/const-eval/issue-85155.stderr +++ b/src/test/ui/consts/const-eval/issue-85155.stderr @@ -1,10 +1,10 @@ -error[E0080]: evaluation of `post_monomorphization_error::ValidateConstImm::<2, 0, 1>::VALID` failed +error[E0080]: evaluation of `post_monomorphization_error::ValidateConstImm::<2_i32, 0_i32, 1_i32>::VALID` failed --> $DIR/auxiliary/post_monomorphization_error.rs:7:17 | LL | let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to divide `1_usize` by zero -note: the above error was encountered while instantiating `fn post_monomorphization_error::stdarch_intrinsic::<2>` +note: the above error was encountered while instantiating `fn post_monomorphization_error::stdarch_intrinsic::<2_i32>` --> $DIR/issue-85155.rs:19:5 | LL | post_monomorphization_error::stdarch_intrinsic::<2>(); diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr index 965256de21a0f..c6422447a4b79 100644 --- a/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr @@ -2,19 +2,19 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-incorrect-vtable.rs:19:14 | LL | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid vtable: alignment `1000` is not a power of 2 error[E0080]: evaluation of constant value failed --> $DIR/ub-incorrect-vtable.rs:24:14 | LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid vtable: size is bigger than largest supported object error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:33:1 + --> $DIR/ub-incorrect-vtable.rs:34:1 | LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: alignment `1000` is not a power of 2 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -22,38 +22,16 @@ LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:38:1 + --> $DIR/ub-incorrect-vtable.rs:39:1 | LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: size is bigger than largest supported object | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:44:1 - | -LL | const INVALID_VTABLE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:91:1 - | -LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; - | ^^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ - } - -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr index bd542a7a5f293..e594ad71b5b48 100644 --- a/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr @@ -2,19 +2,19 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-incorrect-vtable.rs:19:14 | LL | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid vtable: alignment `1000` is not a power of 2 error[E0080]: evaluation of constant value failed --> $DIR/ub-incorrect-vtable.rs:24:14 | LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid vtable: size is bigger than largest supported object error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:33:1 + --> $DIR/ub-incorrect-vtable.rs:34:1 | LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: alignment `1000` is not a power of 2 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -22,38 +22,16 @@ LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:38:1 + --> $DIR/ub-incorrect-vtable.rs:39:1 | LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: size is bigger than largest supported object | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:44:1 - | -LL | const INVALID_VTABLE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:91:1 - | -LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; - | ^^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ - } - -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs b/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs index 4bb30b75bc8eb..4ec853576c91b 100644 --- a/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs +++ b/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs @@ -18,79 +18,27 @@ trait Trait {} const INVALID_VTABLE_ALIGNMENT: &dyn Trait = unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; //~^ ERROR evaluation of constant value failed -//~| does not point to a vtable +//~| invalid vtable: alignment `1000` is not a power of 2 const INVALID_VTABLE_SIZE: &dyn Trait = unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; //~^ ERROR evaluation of constant value failed -//~| does not point to a vtable +//~| invalid vtable: size is bigger than largest supported object #[repr(transparent)] struct W(T); +// The drop fn is checked before size/align are, so get ourselves a "sufficiently valid" drop fn fn drop_me(_: *mut usize) {} const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) }; //~^^ ERROR it is undefined behavior to use this value -//~| expected a vtable pointer +//~| invalid vtable: alignment `1000` is not a power of 2 const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) }; //~^^ ERROR it is undefined behavior to use this value -//~| expected a vtable pointer - -// Even if the vtable has a fn ptr and a reasonable size+align, it still does not work. -const INVALID_VTABLE_UB: W<&dyn Trait> = - unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1usize))) }; -//~^^ ERROR it is undefined behavior to use this value -//~| expected a vtable pointer - -// Trying to access the data in a vtable does not work, either. - -#[derive(Copy, Clone)] -struct Wide<'a>(&'a Foo, &'static VTable); - -struct VTable { - drop: Option fn(&'a mut Foo)>, - size: usize, - align: usize, - bar: for<'a> fn(&'a Foo) -> u32, -} - -trait Bar { - fn bar(&self) -> u32; -} - -struct Foo { - foo: u32, - bar: bool, -} - -impl Bar for Foo { - fn bar(&self) -> u32 { - self.foo - } -} - -impl Drop for Foo { - fn drop(&mut self) { - assert!(!self.bar); - self.bar = true; - println!("dropping Foo"); - } -} - -#[repr(C)] -union Transmute { - t: T, - u: U, -} - -const FOO: &dyn Bar = &Foo { foo: 128, bar: false }; -const G: Wide = unsafe { Transmute { t: FOO }.u }; -//~^ ERROR it is undefined behavior to use this value -//~| encountered a dangling reference -// (it is dangling because vtables do not contain memory that can be dereferenced) +//~| invalid vtable: size is bigger than largest supported object fn main() {} diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr index ae114233c0f72..2cae35bc4d0ed 100644 --- a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr @@ -125,7 +125,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:56:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null function pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -147,7 +147,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:60:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x0000000d, but expected a function pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -158,7 +158,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:62:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered pointer to alloc41, but expected a function pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr index 1b93a869c0dd9..e2cd0e64db806 100644 --- a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr @@ -125,7 +125,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:56:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null function pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -147,7 +147,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:60:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x000000000000000d, but expected a function pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -158,7 +158,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:62:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered pointer to alloc41, but expected a function pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { diff --git a/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr b/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr index f7898e55ee2c5..43f73f6ec7f27 100644 --- a/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr @@ -6,7 +6,7 @@ LL | const BAD_UPVAR: &dyn FnOnce() = &{ | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾─alloc3──╼ ╾─alloc4──╼ │ ╾──╼╾──╼ + ╾─alloc3──╼ ╾─alloc6──╼ │ ╾──╼╾──╼ } error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr b/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr index 60432380e1347..64185a0636297 100644 --- a/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr @@ -6,7 +6,7 @@ LL | const BAD_UPVAR: &dyn FnOnce() = &{ | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────alloc3────────╼ ╾───────alloc4────────╼ │ ╾──────╼╾──────╼ + ╾───────alloc3────────╼ ╾───────alloc6────────╼ │ ╾──────╼╾──────╼ } error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr index 345ead48151df..2fd98ea322b02 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr @@ -209,7 +209,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:117:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -217,10 +217,10 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:121:1 + --> $DIR/ub-wide-ptr.rs:120:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -228,39 +228,54 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:125:1 + --> $DIR/ub-wide-ptr.rs:123:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered dangling vtable pointer in wide pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾allocN─╼ 04 00 00 00 │ ╾──╼.... } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:128:57 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:125:1 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered unaligned vtable pointer in wide pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼ + } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:131:57 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:127:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼ + } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:134:56 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:129:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼ + } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:137:1 + --> $DIR/ub-wide-ptr.rs:131:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid drop function pointer in vtable (not pointing to a function) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -268,7 +283,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:142:1 + --> $DIR/ub-wide-ptr.rs:135:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..: encountered 0x03, but expected a boolean @@ -278,29 +293,39 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼ } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:147:62 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:139:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered dangling vtable pointer in wide pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾allocN─╼ 00 00 00 00 │ ╾──╼.... + } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:150:65 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:141:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered too small vtable + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼ + } error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:157:5 + --> $DIR/ub-wide-ptr.rs:147:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:161:5 + --> $DIR/ub-wide-ptr.rs:151:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: allocN has size N, so pointer to 12 bytes starting at offset N is out-of-bounds error: aborting due to 32 previous errors diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr index 501932cb95c63..bae249076598e 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr @@ -209,7 +209,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:117:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -217,10 +217,10 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:121:1 + --> $DIR/ub-wide-ptr.rs:120:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -228,39 +228,54 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:125:1 + --> $DIR/ub-wide-ptr.rs:123:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered dangling vtable pointer in wide pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾──────allocN───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:128:57 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:125:1 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered unaligned vtable pointer in wide pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼ + } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:131:57 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:127:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼ + } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:134:56 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:129:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼ + } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:137:1 + --> $DIR/ub-wide-ptr.rs:131:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid drop function pointer in vtable (not pointing to a function) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -268,7 +283,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:142:1 + --> $DIR/ub-wide-ptr.rs:135:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..: encountered 0x03, but expected a boolean @@ -278,29 +293,39 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼ } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:147:62 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:139:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered dangling vtable pointer in wide pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾──────allocN───────╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........ + } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:150:65 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:141:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered too small vtable + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼ + } error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:157:5 + --> $DIR/ub-wide-ptr.rs:147:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:161:5 + --> $DIR/ub-wide-ptr.rs:151:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: allocN has size N, so pointer to 24 bytes starting at offset N is out-of-bounds error: aborting due to 32 previous errors diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.rs b/src/test/ui/consts/const-eval/ub-wide-ptr.rs index a0377ab1efd23..f2e5738f88c9f 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.rs +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.rs @@ -116,40 +116,30 @@ const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { // bad trait object const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; //~^ ERROR it is undefined behavior to use this value -//~| expected a vtable // bad trait object const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; //~^ ERROR it is undefined behavior to use this value -//~| expected a vtable // bad trait object const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; //~^ ERROR it is undefined behavior to use this value -//~| expected a vtable const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; -//~^ ERROR evaluation of constant value failed -//~| does not point to a vtable +//~^ ERROR it is undefined behavior to use this value const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; -//~^ ERROR evaluation of constant value failed -//~| does not point to a vtable +//~^ ERROR it is undefined behavior to use this value const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; -//~^ ERROR evaluation of constant value failed -//~| does not point to a vtable +//~^ ERROR it is undefined behavior to use this value const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; //~^ ERROR it is undefined behavior to use this value -//~| expected a vtable // bad data *inside* the trait object const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; //~^ ERROR it is undefined behavior to use this value -//~| expected a boolean // # raw trait object const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; -//~^ ERROR evaluation of constant value failed -//~| null pointer +//~^ ERROR it is undefined behavior to use this value const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; -//~^ ERROR evaluation of constant value failed -//~| does not point to a vtable +//~^ ERROR it is undefined behavior to use this value const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) } as *const dyn Trait; // ok because raw // Const eval fails for these, so they need to be statics to error. diff --git a/src/test/ui/consts/issue-25826.rs b/src/test/ui/consts/issue-25826.rs index c340c30a113b5..d1093c205798a 100644 --- a/src/test/ui/consts/issue-25826.rs +++ b/src/test/ui/consts/issue-25826.rs @@ -1,6 +1,6 @@ fn id(t: T) -> T { t } fn main() { const A: bool = unsafe { id:: as *const () < id:: as *const () }; - //~^ ERROR can't compare + //~^ ERROR pointers cannot be reliably compared during const eval println!("{}", A); } diff --git a/src/test/ui/consts/issue-25826.stderr b/src/test/ui/consts/issue-25826.stderr index b80befa26f6e0..780edd2149fe1 100644 --- a/src/test/ui/consts/issue-25826.stderr +++ b/src/test/ui/consts/issue-25826.stderr @@ -1,20 +1,10 @@ -error[E0277]: can't compare `*const ()` with `*const ()` in const contexts - --> $DIR/issue-25826.rs:3:52 +error: pointers cannot be reliably compared during const eval + --> $DIR/issue-25826.rs:3:30 | LL | const A: bool = unsafe { id:: as *const () < id:: as *const () }; - | ^ no implementation for `*const () < *const ()` and `*const () > *const ()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: the trait `~const PartialOrd` is not implemented for `*const ()` -note: the trait `PartialOrd` is implemented for `*const ()`, but that implementation is not `const` - --> $DIR/issue-25826.rs:3:52 - | -LL | const A: bool = unsafe { id:: as *const () < id:: as *const () }; - | ^ -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement - | -LL | fn main() where *const (): ~const PartialOrd { - | ++++++++++++++++++++++++++++++++++ + = note: see issue #53020 for more information error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/consts/issue-79690.64bit.stderr b/src/test/ui/consts/issue-79690.64bit.stderr index b8798a9755fe2..c7aba55537088 100644 --- a/src/test/ui/consts/issue-79690.64bit.stderr +++ b/src/test/ui/consts/issue-79690.64bit.stderr @@ -2,11 +2,11 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-79690.rs:30:1 | LL | const G: Fat = unsafe { Transmute { t: FOO }.u }; - | ^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^ constructing invalid value at .1..size.foo: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────alloc3────────╼ ╾───────alloc4────────╼ │ ╾──────╼╾──────╼ + ╾───────alloc3────────╼ ╾───────alloc6────────╼ │ ╾──────╼╾──────╼ } error: aborting due to previous error diff --git a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs index 9a2775688c6fa..e07b269c386ea 100644 --- a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs +++ b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs @@ -1,6 +1,6 @@ const fn cmp(x: fn(), y: fn()) -> bool { unsafe { x == y } - //~^ ERROR can't compare + //~^ ERROR pointers cannot be reliably compared } fn main() {} diff --git a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr index 8a1b20a334567..3845068d8411c 100644 --- a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr +++ b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr @@ -1,16 +1,10 @@ -error[E0277]: can't compare `fn()` with `_` in const contexts - --> $DIR/cmp_fn_pointers.rs:2:16 +error: pointers cannot be reliably compared during const eval + --> $DIR/cmp_fn_pointers.rs:2:14 | LL | unsafe { x == y } - | ^^ no implementation for `fn() == _` + | ^^^^^^ | - = help: the trait `~const PartialEq<_>` is not implemented for `fn()` -note: the trait `PartialEq<_>` is implemented for `fn()`, but that implementation is not `const` - --> $DIR/cmp_fn_pointers.rs:2:16 - | -LL | unsafe { x == y } - | ^^ + = note: see issue #53020 for more information error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr index 7ea35f70d108e..bb8636f1225ad 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr @@ -17,7 +17,7 @@ LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾─alloc7──╼ ╾─alloc8──╼ │ ╾──╼╾──╼ + ╾─alloc7──╼ ╾─alloc9──╼ │ ╾──╼╾──╼ } error[E0080]: it is undefined behavior to use this value @@ -28,7 +28,7 @@ LL | const BLUNT: &mut i32 = &mut 42; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - ╾─alloc10─╼ │ ╾──╼ + ╾─alloc11─╼ │ ╾──╼ } warning: skipping const checks diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr index 5ad3989308909..f1652da922a57 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr @@ -17,7 +17,7 @@ LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────alloc7────────╼ ╾───────alloc8────────╼ │ ╾──────╼╾──────╼ + ╾───────alloc7────────╼ ╾───────alloc9────────╼ │ ╾──────╼╾──────╼ } error[E0080]: it is undefined behavior to use this value @@ -28,7 +28,7 @@ LL | const BLUNT: &mut i32 = &mut 42; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────alloc10───────╼ │ ╾──────╼ + ╾───────alloc11───────╼ │ ╾──────╼ } warning: skipping const checks diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.rs b/src/test/ui/consts/miri_unleashed/ptr_arith.rs index 13e6af36e0200..2beb531cc6890 100644 --- a/src/test/ui/consts/miri_unleashed/ptr_arith.rs +++ b/src/test/ui/consts/miri_unleashed/ptr_arith.rs @@ -2,8 +2,14 @@ #![feature(core_intrinsics)] #![allow(const_err)] -// During CTFE, we prevent pointer-to-int casts. -// Pointer comparisons are prevented in the trait system. +// During CTFE, we prevent pointer comparison and pointer-to-int casts. + +static CMP: () = { + let x = &0 as *const _; + let _v = x == x; + //~^ ERROR could not evaluate static initializer + //~| "pointer arithmetic or comparison" needs an rfc before being allowed inside constants +}; static PTR_INT_CAST: () = { let x = &0 as *const _ as usize; diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr index 00cff23fb3fbe..47142752f0ee0 100644 --- a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr +++ b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr @@ -1,11 +1,17 @@ error[E0080]: could not evaluate static initializer - --> $DIR/ptr_arith.rs:9:13 + --> $DIR/ptr_arith.rs:9:14 + | +LL | let _v = x == x; + | ^^^^^^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants + +error[E0080]: could not evaluate static initializer + --> $DIR/ptr_arith.rs:15:13 | LL | let x = &0 as *const _ as usize; | ^^^^^^^^^^^^^^^^^^^^^^^ "exposing pointers" needs an rfc before being allowed inside constants error[E0080]: could not evaluate static initializer - --> $DIR/ptr_arith.rs:17:14 + --> $DIR/ptr_arith.rs:23:14 | LL | let _v = x + 0; | ^ unable to turn pointer into raw bytes @@ -13,11 +19,16 @@ LL | let _v = x + 0; warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/ptr_arith.rs:9:13 + --> $DIR/ptr_arith.rs:9:14 + | +LL | let _v = x == x; + | ^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/ptr_arith.rs:15:13 | LL | let x = &0 as *const _ as usize; | ^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 3 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/offset_from_ub.rs b/src/test/ui/consts/offset_from_ub.rs index 1f29a690550bc..db2d421427c3e 100644 --- a/src/test/ui/consts/offset_from_ub.rs +++ b/src/test/ui/consts/offset_from_ub.rs @@ -2,7 +2,6 @@ #![feature(core_intrinsics)] use std::intrinsics::{ptr_offset_from, ptr_offset_from_unsigned}; -use std::ptr; #[repr(C)] struct Struct { @@ -76,21 +75,9 @@ pub const DIFFERENT_ALLOC_UNSIGNED: usize = { let base_ptr: *const Struct = &uninit as *const _ as *const Struct; let uninit2 = std::mem::MaybeUninit::::uninit(); let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct; - unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } //~ERROR evaluation of constant value failed + let offset = unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) }; //~ERROR evaluation of constant value failed //~| pointers into different allocations -}; - -pub const TOO_FAR_APART1: isize = { - let ptr1 = ptr::null::(); - let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42); - unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed - //~| too far ahead -}; -pub const TOO_FAR_APART2: isize = { - let ptr1 = ptr::null::(); - let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42); - unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed - //~| too far before + offset as usize }; const WRONG_ORDER_UNSIGNED: usize = { @@ -99,27 +86,5 @@ const WRONG_ORDER_UNSIGNED: usize = { unsafe { ptr_offset_from_unsigned(p, p.add(2) ) } //~ERROR evaluation of constant value failed //~| first pointer has smaller offset than second: 0 < 8 }; -pub const TOO_FAR_APART_UNSIGNED: usize = { - let ptr1 = ptr::null::(); - let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42); - // This would fit into a `usize` but we still don't allow it. - unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } //~ERROR evaluation of constant value failed - //~| too far ahead -}; - -// These do NOT complain that pointers are too far apart; they pass that check (to then fail the -// next one). -pub const OFFSET_VERY_FAR1: isize = { - let ptr1 = ptr::null::(); - let ptr2 = ptr1.wrapping_offset(isize::MAX); - unsafe { ptr2.offset_from(ptr1) } - //~^ inside -}; -pub const OFFSET_VERY_FAR2: isize = { - let ptr1 = ptr::null::(); - let ptr2 = ptr1.wrapping_offset(isize::MAX); - unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) } - //~^ inside -}; fn main() {} diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr index 62a087d94d356..94d778bc8a150 100644 --- a/src/test/ui/consts/offset_from_ub.stderr +++ b/src/test/ui/consts/offset_from_ub.stderr @@ -1,8 +1,8 @@ error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:18:27 + --> $DIR/offset_from_ub.rs:17:27 | LL | let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on pointers into different allocations + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ptr_offset_from called on pointers into different allocations error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -10,108 +10,62 @@ error[E0080]: evaluation of constant value failed LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | `ptr_offset_from` called on pointers into different allocations + | ptr_offset_from called on pointers into different allocations | inside `ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - ::: $DIR/offset_from_ub.rs:24:14 + ::: $DIR/offset_from_ub.rs:23:14 | LL | unsafe { (42 as *const u8).offset_from(&5u8) as usize } - | ----------------------------------- inside `NOT_PTR` at $DIR/offset_from_ub.rs:24:14 + | ----------------------------------- inside `NOT_PTR` at $DIR/offset_from_ub.rs:23:14 error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:31:14 + --> $DIR/offset_from_ub.rs:30:14 | LL | unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 1_isize cannot be divided by 2_isize without remainder error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:37:14 + --> $DIR/offset_from_ub.rs:36:14 | LL | unsafe { ptr_offset_from(ptr, ptr) } | ^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:44:14 + --> $DIR/offset_from_ub.rs:43:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: 0x8[noalloc] is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:53:14 + --> $DIR/offset_from_ub.rs:52:14 | LL | unsafe { ptr_offset_from(end_ptr, start_ptr) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc18 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:62:14 + --> $DIR/offset_from_ub.rs:61:14 | LL | unsafe { ptr_offset_from(start_ptr, end_ptr) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc21 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:70:14 + --> $DIR/offset_from_ub.rs:69:14 | LL | unsafe { ptr_offset_from(end_ptr, end_ptr) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc24 has size 4, so pointer at offset 10 is out-of-bounds error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:79:14 + --> $DIR/offset_from_ub.rs:78:27 | -LL | unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations +LL | let offset = unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ptr_offset_from_unsigned called on pointers into different allocations error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:86:14 | -LL | unsafe { ptr_offset_from(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far ahead of second - -error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:92:14 - | -LL | unsafe { ptr_offset_from(ptr1, ptr2) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second - -error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:99:14 - | LL | unsafe { ptr_offset_from_unsigned(p, p.add(2) ) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8 - -error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:106:14 - | -LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer is too far ahead of second - -error[E0080]: evaluation of constant value failed - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - | -LL | unsafe { intrinsics::ptr_offset_from(self, origin) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance) - | inside `ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - | - ::: $DIR/offset_from_ub.rs:115:14 - | -LL | unsafe { ptr2.offset_from(ptr1) } - | ---------------------- inside `OFFSET_VERY_FAR1` at $DIR/offset_from_ub.rs:115:14 - -error[E0080]: evaluation of constant value failed - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - | -LL | unsafe { intrinsics::ptr_offset_from(self, origin) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance) - | inside `ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - | - ::: $DIR/offset_from_ub.rs:121:14 - | -LL | unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) } - | ----------------------------------------- inside `OFFSET_VERY_FAR2` at $DIR/offset_from_ub.rs:121:14 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 8 -error: aborting due to 15 previous errors +error: aborting due to 10 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/refs_check_const_eq-issue-88384.rs b/src/test/ui/consts/refs_check_const_eq-issue-88384.rs index 1496b28bd3ee6..204d18ea25de4 100644 --- a/src/test/ui/consts/refs_check_const_eq-issue-88384.rs +++ b/src/test/ui/consts/refs_check_const_eq-issue-88384.rs @@ -1,3 +1,5 @@ +// check-pass + #![feature(fn_traits)] #![feature(adt_const_params)] //~^ WARNING the feature `adt_const_params` is incomplete @@ -8,10 +10,8 @@ struct CompileTimeSettings{ } struct Foo; -//~^ ERROR using function pointers as const generic parameters is forbidden impl Foo { - //~^ ERROR using function pointers as const generic parameters is forbidden fn call_hooks(){ } } diff --git a/src/test/ui/consts/refs_check_const_eq-issue-88384.stderr b/src/test/ui/consts/refs_check_const_eq-issue-88384.stderr index 4f2f5e244b67e..f2bad2f552759 100644 --- a/src/test/ui/consts/refs_check_const_eq-issue-88384.stderr +++ b/src/test/ui/consts/refs_check_const_eq-issue-88384.stderr @@ -1,5 +1,5 @@ warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/refs_check_const_eq-issue-88384.rs:2:12 + --> $DIR/refs_check_const_eq-issue-88384.rs:4:12 | LL | #![feature(adt_const_params)] | ^^^^^^^^^^^^^^^^ @@ -7,18 +7,5 @@ LL | #![feature(adt_const_params)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #95174 for more information -error[E0741]: using function pointers as const generic parameters is forbidden - --> $DIR/refs_check_const_eq-issue-88384.rs:10:21 - | -LL | struct Foo; - | ^^^^^^^^^^^^^^^^^^^ - -error[E0741]: using function pointers as const generic parameters is forbidden - --> $DIR/refs_check_const_eq-issue-88384.rs:13:15 - | -LL | impl Foo { - | ^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors; 1 warning emitted +warning: 1 warning emitted -For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/derives/deriving-with-repr-packed.rs b/src/test/ui/derives/deriving-with-repr-packed.rs index 3884e397764e7..b78eeaa90551b 100644 --- a/src/test/ui/derives/deriving-with-repr-packed.rs +++ b/src/test/ui/derives/deriving-with-repr-packed.rs @@ -1,43 +1,29 @@ #![deny(unaligned_references)] -// Check that deriving certain builtin traits on certain packed structs cause -// errors. This happens when the derived trait would need to use a potentially -// misaligned reference. But there are two cases that are allowed: -// - If all the fields within the struct meet the required alignment: 1 for -// `repr(packed)`, or `N` for `repr(packed(N))`. -// - If `Default` is the only trait derived, because it doesn't involve any -// references. +// check that derive on a packed struct with non-Copy fields +// correctly. This can't be made to work perfectly because +// we can't just use the field from the struct as it might +// not be aligned. -#[derive(Copy, Clone, Default, PartialEq, Eq)] -//~^ ERROR `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters +#[derive(Copy, Clone, PartialEq, Eq)] +//~^ ERROR `#[derive]` can't be used //~| hard error -//~^^^ ERROR `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters +//~^^^ ERROR `#[derive]` can't be used //~| hard error #[repr(packed)] pub struct Foo(T, T, T); -#[derive(Default, Hash)] -//~^ ERROR `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` +#[derive(PartialEq, Eq)] +//~^ ERROR `#[derive]` can't be used //~| hard error #[repr(packed)] pub struct Bar(u32, u32, u32); -// This one is fine because the field alignment is 1. -#[derive(Default, Hash)] -#[repr(packed)] -pub struct Bar2(u8, i8, bool); - -// This one is fine because the field alignment is 2, matching `packed(2)`. -#[derive(Default, Hash)] -#[repr(packed(2))] -pub struct Bar3(u16, i16, bool); - -// This one is fine because it's not packed. -#[derive(Debug, Default)] +#[derive(PartialEq)] struct Y(usize); -#[derive(Debug, Default)] -//~^ ERROR `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` +#[derive(PartialEq)] +//~^ ERROR `#[derive]` can't be used //~| hard error #[repr(packed)] struct X(Y); diff --git a/src/test/ui/derives/deriving-with-repr-packed.stderr b/src/test/ui/derives/deriving-with-repr-packed.stderr index d3fe550c3e48f..1002b359f60ba 100644 --- a/src/test/ui/derives/deriving-with-repr-packed.stderr +++ b/src/test/ui/derives/deriving-with-repr-packed.stderr @@ -1,7 +1,7 @@ -error: `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters - --> $DIR/deriving-with-repr-packed.rs:11:16 +error: `#[derive]` can't be used on a `#[repr(packed)]` struct with type or const parameters (error E0133) + --> $DIR/deriving-with-repr-packed.rs:8:16 | -LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] +LL | #[derive(Copy, Clone, PartialEq, Eq)] | ^^^^^ | note: the lint level is defined here @@ -13,43 +13,43 @@ LL | #![deny(unaligned_references)] = note: for more information, see issue #82523 = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters - --> $DIR/deriving-with-repr-packed.rs:11:32 +error: `#[derive]` can't be used on a `#[repr(packed)]` struct with type or const parameters (error E0133) + --> $DIR/deriving-with-repr-packed.rs:8:23 | -LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] - | ^^^^^^^^^ +LL | #[derive(Copy, Clone, PartialEq, Eq)] + | ^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82523 = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` - --> $DIR/deriving-with-repr-packed.rs:19:19 +error: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133) + --> $DIR/deriving-with-repr-packed.rs:16:10 | -LL | #[derive(Default, Hash)] - | ^^^^ +LL | #[derive(PartialEq, Eq)] + | ^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82523 - = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` - --> $DIR/deriving-with-repr-packed.rs:39:10 +error: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133) + --> $DIR/deriving-with-repr-packed.rs:25:10 | -LL | #[derive(Debug, Default)] - | ^^^^^ +LL | #[derive(PartialEq)] + | ^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82523 - = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors Future incompatibility report: Future breakage diagnostic: -error: `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters - --> $DIR/deriving-with-repr-packed.rs:11:16 +error: `#[derive]` can't be used on a `#[repr(packed)]` struct with type or const parameters (error E0133) + --> $DIR/deriving-with-repr-packed.rs:8:16 | -LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] +LL | #[derive(Copy, Clone, PartialEq, Eq)] | ^^^^^ | note: the lint level is defined here @@ -62,11 +62,11 @@ LL | #![deny(unaligned_references)] = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: -error: `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters - --> $DIR/deriving-with-repr-packed.rs:11:32 +error: `#[derive]` can't be used on a `#[repr(packed)]` struct with type or const parameters (error E0133) + --> $DIR/deriving-with-repr-packed.rs:8:23 | -LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] - | ^^^^^^^^^ +LL | #[derive(Copy, Clone, PartialEq, Eq)] + | ^^^^^^^^^ | note: the lint level is defined here --> $DIR/deriving-with-repr-packed.rs:1:9 @@ -78,11 +78,11 @@ LL | #![deny(unaligned_references)] = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: -error: `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` - --> $DIR/deriving-with-repr-packed.rs:19:19 +error: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133) + --> $DIR/deriving-with-repr-packed.rs:16:10 | -LL | #[derive(Default, Hash)] - | ^^^^ +LL | #[derive(PartialEq, Eq)] + | ^^^^^^^^^ | note: the lint level is defined here --> $DIR/deriving-with-repr-packed.rs:1:9 @@ -91,14 +91,14 @@ LL | #![deny(unaligned_references)] | ^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82523 - = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: -error: `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` - --> $DIR/deriving-with-repr-packed.rs:39:10 +error: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133) + --> $DIR/deriving-with-repr-packed.rs:25:10 | -LL | #[derive(Debug, Default)] - | ^^^^^ +LL | #[derive(PartialEq)] + | ^^^^^^^^^ | note: the lint level is defined here --> $DIR/deriving-with-repr-packed.rs:1:9 @@ -107,5 +107,5 @@ LL | #![deny(unaligned_references)] | ^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82523 - = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/dropck/reject-specialized-drops-8142.stderr b/src/test/ui/dropck/reject-specialized-drops-8142.stderr index cb48221c67a82..ebd484b880001 100644 --- a/src/test/ui/dropck/reject-specialized-drops-8142.stderr +++ b/src/test/ui/dropck/reject-specialized-drops-8142.stderr @@ -104,7 +104,7 @@ error[E0366]: `Drop` impls cannot be specialized LL | impl Drop for X<3> { fn drop(&mut self) { } } // REJECT | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `3` is not a generic parameter + = note: `3_usize` is not a generic parameter note: use the same sequence of generic lifetime, type and const parameters as the struct definition --> $DIR/reject-specialized-drops-8142.rs:17:1 | diff --git a/src/test/ui/error-codes/E0106.stderr b/src/test/ui/error-codes/E0106.stderr index d11a24f776855..fbd77d9670091 100644 --- a/src/test/ui/error-codes/E0106.stderr +++ b/src/test/ui/error-codes/E0106.stderr @@ -23,17 +23,6 @@ LL | A(u8), LL ~ B(&'a bool), | -error[E0106]: missing lifetime specifier - --> $DIR/E0106.rs:10:14 - | -LL | type MyStr = &str; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type MyStr<'a> = &'a str; - | ++++ ++ - error[E0106]: missing lifetime specifier --> $DIR/E0106.rs:17:10 | @@ -61,6 +50,17 @@ LL | LL ~ buzz: Buzz<'a, 'a>, | +error[E0106]: missing lifetime specifier + --> $DIR/E0106.rs:10:14 + | +LL | type MyStr = &str; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type MyStr<'a> = &'a str; + | ++++ ++ + error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/error-codes/E0395.rs b/src/test/ui/error-codes/E0395.rs new file mode 100644 index 0000000000000..d2edd97efb232 --- /dev/null +++ b/src/test/ui/error-codes/E0395.rs @@ -0,0 +1,8 @@ +static FOO: i32 = 42; +static BAR: i32 = 42; + +static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; +//~^ ERROR pointers cannot be reliably compared during const eval + +fn main() { +} diff --git a/src/test/ui/error-codes/E0395.stderr b/src/test/ui/error-codes/E0395.stderr new file mode 100644 index 0000000000000..ea17e95a719af --- /dev/null +++ b/src/test/ui/error-codes/E0395.stderr @@ -0,0 +1,10 @@ +error: pointers cannot be reliably compared during const eval + --> $DIR/E0395.rs:4:29 + | +LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #53020 for more information + +error: aborting due to previous error + diff --git a/src/test/ui/error-codes/E0637.stderr b/src/test/ui/error-codes/E0637.stderr index 35a4b34fb0a4d..87aaba65a73ad 100644 --- a/src/test/ui/error-codes/E0637.stderr +++ b/src/test/ui/error-codes/E0637.stderr @@ -4,6 +4,12 @@ error[E0637]: `'_` cannot be used here LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str { | ^^ `'_` is a reserved lifetime name +error[E0637]: `&` without an explicit lifetime name cannot be used here + --> $DIR/E0637.rs:13:13 + | +LL | T: Into<&u32>, + | ^ explicit lifetime name needed here + error[E0106]: missing lifetime specifier --> $DIR/E0637.rs:1:62 | @@ -16,12 +22,6 @@ help: consider introducing a named lifetime parameter LL | fn underscore_lifetime<'a, '_>(str1: &'a str, str2: &'a str) -> &'a str { | +++ ~~ ~~ ~~ -error[E0637]: `&` without an explicit lifetime name cannot be used here - --> $DIR/E0637.rs:13:13 - | -LL | T: Into<&u32>, - | ^ explicit lifetime name needed here - error: aborting due to 3 previous errors Some errors have detailed explanations: E0106, E0637. diff --git a/src/test/ui/extern-flag/empty-extern-arg.stderr b/src/test/ui/extern-flag/empty-extern-arg.stderr index 54b5e66fc2100..39a66c08de098 100644 --- a/src/test/ui/extern-flag/empty-extern-arg.stderr +++ b/src/test/ui/extern-flag/empty-extern-arg.stderr @@ -1,11 +1,11 @@ error: extern location for std does not exist: -error: `#[panic_handler]` function required, but not found - error: language item required, but not found: `eh_personality` | = note: this can occur when a binary crate with `#![no_std]` is compiled for a target where `eh_personality` is defined in the standard library = help: you may be able to compile for a target that doesn't need `eh_personality`, specify a target with `--target` or in `.cargo/config` +error: `#[panic_handler]` function required, but not found + error: aborting due to 3 previous errors diff --git a/src/test/ui/fmt/ifmt-bad-arg.rs b/src/test/ui/fmt/ifmt-bad-arg.rs index 84f4cc7f4ccd8..b3e54ed32aac7 100644 --- a/src/test/ui/fmt/ifmt-bad-arg.rs +++ b/src/test/ui/fmt/ifmt-bad-arg.rs @@ -86,9 +86,6 @@ tenth number: {}", println!("{:foo}", 1); //~ ERROR unknown format trait `foo` println!("{5} {:4$} {6:7$}", 1); //~^ ERROR invalid reference to positional arguments 4, 5, 6 and 7 (there is 1 argument) - let foo = 1; - println!("{foo:0$}"); - //~^ ERROR invalid reference to positional argument 0 (no arguments were given) // We used to ICE here because we tried to unconditionally access the first argument, which // doesn't exist. diff --git a/src/test/ui/fmt/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr index 5439ee173985b..d181fe14107e7 100644 --- a/src/test/ui/fmt/ifmt-bad-arg.stderr +++ b/src/test/ui/fmt/ifmt-bad-arg.stderr @@ -251,19 +251,8 @@ LL | println!("{5} {:4$} {6:7$}", 1); = note: positional arguments are zero-based = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html -error: invalid reference to positional argument 0 (no arguments were given) - --> $DIR/ifmt-bad-arg.rs:90:15 - | -LL | println!("{foo:0$}"); - | ^^^^^--^ - | | - | this width flag expects an `usize` argument at position 0, but no arguments were given - | - = note: positional arguments are zero-based - = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html - error: 2 positional arguments in format string, but no arguments were given - --> $DIR/ifmt-bad-arg.rs:95:15 + --> $DIR/ifmt-bad-arg.rs:92:15 | LL | println!("{:.*}"); | ^^--^ @@ -339,7 +328,7 @@ LL | pub fn from_usize(x: &usize) -> ArgumentV1<'_> { | ^^^^^^^^^^ = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 37 previous errors +error: aborting due to 36 previous errors Some errors have detailed explanations: E0308, E0425. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/foreign-fn-return-lifetime.stderr b/src/test/ui/foreign-fn-return-lifetime.stderr index df1a23a19edd5..b174766cd3d0c 100644 --- a/src/test/ui/foreign-fn-return-lifetime.stderr +++ b/src/test/ui/foreign-fn-return-lifetime.stderr @@ -8,7 +8,7 @@ LL | pub fn f() -> &u8; help: consider using the `'static` lifetime | LL | pub fn f() -> &'static u8; - | +++++++ + | ~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/generator/issue-52304.rs b/src/test/ui/generator/issue-52304.rs deleted file mode 100644 index 3e9de765b12b2..0000000000000 --- a/src/test/ui/generator/issue-52304.rs +++ /dev/null @@ -1,11 +0,0 @@ -// check-pass - -#![feature(generators, generator_trait)] - -use std::ops::Generator; - -pub fn example() -> impl Generator { - || yield &1 -} - -fn main() {} diff --git a/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs b/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs index dbf7e02aeafcc..246659a268ac9 100644 --- a/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs +++ b/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs @@ -7,10 +7,9 @@ trait Foo { } impl Foo for T { - //~^ ERROR: the type parameter `T1` is not constrained type F = &[u8]; //~^ ERROR: the name `T1` is already used for - //~| ERROR: `&` without an explicit lifetime name cannot be used here + //~| ERROR: missing lifetime specifier } fn main() {} diff --git a/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr b/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr index dad0dae6a44bf..e82cbf7e8e5ef 100644 --- a/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr +++ b/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr @@ -1,25 +1,23 @@ error[E0403]: the name `T1` is already used for a generic parameter in this item's generic parameters - --> $DIR/gat-trait-path-generic-type-arg.rs:11:12 + --> $DIR/gat-trait-path-generic-type-arg.rs:10:12 | LL | impl Foo for T { | -- first use of `T1` -LL | LL | type F = &[u8]; | ^^ already used -error[E0637]: `&` without an explicit lifetime name cannot be used here - --> $DIR/gat-trait-path-generic-type-arg.rs:11:18 +error[E0106]: missing lifetime specifier + --> $DIR/gat-trait-path-generic-type-arg.rs:10:18 | LL | type F = &[u8]; - | ^ explicit lifetime name needed here - -error[E0207]: the type parameter `T1` is not constrained by the impl trait, self type, or predicates - --> $DIR/gat-trait-path-generic-type-arg.rs:9:10 + | ^ expected named lifetime parameter | -LL | impl Foo for T { - | ^^ unconstrained type parameter +help: consider introducing a named lifetime parameter + | +LL | type F<'a, T1> = &'a [u8]; + | +++ ++ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0207, E0403, E0637. -For more information about an error, try `rustc --explain E0207`. +Some errors have detailed explanations: E0106, E0403. +For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr index e866b3bab7972..c7ebb9880f710 100644 --- a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr +++ b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr @@ -11,13 +11,13 @@ LL | type Assoc2 = Vec; | +++++++++++++++++++ error[E0276]: impl has stricter requirements than trait - --> $DIR/generic-associated-types-where.rs:22:38 + --> $DIR/generic-associated-types-where.rs:22:5 | LL | type Assoc3; | -------------- definition of `Assoc3` from trait ... LL | type Assoc3 = Vec where T: Iterator; - | ^^^^^^^^ impl has extra requirement `T: Iterator` + | ^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator` error: aborting due to 2 previous errors diff --git a/src/test/ui/generic-associated-types/impl_bounds.rs b/src/test/ui/generic-associated-types/impl_bounds.rs index ec1d171c04470..bb5992c88f08f 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.rs +++ b/src/test/ui/generic-associated-types/impl_bounds.rs @@ -13,9 +13,9 @@ struct Fooy(T); impl Foo for Fooy { type A<'a> = (&'a ()) where Self: 'static; - //~^ ERROR impl has stricter requirements than trait + //~^ ERROR `impl` associated type type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a; - //~^ ERROR impl has stricter requirements than trait + //~^ ERROR `impl` associated type //~| ERROR lifetime bound not satisfied type C = String where Self: Copy; //~^ ERROR the trait bound `T: Copy` is not satisfied diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr index ce79c635add69..6aa52b179a3c6 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.stderr +++ b/src/test/ui/generic-associated-types/impl_bounds.stderr @@ -1,20 +1,20 @@ -error[E0276]: impl has stricter requirements than trait - --> $DIR/impl_bounds.rs:15:39 +error: `impl` associated type signature for `A` doesn't match `trait` associated type signature + --> $DIR/impl_bounds.rs:15:5 | LL | type A<'a> where Self: 'a; - | ---------- definition of `A` from trait + | ---------- expected ... LL | type A<'a> = (&'a ()) where Self: 'static; - | ^^^^^^^ impl has extra requirement `T: 'static` + | ^^^^^^^^^^ found -error[E0276]: impl has stricter requirements than trait - --> $DIR/impl_bounds.rs:17:48 +error: `impl` associated type signature for `B` doesn't match `trait` associated type signature + --> $DIR/impl_bounds.rs:17:5 | LL | type B<'a, 'b> where 'a: 'b; - | -------------- definition of `B` from trait + | -------------- expected ... LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a; - | ^^ impl has extra requirement `'b: 'a` + | ^^^^^^^^^^^^^^ found error[E0478]: lifetime bound not satisfied --> $DIR/impl_bounds.rs:17:22 @@ -37,24 +37,24 @@ LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a; | ^^ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/impl_bounds.rs:20:33 + --> $DIR/impl_bounds.rs:20:5 | LL | type C = String where Self: Copy; - | ^^^^ the trait `Copy` is not implemented for `T` + | ^^^^^^ the trait `Copy` is not implemented for `T` | note: required because of the requirements on the impl of `Copy` for `Fooy` --> $DIR/impl_bounds.rs:11:10 | LL | #[derive(Copy, Clone)] | ^^^^ -note: the requirement `Fooy: Copy` appears on the `impl`'s associated type `C` but not on the corresponding trait's associated type - --> $DIR/impl_bounds.rs:7:10 +note: the requirement `Fooy: Copy` appears on the associated impl type `C` but not on the corresponding associated trait type + --> $DIR/impl_bounds.rs:7:5 | LL | trait Foo { | --- in this trait ... LL | type C where Self: Clone; - | ^ this trait's associated type doesn't have the requirement `Fooy: Copy` + | ^^^^^^ this trait associated type doesn't have the requirement `Fooy: Copy` = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | @@ -72,14 +72,14 @@ note: required because of the requirements on the impl of `Copy` for `Fooy` | LL | #[derive(Copy, Clone)] | ^^^^ -note: the requirement `Fooy: Copy` appears on the `impl`'s method `d` but not on the corresponding trait's method +note: the requirement `Fooy: Copy` appears on the impl method `d` but not on the corresponding trait method --> $DIR/impl_bounds.rs:8:8 | LL | trait Foo { | --- in this trait ... LL | fn d() where Self: Clone; - | ^ this trait's method doesn't have the requirement `Fooy: Copy` + | ^ this trait method doesn't have the requirement `Fooy: Copy` = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | @@ -88,5 +88,5 @@ LL | impl Foo for Fooy { error: aborting due to 5 previous errors -Some errors have detailed explanations: E0276, E0277, E0478. -For more information about an error, try `rustc --explain E0276`. +Some errors have detailed explanations: E0277, E0478. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr index 31948a878edfa..c560e2405d5a7 100644 --- a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr +++ b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr @@ -1,11 +1,11 @@ error[E0276]: impl has stricter requirements than trait - --> $DIR/issue-47206-where-clause.rs:12:38 + --> $DIR/issue-47206-where-clause.rs:12:5 | LL | type Assoc3; | -------------- definition of `Assoc3` from trait ... LL | type Assoc3 = Vec where T: Iterator; - | ^^^^^^^^ impl has extra requirement `T: Iterator` + | ^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator` error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/issue-70304.rs b/src/test/ui/generic-associated-types/issue-70304.rs index f778f985cf0d1..c9fd7248a8004 100644 --- a/src/test/ui/generic-associated-types/issue-70304.rs +++ b/src/test/ui/generic-associated-types/issue-70304.rs @@ -2,7 +2,6 @@ trait Document { type Cursor<'a>: DocCursor<'a>; - //~^ ERROR: missing required bound on `Cursor` fn cursor(&self) -> Self::Cursor<'_>; } diff --git a/src/test/ui/generic-associated-types/issue-70304.stderr b/src/test/ui/generic-associated-types/issue-70304.stderr index bba7cab7093ce..b3881ccb099f0 100644 --- a/src/test/ui/generic-associated-types/issue-70304.stderr +++ b/src/test/ui/generic-associated-types/issue-70304.stderr @@ -1,11 +1,11 @@ error[E0637]: `'_` cannot be used here - --> $DIR/issue-70304.rs:48:41 + --> $DIR/issue-70304.rs:47:41 | LL | fn create_doc() -> impl Document = DocCursorImpl<'_>> { | ^^ `'_` is a reserved lifetime name error[E0106]: missing lifetime specifier - --> $DIR/issue-70304.rs:48:61 + --> $DIR/issue-70304.rs:47:61 | LL | fn create_doc() -> impl Document = DocCursorImpl<'_>> { | ^^ expected named lifetime parameter @@ -16,18 +16,7 @@ help: consider using the `'static` lifetime LL | fn create_doc() -> impl Document = DocCursorImpl<'static>> { | ~~~~~~~ -error: missing required bound on `Cursor` - --> $DIR/issue-70304.rs:4:5 - | -LL | type Cursor<'a>: DocCursor<'a>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | help: add the required where clause: `where Self: 'a` - | - = note: this bound is currently required to ensure that impls have maximum flexibility - = note: we are soliciting feedback, see issue #87479 for more information - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0106, E0637. For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs index 8171dc0ae28d6..5fb8f7a4773d6 100644 --- a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs +++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs @@ -7,7 +7,7 @@ trait Foo { } impl Foo for () { type Assoc<'a, 'b> = () where 'a: 'b; - //~^ impl has stricter requirements than trait + //~^ `impl` associated type } fn main() {} diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr index edd1f9367d129..0256d2f20fc1e 100644 --- a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr +++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr @@ -1,12 +1,11 @@ -error[E0276]: impl has stricter requirements than trait - --> $DIR/missing-where-clause-on-trait.rs:9:39 +error: `impl` associated type signature for `Assoc` doesn't match `trait` associated type signature + --> $DIR/missing-where-clause-on-trait.rs:9:5 | LL | type Assoc<'a, 'b>; - | ------------------ definition of `Assoc` from trait + | ------------------ expected ... LL | type Assoc<'a, 'b> = () where 'a: 'b; - | ^^ impl has extra requirement `'a: 'b` + | ^^^^^^^^^^^^^^^^^^ found error: aborting due to previous error -For more information about this error, try `rustc --explain E0276`. diff --git a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs index 9ea9fc71b557f..54b483f53d4cb 100644 --- a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs +++ b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs @@ -8,7 +8,6 @@ fn should_error() where T : Into<&u32> {} trait X<'a, K: 'a> { fn foo<'b, L: X<&'b Nested>>(); //~^ ERROR missing lifetime specifier [E0106] - //~| ERROR the type `&'b Nested` does not fulfill the required lifetime } fn bar<'b, L: X<&'b Nested>>(){} diff --git a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr index e45387acaf31d..270d6b8e18e22 100644 --- a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr +++ b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr @@ -5,10 +5,21 @@ LL | fn should_error() where T : Into<&u32> {} | ^ explicit lifetime name needed here error[E0106]: missing lifetime specifier - --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:20 + --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:13:17 + | +LL | fn bar<'b, L: X<&'b Nested>>(){} + | ^ expected named lifetime parameter + | +help: consider using the `'b` lifetime + | +LL | fn bar<'b, L: X<'b, &'b Nested>>(){} + | +++ + +error[E0106]: missing lifetime specifier + --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:21 | LL | fn foo<'b, L: X<&'b Nested>>(); - | ^ expected named lifetime parameter + | ^ expected named lifetime parameter | note: these named lifetimes are available to use --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:8:9 @@ -22,30 +33,7 @@ help: consider using one of the available lifetimes here LL | fn foo<'b, L: X<'lifetime, &'b Nested>>(); | ++++++++++ -error[E0106]: missing lifetime specifier - --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:14:16 - | -LL | fn bar<'b, L: X<&'b Nested>>(){} - | ^ expected named lifetime parameter - | -help: consider using the `'b` lifetime - | -LL | fn bar<'b, L: X<'b, &'b Nested>>(){} - | +++ - -error[E0477]: the type `&'b Nested` does not fulfill the required lifetime - --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:19 - | -LL | fn foo<'b, L: X<&'b Nested>>(); - | ^^^^^^^^^^^^^^^^ - | -note: type must satisfy the static lifetime as required by this binding - --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:8:16 - | -LL | trait X<'a, K: 'a> { - | ^^ - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0106, E0477, E0637. +Some errors have detailed explanations: E0106, E0637. For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/generics/wrong-number-of-args.rs b/src/test/ui/generics/wrong-number-of-args.rs index cd2f96a1819e4..272cd36196804 100644 --- a/src/test/ui/generics/wrong-number-of-args.rs +++ b/src/test/ui/generics/wrong-number-of-args.rs @@ -120,7 +120,6 @@ mod r#trait { type B = Box; //~^ ERROR missing lifetime specifier //~| HELP consider introducing - //~| HELP consider making the bound lifetime-generic type C = Box>; //~^ ERROR this trait takes 1 lifetime argument but 2 lifetime arguments were supplied @@ -137,7 +136,6 @@ mod r#trait { type F = Box>; //~^ ERROR missing lifetime specifier //~| HELP consider introducing - //~| HELP consider making the bound lifetime-generic type G = Box>; //~^ ERROR this trait takes 1 generic argument but 0 generic arguments @@ -163,7 +161,6 @@ mod associated_item { type A = Box>; //~^ ERROR missing lifetime specifier //~| HELP consider introducing - //~| HELP consider making the bound lifetime-generic type B = Box>; //~^ ERROR this trait takes 1 lifetime argument but 2 lifetime arguments were supplied @@ -172,7 +169,6 @@ mod associated_item { type C = Box>; //~^ ERROR missing lifetime specifier //~| HELP consider introducing - //~| HELP consider making the bound lifetime-generic //~| ERROR this trait takes 0 generic arguments but 1 generic argument //~| HELP remove } @@ -207,7 +203,6 @@ mod associated_item { //~| HELP add missing //~| ERROR missing lifetime specifier //~| HELP consider introducing - //~| HELP consider making the bound lifetime-generic type B = Box>; //~^ ERROR this trait takes 1 generic argument but 0 generic arguments were supplied @@ -222,12 +217,10 @@ mod associated_item { type D = Box>; //~^ ERROR missing lifetime specifier //~| HELP consider introducing - //~| HELP consider making the bound lifetime-generic type E = Box>; //~^ ERROR missing lifetime specifier //~| HELP consider introducing - //~| HELP consider making the bound lifetime-generic //~| ERROR this trait takes 1 generic argument but 2 generic arguments //~| HELP remove @@ -272,7 +265,6 @@ mod associated_item { type A = Box>; //~^ ERROR missing lifetime specifier //~| HELP consider introducing - //~| HELP consider making the bound lifetime-generic type B = Box>; //~^ ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied @@ -287,7 +279,6 @@ mod associated_item { type A = Box>; //~^ ERROR missing lifetime specifier //~| HELP consider introducing - //~| HELP consider making the bound lifetime-generic //~| ERROR this trait takes 1 generic argument but 0 generic arguments //~| HELP add missing diff --git a/src/test/ui/generics/wrong-number-of-args.stderr b/src/test/ui/generics/wrong-number-of-args.stderr index 388c23fc24f74..3b0834a5f51b2 100644 --- a/src/test/ui/generics/wrong-number-of-args.stderr +++ b/src/test/ui/generics/wrong-number-of-args.stderr @@ -1,172 +1,3 @@ -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:48:14 - | -LL | type A = Ty; - | ^^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type A<'a> = Ty<'a>; - | ++++ ++++ - -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:58:16 - | -LL | type C = Ty; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type C<'a> = Ty<'a, usize>; - | ++++ +++ - -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:64:16 - | -LL | type E = Ty<>; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type E<'a> = Ty<'a, >; - | ++++ +++ - -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:120:22 - | -LL | type B = Box; - | ^^^^^^^^^^^^^^^ expected named lifetime parameter - | - = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html -help: consider making the bound lifetime-generic with a new `'a` lifetime - | -LL | type B = Box GenericLifetime<'a>>; - | +++++++ ++++ -help: consider introducing a named lifetime parameter - | -LL | type B<'a> = Box>; - | ++++ ++++ - -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:137:37 - | -LL | type F = Box>; - | ^ expected named lifetime parameter - | -help: consider making the bound lifetime-generic with a new `'a` lifetime - | -LL | type F = Box GenericLifetime<'a, >>; - | +++++++ +++ -help: consider introducing a named lifetime parameter - | -LL | type F<'a> = Box>; - | ++++ +++ - -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:163:43 - | -LL | type A = Box>; - | ^ expected named lifetime parameter - | -help: consider making the bound lifetime-generic with a new `'a` lifetime - | -LL | type A = Box GenericLifetimeAT<'a, AssocTy=()>>; - | +++++++ +++ -help: consider introducing a named lifetime parameter - | -LL | type A<'a> = Box>; - | ++++ +++ - -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:172:43 - | -LL | type C = Box>; - | ^ expected named lifetime parameter - | -help: consider making the bound lifetime-generic with a new `'a` lifetime - | -LL | type C = Box GenericLifetimeAT<'a, (), AssocTy=()>>; - | +++++++ +++ -help: consider introducing a named lifetime parameter - | -LL | type C<'a> = Box>; - | ++++ +++ - -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:205:47 - | -LL | type A = Box>; - | ^ expected named lifetime parameter - | -help: consider making the bound lifetime-generic with a new `'a` lifetime - | -LL | type A = Box GenericLifetimeTypeAT<'a, AssocTy=()>>; - | +++++++ +++ -help: consider introducing a named lifetime parameter - | -LL | type A<'a> = Box>; - | ++++ +++ - -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:222:47 - | -LL | type D = Box>; - | ^ expected named lifetime parameter - | -help: consider making the bound lifetime-generic with a new `'a` lifetime - | -LL | type D = Box GenericLifetimeTypeAT<'a, (), AssocTy=()>>; - | +++++++ +++ -help: consider introducing a named lifetime parameter - | -LL | type D<'a> = Box>; - | ++++ +++ - -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:227:47 - | -LL | type E = Box>; - | ^ expected named lifetime parameter - | -help: consider making the bound lifetime-generic with a new `'a` lifetime - | -LL | type E = Box GenericLifetimeTypeAT<'a, (), (), AssocTy=()>>; - | +++++++ +++ -help: consider introducing a named lifetime parameter - | -LL | type E<'a> = Box>; - | ++++ +++ - -error[E0106]: missing lifetime specifiers - --> $DIR/wrong-number-of-args.rs:272:51 - | -LL | type A = Box>; - | ^ expected 2 lifetime parameters - | -help: consider making the bound lifetime-generic with a new `'a` lifetime - | -LL | type A = Box GenericLifetimeLifetimeAT<'a, 'a, AssocTy=()>>; - | +++++++ +++++++ -help: consider introducing a named lifetime parameter - | -LL | type A<'a> = Box>; - | ++++ +++++++ - -error[E0106]: missing lifetime specifiers - --> $DIR/wrong-number-of-args.rs:287:55 - | -LL | type A = Box>; - | ^ expected 2 lifetime parameters - | -help: consider making the bound lifetime-generic with a new `'a` lifetime - | -LL | type A = Box GenericLifetimeLifetimeTypeAT<'a, 'a, AssocTy=()>>; - | +++++++ +++++++ -help: consider introducing a named lifetime parameter - | -LL | type A<'a> = Box>; - | ++++ +++++++ - error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied --> $DIR/wrong-number-of-args.rs:6:14 | @@ -317,6 +148,17 @@ help: add missing generic argument LL | type A = Ty; | ~~~~~ +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:48:14 + | +LL | type A = Ty; + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type A<'a> = Ty<'a>; + | ++++ ~~~~~~ + error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied --> $DIR/wrong-number-of-args.rs:54:14 | @@ -333,6 +175,17 @@ help: add missing generic argument LL | type B = Ty<'static, T>; | +++ +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:58:17 + | +LL | type C = Ty; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type C<'a> = Ty<'a, usize>; + | ++++ +++ + error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied --> $DIR/wrong-number-of-args.rs:64:14 | @@ -349,6 +202,17 @@ help: add missing generic argument LL | type E = Ty; | + +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:64:16 + | +LL | type E = Ty<>; + | ^- expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type E<'a> = Ty<'a>; + | ++++ ++ + error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied --> $DIR/wrong-number-of-args.rs:70:14 | @@ -455,8 +319,19 @@ note: trait defined here, with 0 generic parameters LL | trait NonGeneric { | ^^^^^^^^^^ +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:120:22 + | +LL | type B = Box; + | ^^^^^^^^^^^^^^^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type B<'a> = Box>; + | ++++ ~~~~~~~~~~~~~~~~~~~ + error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied - --> $DIR/wrong-number-of-args.rs:125:22 + --> $DIR/wrong-number-of-args.rs:124:22 | LL | type C = Box>; | ^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument @@ -470,7 +345,7 @@ LL | trait GenericLifetime<'a> { | ^^^^^^^^^^^^^^^ -- error[E0107]: missing generics for trait `GenericType` - --> $DIR/wrong-number-of-args.rs:129:22 + --> $DIR/wrong-number-of-args.rs:128:22 | LL | type D = Box; | ^^^^^^^^^^^ expected 1 generic argument @@ -486,7 +361,7 @@ LL | type D = Box>; | ~~~~~~~~~~~~~~ error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:133:22 + --> $DIR/wrong-number-of-args.rs:132:22 | LL | type E = Box>; | ^^^^^^^^^^^ ----- help: remove this generic argument @@ -499,8 +374,19 @@ note: trait defined here, with 1 generic parameter: `A` LL | trait GenericType { | ^^^^^^^^^^^ - +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:136:37 + | +LL | type F = Box>; + | ^- expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type F<'a> = Box>; + | ++++ ++ + error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:142:22 + --> $DIR/wrong-number-of-args.rs:140:22 | LL | type G = Box>; | ^^^^^^^^^^^ expected 1 generic argument @@ -516,7 +402,7 @@ LL | type G = Box>; | + error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:153:26 + --> $DIR/wrong-number-of-args.rs:151:26 | LL | type A = Box>; | ^^^^^^^^^^^^------------------- help: remove these generics @@ -524,13 +410,24 @@ LL | type A = Box>; | expected 0 generic arguments | note: trait defined here, with 0 generic parameters - --> $DIR/wrong-number-of-args.rs:149:15 + --> $DIR/wrong-number-of-args.rs:147:15 | LL | trait NonGenericAT { | ^^^^^^^^^^^^ +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:161:44 + | +LL | type A = Box>; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type A<'a> = Box>; + | ++++ +++ + error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied - --> $DIR/wrong-number-of-args.rs:168:26 + --> $DIR/wrong-number-of-args.rs:165:26 | LL | type B = Box>; | ^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument @@ -538,13 +435,13 @@ LL | type B = Box>; | expected 1 lifetime argument | note: trait defined here, with 1 lifetime parameter: `'a` - --> $DIR/wrong-number-of-args.rs:159:15 + --> $DIR/wrong-number-of-args.rs:157:15 | LL | trait GenericLifetimeAT<'a> { | ^^^^^^^^^^^^^^^^^ -- error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:172:26 + --> $DIR/wrong-number-of-args.rs:169:26 | LL | type C = Box>; | ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument @@ -552,19 +449,30 @@ LL | type C = Box>; | expected 0 generic arguments | note: trait defined here, with 0 generic parameters - --> $DIR/wrong-number-of-args.rs:159:15 + --> $DIR/wrong-number-of-args.rs:157:15 | LL | trait GenericLifetimeAT<'a> { | ^^^^^^^^^^^^^^^^^ +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:169:44 + | +LL | type C = Box>; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type C<'a> = Box>; + | ++++ +++ + error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:185:26 + --> $DIR/wrong-number-of-args.rs:181:26 | LL | type A = Box>; | ^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:181:15 + --> $DIR/wrong-number-of-args.rs:177:15 | LL | trait GenericTypeAT { | ^^^^^^^^^^^^^ - @@ -574,7 +482,7 @@ LL | type A = Box>; | ++ error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:189:26 + --> $DIR/wrong-number-of-args.rs:185:26 | LL | type B = Box>; | ^^^^^^^^^^^^^ -- help: remove this generic argument @@ -582,13 +490,13 @@ LL | type B = Box>; | expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:181:15 + --> $DIR/wrong-number-of-args.rs:177:15 | LL | trait GenericTypeAT { | ^^^^^^^^^^^^^ - error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:193:26 + --> $DIR/wrong-number-of-args.rs:189:26 | LL | type C = Box>; | ^^^^^^^^^^^^^--------------------- help: remove these generics @@ -596,19 +504,19 @@ LL | type C = Box>; | expected 0 lifetime arguments | note: trait defined here, with 0 lifetime parameters - --> $DIR/wrong-number-of-args.rs:181:15 + --> $DIR/wrong-number-of-args.rs:177:15 | LL | trait GenericTypeAT { | ^^^^^^^^^^^^^ error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:193:26 + --> $DIR/wrong-number-of-args.rs:189:26 | LL | type C = Box>; | ^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:181:15 + --> $DIR/wrong-number-of-args.rs:177:15 | LL | trait GenericTypeAT { | ^^^^^^^^^^^^^ - @@ -618,13 +526,13 @@ LL | type C = Box>; | +++ error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:205:26 + --> $DIR/wrong-number-of-args.rs:201:26 | LL | type A = Box>; | ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:201:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - @@ -633,14 +541,25 @@ help: add missing generic argument LL | type A = Box>; | ++ +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:201:48 + | +LL | type A = Box>; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type A<'a> = Box>; + | ++++ +++ + error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:212:26 + --> $DIR/wrong-number-of-args.rs:207:26 | LL | type B = Box>; | ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:201:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - @@ -650,7 +569,7 @@ LL | type B = Box>; | +++ error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied - --> $DIR/wrong-number-of-args.rs:216:26 + --> $DIR/wrong-number-of-args.rs:211:26 | LL | type C = Box>; | ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument @@ -658,19 +577,19 @@ LL | type C = Box $DIR/wrong-number-of-args.rs:201:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ -- error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:216:26 + --> $DIR/wrong-number-of-args.rs:211:26 | LL | type C = Box>; | ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:201:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - @@ -679,8 +598,19 @@ help: add missing generic argument LL | type C = Box>; | +++ +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:217:48 + | +LL | type D = Box>; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type D<'a> = Box>; + | ++++ +++ + error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:227:26 + --> $DIR/wrong-number-of-args.rs:221:26 | LL | type E = Box>; | ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument @@ -688,13 +618,24 @@ LL | type E = Box>; | expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:201:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:221:48 + | +LL | type E = Box>; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type E<'a> = Box>; + | ++++ +++ + error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied - --> $DIR/wrong-number-of-args.rs:234:26 + --> $DIR/wrong-number-of-args.rs:227:26 | LL | type F = Box>; | ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument @@ -702,13 +643,13 @@ LL | type F = Box $DIR/wrong-number-of-args.rs:201:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ -- error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:238:26 + --> $DIR/wrong-number-of-args.rs:231:26 | LL | type G = Box>; | ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument @@ -716,13 +657,13 @@ LL | type G = Box | expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:201:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied - --> $DIR/wrong-number-of-args.rs:242:26 + --> $DIR/wrong-number-of-args.rs:235:26 | LL | type H = Box>; | ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument @@ -730,13 +671,13 @@ LL | type H = Box $DIR/wrong-number-of-args.rs:201:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ -- error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:242:26 + --> $DIR/wrong-number-of-args.rs:235:26 | LL | type H = Box>; | ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument @@ -744,19 +685,19 @@ LL | type H = Box $DIR/wrong-number-of-args.rs:201:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - error[E0107]: this trait takes 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:254:26 + --> $DIR/wrong-number-of-args.rs:247:26 | LL | type A = Box>; | ^^^^^^^^^^^^^^^^^ expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `A`, `B` - --> $DIR/wrong-number-of-args.rs:250:15 + --> $DIR/wrong-number-of-args.rs:243:15 | LL | trait GenericTypeTypeAT { | ^^^^^^^^^^^^^^^^^ - - @@ -766,7 +707,7 @@ LL | type A = Box>; | +++++ error[E0107]: this trait takes 2 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:258:26 + --> $DIR/wrong-number-of-args.rs:251:26 | LL | type B = Box>; | ^^^^^^^^^^^^^^^^^ -- supplied 1 generic argument @@ -774,7 +715,7 @@ LL | type B = Box>; | expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `A`, `B` - --> $DIR/wrong-number-of-args.rs:250:15 + --> $DIR/wrong-number-of-args.rs:243:15 | LL | trait GenericTypeTypeAT { | ^^^^^^^^^^^^^^^^^ - - @@ -784,7 +725,7 @@ LL | type B = Box>; | +++ error[E0107]: this trait takes 2 generic arguments but 3 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:262:26 + --> $DIR/wrong-number-of-args.rs:255:26 | LL | type C = Box>; | ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument @@ -792,13 +733,24 @@ LL | type C = Box>; | expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `A`, `B` - --> $DIR/wrong-number-of-args.rs:250:15 + --> $DIR/wrong-number-of-args.rs:243:15 | LL | trait GenericTypeTypeAT { | ^^^^^^^^^^^^^^^^^ - - +error[E0106]: missing lifetime specifiers + --> $DIR/wrong-number-of-args.rs:265:52 + | +LL | type A = Box>; + | ^ expected 2 lifetime parameters + | +help: consider introducing a named lifetime parameter + | +LL | type A<'a> = Box>; + | ++++ +++++++ + error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:277:26 + --> $DIR/wrong-number-of-args.rs:269:26 | LL | type B = Box>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument @@ -806,7 +758,7 @@ LL | type B = Box>; | expected 2 lifetime arguments | note: trait defined here, with 2 lifetime parameters: `'a`, `'b` - --> $DIR/wrong-number-of-args.rs:268:15 + --> $DIR/wrong-number-of-args.rs:261:15 | LL | trait GenericLifetimeLifetimeAT<'a, 'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -- -- @@ -816,13 +768,13 @@ LL | type B = Box | ++++ error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:287:26 + --> $DIR/wrong-number-of-args.rs:279:26 | LL | type A = Box>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:283:15 + --> $DIR/wrong-number-of-args.rs:275:15 | LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - @@ -831,8 +783,19 @@ help: add missing generic argument LL | type A = Box>; | ++ +error[E0106]: missing lifetime specifiers + --> $DIR/wrong-number-of-args.rs:279:56 + | +LL | type A = Box>; + | ^ expected 2 lifetime parameters + | +help: consider introducing a named lifetime parameter + | +LL | type A<'a> = Box>; + | ++++ +++++++ + error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:294:26 + --> $DIR/wrong-number-of-args.rs:285:26 | LL | type B = Box>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument @@ -840,7 +803,7 @@ LL | type B = Box | expected 2 lifetime arguments | note: trait defined here, with 2 lifetime parameters: `'a`, `'b` - --> $DIR/wrong-number-of-args.rs:283:15 + --> $DIR/wrong-number-of-args.rs:275:15 | LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- -- @@ -850,13 +813,13 @@ LL | type B = Box $DIR/wrong-number-of-args.rs:294:26 + --> $DIR/wrong-number-of-args.rs:285:26 | LL | type B = Box>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:283:15 + --> $DIR/wrong-number-of-args.rs:275:15 | LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - @@ -866,7 +829,7 @@ LL | type B = Box $DIR/wrong-number-of-args.rs:300:26 + --> $DIR/wrong-number-of-args.rs:291:26 | LL | type C = Box>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument @@ -874,7 +837,7 @@ LL | type C = Box $DIR/wrong-number-of-args.rs:283:15 + --> $DIR/wrong-number-of-args.rs:275:15 | LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- -- @@ -884,7 +847,7 @@ LL | type C = Box $DIR/wrong-number-of-args.rs:310:18 + --> $DIR/wrong-number-of-args.rs:301:18 | LL | type A = HashMap; | ^^^^^^^ expected at least 2 generic arguments @@ -900,7 +863,7 @@ LL | type A = HashMap; | ~~~~~~~~~~~~~ error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:314:18 + --> $DIR/wrong-number-of-args.rs:305:18 | LL | type B = HashMap; | ^^^^^^^ ------ supplied 1 generic argument @@ -918,7 +881,7 @@ LL | type B = HashMap; | +++ error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:318:18 + --> $DIR/wrong-number-of-args.rs:309:18 | LL | type C = HashMap<'static>; | ^^^^^^^--------- help: remove these generics @@ -932,7 +895,7 @@ LL | pub struct HashMap { | ^^^^^^^ error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:318:18 + --> $DIR/wrong-number-of-args.rs:309:18 | LL | type C = HashMap<'static>; | ^^^^^^^ expected at least 2 generic arguments @@ -948,7 +911,7 @@ LL | type C = HashMap<'static, K, V>; | ++++++ error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:324:18 + --> $DIR/wrong-number-of-args.rs:315:18 | LL | type D = HashMap; | ^^^^^^^ --- help: remove this generic argument @@ -962,7 +925,7 @@ LL | pub struct HashMap { | ^^^^^^^ - - --------------- error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:328:18 + --> $DIR/wrong-number-of-args.rs:319:18 | LL | type E = HashMap<>; | ^^^^^^^ expected at least 2 generic arguments @@ -978,7 +941,7 @@ LL | type E = HashMap; | ++++ error[E0107]: missing generics for enum `Result` - --> $DIR/wrong-number-of-args.rs:334:18 + --> $DIR/wrong-number-of-args.rs:325:18 | LL | type A = Result; | ^^^^^^ expected 2 generic arguments @@ -994,7 +957,7 @@ LL | type A = Result; | ~~~~~~~~~~~~ error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:338:18 + --> $DIR/wrong-number-of-args.rs:329:18 | LL | type B = Result; | ^^^^^^ ------ supplied 1 generic argument @@ -1012,7 +975,7 @@ LL | type B = Result; | +++ error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:342:18 + --> $DIR/wrong-number-of-args.rs:333:18 | LL | type C = Result<'static>; | ^^^^^^--------- help: remove these generics @@ -1026,7 +989,7 @@ LL | pub enum Result { | ^^^^^^ error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:342:18 + --> $DIR/wrong-number-of-args.rs:333:18 | LL | type C = Result<'static>; | ^^^^^^ expected 2 generic arguments @@ -1042,7 +1005,7 @@ LL | type C = Result<'static, T, E>; | ++++++ error[E0107]: this enum takes 2 generic arguments but 3 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:348:18 + --> $DIR/wrong-number-of-args.rs:339:18 | LL | type D = Result; | ^^^^^^ ---- help: remove this generic argument @@ -1056,7 +1019,7 @@ LL | pub enum Result { | ^^^^^^ - - error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:352:18 + --> $DIR/wrong-number-of-args.rs:343:18 | LL | type E = Result<>; | ^^^^^^ expected 2 generic arguments diff --git a/src/test/ui/impl-header-lifetime-elision/assoc-type.rs b/src/test/ui/impl-header-lifetime-elision/assoc-type.rs index b0089a37aa05f..44c46e444d66d 100644 --- a/src/test/ui/impl-header-lifetime-elision/assoc-type.rs +++ b/src/test/ui/impl-header-lifetime-elision/assoc-type.rs @@ -9,12 +9,12 @@ trait MyTrait { impl MyTrait for &i32 { type Output = &i32; - //~^ ERROR `&` without an explicit lifetime name cannot be used here + //~^ ERROR missing lifetime specifier } impl MyTrait for &u32 { type Output = &'_ i32; - //~^ ERROR `'_` cannot be used here + //~^ ERROR missing lifetime specifier } // This is what you have to do: diff --git a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr index c4f27e0b80e41..44955c58889aa 100644 --- a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr +++ b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr @@ -1,15 +1,25 @@ -error[E0637]: `&` without an explicit lifetime name cannot be used here +error[E0106]: missing lifetime specifier --> $DIR/assoc-type.rs:11:19 | LL | type Output = &i32; - | ^ explicit lifetime name needed here + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type Output<'a> = &'a i32; + | ++++ ++ -error[E0637]: `'_` cannot be used here +error[E0106]: missing lifetime specifier --> $DIR/assoc-type.rs:16:20 | LL | type Output = &'_ i32; - | ^^ `'_` is a reserved lifetime name + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type Output<'a> = &'a i32; + | ++++ ~~ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0637`. +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/impl-header-lifetime-elision/constant-used-as-arraylen.rs b/src/test/ui/impl-header-lifetime-elision/constant-used-as-arraylen.rs deleted file mode 100644 index 929b82bfc432e..0000000000000 --- a/src/test/ui/impl-header-lifetime-elision/constant-used-as-arraylen.rs +++ /dev/null @@ -1,24 +0,0 @@ -// check-pass -// Verify that we do not ICE when anonymous lifetimes appear inside an AnonConst. - -pub struct EntriesBuffer(Box<[[u8; HashesEntry::LEN]; 5]>); - -impl EntriesBuffer { - pub fn iter_child_buffers(&mut self) -> impl Iterator { - self.0.iter_mut() - } - - pub fn iter_child_buffers_explicit( - &mut self, - ) -> impl Iterator::LEN]> { - self.0.iter_mut() - } -} - -pub struct HashesEntry<'a>(&'a [u8]); - -impl HashesEntry<'_> { - pub const LEN: usize = 1; -} - -fn main() {} diff --git a/src/test/ui/impl-trait/hidden-lifetimes.stderr b/src/test/ui/impl-trait/hidden-lifetimes.stderr index efc228de58be5..97652f5462ef0 100644 --- a/src/test/ui/impl-trait/hidden-lifetimes.stderr +++ b/src/test/ui/impl-trait/hidden-lifetimes.stderr @@ -1,4 +1,4 @@ -error[E0700]: hidden type for `impl Swap` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/hidden-lifetimes.rs:29:5 | LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a { @@ -11,7 +11,7 @@ help: to declare that the `impl Trait` captures `'b`, you can add an explicit `' LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a + 'b { | ++++ -error[E0700]: hidden type for `impl Swap` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/hidden-lifetimes.rs:46:5 | LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc>) -> impl Swap + 'a { diff --git a/src/test/ui/impl-trait/issue-99073-2.rs b/src/test/ui/impl-trait/issue-99073-2.rs index 14ac688806bda..bebd8286de9fe 100644 --- a/src/test/ui/impl-trait/issue-99073-2.rs +++ b/src/test/ui/impl-trait/issue-99073-2.rs @@ -7,7 +7,7 @@ fn main() { fn test(t: T, recurse: bool) -> impl Display { let f = || { let i: u32 = test::(-1, false); - //~^ ERROR concrete type differs from previous defining opaque type use + //~^ ERROR mismatched types println!("{i}"); }; if recurse { diff --git a/src/test/ui/impl-trait/issue-99073-2.stderr b/src/test/ui/impl-trait/issue-99073-2.stderr index 913bc8f5674ac..c1e4b823c08e7 100644 --- a/src/test/ui/impl-trait/issue-99073-2.stderr +++ b/src/test/ui/impl-trait/issue-99073-2.stderr @@ -1,14 +1,15 @@ -error: concrete type differs from previous defining opaque type use +error[E0308]: mismatched types --> $DIR/issue-99073-2.rs:9:22 | +LL | fn test(t: T, recurse: bool) -> impl Display { + | ------------ the expected opaque type +LL | let f = || { LL | let i: u32 = test::(-1, false); - | ^^^^^^^^^^^^^^^^^^^^^^ expected `T`, got `u32` + | ^^^^^^^^^^^^^^^^^^^^^^ types differ | -note: previous use here - --> $DIR/issue-99073-2.rs:16:5 - | -LL | t - | ^ + = note: expected opaque type `impl std::fmt::Display` + found type `u32` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/impl-trait/issue-99073.rs b/src/test/ui/impl-trait/issue-99073.rs index 7798e247df0a2..1d75f6086664f 100644 --- a/src/test/ui/impl-trait/issue-99073.rs +++ b/src/test/ui/impl-trait/issue-99073.rs @@ -1,8 +1,8 @@ fn main() { - let _ = fix(|_: &dyn Fn()| {}); + let _ = fix(|_: &dyn Fn()| {}); } fn fix(f: F) -> impl Fn() { - move || f(fix(&f)) - //~^ ERROR concrete type differs from previous defining opaque type use + move || f(fix(&f)) + //~^ ERROR mismatched types } diff --git a/src/test/ui/impl-trait/issue-99073.stderr b/src/test/ui/impl-trait/issue-99073.stderr index 5463679534968..b35d58093d5fc 100644 --- a/src/test/ui/impl-trait/issue-99073.stderr +++ b/src/test/ui/impl-trait/issue-99073.stderr @@ -1,14 +1,14 @@ -error: concrete type differs from previous defining opaque type use - --> $DIR/issue-99073.rs:6:11 +error[E0308]: mismatched types + --> $DIR/issue-99073.rs:6:13 | -LL | move || f(fix(&f)) - | ^^^^^^^^^^ expected `[closure@$DIR/issue-99073.rs:6:3: 6:10]`, got `G` +LL | fn fix(f: F) -> impl Fn() { + | --------- the expected opaque type +LL | move || f(fix(&f)) + | ^^^^^^^^^^ types differ | -note: previous use here - --> $DIR/issue-99073.rs:6:3 - | -LL | move || f(fix(&f)) - | ^^^^^^^^^^^^^^^^^^ + = note: expected opaque type `impl Fn()` + found type parameter `G` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/impl-trait/issue-99642-2.rs b/src/test/ui/impl-trait/issue-99642-2.rs deleted file mode 100644 index 0e88b363338a9..0000000000000 --- a/src/test/ui/impl-trait/issue-99642-2.rs +++ /dev/null @@ -1,8 +0,0 @@ -// check-pass - -#![feature(type_alias_impl_trait)] -type Opq = impl Sized; -fn test() -> impl Iterator { - Box::new(0..) as Box> -} -fn main(){} diff --git a/src/test/ui/impl-trait/issue-99642.rs b/src/test/ui/impl-trait/issue-99642.rs deleted file mode 100644 index 75af60491e438..0000000000000 --- a/src/test/ui/impl-trait/issue-99642.rs +++ /dev/null @@ -1,7 +0,0 @@ -// check-pass - -fn test() -> impl Iterator { - Box::new(0..) as Box> -} - -fn main() {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs index 2a2be6b742992..f5aaf1185211b 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs @@ -20,7 +20,7 @@ fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { let _: &'b i32 = *u.0; } u.0 - //~^ ERROR hidden type for `E<'b, 'c>` captures lifetime that does not appear in bounds + //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds } fn main() {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr index 9087570809404..b837b64110365 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr @@ -1,4 +1,4 @@ -error[E0700]: hidden type for `E<'b, 'c>` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/error-handling-2.rs:22:5 | LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs index c6eea5323fd80..47e05bce0f8de 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs @@ -26,7 +26,7 @@ where // 'a in ['d, 'e] // ``` if condition() { a } else { b } - //~^ ERROR hidden type for `impl Trait<'d, 'e>` captures lifetime that does not appear in bounds + //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds } fn condition() -> bool { diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr index cb1dc0b7d50ae..15476c706a7f2 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr @@ -1,4 +1,4 @@ -error[E0700]: hidden type for `impl Trait<'d, 'e>` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/ordinary-bounds-unrelated.rs:28:33 | LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs index adcbca2a438b4..321cb8c92a177 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs @@ -29,7 +29,7 @@ fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> // // We are forced to pick that '0 = 'e, because only 'e is outlived by *both* 'a and 'b. if condition() { a } else { b } - //~^ ERROR hidden type for `impl Trait<'a, 'b>` captures lifetime that does not appear in bounds + //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds } fn condition() -> bool { diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr index 4388e6601a6cf..7315aa8e9d478 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr @@ -1,4 +1,4 @@ -error[E0700]: hidden type for `impl Trait<'a, 'b>` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/ordinary-bounds-unsuited.rs:31:33 | LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 16767abd72241..586563c39061e 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -1,4 +1,4 @@ -error[E0700]: hidden type for `impl Copy` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/must_outlive_least_region_or_bound.rs:3:35 | LL | fn elided(x: &i32) -> impl Copy { x } @@ -11,7 +11,7 @@ help: to declare that the `impl Trait` captures `'_`, you can add an explicit `' LL | fn elided(x: &i32) -> impl Copy + '_ { x } | ++++ -error[E0700]: hidden type for `impl Copy` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/must_outlive_least_region_or_bound.rs:6:44 | LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } @@ -96,7 +96,7 @@ help: alternatively, add an explicit `'static` bound to this reference LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x } | ~~~~~~~~~~~~ -error[E0700]: hidden type for `impl Fn(&'a u32)` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/must_outlive_least_region_or_bound.rs:38:5 | LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { diff --git a/src/test/ui/impl-trait/region-escape-via-bound.rs b/src/test/ui/impl-trait/region-escape-via-bound.rs index fe60c76ca1755..a04cb1702b638 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound.rs +++ b/src/test/ui/impl-trait/region-escape-via-bound.rs @@ -15,7 +15,7 @@ fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> where 'x: 'y { x - //~^ ERROR hidden type for `impl Trait<'y>` captures lifetime that does not appear in bounds [E0700] + //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0700] } fn main() { } diff --git a/src/test/ui/impl-trait/region-escape-via-bound.stderr b/src/test/ui/impl-trait/region-escape-via-bound.stderr index fdb2fe022b4d2..bc02f7694d7f6 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound.stderr +++ b/src/test/ui/impl-trait/region-escape-via-bound.stderr @@ -1,4 +1,4 @@ -error[E0700]: hidden type for `impl Trait<'y>` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/region-escape-via-bound.rs:17:5 | LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr index b868152315503..951abb127c13f 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr @@ -1,4 +1,4 @@ -error[E0700]: hidden type for `impl Iterator` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/static-return-lifetime-infered.rs:7:9 | LL | fn iter_values_anon(&self) -> impl Iterator { @@ -11,7 +11,7 @@ help: to declare that the `impl Trait` captures `'_`, you can add an explicit `' LL | fn iter_values_anon(&self) -> impl Iterator + '_ { | ++++ -error[E0700]: hidden type for `impl Iterator` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/static-return-lifetime-infered.rs:7:9 | LL | fn iter_values_anon(&self) -> impl Iterator { @@ -24,7 +24,7 @@ help: to declare that the `impl Trait` captures `'_`, you can add an explicit `' LL | fn iter_values_anon(&self) -> impl Iterator + '_ { | ++++ -error[E0700]: hidden type for `impl Iterator` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/static-return-lifetime-infered.rs:12:9 | LL | fn iter_values<'a>(&'a self) -> impl Iterator { @@ -37,7 +37,7 @@ help: to declare that the `impl Trait` captures `'a`, you can add an explicit `' LL | fn iter_values<'a>(&'a self) -> impl Iterator + 'a { | ++++ -error[E0700]: hidden type for `impl Iterator` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/static-return-lifetime-infered.rs:12:9 | LL | fn iter_values<'a>(&'a self) -> impl Iterator { diff --git a/src/test/ui/inference/deref-suggestion.rs b/src/test/ui/inference/deref-suggestion.rs index 0d8e7289dc8a2..4fd695585ba06 100644 --- a/src/test/ui/inference/deref-suggestion.rs +++ b/src/test/ui/inference/deref-suggestion.rs @@ -1,5 +1,5 @@ macro_rules! borrow { - ($x:expr) => { &$x } + ($x:expr) => { &$x } //~ ERROR mismatched types } fn foo(_: String) {} @@ -32,7 +32,6 @@ fn main() { foo(&mut "aaa".to_owned()); //~^ ERROR mismatched types foo3(borrow!(0)); - //~^ ERROR mismatched types foo4(&0); assert_eq!(3i32, &3i32); //~^ ERROR mismatched types diff --git a/src/test/ui/inference/deref-suggestion.stderr b/src/test/ui/inference/deref-suggestion.stderr index d729f2d682a61..e763e17e51786 100644 --- a/src/test/ui/inference/deref-suggestion.stderr +++ b/src/test/ui/inference/deref-suggestion.stderr @@ -70,10 +70,13 @@ LL + foo("aaa".to_owned()); | error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:34:10 + --> $DIR/deref-suggestion.rs:2:20 | +LL | ($x:expr) => { &$x } + | ^^^ expected `u32`, found `&{integer}` +... LL | foo3(borrow!(0)); - | ---- ^^^^^^^^^^ expected `u32`, found `&{integer}` + | ---- ---------- in this macro invocation | | | arguments to this function are incorrect | @@ -82,9 +85,10 @@ note: function defined here | LL | fn foo3(_: u32) {} | ^^^^ ------ + = note: this error originates in the macro `borrow` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:37:5 + --> $DIR/deref-suggestion.rs:36:5 | LL | assert_eq!(3i32, &3i32); | ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `&i32` @@ -92,7 +96,7 @@ LL | assert_eq!(3i32, &3i32); = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:40:17 + --> $DIR/deref-suggestion.rs:39:17 | LL | let s = S { u }; | ^ @@ -101,7 +105,7 @@ LL | let s = S { u }; | help: consider borrowing here: `u: &u` error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:42:20 + --> $DIR/deref-suggestion.rs:41:20 | LL | let s = S { u: u }; | ^ @@ -110,7 +114,7 @@ LL | let s = S { u: u }; | help: consider borrowing here: `&u` error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:45:17 + --> $DIR/deref-suggestion.rs:44:17 | LL | let r = R { i }; | ^ expected `u32`, found `&{integer}` @@ -121,7 +125,7 @@ LL | let r = R { i: *i }; | ++++ error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:47:20 + --> $DIR/deref-suggestion.rs:46:20 | LL | let r = R { i: i }; | ^ expected `u32`, found `&{integer}` @@ -132,7 +136,7 @@ LL | let r = R { i: *i }; | + error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:56:9 + --> $DIR/deref-suggestion.rs:55:9 | LL | b | ^ expected `i32`, found `&{integer}` @@ -143,7 +147,7 @@ LL | *b | + error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:64:9 + --> $DIR/deref-suggestion.rs:63:9 | LL | b | ^ expected `i32`, found `&{integer}` @@ -154,7 +158,7 @@ LL | *b | + error[E0308]: `if` and `else` have incompatible types - --> $DIR/deref-suggestion.rs:69:12 + --> $DIR/deref-suggestion.rs:68:12 | LL | let val = if true { | _______________- diff --git a/src/test/ui/inline-const/const-expr-generic-err.stderr b/src/test/ui/inline-const/const-expr-generic-err.stderr index fc0b6cc445164..db0d85a2d4e74 100644 --- a/src/test/ui/inline-const/const-expr-generic-err.stderr +++ b/src/test/ui/inline-const/const-expr-generic-err.stderr @@ -12,13 +12,13 @@ note: the above error was encountered while instantiating `fn foo::` LL | foo::(); | ^^^^^^^^^^^^ -error[E0080]: evaluation of `bar::<0>::{constant#0}` failed +error[E0080]: evaluation of `bar::<0_usize>::{constant#0}` failed --> $DIR/const-expr-generic-err.rs:9:13 | LL | const { N - 1 } | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow -note: the above error was encountered while instantiating `fn bar::<0>` +note: the above error was encountered while instantiating `fn bar::<0_usize>` --> $DIR/const-expr-generic-err.rs:14:5 | LL | bar::<0>(); diff --git a/src/test/ui/intrinsics/const-eval-select-bad.stderr b/src/test/ui/intrinsics/const-eval-select-bad.stderr index d65818234ef97..6103d6c6e3a6f 100644 --- a/src/test/ui/intrinsics/const-eval-select-bad.stderr +++ b/src/test/ui/intrinsics/const-eval-select-bad.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]: FnOnce<()>` is not satisfied +error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]: ~const FnOnce<()>` is not satisfied --> $DIR/const-eval-select-bad.rs:7:27 | LL | const_eval_select((), || {}, || {}); @@ -19,7 +19,7 @@ note: required by a bound in `const_eval_select` LL | F: ~const FnOnce, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` -error[E0277]: the trait bound `{integer}: FnOnce<()>` is not satisfied +error[E0277]: the trait bound `{integer}: ~const FnOnce<()>` is not satisfied --> $DIR/const-eval-select-bad.rs:9:27 | LL | const_eval_select((), 42, 0xDEADBEEF); diff --git a/src/test/ui/invalid/invalid-no-sanitize.stderr b/src/test/ui/invalid/invalid-no-sanitize.stderr index d328cafa00b93..5a92555eb322e 100644 --- a/src/test/ui/invalid/invalid-no-sanitize.stderr +++ b/src/test/ui/invalid/invalid-no-sanitize.stderr @@ -4,7 +4,7 @@ error: invalid argument for `no_sanitize` LL | #[no_sanitize(brontosaurus)] | ^^^^^^^^^^^^ | - = note: expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread` + = note: expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread` error: aborting due to previous error diff --git a/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr index 1ced1433fe955..bfe7bb2e10dcc 100644 --- a/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr +++ b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr @@ -50,13 +50,13 @@ error: arguments should be non-negative integers LL | #[rustc_legacy_const_generics(1, a, 2, b)] | ^ ^ -error: attribute should be applied to a function definition +error: attribute should be applied to a function --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:18:1 | LL | #[rustc_legacy_const_generics(0)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | struct S; - | --------- not a function definition + | --------- not a function error: #[rustc_legacy_const_generics] functions must only have const generics --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:29:1 @@ -66,21 +66,21 @@ LL | #[rustc_legacy_const_generics(0)] LL | fn foo8() {} | - non-const generic parameter -error: attribute should be applied to a function definition +error: attribute should be applied to a function --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:33:5 | LL | #[rustc_legacy_const_generics(0)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | fn foo9() {} - | ---------------------------- not a function definition + | ---------------------------- not a function -error: attribute should be applied to a function definition +error: attribute should be applied to a function --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:25:5 | LL | #[rustc_legacy_const_generics(1)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | fn foo7(); - | -------------------------- not a function definition + | -------------------------- not a function error[E0044]: foreign items may not have const parameters --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:26:5 diff --git a/src/test/ui/issues/issue-13497.stderr b/src/test/ui/issues/issue-13497.stderr index 4b1d979da36e3..6521a67428eb2 100644 --- a/src/test/ui/issues/issue-13497.stderr +++ b/src/test/ui/issues/issue-13497.stderr @@ -8,7 +8,7 @@ LL | &str help: consider using the `'static` lifetime | LL | &'static str - | +++++++ + | ~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-19707.stderr b/src/test/ui/issues/issue-19707.stderr index 3e1bb32c19b92..18f69bb57755a 100644 --- a/src/test/ui/issues/issue-19707.stderr +++ b/src/test/ui/issues/issue-19707.stderr @@ -22,6 +22,7 @@ LL | fn bar &u8>(f: &F) {} | --- --- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider making the bound lifetime-generic with a new `'a` lifetime | LL | fn bar Fn(&'a u8, &'a u8) -> &'a u8>(f: &F) {} diff --git a/src/test/ui/issues/issue-23041.stderr b/src/test/ui/issues/issue-23041.stderr index 6592b76a39f7a..7b9a1634a0d4c 100644 --- a/src/test/ui/issues/issue-23041.stderr +++ b/src/test/ui/issues/issue-23041.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | b.downcast_ref::_>(); | ^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `downcast_ref` | -help: consider specifying the generic argument +help: consider specifying the generic arguments | LL | b.downcast_ref:: _>(); | ~~~~~~~~~~~~~~ diff --git a/src/test/ui/issues/issue-24013.stderr b/src/test/ui/issues/issue-24013.stderr index 995dce552e37f..863993f450904 100644 --- a/src/test/ui/issues/issue-24013.stderr +++ b/src/test/ui/issues/issue-24013.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))}; | ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `swap` | -help: consider specifying the generic argument +help: consider specifying the generic arguments | LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))}; | ~~~~~~~~~~ diff --git a/src/test/ui/issues/issue-30255.stderr b/src/test/ui/issues/issue-30255.stderr index adb721a1cbaf1..e5f492af5b366 100644 --- a/src/test/ui/issues/issue-30255.stderr +++ b/src/test/ui/issues/issue-30255.stderr @@ -7,8 +7,8 @@ LL | fn f(a: &S, b: i32) -> &i32 { = help: this function's return type contains a borrowed value, but the signature does not say which one of `a`'s 2 lifetimes it is borrowed from help: consider introducing a named lifetime parameter | -LL | fn f<'a>(a: &'a S<'a>, b: i32) -> &'a i32 { - | ++++ ++ ++++ ++ +LL | fn f<'a>(a: &'a S, b: i32) -> &'a i32 { + | ++++ ++ ++ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:14:34 @@ -19,8 +19,8 @@ LL | fn g(a: &S, b: bool, c: &i32) -> &i32 { = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `a`'s 2 lifetimes or `c` help: consider introducing a named lifetime parameter | -LL | fn g<'a>(a: &'a S<'a>, b: bool, c: &'a i32) -> &'a i32 { - | ++++ ++ ++++ ++ ++ +LL | fn g<'a>(a: &'a S, b: bool, c: &'a i32) -> &'a i32 { + | ++++ ++ ++ ++ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:19:44 @@ -31,8 +31,8 @@ LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 { = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a`, one of `c`'s 2 lifetimes, or `d` help: consider introducing a named lifetime parameter | -LL | fn h<'a>(a: &'a bool, b: bool, c: &'a S<'a>, d: &'a i32) -> &'a i32 { - | ++++ ++ ++ ++++ ++ ++ +LL | fn h<'a>(a: &'a bool, b: bool, c: &'a S, d: &'a i32) -> &'a i32 { + | ++++ ++ ++ ++ ++ error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-30371.rs b/src/test/ui/issues/issue-30371.rs index a1ae9a36bc1d7..58521b95cf637 100644 --- a/src/test/ui/issues/issue-30371.rs +++ b/src/test/ui/issues/issue-30371.rs @@ -1,5 +1,6 @@ // run-pass #![allow(unreachable_code)] +#![allow(unused_mut)] // rust-lang/rust#54586 #![deny(unused_variables)] fn main() { diff --git a/src/test/ui/issues/issue-59494.stderr b/src/test/ui/issues/issue-59494.stderr index a9284535e4dc4..8b542bb69de2e 100644 --- a/src/test/ui/issues/issue-59494.stderr +++ b/src/test/ui/issues/issue-59494.stderr @@ -7,6 +7,8 @@ LL | let t8 = t8n(t7, t7p(f, g)); | required by a bound introduced by this call | = help: the trait `Fn<(_,)>` is not implemented for `impl Fn(((_, _), _))` + = note: expected a closure with arguments `(((_, _), _),)` + found a closure with arguments `(_,)` note: required by a bound in `t8n` --> $DIR/issue-59494.rs:5:45 | diff --git a/src/test/ui/issues/issue-72554.rs b/src/test/ui/issues/issue-72554.rs index 7287639c61dde..47aca05d7786f 100644 --- a/src/test/ui/issues/issue-72554.rs +++ b/src/test/ui/issues/issue-72554.rs @@ -1,13 +1,10 @@ use std::collections::BTreeSet; #[derive(Hash)] -pub enum ElemDerived { - //~^ ERROR recursive type `ElemDerived` has infinite size - //~| ERROR cycle detected when computing drop-check constraints for `ElemDerived` +pub enum ElemDerived { //~ ERROR recursive type `ElemDerived` has infinite size A(ElemDerived) } - pub enum Elem { Derived(ElemDerived) } diff --git a/src/test/ui/issues/issue-72554.stderr b/src/test/ui/issues/issue-72554.stderr index 3e5adcae133ca..a6e44be636a43 100644 --- a/src/test/ui/issues/issue-72554.stderr +++ b/src/test/ui/issues/issue-72554.stderr @@ -3,7 +3,6 @@ error[E0072]: recursive type `ElemDerived` has infinite size | LL | pub enum ElemDerived { | ^^^^^^^^^^^^^^^^^^^^ recursive type has infinite size -... LL | A(ElemDerived) | ----------- recursive without indirection | @@ -12,20 +11,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ElemDerived LL | A(Box) | ++++ + -error[E0391]: cycle detected when computing drop-check constraints for `ElemDerived` - --> $DIR/issue-72554.rs:4:1 - | -LL | pub enum ElemDerived { - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: ...which immediately requires computing drop-check constraints for `ElemDerived` again -note: cycle used when computing drop-check constraints for `Elem` - --> $DIR/issue-72554.rs:11:1 - | -LL | pub enum Elem { - | ^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/ui/issues/issue-77919.rs b/src/test/ui/issues/issue-77919.rs index 966d76d148af3..1d5d593073117 100644 --- a/src/test/ui/issues/issue-77919.rs +++ b/src/test/ui/issues/issue-77919.rs @@ -1,5 +1,6 @@ fn main() { [1; >::VAL]; + //~^ ERROR: constant expression depends on a generic parameter } trait TypeVal { const VAL: T; diff --git a/src/test/ui/issues/issue-77919.stderr b/src/test/ui/issues/issue-77919.stderr index ca256847b1f3b..b4c877a2d74a4 100644 --- a/src/test/ui/issues/issue-77919.stderr +++ b/src/test/ui/issues/issue-77919.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `PhantomData` in this scope - --> $DIR/issue-77919.rs:9:9 + --> $DIR/issue-77919.rs:10:9 | LL | _n: PhantomData, | ^^^^^^^^^^^ not found in this scope @@ -10,7 +10,7 @@ LL | use std::marker::PhantomData; | error[E0412]: cannot find type `VAL` in this scope - --> $DIR/issue-77919.rs:11:63 + --> $DIR/issue-77919.rs:12:63 | LL | impl TypeVal for Multiply where N: TypeVal {} | - ^^^ not found in this scope @@ -18,7 +18,7 @@ LL | impl TypeVal for Multiply where N: TypeVal {} | help: you might be missing a type parameter: `, VAL` error[E0046]: not all trait items implemented, missing: `VAL` - --> $DIR/issue-77919.rs:11:1 + --> $DIR/issue-77919.rs:12:1 | LL | const VAL: T; | ------------ `VAL` from trait @@ -26,7 +26,15 @@ LL | const VAL: T; LL | impl TypeVal for Multiply where N: TypeVal {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation -error: aborting due to 3 previous errors +error: constant expression depends on a generic parameter + --> $DIR/issue-77919.rs:2:9 + | +LL | [1; >::VAL]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 4 previous errors Some errors have detailed explanations: E0046, E0412. For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/kindck/kindck-copy.stderr b/src/test/ui/kindck/kindck-copy.stderr index 025a5008d0f11..1c61c85368be9 100644 --- a/src/test/ui/kindck/kindck-copy.stderr +++ b/src/test/ui/kindck/kindck-copy.stderr @@ -91,10 +91,10 @@ LL | fn assert_copy() { } | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Box: Copy` is not satisfied - --> $DIR/kindck-copy.rs:42:19 + --> $DIR/kindck-copy.rs:42:5 | LL | assert_copy::>(); - | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` | note: required by a bound in `assert_copy` --> $DIR/kindck-copy.rs:5:18 @@ -103,10 +103,10 @@ LL | fn assert_copy() { } | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Box: Copy` is not satisfied - --> $DIR/kindck-copy.rs:43:19 + --> $DIR/kindck-copy.rs:43:5 | LL | assert_copy::>(); - | ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` | note: required by a bound in `assert_copy` --> $DIR/kindck-copy.rs:5:18 diff --git a/src/test/ui/lifetimes/issue-26638.rs b/src/test/ui/lifetimes/issue-26638.rs index 000ab6492bb96..72fe4286a06b3 100644 --- a/src/test/ui/lifetimes/issue-26638.rs +++ b/src/test/ui/lifetimes/issue-26638.rs @@ -1,11 +1,8 @@ fn parse_type(iter: Box+'static>) -> &str { iter.next() } //~^ ERROR missing lifetime specifier [E0106] -//~| ERROR mismatched types fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() } //~^ ERROR missing lifetime specifier [E0106] -//~| ERROR mismatched types -//~| ERROR this function takes 1 argument but 0 arguments were supplied fn parse_type_3() -> &str { unimplemented!() } //~^ ERROR missing lifetime specifier [E0106] diff --git a/src/test/ui/lifetimes/issue-26638.stderr b/src/test/ui/lifetimes/issue-26638.stderr index f3af5cf5a3576..bb7cdcbb100ff 100644 --- a/src/test/ui/lifetimes/issue-26638.stderr +++ b/src/test/ui/lifetimes/issue-26638.stderr @@ -7,23 +7,23 @@ LL | fn parse_type(iter: Box+'static>) -> &str { iter.ne = help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from help: consider introducing a named lifetime parameter | -LL | fn parse_type<'a>(iter: Box+'static>) -> &'a str { iter.next() } - | ++++ ++ ++ +LL | fn parse_type<'a>(iter: Box+'static>) -> &'a str { iter.next() } + | ++++ ++ error[E0106]: missing lifetime specifier - --> $DIR/issue-26638.rs:5:40 + --> $DIR/issue-26638.rs:4:40 | LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() } | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments help: consider using the `'static` lifetime | LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &'static str { iter() } - | +++++++ + | ~~~~~~~~ error[E0106]: missing lifetime specifier - --> $DIR/issue-26638.rs:10:22 + --> $DIR/issue-26638.rs:7:22 | LL | fn parse_type_3() -> &str { unimplemented!() } | ^ expected named lifetime parameter @@ -32,42 +32,8 @@ LL | fn parse_type_3() -> &str { unimplemented!() } help: consider using the `'static` lifetime | LL | fn parse_type_3() -> &'static str { unimplemented!() } - | +++++++ - -error[E0308]: mismatched types - --> $DIR/issue-26638.rs:1:69 - | -LL | fn parse_type(iter: Box+'static>) -> &str { iter.next() } - | ---- ^^^^^^^^^^^ expected `&str`, found enum `Option` - | | - | expected `&'static str` because of return type - | - = note: expected reference `&'static str` - found enum `Option<&str>` - -error[E0061]: this function takes 1 argument but 0 arguments were supplied - --> $DIR/issue-26638.rs:5:47 - | -LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() } - | ^^^^-- an argument of type `&u8` is missing - | -help: provide the argument - | -LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter(/* &u8 */) } - | ~~~~~~~~~~~~~~~ - -error[E0308]: mismatched types - --> $DIR/issue-26638.rs:5:47 - | -LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() } - | ---- ^^^^^^ expected `str`, found `u8` - | | - | expected `&'static str` because of return type - | - = note: expected reference `&'static str` - found reference `&u8` + | ~~~~~~~~ -error: aborting due to 6 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0061, E0106, E0308. -For more information about an error, try `rustc --explain E0061`. +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr index d07754879559a..0e69cd50f6a82 100644 --- a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr +++ b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr @@ -8,7 +8,7 @@ LL | fn f() -> &isize { help: consider using the `'static` lifetime | LL | fn f() -> &'static isize { - | +++++++ + | ~~~~~~~~ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:33 @@ -31,8 +31,8 @@ LL | fn h(_x: &Foo) -> &isize { = help: this function's return type contains a borrowed value, but the signature does not say which one of `_x`'s 2 lifetimes it is borrowed from help: consider introducing a named lifetime parameter | -LL | fn h<'a>(_x: &'a Foo<'a>) -> &'a isize { - | ++++ ++ ++++ ++ +LL | fn h<'a>(_x: &'a Foo) -> &'a isize { + | ++++ ++ ++ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:21:20 @@ -40,11 +40,11 @@ error[E0106]: missing lifetime specifier LL | fn i(_x: isize) -> &isize { | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments help: consider using the `'static` lifetime | LL | fn i(_x: isize) -> &'static isize { - | +++++++ + | ~~~~~~~~ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:34:24 @@ -52,11 +52,11 @@ error[E0106]: missing lifetime specifier LL | fn j(_x: StaticStr) -> &isize { | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments help: consider using the `'static` lifetime | LL | fn j(_x: StaticStr) -> &'static isize { - | +++++++ + | ~~~~~~~~ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:40:49 @@ -64,11 +64,11 @@ error[E0106]: missing lifetime specifier LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &isize { | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments help: consider using the `'a` lifetime | LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &'a isize { - | ++ + | ~~~ error: aborting due to 6 previous errors diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs index d6c918843c700..d1263a4acb28a 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs +++ b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs @@ -2,4 +2,4 @@ fn foo(x: &i32, y: &i32) -> &i32 { //~ ERROR missing lifetime if x > y { x } else { y } } -fn main() {} +fn main() { } diff --git a/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr b/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr index b8c68a4607da8..b16b792aefee9 100644 --- a/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr +++ b/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr @@ -7,7 +7,7 @@ LL | type B<'a> = as Trait>::Foo; help: consider using the `'a` lifetime | LL | type B<'a> = as Trait<'a>>::Foo; - | ++++ + | ~~~~~~~~~ error[E0106]: missing lifetime specifier --> $DIR/missing-lifetime-in-alias.rs:26:28 @@ -20,10 +20,6 @@ note: these named lifetimes are available to use | LL | type C<'a, 'b> = as Trait>::Bar; | ^^ ^^ -help: consider using one of the available lifetimes here - | -LL | type C<'a, 'b> = as Trait<'lifetime>>::Bar; - | +++++++++++ error[E0107]: missing generics for associated type `Trait::Bar` --> $DIR/missing-lifetime-in-alias.rs:26:36 diff --git a/src/test/ui/linkage-attr/issue-10755.rs b/src/test/ui/linkage-attr/issue-10755.rs index afd2dc46ca3cb..5ce69bceed37a 100644 --- a/src/test/ui/linkage-attr/issue-10755.rs +++ b/src/test/ui/linkage-attr/issue-10755.rs @@ -1,10 +1,7 @@ // build-fail // dont-check-compiler-stderr // compile-flags: -C linker=llllll -C linker-flavor=ld -// error-pattern: `llllll` - -// Before, the error-pattern checked for "not found". On WSL with appendWindowsPath=true, running -// in invalid command returns a PermissionDenied instead. +// error-pattern: linker `llllll` not found fn main() { } diff --git a/src/test/ui/lint/function-item-references.stderr b/src/test/ui/lint/function-item-references.stderr index a9d18bb6a4743..33db687df31d2 100644 --- a/src/test/ui/lint/function-item-references.stderr +++ b/src/test/ui/lint/function-item-references.stderr @@ -116,7 +116,7 @@ warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:118:22 | LL | println!("{:p}", &take_generic_array::); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: cast `take_generic_array` to obtain a function pointer: `take_generic_array:: as fn(_)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: cast `take_generic_array` to obtain a function pointer: `take_generic_array:: as fn(_)` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:120:22 @@ -128,7 +128,7 @@ warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:122:22 | LL | println!("{:p}", &multiple_generic_arrays::); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: cast `multiple_generic_arrays` to obtain a function pointer: `multiple_generic_arrays:: as fn(_, _)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: cast `multiple_generic_arrays` to obtain a function pointer: `multiple_generic_arrays:: as fn(_, _)` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:124:22 diff --git a/src/test/ui/macros/format-args-temporaries-async.rs b/src/test/ui/macros/format-args-temporaries-async.rs deleted file mode 100644 index d959329b9fce2..0000000000000 --- a/src/test/ui/macros/format-args-temporaries-async.rs +++ /dev/null @@ -1,37 +0,0 @@ -// check-pass -// edition:2021 - -use std::fmt::{self, Display}; -use std::future::Future; -use std::io; -use std::pin::Pin; -use std::task::{Context, Poll}; - -struct AsyncStdout; - -impl AsyncStdout { - fn write_fmt<'a>(&'a mut self, _args: fmt::Arguments) -> WriteFmtFuture<'a, Self> - where - Self: Unpin, - { - WriteFmtFuture(self) - } -} - -struct WriteFmtFuture<'a, T>(&'a mut T); - -impl<'a, T> Future for WriteFmtFuture<'a, T> { - type Output = io::Result<()>; - fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { - unimplemented!() - } -} - -async fn async_main() { - let _write = write!(&mut AsyncStdout, "...").await; - let _writeln = writeln!(&mut AsyncStdout, "...").await; -} - -fn main() { - let _ = async_main; -} diff --git a/src/test/ui/macros/format-args-temporaries-in-write.rs b/src/test/ui/macros/format-args-temporaries-in-write.rs deleted file mode 100644 index 339ccbc33ac98..0000000000000 --- a/src/test/ui/macros/format-args-temporaries-in-write.rs +++ /dev/null @@ -1,50 +0,0 @@ -// check-fail - -use std::fmt::{self, Display}; - -struct Mutex; - -impl Mutex { - fn lock(&self) -> MutexGuard { - MutexGuard(self) - } -} - -struct MutexGuard<'a>(&'a Mutex); - -impl<'a> Drop for MutexGuard<'a> { - fn drop(&mut self) { - // Empty but this is a necessary part of the repro. Otherwise borrow - // checker is fine with 'a dangling at the time that MutexGuard goes out - // of scope. - } -} - -struct Out; - -impl Out { - fn write_fmt(&self, _args: fmt::Arguments) {} -} - -impl<'a> Display for MutexGuard<'a> { - fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { - Ok(()) - } -} - -fn main() { - // FIXME(dtolnay): We actually want both of these to work. I think it's - // sadly unimplementable today though. - - let _write = { - let mutex = Mutex; - write!(Out, "{}", mutex.lock()) /* no semicolon */ - //~^ ERROR `mutex` does not live long enough - }; - - let _writeln = { - let mutex = Mutex; - writeln!(Out, "{}", mutex.lock()) /* no semicolon */ - //~^ ERROR `mutex` does not live long enough - }; -} diff --git a/src/test/ui/macros/format-args-temporaries-in-write.stderr b/src/test/ui/macros/format-args-temporaries-in-write.stderr deleted file mode 100644 index 03ecc4b4418c6..0000000000000 --- a/src/test/ui/macros/format-args-temporaries-in-write.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0597]: `mutex` does not live long enough - --> $DIR/format-args-temporaries-in-write.rs:41:27 - | -LL | write!(Out, "{}", mutex.lock()) /* no semicolon */ - | ^^^^^^^^^^^^ - | | - | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... -LL | -LL | }; - | -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard` - | | - | `mutex` dropped here while still borrowed - | -help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped - --> $SRC_DIR/core/src/macros/mod.rs:LL:COL - | -LL | $dst.write_fmt($crate::format_args!($($arg)*)); - | + - -error[E0597]: `mutex` does not live long enough - --> $DIR/format-args-temporaries-in-write.rs:47:29 - | -LL | writeln!(Out, "{}", mutex.lock()) /* no semicolon */ - | ^^^^^^^^^^^^ - | | - | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... -LL | -LL | }; - | -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard` - | | - | `mutex` dropped here while still borrowed - | -help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped - --> $SRC_DIR/core/src/macros/mod.rs:LL:COL - | -LL | $dst.write_fmt($crate::format_args_nl!($($arg)*)); - | + - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/macros/format-args-temporaries.rs b/src/test/ui/macros/format-args-temporaries.rs index 59323828bc37f..ddd4c9754bfa4 100644 --- a/src/test/ui/macros/format-args-temporaries.rs +++ b/src/test/ui/macros/format-args-temporaries.rs @@ -20,6 +20,10 @@ impl<'a> Drop for MutexGuard<'a> { } } +impl<'a> MutexGuard<'a> { + fn write_fmt(&self, _args: fmt::Arguments) {} +} + impl<'a> Display for MutexGuard<'a> { fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { Ok(()) @@ -27,6 +31,18 @@ impl<'a> Display for MutexGuard<'a> { } fn main() { + let _write = { + let out = Mutex; + let mutex = Mutex; + write!(out.lock(), "{}", mutex.lock()) /* no semicolon */ + }; + + let _writeln = { + let out = Mutex; + let mutex = Mutex; + writeln!(out.lock(), "{}", mutex.lock()) /* no semicolon */ + }; + let _print = { let mutex = Mutex; print!("{}", mutex.lock()) /* no semicolon */ diff --git a/src/test/ui/macros/issue-98466.stderr b/src/test/ui/macros/issue-98466.stderr index 4a39dd1440b1f..ad11d181b6218 100644 --- a/src/test/ui/macros/issue-98466.stderr +++ b/src/test/ui/macros/issue-98466.stderr @@ -2,80 +2,80 @@ warning: named argument `_x` is not used by name --> $DIR/issue-98466.rs:7:26 | LL | println!("_x is {}", _x = 5); - | - ^^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `_x` by position + | -- ^^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `_x` by position | = note: `#[warn(named_arguments_used_positionally)]` on by default help: use the named argument by name to avoid ambiguity | LL | println!("_x is {_x}", _x = 5); - | ++ + | ~~~~ warning: named argument `y` is not used by name --> $DIR/issue-98466.rs:10:26 | LL | println!("_x is {}", y = _x); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `y` by position + | -- ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `y` by position | help: use the named argument by name to avoid ambiguity | LL | println!("_x is {y}", y = _x); - | + + | ~~~ warning: named argument `y` is not used by name --> $DIR/issue-98466.rs:13:83 | LL | println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `y` by position + | -- ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `y` by position | help: use the named argument by name to avoid ambiguity | LL | println!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x); - | + + | ~~~ warning: named argument `_x` is not used by name --> $DIR/issue-98466.rs:19:34 | LL | let _f = format!("_x is {}", _x = 5); - | - ^^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `_x` by position + | -- ^^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `_x` by position | help: use the named argument by name to avoid ambiguity | LL | let _f = format!("_x is {_x}", _x = 5); - | ++ + | ~~~~ warning: named argument `y` is not used by name --> $DIR/issue-98466.rs:22:34 | LL | let _f = format!("_x is {}", y = _x); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `y` by position + | -- ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `y` by position | help: use the named argument by name to avoid ambiguity | LL | let _f = format!("_x is {y}", y = _x); - | + + | ~~~ warning: named argument `y` is not used by name --> $DIR/issue-98466.rs:25:91 | LL | let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `y` by position + | -- ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `y` by position | help: use the named argument by name to avoid ambiguity | LL | let _f = format!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x); - | + + | ~~~ warning: 6 warnings emitted diff --git a/src/test/ui/macros/issue-99265.fixed b/src/test/ui/macros/issue-99265.fixed deleted file mode 100644 index f3be9c6285d6c..0000000000000 --- a/src/test/ui/macros/issue-99265.fixed +++ /dev/null @@ -1,139 +0,0 @@ -// check-pass -// run-rustfix - -fn main() { - println!("{b} {a}", a=1, b=2); - //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - - println!("{} {a} {b} {c} {d}", 0, a=1, b=2, c=3, d=4); - //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `d` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - - println!("Hello {:width$}!", "x", width = 5); - //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally - //~| HELP use the named argument by name to avoid ambiguity - - println!("Hello {f:width$.precision$}!", f = 0.02f32, width = 5, precision = 2); - //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally - //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - - println!("Hello {f:width$.precision$}!", f = 0.02f32, width = 5, precision = 2); - //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally - //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - - println!( - "{}, Hello {f:width$.precision$} {g:width2$.precision2$}! {f}", - //~^ HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - 1, - f = 0.02f32, - //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] - width = 5, - //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally - precision = 2, - //~^ WARNING named argument `precision` is not used by name [named_arguments_used_positionally] - g = 0.02f32, - //~^ WARNING named argument `g` is not used by name [named_arguments_used_positionally] - width2 = 5, - //~^ WARNING named argument `width2` is not used by name [named_arguments_used_positionally - precision2 = 2 - //~^ WARNING named argument `precision2` is not used by name [named_arguments_used_positionally] - ); - - println!("Hello {f:0.1}!", f = 0.02f32); - //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - - println!("Hello {f:0.1}!", f = 0.02f32); - //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - - println!("Hello {f:width$.precision$}!", f = 0.02f32, width = 5, precision = 2); - - let width = 5; - let precision = 2; - println!("Hello {f:width$.precision$}!", f = 0.02f32); - - let val = 5; - println!("{v:v$}", v = val); - //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - println!("{v:v$}", v = val); - //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - println!("{v:v$.v$}", v = val); - //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - println!("{v:v$.v$}", v = val); - //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - - println!("{a} {a} {a}", a = 1); - //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `a` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - - println!("aaaaaaaaaaaaaaa\ - {a:b$.c$}", - //~^ HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - a = 1.0, b = 1, c = 2, - //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] - ); - - println!("aaaaaaaaaaaaaaa\ - {a:b$.c$}", - //~^ HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - a = 1.0, b = 1, c = 2, - //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] - ); - - println!("{{{x:width$.precision$}}}", x = 1.0, width = 3, precision = 2); - //~^ WARNING named argument `x` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `width` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity -} diff --git a/src/test/ui/macros/issue-99265.rs b/src/test/ui/macros/issue-99265.rs deleted file mode 100644 index e7cf608765b0d..0000000000000 --- a/src/test/ui/macros/issue-99265.rs +++ /dev/null @@ -1,139 +0,0 @@ -// check-pass -// run-rustfix - -fn main() { - println!("{b} {}", a=1, b=2); - //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - - println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4); - //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `d` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - - println!("Hello {:1$}!", "x", width = 5); - //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally - //~| HELP use the named argument by name to avoid ambiguity - - println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2); - //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally - //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - - println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2); - //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally - //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - - println!( - "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", - //~^ HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - 1, - f = 0.02f32, - //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] - width = 5, - //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally - precision = 2, - //~^ WARNING named argument `precision` is not used by name [named_arguments_used_positionally] - g = 0.02f32, - //~^ WARNING named argument `g` is not used by name [named_arguments_used_positionally] - width2 = 5, - //~^ WARNING named argument `width2` is not used by name [named_arguments_used_positionally - precision2 = 2 - //~^ WARNING named argument `precision2` is not used by name [named_arguments_used_positionally] - ); - - println!("Hello {:0.1}!", f = 0.02f32); - //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - - println!("Hello {0:0.1}!", f = 0.02f32); - //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - - println!("Hello {f:width$.precision$}!", f = 0.02f32, width = 5, precision = 2); - - let width = 5; - let precision = 2; - println!("Hello {f:width$.precision$}!", f = 0.02f32); - - let val = 5; - println!("{:0$}", v = val); - //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - println!("{0:0$}", v = val); - //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - println!("{:0$.0$}", v = val); - //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - println!("{0:0$.0$}", v = val); - //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - - println!("{} {a} {0}", a = 1); - //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `a` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - - println!("aaaaaaaaaaaaaaa\ - {:1$.2$}", - //~^ HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - a = 1.0, b = 1, c = 2, - //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] - ); - - println!("aaaaaaaaaaaaaaa\ - {0:1$.2$}", - //~^ HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - a = 1.0, b = 1, c = 2, - //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] - ); - - println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2); - //~^ WARNING named argument `x` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `width` is not used by name [named_arguments_used_positionally] - //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity - //~| HELP use the named argument by name to avoid ambiguity -} diff --git a/src/test/ui/macros/issue-99265.stderr b/src/test/ui/macros/issue-99265.stderr deleted file mode 100644 index 0798ad8dc517c..0000000000000 --- a/src/test/ui/macros/issue-99265.stderr +++ /dev/null @@ -1,562 +0,0 @@ -warning: named argument `a` is not used by name - --> $DIR/issue-99265.rs:5:24 - | -LL | println!("{b} {}", a=1, b=2); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `a` by position - | - = note: `#[warn(named_arguments_used_positionally)]` on by default -help: use the named argument by name to avoid ambiguity - | -LL | println!("{b} {a}", a=1, b=2); - | + - -warning: named argument `a` is not used by name - --> $DIR/issue-99265.rs:9:35 - | -LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `a` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{} {a} {} {} {}", 0, a=1, b=2, c=3, d=4); - | + - -warning: named argument `b` is not used by name - --> $DIR/issue-99265.rs:9:40 - | -LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `b` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{} {} {b} {} {}", 0, a=1, b=2, c=3, d=4); - | + - -warning: named argument `c` is not used by name - --> $DIR/issue-99265.rs:9:45 - | -LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `c` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{} {} {} {c} {}", 0, a=1, b=2, c=3, d=4); - | + - -warning: named argument `d` is not used by name - --> $DIR/issue-99265.rs:9:50 - | -LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `d` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{} {} {} {} {d}", 0, a=1, b=2, c=3, d=4); - | + - -warning: named argument `width` is not used by name - --> $DIR/issue-99265.rs:19:35 - | -LL | println!("Hello {:1$}!", "x", width = 5); - | -- ^^^^^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `width$` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("Hello {:width$}!", "x", width = 5); - | ~~~~~~ - -warning: named argument `width` is not used by name - --> $DIR/issue-99265.rs:23:46 - | -LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2); - | -- ^^^^^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `width$` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("Hello {:width$.2$}!", f = 0.02f32, width = 5, precision = 2); - | ~~~~~~ - -warning: named argument `precision` is not used by name - --> $DIR/issue-99265.rs:23:57 - | -LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2); - | -- ^^^^^^^^^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `precision$` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("Hello {:1$.precision$}!", f = 0.02f32, width = 5, precision = 2); - | ~~~~~~~~~~ - -warning: named argument `f` is not used by name - --> $DIR/issue-99265.rs:23:33 - | -LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `f` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("Hello {f:1$.2$}!", f = 0.02f32, width = 5, precision = 2); - | + - -warning: named argument `width` is not used by name - --> $DIR/issue-99265.rs:31:47 - | -LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2); - | -- ^^^^^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `width$` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("Hello {0:width$.2$}!", f = 0.02f32, width = 5, precision = 2); - | ~~~~~~ - -warning: named argument `precision` is not used by name - --> $DIR/issue-99265.rs:31:58 - | -LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2); - | -- ^^^^^^^^^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `precision$` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("Hello {0:1$.precision$}!", f = 0.02f32, width = 5, precision = 2); - | ~~~~~~~~~~ - -warning: named argument `f` is not used by name - --> $DIR/issue-99265.rs:31:34 - | -LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `f` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("Hello {f:1$.2$}!", f = 0.02f32, width = 5, precision = 2); - | ~ - -warning: named argument `width` is not used by name - --> $DIR/issue-99265.rs:52:9 - | -LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", - | -- this formatting argument uses named argument `width$` by position -... -LL | width = 5, - | ^^^^^ this named argument is only referred to by position in formatting string - | -help: use the named argument by name to avoid ambiguity - | -LL | "{}, Hello {1:width$.3$} {4:5$.6$}! {1}", - | ~~~~~~ - -warning: named argument `precision` is not used by name - --> $DIR/issue-99265.rs:54:9 - | -LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", - | -- this formatting argument uses named argument `precision$` by position -... -LL | precision = 2, - | ^^^^^^^^^ this named argument is only referred to by position in formatting string - | -help: use the named argument by name to avoid ambiguity - | -LL | "{}, Hello {1:2$.precision$} {4:5$.6$}! {1}", - | ~~~~~~~~~~ - -warning: named argument `f` is not used by name - --> $DIR/issue-99265.rs:49:9 - | -LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", - | - this formatting argument uses named argument `f` by position -... -LL | f = 0.02f32, - | ^ this named argument is only referred to by position in formatting string - | -help: use the named argument by name to avoid ambiguity - | -LL | "{}, Hello {f:2$.3$} {4:5$.6$}! {1}", - | ~ - -warning: named argument `width2` is not used by name - --> $DIR/issue-99265.rs:58:9 - | -LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", - | -- this formatting argument uses named argument `width2$` by position -... -LL | width2 = 5, - | ^^^^^^ this named argument is only referred to by position in formatting string - | -help: use the named argument by name to avoid ambiguity - | -LL | "{}, Hello {1:2$.3$} {4:width2$.6$}! {1}", - | ~~~~~~~ - -warning: named argument `precision2` is not used by name - --> $DIR/issue-99265.rs:60:9 - | -LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", - | -- this formatting argument uses named argument `precision2$` by position -... -LL | precision2 = 2 - | ^^^^^^^^^^ this named argument is only referred to by position in formatting string - | -help: use the named argument by name to avoid ambiguity - | -LL | "{}, Hello {1:2$.3$} {4:5$.precision2$}! {1}", - | ~~~~~~~~~~~ - -warning: named argument `g` is not used by name - --> $DIR/issue-99265.rs:56:9 - | -LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", - | - this formatting argument uses named argument `g` by position -... -LL | g = 0.02f32, - | ^ this named argument is only referred to by position in formatting string - | -help: use the named argument by name to avoid ambiguity - | -LL | "{}, Hello {1:2$.3$} {g:5$.6$}! {1}", - | ~ - -warning: named argument `f` is not used by name - --> $DIR/issue-99265.rs:49:9 - | -LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", - | - this formatting argument uses named argument `f` by position -... -LL | f = 0.02f32, - | ^ this named argument is only referred to by position in formatting string - | -help: use the named argument by name to avoid ambiguity - | -LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {f}", - | ~ - -warning: named argument `f` is not used by name - --> $DIR/issue-99265.rs:64:31 - | -LL | println!("Hello {:0.1}!", f = 0.02f32); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `f` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("Hello {f:0.1}!", f = 0.02f32); - | + - -warning: named argument `f` is not used by name - --> $DIR/issue-99265.rs:68:32 - | -LL | println!("Hello {0:0.1}!", f = 0.02f32); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `f` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("Hello {f:0.1}!", f = 0.02f32); - | ~ - -warning: named argument `v` is not used by name - --> $DIR/issue-99265.rs:79:23 - | -LL | println!("{:0$}", v = val); - | -- ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `v$` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{:v$}", v = val); - | ~~ - -warning: named argument `v` is not used by name - --> $DIR/issue-99265.rs:79:23 - | -LL | println!("{:0$}", v = val); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `v` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{v:0$}", v = val); - | + - -warning: named argument `v` is not used by name - --> $DIR/issue-99265.rs:84:24 - | -LL | println!("{0:0$}", v = val); - | -- ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `v$` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{0:v$}", v = val); - | ~~ - -warning: named argument `v` is not used by name - --> $DIR/issue-99265.rs:84:24 - | -LL | println!("{0:0$}", v = val); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `v` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{v:0$}", v = val); - | ~ - -warning: named argument `v` is not used by name - --> $DIR/issue-99265.rs:89:26 - | -LL | println!("{:0$.0$}", v = val); - | -- ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `v$` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{:v$.0$}", v = val); - | ~~ - -warning: named argument `v` is not used by name - --> $DIR/issue-99265.rs:89:26 - | -LL | println!("{:0$.0$}", v = val); - | -- ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `v$` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{:0$.v$}", v = val); - | ~~ - -warning: named argument `v` is not used by name - --> $DIR/issue-99265.rs:89:26 - | -LL | println!("{:0$.0$}", v = val); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `v` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{v:0$.0$}", v = val); - | + - -warning: named argument `v` is not used by name - --> $DIR/issue-99265.rs:96:27 - | -LL | println!("{0:0$.0$}", v = val); - | -- ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `v$` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{0:v$.0$}", v = val); - | ~~ - -warning: named argument `v` is not used by name - --> $DIR/issue-99265.rs:96:27 - | -LL | println!("{0:0$.0$}", v = val); - | -- ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `v$` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{0:0$.v$}", v = val); - | ~~ - -warning: named argument `v` is not used by name - --> $DIR/issue-99265.rs:96:27 - | -LL | println!("{0:0$.0$}", v = val); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `v` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{v:0$.0$}", v = val); - | ~ - -warning: named argument `a` is not used by name - --> $DIR/issue-99265.rs:104:28 - | -LL | println!("{} {a} {0}", a = 1); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `a` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{a} {a} {0}", a = 1); - | + - -warning: named argument `a` is not used by name - --> $DIR/issue-99265.rs:104:28 - | -LL | println!("{} {a} {0}", a = 1); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `a` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{} {a} {a}", a = 1); - | ~ - -warning: named argument `b` is not used by name - --> $DIR/issue-99265.rs:115:23 - | -LL | {:1$.2$}", - | -- this formatting argument uses named argument `b$` by position -... -LL | a = 1.0, b = 1, c = 2, - | ^ this named argument is only referred to by position in formatting string - | -help: use the named argument by name to avoid ambiguity - | -LL | {:b$.2$}", - | ~~ - -warning: named argument `c` is not used by name - --> $DIR/issue-99265.rs:115:30 - | -LL | {:1$.2$}", - | -- this formatting argument uses named argument `c$` by position -... -LL | a = 1.0, b = 1, c = 2, - | ^ this named argument is only referred to by position in formatting string - | -help: use the named argument by name to avoid ambiguity - | -LL | {:1$.c$}", - | ~~ - -warning: named argument `a` is not used by name - --> $DIR/issue-99265.rs:115:14 - | -LL | {:1$.2$}", - | - this formatting argument uses named argument `a` by position -... -LL | a = 1.0, b = 1, c = 2, - | ^ this named argument is only referred to by position in formatting string - | -help: use the named argument by name to avoid ambiguity - | -LL | {a:1$.2$}", - | + - -warning: named argument `b` is not used by name - --> $DIR/issue-99265.rs:126:23 - | -LL | {0:1$.2$}", - | -- this formatting argument uses named argument `b$` by position -... -LL | a = 1.0, b = 1, c = 2, - | ^ this named argument is only referred to by position in formatting string - | -help: use the named argument by name to avoid ambiguity - | -LL | {0:b$.2$}", - | ~~ - -warning: named argument `c` is not used by name - --> $DIR/issue-99265.rs:126:30 - | -LL | {0:1$.2$}", - | -- this formatting argument uses named argument `c$` by position -... -LL | a = 1.0, b = 1, c = 2, - | ^ this named argument is only referred to by position in formatting string - | -help: use the named argument by name to avoid ambiguity - | -LL | {0:1$.c$}", - | ~~ - -warning: named argument `a` is not used by name - --> $DIR/issue-99265.rs:126:14 - | -LL | {0:1$.2$}", - | - this formatting argument uses named argument `a` by position -... -LL | a = 1.0, b = 1, c = 2, - | ^ this named argument is only referred to by position in formatting string - | -help: use the named argument by name to avoid ambiguity - | -LL | {a:1$.2$}", - | ~ - -warning: named argument `width` is not used by name - --> $DIR/issue-99265.rs:132:39 - | -LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2); - | -- ^^^^^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `width$` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{{{:width$.2$}}}", x = 1.0, width = 3, precision = 2); - | ~~~~~~ - -warning: named argument `precision` is not used by name - --> $DIR/issue-99265.rs:132:50 - | -LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2); - | -- ^^^^^^^^^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `precision$` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{{{:1$.precision$}}}", x = 1.0, width = 3, precision = 2); - | ~~~~~~~~~~ - -warning: named argument `x` is not used by name - --> $DIR/issue-99265.rs:132:30 - | -LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2); - | - ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `x` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{{{x:1$.2$}}}", x = 1.0, width = 3, precision = 2); - | + - -warning: 42 warnings emitted - diff --git a/src/test/ui/macros/meta-variable-depth-outside-repeat.rs b/src/test/ui/macros/meta-variable-depth-outside-repeat.rs deleted file mode 100644 index b7fb947854f04..0000000000000 --- a/src/test/ui/macros/meta-variable-depth-outside-repeat.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![feature(macro_metavar_expr)] - -macro_rules! metavar { - ( $i:expr ) => { - ${length(0)} - //~^ ERROR meta-variable expression `length` with depth parameter must be called inside of a macro repetition - }; -} - -const _: i32 = metavar!(0); - -fn main() {} diff --git a/src/test/ui/macros/meta-variable-depth-outside-repeat.stderr b/src/test/ui/macros/meta-variable-depth-outside-repeat.stderr deleted file mode 100644 index fad150cadfca6..0000000000000 --- a/src/test/ui/macros/meta-variable-depth-outside-repeat.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: meta-variable expression `length` with depth parameter must be called inside of a macro repetition - --> $DIR/meta-variable-depth-outside-repeat.rs:5:10 - | -LL | ${length(0)} - | ^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs index 6a0d68bd6b16a..d81c8628bab26 100644 --- a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs +++ b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs @@ -5,7 +5,7 @@ macro_rules! a { ( ${count(foo, 0)}, ${count(foo, 10)}, - //~^ ERROR depth parameter on meta-variable expression `count` must be less than 4 + //~^ ERROR count depth must be less than 4 ) }; } @@ -17,7 +17,7 @@ macro_rules! b { ${ignore(foo)} ${index(0)}, ${index(10)}, - //~^ ERROR depth parameter on meta-variable expression `index` must be less than 3 + //~^ ERROR index depth must be less than 3 )* )* )* ) }; @@ -30,14 +30,15 @@ macro_rules! c { ${ignore(foo)} ${length(0)} ${length(10)} - //~^ ERROR depth parameter on meta-variable expression `length` must be less than 2 + //~^ ERROR length depth must be less than 2 )* )* ) }; } + fn main() { a!( { [ (a) ] [ (b c) ] } ); b!( { [ a b ] } ); - c!({ a }); + c!( { a } ); } diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr index 236122b6465b2..7474c03c0f98b 100644 --- a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr +++ b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr @@ -1,16 +1,16 @@ -error: depth parameter on meta-variable expression `count` must be less than 4 +error: count depth must be less than 4 --> $DIR/out-of-bounds-arguments.rs:7:14 | LL | ${count(foo, 10)}, | ^^^^^^^^^^^^^^^^ -error: depth parameter on meta-variable expression `index` must be less than 3 +error: index depth must be less than 3 --> $DIR/out-of-bounds-arguments.rs:19:18 | LL | ${index(10)}, | ^^^^^^^^^^^ -error: depth parameter on meta-variable expression `length` must be less than 2 +error: length depth must be less than 2 --> $DIR/out-of-bounds-arguments.rs:32:18 | LL | ${length(10)} diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.rs b/src/test/ui/methods/method-not-found-generic-arg-elision.rs index 799ced5e9c460..3df928b5d804d 100644 --- a/src/test/ui/methods/method-not-found-generic-arg-elision.rs +++ b/src/test/ui/methods/method-not-found-generic-arg-elision.rs @@ -61,13 +61,13 @@ impl Other { fn other(&self) {} } -struct Struct { - _phatom: PhantomData, +struct Struct{ + _phatom: PhantomData } impl Default for Struct { fn default() -> Self { - Self { _phatom: PhantomData } + Self{ _phatom: PhantomData } } } @@ -76,9 +76,9 @@ impl Struct { } fn main() { - let point_f64 = Point { x: 1_f64, y: 1_f64 }; + let point_f64 = Point{ x: 1_f64, y: 1_f64}; let d = point_f64.distance(); - let point_i32 = Point { x: 1_i32, y: 1_i32 }; + let point_i32 = Point{ x: 1_i32, y: 1_i32}; let d = point_i32.distance(); //~^ ERROR no method named `distance` found for struct `Point let d = point_i32.other(); @@ -92,9 +92,9 @@ fn main() { wrapper.other(); //~^ ERROR no method named `other` found for struct `Wrapper let boolean = true; - let wrapper = Wrapper2::<'_, _, 3> { x: &boolean }; + let wrapper = Wrapper2::<'_, _, 3> {x: &boolean}; wrapper.method(); - //~^ ERROR no method named `method` found for struct `Wrapper2<'_, bool, 3> + //~^ ERROR no method named `method` found for struct `Wrapper2<'_, bool, 3_usize> wrapper.other(); //~^ ERROR no method named `other` found for struct `Wrapper2 let a = vec![1, 2, 3]; diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.stderr b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr index fc42d1a4dcd08..56e1b5a0f4473 100644 --- a/src/test/ui/methods/method-not-found-generic-arg-elision.stderr +++ b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr @@ -50,14 +50,14 @@ LL | struct Wrapper(T); LL | wrapper.other(); | ^^^^^ method not found in `Wrapper` -error[E0599]: no method named `method` found for struct `Wrapper2<'_, bool, 3>` in the current scope +error[E0599]: no method named `method` found for struct `Wrapper2<'_, bool, 3_usize>` in the current scope --> $DIR/method-not-found-generic-arg-elision.rs:96:13 | LL | struct Wrapper2<'a, T, const C: usize> { | -------------------------------------- method `method` not found for this struct ... LL | wrapper.method(); - | ^^^^^^ method not found in `Wrapper2<'_, bool, 3>` + | ^^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>` | = note: the method was found for - `Wrapper2<'a, i8, C>` @@ -71,7 +71,7 @@ LL | struct Wrapper2<'a, T, const C: usize> { | -------------------------------------- method `other` not found for this struct ... LL | wrapper.other(); - | ^^^^^ method not found in `Wrapper2<'_, bool, 3>` + | ^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>` error[E0599]: no method named `not_found` found for struct `Vec<{integer}>` in the current scope --> $DIR/method-not-found-generic-arg-elision.rs:101:7 @@ -82,7 +82,7 @@ LL | a.not_found(); error[E0599]: the method `method` exists for struct `Struct`, but its trait bounds were not satisfied --> $DIR/method-not-found-generic-arg-elision.rs:104:7 | -LL | struct Struct { +LL | struct Struct{ | ---------------- method `method` not found for this struct ... LL | s.method(); diff --git a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs index c7842667dc614..6aa34354a7ad9 100644 --- a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs +++ b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs @@ -9,7 +9,6 @@ impl> Iterator for ChunkingIterator { type Item = IteratorChunk; //~ ERROR missing lifetime fn next(&mut self) -> Option> { - //~^ ERROR `impl` item signature doesn't match `trait` item signature todo!() } } diff --git a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr index 94a9c97576f67..c7e1f87f2d4d4 100644 --- a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr +++ b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr @@ -1,30 +1,14 @@ error[E0106]: missing lifetime specifier - --> $DIR/issue-74918-missing-lifetime.rs:9:30 + --> $DIR/issue-74918-missing-lifetime.rs:9:31 | LL | type Item = IteratorChunk; - | ^ expected named lifetime parameter + | ^ expected named lifetime parameter | help: consider introducing a named lifetime parameter | LL | type Item<'a> = IteratorChunk<'a, T, S>; | ++++ +++ -error: `impl` item signature doesn't match `trait` item signature - --> $DIR/issue-74918-missing-lifetime.rs:11:5 - | -LL | fn next(&mut self) -> Option> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 mut ChunkingIterator) -> Option>` - | - ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL - | -LL | fn next(&mut self) -> Option; - | ----------------------------------------- expected `fn(&'1 mut ChunkingIterator) -> Option>` - | - = note: expected `fn(&'1 mut ChunkingIterator) -> Option>` - found `fn(&'1 mut ChunkingIterator) -> Option>` - = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` - = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.fixed b/src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.fixed deleted file mode 100644 index 63b65ab20fea8..0000000000000 --- a/src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.fixed +++ /dev/null @@ -1,17 +0,0 @@ -// run-rustfix - -macro_rules! my_wrapper { - ($expr:expr) => { MyWrapper($expr) } -} - -pub struct MyWrapper(u32); - -fn main() { - let value = MyWrapper(123); - some_fn(value); //~ ERROR mismatched types - some_fn(my_wrapper!(123)); //~ ERROR mismatched types -} - -fn some_fn(wrapped: MyWrapper) { - drop(wrapped); -} diff --git a/src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.rs b/src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.rs deleted file mode 100644 index 2ab4e3955f336..0000000000000 --- a/src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.rs +++ /dev/null @@ -1,17 +0,0 @@ -// run-rustfix - -macro_rules! my_wrapper { - ($expr:expr) => { MyWrapper($expr) } -} - -pub struct MyWrapper(u32); - -fn main() { - let value = MyWrapper(123); - some_fn(value.0); //~ ERROR mismatched types - some_fn(my_wrapper!(123).0); //~ ERROR mismatched types -} - -fn some_fn(wrapped: MyWrapper) { - drop(wrapped); -} diff --git a/src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.stderr b/src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.stderr deleted file mode 100644 index 82a7f276372c9..0000000000000 --- a/src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.stderr +++ /dev/null @@ -1,41 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/suggest-removing-tulpe-struct-field.rs:11:13 - | -LL | some_fn(value.0); - | ------- ^^^^^^^ expected struct `MyWrapper`, found `u32` - | | - | arguments to this function are incorrect - | -note: function defined here - --> $DIR/suggest-removing-tulpe-struct-field.rs:15:4 - | -LL | fn some_fn(wrapped: MyWrapper) { - | ^^^^^^^ ------------------ -help: consider removing the tuple struct field `0` - | -LL - some_fn(value.0); -LL + some_fn(value); - | - -error[E0308]: mismatched types - --> $DIR/suggest-removing-tulpe-struct-field.rs:12:13 - | -LL | some_fn(my_wrapper!(123).0); - | ------- ^^^^^^^^^^^^^^^^^^ expected struct `MyWrapper`, found `u32` - | | - | arguments to this function are incorrect - | -note: function defined here - --> $DIR/suggest-removing-tulpe-struct-field.rs:15:4 - | -LL | fn some_fn(wrapped: MyWrapper) { - | ^^^^^^^ ------------------ -help: consider removing the tuple struct field `0` - | -LL - some_fn(my_wrapper!(123).0); -LL + some_fn(my_wrapper!(123)); - | - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/nll/issue-73159-rpit-static.stderr b/src/test/ui/nll/issue-73159-rpit-static.stderr index 260b9b59772ef..ab0dfe5fca41c 100644 --- a/src/test/ui/nll/issue-73159-rpit-static.stderr +++ b/src/test/ui/nll/issue-73159-rpit-static.stderr @@ -1,4 +1,4 @@ -error[E0700]: hidden type for `impl Iterator` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/issue-73159-rpit-static.rs:8:9 | LL | impl<'a> Foo<'a> { diff --git a/src/test/ui/nll/trait-associated-constant.rs b/src/test/ui/nll/trait-associated-constant.rs index e13ae80f918b2..31dc58185e90a 100644 --- a/src/test/ui/nll/trait-associated-constant.rs +++ b/src/test/ui/nll/trait-associated-constant.rs @@ -19,7 +19,7 @@ struct FailStruct { } impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct { const AC: Option<&'c str> = None; - //~^ ERROR: const not compatible with trait + //~^ ERROR: mismatched types } struct OKStruct2 { } diff --git a/src/test/ui/nll/trait-associated-constant.stderr b/src/test/ui/nll/trait-associated-constant.stderr index ae0ffd904e799..000ebc716572a 100644 --- a/src/test/ui/nll/trait-associated-constant.stderr +++ b/src/test/ui/nll/trait-associated-constant.stderr @@ -1,4 +1,4 @@ -error[E0308]: const not compatible with trait +error[E0308]: mismatched types --> $DIR/trait-associated-constant.rs:21:5 | LL | const AC: Option<&'c str> = None; diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr index 330c6fafa2d61..06256ebbc29a3 100644 --- a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr +++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr @@ -1,4 +1,4 @@ -error[E0700]: hidden type for `Opaque(DefId(0:11 ~ impl_trait_captures[1afc]::foo::{opaque#0}), [ReStatic, T, ReEarlyBound(0, 'a)])` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/impl-trait-captures.rs:11:5 | LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { diff --git a/src/test/ui/not-panic/not-panic-safe.stderr b/src/test/ui/not-panic/not-panic-safe.stderr index 2cd51a439988d..3e54df12376ba 100644 --- a/src/test/ui/not-panic/not-panic-safe.stderr +++ b/src/test/ui/not-panic/not-panic-safe.stderr @@ -1,11 +1,8 @@ error[E0277]: the type `&mut i32` may not be safely transferred across an unwind boundary - --> $DIR/not-panic-safe.rs:8:14 + --> $DIR/not-panic-safe.rs:8:5 | LL | assert::<&mut i32>(); - | -^^^^^^^ - | | - | `&mut i32` may not be safely transferred across an unwind boundary - | help: consider removing the leading `&`-reference + | ^^^^^^^^^^^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary | = help: the trait `UnwindSafe` is not implemented for `&mut i32` = note: `UnwindSafe` is implemented for `&i32`, but not for `&mut i32` diff --git a/src/test/ui/panic-handler/weak-lang-item.stderr b/src/test/ui/panic-handler/weak-lang-item.stderr index 202f3309d035e..cc25f08e33a80 100644 --- a/src/test/ui/panic-handler/weak-lang-item.stderr +++ b/src/test/ui/panic-handler/weak-lang-item.stderr @@ -10,13 +10,13 @@ help: you can use `as` to change the binding name of the import LL | extern crate core as other_core; | -error: `#[panic_handler]` function required, but not found - error: language item required, but not found: `eh_personality` | = note: this can occur when a binary crate with `#![no_std]` is compiled for a target where `eh_personality` is defined in the standard library = help: you may be able to compile for a target that doesn't need `eh_personality`, specify a target with `--target` or in `.cargo/config` +error: `#[panic_handler]` function required, but not found + error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0259`. diff --git a/src/test/ui/process/nofile-limit.rs b/src/test/ui/process/nofile-limit.rs index 3ddf8d6ef2405..549135a46cf10 100644 --- a/src/test/ui/process/nofile-limit.rs +++ b/src/test/ui/process/nofile-limit.rs @@ -6,7 +6,7 @@ // dont-check-compiler-stderr // only-linux // no-prefer-dynamic -// compile-flags: -Ctarget-feature=+crt-static -Crpath=no -Crelocation-model=static +// compile-flags: -Ctarget-feature=+crt-static -Crpath=no #![feature(exit_status_error)] #![feature(rustc_private)] extern crate libc; diff --git a/src/test/ui/process/process-spawn-nonexistent.rs b/src/test/ui/process/process-spawn-nonexistent.rs index a513722639adb..70de7316a8170 100644 --- a/src/test/ui/process/process-spawn-nonexistent.rs +++ b/src/test/ui/process/process-spawn-nonexistent.rs @@ -6,11 +6,9 @@ use std::io::ErrorKind; use std::process::Command; fn main() { - let result = Command::new("nonexistent").spawn().unwrap_err().kind(); - - assert!(matches!( - result, - // Under WSL with appendWindowsPath=true, this fails with PermissionDenied - ErrorKind::NotFound | ErrorKind::PermissionDenied - )); + assert_eq!(Command::new("nonexistent") + .spawn() + .unwrap_err() + .kind(), + ErrorKind::NotFound); } diff --git a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs index c377ecea94d0c..4397baea4a940 100644 --- a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs +++ b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs @@ -2,5 +2,5 @@ fn main() {} trait Foo { fn fn_with_type_named_same_as_local_in_param(b: b); - //~^ ERROR cannot find type `b` in this scope [E0412] + //~^ ERROR cannot find type `b` in this scope } diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs index 2bc5ee512c52f..8df68225d44cd 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs @@ -3,6 +3,7 @@ pub const fn equals_self(t: &T) -> bool { *t == *t //~^ ERROR can't compare + //~| ERROR cannot call non-const } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr index 83d395dda196a..cf114334cc391 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr @@ -1,16 +1,28 @@ -error[E0277]: can't compare `T` with `_` in const contexts - --> $DIR/call-generic-method-fail.rs:4:8 +error[E0277]: can't compare `T` with `T` in const contexts + --> $DIR/call-generic-method-fail.rs:4:5 | LL | *t == *t - | ^^ no implementation for `T == _` + | ^^^^^^^^ no implementation for `T == T` | -note: the trait `PartialEq<_>` is implemented for `T`, but that implementation is not `const` - --> $DIR/call-generic-method-fail.rs:4:8 +note: the trait `PartialEq` is implemented for `T`, but that implementation is not `const` + --> $DIR/call-generic-method-fail.rs:4:5 | LL | *t == *t - | ^^ - = help: the trait `PartialEq<&B>` is implemented for `&A` + | ^^^^^^^^ -error: aborting due to previous error +error[E0015]: cannot call non-const operator in constant functions + --> $DIR/call-generic-method-fail.rs:4:5 + | +LL | *t == *t + | ^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: consider further restricting this bound + | +LL | pub const fn equals_self(t: &T) -> bool { + | ++++++++++++++++++++++++++++ + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs index 140a06a73ac6d..0b981d1621eca 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs @@ -23,6 +23,7 @@ impl const ConstDefaultFn for ConstImpl { const fn test() { NonConstImpl.a(); //~^ ERROR the trait bound + //~| ERROR cannot call non-const fn ConstImpl.a(); } diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr index ec724cc9675f1..fe788b43a5416 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr @@ -2,18 +2,23 @@ error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satis --> $DIR/const-default-method-bodies.rs:24:18 | LL | NonConstImpl.a(); - | ^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl` + | ^^^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl` | note: the trait `ConstDefaultFn` is implemented for `NonConstImpl`, but that implementation is not `const` --> $DIR/const-default-method-bodies.rs:24:18 | LL | NonConstImpl.a(); - | ^ -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | ^^^ + +error[E0015]: cannot call non-const fn `::a` in constant functions + --> $DIR/const-default-method-bodies.rs:24:18 + | +LL | NonConstImpl.a(); + | ^^^ | -LL | const fn test() where NonConstImpl: ~const ConstDefaultFn { - | +++++++++++++++++++++++++++++++++++++++++ + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr new file mode 100644 index 0000000000000..3ca9abb139b86 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied + --> $DIR/cross-crate.rs:15:14 + | +LL | NonConst.func(); + | ^^^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst` + | +note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const` + --> $DIR/cross-crate.rs:15:14 + | +LL | NonConst.func(); + | ^^^^^^ + +error[E0015]: cannot call non-const fn `::func` in constant functions + --> $DIR/cross-crate.rs:15:14 + | +LL | NonConst.func(); + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr deleted file mode 100644 index 174c62912fcee..0000000000000 --- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied - --> $DIR/cross-crate.rs:17:14 - | -LL | NonConst.func(); - | ^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst` - | -note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const` - --> $DIR/cross-crate.rs:17:14 - | -LL | NonConst.func(); - | ^^^^ -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement - | -LL | const fn const_context() where cross_crate::NonConst: ~const cross_crate::MyTrait { - | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs index 6df47022cc948..fa049ab86ff49 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs @@ -1,6 +1,5 @@ -// revisions: stock gated stocknc gatednc -// [gated] check-pass -#![cfg_attr(any(gated, gatednc), feature(const_trait_impl))] +// revisions: stock gated +#![cfg_attr(gated, feature(const_trait_impl))] // aux-build: cross-crate.rs extern crate cross_crate; @@ -13,12 +12,10 @@ fn non_const_context() { } const fn const_context() { - #[cfg(any(stocknc, gatednc))] - NonConst.func(); - //[stocknc]~^ ERROR: the trait bound - //[gatednc]~^^ ERROR: the trait bound + NonConst.func(); //~ ERROR: cannot call non-const fn + //[gated]~^ ERROR: the trait bound Const.func(); - //[stock]~^ ERROR: cannot call + //[stock]~^ ERROR: cannot call non-const fn } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr index 086547542bb09..ea75ad0aeaf8c 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr @@ -1,11 +1,19 @@ +error[E0015]: cannot call non-const fn `::func` in constant functions + --> $DIR/cross-crate.rs:15:14 + | +LL | NonConst.func(); + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + error[E0015]: cannot call non-const fn `::func` in constant functions - --> $DIR/cross-crate.rs:20:11 + --> $DIR/cross-crate.rs:17:11 | LL | Const.func(); | ^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr deleted file mode 100644 index 4619dd1138e1f..0000000000000 --- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: the trait bound `cross_crate::NonConst: cross_crate::MyTrait` is not satisfied - --> $DIR/cross-crate.rs:17:14 - | -LL | NonConst.func(); - | ^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst` - | -note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const` - --> $DIR/cross-crate.rs:17:14 - | -LL | NonConst.func(); - | ^^^^ -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement - | -LL | const fn const_context() where cross_crate::NonConst: ~const cross_crate::MyTrait { - | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs index f70ecbc3746f9..d798516ff70fd 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs @@ -7,6 +7,7 @@ pub trait Tr { fn b(&self) { ().a() //~^ ERROR the trait bound + //~| ERROR cannot call } } diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr index b229053eb50cf..8bb7f0141033d 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr @@ -2,18 +2,23 @@ error[E0277]: the trait bound `(): ~const Tr` is not satisfied --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12 | LL | ().a() - | ^ the trait `~const Tr` is not implemented for `()` + | ^^^ the trait `~const Tr` is not implemented for `()` | note: the trait `Tr` is implemented for `()`, but that implementation is not `const` --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12 | LL | ().a() - | ^ -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | ^^^ + +error[E0015]: cannot call non-const fn `<() as Tr>::a` in constant functions + --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12 + | +LL | ().a() + | ^^^ | -LL | pub trait Tr where (): ~const Tr { - | +++++++++++++++++++ + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs deleted file mode 100644 index 7b38c15afc20b..0000000000000 --- a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![feature(const_trait_impl)] - -trait Foo { - fn a(&self); -} -trait Bar: ~const Foo {} - -const fn foo(x: &T) { - x.a(); - //~^ ERROR the trait bound - //~| ERROR cannot call -} - -fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.stderr deleted file mode 100644 index 1766cdbee8af2..0000000000000 --- a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0277]: the trait bound `T: ~const Foo` is not satisfied - --> $DIR/super-traits-fail-2.rs:9:7 - | -LL | x.a(); - | ^^^ the trait `~const Foo` is not implemented for `T` - | -note: the trait `Foo` is implemented for `T`, but that implementation is not `const` - --> $DIR/super-traits-fail-2.rs:9:7 - | -LL | x.a(); - | ^^^ - -error[E0015]: cannot call non-const fn `::a` in constant functions - --> $DIR/super-traits-fail-2.rs:9:7 - | -LL | x.a(); - | ^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0015, E0277. -For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs deleted file mode 100644 index af465cad3d240..0000000000000 --- a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![feature(const_trait_impl)] - -trait Foo { - fn a(&self); -} -trait Bar: ~const Foo {} - -struct S; -impl Foo for S { - fn a(&self) {} -} - -impl const Bar for S {} -//~^ ERROR the trait bound - -fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr deleted file mode 100644 index 9e8b8f8c6ba1f..0000000000000 --- a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0277]: the trait bound `S: ~const Foo` is not satisfied - --> $DIR/super-traits-fail.rs:13:12 - | -LL | impl const Bar for S {} - | ^^^ the trait `~const Foo` is not implemented for `S` - | -note: the trait `Foo` is implemented for `S`, but that implementation is not `const` - --> $DIR/super-traits-fail.rs:13:12 - | -LL | impl const Bar for S {} - | ^^^ -note: required by a bound in `Bar` - --> $DIR/super-traits-fail.rs:6:12 - | -LL | trait Bar: ~const Foo {} - | ^^^^^^^^^^ required by this bound in `Bar` -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement - | -LL | impl const Bar for S where S: ~const Foo {} - | +++++++++++++++++++ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits.rs b/src/test/ui/rfc-2632-const-trait-impl/super-traits.rs deleted file mode 100644 index aded4ca9a998c..0000000000000 --- a/src/test/ui/rfc-2632-const-trait-impl/super-traits.rs +++ /dev/null @@ -1,22 +0,0 @@ -// check-pass -#![feature(const_trait_impl)] - -trait Foo { - fn a(&self); -} -trait Bar: ~const Foo {} - -struct S; -impl const Foo for S { - fn a(&self) {} -} - -impl const Bar for S {} - -const fn foo(t: &T) { - t.a(); -} - -const _: () = foo(&S); - -fn main() {} diff --git a/src/test/ui/rfc1623-2.rs b/src/test/ui/rfc1623-2.rs index 26fa6fdb57f95..35a2ef10c2e3c 100644 --- a/src/test/ui/rfc1623-2.rs +++ b/src/test/ui/rfc1623-2.rs @@ -9,6 +9,5 @@ static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = //~^ ERROR missing lifetime specifier [E0106] &(non_elidable as fn(&u8, &u8) -> &u8); //~^ ERROR missing lifetime specifier [E0106] - //~| ERROR non-primitive cast fn main() {} diff --git a/src/test/ui/rfc1623-2.stderr b/src/test/ui/rfc1623-2.stderr index 495d45e223416..65b9f68817aa4 100644 --- a/src/test/ui/rfc1623-2.stderr +++ b/src/test/ui/rfc1623-2.stderr @@ -18,18 +18,12 @@ LL | &(non_elidable as fn(&u8, &u8) -> &u8); | --- --- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider making the type lifetime-generic with a new `'a` lifetime | LL | &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8); | +++++++ ++ ++ ++ -error[E0605]: non-primitive cast: `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {non_elidable}` as `for<'r, 's> fn(&'r u8, &'s u8) -> &u8` - --> $DIR/rfc1623-2.rs:10:6 - | -LL | &(non_elidable as fn(&u8, &u8) -> &u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0106, E0605. -For more information about an error, try `rustc --explain E0106`. +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index 7e7d60d0ff90a..5b8b9bb68ad1e 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -1,4 +1,4 @@ -error[E0700]: hidden type for `impl Clone` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:48 | LL | async fn f(self: Pin<&Self>) -> impl Clone { self } diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index 30d2250c0c81d..abdc650c68e78 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -1,4 +1,4 @@ -error[E0700]: hidden type for `impl Clone` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44 | LL | fn f(self: Pin<&Self>) -> impl Clone { self } diff --git a/src/test/ui/simd/intrinsic/generic-shuffle.stderr b/src/test/ui/simd/intrinsic/generic-shuffle.stderr index 81e641612ce00..44c57cd7c47bc 100644 --- a/src/test/ui/simd/intrinsic/generic-shuffle.stderr +++ b/src/test/ui/simd/intrinsic/generic-shuffle.stderr @@ -1,10 +1,10 @@ -error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `Simd` with length 4 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `Simd` with length 4 --> $DIR/generic-shuffle.rs:24:31 | LL | let _: Simd = simd_shuffle(v, v, I); | ^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `u32` (element of input `Simd`), found `Simd` with element type `f32` +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `u32` (element of input `Simd`), found `Simd` with element type `f32` --> $DIR/generic-shuffle.rs:27:31 | LL | let _: Simd = simd_shuffle(v, v, I); diff --git a/src/test/ui/simd/libm_no_std_cant_float.rs b/src/test/ui/simd/libm_no_std_cant_float.rs index 50ac8e208390f..abe460a326bb3 100644 --- a/src/test/ui/simd/libm_no_std_cant_float.rs +++ b/src/test/ui/simd/libm_no_std_cant_float.rs @@ -2,7 +2,6 @@ #![no_std] #![feature(portable_simd)] use core::simd::f32x4; -use core::simd::SimdFloat; // For SIMD float ops, the LLIR version which is used to implement the portable // forms of them may become calls to math.h AKA libm. So, we can't guarantee diff --git a/src/test/ui/simd/libm_no_std_cant_float.stderr b/src/test/ui/simd/libm_no_std_cant_float.stderr index 97e0b7efe2abc..dc8638f6ab72d 100644 --- a/src/test/ui/simd/libm_no_std_cant_float.stderr +++ b/src/test/ui/simd/libm_no_std_cant_float.stderr @@ -1,38 +1,38 @@ error[E0599]: no method named `ceil` found for struct `Simd` in the current scope - --> $DIR/libm_no_std_cant_float.rs:15:17 + --> $DIR/libm_no_std_cant_float.rs:14:17 | LL | let _xc = x.ceil(); - | ^^^^ method not found in `Simd` + | ^^^^ method not found in `Simd` error[E0599]: no method named `floor` found for struct `Simd` in the current scope - --> $DIR/libm_no_std_cant_float.rs:16:17 + --> $DIR/libm_no_std_cant_float.rs:15:17 | LL | let _xf = x.floor(); - | ^^^^^ method not found in `Simd` + | ^^^^^ method not found in `Simd` error[E0599]: no method named `round` found for struct `Simd` in the current scope - --> $DIR/libm_no_std_cant_float.rs:17:17 + --> $DIR/libm_no_std_cant_float.rs:16:17 | LL | let _xr = x.round(); - | ^^^^^ method not found in `Simd` + | ^^^^^ method not found in `Simd` error[E0599]: no method named `trunc` found for struct `Simd` in the current scope - --> $DIR/libm_no_std_cant_float.rs:18:17 + --> $DIR/libm_no_std_cant_float.rs:17:17 | LL | let _xt = x.trunc(); - | ^^^^^ method not found in `Simd` + | ^^^^^ method not found in `Simd` error[E0599]: no method named `mul_add` found for struct `Simd` in the current scope - --> $DIR/libm_no_std_cant_float.rs:19:19 + --> $DIR/libm_no_std_cant_float.rs:18:19 | LL | let _xfma = x.mul_add(x, x); - | ^^^^^^^ method not found in `Simd` + | ^^^^^^^ method not found in `Simd` error[E0599]: no method named `sqrt` found for struct `Simd` in the current scope - --> $DIR/libm_no_std_cant_float.rs:20:20 + --> $DIR/libm_no_std_cant_float.rs:19:20 | LL | let _xsqrt = x.sqrt(); - | ^^^^ method not found in `Simd` + | ^^^^ method not found in `Simd` error: aborting due to 6 previous errors diff --git a/src/test/ui/simd/libm_std_can_float.rs b/src/test/ui/simd/libm_std_can_float.rs index 1c520856e9818..6a844e7120e79 100644 --- a/src/test/ui/simd/libm_std_can_float.rs +++ b/src/test/ui/simd/libm_std_can_float.rs @@ -3,7 +3,7 @@ // This is the converse of the other libm test. #![feature(portable_simd)] use std::simd::f32x4; -use std::simd::{SimdFloat, StdFloat}; +use std::simd::StdFloat; // For SIMD float ops, the LLIR version which is used to implement the portable // forms of them may become calls to math.h AKA libm. So, we can't guarantee diff --git a/src/test/ui/simd/type-generic-monomorphisation-empty.rs b/src/test/ui/simd/type-generic-monomorphisation-empty.rs index 2bf6641e9c91c..0121404c74935 100644 --- a/src/test/ui/simd/type-generic-monomorphisation-empty.rs +++ b/src/test/ui/simd/type-generic-monomorphisation-empty.rs @@ -2,7 +2,7 @@ #![feature(repr_simd, platform_intrinsics)] -// error-pattern:monomorphising SIMD type `Simd<0>` of zero length +// error-pattern:monomorphising SIMD type `Simd<0_usize>` of zero length #[repr(simd)] struct Simd([f32; N]); diff --git a/src/test/ui/simd/type-generic-monomorphisation-empty.stderr b/src/test/ui/simd/type-generic-monomorphisation-empty.stderr index b334b1f4b5893..00fde199b12a2 100644 --- a/src/test/ui/simd/type-generic-monomorphisation-empty.stderr +++ b/src/test/ui/simd/type-generic-monomorphisation-empty.stderr @@ -1,4 +1,4 @@ -error: monomorphising SIMD type `Simd<0>` of zero length +error: monomorphising SIMD type `Simd<0_usize>` of zero length error: aborting due to previous error diff --git a/src/test/ui/simd/type-generic-monomorphisation-oversized.rs b/src/test/ui/simd/type-generic-monomorphisation-oversized.rs index a7dc482f3cb1d..bd0d457b35e27 100644 --- a/src/test/ui/simd/type-generic-monomorphisation-oversized.rs +++ b/src/test/ui/simd/type-generic-monomorphisation-oversized.rs @@ -2,7 +2,7 @@ #![feature(repr_simd, platform_intrinsics)] -// error-pattern:monomorphising SIMD type `Simd<65536>` of length greater than 32768 +// error-pattern:monomorphising SIMD type `Simd<65536_usize>` of length greater than 32768 #[repr(simd)] struct Simd([f32; N]); diff --git a/src/test/ui/simd/type-generic-monomorphisation-oversized.stderr b/src/test/ui/simd/type-generic-monomorphisation-oversized.stderr index a2dba1222eecd..f441835011532 100644 --- a/src/test/ui/simd/type-generic-monomorphisation-oversized.stderr +++ b/src/test/ui/simd/type-generic-monomorphisation-oversized.stderr @@ -1,4 +1,4 @@ -error: monomorphising SIMD type `Simd<65536>` of length greater than 32768 +error: monomorphising SIMD type `Simd<65536_usize>` of length greater than 32768 error: aborting due to previous error diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/hidden-child.rs b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/hidden-child.rs deleted file mode 100644 index 15e0af1de6446..0000000000000 --- a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/hidden-child.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![crate_type = "lib"] - -extern crate core; - -pub mod __private { - #[doc(hidden)] - pub use core::option::Option::{self, None, Some}; -} diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/hidden-parent.rs b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/hidden-parent.rs deleted file mode 100644 index 5a5079d8204ac..0000000000000 --- a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/hidden-parent.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![crate_type = "lib"] - -extern crate core; - -#[doc(hidden)] -pub mod __private { - pub use core::option::Option::{self, None, Some}; -} diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.rs b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.rs deleted file mode 100644 index 38dabc9d71ff7..0000000000000 --- a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.rs +++ /dev/null @@ -1,10 +0,0 @@ -// aux-build:hidden-child.rs - -// FIXME(compiler-errors): This currently suggests the wrong thing. -// UI test exists to track the problem. - -extern crate hidden_child; - -fn main() { - let x: Option = 1i32; //~ ERROR mismatched types -} diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.stderr b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.stderr deleted file mode 100644 index 67f4ac08de2c5..0000000000000 --- a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/hidden-child.rs:9:26 - | -LL | let x: Option = 1i32; - | ----------- ^^^^ expected enum `Option`, found `i32` - | | - | expected due to this - | - = note: expected enum `Option` - found type `i32` -help: try wrapping the expression in `hidden_child::__private::Some` - | -LL | let x: Option = hidden_child::__private::Some(1i32); - | ++++++++++++++++++++++++++++++ + - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-parent.rs b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-parent.rs deleted file mode 100644 index 4d96d6c16cba0..0000000000000 --- a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-parent.rs +++ /dev/null @@ -1,7 +0,0 @@ -// aux-build:hidden-parent.rs - -extern crate hidden_parent; - -fn main() { - let x: Option = 1i32; //~ ERROR mismatched types -} diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-parent.stderr b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-parent.stderr deleted file mode 100644 index d92b812791014..0000000000000 --- a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-parent.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/hidden-parent.rs:6:26 - | -LL | let x: Option = 1i32; - | ----------- ^^^^ expected enum `Option`, found `i32` - | | - | expected due to this - | - = note: expected enum `Option` - found type `i32` -help: try wrapping the expression in `Some` - | -LL | let x: Option = Some(1i32); - | +++++ + - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr index 6d7c3d73097a9..a761ec5916745 100644 --- a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr +++ b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr @@ -21,6 +21,7 @@ LL | struct S2 &i32>(F); | ---- ---- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider making the bound lifetime-generic with a new `'a` lifetime | LL | struct S2 Fn(&'a i32, &'a i32) -> &'a i32>(F); diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr index e82a6f769e090..9adc9679eee47 100644 --- a/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr @@ -1,43 +1,43 @@ +error[E0658]: anonymous lifetimes in `impl Trait` are unstable + --> $DIR/impl-trait-missing-lifetime-gated.rs:5:31 + | +LL | fn f(_: impl Iterator) {} + | ^^ + | + = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable + error[E0106]: missing lifetime specifier --> $DIR/impl-trait-missing-lifetime-gated.rs:8:50 | LL | fn g(x: impl Iterator) -> Option<&'_ ()> { x.next() } | ^^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments help: consider using the `'static` lifetime | LL | fn g(x: impl Iterator) -> Option<&'static ()> { x.next() } | ~~~~~~~ +error[E0658]: anonymous lifetimes in `impl Trait` are unstable + --> $DIR/impl-trait-missing-lifetime-gated.rs:8:31 + | +LL | fn g(x: impl Iterator) -> Option<&'_ ()> { x.next() } + | ^^ + | + = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable + error[E0106]: missing lifetime specifier --> $DIR/impl-trait-missing-lifetime-gated.rs:18:56 | LL | async fn i(x: impl Iterator) -> Option<&'_ ()> { x.next() } | ^^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments help: consider using the `'static` lifetime | LL | async fn i(x: impl Iterator) -> Option<&'static ()> { x.next() } | ~~~~~~~ -error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:5:31 - | -LL | fn f(_: impl Iterator) {} - | ^^ - | - = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable - -error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:8:31 - | -LL | fn g(x: impl Iterator) -> Option<&'_ ()> { x.next() } - | ^^ - | - = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable - error: aborting due to 4 previous errors Some errors have detailed explanations: E0106, E0658. diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime.rs b/src/test/ui/suggestions/impl-trait-missing-lifetime.rs index 6f7c912d707cf..dcc716f56b705 100644 --- a/src/test/ui/suggestions/impl-trait-missing-lifetime.rs +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime.rs @@ -6,15 +6,14 @@ fn f(_: impl Iterator) {} // But that lifetime does not participate in resolution. -fn g(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } +fn g(x: impl Iterator) -> Option<&'_ ()> { x.next() } //~^ ERROR missing lifetime specifier // This is understood as `fn foo<'_1>(_: impl Iterator) {}`. async fn h(_: impl Iterator) {} // But that lifetime does not participate in resolution. -async fn i(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } +async fn i(x: impl Iterator) -> Option<&'_ ()> { x.next() } //~^ ERROR missing lifetime specifier -//~| ERROR lifetime may not live long enough fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr b/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr index b476d61017f14..d3c64cb466d74 100644 --- a/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr @@ -1,35 +1,27 @@ error[E0106]: missing lifetime specifier - --> $DIR/impl-trait-missing-lifetime.rs:9:54 + --> $DIR/impl-trait-missing-lifetime.rs:9:50 | -LL | fn g(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } - | ^^ expected named lifetime parameter +LL | fn g(x: impl Iterator) -> Option<&'_ ()> { x.next() } + | ^^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments help: consider using the `'static` lifetime | -LL | fn g(mut x: impl Iterator) -> Option<&'static ()> { x.next() } - | ~~~~~~~ +LL | fn g(x: impl Iterator) -> Option<&'static ()> { x.next() } + | ~~~~~~~ error[E0106]: missing lifetime specifier - --> $DIR/impl-trait-missing-lifetime.rs:16:60 + --> $DIR/impl-trait-missing-lifetime.rs:16:56 | -LL | async fn i(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } - | ^^ expected named lifetime parameter +LL | async fn i(x: impl Iterator) -> Option<&'_ ()> { x.next() } + | ^^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments help: consider using the `'static` lifetime | -LL | async fn i(mut x: impl Iterator) -> Option<&'static ()> { x.next() } - | ~~~~~~~ +LL | async fn i(x: impl Iterator) -> Option<&'static ()> { x.next() } + | ~~~~~~~ -error: lifetime may not live long enough - --> $DIR/impl-trait-missing-lifetime.rs:16:69 - | -LL | async fn i(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } - | -------------- ^^^^^^^^ returning this value requires that `'1` must outlive `'static` - | | - | return type `impl Future>` contains a lifetime `'1` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/issue-86667.rs b/src/test/ui/suggestions/issue-86667.rs index 366787df1b4dd..6aceb13746937 100644 --- a/src/test/ui/suggestions/issue-86667.rs +++ b/src/test/ui/suggestions/issue-86667.rs @@ -6,7 +6,6 @@ async fn a(s1: &str, s2: &str) -> &str { //~^ ERROR: missing lifetime specifier [E0106] s1 -//~^ ERROR: lifetime may not live long enough } fn b(s1: &str, s2: &str) -> &str { diff --git a/src/test/ui/suggestions/issue-86667.stderr b/src/test/ui/suggestions/issue-86667.stderr index 8d611641626e1..14dbbfffb0e62 100644 --- a/src/test/ui/suggestions/issue-86667.stderr +++ b/src/test/ui/suggestions/issue-86667.stderr @@ -11,7 +11,7 @@ LL | async fn a<'a>(s1: &'a str, s2: &'a str) -> &'a str { | ++++ ++ ++ ++ error[E0106]: missing lifetime specifier - --> $DIR/issue-86667.rs:12:29 + --> $DIR/issue-86667.rs:11:29 | LL | fn b(s1: &str, s2: &str) -> &str { | ---- ---- ^ expected named lifetime parameter @@ -22,15 +22,6 @@ help: consider introducing a named lifetime parameter LL | fn b<'a>(s1: &'a str, s2: &'a str) -> &'a str { | ++++ ++ ++ ++ -error: lifetime may not live long enough - --> $DIR/issue-86667.rs:8:5 - | -LL | async fn a(s1: &str, s2: &str) -> &str { - | - let's call the lifetime of this reference `'1` -LL | -LL | s1 - | ^^ returning this value requires that `'1` must outlive `'static` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs index b641f5941dcef..19a791a8c43af 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs @@ -17,7 +17,7 @@ where G: Get, { move || { - //~^ ERROR hidden type for `impl FnOnce()` captures lifetime + //~^ ERROR hidden type for `impl Trait` captures lifetime *dest = g.get(); } } diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 0d749f04bea77..e3fe25d5f9c97 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -6,7 +6,7 @@ LL | fn baz(g: G, dest: &mut T) -> impl FnOnce() + '_ | | | help: consider introducing lifetime `'a` here: `'a,` -error[E0700]: hidden type for `impl FnOnce()` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/missing-lifetimes-in-signature.rs:19:5 | LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() diff --git a/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr index 233f1bc5a86ee..1ecaade93c8ca 100644 --- a/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr +++ b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr @@ -4,6 +4,10 @@ error[E0106]: missing lifetime specifier LL | const A: &str = ""; | ^ expected named lifetime parameter | +help: consider using the `'static` lifetime + | +LL | const A: &'static str = ""; + | +++++++ help: consider introducing a named lifetime parameter | LL ~ trait ZstAssert<'a>: Sized { @@ -16,6 +20,10 @@ error[E0106]: missing lifetime specifier LL | const B: S = S { s: &() }; | ^ expected named lifetime parameter | +help: consider using the `'static` lifetime + | +LL | const B: S<'static> = S { s: &() }; + | +++++++++ help: consider introducing a named lifetime parameter | LL ~ trait ZstAssert<'a>: Sized { @@ -29,6 +37,10 @@ error[E0106]: missing lifetime specifier LL | const C: &'_ str = ""; | ^^ expected named lifetime parameter | +help: consider using the `'static` lifetime + | +LL | const C: &'static str = ""; + | ~~~~~~~ help: consider introducing a named lifetime parameter | LL ~ trait ZstAssert<'a>: Sized { @@ -43,6 +55,10 @@ error[E0106]: missing lifetime specifiers LL | const D: T = T { a: &(), b: &() }; | ^ expected 2 lifetime parameters | +help: consider using the `'static` lifetime + | +LL | const D: T<'static, 'static> = T { a: &(), b: &() }; + | ++++++++++++++++++ help: consider introducing a named lifetime parameter | LL ~ trait ZstAssert<'a>: Sized { diff --git a/src/test/ui/suggestions/missing-lifetime-specifier.rs b/src/test/ui/suggestions/missing-lifetime-specifier.rs index 24f5f782f3521..ce847c86bedde 100644 --- a/src/test/ui/suggestions/missing-lifetime-specifier.rs +++ b/src/test/ui/suggestions/missing-lifetime-specifier.rs @@ -21,18 +21,22 @@ thread_local! { } thread_local! { static b: RefCell>>> = RefCell::new(HashMap::new()); - //~^ ERROR missing lifetime specifiers - //~| ERROR missing lifetime specifiers + //~^ ERROR missing lifetime specifier + //~| ERROR missing lifetime specifier + //~| ERROR missing lifetime specifier + //~| ERROR missing lifetime specifier } thread_local! { static c: RefCell>>>> = RefCell::new(HashMap::new()); - //~^ ERROR missing lifetime specifiers - //~| ERROR missing lifetime specifiers + //~^ ERROR missing lifetime + //~| ERROR missing lifetime } thread_local! { static d: RefCell>>>> = RefCell::new(HashMap::new()); - //~^ ERROR missing lifetime specifiers - //~| ERROR missing lifetime specifiers + //~^ ERROR missing lifetime + //~| ERROR missing lifetime + //~| ERROR missing lifetime + //~| ERROR missing lifetime } thread_local! { diff --git a/src/test/ui/suggestions/missing-lifetime-specifier.stderr b/src/test/ui/suggestions/missing-lifetime-specifier.stderr index 10fb28c189197..1498337549d81 100644 --- a/src/test/ui/suggestions/missing-lifetime-specifier.stderr +++ b/src/test/ui/suggestions/missing-lifetime-specifier.stderr @@ -8,7 +8,7 @@ LL | static a: RefCell>>> = RefCell::new(HashMap:: help: consider using the `'static` lifetime | LL | static a: RefCell>>>> = RefCell::new(HashMap::new()); - | ++++++++++++++++++ + | ~~~~~~~~~~~~~~~~~~~~~ error[E0106]: missing lifetime specifiers --> $DIR/missing-lifetime-specifier.rs:18:44 @@ -23,28 +23,38 @@ LL | | } | = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from -error[E0106]: missing lifetime specifiers +error[E0106]: missing lifetime specifier --> $DIR/missing-lifetime-specifier.rs:23:44 | LL | static b: RefCell>>> = RefCell::new(HashMap::new()); - | ^^^^ expected 2 lifetime parameters - | | - | expected named lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from help: consider using the `'static` lifetime | -LL | static b: RefCell>>>> = RefCell::new(HashMap::new()); - | +++++++ ++++++++++++++++++ +LL | static b: RefCell>>> = RefCell::new(HashMap::new()); + | ~~~~~~~~ error[E0106]: missing lifetime specifiers + --> $DIR/missing-lifetime-specifier.rs:23:45 + | +LL | static b: RefCell>>> = RefCell::new(HashMap::new()); + | ^^^ expected 2 lifetime parameters + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static b: RefCell>>>> = RefCell::new(HashMap::new()); + | ~~~~~~~~~~~~~~~~~~~~~ + +error[E0106]: missing lifetime specifier --> $DIR/missing-lifetime-specifier.rs:23:44 | LL | / thread_local! { LL | | static b: RefCell>>> = RefCell::new(HashMap::new()); - | | ^^^^ expected 2 lifetime parameters - | | | - | | expected named lifetime parameter + | | ^ expected named lifetime parameter +LL | | +LL | | LL | | LL | | LL | | } @@ -53,10 +63,25 @@ LL | | } = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:28:47 + --> $DIR/missing-lifetime-specifier.rs:23:45 + | +LL | / thread_local! { +LL | | static b: RefCell>>> = RefCell::new(HashMap::new()); + | | ^^^ expected 2 lifetime parameters +LL | | +LL | | +LL | | +LL | | +LL | | } + | |_- + | + = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from + +error[E0106]: missing lifetime specifiers + --> $DIR/missing-lifetime-specifier.rs:30:48 | LL | static c: RefCell>>>> = RefCell::new(HashMap::new()); - | ^ expected 2 lifetime parameters + | ^ expected 2 lifetime parameters | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from help: consider using the `'static` lifetime @@ -65,11 +90,11 @@ LL | static c: RefCell>>>> = | +++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:28:47 + --> $DIR/missing-lifetime-specifier.rs:30:48 | LL | / thread_local! { LL | | static c: RefCell>>>> = RefCell::new(HashMap::new()); - | | ^ expected 2 lifetime parameters + | | ^ expected 2 lifetime parameters LL | | LL | | LL | | } @@ -77,28 +102,38 @@ LL | | } | = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from -error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:33:44 +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-specifier.rs:35:44 | LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); - | ^ ^ expected 2 lifetime parameters - | | - | expected named lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from help: consider using the `'static` lifetime | -LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); - | +++++++ +++++++++++++++++ +LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); + | ~~~~~~~~ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:33:44 + --> $DIR/missing-lifetime-specifier.rs:35:49 + | +LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); + | ^ expected 2 lifetime parameters + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); + | +++++++++++++++++ + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-specifier.rs:35:44 | LL | / thread_local! { LL | | static d: RefCell>>>> = RefCell::new(HashMap::new()); - | | ^ ^ expected 2 lifetime parameters - | | | - | | expected named lifetime parameter + | | ^ expected named lifetime parameter +LL | | +LL | | LL | | LL | | LL | | } @@ -106,35 +141,23 @@ LL | | } | = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:47:44 - | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | ^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime - | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | +++++++ - -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:47:44 +error[E0106]: missing lifetime specifiers + --> $DIR/missing-lifetime-specifier.rs:35:49 | LL | / thread_local! { -LL | | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | | ^ expected named lifetime parameter +LL | | static d: RefCell>>>> = RefCell::new(HashMap::new()); + | | ^ expected 2 lifetime parameters +LL | | LL | | LL | | -... | LL | | LL | | } | |_- | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from + = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:39:44 + --> $DIR/missing-lifetime-specifier.rs:43:44 | LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -152,7 +175,7 @@ LL | static e: RefCell>>>> = | +++++++++ error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:39:44 + --> $DIR/missing-lifetime-specifier.rs:43:44 | LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -170,7 +193,7 @@ LL | static e: RefCell>>>> = RefC | ++++ error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:39:44 + --> $DIR/missing-lifetime-specifier.rs:43:44 | LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -188,7 +211,7 @@ LL | static e: RefCell>>>> = RefC | ++++ error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:39:44 + --> $DIR/missing-lifetime-specifier.rs:43:44 | LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -206,7 +229,7 @@ LL | static e: RefCell>>>> = RefC | ++++ error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:39:44 + --> $DIR/missing-lifetime-specifier.rs:43:44 | LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -224,7 +247,7 @@ LL | static e: RefCell>>>> = | +++++++++ error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:47:45 + --> $DIR/missing-lifetime-specifier.rs:51:45 | LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -241,8 +264,20 @@ help: add missing lifetime argument LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | +++++++++ +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-specifier.rs:51:44 + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ~~~~~~~~ + error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:47:45 + --> $DIR/missing-lifetime-specifier.rs:51:45 | LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -259,8 +294,23 @@ help: add missing lifetime argument LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | ++++ +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-specifier.rs:51:44 + | +LL | / thread_local! { +LL | | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | | ^ expected named lifetime parameter +LL | | +LL | | +... | +LL | | +LL | | } + | |_- + | + = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from + error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:47:45 + --> $DIR/missing-lifetime-specifier.rs:51:45 | LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -278,7 +328,7 @@ LL | static f: RefCell>>>> = Ref | ++++ error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:47:45 + --> $DIR/missing-lifetime-specifier.rs:51:45 | LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -296,7 +346,7 @@ LL | static f: RefCell>>>> = Ref | ++++ error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:47:45 + --> $DIR/missing-lifetime-specifier.rs:51:45 | LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -313,7 +363,7 @@ help: add missing lifetime argument LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | +++++++++ -error: aborting due to 20 previous errors +error: aborting due to 24 previous errors Some errors have detailed explanations: E0106, E0107. For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/missing-lt-for-hrtb.rs b/src/test/ui/suggestions/missing-lt-for-hrtb.rs index 04ea3d831c93a..a90a90122ad19 100644 --- a/src/test/ui/suggestions/missing-lt-for-hrtb.rs +++ b/src/test/ui/suggestions/missing-lt-for-hrtb.rs @@ -1,8 +1,10 @@ struct X<'a>(&'a ()); struct S<'a>(&'a dyn Fn(&X) -> &X); -//~^ ERROR missing lifetime specifiers +//~^ ERROR missing lifetime specifier +//~| ERROR missing lifetime specifier struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X); -//~^ ERROR missing lifetime specifiers +//~^ ERROR missing lifetime specifier +//~| ERROR missing lifetime specifier fn main() { let x = S(&|x| { diff --git a/src/test/ui/suggestions/missing-lt-for-hrtb.stderr b/src/test/ui/suggestions/missing-lt-for-hrtb.stderr index fa515644431ac..33f9d092e6ee0 100644 --- a/src/test/ui/suggestions/missing-lt-for-hrtb.stderr +++ b/src/test/ui/suggestions/missing-lt-for-hrtb.stderr @@ -1,36 +1,67 @@ -error[E0106]: missing lifetime specifiers +error[E0106]: missing lifetime specifier --> $DIR/missing-lt-for-hrtb.rs:2:32 | LL | struct S<'a>(&'a dyn Fn(&X) -> &X); - | -- ^^ expected named lifetime parameter - | | - | expected named lifetime parameter + | -- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | struct S<'a>(&'a dyn for<'b> Fn(&'b X) -> &'b X); + | +++++++ ~~~~~ ~~~ +help: consider using the `'a` lifetime + | +LL | struct S<'a>(&'a dyn Fn(&X) -> &'a X); + | ~~~ + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lt-for-hrtb.rs:2:33 + | +LL | struct S<'a>(&'a dyn Fn(&X) -> &X); + | -- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | struct S<'a>(&'a dyn for<'b> Fn(&'b X) -> &X<'b>); + | +++++++ ~~~~~ ~~~~~ help: consider using the `'a` lifetime | -LL | struct S<'a>(&'a dyn Fn(&X) -> &'a X<'a>); - | ++ ++++ +LL | struct S<'a>(&'a dyn Fn(&X) -> &X<'a>); + | ~~~~~ -error[E0106]: missing lifetime specifiers - --> $DIR/missing-lt-for-hrtb.rs:4:40 +error[E0106]: missing lifetime specifier + --> $DIR/missing-lt-for-hrtb.rs:5:40 | LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X); - | -- ^^ expected named lifetime parameter - | | - | expected named lifetime parameter + | -- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from note: these named lifetimes are available to use - --> $DIR/missing-lt-for-hrtb.rs:4:10 + --> $DIR/missing-lt-for-hrtb.rs:5:10 | LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X); | ^^ ^^ help: consider using one of the available lifetimes here | -LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &'lifetime X<'lifetime>); - | +++++++++ +++++++++++ +LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &'lifetime X); + | +++++++++ + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lt-for-hrtb.rs:5:41 + | +LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X); + | -- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from +note: these named lifetimes are available to use + --> $DIR/missing-lt-for-hrtb.rs:5:10 + | +LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X); + | ^^ ^^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/return-bindings.fixed b/src/test/ui/suggestions/return-bindings.fixed new file mode 100644 index 0000000000000..4fabc411abcbe --- /dev/null +++ b/src/test/ui/suggestions/return-bindings.fixed @@ -0,0 +1,23 @@ +// run-rustfix + +#![allow(unused)] + +fn a(i: i32) -> i32 { i } +//~^ ERROR mismatched types + +fn b(opt_str: Option) { + let s: String = if let Some(s) = opt_str { + s + //~^ ERROR mismatched types + } else { + String::new() + }; +} + +fn c() -> Option { + //~^ ERROR mismatched types + let x = Some(1); + x +} + +fn main() {} diff --git a/src/test/ui/suggestions/return-bindings.rs b/src/test/ui/suggestions/return-bindings.rs index fa1bad37699f3..d05b4ba27d6e8 100644 --- a/src/test/ui/suggestions/return-bindings.rs +++ b/src/test/ui/suggestions/return-bindings.rs @@ -1,3 +1,5 @@ +// run-rustfix + #![allow(unused)] fn a(i: i32) -> i32 {} @@ -16,36 +18,4 @@ fn c() -> Option { let x = Some(1); } -fn d(opt_str: Option) { - let s: String = if let Some(s) = opt_str { - //~^ ERROR mismatched types - } else { - String::new() - }; -} - -fn d2(opt_str: Option) { - let s = if let Some(s) = opt_str { - } else { - String::new() - //~^ ERROR `if` and `else` have incompatible types - }; -} - -fn e(opt_str: Option) { - let s: String = match opt_str { - Some(s) => {} - //~^ ERROR mismatched types - None => String::new(), - }; -} - -fn e2(opt_str: Option) { - let s = match opt_str { - Some(s) => {} - None => String::new(), - //~^ ERROR `match` arms have incompatible types - }; -} - fn main() {} diff --git a/src/test/ui/suggestions/return-bindings.stderr b/src/test/ui/suggestions/return-bindings.stderr index c14fb336773d1..e5d4925500556 100644 --- a/src/test/ui/suggestions/return-bindings.stderr +++ b/src/test/ui/suggestions/return-bindings.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/return-bindings.rs:3:17 + --> $DIR/return-bindings.rs:5:17 | LL | fn a(i: i32) -> i32 {} | - ^^^ expected `i32`, found `()` @@ -12,7 +12,7 @@ LL | fn a(i: i32) -> i32 { i } | + error[E0308]: mismatched types - --> $DIR/return-bindings.rs:7:46 + --> $DIR/return-bindings.rs:9:46 | LL | let s: String = if let Some(s) = opt_str { | ______________________________________________^ @@ -28,7 +28,7 @@ LL ~ | error[E0308]: mismatched types - --> $DIR/return-bindings.rs:14:11 + --> $DIR/return-bindings.rs:16:11 | LL | fn c() -> Option { | - ^^^^^^^^^^^ expected enum `Option`, found `()` @@ -43,68 +43,6 @@ LL ~ let x = Some(1); LL + x | -error[E0308]: mismatched types - --> $DIR/return-bindings.rs:20:46 - | -LL | let s: String = if let Some(s) = opt_str { - | ______________________________________________^ -LL | | -LL | | } else { - | |_____^ expected struct `String`, found `()` - | -help: consider returning the local binding `s` - | -LL ~ let s: String = if let Some(s) = opt_str { -LL + s -LL ~ - | - -error[E0308]: `if` and `else` have incompatible types - --> $DIR/return-bindings.rs:30:9 - | -LL | let s = if let Some(s) = opt_str { - | ______________________________________- -LL | | } else { - | |_____- expected because of this -LL | String::new() - | ^^^^^^^^^^^^^ expected `()`, found struct `String` - | -help: consider returning the local binding `s` - | -LL ~ let s = if let Some(s) = opt_str { -LL + s -LL ~ } else { - | - -error[E0308]: mismatched types - --> $DIR/return-bindings.rs:37:20 - | -LL | Some(s) => {} - | ^^ expected struct `String`, found `()` - | -help: consider returning the local binding `s` - | -LL | Some(s) => { s } - | + - -error[E0308]: `match` arms have incompatible types - --> $DIR/return-bindings.rs:46:17 - | -LL | let s = match opt_str { - | _____________- -LL | | Some(s) => {} - | | -- this is found to be of type `()` -LL | | None => String::new(), - | | ^^^^^^^^^^^^^ expected `()`, found struct `String` -LL | | -LL | | }; - | |_____- `match` arms have incompatible types - | -help: consider returning the local binding `s` - | -LL | Some(s) => { s } - | + - -error: aborting due to 7 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/return-elided-lifetime.rs b/src/test/ui/suggestions/return-elided-lifetime.rs index 012d5492a0404..ca336bbb056d5 100644 --- a/src/test/ui/suggestions/return-elided-lifetime.rs +++ b/src/test/ui/suggestions/return-elided-lifetime.rs @@ -6,27 +6,32 @@ fn f1() -> &i32 { loop {} } //~^ ERROR missing lifetime specifier [E0106] fn f1_() -> (&i32, &i32) { loop {} } -//~^ ERROR missing lifetime specifiers [E0106] +//~^ ERROR missing lifetime specifier [E0106] +//~^^ ERROR missing lifetime specifier [E0106] fn f2(a: i32, b: i32) -> &i32 { loop {} } //~^ ERROR missing lifetime specifier [E0106] fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} } -//~^ ERROR missing lifetime specifiers [E0106] +//~^ ERROR missing lifetime specifier [E0106] +//~^^ ERROR missing lifetime specifier [E0106] struct S<'a, 'b> { a: &'a i32, b: &'b i32 } fn f3(s: &S) -> &i32 { loop {} } //~^ ERROR missing lifetime specifier [E0106] fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} } -//~^ ERROR missing lifetime specifiers [E0106] +//~^ ERROR missing lifetime specifier [E0106] +//~^^ ERROR missing lifetime specifier [E0106] fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} } //~^ ERROR missing lifetime specifier [E0106] fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} } -//~^ ERROR missing lifetime specifiers [E0106] +//~^ ERROR missing lifetime specifier [E0106] +//~^^ ERROR missing lifetime specifier [E0106] fn f5<'a>(a: &'a i32, b: &i32) -> &i32 { loop {} } //~^ ERROR missing lifetime specifier [E0106] fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} } -//~^ ERROR missing lifetime specifiers [E0106] +//~^ ERROR missing lifetime specifier [E0106] +//~^^ ERROR missing lifetime specifier [E0106] fn main() {} diff --git a/src/test/ui/suggestions/return-elided-lifetime.stderr b/src/test/ui/suggestions/return-elided-lifetime.stderr index 273d95bc747d3..f147b4463e2f2 100644 --- a/src/test/ui/suggestions/return-elided-lifetime.stderr +++ b/src/test/ui/suggestions/return-elided-lifetime.stderr @@ -8,50 +8,70 @@ LL | fn f1() -> &i32 { loop {} } help: consider using the `'static` lifetime | LL | fn f1() -> &'static i32 { loop {} } - | +++++++ + | ~~~~~~~~ -error[E0106]: missing lifetime specifiers +error[E0106]: missing lifetime specifier --> $DIR/return-elided-lifetime.rs:8:14 | LL | fn f1_() -> (&i32, &i32) { loop {} } - | ^ ^ expected named lifetime parameter - | | - | expected named lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from help: consider using the `'static` lifetime | -LL | fn f1_() -> (&'static i32, &'static i32) { loop {} } - | +++++++ +++++++ +LL | fn f1_() -> (&'static i32, &i32) { loop {} } + | ~~~~~~~~ error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:11:26 + --> $DIR/return-elided-lifetime.rs:8:20 + | +LL | fn f1_() -> (&i32, &i32) { loop {} } + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | fn f1_() -> (&i32, &'static i32) { loop {} } + | ~~~~~~~~ + +error[E0106]: missing lifetime specifier + --> $DIR/return-elided-lifetime.rs:12:26 | LL | fn f2(a: i32, b: i32) -> &i32 { loop {} } | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments help: consider using the `'static` lifetime | LL | fn f2(a: i32, b: i32) -> &'static i32 { loop {} } - | +++++++ + | ~~~~~~~~ -error[E0106]: missing lifetime specifiers - --> $DIR/return-elided-lifetime.rs:13:28 +error[E0106]: missing lifetime specifier + --> $DIR/return-elided-lifetime.rs:14:28 | LL | fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} } - | ^ ^ expected named lifetime parameter - | | - | expected named lifetime parameter + | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments help: consider using the `'static` lifetime | -LL | fn f2_(a: i32, b: i32) -> (&'static i32, &'static i32) { loop {} } - | +++++++ +++++++ +LL | fn f2_(a: i32, b: i32) -> (&'static i32, &i32) { loop {} } + | ~~~~~~~~ error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:17:17 + --> $DIR/return-elided-lifetime.rs:14:34 + | +LL | fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} } + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments +help: consider using the `'static` lifetime + | +LL | fn f2_(a: i32, b: i32) -> (&i32, &'static i32) { loop {} } + | ~~~~~~~~ + +error[E0106]: missing lifetime specifier + --> $DIR/return-elided-lifetime.rs:19:17 | LL | fn f3(s: &S) -> &i32 { loop {} } | -- ^ expected named lifetime parameter @@ -59,32 +79,42 @@ LL | fn f3(s: &S) -> &i32 { loop {} } = help: this function's return type contains a borrowed value, but the signature does not say which one of `s`'s 3 lifetimes it is borrowed from help: consider introducing a named lifetime parameter | -LL | fn f3<'a>(s: &'a S<'a, 'a>) -> &'a i32 { loop {} } - | ++++ ++ ++++++++ ++ +LL | fn f3<'a>(s: &'a S) -> &'a i32 { loop {} } + | ++++ ++ ++ -error[E0106]: missing lifetime specifiers - --> $DIR/return-elided-lifetime.rs:19:26 +error[E0106]: missing lifetime specifier + --> $DIR/return-elided-lifetime.rs:21:26 | LL | fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} } - | -- -- ^ ^ expected named lifetime parameter - | | - | expected named lifetime parameter + | -- -- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `s`'s 3 lifetimes or one of `t`'s 3 lifetimes help: consider introducing a named lifetime parameter | -LL | fn f3_<'a>(s: &'a S<'a, 'a>, t: &'a S<'a, 'a>) -> (&'a i32, &'a i32) { loop {} } - | ++++ ++ ++++++++ ++ ++++++++ ++ ++ +LL | fn f3_<'a>(s: &'a S, t: &'a S) -> (&'a i32, &i32) { loop {} } + | ++++ ++ ++ ++ error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:22:42 + --> $DIR/return-elided-lifetime.rs:21:32 + | +LL | fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} } + | -- -- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `s`'s 3 lifetimes or one of `t`'s 3 lifetimes +help: consider introducing a named lifetime parameter + | +LL | fn f3_<'a>(s: &'a S, t: &'a S) -> (&i32, &'a i32) { loop {} } + | ++++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/return-elided-lifetime.rs:25:42 | LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} } | ------- ------- ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b` note: these named lifetimes are available to use - --> $DIR/return-elided-lifetime.rs:22:7 + --> $DIR/return-elided-lifetime.rs:25:7 | LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} } | ^^ ^^ @@ -93,27 +123,42 @@ help: consider using one of the available lifetimes here LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &'lifetime i32 { loop {} } | +++++++++ -error[E0106]: missing lifetime specifiers - --> $DIR/return-elided-lifetime.rs:24:44 +error[E0106]: missing lifetime specifier + --> $DIR/return-elided-lifetime.rs:27:44 | LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} } - | ------- ------- ^ ^ expected named lifetime parameter - | | - | expected named lifetime parameter + | ------- ------- ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b` +note: these named lifetimes are available to use + --> $DIR/return-elided-lifetime.rs:27:8 + | +LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} } + | ^^ ^^ +help: consider using one of the available lifetimes here + | +LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&'lifetime i32, &i32) { loop {} } + | +++++++++ + +error[E0106]: missing lifetime specifier + --> $DIR/return-elided-lifetime.rs:27:50 + | +LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} } + | ------- ------- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b` note: these named lifetimes are available to use - --> $DIR/return-elided-lifetime.rs:24:8 + --> $DIR/return-elided-lifetime.rs:27:8 | LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} } | ^^ ^^ help: consider using one of the available lifetimes here | -LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&'lifetime i32, &'lifetime i32) { loop {} } - | +++++++++ +++++++++ +LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &'lifetime i32) { loop {} } + | +++++++++ error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:27:35 + --> $DIR/return-elided-lifetime.rs:31:35 | LL | fn f5<'a>(a: &'a i32, b: &i32) -> &i32 { loop {} } | ------- ---- ^ expected named lifetime parameter @@ -122,22 +167,32 @@ LL | fn f5<'a>(a: &'a i32, b: &i32) -> &i32 { loop {} } help: consider using the `'a` lifetime | LL | fn f5<'a>(a: &'a i32, b: &i32) -> &'a i32 { loop {} } - | ++ + | ~~~ + +error[E0106]: missing lifetime specifier + --> $DIR/return-elided-lifetime.rs:33:37 + | +LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} } + | ------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b` +help: consider using the `'a` lifetime + | +LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&'a i32, &i32) { loop {} } + | ~~~ -error[E0106]: missing lifetime specifiers - --> $DIR/return-elided-lifetime.rs:29:37 +error[E0106]: missing lifetime specifier + --> $DIR/return-elided-lifetime.rs:33:43 | LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} } - | ------- ---- ^ ^ expected named lifetime parameter - | | - | expected named lifetime parameter + | ------- ---- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b` help: consider using the `'a` lifetime | -LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&'a i32, &'a i32) { loop {} } - | ++ ++ +LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &'a i32) { loop {} } + | ~~~ -error: aborting due to 10 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr index 5028e8d628f27..449a61d48090c 100644 --- a/src/test/ui/suggestions/return-without-lifetime.stderr +++ b/src/test/ui/suggestions/return-without-lifetime.stderr @@ -7,7 +7,7 @@ LL | struct Foo<'a>(&usize); help: consider using the `'a` lifetime | LL | struct Foo<'a>(&'a usize); - | ++ + | ~~~ error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:5:34 @@ -19,7 +19,7 @@ LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } help: consider using the `'a` lifetime | LL | fn func1<'a>(_arg: &'a Thing) -> &'a () { unimplemented!() } - | ++ + | ~~~ error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:7:35 @@ -31,7 +31,7 @@ LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } help: consider using the `'a` lifetime | LL | fn func2<'a>(_arg: &Thing<'a>) -> &'a () { unimplemented!() } - | ++ + | ~~~ error: aborting due to 3 previous errors diff --git a/src/test/ui/traits/issue-32963.rs b/src/test/ui/traits/issue-32963.rs index 56a68f3a2312c..58055cd54561a 100644 --- a/src/test/ui/traits/issue-32963.rs +++ b/src/test/ui/traits/issue-32963.rs @@ -7,5 +7,6 @@ fn size_of_copy() -> usize { mem::size_of::() } fn main() { size_of_copy::(); //~^ ERROR only auto traits can be used as additional traits in a trait object + //~| ERROR only auto traits can be used as additional traits in a trait object //~| ERROR the trait bound `dyn Misc: Copy` is not satisfied } diff --git a/src/test/ui/traits/issue-32963.stderr b/src/test/ui/traits/issue-32963.stderr index bad45e54d6428..5e7762b32200a 100644 --- a/src/test/ui/traits/issue-32963.stderr +++ b/src/test/ui/traits/issue-32963.stderr @@ -9,11 +9,22 @@ LL | size_of_copy::(); = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/issue-32963.rs:8:31 + | +LL | size_of_copy::(); + | ---- ^^^^ additional non-auto trait + | | + | first non-auto trait + | + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}` + = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit + error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied - --> $DIR/issue-32963.rs:8:20 + --> $DIR/issue-32963.rs:8:5 | LL | size_of_copy::(); - | ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc` | note: required by a bound in `size_of_copy` --> $DIR/issue-32963.rs:5:20 @@ -21,7 +32,7 @@ note: required by a bound in `size_of_copy` LL | fn size_of_copy() -> usize { mem::size_of::() } | ^^^^ required by this bound in `size_of_copy` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0225, E0277. For more information about an error, try `rustc --explain E0225`. diff --git a/src/test/ui/traits/suggest-where-clause.stderr b/src/test/ui/traits/suggest-where-clause.stderr index d4d9b4967478a..21b339d12a8de 100644 --- a/src/test/ui/traits/suggest-where-clause.stderr +++ b/src/test/ui/traits/suggest-where-clause.stderr @@ -85,10 +85,10 @@ LL | pub const fn size_of() -> usize { | ^ required by this bound in `std::mem::size_of` error[E0277]: the size for values of type `[&U]` cannot be known at compilation time - --> $DIR/suggest-where-clause.rs:31:20 + --> $DIR/suggest-where-clause.rs:31:5 | LL | mem::size_of::<[&U]>(); - | ^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[&U]` note: required by a bound in `std::mem::size_of` diff --git a/src/test/ui/traits/vtable/vtable-diamond.rs b/src/test/ui/traits/vtable/vtable-diamond.rs index dc3c17ac3144b..ec25e8a707111 100644 --- a/src/test/ui/traits/vtable/vtable-diamond.rs +++ b/src/test/ui/traits/vtable/vtable-diamond.rs @@ -34,11 +34,6 @@ fn foo(d: &dyn D) { d.foo_d(); } -fn bar(d: &dyn C) { - d.foo_c(); -} - fn main() { foo(&S); - bar(&S); } diff --git a/src/test/ui/traits/vtable/vtable-multi-level.rs b/src/test/ui/traits/vtable/vtable-multi-level.rs index ebd55bcf39b17..fcb5fd5274be4 100644 --- a/src/test/ui/traits/vtable/vtable-multi-level.rs +++ b/src/test/ui/traits/vtable/vtable-multi-level.rs @@ -12,7 +12,6 @@ #[rustc_dump_vtable] trait A { - //~^ error vtable fn foo_a(&self) {} } @@ -24,7 +23,6 @@ trait B { #[rustc_dump_vtable] trait C: A + B { - //~^ error vtable fn foo_c(&self) {} } @@ -117,27 +115,8 @@ impl M for S {} impl N for S {} impl O for S {} -macro_rules! monomorphize_vtable { - ($trait:ident) => {{ - fn foo(_ : &dyn $trait) {} - foo(&S); - }} -} +fn foo(_: &dyn O) {} fn main() { - monomorphize_vtable!(O); - - monomorphize_vtable!(A); - monomorphize_vtable!(B); - monomorphize_vtable!(C); - monomorphize_vtable!(D); - monomorphize_vtable!(E); - monomorphize_vtable!(F); - monomorphize_vtable!(H); - monomorphize_vtable!(I); - monomorphize_vtable!(J); - monomorphize_vtable!(K); - monomorphize_vtable!(L); - monomorphize_vtable!(M); - monomorphize_vtable!(N); + foo(&S); } diff --git a/src/test/ui/traits/vtable/vtable-multi-level.stderr b/src/test/ui/traits/vtable/vtable-multi-level.stderr index c4389e23fc10f..d4d7a8fa3a470 100644 --- a/src/test/ui/traits/vtable/vtable-multi-level.stderr +++ b/src/test/ui/traits/vtable/vtable-multi-level.stderr @@ -29,54 +29,29 @@ error: vtable entries for ``: [ TraitVPtr(), Method(::foo_o), ] - --> $DIR/vtable-multi-level.rs:97:1 + --> $DIR/vtable-multi-level.rs:95:1 | LL | trait O: G + N { | ^^^^^^^^^^^^^^ -error: vtable entries for ``: [ - MetadataDropInPlace, - MetadataSize, - MetadataAlign, - Method(::foo_a), - ] - --> $DIR/vtable-multi-level.rs:14:1 - | -LL | trait A { - | ^^^^^^^ - error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, Method(::foo_b), ] - --> $DIR/vtable-multi-level.rs:20:1 + --> $DIR/vtable-multi-level.rs:19:1 | LL | trait B { | ^^^^^^^ -error: vtable entries for ``: [ - MetadataDropInPlace, - MetadataSize, - MetadataAlign, - Method(::foo_a), - Method(::foo_b), - TraitVPtr(), - Method(::foo_c), - ] - --> $DIR/vtable-multi-level.rs:26:1 - | -LL | trait C: A + B { - | ^^^^^^^^^^^^^^ - error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, Method(::foo_d), ] - --> $DIR/vtable-multi-level.rs:32:1 + --> $DIR/vtable-multi-level.rs:30:1 | LL | trait D { | ^^^^^^^ @@ -87,7 +62,7 @@ error: vtable entries for ``: [ MetadataAlign, Method(::foo_e), ] - --> $DIR/vtable-multi-level.rs:38:1 + --> $DIR/vtable-multi-level.rs:36:1 | LL | trait E { | ^^^^^^^ @@ -101,7 +76,7 @@ error: vtable entries for ``: [ TraitVPtr(), Method(::foo_f), ] - --> $DIR/vtable-multi-level.rs:44:1 + --> $DIR/vtable-multi-level.rs:42:1 | LL | trait F: D + E { | ^^^^^^^^^^^^^^ @@ -112,7 +87,7 @@ error: vtable entries for ``: [ MetadataAlign, Method(::foo_h), ] - --> $DIR/vtable-multi-level.rs:55:1 + --> $DIR/vtable-multi-level.rs:53:1 | LL | trait H { | ^^^^^^^ @@ -123,7 +98,7 @@ error: vtable entries for ``: [ MetadataAlign, Method(::foo_i), ] - --> $DIR/vtable-multi-level.rs:61:1 + --> $DIR/vtable-multi-level.rs:59:1 | LL | trait I { | ^^^^^^^ @@ -137,7 +112,7 @@ error: vtable entries for ``: [ TraitVPtr(), Method(::foo_j), ] - --> $DIR/vtable-multi-level.rs:67:1 + --> $DIR/vtable-multi-level.rs:65:1 | LL | trait J: H + I { | ^^^^^^^^^^^^^^ @@ -148,7 +123,7 @@ error: vtable entries for ``: [ MetadataAlign, Method(::foo_k), ] - --> $DIR/vtable-multi-level.rs:73:1 + --> $DIR/vtable-multi-level.rs:71:1 | LL | trait K { | ^^^^^^^ @@ -159,7 +134,7 @@ error: vtable entries for ``: [ MetadataAlign, Method(::foo_l), ] - --> $DIR/vtable-multi-level.rs:79:1 + --> $DIR/vtable-multi-level.rs:77:1 | LL | trait L { | ^^^^^^^ @@ -173,7 +148,7 @@ error: vtable entries for ``: [ TraitVPtr(), Method(::foo_m), ] - --> $DIR/vtable-multi-level.rs:85:1 + --> $DIR/vtable-multi-level.rs:83:1 | LL | trait M: K + L { | ^^^^^^^^^^^^^^ @@ -194,10 +169,10 @@ error: vtable entries for ``: [ TraitVPtr(), Method(::foo_n), ] - --> $DIR/vtable-multi-level.rs:91:1 + --> $DIR/vtable-multi-level.rs:89:1 | LL | trait N: J + M { | ^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: aborting due to 12 previous errors diff --git a/src/test/ui/traits/vtable/vtable-multiple.rs b/src/test/ui/traits/vtable/vtable-multiple.rs index 7a0111c5ef251..8e7098a495ed1 100644 --- a/src/test/ui/traits/vtable/vtable-multiple.rs +++ b/src/test/ui/traits/vtable/vtable-multiple.rs @@ -25,9 +25,7 @@ impl B for S {} impl C for S {} fn foo(c: &dyn C) {} -fn bar(c: &dyn B) {} fn main() { foo(&S); - bar(&S); } diff --git a/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr b/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr index e7565525ad338..6c82d31e18d8b 100644 --- a/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr @@ -25,7 +25,7 @@ error: non-defining opaque type use in defining scope LL | 7u32 | ^^^^ | -note: used non-generic constant `123` for generic parameter +note: used non-generic constant `123_usize` for generic parameter --> $DIR/generic_nondefining_use.rs:11:15 | LL | type OneConst = impl Debug; diff --git a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr index d20b1cc6d851b..00c682b21939c 100644 --- a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr @@ -1,10 +1,8 @@ -error[E0275]: overflow evaluating the requirement `fn() -> Foo {foo}: Sized` +error[E0275]: overflow evaluating the requirement ` Foo {foo} as FnOnce<()>>::Output == fn() -> Foo {foo}` --> $DIR/issue-53398-cyclic-types.rs:5:13 | LL | fn foo() -> Foo { | ^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_53398_cyclic_types`) error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr index 468a14762c0d7..7aefa0646114c 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr @@ -1,8 +1,8 @@ error[E0277]: `::AssocType` cannot be sent between threads safely - --> $DIR/typeck-default-trait-impl-assoc-type.rs:11:15 + --> $DIR/typeck-default-trait-impl-assoc-type.rs:11:5 | LL | is_send::(); - | ^^^^^^^^^^^^ `::AssocType` cannot be sent between threads safely + | ^^^^^^^^^^^^^^^^^^^^^^^ `::AssocType` cannot be sent between threads safely | = help: the trait `Send` is not implemented for `::AssocType` note: required by a bound in `is_send` diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr index a3b32d2c1c8ce..09d3eec6b2148 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `dyn Foo<(isize,), isize, Output = ()>: Eq>` is not satisfied - --> $DIR/unboxed-closure-sugar-default.rs:21:10 + --> $DIR/unboxed-closure-sugar-default.rs:21:5 | LL | eq::, dyn Foo(isize)>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq>` is not implemented for `dyn Foo<(isize,), isize, Output = ()>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq>` is not implemented for `dyn Foo<(isize,), isize, Output = ()>` | note: required by a bound in `eq` --> $DIR/unboxed-closure-sugar-default.rs:14:40 diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs index acf0227a79b8c..0fc3e23ec73ef 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs @@ -42,7 +42,7 @@ fn test<'a,'b>() { // Errors expected: eq::< dyn Foo<(),Output=()>, dyn Foo(char) >(); - //~^ ERROR E0277 + //~^^ ERROR E0277 } fn main() { } diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr index bccbf307ae157..a1cbf842a683b 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr @@ -1,8 +1,9 @@ error[E0277]: the trait bound `dyn Foo<(char,), Output = ()>: Eq>` is not satisfied - --> $DIR/unboxed-closure-sugar-equiv.rs:44:11 + --> $DIR/unboxed-closure-sugar-equiv.rs:43:5 | -LL | dyn Foo(char) >(); - | ^^^^^^^^^^^^^ the trait `Eq>` is not implemented for `dyn Foo<(char,), Output = ()>` +LL | / eq::< dyn Foo<(),Output=()>, +LL | | dyn Foo(char) >(); + | |_______________________________________________________________________^ the trait `Eq>` is not implemented for `dyn Foo<(char,), Output = ()>` | note: required by a bound in `eq` --> $DIR/unboxed-closure-sugar-equiv.rs:16:28 diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr index 2b8fec86c8a18..d25452456bb21 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr @@ -5,11 +5,6 @@ LL | let _: dyn Foo(&isize, &usize) -> &usize; | ------ ------ ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 - = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html -help: consider making the bound lifetime-generic with a new `'a` lifetime - | -LL | let _: dyn for<'a> Foo(&'a isize, &'a usize) -> &'a usize; - | +++++++ ++ ++ ++ help: consider introducing a named lifetime parameter | LL ~ fn main<'a>() { diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs index e1deab736cf56..37c87dbeaa9e5 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs @@ -7,6 +7,7 @@ use std::fmt::Debug; struct Foo { x: Box, //~ ERROR missing lifetime specifier + //~^ ERROR E0228 } -fn main() {} +fn main() { } diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr index fd08600280393..b865278e25fd8 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr @@ -10,6 +10,13 @@ LL ~ struct Foo<'a> { LL ~ x: Box, | -error: aborting due to previous error +error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound + --> $DIR/dyn-trait-underscore-in-struct.rs:9:12 + | +LL | x: Box, + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0106`. +Some errors have detailed explanations: E0106, E0228. +For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index 50401791effb8..22bf1fdba326f 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -1,14 +1,3 @@ -error[E0106]: missing lifetime specifier - --> $DIR/underscore-lifetime-binders.rs:2:17 - | -LL | struct Baz<'a>(&'_ &'a u8); - | ^^ expected named lifetime parameter - | -help: consider using the `'a` lifetime - | -LL | struct Baz<'a>(&'a &'a u8); - | ~~ - error[E0637]: `'_` cannot be used here --> $DIR/underscore-lifetime-binders.rs:4:8 | @@ -21,6 +10,17 @@ error[E0637]: `'_` cannot be used here LL | fn meh() -> Box Meh<'_>> | ^^ `'_` is a reserved lifetime name +error[E0106]: missing lifetime specifier + --> $DIR/underscore-lifetime-binders.rs:2:17 + | +LL | struct Baz<'a>(&'_ &'a u8); + | ^^ expected named lifetime parameter + | +help: consider using the `'a` lifetime + | +LL | struct Baz<'a>(&'a &'a u8); + | ~~ + error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:10:33 | diff --git a/src/test/ui/unsized/issue-30355.rs b/src/test/ui/unsized/issue-30355.rs index 6ff5b37f6e5b9..0181109050320 100644 --- a/src/test/ui/unsized/issue-30355.rs +++ b/src/test/ui/unsized/issue-30355.rs @@ -4,6 +4,7 @@ pub static Y: &'static X = { const Y: &'static [u8] = b""; &X(*Y) //~^ ERROR E0277 + //~| ERROR E0277 }; fn main() {} diff --git a/src/test/ui/unsized/issue-30355.stderr b/src/test/ui/unsized/issue-30355.stderr index 71bbdf5dec769..62b6007a15a61 100644 --- a/src/test/ui/unsized/issue-30355.stderr +++ b/src/test/ui/unsized/issue-30355.stderr @@ -8,6 +8,20 @@ LL | &X(*Y) = note: all function arguments must have a statically known size = help: unsized fn params are gated as an unstable feature -error: aborting due to previous error +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/issue-30355.rs:5:6 + | +LL | &X(*Y) + | ^ doesn't have a size known at compile-time + | + = help: within `X`, the trait `Sized` is not implemented for `[u8]` +note: required because it appears within the type `X` + --> $DIR/issue-30355.rs:1:12 + | +LL | pub struct X([u8]); + | ^ + = note: the return type of a function must have a statically known size + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/tools/bump-stage0/Cargo.toml b/src/tools/bump-stage0/Cargo.toml index 758b1b139ade1..352a855561417 100644 --- a/src/tools/bump-stage0/Cargo.toml +++ b/src/tools/bump-stage0/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] anyhow = "1.0.34" curl = "0.4.38" -indexmap = { version = "1.9.1", features = ["serde"] } +indexmap = { version = "1.7.0", features = ["serde"] } serde = { version = "1.0.125", features = ["derive"] } serde_json = { version = "1.0.59", features = ["preserve_order"] } toml = "0.5.7" diff --git a/src/tools/cargo b/src/tools/cargo index 85b500ccad8cd..d8d30a75376f7 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 85b500ccad8cd0b63995fd94a03ddd4b83f7905b +Subproject commit d8d30a75376f78bb0fabe3d28ee9d87aa8035309 diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 95fe98a683ffd..908cfc15c0d10 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -11,8 +11,6 @@ struct Test { packages: &'static [&'static str], features: Option<&'static [&'static str]>, manifest_path: Option<&'static str>, - /// `filters` are passed to libtest (i.e., after a `--` in the `cargo test` invocation). - filters: &'static [&'static str], } const TEST_REPOS: &[Test] = &[ @@ -24,7 +22,6 @@ const TEST_REPOS: &[Test] = &[ packages: &[], features: None, manifest_path: None, - filters: &[], }, Test { name: "ripgrep", @@ -34,7 +31,6 @@ const TEST_REPOS: &[Test] = &[ packages: &[], features: None, manifest_path: None, - filters: &[], }, Test { name: "tokei", @@ -44,7 +40,6 @@ const TEST_REPOS: &[Test] = &[ packages: &[], features: None, manifest_path: None, - filters: &[], }, Test { name: "xsv", @@ -54,21 +49,6 @@ const TEST_REPOS: &[Test] = &[ packages: &[], features: None, manifest_path: None, - // Many tests here use quickcheck and some of them can fail randomly, so only run deterministic tests. - filters: &[ - "test_flatten::", - "test_fmt::", - "test_headers::", - "test_index::", - "test_join::", - "test_partition::", - "test_search::", - "test_select::", - "test_slice::", - "test_split::", - "test_stats::", - "test_table::", - ], }, Test { name: "servo", @@ -80,7 +60,6 @@ const TEST_REPOS: &[Test] = &[ packages: &["selectors"], features: None, manifest_path: None, - filters: &[], }, Test { name: "diesel", @@ -96,7 +75,6 @@ const TEST_REPOS: &[Test] = &[ // not any other crate present in the diesel workspace // (This is required to set the feature flags above) manifest_path: Some("diesel/Cargo.toml"), - filters: &[], }, ]; @@ -119,8 +97,7 @@ fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) { if let Some(lockfile) = test.lock { fs::write(&dir.join("Cargo.lock"), lockfile).unwrap(); } - if !run_cargo_test(cargo, &dir, test.packages, test.features, test.manifest_path, test.filters) - { + if !run_cargo_test(cargo, &dir, test.packages, test.features, test.manifest_path) { panic!("tests failed for {}", test.repo); } } @@ -178,7 +155,6 @@ fn run_cargo_test( packages: &[&str], features: Option<&[&str]>, manifest_path: Option<&str>, - filters: &[&str], ) -> bool { let mut command = Command::new(cargo_path); command.arg("test"); @@ -198,9 +174,6 @@ fn run_cargo_test( command.arg("-p").arg(name); } - command.arg("--"); - command.args(filters); - let status = command // Disable rust-lang/cargo's cross-compile tests .env("CFG_DISABLE_CROSS_TESTS", "1") diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 2278a8dc16ba0..920d397add716 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -3437,11 +3437,9 @@ Released 2018-09-13 [`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant -[`arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions [`as_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_underscore [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants -[`assertions_on_result_states`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_result_states [`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern [`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops [`async_yields_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#async_yields_async @@ -3795,7 +3793,6 @@ Released 2018-09-13 [`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options [`nonstandard_macro_braces`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces [`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref -[`obfuscated_if_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#obfuscated_if_else [`octal_escapes`]: https://rust-lang.github.io/rust-clippy/master/index.html#octal_escapes [`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect [`only_used_in_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#only_used_in_recursion diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index 1c875c3adcf55..644ca6318f625 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -32,7 +32,6 @@ compiletest_rs = { version = "0.8", features = ["tmp"] } tester = "0.9" regex = "1.5" toml = "0.5" -walkdir = "2.3" # This is used by the `collect-metadata` alias. filetime = "0.2" diff --git a/src/tools/clippy/book/src/continuous_integration/github_actions.md b/src/tools/clippy/book/src/continuous_integration/github_actions.md index 339287a7dd95f..42a43ef138016 100644 --- a/src/tools/clippy/book/src/continuous_integration/github_actions.md +++ b/src/tools/clippy/book/src/continuous_integration/github_actions.md @@ -1,7 +1,7 @@ # GitHub Actions -GitHub hosted runners using the latest stable version of Rust have Clippy pre-installed. -It is as simple as running `cargo clippy` to run lints against the codebase. +On the GitHub hosted runners, Clippy from the latest stable Rust version comes +pre-installed. So all you have to do is to run `cargo clippy`. ```yml on: push @@ -15,7 +15,7 @@ jobs: clippy_check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v1 - name: Run Clippy run: cargo clippy --all-targets --all-features ``` diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md index da781eb970df7..d06297f2e079a 100644 --- a/src/tools/clippy/book/src/development/adding_lints.md +++ b/src/tools/clippy/book/src/development/adding_lints.md @@ -10,10 +10,6 @@ because that's clearly a non-descriptive name. - [Adding a new lint](#adding-a-new-lint) - [Setup](#setup) - [Getting Started](#getting-started) - - [Defining Our Lint](#defining-our-lint) - - [Standalone](#standalone) - - [Specific Type](#specific-type) - - [Tests Location](#tests-location) - [Testing](#testing) - [Cargo lints](#cargo-lints) - [Rustfix tests](#rustfix-tests) @@ -40,38 +36,17 @@ See the [Basics](basics.md#get-the-code) documentation. ## Getting Started There is a bit of boilerplate code that needs to be set up when creating a new -lint. Fortunately, you can use the Clippy dev tools to handle this for you. We +lint. Fortunately, you can use the clippy dev tools to handle this for you. We are naming our new lint `foo_functions` (lints are generally written in snake -case), and we don't need type information, so it will have an early pass type -(more on this later). If you're unsure if the name you chose fits the lint, -take a look at our [lint naming guidelines][lint_naming]. - -## Defining Our Lint -To get started, there are two ways to define our lint. - -### Standalone -Command: `cargo dev new_lint --name=foo_functions --pass=early --category=pedantic` -(category will default to nursery if not provided) - -This command will create a new file: `clippy_lints/src/foo_functions.rs`, as well -as [register the lint](#lint-registration). - -### Specific Type -Command: `cargo dev new_lint --name=foo_functions --type=functions --category=pedantic` - -This command will create a new file: `clippy_lints/src/{type}/foo_functions.rs`. - -Notice how this command has a `--type` flag instead of `--pass`. Unlike a standalone -definition, this lint won't be registered in the traditional sense. Instead, you will -call your lint from within the type's lint pass, found in `clippy_lints/src/{type}/mod.rs`. - -A "type" is just the name of a directory in `clippy_lints/src`, like `functions` in -the example command. These are groupings of lints with common behaviors, so if your -lint falls into one, it would be best to add it to that type. - -### Tests Location -Both commands will create a file: `tests/ui/foo_functions.rs`. For cargo lints, -two project hierarchies (fail/pass) will be created by default under `tests/ui-cargo`. +case), and we don't need type information so it will have an early pass type +(more on this later on). If you're not sure if the name you chose fits the lint, +take a look at our [lint naming guidelines][lint_naming]. To get started on this +lint you can run `cargo dev new_lint --name=foo_functions --pass=early +--category=pedantic` (category will default to nursery if not provided). This +command will create two files: `tests/ui/foo_functions.rs` and +`clippy_lints/src/foo_functions.rs`, as well as [registering the +lint](#lint-registration). For cargo lints, two project hierarchies (fail/pass) +will be created by default under `tests/ui-cargo`. Next, we'll open up these files and add our lint! diff --git a/src/tools/clippy/book/src/development/infrastructure/book.md b/src/tools/clippy/book/src/development/infrastructure/book.md index a48742191850b..b62314c6735a2 100644 --- a/src/tools/clippy/book/src/development/infrastructure/book.md +++ b/src/tools/clippy/book/src/development/infrastructure/book.md @@ -25,7 +25,7 @@ instructions for other options. ## Make changes The book's -[src](https://github.com/rust-lang/rust-clippy/tree/master/book/src) +[src](https://github.com/joshrotenberg/rust-clippy/tree/clippy_guide/book/src) directory contains all of the markdown files used to generate the book. If you want to see your changes in real time, you can use the mdbook `serve` command to run a web server locally that will automatically update changes as they are diff --git a/src/tools/clippy/clippy_dev/src/fmt.rs b/src/tools/clippy/clippy_dev/src/fmt.rs index 3b27f061eb0b4..d513a229b7e38 100644 --- a/src/tools/clippy/clippy_dev/src/fmt.rs +++ b/src/tools/clippy/clippy_dev/src/fmt.rs @@ -13,7 +13,7 @@ pub enum CliError { IoError(io::Error), RustfmtNotInstalled, WalkDirError(walkdir::Error), - IntellijSetupActive, + RaSetupActive, } impl From for CliError { @@ -48,7 +48,7 @@ pub fn run(check: bool, verbose: bool) { .expect("Failed to read clippy Cargo.toml") .contains(&"[target.'cfg(NOT_A_PLATFORM)'.dependencies]") { - return Err(CliError::IntellijSetupActive); + return Err(CliError::RaSetupActive); } rustfmt_test(context)?; @@ -93,11 +93,11 @@ pub fn run(check: bool, verbose: bool) { CliError::WalkDirError(err) => { eprintln!("error: {}", err); }, - CliError::IntellijSetupActive => { + CliError::RaSetupActive => { eprintln!( "error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`. Not formatting because that would format the local repo as well! -Please revert the changes to Cargo.tomls with `cargo dev remove intellij`." +Please revert the changes to Cargo.tomls first." ); }, } diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs index a417d3dd8a4e7..a29ba2d0c85e3 100644 --- a/src/tools/clippy/clippy_dev/src/main.rs +++ b/src/tools/clippy/clippy_dev/src/main.rs @@ -36,8 +36,7 @@ fn main() { match new_lint::create( matches.get_one::("pass"), matches.get_one::("name"), - matches.get_one::("category").map(String::as_str), - matches.get_one::("type").map(String::as_str), + matches.get_one::("category"), matches.contains_id("msrv"), ) { Ok(_) => update_lints::update(update_lints::UpdateMode::Change), @@ -158,8 +157,7 @@ fn get_clap_config() -> ArgMatches { .help("Specify whether the lint runs during the early or late pass") .takes_value(true) .value_parser([PossibleValue::new("early"), PossibleValue::new("late")]) - .conflicts_with("type") - .required_unless_present("type"), + .required(true), Arg::new("name") .short('n') .long("name") @@ -185,11 +183,6 @@ fn get_clap_config() -> ArgMatches { PossibleValue::new("internal_warn"), ]) .takes_value(true), - Arg::new("type") - .long("type") - .help("What directory the lint belongs in") - .takes_value(true) - .required(false), Arg::new("msrv").long("msrv").help("Add MSRV config code to the lint"), ]), Command::new("setup") diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs index 03d2ef3d19edd..7d7e760ef446c 100644 --- a/src/tools/clippy/clippy_dev/src/new_lint.rs +++ b/src/tools/clippy/clippy_dev/src/new_lint.rs @@ -1,5 +1,5 @@ use crate::clippy_project_root; -use indoc::{indoc, writedoc}; +use indoc::indoc; use std::fmt::Write as _; use std::fs::{self, OpenOptions}; use std::io::prelude::*; @@ -10,7 +10,6 @@ struct LintData<'a> { pass: &'a str, name: &'a str, category: &'a str, - ty: Option<&'a str>, project_root: PathBuf, } @@ -38,44 +37,26 @@ impl Context for io::Result { pub fn create( pass: Option<&String>, lint_name: Option<&String>, - category: Option<&str>, - mut ty: Option<&str>, + category: Option<&String>, msrv: bool, ) -> io::Result<()> { - if category == Some("cargo") && ty.is_none() { - // `cargo` is a special category, these lints should always be in `clippy_lints/src/cargo` - ty = Some("cargo"); - } - let lint = LintData { - pass: pass.map_or("", String::as_str), + pass: pass.expect("`pass` argument is validated by clap"), name: lint_name.expect("`name` argument is validated by clap"), category: category.expect("`category` argument is validated by clap"), - ty, project_root: clippy_project_root(), }; create_lint(&lint, msrv).context("Unable to create lint implementation")?; create_test(&lint).context("Unable to create a test for the new lint")?; - - if lint.ty.is_none() { - add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")?; - } - - Ok(()) + add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs") } fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { - if let Some(ty) = lint.ty { - create_lint_for_ty(lint, enable_msrv, ty) - } else { - let lint_contents = get_lint_file_contents(lint, enable_msrv); - let lint_path = format!("clippy_lints/src/{}.rs", lint.name); - write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())?; - println!("Generated lint file: `{}`", lint_path); + let lint_contents = get_lint_file_contents(lint, enable_msrv); - Ok(()) - } + let lint_path = format!("clippy_lints/src/{}.rs", lint.name); + write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes()) } fn create_test(lint: &LintData<'_>) -> io::Result<()> { @@ -94,22 +75,16 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> { if lint.category == "cargo" { let relative_test_dir = format!("tests/ui-cargo/{}", lint.name); - let test_dir = lint.project_root.join(&relative_test_dir); + let test_dir = lint.project_root.join(relative_test_dir); fs::create_dir(&test_dir)?; create_project_layout(lint.name, &test_dir, "fail", "Content that triggers the lint goes here")?; - create_project_layout(lint.name, &test_dir, "pass", "This file should not trigger the lint")?; - - println!("Generated test directories: `{relative_test_dir}/pass`, `{relative_test_dir}/fail`"); + create_project_layout(lint.name, &test_dir, "pass", "This file should not trigger the lint") } else { let test_path = format!("tests/ui/{}.rs", lint.name); let test_contents = get_test_file_contents(lint.name, None); - write_file(lint.project_root.join(&test_path), test_contents)?; - - println!("Generated test file: `{}`", test_path); + write_file(lint.project_root.join(test_path), test_contents) } - - Ok(()) } fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { @@ -229,6 +204,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { }, }; + let version = get_stabilization_version(); let lint_name = lint.name; let category = lint.category; let name_camel = to_camel_case(lint.name); @@ -262,7 +238,32 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { ) }); - let _ = write!(result, "{}", get_lint_declaration(&name_upper, category)); + let _ = write!( + result, + indoc! {r#" + declare_clippy_lint! {{ + /// ### What it does + /// + /// ### Why is this bad? + /// + /// ### Example + /// ```rust + /// // example code where clippy issues a warning + /// ``` + /// Use instead: + /// ```rust + /// // example code which does not raise clippy warning + /// ``` + #[clippy::version = "{version}"] + pub {name_upper}, + {category}, + "default lint description" + }} + "#}, + version = version, + name_upper = name_upper, + category = category, + ); result.push_str(&if enable_msrv { format!( @@ -311,254 +312,6 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { result } -fn get_lint_declaration(name_upper: &str, category: &str) -> String { - format!( - indoc! {r#" - declare_clippy_lint! {{ - /// ### What it does - /// - /// ### Why is this bad? - /// - /// ### Example - /// ```rust - /// // example code where clippy issues a warning - /// ``` - /// Use instead: - /// ```rust - /// // example code which does not raise clippy warning - /// ``` - #[clippy::version = "{version}"] - pub {name_upper}, - {category}, - "default lint description" - }} - "#}, - version = get_stabilization_version(), - name_upper = name_upper, - category = category, - ) -} - -fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::Result<()> { - match ty { - "cargo" => assert_eq!( - lint.category, "cargo", - "Lints of type `cargo` must have the `cargo` category" - ), - _ if lint.category == "cargo" => panic!("Lints of category `cargo` must have the `cargo` type"), - _ => {}, - } - - let ty_dir = lint.project_root.join(format!("clippy_lints/src/{}", ty)); - assert!( - ty_dir.exists() && ty_dir.is_dir(), - "Directory `{}` does not exist!", - ty_dir.display() - ); - - let lint_file_path = ty_dir.join(format!("{}.rs", lint.name)); - assert!( - !lint_file_path.exists(), - "File `{}` already exists", - lint_file_path.display() - ); - - let mod_file_path = ty_dir.join("mod.rs"); - let context_import = setup_mod_file(&mod_file_path, lint)?; - - let name_upper = lint.name.to_uppercase(); - let mut lint_file_contents = String::new(); - - if enable_msrv { - let _ = writedoc!( - lint_file_contents, - r#" - use clippy_utils::{{meets_msrv, msrvs}}; - use rustc_lint::{{{context_import}, LintContext}}; - use rustc_semver::RustcVersion; - - use super::{name_upper}; - - // TODO: Adjust the parameters as necessary - pub(super) fn check(cx: &{context_import}, msrv: Option) {{ - if !meets_msrv(msrv, todo!("Add a new entry in `clippy_utils/src/msrvs`")) {{ - return; - }} - todo!(); - }} - "#, - context_import = context_import, - name_upper = name_upper, - ); - } else { - let _ = writedoc!( - lint_file_contents, - r#" - use rustc_lint::{{{context_import}, LintContext}}; - - use super::{name_upper}; - - // TODO: Adjust the parameters as necessary - pub(super) fn check(cx: &{context_import}) {{ - todo!(); - }} - "#, - context_import = context_import, - name_upper = name_upper, - ); - } - - write_file(lint_file_path.as_path(), lint_file_contents)?; - println!("Generated lint file: `clippy_lints/src/{}/{}.rs`", ty, lint.name); - println!( - "Be sure to add a call to `{}::check` in `clippy_lints/src/{}/mod.rs`!", - lint.name, ty - ); - - Ok(()) -} - -#[allow(clippy::too_many_lines)] -fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> { - use super::update_lints::{match_tokens, LintDeclSearchResult}; - use rustc_lexer::TokenKind; - - let lint_name_upper = lint.name.to_uppercase(); - - let mut file_contents = fs::read_to_string(path)?; - assert!( - !file_contents.contains(&lint_name_upper), - "Lint `{}` already defined in `{}`", - lint.name, - path.display() - ); - - let mut offset = 0usize; - let mut last_decl_curly_offset = None; - let mut lint_context = None; - - let mut iter = rustc_lexer::tokenize(&file_contents).map(|t| { - let range = offset..offset + t.len; - offset = range.end; - - LintDeclSearchResult { - token_kind: t.kind, - content: &file_contents[range.clone()], - range, - } - }); - - // Find both the last lint declaration (declare_clippy_lint!) and the lint pass impl - while let Some(LintDeclSearchResult { content, .. }) = iter.find(|result| result.token_kind == TokenKind::Ident) { - let mut iter = iter - .by_ref() - .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. })); - - match content { - "declare_clippy_lint" => { - // matches `!{` - match_tokens!(iter, Bang OpenBrace); - if let Some(LintDeclSearchResult { range, .. }) = - iter.find(|result| result.token_kind == TokenKind::CloseBrace) - { - last_decl_curly_offset = Some(range.end); - } - }, - "impl" => { - let mut token = iter.next(); - match token { - // matches <'foo> - Some(LintDeclSearchResult { - token_kind: TokenKind::Lt, - .. - }) => { - match_tokens!(iter, Lifetime { .. } Gt); - token = iter.next(); - }, - None => break, - _ => {}, - } - - if let Some(LintDeclSearchResult { - token_kind: TokenKind::Ident, - content, - .. - }) = token - { - // Get the appropriate lint context struct - lint_context = match content { - "LateLintPass" => Some("LateContext"), - "EarlyLintPass" => Some("EarlyContext"), - _ => continue, - }; - } - }, - _ => {}, - } - } - - drop(iter); - - let last_decl_curly_offset = - last_decl_curly_offset.unwrap_or_else(|| panic!("No lint declarations found in `{}`", path.display())); - let lint_context = - lint_context.unwrap_or_else(|| panic!("No lint pass implementation found in `{}`", path.display())); - - // Add the lint declaration to `mod.rs` - file_contents.replace_range( - // Remove the trailing newline, which should always be present - last_decl_curly_offset..=last_decl_curly_offset, - &format!("\n\n{}", get_lint_declaration(&lint_name_upper, lint.category)), - ); - - // Add the lint to `impl_lint_pass`/`declare_lint_pass` - let impl_lint_pass_start = file_contents.find("impl_lint_pass!").unwrap_or_else(|| { - file_contents - .find("declare_lint_pass!") - .unwrap_or_else(|| panic!("failed to find `impl_lint_pass`/`declare_lint_pass`")) - }); - - let mut arr_start = file_contents[impl_lint_pass_start..].find('[').unwrap_or_else(|| { - panic!("malformed `impl_lint_pass`/`declare_lint_pass`"); - }); - - arr_start += impl_lint_pass_start; - - let mut arr_end = file_contents[arr_start..] - .find(']') - .expect("failed to find `impl_lint_pass` terminator"); - - arr_end += arr_start; - - let mut arr_content = file_contents[arr_start + 1..arr_end].to_string(); - arr_content.retain(|c| !c.is_whitespace()); - - let mut new_arr_content = String::new(); - for ident in arr_content - .split(',') - .chain(std::iter::once(&*lint_name_upper)) - .filter(|s| !s.is_empty()) - { - let _ = write!(new_arr_content, "\n {},", ident); - } - new_arr_content.push('\n'); - - file_contents.replace_range(arr_start + 1..arr_end, &new_arr_content); - - // Just add the mod declaration at the top, it'll be fixed by rustfmt - file_contents.insert_str(0, &format!("mod {};\n", &lint.name)); - - let mut file = OpenOptions::new() - .write(true) - .truncate(true) - .open(path) - .context(format!("trying to open: `{}`", path.display()))?; - file.write_all(file_contents.as_bytes()) - .context(format!("writing to file: `{}`", path.display()))?; - - Ok(lint_context) -} - #[test] fn test_camel_case() { let s = "a_lint"; diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs index aed38bc281760..c089f4d8ce4bb 100644 --- a/src/tools/clippy/clippy_dev/src/update_lints.rs +++ b/src/tools/clippy/clippy_dev/src/update_lints.rs @@ -824,12 +824,10 @@ macro_rules! match_tokens { } } -pub(crate) use match_tokens; - -pub(crate) struct LintDeclSearchResult<'a> { - pub token_kind: TokenKind, - pub content: &'a str, - pub range: Range, +struct LintDeclSearchResult<'a> { + token_kind: TokenKind, + content: &'a str, + range: Range, } /// Parse a source file looking for `declare_clippy_lint` macro invocations. diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs index c7a76e5f9077c..6e5c8f445818e 100644 --- a/src/tools/clippy/clippy_lints/src/as_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs @@ -11,7 +11,7 @@ declare_clippy_lint! { /// Note that this lint is specialized in linting *every single* use of `as` /// regardless of whether good alternatives exist or not. /// If you want more precise lints for `as`, please consider using these separate lints: - /// `unnecessary_cast`, `cast_lossless/cast_possible_truncation/cast_possible_wrap/cast_precision_loss/cast_sign_loss`, + /// `unnecessary_cast`, `cast_lossless/possible_truncation/possible_wrap/precision_loss/sign_loss`, /// `fn_to_numeric_cast(_with_truncation)`, `char_lit_as_u8`, `ref_to_mut` and `ptr_as_ptr`. /// There is a good explanation the reason why this lint should work in this way and how it is useful /// [in this issue](https://github.com/rust-lang/rust-clippy/issues/5122). diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs deleted file mode 100644 index b6affdee52364..0000000000000 --- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs +++ /dev/null @@ -1,98 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; -use clippy_utils::path_res; -use clippy_utils::source::snippet_with_context; -use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item}; -use clippy_utils::usage::local_used_after_expr; -use rustc_errors::Applicability; -use rustc_hir::def::Res; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for `assert!(r.is_ok())` or `assert!(r.is_err())` calls. - /// - /// ### Why is this bad? - /// An assertion failure cannot output an useful message of the error. - /// - /// ### Example - /// ```rust,ignore - /// # let r = Ok::<_, ()>(()); - /// assert!(r.is_ok()); - /// # let r = Err::<_, ()>(()); - /// assert!(r.is_err()); - /// ``` - #[clippy::version = "1.64.0"] - pub ASSERTIONS_ON_RESULT_STATES, - style, - "`assert!(r.is_ok())`/`assert!(r.is_err())` gives worse error message than directly calling `r.unwrap()`/`r.unwrap_err()`" -} - -declare_lint_pass!(AssertionsOnResultStates => [ASSERTIONS_ON_RESULT_STATES]); - -impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { - fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let Some(macro_call) = root_macro_call_first_node(cx, e) - && matches!(cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::assert_macro)) - && let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) - && matches!(panic_expn, PanicExpn::Empty) - && let ExprKind::MethodCall(method_segment, [recv], _) = condition.kind - && let result_type_with_refs = cx.typeck_results().expr_ty(recv) - && let result_type = result_type_with_refs.peel_refs() - && is_type_diagnostic_item(cx, result_type, sym::Result) - && let ty::Adt(_, substs) = result_type.kind() - { - if !is_copy(cx, result_type) { - if result_type_with_refs != result_type { - return; - } else if let Res::Local(binding_id) = path_res(cx, recv) - && local_used_after_expr(cx, binding_id, recv) { - return; - } - } - let mut app = Applicability::MachineApplicable; - match method_segment.ident.as_str() { - "is_ok" if has_debug_impl(cx, substs.type_at(1)) => { - span_lint_and_sugg( - cx, - ASSERTIONS_ON_RESULT_STATES, - macro_call.span, - "called `assert!` with `Result::is_ok`", - "replace with", - format!( - "{}.unwrap()", - snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0 - ), - app, - ); - } - "is_err" if has_debug_impl(cx, substs.type_at(0)) => { - span_lint_and_sugg( - cx, - ASSERTIONS_ON_RESULT_STATES, - macro_call.span, - "called `assert!` with `Result::is_err`", - "replace with", - format!( - "{}.unwrap_err()", - snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0 - ), - app, - ); - } - _ => (), - }; - } - } -} - -/// This checks whether a given type is known to implement Debug. -fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - cx.tcx - .get_diagnostic_item(sym::Debug) - .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) -} diff --git a/src/tools/clippy/clippy_lints/src/cargo/mod.rs b/src/tools/clippy/clippy_lints/src/cargo/mod.rs index 9f45db86a0913..abe95c6663f70 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/mod.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/mod.rs @@ -1,8 +1,3 @@ -mod common_metadata; -mod feature_name; -mod multiple_crate_versions; -mod wildcard_dependencies; - use cargo_metadata::MetadataCommand; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_lint_allowed; @@ -11,6 +6,11 @@ use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::DUMMY_SP; +mod common_metadata; +mod feature_name; +mod multiple_crate_versions; +mod wildcard_dependencies; + declare_clippy_lint! { /// ### What it does /// Checks to see if all common metadata is defined in diff --git a/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs index 7eff71d500743..7af200708ff03 100644 --- a/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs @@ -24,10 +24,7 @@ declare_clippy_lint! { /// Use instead: /// ```rust /// fn is_rust_file(filename: &str) -> bool { - /// let filename = std::path::Path::new(filename); - /// filename.extension() - /// .map(|ext| ext.eq_ignore_ascii_case("rs")) - /// .unwrap_or(false) + /// filename.rsplit('.').next().map(|ext| ext.eq_ignore_ascii_case("rs")) == Some(true) /// } /// ``` #[clippy::version = "1.51.0"] diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index a90f894a7b19c..8c7cf7748be13 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1028,10 +1028,9 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data let mut app = Applicability::MachineApplicable; let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app); span_lint_hir_and_then(cx, NEEDLESS_BORROW, data.hir_id, data.span, state.msg, |diag| { - let calls_field = matches!(expr.kind, ExprKind::Field(..)) && matches!(data.position, Position::Callee); let sugg = if !snip_is_macro + && expr.precedence().order() < data.position.precedence() && !has_enclosing_paren(&snip) - && (expr.precedence().order() < data.position.precedence() || calls_field) { format!("({})", snip) } else { diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs index 925a8cb8deed9..0aa085fc71bfe 100644 --- a/src/tools/clippy/clippy_lints/src/format.rs +++ b/src/tools/clippy/clippy_lints/src/format.rs @@ -9,7 +9,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::kw; -use rustc_span::{sym, Span}; +use rustc_span::{sym, BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -85,7 +85,22 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { ExprKind::MethodCall(path, ..) => path.ident.name == sym::to_string, _ => false, }; - let sugg = if is_new_string { + let sugg = if format_args.format_string_span.contains(value.span) { + // Implicit argument. e.g. `format!("{x}")` span points to `{x}` + let spdata = value.span.data(); + let span = Span::new( + spdata.lo + BytePos(1), + spdata.hi - BytePos(1), + spdata.ctxt, + spdata.parent + ); + let snip = snippet_with_applicability(cx, span, "..", &mut applicability); + if is_new_string { + snip.into() + } else { + format!("{snip}.to_string()") + } + } else if is_new_string { snippet_with_applicability(cx, value.span, "..", &mut applicability).into_owned() } else { let sugg = Sugg::hir_with_applicability(cx, value, "", &mut applicability); diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs index 04b5be6c80ec6..ef8be9e878f6c 100644 --- a/src/tools/clippy/clippy_lints/src/format_impl.rs +++ b/src/tools/clippy/clippy_lints/src/format_impl.rs @@ -141,7 +141,7 @@ fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) { // Get the hir_id of the object we are calling the method on if let ExprKind::MethodCall(path, [ref self_arg, ..], _) = expr.kind; // Is the method to_string() ? - if path.ident.name == sym::to_string; + if path.ident.name == sym!(to_string); // Is the method a part of the ToString trait? (i.e. not to_string() implemented // separately) if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs index 5be1c417bf8f6..9afc714b11ca1 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs @@ -6,7 +6,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE), LintId::of(approx_const::APPROX_CONSTANT), LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), - LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES), LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), LintId::of(attrs::DEPRECATED_CFG_ATTR), @@ -188,7 +187,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::NEEDLESS_SPLITN), LintId::of(methods::NEW_RET_NO_SELF), LintId::of(methods::NO_EFFECT_REPLACE), - LintId::of(methods::OBFUSCATED_IF_ELSE), LintId::of(methods::OK_EXPECT), LintId::of(methods::OPTION_AS_REF_DEREF), LintId::of(methods::OPTION_FILTER_MAP), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs index 99bde35cf152b..91d27bf526d09 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs @@ -42,7 +42,6 @@ store.register_lints(&[ asm_syntax::INLINE_ASM_X86_ATT_SYNTAX, asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX, assertions_on_constants::ASSERTIONS_ON_CONSTANTS, - assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES, async_yields_async::ASYNC_YIELDS_ASYNC, attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON, attrs::BLANKET_CLIPPY_RESTRICTION_LINTS, @@ -331,7 +330,6 @@ store.register_lints(&[ methods::NEEDLESS_SPLITN, methods::NEW_RET_NO_SELF, methods::NO_EFFECT_REPLACE, - methods::OBFUSCATED_IF_ELSE, methods::OK_EXPECT, methods::OPTION_AS_REF_DEREF, methods::OPTION_FILTER_MAP, @@ -419,7 +417,6 @@ store.register_lints(&[ only_used_in_recursion::ONLY_USED_IN_RECURSION, open_options::NONSENSICAL_OPEN_OPTIONS, operators::ABSURD_EXTREME_COMPARISONS, - operators::ARITHMETIC, operators::ASSIGN_OP_PATTERN, operators::BAD_BIT_MASK, operators::CMP_NAN, diff --git a/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs b/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs index 495abd8387e85..43f1c892eb9b9 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs @@ -48,7 +48,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION), LintId::of(module_style::MOD_MODULE_FILES), LintId::of(module_style::SELF_NAMED_MODULE_FILES), - LintId::of(operators::ARITHMETIC), LintId::of(operators::FLOAT_ARITHMETIC), LintId::of(operators::FLOAT_CMP_CONST), LintId::of(operators::INTEGER_ARITHMETIC), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_style.rs b/src/tools/clippy/clippy_lints/src/lib.register_style.rs index e029a5235e720..15a1bc569af23 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_style.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_style.rs @@ -4,7 +4,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), - LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES), LintId::of(blacklisted_name::BLACKLISTED_NAME), LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), @@ -71,7 +70,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), LintId::of(methods::NEW_RET_NO_SELF), - LintId::of(methods::OBFUSCATED_IF_ELSE), LintId::of(methods::OK_EXPECT), LintId::of(methods::OPTION_MAP_OR_NONE), LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index eb3841272b17f..1988c24578e0b 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -174,7 +174,6 @@ mod as_conversions; mod as_underscore; mod asm_syntax; mod assertions_on_constants; -mod assertions_on_result_states; mod async_yields_async; mod attrs; mod await_holding_invalid; @@ -549,8 +548,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(utils::internal_lints::MsrvAttrImpl)); } - let arithmetic_allowed = conf.arithmetic_allowed.clone(); - store.register_late_pass(move || Box::new(operators::arithmetic::Arithmetic::new(arithmetic_allowed.clone()))); store.register_late_pass(|| Box::new(utils::dump_hir::DumpHir)); store.register_late_pass(|| Box::new(utils::author::Author)); let await_holding_invalid_types = conf.await_holding_invalid_types.clone(); @@ -730,7 +727,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(unnecessary_sort_by::UnnecessarySortBy)); store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api))); store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants)); - store.register_late_pass(|| Box::new(assertions_on_result_states::AssertionsOnResultStates)); store.register_late_pass(|| Box::new(transmuting_null::TransmutingNull)); store.register_late_pass(|| Box::new(path_buf_push_overwrite::PathBufPushOverwrite)); store.register_late_pass(|| Box::new(inherent_to_string::InherentToString)); @@ -786,7 +782,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); store.register_late_pass(|| Box::new(default::Default::default())); - store.register_late_pass(move || Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api))); + store.register_late_pass(|| Box::new(unused_self::UnusedSelf)); store.register_late_pass(|| Box::new(mutable_debug_assertion::DebugAssertWithMutCall)); store.register_late_pass(|| Box::new(exit::Exit)); store.register_late_pass(|| Box::new(to_digit_is_some::ToDigitIsSome)); @@ -920,7 +916,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; store.register_late_pass(move || Box::new(operators::Operators::new(verbose_bit_mask_threshold))); store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); - store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default())); + store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 573a7c016b8e8..083c437a293c0 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -9,14 +9,12 @@ use rustc_hir::intravisit::{ use rustc_hir::FnRetTy::Return; use rustc_hir::{ BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem, - ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin, - TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, + ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, LifetimeParamKind, ParamName, PolyTraitRef, + PredicateOrigin, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter as middle_nested_filter; -use rustc_middle::ty::TyCtxt; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, Ident, Symbol}; @@ -131,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { enum RefLt { Unnamed, Static, - Named(LocalDefId), + Named(Symbol), } fn check_fn_inner<'tcx>( @@ -234,7 +232,7 @@ fn could_use_elision<'tcx>( // level of the current item. // check named LTs - let allowed_lts = allowed_lts_from(cx.tcx, named_generics); + let allowed_lts = allowed_lts_from(named_generics); // these will collect all the lifetimes for references in arg/return types let mut input_visitor = RefVisitor::new(cx); @@ -256,6 +254,22 @@ fn could_use_elision<'tcx>( return false; } + if allowed_lts + .intersection( + &input_visitor + .nested_elision_site_lts + .iter() + .chain(output_visitor.nested_elision_site_lts.iter()) + .cloned() + .filter(|v| matches!(v, RefLt::Named(_))) + .collect(), + ) + .next() + .is_some() + { + return false; + } + let input_lts = input_visitor.lts; let output_lts = output_visitor.lts; @@ -289,31 +303,6 @@ fn could_use_elision<'tcx>( } } - // check for higher-ranked trait bounds - if !input_visitor.nested_elision_site_lts.is_empty() || !output_visitor.nested_elision_site_lts.is_empty() { - let allowed_lts: FxHashSet<_> = allowed_lts - .iter() - .filter_map(|lt| match lt { - RefLt::Named(def_id) => Some(cx.tcx.item_name(def_id.to_def_id())), - _ => None, - }) - .collect(); - for lt in input_visitor.nested_elision_site_lts { - if let RefLt::Named(def_id) = lt { - if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) { - return false; - } - } - } - for lt in output_visitor.nested_elision_site_lts { - if let RefLt::Named(def_id) = lt { - if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) { - return false; - } - } - } - } - // no input lifetimes? easy case! if input_lts.is_empty() { false @@ -346,11 +335,14 @@ fn could_use_elision<'tcx>( } } -fn allowed_lts_from(tcx: TyCtxt<'_>, named_generics: &[GenericParam<'_>]) -> FxHashSet { +fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet { let mut allowed_lts = FxHashSet::default(); for par in named_generics.iter() { - if let GenericParamKind::Lifetime { .. } = par.kind { - allowed_lts.insert(RefLt::Named(tcx.hir().local_def_id(par.hir_id))); + if let GenericParamKind::Lifetime { + kind: LifetimeParamKind::Explicit, + } = par.kind + { + allowed_lts.insert(RefLt::Named(par.name.ident().name)); } } allowed_lts.insert(RefLt::Unnamed); @@ -393,10 +385,8 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> { self.lts.push(RefLt::Unnamed); } else if lt.is_elided() { self.lts.push(RefLt::Unnamed); - } else if let LifetimeName::Param(def_id, _) = lt.name { - self.lts.push(RefLt::Named(def_id)); } else { - self.lts.push(RefLt::Unnamed); + self.lts.push(RefLt::Named(lt.name.ident().name)); } } else { self.lts.push(RefLt::Unnamed); @@ -444,15 +434,10 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { TyKind::OpaqueDef(item, bounds) => { let map = self.cx.tcx.hir(); let item = map.item(item); - let len = self.lts.len(); walk_item(self, item); - self.lts.truncate(len); + walk_ty(self, ty); self.lts.extend(bounds.iter().filter_map(|bound| match bound { - GenericArg::Lifetime(l) => Some(if let LifetimeName::Param(def_id, _) = l.name { - RefLt::Named(def_id) - } else { - RefLt::Unnamed - }), + GenericArg::Lifetime(l) => Some(RefLt::Named(l.name.ident().name)), _ => None, })); }, @@ -460,6 +445,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { let mut sub_visitor = RefVisitor::new(self.cx); sub_visitor.visit_fn_decl(decl); self.nested_elision_site_lts.append(&mut sub_visitor.all_lts()); + return; }, TyKind::TraitObject(bounds, ref lt, _) => { if !lt.is_elided() { @@ -468,9 +454,11 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { for bound in bounds { self.visit_poly_trait_ref(bound, TraitBoundModifier::None); } + return; }, - _ => walk_ty(self, ty), + _ => (), } + walk_ty(self, ty); } } @@ -489,7 +477,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_ return true; } // if the bounds define new lifetimes, they are fine to occur - let allowed_lts = allowed_lts_from(cx.tcx, pred.bound_generic_params); + let allowed_lts = allowed_lts_from(pred.bound_generic_params); // now walk the bounds for bound in pred.bounds.iter() { walk_param_bound(&mut visitor, bound); @@ -613,7 +601,7 @@ struct BodyLifetimeChecker { impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker { // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { - if lifetime.name.ident().name != kw::UnderscoreLifetime && lifetime.name.ident().name != kw::StaticLifetime { + if lifetime.name.ident().name != kw::Empty && lifetime.name.ident().name != kw::StaticLifetime { self.lifetimes_used_in_body = true; } } diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index a0ca7e6ff1e22..945880d21471b 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -166,7 +166,7 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName]) // - There's only one output lifetime bound using `+ '_` // - All input lifetimes are explicitly bound to the output input_lifetimes.is_empty() - || (output_lifetimes.len() == 1 && matches!(output_lifetimes[0], LifetimeName::Infer)) + || (output_lifetimes.len() == 1 && matches!(output_lifetimes[0], LifetimeName::Underscore)) || input_lifetimes .iter() .all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt)) diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index b638f27160282..d55082c66dc86 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -1,3 +1,13 @@ +use clippy_utils::source::{snippet_opt, span_starts_with, walk_span_to_context}; +use clippy_utils::{higher, in_constant, meets_msrv, msrvs}; +use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; +use rustc_lexer::{tokenize, TokenKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{Span, SpanData, SyntaxContext}; + mod collapsible_match; mod infallible_destructuring_match; mod manual_map; @@ -21,16 +31,6 @@ mod single_match; mod try_err; mod wild_in_or_pats; -use clippy_utils::source::{snippet_opt, span_starts_with, walk_span_to_context}; -use clippy_utils::{higher, in_constant, meets_msrv, msrvs}; -use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; -use rustc_lexer::{tokenize, TokenKind}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; -use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{Span, SpanData, SyntaxContext}; - declare_clippy_lint! { /// ### What it does /// Checks for matches with a single arm where an `if let` @@ -793,13 +793,18 @@ declare_clippy_lint! { /// ### Example /// ```rust,ignore /// # use std::sync::Mutex; + /// /// # struct State {} + /// /// # impl State { /// # fn foo(&self) -> bool { /// # true /// # } + /// /// # fn bar(&self) {} /// # } + /// + /// /// let mutex = Mutex::new(State {}); /// /// match mutex.lock().unwrap().foo() { @@ -810,17 +815,22 @@ declare_clippy_lint! { /// }; /// /// println!("All done!"); + /// /// ``` /// Use instead: /// ```rust /// # use std::sync::Mutex; + /// /// # struct State {} + /// /// # impl State { /// # fn foo(&self) -> bool { /// # true /// # } + /// /// # fn bar(&self) {} /// # } + /// /// let mutex = Mutex::new(State {}); /// /// let is_foo = mutex.lock().unwrap().foo(); diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs index f52170df662ca..06ead144afa24 100644 --- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs @@ -14,7 +14,7 @@ use super::INEFFICIENT_TO_STRING; /// Checks for the `INEFFICIENT_TO_STRING` lint pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { if_chain! { - if args.len() == 1 && method_name == sym::to_string; + if args.len() == 1 && method_name == sym!(to_string); if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD); if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id); diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 202fbc1f7f668..6981b4a66318e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -46,7 +46,6 @@ mod map_unwrap_or; mod needless_option_as_deref; mod needless_option_take; mod no_effect_replace; -mod obfuscated_if_else; mod ok_expect; mod option_as_ref_deref; mod option_map_or_none; @@ -2264,35 +2263,6 @@ declare_clippy_lint! { "replace with no effect" } -declare_clippy_lint! { - /// ### What it does - /// Checks for usages of `.then_some(..).unwrap_or(..)` - /// - /// ### Why is this bad? - /// This can be written more clearly with `if .. else ..` - /// - /// ### Limitations - /// This lint currently only looks for usages of - /// `.then_some(..).unwrap_or(..)`, but will be expanded - /// to account for similar patterns. - /// - /// ### Example - /// ```rust - /// let x = true; - /// x.then_some("a").unwrap_or("b"); - /// ``` - /// Use instead: - /// ```rust - /// let x = true; - /// if x { "a" } else { "b" }; - /// ``` - #[clippy::version = "1.64.0"] - pub OBFUSCATED_IF_ELSE, - style, - "use of `.then_some(..).unwrap_or(..)` can be written \ - more clearly with `if .. else ..`" -} - pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2394,7 +2364,6 @@ impl_lint_pass!(Methods => [ IS_DIGIT_ASCII_RADIX, NEEDLESS_OPTION_TAKE, NO_EFFECT_REPLACE, - OBFUSCATED_IF_ELSE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2803,9 +2772,6 @@ impl Methods { Some(("map", [m_recv, m_arg], span)) => { option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span); }, - Some(("then_some", [t_recv, t_arg], _)) => { - obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg); - }, _ => {}, }, ("unwrap_or_else", [u_arg]) => match method_call(recv) { diff --git a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs deleted file mode 100644 index 4d7427b266213..0000000000000 --- a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs +++ /dev/null @@ -1,42 +0,0 @@ -// run-rustfix - -use super::OBFUSCATED_IF_ELSE; -use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_with_applicability}; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::LateContext; - -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - then_recv: &'tcx hir::Expr<'_>, - then_arg: &'tcx hir::Expr<'_>, - unwrap_arg: &'tcx hir::Expr<'_>, -) { - // something.then_some(blah).unwrap_or(blah) - // ^^^^^^^^^-then_recv ^^^^-then_arg ^^^^- unwrap_arg - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr - - let recv_ty = cx.typeck_results().expr_ty(then_recv); - - if recv_ty.is_bool() { - let mut applicability = Applicability::MachineApplicable; - let sugg = format!( - "if {} {{ {} }} else {{ {} }}", - snippet_with_applicability(cx, then_recv.span, "..", &mut applicability), - snippet_with_applicability(cx, then_arg.span, "..", &mut applicability), - snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability) - ); - - span_lint_and_sugg( - cx, - OBFUSCATED_IF_ELSE, - expr.span, - "use of `.then_some(..).unwrap_or(..)` can be written \ - more clearly with `if .. else ..`", - "try", - sugg, - applicability, - ); - } -} diff --git a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs index f763e0d24c944..254d9a70010a8 100644 --- a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs +++ b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs @@ -18,11 +18,6 @@ declare_clippy_lint! { /// Naming type parameters inconsistently may cause you to refer to the /// wrong type parameter. /// - /// ### Limitations - /// This lint only applies to impl blocks with simple generic params, e.g. - /// `A`. If there is anything more complicated, such as a tuple, it will be - /// ignored. - /// /// ### Example /// ```rust /// struct Foo { @@ -58,15 +53,14 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { if !generic_args.args.is_empty(); then { // get the name and span of the generic parameters in the Impl - let mut impl_params = Vec::new(); - for p in generic_args.args.iter() { + let impl_params = generic_args.args.iter() + .filter_map(|p| match p { GenericArg::Type(Ty {kind: TyKind::Path(QPath::Resolved(_, path)), ..}) => - impl_params.push((path.segments[0].ident.to_string(), path.span)), - GenericArg::Type(_) => return, - _ => (), - }; - } + Some((path.segments[0].ident.to_string(), path.span)), + _ => None, + } + ); // find the type that the Impl is for // only lint on struct/enum/union for now @@ -89,8 +83,8 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { type_param_names.iter().enumerate().map(|(i, param)| (param, i)).collect(); let type_name = segment.ident; - for (i, (impl_param_name, impl_param_span)) in impl_params.iter().enumerate() { - if mismatch_param_name(i, impl_param_name, &type_param_names_hashmap) { + for (i, (impl_param_name, impl_param_span)) in impl_params.enumerate() { + if mismatch_param_name(i, &impl_param_name, &type_param_names_hashmap) { let msg = format!("`{}` has a similarly named generic type parameter `{}` in its declaration, but in a different order", type_name, impl_param_name); let help = format!("try `{}`, or a name that does not conflict with `{}`'s generic params", @@ -98,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { span_lint_and_help( cx, MISMATCHING_TYPE_PARAM_ORDER, - *impl_param_span, + impl_param_span, &msg, None, &help diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 72c86f28bbc6c..6bce5fbd4c1fe 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -251,7 +251,14 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { if let ItemKind::Const(hir_ty, body_id) = it.kind { let ty = hir_ty_to_ty(cx.tcx, hir_ty); - if !ignored_macro(cx, it) && is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) { + if !macro_backtrace(it.span).last().map_or(false, |macro_call| { + matches!( + cx.tcx.get_diagnostic_name(macro_call.def_id), + Some(sym::thread_local_macro) + ) + }) && is_unfrozen(cx, ty) + && is_value_unfrozen_poly(cx, body_id, ty) + { lint(cx, Source::Item { item: it.span }); } } @@ -438,12 +445,3 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { } } } - -fn ignored_macro(cx: &LateContext<'_>, it: &rustc_hir::Item<'_>) -> bool { - macro_backtrace(it.span).any(|macro_call| { - matches!( - cx.tcx.get_diagnostic_name(macro_call.def_id), - Some(sym::thread_local_macro) - ) - }) -} diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic.rs deleted file mode 100644 index 800cf249f5c78..0000000000000 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic.rs +++ /dev/null @@ -1,119 +0,0 @@ -#![allow( - // False positive - clippy::match_same_arms -)] - -use super::ARITHMETIC; -use clippy_utils::{consts::constant_simple, diagnostics::span_lint}; -use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::impl_lint_pass; -use rustc_span::source_map::Span; - -const HARD_CODED_ALLOWED: &[&str] = &["std::num::Saturating", "std::string::String", "std::num::Wrapping"]; - -#[derive(Debug)] -pub struct Arithmetic { - allowed: FxHashSet, - // Used to check whether expressions are constants, such as in enum discriminants and consts - const_span: Option, - expr_span: Option, -} - -impl_lint_pass!(Arithmetic => [ARITHMETIC]); - -impl Arithmetic { - #[must_use] - pub fn new(mut allowed: FxHashSet) -> Self { - allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from)); - Self { - allowed, - const_span: None, - expr_span: None, - } - } - - /// Checks if the given `expr` has any of the inner `allowed` elements. - fn is_allowed_ty(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - self.allowed.contains( - cx.typeck_results() - .expr_ty(expr) - .to_string() - .split('<') - .next() - .unwrap_or_default(), - ) - } - - fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { - span_lint(cx, ARITHMETIC, expr.span, "arithmetic detected"); - self.expr_span = Some(expr.span); - } -} - -impl<'tcx> LateLintPass<'tcx> for Arithmetic { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if self.expr_span.is_some() { - return; - } - if let Some(span) = self.const_span && span.contains(expr.span) { - return; - } - match &expr.kind { - hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(op, lhs, rhs) => { - let ( - hir::BinOpKind::Add - | hir::BinOpKind::Sub - | hir::BinOpKind::Mul - | hir::BinOpKind::Div - | hir::BinOpKind::Rem - | hir::BinOpKind::Shl - | hir::BinOpKind::Shr - ) = op.node else { - return; - }; - if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) { - return; - } - self.issue_lint(cx, expr); - }, - hir::ExprKind::Unary(hir::UnOp::Neg, _) => { - // CTFE already takes care of things like `-1` that do not overflow. - if constant_simple(cx, cx.typeck_results(), expr).is_none() { - self.issue_lint(cx, expr); - } - }, - _ => {}, - } - } - - fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { - let body_owner = cx.tcx.hir().body_owner_def_id(body.id()); - match cx.tcx.hir().body_owner_kind(body_owner) { - hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => { - let body_span = cx.tcx.def_span(body_owner); - if let Some(span) = self.const_span && span.contains(body_span) { - return; - } - self.const_span = Some(body_span); - }, - hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => {}, - } - } - - fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { - let body_owner = cx.tcx.hir().body_owner(body.id()); - let body_span = cx.tcx.hir().span(body_owner); - if let Some(span) = self.const_span && span.contains(body_span) { - return; - } - self.const_span = None; - } - - fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if Some(expr.span) == self.expr_span { - self.expr_span = None; - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs index 945a09a647c41..979e0a66707dd 100644 --- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs @@ -8,10 +8,6 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_lint::LateContext; -use rustc_middle::mir::FakeReadCause; -use rustc_middle::ty::BorrowKind; -use rustc_trait_selection::infer::TyCtxtInferExt; -use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use super::ASSIGN_OP_PATTERN; @@ -33,16 +29,6 @@ pub(super) fn check<'tcx>( .map_or(true, |t| t.path.res.def_id() != trait_id); if implements_trait(cx, ty, trait_id, &[rty.into()]); then { - // Primitive types execute assign-ops right-to-left. Every other type is left-to-right. - if !(ty.is_primitive() && rty.is_primitive()) { - // TODO: This will have false negatives as it doesn't check if the borrows are - // actually live at the end of their respective expressions. - let mut_borrows = mut_borrows_in_expr(cx, assignee); - let imm_borrows = imm_borrows_in_expr(cx, rhs); - if mut_borrows.iter().any(|id| imm_borrows.contains(id)) { - return; - } - } span_lint_and_then( cx, ASSIGN_OP_PATTERN, @@ -113,69 +99,3 @@ impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> { walk_expr(self, expr); } } - -fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> hir::HirIdSet { - struct S(hir::HirIdSet); - impl Delegate<'_> for S { - fn borrow(&mut self, place: &PlaceWithHirId<'_>, _: hir::HirId, kind: BorrowKind) { - if matches!(kind, BorrowKind::ImmBorrow | BorrowKind::UniqueImmBorrow) { - self.0.insert(match place.place.base { - PlaceBase::Local(id) => id, - PlaceBase::Upvar(id) => id.var_path.hir_id, - _ => return, - }); - } - } - - fn consume(&mut self, _: &PlaceWithHirId<'_>, _: hir::HirId) {} - fn mutate(&mut self, _: &PlaceWithHirId<'_>, _: hir::HirId) {} - fn fake_read(&mut self, _: &PlaceWithHirId<'_>, _: FakeReadCause, _: hir::HirId) {} - fn copy(&mut self, _: &PlaceWithHirId<'_>, _: hir::HirId) {} - } - - let mut s = S(hir::HirIdSet::default()); - cx.tcx.infer_ctxt().enter(|infcx| { - let mut v = ExprUseVisitor::new( - &mut s, - &infcx, - cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()), - cx.param_env, - cx.typeck_results(), - ); - v.consume_expr(e); - }); - s.0 -} - -fn mut_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> hir::HirIdSet { - struct S(hir::HirIdSet); - impl Delegate<'_> for S { - fn borrow(&mut self, place: &PlaceWithHirId<'_>, _: hir::HirId, kind: BorrowKind) { - if matches!(kind, BorrowKind::MutBorrow) { - self.0.insert(match place.place.base { - PlaceBase::Local(id) => id, - PlaceBase::Upvar(id) => id.var_path.hir_id, - _ => return, - }); - } - } - - fn consume(&mut self, _: &PlaceWithHirId<'_>, _: hir::HirId) {} - fn mutate(&mut self, _: &PlaceWithHirId<'_>, _: hir::HirId) {} - fn fake_read(&mut self, _: &PlaceWithHirId<'_>, _: FakeReadCause, _: hir::HirId) {} - fn copy(&mut self, _: &PlaceWithHirId<'_>, _: hir::HirId) {} - } - - let mut s = S(hir::HirIdSet::default()); - cx.tcx.infer_ctxt().enter(|infcx| { - let mut v = ExprUseVisitor::new( - &mut s, - &infcx, - cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()), - cx.param_env, - cx.typeck_results(), - ); - v.consume_expr(e); - }); - s.0 -} diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs index bb6d99406b493..35fe405bcf14f 100644 --- a/src/tools/clippy/clippy_lints/src/operators/mod.rs +++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs @@ -1,3 +1,7 @@ +use rustc_hir::{Body, Expr, ExprKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; + mod absurd_extreme_comparisons; mod assign_op_pattern; mod bit_mask; @@ -21,12 +25,6 @@ mod ptr_eq; mod self_assignment; mod verbose_bit_mask; -pub(crate) mod arithmetic; - -use rustc_hir::{Body, Expr, ExprKind, UnOp}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; - declare_clippy_lint! { /// ### What it does /// Checks for comparisons where one side of the relation is @@ -59,42 +57,6 @@ declare_clippy_lint! { "a comparison with a maximum or minimum value that is always true or false" } -declare_clippy_lint! { - /// ### What it does - /// Checks for any kind of arithmetic operation of any type. - /// - /// Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust - /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), - /// or can panic (`/`, `%`). Known safe built-in types like `Wrapping` or `Saturing` are filtered - /// away. - /// - /// ### Why is this bad? - /// Integer overflow will trigger a panic in debug builds or will wrap in - /// release mode. Division by zero will cause a panic in either mode. In some applications one - /// wants explicitly checked, wrapping or saturating arithmetic. - /// - /// #### Example - /// ```rust - /// # let a = 0; - /// a + 1; - /// ``` - /// - /// Third-party types also tend to overflow. - /// - /// #### Example - /// ```ignore,rust - /// use rust_decimal::Decimal; - /// let _n = Decimal::MAX + Decimal::MAX; - /// ``` - /// - /// ### Allowed types - /// Custom allowed types can be specified through the "arithmetic-allowed" filter. - #[clippy::version = "1.64.0"] - pub ARITHMETIC, - restriction, - "any arithmetic expression that could overflow or panic" -} - declare_clippy_lint! { /// ### What it does /// Checks for integer arithmetic operations which could overflow or panic. @@ -785,7 +747,6 @@ pub struct Operators { } impl_lint_pass!(Operators => [ ABSURD_EXTREME_COMPARISONS, - ARITHMETIC, INTEGER_ARITHMETIC, FLOAT_ARITHMETIC, ASSIGN_OP_PATTERN, diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 3c5ea2d94144f..8534d8a29f10d 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -351,7 +351,7 @@ impl fmt::Display for RefPrefix { name.fmt(f)?; f.write_char(' ')?; }, - LifetimeName::Infer => f.write_str("'_ ")?, + LifetimeName::Underscore => f.write_str("'_ ")?, LifetimeName::Static => f.write_str("'static ")?, _ => (), } diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index fd0a53839e6ea..f0155ed6051f6 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -123,8 +123,8 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: if_chain! { if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr); if !is_else_clause(cx.tcx, expr); - if let PatKind::TupleStruct(ref path1, [field], None) = let_pat.kind; - if let PatKind::Binding(annot, bind_id, ident, _) = field.kind; + if let PatKind::TupleStruct(ref path1, fields, None) = let_pat.kind; + if let PatKind::Binding(annot, bind_id, ident, _) = fields[0].kind; let caller_ty = cx.typeck_results().expr_ty(let_expr); let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else); if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id)) diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs index ffd63cc687a11..56f2a7bae152b 100644 --- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs +++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{def::Res, HirId, Path, PathSegment}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{sym, symbol::kw, Span}; +use rustc_lint::{LateContext, LateLintPass, Lint}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{sym, symbol::kw, Symbol}; declare_clippy_lint! { /// ### What it does @@ -63,7 +63,7 @@ declare_clippy_lint! { /// ### Why is this bad? /// /// Crates which have `no_std` compatibility and may optionally require alloc may wish to ensure types are - /// imported from core to ensure disabling `alloc` does not cause the crate to fail to compile. This lint + /// imported from alloc to ensure disabling `alloc` does not cause the crate to fail to compile. This lint /// is also useful for crates migrating to become `no_std` compatible. /// /// ### Example @@ -81,55 +81,39 @@ declare_clippy_lint! { "type is imported from alloc when available in core" } -#[derive(Default)] -pub struct StdReexports { - // Paths which can be either a module or a macro (e.g. `std::env`) will cause this check to happen - // twice. First for the mod, second for the macro. This is used to avoid the lint reporting for the macro - // when the path could be also be used to access the module. - prev_span: Span, -} -impl_lint_pass!(StdReexports => [STD_INSTEAD_OF_CORE, STD_INSTEAD_OF_ALLOC, ALLOC_INSTEAD_OF_CORE]); +declare_lint_pass!(StdReexports => [STD_INSTEAD_OF_CORE, STD_INSTEAD_OF_ALLOC, ALLOC_INSTEAD_OF_CORE]); impl<'tcx> LateLintPass<'tcx> for StdReexports { fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) { - if let Res::Def(_, def_id) = path.res - && let Some(first_segment) = get_first_segment(path) - { - let (lint, msg, help) = match first_segment.ident.name { - sym::std => match cx.tcx.crate_name(def_id.krate) { - sym::core => ( - STD_INSTEAD_OF_CORE, - "used import from `std` instead of `core`", - "consider importing the item from `core`", - ), - sym::alloc => ( - STD_INSTEAD_OF_ALLOC, - "used import from `std` instead of `alloc`", - "consider importing the item from `alloc`", - ), - _ => { - self.prev_span = path.span; - return; - }, - }, - sym::alloc => { - if cx.tcx.crate_name(def_id.krate) == sym::core { - ( - ALLOC_INSTEAD_OF_CORE, - "used import from `alloc` instead of `core`", - "consider importing the item from `core`", - ) - } else { - self.prev_span = path.span; - return; - } - }, - _ => return, - }; - if path.span != self.prev_span { - span_lint_and_help(cx, lint, path.span, msg, None, help); - self.prev_span = path.span; - } + // std_instead_of_core + check_path(cx, path, sym::std, sym::core, STD_INSTEAD_OF_CORE); + // std_instead_of_alloc + check_path(cx, path, sym::std, sym::alloc, STD_INSTEAD_OF_ALLOC); + // alloc_instead_of_core + check_path(cx, path, sym::alloc, sym::core, ALLOC_INSTEAD_OF_CORE); + } +} + +fn check_path(cx: &LateContext<'_>, path: &Path<'_>, krate: Symbol, suggested_crate: Symbol, lint: &'static Lint) { + if_chain! { + // check if path resolves to the suggested crate. + if let Res::Def(_, def_id) = path.res; + if suggested_crate == cx.tcx.crate_name(def_id.krate); + + // check if the first segment of the path is the crate we want to identify + if let Some(path_root_segment) = get_first_segment(path); + + // check if the path matches the crate we want to suggest the other path for. + if krate == path_root_segment.ident.name; + then { + span_lint_and_help( + cx, + lint, + path.span, + &format!("used import from `{}` instead of `{}`", krate, suggested_crate), + None, + &format!("consider importing the item from `{}`", suggested_crate), + ); } } } @@ -139,10 +123,12 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { /// If this is a global path (such as `::std::fmt::Debug`), then the segment after [`kw::PathRoot`] /// is returned. fn get_first_segment<'tcx>(path: &Path<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { - match path.segments { - // A global path will have PathRoot as the first segment. In this case, return the segment after. - [x, y, ..] if x.ident.name == kw::PathRoot => Some(y), - [x, ..] => Some(x), - _ => None, + let segment = path.segments.first()?; + + // A global path will have PathRoot as the first segment. In this case, return the segment after. + if segment.ident.name == kw::PathRoot { + path.segments.get(1) + } else { + Some(segment) } } diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 22eb06b364632..eb704a07451ca 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -394,7 +394,7 @@ impl<'tcx> LateLintPass<'tcx> for StrToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { if_chain! { if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind; - if path.ident.name == sym::to_string; + if path.ident.name == sym!(to_string); let ty = cx.typeck_results().expr_ty(self_arg); if let ty::Ref(_, ty, ..) = ty.kind(); if *ty.kind() == ty::Str; @@ -444,7 +444,7 @@ impl<'tcx> LateLintPass<'tcx> for StringToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { if_chain! { if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind; - if path.ident.name == sym::to_string; + if path.ident.name == sym!(to_string); let ty = cx.typeck_results().expr_ty(self_arg); if is_type_diagnostic_item(cx, ty, sym::String); then { diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs index 51c65d898cf5f..fd9d5b52e501f 100644 --- a/src/tools/clippy/clippy_lints/src/unused_self.rs +++ b/src/tools/clippy/clippy_lints/src/unused_self.rs @@ -3,7 +3,7 @@ use clippy_utils::visitors::is_local_used; use if_chain::if_chain; use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// ### What it does @@ -35,19 +35,7 @@ declare_clippy_lint! { "methods that contain a `self` argument but don't use it" } -pub struct UnusedSelf { - avoid_breaking_exported_api: bool, -} - -impl_lint_pass!(UnusedSelf => [UNUSED_SELF]); - -impl UnusedSelf { - pub fn new(avoid_breaking_exported_api: bool) -> Self { - Self { - avoid_breaking_exported_api, - } - } -} +declare_lint_pass!(UnusedSelf => [UNUSED_SELF]); impl<'tcx> LateLintPass<'tcx> for UnusedSelf { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &ImplItem<'_>) { @@ -61,7 +49,6 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind; if assoc_item.fn_has_self_parameter; if let ImplItemKind::Fn(.., body_id) = &impl_item.kind; - if !cx.access_levels.is_exported(impl_item.def_id) || !self.avoid_breaking_exported_api; let body = cx.tcx.hir().body(*body_id); if let [self_param, ..] = body.params; if !is_local_used(cx, body, self_param.pat.hir_id); diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index 6e033b3be2d87..38e5c5e5b7365 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -191,11 +191,7 @@ macro_rules! define_Conf { } define_Conf! { - /// Lint: Arithmetic. - /// - /// Suppress checking of the passed type names. - (arithmetic_allowed: rustc_data_structures::fx::FxHashSet = <_>::default()), - /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX. + /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index 3a99d1b417fee..08b8894752011 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -441,7 +441,7 @@ impl SimpleFormatArgs { }; match arg.position { - ArgumentIs(n, _) | ArgumentImplicitlyIs(n) => { + ArgumentIs(n) | ArgumentImplicitlyIs(n) => { if self.unnamed.len() <= n { // Use a dummy span to mark all unseen arguments. self.unnamed.resize_with(n, || vec![DUMMY_SP]); diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 351a3f4aec8c8..6d4a48b53de3c 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -619,24 +619,32 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) - }, mir::ConstantKind::Val(ConstValue::ByRef { alloc, offset: _ }, _) => match result.ty().kind() { ty::Array(sub_type, len) => match sub_type.kind() { - ty::Float(FloatTy::F32) => match len.kind().try_to_machine_usize(tcx) { + ty::Float(FloatTy::F32) => match len.to_valtree().try_to_machine_usize(tcx) { Some(len) => alloc .inner() .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap())) .to_owned() - .array_chunks::<4>() - .map(|&chunk| Some(Constant::F32(f32::from_le_bytes(chunk)))) + .chunks(4) + .map(|chunk| { + Some(Constant::F32(f32::from_le_bytes( + chunk.try_into().expect("this shouldn't happen"), + ))) + }) .collect::>>() .map(Constant::Vec), _ => None, }, - ty::Float(FloatTy::F64) => match len.kind().try_to_machine_usize(tcx) { + ty::Float(FloatTy::F64) => match len.to_valtree().try_to_machine_usize(tcx) { Some(len) => alloc .inner() .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap())) .to_owned() - .array_chunks::<8>() - .map(|&chunk| Some(Constant::F64(f64::from_le_bytes(chunk)))) + .chunks(8) + .map(|chunk| { + Some(Constant::F64(f64::from_le_bytes( + chunk.try_into().expect("this shouldn't happen"), + ))) + }) .collect::>>() .map(Constant::Vec), _ => None, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index eaf260ddfb832..77c974582ecb0 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -127,6 +127,9 @@ impl HirEqInterExpr<'_, '_, '_> { /// Checks whether two blocks are the same. fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool { + if self.cannot_be_compared_block(left) || self.cannot_be_compared_block(right) { + return false; + } match (left.stmts, left.expr, right.stmts, right.expr) { ([], None, [], None) => { // For empty blocks, check to see if the tokens are equal. This will catch the case where a macro @@ -177,13 +180,36 @@ impl HirEqInterExpr<'_, '_, '_> { } } + fn cannot_be_compared_block(&mut self, block: &Block<'_>) -> bool { + if block.stmts.last().map_or(false, |stmt| { + matches!( + stmt.kind, + StmtKind::Semi(semi_expr) if self.should_ignore(semi_expr) + ) + }) { + return true; + } + + if let Some(block_expr) = block.expr + && self.should_ignore(block_expr) + { + return true + } + + false + } + fn should_ignore(&mut self, expr: &Expr<'_>) -> bool { - macro_backtrace(expr.span).last().map_or(false, |macro_call| { + if macro_backtrace(expr.span).last().map_or(false, |macro_call| { matches!( &self.inner.cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::todo_macro | sym::unimplemented_macro) ) - }) + }) { + return true; + } + + false } pub fn eq_array_length(&mut self, left: ArrayLen, right: ArrayLen) -> bool { @@ -301,8 +327,7 @@ impl HirEqInterExpr<'_, '_, '_> { (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re), _ => false, }; - (is_eq && (!self.should_ignore(left) || !self.should_ignore(right))) - || self.inner.expr_fallback.as_mut().map_or(false, |f| f(left, right)) + is_eq || self.inner.expr_fallback.as_mut().map_or(false, |f| f(left, right)) } fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 34a1cdaf1d52a..2fdda9fac1629 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1,4 +1,3 @@ -#![feature(array_chunks)] #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(let_else)] @@ -2142,7 +2141,7 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { static TEST_ITEM_NAMES_CACHE: OnceLock>>> = OnceLock::new(); -fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool { +fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool { let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default())); let mut map: MutexGuard<'_, FxHashMap>> = cache.lock().unwrap(); let value = map.entry(module); diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 23ba7c712779e..e693e6837592f 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-07-28" +channel = "nightly-2022-07-15" components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index c1ec2bd5bd665..c219c7de830ef 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -94,8 +94,6 @@ struct ClippyCallbacks { } impl rustc_driver::Callbacks for ClippyCallbacks { - // JUSTIFICATION: necessary in clippy driver to set `mir_opt_level` - #[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] fn config(&mut self, config: &mut interface::Config) { let previous = config.register_lints.take(); let clippy_args_var = self.clippy_args_var.take(); diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 92ac1a2be5614..3615d07154dfb 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -433,7 +433,7 @@ fn rustfix_coverage_known_exceptions_accuracy() { let rs_path = Path::new("tests/ui").join(filename); assert!( rs_path.exists(), - "`{}` does not exist", + "`{}` does not exists", rs_path.strip_prefix(env!("CARGO_MANIFEST_DIR")).unwrap().display() ); let fixed_path = rs_path.with_extension("fixed"); @@ -445,45 +445,6 @@ fn rustfix_coverage_known_exceptions_accuracy() { } } -#[test] -fn ui_cargo_toml_metadata() { - let ui_cargo_path = Path::new("tests/ui-cargo"); - let cargo_common_metadata_path = ui_cargo_path.join("cargo_common_metadata"); - let publish_exceptions = - ["fail_publish", "fail_publish_true", "pass_publish_empty"].map(|path| cargo_common_metadata_path.join(path)); - - for entry in walkdir::WalkDir::new(ui_cargo_path) { - let entry = entry.unwrap(); - let path = entry.path(); - if path.file_name() != Some(OsStr::new("Cargo.toml")) { - continue; - } - - let toml = fs::read_to_string(path).unwrap().parse::().unwrap(); - - let package = toml.as_table().unwrap().get("package").unwrap().as_table().unwrap(); - - let name = package.get("name").unwrap().as_str().unwrap().replace('-', "_"); - assert!( - path.parent() - .unwrap() - .components() - .map(|component| component.as_os_str().to_string_lossy().replace('-', "_")) - .any(|s| *s == name) - || path.starts_with(&cargo_common_metadata_path), - "{:?} has incorrect package name", - path - ); - - let publish = package.get("publish").and_then(toml::Value::as_bool).unwrap_or(true); - assert!( - !publish || publish_exceptions.contains(&path.parent().unwrap().to_path_buf()), - "{:?} lacks `publish = false`", - path - ); - } -} - /// Restores an env var on drop #[must_use] struct VarGuard { diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml index bc8e428f8595b..ae0a603299629 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cargo_common_metadata_fail" +name = "cargo_common_metadata" version = "0.1.0" publish = false diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr index 86953142befad..5e9aa8dc36a6e 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr @@ -1,16 +1,16 @@ -error: package `cargo_common_metadata_fail` is missing `package.description` metadata +error: package `cargo_common_metadata` is missing `package.description` metadata | = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` -error: package `cargo_common_metadata_fail` is missing `either package.license or package.license_file` metadata +error: package `cargo_common_metadata` is missing `either package.license or package.license_file` metadata -error: package `cargo_common_metadata_fail` is missing `package.repository` metadata +error: package `cargo_common_metadata` is missing `package.repository` metadata -error: package `cargo_common_metadata_fail` is missing `package.readme` metadata +error: package `cargo_common_metadata` is missing `package.readme` metadata -error: package `cargo_common_metadata_fail` is missing `package.keywords` metadata +error: package `cargo_common_metadata` is missing `package.keywords` metadata -error: package `cargo_common_metadata_fail` is missing `package.categories` metadata +error: package `cargo_common_metadata` is missing `package.categories` metadata error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.toml index 5005b83f59d14..7595696353cd4 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cargo_common_metadata_fail_publish" +name = "cargo_common_metadata" version = "0.1.0" publish = ["some-registry-name"] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr index ac1b5e8e90347..5e9aa8dc36a6e 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr @@ -1,16 +1,16 @@ -error: package `cargo_common_metadata_fail_publish` is missing `package.description` metadata +error: package `cargo_common_metadata` is missing `package.description` metadata | = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` -error: package `cargo_common_metadata_fail_publish` is missing `either package.license or package.license_file` metadata +error: package `cargo_common_metadata` is missing `either package.license or package.license_file` metadata -error: package `cargo_common_metadata_fail_publish` is missing `package.repository` metadata +error: package `cargo_common_metadata` is missing `package.repository` metadata -error: package `cargo_common_metadata_fail_publish` is missing `package.readme` metadata +error: package `cargo_common_metadata` is missing `package.readme` metadata -error: package `cargo_common_metadata_fail_publish` is missing `package.keywords` metadata +error: package `cargo_common_metadata` is missing `package.keywords` metadata -error: package `cargo_common_metadata_fail_publish` is missing `package.categories` metadata +error: package `cargo_common_metadata` is missing `package.categories` metadata error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.toml index 51858eecd0a6f..7e5b88383ccc3 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cargo_common_metadata_fail_publish_true" +name = "cargo_common_metadata" version = "0.1.0" publish = true diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr index be32c0dc418fa..5e9aa8dc36a6e 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr @@ -1,16 +1,16 @@ -error: package `cargo_common_metadata_fail_publish_true` is missing `package.description` metadata +error: package `cargo_common_metadata` is missing `package.description` metadata | = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` -error: package `cargo_common_metadata_fail_publish_true` is missing `either package.license or package.license_file` metadata +error: package `cargo_common_metadata` is missing `either package.license or package.license_file` metadata -error: package `cargo_common_metadata_fail_publish_true` is missing `package.repository` metadata +error: package `cargo_common_metadata` is missing `package.repository` metadata -error: package `cargo_common_metadata_fail_publish_true` is missing `package.readme` metadata +error: package `cargo_common_metadata` is missing `package.readme` metadata -error: package `cargo_common_metadata_fail_publish_true` is missing `package.keywords` metadata +error: package `cargo_common_metadata` is missing `package.keywords` metadata -error: package `cargo_common_metadata_fail_publish_true` is missing `package.categories` metadata +error: package `cargo_common_metadata` is missing `package.categories` metadata error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml index 9f6e51fb4d9f0..cb4774d43a2c1 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cargo_common_metadata_pass" +name = "cargo_common_metadata" version = "0.1.0" publish = false description = "A test package for the cargo_common_metadata lint" diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml index 828efee3a8f8b..0a879c99b5bd8 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cargo_common_metadata_pass_publish_empty" +name = "cargo_common_metadata" version = "0.1.0" publish = [] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml index 45a5bf7c57459..ae0a603299629 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cargo_common_metadata_pass_publish_false" +name = "cargo_common_metadata" version = "0.1.0" publish = false diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_diff/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_diff/Cargo.toml index 946d1b366f099..73ec29c5803bd 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_diff/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_diff/Cargo.toml @@ -2,7 +2,6 @@ name = "fail-both-diff" version = "0.1.0" rust-version = "1.56" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_same/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_same/Cargo.toml index 46b92a1050e31..2d6d547e4fe3a 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_same/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_same/Cargo.toml @@ -2,7 +2,6 @@ name = "fail-both-same" version = "0.1.0" rust-version = "1.57.0" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_cargo/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_cargo/Cargo.toml index 189cc9f68dc4b..36a53bd829d9e 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_cargo/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_cargo/Cargo.toml @@ -2,7 +2,6 @@ name = "fail-cargo" version = "0.1.0" rust-version = "1.56.1" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_clippy/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_clippy/Cargo.toml index bdb7f261d9e4f..9f644a1a39a50 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_clippy/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_clippy/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "fail-clippy" version = "0.1.0" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_file_attr/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_file_attr/Cargo.toml index 84448ea41f647..5380e993b2936 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_file_attr/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_file_attr/Cargo.toml @@ -2,7 +2,6 @@ name = "fail-file-attr" version = "0.1.0" rust-version = "1.13" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_both_same/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_both_same/Cargo.toml index 809c0e74875b9..1f9bd8f9a84e3 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_both_same/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_both_same/Cargo.toml @@ -1,8 +1,7 @@ [package] -name = "pass-both-same" +name = "fail-both-same" version = "0.1.0" rust-version = "1.13.0" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_cargo/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_cargo/Cargo.toml index 32d404f842cf4..77538027c0f87 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_cargo/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_cargo/Cargo.toml @@ -1,8 +1,7 @@ [package] -name = "pass-cargo" +name = "fail-cargo" version = "0.1.0" rust-version = "1.13.0" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_clippy/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_clippy/Cargo.toml index cc937d6e62547..9f644a1a39a50 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_clippy/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_clippy/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "pass-clippy" +name = "fail-clippy" version = "0.1.0" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_file_attr/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_file_attr/Cargo.toml index 8ef689880d414..f0387cd90b80f 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_file_attr/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_file_attr/Cargo.toml @@ -1,8 +1,7 @@ [package] -name = "pass-file-attr" +name = "fail-file-attr" version = "0.1.0" rust-version = "1.59" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/warn_both_diff/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/warn_both_diff/Cargo.toml index e9f94594f702c..a19d5b33fe563 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/warn_both_diff/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/warn_both_diff/Cargo.toml @@ -2,7 +2,6 @@ name = "warn-both-diff" version = "0.1.0" rust-version = "1.56.0" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/Cargo.toml b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/Cargo.toml index b3d36a9fb6457..27b61c09fb48b 100644 --- a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/Cargo.toml @@ -1,8 +1,7 @@ [package] -name = "fail-mod" +name = "fail" version = "0.1.0" edition = "2018" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.toml b/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.toml index 3610d13c1f30d..27b61c09fb48b 100644 --- a/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.toml @@ -1,8 +1,7 @@ [package] -name = "fail-no-mod" +name = "fail" version = "0.1.0" edition = "2018" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/Cargo.toml b/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/Cargo.toml index 1c2991695bc0c..27b61c09fb48b 100644 --- a/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/Cargo.toml @@ -1,8 +1,7 @@ [package] -name = "pass-mod" +name = "fail" version = "0.1.0" edition = "2018" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/tests/ui-cargo/module_style/pass_no_mod/Cargo.toml b/src/tools/clippy/tests/ui-cargo/module_style/pass_no_mod/Cargo.toml index 4180aaf5185cf..3c0896dd2cda7 100644 --- a/src/tools/clippy/tests/ui-cargo/module_style/pass_no_mod/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/module_style/pass_no_mod/Cargo.toml @@ -1,8 +1,7 @@ [package] -name = "pass-no-mod" +name = "pass" version = "0.1.0" edition = "2018" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/tests/ui-cargo/multiple_config_files/no_warn/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_config_files/no_warn/Cargo.toml index 7eb56cc4e9d97..79c973cbfd2d5 100644 --- a/src/tools/clippy/tests/ui-cargo/multiple_config_files/no_warn/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/multiple_config_files/no_warn/Cargo.toml @@ -2,7 +2,6 @@ name = "no_warn" version = "0.1.0" edition = "2021" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/Cargo.toml index b4847d070aab8..3d5c707579bca 100644 --- a/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/Cargo.toml @@ -2,7 +2,6 @@ name = "warn" version = "0.1.0" edition = "2021" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/src/main.rs index e7a11a969c037..2d0b4a7948c4a 100644 --- a/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/src/main.rs @@ -1,3 +1,5 @@ +// ignore-windows + fn main() { println!("Hello, world!"); } diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml index 6c46571c5bf6e..b4b49bb369acd 100644 --- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "multiple_crate_versions" +name = "cargo_common_metadata" version = "0.1.0" publish = false diff --git a/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr b/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr index 5331075885c1d..67e1a07b7f5fa 100644 --- a/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr +++ b/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr @@ -17,7 +17,7 @@ LL | #![deny(clippy::internal)] | ^^^^^^^^^^^^^^^^ = note: `#[deny(clippy::invalid_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]` = help: please use a valid sematic version, see `doc/adding_lints.md` - = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this item has an invalid `clippy::version` attribute --> $DIR/check_clippy_version_attribute.rs:48:1 @@ -32,7 +32,7 @@ LL | | } | |_^ | = help: please use a valid sematic version, see `doc/adding_lints.md` - = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this lint is missing the `clippy::version` attribute or version value --> $DIR/check_clippy_version_attribute.rs:59:1 @@ -48,7 +48,7 @@ LL | | } | = note: `#[deny(clippy::missing_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]` = help: please use a `clippy::version` attribute, see `doc/adding_lints.md` - = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this lint is missing the `clippy::version` attribute or version value --> $DIR/check_clippy_version_attribute.rs:67:1 @@ -62,7 +62,7 @@ LL | | } | |_^ | = help: please use a `clippy::version` attribute, see `doc/adding_lints.md` - = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui-internal/default_lint.stderr b/src/tools/clippy/tests/ui-internal/default_lint.stderr index 8961bd4624f45..af6735f4e4d82 100644 --- a/src/tools/clippy/tests/ui-internal/default_lint.stderr +++ b/src/tools/clippy/tests/ui-internal/default_lint.stderr @@ -15,7 +15,7 @@ note: the lint level is defined here LL | #![deny(clippy::internal)] | ^^^^^^^^^^^^^^^^ = note: `#[deny(clippy::default_lint)]` implied by `#[deny(clippy::internal)]` - = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui-internal/if_chain_style.stderr b/src/tools/clippy/tests/ui-internal/if_chain_style.stderr index 24106510e73be..d0f100f00692f 100644 --- a/src/tools/clippy/tests/ui-internal/if_chain_style.stderr +++ b/src/tools/clippy/tests/ui-internal/if_chain_style.stderr @@ -56,7 +56,7 @@ LL | | } LL | | } | |_____^ | - = note: this error originates in the macro `__if_chain` which comes from the expansion of the macro `if_chain` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__if_chain` (in Nightly builds, run with -Z macro-backtrace for more info) error: `let` expression should be above the `if_chain!` --> $DIR/if_chain_style.rs:40:9 diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs b/src/tools/clippy/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs deleted file mode 100644 index 195fabdbf710b..0000000000000 --- a/src/tools/clippy/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![warn(clippy::arithmetic)] - -use core::ops::Add; - -#[derive(Clone, Copy)] -struct Point { - x: i32, - y: i32, -} - -impl Add for Point { - type Output = Self; - - fn add(self, other: Self) -> Self { - todo!() - } -} - -fn main() { - let _ = Point { x: 1, y: 0 } + Point { x: 2, y: 3 }; - - let point: Point = Point { x: 1, y: 0 }; - let _ = point + point; -} diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_allowed/clippy.toml b/src/tools/clippy/tests/ui-toml/arithmetic_allowed/clippy.toml deleted file mode 100644 index cc40570b12a08..0000000000000 --- a/src/tools/clippy/tests/ui-toml/arithmetic_allowed/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -arithmetic-allowed = ["Point"] diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index fe5139c47680c..1d87fd91a2532 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -3,7 +3,6 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie allow-expect-in-tests allow-unwrap-in-tests allowed-scripts - arithmetic-allowed array-size-threshold avoid-breaking-exported-api await-holding-invalid-types diff --git a/src/tools/clippy/tests/ui/arithmetic.fixed b/src/tools/clippy/tests/ui/arithmetic.fixed deleted file mode 100644 index a2a1c4394c21f..0000000000000 --- a/src/tools/clippy/tests/ui/arithmetic.fixed +++ /dev/null @@ -1,27 +0,0 @@ -// run-rustfix - -#![allow(clippy::unnecessary_owned_empty_strings)] -#![feature(saturating_int_impl)] -#![warn(clippy::arithmetic)] - -use core::num::{Saturating, Wrapping}; - -pub fn hard_coded_allowed() { - let _ = Saturating(0u32) + Saturating(0u32); - let _ = String::new() + ""; - let _ = Wrapping(0u32) + Wrapping(0u32); - - let saturating: Saturating = Saturating(0u32); - let string: String = String::new(); - let wrapping: Wrapping = Wrapping(0u32); - - let inferred_saturating = saturating + saturating; - let inferred_string = string + ""; - let inferred_wrapping = wrapping + wrapping; - - let _ = inferred_saturating + inferred_saturating; - let _ = inferred_string + ""; - let _ = inferred_wrapping + inferred_wrapping; -} - -fn main() {} diff --git a/src/tools/clippy/tests/ui/arithmetic.rs b/src/tools/clippy/tests/ui/arithmetic.rs deleted file mode 100644 index a2a1c4394c21f..0000000000000 --- a/src/tools/clippy/tests/ui/arithmetic.rs +++ /dev/null @@ -1,27 +0,0 @@ -// run-rustfix - -#![allow(clippy::unnecessary_owned_empty_strings)] -#![feature(saturating_int_impl)] -#![warn(clippy::arithmetic)] - -use core::num::{Saturating, Wrapping}; - -pub fn hard_coded_allowed() { - let _ = Saturating(0u32) + Saturating(0u32); - let _ = String::new() + ""; - let _ = Wrapping(0u32) + Wrapping(0u32); - - let saturating: Saturating = Saturating(0u32); - let string: String = String::new(); - let wrapping: Wrapping = Wrapping(0u32); - - let inferred_saturating = saturating + saturating; - let inferred_string = string + ""; - let inferred_wrapping = wrapping + wrapping; - - let _ = inferred_saturating + inferred_saturating; - let _ = inferred_string + ""; - let _ = inferred_wrapping + inferred_wrapping; -} - -fn main() {} diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.fixed b/src/tools/clippy/tests/ui/assertions_on_result_states.fixed deleted file mode 100644 index 7bde72e4b6b57..0000000000000 --- a/src/tools/clippy/tests/ui/assertions_on_result_states.fixed +++ /dev/null @@ -1,69 +0,0 @@ -// run-rustfix -#![warn(clippy::assertions_on_result_states)] - -use std::result::Result; - -struct Foo; - -#[derive(Debug)] -struct DebugFoo; - -#[derive(Copy, Clone, Debug)] -struct CopyFoo; - -macro_rules! get_ok_macro { - () => { - Ok::<_, DebugFoo>(Foo) - }; -} - -fn main() { - // test ok - let r: Result = Ok(Foo); - debug_assert!(r.is_ok()); - r.unwrap(); - - // test ok with non-debug error type - let r: Result = Ok(Foo); - assert!(r.is_ok()); - - // test temporary ok - fn get_ok() -> Result { - Ok(Foo) - } - get_ok().unwrap(); - - // test macro ok - get_ok_macro!().unwrap(); - - // test ok that shouldn't be moved - let r: Result = Ok(CopyFoo); - fn test_ref_unmoveable_ok(r: &Result) { - assert!(r.is_ok()); - } - test_ref_unmoveable_ok(&r); - assert!(r.is_ok()); - r.unwrap(); - - // test ok that is copied - let r: Result = Ok(CopyFoo); - r.unwrap(); - r.unwrap(); - - // test reference to ok - let r: Result = Ok(CopyFoo); - fn test_ref_copy_ok(r: &Result) { - r.unwrap(); - } - test_ref_copy_ok(&r); - r.unwrap(); - - // test err - let r: Result = Err(Foo); - debug_assert!(r.is_err()); - r.unwrap_err(); - - // test err with non-debug value type - let r: Result = Err(Foo); - assert!(r.is_err()); -} diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.rs b/src/tools/clippy/tests/ui/assertions_on_result_states.rs deleted file mode 100644 index 4c5af81efc23f..0000000000000 --- a/src/tools/clippy/tests/ui/assertions_on_result_states.rs +++ /dev/null @@ -1,69 +0,0 @@ -// run-rustfix -#![warn(clippy::assertions_on_result_states)] - -use std::result::Result; - -struct Foo; - -#[derive(Debug)] -struct DebugFoo; - -#[derive(Copy, Clone, Debug)] -struct CopyFoo; - -macro_rules! get_ok_macro { - () => { - Ok::<_, DebugFoo>(Foo) - }; -} - -fn main() { - // test ok - let r: Result = Ok(Foo); - debug_assert!(r.is_ok()); - assert!(r.is_ok()); - - // test ok with non-debug error type - let r: Result = Ok(Foo); - assert!(r.is_ok()); - - // test temporary ok - fn get_ok() -> Result { - Ok(Foo) - } - assert!(get_ok().is_ok()); - - // test macro ok - assert!(get_ok_macro!().is_ok()); - - // test ok that shouldn't be moved - let r: Result = Ok(CopyFoo); - fn test_ref_unmoveable_ok(r: &Result) { - assert!(r.is_ok()); - } - test_ref_unmoveable_ok(&r); - assert!(r.is_ok()); - r.unwrap(); - - // test ok that is copied - let r: Result = Ok(CopyFoo); - assert!(r.is_ok()); - r.unwrap(); - - // test reference to ok - let r: Result = Ok(CopyFoo); - fn test_ref_copy_ok(r: &Result) { - assert!(r.is_ok()); - } - test_ref_copy_ok(&r); - r.unwrap(); - - // test err - let r: Result = Err(Foo); - debug_assert!(r.is_err()); - assert!(r.is_err()); - - // test err with non-debug value type - let r: Result = Err(Foo); - assert!(r.is_err()); -} diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.stderr b/src/tools/clippy/tests/ui/assertions_on_result_states.stderr deleted file mode 100644 index 13c2dd877a976..0000000000000 --- a/src/tools/clippy/tests/ui/assertions_on_result_states.stderr +++ /dev/null @@ -1,40 +0,0 @@ -error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:24:5 - | -LL | assert!(r.is_ok()); - | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` - | - = note: `-D clippy::assertions-on-result-states` implied by `-D warnings` - -error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:34:5 - | -LL | assert!(get_ok().is_ok()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok().unwrap()` - -error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:37:5 - | -LL | assert!(get_ok_macro!().is_ok()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok_macro!().unwrap()` - -error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:50:5 - | -LL | assert!(r.is_ok()); - | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` - -error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:56:9 - | -LL | assert!(r.is_ok()); - | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` - -error: called `assert!` with `Result::is_err` - --> $DIR/assertions_on_result_states.rs:64:5 - | -LL | assert!(r.is_err()); - | ^^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap_err()` - -error: aborting due to 6 previous errors - diff --git a/src/tools/clippy/tests/ui/assign_ops.fixed b/src/tools/clippy/tests/ui/assign_ops.fixed index da034b51cfdb9..52b1b3afe16fe 100644 --- a/src/tools/clippy/tests/ui/assign_ops.fixed +++ b/src/tools/clippy/tests/ui/assign_ops.fixed @@ -1,7 +1,5 @@ // run-rustfix -use core::num::Wrapping; - #[allow(dead_code, unused_assignments)] #[warn(clippy::assign_op_pattern)] fn main() { @@ -20,13 +18,4 @@ fn main() { a = 6 << a; let mut s = String::new(); s += "bla"; - - // Issue #9180 - let mut a = Wrapping(0u32); - a += Wrapping(1u32); - let mut v = vec![0u32, 1u32]; - v[0] += v[1]; - let mut v = vec![Wrapping(0u32), Wrapping(1u32)]; - v[0] = v[0] + v[1]; - let _ = || v[0] = v[0] + v[1]; } diff --git a/src/tools/clippy/tests/ui/assign_ops.rs b/src/tools/clippy/tests/ui/assign_ops.rs index 337bb02c8a612..527a46b2c2bb9 100644 --- a/src/tools/clippy/tests/ui/assign_ops.rs +++ b/src/tools/clippy/tests/ui/assign_ops.rs @@ -1,7 +1,5 @@ // run-rustfix -use core::num::Wrapping; - #[allow(dead_code, unused_assignments)] #[warn(clippy::assign_op_pattern)] fn main() { @@ -20,13 +18,4 @@ fn main() { a = 6 << a; let mut s = String::new(); s = s + "bla"; - - // Issue #9180 - let mut a = Wrapping(0u32); - a = a + Wrapping(1u32); - let mut v = vec![0u32, 1u32]; - v[0] = v[0] + v[1]; - let mut v = vec![Wrapping(0u32), Wrapping(1u32)]; - v[0] = v[0] + v[1]; - let _ = || v[0] = v[0] + v[1]; } diff --git a/src/tools/clippy/tests/ui/assign_ops.stderr b/src/tools/clippy/tests/ui/assign_ops.stderr index 63a938ab4b435..3486bd8da4d07 100644 --- a/src/tools/clippy/tests/ui/assign_ops.stderr +++ b/src/tools/clippy/tests/ui/assign_ops.stderr @@ -1,5 +1,5 @@ error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:9:5 + --> $DIR/assign_ops.rs:7:5 | LL | a = a + 1; | ^^^^^^^^^ help: replace it with: `a += 1` @@ -7,64 +7,52 @@ LL | a = a + 1; = note: `-D clippy::assign-op-pattern` implied by `-D warnings` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:10:5 + --> $DIR/assign_ops.rs:8:5 | LL | a = 1 + a; | ^^^^^^^^^ help: replace it with: `a += 1` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:11:5 + --> $DIR/assign_ops.rs:9:5 | LL | a = a - 1; | ^^^^^^^^^ help: replace it with: `a -= 1` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:12:5 + --> $DIR/assign_ops.rs:10:5 | LL | a = a * 99; | ^^^^^^^^^^ help: replace it with: `a *= 99` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:13:5 + --> $DIR/assign_ops.rs:11:5 | LL | a = 42 * a; | ^^^^^^^^^^ help: replace it with: `a *= 42` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:14:5 + --> $DIR/assign_ops.rs:12:5 | LL | a = a / 2; | ^^^^^^^^^ help: replace it with: `a /= 2` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:15:5 + --> $DIR/assign_ops.rs:13:5 | LL | a = a % 5; | ^^^^^^^^^ help: replace it with: `a %= 5` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:16:5 + --> $DIR/assign_ops.rs:14:5 | LL | a = a & 1; | ^^^^^^^^^ help: replace it with: `a &= 1` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:22:5 + --> $DIR/assign_ops.rs:20:5 | LL | s = s + "bla"; | ^^^^^^^^^^^^^ help: replace it with: `s += "bla"` -error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:26:5 - | -LL | a = a + Wrapping(1u32); - | ^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a += Wrapping(1u32)` - -error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:28:5 - | -LL | v[0] = v[0] + v[1]; - | ^^^^^^^^^^^^^^^^^^ help: replace it with: `v[0] += v[1]` - -error: aborting due to 11 previous errors +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr index 638e4a5484932..a1e37e7317b2e 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr @@ -30,7 +30,15 @@ LL | const VAL: T; LL | impl TypeVal for Multiply where N: TypeVal {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation -error: aborting due to 3 previous errors +error: constant expression depends on a generic parameter + --> $DIR/ice-6252.rs:13:9 + | +LL | [1; >::VAL]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 4 previous errors Some errors have detailed explanations: E0046, E0412. For more information about an error, try `rustc --explain E0046`. diff --git a/src/tools/clippy/tests/ui/crashes/ice-9238.rs b/src/tools/clippy/tests/ui/crashes/ice-9238.rs deleted file mode 100644 index ee6abd519f16e..0000000000000 --- a/src/tools/clippy/tests/ui/crashes/ice-9238.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![allow(incomplete_features)] -#![feature(generic_const_exprs)] -#![warn(clippy::branches_sharing_code)] - -const fn f() -> usize { - 2 -} -const C: [f64; f()] = [0f64; f()]; - -fn main() { - let _ = if true { C[0] } else { C[1] }; -} diff --git a/src/tools/clippy/tests/ui/crashes/ice-9242.rs b/src/tools/clippy/tests/ui/crashes/ice-9242.rs deleted file mode 100644 index 0099e6e2f34b8..0000000000000 --- a/src/tools/clippy/tests/ui/crashes/ice-9242.rs +++ /dev/null @@ -1,8 +0,0 @@ -enum E { - X(), - Y, -} - -fn main() { - let _ = if let E::X() = E::X() { 1 } else { 2 }; -} diff --git a/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs b/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs index 1b3bcece6f1e7..7ff5a16ed86ca 100644 --- a/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs +++ b/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs @@ -1,4 +1,5 @@ // ignore-macos +// ignore-windows #![feature(rustc_attrs)] diff --git a/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.stderr b/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.stderr index 459cf12a1c209..f52fc949f6c3e 100644 --- a/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.stderr +++ b/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.stderr @@ -1,5 +1,5 @@ error: recursing into entrypoint `a` - --> $DIR/entrypoint_recursion.rs:10:5 + --> $DIR/entrypoint_recursion.rs:11:5 | LL | a(); | ^ diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs index 896596b567922..62af545db503b 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs @@ -31,25 +31,9 @@ const NO_ANN: &dyn Display = &70; static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); //^ there should be no lints on this line -mod issue_8493 { - use std::cell::Cell; - - thread_local! { - static _BAR: Cell = const { Cell::new(0) }; - } - - macro_rules! issue_8493 { - () => { - const _BAZ: Cell = Cell::new(0); //~ ERROR interior mutable - static _FOOBAR: () = { - thread_local! { - static _VAR: Cell = const { Cell::new(0) }; - } - }; - }; - } - - issue_8493!(); +// issue #8493 +thread_local! { + static THREAD_LOCAL: Cell = const { Cell::new(0) }; } fn main() {} diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr index 1fd6d7322a76c..fd0689dfc4c99 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr @@ -35,16 +35,5 @@ LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable | = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) -error: a `const` item should never be interior mutable - --> $DIR/others.rs:43:13 - | -LL | const _BAZ: Cell = Cell::new(0); //~ ERROR interior mutable - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | issue_8493!(); - | ------------- in this macro invocation - | - = note: this error originates in the macro `issue_8493` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/format.fixed b/src/tools/clippy/tests/ui/format.fixed index f4db2d20c713c..d08f8f52495ad 100644 --- a/src/tools/clippy/tests/ui/format.fixed +++ b/src/tools/clippy/tests/ui/format.fixed @@ -84,10 +84,4 @@ fn main() { let _ = x.to_string(); let _ = format!("{x:?}"); // Don't lint on debug let _ = x.to_string(); - - // Issue #9234 - let abc = "abc"; - let _ = abc.to_string(); - let xx = "xx"; - let _ = xx.to_string(); } diff --git a/src/tools/clippy/tests/ui/format.rs b/src/tools/clippy/tests/ui/format.rs index bf687cb1e96c7..4a10b580d2600 100644 --- a/src/tools/clippy/tests/ui/format.rs +++ b/src/tools/clippy/tests/ui/format.rs @@ -86,10 +86,4 @@ fn main() { let _ = format!("{x}"); let _ = format!("{x:?}"); // Don't lint on debug let _ = format!("{y}", y = x); - - // Issue #9234 - let abc = "abc"; - let _ = format!("{abc}"); - let xx = "xx"; - let _ = format!("{xx}"); } diff --git a/src/tools/clippy/tests/ui/format.stderr b/src/tools/clippy/tests/ui/format.stderr index a0f8e7d193791..f25c7fb1ff1cb 100644 --- a/src/tools/clippy/tests/ui/format.stderr +++ b/src/tools/clippy/tests/ui/format.stderr @@ -111,17 +111,5 @@ error: useless use of `format!` LL | let _ = format!("{y}", y = x); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` -error: useless use of `format!` - --> $DIR/format.rs:92:13 - | -LL | let _ = format!("{abc}"); - | ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()` - -error: useless use of `format!` - --> $DIR/format.rs:94:13 - | -LL | let _ = format!("{xx}"); - | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()` - -error: aborting due to 19 previous errors +error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs index 7aba5b447d553..dbfeb4379d513 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.rs +++ b/src/tools/clippy/tests/ui/match_same_arms2.rs @@ -1,5 +1,5 @@ #![warn(clippy::match_same_arms)] -#![allow(clippy::blacklisted_name, clippy::diverging_sub_expression)] +#![allow(clippy::blacklisted_name)] fn bar(_: T) {} fn foo() -> bool { @@ -227,12 +227,4 @@ fn main() { Some(Bar { y: 0, x: 5, .. }) => 1, _ => 200, }; - - let _ = match 0 { - 0 => todo!(), - 1 => todo!(), - 2 => core::convert::identity::(todo!()), - 3 => core::convert::identity::(todo!()), - _ => 5, - }; } diff --git a/src/tools/clippy/tests/ui/mismatching_type_param_order.rs b/src/tools/clippy/tests/ui/mismatching_type_param_order.rs index 8c0da84d8e975..8f286c9304ccb 100644 --- a/src/tools/clippy/tests/ui/mismatching_type_param_order.rs +++ b/src/tools/clippy/tests/ui/mismatching_type_param_order.rs @@ -57,8 +57,4 @@ fn main() { B: Copy, { } - - // if the types are complicated, do not lint - impl Foo<(K, V), B> {} - impl Foo<(K, V), A> {} } diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed index bfd2725ecaaa8..09afe2ddbbf62 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.fixed +++ b/src/tools/clippy/tests/ui/needless_borrow.fixed @@ -158,28 +158,3 @@ fn check_expect_suppression() { #[expect(clippy::needless_borrow)] let _ = x(&&a); } - -#[allow(dead_code)] -mod issue9160 { - pub struct S { - f: F, - } - - impl S - where - F: Fn() -> T, - { - fn calls_field(&self) -> T { - (self.f)() - } - } - - impl S - where - F: FnMut() -> T, - { - fn calls_mut_field(&mut self) -> T { - (self.f)() - } - } -} diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs index c457d8c547188..3ae4722a1f898 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.rs +++ b/src/tools/clippy/tests/ui/needless_borrow.rs @@ -158,28 +158,3 @@ fn check_expect_suppression() { #[expect(clippy::needless_borrow)] let _ = x(&&a); } - -#[allow(dead_code)] -mod issue9160 { - pub struct S { - f: F, - } - - impl S - where - F: Fn() -> T, - { - fn calls_field(&self) -> T { - (&self.f)() - } - } - - impl S - where - F: FnMut() -> T, - { - fn calls_mut_field(&mut self) -> T { - (&mut self.f)() - } - } -} diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr index 66588689d8185..8a2e2b9895908 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.stderr +++ b/src/tools/clippy/tests/ui/needless_borrow.stderr @@ -120,17 +120,5 @@ error: this expression creates a reference which is immediately dereferenced by LL | (&&5).foo(); | ^^^^^ help: change this to: `(&5)` -error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:173:13 - | -LL | (&self.f)() - | ^^^^^^^^^ help: change this to: `(self.f)` - -error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:182:13 - | -LL | (&mut self.f)() - | ^^^^^^^^^^^^^ help: change this to: `(self.f)` - -error: aborting due to 22 previous errors +error: aborting due to 20 previous errors diff --git a/src/tools/clippy/tests/ui/obfuscated_if_else.fixed b/src/tools/clippy/tests/ui/obfuscated_if_else.fixed deleted file mode 100644 index 62d932c2c6b79..0000000000000 --- a/src/tools/clippy/tests/ui/obfuscated_if_else.fixed +++ /dev/null @@ -1,7 +0,0 @@ -// run-rustfix - -#![warn(clippy::obfuscated_if_else)] - -fn main() { - if true { "a" } else { "b" }; -} diff --git a/src/tools/clippy/tests/ui/obfuscated_if_else.rs b/src/tools/clippy/tests/ui/obfuscated_if_else.rs deleted file mode 100644 index 273be9092a745..0000000000000 --- a/src/tools/clippy/tests/ui/obfuscated_if_else.rs +++ /dev/null @@ -1,7 +0,0 @@ -// run-rustfix - -#![warn(clippy::obfuscated_if_else)] - -fn main() { - true.then_some("a").unwrap_or("b"); -} diff --git a/src/tools/clippy/tests/ui/obfuscated_if_else.stderr b/src/tools/clippy/tests/ui/obfuscated_if_else.stderr deleted file mode 100644 index e4180c288693f..0000000000000 --- a/src/tools/clippy/tests/ui/obfuscated_if_else.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: use of `.then_some(..).unwrap_or(..)` can be written more clearly with `if .. else ..` - --> $DIR/obfuscated_if_else.rs:6:5 - | -LL | true.then_some("a").unwrap_or("b"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { "a" } else { "b" }` - | - = note: `-D clippy::obfuscated-if-else` implied by `-D warnings` - -error: aborting due to previous error - diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.rs b/src/tools/clippy/tests/ui/std_instead_of_core.rs index 6b27475de4c87..74f05ec1f658a 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.rs +++ b/src/tools/clippy/tests/ui/std_instead_of_core.rs @@ -9,8 +9,6 @@ fn std_instead_of_core() { use std::hash::Hasher; // Absolute path use ::std::hash::Hash; - // Don't lint on `env` macro - use std::env; // Multiple imports use std::fmt::{Debug, Result}; @@ -22,14 +20,10 @@ fn std_instead_of_core() { // Types let cell = std::cell::Cell::new(8u32); let cell_absolute = ::std::cell::Cell::new(8u32); - - let _ = std::env!("PATH"); } #[warn(clippy::std_instead_of_alloc)] fn std_instead_of_alloc() { - // Only lint once. - use std::vec; use std::vec::Vec; } diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.stderr b/src/tools/clippy/tests/ui/std_instead_of_core.stderr index bc49dabf5868a..9f1644835c10d 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.stderr +++ b/src/tools/clippy/tests/ui/std_instead_of_core.stderr @@ -16,7 +16,7 @@ LL | use ::std::hash::Hash; = help: consider importing the item from `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:16:20 + --> $DIR/std_instead_of_core.rs:14:20 | LL | use std::fmt::{Debug, Result}; | ^^^^^ @@ -24,7 +24,7 @@ LL | use std::fmt::{Debug, Result}; = help: consider importing the item from `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:16:27 + --> $DIR/std_instead_of_core.rs:14:27 | LL | use std::fmt::{Debug, Result}; | ^^^^^^ @@ -32,7 +32,7 @@ LL | use std::fmt::{Debug, Result}; = help: consider importing the item from `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:19:15 + --> $DIR/std_instead_of_core.rs:17:15 | LL | let ptr = std::ptr::null::(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | let ptr = std::ptr::null::(); = help: consider importing the item from `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:20:19 + --> $DIR/std_instead_of_core.rs:18:19 | LL | let ptr_mut = ::std::ptr::null_mut::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | let ptr_mut = ::std::ptr::null_mut::(); = help: consider importing the item from `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:23:16 + --> $DIR/std_instead_of_core.rs:21:16 | LL | let cell = std::cell::Cell::new(8u32); | ^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | let cell = std::cell::Cell::new(8u32); = help: consider importing the item from `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:24:25 + --> $DIR/std_instead_of_core.rs:22:25 | LL | let cell_absolute = ::std::cell::Cell::new(8u32); | ^^^^^^^^^^^^^^^^^ @@ -64,24 +64,16 @@ LL | let cell_absolute = ::std::cell::Cell::new(8u32); = help: consider importing the item from `core` error: used import from `std` instead of `alloc` - --> $DIR/std_instead_of_core.rs:32:9 - | -LL | use std::vec; - | ^^^^^^^^ - | - = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings` - = help: consider importing the item from `alloc` - -error: used import from `std` instead of `alloc` - --> $DIR/std_instead_of_core.rs:33:9 + --> $DIR/std_instead_of_core.rs:27:9 | LL | use std::vec::Vec; | ^^^^^^^^^^^^^ | + = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings` = help: consider importing the item from `alloc` error: used import from `alloc` instead of `core` - --> $DIR/std_instead_of_core.rs:38:9 + --> $DIR/std_instead_of_core.rs:32:9 | LL | use alloc::slice::from_ref; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -89,5 +81,5 @@ LL | use alloc::slice::from_ref; = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings` = help: consider importing the item from `core` -error: aborting due to 11 previous errors +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/unused_self.rs b/src/tools/clippy/tests/ui/unused_self.rs index 92e8e1dba69dd..08bf58fec7c3e 100644 --- a/src/tools/clippy/tests/ui/unused_self.rs +++ b/src/tools/clippy/tests/ui/unused_self.rs @@ -53,17 +53,8 @@ mod unused_self_allow { // shouldn't trigger fn unused_self_move(self) {} } - - pub struct D; - - impl D { - // shouldn't trigger for public methods - pub fn unused_self_move(self) {} - } } -pub use unused_self_allow::D; - mod used_self { use std::pin::Pin; diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index f8f193ddf83fb..17f2b77dab052 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -535,29 +535,6 @@ impl TestProps { } } -pub fn line_directive<'line>( - comment: &str, - ln: &'line str, -) -> Option<(Option<&'line str>, &'line str)> { - if ln.starts_with(comment) { - let ln = ln[comment.len()..].trim_start(); - if ln.starts_with('[') { - // A comment like `//[foo]` is specific to revision `foo` - if let Some(close_brace) = ln.find(']') { - let lncfg = &ln[1..close_brace]; - - Some((Some(lncfg), ln[(close_brace + 1)..].trim_start())) - } else { - panic!("malformed condition directive: expected `{}[foo]`, found `{}`", comment, ln) - } - } else { - Some((None, ln)) - } - } else { - None - } -} - fn iter_header(testfile: &Path, rdr: R, it: &mut dyn FnMut(Option<&str>, &str)) { if testfile.is_dir() { return; @@ -580,8 +557,17 @@ fn iter_header(testfile: &Path, rdr: R, it: &mut dyn FnMut(Option<&str> let ln = ln.trim(); if ln.starts_with("fn") || ln.starts_with("mod") { return; - } else if let Some((lncfg, ln)) = line_directive(comment, ln) { - it(lncfg, ln); + } else if ln.starts_with(comment) && ln[comment.len()..].trim_start().starts_with('[') { + // A comment like `//[foo]` is specific to revision `foo` + if let Some(close_brace) = ln.find(']') { + let open_brace = ln.find('[').unwrap(); + let lncfg = &ln[open_brace + 1..close_brace]; + it(Some(lncfg), ln[(close_brace + 1)..].trim_start()); + } else { + panic!("malformed condition directive: expected `{}[foo]`, found `{}`", comment, ln) + } + } else if ln.starts_with(comment) { + it(None, ln[comment.len()..].trim_start()); } } } @@ -871,13 +857,11 @@ pub fn make_test_description( let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(); let has_asm_support = util::has_asm_support(&config.target); let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target); - let has_cfi = util::CFI_SUPPORTED_TARGETS.contains(&&*config.target); let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_memtag = util::MEMTAG_SUPPORTED_TARGETS.contains(&&*config.target); - let has_shadow_call_stack = util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(&&*config.target); // for `-Z gcc-ld=lld` let has_rust_lld = config .compile_lib_path @@ -910,14 +894,11 @@ pub fn make_test_description( ignore |= !rustc_has_sanitizer_support && config.parse_name_directive(ln, "needs-sanitizer-support"); ignore |= !has_asan && config.parse_name_directive(ln, "needs-sanitizer-address"); - ignore |= !has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi"); ignore |= !has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak"); ignore |= !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory"); ignore |= !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread"); ignore |= !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress"); ignore |= !has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag"); - ignore |= !has_shadow_call_stack - && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack"); ignore |= config.target_panic == PanicStrategy::Abort && config.parse_name_directive(ln, "needs-unwind"); ignore |= config.target == "wasm32-unknown-unknown" diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index d3e5a2dd644af..5517b5a12c393 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -648,6 +648,8 @@ impl<'test> TestCx<'test> { } fn run_debuginfo_cdb_test(&self) { + assert!(self.revision.is_none(), "revisions not relevant here"); + let config = Config { target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags), host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags), @@ -693,12 +695,7 @@ impl<'test> TestCx<'test> { // Parse debugger commands etc from test files let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } = - match DebuggerCommands::parse_from( - &self.testpaths.file, - self.config, - prefixes, - self.revision, - ) { + match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) { Ok(cmds) => cmds, Err(e) => self.fatal(&e), }; @@ -759,6 +756,8 @@ impl<'test> TestCx<'test> { } fn run_debuginfo_gdb_test(&self) { + assert!(self.revision.is_none(), "revisions not relevant here"); + let config = Config { target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags), host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags), @@ -784,12 +783,7 @@ impl<'test> TestCx<'test> { }; let DebuggerCommands { commands, check_lines, breakpoint_lines } = - match DebuggerCommands::parse_from( - &self.testpaths.file, - self.config, - prefixes, - self.revision, - ) { + match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) { Ok(cmds) => cmds, Err(e) => self.fatal(&e), }; @@ -1011,6 +1005,8 @@ impl<'test> TestCx<'test> { } fn run_debuginfo_lldb_test(&self) { + assert!(self.revision.is_none(), "revisions not relevant here"); + if self.config.lldb_python_dir.is_none() { self.fatal("Can't run LLDB test because LLDB's python path is not set."); } @@ -1063,12 +1059,7 @@ impl<'test> TestCx<'test> { // Parse debugger commands etc from test files let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } = - match DebuggerCommands::parse_from( - &self.testpaths.file, - self.config, - prefixes, - self.revision, - ) { + match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) { Ok(cmds) => cmds, Err(e) => self.fatal(&e), }; @@ -1960,7 +1951,6 @@ impl<'test> TestCx<'test> { "-Zdump-mir=all", "-Zvalidate-mir", "-Zdump-mir-exclude-pass-number", - "-Zmir-pretty-relative-line-numbers=yes", ]); if let Some(pass) = &self.props.mir_unit_test { rustc.args(&["-Zmir-opt-level=0", &format!("-Zmir-enable-passes=+{}", pass)]); diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index 379ff0bab408a..cbd5e4c431f56 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -1,5 +1,4 @@ use crate::common::Config; -use crate::header::line_directive; use crate::runtest::ProcRes; use std::fs::File; @@ -17,7 +16,6 @@ impl DebuggerCommands { file: &Path, config: &Config, debugger_prefixes: &[&str], - rev: Option<&str>, ) -> Result { let directives = debugger_prefixes .iter() @@ -27,19 +25,13 @@ impl DebuggerCommands { let mut breakpoint_lines = vec![]; let mut commands = vec![]; let mut check_lines = vec![]; - let mut counter = 0; + let mut counter = 1; let reader = BufReader::new(File::open(file).unwrap()); for line in reader.lines() { - counter += 1; match line { Ok(line) => { - let (lnrev, line) = line_directive("//", &line).unwrap_or((None, &line)); - - // Skip any revision specific directive that doesn't match the current - // revision being tested - if lnrev.is_some() && lnrev != rev { - continue; - } + let line = + if line.starts_with("//") { line[2..].trim_start() } else { line.as_str() }; if line.contains("#break") { breakpoint_lines.push(counter); @@ -57,6 +49,7 @@ impl DebuggerCommands { } Err(e) => return Err(format!("Error while parsing debugger commands: {}", e)), } + counter += 1; } Ok(Self { commands, check_lines, breakpoint_lines }) diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 22df18ee9fbb8..215af347f17d2 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -96,23 +96,6 @@ pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[ "x86_64-unknown-linux-gnu", ]; -// FIXME(rcvalle): More targets are likely supported. -pub const CFI_SUPPORTED_TARGETS: &[&str] = &[ - "aarch64-apple-darwin", - "aarch64-fuchsia", - "aarch64-linux-android", - "aarch64-unknown-freebsd", - "aarch64-unknown-linux-gnu", - "x86_64-apple-darwin", - "x86_64-fuchsia", - "x86_64-pc-solaris", - "x86_64-unknown-freebsd", - "x86_64-unknown-illumos", - "x86_64-unknown-linux-gnu", - "x86_64-unknown-linux-musl", - "x86_64-unknown-netbsd", -]; - pub const LSAN_SUPPORTED_TARGETS: &[&str] = &[ // FIXME: currently broken, see #88132 // "aarch64-apple-darwin", @@ -138,8 +121,6 @@ pub const HWASAN_SUPPORTED_TARGETS: &[&str] = pub const MEMTAG_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android", "aarch64-unknown-linux-gnu"]; -pub const SHADOWCALLSTACK_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android"]; - const BIG_ENDIAN: &[&str] = &[ "aarch64_be", "armebv7r", diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index a7c78d80ccd76..c9b1649200d9c 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -348,6 +348,11 @@ impl Checker { return; } + // These appear to be broken in mdbook right now? + if fragment.starts_with('-') { + return; + } + parse_ids(&mut target_ids.borrow_mut(), &pretty_path, target_source, report); if target_ids.borrow().contains(*fragment) { diff --git a/src/tools/miri b/src/tools/miri index b938529fb8ed8..416cddb2516de 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit b938529fb8ed8f7b5b374282ffc3ffa74c313111 +Subproject commit 416cddb2516dea056bf6269eaaa5ba4d24ad0832 diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer new file mode 160000 index 0000000000000..897a7ec4b826f --- /dev/null +++ b/src/tools/rust-analyzer @@ -0,0 +1 @@ +Subproject commit 897a7ec4b826f85ec1626870e734490701138097 diff --git a/src/tools/rust-analyzer/.cargo/config.toml b/src/tools/rust-analyzer/.cargo/config.toml deleted file mode 100644 index 24745d1c806fe..0000000000000 --- a/src/tools/rust-analyzer/.cargo/config.toml +++ /dev/null @@ -1,11 +0,0 @@ -[alias] -xtask = "run --package xtask --bin xtask --" -tq = "test -- -q" -qt = "tq" -lint = "clippy --all-targets -- -Aclippy::collapsible_if -Aclippy::needless_pass_by_value -Aclippy::nonminimal_bool -Aclippy::redundant_pattern_matching --cap-lints warn" - -[target.x86_64-pc-windows-msvc] -linker = "rust-lld" - -[env] -CARGO_WORKSPACE_DIR = { value = "", relative = true } \ No newline at end of file diff --git a/src/tools/rust-analyzer/.editorconfig b/src/tools/rust-analyzer/.editorconfig deleted file mode 100644 index 314f79d3f901c..0000000000000 --- a/src/tools/rust-analyzer/.editorconfig +++ /dev/null @@ -1,19 +0,0 @@ -# https://EditorConfig.org -root = true - -[*] -charset = utf-8 -trim_trailing_whitespace = true -end_of_line = lf -insert_final_newline = true -indent_style = space - -[*.{rs,toml}] -indent_size = 4 - -[*.ts] -indent_size = 4 -[*.js] -indent_size = 4 -[*.json] -indent_size = 4 diff --git a/src/tools/rust-analyzer/.git-blame-ignore-revs b/src/tools/rust-analyzer/.git-blame-ignore-revs deleted file mode 100644 index a302e23781ae9..0000000000000 --- a/src/tools/rust-analyzer/.git-blame-ignore-revs +++ /dev/null @@ -1,8 +0,0 @@ -# for this file to take effect make sure you use git ^2.23 and -# add ignoreFile to your git configuration: -# ``` -# git config --global blame.ignoreRevsFile .git-blame-ignore-revs -# ``` - -# prettier format -f247090558c9ba3c551566eae5882b7ca865225f diff --git a/src/tools/rust-analyzer/.gitattributes b/src/tools/rust-analyzer/.gitattributes deleted file mode 100644 index cb87b5d01385a..0000000000000 --- a/src/tools/rust-analyzer/.gitattributes +++ /dev/null @@ -1,9 +0,0 @@ -* text=auto eol=lf - -# git grep shouldn't match entries in this benchmark data -bench_data/** binary - -# Older git versions try to fix line endings on images, this prevents it. -*.png binary -*.jpg binary -*.ico binary diff --git a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/blank_issue.md b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/blank_issue.md deleted file mode 100644 index a08ad07cbf8d3..0000000000000 --- a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/blank_issue.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: Blank Issue -about: Create a blank issue. -title: '' -labels: '' -assignees: '' - ---- - - diff --git a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/bug_report.md b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 7ba06356a37ce..0000000000000 --- a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -name: Bug report -about: Create a bug report for rust-analyzer. -title: '' -labels: '' -assignees: '' - ---- - - - -**rust-analyzer version**: (eg. output of "Rust Analyzer: Show RA Version" command) - -**rustc version**: (eg. output of `rustc -V`) - -**relevant settings**: (eg. client settings, or environment variables like `CARGO`, `RUSTUP_HOME` or `CARGO_HOME`) diff --git a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/critical_nightly_regression.md b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/critical_nightly_regression.md deleted file mode 100644 index a0b1627d7e2ef..0000000000000 --- a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/critical_nightly_regression.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -name: Critical Nightly Regression -about: You are using nightly rust-analyzer and the latest version is unusable. -title: '' -labels: '' -assignees: 'matklad' - ---- - - - -This is a serious regression in nightly and it's important to fix it before the next release. -@matklad, please take a look. diff --git a/src/tools/rust-analyzer/.github/actions/github-release/Dockerfile b/src/tools/rust-analyzer/.github/actions/github-release/Dockerfile deleted file mode 100644 index 5849eac7d246a..0000000000000 --- a/src/tools/rust-analyzer/.github/actions/github-release/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM node:slim - -COPY . /action -WORKDIR /action - -RUN npm install --production - -ENTRYPOINT ["node", "/action/main.js"] diff --git a/src/tools/rust-analyzer/.github/actions/github-release/README.md b/src/tools/rust-analyzer/.github/actions/github-release/README.md deleted file mode 100644 index 7b50d002001ee..0000000000000 --- a/src/tools/rust-analyzer/.github/actions/github-release/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# github-release - -Copy-pasted from -https://github.com/bytecodealliance/wasmtime/tree/8acfdbdd8aa550d1b84e0ce1e6222a6605d14e38/.github/actions/github-release - -An action used to publish GitHub releases for `wasmtime`. - -As of the time of this writing there's a few actions floating around which -perform github releases but they all tend to have their set of drawbacks. -Additionally nothing handles deleting releases which we need for our rolling -`dev` release. - -To handle all this this action rolls-its-own implementation using the -actions/toolkit repository and packages published there. These run in a Docker -container and take various inputs to orchestrate the release from the build. - -More comments can be found in `main.js`. - -Testing this is really hard. If you want to try though run `npm install` and -then `node main.js`. You'll have to configure a bunch of env vars though to get -anything reasonably working. diff --git a/src/tools/rust-analyzer/.github/actions/github-release/action.yml b/src/tools/rust-analyzer/.github/actions/github-release/action.yml deleted file mode 100644 index 51a074adfaa88..0000000000000 --- a/src/tools/rust-analyzer/.github/actions/github-release/action.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: 'wasmtime github releases' -description: 'wasmtime github releases' -inputs: - token: - description: '' - required: true - name: - description: '' - required: true - files: - description: '' - required: true -runs: - using: 'docker' - image: 'Dockerfile' diff --git a/src/tools/rust-analyzer/.github/actions/github-release/main.js b/src/tools/rust-analyzer/.github/actions/github-release/main.js deleted file mode 100644 index e8dba398733c1..0000000000000 --- a/src/tools/rust-analyzer/.github/actions/github-release/main.js +++ /dev/null @@ -1,144 +0,0 @@ -const core = require('@actions/core'); -const path = require("path"); -const fs = require("fs"); -const github = require('@actions/github'); -const glob = require('glob'); - -function sleep(milliseconds) { - return new Promise(resolve => setTimeout(resolve, milliseconds)); -} - -async function runOnce() { - // Load all our inputs and env vars. Note that `getInput` reads from `INPUT_*` - const files = core.getInput('files'); - const name = core.getInput('name'); - const token = core.getInput('token'); - const slug = process.env.GITHUB_REPOSITORY; - const owner = slug.split('/')[0]; - const repo = slug.split('/')[1]; - const sha = process.env.HEAD_SHA; - - core.info(`files: ${files}`); - core.info(`name: ${name}`); - - const options = { - request: { - timeout: 30000, - } - }; - const octokit = github.getOctokit(token, options); - - // Delete the previous release since we can't overwrite one. This may happen - // due to retrying an upload or it may happen because we're doing the dev - // release. - const releases = await octokit.paginate("GET /repos/:owner/:repo/releases", { owner, repo }); - for (const release of releases) { - if (release.tag_name !== name) { - continue; - } - const release_id = release.id; - core.info(`deleting release ${release_id}`); - await octokit.rest.repos.deleteRelease({ owner, repo, release_id }); - } - - // We also need to update the `dev` tag while we're at it on the `dev` branch. - if (name == 'nightly') { - try { - core.info(`updating nightly tag`); - await octokit.rest.git.updateRef({ - owner, - repo, - ref: 'tags/nightly', - sha, - force: true, - }); - } catch (e) { - core.error(e); - core.info(`creating nightly tag`); - await octokit.rest.git.createTag({ - owner, - repo, - tag: 'nightly', - message: 'nightly release', - object: sha, - type: 'commit', - }); - } - } - - // Creates an official GitHub release for this `tag`, and if this is `dev` - // then we know that from the previous block this should be a fresh release. - core.info(`creating a release`); - const release = await octokit.rest.repos.createRelease({ - owner, - repo, - name, - tag_name: name, - target_commitish: sha, - prerelease: name === 'nightly', - }); - const release_id = release.data.id; - - // Upload all the relevant assets for this release as just general blobs. - for (const file of glob.sync(files)) { - const size = fs.statSync(file).size; - const name = path.basename(file); - - await runWithRetry(async function () { - // We can't overwrite assets, so remove existing ones from a previous try. - let assets = await octokit.rest.repos.listReleaseAssets({ - owner, - repo, - release_id - }); - for (const asset of assets.data) { - if (asset.name === name) { - core.info(`delete asset ${name}`); - const asset_id = asset.id; - await octokit.rest.repos.deleteReleaseAsset({ owner, repo, asset_id }); - } - } - - core.info(`upload ${file}`); - const headers = { 'content-length': size, 'content-type': 'application/octet-stream' }; - const data = fs.createReadStream(file); - await octokit.rest.repos.uploadReleaseAsset({ - data, - headers, - name, - url: release.data.upload_url, - }); - }); - } -} - -async function runWithRetry(f) { - const retries = 10; - const maxDelay = 4000; - let delay = 1000; - - for (let i = 0; i < retries; i++) { - try { - await f(); - break; - } catch (e) { - if (i === retries - 1) - throw e; - - core.error(e); - const currentDelay = Math.round(Math.random() * delay); - core.info(`sleeping ${currentDelay} ms`); - await sleep(currentDelay); - delay = Math.min(delay * 2, maxDelay); - } - } -} - -async function run() { - await runWithRetry(runOnce); -} - -run().catch(err => { - core.error(err); - core.setFailed(err.message); -}); diff --git a/src/tools/rust-analyzer/.github/actions/github-release/package.json b/src/tools/rust-analyzer/.github/actions/github-release/package.json deleted file mode 100644 index af4bf074d2d03..0000000000000 --- a/src/tools/rust-analyzer/.github/actions/github-release/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "wasmtime-github-release", - "version": "0.0.0", - "main": "main.js", - "dependencies": { - "@actions/core": "^1.6", - "@actions/github": "^5.0", - "glob": "^7.1.5" - } -} diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml deleted file mode 100644 index 0c81ff0789fbb..0000000000000 --- a/src/tools/rust-analyzer/.github/workflows/ci.yaml +++ /dev/null @@ -1,156 +0,0 @@ -# Please make sure that the `needs` fields for both `end-success` and `end-failure` -# are updated when adding new jobs! - -name: CI -on: - pull_request: - push: - branches: - - auto - - try - -env: - CARGO_INCREMENTAL: 0 - CARGO_NET_RETRY: 10 - CI: 1 - RUST_BACKTRACE: short - RUSTFLAGS: "-D warnings -W unreachable-pub -W rust-2021-compatibility" - RUSTUP_MAX_RETRIES: 10 - -jobs: - rust: - if: github.repository == 'rust-lang/rust-analyzer' - name: Rust - runs-on: ${{ matrix.os }} - env: - CC: deny_c - - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.sha }} - fetch-depth: 20 - - - name: Install Rust toolchain - run: | - rustup update --no-self-update stable - rustup component add rustfmt rust-src - - - name: Cache Dependencies - uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72 - - - name: Compile - run: cargo test --no-run --locked - - - name: Test - run: cargo test -- --nocapture --quiet - - # Weird targets to catch non-portable code - rust-cross: - if: github.repository == 'rust-lang/rust-analyzer' - name: Rust Cross - runs-on: ubuntu-latest - - env: - targets: "powerpc-unknown-linux-gnu x86_64-unknown-linux-musl" - # The rust-analyzer binary is not expected to compile on WASM, but the IDE - # crate should - targets_ide: "wasm32-unknown-unknown" - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Install Rust toolchain - run: | - rustup update --no-self-update stable - rustup target add ${{ env.targets }} ${{ env.targets_ide }} - - - name: Cache Dependencies - uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72 - - - name: Check - run: | - for target in ${{ env.targets }}; do - cargo check --target=$target --all-targets - done - for target in ${{ env.targets_ide }}; do - cargo check -p ide --target=$target --all-targets - done - - typescript: - if: github.repository == 'rust-lang/rust-analyzer' - name: TypeScript - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest] - - runs-on: ${{ matrix.os }} - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Install Nodejs - uses: actions/setup-node@v1 - with: - node-version: 14.x - - - name: Install xvfb - if: matrix.os == 'ubuntu-latest' - run: sudo apt-get install -y xvfb - - - run: npm ci - working-directory: ./editors/code - -# - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; } -# if: runner.os == 'Linux' -# working-directory: ./editors/code - - - run: npm run lint - working-directory: ./editors/code - - - name: Run VS Code tests (Linux) - if: matrix.os == 'ubuntu-latest' - env: - VSCODE_CLI: 1 - run: xvfb-run npm test - working-directory: ./editors/code - - - name: Run VS Code tests (Windows) - if: matrix.os == 'windows-latest' - env: - VSCODE_CLI: 1 - run: npm test - working-directory: ./editors/code - - - run: npm run pretest - working-directory: ./editors/code - - - run: npm run package --scripts-prepend-node-path - working-directory: ./editors/code - - end-success: - name: bors build finished - if: github.event.pusher.name == 'bors' && success() - runs-on: ubuntu-latest - needs: [rust, rust-cross, typescript] - steps: - - name: Mark the job as successful - run: exit 0 - - end-failure: - name: bors build finished - if: github.event.pusher.name == 'bors' && (failure() || cancelled()) - runs-on: ubuntu-latest - needs: [rust, rust-cross, typescript] - steps: - - name: Mark the job as a failure - run: exit 1 diff --git a/src/tools/rust-analyzer/.github/workflows/metrics.yaml b/src/tools/rust-analyzer/.github/workflows/metrics.yaml deleted file mode 100644 index 3fe2fc917a39a..0000000000000 --- a/src/tools/rust-analyzer/.github/workflows/metrics.yaml +++ /dev/null @@ -1,30 +0,0 @@ -name: metrics -on: - push: - branches: - - master - -env: - CARGO_INCREMENTAL: 0 - CARGO_NET_RETRY: 10 - RUSTFLAGS: "-D warnings -W unreachable-pub" - RUSTUP_MAX_RETRIES: 10 - -jobs: - metrics: - if: github.repository == 'rust-lang/rust-analyzer' - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Install Rust toolchain - run: | - rustup update --no-self-update stable - rustup component add rustfmt rust-src - - - name: Collect metrics - run: cargo xtask metrics - env: - METRICS_TOKEN: ${{ secrets.METRICS_TOKEN }} diff --git a/src/tools/rust-analyzer/.github/workflows/publish.yml b/src/tools/rust-analyzer/.github/workflows/publish.yml deleted file mode 100644 index 927996c1bef21..0000000000000 --- a/src/tools/rust-analyzer/.github/workflows/publish.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: publish -on: - workflow_dispatch: # We can add version input when 1.0 is released and scheduled releases are removed - -# schedule: -# - cron: "0 0 * * *" # midnight UTC - - push: - branches: - - release - -jobs: - publish: - name: publish - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Install Rust toolchain - run: rustup update --no-self-update stable - - - name: Install cargo-workspaces - run: cargo install cargo-workspaces - - - name: Release - env: - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} - PATCH: ${{ github.run_number }} - shell: bash - run: | - git config --global user.email "runner@gha.local" - git config --global user.name "Github Action" - rm Cargo.lock - cargo workspaces rename ra_ap_%n - find crates/rust-analyzer -type f -name '*.rs' -exec sed -i 's/rust_analyzer/ra_ap_rust_analyzer/g' {} + - # Fix names for crates that were published before switch to kebab-case. - find crates -name 'Cargo.toml' -exec sed -i "s/ra_ap_base-db/ra_ap_base_db/g; s/ra_ap_hir-def/ra_ap_hir_def/g; s/ra_ap_hir-expand/ra_ap_hir_expand/g; s/ra_ap_hir-ty/ra_ap_hir_ty/g; s/ra_ap_ide-assists/ra_ap_ide_assists/g; s/ra_ap_ide-completion/ra_ap_ide_completion/g; s/ra_ap_ide-db/ra_ap_ide_db/g; s/ra_ap_ide-diagnostics/ra_ap_ide_diagnostics/g; s/ra_ap_ide-ssr/ra_ap_ide_ssr/g; s/ra_ap_proc-macro-api/ra_ap_proc_macro_api/g; s/ra_ap_proc-macro-srv/ra_ap_proc_macro_srv/g; s/ra_ap_project-model/ra_ap_project_model/g; s/ra_ap_test-utils/ra_ap_test_utils/g; s/ra_ap_text-edit/ra_ap_text_edit/g" {} + - cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$PATCH diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml deleted file mode 100644 index 4e62f2cde2799..0000000000000 --- a/src/tools/rust-analyzer/.github/workflows/release.yaml +++ /dev/null @@ -1,249 +0,0 @@ -name: release -on: - schedule: - - cron: "0 0 * * *" # midnight UTC - - workflow_dispatch: - - push: - branches: - - release - - trigger-nightly - -env: - CARGO_INCREMENTAL: 0 - CARGO_NET_RETRY: 10 - RUSTFLAGS: "-D warnings -W unreachable-pub" - RUSTUP_MAX_RETRIES: 10 - FETCH_DEPTH: 0 # pull in the tags for the version string - MACOSX_DEPLOYMENT_TARGET: 10.15 - CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc - -jobs: - dist: - strategy: - matrix: - include: - - os: windows-latest - target: x86_64-pc-windows-msvc - code-target: win32-x64 - - os: windows-latest - target: aarch64-pc-windows-msvc - code-target: win32-arm64 - - os: ubuntu-18.04 - target: x86_64-unknown-linux-gnu - code-target: linux-x64 - - os: ubuntu-18.04 - target: aarch64-unknown-linux-gnu - code-target: linux-arm64 - - os: macos-11 - target: x86_64-apple-darwin - code-target: darwin-x64 - - os: macos-11 - target: aarch64-apple-darwin - code-target: darwin-arm64 - - name: dist (${{ matrix.target }}) - runs-on: ${{ matrix.os }} - - env: - RA_TARGET: ${{ matrix.target }} - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - fetch-depth: ${{ env.FETCH_DEPTH }} - - - name: Install Rust toolchain - run: | - rustup update --no-self-update stable - rustup target add ${{ matrix.target }} - rustup component add rust-src - - - name: Install Node.js - uses: actions/setup-node@v1 - with: - node-version: 14.x - - - name: Update apt repositories - if: matrix.target == 'aarch64-unknown-linux-gnu' - run: sudo apt-get update - - - name: Install target toolchain - if: matrix.target == 'aarch64-unknown-linux-gnu' - run: sudo apt-get install gcc-aarch64-linux-gnu - - - name: Dist - run: cargo xtask dist --client-patch-version ${{ github.run_number }} - - - run: npm ci - working-directory: editors/code - - - name: Package Extension (release) - if: github.ref == 'refs/heads/release' - run: npx vsce package -o "../../dist/rust-analyzer-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} - working-directory: editors/code - - - name: Package Extension (nightly) - if: github.ref != 'refs/heads/release' - run: npx vsce package -o "../../dist/rust-analyzer-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} --pre-release - working-directory: editors/code - - - if: matrix.target == 'x86_64-unknown-linux-gnu' - run: rm -rf editors/code/server - - - if: matrix.target == 'x86_64-unknown-linux-gnu' && github.ref == 'refs/heads/release' - run: npx vsce package -o ../../dist/rust-analyzer-no-server.vsix - working-directory: editors/code - - - if: matrix.target == 'x86_64-unknown-linux-gnu' && github.ref != 'refs/heads/release' - run: npx vsce package -o ../../dist/rust-analyzer-no-server.vsix --pre-release - working-directory: editors/code - - - name: Run analysis-stats on rust-analyzer - if: matrix.target == 'x86_64-unknown-linux-gnu' - run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats . - - - name: Run analysis-stats on rust std library - if: matrix.target == 'x86_64-unknown-linux-gnu' - run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std - - - name: Upload artifacts - uses: actions/upload-artifact@v1 - with: - name: dist-${{ matrix.target }} - path: ./dist - - dist-x86_64-unknown-linux-musl: - name: dist (x86_64-unknown-linux-musl) - runs-on: ubuntu-latest - env: - RA_TARGET: x86_64-unknown-linux-musl - # For some reason `-crt-static` is not working for clang without lld - RUSTFLAGS: "-C link-arg=-fuse-ld=lld -C target-feature=-crt-static" - container: - image: rust:alpine - volumes: - - /usr/local/cargo/registry - - steps: - - name: Install dependencies - run: apk add --no-cache git clang lld musl-dev nodejs npm - - - name: Checkout repository - uses: actions/checkout@v3 - with: - fetch-depth: ${{ env.FETCH_DEPTH }} - - - name: Dist - run: cargo xtask dist --client-patch-version ${{ github.run_number }} - - - run: npm ci - working-directory: editors/code - - - name: Package Extension (release) - if: github.ref == 'refs/heads/release' - run: npx vsce package -o "../../dist/rust-analyzer-alpine-x64.vsix" --target alpine-x64 - working-directory: editors/code - - - name: Package Extension (nightly) - if: github.ref != 'refs/heads/release' - run: npx vsce package -o "../../dist/rust-analyzer-alpine-x64.vsix" --target alpine-x64 --pre-release - working-directory: editors/code - - - run: rm -rf editors/code/server - - - name: Upload artifacts - uses: actions/upload-artifact@v1 - with: - name: dist-x86_64-unknown-linux-musl - path: ./dist - - publish: - name: publish - runs-on: ubuntu-latest - needs: ["dist", "dist-x86_64-unknown-linux-musl"] - steps: - - name: Install Nodejs - uses: actions/setup-node@v1 - with: - node-version: 14.x - - - run: echo "TAG=$(date --iso -u)" >> $GITHUB_ENV - if: github.ref == 'refs/heads/release' - - run: echo "TAG=nightly" >> $GITHUB_ENV - if: github.ref != 'refs/heads/release' - - run: 'echo "TAG: $TAG"' - - - name: Checkout repository - uses: actions/checkout@v3 - with: - fetch-depth: ${{ env.FETCH_DEPTH }} - - - run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV - - run: 'echo "HEAD_SHA: $HEAD_SHA"' - - - uses: actions/download-artifact@v1 - with: - name: dist-aarch64-apple-darwin - path: dist - - uses: actions/download-artifact@v1 - with: - name: dist-x86_64-apple-darwin - path: dist - - uses: actions/download-artifact@v1 - with: - name: dist-x86_64-unknown-linux-gnu - path: dist - - uses: actions/download-artifact@v1 - with: - name: dist-x86_64-unknown-linux-musl - path: dist - - uses: actions/download-artifact@v1 - with: - name: dist-aarch64-unknown-linux-gnu - path: dist - - uses: actions/download-artifact@v1 - with: - name: dist-x86_64-pc-windows-msvc - path: dist - - uses: actions/download-artifact@v1 - with: - name: dist-aarch64-pc-windows-msvc - path: dist - - run: ls -al ./dist - - - name: Publish Release - uses: ./.github/actions/github-release - with: - files: "dist/*" - name: ${{ env.TAG }} - token: ${{ secrets.GITHUB_TOKEN }} - - - run: rm dist/rust-analyzer-no-server.vsix - - - run: npm ci - working-directory: ./editors/code - - - name: Publish Extension (Code Marketplace, release) - if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer') - working-directory: ./editors/code - # token from https://dev.azure.com/rust-analyzer/ - run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix - - - name: Publish Extension (OpenVSX, release) - if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer') - working-directory: ./editors/code - # token from https://dev.azure.com/rust-analyzer/ - run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix - - - name: Publish Extension (Code Marketplace, nightly) - if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer') - working-directory: ./editors/code - run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix --pre-release - - - name: Publish Extension (OpenVSX, nightly) - if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer') - working-directory: ./editors/code - run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix --pre-release diff --git a/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml b/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml deleted file mode 100644 index 05f3e254e5f5a..0000000000000 --- a/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml +++ /dev/null @@ -1,34 +0,0 @@ -name: rustdoc -on: - push: - branches: - - master - -env: - CARGO_INCREMENTAL: 0 - CARGO_NET_RETRY: 10 - RUSTFLAGS: "-D warnings -W unreachable-pub" - RUSTUP_MAX_RETRIES: 10 - -jobs: - rustdoc: - if: github.repository == 'rust-lang/rust-analyzer' - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Install Rust toolchain - run: rustup update --no-self-update stable - - - name: Build Documentation - run: cargo doc --all --no-deps - - - name: Deploy Docs - uses: peaceiris/actions-gh-pages@364c31d33bb99327c77b3a5438a83a357a6729ad # v3.4.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_branch: gh-pages - publish_dir: ./target/doc - force_orphan: true diff --git a/src/tools/rust-analyzer/.gitignore b/src/tools/rust-analyzer/.gitignore deleted file mode 100644 index 68c87a6b1ed41..0000000000000 --- a/src/tools/rust-analyzer/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -/target/ -/dist/ -crates/*/target -**/*.rs.bk -**/*.rs.pending-snap -.idea/* -*.log -*.iml -.vscode/settings.json -generated_assists.adoc -generated_features.adoc -generated_diagnostic.adoc -.DS_Store -/out/ -/dump.lsif -.envrc diff --git a/src/tools/rust-analyzer/.vscode/extensions.json b/src/tools/rust-analyzer/.vscode/extensions.json deleted file mode 100644 index 027eeabc4c3e5..0000000000000 --- a/src/tools/rust-analyzer/.vscode/extensions.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. - // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp - - // List of extensions which should be recommended for users of this workspace. - "recommendations": ["vadimcn.vscode-lldb"], - // List of extensions recommended by VS Code that should not be recommended for users of this workspace. - "unwantedRecommendations": [] -} diff --git a/src/tools/rust-analyzer/.vscode/launch.json b/src/tools/rust-analyzer/.vscode/launch.json deleted file mode 100644 index 021b8f048cf2c..0000000000000 --- a/src/tools/rust-analyzer/.vscode/launch.json +++ /dev/null @@ -1,131 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - - // NOTE: --disable-extensions - // Disable all installed extensions to increase performance of the debug instance - // and prevent potential conflicts with other installed extensions. - - "version": "0.2.0", - "configurations": [ - { - // Used for testing the extension with the installed LSP server. - "name": "Run Installed Extension", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": [ - // "--user-data-dir=${workspaceFolder}/target/code", - "--disable-extensions", - "--extensionDevelopmentPath=${workspaceFolder}/editors/code" - ], - "outFiles": [ - "${workspaceFolder}/editors/code/out/**/*.js" - ], - "preLaunchTask": "Build Extension", - "skipFiles": [ - "/**/*.js" - ] - }, - { - // Used for testing the extension with a local build of the LSP server (in `target/debug`). - "name": "Run Extension (Debug Build)", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": [ - "--disable-extensions", - "--extensionDevelopmentPath=${workspaceFolder}/editors/code" - ], - "outFiles": [ - "${workspaceFolder}/editors/code/out/**/*.js" - ], - "preLaunchTask": "Build Server and Extension", - "skipFiles": [ - "/**/*.js" - ], - "env": { - "__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/debug/rust-analyzer" - } - }, - { - // Used for testing the extension with a local build of the LSP server (in `target/release`). - "name": "Run Extension (Release Build)", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": [ - "--disable-extensions", - "--extensionDevelopmentPath=${workspaceFolder}/editors/code" - ], - "outFiles": [ - "${workspaceFolder}/editors/code/out/**/*.js" - ], - "preLaunchTask": "Build Server (Release) and Extension", - "skipFiles": [ - "/**/*.js" - ], - "env": { - "__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/release/rust-analyzer" - } - }, - { - // Used for testing the extension with a local build of the LSP server (in `target/release`) - // with all other extendions loaded. - "name": "Run With Extensions", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": [ - "--disable-extension", "matklad.rust-analyzer", - "--extensionDevelopmentPath=${workspaceFolder}/editors/code" - ], - "outFiles": [ - "${workspaceFolder}/editors/code/out/**/*.js" - ], - "preLaunchTask": "Build Server (Release) and Extension", - "skipFiles": [ - "/**/*.js" - ], - "env": { - "__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/release/rust-analyzer" - } - }, - { - // Used to attach LLDB to a running LSP server. - // NOTE: Might require root permissions. For this run: - // - // `echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope` - // - // Don't forget to set `debug = 2` in `Cargo.toml` before building the server - - "name": "Attach To Server", - "type": "lldb", - "request": "attach", - "program": "${workspaceFolder}/target/debug/rust-analyzer", - "pid": "${command:pickMyProcess}", - "sourceLanguages": [ - "rust" - ] - }, - { - "name": "Run Unit Tests", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": [ - "--extensionDevelopmentPath=${workspaceFolder}/editors/code", - "--extensionTestsPath=${workspaceFolder}/editors/code/out/tests/unit" ], - "sourceMaps": true, - "outFiles": [ "${workspaceFolder}/editors/code/out/tests/unit/**/*.js" ], - "preLaunchTask": "Pretest" - }, - { - "name": "Win Attach to Server", - "type": "cppvsdbg", - "processId":"${command:pickProcess}", - "request": "attach" - } - ] -} diff --git a/src/tools/rust-analyzer/.vscode/tasks.json b/src/tools/rust-analyzer/.vscode/tasks.json deleted file mode 100644 index a25dff19e4155..0000000000000 --- a/src/tools/rust-analyzer/.vscode/tasks.json +++ /dev/null @@ -1,67 +0,0 @@ -// See https://go.microsoft.com/fwlink/?LinkId=733558 -// for the documentation about the tasks.json format -{ - "version": "2.0.0", - "tasks": [ - { - "label": "Build Extension in Background", - "group": "build", - "type": "npm", - "script": "watch", - "path": "editors/code/", - "problemMatcher": { - "base": "$tsc-watch", - "fileLocation": ["relative", "${workspaceFolder}/editors/code/"] - }, - "isBackground": true, - }, - { - "label": "Build Extension", - "group": "build", - "type": "npm", - "script": "build", - "path": "editors/code/", - "problemMatcher": { - "base": "$tsc", - "fileLocation": ["relative", "${workspaceFolder}/editors/code/"] - }, - }, - { - "label": "Build Server", - "group": "build", - "type": "shell", - "command": "cargo build --package rust-analyzer", - "problemMatcher": "$rustc" - }, - { - "label": "Build Server (Release)", - "group": "build", - "type": "shell", - "command": "cargo build --release --package rust-analyzer", - "problemMatcher": "$rustc" - }, - { - "label": "Pretest", - "group": "build", - "isBackground": false, - "type": "npm", - "script": "pretest", - "path": "editors/code/", - "problemMatcher": { - "base": "$tsc", - "fileLocation": ["relative", "${workspaceFolder}/editors/code/"] - } - }, - - { - "label": "Build Server and Extension", - "dependsOn": ["Build Server", "Build Extension"], - "problemMatcher": "$rustc" - }, - { - "label": "Build Server (Release) and Extension", - "dependsOn": ["Build Server (Release)", "Build Extension"], - "problemMatcher": "$rustc" - } - ] -} diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock deleted file mode 100644 index 703f0e5b8af9f..0000000000000 --- a/src/tools/rust-analyzer/Cargo.lock +++ /dev/null @@ -1,2101 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "always-assert" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf688625d06217d5b1bb0ea9d9c44a1635fd0ee3534466388d18203174f4d11" -dependencies = [ - "log", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "anyhow" -version = "1.0.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" - -[[package]] -name = "anymap" -version = "1.0.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1f8f5a6f3d50d89e3797d7593a50f96bb2aaa20ca0cc7be1fb673232c91d72" - -[[package]] -name = "arbitrary" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a7924531f38b1970ff630f03eb20a2fde69db5c590c93b0f3482e95dcc5fd60" - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object 0.28.4", - "rustc-demangle", -] - -[[package]] -name = "base-db" -version = "0.0.0" -dependencies = [ - "cfg", - "profile", - "rustc-hash", - "salsa", - "stdx", - "syntax", - "test-utils", - "tt", - "vfs", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "camino" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", -] - -[[package]] -name = "cc" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" - -[[package]] -name = "cfg" -version = "0.0.0" -dependencies = [ - "arbitrary", - "derive_arbitrary", - "expect-test", - "mbe", - "oorandom", - "rustc-hash", - "syntax", - "tt", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chalk-derive" -version = "0.83.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83553c2ef7717e58aecdf42dd9e3c876229f5a1f35a16435b5ddc4addef81827" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "chalk-ir" -version = "0.83.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dd42107d579d8ec2a5af20a8de62a37524a67bf6a4c0ff08a950068f0bfea91" -dependencies = [ - "bitflags", - "chalk-derive", - "lazy_static", -] - -[[package]] -name = "chalk-recursive" -version = "0.83.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c444031541a76c13c145e76d91f1548e9feb2240e7f0c3e77879ceb694994f2d" -dependencies = [ - "chalk-derive", - "chalk-ir", - "chalk-solve", - "rustc-hash", - "tracing", -] - -[[package]] -name = "chalk-solve" -version = "0.83.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c76f2db19c5e8a3d42340cf5b4d90b8c218750536fca35e2bb285ab6653c0bc8" -dependencies = [ - "chalk-derive", - "chalk-ir", - "ena", - "indexmap", - "itertools", - "petgraph", - "rustc-hash", - "tracing", -] - -[[package]] -name = "countme" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" -dependencies = [ - "dashmap", - "once_cell", - "rustc-hash", -] - -[[package]] -name = "cov-mark" -version = "2.0.0-pre.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d48d8f76bd9331f19fe2aaf3821a9f9fb32c3963e1e3d6ce82a8c09cef7444a" - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" -dependencies = [ - "cfg-if", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "once_cell", - "scopeguard", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "dashmap" -version = "5.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3495912c9c1ccf2e18976439f4443f3fee0fd61f424ff99fde6a66b15ecb448f" -dependencies = [ - "cfg-if", - "hashbrown", - "lock_api", - "parking_lot_core 0.9.3", -] - -[[package]] -name = "derive_arbitrary" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a577516173adb681466d517d39bd468293bc2c2a16439375ef0f35bba45f3d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "dissimilar" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c97b9233581d84b8e1e689cdd3a47b6f69770084fc246e86a7f78b0d9c1d4a5" - -[[package]] -name = "dot" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a74b6c4d4a1cff5f454164363c16b72fa12463ca6b31f4b5f2035a65fa3d5906" - -[[package]] -name = "drop_bomb" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1" - -[[package]] -name = "either" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" - -[[package]] -name = "ena" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" -dependencies = [ - "log", -] - -[[package]] -name = "expect-test" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d4661aca38d826eb7c72fe128e4238220616de4c0cc00db7bfc38e2e1364dd3" -dependencies = [ - "dissimilar", - "once_cell", -] - -[[package]] -name = "filetime" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "windows-sys 0.36.1", -] - -[[package]] -name = "fixedbitset" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" - -[[package]] -name = "flate2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "flycheck" -version = "0.0.0" -dependencies = [ - "cargo_metadata", - "crossbeam-channel", - "jod-thread", - "paths", - "serde", - "serde_json", - "stdx", - "toolchain", - "tracing", -] - -[[package]] -name = "form_urlencoded" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" -dependencies = [ - "matches", - "percent-encoding", -] - -[[package]] -name = "fs_extra" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" - -[[package]] -name = "fsevent-sys" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" -dependencies = [ - "libc", -] - -[[package]] -name = "fst" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" - -[[package]] -name = "gimli" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" - -[[package]] -name = "hashbrown" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hir" -version = "0.0.0" -dependencies = [ - "arrayvec", - "base-db", - "cfg", - "either", - "hir-def", - "hir-expand", - "hir-ty", - "itertools", - "once_cell", - "profile", - "rustc-hash", - "smallvec", - "stdx", - "syntax", - "tt", -] - -[[package]] -name = "hir-def" -version = "0.0.0" -dependencies = [ - "anymap", - "arrayvec", - "base-db", - "bitflags", - "cfg", - "cov-mark", - "dashmap", - "drop_bomb", - "either", - "expect-test", - "fst", - "hashbrown", - "hir-expand", - "indexmap", - "itertools", - "la-arena", - "limit", - "mbe", - "once_cell", - "profile", - "rustc-hash", - "smallvec", - "stdx", - "syntax", - "test-utils", - "tracing", - "tt", -] - -[[package]] -name = "hir-expand" -version = "0.0.0" -dependencies = [ - "base-db", - "cfg", - "cov-mark", - "either", - "expect-test", - "hashbrown", - "itertools", - "la-arena", - "limit", - "mbe", - "profile", - "rustc-hash", - "smallvec", - "stdx", - "syntax", - "tracing", - "tt", -] - -[[package]] -name = "hir-ty" -version = "0.0.0" -dependencies = [ - "arrayvec", - "base-db", - "chalk-ir", - "chalk-recursive", - "chalk-solve", - "cov-mark", - "ena", - "expect-test", - "hir-def", - "hir-expand", - "itertools", - "la-arena", - "limit", - "once_cell", - "profile", - "rustc-hash", - "scoped-tls", - "smallvec", - "stdx", - "syntax", - "test-utils", - "tracing", - "tracing-subscriber", - "tracing-tree", - "typed-arena", -] - -[[package]] -name = "home" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" -dependencies = [ - "winapi", -] - -[[package]] -name = "ide" -version = "0.0.0" -dependencies = [ - "cfg", - "cov-mark", - "crossbeam-channel", - "dot", - "either", - "expect-test", - "hir", - "ide-assists", - "ide-completion", - "ide-db", - "ide-diagnostics", - "ide-ssr", - "itertools", - "oorandom", - "profile", - "pulldown-cmark", - "pulldown-cmark-to-cmark", - "stdx", - "syntax", - "test-utils", - "text-edit", - "toolchain", - "tracing", - "url", -] - -[[package]] -name = "ide-assists" -version = "0.0.0" -dependencies = [ - "cov-mark", - "either", - "expect-test", - "hir", - "ide-db", - "itertools", - "profile", - "sourcegen", - "stdx", - "syntax", - "test-utils", - "text-edit", -] - -[[package]] -name = "ide-completion" -version = "0.0.0" -dependencies = [ - "base-db", - "cov-mark", - "expect-test", - "hir", - "ide-db", - "itertools", - "once_cell", - "profile", - "smallvec", - "stdx", - "syntax", - "test-utils", - "text-edit", -] - -[[package]] -name = "ide-db" -version = "0.0.0" -dependencies = [ - "arrayvec", - "base-db", - "cov-mark", - "either", - "expect-test", - "fst", - "hir", - "indexmap", - "itertools", - "limit", - "once_cell", - "parser", - "profile", - "rayon", - "rustc-hash", - "sourcegen", - "stdx", - "syntax", - "test-utils", - "text-edit", - "tracing", - "xshell", -] - -[[package]] -name = "ide-diagnostics" -version = "0.0.0" -dependencies = [ - "cfg", - "cov-mark", - "either", - "expect-test", - "hir", - "ide-db", - "itertools", - "profile", - "sourcegen", - "stdx", - "syntax", - "test-utils", - "text-edit", -] - -[[package]] -name = "ide-ssr" -version = "0.0.0" -dependencies = [ - "cov-mark", - "expect-test", - "hir", - "ide-db", - "itertools", - "parser", - "syntax", - "test-utils", - "text-edit", -] - -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "inotify" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" -dependencies = [ - "bitflags", - "inotify-sys", - "libc", -] - -[[package]] -name = "inotify-sys" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" -dependencies = [ - "libc", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "itertools" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" - -[[package]] -name = "jod-thread" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae" - -[[package]] -name = "kqueue" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6112e8f37b59803ac47a42d14f1f3a59bbf72fc6857ffc5be455e28a691f8e" -dependencies = [ - "kqueue-sys", - "libc", -] - -[[package]] -name = "kqueue-sys" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587" -dependencies = [ - "bitflags", - "libc", -] - -[[package]] -name = "la-arena" -version = "0.3.0" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" - -[[package]] -name = "libloading" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" -dependencies = [ - "cfg-if", - "winapi", -] - -[[package]] -name = "libmimalloc-sys" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ca136052550448f55df7898c6dbe651c6b574fe38a0d9ea687a9f8088a2e2c" -dependencies = [ - "cc", -] - -[[package]] -name = "limit" -version = "0.0.0" - -[[package]] -name = "lock_api" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "lsp-server" -version = "0.6.0" -dependencies = [ - "crossbeam-channel", - "log", - "lsp-types", - "serde", - "serde_json", -] - -[[package]] -name = "lsp-types" -version = "0.93.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70c74e2173b2b31f8655d33724b4b45ac13f439386f66290f539c22b144c2212" -dependencies = [ - "bitflags", - "serde", - "serde_json", - "serde_repr", - "url", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - -[[package]] -name = "mbe" -version = "0.0.0" -dependencies = [ - "cov-mark", - "parser", - "rustc-hash", - "smallvec", - "stdx", - "syntax", - "test-utils", - "tracing", - "tt", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memmap2" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5172b50c23043ff43dd53e51392f36519d9b35a8f3a410d30ece5d1aedd58ae" -dependencies = [ - "libc", -] - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "mimalloc" -version = "0.1.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f64ad83c969af2e732e907564deb0d0ed393cec4af80776f77dd77a1a427698" -dependencies = [ - "libmimalloc-sys", -] - -[[package]] -name = "miniz_oxide" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.36.1", -] - -[[package]] -name = "miow" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7377f7792b3afb6a3cba68daa54ca23c032137010460d667fda53a8d66be00e" -dependencies = [ - "windows-sys 0.28.0", -] - -[[package]] -name = "notify" -version = "5.0.0-pre.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "553f9844ad0b0824605c20fb55a661679782680410abfb1a8144c2e7e437e7a7" -dependencies = [ - "bitflags", - "crossbeam-channel", - "filetime", - "fsevent-sys", - "inotify", - "kqueue", - "libc", - "mio", - "walkdir", - "winapi", -] - -[[package]] -name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.28.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" -dependencies = [ - "memchr", -] - -[[package]] -name = "object" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" - -[[package]] -name = "oorandom" -version = "11.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.5", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core 0.9.3", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys 0.36.1", -] - -[[package]] -name = "parser" -version = "0.0.0" -dependencies = [ - "drop_bomb", - "expect-test", - "limit", - "rustc-ap-rustc_lexer", - "sourcegen", -] - -[[package]] -name = "paste" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" - -[[package]] -name = "paths" -version = "0.0.0" - -[[package]] -name = "percent-encoding" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" - -[[package]] -name = "perf-event" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5396562cd2eaa828445d6d34258ae21ee1eb9d40fe626ca7f51c8dccb4af9d66" -dependencies = [ - "libc", - "perf-event-open-sys", -] - -[[package]] -name = "perf-event-open-sys" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce9bedf5da2c234fdf2391ede2b90fabf585355f33100689bc364a3ea558561a" -dependencies = [ - "libc", -] - -[[package]] -name = "petgraph" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "proc-macro-api" -version = "0.0.0" -dependencies = [ - "memmap2", - "object 0.29.0", - "paths", - "profile", - "serde", - "serde_json", - "snap", - "stdx", - "tracing", - "tt", -] - -[[package]] -name = "proc-macro-srv" -version = "0.0.0" -dependencies = [ - "crossbeam", - "expect-test", - "libloading", - "mbe", - "memmap2", - "object 0.29.0", - "paths", - "proc-macro-api", - "proc-macro-test", - "tt", -] - -[[package]] -name = "proc-macro-srv-cli" -version = "0.0.0" -dependencies = [ - "proc-macro-srv", -] - -[[package]] -name = "proc-macro-test" -version = "0.0.0" -dependencies = [ - "cargo_metadata", - "proc-macro-test-impl", - "toolchain", -] - -[[package]] -name = "proc-macro-test-impl" -version = "0.0.0" - -[[package]] -name = "proc-macro2" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "profile" -version = "0.0.0" -dependencies = [ - "cfg-if", - "countme", - "la-arena", - "libc", - "once_cell", - "perf-event", - "tikv-jemalloc-ctl", - "winapi", -] - -[[package]] -name = "project-model" -version = "0.0.0" -dependencies = [ - "anyhow", - "base-db", - "cargo_metadata", - "cfg", - "expect-test", - "la-arena", - "paths", - "profile", - "rustc-hash", - "semver", - "serde", - "serde_json", - "stdx", - "toolchain", - "tracing", -] - -[[package]] -name = "pulldown-cmark" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6" -dependencies = [ - "bitflags", - "memchr", - "unicase", -] - -[[package]] -name = "pulldown-cmark-to-cmark" -version = "10.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1353ac408192fa925228d3e60ff746167d03f4f7e54835d78ef79e08225d913" -dependencies = [ - "pulldown-cmark", -] - -[[package]] -name = "quote" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rayon" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" -dependencies = [ - "autocfg", - "crossbeam-deque", - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", -] - -[[package]] -name = "redox_syscall" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" - -[[package]] -name = "rowan" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88acf7b001007e9e8c989fe7449f6601d909e5dd2c56399fc158977ad6c56e8" -dependencies = [ - "countme", - "hashbrown", - "memoffset", - "rustc-hash", - "text-size", -] - -[[package]] -name = "rust-analyzer" -version = "0.0.0" -dependencies = [ - "always-assert", - "anyhow", - "cfg", - "crossbeam-channel", - "dissimilar", - "expect-test", - "flycheck", - "hir", - "hir-def", - "hir-ty", - "ide", - "ide-db", - "ide-ssr", - "itertools", - "jod-thread", - "lsp-server", - "lsp-types", - "mbe", - "mimalloc", - "num_cpus", - "oorandom", - "parking_lot 0.12.1", - "proc-macro-api", - "proc-macro-srv", - "profile", - "project-model", - "rayon", - "rustc-hash", - "serde", - "serde_json", - "sourcegen", - "stdx", - "syntax", - "test-utils", - "threadpool", - "tikv-jemallocator", - "toolchain", - "tracing", - "tracing-log", - "tracing-subscriber", - "tracing-tree", - "tt", - "vfs", - "vfs-notify", - "winapi", - "xflags", - "xshell", -] - -[[package]] -name = "rustc-ap-rustc_lexer" -version = "725.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950742ef8a203aa7661aad3ab880438ddeb7f95d4b837c30d65db1a2c5df68e" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "ryu" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" - -[[package]] -name = "salsa" -version = "0.17.0-pre.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b223dccb46c32753144d0b51290da7230bb4aedcd8379d6b4c9a474c18bf17a" -dependencies = [ - "crossbeam-utils", - "indexmap", - "lock_api", - "log", - "oorandom", - "parking_lot 0.11.2", - "rustc-hash", - "salsa-macros", - "smallvec", -] - -[[package]] -name = "salsa-macros" -version = "0.17.0-pre.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac6c2e352df550bf019da7b16164ed2f7fa107c39653d1311d1bba42d1582ff7" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" -dependencies = [ - "serde", -] - -[[package]] -name = "serde" -version = "1.0.138" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.138" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sharded-slab" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "smallvec" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" - -[[package]] -name = "smol_str" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7475118a28b7e3a2e157ce0131ba8c5526ea96e90ee601d9f6bb2e286a35ab44" -dependencies = [ - "serde", -] - -[[package]] -name = "snap" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45456094d1983e2ee2a18fdfebce3189fa451699d0502cb8e3b49dba5ba41451" - -[[package]] -name = "sourcegen" -version = "0.0.0" -dependencies = [ - "xshell", -] - -[[package]] -name = "stdx" -version = "0.0.0" -dependencies = [ - "always-assert", - "backtrace", - "libc", - "miow", - "winapi", -] - -[[package]] -name = "syn" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - -[[package]] -name = "syntax" -version = "0.0.0" -dependencies = [ - "cov-mark", - "expect-test", - "indexmap", - "itertools", - "once_cell", - "parser", - "proc-macro2", - "profile", - "quote", - "rayon", - "rowan", - "rustc-ap-rustc_lexer", - "rustc-hash", - "smol_str", - "sourcegen", - "stdx", - "test-utils", - "text-edit", - "ungrammar", -] - -[[package]] -name = "test-utils" -version = "0.0.0" -dependencies = [ - "dissimilar", - "profile", - "rustc-hash", - "stdx", - "text-size", -] - -[[package]] -name = "text-edit" -version = "0.0.0" -dependencies = [ - "itertools", - "text-size", -] - -[[package]] -name = "text-size" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "288cb548dbe72b652243ea797201f3d481a0609a967980fcc5b2315ea811560a" - -[[package]] -name = "thread_local" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" -dependencies = [ - "once_cell", -] - -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", -] - -[[package]] -name = "tikv-jemalloc-ctl" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37706572f4b151dff7a0146e040804e9c26fe3a3118591112f05cf12a4216c1" -dependencies = [ - "libc", - "paste", - "tikv-jemalloc-sys", -] - -[[package]] -name = "tikv-jemalloc-sys" -version = "0.5.1+5.3.0-patched" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "931e876f91fed0827f863a2d153897790da0b24d882c721a79cb3beb0b903261" -dependencies = [ - "cc", - "fs_extra", - "libc", -] - -[[package]] -name = "tikv-jemallocator" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20612db8a13a6c06d57ec83953694185a367e16945f66565e8028d2c0bd76979" -dependencies = [ - "libc", - "tikv-jemalloc-sys", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "toolchain" -version = "0.0.0" -dependencies = [ - "home", -] - -[[package]] -name = "tracing" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" -dependencies = [ - "lazy_static", - "log", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a713421342a5a666b7577783721d3117f1b69a393df803ee17bb73b1e122a59" -dependencies = [ - "matchers", - "once_cell", - "regex", - "sharded-slab", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "tracing-tree" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07e90b329c621ade432823988574e820212648aa40e7a2497777d58de0fb453" -dependencies = [ - "ansi_term", - "atty", - "tracing-core", - "tracing-log", - "tracing-subscriber", -] - -[[package]] -name = "tt" -version = "0.0.0" -dependencies = [ - "smol_str", - "stdx", -] - -[[package]] -name = "typed-arena" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae" - -[[package]] -name = "ungrammar" -version = "1.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e5df347f0bf3ec1d670aad6ca5c6a1859cd9ea61d2113125794654ccced68f" - -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" - -[[package]] -name = "unicode-ident" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" - -[[package]] -name = "unicode-normalization" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" - -[[package]] -name = "unicode-xid" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" - -[[package]] -name = "url" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" -dependencies = [ - "form_urlencoded", - "idna", - "matches", - "percent-encoding", - "serde", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "vfs" -version = "0.0.0" -dependencies = [ - "fst", - "indexmap", - "paths", - "rustc-hash", -] - -[[package]] -name = "vfs-notify" -version = "0.0.0" -dependencies = [ - "crossbeam-channel", - "jod-thread", - "notify", - "paths", - "tracing", - "vfs", - "walkdir", -] - -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82ca39602d5cbfa692c4b67e3bcbb2751477355141c1ed434c94da4186836ff6" -dependencies = [ - "windows_aarch64_msvc 0.28.0", - "windows_i686_gnu 0.28.0", - "windows_i686_msvc 0.28.0", - "windows_x86_64_gnu 0.28.0", - "windows_x86_64_msvc 0.28.0", -] - -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", -] - -[[package]] -name = "windows_aarch64_msvc" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_i686_gnu" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a" - -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_msvc" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64" - -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - -[[package]] -name = "write-json" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06069a848f95fceae3e5e03c0ddc8cb78452b56654ee0c8e68f938cf790fb9e3" - -[[package]] -name = "xflags" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f14fe1ed41a5a2b5ef3f565586c4a8a559ee55d3953faab360a771135bdee00" -dependencies = [ - "xflags-macros", -] - -[[package]] -name = "xflags-macros" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45d11d5fc2a97287eded8b170ca80533b3c42646dd7fa386a5eb045817921022" - -[[package]] -name = "xshell" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d47097dc5c85234b1e41851b3422dd6d19b3befdd35b4ae5ce386724aeca981" -dependencies = [ - "xshell-macros", -] - -[[package]] -name = "xshell-macros" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88301b56c26dd9bf5c43d858538f82d6f3f7764767defbc5d34e59459901c41a" - -[[package]] -name = "xtask" -version = "0.1.0" -dependencies = [ - "anyhow", - "flate2", - "write-json", - "xflags", - "xshell", -] diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml deleted file mode 100644 index 6b68ca823894f..0000000000000 --- a/src/tools/rust-analyzer/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[workspace] -members = ["xtask/", "lib/*", "crates/*"] -exclude = ["crates/proc-macro-test/imp"] - -[profile.dev] -# Disabling debug info speeds up builds a bunch, -# and we don't rely on it for debugging that much. -debug = 0 - -[profile.dev.package] -# These speed up local tests. -rowan.opt-level = 3 -rustc-hash.opt-level = 3 -smol_str.opt-level = 3 -text-size.opt-level = 3 -# This speeds up `cargo xtask dist`. -miniz_oxide.opt-level = 3 - -[profile.release] -incremental = true -# Set this to 1 or 2 to get more useful backtraces in debugger. -debug = 0 - -[patch.'crates-io'] -# rowan = { path = "../rowan" } - -# chalk-solve = { path = "../chalk/chalk-solve" } -# chalk-ir = { path = "../chalk/chalk-ir" } -# chalk-recursive = { path = "../chalk/chalk-recursive" } - -# ungrammar = { path = "../ungrammar" } - -# salsa = { path = "../salsa" } diff --git a/src/tools/rust-analyzer/LICENSE-APACHE b/src/tools/rust-analyzer/LICENSE-APACHE deleted file mode 100644 index 16fe87b06e802..0000000000000 --- a/src/tools/rust-analyzer/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/src/tools/rust-analyzer/LICENSE-MIT b/src/tools/rust-analyzer/LICENSE-MIT deleted file mode 100644 index 31aa79387f27e..0000000000000 --- a/src/tools/rust-analyzer/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/src/tools/rust-analyzer/PRIVACY.md b/src/tools/rust-analyzer/PRIVACY.md deleted file mode 100644 index 89e252be731d0..0000000000000 --- a/src/tools/rust-analyzer/PRIVACY.md +++ /dev/null @@ -1 +0,0 @@ -See the [Privacy](https://rust-analyzer.github.io/manual.html#privacy) section of the user manual. diff --git a/src/tools/rust-analyzer/README.md b/src/tools/rust-analyzer/README.md deleted file mode 100644 index 8bb0517ed5abb..0000000000000 --- a/src/tools/rust-analyzer/README.md +++ /dev/null @@ -1,49 +0,0 @@ -

- rust-analyzer logo -

- -rust-analyzer is a modular compiler frontend for the Rust language. -It is a part of a larger rls-2.0 effort to create excellent IDE support for Rust. - -## Quick Start - -https://rust-analyzer.github.io/manual.html#installation - -## Documentation - -If you want to **contribute** to rust-analyzer or are just curious about how -things work under the hood, check the [./docs/dev](./docs/dev) folder. - -If you want to **use** rust-analyzer's language server with your editor of -choice, check [the manual](https://rust-analyzer.github.io/manual.html) folder. -It also contains some tips & tricks to help you be more productive when using rust-analyzer. - -## Security and Privacy - -See the corresponding sections of [the manual](https://rust-analyzer.github.io/manual.html#security). - -## Communication - -For usage and troubleshooting requests, please use "IDEs and Editors" category of the Rust forum: - -https://users.rust-lang.org/c/ide/14 - -For questions about development and implementation, join rust-analyzer working group on Zulip: - -https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer - -## Quick Links - -* Website: https://rust-analyzer.github.io/ -* Metrics: https://rust-analyzer.github.io/metrics/ -* API docs: https://rust-lang.github.io/rust-analyzer/ide/ -* Changelog: https://rust-analyzer.github.io/thisweek - -## License - -Rust analyzer is primarily distributed under the terms of both the MIT -license and the Apache License (Version 2.0). - -See LICENSE-APACHE and LICENSE-MIT for details. diff --git a/src/tools/rust-analyzer/assets/logo-square.svg b/src/tools/rust-analyzer/assets/logo-square.svg deleted file mode 100644 index fe1c1fa02271b..0000000000000 --- a/src/tools/rust-analyzer/assets/logo-square.svg +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - diff --git a/src/tools/rust-analyzer/assets/logo-wide.svg b/src/tools/rust-analyzer/assets/logo-wide.svg deleted file mode 100644 index c5fb55b36a899..0000000000000 --- a/src/tools/rust-analyzer/assets/logo-wide.svg +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/tools/rust-analyzer/bench_data/glorious_old_parser b/src/tools/rust-analyzer/bench_data/glorious_old_parser deleted file mode 100644 index 7e900dfeb1eeb..0000000000000 --- a/src/tools/rust-analyzer/bench_data/glorious_old_parser +++ /dev/null @@ -1,8562 +0,0 @@ -use crate::ast::{AngleBracketedArgs, ParenthesizedArgs, AttrStyle, BareFnTy}; -use crate::ast::{GenericBound, TraitBoundModifier}; -use crate::ast::Unsafety; -use crate::ast::{Mod, AnonConst, Arg, Arm, Guard, Attribute, BindingMode, TraitItemKind}; -use crate::ast::Block; -use crate::ast::{BlockCheckMode, CaptureBy, Movability}; -use crate::ast::{Constness, Crate}; -use crate::ast::Defaultness; -use crate::ast::EnumDef; -use crate::ast::{Expr, ExprKind, RangeLimits}; -use crate::ast::{Field, FnDecl, FnHeader}; -use crate::ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; -use crate::ast::{GenericParam, GenericParamKind}; -use crate::ast::GenericArg; -use crate::ast::{Ident, ImplItem, IsAsync, IsAuto, Item, ItemKind}; -use crate::ast::{Label, Lifetime, Lit, LitKind}; -use crate::ast::Local; -use crate::ast::MacStmtStyle; -use crate::ast::{Mac, Mac_, MacDelimiter}; -use crate::ast::{MutTy, Mutability}; -use crate::ast::{Pat, PatKind, PathSegment}; -use crate::ast::{PolyTraitRef, QSelf}; -use crate::ast::{Stmt, StmtKind}; -use crate::ast::{VariantData, StructField}; -use crate::ast::StrStyle; -use crate::ast::SelfKind; -use crate::ast::{TraitItem, TraitRef, TraitObjectSyntax}; -use crate::ast::{Ty, TyKind, TypeBinding, GenericBounds}; -use crate::ast::{Visibility, VisibilityKind, WhereClause, CrateSugar}; -use crate::ast::{UseTree, UseTreeKind}; -use crate::ast::{BinOpKind, UnOp}; -use crate::ast::{RangeEnd, RangeSyntax}; -use crate::{ast, attr}; -use crate::ext::base::DummyResult; -use crate::source_map::{self, SourceMap, Spanned, respan}; -use crate::parse::{self, SeqSep, classify, token}; -use crate::parse::lexer::{TokenAndSpan, UnmatchedBrace}; -use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; -use crate::parse::token::DelimToken; -use crate::parse::{new_sub_parser_from_file, ParseSess, Directory, DirectoryOwnership}; -use crate::util::parser::{AssocOp, Fixity}; -use crate::print::pprust; -use crate::ptr::P; -use crate::parse::PResult; -use crate::ThinVec; -use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; -use crate::symbol::{Symbol, keywords}; - -use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; -use rustc_target::spec::abi::{self, Abi}; -use syntax_pos::{Span, MultiSpan, BytePos, FileName}; -use log::{debug, trace}; - -use std::borrow::Cow; -use std::cmp; -use std::mem; -use std::path::{self, Path, PathBuf}; -use std::slice; - -#[derive(Debug)] -/// Whether the type alias or associated type is a concrete type or an existential type -pub enum AliasKind { - /// Just a new name for the same type - Weak(P), - /// Only trait impls of the type will be usable, not the actual type itself - Existential(GenericBounds), -} - -bitflags::bitflags! { - struct Restrictions: u8 { - const STMT_EXPR = 1 << 0; - const NO_STRUCT_LITERAL = 1 << 1; - } -} - -type ItemInfo = (Ident, ItemKind, Option>); - -/// Specifies how to parse a path. -#[derive(Copy, Clone, PartialEq)] -pub enum PathStyle { - /// In some contexts, notably in expressions, paths with generic arguments are ambiguous - /// with something else. For example, in expressions `segment < ....` can be interpreted - /// as a comparison and `segment ( ....` can be interpreted as a function call. - /// In all such contexts the non-path interpretation is preferred by default for practical - /// reasons, but the path interpretation can be forced by the disambiguator `::`, e.g. - /// `x` - comparisons, `x::` - unambiguously a path. - Expr, - /// In other contexts, notably in types, no ambiguity exists and paths can be written - /// without the disambiguator, e.g., `x` - unambiguously a path. - /// Paths with disambiguators are still accepted, `x::` - unambiguously a path too. - Type, - /// A path with generic arguments disallowed, e.g., `foo::bar::Baz`, used in imports, - /// visibilities or attributes. - /// Technically, this variant is unnecessary and e.g., `Expr` can be used instead - /// (paths in "mod" contexts have to be checked later for absence of generic arguments - /// anyway, due to macros), but it is used to avoid weird suggestions about expected - /// tokens when something goes wrong. - Mod, -} - -#[derive(Clone, Copy, PartialEq, Debug)] -enum SemiColonMode { - Break, - Ignore, - Comma, -} - -#[derive(Clone, Copy, PartialEq, Debug)] -enum BlockMode { - Break, - Ignore, -} - -/// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression -/// dropped into the token stream, which happens while parsing the result of -/// macro expansion). Placement of these is not as complex as I feared it would -/// be. The important thing is to make sure that lookahead doesn't balk at -/// `token::Interpolated` tokens. -macro_rules! maybe_whole_expr { - ($p:expr) => { - if let token::Interpolated(nt) = $p.token.clone() { - match *nt { - token::NtExpr(ref e) | token::NtLiteral(ref e) => { - $p.bump(); - return Ok((*e).clone()); - } - token::NtPath(ref path) => { - $p.bump(); - let span = $p.span; - let kind = ExprKind::Path(None, (*path).clone()); - return Ok($p.mk_expr(span, kind, ThinVec::new())); - } - token::NtBlock(ref block) => { - $p.bump(); - let span = $p.span; - let kind = ExprKind::Block((*block).clone(), None); - return Ok($p.mk_expr(span, kind, ThinVec::new())); - } - _ => {}, - }; - } - } -} - -/// As maybe_whole_expr, but for things other than expressions -macro_rules! maybe_whole { - ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { - if let token::Interpolated(nt) = $p.token.clone() { - if let token::$constructor($x) = (*nt).clone() { - $p.bump(); - return Ok($e); - } - } - }; -} - -fn maybe_append(mut lhs: Vec, mut rhs: Option>) -> Vec { - if let Some(ref mut rhs) = rhs { - lhs.append(rhs); - } - lhs -} - -#[derive(Debug, Clone, Copy, PartialEq)] -enum PrevTokenKind { - DocComment, - Comma, - Plus, - Interpolated, - Eof, - Ident, - Other, -} - -trait RecoverQPath: Sized { - const PATH_STYLE: PathStyle = PathStyle::Expr; - fn to_ty(&self) -> Option>; - fn to_recovered(&self, qself: Option, path: ast::Path) -> Self; - fn to_string(&self) -> String; -} - -impl RecoverQPath for Ty { - const PATH_STYLE: PathStyle = PathStyle::Type; - fn to_ty(&self) -> Option> { - Some(P(self.clone())) - } - fn to_recovered(&self, qself: Option, path: ast::Path) -> Self { - Self { span: path.span, node: TyKind::Path(qself, path), id: self.id } - } - fn to_string(&self) -> String { - pprust::ty_to_string(self) - } -} - -impl RecoverQPath for Pat { - fn to_ty(&self) -> Option> { - self.to_ty() - } - fn to_recovered(&self, qself: Option, path: ast::Path) -> Self { - Self { span: path.span, node: PatKind::Path(qself, path), id: self.id } - } - fn to_string(&self) -> String { - pprust::pat_to_string(self) - } -} - -impl RecoverQPath for Expr { - fn to_ty(&self) -> Option> { - self.to_ty() - } - fn to_recovered(&self, qself: Option, path: ast::Path) -> Self { - Self { span: path.span, node: ExprKind::Path(qself, path), - id: self.id, attrs: self.attrs.clone() } - } - fn to_string(&self) -> String { - pprust::expr_to_string(self) - } -} - -/* ident is handled by common.rs */ - -#[derive(Clone)] -pub struct Parser<'a> { - pub sess: &'a ParseSess, - /// the current token: - pub token: token::Token, - /// the span of the current token: - pub span: Span, - /// the span of the previous token: - meta_var_span: Option, - pub prev_span: Span, - /// the previous token kind - prev_token_kind: PrevTokenKind, - restrictions: Restrictions, - /// Used to determine the path to externally loaded source files - crate directory: Directory<'a>, - /// Whether to parse sub-modules in other files. - pub recurse_into_file_modules: bool, - /// Name of the root module this parser originated from. If `None`, then the - /// name is not known. This does not change while the parser is descending - /// into modules, and sub-parsers have new values for this name. - pub root_module_name: Option, - crate expected_tokens: Vec, - token_cursor: TokenCursor, - desugar_doc_comments: bool, - /// Whether we should configure out of line modules as we parse. - pub cfg_mods: bool, - /// This field is used to keep track of how many left angle brackets we have seen. This is - /// required in order to detect extra leading left angle brackets (`<` characters) and error - /// appropriately. - /// - /// See the comments in the `parse_path_segment` function for more details. - crate unmatched_angle_bracket_count: u32, - crate max_angle_bracket_count: u32, - /// List of all unclosed delimiters found by the lexer. If an entry is used for error recovery - /// it gets removed from here. Every entry left at the end gets emitted as an independent - /// error. - crate unclosed_delims: Vec, -} - - -#[derive(Clone)] -struct TokenCursor { - frame: TokenCursorFrame, - stack: Vec, -} - -#[derive(Clone)] -struct TokenCursorFrame { - delim: token::DelimToken, - span: DelimSpan, - open_delim: bool, - tree_cursor: tokenstream::Cursor, - close_delim: bool, - last_token: LastToken, -} - -/// This is used in `TokenCursorFrame` above to track tokens that are consumed -/// by the parser, and then that's transitively used to record the tokens that -/// each parse AST item is created with. -/// -/// Right now this has two states, either collecting tokens or not collecting -/// tokens. If we're collecting tokens we just save everything off into a local -/// `Vec`. This should eventually though likely save tokens from the original -/// token stream and just use slicing of token streams to avoid creation of a -/// whole new vector. -/// -/// The second state is where we're passively not recording tokens, but the last -/// token is still tracked for when we want to start recording tokens. This -/// "last token" means that when we start recording tokens we'll want to ensure -/// that this, the first token, is included in the output. -/// -/// You can find some more example usage of this in the `collect_tokens` method -/// on the parser. -#[derive(Clone)] -enum LastToken { - Collecting(Vec), - Was(Option), -} - -impl TokenCursorFrame { - fn new(sp: DelimSpan, delim: DelimToken, tts: &TokenStream) -> Self { - TokenCursorFrame { - delim: delim, - span: sp, - open_delim: delim == token::NoDelim, - tree_cursor: tts.clone().into_trees(), - close_delim: delim == token::NoDelim, - last_token: LastToken::Was(None), - } - } -} - -impl TokenCursor { - fn next(&mut self) -> TokenAndSpan { - loop { - let tree = if !self.frame.open_delim { - self.frame.open_delim = true; - TokenTree::open_tt(self.frame.span.open, self.frame.delim) - } else if let Some(tree) = self.frame.tree_cursor.next() { - tree - } else if !self.frame.close_delim { - self.frame.close_delim = true; - TokenTree::close_tt(self.frame.span.close, self.frame.delim) - } else if let Some(frame) = self.stack.pop() { - self.frame = frame; - continue - } else { - return TokenAndSpan { tok: token::Eof, sp: syntax_pos::DUMMY_SP } - }; - - match self.frame.last_token { - LastToken::Collecting(ref mut v) => v.push(tree.clone().into()), - LastToken::Was(ref mut t) => *t = Some(tree.clone().into()), - } - - match tree { - TokenTree::Token(sp, tok) => return TokenAndSpan { tok: tok, sp: sp }, - TokenTree::Delimited(sp, delim, tts) => { - let frame = TokenCursorFrame::new(sp, delim, &tts); - self.stack.push(mem::replace(&mut self.frame, frame)); - } - } - } - } - - fn next_desugared(&mut self) -> TokenAndSpan { - let (sp, name) = match self.next() { - TokenAndSpan { sp, tok: token::DocComment(name) } => (sp, name), - tok => return tok, - }; - - let stripped = strip_doc_comment_decoration(&name.as_str()); - - // Searches for the occurrences of `"#*` and returns the minimum number of `#`s - // required to wrap the text. - let mut num_of_hashes = 0; - let mut count = 0; - for ch in stripped.chars() { - count = match ch { - '"' => 1, - '#' if count > 0 => count + 1, - _ => 0, - }; - num_of_hashes = cmp::max(num_of_hashes, count); - } - - let delim_span = DelimSpan::from_single(sp); - let body = TokenTree::Delimited( - delim_span, - token::Bracket, - [TokenTree::Token(sp, token::Ident(ast::Ident::from_str("doc"), false)), - TokenTree::Token(sp, token::Eq), - TokenTree::Token(sp, token::Literal( - token::StrRaw(Symbol::intern(&stripped), num_of_hashes), None)) - ] - .iter().cloned().collect::().into(), - ); - - self.stack.push(mem::replace(&mut self.frame, TokenCursorFrame::new( - delim_span, - token::NoDelim, - &if doc_comment_style(&name.as_str()) == AttrStyle::Inner { - [TokenTree::Token(sp, token::Pound), TokenTree::Token(sp, token::Not), body] - .iter().cloned().collect::().into() - } else { - [TokenTree::Token(sp, token::Pound), body] - .iter().cloned().collect::().into() - }, - ))); - - self.next() - } -} - -#[derive(Clone, PartialEq)] -crate enum TokenType { - Token(token::Token), - Keyword(keywords::Keyword), - Operator, - Lifetime, - Ident, - Path, - Type, - Const, -} - -impl TokenType { - fn to_string(&self) -> String { - match *self { - TokenType::Token(ref t) => format!("`{}`", pprust::token_to_string(t)), - TokenType::Keyword(kw) => format!("`{}`", kw.name()), - TokenType::Operator => "an operator".to_string(), - TokenType::Lifetime => "lifetime".to_string(), - TokenType::Ident => "identifier".to_string(), - TokenType::Path => "path".to_string(), - TokenType::Type => "type".to_string(), - TokenType::Const => "const".to_string(), - } - } -} - -/// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT`, -/// `IDENT<::AssocTy>`. -/// -/// Types can also be of the form `IDENT(u8, u8) -> u8`, however this assumes -/// that `IDENT` is not the ident of a fn trait. -fn can_continue_type_after_non_fn_ident(t: &token::Token) -> bool { - t == &token::ModSep || t == &token::Lt || - t == &token::BinOp(token::Shl) -} - -/// Information about the path to a module. -pub struct ModulePath { - name: String, - path_exists: bool, - pub result: Result, -} - -pub struct ModulePathSuccess { - pub path: PathBuf, - pub directory_ownership: DirectoryOwnership, - warn: bool, -} - -pub enum Error { - FileNotFoundForModule { - mod_name: String, - default_path: String, - secondary_path: String, - dir_path: String, - }, - DuplicatePaths { - mod_name: String, - default_path: String, - secondary_path: String, - }, - UselessDocComment, - InclusiveRangeWithNoEnd, -} - -impl Error { - fn span_err>(self, - sp: S, - handler: &errors::Handler) -> DiagnosticBuilder<'_> { - match self { - Error::FileNotFoundForModule { ref mod_name, - ref default_path, - ref secondary_path, - ref dir_path } => { - let mut err = struct_span_err!(handler, sp, E0583, - "file not found for module `{}`", mod_name); - err.help(&format!("name the file either {} or {} inside the directory \"{}\"", - default_path, - secondary_path, - dir_path)); - err - } - Error::DuplicatePaths { ref mod_name, ref default_path, ref secondary_path } => { - let mut err = struct_span_err!(handler, sp, E0584, - "file for module `{}` found at both {} and {}", - mod_name, - default_path, - secondary_path); - err.help("delete or rename one of them to remove the ambiguity"); - err - } - Error::UselessDocComment => { - let mut err = struct_span_err!(handler, sp, E0585, - "found a documentation comment that doesn't document anything"); - err.help("doc comments must come before what they document, maybe a comment was \ - intended with `//`?"); - err - } - Error::InclusiveRangeWithNoEnd => { - let mut err = struct_span_err!(handler, sp, E0586, - "inclusive range with no end"); - err.help("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)"); - err - } - } - } -} - -#[derive(Debug)] -enum LhsExpr { - NotYetParsed, - AttributesParsed(ThinVec), - AlreadyParsed(P), -} - -impl From>> for LhsExpr { - fn from(o: Option>) -> Self { - if let Some(attrs) = o { - LhsExpr::AttributesParsed(attrs) - } else { - LhsExpr::NotYetParsed - } - } -} - -impl From> for LhsExpr { - fn from(expr: P) -> Self { - LhsExpr::AlreadyParsed(expr) - } -} - -/// Creates a placeholder argument. -fn dummy_arg(span: Span) -> Arg { - let ident = Ident::new(keywords::Invalid.name(), span); - let pat = P(Pat { - id: ast::DUMMY_NODE_ID, - node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None), - span, - }); - let ty = Ty { - node: TyKind::Err, - span, - id: ast::DUMMY_NODE_ID - }; - Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID } -} - -#[derive(Copy, Clone, Debug)] -enum TokenExpectType { - Expect, - NoExpect, -} - -impl<'a> Parser<'a> { - pub fn new(sess: &'a ParseSess, - tokens: TokenStream, - directory: Option>, - recurse_into_file_modules: bool, - desugar_doc_comments: bool) - -> Self { - let mut parser = Parser { - sess, - token: token::Whitespace, - span: syntax_pos::DUMMY_SP, - prev_span: syntax_pos::DUMMY_SP, - meta_var_span: None, - prev_token_kind: PrevTokenKind::Other, - restrictions: Restrictions::empty(), - recurse_into_file_modules, - directory: Directory { - path: Cow::from(PathBuf::new()), - ownership: DirectoryOwnership::Owned { relative: None } - }, - root_module_name: None, - expected_tokens: Vec::new(), - token_cursor: TokenCursor { - frame: TokenCursorFrame::new( - DelimSpan::dummy(), - token::NoDelim, - &tokens.into(), - ), - stack: Vec::new(), - }, - desugar_doc_comments, - cfg_mods: true, - unmatched_angle_bracket_count: 0, - max_angle_bracket_count: 0, - unclosed_delims: Vec::new(), - }; - - let tok = parser.next_tok(); - parser.token = tok.tok; - parser.span = tok.sp; - - if let Some(directory) = directory { - parser.directory = directory; - } else if !parser.span.is_dummy() { - if let FileName::Real(mut path) = sess.source_map().span_to_unmapped_path(parser.span) { - path.pop(); - parser.directory.path = Cow::from(path); - } - } - - parser.process_potential_macro_variable(); - parser - } - - fn next_tok(&mut self) -> TokenAndSpan { - let mut next = if self.desugar_doc_comments { - self.token_cursor.next_desugared() - } else { - self.token_cursor.next() - }; - if next.sp.is_dummy() { - // Tweak the location for better diagnostics, but keep syntactic context intact. - next.sp = self.prev_span.with_ctxt(next.sp.ctxt()); - } - next - } - - /// Converts the current token to a string using `self`'s reader. - pub fn this_token_to_string(&self) -> String { - pprust::token_to_string(&self.token) - } - - fn token_descr(&self) -> Option<&'static str> { - Some(match &self.token { - t if t.is_special_ident() => "reserved identifier", - t if t.is_used_keyword() => "keyword", - t if t.is_unused_keyword() => "reserved keyword", - token::DocComment(..) => "doc comment", - _ => return None, - }) - } - - fn this_token_descr(&self) -> String { - if let Some(prefix) = self.token_descr() { - format!("{} `{}`", prefix, self.this_token_to_string()) - } else { - format!("`{}`", self.this_token_to_string()) - } - } - - fn unexpected_last(&self, t: &token::Token) -> PResult<'a, T> { - let token_str = pprust::token_to_string(t); - Err(self.span_fatal(self.prev_span, &format!("unexpected token: `{}`", token_str))) - } - - crate fn unexpected(&mut self) -> PResult<'a, T> { - match self.expect_one_of(&[], &[]) { - Err(e) => Err(e), - Ok(_) => unreachable!(), - } - } - - /// Expects and consumes the token `t`. Signals an error if the next token is not `t`. - pub fn expect(&mut self, t: &token::Token) -> PResult<'a, bool /* recovered */> { - if self.expected_tokens.is_empty() { - if self.token == *t { - self.bump(); - Ok(false) - } else { - let token_str = pprust::token_to_string(t); - let this_token_str = self.this_token_descr(); - let mut err = self.fatal(&format!("expected `{}`, found {}", - token_str, - this_token_str)); - - let sp = if self.token == token::Token::Eof { - // EOF, don't want to point at the following char, but rather the last token - self.prev_span - } else { - self.sess.source_map().next_point(self.prev_span) - }; - let label_exp = format!("expected `{}`", token_str); - match self.recover_closing_delimiter(&[t.clone()], err) { - Err(e) => err = e, - Ok(recovered) => { - return Ok(recovered); - } - } - let cm = self.sess.source_map(); - match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) { - (Ok(ref a), Ok(ref b)) if a.line == b.line => { - // When the spans are in the same line, it means that the only content - // between them is whitespace, point only at the found token. - err.span_label(self.span, label_exp); - } - _ => { - err.span_label(sp, label_exp); - err.span_label(self.span, "unexpected token"); - } - } - Err(err) - } - } else { - self.expect_one_of(slice::from_ref(t), &[]) - } - } - - fn recover_closing_delimiter( - &mut self, - tokens: &[token::Token], - mut err: DiagnosticBuilder<'a>, - ) -> PResult<'a, bool> { - let mut pos = None; - // we want to use the last closing delim that would apply - for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() { - if tokens.contains(&token::CloseDelim(unmatched.expected_delim)) - && Some(self.span) > unmatched.unclosed_span - { - pos = Some(i); - } - } - match pos { - Some(pos) => { - // Recover and assume that the detected unclosed delimiter was meant for - // this location. Emit the diagnostic and act as if the delimiter was - // present for the parser's sake. - - // Don't attempt to recover from this unclosed delimiter more than once. - let unmatched = self.unclosed_delims.remove(pos); - let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim)); - - // We want to suggest the inclusion of the closing delimiter where it makes - // the most sense, which is immediately after the last token: - // - // {foo(bar {}} - // - ^ - // | | - // | help: `)` may belong here (FIXME: #58270) - // | - // unclosed delimiter - if let Some(sp) = unmatched.unclosed_span { - err.span_label(sp, "unclosed delimiter"); - } - err.span_suggestion_short( - self.sess.source_map().next_point(self.prev_span), - &format!("{} may belong here", delim.to_string()), - delim.to_string(), - Applicability::MaybeIncorrect, - ); - err.emit(); - self.expected_tokens.clear(); // reduce errors - Ok(true) - } - _ => Err(err), - } - } - - /// Expect next token to be edible or inedible token. If edible, - /// then consume it; if inedible, then return without consuming - /// anything. Signal a fatal error if next token is unexpected. - pub fn expect_one_of( - &mut self, - edible: &[token::Token], - inedible: &[token::Token], - ) -> PResult<'a, bool /* recovered */> { - fn tokens_to_string(tokens: &[TokenType]) -> String { - let mut i = tokens.iter(); - // This might be a sign we need a connect method on Iterator. - let b = i.next() - .map_or(String::new(), |t| t.to_string()); - i.enumerate().fold(b, |mut b, (i, a)| { - if tokens.len() > 2 && i == tokens.len() - 2 { - b.push_str(", or "); - } else if tokens.len() == 2 && i == tokens.len() - 2 { - b.push_str(" or "); - } else { - b.push_str(", "); - } - b.push_str(&a.to_string()); - b - }) - } - if edible.contains(&self.token) { - self.bump(); - Ok(false) - } else if inedible.contains(&self.token) { - // leave it in the input - Ok(false) - } else { - let mut expected = edible.iter() - .map(|x| TokenType::Token(x.clone())) - .chain(inedible.iter().map(|x| TokenType::Token(x.clone()))) - .chain(self.expected_tokens.iter().cloned()) - .collect::>(); - expected.sort_by_cached_key(|x| x.to_string()); - expected.dedup(); - let expect = tokens_to_string(&expected[..]); - let actual = self.this_token_to_string(); - let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { - let short_expect = if expected.len() > 6 { - format!("{} possible tokens", expected.len()) - } else { - expect.clone() - }; - (format!("expected one of {}, found `{}`", expect, actual), - (self.sess.source_map().next_point(self.prev_span), - format!("expected one of {} here", short_expect))) - } else if expected.is_empty() { - (format!("unexpected token: `{}`", actual), - (self.prev_span, "unexpected token after this".to_string())) - } else { - (format!("expected {}, found `{}`", expect, actual), - (self.sess.source_map().next_point(self.prev_span), - format!("expected {} here", expect))) - }; - let mut err = self.fatal(&msg_exp); - if self.token.is_ident_named("and") { - err.span_suggestion_short( - self.span, - "use `&&` instead of `and` for the boolean operator", - "&&".to_string(), - Applicability::MaybeIncorrect, - ); - } - if self.token.is_ident_named("or") { - err.span_suggestion_short( - self.span, - "use `||` instead of `or` for the boolean operator", - "||".to_string(), - Applicability::MaybeIncorrect, - ); - } - let sp = if self.token == token::Token::Eof { - // This is EOF, don't want to point at the following char, but rather the last token - self.prev_span - } else { - label_sp - }; - match self.recover_closing_delimiter(&expected.iter().filter_map(|tt| match tt { - TokenType::Token(t) => Some(t.clone()), - _ => None, - }).collect::>(), err) { - Err(e) => err = e, - Ok(recovered) => { - return Ok(recovered); - } - } - - let cm = self.sess.source_map(); - match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) { - (Ok(ref a), Ok(ref b)) if a.line == b.line => { - // When the spans are in the same line, it means that the only content between - // them is whitespace, point at the found token in that case: - // - // X | () => { syntax error }; - // | ^^^^^ expected one of 8 possible tokens here - // - // instead of having: - // - // X | () => { syntax error }; - // | -^^^^^ unexpected token - // | | - // | expected one of 8 possible tokens here - err.span_label(self.span, label_exp); - } - _ if self.prev_span == syntax_pos::DUMMY_SP => { - // Account for macro context where the previous span might not be - // available to avoid incorrect output (#54841). - err.span_label(self.span, "unexpected token"); - } - _ => { - err.span_label(sp, label_exp); - err.span_label(self.span, "unexpected token"); - } - } - Err(err) - } - } - - /// Returns the span of expr, if it was not interpolated or the span of the interpolated token. - fn interpolated_or_expr_span(&self, - expr: PResult<'a, P>) - -> PResult<'a, (Span, P)> { - expr.map(|e| { - if self.prev_token_kind == PrevTokenKind::Interpolated { - (self.prev_span, e) - } else { - (e.span, e) - } - }) - } - - fn expected_ident_found(&self) -> DiagnosticBuilder<'a> { - let mut err = self.struct_span_err(self.span, - &format!("expected identifier, found {}", - self.this_token_descr())); - if let token::Ident(ident, false) = &self.token { - if ident.is_reserved() && !ident.is_path_segment_keyword() && - ident.name != keywords::Underscore.name() - { - err.span_suggestion( - self.span, - "you can escape reserved keywords to use them as identifiers", - format!("r#{}", ident), - Applicability::MaybeIncorrect, - ); - } - } - if let Some(token_descr) = self.token_descr() { - err.span_label(self.span, format!("expected identifier, found {}", token_descr)); - } else { - err.span_label(self.span, "expected identifier"); - if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { - err.span_suggestion( - self.span, - "remove this comma", - String::new(), - Applicability::MachineApplicable, - ); - } - } - err - } - - pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> { - self.parse_ident_common(true) - } - - fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, ast::Ident> { - match self.token { - token::Ident(ident, _) => { - if self.token.is_reserved_ident() { - let mut err = self.expected_ident_found(); - if recover { - err.emit(); - } else { - return Err(err); - } - } - let span = self.span; - self.bump(); - Ok(Ident::new(ident.name, span)) - } - _ => { - Err(if self.prev_token_kind == PrevTokenKind::DocComment { - self.span_fatal_err(self.prev_span, Error::UselessDocComment) - } else { - self.expected_ident_found() - }) - } - } - } - - /// Checks if the next token is `tok`, and returns `true` if so. - /// - /// This method will automatically add `tok` to `expected_tokens` if `tok` is not - /// encountered. - crate fn check(&mut self, tok: &token::Token) -> bool { - let is_present = self.token == *tok; - if !is_present { self.expected_tokens.push(TokenType::Token(tok.clone())); } - is_present - } - - /// Consumes a token 'tok' if it exists. Returns whether the given token was present. - pub fn eat(&mut self, tok: &token::Token) -> bool { - let is_present = self.check(tok); - if is_present { self.bump() } - is_present - } - - fn check_keyword(&mut self, kw: keywords::Keyword) -> bool { - self.expected_tokens.push(TokenType::Keyword(kw)); - self.token.is_keyword(kw) - } - - /// If the next token is the given keyword, eats it and returns - /// `true`. Otherwise, returns `false`. - pub fn eat_keyword(&mut self, kw: keywords::Keyword) -> bool { - if self.check_keyword(kw) { - self.bump(); - true - } else { - false - } - } - - fn eat_keyword_noexpect(&mut self, kw: keywords::Keyword) -> bool { - if self.token.is_keyword(kw) { - self.bump(); - true - } else { - false - } - } - - /// If the given word is not a keyword, signals an error. - /// If the next token is not the given word, signals an error. - /// Otherwise, eats it. - fn expect_keyword(&mut self, kw: keywords::Keyword) -> PResult<'a, ()> { - if !self.eat_keyword(kw) { - self.unexpected() - } else { - Ok(()) - } - } - - fn check_ident(&mut self) -> bool { - if self.token.is_ident() { - true - } else { - self.expected_tokens.push(TokenType::Ident); - false - } - } - - fn check_path(&mut self) -> bool { - if self.token.is_path_start() { - true - } else { - self.expected_tokens.push(TokenType::Path); - false - } - } - - fn check_type(&mut self) -> bool { - if self.token.can_begin_type() { - true - } else { - self.expected_tokens.push(TokenType::Type); - false - } - } - - fn check_const_arg(&mut self) -> bool { - if self.token.can_begin_const_arg() { - true - } else { - self.expected_tokens.push(TokenType::Const); - false - } - } - - /// Expects and consumes a `+`. if `+=` is seen, replaces it with a `=` - /// and continues. If a `+` is not seen, returns `false`. - /// - /// This is used when token-splitting `+=` into `+`. - /// See issue #47856 for an example of when this may occur. - fn eat_plus(&mut self) -> bool { - self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); - match self.token { - token::BinOp(token::Plus) => { - self.bump(); - true - } - token::BinOpEq(token::Plus) => { - let span = self.span.with_lo(self.span.lo() + BytePos(1)); - self.bump_with(token::Eq, span); - true - } - _ => false, - } - } - - - /// Checks to see if the next token is either `+` or `+=`. - /// Otherwise returns `false`. - fn check_plus(&mut self) -> bool { - if self.token.is_like_plus() { - true - } - else { - self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); - false - } - } - - /// Expects and consumes an `&`. If `&&` is seen, replaces it with a single - /// `&` and continues. If an `&` is not seen, signals an error. - fn expect_and(&mut self) -> PResult<'a, ()> { - self.expected_tokens.push(TokenType::Token(token::BinOp(token::And))); - match self.token { - token::BinOp(token::And) => { - self.bump(); - Ok(()) - } - token::AndAnd => { - let span = self.span.with_lo(self.span.lo() + BytePos(1)); - Ok(self.bump_with(token::BinOp(token::And), span)) - } - _ => self.unexpected() - } - } - - /// Expects and consumes an `|`. If `||` is seen, replaces it with a single - /// `|` and continues. If an `|` is not seen, signals an error. - fn expect_or(&mut self) -> PResult<'a, ()> { - self.expected_tokens.push(TokenType::Token(token::BinOp(token::Or))); - match self.token { - token::BinOp(token::Or) => { - self.bump(); - Ok(()) - } - token::OrOr => { - let span = self.span.with_lo(self.span.lo() + BytePos(1)); - Ok(self.bump_with(token::BinOp(token::Or), span)) - } - _ => self.unexpected() - } - } - - fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option) { - match suffix { - None => {/* everything ok */} - Some(suf) => { - let text = suf.as_str(); - if text.is_empty() { - self.span_bug(sp, "found empty literal suffix in Some") - } - let msg = format!("{} with a suffix is invalid", kind); - self.struct_span_err(sp, &msg) - .span_label(sp, msg) - .emit(); - } - } - } - - /// Attempts to consume a `<`. If `<<` is seen, replaces it with a single - /// `<` and continue. If `<-` is seen, replaces it with a single `<` - /// and continue. If a `<` is not seen, returns false. - /// - /// This is meant to be used when parsing generics on a path to get the - /// starting token. - fn eat_lt(&mut self) -> bool { - self.expected_tokens.push(TokenType::Token(token::Lt)); - let ate = match self.token { - token::Lt => { - self.bump(); - true - } - token::BinOp(token::Shl) => { - let span = self.span.with_lo(self.span.lo() + BytePos(1)); - self.bump_with(token::Lt, span); - true - } - token::LArrow => { - let span = self.span.with_lo(self.span.lo() + BytePos(1)); - self.bump_with(token::BinOp(token::Minus), span); - true - } - _ => false, - }; - - if ate { - // See doc comment for `unmatched_angle_bracket_count`. - self.unmatched_angle_bracket_count += 1; - self.max_angle_bracket_count += 1; - debug!("eat_lt: (increment) count={:?}", self.unmatched_angle_bracket_count); - } - - ate - } - - fn expect_lt(&mut self) -> PResult<'a, ()> { - if !self.eat_lt() { - self.unexpected() - } else { - Ok(()) - } - } - - /// Expects and consumes a single `>` token. if a `>>` is seen, replaces it - /// with a single `>` and continues. If a `>` is not seen, signals an error. - fn expect_gt(&mut self) -> PResult<'a, ()> { - self.expected_tokens.push(TokenType::Token(token::Gt)); - let ate = match self.token { - token::Gt => { - self.bump(); - Some(()) - } - token::BinOp(token::Shr) => { - let span = self.span.with_lo(self.span.lo() + BytePos(1)); - Some(self.bump_with(token::Gt, span)) - } - token::BinOpEq(token::Shr) => { - let span = self.span.with_lo(self.span.lo() + BytePos(1)); - Some(self.bump_with(token::Ge, span)) - } - token::Ge => { - let span = self.span.with_lo(self.span.lo() + BytePos(1)); - Some(self.bump_with(token::Eq, span)) - } - _ => None, - }; - - match ate { - Some(_) => { - // See doc comment for `unmatched_angle_bracket_count`. - if self.unmatched_angle_bracket_count > 0 { - self.unmatched_angle_bracket_count -= 1; - debug!("expect_gt: (decrement) count={:?}", self.unmatched_angle_bracket_count); - } - - Ok(()) - }, - None => self.unexpected(), - } - } - - /// Eats and discards tokens until one of `kets` is encountered. Respects token trees, - /// passes through any errors encountered. Used for error recovery. - fn eat_to_tokens(&mut self, kets: &[&token::Token]) { - let handler = self.diagnostic(); - - if let Err(ref mut err) = self.parse_seq_to_before_tokens(kets, - SeqSep::none(), - TokenExpectType::Expect, - |p| Ok(p.parse_token_tree())) { - handler.cancel(err); - } - } - - /// Parses a sequence, including the closing delimiter. The function - /// `f` must consume tokens until reaching the next separator or - /// closing bracket. - pub fn parse_seq_to_end(&mut self, - ket: &token::Token, - sep: SeqSep, - f: F) - -> PResult<'a, Vec> where - F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, - { - let (val, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; - if !recovered { - self.bump(); - } - Ok(val) - } - - /// Parses a sequence, not including the closing delimiter. The function - /// `f` must consume tokens until reaching the next separator or - /// closing bracket. - pub fn parse_seq_to_before_end( - &mut self, - ket: &token::Token, - sep: SeqSep, - f: F, - ) -> PResult<'a, (Vec, bool)> - where F: FnMut(&mut Parser<'a>) -> PResult<'a, T> - { - self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f) - } - - fn parse_seq_to_before_tokens( - &mut self, - kets: &[&token::Token], - sep: SeqSep, - expect: TokenExpectType, - mut f: F, - ) -> PResult<'a, (Vec, bool /* recovered */)> - where F: FnMut(&mut Parser<'a>) -> PResult<'a, T> - { - let mut first = true; - let mut recovered = false; - let mut v = vec![]; - while !kets.iter().any(|k| { - match expect { - TokenExpectType::Expect => self.check(k), - TokenExpectType::NoExpect => self.token == **k, - } - }) { - match self.token { - token::CloseDelim(..) | token::Eof => break, - _ => {} - }; - if let Some(ref t) = sep.sep { - if first { - first = false; - } else { - match self.expect(t) { - Ok(false) => {} - Ok(true) => { - recovered = true; - break; - } - Err(mut e) => { - // Attempt to keep parsing if it was a similar separator - if let Some(ref tokens) = t.similar_tokens() { - if tokens.contains(&self.token) { - self.bump(); - } - } - e.emit(); - // Attempt to keep parsing if it was an omitted separator - match f(self) { - Ok(t) => { - v.push(t); - continue; - }, - Err(mut e) => { - e.cancel(); - break; - } - } - } - } - } - } - if sep.trailing_sep_allowed && kets.iter().any(|k| { - match expect { - TokenExpectType::Expect => self.check(k), - TokenExpectType::NoExpect => self.token == **k, - } - }) { - break; - } - - let t = f(self)?; - v.push(t); - } - - Ok((v, recovered)) - } - - /// Parses a sequence, including the closing delimiter. The function - /// `f` must consume tokens until reaching the next separator or - /// closing bracket. - fn parse_unspanned_seq( - &mut self, - bra: &token::Token, - ket: &token::Token, - sep: SeqSep, - f: F, - ) -> PResult<'a, Vec> where - F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, - { - self.expect(bra)?; - let (result, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; - if !recovered { - self.eat(ket); - } - Ok(result) - } - - /// Advance the parser by one token - pub fn bump(&mut self) { - if self.prev_token_kind == PrevTokenKind::Eof { - // Bumping after EOF is a bad sign, usually an infinite loop. - self.bug("attempted to bump the parser past EOF (may be stuck in a loop)"); - } - - self.prev_span = self.meta_var_span.take().unwrap_or(self.span); - - // Record last token kind for possible error recovery. - self.prev_token_kind = match self.token { - token::DocComment(..) => PrevTokenKind::DocComment, - token::Comma => PrevTokenKind::Comma, - token::BinOp(token::Plus) => PrevTokenKind::Plus, - token::Interpolated(..) => PrevTokenKind::Interpolated, - token::Eof => PrevTokenKind::Eof, - token::Ident(..) => PrevTokenKind::Ident, - _ => PrevTokenKind::Other, - }; - - let next = self.next_tok(); - self.span = next.sp; - self.token = next.tok; - self.expected_tokens.clear(); - // check after each token - self.process_potential_macro_variable(); - } - - /// Advance the parser using provided token as a next one. Use this when - /// consuming a part of a token. For example a single `<` from `<<`. - fn bump_with(&mut self, next: token::Token, span: Span) { - self.prev_span = self.span.with_hi(span.lo()); - // It would be incorrect to record the kind of the current token, but - // fortunately for tokens currently using `bump_with`, the - // prev_token_kind will be of no use anyway. - self.prev_token_kind = PrevTokenKind::Other; - self.span = span; - self.token = next; - self.expected_tokens.clear(); - } - - pub fn look_ahead(&self, dist: usize, f: F) -> R where - F: FnOnce(&token::Token) -> R, - { - if dist == 0 { - return f(&self.token) - } - - f(&match self.token_cursor.frame.tree_cursor.look_ahead(dist - 1) { - Some(tree) => match tree { - TokenTree::Token(_, tok) => tok, - TokenTree::Delimited(_, delim, _) => token::OpenDelim(delim), - }, - None => token::CloseDelim(self.token_cursor.frame.delim), - }) - } - - fn look_ahead_span(&self, dist: usize) -> Span { - if dist == 0 { - return self.span - } - - match self.token_cursor.frame.tree_cursor.look_ahead(dist - 1) { - Some(TokenTree::Token(span, _)) => span, - Some(TokenTree::Delimited(span, ..)) => span.entire(), - None => self.look_ahead_span(dist - 1), - } - } - pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> { - self.sess.span_diagnostic.struct_span_fatal(self.span, m) - } - pub fn span_fatal>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { - self.sess.span_diagnostic.struct_span_fatal(sp, m) - } - fn span_fatal_err>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> { - err.span_err(sp, self.diagnostic()) - } - fn bug(&self, m: &str) -> ! { - self.sess.span_diagnostic.span_bug(self.span, m) - } - fn span_err>(&self, sp: S, m: &str) { - self.sess.span_diagnostic.span_err(sp, m) - } - fn struct_span_err>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { - self.sess.span_diagnostic.struct_span_err(sp, m) - } - crate fn span_bug>(&self, sp: S, m: &str) -> ! { - self.sess.span_diagnostic.span_bug(sp, m) - } - - fn cancel(&self, err: &mut DiagnosticBuilder<'_>) { - self.sess.span_diagnostic.cancel(err) - } - - crate fn diagnostic(&self) -> &'a errors::Handler { - &self.sess.span_diagnostic - } - - /// Is the current token one of the keywords that signals a bare function type? - fn token_is_bare_fn_keyword(&mut self) -> bool { - self.check_keyword(keywords::Fn) || - self.check_keyword(keywords::Unsafe) || - self.check_keyword(keywords::Extern) - } - - /// Parses a `TyKind::BareFn` type. - fn parse_ty_bare_fn(&mut self, generic_params: Vec) -> PResult<'a, TyKind> { - /* - - [unsafe] [extern "ABI"] fn (S) -> T - ^~~~^ ^~~~^ ^~^ ^ - | | | | - | | | Return type - | | Argument types - | | - | ABI - Function Style - */ - - let unsafety = self.parse_unsafety(); - let abi = if self.eat_keyword(keywords::Extern) { - self.parse_opt_abi()?.unwrap_or(Abi::C) - } else { - Abi::Rust - }; - - self.expect_keyword(keywords::Fn)?; - let (inputs, variadic) = self.parse_fn_args(false, true)?; - let ret_ty = self.parse_ret_ty(false)?; - let decl = P(FnDecl { - inputs, - output: ret_ty, - variadic, - }); - Ok(TyKind::BareFn(P(BareFnTy { - abi, - unsafety, - generic_params, - decl, - }))) - } - - /// Parses asyncness: `async` or nothing. - fn parse_asyncness(&mut self) -> IsAsync { - if self.eat_keyword(keywords::Async) { - IsAsync::Async { - closure_id: ast::DUMMY_NODE_ID, - return_impl_trait_id: ast::DUMMY_NODE_ID, - } - } else { - IsAsync::NotAsync - } - } - - /// Parses unsafety: `unsafe` or nothing. - fn parse_unsafety(&mut self) -> Unsafety { - if self.eat_keyword(keywords::Unsafe) { - Unsafety::Unsafe - } else { - Unsafety::Normal - } - } - - /// Parses the items in a trait declaration. - pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> { - maybe_whole!(self, NtTraitItem, |x| x); - let attrs = self.parse_outer_attributes()?; - let (mut item, tokens) = self.collect_tokens(|this| { - this.parse_trait_item_(at_end, attrs) - })?; - // See `parse_item` for why this clause is here. - if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { - item.tokens = Some(tokens); - } - Ok(item) - } - - fn parse_trait_item_(&mut self, - at_end: &mut bool, - mut attrs: Vec) -> PResult<'a, TraitItem> { - let lo = self.span; - - let (name, node, generics) = if self.eat_keyword(keywords::Type) { - self.parse_trait_item_assoc_ty()? - } else if self.is_const_item() { - self.expect_keyword(keywords::Const)?; - let ident = self.parse_ident()?; - self.expect(&token::Colon)?; - let ty = self.parse_ty()?; - let default = if self.eat(&token::Eq) { - let expr = self.parse_expr()?; - self.expect(&token::Semi)?; - Some(expr) - } else { - self.expect(&token::Semi)?; - None - }; - (ident, TraitItemKind::Const(ty, default), ast::Generics::default()) - } else if let Some(mac) = self.parse_assoc_macro_invoc("trait", None, &mut false)? { - // trait item macro. - (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default()) - } else { - let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; - - let ident = self.parse_ident()?; - let mut generics = self.parse_generics()?; - - let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| { - // This is somewhat dubious; We don't want to allow - // argument names to be left off if there is a - // definition... - - // We don't allow argument names to be left off in edition 2018. - p.parse_arg_general(p.span.rust_2018(), true) - })?; - generics.where_clause = self.parse_where_clause()?; - - let sig = ast::MethodSig { - header: FnHeader { - unsafety, - constness, - abi, - asyncness, - }, - decl: d, - }; - - let body = match self.token { - token::Semi => { - self.bump(); - *at_end = true; - debug!("parse_trait_methods(): parsing required method"); - None - } - token::OpenDelim(token::Brace) => { - debug!("parse_trait_methods(): parsing provided method"); - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) - } - token::Interpolated(ref nt) => { - match **nt { - token::NtBlock(..) => { - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) - } - _ => { - let token_str = self.this_token_descr(); - let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", - token_str)); - err.span_label(self.span, "expected `;` or `{`"); - return Err(err); - } - } - } - _ => { - let token_str = self.this_token_descr(); - let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", - token_str)); - err.span_label(self.span, "expected `;` or `{`"); - return Err(err); - } - }; - (ident, ast::TraitItemKind::Method(sig, body), generics) - }; - - Ok(TraitItem { - id: ast::DUMMY_NODE_ID, - ident: name, - attrs, - generics, - node, - span: lo.to(self.prev_span), - tokens: None, - }) - } - - /// Parses an optional return type `[ -> TY ]` in a function declaration. - fn parse_ret_ty(&mut self, allow_plus: bool) -> PResult<'a, FunctionRetTy> { - if self.eat(&token::RArrow) { - Ok(FunctionRetTy::Ty(self.parse_ty_common(allow_plus, true)?)) - } else { - Ok(FunctionRetTy::Default(self.span.shrink_to_lo())) - } - } - - /// Parses a type. - pub fn parse_ty(&mut self) -> PResult<'a, P> { - self.parse_ty_common(true, true) - } - - /// Parses a type in restricted contexts where `+` is not permitted. - /// - /// Example 1: `&'a TYPE` - /// `+` is prohibited to maintain operator priority (P(+) < P(&)). - /// Example 2: `value1 as TYPE + value2` - /// `+` is prohibited to avoid interactions with expression grammar. - fn parse_ty_no_plus(&mut self) -> PResult<'a, P> { - self.parse_ty_common(false, true) - } - - fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool) - -> PResult<'a, P> { - maybe_whole!(self, NtTy, |x| x); - - let lo = self.span; - let mut impl_dyn_multi = false; - let node = if self.eat(&token::OpenDelim(token::Paren)) { - // `(TYPE)` is a parenthesized type. - // `(TYPE,)` is a tuple with a single field of type TYPE. - let mut ts = vec![]; - let mut last_comma = false; - while self.token != token::CloseDelim(token::Paren) { - ts.push(self.parse_ty()?); - if self.eat(&token::Comma) { - last_comma = true; - } else { - last_comma = false; - break; - } - } - let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus; - self.expect(&token::CloseDelim(token::Paren))?; - - if ts.len() == 1 && !last_comma { - let ty = ts.into_iter().nth(0).unwrap().into_inner(); - let maybe_bounds = allow_plus && self.token.is_like_plus(); - match ty.node { - // `(TY_BOUND_NOPAREN) + BOUND + ...`. - TyKind::Path(None, ref path) if maybe_bounds => { - self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)? - } - TyKind::TraitObject(ref bounds, TraitObjectSyntax::None) - if maybe_bounds && bounds.len() == 1 && !trailing_plus => { - let path = match bounds[0] { - GenericBound::Trait(ref pt, ..) => pt.trait_ref.path.clone(), - GenericBound::Outlives(..) => self.bug("unexpected lifetime bound"), - }; - self.parse_remaining_bounds(Vec::new(), path, lo, true)? - } - // `(TYPE)` - _ => TyKind::Paren(P(ty)) - } - } else { - TyKind::Tup(ts) - } - } else if self.eat(&token::Not) { - // Never type `!` - TyKind::Never - } else if self.eat(&token::BinOp(token::Star)) { - // Raw pointer - TyKind::Ptr(self.parse_ptr()?) - } else if self.eat(&token::OpenDelim(token::Bracket)) { - // Array or slice - let t = self.parse_ty()?; - // Parse optional `; EXPR` in `[TYPE; EXPR]` - let t = match self.maybe_parse_fixed_length_of_vec()? { - None => TyKind::Slice(t), - Some(length) => TyKind::Array(t, AnonConst { - id: ast::DUMMY_NODE_ID, - value: length, - }), - }; - self.expect(&token::CloseDelim(token::Bracket))?; - t - } else if self.check(&token::BinOp(token::And)) || self.check(&token::AndAnd) { - // Reference - self.expect_and()?; - self.parse_borrowed_pointee()? - } else if self.eat_keyword_noexpect(keywords::Typeof) { - // `typeof(EXPR)` - // In order to not be ambiguous, the type must be surrounded by parens. - self.expect(&token::OpenDelim(token::Paren))?; - let e = AnonConst { - id: ast::DUMMY_NODE_ID, - value: self.parse_expr()?, - }; - self.expect(&token::CloseDelim(token::Paren))?; - TyKind::Typeof(e) - } else if self.eat_keyword(keywords::Underscore) { - // A type to be inferred `_` - TyKind::Infer - } else if self.token_is_bare_fn_keyword() { - // Function pointer type - self.parse_ty_bare_fn(Vec::new())? - } else if self.check_keyword(keywords::For) { - // Function pointer type or bound list (trait object type) starting with a poly-trait. - // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` - // `for<'lt> Trait1<'lt> + Trait2 + 'a` - let lo = self.span; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - if self.token_is_bare_fn_keyword() { - self.parse_ty_bare_fn(lifetime_defs)? - } else { - let path = self.parse_path(PathStyle::Type)?; - let parse_plus = allow_plus && self.check_plus(); - self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? - } - } else if self.eat_keyword(keywords::Impl) { - // Always parse bounds greedily for better error recovery. - let bounds = self.parse_generic_bounds(None)?; - impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; - TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds) - } else if self.check_keyword(keywords::Dyn) && - (self.span.rust_2018() || - self.look_ahead(1, |t| t.can_begin_bound() && - !can_continue_type_after_non_fn_ident(t))) { - self.bump(); // `dyn` - // Always parse bounds greedily for better error recovery. - let bounds = self.parse_generic_bounds(None)?; - impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; - TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn) - } else if self.check(&token::Question) || - self.check_lifetime() && self.look_ahead(1, |t| t.is_like_plus()) { - // Bound list (trait object type) - TyKind::TraitObject(self.parse_generic_bounds_common(allow_plus, None)?, - TraitObjectSyntax::None) - } else if self.eat_lt() { - // Qualified path - let (qself, path) = self.parse_qpath(PathStyle::Type)?; - TyKind::Path(Some(qself), path) - } else if self.token.is_path_start() { - // Simple path - let path = self.parse_path(PathStyle::Type)?; - if self.eat(&token::Not) { - // Macro invocation in type position - let (delim, tts) = self.expect_delimited_token_tree()?; - let node = Mac_ { path, tts, delim }; - TyKind::Mac(respan(lo.to(self.prev_span), node)) - } else { - // Just a type path or bound list (trait object type) starting with a trait. - // `Type` - // `Trait1 + Trait2 + 'a` - if allow_plus && self.check_plus() { - self.parse_remaining_bounds(Vec::new(), path, lo, true)? - } else { - TyKind::Path(None, path) - } - } - } else { - let msg = format!("expected type, found {}", self.this_token_descr()); - return Err(self.fatal(&msg)); - }; - - let span = lo.to(self.prev_span); - let ty = Ty { node, span, id: ast::DUMMY_NODE_ID }; - - // Try to recover from use of `+` with incorrect priority. - self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty); - self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?; - let ty = self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)?; - - Ok(P(ty)) - } - - fn parse_remaining_bounds(&mut self, generic_params: Vec, path: ast::Path, - lo: Span, parse_plus: bool) -> PResult<'a, TyKind> { - let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span)); - let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)]; - if parse_plus { - self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded - bounds.append(&mut self.parse_generic_bounds(None)?); - } - Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) - } - - fn maybe_report_ambiguous_plus(&mut self, allow_plus: bool, impl_dyn_multi: bool, ty: &Ty) { - if !allow_plus && impl_dyn_multi { - let sum_with_parens = format!("({})", pprust::ty_to_string(&ty)); - self.struct_span_err(ty.span, "ambiguous `+` in a type") - .span_suggestion( - ty.span, - "use parentheses to disambiguate", - sum_with_parens, - Applicability::MachineApplicable - ).emit(); - } - } - - fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> { - // Do not add `+` to expected tokens. - if !allow_plus || !self.token.is_like_plus() { - return Ok(()) - } - - self.bump(); // `+` - let bounds = self.parse_generic_bounds(None)?; - let sum_span = ty.span.to(self.prev_span); - - let mut err = struct_span_err!(self.sess.span_diagnostic, sum_span, E0178, - "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(ty)); - - match ty.node { - TyKind::Rptr(ref lifetime, ref mut_ty) => { - let sum_with_parens = pprust::to_string(|s| { - use crate::print::pprust::PrintState; - - s.s.word("&")?; - s.print_opt_lifetime(lifetime)?; - s.print_mutability(mut_ty.mutbl)?; - s.popen()?; - s.print_type(&mut_ty.ty)?; - s.print_type_bounds(" +", &bounds)?; - s.pclose() - }); - err.span_suggestion( - sum_span, - "try adding parentheses", - sum_with_parens, - Applicability::MachineApplicable - ); - } - TyKind::Ptr(..) | TyKind::BareFn(..) => { - err.span_label(sum_span, "perhaps you forgot parentheses?"); - } - _ => { - err.span_label(sum_span, "expected a path"); - }, - } - err.emit(); - Ok(()) - } - - // Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`. - fn maybe_recover_from_bad_qpath(&mut self, base: T, allow_recovery: bool) - -> PResult<'a, T> { - // Do not add `::` to expected tokens. - if !allow_recovery || self.token != token::ModSep { - return Ok(base); - } - let ty = match base.to_ty() { - Some(ty) => ty, - None => return Ok(base), - }; - - self.bump(); // `::` - let mut segments = Vec::new(); - self.parse_path_segments(&mut segments, T::PATH_STYLE, true)?; - - let span = ty.span.to(self.prev_span); - let path_span = span.to(span); // use an empty path since `position` == 0 - let recovered = base.to_recovered( - Some(QSelf { ty, path_span, position: 0 }), - ast::Path { segments, span }, - ); - - self.diagnostic() - .struct_span_err(span, "missing angle brackets in associated item path") - .span_suggestion( // this is a best-effort recovery - span, "try", recovered.to_string(), Applicability::MaybeIncorrect - ).emit(); - - Ok(recovered) - } - - fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { - let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; - let mutbl = self.parse_mutability(); - let ty = self.parse_ty_no_plus()?; - return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty: ty, mutbl: mutbl })); - } - - fn parse_ptr(&mut self) -> PResult<'a, MutTy> { - let mutbl = if self.eat_keyword(keywords::Mut) { - Mutability::Mutable - } else if self.eat_keyword(keywords::Const) { - Mutability::Immutable - } else { - let span = self.prev_span; - let msg = "expected mut or const in raw pointer type"; - self.struct_span_err(span, msg) - .span_label(span, msg) - .help("use `*mut T` or `*const T` as appropriate") - .emit(); - Mutability::Immutable - }; - let t = self.parse_ty_no_plus()?; - Ok(MutTy { ty: t, mutbl: mutbl }) - } - - fn is_named_argument(&mut self) -> bool { - let offset = match self.token { - token::Interpolated(ref nt) => match **nt { - token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), - _ => 0, - } - token::BinOp(token::And) | token::AndAnd => 1, - _ if self.token.is_keyword(keywords::Mut) => 1, - _ => 0, - }; - - self.look_ahead(offset, |t| t.is_ident()) && - self.look_ahead(offset + 1, |t| t == &token::Colon) - } - - /// Skips unexpected attributes and doc comments in this position and emits an appropriate - /// error. - fn eat_incorrect_doc_comment(&mut self, applied_to: &str) { - if let token::DocComment(_) = self.token { - let mut err = self.diagnostic().struct_span_err( - self.span, - &format!("documentation comments cannot be applied to {}", applied_to), - ); - err.span_label(self.span, "doc comments are not allowed here"); - err.emit(); - self.bump(); - } else if self.token == token::Pound && self.look_ahead(1, |t| { - *t == token::OpenDelim(token::Bracket) - }) { - let lo = self.span; - // Skip every token until next possible arg. - while self.token != token::CloseDelim(token::Bracket) { - self.bump(); - } - let sp = lo.to(self.span); - self.bump(); - let mut err = self.diagnostic().struct_span_err( - sp, - &format!("attributes cannot be applied to {}", applied_to), - ); - err.span_label(sp, "attributes are not allowed here"); - err.emit(); - } - } - - /// This version of parse arg doesn't necessarily require identifier names. - fn parse_arg_general(&mut self, require_name: bool, is_trait_item: bool) -> PResult<'a, Arg> { - maybe_whole!(self, NtArg, |x| x); - - if let Ok(Some(_)) = self.parse_self_arg() { - let mut err = self.struct_span_err(self.prev_span, - "unexpected `self` argument in function"); - err.span_label(self.prev_span, - "`self` is only valid as the first argument of an associated function"); - return Err(err); - } - - let (pat, ty) = if require_name || self.is_named_argument() { - debug!("parse_arg_general parse_pat (require_name:{})", - require_name); - self.eat_incorrect_doc_comment("method arguments"); - let pat = self.parse_pat(Some("argument name"))?; - - if let Err(mut err) = self.expect(&token::Colon) { - // If we find a pattern followed by an identifier, it could be an (incorrect) - // C-style parameter declaration. - if self.check_ident() && self.look_ahead(1, |t| { - *t == token::Comma || *t == token::CloseDelim(token::Paren) - }) { - let ident = self.parse_ident().unwrap(); - let span = pat.span.with_hi(ident.span.hi()); - - err.span_suggestion( - span, - "declare the type after the parameter binding", - String::from(": "), - Applicability::HasPlaceholders, - ); - } else if require_name && is_trait_item { - if let PatKind::Ident(_, ident, _) = pat.node { - err.span_suggestion( - pat.span, - "explicitly ignore parameter", - format!("_: {}", ident), - Applicability::MachineApplicable, - ); - } - - err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)"); - } - - return Err(err); - } - - self.eat_incorrect_doc_comment("a method argument's type"); - (pat, self.parse_ty()?) - } else { - debug!("parse_arg_general ident_to_pat"); - let parser_snapshot_before_ty = self.clone(); - self.eat_incorrect_doc_comment("a method argument's type"); - let mut ty = self.parse_ty(); - if ty.is_ok() && self.token != token::Comma && - self.token != token::CloseDelim(token::Paren) { - // This wasn't actually a type, but a pattern looking like a type, - // so we are going to rollback and re-parse for recovery. - ty = self.unexpected(); - } - match ty { - Ok(ty) => { - let ident = Ident::new(keywords::Invalid.name(), self.prev_span); - let pat = P(Pat { - id: ast::DUMMY_NODE_ID, - node: PatKind::Ident( - BindingMode::ByValue(Mutability::Immutable), ident, None), - span: ty.span, - }); - (pat, ty) - } - Err(mut err) => { - // Recover from attempting to parse the argument as a type without pattern. - err.cancel(); - mem::replace(self, parser_snapshot_before_ty); - let pat = self.parse_pat(Some("argument name"))?; - self.expect(&token::Colon)?; - let ty = self.parse_ty()?; - - let mut err = self.diagnostic().struct_span_err_with_code( - pat.span, - "patterns aren't allowed in methods without bodies", - DiagnosticId::Error("E0642".into()), - ); - err.span_suggestion_short( - pat.span, - "give this argument a name or use an underscore to ignore it", - "_".to_owned(), - Applicability::MachineApplicable, - ); - err.emit(); - - // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. - let pat = P(Pat { - node: PatKind::Wild, - span: pat.span, - id: ast::DUMMY_NODE_ID - }); - (pat, ty) - } - } - }; - - Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID }) - } - - /// Parses a single function argument. - crate fn parse_arg(&mut self) -> PResult<'a, Arg> { - self.parse_arg_general(true, false) - } - - /// Parses an argument in a lambda header (e.g., `|arg, arg|`). - fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> { - let pat = self.parse_pat(Some("argument name"))?; - let t = if self.eat(&token::Colon) { - self.parse_ty()? - } else { - P(Ty { - id: ast::DUMMY_NODE_ID, - node: TyKind::Infer, - span: self.prev_span, - }) - }; - Ok(Arg { - ty: t, - pat, - id: ast::DUMMY_NODE_ID - }) - } - - fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option>> { - if self.eat(&token::Semi) { - Ok(Some(self.parse_expr()?)) - } else { - Ok(None) - } - } - - /// Matches `token_lit = LIT_INTEGER | ...`. - fn parse_lit_token(&mut self) -> PResult<'a, LitKind> { - let out = match self.token { - token::Interpolated(ref nt) => match **nt { - token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node { - ExprKind::Lit(ref lit) => { lit.node.clone() } - _ => { return self.unexpected_last(&self.token); } - }, - _ => { return self.unexpected_last(&self.token); } - }, - token::Literal(lit, suf) => { - let diag = Some((self.span, &self.sess.span_diagnostic)); - let (suffix_illegal, result) = parse::lit_token(lit, suf, diag); - - if suffix_illegal { - let sp = self.span; - self.expect_no_suffix(sp, lit.literal_name(), suf) - } - - result.unwrap() - } - token::Dot if self.look_ahead(1, |t| match t { - token::Literal(parse::token::Lit::Integer(_) , _) => true, - _ => false, - }) => { // recover from `let x = .4;` - let lo = self.span; - self.bump(); - if let token::Literal( - parse::token::Lit::Integer(val), - suffix, - ) = self.token { - let suffix = suffix.and_then(|s| { - let s = s.as_str().get(); - if ["f32", "f64"].contains(&s) { - Some(s) - } else { - None - } - }).unwrap_or(""); - self.bump(); - let sp = lo.to(self.prev_span); - let mut err = self.diagnostic() - .struct_span_err(sp, "float literals must have an integer part"); - err.span_suggestion( - sp, - "must have an integer part", - format!("0.{}{}", val, suffix), - Applicability::MachineApplicable, - ); - err.emit(); - return Ok(match suffix { - "f32" => ast::LitKind::Float(val, ast::FloatTy::F32), - "f64" => ast::LitKind::Float(val, ast::FloatTy::F64), - _ => ast::LitKind::FloatUnsuffixed(val), - }); - } else { - unreachable!(); - }; - } - _ => { return self.unexpected_last(&self.token); } - }; - - self.bump(); - Ok(out) - } - - /// Matches `lit = true | false | token_lit`. - crate fn parse_lit(&mut self) -> PResult<'a, Lit> { - let lo = self.span; - let lit = if self.eat_keyword(keywords::True) { - LitKind::Bool(true) - } else if self.eat_keyword(keywords::False) { - LitKind::Bool(false) - } else { - let lit = self.parse_lit_token()?; - lit - }; - Ok(source_map::Spanned { node: lit, span: lo.to(self.prev_span) }) - } - - /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). - crate fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P> { - maybe_whole_expr!(self); - - let minus_lo = self.span; - let minus_present = self.eat(&token::BinOp(token::Minus)); - let lo = self.span; - let literal = self.parse_lit()?; - let hi = self.prev_span; - let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), ThinVec::new()); - - if minus_present { - let minus_hi = self.prev_span; - let unary = self.mk_unary(UnOp::Neg, expr); - Ok(self.mk_expr(minus_lo.to(minus_hi), unary, ThinVec::new())) - } else { - Ok(expr) - } - } - - fn parse_path_segment_ident(&mut self) -> PResult<'a, ast::Ident> { - match self.token { - token::Ident(ident, _) if self.token.is_path_segment_keyword() => { - let span = self.span; - self.bump(); - Ok(Ident::new(ident.name, span)) - } - _ => self.parse_ident(), - } - } - - fn parse_ident_or_underscore(&mut self) -> PResult<'a, ast::Ident> { - match self.token { - token::Ident(ident, false) if ident.name == keywords::Underscore.name() => { - let span = self.span; - self.bump(); - Ok(Ident::new(ident.name, span)) - } - _ => self.parse_ident(), - } - } - - /// Parses a qualified path. - /// Assumes that the leading `<` has been parsed already. - /// - /// `qualified_path = ::path` - /// - /// # Examples - /// `::default` - /// `::a` - /// `::F::a` (without disambiguator) - /// `::F::a::` (with disambiguator) - fn parse_qpath(&mut self, style: PathStyle) -> PResult<'a, (QSelf, ast::Path)> { - let lo = self.prev_span; - let ty = self.parse_ty()?; - - // `path` will contain the prefix of the path up to the `>`, - // if any (e.g., `U` in the `::*` examples - // above). `path_span` has the span of that path, or an empty - // span in the case of something like `::Bar`. - let (mut path, path_span); - if self.eat_keyword(keywords::As) { - let path_lo = self.span; - path = self.parse_path(PathStyle::Type)?; - path_span = path_lo.to(self.prev_span); - } else { - path = ast::Path { segments: Vec::new(), span: syntax_pos::DUMMY_SP }; - path_span = self.span.to(self.span); - } - - // See doc comment for `unmatched_angle_bracket_count`. - self.expect(&token::Gt)?; - if self.unmatched_angle_bracket_count > 0 { - self.unmatched_angle_bracket_count -= 1; - debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count); - } - - self.expect(&token::ModSep)?; - - let qself = QSelf { ty, path_span, position: path.segments.len() }; - self.parse_path_segments(&mut path.segments, style, true)?; - - Ok((qself, ast::Path { segments: path.segments, span: lo.to(self.prev_span) })) - } - - /// Parses simple paths. - /// - /// `path = [::] segment+` - /// `segment = ident | ident[::] | ident[::](args) [-> type]` - /// - /// # Examples - /// `a::b::C` (without disambiguator) - /// `a::b::C::` (with disambiguator) - /// `Fn(Args)` (without disambiguator) - /// `Fn::(Args)` (with disambiguator) - pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, ast::Path> { - self.parse_path_common(style, true) - } - - crate fn parse_path_common(&mut self, style: PathStyle, enable_warning: bool) - -> PResult<'a, ast::Path> { - maybe_whole!(self, NtPath, |path| { - if style == PathStyle::Mod && - path.segments.iter().any(|segment| segment.args.is_some()) { - self.diagnostic().span_err(path.span, "unexpected generic arguments in path"); - } - path - }); - - let lo = self.meta_var_span.unwrap_or(self.span); - let mut segments = Vec::new(); - let mod_sep_ctxt = self.span.ctxt(); - if self.eat(&token::ModSep) { - segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt))); - } - self.parse_path_segments(&mut segments, style, enable_warning)?; - - Ok(ast::Path { segments, span: lo.to(self.prev_span) }) - } - - /// Like `parse_path`, but also supports parsing `Word` meta items into paths for - /// backwards-compatibility. This is used when parsing derive macro paths in `#[derive]` - /// attributes. - pub fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, ast::Path> { - let meta_ident = match self.token { - token::Interpolated(ref nt) => match **nt { - token::NtMeta(ref meta) => match meta.node { - ast::MetaItemKind::Word => Some(meta.ident.clone()), - _ => None, - }, - _ => None, - }, - _ => None, - }; - if let Some(path) = meta_ident { - self.bump(); - return Ok(path); - } - self.parse_path(style) - } - - fn parse_path_segments(&mut self, - segments: &mut Vec, - style: PathStyle, - enable_warning: bool) - -> PResult<'a, ()> { - loop { - let segment = self.parse_path_segment(style, enable_warning)?; - if style == PathStyle::Expr { - // In order to check for trailing angle brackets, we must have finished - // recursing (`parse_path_segment` can indirectly call this function), - // that is, the next token must be the highlighted part of the below example: - // - // `Foo::>::Qux` - // ^ here - // - // As opposed to the below highlight (if we had only finished the first - // recursion): - // - // `Foo::>::Qux` - // ^ here - // - // `PathStyle::Expr` is only provided at the root invocation and never in - // `parse_path_segment` to recurse and therefore can be checked to maintain - // this invariant. - self.check_trailing_angle_brackets(&segment, token::ModSep); - } - segments.push(segment); - - if self.is_import_coupler() || !self.eat(&token::ModSep) { - return Ok(()); - } - } - } - - fn parse_path_segment(&mut self, style: PathStyle, enable_warning: bool) - -> PResult<'a, PathSegment> { - let ident = self.parse_path_segment_ident()?; - - let is_args_start = |token: &token::Token| match *token { - token::Lt | token::BinOp(token::Shl) | token::OpenDelim(token::Paren) => true, - _ => false, - }; - let check_args_start = |this: &mut Self| { - this.expected_tokens.extend_from_slice( - &[TokenType::Token(token::Lt), TokenType::Token(token::OpenDelim(token::Paren))] - ); - is_args_start(&this.token) - }; - - Ok(if style == PathStyle::Type && check_args_start(self) || - style != PathStyle::Mod && self.check(&token::ModSep) - && self.look_ahead(1, |t| is_args_start(t)) { - // Generic arguments are found - `<`, `(`, `::<` or `::(`. - if self.eat(&token::ModSep) && style == PathStyle::Type && enable_warning { - self.diagnostic().struct_span_warn(self.prev_span, "unnecessary path disambiguator") - .span_label(self.prev_span, "try removing `::`").emit(); - } - let lo = self.span; - - // We use `style == PathStyle::Expr` to check if this is in a recursion or not. If - // it isn't, then we reset the unmatched angle bracket count as we're about to start - // parsing a new path. - if style == PathStyle::Expr { - self.unmatched_angle_bracket_count = 0; - self.max_angle_bracket_count = 0; - } - - let args = if self.eat_lt() { - // `<'a, T, A = U>` - let (args, bindings) = - self.parse_generic_args_with_leaning_angle_bracket_recovery(style, lo)?; - self.expect_gt()?; - let span = lo.to(self.prev_span); - AngleBracketedArgs { args, bindings, span }.into() - } else { - // `(T, U) -> R` - self.bump(); // `(` - let (inputs, recovered) = self.parse_seq_to_before_tokens( - &[&token::CloseDelim(token::Paren)], - SeqSep::trailing_allowed(token::Comma), - TokenExpectType::Expect, - |p| p.parse_ty())?; - if !recovered { - self.bump(); // `)` - } - let span = lo.to(self.prev_span); - let output = if self.eat(&token::RArrow) { - Some(self.parse_ty_common(false, false)?) - } else { - None - }; - ParenthesizedArgs { inputs, output, span }.into() - }; - - PathSegment { ident, args, id: ast::DUMMY_NODE_ID } - } else { - // Generic arguments are not found. - PathSegment::from_ident(ident) - }) - } - - crate fn check_lifetime(&mut self) -> bool { - self.expected_tokens.push(TokenType::Lifetime); - self.token.is_lifetime() - } - - /// Parses a single lifetime `'a` or panics. - crate fn expect_lifetime(&mut self) -> Lifetime { - if let Some(ident) = self.token.lifetime() { - let span = self.span; - self.bump(); - Lifetime { ident: Ident::new(ident.name, span), id: ast::DUMMY_NODE_ID } - } else { - self.span_bug(self.span, "not a lifetime") - } - } - - fn eat_label(&mut self) -> Option{# [ doc = " See also [`Any`](trait.Any.html) for a version without the `Clone` requirement." ] pub trait CloneAny : Any + CloneToAny {} impl < T : StdAny + Clone > CloneAny for T {}}; ( Any trait )=>{# [ doc = " See also [`CloneAny`](trait.CloneAny.html) for a cloneable version of this trait." ] pub trait Any : StdAny {} impl < T : StdAny > Any for T {}}; } -macro_rules! __ra_macro_fixture317 {($base : ident , $(+ $bounds : ident )*)=>{ impl fmt :: Debug for $base $(+ $bounds )* {# [ inline ] fn fmt (& self , f : & mut fmt :: Formatter )-> fmt :: Result { f . pad ( stringify ! ($base $(+ $bounds )*))}} impl UncheckedAnyExt for $base $(+ $bounds )* {# [ inline ] unsafe fn downcast_ref_unchecked < T : 'static > (& self )-> & T {&* ( self as * const Self as * const T )}# [ inline ] unsafe fn downcast_mut_unchecked < T : 'static > (& mut self )-> & mut T {& mut * ( self as * mut Self as * mut T )}# [ inline ] unsafe fn downcast_unchecked < T : 'static > ( self : Box < Self >)-> Box < T > { Box :: from_raw ( Box :: into_raw ( self ) as * mut T )}} impl < T : $base $(+ $bounds )*> IntoBox <$base $(+ $bounds )*> for T {# [ inline ] fn into_box ( self )-> Box <$base $(+ $bounds )*> { Box :: new ( self )}}}} -macro_rules! __ra_macro_fixture318 {($t : ty , $method : ident )=>{ impl Clone for Box <$t > {# [ inline ] fn clone (& self )-> Box <$t > {(** self ).$method ()}}}} -macro_rules! __ra_macro_fixture319 {( field : $t : ident .$field : ident ; new ()=>$new : expr ; with_capacity ($with_capacity_arg : ident )=>$with_capacity : expr ; )=>{ impl < A : ? Sized + UncheckedAnyExt > $t < A > {# [ doc = " Create an empty collection." ]# [ inline ] pub fn new ()-> $t < A > {$t {$field : $new , }}# [ doc = " Creates an empty collection with the given initial capacity." ]# [ inline ] pub fn with_capacity ($with_capacity_arg : usize )-> $t < A > {$t {$field : $with_capacity , }}# [ doc = " Returns the number of elements the collection can hold without reallocating." ]# [ inline ] pub fn capacity (& self )-> usize { self .$field . capacity ()}# [ doc = " Reserves capacity for at least `additional` more elements to be inserted" ]# [ doc = " in the collection. The collection may reserve more space to avoid" ]# [ doc = " frequent reallocations." ]# [ doc = "" ]# [ doc = " # Panics" ]# [ doc = "" ]# [ doc = " Panics if the new allocation size overflows `usize`." ]# [ inline ] pub fn reserve (& mut self , additional : usize ){ self .$field . reserve ( additional )}# [ doc = " Shrinks the capacity of the collection as much as possible. It will drop" ]# [ doc = " down as much as possible while maintaining the internal rules" ]# [ doc = " and possibly leaving some space in accordance with the resize policy." ]# [ inline ] pub fn shrink_to_fit (& mut self ){ self .$field . shrink_to_fit ()}# [ doc = " Returns the number of items in the collection." ]# [ inline ] pub fn len (& self )-> usize { self .$field . len ()}# [ doc = " Returns true if there are no items in the collection." ]# [ inline ] pub fn is_empty (& self )-> bool { self .$field . is_empty ()}# [ doc = " Removes all items from the collection. Keeps the allocated memory for reuse." ]# [ inline ] pub fn clear (& mut self ){ self .$field . clear ()}}}} -macro_rules! __ra_macro_fixture320 {($name : ident , $init : ty )=>{# [ test ] fn $name (){ let mut map = <$init >:: new (); assert_eq ! ( map . insert ( A ( 10 )), None ); assert_eq ! ( map . insert ( B ( 20 )), None ); assert_eq ! ( map . insert ( C ( 30 )), None ); assert_eq ! ( map . insert ( D ( 40 )), None ); assert_eq ! ( map . insert ( E ( 50 )), None ); assert_eq ! ( map . insert ( F ( 60 )), None ); match map . entry ::< A > (){ Entry :: Vacant (_)=> unreachable ! (), Entry :: Occupied ( mut view )=>{ assert_eq ! ( view . get (), & A ( 10 )); assert_eq ! ( view . insert ( A ( 100 )), A ( 10 )); }} assert_eq ! ( map . get ::< A > (). unwrap (), & A ( 100 )); assert_eq ! ( map . len (), 6 ); match map . entry ::< B > (){ Entry :: Vacant (_)=> unreachable ! (), Entry :: Occupied ( mut view )=>{ let v = view . get_mut (); let new_v = B ( v . 0 * 10 ); * v = new_v ; }} assert_eq ! ( map . get ::< B > (). unwrap (), & B ( 200 )); assert_eq ! ( map . len (), 6 ); match map . entry ::< C > (){ Entry :: Vacant (_)=> unreachable ! (), Entry :: Occupied ( view )=>{ assert_eq ! ( view . remove (), C ( 30 )); }} assert_eq ! ( map . get ::< C > (), None ); assert_eq ! ( map . len (), 5 ); match map . entry ::< J > (){ Entry :: Occupied (_)=> unreachable ! (), Entry :: Vacant ( view )=>{ assert_eq ! (* view . insert ( J ( 1000 )), J ( 1000 )); }} assert_eq ! ( map . get ::< J > (). unwrap (), & J ( 1000 )); assert_eq ! ( map . len (), 6 ); map . entry ::< B > (). or_insert ( B ( 71 )). 0 += 1 ; assert_eq ! ( map . get ::< B > (). unwrap (), & B ( 201 )); assert_eq ! ( map . len (), 6 ); map . entry ::< C > (). or_insert ( C ( 300 )). 0 += 1 ; assert_eq ! ( map . get ::< C > (). unwrap (), & C ( 301 )); assert_eq ! ( map . len (), 7 ); }}} -macro_rules! __ra_macro_fixture321 {($(# [$outer : meta ])* pub struct $BitFlags : ident : $T : ty {$($(# [$inner : ident $($args : tt )*])* const $Flag : ident = $value : expr ; )+ })=>{ __bitflags ! {$(# [$outer ])* ( pub )$BitFlags : $T {$($(# [$inner $($args )*])* $Flag = $value ; )+ }}}; ($(# [$outer : meta ])* struct $BitFlags : ident : $T : ty {$($(# [$inner : ident $($args : tt )*])* const $Flag : ident = $value : expr ; )+ })=>{ __bitflags ! {$(# [$outer ])* ()$BitFlags : $T {$($(# [$inner $($args )*])* $Flag = $value ; )+ }}}; ($(# [$outer : meta ])* pub ($($vis : tt )+) struct $BitFlags : ident : $T : ty {$($(# [$inner : ident $($args : tt )*])* const $Flag : ident = $value : expr ; )+ })=>{ __bitflags ! {$(# [$outer ])* ( pub ($($vis )+))$BitFlags : $T {$($(# [$inner $($args )*])* $Flag = $value ; )+ }}}; } -macro_rules! __ra_macro_fixture322 {($(# [$outer : meta ])* ($($vis : tt )*)$BitFlags : ident : $T : ty {$($(# [$inner : ident $($args : tt )*])* $Flag : ident = $value : expr ; )+ })=>{$(# [$outer ])* # [ derive ( Copy , PartialEq , Eq , Clone , PartialOrd , Ord , Hash )]$($vis )* struct $BitFlags { bits : $T , } __impl_bitflags ! {$BitFlags : $T {$($(# [$inner $($args )*])* $Flag = $value ; )+ }}}; } -macro_rules! __ra_macro_fixture323 {($BitFlags : ident : $T : ty {$($(# [$attr : ident $($args : tt )*])* $Flag : ident = $value : expr ; )+ })=>{ impl $crate :: _core :: fmt :: Debug for $BitFlags { fn fmt (& self , f : & mut $crate :: _core :: fmt :: Formatter )-> $crate :: _core :: fmt :: Result {# [ allow ( non_snake_case )] trait __BitFlags {$(# [ inline ] fn $Flag (& self )-> bool { false })+ } impl __BitFlags for $BitFlags {$(__impl_bitflags ! {# [ allow ( deprecated )]# [ inline ]$(? # [$attr $($args )*])* fn $Flag (& self )-> bool { if Self ::$Flag . bits == 0 && self . bits != 0 { false } else { self . bits & Self ::$Flag . bits == Self ::$Flag . bits }}})+ } let mut first = true ; $(if <$BitFlags as __BitFlags >::$Flag ( self ){ if ! first { f . write_str ( " | " )?; } first = false ; f . write_str ( __bitflags_stringify ! ($Flag ))?; })+ let extra_bits = self . bits & !$BitFlags :: all (). bits (); if extra_bits != 0 { if ! first { f . write_str ( " | " )?; } first = false ; f . write_str ( "0x" )?; $crate :: _core :: fmt :: LowerHex :: fmt (& extra_bits , f )?; } if first { f . write_str ( "(empty)" )?; } Ok (())}} impl $crate :: _core :: fmt :: Binary for $BitFlags { fn fmt (& self , f : & mut $crate :: _core :: fmt :: Formatter )-> $crate :: _core :: fmt :: Result {$crate :: _core :: fmt :: Binary :: fmt (& self . bits , f )}} impl $crate :: _core :: fmt :: Octal for $BitFlags { fn fmt (& self , f : & mut $crate :: _core :: fmt :: Formatter )-> $crate :: _core :: fmt :: Result {$crate :: _core :: fmt :: Octal :: fmt (& self . bits , f )}} impl $crate :: _core :: fmt :: LowerHex for $BitFlags { fn fmt (& self , f : & mut $crate :: _core :: fmt :: Formatter )-> $crate :: _core :: fmt :: Result {$crate :: _core :: fmt :: LowerHex :: fmt (& self . bits , f )}} impl $crate :: _core :: fmt :: UpperHex for $BitFlags { fn fmt (& self , f : & mut $crate :: _core :: fmt :: Formatter )-> $crate :: _core :: fmt :: Result {$crate :: _core :: fmt :: UpperHex :: fmt (& self . bits , f )}}# [ allow ( dead_code )] impl $BitFlags {$($(# [$attr $($args )*])* pub const $Flag : $BitFlags = $BitFlags { bits : $value }; )+ __fn_bitflags ! {# [ doc = " Returns an empty set of flags" ]# [ inline ] pub const fn empty ()-> $BitFlags {$BitFlags { bits : 0 }}} __fn_bitflags ! {# [ doc = " Returns the set containing all flags." ]# [ inline ] pub const fn all ()-> $BitFlags {# [ allow ( non_snake_case )] trait __BitFlags {$(const $Flag : $T = 0 ; )+ } impl __BitFlags for $BitFlags {$(__impl_bitflags ! {# [ allow ( deprecated )]$(? # [$attr $($args )*])* const $Flag : $T = Self ::$Flag . bits ; })+ }$BitFlags { bits : $(<$BitFlags as __BitFlags >::$Flag )|+ }}} __fn_bitflags ! {# [ doc = " Returns the raw value of the flags currently stored." ]# [ inline ] pub const fn bits (& self )-> $T { self . bits }}# [ doc = " Convert from underlying bit representation, unless that" ]# [ doc = " representation contains bits that do not correspond to a flag." ]# [ inline ] pub fn from_bits ( bits : $T )-> $crate :: _core :: option :: Option <$BitFlags > { if ( bits & !$BitFlags :: all (). bits ())== 0 {$crate :: _core :: option :: Option :: Some ($BitFlags { bits })} else {$crate :: _core :: option :: Option :: None }} __fn_bitflags ! {# [ doc = " Convert from underlying bit representation, dropping any bits" ]# [ doc = " that do not correspond to flags." ]# [ inline ] pub const fn from_bits_truncate ( bits : $T )-> $BitFlags {$BitFlags { bits : bits & $BitFlags :: all (). bits }}} __fn_bitflags ! {# [ doc = " Convert from underlying bit representation, preserving all" ]# [ doc = " bits (even those not corresponding to a defined flag)." ]# [ inline ] pub const unsafe fn from_bits_unchecked ( bits : $T )-> $BitFlags {$BitFlags { bits }}} __fn_bitflags ! {# [ doc = " Returns `true` if no flags are currently stored." ]# [ inline ] pub const fn is_empty (& self )-> bool { self . bits ()== $BitFlags :: empty (). bits ()}} __fn_bitflags ! {# [ doc = " Returns `true` if all flags are currently set." ]# [ inline ] pub const fn is_all (& self )-> bool { self . bits == $BitFlags :: all (). bits }} __fn_bitflags ! {# [ doc = " Returns `true` if there are flags common to both `self` and `other`." ]# [ inline ] pub const fn intersects (& self , other : $BitFlags )-> bool {!$BitFlags { bits : self . bits & other . bits }. is_empty ()}} __fn_bitflags ! {# [ doc = " Returns `true` all of the flags in `other` are contained within `self`." ]# [ inline ] pub const fn contains (& self , other : $BitFlags )-> bool {( self . bits & other . bits )== other . bits }}# [ doc = " Inserts the specified flags in-place." ]# [ inline ] pub fn insert (& mut self , other : $BitFlags ){ self . bits |= other . bits ; }# [ doc = " Removes the specified flags in-place." ]# [ inline ] pub fn remove (& mut self , other : $BitFlags ){ self . bits &= ! other . bits ; }# [ doc = " Toggles the specified flags in-place." ]# [ inline ] pub fn toggle (& mut self , other : $BitFlags ){ self . bits ^= other . bits ; }# [ doc = " Inserts or removes the specified flags depending on the passed value." ]# [ inline ] pub fn set (& mut self , other : $BitFlags , value : bool ){ if value { self . insert ( other ); } else { self . remove ( other ); }}} impl $crate :: _core :: ops :: BitOr for $BitFlags { type Output = $BitFlags ; # [ doc = " Returns the union of the two sets of flags." ]# [ inline ] fn bitor ( self , other : $BitFlags )-> $BitFlags {$BitFlags { bits : self . bits | other . bits }}} impl $crate :: _core :: ops :: BitOrAssign for $BitFlags {# [ doc = " Adds the set of flags." ]# [ inline ] fn bitor_assign (& mut self , other : $BitFlags ){ self . bits |= other . bits ; }} impl $crate :: _core :: ops :: BitXor for $BitFlags { type Output = $BitFlags ; # [ doc = " Returns the left flags, but with all the right flags toggled." ]# [ inline ] fn bitxor ( self , other : $BitFlags )-> $BitFlags {$BitFlags { bits : self . bits ^ other . bits }}} impl $crate :: _core :: ops :: BitXorAssign for $BitFlags {# [ doc = " Toggles the set of flags." ]# [ inline ] fn bitxor_assign (& mut self , other : $BitFlags ){ self . bits ^= other . bits ; }} impl $crate :: _core :: ops :: BitAnd for $BitFlags { type Output = $BitFlags ; # [ doc = " Returns the intersection between the two sets of flags." ]# [ inline ] fn bitand ( self , other : $BitFlags )-> $BitFlags {$BitFlags { bits : self . bits & other . bits }}} impl $crate :: _core :: ops :: BitAndAssign for $BitFlags {# [ doc = " Disables all flags disabled in the set." ]# [ inline ] fn bitand_assign (& mut self , other : $BitFlags ){ self . bits &= other . bits ; }} impl $crate :: _core :: ops :: Sub for $BitFlags { type Output = $BitFlags ; # [ doc = " Returns the set difference of the two sets of flags." ]# [ inline ] fn sub ( self , other : $BitFlags )-> $BitFlags {$BitFlags { bits : self . bits & ! other . bits }}} impl $crate :: _core :: ops :: SubAssign for $BitFlags {# [ doc = " Disables all flags enabled in the set." ]# [ inline ] fn sub_assign (& mut self , other : $BitFlags ){ self . bits &= ! other . bits ; }} impl $crate :: _core :: ops :: Not for $BitFlags { type Output = $BitFlags ; # [ doc = " Returns the complement of this set of flags." ]# [ inline ] fn not ( self )-> $BitFlags {$BitFlags { bits : ! self . bits }& $BitFlags :: all ()}} impl $crate :: _core :: iter :: Extend <$BitFlags > for $BitFlags { fn extend < T : $crate :: _core :: iter :: IntoIterator < Item =$BitFlags >> (& mut self , iterator : T ){ for item in iterator { self . insert ( item )}}} impl $crate :: _core :: iter :: FromIterator <$BitFlags > for $BitFlags { fn from_iter < T : $crate :: _core :: iter :: IntoIterator < Item =$BitFlags >> ( iterator : T )-> $BitFlags { let mut result = Self :: empty (); result . extend ( iterator ); result }}}; ($(# [$filtered : meta ])* ? # [ cfg $($cfgargs : tt )*]$(? # [$rest : ident $($restargs : tt )*])* fn $($item : tt )* )=>{ __impl_bitflags ! {$(# [$filtered ])* # [ cfg $($cfgargs )*]$(? # [$rest $($restargs )*])* fn $($item )* }}; ($(# [$filtered : meta ])* ? # [$next : ident $($nextargs : tt )*]$(? # [$rest : ident $($restargs : tt )*])* fn $($item : tt )* )=>{ __impl_bitflags ! {$(# [$filtered ])* $(? # [$rest $($restargs )*])* fn $($item )* }}; ($(# [$filtered : meta ])* fn $($item : tt )* )=>{$(# [$filtered ])* fn $($item )* }; ($(# [$filtered : meta ])* ? # [ cfg $($cfgargs : tt )*]$(? # [$rest : ident $($restargs : tt )*])* const $($item : tt )* )=>{ __impl_bitflags ! {$(# [$filtered ])* # [ cfg $($cfgargs )*]$(? # [$rest $($restargs )*])* const $($item )* }}; ($(# [$filtered : meta ])* ? # [$next : ident $($nextargs : tt )*]$(? # [$rest : ident $($restargs : tt )*])* const $($item : tt )* )=>{ __impl_bitflags ! {$(# [$filtered ])* $(? # [$rest $($restargs )*])* const $($item )* }}; ($(# [$filtered : meta ])* const $($item : tt )* )=>{$(# [$filtered ])* const $($item )* }; } -macro_rules! __ra_macro_fixture324 {($($item : item )*)=>{$(# [ cfg ( feature = "os-poll" )]# [ cfg_attr ( docsrs , doc ( cfg ( feature = "os-poll" )))]$item )* }} -macro_rules! __ra_macro_fixture325 {($($item : item )*)=>{$(# [ cfg ( not ( feature = "os-poll" ))]$item )* }} -macro_rules! __ra_macro_fixture326 {($($item : item )*)=>{$(# [ cfg ( any ( feature = "net" , all ( unix , feature = "os-ext" )))]# [ cfg_attr ( docsrs , doc ( any ( feature = "net" , all ( unix , feature = "os-ext" ))))]$item )* }} -macro_rules! __ra_macro_fixture327 {($($item : item )*)=>{$(# [ cfg ( feature = "net" )]# [ cfg_attr ( docsrs , doc ( cfg ( feature = "net" )))]$item )* }} -macro_rules! __ra_macro_fixture328 {($($item : item )*)=>{$(# [ cfg ( feature = "os-ext" )]# [ cfg_attr ( docsrs , doc ( cfg ( feature = "os-ext" )))]$item )* }} -macro_rules! __ra_macro_fixture329 {($name : ident , $read : ident , $bytes : expr , $data : expr )=>{ mod $name { use byteorder :: { BigEndian , ByteOrder , LittleEndian , NativeEndian , }; use test :: black_box as bb ; use test :: Bencher ; const NITER : usize = 100_000 ; # [ bench ] fn read_big_endian ( b : & mut Bencher ){ let buf = $data ; b . iter (|| { for _ in 0 .. NITER { bb ( BigEndian ::$read (& buf , $bytes )); }}); }# [ bench ] fn read_little_endian ( b : & mut Bencher ){ let buf = $data ; b . iter (|| { for _ in 0 .. NITER { bb ( LittleEndian ::$read (& buf , $bytes )); }}); }# [ bench ] fn read_native_endian ( b : & mut Bencher ){ let buf = $data ; b . iter (|| { for _ in 0 .. NITER { bb ( NativeEndian ::$read (& buf , $bytes )); }}); }}}; ($ty : ident , $max : ident , $read : ident , $write : ident , $size : expr , $data : expr )=>{ mod $ty { use byteorder :: { BigEndian , ByteOrder , LittleEndian , NativeEndian , }; use std ::$ty ; use test :: black_box as bb ; use test :: Bencher ; const NITER : usize = 100_000 ; # [ bench ] fn read_big_endian ( b : & mut Bencher ){ let buf = $data ; b . iter (|| { for _ in 0 .. NITER { bb ( BigEndian ::$read (& buf )); }}); }# [ bench ] fn read_little_endian ( b : & mut Bencher ){ let buf = $data ; b . iter (|| { for _ in 0 .. NITER { bb ( LittleEndian ::$read (& buf )); }}); }# [ bench ] fn read_native_endian ( b : & mut Bencher ){ let buf = $data ; b . iter (|| { for _ in 0 .. NITER { bb ( NativeEndian ::$read (& buf )); }}); }# [ bench ] fn write_big_endian ( b : & mut Bencher ){ let mut buf = $data ; let n = $ty ::$max ; b . iter (|| { for _ in 0 .. NITER { bb ( BigEndian ::$write (& mut buf , n )); }}); }# [ bench ] fn write_little_endian ( b : & mut Bencher ){ let mut buf = $data ; let n = $ty ::$max ; b . iter (|| { for _ in 0 .. NITER { bb ( LittleEndian ::$write (& mut buf , n )); }}); }# [ bench ] fn write_native_endian ( b : & mut Bencher ){ let mut buf = $data ; let n = $ty ::$max ; b . iter (|| { for _ in 0 .. NITER { bb ( NativeEndian ::$write (& mut buf , n )); }}); }}}; } -macro_rules! __ra_macro_fixture330 {($name : ident , $numty : ty , $read : ident , $write : ident )=>{ mod $name { use std :: mem :: size_of ; use byteorder :: { BigEndian , ByteOrder , LittleEndian }; use rand :: distributions ; use rand :: { self , Rng }; use test :: Bencher ; # [ bench ] fn read_big_endian ( b : & mut Bencher ){ let mut numbers : Vec <$numty > = rand :: thread_rng (). sample_iter (& distributions :: Standard ). take ( 100000 ). collect (); let mut bytes = vec ! [ 0 ; numbers . len ()* size_of ::<$numty > ()]; BigEndian ::$write (& numbers , & mut bytes ); b . bytes = bytes . len () as u64 ; b . iter (|| { BigEndian ::$read (& bytes , & mut numbers ); }); }# [ bench ] fn read_little_endian ( b : & mut Bencher ){ let mut numbers : Vec <$numty > = rand :: thread_rng (). sample_iter (& distributions :: Standard ). take ( 100000 ). collect (); let mut bytes = vec ! [ 0 ; numbers . len ()* size_of ::<$numty > ()]; LittleEndian ::$write (& numbers , & mut bytes ); b . bytes = bytes . len () as u64 ; b . iter (|| { LittleEndian ::$read (& bytes , & mut numbers ); }); }# [ bench ] fn write_big_endian ( b : & mut Bencher ){ let numbers : Vec <$numty > = rand :: thread_rng (). sample_iter (& distributions :: Standard ). take ( 100000 ). collect (); let mut bytes = vec ! [ 0 ; numbers . len ()* size_of ::<$numty > ()]; b . bytes = bytes . len () as u64 ; b . iter (|| { BigEndian ::$write (& numbers , & mut bytes ); }); }# [ bench ] fn write_little_endian ( b : & mut Bencher ){ let numbers : Vec <$numty > = rand :: thread_rng (). sample_iter (& distributions :: Standard ). take ( 100000 ). collect (); let mut bytes = vec ! [ 0 ; numbers . len ()* size_of ::<$numty > ()]; b . bytes = bytes . len () as u64 ; b . iter (|| { LittleEndian ::$write (& numbers , & mut bytes ); }); }}}; } -macro_rules! __ra_macro_fixture331 {{$($(#$attr : tt )* fn $fn_name : ident ($($arg : tt )*)-> $ret : ty {$($code : tt )* })*}=>($(# [ test ]$(#$attr )* fn $fn_name (){ fn prop ($($arg )*)-> $ret {$($code )* }:: quickcheck :: quickcheck ( quickcheck ! (@ fn prop []$($arg )*)); })* ); (@ fn $f : ident [$($t : tt )*])=>{$f as fn ($($t ),*)-> _ }; (@ fn $f : ident [$($p : tt )*]: $($tail : tt )*)=>{ quickcheck ! (@ fn $f [$($p )* _]$($tail )*)}; (@ fn $f : ident [$($p : tt )*]$t : tt $($tail : tt )*)=>{ quickcheck ! (@ fn $f [$($p )*]$($tail )*)}; } -macro_rules! __ra_macro_fixture332 {($from : ty =>$to : ty ; $by : ident )=>( impl < 'a > From <$from > for UniCase <$to > { fn from ( s : $from )-> Self { UniCase :: unicode ( s .$by ())}}); ($from : ty =>$to : ty )=>( from_impl ! ($from =>$to ; into ); )} -macro_rules! __ra_macro_fixture333 {($to : ty )=>( impl < 'a > Into <$to > for UniCase <$to > { fn into ( self )-> $to { self . into_inner ()}}); } -macro_rules! __ra_macro_fixture334 {($name : ident , $ty : ident )=>{ fn $name ()-> usize { let mut rng = rand_xorshift :: XorShiftRng :: from_seed ([ 123u8 ; 16 ]); let mut mv = MeanAndVariance :: new (); let mut throwaway = 0 ; for _ in 0 .. SAMPLES { let f = loop { let f = $ty :: from_bits ( rng . gen ()); if f . is_finite (){ break f ; }}; let t1 = std :: time :: SystemTime :: now (); for _ in 0 .. ITERATIONS { throwaway += ryu :: Buffer :: new (). format_finite ( f ). len (); } let duration = t1 . elapsed (). unwrap (); let nanos = duration . as_secs ()* 1_000_000_000 + duration . subsec_nanos () as u64 ; mv . update ( nanos as f64 / ITERATIONS as f64 ); } println ! ( "{:12} {:8.3} {:8.3}" , concat ! ( stringify ! ($name ), ":" ), mv . mean , mv . stddev (), ); throwaway }}; } -macro_rules! __ra_macro_fixture335 {($(# [$doc : meta ])* pub trait $name : ident $($methods : tt )*)=>{ macro_rules ! $name {($m : ident $extra : tt )=>{$m ! {$extra pub trait $name $($methods )* }}} remove_sections ! {[]$(# [$doc ])* pub trait $name $($methods )* }}} -macro_rules! __ra_macro_fixture336 {($name : ident <$($typarm : tt ),*> where {$($bounds : tt )* } item : $item : ty , iter : $iter : ty , )=>( pub struct $name <$($typarm ),*> where $($bounds )* { iter : $iter , } impl <$($typarm ),*> Iterator for $name <$($typarm ),*> where $($bounds )* { type Item = $item ; # [ inline ] fn next (& mut self )-> Option < Self :: Item > { self . iter . next ()}# [ inline ] fn size_hint (& self )-> ( usize , Option < usize >){ self . iter . size_hint ()}}); } -macro_rules! __ra_macro_fixture337 {($($fmt_trait : ident )*)=>{$(impl < 'a , I > fmt ::$fmt_trait for Format < 'a , I > where I : Iterator , I :: Item : fmt ::$fmt_trait , { fn fmt (& self , f : & mut fmt :: Formatter )-> fmt :: Result { self . format ( f , fmt ::$fmt_trait :: fmt )}})* }} -macro_rules! __ra_macro_fixture338 {($($t : ty ),*)=>{$(not_zero_impl ! ($t , 0 ); )* }} -macro_rules! __ra_macro_fixture339 {($name : ident )=>{ impl Clone for $name {# [ inline ] fn clone (& self )-> Self {* self }}}; } -macro_rules! __ra_macro_fixture340 {([$($stack : tt )*])=>{$($stack )* }; ([$($stack : tt )*]{$($tail : tt )* })=>{$($stack )* { remove_sections_inner ! ([]$($tail )*); }}; ([$($stack : tt )*]$t : tt $($tail : tt )*)=>{ remove_sections ! ([$($stack )* $t ]$($tail )*); }; } -macro_rules! __ra_macro_fixture341 {($t : ty ,$z : expr )=>{ impl Zero for $t { fn zero ()-> Self {$z as $t } fn is_zero (& self )-> bool { self == & Self :: zero ()}}}; } -macro_rules! __ra_macro_fixture342 {($($ident : ident ),* $(,)?)=>{$(# [ allow ( bad_style )] pub const $ident : super :: Name = super :: Name :: new_inline ( stringify ! ($ident )); )* }; } -macro_rules! __ra_macro_fixture343 {($($trait : ident =>$expand : ident ),* )=>{# [ derive ( Debug , Clone , Copy , PartialEq , Eq , Hash )] pub enum BuiltinDeriveExpander {$($trait ),* } impl BuiltinDeriveExpander { pub fn expand (& self , db : & dyn AstDatabase , id : LazyMacroId , tt : & tt :: Subtree , )-> Result < tt :: Subtree , mbe :: ExpandError > { let expander = match * self {$(BuiltinDeriveExpander ::$trait =>$expand , )* }; expander ( db , id , tt )} fn find_by_name ( name : & name :: Name )-> Option < Self > { match name {$(id if id == & name :: name ! [$trait ]=> Some ( BuiltinDeriveExpander ::$trait ), )* _ => None , }}}}; } -macro_rules! __ra_macro_fixture344 {( LAZY : $(($name : ident , $kind : ident )=>$expand : ident ),* , EAGER : $(($e_name : ident , $e_kind : ident )=>$e_expand : ident ),* )=>{# [ derive ( Debug , Clone , Copy , PartialEq , Eq , Hash )] pub enum BuiltinFnLikeExpander {$($kind ),* }# [ derive ( Debug , Clone , Copy , PartialEq , Eq , Hash )] pub enum EagerExpander {$($e_kind ),* } impl BuiltinFnLikeExpander { pub fn expand (& self , db : & dyn AstDatabase , id : LazyMacroId , tt : & tt :: Subtree , )-> ExpandResult < tt :: Subtree > { let expander = match * self {$(BuiltinFnLikeExpander ::$kind =>$expand , )* }; expander ( db , id , tt )}} impl EagerExpander { pub fn expand (& self , db : & dyn AstDatabase , arg_id : EagerMacroId , tt : & tt :: Subtree , )-> ExpandResult < Option < ( tt :: Subtree , FragmentKind )>> { let expander = match * self {$(EagerExpander ::$e_kind =>$e_expand , )* }; expander ( db , arg_id , tt )}} fn find_by_name ( ident : & name :: Name )-> Option < Either < BuiltinFnLikeExpander , EagerExpander >> { match ident {$(id if id == & name :: name ! [$name ]=> Some ( Either :: Left ( BuiltinFnLikeExpander ::$kind )), )* $(id if id == & name :: name ! [$e_name ]=> Some ( Either :: Right ( EagerExpander ::$e_kind )), )* _ => return None , }}}; } -macro_rules! __ra_macro_fixture345 {($($ty : ty =>$this : ident $im : block );*)=>{$(impl ToTokenTree for $ty { fn to_token ($this )-> tt :: TokenTree { let leaf : tt :: Leaf = $im . into (); leaf . into ()}} impl ToTokenTree for &$ty { fn to_token ($this )-> tt :: TokenTree { let leaf : tt :: Leaf = $im . clone (). into (); leaf . into ()}})* }} -macro_rules! __ra_macro_fixture346 {($name : ident )=>{ impl $crate :: salsa :: InternKey for $name { fn from_intern_id ( v : $crate :: salsa :: InternId )-> Self {$name ( v )} fn as_intern_id (& self )-> $crate :: salsa :: InternId { self . 0 }}}; } -macro_rules! __ra_macro_fixture347 {($($var : ident ($t : ty )),+ )=>{$(impl From <$t > for AttrOwner { fn from ( t : $t )-> AttrOwner { AttrOwner ::$var ( t )}})+ }; } -macro_rules! __ra_macro_fixture348 {($($typ : ident in $fld : ident -> $ast : ty ),+ $(,)? )=>{# [ derive ( Debug , Copy , Clone , Eq , PartialEq , Hash )] pub enum ModItem {$($typ ( FileItemTreeId <$typ >), )+ }$(impl From < FileItemTreeId <$typ >> for ModItem { fn from ( id : FileItemTreeId <$typ >)-> ModItem { ModItem ::$typ ( id )}})+ $(impl ItemTreeNode for $typ { type Source = $ast ; fn ast_id (& self )-> FileAstId < Self :: Source > { self . ast_id } fn lookup ( tree : & ItemTree , index : Idx < Self >)-> & Self {& tree . data ().$fld [ index ]} fn id_from_mod_item ( mod_item : ModItem )-> Option < FileItemTreeId < Self >> { if let ModItem ::$typ ( id )= mod_item { Some ( id )} else { None }} fn id_to_mod_item ( id : FileItemTreeId < Self >)-> ModItem { ModItem ::$typ ( id )}} impl Index < Idx <$typ >> for ItemTree { type Output = $typ ; fn index (& self , index : Idx <$typ >)-> & Self :: Output {& self . data ().$fld [ index ]}})+ }; } -macro_rules! __ra_macro_fixture349 {($($fld : ident : $t : ty ),+ $(,)? )=>{$(impl Index < Idx <$t >> for ItemTree { type Output = $t ; fn index (& self , index : Idx <$t >)-> & Self :: Output {& self . data ().$fld [ index ]}})+ }; } -macro_rules! __ra_macro_fixture350 {($e : ident {$($v : ident ($t : ty )),* $(,)? })=>{$(impl From <$t > for $e { fn from ( it : $t )-> $e {$e ::$v ( it )}})* }} -macro_rules! __ra_macro_fixture351 {($id : ident , $loc : ident , $intern : ident , $lookup : ident )=>{ impl_intern_key ! ($id ); impl Intern for $loc { type ID = $id ; fn intern ( self , db : & dyn db :: DefDatabase )-> $id { db .$intern ( self )}} impl Lookup for $id { type Data = $loc ; fn lookup (& self , db : & dyn db :: DefDatabase )-> $loc { db .$lookup (* self )}}}; } -macro_rules! __ra_macro_fixture352 {([$derives : ident $($derive_t : tt )*]=>$(# [$($attrs : tt )*])* $inner : path )=>{# [ proc_macro_derive ($derives $($derive_t )*)]# [ allow ( non_snake_case )]$(# [$($attrs )*])* pub fn $derives ( i : $crate :: macros :: TokenStream )-> $crate :: macros :: TokenStream { match $crate :: macros :: parse ::<$crate :: macros :: DeriveInput > ( i ){ Ok ( p )=>{ match $crate :: Structure :: try_new (& p ){ Ok ( s )=>$crate :: MacroResult :: into_stream ($inner ( s )), Err ( e )=> e . to_compile_error (). into (), }} Err ( e )=> e . to_compile_error (). into (), }}}; } -macro_rules! __ra_macro_fixture353 {($I : ident =>$t : ty )=>{ impl <$I : Interner > Zip <$I > for $t { fn zip_with < 'i , Z : Zipper < 'i , $I >> ( _zipper : & mut Z , _variance : Variance , a : & Self , b : & Self , )-> Fallible < ()> where I : 'i , { if a != b { return Err ( NoSolution ); } Ok (())}}}; } -macro_rules! __ra_macro_fixture354 {($($n : ident ),*)=>{ impl <$($n : Fold < I >,)* I : Interner > Fold < I > for ($($n ,)*){ type Result = ($($n :: Result ,)*); fn fold_with < 'i > ( self , folder : & mut dyn Folder < 'i , I >, outer_binder : DebruijnIndex )-> Fallible < Self :: Result > where I : 'i , {# [ allow ( non_snake_case )] let ($($n ),*)= self ; Ok (($($n . fold_with ( folder , outer_binder )?,)*))}}}} -macro_rules! __ra_macro_fixture355 {($t : ty )=>{ impl < I : Interner > $crate :: fold :: Fold < I > for $t { type Result = Self ; fn fold_with < 'i > ( self , _folder : & mut dyn ($crate :: fold :: Folder < 'i , I >), _outer_binder : DebruijnIndex , )-> :: chalk_ir :: Fallible < Self :: Result > where I : 'i , { Ok ( self )}}}; } -macro_rules! __ra_macro_fixture356 {($t : ident )=>{ impl < I : Interner > $crate :: fold :: Fold < I > for $t < I > { type Result = $t < I >; fn fold_with < 'i > ( self , _folder : & mut dyn ($crate :: fold :: Folder < 'i , I >), _outer_binder : DebruijnIndex , )-> :: chalk_ir :: Fallible < Self :: Result > where I : 'i , { Ok ( self )}}}; } -macro_rules! __ra_macro_fixture357 {($($n : ident ),*)=>{ impl <$($n : Visit < I >,)* I : Interner > Visit < I > for ($($n ,)*){ fn visit_with < 'i , BT > (& self , visitor : & mut dyn Visitor < 'i , I , BreakTy = BT >, outer_binder : DebruijnIndex )-> ControlFlow < BT > where I : 'i {# [ allow ( non_snake_case )] let & ($(ref $n ),*)= self ; $(try_break ! ($n . visit_with ( visitor , outer_binder )); )* ControlFlow :: CONTINUE }}}} -macro_rules! __ra_macro_fixture358 {($t : ty )=>{ impl < I : Interner > $crate :: visit :: Visit < I > for $t { fn visit_with < 'i , B > (& self , _visitor : & mut dyn ($crate :: visit :: Visitor < 'i , I , BreakTy = B >), _outer_binder : DebruijnIndex , )-> ControlFlow < B > where I : 'i , { ControlFlow :: CONTINUE }}}; } -macro_rules! __ra_macro_fixture359 {($t : ident )=>{ impl < I : Interner > $crate :: visit :: Visit < I > for $t < I > { fn visit_with < 'i , B > (& self , _visitor : & mut dyn ($crate :: visit :: Visitor < 'i , I , BreakTy = B >), _outer_binder : DebruijnIndex , )-> ControlFlow < B > where I : 'i , { ControlFlow :: CONTINUE }}}; } -macro_rules! __ra_macro_fixture360 {( for ($($t : tt )*)$u : ty )=>{ impl <$($t )*> CastTo <$u > for $u { fn cast_to ( self , _interner : &<$u as HasInterner >:: Interner )-> $u { self }}}; ($u : ty )=>{ impl CastTo <$u > for $u { fn cast_to ( self , interner : &<$u as HasInterner >:: Interner )-> $u { self }}}; } -macro_rules! __ra_macro_fixture361 {($($id : ident ), *)=>{$(impl < I : Interner > std :: fmt :: Debug for $id < I > { fn fmt (& self , fmt : & mut std :: fmt :: Formatter < '_ >)-> Result < (), std :: fmt :: Error > { write ! ( fmt , "{}({:?})" , stringify ! ($id ), self . 0 )}})* }; } -macro_rules! __ra_macro_fixture362 {($seq : ident , $data : ident =>$elem : ty , $intern : ident =>$interned : ident )=>{ interned_slice_common ! ($seq , $data =>$elem , $intern =>$interned ); impl < I : Interner > $seq < I > {# [ doc = " Tries to create a sequence using an iterator of element-like things." ] pub fn from_fallible < E > ( interner : & I , elements : impl IntoIterator < Item = Result < impl CastTo <$elem >, E >>, )-> Result < Self , E > { Ok ( Self { interned : I ::$intern ( interner , elements . into_iter (). casted ( interner ))?, })}# [ doc = " Create a sequence from elements" ] pub fn from_iter ( interner : & I , elements : impl IntoIterator < Item = impl CastTo <$elem >>, )-> Self { Self :: from_fallible ( interner , elements . into_iter (). map (| el | -> Result <$elem , ()> { Ok ( el . cast ( interner ))}), ). unwrap ()}# [ doc = " Create a sequence from a single element." ] pub fn from1 ( interner : & I , element : impl CastTo <$elem >)-> Self { Self :: from_iter ( interner , Some ( element ))}}}; } -macro_rules! __ra_macro_fixture363 {($seq : ident , $data : ident =>$elem : ty , $intern : ident =>$interned : ident )=>{# [ doc = " List of interned elements." ]# [ derive ( Copy , Clone , PartialEq , Eq , Hash , PartialOrd , Ord , HasInterner )] pub struct $seq < I : Interner > { interned : I ::$interned , } impl < I : Interner > $seq < I > {# [ doc = " Get the interned elements." ] pub fn interned (& self )-> & I ::$interned {& self . interned }# [ doc = " Returns a slice containing the elements." ] pub fn as_slice (& self , interner : & I )-> & [$elem ]{ Interner ::$data ( interner , & self . interned )}# [ doc = " Index into the sequence." ] pub fn at (& self , interner : & I , index : usize )-> &$elem {& self . as_slice ( interner )[ index ]}# [ doc = " Create an empty sequence." ] pub fn empty ( interner : & I )-> Self { Self :: from_iter ( interner , None ::<$elem >)}# [ doc = " Check whether this is an empty sequence." ] pub fn is_empty (& self , interner : & I )-> bool { self . as_slice ( interner ). is_empty ()}# [ doc = " Get an iterator over the elements of the sequence." ] pub fn iter (& self , interner : & I )-> std :: slice :: Iter < '_ , $elem > { self . as_slice ( interner ). iter ()}# [ doc = " Get the length of the sequence." ] pub fn len (& self , interner : & I )-> usize { self . as_slice ( interner ). len ()}}}; } -macro_rules! __ra_macro_fixture364 {($(# [$attrs : meta ])* $vis : vis static $name : ident : $ty : ty )=>($(# [$attrs ])* $vis static $name : $crate :: ScopedKey <$ty > = $crate :: ScopedKey { inner : { thread_local ! ( static FOO : :: std :: cell :: Cell < usize > = {:: std :: cell :: Cell :: new ( 0 )}); & FOO }, _marker : :: std :: marker :: PhantomData , }; )} -macro_rules! __ra_macro_fixture365 {($(($def : path , $ast : path , $meth : ident )),* ,)=>{$(impl ToDef for $ast { type Def = $def ; fn to_def ( sema : & SemanticsImpl , src : InFile < Self >)-> Option < Self :: Def > { sema . with_ctx (| ctx | ctx .$meth ( src )). map (<$def >:: from )}})*}} -macro_rules! __ra_macro_fixture366 {($(($id : path , $ty : path )),*)=>{$(impl From <$id > for $ty { fn from ( id : $id )-> $ty {$ty { id }}} impl From <$ty > for $id { fn from ( ty : $ty )-> $id { ty . id }})*}} -macro_rules! __ra_macro_fixture367 {($(($def : ident , $def_id : ident ),)*)=>{$(impl HasAttrs for $def { fn attrs ( self , db : & dyn HirDatabase )-> Attrs { let def = AttrDefId ::$def_id ( self . into ()); db . attrs ( def )} fn docs ( self , db : & dyn HirDatabase )-> Option < Documentation > { let def = AttrDefId ::$def_id ( self . into ()); db . attrs ( def ). docs ()} fn resolve_doc_path ( self , db : & dyn HirDatabase , link : & str , ns : Option < Namespace >)-> Option < ModuleDef > { let def = AttrDefId ::$def_id ( self . into ()); resolve_doc_path ( db , def , link , ns ). map ( ModuleDef :: from )}})*}; } -macro_rules! __ra_macro_fixture368 {($($variant : ident ),* for $enum : ident )=>{$(impl HasAttrs for $variant { fn attrs ( self , db : & dyn HirDatabase )-> Attrs {$enum ::$variant ( self ). attrs ( db )} fn docs ( self , db : & dyn HirDatabase )-> Option < Documentation > {$enum ::$variant ( self ). docs ( db )} fn resolve_doc_path ( self , db : & dyn HirDatabase , link : & str , ns : Option < Namespace >)-> Option < ModuleDef > {$enum ::$variant ( self ). resolve_doc_path ( db , link , ns )}})*}; } -macro_rules! __ra_macro_fixture369 {{$($(#$attr : tt )* fn $fn_name : ident ($($arg : tt )*)-> $ret : ty {$($code : tt )* })*}=>($(# [ test ]$(#$attr )* fn $fn_name (){ fn prop ($($arg )*)-> $ret {$($code )* }:: quickcheck :: quickcheck ( quickcheck ! (@ fn prop []$($arg )*)); })* ); (@ fn $f : ident [$($t : tt )*])=>{$f as fn ($($t ),*)-> _ }; (@ fn $f : ident [$($p : tt )*]: $($tail : tt )*)=>{ quickcheck ! (@ fn $f [$($p )* _]$($tail )*)}; (@ fn $f : ident [$($p : tt )*]$t : tt $($tail : tt )*)=>{ quickcheck ! (@ fn $f [$($p )*]$($tail )*)}; } -macro_rules! __ra_macro_fixture370 {($($bool : expr , )+)=>{ fn _static_assert (){$(let _ = std :: mem :: transmute ::< [ u8 ; $bool as usize ], u8 >; )+ }}} -macro_rules! __ra_macro_fixture371 {($ty : ident is $($marker : ident ) and +)=>{# [ test ]# [ allow ( non_snake_case )] fn $ty (){ fn assert_implemented < T : $($marker +)+> (){} assert_implemented ::<$ty > (); }}; ($ty : ident is not $($marker : ident ) or +)=>{# [ test ]# [ allow ( non_snake_case )] fn $ty (){$({trait IsNotImplemented { fn assert_not_implemented (){}} impl < T : $marker > IsNotImplemented for T {} trait IsImplemented { fn assert_not_implemented (){}} impl IsImplemented for $ty {}<$ty >:: assert_not_implemented (); })+ }}; } -macro_rules! __ra_macro_fixture372 {($($types : ident )*)=>{$(assert_impl ! ($types is UnwindSafe and RefUnwindSafe ); )* }; } -macro_rules! __ra_macro_fixture373 {($($(# [$attr : meta ])* $name : ident ($value : expr , $expected : expr )),* )=>{$($(# [$attr ])* # [ test ] fn $name (){# [ cfg ( feature = "std" )]{ let mut buf = [ b'\0' ; 40 ]; let len = itoa :: write (& mut buf [..], $value ). unwrap (); assert_eq ! (& buf [ 0 .. len ], $expected . as_bytes ()); } let mut s = String :: new (); itoa :: fmt (& mut s , $value ). unwrap (); assert_eq ! ( s , $expected ); })* }} -macro_rules! __ra_macro_fixture374 {($($name : ident =>$description : expr ,)+)=>{# [ doc = " Errors that can occur during parsing." ]# [ doc = "" ]# [ doc = " This may be extended in the future so exhaustive matching is" ]# [ doc = " discouraged with an unused variant." ]# [ allow ( clippy :: manual_non_exhaustive )]# [ derive ( PartialEq , Eq , Clone , Copy , Debug )] pub enum ParseError {$($name , )+ # [ doc = " Unused variant enable non-exhaustive matching" ]# [ doc ( hidden )] __FutureProof , } impl fmt :: Display for ParseError { fn fmt (& self , fmt : & mut Formatter < '_ >)-> fmt :: Result { match * self {$(ParseError ::$name => fmt . write_str ($description ), )+ ParseError :: __FutureProof =>{ unreachable ! ( "Don't abuse the FutureProof!" ); }}}}}} -macro_rules! __ra_macro_fixture375 {($($name : ident =>$description : expr ,)+)=>{# [ doc = " Non-fatal syntax violations that can occur during parsing." ]# [ doc = "" ]# [ doc = " This may be extended in the future so exhaustive matching is" ]# [ doc = " discouraged with an unused variant." ]# [ allow ( clippy :: manual_non_exhaustive )]# [ derive ( PartialEq , Eq , Clone , Copy , Debug )] pub enum SyntaxViolation {$($name , )+ # [ doc = " Unused variant enable non-exhaustive matching" ]# [ doc ( hidden )] __FutureProof , } impl SyntaxViolation { pub fn description (& self )-> & 'static str { match * self {$(SyntaxViolation ::$name =>$description , )+ SyntaxViolation :: __FutureProof =>{ unreachable ! ( "Don't abuse the FutureProof!" ); }}}}}} -macro_rules! __ra_macro_fixture376 {('owned : $($oty : ident ,)* 'interned : $($ity : ident ,)* )=>{# [ repr ( C )]# [ allow ( non_snake_case )] pub struct HandleCounters {$($oty : AtomicUsize ,)* $($ity : AtomicUsize ,)* } impl HandleCounters { extern "C" fn get ()-> & 'static Self { static COUNTERS : HandleCounters = HandleCounters {$($oty : AtomicUsize :: new ( 1 ),)* $($ity : AtomicUsize :: new ( 1 ),)* }; & COUNTERS }}# [ repr ( C )]# [ allow ( non_snake_case )] pub ( super ) struct HandleStore < S : server :: Types > {$($oty : handle :: OwnedStore < S ::$oty >,)* $($ity : handle :: InternedStore < S ::$ity >,)* } impl < S : server :: Types > HandleStore < S > { pub ( super ) fn new ( handle_counters : & 'static HandleCounters )-> Self { HandleStore {$($oty : handle :: OwnedStore :: new (& handle_counters .$oty ),)* $($ity : handle :: InternedStore :: new (& handle_counters .$ity ),)* }}}$(# [ repr ( C )] pub struct $oty ( pub ( crate ) handle :: Handle ); impl Drop for $oty { fn drop (& mut self ){$oty ( self . 0 ). drop (); }} impl < S > Encode < S > for $oty { fn encode ( self , w : & mut Writer , s : & mut S ){ let handle = self . 0 ; mem :: forget ( self ); handle . encode ( w , s ); }} impl < S : server :: Types > DecodeMut < '_ , '_ , HandleStore < server :: MarkedTypes < S >>> for Marked < S ::$oty , $oty > { fn decode ( r : & mut Reader < '_ >, s : & mut HandleStore < server :: MarkedTypes < S >>)-> Self { s .$oty . take ( handle :: Handle :: decode ( r , & mut ()))}} impl < S > Encode < S > for &$oty { fn encode ( self , w : & mut Writer , s : & mut S ){ self . 0 . encode ( w , s ); }} impl < 's , S : server :: Types ,> Decode < '_ , 's , HandleStore < server :: MarkedTypes < S >>> for & 's Marked < S ::$oty , $oty > { fn decode ( r : & mut Reader < '_ >, s : & 's HandleStore < server :: MarkedTypes < S >>)-> Self {& s .$oty [ handle :: Handle :: decode ( r , & mut ())]}} impl < S > Encode < S > for & mut $oty { fn encode ( self , w : & mut Writer , s : & mut S ){ self . 0 . encode ( w , s ); }} impl < 's , S : server :: Types > DecodeMut < '_ , 's , HandleStore < server :: MarkedTypes < S >>> for & 's mut Marked < S ::$oty , $oty > { fn decode ( r : & mut Reader < '_ >, s : & 's mut HandleStore < server :: MarkedTypes < S >> )-> Self {& mut s .$oty [ handle :: Handle :: decode ( r , & mut ())]}} impl < S : server :: Types > Encode < HandleStore < server :: MarkedTypes < S >>> for Marked < S ::$oty , $oty > { fn encode ( self , w : & mut Writer , s : & mut HandleStore < server :: MarkedTypes < S >>){ s .$oty . alloc ( self ). encode ( w , s ); }} impl < S > DecodeMut < '_ , '_ , S > for $oty { fn decode ( r : & mut Reader < '_ >, s : & mut S )-> Self {$oty ( handle :: Handle :: decode ( r , s ))}})* $(# [ repr ( C )]# [ derive ( Copy , Clone , PartialEq , Eq , Hash )] pub ( crate ) struct $ity ( handle :: Handle ); impl < S > Encode < S > for $ity { fn encode ( self , w : & mut Writer , s : & mut S ){ self . 0 . encode ( w , s ); }} impl < S : server :: Types > DecodeMut < '_ , '_ , HandleStore < server :: MarkedTypes < S >>> for Marked < S ::$ity , $ity > { fn decode ( r : & mut Reader < '_ >, s : & mut HandleStore < server :: MarkedTypes < S >>)-> Self { s .$ity . copy ( handle :: Handle :: decode ( r , & mut ()))}} impl < S : server :: Types > Encode < HandleStore < server :: MarkedTypes < S >>> for Marked < S ::$ity , $ity > { fn encode ( self , w : & mut Writer , s : & mut HandleStore < server :: MarkedTypes < S >>){ s .$ity . alloc ( self ). encode ( w , s ); }} impl < S > DecodeMut < '_ , '_ , S > for $ity { fn decode ( r : & mut Reader < '_ >, s : & mut S )-> Self {$ity ( handle :: Handle :: decode ( r , s ))}})* }} -macro_rules! __ra_macro_fixture377 {($S : ident , $self : ident , $m : ident )=>{$m ! { FreeFunctions { fn drop ($self : $S :: FreeFunctions ); fn track_env_var ( var : & str , value : Option <& str >); }, TokenStream { fn drop ($self : $S :: TokenStream ); fn clone ($self : &$S :: TokenStream )-> $S :: TokenStream ; fn new ()-> $S :: TokenStream ; fn is_empty ($self : &$S :: TokenStream )-> bool ; fn from_str ( src : & str )-> $S :: TokenStream ; fn to_string ($self : &$S :: TokenStream )-> String ; fn from_token_tree ( tree : TokenTree <$S :: Group , $S :: Punct , $S :: Ident , $S :: Literal >, )-> $S :: TokenStream ; fn into_iter ($self : $S :: TokenStream )-> $S :: TokenStreamIter ; }, TokenStreamBuilder { fn drop ($self : $S :: TokenStreamBuilder ); fn new ()-> $S :: TokenStreamBuilder ; fn push ($self : & mut $S :: TokenStreamBuilder , stream : $S :: TokenStream ); fn build ($self : $S :: TokenStreamBuilder )-> $S :: TokenStream ; }, TokenStreamIter { fn drop ($self : $S :: TokenStreamIter ); fn clone ($self : &$S :: TokenStreamIter )-> $S :: TokenStreamIter ; fn next ($self : & mut $S :: TokenStreamIter , )-> Option < TokenTree <$S :: Group , $S :: Punct , $S :: Ident , $S :: Literal >>; }, Group { fn drop ($self : $S :: Group ); fn clone ($self : &$S :: Group )-> $S :: Group ; fn new ( delimiter : Delimiter , stream : $S :: TokenStream )-> $S :: Group ; fn delimiter ($self : &$S :: Group )-> Delimiter ; fn stream ($self : &$S :: Group )-> $S :: TokenStream ; fn span ($self : &$S :: Group )-> $S :: Span ; fn span_open ($self : &$S :: Group )-> $S :: Span ; fn span_close ($self : &$S :: Group )-> $S :: Span ; fn set_span ($self : & mut $S :: Group , span : $S :: Span ); }, Punct { fn new ( ch : char , spacing : Spacing )-> $S :: Punct ; fn as_char ($self : $S :: Punct )-> char ; fn spacing ($self : $S :: Punct )-> Spacing ; fn span ($self : $S :: Punct )-> $S :: Span ; fn with_span ($self : $S :: Punct , span : $S :: Span )-> $S :: Punct ; }, Ident { fn new ( string : & str , span : $S :: Span , is_raw : bool )-> $S :: Ident ; fn span ($self : $S :: Ident )-> $S :: Span ; fn with_span ($self : $S :: Ident , span : $S :: Span )-> $S :: Ident ; }, Literal { fn drop ($self : $S :: Literal ); fn clone ($self : &$S :: Literal )-> $S :: Literal ; fn debug_kind ($self : &$S :: Literal )-> String ; fn symbol ($self : &$S :: Literal )-> String ; fn suffix ($self : &$S :: Literal )-> Option < String >; fn integer ( n : & str )-> $S :: Literal ; fn typed_integer ( n : & str , kind : & str )-> $S :: Literal ; fn float ( n : & str )-> $S :: Literal ; fn f32 ( n : & str )-> $S :: Literal ; fn f64 ( n : & str )-> $S :: Literal ; fn string ( string : & str )-> $S :: Literal ; fn character ( ch : char )-> $S :: Literal ; fn byte_string ( bytes : & [ u8 ])-> $S :: Literal ; fn span ($self : &$S :: Literal )-> $S :: Span ; fn set_span ($self : & mut $S :: Literal , span : $S :: Span ); fn subspan ($self : &$S :: Literal , start : Bound < usize >, end : Bound < usize >, )-> Option <$S :: Span >; }, SourceFile { fn drop ($self : $S :: SourceFile ); fn clone ($self : &$S :: SourceFile )-> $S :: SourceFile ; fn eq ($self : &$S :: SourceFile , other : &$S :: SourceFile )-> bool ; fn path ($self : &$S :: SourceFile )-> String ; fn is_real ($self : &$S :: SourceFile )-> bool ; }, MultiSpan { fn drop ($self : $S :: MultiSpan ); fn new ()-> $S :: MultiSpan ; fn push ($self : & mut $S :: MultiSpan , span : $S :: Span ); }, Diagnostic { fn drop ($self : $S :: Diagnostic ); fn new ( level : Level , msg : & str , span : $S :: MultiSpan )-> $S :: Diagnostic ; fn sub ($self : & mut $S :: Diagnostic , level : Level , msg : & str , span : $S :: MultiSpan , ); fn emit ($self : $S :: Diagnostic ); }, Span { fn debug ($self : $S :: Span )-> String ; fn def_site ()-> $S :: Span ; fn call_site ()-> $S :: Span ; fn mixed_site ()-> $S :: Span ; fn source_file ($self : $S :: Span )-> $S :: SourceFile ; fn parent ($self : $S :: Span )-> Option <$S :: Span >; fn source ($self : $S :: Span )-> $S :: Span ; fn start ($self : $S :: Span )-> LineColumn ; fn end ($self : $S :: Span )-> LineColumn ; fn join ($self : $S :: Span , other : $S :: Span )-> Option <$S :: Span >; fn resolved_at ($self : $S :: Span , at : $S :: Span )-> $S :: Span ; fn source_text ($self : $S :: Span )-> Option < String >; }, }}; } -macro_rules! __ra_macro_fixture378 {( le $ty : ty )=>{ impl < S > Encode < S > for $ty { fn encode ( self , w : & mut Writer , _: & mut S ){ w . write_all (& self . to_le_bytes ()). unwrap (); }} impl < S > DecodeMut < '_ , '_ , S > for $ty { fn decode ( r : & mut Reader < '_ >, _: & mut S )-> Self { const N : usize = :: std :: mem :: size_of ::<$ty > (); let mut bytes = [ 0 ; N ]; bytes . copy_from_slice (& r [.. N ]); * r = & r [ N ..]; Self :: from_le_bytes ( bytes )}}}; ( struct $name : ident {$($field : ident ),* $(,)? })=>{ impl < S > Encode < S > for $name { fn encode ( self , w : & mut Writer , s : & mut S ){$(self .$field . encode ( w , s );)* }} impl < S > DecodeMut < '_ , '_ , S > for $name { fn decode ( r : & mut Reader < '_ >, s : & mut S )-> Self {$name {$($field : DecodeMut :: decode ( r , s )),* }}}}; ( enum $name : ident $(<$($T : ident ),+>)? {$($variant : ident $(($field : ident ))*),* $(,)? })=>{ impl < S , $($($T : Encode < S >),+)?> Encode < S > for $name $(<$($T ),+>)? { fn encode ( self , w : & mut Writer , s : & mut S ){# [ allow ( non_upper_case_globals )] mod tag {# [ repr ( u8 )] enum Tag {$($variant ),* }$(pub const $variant : u8 = Tag ::$variant as u8 ;)* } match self {$($name ::$variant $(($field ))* =>{ tag ::$variant . encode ( w , s ); $($field . encode ( w , s );)* })* }}} impl < 'a , S , $($($T : for < 's > DecodeMut < 'a , 's , S >),+)?> DecodeMut < 'a , '_ , S > for $name $(<$($T ),+>)? { fn decode ( r : & mut Reader < 'a >, s : & mut S )-> Self {# [ allow ( non_upper_case_globals )] mod tag {# [ repr ( u8 )] enum Tag {$($variant ),* }$(pub const $variant : u8 = Tag ::$variant as u8 ;)* } match u8 :: decode ( r , s ){$(tag ::$variant =>{$(let $field = DecodeMut :: decode ( r , s );)* $name ::$variant $(($field ))* })* _ => unreachable ! (), }}}}} -macro_rules! __ra_macro_fixture379 {($($ty : ty ),* $(,)?)=>{$(impl Mark for $ty { type Unmarked = Self ; fn mark ( unmarked : Self :: Unmarked )-> Self { unmarked }} impl Unmark for $ty { type Unmarked = Self ; fn unmark ( self )-> Self :: Unmarked { self }})* }} -macro_rules! __ra_macro_fixture380 {($($name : ident {$(fn $method : ident ($($arg : ident : $arg_ty : ty ),* $(,)?)$(-> $ret_ty : ty )*;)* }),* $(,)?)=>{$(impl $name {# [ allow ( unused )]$(pub ( crate ) fn $method ($($arg : $arg_ty ),*)$(-> $ret_ty )* { panic ! ( "hello" ); })* })* }} -macro_rules! __ra_macro_fixture381 {($($name : ident {$(fn $method : ident ($($arg : ident : $arg_ty : ty ),* $(,)?)$(-> $ret_ty : ty )?;)* }),* $(,)?)=>{ pub trait Types {$(associated_item ! ( type $name );)* }$(pub trait $name : Types {$(associated_item ! ( fn $method (& mut self , $($arg : $arg_ty ),*)$(-> $ret_ty )?);)* })* pub trait Server : Types $(+ $name )* {} impl < S : Types $(+ $name )*> Server for S {}}} -macro_rules! __ra_macro_fixture382 {($($name : ident {$(fn $method : ident ($($arg : ident : $arg_ty : ty ),* $(,)?)$(-> $ret_ty : ty )?;)* }),* $(,)?)=>{ impl < S : Types > Types for MarkedTypes < S > {$(type $name = Marked < S ::$name , client ::$name >;)* }$(impl < S : $name > $name for MarkedTypes < S > {$(fn $method (& mut self , $($arg : $arg_ty ),*)$(-> $ret_ty )? {<_>:: mark ($name ::$method (& mut self . 0 , $($arg . unmark ()),*))})* })* }} -macro_rules! __ra_macro_fixture383 {($($name : ident {$(fn $method : ident ($($arg : ident : $arg_ty : ty ),* $(,)?)$(-> $ret_ty : ty )?;)* }),* $(,)?)=>{ pub trait DispatcherTrait {$(type $name ;)* fn dispatch (& mut self , b : Buffer < u8 >)-> Buffer < u8 >; } impl < S : Server > DispatcherTrait for Dispatcher < MarkedTypes < S >> {$(type $name = < MarkedTypes < S > as Types >::$name ;)* fn dispatch (& mut self , mut b : Buffer < u8 >)-> Buffer < u8 > { let Dispatcher { handle_store , server }= self ; let mut reader = & b [..]; match api_tags :: Method :: decode (& mut reader , & mut ()){$(api_tags :: Method ::$name ( m )=> match m {$(api_tags ::$name ::$method =>{ let mut call_method = || { reverse_decode ! ( reader , handle_store ; $($arg : $arg_ty ),*); $name ::$method ( server , $($arg ),*)}; let r = if thread :: panicking (){ Ok ( call_method ())} else { panic :: catch_unwind ( panic :: AssertUnwindSafe ( call_method )). map_err ( PanicMessage :: from )}; b . clear (); r . encode (& mut b , handle_store ); })* }),* } b }}}} -macro_rules! __ra_macro_fixture384 {($($name : ident {$(fn $method : ident ($($arg : ident : $arg_ty : ty ),* $(,)?)$(-> $ret_ty : ty )*;)* }),* $(,)?)=>{$(pub ( super ) enum $name {$($method ),* } rpc_encode_decode ! ( enum $name {$($method ),* }); )* pub ( super ) enum Method {$($name ($name )),* } rpc_encode_decode ! ( enum Method {$($name ( m )),* }); }} -macro_rules! __ra_macro_fixture385 {($(($ident : ident , $string : literal )),*$(,)?)=>{$(pub ( crate ) const $ident : SemanticTokenType = SemanticTokenType :: new ($string );)* pub ( crate ) const SUPPORTED_TYPES : & [ SemanticTokenType ]= & [ SemanticTokenType :: COMMENT , SemanticTokenType :: KEYWORD , SemanticTokenType :: STRING , SemanticTokenType :: NUMBER , SemanticTokenType :: REGEXP , SemanticTokenType :: OPERATOR , SemanticTokenType :: NAMESPACE , SemanticTokenType :: TYPE , SemanticTokenType :: STRUCT , SemanticTokenType :: CLASS , SemanticTokenType :: INTERFACE , SemanticTokenType :: ENUM , SemanticTokenType :: ENUM_MEMBER , SemanticTokenType :: TYPE_PARAMETER , SemanticTokenType :: FUNCTION , SemanticTokenType :: METHOD , SemanticTokenType :: PROPERTY , SemanticTokenType :: MACRO , SemanticTokenType :: VARIABLE , SemanticTokenType :: PARAMETER , $($ident ),* ]; }; } -macro_rules! __ra_macro_fixture386 {($(($ident : ident , $string : literal )),*$(,)?)=>{$(pub ( crate ) const $ident : SemanticTokenModifier = SemanticTokenModifier :: new ($string );)* pub ( crate ) const SUPPORTED_MODIFIERS : & [ SemanticTokenModifier ]= & [ SemanticTokenModifier :: DOCUMENTATION , SemanticTokenModifier :: DECLARATION , SemanticTokenModifier :: DEFINITION , SemanticTokenModifier :: STATIC , SemanticTokenModifier :: ABSTRACT , SemanticTokenModifier :: DEPRECATED , SemanticTokenModifier :: READONLY , $($ident ),* ]; }; } -macro_rules! __ra_macro_fixture387 {( struct $name : ident {$($(# [ doc =$doc : literal ])* $field : ident $(| $alias : ident )?: $ty : ty = $default : expr , )* })=>{# [ allow ( non_snake_case )]# [ derive ( Debug , Clone )] struct $name {$($field : $ty ,)* } impl $name { fn from_json ( mut json : serde_json :: Value )-> $name {$name {$($field : get_field (& mut json , stringify ! ($field ), None $(. or ( Some ( stringify ! ($alias ))))?, $default , ), )*}} fn json_schema ()-> serde_json :: Value { schema (& [$({let field = stringify ! ($field ); let ty = stringify ! ($ty ); ( field , ty , & [$($doc ),*], $default )},)* ])}# [ cfg ( test )] fn manual ()-> String { manual (& [$({let field = stringify ! ($field ); let ty = stringify ! ($ty ); ( field , ty , & [$($doc ),*], $default )},)* ])}}}; } -macro_rules! __ra_macro_fixture388 {($($name : ident ($value : expr ),)*)=>{ mod bench_ryu { use super ::*; $(# [ bench ] fn $name ( b : & mut Bencher ){ let mut buf = ryu :: Buffer :: new (); b . iter ( move || { let value = black_box ($value ); let formatted = buf . format_finite ( value ); black_box ( formatted ); }); })* } mod bench_std_fmt { use super ::*; $(# [ bench ] fn $name ( b : & mut Bencher ){ let mut buf = Vec :: with_capacity ( 20 ); b . iter (|| { buf . clear (); let value = black_box ($value ); write ! (& mut buf , "{}" , value ). unwrap (); black_box ( buf . as_slice ()); }); })* }}; } -macro_rules! __ra_macro_fixture389 {($($T : ident ),*)=>{$(mod $T { use test :: Bencher ; use num_integer :: { Average , Integer }; use super :: { UncheckedAverage , NaiveAverage , ModuloAverage }; use super :: { bench_ceil , bench_floor , bench_unchecked }; naive_average ! ($T ); unchecked_average ! ($T ); modulo_average ! ($T ); const SIZE : $T = 30 ; fn overflowing ()-> Vec < ($T , $T )> {(($T :: max_value ()- SIZE )..$T :: max_value ()). flat_map (| x | -> Vec <_> {(($T :: max_value ()- 100 ).. ($T :: max_value ()- 100 + SIZE )). map (| y | ( x , y )). collect ()}). collect ()} fn small ()-> Vec < ($T , $T )> {( 0 .. SIZE ). flat_map (| x | -> Vec <_> {( 0 .. SIZE ). map (| y | ( x , y )). collect ()}). collect ()} fn rand ()-> Vec < ($T , $T )> { small (). into_iter (). map (| ( x , y )| ( super :: lcg ( x ), super :: lcg ( y ))). collect ()} mod ceil { use super ::*; mod small { use super ::*; # [ bench ] fn optimized ( b : & mut Bencher ){ let v = small (); bench_ceil ( b , & v , | x : &$T , y : &$T | x . average_ceil ( y )); }# [ bench ] fn naive ( b : & mut Bencher ){ let v = small (); bench_ceil ( b , & v , | x : &$T , y : &$T | x . naive_average_ceil ( y )); }# [ bench ] fn unchecked ( b : & mut Bencher ){ let v = small (); bench_unchecked ( b , & v , | x : &$T , y : &$T | x . unchecked_average_ceil ( y )); }# [ bench ] fn modulo ( b : & mut Bencher ){ let v = small (); bench_ceil ( b , & v , | x : &$T , y : &$T | x . modulo_average_ceil ( y )); }} mod overflowing { use super ::*; # [ bench ] fn optimized ( b : & mut Bencher ){ let v = overflowing (); bench_ceil ( b , & v , | x : &$T , y : &$T | x . average_ceil ( y )); }# [ bench ] fn naive ( b : & mut Bencher ){ let v = overflowing (); bench_ceil ( b , & v , | x : &$T , y : &$T | x . naive_average_ceil ( y )); }# [ bench ] fn unchecked ( b : & mut Bencher ){ let v = overflowing (); bench_unchecked ( b , & v , | x : &$T , y : &$T | x . unchecked_average_ceil ( y )); }# [ bench ] fn modulo ( b : & mut Bencher ){ let v = overflowing (); bench_ceil ( b , & v , | x : &$T , y : &$T | x . modulo_average_ceil ( y )); }} mod rand { use super ::*; # [ bench ] fn optimized ( b : & mut Bencher ){ let v = rand (); bench_ceil ( b , & v , | x : &$T , y : &$T | x . average_ceil ( y )); }# [ bench ] fn naive ( b : & mut Bencher ){ let v = rand (); bench_ceil ( b , & v , | x : &$T , y : &$T | x . naive_average_ceil ( y )); }# [ bench ] fn unchecked ( b : & mut Bencher ){ let v = rand (); bench_unchecked ( b , & v , | x : &$T , y : &$T | x . unchecked_average_ceil ( y )); }# [ bench ] fn modulo ( b : & mut Bencher ){ let v = rand (); bench_ceil ( b , & v , | x : &$T , y : &$T | x . modulo_average_ceil ( y )); }}} mod floor { use super ::*; mod small { use super ::*; # [ bench ] fn optimized ( b : & mut Bencher ){ let v = small (); bench_floor ( b , & v , | x : &$T , y : &$T | x . average_floor ( y )); }# [ bench ] fn naive ( b : & mut Bencher ){ let v = small (); bench_floor ( b , & v , | x : &$T , y : &$T | x . naive_average_floor ( y )); }# [ bench ] fn unchecked ( b : & mut Bencher ){ let v = small (); bench_unchecked ( b , & v , | x : &$T , y : &$T | x . unchecked_average_floor ( y )); }# [ bench ] fn modulo ( b : & mut Bencher ){ let v = small (); bench_floor ( b , & v , | x : &$T , y : &$T | x . modulo_average_floor ( y )); }} mod overflowing { use super ::*; # [ bench ] fn optimized ( b : & mut Bencher ){ let v = overflowing (); bench_floor ( b , & v , | x : &$T , y : &$T | x . average_floor ( y )); }# [ bench ] fn naive ( b : & mut Bencher ){ let v = overflowing (); bench_floor ( b , & v , | x : &$T , y : &$T | x . naive_average_floor ( y )); }# [ bench ] fn unchecked ( b : & mut Bencher ){ let v = overflowing (); bench_unchecked ( b , & v , | x : &$T , y : &$T | x . unchecked_average_floor ( y )); }# [ bench ] fn modulo ( b : & mut Bencher ){ let v = overflowing (); bench_floor ( b , & v , | x : &$T , y : &$T | x . modulo_average_floor ( y )); }} mod rand { use super ::*; # [ bench ] fn optimized ( b : & mut Bencher ){ let v = rand (); bench_floor ( b , & v , | x : &$T , y : &$T | x . average_floor ( y )); }# [ bench ] fn naive ( b : & mut Bencher ){ let v = rand (); bench_floor ( b , & v , | x : &$T , y : &$T | x . naive_average_floor ( y )); }# [ bench ] fn unchecked ( b : & mut Bencher ){ let v = rand (); bench_unchecked ( b , & v , | x : &$T , y : &$T | x . unchecked_average_floor ( y )); }# [ bench ] fn modulo ( b : & mut Bencher ){ let v = rand (); bench_floor ( b , & v , | x : &$T , y : &$T | x . modulo_average_floor ( y )); }}}})*}} -macro_rules! __ra_macro_fixture390 {($T : ident )=>{ impl super :: NaiveAverage for $T { fn naive_average_floor (& self , other : &$T )-> $T { match self . checked_add (* other ){ Some ( z )=> z . div_floor (& 2 ), None =>{ if self > other { let diff = self - other ; other + diff . div_floor (& 2 )} else { let diff = other - self ; self + diff . div_floor (& 2 )}}}} fn naive_average_ceil (& self , other : &$T )-> $T { match self . checked_add (* other ){ Some ( z )=> z . div_ceil (& 2 ), None =>{ if self > other { let diff = self - other ; self - diff . div_floor (& 2 )} else { let diff = other - self ; other - diff . div_floor (& 2 )}}}}}}; } -macro_rules! __ra_macro_fixture391 {($T : ident )=>{ impl super :: UncheckedAverage for $T { fn unchecked_average_floor (& self , other : &$T )-> $T { self . wrapping_add (* other )/ 2 } fn unchecked_average_ceil (& self , other : &$T )-> $T {( self . wrapping_add (* other )/ 2 ). wrapping_add ( 1 )}}}; } -macro_rules! __ra_macro_fixture392 {($T : ident )=>{ impl super :: ModuloAverage for $T { fn modulo_average_ceil (& self , other : &$T )-> $T { let ( q1 , r1 )= self . div_mod_floor (& 2 ); let ( q2 , r2 )= other . div_mod_floor (& 2 ); q1 + q2 + ( r1 | r2 )} fn modulo_average_floor (& self , other : &$T )-> $T { let ( q1 , r1 )= self . div_mod_floor (& 2 ); let ( q2 , r2 )= other . div_mod_floor (& 2 ); q1 + q2 + ( r1 * r2 )}}}; } -macro_rules! __ra_macro_fixture393 {($N : expr , $FUN : ident , $BENCH_NAME : ident , )=>( mod $BENCH_NAME { use super ::*; pub fn sum ( c : & mut Criterion ){ let v : Vec < u32 > = ( 0 .. $N ). collect (); c . bench_function (& ( stringify ! ($BENCH_NAME ). replace ( '_' , " " )+ " sum" ), move | b | { b . iter (|| { cloned (& v ).$FUN (| x , y | x + y )})}); } pub fn complex_iter ( c : & mut Criterion ){ let u = ( 3 ..). take ($N / 2 ); let v = ( 5 ..). take ($N / 2 ); let it = u . chain ( v ); c . bench_function (& ( stringify ! ($BENCH_NAME ). replace ( '_' , " " )+ " complex iter" ), move | b | { b . iter (|| { it . clone (). map (| x | x as f32 ).$FUN ( f32 :: atan2 )})}); } pub fn string_format ( c : & mut Criterion ){ let v : Vec < u32 > = ( 0 .. ($N / 4 )). collect (); c . bench_function (& ( stringify ! ($BENCH_NAME ). replace ( '_' , " " )+ " string format" ), move | b | { b . iter (|| { cloned (& v ). map (| x | x . to_string ()).$FUN (| x , y | format ! ( "{} + {}" , x , y ))})}); }} criterion_group ! ($BENCH_NAME , $BENCH_NAME :: sum , $BENCH_NAME :: complex_iter , $BENCH_NAME :: string_format , ); )} -macro_rules! __ra_macro_fixture394 {($ast : ident , $kind : ident )=>{# [ derive ( PartialEq , Eq , Hash )]# [ repr ( transparent )] struct $ast ( SyntaxNode ); impl $ast {# [ allow ( unused )] fn cast ( node : SyntaxNode )-> Option < Self > { if node . kind ()== $kind { Some ( Self ( node ))} else { None }}}}; } -macro_rules! __ra_macro_fixture395 {($I : ident , $U : ident )=>{ mod $I { mod ceil { use num_integer :: Average ; # [ test ] fn same_sign (){ assert_eq ! (( 14 as $I ). average_ceil (& 16 ), 15 as $I ); assert_eq ! (( 14 as $I ). average_ceil (& 17 ), 16 as $I ); let max = $crate :: std ::$I :: MAX ; assert_eq ! (( max - 3 ). average_ceil (& ( max - 1 )), max - 2 ); assert_eq ! (( max - 3 ). average_ceil (& ( max - 2 )), max - 2 ); }# [ test ] fn different_sign (){ assert_eq ! (( 14 as $I ). average_ceil (&- 4 ), 5 as $I ); assert_eq ! (( 14 as $I ). average_ceil (&- 5 ), 5 as $I ); let min = $crate :: std ::$I :: MIN ; let max = $crate :: std ::$I :: MAX ; assert_eq ! ( min . average_ceil (& max ), 0 as $I ); }} mod floor { use num_integer :: Average ; # [ test ] fn same_sign (){ assert_eq ! (( 14 as $I ). average_floor (& 16 ), 15 as $I ); assert_eq ! (( 14 as $I ). average_floor (& 17 ), 15 as $I ); let max = $crate :: std ::$I :: MAX ; assert_eq ! (( max - 3 ). average_floor (& ( max - 1 )), max - 2 ); assert_eq ! (( max - 3 ). average_floor (& ( max - 2 )), max - 3 ); }# [ test ] fn different_sign (){ assert_eq ! (( 14 as $I ). average_floor (&- 4 ), 5 as $I ); assert_eq ! (( 14 as $I ). average_floor (&- 5 ), 4 as $I ); let min = $crate :: std ::$I :: MIN ; let max = $crate :: std ::$I :: MAX ; assert_eq ! ( min . average_floor (& max ), - 1 as $I ); }}} mod $U { mod ceil { use num_integer :: Average ; # [ test ] fn bounded (){ assert_eq ! (( 14 as $U ). average_ceil (& 16 ), 15 as $U ); assert_eq ! (( 14 as $U ). average_ceil (& 17 ), 16 as $U ); }# [ test ] fn overflow (){ let max = $crate :: std ::$U :: MAX ; assert_eq ! (( max - 3 ). average_ceil (& ( max - 1 )), max - 2 ); assert_eq ! (( max - 3 ). average_ceil (& ( max - 2 )), max - 2 ); }} mod floor { use num_integer :: Average ; # [ test ] fn bounded (){ assert_eq ! (( 14 as $U ). average_floor (& 16 ), 15 as $U ); assert_eq ! (( 14 as $U ). average_floor (& 17 ), 15 as $U ); }# [ test ] fn overflow (){ let max = $crate :: std ::$U :: MAX ; assert_eq ! (( max - 3 ). average_floor (& ( max - 1 )), max - 2 ); assert_eq ! (( max - 3 ). average_floor (& ( max - 2 )), max - 3 ); }}}}; } -macro_rules! __ra_macro_fixture396 {($N : expr ; $BENCH_GROUP : ident , $TUPLE_FUN : ident , $TUPLES : ident , $TUPLE_WINDOWS : ident ; $SLICE_FUN : ident , $CHUNKS : ident , $WINDOWS : ident ; $FOR_CHUNKS : ident , $FOR_WINDOWS : ident )=>( fn $FOR_CHUNKS ( c : & mut Criterion ){ let v : Vec < u32 > = ( 0 .. $N * 1_000 ). collect (); let mut s = 0 ; c . bench_function (& stringify ! ($FOR_CHUNKS ). replace ( '_' , " " ), move | b | { b . iter (|| { let mut j = 0 ; for _ in 0 .. 1_000 { s += $SLICE_FUN (& v [ j .. ( j + $N )]); j += $N ; } s })}); } fn $FOR_WINDOWS ( c : & mut Criterion ){ let v : Vec < u32 > = ( 0 .. 1_000 ). collect (); let mut s = 0 ; c . bench_function (& stringify ! ($FOR_WINDOWS ). replace ( '_' , " " ), move | b | { b . iter (|| { for i in 0 .. ( 1_000 - $N ){ s += $SLICE_FUN (& v [ i .. ( i + $N )]); } s })}); } fn $TUPLES ( c : & mut Criterion ){ let v : Vec < u32 > = ( 0 .. $N * 1_000 ). collect (); let mut s = 0 ; c . bench_function (& stringify ! ($TUPLES ). replace ( '_' , " " ), move | b | { b . iter (|| { for x in v . iter (). tuples (){ s += $TUPLE_FUN (& x ); } s })}); } fn $CHUNKS ( c : & mut Criterion ){ let v : Vec < u32 > = ( 0 .. $N * 1_000 ). collect (); let mut s = 0 ; c . bench_function (& stringify ! ($CHUNKS ). replace ( '_' , " " ), move | b | { b . iter (|| { for x in v . chunks ($N ){ s += $SLICE_FUN ( x ); } s })}); } fn $TUPLE_WINDOWS ( c : & mut Criterion ){ let v : Vec < u32 > = ( 0 .. 1_000 ). collect (); let mut s = 0 ; c . bench_function (& stringify ! ($TUPLE_WINDOWS ). replace ( '_' , " " ), move | b | { b . iter (|| { for x in v . iter (). tuple_windows (){ s += $TUPLE_FUN (& x ); } s })}); } fn $WINDOWS ( c : & mut Criterion ){ let v : Vec < u32 > = ( 0 .. 1_000 ). collect (); let mut s = 0 ; c . bench_function (& stringify ! ($WINDOWS ). replace ( '_' , " " ), move | b | { b . iter (|| { for x in v . windows ($N ){ s += $SLICE_FUN ( x ); } s })}); } criterion_group ! ($BENCH_GROUP , $FOR_CHUNKS , $FOR_WINDOWS , $TUPLES , $CHUNKS , $TUPLE_WINDOWS , $WINDOWS , ); )} -macro_rules! __ra_macro_fixture397 {($N : expr , $FUN : ident , $BENCH_NAME : ident , )=>( mod $BENCH_NAME { use super ::*; pub fn sum ( c : & mut Criterion ){ let v : Vec < u32 > = ( 0 .. $N ). collect (); c . bench_function (& ( stringify ! ($BENCH_NAME ). replace ( '_' , " " )+ " sum" ), move | b | { b . iter (|| { cloned (& v ).$FUN (| x , y | x + y )})}); } pub fn complex_iter ( c : & mut Criterion ){ let u = ( 3 ..). take ($N / 2 ); let v = ( 5 ..). take ($N / 2 ); let it = u . chain ( v ); c . bench_function (& ( stringify ! ($BENCH_NAME ). replace ( '_' , " " )+ " complex iter" ), move | b | { b . iter (|| { it . clone (). map (| x | x as f32 ).$FUN ( f32 :: atan2 )})}); } pub fn string_format ( c : & mut Criterion ){ let v : Vec < u32 > = ( 0 .. ($N / 4 )). collect (); c . bench_function (& ( stringify ! ($BENCH_NAME ). replace ( '_' , " " )+ " string format" ), move | b | { b . iter (|| { cloned (& v ). map (| x | x . to_string ()).$FUN (| x , y | format ! ( "{} + {}" , x , y ))})}); }} criterion_group ! ($BENCH_NAME , $BENCH_NAME :: sum , $BENCH_NAME :: complex_iter , $BENCH_NAME :: string_format , ); )} -macro_rules! __ra_macro_fixture398 {($N : expr ; $BENCH_GROUP : ident , $TUPLE_FUN : ident , $TUPLES : ident , $TUPLE_WINDOWS : ident ; $SLICE_FUN : ident , $CHUNKS : ident , $WINDOWS : ident ; $FOR_CHUNKS : ident , $FOR_WINDOWS : ident )=>( fn $FOR_CHUNKS ( c : & mut Criterion ){ let v : Vec < u32 > = ( 0 .. $N * 1_000 ). collect (); let mut s = 0 ; c . bench_function (& stringify ! ($FOR_CHUNKS ). replace ( '_' , " " ), move | b | { b . iter (|| { let mut j = 0 ; for _ in 0 .. 1_000 { s += $SLICE_FUN (& v [ j .. ( j + $N )]); j += $N ; } s })}); } fn $FOR_WINDOWS ( c : & mut Criterion ){ let v : Vec < u32 > = ( 0 .. 1_000 ). collect (); let mut s = 0 ; c . bench_function (& stringify ! ($FOR_WINDOWS ). replace ( '_' , " " ), move | b | { b . iter (|| { for i in 0 .. ( 1_000 - $N ){ s += $SLICE_FUN (& v [ i .. ( i + $N )]); } s })}); } fn $TUPLES ( c : & mut Criterion ){ let v : Vec < u32 > = ( 0 .. $N * 1_000 ). collect (); let mut s = 0 ; c . bench_function (& stringify ! ($TUPLES ). replace ( '_' , " " ), move | b | { b . iter (|| { for x in v . iter (). tuples (){ s += $TUPLE_FUN (& x ); } s })}); } fn $CHUNKS ( c : & mut Criterion ){ let v : Vec < u32 > = ( 0 .. $N * 1_000 ). collect (); let mut s = 0 ; c . bench_function (& stringify ! ($CHUNKS ). replace ( '_' , " " ), move | b | { b . iter (|| { for x in v . chunks ($N ){ s += $SLICE_FUN ( x ); } s })}); } fn $TUPLE_WINDOWS ( c : & mut Criterion ){ let v : Vec < u32 > = ( 0 .. 1_000 ). collect (); let mut s = 0 ; c . bench_function (& stringify ! ($TUPLE_WINDOWS ). replace ( '_' , " " ), move | b | { b . iter (|| { for x in v . iter (). tuple_windows (){ s += $TUPLE_FUN (& x ); } s })}); } fn $WINDOWS ( c : & mut Criterion ){ let v : Vec < u32 > = ( 0 .. 1_000 ). collect (); let mut s = 0 ; c . bench_function (& stringify ! ($WINDOWS ). replace ( '_' , " " ), move | b | { b . iter (|| { for x in v . windows ($N ){ s += $SLICE_FUN ( x ); } s })}); } criterion_group ! ($BENCH_GROUP , $FOR_CHUNKS , $FOR_WINDOWS , $TUPLES , $CHUNKS , $TUPLE_WINDOWS , $WINDOWS , ); )} -macro_rules! __ra_macro_fixture399 {($name : ident : $e : expr )=>{# [ cfg_attr ( target_arch = "wasm32" , wasm_bindgen_test :: wasm_bindgen_test )]# [ test ] fn $name (){ let ( subscriber , handle )= subscriber :: mock (). event ( event :: mock (). with_fields ( field :: mock ( "answer" ). with_value (& 42 ). and ( field :: mock ( "to_question" ). with_value (& "life, the universe, and everything" ), ). only (), ), ). done (). run_with_handle (); with_default ( subscriber , || { info ! ( answer = $e , to_question = "life, the universe, and everything" ); }); handle . assert_finished (); }}; } -macro_rules! __ra_macro_fixture400 {($T : ty )=>{ impl GcdOld for $T {# [ doc = " Calculates the Greatest Common Divisor (GCD) of the number and" ]# [ doc = " `other`. The result is always positive." ]# [ inline ] fn gcd_old (& self , other : & Self )-> Self { let mut m = * self ; let mut n = * other ; if m == 0 || n == 0 { return ( m | n ). abs (); } let shift = ( m | n ). trailing_zeros (); if m == Self :: min_value ()|| n == Self :: min_value (){ return ( 1 << shift ). abs (); } m = m . abs (); n = n . abs (); n >>= n . trailing_zeros (); while m != 0 { m >>= m . trailing_zeros (); if n > m { std :: mem :: swap (& mut n , & mut m )} m -= n ; } n << shift }}}; } -macro_rules! __ra_macro_fixture401 {($T : ty )=>{ impl GcdOld for $T {# [ doc = " Calculates the Greatest Common Divisor (GCD) of the number and" ]# [ doc = " `other`. The result is always positive." ]# [ inline ] fn gcd_old (& self , other : & Self )-> Self { let mut m = * self ; let mut n = * other ; if m == 0 || n == 0 { return m | n ; } let shift = ( m | n ). trailing_zeros (); n >>= n . trailing_zeros (); while m != 0 { m >>= m . trailing_zeros (); if n > m { std :: mem :: swap (& mut n , & mut m )} m -= n ; } n << shift }}}; } -macro_rules! __ra_macro_fixture402 {($T : ident )=>{ mod $T { use crate :: { run_bench , GcdOld }; use num_integer :: Integer ; use test :: Bencher ; # [ bench ] fn bench_gcd ( b : & mut Bencher ){ run_bench ( b , $T :: gcd ); }# [ bench ] fn bench_gcd_old ( b : & mut Bencher ){ run_bench ( b , $T :: gcd_old ); }}}; } -macro_rules! __ra_macro_fixture403 {($f : ident , $($t : ty ),+)=>{$(paste :: item ! { qc :: quickcheck ! { fn [< $f _ $t >]( i : RandIter <$t >, k : u16 )-> (){$f ( i , k )}}})+ }; } -macro_rules! __ra_macro_fixture404 {($name : ident )=>{# [ derive ( Debug )] struct $name { message : & 'static str , drop : DetectDrop , } impl Display for $name { fn fmt (& self , f : & mut fmt :: Formatter )-> fmt :: Result { f . write_str ( self . message )}}}; } -macro_rules! __ra_macro_fixture405 {($($(# [$attr : meta ])* $name : ident ($value : expr )),* )=>{ mod bench_itoa_write { use test :: { Bencher , black_box }; $($(# [$attr ])* # [ bench ] fn $name ( b : & mut Bencher ){ use itoa ; let mut buf = Vec :: with_capacity ( 40 ); b . iter (|| { buf . clear (); itoa :: write (& mut buf , black_box ($value )). unwrap ()}); })* } mod bench_itoa_fmt { use test :: { Bencher , black_box }; $($(# [$attr ])* # [ bench ] fn $name ( b : & mut Bencher ){ use itoa ; let mut buf = String :: with_capacity ( 40 ); b . iter (|| { buf . clear (); itoa :: fmt (& mut buf , black_box ($value )). unwrap ()}); })* } mod bench_std_fmt { use test :: { Bencher , black_box }; $($(# [$attr ])* # [ bench ] fn $name ( b : & mut Bencher ){ use std :: io :: Write ; let mut buf = Vec :: with_capacity ( 40 ); b . iter (|| { buf . clear (); write ! (& mut buf , "{}" , black_box ($value )). unwrap ()}); })* }}} -macro_rules! __ra_macro_fixture406 {($typ : ty {$($b_name : ident =>$g_name : ident ($($args : expr ),*),)* })=>{$(# [ bench ] fn $b_name ( b : & mut Bencher ){$g_name ::<$typ > ($($args ,)* b )})* }} -macro_rules! __ra_macro_fixture407 {($($T : ident ),*)=>{$(mod $T { use test :: Bencher ; use num_integer :: Roots ; # [ bench ] fn sqrt_rand ( b : & mut Bencher ){:: bench_rand_pos ( b , $T :: sqrt , 2 ); }# [ bench ] fn sqrt_small ( b : & mut Bencher ){:: bench_small_pos ( b , $T :: sqrt , 2 ); }# [ bench ] fn cbrt_rand ( b : & mut Bencher ){:: bench_rand ( b , $T :: cbrt , 3 ); }# [ bench ] fn cbrt_small ( b : & mut Bencher ){:: bench_small ( b , $T :: cbrt , 3 ); }# [ bench ] fn fourth_root_rand ( b : & mut Bencher ){:: bench_rand_pos ( b , | x : &$T | x . nth_root ( 4 ), 4 ); }# [ bench ] fn fourth_root_small ( b : & mut Bencher ){:: bench_small_pos ( b , | x : &$T | x . nth_root ( 4 ), 4 ); }# [ bench ] fn fifth_root_rand ( b : & mut Bencher ){:: bench_rand ( b , | x : &$T | x . nth_root ( 5 ), 5 ); }# [ bench ] fn fifth_root_small ( b : & mut Bencher ){:: bench_small ( b , | x : &$T | x . nth_root ( 5 ), 5 ); }})*}} -macro_rules! __ra_macro_fixture408 {($name : ident , $level : expr )=>{# [ doc = " Creates a new `Diagnostic` with the given `message` at the span" ]# [ doc = " `self`." ] pub fn $name < T : Into < String >> ( self , message : T )-> Diagnostic { Diagnostic :: spanned ( self , $level , message )}}; } -macro_rules! __ra_macro_fixture409 {($($name : ident =>$kind : ident ,)*)=>($(# [ doc = " Creates a new suffixed integer literal with the specified value." ]# [ doc = "" ]# [ doc = " This function will create an integer like `1u32` where the integer" ]# [ doc = " value specified is the first part of the token and the integral is" ]# [ doc = " also suffixed at the end." ]# [ doc = " Literals created from negative numbers may not survive round-trips through" ]# [ doc = " `TokenStream` or strings and may be broken into two tokens (`-` and positive literal)." ]# [ doc = "" ]# [ doc = " Literals created through this method have the `Span::call_site()`" ]# [ doc = " span by default, which can be configured with the `set_span` method" ]# [ doc = " below." ] pub fn $name ( n : $kind )-> Literal { Literal ( bridge :: client :: Literal :: typed_integer (& n . to_string (), stringify ! ($kind )))})*)} -macro_rules! __ra_macro_fixture410 {($($name : ident =>$kind : ident ,)*)=>($(# [ doc = " Creates a new unsuffixed integer literal with the specified value." ]# [ doc = "" ]# [ doc = " This function will create an integer like `1` where the integer" ]# [ doc = " value specified is the first part of the token. No suffix is" ]# [ doc = " specified on this token, meaning that invocations like" ]# [ doc = " `Literal::i8_unsuffixed(1)` are equivalent to" ]# [ doc = " `Literal::u32_unsuffixed(1)`." ]# [ doc = " Literals created from negative numbers may not survive rountrips through" ]# [ doc = " `TokenStream` or strings and may be broken into two tokens (`-` and positive literal)." ]# [ doc = "" ]# [ doc = " Literals created through this method have the `Span::call_site()`" ]# [ doc = " span by default, which can be configured with the `set_span` method" ]# [ doc = " below." ] pub fn $name ( n : $kind )-> Literal { Literal ( bridge :: client :: Literal :: integer (& n . to_string ()))})*)} -macro_rules! __ra_macro_fixture411 {($spanned : ident , $regular : ident , $level : expr )=>{# [ doc = " Adds a new child diagnostic message to `self` with the level" ]# [ doc = " identified by this method\\\'s name with the given `spans` and" ]# [ doc = " `message`." ] pub fn $spanned < S , T > ( mut self , spans : S , message : T )-> Diagnostic where S : MultiSpan , T : Into < String >, { self . children . push ( Diagnostic :: spanned ( spans , $level , message )); self }# [ doc = " Adds a new child diagnostic message to `self` with the level" ]# [ doc = " identified by this method\\\'s name with the given `message`." ] pub fn $regular < T : Into < String >> ( mut self , message : T )-> Diagnostic { self . children . push ( Diagnostic :: new ($level , message )); self }}; } -macro_rules! __ra_macro_fixture412 {($($arg : tt )*)=>{{ let res = $crate :: fmt :: format ($crate :: __export :: format_args ! ($($arg )*)); res }}} -macro_rules! __ra_macro_fixture413 {($dst : expr , $($arg : tt )*)=>($dst . write_fmt ($crate :: format_args ! ($($arg )*)))} -macro_rules! __ra_macro_fixture414 {($dst : expr $(,)?)=>($crate :: write ! ($dst , "\n" )); ($dst : expr , $($arg : tt )*)=>($dst . write_fmt ($crate :: format_args_nl ! ($($arg )*))); } -macro_rules! __ra_macro_fixture415 {($($name : ident =>$kind : ident ,)*)=>($(# [ doc = " Creates a new suffixed integer literal with the specified value." ]# [ doc = "" ]# [ doc = " This function will create an integer like `1u32` where the integer" ]# [ doc = " value specified is the first part of the token and the integral is" ]# [ doc = " also suffixed at the end. Literals created from negative numbers may" ]# [ doc = " not survive rountrips through `TokenStream` or strings and may be" ]# [ doc = " broken into two tokens (`-` and positive literal)." ]# [ doc = "" ]# [ doc = " Literals created through this method have the `Span::call_site()`" ]# [ doc = " span by default, which can be configured with the `set_span` method" ]# [ doc = " below." ] pub fn $name ( n : $kind )-> Literal { Literal :: _new ( imp :: Literal ::$name ( n ))})*)} -macro_rules! __ra_macro_fixture416 {($($name : ident =>$kind : ident ,)*)=>($(# [ doc = " Creates a new unsuffixed integer literal with the specified value." ]# [ doc = "" ]# [ doc = " This function will create an integer like `1` where the integer" ]# [ doc = " value specified is the first part of the token. No suffix is" ]# [ doc = " specified on this token, meaning that invocations like" ]# [ doc = " `Literal::i8_unsuffixed(1)` are equivalent to" ]# [ doc = " `Literal::u32_unsuffixed(1)`. Literals created from negative numbers" ]# [ doc = " may not survive rountrips through `TokenStream` or strings and may" ]# [ doc = " be broken into two tokens (`-` and positive literal)." ]# [ doc = "" ]# [ doc = " Literals created through this method have the `Span::call_site()`" ]# [ doc = " span by default, which can be configured with the `set_span` method" ]# [ doc = " below." ] pub fn $name ( n : $kind )-> Literal { Literal :: _new ( imp :: Literal ::$name ( n ))})*)} -macro_rules! __ra_macro_fixture417 {($($name : ident =>$kind : ident ,)*)=>($(pub fn $name ( n : $kind )-> Literal { Literal :: _new ( format ! ( concat ! ( "{}" , stringify ! ($kind )), n ))})*)} -macro_rules! __ra_macro_fixture418 {($($name : ident =>$kind : ident ,)*)=>($(pub fn $name ( n : $kind )-> Literal { Literal :: _new ( n . to_string ())})*)} -macro_rules! __ra_macro_fixture419 {(<$visitor : ident : Visitor <$lifetime : tt >> $($func : ident )*)=>{$(forward_to_deserialize_any_helper ! {$func <$lifetime , $visitor >})* }; ($($func : ident )*)=>{$(forward_to_deserialize_any_helper ! {$func < 'de , V >})* }; } -macro_rules! __ra_macro_fixture420 {( bool <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_bool <$l , $v > ()}}; ( i8 <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_i8 <$l , $v > ()}}; ( i16 <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_i16 <$l , $v > ()}}; ( i32 <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_i32 <$l , $v > ()}}; ( i64 <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_i64 <$l , $v > ()}}; ( i128 <$l : tt , $v : ident >)=>{ serde_if_integer128 ! { forward_to_deserialize_any_method ! { deserialize_i128 <$l , $v > ()}}}; ( u8 <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_u8 <$l , $v > ()}}; ( u16 <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_u16 <$l , $v > ()}}; ( u32 <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_u32 <$l , $v > ()}}; ( u64 <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_u64 <$l , $v > ()}}; ( u128 <$l : tt , $v : ident >)=>{ serde_if_integer128 ! { forward_to_deserialize_any_method ! { deserialize_u128 <$l , $v > ()}}}; ( f32 <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_f32 <$l , $v > ()}}; ( f64 <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_f64 <$l , $v > ()}}; ( char <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_char <$l , $v > ()}}; ( str <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_str <$l , $v > ()}}; ( string <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_string <$l , $v > ()}}; ( bytes <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_bytes <$l , $v > ()}}; ( byte_buf <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_byte_buf <$l , $v > ()}}; ( option <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_option <$l , $v > ()}}; ( unit <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_unit <$l , $v > ()}}; ( unit_struct <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_unit_struct <$l , $v > ( name : & 'static str )}}; ( newtype_struct <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_newtype_struct <$l , $v > ( name : & 'static str )}}; ( seq <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_seq <$l , $v > ()}}; ( tuple <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_tuple <$l , $v > ( len : usize )}}; ( tuple_struct <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_tuple_struct <$l , $v > ( name : & 'static str , len : usize )}}; ( map <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_map <$l , $v > ()}}; ( struct <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_struct <$l , $v > ( name : & 'static str , fields : & 'static [& 'static str ])}}; ( enum <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_enum <$l , $v > ( name : & 'static str , variants : & 'static [& 'static str ])}}; ( identifier <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_identifier <$l , $v > ()}}; ( ignored_any <$l : tt , $v : ident >)=>{ forward_to_deserialize_any_method ! { deserialize_ignored_any <$l , $v > ()}}; } -macro_rules! __ra_macro_fixture421 {($func : ident <$l : tt , $v : ident > ($($arg : ident : $ty : ty ),*))=>{# [ inline ] fn $func <$v > ( self , $($arg : $ty ,)* visitor : $v )-> $crate :: __private :: Result <$v :: Value , Self :: Error > where $v : $crate :: de :: Visitor <$l >, {$(let _ = $arg ; )* self . deserialize_any ( visitor )}}; } -macro_rules! __ra_macro_fixture422 {($($f : ident : $t : ty ,)*)=>{$(fn $f ( self , v : $t )-> fmt :: Result { Display :: fmt (& v , self )})* }; } -macro_rules! __ra_macro_fixture423 {($name : ident , $level : expr )=>{# [ doc = " Creates a new `Diagnostic` with the given `message` at the span" ]# [ doc = " `self`." ]# [ unstable ( feature = "proc_macro_diagnostic" , issue = "54140" )] pub fn $name < T : Into < String >> ( self , message : T )-> Diagnostic { Diagnostic :: spanned ( self , $level , message )}}; } -macro_rules! __ra_macro_fixture424 {($($name : ident =>$kind : ident ,)*)=>($(# [ doc = " Creates a new suffixed integer literal with the specified value." ]# [ doc = "" ]# [ doc = " This function will create an integer like `1u32` where the integer" ]# [ doc = " value specified is the first part of the token and the integral is" ]# [ doc = " also suffixed at the end." ]# [ doc = " Literals created from negative numbers may not survive round-trips through" ]# [ doc = " `TokenStream` or strings and may be broken into two tokens (`-` and positive literal)." ]# [ doc = "" ]# [ doc = " Literals created through this method have the `Span::call_site()`" ]# [ doc = " span by default, which can be configured with the `set_span` method" ]# [ doc = " below." ]# [ stable ( feature = "proc_macro_lib2" , since = "1.29.0" )] pub fn $name ( n : $kind )-> Literal { Literal ( bridge :: client :: Literal :: typed_integer (& n . to_string (), stringify ! ($kind )))})*)} -macro_rules! __ra_macro_fixture425 {($($name : ident =>$kind : ident ,)*)=>($(# [ doc = " Creates a new unsuffixed integer literal with the specified value." ]# [ doc = "" ]# [ doc = " This function will create an integer like `1` where the integer" ]# [ doc = " value specified is the first part of the token. No suffix is" ]# [ doc = " specified on this token, meaning that invocations like" ]# [ doc = " `Literal::i8_unsuffixed(1)` are equivalent to" ]# [ doc = " `Literal::u32_unsuffixed(1)`." ]# [ doc = " Literals created from negative numbers may not survive rountrips through" ]# [ doc = " `TokenStream` or strings and may be broken into two tokens (`-` and positive literal)." ]# [ doc = "" ]# [ doc = " Literals created through this method have the `Span::call_site()`" ]# [ doc = " span by default, which can be configured with the `set_span` method" ]# [ doc = " below." ]# [ stable ( feature = "proc_macro_lib2" , since = "1.29.0" )] pub fn $name ( n : $kind )-> Literal { Literal ( bridge :: client :: Literal :: integer (& n . to_string ()))})*)} -macro_rules! __ra_macro_fixture426 {( type FreeFunctions )=>( type FreeFunctions : 'static ;); ( type TokenStream )=>( type TokenStream : 'static + Clone ;); ( type TokenStreamBuilder )=>( type TokenStreamBuilder : 'static ;); ( type TokenStreamIter )=>( type TokenStreamIter : 'static + Clone ;); ( type Group )=>( type Group : 'static + Clone ;); ( type Punct )=>( type Punct : 'static + Copy + Eq + Hash ;); ( type Ident )=>( type Ident : 'static + Copy + Eq + Hash ;); ( type Literal )=>( type Literal : 'static + Clone ;); ( type SourceFile )=>( type SourceFile : 'static + Clone ;); ( type MultiSpan )=>( type MultiSpan : 'static ;); ( type Diagnostic )=>( type Diagnostic : 'static ;); ( type Span )=>( type Span : 'static + Copy + Eq + Hash ;); ( fn drop (& mut self , $arg : ident : $arg_ty : ty ))=>( fn drop (& mut self , $arg : $arg_ty ){ mem :: drop ($arg )}); ( fn clone (& mut self , $arg : ident : $arg_ty : ty )-> $ret_ty : ty )=>( fn clone (& mut self , $arg : $arg_ty )-> $ret_ty {$arg . clone ()}); ($($item : tt )*)=>($($item )*;)} -macro_rules! __ra_macro_fixture427 {($spanned : ident , $regular : ident , $level : expr )=>{# [ doc = " Adds a new child diagnostic message to `self` with the level" ]# [ doc = " identified by this method\\\'s name with the given `spans` and" ]# [ doc = " `message`." ]# [ unstable ( feature = "proc_macro_diagnostic" , issue = "54140" )] pub fn $spanned < S , T > ( mut self , spans : S , message : T )-> Diagnostic where S : MultiSpan , T : Into < String >, { self . children . push ( Diagnostic :: spanned ( spans , $level , message )); self }# [ doc = " Adds a new child diagnostic message to `self` with the level" ]# [ doc = " identified by this method\\\'s name with the given `message`." ]# [ unstable ( feature = "proc_macro_diagnostic" , issue = "54140" )] pub fn $regular < T : Into < String >> ( mut self , message : T )-> Diagnostic { self . children . push ( Diagnostic :: new ($level , message )); self }}; } -macro_rules! __ra_macro_fixture428 {($SelfT : ty , $ActualT : ident , $UnsignedT : ty , $BITS : expr , $Min : expr , $Max : expr , $Feature : expr , $EndFeature : expr , $rot : expr , $rot_op : expr , $rot_result : expr , $swap_op : expr , $swapped : expr , $reversed : expr , $le_bytes : expr , $be_bytes : expr , $to_xe_bytes_doc : expr , $from_xe_bytes_doc : expr )=>{ doc_comment ! { concat ! ( "The smallest value that can be represented by this integer type.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(" , stringify ! ($SelfT ), "::MIN, " , stringify ! ($Min ), ");" , $EndFeature , "\n```" ), # [ stable ( feature = "assoc_int_consts" , since = "1.43.0" )] pub const MIN : Self = ! 0 ^ ((! 0 as $UnsignedT )>> 1 ) as Self ; } doc_comment ! { concat ! ( "The largest value that can be represented by this integer type.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(" , stringify ! ($SelfT ), "::MAX, " , stringify ! ($Max ), ");" , $EndFeature , "\n```" ), # [ stable ( feature = "assoc_int_consts" , since = "1.43.0" )] pub const MAX : Self = ! Self :: MIN ; } doc_comment ! { concat ! ( "The size of this integer type in bits.\n\n# Examples\n\n```\n" , $Feature , "#![feature(int_bits_const)]\nassert_eq!(" , stringify ! ($SelfT ), "::BITS, " , stringify ! ($BITS ), ");" , $EndFeature , "\n```" ), # [ unstable ( feature = "int_bits_const" , issue = "76904" )] pub const BITS : u32 = $BITS ; } doc_comment ! { concat ! ( "Converts a string slice in a given base to an integer.\n\nThe string is expected to be an optional `+` or `-` sign followed by digits.\nLeading and trailing whitespace represent an error. Digits are a subset of these characters,\ndepending on `radix`:\n\n * `0-9`\n * `a-z`\n * `A-Z`\n\n# Panics\n\nThis function panics if `radix` is not in the range from 2 to 36.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(" , stringify ! ($SelfT ), "::from_str_radix(\"A\", 16), Ok(10));" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )] pub fn from_str_radix ( src : & str , radix : u32 )-> Result < Self , ParseIntError > { from_str_radix ( src , radix )}} doc_comment ! { concat ! ( "Returns the number of ones in the binary representation of `self`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = 0b100_0000" , stringify ! ($SelfT ), ";\n\nassert_eq!(n.count_ones(), 1);" , $EndFeature , "\n```\n" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ inline ] pub const fn count_ones ( self )-> u32 {( self as $UnsignedT ). count_ones ()}} doc_comment ! { concat ! ( "Returns the number of zeros in the binary representation of `self`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(" , stringify ! ($SelfT ), "::MAX.count_zeros(), 1);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ inline ] pub const fn count_zeros ( self )-> u32 {(! self ). count_ones ()}} doc_comment ! { concat ! ( "Returns the number of leading zeros in the binary representation of `self`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = -1" , stringify ! ($SelfT ), ";\n\nassert_eq!(n.leading_zeros(), 0);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ inline ] pub const fn leading_zeros ( self )-> u32 {( self as $UnsignedT ). leading_zeros ()}} doc_comment ! { concat ! ( "Returns the number of trailing zeros in the binary representation of `self`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = -4" , stringify ! ($SelfT ), ";\n\nassert_eq!(n.trailing_zeros(), 2);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ inline ] pub const fn trailing_zeros ( self )-> u32 {( self as $UnsignedT ). trailing_zeros ()}} doc_comment ! { concat ! ( "Returns the number of leading ones in the binary representation of `self`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = -1" , stringify ! ($SelfT ), ";\n\nassert_eq!(n.leading_ones(), " , stringify ! ($BITS ), ");" , $EndFeature , "\n```" ), # [ stable ( feature = "leading_trailing_ones" , since = "1.46.0" )]# [ rustc_const_stable ( feature = "leading_trailing_ones" , since = "1.46.0" )]# [ inline ] pub const fn leading_ones ( self )-> u32 {( self as $UnsignedT ). leading_ones ()}} doc_comment ! { concat ! ( "Returns the number of trailing ones in the binary representation of `self`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = 3" , stringify ! ($SelfT ), ";\n\nassert_eq!(n.trailing_ones(), 2);" , $EndFeature , "\n```" ), # [ stable ( feature = "leading_trailing_ones" , since = "1.46.0" )]# [ rustc_const_stable ( feature = "leading_trailing_ones" , since = "1.46.0" )]# [ inline ] pub const fn trailing_ones ( self )-> u32 {( self as $UnsignedT ). trailing_ones ()}} doc_comment ! { concat ! ( "Shifts the bits to the left by a specified amount, `n`,\nwrapping the truncated bits to the end of the resulting integer.\n\nPlease note this isn't the same operation as the `<<` shifting operator!\n\n# Examples\n\nBasic usage:\n\n```\nlet n = " , $rot_op , stringify ! ($SelfT ), ";\nlet m = " , $rot_result , ";\n\nassert_eq!(n.rotate_left(" , $rot , "), m);\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn rotate_left ( self , n : u32 )-> Self {( self as $UnsignedT ). rotate_left ( n ) as Self }} doc_comment ! { concat ! ( "Shifts the bits to the right by a specified amount, `n`,\nwrapping the truncated bits to the beginning of the resulting\ninteger.\n\nPlease note this isn't the same operation as the `>>` shifting operator!\n\n# Examples\n\nBasic usage:\n\n```\nlet n = " , $rot_result , stringify ! ($SelfT ), ";\nlet m = " , $rot_op , ";\n\nassert_eq!(n.rotate_right(" , $rot , "), m);\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn rotate_right ( self , n : u32 )-> Self {( self as $UnsignedT ). rotate_right ( n ) as Self }} doc_comment ! { concat ! ( "Reverses the byte order of the integer.\n\n# Examples\n\nBasic usage:\n\n```\nlet n = " , $swap_op , stringify ! ($SelfT ), ";\n\nlet m = n.swap_bytes();\n\nassert_eq!(m, " , $swapped , ");\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ inline ] pub const fn swap_bytes ( self )-> Self {( self as $UnsignedT ). swap_bytes () as Self }} doc_comment ! { concat ! ( "Reverses the order of bits in the integer. The least significant bit becomes the most significant bit,\n second least-significant bit becomes second most-significant bit, etc.\n\n# Examples\n\nBasic usage:\n\n```\nlet n = " , $swap_op , stringify ! ($SelfT ), ";\nlet m = n.reverse_bits();\n\nassert_eq!(m, " , $reversed , ");\nassert_eq!(0, 0" , stringify ! ($SelfT ), ".reverse_bits());\n```" ), # [ stable ( feature = "reverse_bits" , since = "1.37.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ inline ]# [ must_use ] pub const fn reverse_bits ( self )-> Self {( self as $UnsignedT ). reverse_bits () as Self }} doc_comment ! { concat ! ( "Converts an integer from big endian to the target's endianness.\n\nOn big endian this is a no-op. On little endian the bytes are swapped.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = 0x1A" , stringify ! ($SelfT ), ";\n\nif cfg!(target_endian = \"big\") {\n assert_eq!(" , stringify ! ($SelfT ), "::from_be(n), n)\n} else {\n assert_eq!(" , stringify ! ($SelfT ), "::from_be(n), n.swap_bytes())\n}" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_conversions" , since = "1.32.0" )]# [ inline ] pub const fn from_be ( x : Self )-> Self {# [ cfg ( target_endian = "big" )]{ x }# [ cfg ( not ( target_endian = "big" ))]{ x . swap_bytes ()}}} doc_comment ! { concat ! ( "Converts an integer from little endian to the target's endianness.\n\nOn little endian this is a no-op. On big endian the bytes are swapped.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = 0x1A" , stringify ! ($SelfT ), ";\n\nif cfg!(target_endian = \"little\") {\n assert_eq!(" , stringify ! ($SelfT ), "::from_le(n), n)\n} else {\n assert_eq!(" , stringify ! ($SelfT ), "::from_le(n), n.swap_bytes())\n}" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_conversions" , since = "1.32.0" )]# [ inline ] pub const fn from_le ( x : Self )-> Self {# [ cfg ( target_endian = "little" )]{ x }# [ cfg ( not ( target_endian = "little" ))]{ x . swap_bytes ()}}} doc_comment ! { concat ! ( "Converts `self` to big endian from the target's endianness.\n\nOn big endian this is a no-op. On little endian the bytes are swapped.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = 0x1A" , stringify ! ($SelfT ), ";\n\nif cfg!(target_endian = \"big\") {\n assert_eq!(n.to_be(), n)\n} else {\n assert_eq!(n.to_be(), n.swap_bytes())\n}" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_conversions" , since = "1.32.0" )]# [ inline ] pub const fn to_be ( self )-> Self {# [ cfg ( target_endian = "big" )]{ self }# [ cfg ( not ( target_endian = "big" ))]{ self . swap_bytes ()}}} doc_comment ! { concat ! ( "Converts `self` to little endian from the target's endianness.\n\nOn little endian this is a no-op. On big endian the bytes are swapped.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = 0x1A" , stringify ! ($SelfT ), ";\n\nif cfg!(target_endian = \"little\") {\n assert_eq!(n.to_le(), n)\n} else {\n assert_eq!(n.to_le(), n.swap_bytes())\n}" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_conversions" , since = "1.32.0" )]# [ inline ] pub const fn to_le ( self )-> Self {# [ cfg ( target_endian = "little" )]{ self }# [ cfg ( not ( target_endian = "little" ))]{ self . swap_bytes ()}}} doc_comment ! { concat ! ( "Checked integer addition. Computes `self + rhs`, returning `None`\nif overflow occurred.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!((" , stringify ! ($SelfT ), "::MAX - 2).checked_add(1), Some(" , stringify ! ($SelfT ), "::MAX - 1));\nassert_eq!((" , stringify ! ($SelfT ), "::MAX - 2).checked_add(3), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_checked_int_methods" , since = "1.47.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_add ( self , rhs : Self )-> Option < Self > { let ( a , b )= self . overflowing_add ( rhs ); if unlikely ! ( b ){ None } else { Some ( a )}}} doc_comment ! { concat ! ( "Unchecked integer addition. Computes `self + rhs`, assuming overflow\ncannot occur. This results in undefined behavior when `self + rhs > " , stringify ! ($SelfT ), "::MAX` or `self + rhs < " , stringify ! ($SelfT ), "::MIN`." ), # [ unstable ( feature = "unchecked_math" , reason = "niche optimization path" , issue = "none" , )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub unsafe fn unchecked_add ( self , rhs : Self )-> Self { unsafe { intrinsics :: unchecked_add ( self , rhs )}}} doc_comment ! { concat ! ( "Checked integer subtraction. Computes `self - rhs`, returning `None` if\noverflow occurred.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!((" , stringify ! ($SelfT ), "::MIN + 2).checked_sub(1), Some(" , stringify ! ($SelfT ), "::MIN + 1));\nassert_eq!((" , stringify ! ($SelfT ), "::MIN + 2).checked_sub(3), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_checked_int_methods" , since = "1.47.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_sub ( self , rhs : Self )-> Option < Self > { let ( a , b )= self . overflowing_sub ( rhs ); if unlikely ! ( b ){ None } else { Some ( a )}}} doc_comment ! { concat ! ( "Unchecked integer subtraction. Computes `self - rhs`, assuming overflow\ncannot occur. This results in undefined behavior when `self - rhs > " , stringify ! ($SelfT ), "::MAX` or `self - rhs < " , stringify ! ($SelfT ), "::MIN`." ), # [ unstable ( feature = "unchecked_math" , reason = "niche optimization path" , issue = "none" , )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub unsafe fn unchecked_sub ( self , rhs : Self )-> Self { unsafe { intrinsics :: unchecked_sub ( self , rhs )}}} doc_comment ! { concat ! ( "Checked integer multiplication. Computes `self * rhs`, returning `None` if\noverflow occurred.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(" , stringify ! ($SelfT ), "::MAX.checked_mul(1), Some(" , stringify ! ($SelfT ), "::MAX));\nassert_eq!(" , stringify ! ($SelfT ), "::MAX.checked_mul(2), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_checked_int_methods" , since = "1.47.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_mul ( self , rhs : Self )-> Option < Self > { let ( a , b )= self . overflowing_mul ( rhs ); if unlikely ! ( b ){ None } else { Some ( a )}}} doc_comment ! { concat ! ( "Unchecked integer multiplication. Computes `self * rhs`, assuming overflow\ncannot occur. This results in undefined behavior when `self * rhs > " , stringify ! ($SelfT ), "::MAX` or `self * rhs < " , stringify ! ($SelfT ), "::MIN`." ), # [ unstable ( feature = "unchecked_math" , reason = "niche optimization path" , issue = "none" , )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub unsafe fn unchecked_mul ( self , rhs : Self )-> Self { unsafe { intrinsics :: unchecked_mul ( self , rhs )}}} doc_comment ! { concat ! ( "Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`\nor the division results in overflow.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!((" , stringify ! ($SelfT ), "::MIN + 1).checked_div(-1), Some(" , stringify ! ($Max ), "));\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.checked_div(-1), None);\nassert_eq!((1" , stringify ! ($SelfT ), ").checked_div(0), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_unstable ( feature = "const_checked_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_div ( self , rhs : Self )-> Option < Self > { if unlikely ! ( rhs == 0 || ( self == Self :: MIN && rhs == - 1 )){ None } else { Some ( unsafe { intrinsics :: unchecked_div ( self , rhs )})}}} doc_comment ! { concat ! ( "Checked Euclidean division. Computes `self.div_euclid(rhs)`,\nreturning `None` if `rhs == 0` or the division results in overflow.\n\n# Examples\n\nBasic usage:\n\n```\nassert_eq!((" , stringify ! ($SelfT ), "::MIN + 1).checked_div_euclid(-1), Some(" , stringify ! ($Max ), "));\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.checked_div_euclid(-1), None);\nassert_eq!((1" , stringify ! ($SelfT ), ").checked_div_euclid(0), None);\n```" ), # [ stable ( feature = "euclidean_division" , since = "1.38.0" )]# [ rustc_const_unstable ( feature = "const_euclidean_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_div_euclid ( self , rhs : Self )-> Option < Self > { if unlikely ! ( rhs == 0 || ( self == Self :: MIN && rhs == - 1 )){ None } else { Some ( self . div_euclid ( rhs ))}}} doc_comment ! { concat ! ( "Checked integer remainder. Computes `self % rhs`, returning `None` if\n`rhs == 0` or the division results in overflow.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "\nassert_eq!(5" , stringify ! ($SelfT ), ".checked_rem(2), Some(1));\nassert_eq!(5" , stringify ! ($SelfT ), ".checked_rem(0), None);\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.checked_rem(-1), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_unstable ( feature = "const_checked_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_rem ( self , rhs : Self )-> Option < Self > { if unlikely ! ( rhs == 0 || ( self == Self :: MIN && rhs == - 1 )){ None } else { Some ( unsafe { intrinsics :: unchecked_rem ( self , rhs )})}}} doc_comment ! { concat ! ( "Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None`\nif `rhs == 0` or the division results in overflow.\n\n# Examples\n\nBasic usage:\n\n```\nassert_eq!(5" , stringify ! ($SelfT ), ".checked_rem_euclid(2), Some(1));\nassert_eq!(5" , stringify ! ($SelfT ), ".checked_rem_euclid(0), None);\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.checked_rem_euclid(-1), None);\n```" ), # [ stable ( feature = "euclidean_division" , since = "1.38.0" )]# [ rustc_const_unstable ( feature = "const_euclidean_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_rem_euclid ( self , rhs : Self )-> Option < Self > { if unlikely ! ( rhs == 0 || ( self == Self :: MIN && rhs == - 1 )){ None } else { Some ( self . rem_euclid ( rhs ))}}} doc_comment ! { concat ! ( "Checked negation. Computes `-self`, returning `None` if `self == MIN`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "\nassert_eq!(5" , stringify ! ($SelfT ), ".checked_neg(), Some(-5));\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.checked_neg(), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_checked_int_methods" , since = "1.47.0" )]# [ inline ] pub const fn checked_neg ( self )-> Option < Self > { let ( a , b )= self . overflowing_neg (); if unlikely ! ( b ){ None } else { Some ( a )}}} doc_comment ! { concat ! ( "Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger\nthan or equal to the number of bits in `self`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(0x1" , stringify ! ($SelfT ), ".checked_shl(4), Some(0x10));\nassert_eq!(0x1" , stringify ! ($SelfT ), ".checked_shl(129), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_checked_int_methods" , since = "1.47.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_shl ( self , rhs : u32 )-> Option < Self > { let ( a , b )= self . overflowing_shl ( rhs ); if unlikely ! ( b ){ None } else { Some ( a )}}} doc_comment ! { concat ! ( "Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is\nlarger than or equal to the number of bits in `self`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(0x10" , stringify ! ($SelfT ), ".checked_shr(4), Some(0x1));\nassert_eq!(0x10" , stringify ! ($SelfT ), ".checked_shr(128), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_checked_int_methods" , since = "1.47.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_shr ( self , rhs : u32 )-> Option < Self > { let ( a , b )= self . overflowing_shr ( rhs ); if unlikely ! ( b ){ None } else { Some ( a )}}} doc_comment ! { concat ! ( "Checked absolute value. Computes `self.abs()`, returning `None` if\n`self == MIN`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "\nassert_eq!((-5" , stringify ! ($SelfT ), ").checked_abs(), Some(5));\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.checked_abs(), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "no_panic_abs" , since = "1.13.0" )]# [ rustc_const_stable ( feature = "const_checked_int_methods" , since = "1.47.0" )]# [ inline ] pub const fn checked_abs ( self )-> Option < Self > { if self . is_negative (){ self . checked_neg ()} else { Some ( self )}}} doc_comment ! { concat ! ( "Checked exponentiation. Computes `self.pow(exp)`, returning `None` if\noverflow occurred.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(8" , stringify ! ($SelfT ), ".checked_pow(2), Some(64));\nassert_eq!(" , stringify ! ($SelfT ), "::MAX.checked_pow(2), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "no_panic_pow" , since = "1.34.0" )]# [ rustc_const_unstable ( feature = "const_int_pow" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_pow ( self , mut exp : u32 )-> Option < Self > { if exp == 0 { return Some ( 1 ); } let mut base = self ; let mut acc : Self = 1 ; while exp > 1 { if ( exp & 1 )== 1 { acc = try_opt ! ( acc . checked_mul ( base )); } exp /= 2 ; base = try_opt ! ( base . checked_mul ( base )); } Some ( try_opt ! ( acc . checked_mul ( base )))}} doc_comment ! { concat ! ( "Saturating integer addition. Computes `self + rhs`, saturating at the numeric\nbounds instead of overflowing.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(100" , stringify ! ($SelfT ), ".saturating_add(1), 101);\nassert_eq!(" , stringify ! ($SelfT ), "::MAX.saturating_add(100), " , stringify ! ($SelfT ), "::MAX);\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.saturating_add(-1), " , stringify ! ($SelfT ), "::MIN);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_saturating_int_methods" , since = "1.47.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn saturating_add ( self , rhs : Self )-> Self { intrinsics :: saturating_add ( self , rhs )}} doc_comment ! { concat ! ( "Saturating integer subtraction. Computes `self - rhs`, saturating at the\nnumeric bounds instead of overflowing.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(100" , stringify ! ($SelfT ), ".saturating_sub(127), -27);\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.saturating_sub(100), " , stringify ! ($SelfT ), "::MIN);\nassert_eq!(" , stringify ! ($SelfT ), "::MAX.saturating_sub(-1), " , stringify ! ($SelfT ), "::MAX);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_saturating_int_methods" , since = "1.47.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn saturating_sub ( self , rhs : Self )-> Self { intrinsics :: saturating_sub ( self , rhs )}} doc_comment ! { concat ! ( "Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN`\ninstead of overflowing.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(100" , stringify ! ($SelfT ), ".saturating_neg(), -100);\nassert_eq!((-100" , stringify ! ($SelfT ), ").saturating_neg(), 100);\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.saturating_neg(), " , stringify ! ($SelfT ), "::MAX);\nassert_eq!(" , stringify ! ($SelfT ), "::MAX.saturating_neg(), " , stringify ! ($SelfT ), "::MIN + 1);" , $EndFeature , "\n```" ), # [ stable ( feature = "saturating_neg" , since = "1.45.0" )]# [ rustc_const_stable ( feature = "const_saturating_int_methods" , since = "1.47.0" )]# [ inline ] pub const fn saturating_neg ( self )-> Self { intrinsics :: saturating_sub ( 0 , self )}} doc_comment ! { concat ! ( "Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self ==\nMIN` instead of overflowing.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(100" , stringify ! ($SelfT ), ".saturating_abs(), 100);\nassert_eq!((-100" , stringify ! ($SelfT ), ").saturating_abs(), 100);\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.saturating_abs(), " , stringify ! ($SelfT ), "::MAX);\nassert_eq!((" , stringify ! ($SelfT ), "::MIN + 1).saturating_abs(), " , stringify ! ($SelfT ), "::MAX);" , $EndFeature , "\n```" ), # [ stable ( feature = "saturating_neg" , since = "1.45.0" )]# [ rustc_const_stable ( feature = "const_saturating_int_methods" , since = "1.47.0" )]# [ inline ] pub const fn saturating_abs ( self )-> Self { if self . is_negative (){ self . saturating_neg ()} else { self }}} doc_comment ! { concat ! ( "Saturating integer multiplication. Computes `self * rhs`, saturating at the\nnumeric bounds instead of overflowing.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "\nassert_eq!(10" , stringify ! ($SelfT ), ".saturating_mul(12), 120);\nassert_eq!(" , stringify ! ($SelfT ), "::MAX.saturating_mul(10), " , stringify ! ($SelfT ), "::MAX);\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.saturating_mul(10), " , stringify ! ($SelfT ), "::MIN);" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_saturating_int_methods" , since = "1.47.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn saturating_mul ( self , rhs : Self )-> Self { match self . checked_mul ( rhs ){ Some ( x )=> x , None => if ( self < 0 )== ( rhs < 0 ){ Self :: MAX } else { Self :: MIN }}}} doc_comment ! { concat ! ( "Saturating integer exponentiation. Computes `self.pow(exp)`,\nsaturating at the numeric bounds instead of overflowing.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "\nassert_eq!((-4" , stringify ! ($SelfT ), ").saturating_pow(3), -64);\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.saturating_pow(2), " , stringify ! ($SelfT ), "::MAX);\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.saturating_pow(3), " , stringify ! ($SelfT ), "::MIN);" , $EndFeature , "\n```" ), # [ stable ( feature = "no_panic_pow" , since = "1.34.0" )]# [ rustc_const_unstable ( feature = "const_int_pow" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn saturating_pow ( self , exp : u32 )-> Self { match self . checked_pow ( exp ){ Some ( x )=> x , None if self < 0 && exp % 2 == 1 => Self :: MIN , None => Self :: MAX , }}} doc_comment ! { concat ! ( "Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the\nboundary of the type.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(100" , stringify ! ($SelfT ), ".wrapping_add(27), 127);\nassert_eq!(" , stringify ! ($SelfT ), "::MAX.wrapping_add(2), " , stringify ! ($SelfT ), "::MIN + 1);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_add ( self , rhs : Self )-> Self { intrinsics :: wrapping_add ( self , rhs )}} doc_comment ! { concat ! ( "Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the\nboundary of the type.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(0" , stringify ! ($SelfT ), ".wrapping_sub(127), -127);\nassert_eq!((-2" , stringify ! ($SelfT ), ").wrapping_sub(" , stringify ! ($SelfT ), "::MAX), " , stringify ! ($SelfT ), "::MAX);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_sub ( self , rhs : Self )-> Self { intrinsics :: wrapping_sub ( self , rhs )}} doc_comment ! { concat ! ( "Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at\nthe boundary of the type.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(10" , stringify ! ($SelfT ), ".wrapping_mul(12), 120);\nassert_eq!(11i8.wrapping_mul(12), -124);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_mul ( self , rhs : Self )-> Self { intrinsics :: wrapping_mul ( self , rhs )}} doc_comment ! { concat ! ( "Wrapping (modular) division. Computes `self / rhs`, wrapping around at the\nboundary of the type.\n\nThe only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where\n`MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value\nthat is too large to represent in the type. In such a case, this function returns `MIN` itself.\n\n# Panics\n\nThis function will panic if `rhs` is 0.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(100" , stringify ! ($SelfT ), ".wrapping_div(10), 10);\nassert_eq!((-128i8).wrapping_div(-1), -128);" , $EndFeature , "\n```" ), # [ stable ( feature = "num_wrapping" , since = "1.2.0" )]# [ rustc_const_unstable ( feature = "const_wrapping_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_div ( self , rhs : Self )-> Self { self . overflowing_div ( rhs ). 0 }} doc_comment ! { concat ! ( "Wrapping Euclidean division. Computes `self.div_euclid(rhs)`,\nwrapping around at the boundary of the type.\n\nWrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value\nfor the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the\ntype. In this case, this method returns `MIN` itself.\n\n# Panics\n\nThis function will panic if `rhs` is 0.\n\n# Examples\n\nBasic usage:\n\n```\nassert_eq!(100" , stringify ! ($SelfT ), ".wrapping_div_euclid(10), 10);\nassert_eq!((-128i8).wrapping_div_euclid(-1), -128);\n```" ), # [ stable ( feature = "euclidean_division" , since = "1.38.0" )]# [ rustc_const_unstable ( feature = "const_euclidean_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_div_euclid ( self , rhs : Self )-> Self { self . overflowing_div_euclid ( rhs ). 0 }} doc_comment ! { concat ! ( "Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the\nboundary of the type.\n\nSuch wrap-around never actually occurs mathematically; implementation artifacts make `x % y`\ninvalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case,\nthis function returns `0`.\n\n# Panics\n\nThis function will panic if `rhs` is 0.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(100" , stringify ! ($SelfT ), ".wrapping_rem(10), 0);\nassert_eq!((-128i8).wrapping_rem(-1), 0);" , $EndFeature , "\n```" ), # [ stable ( feature = "num_wrapping" , since = "1.2.0" )]# [ rustc_const_unstable ( feature = "const_wrapping_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_rem ( self , rhs : Self )-> Self { self . overflowing_rem ( rhs ). 0 }} doc_comment ! { concat ! ( "Wrapping Euclidean remainder. Computes `self.rem_euclid(rhs)`, wrapping around\nat the boundary of the type.\n\nWrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value\nfor the type). In this case, this method returns 0.\n\n# Panics\n\nThis function will panic if `rhs` is 0.\n\n# Examples\n\nBasic usage:\n\n```\nassert_eq!(100" , stringify ! ($SelfT ), ".wrapping_rem_euclid(10), 0);\nassert_eq!((-128i8).wrapping_rem_euclid(-1), 0);\n```" ), # [ stable ( feature = "euclidean_division" , since = "1.38.0" )]# [ rustc_const_unstable ( feature = "const_euclidean_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_rem_euclid ( self , rhs : Self )-> Self { self . overflowing_rem_euclid ( rhs ). 0 }} doc_comment ! { concat ! ( "Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary\nof the type.\n\nThe only case where such wrapping can occur is when one negates `MIN` on a signed type (where `MIN`\nis the negative minimal value for the type); this is a positive value that is too large to represent\nin the type. In such a case, this function returns `MIN` itself.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(100" , stringify ! ($SelfT ), ".wrapping_neg(), -100);\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.wrapping_neg(), " , stringify ! ($SelfT ), "::MIN);" , $EndFeature , "\n```" ), # [ stable ( feature = "num_wrapping" , since = "1.2.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ inline ] pub const fn wrapping_neg ( self )-> Self { self . overflowing_neg (). 0 }} doc_comment ! { concat ! ( "Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes\nany high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type.\n\nNote that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to\nthe range of the type, rather than the bits shifted out of the LHS being returned to the other end.\nThe primitive integer types all implement a `[`rotate_left`](#method.rotate_left) function,\nwhich may be what you want instead.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!((-1" , stringify ! ($SelfT ), ").wrapping_shl(7), -128);\nassert_eq!((-1" , stringify ! ($SelfT ), ").wrapping_shl(128), -1);" , $EndFeature , "\n```" ), # [ stable ( feature = "num_wrapping" , since = "1.2.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_shl ( self , rhs : u32 )-> Self { unsafe { intrinsics :: unchecked_shl ( self , ( rhs & ($BITS - 1 )) as $SelfT )}}} doc_comment ! { concat ! ( "Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask`\nremoves any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type.\n\nNote that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted\nto the range of the type, rather than the bits shifted out of the LHS being returned to the other\nend. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function,\nwhich may be what you want instead.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!((-128" , stringify ! ($SelfT ), ").wrapping_shr(7), -1);\nassert_eq!((-128i16).wrapping_shr(64), -128);" , $EndFeature , "\n```" ), # [ stable ( feature = "num_wrapping" , since = "1.2.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_shr ( self , rhs : u32 )-> Self { unsafe { intrinsics :: unchecked_shr ( self , ( rhs & ($BITS - 1 )) as $SelfT )}}} doc_comment ! { concat ! ( "Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at\nthe boundary of the type.\n\nThe only case where such wrapping can occur is when one takes the absolute value of the negative\nminimal value for the type; this is a positive value that is too large to represent in the type. In\nsuch a case, this function returns `MIN` itself.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(100" , stringify ! ($SelfT ), ".wrapping_abs(), 100);\nassert_eq!((-100" , stringify ! ($SelfT ), ").wrapping_abs(), 100);\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.wrapping_abs(), " , stringify ! ($SelfT ), "::MIN);\nassert_eq!((-128i8).wrapping_abs() as u8, 128);" , $EndFeature , "\n```" ), # [ stable ( feature = "no_panic_abs" , since = "1.13.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ allow ( unused_attributes )]# [ inline ] pub const fn wrapping_abs ( self )-> Self { if self . is_negative (){ self . wrapping_neg ()} else { self }}} doc_comment ! { concat ! ( "Computes the absolute value of `self` without any wrapping\nor panicking.\n\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "#![feature(unsigned_abs)]\nassert_eq!(100" , stringify ! ($SelfT ), ".unsigned_abs(), 100" , stringify ! ($UnsignedT ), ");\nassert_eq!((-100" , stringify ! ($SelfT ), ").unsigned_abs(), 100" , stringify ! ($UnsignedT ), ");\nassert_eq!((-128i8).unsigned_abs(), 128u8);" , $EndFeature , "\n```" ), # [ unstable ( feature = "unsigned_abs" , issue = "74913" )]# [ inline ] pub const fn unsigned_abs ( self )-> $UnsignedT { self . wrapping_abs () as $UnsignedT }} doc_comment ! { concat ! ( "Wrapping (modular) exponentiation. Computes `self.pow(exp)`,\nwrapping around at the boundary of the type.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(3" , stringify ! ($SelfT ), ".wrapping_pow(4), 81);\nassert_eq!(3i8.wrapping_pow(5), -13);\nassert_eq!(3i8.wrapping_pow(6), -39);" , $EndFeature , "\n```" ), # [ stable ( feature = "no_panic_pow" , since = "1.34.0" )]# [ rustc_const_unstable ( feature = "const_int_pow" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_pow ( self , mut exp : u32 )-> Self { if exp == 0 { return 1 ; } let mut base = self ; let mut acc : Self = 1 ; while exp > 1 { if ( exp & 1 )== 1 { acc = acc . wrapping_mul ( base ); } exp /= 2 ; base = base . wrapping_mul ( base ); } acc . wrapping_mul ( base )}} doc_comment ! { concat ! ( "Calculates `self` + `rhs`\n\nReturns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would\noccur. If an overflow would have occurred then the wrapped value is returned.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "\nassert_eq!(5" , stringify ! ($SelfT ), ".overflowing_add(2), (7, false));\nassert_eq!(" , stringify ! ($SelfT ), "::MAX.overflowing_add(1), (" , stringify ! ($SelfT ), "::MIN, true));" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn overflowing_add ( self , rhs : Self )-> ( Self , bool ){ let ( a , b )= intrinsics :: add_with_overflow ( self as $ActualT , rhs as $ActualT ); ( a as Self , b )}} doc_comment ! { concat ! ( "Calculates `self` - `rhs`\n\nReturns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow\nwould occur. If an overflow would have occurred then the wrapped value is returned.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "\nassert_eq!(5" , stringify ! ($SelfT ), ".overflowing_sub(2), (3, false));\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.overflowing_sub(1), (" , stringify ! ($SelfT ), "::MAX, true));" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn overflowing_sub ( self , rhs : Self )-> ( Self , bool ){ let ( a , b )= intrinsics :: sub_with_overflow ( self as $ActualT , rhs as $ActualT ); ( a as Self , b )}} doc_comment ! { concat ! ( "Calculates the multiplication of `self` and `rhs`.\n\nReturns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow\nwould occur. If an overflow would have occurred then the wrapped value is returned.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(5" , stringify ! ($SelfT ), ".overflowing_mul(2), (10, false));\nassert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn overflowing_mul ( self , rhs : Self )-> ( Self , bool ){ let ( a , b )= intrinsics :: mul_with_overflow ( self as $ActualT , rhs as $ActualT ); ( a as Self , b )}} doc_comment ! { concat ! ( "Calculates the divisor when `self` is divided by `rhs`.\n\nReturns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would\noccur. If an overflow would occur then self is returned.\n\n# Panics\n\nThis function will panic if `rhs` is 0.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "\nassert_eq!(5" , stringify ! ($SelfT ), ".overflowing_div(2), (2, false));\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.overflowing_div(-1), (" , stringify ! ($SelfT ), "::MIN, true));" , $EndFeature , "\n```" ), # [ inline ]# [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_unstable ( feature = "const_overflowing_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ] pub const fn overflowing_div ( self , rhs : Self )-> ( Self , bool ){ if unlikely ! ( self == Self :: MIN && rhs == - 1 ){( self , true )} else {( self / rhs , false )}}} doc_comment ! { concat ! ( "Calculates the quotient of Euclidean division `self.div_euclid(rhs)`.\n\nReturns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would\noccur. If an overflow would occur then `self` is returned.\n\n# Panics\n\nThis function will panic if `rhs` is 0.\n\n# Examples\n\nBasic usage:\n\n```\nassert_eq!(5" , stringify ! ($SelfT ), ".overflowing_div_euclid(2), (2, false));\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.overflowing_div_euclid(-1), (" , stringify ! ($SelfT ), "::MIN, true));\n```" ), # [ inline ]# [ stable ( feature = "euclidean_division" , since = "1.38.0" )]# [ rustc_const_unstable ( feature = "const_euclidean_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ] pub const fn overflowing_div_euclid ( self , rhs : Self )-> ( Self , bool ){ if unlikely ! ( self == Self :: MIN && rhs == - 1 ){( self , true )} else {( self . div_euclid ( rhs ), false )}}} doc_comment ! { concat ! ( "Calculates the remainder when `self` is divided by `rhs`.\n\nReturns a tuple of the remainder after dividing along with a boolean indicating whether an\narithmetic overflow would occur. If an overflow would occur then 0 is returned.\n\n# Panics\n\nThis function will panic if `rhs` is 0.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "\nassert_eq!(5" , stringify ! ($SelfT ), ".overflowing_rem(2), (1, false));\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.overflowing_rem(-1), (0, true));" , $EndFeature , "\n```" ), # [ inline ]# [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_unstable ( feature = "const_overflowing_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ] pub const fn overflowing_rem ( self , rhs : Self )-> ( Self , bool ){ if unlikely ! ( self == Self :: MIN && rhs == - 1 ){( 0 , true )} else {( self % rhs , false )}}} doc_comment ! { concat ! ( "Overflowing Euclidean remainder. Calculates `self.rem_euclid(rhs)`.\n\nReturns a tuple of the remainder after dividing along with a boolean indicating whether an\narithmetic overflow would occur. If an overflow would occur then 0 is returned.\n\n# Panics\n\nThis function will panic if `rhs` is 0.\n\n# Examples\n\nBasic usage:\n\n```\nassert_eq!(5" , stringify ! ($SelfT ), ".overflowing_rem_euclid(2), (1, false));\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.overflowing_rem_euclid(-1), (0, true));\n```" ), # [ stable ( feature = "euclidean_division" , since = "1.38.0" )]# [ rustc_const_unstable ( feature = "const_euclidean_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn overflowing_rem_euclid ( self , rhs : Self )-> ( Self , bool ){ if unlikely ! ( self == Self :: MIN && rhs == - 1 ){( 0 , true )} else {( self . rem_euclid ( rhs ), false )}}} doc_comment ! { concat ! ( "Negates self, overflowing if this is equal to the minimum value.\n\nReturns a tuple of the negated version of self along with a boolean indicating whether an overflow\nhappened. If `self` is the minimum value (e.g., `i32::MIN` for values of type `i32`), then the\nminimum value will be returned again and `true` will be returned for an overflow happening.\n\n# Examples\n\nBasic usage:\n\n```\nassert_eq!(2" , stringify ! ($SelfT ), ".overflowing_neg(), (-2, false));\nassert_eq!(" , stringify ! ($SelfT ), "::MIN.overflowing_neg(), (" , stringify ! ($SelfT ), "::MIN, true));" , $EndFeature , "\n```" ), # [ inline ]# [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ allow ( unused_attributes )] pub const fn overflowing_neg ( self )-> ( Self , bool ){ if unlikely ! ( self == Self :: MIN ){( Self :: MIN , true )} else {(- self , false )}}} doc_comment ! { concat ! ( "Shifts self left by `rhs` bits.\n\nReturns a tuple of the shifted version of self along with a boolean indicating whether the shift\nvalue was larger than or equal to the number of bits. If the shift value is too large, then value is\nmasked (N-1) where N is the number of bits, and this value is then used to perform the shift.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(0x1" , stringify ! ($SelfT ), ".overflowing_shl(4), (0x10, false));\nassert_eq!(0x1i32.overflowing_shl(36), (0x10, true));" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn overflowing_shl ( self , rhs : u32 )-> ( Self , bool ){( self . wrapping_shl ( rhs ), ( rhs > ($BITS - 1 )))}} doc_comment ! { concat ! ( "Shifts self right by `rhs` bits.\n\nReturns a tuple of the shifted version of self along with a boolean indicating whether the shift\nvalue was larger than or equal to the number of bits. If the shift value is too large, then value is\nmasked (N-1) where N is the number of bits, and this value is then used to perform the shift.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(0x10" , stringify ! ($SelfT ), ".overflowing_shr(4), (0x1, false));\nassert_eq!(0x10i32.overflowing_shr(36), (0x1, true));" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn overflowing_shr ( self , rhs : u32 )-> ( Self , bool ){( self . wrapping_shr ( rhs ), ( rhs > ($BITS - 1 )))}} doc_comment ! { concat ! ( "Computes the absolute value of `self`.\n\nReturns a tuple of the absolute version of self along with a boolean indicating whether an overflow\nhappened. If self is the minimum value (e.g., " , stringify ! ($SelfT ), "::MIN for values of type\n " , stringify ! ($SelfT ), "), then the minimum value will be returned again and true will be returned\nfor an overflow happening.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(10" , stringify ! ($SelfT ), ".overflowing_abs(), (10, false));\nassert_eq!((-10" , stringify ! ($SelfT ), ").overflowing_abs(), (10, false));\nassert_eq!((" , stringify ! ($SelfT ), "::MIN).overflowing_abs(), (" , stringify ! ($SelfT ), "::MIN, true));" , $EndFeature , "\n```" ), # [ stable ( feature = "no_panic_abs" , since = "1.13.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ inline ] pub const fn overflowing_abs ( self )-> ( Self , bool ){( self . wrapping_abs (), self == Self :: MIN )}} doc_comment ! { concat ! ( "Raises self to the power of `exp`, using exponentiation by squaring.\n\nReturns a tuple of the exponentiation along with a bool indicating\nwhether an overflow happened.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(3" , stringify ! ($SelfT ), ".overflowing_pow(4), (81, false));\nassert_eq!(3i8.overflowing_pow(5), (-13, true));" , $EndFeature , "\n```" ), # [ stable ( feature = "no_panic_pow" , since = "1.34.0" )]# [ rustc_const_unstable ( feature = "const_int_pow" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn overflowing_pow ( self , mut exp : u32 )-> ( Self , bool ){ if exp == 0 { return ( 1 , false ); } let mut base = self ; let mut acc : Self = 1 ; let mut overflown = false ; let mut r ; while exp > 1 { if ( exp & 1 )== 1 { r = acc . overflowing_mul ( base ); acc = r . 0 ; overflown |= r . 1 ; } exp /= 2 ; r = base . overflowing_mul ( base ); base = r . 0 ; overflown |= r . 1 ; } r = acc . overflowing_mul ( base ); r . 1 |= overflown ; r }} doc_comment ! { concat ! ( "Raises self to the power of `exp`, using exponentiation by squaring.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let x: " , stringify ! ($SelfT ), " = 2; // or any other integer type\n\nassert_eq!(x.pow(5), 32);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_unstable ( feature = "const_int_pow" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ]# [ rustc_inherit_overflow_checks ] pub const fn pow ( self , mut exp : u32 )-> Self { if exp == 0 { return 1 ; } let mut base = self ; let mut acc = 1 ; while exp > 1 { if ( exp & 1 )== 1 { acc = acc * base ; } exp /= 2 ; base = base * base ; } acc * base }} doc_comment ! { concat ! ( "Calculates the quotient of Euclidean division of `self` by `rhs`.\n\nThis computes the integer `n` such that `self = n * rhs + self.rem_euclid(rhs)`,\nwith `0 <= self.rem_euclid(rhs) < rhs`.\n\nIn other words, the result is `self / rhs` rounded to the integer `n`\nsuch that `self >= n * rhs`.\nIf `self > 0`, this is equal to round towards zero (the default in Rust);\nif `self < 0`, this is equal to round towards +/- infinity.\n\n# Panics\n\nThis function will panic if `rhs` is 0 or the division results in overflow.\n\n# Examples\n\nBasic usage:\n\n```\nlet a: " , stringify ! ($SelfT ), " = 7; // or any other integer type\nlet b = 4;\n\nassert_eq!(a.div_euclid(b), 1); // 7 >= 4 * 1\nassert_eq!(a.div_euclid(-b), -1); // 7 >= -4 * -1\nassert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2\nassert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2\n```" ), # [ stable ( feature = "euclidean_division" , since = "1.38.0" )]# [ rustc_const_unstable ( feature = "const_euclidean_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ]# [ rustc_inherit_overflow_checks ] pub const fn div_euclid ( self , rhs : Self )-> Self { let q = self / rhs ; if self % rhs < 0 { return if rhs > 0 { q - 1 } else { q + 1 }} q }} doc_comment ! { concat ! ( "Calculates the least nonnegative remainder of `self (mod rhs)`.\n\nThis is done as if by the Euclidean division algorithm -- given\n`r = self.rem_euclid(rhs)`, `self = rhs * self.div_euclid(rhs) + r`, and\n`0 <= r < abs(rhs)`.\n\n# Panics\n\nThis function will panic if `rhs` is 0 or the division results in overflow.\n\n# Examples\n\nBasic usage:\n\n```\nlet a: " , stringify ! ($SelfT ), " = 7; // or any other integer type\nlet b = 4;\n\nassert_eq!(a.rem_euclid(b), 3);\nassert_eq!((-a).rem_euclid(b), 1);\nassert_eq!(a.rem_euclid(-b), 3);\nassert_eq!((-a).rem_euclid(-b), 1);\n```" ), # [ stable ( feature = "euclidean_division" , since = "1.38.0" )]# [ rustc_const_unstable ( feature = "const_euclidean_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ]# [ rustc_inherit_overflow_checks ] pub const fn rem_euclid ( self , rhs : Self )-> Self { let r = self % rhs ; if r < 0 { if rhs < 0 { r - rhs } else { r + rhs }} else { r }}} doc_comment ! { concat ! ( "Computes the absolute value of `self`.\n\n# Overflow behavior\n\nThe absolute value of `" , stringify ! ($SelfT ), "::MIN` cannot be represented as an\n`" , stringify ! ($SelfT ), "`, and attempting to calculate it will cause an overflow. This means that\ncode in debug mode will trigger a panic on this case and optimized code will return `" , stringify ! ($SelfT ), "::MIN` without a panic.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(10" , stringify ! ($SelfT ), ".abs(), 10);\nassert_eq!((-10" , stringify ! ($SelfT ), ").abs(), 10);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ allow ( unused_attributes )]# [ inline ]# [ rustc_inherit_overflow_checks ] pub const fn abs ( self )-> Self { if self . is_negative (){- self } else { self }}} doc_comment ! { concat ! ( "Returns a number representing sign of `self`.\n\n - `0` if the number is zero\n - `1` if the number is positive\n - `-1` if the number is negative\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(10" , stringify ! ($SelfT ), ".signum(), 1);\nassert_eq!(0" , stringify ! ($SelfT ), ".signum(), 0);\nassert_eq!((-10" , stringify ! ($SelfT ), ").signum(), -1);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_sign" , since = "1.47.0" )]# [ inline ] pub const fn signum ( self )-> Self { match self { n if n > 0 => 1 , 0 => 0 , _ =>- 1 , }}} doc_comment ! { concat ! ( "Returns `true` if `self` is positive and `false` if the number is zero or\nnegative.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert!(10" , stringify ! ($SelfT ), ".is_positive());\nassert!(!(-10" , stringify ! ($SelfT ), ").is_positive());" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ inline ] pub const fn is_positive ( self )-> bool { self > 0 }} doc_comment ! { concat ! ( "Returns `true` if `self` is negative and `false` if the number is zero or\npositive.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert!((-10" , stringify ! ($SelfT ), ").is_negative());\nassert!(!10" , stringify ! ($SelfT ), ".is_negative());" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_int_methods" , since = "1.32.0" )]# [ inline ] pub const fn is_negative ( self )-> bool { self < 0 }} doc_comment ! { concat ! ( "Return the memory representation of this integer as a byte array in\nbig-endian (network) byte order.\n" , $to_xe_bytes_doc , "\n# Examples\n\n```\nlet bytes = " , $swap_op , stringify ! ($SelfT ), ".to_be_bytes();\nassert_eq!(bytes, " , $be_bytes , ");\n```" ), # [ stable ( feature = "int_to_from_bytes" , since = "1.32.0" )]# [ rustc_const_stable ( feature = "const_int_conversion" , since = "1.44.0" )]# [ inline ] pub const fn to_be_bytes ( self )-> [ u8 ; mem :: size_of ::< Self > ()]{ self . to_be (). to_ne_bytes ()}} doc_comment ! { concat ! ( "Return the memory representation of this integer as a byte array in\nlittle-endian byte order.\n" , $to_xe_bytes_doc , "\n# Examples\n\n```\nlet bytes = " , $swap_op , stringify ! ($SelfT ), ".to_le_bytes();\nassert_eq!(bytes, " , $le_bytes , ");\n```" ), # [ stable ( feature = "int_to_from_bytes" , since = "1.32.0" )]# [ rustc_const_stable ( feature = "const_int_conversion" , since = "1.44.0" )]# [ inline ] pub const fn to_le_bytes ( self )-> [ u8 ; mem :: size_of ::< Self > ()]{ self . to_le (). to_ne_bytes ()}} doc_comment ! { concat ! ( "\nReturn the memory representation of this integer as a byte array in\nnative byte order.\n\nAs the target platform's native endianness is used, portable code\nshould use [`to_be_bytes`] or [`to_le_bytes`], as appropriate,\ninstead.\n" , $to_xe_bytes_doc , "\n[`to_be_bytes`]: #method.to_be_bytes\n[`to_le_bytes`]: #method.to_le_bytes\n\n# Examples\n\n```\nlet bytes = " , $swap_op , stringify ! ($SelfT ), ".to_ne_bytes();\nassert_eq!(\n bytes,\n if cfg!(target_endian = \"big\") {\n " , $be_bytes , "\n } else {\n " , $le_bytes , "\n }\n);\n```" ), # [ stable ( feature = "int_to_from_bytes" , since = "1.32.0" )]# [ rustc_const_stable ( feature = "const_int_conversion" , since = "1.44.0" )]# [ cfg_attr ( not ( bootstrap ), rustc_allow_const_fn_unstable ( const_fn_transmute ))]# [ cfg_attr ( bootstrap , allow_internal_unstable ( const_fn_transmute ))]# [ inline ] pub const fn to_ne_bytes ( self )-> [ u8 ; mem :: size_of ::< Self > ()]{ unsafe { mem :: transmute ( self )}}} doc_comment ! { concat ! ( "\nReturn the memory representation of this integer as a byte array in\nnative byte order.\n\n[`to_ne_bytes`] should be preferred over this whenever possible.\n\n[`to_ne_bytes`]: #method.to_ne_bytes\n" , "\n# Examples\n\n```\n#![feature(num_as_ne_bytes)]\nlet num = " , $swap_op , stringify ! ($SelfT ), ";\nlet bytes = num.as_ne_bytes();\nassert_eq!(\n bytes,\n if cfg!(target_endian = \"big\") {\n &" , $be_bytes , "\n } else {\n &" , $le_bytes , "\n }\n);\n```" ), # [ unstable ( feature = "num_as_ne_bytes" , issue = "76976" )]# [ inline ] pub fn as_ne_bytes (& self )-> & [ u8 ; mem :: size_of ::< Self > ()]{ unsafe {&* ( self as * const Self as * const _)}}} doc_comment ! { concat ! ( "Create an integer value from its representation as a byte array in\nbig endian.\n" , $from_xe_bytes_doc , "\n# Examples\n\n```\nlet value = " , stringify ! ($SelfT ), "::from_be_bytes(" , $be_bytes , ");\nassert_eq!(value, " , $swap_op , ");\n```\n\nWhen starting from a slice rather than an array, fallible conversion APIs can be used:\n\n```\nuse std::convert::TryInto;\n\nfn read_be_" , stringify ! ($SelfT ), "(input: &mut &[u8]) -> " , stringify ! ($SelfT ), " {\n let (int_bytes, rest) = input.split_at(std::mem::size_of::<" , stringify ! ($SelfT ), ">());\n *input = rest;\n " , stringify ! ($SelfT ), "::from_be_bytes(int_bytes.try_into().unwrap())\n}\n```" ), # [ stable ( feature = "int_to_from_bytes" , since = "1.32.0" )]# [ rustc_const_stable ( feature = "const_int_conversion" , since = "1.44.0" )]# [ inline ] pub const fn from_be_bytes ( bytes : [ u8 ; mem :: size_of ::< Self > ()])-> Self { Self :: from_be ( Self :: from_ne_bytes ( bytes ))}} doc_comment ! { concat ! ( "\nCreate an integer value from its representation as a byte array in\nlittle endian.\n" , $from_xe_bytes_doc , "\n# Examples\n\n```\nlet value = " , stringify ! ($SelfT ), "::from_le_bytes(" , $le_bytes , ");\nassert_eq!(value, " , $swap_op , ");\n```\n\nWhen starting from a slice rather than an array, fallible conversion APIs can be used:\n\n```\nuse std::convert::TryInto;\n\nfn read_le_" , stringify ! ($SelfT ), "(input: &mut &[u8]) -> " , stringify ! ($SelfT ), " {\n let (int_bytes, rest) = input.split_at(std::mem::size_of::<" , stringify ! ($SelfT ), ">());\n *input = rest;\n " , stringify ! ($SelfT ), "::from_le_bytes(int_bytes.try_into().unwrap())\n}\n```" ), # [ stable ( feature = "int_to_from_bytes" , since = "1.32.0" )]# [ rustc_const_stable ( feature = "const_int_conversion" , since = "1.44.0" )]# [ inline ] pub const fn from_le_bytes ( bytes : [ u8 ; mem :: size_of ::< Self > ()])-> Self { Self :: from_le ( Self :: from_ne_bytes ( bytes ))}} doc_comment ! { concat ! ( "Create an integer value from its memory representation as a byte\narray in native endianness.\n\nAs the target platform's native endianness is used, portable code\nlikely wants to use [`from_be_bytes`] or [`from_le_bytes`], as\nappropriate instead.\n\n[`from_be_bytes`]: #method.from_be_bytes\n[`from_le_bytes`]: #method.from_le_bytes\n" , $from_xe_bytes_doc , "\n# Examples\n\n```\nlet value = " , stringify ! ($SelfT ), "::from_ne_bytes(if cfg!(target_endian = \"big\") {\n " , $be_bytes , "\n} else {\n " , $le_bytes , "\n});\nassert_eq!(value, " , $swap_op , ");\n```\n\nWhen starting from a slice rather than an array, fallible conversion APIs can be used:\n\n```\nuse std::convert::TryInto;\n\nfn read_ne_" , stringify ! ($SelfT ), "(input: &mut &[u8]) -> " , stringify ! ($SelfT ), " {\n let (int_bytes, rest) = input.split_at(std::mem::size_of::<" , stringify ! ($SelfT ), ">());\n *input = rest;\n " , stringify ! ($SelfT ), "::from_ne_bytes(int_bytes.try_into().unwrap())\n}\n```" ), # [ stable ( feature = "int_to_from_bytes" , since = "1.32.0" )]# [ rustc_const_stable ( feature = "const_int_conversion" , since = "1.44.0" )]# [ cfg_attr ( not ( bootstrap ), rustc_allow_const_fn_unstable ( const_fn_transmute ))]# [ cfg_attr ( bootstrap , allow_internal_unstable ( const_fn_transmute ))]# [ inline ] pub const fn from_ne_bytes ( bytes : [ u8 ; mem :: size_of ::< Self > ()])-> Self { unsafe { mem :: transmute ( bytes )}}} doc_comment ! { concat ! ( "**This method is soft-deprecated.**\n\nAlthough using it won’t cause a compilation warning,\nnew code should use [`" , stringify ! ($SelfT ), "::MIN" , "`](#associatedconstant.MIN) instead.\n\nReturns the smallest value that can be represented by this integer type." ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ inline ( always )]# [ rustc_promotable ]# [ rustc_const_stable ( feature = "const_min_value" , since = "1.32.0" )] pub const fn min_value ()-> Self { Self :: MIN }} doc_comment ! { concat ! ( "**This method is soft-deprecated.**\n\nAlthough using it won’t cause a compilation warning,\nnew code should use [`" , stringify ! ($SelfT ), "::MAX" , "`](#associatedconstant.MAX) instead.\n\nReturns the largest value that can be represented by this integer type." ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ inline ( always )]# [ rustc_promotable ]# [ rustc_const_stable ( feature = "const_max_value" , since = "1.32.0" )] pub const fn max_value ()-> Self { Self :: MAX }}}} -macro_rules! __ra_macro_fixture429 {($x : expr , $($tt : tt )*)=>{# [ doc = $x ]$($tt )* }; } -macro_rules! __ra_macro_fixture430 {()=>{ "\n\n**Note**: This function returns an array of length 2, 4 or 8 bytes\ndepending on the target pointer size.\n\n" }; } -macro_rules! __ra_macro_fixture431 {()=>{ "\n\n**Note**: This function takes an array of length 2, 4 or 8 bytes\ndepending on the target pointer size.\n\n" }; } -macro_rules! __ra_macro_fixture432 {($SelfT : ty , $ActualT : ty , $BITS : expr , $MaxV : expr , $Feature : expr , $EndFeature : expr , $rot : expr , $rot_op : expr , $rot_result : expr , $swap_op : expr , $swapped : expr , $reversed : expr , $le_bytes : expr , $be_bytes : expr , $to_xe_bytes_doc : expr , $from_xe_bytes_doc : expr )=>{ doc_comment ! { concat ! ( "The smallest value that can be represented by this integer type.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(" , stringify ! ($SelfT ), "::MIN, 0);" , $EndFeature , "\n```" ), # [ stable ( feature = "assoc_int_consts" , since = "1.43.0" )] pub const MIN : Self = 0 ; } doc_comment ! { concat ! ( "The largest value that can be represented by this integer type.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(" , stringify ! ($SelfT ), "::MAX, " , stringify ! ($MaxV ), ");" , $EndFeature , "\n```" ), # [ stable ( feature = "assoc_int_consts" , since = "1.43.0" )] pub const MAX : Self = ! 0 ; } doc_comment ! { concat ! ( "The size of this integer type in bits.\n\n# Examples\n\n```\n" , $Feature , "#![feature(int_bits_const)]\nassert_eq!(" , stringify ! ($SelfT ), "::BITS, " , stringify ! ($BITS ), ");" , $EndFeature , "\n```" ), # [ unstable ( feature = "int_bits_const" , issue = "76904" )] pub const BITS : u32 = $BITS ; } doc_comment ! { concat ! ( "Converts a string slice in a given base to an integer.\n\nThe string is expected to be an optional `+` sign\nfollowed by digits.\nLeading and trailing whitespace represent an error.\nDigits are a subset of these characters, depending on `radix`:\n\n* `0-9`\n* `a-z`\n* `A-Z`\n\n# Panics\n\nThis function panics if `radix` is not in the range from 2 to 36.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(" , stringify ! ($SelfT ), "::from_str_radix(\"A\", 16), Ok(10));" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )] pub fn from_str_radix ( src : & str , radix : u32 )-> Result < Self , ParseIntError > { from_str_radix ( src , radix )}} doc_comment ! { concat ! ( "Returns the number of ones in the binary representation of `self`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = 0b01001100" , stringify ! ($SelfT ), ";\n\nassert_eq!(n.count_ones(), 3);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_math" , since = "1.32.0" )]# [ inline ] pub const fn count_ones ( self )-> u32 { intrinsics :: ctpop ( self as $ActualT ) as u32 }} doc_comment ! { concat ! ( "Returns the number of zeros in the binary representation of `self`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(" , stringify ! ($SelfT ), "::MAX.count_zeros(), 0);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_math" , since = "1.32.0" )]# [ inline ] pub const fn count_zeros ( self )-> u32 {(! self ). count_ones ()}} doc_comment ! { concat ! ( "Returns the number of leading zeros in the binary representation of `self`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = " , stringify ! ($SelfT ), "::MAX >> 2;\n\nassert_eq!(n.leading_zeros(), 2);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_math" , since = "1.32.0" )]# [ inline ] pub const fn leading_zeros ( self )-> u32 { intrinsics :: ctlz ( self as $ActualT ) as u32 }} doc_comment ! { concat ! ( "Returns the number of trailing zeros in the binary representation\nof `self`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = 0b0101000" , stringify ! ($SelfT ), ";\n\nassert_eq!(n.trailing_zeros(), 3);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_math" , since = "1.32.0" )]# [ inline ] pub const fn trailing_zeros ( self )-> u32 { intrinsics :: cttz ( self ) as u32 }} doc_comment ! { concat ! ( "Returns the number of leading ones in the binary representation of `self`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = !(" , stringify ! ($SelfT ), "::MAX >> 2);\n\nassert_eq!(n.leading_ones(), 2);" , $EndFeature , "\n```" ), # [ stable ( feature = "leading_trailing_ones" , since = "1.46.0" )]# [ rustc_const_stable ( feature = "leading_trailing_ones" , since = "1.46.0" )]# [ inline ] pub const fn leading_ones ( self )-> u32 {(! self ). leading_zeros ()}} doc_comment ! { concat ! ( "Returns the number of trailing ones in the binary representation\nof `self`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = 0b1010111" , stringify ! ($SelfT ), ";\n\nassert_eq!(n.trailing_ones(), 3);" , $EndFeature , "\n```" ), # [ stable ( feature = "leading_trailing_ones" , since = "1.46.0" )]# [ rustc_const_stable ( feature = "leading_trailing_ones" , since = "1.46.0" )]# [ inline ] pub const fn trailing_ones ( self )-> u32 {(! self ). trailing_zeros ()}} doc_comment ! { concat ! ( "Shifts the bits to the left by a specified amount, `n`,\nwrapping the truncated bits to the end of the resulting integer.\n\nPlease note this isn't the same operation as the `<<` shifting operator!\n\n# Examples\n\nBasic usage:\n\n```\nlet n = " , $rot_op , stringify ! ($SelfT ), ";\nlet m = " , $rot_result , ";\n\nassert_eq!(n.rotate_left(" , $rot , "), m);\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_math" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn rotate_left ( self , n : u32 )-> Self { intrinsics :: rotate_left ( self , n as $SelfT )}} doc_comment ! { concat ! ( "Shifts the bits to the right by a specified amount, `n`,\nwrapping the truncated bits to the beginning of the resulting\ninteger.\n\nPlease note this isn't the same operation as the `>>` shifting operator!\n\n# Examples\n\nBasic usage:\n\n```\nlet n = " , $rot_result , stringify ! ($SelfT ), ";\nlet m = " , $rot_op , ";\n\nassert_eq!(n.rotate_right(" , $rot , "), m);\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_math" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn rotate_right ( self , n : u32 )-> Self { intrinsics :: rotate_right ( self , n as $SelfT )}} doc_comment ! { concat ! ( "\nReverses the byte order of the integer.\n\n# Examples\n\nBasic usage:\n\n```\nlet n = " , $swap_op , stringify ! ($SelfT ), ";\nlet m = n.swap_bytes();\n\nassert_eq!(m, " , $swapped , ");\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_math" , since = "1.32.0" )]# [ inline ] pub const fn swap_bytes ( self )-> Self { intrinsics :: bswap ( self as $ActualT ) as Self }} doc_comment ! { concat ! ( "Reverses the order of bits in the integer. The least significant bit becomes the most significant bit,\n second least-significant bit becomes second most-significant bit, etc.\n\n# Examples\n\nBasic usage:\n\n```\nlet n = " , $swap_op , stringify ! ($SelfT ), ";\nlet m = n.reverse_bits();\n\nassert_eq!(m, " , $reversed , ");\nassert_eq!(0, 0" , stringify ! ($SelfT ), ".reverse_bits());\n```" ), # [ stable ( feature = "reverse_bits" , since = "1.37.0" )]# [ rustc_const_stable ( feature = "const_math" , since = "1.32.0" )]# [ inline ]# [ must_use ] pub const fn reverse_bits ( self )-> Self { intrinsics :: bitreverse ( self as $ActualT ) as Self }} doc_comment ! { concat ! ( "Converts an integer from big endian to the target's endianness.\n\nOn big endian this is a no-op. On little endian the bytes are\nswapped.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = 0x1A" , stringify ! ($SelfT ), ";\n\nif cfg!(target_endian = \"big\") {\n assert_eq!(" , stringify ! ($SelfT ), "::from_be(n), n)\n} else {\n assert_eq!(" , stringify ! ($SelfT ), "::from_be(n), n.swap_bytes())\n}" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_math" , since = "1.32.0" )]# [ inline ] pub const fn from_be ( x : Self )-> Self {# [ cfg ( target_endian = "big" )]{ x }# [ cfg ( not ( target_endian = "big" ))]{ x . swap_bytes ()}}} doc_comment ! { concat ! ( "Converts an integer from little endian to the target's endianness.\n\nOn little endian this is a no-op. On big endian the bytes are\nswapped.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = 0x1A" , stringify ! ($SelfT ), ";\n\nif cfg!(target_endian = \"little\") {\n assert_eq!(" , stringify ! ($SelfT ), "::from_le(n), n)\n} else {\n assert_eq!(" , stringify ! ($SelfT ), "::from_le(n), n.swap_bytes())\n}" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_math" , since = "1.32.0" )]# [ inline ] pub const fn from_le ( x : Self )-> Self {# [ cfg ( target_endian = "little" )]{ x }# [ cfg ( not ( target_endian = "little" ))]{ x . swap_bytes ()}}} doc_comment ! { concat ! ( "Converts `self` to big endian from the target's endianness.\n\nOn big endian this is a no-op. On little endian the bytes are\nswapped.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = 0x1A" , stringify ! ($SelfT ), ";\n\nif cfg!(target_endian = \"big\") {\n assert_eq!(n.to_be(), n)\n} else {\n assert_eq!(n.to_be(), n.swap_bytes())\n}" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_math" , since = "1.32.0" )]# [ inline ] pub const fn to_be ( self )-> Self {# [ cfg ( target_endian = "big" )]{ self }# [ cfg ( not ( target_endian = "big" ))]{ self . swap_bytes ()}}} doc_comment ! { concat ! ( "Converts `self` to little endian from the target's endianness.\n\nOn little endian this is a no-op. On big endian the bytes are\nswapped.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "let n = 0x1A" , stringify ! ($SelfT ), ";\n\nif cfg!(target_endian = \"little\") {\n assert_eq!(n.to_le(), n)\n} else {\n assert_eq!(n.to_le(), n.swap_bytes())\n}" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_math" , since = "1.32.0" )]# [ inline ] pub const fn to_le ( self )-> Self {# [ cfg ( target_endian = "little" )]{ self }# [ cfg ( not ( target_endian = "little" ))]{ self . swap_bytes ()}}} doc_comment ! { concat ! ( "Checked integer addition. Computes `self + rhs`, returning `None`\nif overflow occurred.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!((" , stringify ! ($SelfT ), "::MAX - 2).checked_add(1), " , "Some(" , stringify ! ($SelfT ), "::MAX - 1));\nassert_eq!((" , stringify ! ($SelfT ), "::MAX - 2).checked_add(3), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_checked_int_methods" , since = "1.47.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_add ( self , rhs : Self )-> Option < Self > { let ( a , b )= self . overflowing_add ( rhs ); if unlikely ! ( b ){ None } else { Some ( a )}}} doc_comment ! { concat ! ( "Unchecked integer addition. Computes `self + rhs`, assuming overflow\ncannot occur. This results in undefined behavior when `self + rhs > " , stringify ! ($SelfT ), "::MAX` or `self + rhs < " , stringify ! ($SelfT ), "::MIN`." ), # [ unstable ( feature = "unchecked_math" , reason = "niche optimization path" , issue = "none" , )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub unsafe fn unchecked_add ( self , rhs : Self )-> Self { unsafe { intrinsics :: unchecked_add ( self , rhs )}}} doc_comment ! { concat ! ( "Checked integer subtraction. Computes `self - rhs`, returning\n`None` if overflow occurred.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(1" , stringify ! ($SelfT ), ".checked_sub(1), Some(0));\nassert_eq!(0" , stringify ! ($SelfT ), ".checked_sub(1), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_checked_int_methods" , since = "1.47.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_sub ( self , rhs : Self )-> Option < Self > { let ( a , b )= self . overflowing_sub ( rhs ); if unlikely ! ( b ){ None } else { Some ( a )}}} doc_comment ! { concat ! ( "Unchecked integer subtraction. Computes `self - rhs`, assuming overflow\ncannot occur. This results in undefined behavior when `self - rhs > " , stringify ! ($SelfT ), "::MAX` or `self - rhs < " , stringify ! ($SelfT ), "::MIN`." ), # [ unstable ( feature = "unchecked_math" , reason = "niche optimization path" , issue = "none" , )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub unsafe fn unchecked_sub ( self , rhs : Self )-> Self { unsafe { intrinsics :: unchecked_sub ( self , rhs )}}} doc_comment ! { concat ! ( "Checked integer multiplication. Computes `self * rhs`, returning\n`None` if overflow occurred.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(5" , stringify ! ($SelfT ), ".checked_mul(1), Some(5));\nassert_eq!(" , stringify ! ($SelfT ), "::MAX.checked_mul(2), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_checked_int_methods" , since = "1.47.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_mul ( self , rhs : Self )-> Option < Self > { let ( a , b )= self . overflowing_mul ( rhs ); if unlikely ! ( b ){ None } else { Some ( a )}}} doc_comment ! { concat ! ( "Unchecked integer multiplication. Computes `self * rhs`, assuming overflow\ncannot occur. This results in undefined behavior when `self * rhs > " , stringify ! ($SelfT ), "::MAX` or `self * rhs < " , stringify ! ($SelfT ), "::MIN`." ), # [ unstable ( feature = "unchecked_math" , reason = "niche optimization path" , issue = "none" , )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub unsafe fn unchecked_mul ( self , rhs : Self )-> Self { unsafe { intrinsics :: unchecked_mul ( self , rhs )}}} doc_comment ! { concat ! ( "Checked integer division. Computes `self / rhs`, returning `None`\nif `rhs == 0`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(128" , stringify ! ($SelfT ), ".checked_div(2), Some(64));\nassert_eq!(1" , stringify ! ($SelfT ), ".checked_div(0), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_unstable ( feature = "const_checked_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_div ( self , rhs : Self )-> Option < Self > { if unlikely ! ( rhs == 0 ){ None } else { Some ( unsafe { intrinsics :: unchecked_div ( self , rhs )})}}} doc_comment ! { concat ! ( "Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None`\nif `rhs == 0`.\n\n# Examples\n\nBasic usage:\n\n```\nassert_eq!(128" , stringify ! ($SelfT ), ".checked_div_euclid(2), Some(64));\nassert_eq!(1" , stringify ! ($SelfT ), ".checked_div_euclid(0), None);\n```" ), # [ stable ( feature = "euclidean_division" , since = "1.38.0" )]# [ rustc_const_unstable ( feature = "const_euclidean_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_div_euclid ( self , rhs : Self )-> Option < Self > { if unlikely ! ( rhs == 0 ){ None } else { Some ( self . div_euclid ( rhs ))}}} doc_comment ! { concat ! ( "Checked integer remainder. Computes `self % rhs`, returning `None`\nif `rhs == 0`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(5" , stringify ! ($SelfT ), ".checked_rem(2), Some(1));\nassert_eq!(5" , stringify ! ($SelfT ), ".checked_rem(0), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_unstable ( feature = "const_checked_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_rem ( self , rhs : Self )-> Option < Self > { if unlikely ! ( rhs == 0 ){ None } else { Some ( unsafe { intrinsics :: unchecked_rem ( self , rhs )})}}} doc_comment ! { concat ! ( "Checked Euclidean modulo. Computes `self.rem_euclid(rhs)`, returning `None`\nif `rhs == 0`.\n\n# Examples\n\nBasic usage:\n\n```\nassert_eq!(5" , stringify ! ($SelfT ), ".checked_rem_euclid(2), Some(1));\nassert_eq!(5" , stringify ! ($SelfT ), ".checked_rem_euclid(0), None);\n```" ), # [ stable ( feature = "euclidean_division" , since = "1.38.0" )]# [ rustc_const_unstable ( feature = "const_euclidean_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_rem_euclid ( self , rhs : Self )-> Option < Self > { if unlikely ! ( rhs == 0 ){ None } else { Some ( self . rem_euclid ( rhs ))}}} doc_comment ! { concat ! ( "Checked negation. Computes `-self`, returning `None` unless `self ==\n0`.\n\nNote that negating any positive integer will overflow.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(0" , stringify ! ($SelfT ), ".checked_neg(), Some(0));\nassert_eq!(1" , stringify ! ($SelfT ), ".checked_neg(), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_checked_int_methods" , since = "1.47.0" )]# [ inline ] pub const fn checked_neg ( self )-> Option < Self > { let ( a , b )= self . overflowing_neg (); if unlikely ! ( b ){ None } else { Some ( a )}}} doc_comment ! { concat ! ( "Checked shift left. Computes `self << rhs`, returning `None`\nif `rhs` is larger than or equal to the number of bits in `self`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(0x1" , stringify ! ($SelfT ), ".checked_shl(4), Some(0x10));\nassert_eq!(0x10" , stringify ! ($SelfT ), ".checked_shl(129), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_checked_int_methods" , since = "1.47.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_shl ( self , rhs : u32 )-> Option < Self > { let ( a , b )= self . overflowing_shl ( rhs ); if unlikely ! ( b ){ None } else { Some ( a )}}} doc_comment ! { concat ! ( "Checked shift right. Computes `self >> rhs`, returning `None`\nif `rhs` is larger than or equal to the number of bits in `self`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(0x10" , stringify ! ($SelfT ), ".checked_shr(4), Some(0x1));\nassert_eq!(0x10" , stringify ! ($SelfT ), ".checked_shr(129), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_checked_int_methods" , since = "1.47.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_shr ( self , rhs : u32 )-> Option < Self > { let ( a , b )= self . overflowing_shr ( rhs ); if unlikely ! ( b ){ None } else { Some ( a )}}} doc_comment ! { concat ! ( "Checked exponentiation. Computes `self.pow(exp)`, returning `None` if\noverflow occurred.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(2" , stringify ! ($SelfT ), ".checked_pow(5), Some(32));\nassert_eq!(" , stringify ! ($SelfT ), "::MAX.checked_pow(2), None);" , $EndFeature , "\n```" ), # [ stable ( feature = "no_panic_pow" , since = "1.34.0" )]# [ rustc_const_unstable ( feature = "const_int_pow" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn checked_pow ( self , mut exp : u32 )-> Option < Self > { if exp == 0 { return Some ( 1 ); } let mut base = self ; let mut acc : Self = 1 ; while exp > 1 { if ( exp & 1 )== 1 { acc = try_opt ! ( acc . checked_mul ( base )); } exp /= 2 ; base = try_opt ! ( base . checked_mul ( base )); } Some ( try_opt ! ( acc . checked_mul ( base )))}} doc_comment ! { concat ! ( "Saturating integer addition. Computes `self + rhs`, saturating at\nthe numeric bounds instead of overflowing.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(100" , stringify ! ($SelfT ), ".saturating_add(1), 101);\nassert_eq!(" , stringify ! ($SelfT ), "::MAX.saturating_add(127), " , stringify ! ($SelfT ), "::MAX);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ rustc_const_stable ( feature = "const_saturating_int_methods" , since = "1.47.0" )]# [ inline ] pub const fn saturating_add ( self , rhs : Self )-> Self { intrinsics :: saturating_add ( self , rhs )}} doc_comment ! { concat ! ( "Saturating integer subtraction. Computes `self - rhs`, saturating\nat the numeric bounds instead of overflowing.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(100" , stringify ! ($SelfT ), ".saturating_sub(27), 73);\nassert_eq!(13" , stringify ! ($SelfT ), ".saturating_sub(127), 0);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ rustc_const_stable ( feature = "const_saturating_int_methods" , since = "1.47.0" )]# [ inline ] pub const fn saturating_sub ( self , rhs : Self )-> Self { intrinsics :: saturating_sub ( self , rhs )}} doc_comment ! { concat ! ( "Saturating integer multiplication. Computes `self * rhs`,\nsaturating at the numeric bounds instead of overflowing.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "\nassert_eq!(2" , stringify ! ($SelfT ), ".saturating_mul(10), 20);\nassert_eq!((" , stringify ! ($SelfT ), "::MAX).saturating_mul(10), " , stringify ! ($SelfT ), "::MAX);" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_saturating_int_methods" , since = "1.47.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn saturating_mul ( self , rhs : Self )-> Self { match self . checked_mul ( rhs ){ Some ( x )=> x , None => Self :: MAX , }}} doc_comment ! { concat ! ( "Saturating integer exponentiation. Computes `self.pow(exp)`,\nsaturating at the numeric bounds instead of overflowing.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "\nassert_eq!(4" , stringify ! ($SelfT ), ".saturating_pow(3), 64);\nassert_eq!(" , stringify ! ($SelfT ), "::MAX.saturating_pow(2), " , stringify ! ($SelfT ), "::MAX);" , $EndFeature , "\n```" ), # [ stable ( feature = "no_panic_pow" , since = "1.34.0" )]# [ rustc_const_unstable ( feature = "const_int_pow" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn saturating_pow ( self , exp : u32 )-> Self { match self . checked_pow ( exp ){ Some ( x )=> x , None => Self :: MAX , }}} doc_comment ! { concat ! ( "Wrapping (modular) addition. Computes `self + rhs`,\nwrapping around at the boundary of the type.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(200" , stringify ! ($SelfT ), ".wrapping_add(55), 255);\nassert_eq!(200" , stringify ! ($SelfT ), ".wrapping_add(" , stringify ! ($SelfT ), "::MAX), 199);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_wrapping_math" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_add ( self , rhs : Self )-> Self { intrinsics :: wrapping_add ( self , rhs )}} doc_comment ! { concat ! ( "Wrapping (modular) subtraction. Computes `self - rhs`,\nwrapping around at the boundary of the type.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(100" , stringify ! ($SelfT ), ".wrapping_sub(100), 0);\nassert_eq!(100" , stringify ! ($SelfT ), ".wrapping_sub(" , stringify ! ($SelfT ), "::MAX), 101);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_wrapping_math" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_sub ( self , rhs : Self )-> Self { intrinsics :: wrapping_sub ( self , rhs )}}# [ doc = " Wrapping (modular) multiplication. Computes `self *" ]# [ doc = " rhs`, wrapping around at the boundary of the type." ]# [ doc = "" ]# [ doc = " # Examples" ]# [ doc = "" ]# [ doc = " Basic usage:" ]# [ doc = "" ]# [ doc = " Please note that this example is shared between integer types." ]# [ doc = " Which explains why `u8` is used here." ]# [ doc = "" ]# [ doc = " ```" ]# [ doc = " assert_eq!(10u8.wrapping_mul(12), 120);" ]# [ doc = " assert_eq!(25u8.wrapping_mul(12), 44);" ]# [ doc = " ```" ]# [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_wrapping_math" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_mul ( self , rhs : Self )-> Self { intrinsics :: wrapping_mul ( self , rhs )} doc_comment ! { concat ! ( "Wrapping (modular) division. Computes `self / rhs`.\nWrapped division on unsigned types is just normal division.\nThere's no way wrapping could ever happen.\nThis function exists, so that all operations\nare accounted for in the wrapping operations.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(100" , stringify ! ($SelfT ), ".wrapping_div(10), 10);" , $EndFeature , "\n```" ), # [ stable ( feature = "num_wrapping" , since = "1.2.0" )]# [ rustc_const_unstable ( feature = "const_wrapping_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_div ( self , rhs : Self )-> Self { self / rhs }} doc_comment ! { concat ! ( "Wrapping Euclidean division. Computes `self.div_euclid(rhs)`.\nWrapped division on unsigned types is just normal division.\nThere's no way wrapping could ever happen.\nThis function exists, so that all operations\nare accounted for in the wrapping operations.\nSince, for the positive integers, all common\ndefinitions of division are equal, this\nis exactly equal to `self.wrapping_div(rhs)`.\n\n# Examples\n\nBasic usage:\n\n```\nassert_eq!(100" , stringify ! ($SelfT ), ".wrapping_div_euclid(10), 10);\n```" ), # [ stable ( feature = "euclidean_division" , since = "1.38.0" )]# [ rustc_const_unstable ( feature = "const_euclidean_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_div_euclid ( self , rhs : Self )-> Self { self / rhs }} doc_comment ! { concat ! ( "Wrapping (modular) remainder. Computes `self % rhs`.\nWrapped remainder calculation on unsigned types is\njust the regular remainder calculation.\nThere's no way wrapping could ever happen.\nThis function exists, so that all operations\nare accounted for in the wrapping operations.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(100" , stringify ! ($SelfT ), ".wrapping_rem(10), 0);" , $EndFeature , "\n```" ), # [ stable ( feature = "num_wrapping" , since = "1.2.0" )]# [ rustc_const_unstable ( feature = "const_wrapping_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_rem ( self , rhs : Self )-> Self { self % rhs }} doc_comment ! { concat ! ( "Wrapping Euclidean modulo. Computes `self.rem_euclid(rhs)`.\nWrapped modulo calculation on unsigned types is\njust the regular remainder calculation.\nThere's no way wrapping could ever happen.\nThis function exists, so that all operations\nare accounted for in the wrapping operations.\nSince, for the positive integers, all common\ndefinitions of division are equal, this\nis exactly equal to `self.wrapping_rem(rhs)`.\n\n# Examples\n\nBasic usage:\n\n```\nassert_eq!(100" , stringify ! ($SelfT ), ".wrapping_rem_euclid(10), 0);\n```" ), # [ stable ( feature = "euclidean_division" , since = "1.38.0" )]# [ rustc_const_unstable ( feature = "const_euclidean_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_rem_euclid ( self , rhs : Self )-> Self { self % rhs }}# [ doc = " Wrapping (modular) negation. Computes `-self`," ]# [ doc = " wrapping around at the boundary of the type." ]# [ doc = "" ]# [ doc = " Since unsigned types do not have negative equivalents" ]# [ doc = " all applications of this function will wrap (except for `-0`)." ]# [ doc = " For values smaller than the corresponding signed type\\\'s maximum" ]# [ doc = " the result is the same as casting the corresponding signed value." ]# [ doc = " Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where" ]# [ doc = " `MAX` is the corresponding signed type\\\'s maximum." ]# [ doc = "" ]# [ doc = " # Examples" ]# [ doc = "" ]# [ doc = " Basic usage:" ]# [ doc = "" ]# [ doc = " Please note that this example is shared between integer types." ]# [ doc = " Which explains why `i8` is used here." ]# [ doc = "" ]# [ doc = " ```" ]# [ doc = " assert_eq!(100i8.wrapping_neg(), -100);" ]# [ doc = " assert_eq!((-128i8).wrapping_neg(), -128);" ]# [ doc = " ```" ]# [ stable ( feature = "num_wrapping" , since = "1.2.0" )]# [ rustc_const_stable ( feature = "const_wrapping_math" , since = "1.32.0" )]# [ inline ] pub const fn wrapping_neg ( self )-> Self { self . overflowing_neg (). 0 } doc_comment ! { concat ! ( "Panic-free bitwise shift-left; yields `self << mask(rhs)`,\nwhere `mask` removes any high-order bits of `rhs` that\nwould cause the shift to exceed the bitwidth of the type.\n\nNote that this is *not* the same as a rotate-left; the\nRHS of a wrapping shift-left is restricted to the range\nof the type, rather than the bits shifted out of the LHS\nbeing returned to the other end. The primitive integer\ntypes all implement a [`rotate_left`](#method.rotate_left) function,\nwhich may be what you want instead.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(1" , stringify ! ($SelfT ), ".wrapping_shl(7), 128);\nassert_eq!(1" , stringify ! ($SelfT ), ".wrapping_shl(128), 1);" , $EndFeature , "\n```" ), # [ stable ( feature = "num_wrapping" , since = "1.2.0" )]# [ rustc_const_stable ( feature = "const_wrapping_math" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_shl ( self , rhs : u32 )-> Self { unsafe { intrinsics :: unchecked_shl ( self , ( rhs & ($BITS - 1 )) as $SelfT )}}} doc_comment ! { concat ! ( "Panic-free bitwise shift-right; yields `self >> mask(rhs)`,\nwhere `mask` removes any high-order bits of `rhs` that\nwould cause the shift to exceed the bitwidth of the type.\n\nNote that this is *not* the same as a rotate-right; the\nRHS of a wrapping shift-right is restricted to the range\nof the type, rather than the bits shifted out of the LHS\nbeing returned to the other end. The primitive integer\ntypes all implement a [`rotate_right`](#method.rotate_right) function,\nwhich may be what you want instead.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(128" , stringify ! ($SelfT ), ".wrapping_shr(7), 1);\nassert_eq!(128" , stringify ! ($SelfT ), ".wrapping_shr(128), 128);" , $EndFeature , "\n```" ), # [ stable ( feature = "num_wrapping" , since = "1.2.0" )]# [ rustc_const_stable ( feature = "const_wrapping_math" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_shr ( self , rhs : u32 )-> Self { unsafe { intrinsics :: unchecked_shr ( self , ( rhs & ($BITS - 1 )) as $SelfT )}}} doc_comment ! { concat ! ( "Wrapping (modular) exponentiation. Computes `self.pow(exp)`,\nwrapping around at the boundary of the type.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(3" , stringify ! ($SelfT ), ".wrapping_pow(5), 243);\nassert_eq!(3u8.wrapping_pow(6), 217);" , $EndFeature , "\n```" ), # [ stable ( feature = "no_panic_pow" , since = "1.34.0" )]# [ rustc_const_unstable ( feature = "const_int_pow" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn wrapping_pow ( self , mut exp : u32 )-> Self { if exp == 0 { return 1 ; } let mut base = self ; let mut acc : Self = 1 ; while exp > 1 { if ( exp & 1 )== 1 { acc = acc . wrapping_mul ( base ); } exp /= 2 ; base = base . wrapping_mul ( base ); } acc . wrapping_mul ( base )}} doc_comment ! { concat ! ( "Calculates `self` + `rhs`\n\nReturns a tuple of the addition along with a boolean indicating\nwhether an arithmetic overflow would occur. If an overflow would\nhave occurred then the wrapped value is returned.\n\n# Examples\n\nBasic usage\n\n```\n" , $Feature , "\nassert_eq!(5" , stringify ! ($SelfT ), ".overflowing_add(2), (7, false));\nassert_eq!(" , stringify ! ($SelfT ), "::MAX.overflowing_add(1), (0, true));" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_wrapping_math" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn overflowing_add ( self , rhs : Self )-> ( Self , bool ){ let ( a , b )= intrinsics :: add_with_overflow ( self as $ActualT , rhs as $ActualT ); ( a as Self , b )}} doc_comment ! { concat ! ( "Calculates `self` - `rhs`\n\nReturns a tuple of the subtraction along with a boolean indicating\nwhether an arithmetic overflow would occur. If an overflow would\nhave occurred then the wrapped value is returned.\n\n# Examples\n\nBasic usage\n\n```\n" , $Feature , "\nassert_eq!(5" , stringify ! ($SelfT ), ".overflowing_sub(2), (3, false));\nassert_eq!(0" , stringify ! ($SelfT ), ".overflowing_sub(1), (" , stringify ! ($SelfT ), "::MAX, true));" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_wrapping_math" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn overflowing_sub ( self , rhs : Self )-> ( Self , bool ){ let ( a , b )= intrinsics :: sub_with_overflow ( self as $ActualT , rhs as $ActualT ); ( a as Self , b )}}# [ doc = " Calculates the multiplication of `self` and `rhs`." ]# [ doc = "" ]# [ doc = " Returns a tuple of the multiplication along with a boolean" ]# [ doc = " indicating whether an arithmetic overflow would occur. If an" ]# [ doc = " overflow would have occurred then the wrapped value is returned." ]# [ doc = "" ]# [ doc = " # Examples" ]# [ doc = "" ]# [ doc = " Basic usage:" ]# [ doc = "" ]# [ doc = " Please note that this example is shared between integer types." ]# [ doc = " Which explains why `u32` is used here." ]# [ doc = "" ]# [ doc = " ```" ]# [ doc = " assert_eq!(5u32.overflowing_mul(2), (10, false));" ]# [ doc = " assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true));" ]# [ doc = " ```" ]# [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_wrapping_math" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn overflowing_mul ( self , rhs : Self )-> ( Self , bool ){ let ( a , b )= intrinsics :: mul_with_overflow ( self as $ActualT , rhs as $ActualT ); ( a as Self , b )} doc_comment ! { concat ! ( "Calculates the divisor when `self` is divided by `rhs`.\n\nReturns a tuple of the divisor along with a boolean indicating\nwhether an arithmetic overflow would occur. Note that for unsigned\nintegers overflow never occurs, so the second value is always\n`false`.\n\n# Panics\n\nThis function will panic if `rhs` is 0.\n\n# Examples\n\nBasic usage\n\n```\n" , $Feature , "assert_eq!(5" , stringify ! ($SelfT ), ".overflowing_div(2), (2, false));" , $EndFeature , "\n```" ), # [ inline ]# [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_unstable ( feature = "const_overflowing_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ] pub const fn overflowing_div ( self , rhs : Self )-> ( Self , bool ){( self / rhs , false )}} doc_comment ! { concat ! ( "Calculates the quotient of Euclidean division `self.div_euclid(rhs)`.\n\nReturns a tuple of the divisor along with a boolean indicating\nwhether an arithmetic overflow would occur. Note that for unsigned\nintegers overflow never occurs, so the second value is always\n`false`.\nSince, for the positive integers, all common\ndefinitions of division are equal, this\nis exactly equal to `self.overflowing_div(rhs)`.\n\n# Panics\n\nThis function will panic if `rhs` is 0.\n\n# Examples\n\nBasic usage\n\n```\nassert_eq!(5" , stringify ! ($SelfT ), ".overflowing_div_euclid(2), (2, false));\n```" ), # [ inline ]# [ stable ( feature = "euclidean_division" , since = "1.38.0" )]# [ rustc_const_unstable ( feature = "const_euclidean_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ] pub const fn overflowing_div_euclid ( self , rhs : Self )-> ( Self , bool ){( self / rhs , false )}} doc_comment ! { concat ! ( "Calculates the remainder when `self` is divided by `rhs`.\n\nReturns a tuple of the remainder after dividing along with a boolean\nindicating whether an arithmetic overflow would occur. Note that for\nunsigned integers overflow never occurs, so the second value is\nalways `false`.\n\n# Panics\n\nThis function will panic if `rhs` is 0.\n\n# Examples\n\nBasic usage\n\n```\n" , $Feature , "assert_eq!(5" , stringify ! ($SelfT ), ".overflowing_rem(2), (1, false));" , $EndFeature , "\n```" ), # [ inline ]# [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_unstable ( feature = "const_overflowing_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ] pub const fn overflowing_rem ( self , rhs : Self )-> ( Self , bool ){( self % rhs , false )}} doc_comment ! { concat ! ( "Calculates the remainder `self.rem_euclid(rhs)` as if by Euclidean division.\n\nReturns a tuple of the modulo after dividing along with a boolean\nindicating whether an arithmetic overflow would occur. Note that for\nunsigned integers overflow never occurs, so the second value is\nalways `false`.\nSince, for the positive integers, all common\ndefinitions of division are equal, this operation\nis exactly equal to `self.overflowing_rem(rhs)`.\n\n# Panics\n\nThis function will panic if `rhs` is 0.\n\n# Examples\n\nBasic usage\n\n```\nassert_eq!(5" , stringify ! ($SelfT ), ".overflowing_rem_euclid(2), (1, false));\n```" ), # [ inline ]# [ stable ( feature = "euclidean_division" , since = "1.38.0" )]# [ rustc_const_unstable ( feature = "const_euclidean_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ] pub const fn overflowing_rem_euclid ( self , rhs : Self )-> ( Self , bool ){( self % rhs , false )}} doc_comment ! { concat ! ( "Negates self in an overflowing fashion.\n\nReturns `!self + 1` using wrapping operations to return the value\nthat represents the negation of this unsigned value. Note that for\npositive unsigned values overflow always occurs, but negating 0 does\nnot overflow.\n\n# Examples\n\nBasic usage\n\n```\n" , $Feature , "assert_eq!(0" , stringify ! ($SelfT ), ".overflowing_neg(), (0, false));\nassert_eq!(2" , stringify ! ($SelfT ), ".overflowing_neg(), (-2i32 as " , stringify ! ($SelfT ), ", true));" , $EndFeature , "\n```" ), # [ inline ]# [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_wrapping_math" , since = "1.32.0" )] pub const fn overflowing_neg ( self )-> ( Self , bool ){((! self ). wrapping_add ( 1 ), self != 0 )}} doc_comment ! { concat ! ( "Shifts self left by `rhs` bits.\n\nReturns a tuple of the shifted version of self along with a boolean\nindicating whether the shift value was larger than or equal to the\nnumber of bits. If the shift value is too large, then value is\nmasked (N-1) where N is the number of bits, and this value is then\nused to perform the shift.\n\n# Examples\n\nBasic usage\n\n```\n" , $Feature , "assert_eq!(0x1" , stringify ! ($SelfT ), ".overflowing_shl(4), (0x10, false));\nassert_eq!(0x1" , stringify ! ($SelfT ), ".overflowing_shl(132), (0x10, true));" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_wrapping_math" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn overflowing_shl ( self , rhs : u32 )-> ( Self , bool ){( self . wrapping_shl ( rhs ), ( rhs > ($BITS - 1 )))}} doc_comment ! { concat ! ( "Shifts self right by `rhs` bits.\n\nReturns a tuple of the shifted version of self along with a boolean\nindicating whether the shift value was larger than or equal to the\nnumber of bits. If the shift value is too large, then value is\nmasked (N-1) where N is the number of bits, and this value is then\nused to perform the shift.\n\n# Examples\n\nBasic usage\n\n```\n" , $Feature , "assert_eq!(0x10" , stringify ! ($SelfT ), ".overflowing_shr(4), (0x1, false));\nassert_eq!(0x10" , stringify ! ($SelfT ), ".overflowing_shr(132), (0x1, true));" , $EndFeature , "\n```" ), # [ stable ( feature = "wrapping" , since = "1.7.0" )]# [ rustc_const_stable ( feature = "const_wrapping_math" , since = "1.32.0" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn overflowing_shr ( self , rhs : u32 )-> ( Self , bool ){( self . wrapping_shr ( rhs ), ( rhs > ($BITS - 1 )))}} doc_comment ! { concat ! ( "Raises self to the power of `exp`, using exponentiation by squaring.\n\nReturns a tuple of the exponentiation along with a bool indicating\nwhether an overflow happened.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(3" , stringify ! ($SelfT ), ".overflowing_pow(5), (243, false));\nassert_eq!(3u8.overflowing_pow(6), (217, true));" , $EndFeature , "\n```" ), # [ stable ( feature = "no_panic_pow" , since = "1.34.0" )]# [ rustc_const_unstable ( feature = "const_int_pow" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ] pub const fn overflowing_pow ( self , mut exp : u32 )-> ( Self , bool ){ if exp == 0 { return ( 1 , false ); } let mut base = self ; let mut acc : Self = 1 ; let mut overflown = false ; let mut r ; while exp > 1 { if ( exp & 1 )== 1 { r = acc . overflowing_mul ( base ); acc = r . 0 ; overflown |= r . 1 ; } exp /= 2 ; r = base . overflowing_mul ( base ); base = r . 0 ; overflown |= r . 1 ; } r = acc . overflowing_mul ( base ); r . 1 |= overflown ; r }} doc_comment ! { concat ! ( "Raises self to the power of `exp`, using exponentiation by squaring.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(2" , stringify ! ($SelfT ), ".pow(5), 32);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_unstable ( feature = "const_int_pow" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ]# [ rustc_inherit_overflow_checks ] pub const fn pow ( self , mut exp : u32 )-> Self { if exp == 0 { return 1 ; } let mut base = self ; let mut acc = 1 ; while exp > 1 { if ( exp & 1 )== 1 { acc = acc * base ; } exp /= 2 ; base = base * base ; } acc * base }} doc_comment ! { concat ! ( "Performs Euclidean division.\n\nSince, for the positive integers, all common\ndefinitions of division are equal, this\nis exactly equal to `self / rhs`.\n\n# Panics\n\nThis function will panic if `rhs` is 0.\n\n# Examples\n\nBasic usage:\n\n```\nassert_eq!(7" , stringify ! ($SelfT ), ".div_euclid(4), 1); // or any other integer type\n```" ), # [ stable ( feature = "euclidean_division" , since = "1.38.0" )]# [ rustc_const_unstable ( feature = "const_euclidean_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ]# [ rustc_inherit_overflow_checks ] pub const fn div_euclid ( self , rhs : Self )-> Self { self / rhs }} doc_comment ! { concat ! ( "Calculates the least remainder of `self (mod rhs)`.\n\nSince, for the positive integers, all common\ndefinitions of division are equal, this\nis exactly equal to `self % rhs`.\n\n# Panics\n\nThis function will panic if `rhs` is 0.\n\n# Examples\n\nBasic usage:\n\n```\nassert_eq!(7" , stringify ! ($SelfT ), ".rem_euclid(4), 3); // or any other integer type\n```" ), # [ stable ( feature = "euclidean_division" , since = "1.38.0" )]# [ rustc_const_unstable ( feature = "const_euclidean_int_methods" , issue = "53718" )]# [ must_use = "this returns the result of the operation, \\n without modifying the original" ]# [ inline ]# [ rustc_inherit_overflow_checks ] pub const fn rem_euclid ( self , rhs : Self )-> Self { self % rhs }} doc_comment ! { concat ! ( "Returns `true` if and only if `self == 2^k` for some `k`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert!(16" , stringify ! ($SelfT ), ".is_power_of_two());\nassert!(!10" , stringify ! ($SelfT ), ".is_power_of_two());" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_stable ( feature = "const_is_power_of_two" , since = "1.32.0" )]# [ inline ] pub const fn is_power_of_two ( self )-> bool { self . count_ones ()== 1 }}# [ inline ]# [ rustc_const_unstable ( feature = "const_int_pow" , issue = "53718" )] const fn one_less_than_next_power_of_two ( self )-> Self { if self <= 1 { return 0 ; } let p = self - 1 ; let z = unsafe { intrinsics :: ctlz_nonzero ( p )}; <$SelfT >:: MAX >> z } doc_comment ! { concat ! ( "Returns the smallest power of two greater than or equal to `self`.\n\nWhen return value overflows (i.e., `self > (1 << (N-1))` for type\n`uN`), it panics in debug mode and return value is wrapped to 0 in\nrelease mode (the only situation in which method can return 0).\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(2" , stringify ! ($SelfT ), ".next_power_of_two(), 2);\nassert_eq!(3" , stringify ! ($SelfT ), ".next_power_of_two(), 4);" , $EndFeature , "\n```" ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_unstable ( feature = "const_int_pow" , issue = "53718" )]# [ inline ]# [ rustc_inherit_overflow_checks ] pub const fn next_power_of_two ( self )-> Self { self . one_less_than_next_power_of_two ()+ 1 }} doc_comment ! { concat ! ( "Returns the smallest power of two greater than or equal to `n`. If\nthe next power of two is greater than the type's maximum value,\n`None` is returned, otherwise the power of two is wrapped in `Some`.\n\n# Examples\n\nBasic usage:\n\n```\n" , $Feature , "assert_eq!(2" , stringify ! ($SelfT ), ".checked_next_power_of_two(), Some(2));\nassert_eq!(3" , stringify ! ($SelfT ), ".checked_next_power_of_two(), Some(4));\nassert_eq!(" , stringify ! ($SelfT ), "::MAX.checked_next_power_of_two(), None);" , $EndFeature , "\n```" ), # [ inline ]# [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_const_unstable ( feature = "const_int_pow" , issue = "53718" )] pub const fn checked_next_power_of_two ( self )-> Option < Self > { self . one_less_than_next_power_of_two (). checked_add ( 1 )}} doc_comment ! { concat ! ( "Returns the smallest power of two greater than or equal to `n`. If\nthe next power of two is greater than the type's maximum value,\nthe return value is wrapped to `0`.\n\n# Examples\n\nBasic usage:\n\n```\n#![feature(wrapping_next_power_of_two)]\n" , $Feature , "\nassert_eq!(2" , stringify ! ($SelfT ), ".wrapping_next_power_of_two(), 2);\nassert_eq!(3" , stringify ! ($SelfT ), ".wrapping_next_power_of_two(), 4);\nassert_eq!(" , stringify ! ($SelfT ), "::MAX.wrapping_next_power_of_two(), 0);" , $EndFeature , "\n```" ), # [ unstable ( feature = "wrapping_next_power_of_two" , issue = "32463" , reason = "needs decision on wrapping behaviour" )]# [ rustc_const_unstable ( feature = "const_int_pow" , issue = "53718" )] pub const fn wrapping_next_power_of_two ( self )-> Self { self . one_less_than_next_power_of_two (). wrapping_add ( 1 )}} doc_comment ! { concat ! ( "Return the memory representation of this integer as a byte array in\nbig-endian (network) byte order.\n" , $to_xe_bytes_doc , "\n# Examples\n\n```\nlet bytes = " , $swap_op , stringify ! ($SelfT ), ".to_be_bytes();\nassert_eq!(bytes, " , $be_bytes , ");\n```" ), # [ stable ( feature = "int_to_from_bytes" , since = "1.32.0" )]# [ rustc_const_stable ( feature = "const_int_conversion" , since = "1.44.0" )]# [ inline ] pub const fn to_be_bytes ( self )-> [ u8 ; mem :: size_of ::< Self > ()]{ self . to_be (). to_ne_bytes ()}} doc_comment ! { concat ! ( "Return the memory representation of this integer as a byte array in\nlittle-endian byte order.\n" , $to_xe_bytes_doc , "\n# Examples\n\n```\nlet bytes = " , $swap_op , stringify ! ($SelfT ), ".to_le_bytes();\nassert_eq!(bytes, " , $le_bytes , ");\n```" ), # [ stable ( feature = "int_to_from_bytes" , since = "1.32.0" )]# [ rustc_const_stable ( feature = "const_int_conversion" , since = "1.44.0" )]# [ inline ] pub const fn to_le_bytes ( self )-> [ u8 ; mem :: size_of ::< Self > ()]{ self . to_le (). to_ne_bytes ()}} doc_comment ! { concat ! ( "\nReturn the memory representation of this integer as a byte array in\nnative byte order.\n\nAs the target platform's native endianness is used, portable code\nshould use [`to_be_bytes`] or [`to_le_bytes`], as appropriate,\ninstead.\n" , $to_xe_bytes_doc , "\n[`to_be_bytes`]: #method.to_be_bytes\n[`to_le_bytes`]: #method.to_le_bytes\n\n# Examples\n\n```\nlet bytes = " , $swap_op , stringify ! ($SelfT ), ".to_ne_bytes();\nassert_eq!(\n bytes,\n if cfg!(target_endian = \"big\") {\n " , $be_bytes , "\n } else {\n " , $le_bytes , "\n }\n);\n```" ), # [ stable ( feature = "int_to_from_bytes" , since = "1.32.0" )]# [ rustc_const_stable ( feature = "const_int_conversion" , since = "1.44.0" )]# [ cfg_attr ( not ( bootstrap ), rustc_allow_const_fn_unstable ( const_fn_transmute ))]# [ cfg_attr ( bootstrap , allow_internal_unstable ( const_fn_transmute ))]# [ inline ] pub const fn to_ne_bytes ( self )-> [ u8 ; mem :: size_of ::< Self > ()]{ unsafe { mem :: transmute ( self )}}} doc_comment ! { concat ! ( "\nReturn the memory representation of this integer as a byte array in\nnative byte order.\n\n[`to_ne_bytes`] should be preferred over this whenever possible.\n\n[`to_ne_bytes`]: #method.to_ne_bytes\n" , "\n# Examples\n\n```\n#![feature(num_as_ne_bytes)]\nlet num = " , $swap_op , stringify ! ($SelfT ), ";\nlet bytes = num.as_ne_bytes();\nassert_eq!(\n bytes,\n if cfg!(target_endian = \"big\") {\n &" , $be_bytes , "\n } else {\n &" , $le_bytes , "\n }\n);\n```" ), # [ unstable ( feature = "num_as_ne_bytes" , issue = "76976" )]# [ inline ] pub fn as_ne_bytes (& self )-> & [ u8 ; mem :: size_of ::< Self > ()]{ unsafe {&* ( self as * const Self as * const _)}}} doc_comment ! { concat ! ( "Create a native endian integer value from its representation\nas a byte array in big endian.\n" , $from_xe_bytes_doc , "\n# Examples\n\n```\nlet value = " , stringify ! ($SelfT ), "::from_be_bytes(" , $be_bytes , ");\nassert_eq!(value, " , $swap_op , ");\n```\n\nWhen starting from a slice rather than an array, fallible conversion APIs can be used:\n\n```\nuse std::convert::TryInto;\n\nfn read_be_" , stringify ! ($SelfT ), "(input: &mut &[u8]) -> " , stringify ! ($SelfT ), " {\n let (int_bytes, rest) = input.split_at(std::mem::size_of::<" , stringify ! ($SelfT ), ">());\n *input = rest;\n " , stringify ! ($SelfT ), "::from_be_bytes(int_bytes.try_into().unwrap())\n}\n```" ), # [ stable ( feature = "int_to_from_bytes" , since = "1.32.0" )]# [ rustc_const_stable ( feature = "const_int_conversion" , since = "1.44.0" )]# [ inline ] pub const fn from_be_bytes ( bytes : [ u8 ; mem :: size_of ::< Self > ()])-> Self { Self :: from_be ( Self :: from_ne_bytes ( bytes ))}} doc_comment ! { concat ! ( "\nCreate a native endian integer value from its representation\nas a byte array in little endian.\n" , $from_xe_bytes_doc , "\n# Examples\n\n```\nlet value = " , stringify ! ($SelfT ), "::from_le_bytes(" , $le_bytes , ");\nassert_eq!(value, " , $swap_op , ");\n```\n\nWhen starting from a slice rather than an array, fallible conversion APIs can be used:\n\n```\nuse std::convert::TryInto;\n\nfn read_le_" , stringify ! ($SelfT ), "(input: &mut &[u8]) -> " , stringify ! ($SelfT ), " {\n let (int_bytes, rest) = input.split_at(std::mem::size_of::<" , stringify ! ($SelfT ), ">());\n *input = rest;\n " , stringify ! ($SelfT ), "::from_le_bytes(int_bytes.try_into().unwrap())\n}\n```" ), # [ stable ( feature = "int_to_from_bytes" , since = "1.32.0" )]# [ rustc_const_stable ( feature = "const_int_conversion" , since = "1.44.0" )]# [ inline ] pub const fn from_le_bytes ( bytes : [ u8 ; mem :: size_of ::< Self > ()])-> Self { Self :: from_le ( Self :: from_ne_bytes ( bytes ))}} doc_comment ! { concat ! ( "Create a native endian integer value from its memory representation\nas a byte array in native endianness.\n\nAs the target platform's native endianness is used, portable code\nlikely wants to use [`from_be_bytes`] or [`from_le_bytes`], as\nappropriate instead.\n\n[`from_be_bytes`]: #method.from_be_bytes\n[`from_le_bytes`]: #method.from_le_bytes\n" , $from_xe_bytes_doc , "\n# Examples\n\n```\nlet value = " , stringify ! ($SelfT ), "::from_ne_bytes(if cfg!(target_endian = \"big\") {\n " , $be_bytes , "\n} else {\n " , $le_bytes , "\n});\nassert_eq!(value, " , $swap_op , ");\n```\n\nWhen starting from a slice rather than an array, fallible conversion APIs can be used:\n\n```\nuse std::convert::TryInto;\n\nfn read_ne_" , stringify ! ($SelfT ), "(input: &mut &[u8]) -> " , stringify ! ($SelfT ), " {\n let (int_bytes, rest) = input.split_at(std::mem::size_of::<" , stringify ! ($SelfT ), ">());\n *input = rest;\n " , stringify ! ($SelfT ), "::from_ne_bytes(int_bytes.try_into().unwrap())\n}\n```" ), # [ stable ( feature = "int_to_from_bytes" , since = "1.32.0" )]# [ rustc_const_stable ( feature = "const_int_conversion" , since = "1.44.0" )]# [ cfg_attr ( not ( bootstrap ), rustc_allow_const_fn_unstable ( const_fn_transmute ))]# [ cfg_attr ( bootstrap , allow_internal_unstable ( const_fn_transmute ))]# [ inline ] pub const fn from_ne_bytes ( bytes : [ u8 ; mem :: size_of ::< Self > ()])-> Self { unsafe { mem :: transmute ( bytes )}}} doc_comment ! { concat ! ( "**This method is soft-deprecated.**\n\nAlthough using it won’t cause compilation warning,\nnew code should use [`" , stringify ! ($SelfT ), "::MIN" , "`](#associatedconstant.MIN) instead.\n\nReturns the smallest value that can be represented by this integer type." ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_promotable ]# [ inline ( always )]# [ rustc_const_stable ( feature = "const_max_value" , since = "1.32.0" )] pub const fn min_value ()-> Self { Self :: MIN }} doc_comment ! { concat ! ( "**This method is soft-deprecated.**\n\nAlthough using it won’t cause compilation warning,\nnew code should use [`" , stringify ! ($SelfT ), "::MAX" , "`](#associatedconstant.MAX) instead.\n\nReturns the largest value that can be represented by this integer type." ), # [ stable ( feature = "rust1" , since = "1.0.0" )]# [ rustc_promotable ]# [ inline ( always )]# [ rustc_const_stable ( feature = "const_max_value" , since = "1.32.0" )] pub const fn max_value ()-> Self { Self :: MAX }}}} -macro_rules! __ra_macro_fixture433 {($type : ident )=>{ const EXPLICIT_SIG_BITS : u8 = Self :: SIG_BITS - 1 ; const MAX_EXP : i16 = ( 1 << ( Self :: EXP_BITS - 1 ))- 1 ; const MIN_EXP : i16 = -< Self as RawFloat >:: MAX_EXP + 1 ; const MAX_EXP_INT : i16 = < Self as RawFloat >:: MAX_EXP - ( Self :: SIG_BITS as i16 - 1 ); const MAX_ENCODED_EXP : i16 = ( 1 << Self :: EXP_BITS )- 1 ; const MIN_EXP_INT : i16 = < Self as RawFloat >:: MIN_EXP - ( Self :: SIG_BITS as i16 - 1 ); const MAX_SIG : u64 = ( 1 << Self :: SIG_BITS )- 1 ; const MIN_SIG : u64 = 1 << ( Self :: SIG_BITS - 1 ); const INFINITY : Self = $type :: INFINITY ; const NAN : Self = $type :: NAN ; const ZERO : Self = 0.0 ; }; } -macro_rules! __ra_macro_fixture434 {()=>{# [ inline ] unsafe fn forward_unchecked ( start : Self , n : usize )-> Self { unsafe { start . unchecked_add ( n as Self )}}# [ inline ] unsafe fn backward_unchecked ( start : Self , n : usize )-> Self { unsafe { start . unchecked_sub ( n as Self )}}# [ inline ] fn forward ( start : Self , n : usize )-> Self { if Self :: forward_checked ( start , n ). is_none (){ let _ = Add :: add ( Self :: MAX , 1 ); } start . wrapping_add ( n as Self )}# [ inline ] fn backward ( start : Self , n : usize )-> Self { if Self :: backward_checked ( start , n ). is_none (){ let _ = Sub :: sub ( Self :: MIN , 1 ); } start . wrapping_sub ( n as Self )}}; } -macro_rules! __ra_macro_fixture435 {( u8 , $($tt : tt )*)=>{ "" }; ( i8 , $($tt : tt )*)=>{ "" }; ($_: ident , $($tt : tt )*)=>{$($tt )* }; } -macro_rules! __ra_macro_fixture436 {( forward )=>{# [ inline ] fn haystack (& self )-> & 'a str { self . 0 . haystack ()}# [ inline ] fn next (& mut self )-> SearchStep { self . 0 . next ()}# [ inline ] fn next_match (& mut self )-> Option < ( usize , usize )> { self . 0 . next_match ()}# [ inline ] fn next_reject (& mut self )-> Option < ( usize , usize )> { self . 0 . next_reject ()}}; ( reverse )=>{# [ inline ] fn next_back (& mut self )-> SearchStep { self . 0 . next_back ()}# [ inline ] fn next_match_back (& mut self )-> Option < ( usize , usize )> { self . 0 . next_match_back ()}# [ inline ] fn next_reject_back (& mut self )-> Option < ( usize , usize )> { self . 0 . next_reject_back ()}}; } -macro_rules! __ra_macro_fixture437 {($t : ty , $pmap : expr , $smap : expr )=>{ type Searcher = $t ; # [ inline ] fn into_searcher ( self , haystack : & 'a str )-> $t {($smap )(($pmap )( self ). into_searcher ( haystack ))}# [ inline ] fn is_contained_in ( self , haystack : & 'a str )-> bool {($pmap )( self ). is_contained_in ( haystack )}# [ inline ] fn is_prefix_of ( self , haystack : & 'a str )-> bool {($pmap )( self ). is_prefix_of ( haystack )}# [ inline ] fn strip_prefix_of ( self , haystack : & 'a str )-> Option <& 'a str > {($pmap )( self ). strip_prefix_of ( haystack )}# [ inline ] fn is_suffix_of ( self , haystack : & 'a str )-> bool where $t : ReverseSearcher < 'a >, {($pmap )( self ). is_suffix_of ( haystack )}# [ inline ] fn strip_suffix_of ( self , haystack : & 'a str )-> Option <& 'a str > where $t : ReverseSearcher < 'a >, {($pmap )( self ). strip_suffix_of ( haystack )}}; } -macro_rules! __ra_macro_fixture438 {()=>{# [ inline ] fn is_ascii (& self )-> bool { self . is_ascii ()}# [ inline ] fn to_ascii_uppercase (& self )-> Self :: Owned { self . to_ascii_uppercase ()}# [ inline ] fn to_ascii_lowercase (& self )-> Self :: Owned { self . to_ascii_lowercase ()}# [ inline ] fn eq_ignore_ascii_case (& self , o : & Self )-> bool { self . eq_ignore_ascii_case ( o )}# [ inline ] fn make_ascii_uppercase (& mut self ){ self . make_ascii_uppercase (); }# [ inline ] fn make_ascii_lowercase (& mut self ){ self . make_ascii_lowercase (); }}; } -macro_rules! __ra_macro_fixture439 {()=>($crate :: vec :: Vec :: new ()); ($elem : expr ; $n : expr )=>($crate :: vec :: from_elem ($elem , $n )); ($($x : expr ),+ $(,)?)=>(< [_]>:: into_vec ( box [$($x ),+])); } -macro_rules! __ra_macro_fixture440 {($left : expr , $right : expr $(,)?)=>({ match (&$left , &$right ){( left_val , right_val )=>{ if ! (* left_val == * right_val ){ panic ! ( r#"assertion failed: `(left == right)`\n left: `{:?}`,\n right: `{:?}`"# , &* left_val , &* right_val )}}}}); ($left : expr , $right : expr , $($arg : tt )+)=>({ match (& ($left ), & ($right )){( left_val , right_val )=>{ if ! (* left_val == * right_val ){ panic ! ( r#"assertion failed: `(left == right)`\n left: `{:?}`,\n right: `{:?}`: {}"# , &* left_val , &* right_val , $crate :: format_args ! ($($arg )+))}}}}); } -macro_rules! __ra_macro_fixture441 {()=>({$crate :: panic ! ( "explicit panic" )}); ($msg : expr $(,)?)=>({$crate :: rt :: begin_panic ($msg )}); ($fmt : expr , $($arg : tt )+)=>({$crate :: rt :: begin_panic_fmt (&$crate :: format_args ! ($fmt , $($arg )+))}); } -macro_rules! __ra_macro_fixture442 {($expression : expr , $($pattern : pat )|+ $(if $guard : expr )? $(,)?)=>{ match $expression {$($pattern )|+ $(if $guard )? => true , _ => false }}} -macro_rules! __ra_macro_fixture443 {()=>{# [ inline ] fn load_consume (& self )-> Self :: Val { self . load ( Ordering :: Acquire )}}; } -macro_rules! __ra_macro_fixture444 {($($tt : tt )*)=>{$($tt )* }} -macro_rules! __ra_macro_fixture445 {($tyname : ident , $($($field : ident ).+),*)=>{ fn fmt (& self , f : & mut :: std :: fmt :: Formatter )-> :: std :: fmt :: Result { f . debug_struct ( stringify ! ($tyname ))$(. field ( stringify ! ($($field ).+), & self .$($field ).+))* . finish ()}}} -macro_rules! __ra_macro_fixture446 {($($field : ident ),*)=>{ fn clone (& self )-> Self { Self {$($field : self .$field . clone (),)* }}}} -macro_rules! __ra_macro_fixture447 {($method : ident )=>{ fn $method < V > ( self , visitor : V )-> Result < V :: Value > where V : de :: Visitor < 'de >, { self . deserialize_number ( visitor )}}; } -macro_rules! __ra_macro_fixture448 {($method : ident =>$visit : ident )=>{ fn $method < V > ( self , visitor : V )-> Result < V :: Value > where V : de :: Visitor < 'de >, { self . de . eat_char (); self . de . scratch . clear (); let string = tri ! ( self . de . read . parse_str (& mut self . de . scratch )); match ( string . parse (), string ){( Ok ( integer ), _)=> visitor .$visit ( integer ), ( Err (_), Reference :: Borrowed ( s ))=> visitor . visit_borrowed_str ( s ), ( Err (_), Reference :: Copied ( s ))=> visitor . visit_str ( s ), }}}; } -macro_rules! __ra_macro_fixture449 {($method : ident )=>{# [ cfg ( not ( feature = "arbitrary_precision" ))] fn $method < V > ( self , visitor : V )-> Result < V :: Value , Error > where V : Visitor < 'de >, { match self { Value :: Number ( n )=> n . deserialize_any ( visitor ), _ => Err ( self . invalid_type (& visitor )), }}# [ cfg ( feature = "arbitrary_precision" )] fn $method < V > ( self , visitor : V )-> Result < V :: Value , Error > where V : Visitor < 'de >, { match self { Value :: Number ( n )=> n .$method ( visitor ), _ => self . deserialize_any ( visitor ), }}}; } -macro_rules! __ra_macro_fixture450 {($method : ident )=>{# [ cfg ( not ( feature = "arbitrary_precision" ))] fn $method < V > ( self , visitor : V )-> Result < V :: Value , Error > where V : Visitor < 'de >, { match * self { Value :: Number ( ref n )=> n . deserialize_any ( visitor ), _ => Err ( self . invalid_type (& visitor )), }}# [ cfg ( feature = "arbitrary_precision" )] fn $method < V > ( self , visitor : V )-> Result < V :: Value , Error > where V : Visitor < 'de >, { match * self { Value :: Number ( ref n )=> n .$method ( visitor ), _ => self . deserialize_any ( visitor ), }}}; } -macro_rules! __ra_macro_fixture451 {($method : ident =>$visit : ident )=>{ fn $method < V > ( self , visitor : V )-> Result < V :: Value , Error > where V : Visitor < 'de >, { match ( self . key . parse (), self . key ){( Ok ( integer ), _)=> visitor .$visit ( integer ), ( Err (_), Cow :: Borrowed ( s ))=> visitor . visit_borrowed_str ( s ), # [ cfg ( any ( feature = "std" , feature = "alloc" ))]( Err (_), Cow :: Owned ( s ))=> visitor . visit_string ( s ), }}}; } -macro_rules! __ra_macro_fixture452 {(@ expand [$($num_string : tt )*])=>{# [ cfg ( not ( feature = "arbitrary_precision" ))]# [ inline ] fn deserialize_any < V > ( self , visitor : V )-> Result < V :: Value , Error > where V : Visitor < 'de >, { match self . n { N :: PosInt ( u )=> visitor . visit_u64 ( u ), N :: NegInt ( i )=> visitor . visit_i64 ( i ), N :: Float ( f )=> visitor . visit_f64 ( f ), }}# [ cfg ( feature = "arbitrary_precision" )]# [ inline ] fn deserialize_any < V > ( self , visitor : V )-> Result < V :: Value , Error > where V : Visitor < 'de > { if let Some ( u )= self . as_u64 (){ return visitor . visit_u64 ( u ); } else if let Some ( i )= self . as_i64 (){ return visitor . visit_i64 ( i ); } else if let Some ( f )= self . as_f64 (){ if ryu :: Buffer :: new (). format_finite ( f )== self . n || f . to_string ()== self . n { return visitor . visit_f64 ( f ); }} visitor . visit_map ( NumberDeserializer { number : Some ( self .$($num_string )*), })}}; ( owned )=>{ deserialize_any ! (@ expand [ n ]); }; ( ref )=>{ deserialize_any ! (@ expand [ n . clone ()]); }; } -macro_rules! __ra_macro_fixture453 {($deserialize : ident =>$visit : ident )=>{# [ cfg ( not ( feature = "arbitrary_precision" ))] fn $deserialize < V > ( self , visitor : V )-> Result < V :: Value , Error > where V : Visitor < 'de >, { self . deserialize_any ( visitor )}# [ cfg ( feature = "arbitrary_precision" )] fn $deserialize < V > ( self , visitor : V )-> Result < V :: Value , Error > where V : de :: Visitor < 'de >, { visitor .$visit ( self . n . parse (). map_err (|_| invalid_number ())?)}}; } -macro_rules! __ra_macro_fixture454 {()=>{ fn __rayon_private__ (& self )-> crate :: private :: PrivateMarker { crate :: private :: PrivateMarker }}; } -macro_rules! __ra_macro_fixture455 {()=>{ fn __rayon_private__ (& self )-> crate :: private :: PrivateMarker { crate :: private :: PrivateMarker }}; } -macro_rules! __ra_macro_fixture456 {($map_elt : expr )=>{ fn next (& mut self )-> Option < Self :: Item > { self . iter . next (). map ($map_elt )} fn size_hint (& self )-> ( usize , Option < usize >){ self . iter . size_hint ()} fn count ( self )-> usize { self . iter . len ()} fn nth (& mut self , n : usize )-> Option < Self :: Item > { self . iter . nth ( n ). map ($map_elt )} fn last ( mut self )-> Option < Self :: Item > { self . next_back ()} fn collect < C > ( self )-> C where C : FromIterator < Self :: Item >, { self . iter . map ($map_elt ). collect ()}}; } -macro_rules! __ra_macro_fixture457 {($map_elt : expr )=>{ fn next_back (& mut self )-> Option < Self :: Item > { self . iter . next_back (). map ($map_elt )}}; } -macro_rules! __ra_macro_fixture458 {()=>{# [ doc = " This trait is private; this method exists to make it" ]# [ doc = " impossible to implement outside the crate." ]# [ doc ( hidden )] fn __rayon_private__ (& self )-> crate :: private :: PrivateMarker ; }; } -macro_rules! __ra_macro_fixture459 {($ident : ident )=>{{# [ cfg ( test )]{ extern "C" {# [ no_mangle ] static $ident : std :: sync :: atomic :: AtomicUsize ; } unsafe {$ident . fetch_add ( 1 , std :: sync :: atomic :: Ordering :: SeqCst ); }}}}; } -macro_rules! __ra_macro_fixture460 {($ident : ident )=>{# [ no_mangle ] static $ident : std :: sync :: atomic :: AtomicUsize = std :: sync :: atomic :: AtomicUsize :: new ( 0 ); let _checker = $crate :: mark :: MarkChecker :: new (&$ident ); }; } -macro_rules! __ra_macro_fixture461 {( target : $target : expr , $($arg : tt )+)=>( log ! ( target : $target , $crate :: Level :: Debug , $($arg )+)); ($($arg : tt )+)=>( log ! ($crate :: Level :: Debug , $($arg )+))} -macro_rules! __ra_macro_fixture462 {()=>($crate :: eprint ! ( "\n" )); ($($arg : tt )*)=>({$crate :: io :: _eprint ($crate :: format_args_nl ! ($($arg )*)); })} -macro_rules! __ra_macro_fixture463 {( target : $target : expr , $($arg : tt )+)=>( log ! ( target : $target , $crate :: Level :: Warn , $($arg )+)); ($($arg : tt )+)=>( log ! ($crate :: Level :: Warn , $($arg )+))} -macro_rules! __ra_macro_fixture464 {( target : $target : expr , $lvl : expr , $($arg : tt )+)=>({ let lvl = $lvl ; if lvl <= $crate :: STATIC_MAX_LEVEL && lvl <= $crate :: max_level (){$crate :: __private_api_log ( __log_format_args ! ($($arg )+), lvl , & ($target , __log_module_path ! (), __log_file ! (), __log_line ! ()), ); }}); ($lvl : expr , $($arg : tt )+)=>( log ! ( target : __log_module_path ! (), $lvl , $($arg )+))} -macro_rules! __ra_macro_fixture465 {($($args : tt )*)=>{ format_args ! ($($args )*)}; } -macro_rules! __ra_macro_fixture466 {()=>{ module_path ! ()}; } -macro_rules! __ra_macro_fixture467 {()=>{ file ! ()}; } -macro_rules! __ra_macro_fixture468 {()=>{ line ! ()}; } -macro_rules! __ra_macro_fixture469 {($left : expr , $right : expr )=>{ assert_eq_text ! ($left , $right ,)}; ($left : expr , $right : expr , $($tt : tt )*)=>{{ let left = $left ; let right = $right ; if left != right { if left . trim ()== right . trim (){ std :: eprintln ! ( "Left:\n{:?}\n\nRight:\n{:?}\n\nWhitespace difference\n" , left , right ); } else { let diff = $crate :: __diff ( left , right ); std :: eprintln ! ( "Left:\n{}\n\nRight:\n{}\n\nDiff:\n{}\n" , left , right , $crate :: format_diff ( diff )); } std :: eprintln ! ($($tt )*); panic ! ( "text differs" ); }}}; } -macro_rules! __ra_macro_fixture470 {($($arg : tt )*)=>($crate :: io :: _eprint ($crate :: format_args ! ($($arg )*))); } -macro_rules! __ra_macro_fixture471 {($left : expr , $right : expr $(,)?)=>({ match (&$left , &$right ){( left_val , right_val )=>{ if * left_val == * right_val { panic ! ( r#"assertion failed: `(left != right)`\n left: `{:?}`,\n right: `{:?}`"# , &* left_val , &* right_val )}}}}); ($left : expr , $right : expr , $($arg : tt )+)=>({ match (& ($left ), & ($right )){( left_val , right_val )=>{ if * left_val == * right_val { panic ! ( r#"assertion failed: `(left != right)`\n left: `{:?}`,\n right: `{:?}`: {}"# , &* left_val , &* right_val , $crate :: format_args ! ($($arg )+))}}}}); } -macro_rules! __ra_macro_fixture472 {[[$data : literal ]]=>{$crate :: Expect { position : $crate :: Position { file : file ! (), line : line ! (), column : column ! (), }, data : $data , }}; [[]]=>{$crate :: expect ! [[ "" ]]}; } -macro_rules! __ra_macro_fixture473 {( self )=>{$crate :: name :: known :: SELF_PARAM }; ( Self )=>{$crate :: name :: known :: SELF_TYPE }; ('static )=>{$crate :: name :: known :: STATIC_LIFETIME }; ($ident : ident )=>{$crate :: name :: known ::$ident }; } -macro_rules! __ra_macro_fixture474 {()=>({ panic ! ( "internal error: entered unreachable code" )}); ($msg : expr $(,)?)=>({$crate :: unreachable ! ( "{}" , $msg )}); ($fmt : expr , $($arg : tt )*)=>({ panic ! ($crate :: concat ! ( "internal error: entered unreachable code: " , $fmt ), $($arg )*)}); } -macro_rules! __ra_macro_fixture475 {( target : $target : expr , $($arg : tt )+)=>( log ! ( target : $target , $crate :: Level :: Error , $($arg )+)); ($($arg : tt )+)=>( log ! ($crate :: Level :: Error , $($arg )+))} -macro_rules! __ra_macro_fixture476 {( target : $target : expr , $($arg : tt )+)=>( log ! ( target : $target , $crate :: Level :: Trace , $($arg )+)); ($($arg : tt )+)=>( log ! ($crate :: Level :: Trace , $($arg )+))} -macro_rules! __ra_macro_fixture477 {($buf : expr )=>(); ($buf : expr , $lit : literal $($arg : tt )*)=>{{ use :: std :: fmt :: Write as _; let _ = :: std :: write ! ($buf , $lit $($arg )*); }}; } -macro_rules! __ra_macro_fixture478 {( match $node : ident {$($tt : tt )* })=>{ match_ast ! ( match ($node ){$($tt )* })}; ( match ($node : expr ){$(ast ::$ast : ident ($it : ident )=>$res : expr , )* _ =>$catch_all : expr $(,)? })=>{{$(if let Some ($it )= ast ::$ast :: cast ($node . clone ()){$res } else )* {$catch_all }}}; } -macro_rules! __ra_macro_fixture479 {($start : ident $(:: $seg : ident )*)=>({$crate :: __known_path ! ($start $(:: $seg )*); $crate :: path :: ModPath :: from_segments ($crate :: path :: PathKind :: Abs , vec ! [$crate :: path :: __name ! [$start ], $($crate :: path :: __name ! [$seg ],)* ])}); } -macro_rules! __ra_macro_fixture480 {( core :: iter :: IntoIterator )=>{}; ( core :: iter :: Iterator )=>{}; ( core :: result :: Result )=>{}; ( core :: option :: Option )=>{}; ( core :: ops :: Range )=>{}; ( core :: ops :: RangeFrom )=>{}; ( core :: ops :: RangeFull )=>{}; ( core :: ops :: RangeTo )=>{}; ( core :: ops :: RangeToInclusive )=>{}; ( core :: ops :: RangeInclusive )=>{}; ( core :: future :: Future )=>{}; ( core :: ops :: Try )=>{}; ($path : path )=>{ compile_error ! ( "Please register your known path in the path module" )}; } -macro_rules! __ra_macro_fixture481 {($changed : ident , ($this : ident / $def : ident ). $field : ident , $glob_imports : ident [$lookup : ident ], $def_import_type : ident )=>{{ let existing = $this .$field . entry ($lookup . 1 . clone ()); match ( existing , $def .$field ){( Entry :: Vacant ( entry ), Some (_))=>{ match $def_import_type { ImportType :: Glob =>{$glob_imports .$field . insert ($lookup . clone ()); } ImportType :: Named =>{$glob_imports .$field . remove (&$lookup ); }} if let Some ( fld )= $def .$field { entry . insert ( fld ); }$changed = true ; }( Entry :: Occupied ( mut entry ), Some (_)) if $glob_imports .$field . contains (&$lookup )&& matches ! ($def_import_type , ImportType :: Named )=>{ mark :: hit ! ( import_shadowed ); $glob_imports .$field . remove (&$lookup ); if let Some ( fld )= $def .$field { entry . insert ( fld ); }$changed = true ; }_ =>{}}}}; } -macro_rules! __ra_macro_fixture482 {($(# $attr_args : tt )* const fn $($item : tt )* )=>{$(# $attr_args )* fn $($item )* }; ($(# $attr_args : tt )* pub const fn $($item : tt )* )=>{$(# $attr_args )* pub fn $($item )* }; ($(# $attr_args : tt )* pub const unsafe fn $($item : tt )* )=>{$(# $attr_args )* pub unsafe fn $($item )* }; } -macro_rules! __ra_macro_fixture483 {{ type Mirror = $tinyname : ident ; $($(# [$attr : meta ])* $v : vis fn $fname : ident ($seif : ident : $seifty : ty $(,$argname : ident : $argtype : ty )*)$(-> $ret : ty )? ; )* }=>{$($(# [$attr ])* # [ inline ( always )]$v fn $fname ($seif : $seifty , $($argname : $argtype ),*)$(-> $ret )? { match $seif {$tinyname :: Inline ( i )=> i .$fname ($($argname ),*), $tinyname :: Heap ( h )=> h .$fname ($($argname ),*), }})* }; } -macro_rules! __ra_macro_fixture484 {([$($stack : tt )*])=>{$($stack )* }; ([$($stack : tt )*]@ escape $_x : tt $($t : tt )*)=>{ remove_sections_inner ! ([$($stack )*]$($t )*); }; ([$($stack : tt )*]@ section $x : ident $($t : tt )*)=>{ remove_sections_inner ! ([$($stack )*]$($t )*); }; ([$($stack : tt )*]$t : tt $($tail : tt )*)=>{ remove_sections_inner ! ([$($stack )* $t ]$($tail )*); }; } -macro_rules! __ra_macro_fixture485 {($name : ident , $($field : ident ),+ $(,)*)=>( fn clone (& self )-> Self {$name {$($field : self . $field . clone ()),* }}); } -macro_rules! __ra_macro_fixture486 {( type FreeFunctions )=>( type FreeFunctions : 'static ;); ( type TokenStream )=>( type TokenStream : 'static + Clone ;); ( type TokenStreamBuilder )=>( type TokenStreamBuilder : 'static ;); ( type TokenStreamIter )=>( type TokenStreamIter : 'static + Clone ;); ( type Group )=>( type Group : 'static + Clone ;); ( type Punct )=>( type Punct : 'static + Copy + Eq + Hash ;); ( type Ident )=>( type Ident : 'static + Copy + Eq + Hash ;); ( type Literal )=>( type Literal : 'static + Clone ;); ( type SourceFile )=>( type SourceFile : 'static + Clone ;); ( type MultiSpan )=>( type MultiSpan : 'static ;); ( type Diagnostic )=>( type Diagnostic : 'static ;); ( type Span )=>( type Span : 'static + Copy + Eq + Hash ;); ( fn drop (& mut self , $arg : ident : $arg_ty : ty ))=>( fn drop (& mut self , $arg : $arg_ty ){ mem :: drop ($arg )}); ( fn clone (& mut self , $arg : ident : $arg_ty : ty )-> $ret_ty : ty )=>( fn clone (& mut self , $arg : $arg_ty )-> $ret_ty {$arg . clone ()}); ($($item : tt )*)=>($($item )*;)} -macro_rules! __ra_macro_fixture487 {($bit : expr , $is_fn_name : ident , $set_fn_name : ident )=>{ fn $is_fn_name (& self )-> bool { self . bools & ( 0b1 << $bit )> 0 } fn $set_fn_name (& mut self , yes : bool ){ if yes { self . bools |= 1 << $bit ; } else { self . bools &= ! ( 1 << $bit ); }}}; } -macro_rules! __ra_macro_fixture488 {($($(# [$cfg : meta ])* fn $method : ident -> $i : ident ; )*)=>{$(# [ inline ]$(# [$cfg ])* fn $method (& self )-> Option <$i > {( self . 0 ).$method ()})*}} -macro_rules! __ra_macro_fixture489 {($($(# [$cfg : meta ])* fn $method : ident ($i : ident ); )*)=>{$(# [ inline ]$(# [$cfg ])* fn $method ( n : $i )-> Option < Self > { T ::$method ( n ). map ( Wrapping )})*}} -macro_rules! __ra_macro_fixture490 {($SrcT : ident : $($(# [$cfg : meta ])* fn $method : ident -> $DstT : ident ; )*)=>{$(# [ inline ]$(# [$cfg ])* fn $method (& self )-> Option <$DstT > { let min = $DstT :: MIN as $SrcT ; let max = $DstT :: MAX as $SrcT ; if size_of ::<$SrcT > ()<= size_of ::<$DstT > ()|| ( min <= * self && * self <= max ){ Some (* self as $DstT )} else { None }})*}} -macro_rules! __ra_macro_fixture491 {($SrcT : ident : $($(# [$cfg : meta ])* fn $method : ident -> $DstT : ident ; )*)=>{$(# [ inline ]$(# [$cfg ])* fn $method (& self )-> Option <$DstT > { let max = $DstT :: MAX as $SrcT ; if 0 <= * self && ( size_of ::<$SrcT > ()<= size_of ::<$DstT > ()|| * self <= max ){ Some (* self as $DstT )} else { None }})*}} -macro_rules! __ra_macro_fixture492 {($SrcT : ident : $($(# [$cfg : meta ])* fn $method : ident -> $DstT : ident ; )*)=>{$(# [ inline ]$(# [$cfg ])* fn $method (& self )-> Option <$DstT > { let max = $DstT :: MAX as $SrcT ; if size_of ::<$SrcT > ()< size_of ::<$DstT > ()|| * self <= max { Some (* self as $DstT )} else { None }})*}} -macro_rules! __ra_macro_fixture493 {($SrcT : ident : $($(# [$cfg : meta ])* fn $method : ident -> $DstT : ident ; )*)=>{$(# [ inline ]$(# [$cfg ])* fn $method (& self )-> Option <$DstT > { let max = $DstT :: MAX as $SrcT ; if size_of ::<$SrcT > ()<= size_of ::<$DstT > ()|| * self <= max { Some (* self as $DstT )} else { None }})*}} -macro_rules! __ra_macro_fixture494 {($f : ident : $($(# [$cfg : meta ])* fn $method : ident -> $i : ident ; )*)=>{$(# [ inline ]$(# [$cfg ])* fn $method (& self )-> Option <$i > { if size_of ::<$f > ()> size_of ::<$i > (){ const MIN_M1 : $f = $i :: MIN as $f - 1.0 ; const MAX_P1 : $f = $i :: MAX as $f + 1.0 ; if * self > MIN_M1 && * self < MAX_P1 { return Some ( float_to_int_unchecked ! (* self =>$i )); }} else { const MIN : $f = $i :: MIN as $f ; const MAX_P1 : $f = $i :: MAX as $f ; if * self >= MIN && * self < MAX_P1 { return Some ( float_to_int_unchecked ! (* self =>$i )); }} None })*}} -macro_rules! __ra_macro_fixture495 {($f : ident : $($(# [$cfg : meta ])* fn $method : ident -> $u : ident ; )*)=>{$(# [ inline ]$(# [$cfg ])* fn $method (& self )-> Option <$u > { if size_of ::<$f > ()> size_of ::<$u > (){ const MAX_P1 : $f = $u :: MAX as $f + 1.0 ; if * self > - 1.0 && * self < MAX_P1 { return Some ( float_to_int_unchecked ! (* self =>$u )); }} else { const MAX_P1 : $f = $u :: MAX as $f ; if * self > - 1.0 && * self < MAX_P1 { return Some ( float_to_int_unchecked ! (* self =>$u )); }} None })*}} -macro_rules! __ra_macro_fixture496 {($SrcT : ident : $(fn $method : ident -> $DstT : ident ; )*)=>{$(# [ inline ] fn $method (& self )-> Option <$DstT > { Some (* self as $DstT )})*}} -macro_rules! __ra_macro_fixture497 {($($method : ident ()-> $ret : expr ; )*)=>{$(# [ inline ] fn $method ()-> Self {$ret })*}; } -macro_rules! __ra_macro_fixture498 {($(Self :: $method : ident ( self $(, $arg : ident : $ty : ty )* )-> $ret : ty ; )*)=>{$(# [ inline ] fn $method ( self $(, $arg : $ty )* )-> $ret { Self ::$method ( self $(, $arg )* )})*}; ($($base : ident :: $method : ident ( self $(, $arg : ident : $ty : ty )* )-> $ret : ty ; )*)=>{$(# [ inline ] fn $method ( self $(, $arg : $ty )* )-> $ret {< Self as $base >::$method ( self $(, $arg )* )})*}; ($($base : ident :: $method : ident ($($arg : ident : $ty : ty ),* )-> $ret : ty ; )*)=>{$(# [ inline ] fn $method ($($arg : $ty ),* )-> $ret {< Self as $base >::$method ($($arg ),* )})*}} -macro_rules! __ra_macro_fixture499 {($tyname : ident , $($($field : ident ).+),*)=>{ fn fmt (& self , f : & mut :: std :: fmt :: Formatter )-> :: std :: fmt :: Result { f . debug_struct ( stringify ! ($tyname ))$(. field ( stringify ! ($($field ).+), & self .$($field ).+))* . finish ()}}} -macro_rules! __ra_macro_fixture500 {($($field : ident ),*)=>{ fn clone (& self )-> Self { Self {$($field : self .$field . clone (),)* }}}} -macro_rules! __ra_macro_fixture501 {($($json : tt )+)=>{ json_internal ! ($($json )+)}; } -macro_rules! __ra_macro_fixture502 {(@ array [$($elems : expr ,)*])=>{ json_internal_vec ! [$($elems ,)*]}; (@ array [$($elems : expr ),*])=>{ json_internal_vec ! [$($elems ),*]}; (@ array [$($elems : expr ,)*] null $($rest : tt )*)=>{ json_internal ! (@ array [$($elems ,)* json_internal ! ( null )]$($rest )*)}; (@ array [$($elems : expr ,)*] true $($rest : tt )*)=>{ json_internal ! (@ array [$($elems ,)* json_internal ! ( true )]$($rest )*)}; (@ array [$($elems : expr ,)*] false $($rest : tt )*)=>{ json_internal ! (@ array [$($elems ,)* json_internal ! ( false )]$($rest )*)}; (@ array [$($elems : expr ,)*][$($array : tt )*]$($rest : tt )*)=>{ json_internal ! (@ array [$($elems ,)* json_internal ! ([$($array )*])]$($rest )*)}; (@ array [$($elems : expr ,)*]{$($map : tt )*}$($rest : tt )*)=>{ json_internal ! (@ array [$($elems ,)* json_internal ! ({$($map )*})]$($rest )*)}; (@ array [$($elems : expr ,)*]$next : expr , $($rest : tt )*)=>{ json_internal ! (@ array [$($elems ,)* json_internal ! ($next ),]$($rest )*)}; (@ array [$($elems : expr ,)*]$last : expr )=>{ json_internal ! (@ array [$($elems ,)* json_internal ! ($last )])}; (@ array [$($elems : expr ),*], $($rest : tt )*)=>{ json_internal ! (@ array [$($elems ,)*]$($rest )*)}; (@ array [$($elems : expr ),*]$unexpected : tt $($rest : tt )*)=>{ json_unexpected ! ($unexpected )}; (@ object $object : ident ()()())=>{}; (@ object $object : ident [$($key : tt )+]($value : expr ), $($rest : tt )*)=>{ let _ = $object . insert (($($key )+). into (), $value ); json_internal ! (@ object $object ()($($rest )*)($($rest )*)); }; (@ object $object : ident [$($key : tt )+]($value : expr )$unexpected : tt $($rest : tt )*)=>{ json_unexpected ! ($unexpected ); }; (@ object $object : ident [$($key : tt )+]($value : expr ))=>{ let _ = $object . insert (($($key )+). into (), $value ); }; (@ object $object : ident ($($key : tt )+)(: null $($rest : tt )*)$copy : tt )=>{ json_internal ! (@ object $object [$($key )+]( json_internal ! ( null ))$($rest )*); }; (@ object $object : ident ($($key : tt )+)(: true $($rest : tt )*)$copy : tt )=>{ json_internal ! (@ object $object [$($key )+]( json_internal ! ( true ))$($rest )*); }; (@ object $object : ident ($($key : tt )+)(: false $($rest : tt )*)$copy : tt )=>{ json_internal ! (@ object $object [$($key )+]( json_internal ! ( false ))$($rest )*); }; (@ object $object : ident ($($key : tt )+)(: [$($array : tt )*]$($rest : tt )*)$copy : tt )=>{ json_internal ! (@ object $object [$($key )+]( json_internal ! ([$($array )*]))$($rest )*); }; (@ object $object : ident ($($key : tt )+)(: {$($map : tt )*}$($rest : tt )*)$copy : tt )=>{ json_internal ! (@ object $object [$($key )+]( json_internal ! ({$($map )*}))$($rest )*); }; (@ object $object : ident ($($key : tt )+)(: $value : expr , $($rest : tt )*)$copy : tt )=>{ json_internal ! (@ object $object [$($key )+]( json_internal ! ($value )), $($rest )*); }; (@ object $object : ident ($($key : tt )+)(: $value : expr )$copy : tt )=>{ json_internal ! (@ object $object [$($key )+]( json_internal ! ($value ))); }; (@ object $object : ident ($($key : tt )+)(:)$copy : tt )=>{ json_internal ! (); }; (@ object $object : ident ($($key : tt )+)()$copy : tt )=>{ json_internal ! (); }; (@ object $object : ident ()(: $($rest : tt )*)($colon : tt $($copy : tt )*))=>{ json_unexpected ! ($colon ); }; (@ object $object : ident ($($key : tt )*)(, $($rest : tt )*)($comma : tt $($copy : tt )*))=>{ json_unexpected ! ($comma ); }; (@ object $object : ident ()(($key : expr ): $($rest : tt )*)$copy : tt )=>{ json_internal ! (@ object $object ($key )(: $($rest )*)(: $($rest )*)); }; (@ object $object : ident ($($key : tt )*)(: $($unexpected : tt )+)$copy : tt )=>{ json_expect_expr_comma ! ($($unexpected )+); }; (@ object $object : ident ($($key : tt )*)($tt : tt $($rest : tt )*)$copy : tt )=>{ json_internal ! (@ object $object ($($key )* $tt )($($rest )*)($($rest )*)); }; ( null )=>{$crate :: Value :: Null }; ( true )=>{$crate :: Value :: Bool ( true )}; ( false )=>{$crate :: Value :: Bool ( false )}; ([])=>{$crate :: Value :: Array ( json_internal_vec ! [])}; ([$($tt : tt )+ ])=>{$crate :: Value :: Array ( json_internal ! (@ array []$($tt )+))}; ({})=>{$crate :: Value :: Object ($crate :: Map :: new ())}; ({$($tt : tt )+ })=>{$crate :: Value :: Object ({ let mut object = $crate :: Map :: new (); json_internal ! (@ object object ()($($tt )+)($($tt )+)); object })}; ($other : expr )=>{$crate :: to_value (&$other ). unwrap ()}; } -macro_rules! __ra_macro_fixture503 {($($content : tt )*)=>{ vec ! [$($content )*]}; } -macro_rules! __ra_macro_fixture504 {($($cfg : tt )*)=>{}; } -macro_rules! __ra_macro_fixture505 {($($tokens : tt )*)=>{$crate :: crossbeam_channel_internal ! ($($tokens )* )}; } -macro_rules! __ra_macro_fixture506 {(@ list ()($($head : tt )*))=>{$crate :: crossbeam_channel_internal ! (@ case ($($head )*)()())}; (@ list ( default =>$($tail : tt )*)($($head : tt )*))=>{$crate :: crossbeam_channel_internal ! (@ list ( default ()=>$($tail )*)($($head )*))}; (@ list ( default -> $($tail : tt )*)($($head : tt )*))=>{ compile_error ! ( "expected `=>` after `default` case, found `->`" )}; (@ list ( default $args : tt -> $($tail : tt )*)($($head : tt )*))=>{ compile_error ! ( "expected `=>` after `default` case, found `->`" )}; (@ list ( recv ($($args : tt )*)=>$($tail : tt )*)($($head : tt )*))=>{ compile_error ! ( "expected `->` after `recv` case, found `=>`" )}; (@ list ( send ($($args : tt )*)=>$($tail : tt )*)($($head : tt )*))=>{ compile_error ! ( "expected `->` after `send` operation, found `=>`" )}; (@ list ($case : ident $args : tt -> $res : tt -> $($tail : tt )*)($($head : tt )*))=>{ compile_error ! ( "expected `=>`, found `->`" )}; (@ list ($case : ident $args : tt $(-> $res : pat )* =>$body : block ; $($tail : tt )*)($($head : tt )*))=>{ compile_error ! ( "did you mean to put a comma instead of the semicolon after `}`?" )}; (@ list ($case : ident ($($args : tt )*)$(-> $res : pat )* =>$body : expr , $($tail : tt )*)($($head : tt )*))=>{$crate :: crossbeam_channel_internal ! (@ list ($($tail )*)($($head )* $case ($($args )*)$(-> $res )* =>{$body },))}; (@ list ($case : ident ($($args : tt )*)$(-> $res : pat )* =>$body : block $($tail : tt )*)($($head : tt )*))=>{$crate :: crossbeam_channel_internal ! (@ list ($($tail )*)($($head )* $case ($($args )*)$(-> $res )* =>{$body },))}; (@ list ($case : ident ($($args : tt )*)$(-> $res : pat )* =>$body : expr )($($head : tt )*))=>{$crate :: crossbeam_channel_internal ! (@ list ()($($head )* $case ($($args )*)$(-> $res )* =>{$body },))}; (@ list ($case : ident ($($args : tt )*)$(-> $res : pat )* =>$body : expr ,)($($head : tt )*))=>{$crate :: crossbeam_channel_internal ! (@ list ()($($head )* $case ($($args )*)$(-> $res )* =>{$body },))}; (@ list ($($tail : tt )*)($($head : tt )*))=>{$crate :: crossbeam_channel_internal ! (@ list_error1 $($tail )*)}; (@ list_error1 recv $($tail : tt )*)=>{$crate :: crossbeam_channel_internal ! (@ list_error2 recv $($tail )*)}; (@ list_error1 send $($tail : tt )*)=>{$crate :: crossbeam_channel_internal ! (@ list_error2 send $($tail )*)}; (@ list_error1 default $($tail : tt )*)=>{$crate :: crossbeam_channel_internal ! (@ list_error2 default $($tail )*)}; (@ list_error1 $t : tt $($tail : tt )*)=>{ compile_error ! ( concat ! ( "expected one of `recv`, `send`, or `default`, found `" , stringify ! ($t ), "`" , ))}; (@ list_error1 $($tail : tt )*)=>{$crate :: crossbeam_channel_internal ! (@ list_error2 $($tail )*); }; (@ list_error2 $case : ident )=>{ compile_error ! ( concat ! ( "missing argument list after `" , stringify ! ($case ), "`" , ))}; (@ list_error2 $case : ident =>$($tail : tt )*)=>{ compile_error ! ( concat ! ( "missing argument list after `" , stringify ! ($case ), "`" , ))}; (@ list_error2 $($tail : tt )*)=>{$crate :: crossbeam_channel_internal ! (@ list_error3 $($tail )*)}; (@ list_error3 $case : ident ($($args : tt )*)$(-> $r : pat )*)=>{ compile_error ! ( concat ! ( "missing `=>` after `" , stringify ! ($case ), "` case" , ))}; (@ list_error3 $case : ident ($($args : tt )*)$(-> $r : pat )* =>)=>{ compile_error ! ( "expected expression after `=>`" )}; (@ list_error3 $case : ident ($($args : tt )*)$(-> $r : pat )* =>$body : expr ; $($tail : tt )*)=>{ compile_error ! ( concat ! ( "did you mean to put a comma instead of the semicolon after `" , stringify ! ($body ), "`?" , ))}; (@ list_error3 $case : ident ($($args : tt )*)$(-> $r : pat )* => recv ($($a : tt )*)$($tail : tt )*)=>{ compile_error ! ( "expected an expression after `=>`" )}; (@ list_error3 $case : ident ($($args : tt )*)$(-> $r : pat )* => send ($($a : tt )*)$($tail : tt )*)=>{ compile_error ! ( "expected an expression after `=>`" )}; (@ list_error3 $case : ident ($($args : tt )*)$(-> $r : pat )* => default ($($a : tt )*)$($tail : tt )*)=>{ compile_error ! ( "expected an expression after `=>`" )}; (@ list_error3 $case : ident ($($args : tt )*)$(-> $r : pat )* =>$f : ident ($($a : tt )*)$($tail : tt )*)=>{ compile_error ! ( concat ! ( "did you mean to put a comma after `" , stringify ! ($f ), "(" , stringify ! ($($a )*), ")`?" , ))}; (@ list_error3 $case : ident ($($args : tt )*)$(-> $r : pat )* =>$f : ident ! ($($a : tt )*)$($tail : tt )*)=>{ compile_error ! ( concat ! ( "did you mean to put a comma after `" , stringify ! ($f ), "!(" , stringify ! ($($a )*), ")`?" , ))}; (@ list_error3 $case : ident ($($args : tt )*)$(-> $r : pat )* =>$f : ident ! [$($a : tt )*]$($tail : tt )*)=>{ compile_error ! ( concat ! ( "did you mean to put a comma after `" , stringify ! ($f ), "![" , stringify ! ($($a )*), "]`?" , ))}; (@ list_error3 $case : ident ($($args : tt )*)$(-> $r : pat )* =>$f : ident ! {$($a : tt )*}$($tail : tt )*)=>{ compile_error ! ( concat ! ( "did you mean to put a comma after `" , stringify ! ($f ), "!{" , stringify ! ($($a )*), "}`?" , ))}; (@ list_error3 $case : ident ($($args : tt )*)$(-> $r : pat )* =>$body : tt $($tail : tt )*)=>{ compile_error ! ( concat ! ( "did you mean to put a comma after `" , stringify ! ($body ), "`?" , ))}; (@ list_error3 $case : ident ($($args : tt )*)-> =>$($tail : tt )*)=>{ compile_error ! ( "missing pattern after `->`" )}; (@ list_error3 $case : ident ($($args : tt )*)$t : tt $(-> $r : pat )* =>$($tail : tt )*)=>{ compile_error ! ( concat ! ( "expected `->`, found `" , stringify ! ($t ), "`" , ))}; (@ list_error3 $case : ident ($($args : tt )*)-> $t : tt $($tail : tt )*)=>{ compile_error ! ( concat ! ( "expected a pattern, found `" , stringify ! ($t ), "`" , ))}; (@ list_error3 recv ($($args : tt )*)$t : tt $($tail : tt )*)=>{ compile_error ! ( concat ! ( "expected `->`, found `" , stringify ! ($t ), "`" , ))}; (@ list_error3 send ($($args : tt )*)$t : tt $($tail : tt )*)=>{ compile_error ! ( concat ! ( "expected `->`, found `" , stringify ! ($t ), "`" , ))}; (@ list_error3 recv $args : tt $($tail : tt )*)=>{ compile_error ! ( concat ! ( "expected an argument list after `recv`, found `" , stringify ! ($args ), "`" , ))}; (@ list_error3 send $args : tt $($tail : tt )*)=>{ compile_error ! ( concat ! ( "expected an argument list after `send`, found `" , stringify ! ($args ), "`" , ))}; (@ list_error3 default $args : tt $($tail : tt )*)=>{ compile_error ! ( concat ! ( "expected an argument list or `=>` after `default`, found `" , stringify ! ($args ), "`" , ))}; (@ list_error3 $($tail : tt )*)=>{$crate :: crossbeam_channel_internal ! (@ list_error4 $($tail )*)}; (@ list_error4 $($tail : tt )*)=>{ compile_error ! ( "invalid syntax" )}; (@ case ()$cases : tt $default : tt )=>{$crate :: crossbeam_channel_internal ! (@ init $cases $default )}; (@ case ( recv ($r : expr )-> $res : pat =>$body : tt , $($tail : tt )*)($($cases : tt )*)$default : tt )=>{$crate :: crossbeam_channel_internal ! (@ case ($($tail )*)($($cases )* recv ($r )-> $res =>$body ,)$default )}; (@ case ( recv ($r : expr ,)-> $res : pat =>$body : tt , $($tail : tt )*)($($cases : tt )*)$default : tt )=>{$crate :: crossbeam_channel_internal ! (@ case ($($tail )*)($($cases )* recv ($r )-> $res =>$body ,)$default )}; (@ case ( recv ($($args : tt )*)-> $res : pat =>$body : tt , $($tail : tt )*)($($cases : tt )*)$default : tt )=>{ compile_error ! ( concat ! ( "invalid argument list in `recv(" , stringify ! ($($args )*), ")`" , ))}; (@ case ( recv $t : tt $($tail : tt )*)($($cases : tt )*)$default : tt )=>{ compile_error ! ( concat ! ( "expected an argument list after `recv`, found `" , stringify ! ($t ), "`" , ))}; (@ case ( send ($s : expr , $m : expr )-> $res : pat =>$body : tt , $($tail : tt )*)($($cases : tt )*)$default : tt )=>{$crate :: crossbeam_channel_internal ! (@ case ($($tail )*)($($cases )* send ($s , $m )-> $res =>$body ,)$default )}; (@ case ( send ($s : expr , $m : expr ,)-> $res : pat =>$body : tt , $($tail : tt )*)($($cases : tt )*)$default : tt )=>{$crate :: crossbeam_channel_internal ! (@ case ($($tail )*)($($cases )* send ($s , $m )-> $res =>$body ,)$default )}; (@ case ( send ($($args : tt )*)-> $res : pat =>$body : tt , $($tail : tt )*)($($cases : tt )*)$default : tt )=>{ compile_error ! ( concat ! ( "invalid argument list in `send(" , stringify ! ($($args )*), ")`" , ))}; (@ case ( send $t : tt $($tail : tt )*)($($cases : tt )*)$default : tt )=>{ compile_error ! ( concat ! ( "expected an argument list after `send`, found `" , stringify ! ($t ), "`" , ))}; (@ case ( default ()=>$body : tt , $($tail : tt )*)$cases : tt ())=>{$crate :: crossbeam_channel_internal ! (@ case ($($tail )*)$cases ( default ()=>$body ,))}; (@ case ( default ($timeout : expr )=>$body : tt , $($tail : tt )*)$cases : tt ())=>{$crate :: crossbeam_channel_internal ! (@ case ($($tail )*)$cases ( default ($timeout )=>$body ,))}; (@ case ( default ($timeout : expr ,)=>$body : tt , $($tail : tt )*)$cases : tt ())=>{$crate :: crossbeam_channel_internal ! (@ case ($($tail )*)$cases ( default ($timeout )=>$body ,))}; (@ case ( default $($tail : tt )*)$cases : tt ($($def : tt )+))=>{ compile_error ! ( "there can be only one `default` case in a `select!` block" )}; (@ case ( default ($($args : tt )*)=>$body : tt , $($tail : tt )*)$cases : tt $default : tt )=>{ compile_error ! ( concat ! ( "invalid argument list in `default(" , stringify ! ($($args )*), ")`" , ))}; (@ case ( default $t : tt $($tail : tt )*)$cases : tt $default : tt )=>{ compile_error ! ( concat ! ( "expected an argument list or `=>` after `default`, found `" , stringify ! ($t ), "`" , ))}; (@ case ($case : ident $($tail : tt )*)$cases : tt $default : tt )=>{ compile_error ! ( concat ! ( "expected one of `recv`, `send`, or `default`, found `" , stringify ! ($case ), "`" , ))}; (@ init ( recv ($r : expr )-> $res : pat =>$recv_body : tt ,)( default ()=>$default_body : tt ,))=>{{ match $r { ref _r =>{ let _r : &$crate :: Receiver <_> = _r ; match _r . try_recv (){:: std :: result :: Result :: Err ($crate :: TryRecvError :: Empty )=>{$default_body } _res =>{ let _res = _res . map_err (|_| $crate :: RecvError ); let $res = _res ; $recv_body }}}}}}; (@ init ( recv ($r : expr )-> $res : pat =>$body : tt ,)())=>{{ match $r { ref _r =>{ let _r : &$crate :: Receiver <_> = _r ; let _res = _r . recv (); let $res = _res ; $body }}}}; (@ init ( recv ($r : expr )-> $res : pat =>$recv_body : tt ,)( default ($timeout : expr )=>$default_body : tt ,))=>{{ match $r { ref _r =>{ let _r : &$crate :: Receiver <_> = _r ; match _r . recv_timeout ($timeout ){:: std :: result :: Result :: Err ($crate :: RecvTimeoutError :: Timeout )=>{$default_body } _res =>{ let _res = _res . map_err (|_| $crate :: RecvError ); let $res = _res ; $recv_body }}}}}}; (@ init ($($cases : tt )*)$default : tt )=>{{ const _LEN : usize = $crate :: crossbeam_channel_internal ! (@ count ($($cases )*)); let _handle : &$crate :: internal :: SelectHandle = &$crate :: never ::< ()> (); # [ allow ( unused_mut )] let mut _sel = [( _handle , 0 , :: std :: ptr :: null ()); _LEN ]; $crate :: crossbeam_channel_internal ! (@ add _sel ($($cases )*)$default (( 0usize _oper0 )( 1usize _oper1 )( 2usize _oper2 )( 3usize _oper3 )( 4usize _oper4 )( 5usize _oper5 )( 6usize _oper6 )( 7usize _oper7 )( 8usize _oper8 )( 9usize _oper9 )( 10usize _oper10 )( 11usize _oper11 )( 12usize _oper12 )( 13usize _oper13 )( 14usize _oper14 )( 15usize _oper15 )( 16usize _oper16 )( 17usize _oper17 )( 18usize _oper18 )( 19usize _oper19 )( 20usize _oper20 )( 21usize _oper21 )( 22usize _oper22 )( 23usize _oper23 )( 24usize _oper24 )( 25usize _oper25 )( 26usize _oper26 )( 27usize _oper27 )( 28usize _oper28 )( 29usize _oper29 )( 30usize _oper30 )( 31usize _oper31 ))())}}; (@ count ())=>{ 0 }; (@ count ($oper : ident $args : tt -> $res : pat =>$body : tt , $($cases : tt )*))=>{ 1 + $crate :: crossbeam_channel_internal ! (@ count ($($cases )*))}; (@ add $sel : ident ()()$labels : tt $cases : tt )=>{{ let _oper : $crate :: SelectedOperation < '_ > = { let _oper = $crate :: internal :: select (& mut $sel ); unsafe {:: std :: mem :: transmute ( _oper )}}; $crate :: crossbeam_channel_internal ! {@ complete $sel _oper $cases }}}; (@ add $sel : ident ()( default ()=>$body : tt ,)$labels : tt $cases : tt )=>{{ let _oper : :: std :: option :: Option <$crate :: SelectedOperation < '_ >> = { let _oper = $crate :: internal :: try_select (& mut $sel ); unsafe {:: std :: mem :: transmute ( _oper )}}; match _oper { None =>{{$sel }; $body } Some ( _oper )=>{$crate :: crossbeam_channel_internal ! {@ complete $sel _oper $cases }}}}}; (@ add $sel : ident ()( default ($timeout : expr )=>$body : tt ,)$labels : tt $cases : tt )=>{{ let _oper : :: std :: option :: Option <$crate :: SelectedOperation < '_ >> = { let _oper = $crate :: internal :: select_timeout (& mut $sel , $timeout ); unsafe {:: std :: mem :: transmute ( _oper )}}; match _oper {:: std :: option :: Option :: None =>{{$sel }; $body }:: std :: option :: Option :: Some ( _oper )=>{$crate :: crossbeam_channel_internal ! {@ complete $sel _oper $cases }}}}}; (@ add $sel : ident $input : tt $default : tt ()$cases : tt )=>{ compile_error ! ( "too many operations in a `select!` block" )}; (@ add $sel : ident ( recv ($r : expr )-> $res : pat =>$body : tt , $($tail : tt )*)$default : tt (($i : tt $var : ident )$($labels : tt )*)($($cases : tt )*))=>{{ match $r { ref _r =>{ let $var : &$crate :: Receiver <_> = unsafe { let _r : &$crate :: Receiver <_> = _r ; unsafe fn unbind < 'a , T > ( x : & T )-> & 'a T {:: std :: mem :: transmute ( x )} unbind ( _r )}; $sel [$i ]= ($var , $i , $var as * const $crate :: Receiver <_> as * const u8 ); $crate :: crossbeam_channel_internal ! (@ add $sel ($($tail )*)$default ($($labels )*)($($cases )* [$i ] recv ($var )-> $res =>$body ,))}}}}; (@ add $sel : ident ( send ($s : expr , $m : expr )-> $res : pat =>$body : tt , $($tail : tt )*)$default : tt (($i : tt $var : ident )$($labels : tt )*)($($cases : tt )*))=>{{ match $s { ref _s =>{ let $var : &$crate :: Sender <_> = unsafe { let _s : &$crate :: Sender <_> = _s ; unsafe fn unbind < 'a , T > ( x : & T )-> & 'a T {:: std :: mem :: transmute ( x )} unbind ( _s )}; $sel [$i ]= ($var , $i , $var as * const $crate :: Sender <_> as * const u8 ); $crate :: crossbeam_channel_internal ! (@ add $sel ($($tail )*)$default ($($labels )*)($($cases )* [$i ] send ($var , $m )-> $res =>$body ,))}}}}; (@ complete $sel : ident $oper : ident ([$i : tt ] recv ($r : ident )-> $res : pat =>$body : tt , $($tail : tt )*))=>{{ if $oper . index ()== $i { let _res = $oper . recv ($r ); {$sel }; let $res = _res ; $body } else {$crate :: crossbeam_channel_internal ! {@ complete $sel $oper ($($tail )*)}}}}; (@ complete $sel : ident $oper : ident ([$i : tt ] send ($s : ident , $m : expr )-> $res : pat =>$body : tt , $($tail : tt )*))=>{{ if $oper . index ()== $i { let _res = $oper . send ($s , $m ); {$sel }; let $res = _res ; $body } else {$crate :: crossbeam_channel_internal ! {@ complete $sel $oper ($($tail )*)}}}}; (@ complete $sel : ident $oper : ident ())=>{{ unreachable ! ( "internal error in crossbeam-channel: invalid case" )}}; (@$($tokens : tt )*)=>{ compile_error ! ( concat ! ( "internal error in crossbeam-channel: " , stringify ! (@$($tokens )*), ))}; ()=>{ compile_error ! ( "empty `select!` block" )}; ($($case : ident $(($($args : tt )*))* =>$body : expr $(,)*)*)=>{$crate :: crossbeam_channel_internal ! (@ list ($($case $(($($args )*))* =>{$body },)*)())}; ($($tokens : tt )*)=>{$crate :: crossbeam_channel_internal ! (@ list ($($tokens )*)())}; } -macro_rules! __ra_macro_fixture507 {($($tokens : tt )*)=>{ return Err ( crate :: errors :: error ! ($($tokens )*))}} -macro_rules! __ra_macro_fixture508 {($fmt : expr )=>{$crate :: SsrError :: new ( format ! ($fmt ))}; ($fmt : expr , $($arg : tt )+)=>{$crate :: SsrError :: new ( format ! ($fmt , $($arg )+))}} -macro_rules! __ra_macro_fixture509 {[;]=>{$crate :: SyntaxKind :: SEMICOLON }; [,]=>{$crate :: SyntaxKind :: COMMA }; [ '(' ]=>{$crate :: SyntaxKind :: L_PAREN }; [ ')' ]=>{$crate :: SyntaxKind :: R_PAREN }; [ '{' ]=>{$crate :: SyntaxKind :: L_CURLY }; [ '}' ]=>{$crate :: SyntaxKind :: R_CURLY }; [ '[' ]=>{$crate :: SyntaxKind :: L_BRACK }; [ ']' ]=>{$crate :: SyntaxKind :: R_BRACK }; [<]=>{$crate :: SyntaxKind :: L_ANGLE }; [>]=>{$crate :: SyntaxKind :: R_ANGLE }; [@]=>{$crate :: SyntaxKind :: AT }; [#]=>{$crate :: SyntaxKind :: POUND }; [~]=>{$crate :: SyntaxKind :: TILDE }; [?]=>{$crate :: SyntaxKind :: QUESTION }; [$]=>{$crate :: SyntaxKind :: DOLLAR }; [&]=>{$crate :: SyntaxKind :: AMP }; [|]=>{$crate :: SyntaxKind :: PIPE }; [+]=>{$crate :: SyntaxKind :: PLUS }; [*]=>{$crate :: SyntaxKind :: STAR }; [/]=>{$crate :: SyntaxKind :: SLASH }; [^]=>{$crate :: SyntaxKind :: CARET }; [%]=>{$crate :: SyntaxKind :: PERCENT }; [_]=>{$crate :: SyntaxKind :: UNDERSCORE }; [.]=>{$crate :: SyntaxKind :: DOT }; [..]=>{$crate :: SyntaxKind :: DOT2 }; [...]=>{$crate :: SyntaxKind :: DOT3 }; [..=]=>{$crate :: SyntaxKind :: DOT2EQ }; [:]=>{$crate :: SyntaxKind :: COLON }; [::]=>{$crate :: SyntaxKind :: COLON2 }; [=]=>{$crate :: SyntaxKind :: EQ }; [==]=>{$crate :: SyntaxKind :: EQ2 }; [=>]=>{$crate :: SyntaxKind :: FAT_ARROW }; [!]=>{$crate :: SyntaxKind :: BANG }; [!=]=>{$crate :: SyntaxKind :: NEQ }; [-]=>{$crate :: SyntaxKind :: MINUS }; [->]=>{$crate :: SyntaxKind :: THIN_ARROW }; [<=]=>{$crate :: SyntaxKind :: LTEQ }; [>=]=>{$crate :: SyntaxKind :: GTEQ }; [+=]=>{$crate :: SyntaxKind :: PLUSEQ }; [-=]=>{$crate :: SyntaxKind :: MINUSEQ }; [|=]=>{$crate :: SyntaxKind :: PIPEEQ }; [&=]=>{$crate :: SyntaxKind :: AMPEQ }; [^=]=>{$crate :: SyntaxKind :: CARETEQ }; [/=]=>{$crate :: SyntaxKind :: SLASHEQ }; [*=]=>{$crate :: SyntaxKind :: STAREQ }; [%=]=>{$crate :: SyntaxKind :: PERCENTEQ }; [&&]=>{$crate :: SyntaxKind :: AMP2 }; [||]=>{$crate :: SyntaxKind :: PIPE2 }; [<<]=>{$crate :: SyntaxKind :: SHL }; [>>]=>{$crate :: SyntaxKind :: SHR }; [<<=]=>{$crate :: SyntaxKind :: SHLEQ }; [>>=]=>{$crate :: SyntaxKind :: SHREQ }; [ as ]=>{$crate :: SyntaxKind :: AS_KW }; [ async ]=>{$crate :: SyntaxKind :: ASYNC_KW }; [ await ]=>{$crate :: SyntaxKind :: AWAIT_KW }; [ box ]=>{$crate :: SyntaxKind :: BOX_KW }; [ break ]=>{$crate :: SyntaxKind :: BREAK_KW }; [ const ]=>{$crate :: SyntaxKind :: CONST_KW }; [ continue ]=>{$crate :: SyntaxKind :: CONTINUE_KW }; [ crate ]=>{$crate :: SyntaxKind :: CRATE_KW }; [ dyn ]=>{$crate :: SyntaxKind :: DYN_KW }; [ else ]=>{$crate :: SyntaxKind :: ELSE_KW }; [ enum ]=>{$crate :: SyntaxKind :: ENUM_KW }; [ extern ]=>{$crate :: SyntaxKind :: EXTERN_KW }; [ false ]=>{$crate :: SyntaxKind :: FALSE_KW }; [ fn ]=>{$crate :: SyntaxKind :: FN_KW }; [ for ]=>{$crate :: SyntaxKind :: FOR_KW }; [ if ]=>{$crate :: SyntaxKind :: IF_KW }; [ impl ]=>{$crate :: SyntaxKind :: IMPL_KW }; [ in ]=>{$crate :: SyntaxKind :: IN_KW }; [ let ]=>{$crate :: SyntaxKind :: LET_KW }; [ loop ]=>{$crate :: SyntaxKind :: LOOP_KW }; [ macro ]=>{$crate :: SyntaxKind :: MACRO_KW }; [ match ]=>{$crate :: SyntaxKind :: MATCH_KW }; [ mod ]=>{$crate :: SyntaxKind :: MOD_KW }; [ move ]=>{$crate :: SyntaxKind :: MOVE_KW }; [ mut ]=>{$crate :: SyntaxKind :: MUT_KW }; [ pub ]=>{$crate :: SyntaxKind :: PUB_KW }; [ ref ]=>{$crate :: SyntaxKind :: REF_KW }; [ return ]=>{$crate :: SyntaxKind :: RETURN_KW }; [ self ]=>{$crate :: SyntaxKind :: SELF_KW }; [ static ]=>{$crate :: SyntaxKind :: STATIC_KW }; [ struct ]=>{$crate :: SyntaxKind :: STRUCT_KW }; [ super ]=>{$crate :: SyntaxKind :: SUPER_KW }; [ trait ]=>{$crate :: SyntaxKind :: TRAIT_KW }; [ true ]=>{$crate :: SyntaxKind :: TRUE_KW }; [ try ]=>{$crate :: SyntaxKind :: TRY_KW }; [ type ]=>{$crate :: SyntaxKind :: TYPE_KW }; [ unsafe ]=>{$crate :: SyntaxKind :: UNSAFE_KW }; [ use ]=>{$crate :: SyntaxKind :: USE_KW }; [ where ]=>{$crate :: SyntaxKind :: WHERE_KW }; [ while ]=>{$crate :: SyntaxKind :: WHILE_KW }; [ yield ]=>{$crate :: SyntaxKind :: YIELD_KW }; [ auto ]=>{$crate :: SyntaxKind :: AUTO_KW }; [ default ]=>{$crate :: SyntaxKind :: DEFAULT_KW }; [ existential ]=>{$crate :: SyntaxKind :: EXISTENTIAL_KW }; [ union ]=>{$crate :: SyntaxKind :: UNION_KW }; [ raw ]=>{$crate :: SyntaxKind :: RAW_KW }; [ macro_rules ]=>{$crate :: SyntaxKind :: MACRO_RULES_KW }; [ lifetime_ident ]=>{$crate :: SyntaxKind :: LIFETIME_IDENT }; [ ident ]=>{$crate :: SyntaxKind :: IDENT }; [ shebang ]=>{$crate :: SyntaxKind :: SHEBANG }; } -macro_rules! __ra_macro_fixture510 {($($args : tt )*)=>{ return Err ( match_error ! ($($args )*))}; } -macro_rules! __ra_macro_fixture511 {($e : expr )=>{{ MatchFailed { reason : if recording_match_fail_reasons (){ Some ( format ! ( "{}" , $e ))} else { None }}}}; ($fmt : expr , $($arg : tt )+)=>{{ MatchFailed { reason : if recording_match_fail_reasons (){ Some ( format ! ($fmt , $($arg )+))} else { None }}}}; } -macro_rules! __ra_macro_fixture512 {()=>($crate :: print ! ( "\n" )); ($($arg : tt )*)=>({$crate :: io :: _print ($crate :: format_args_nl ! ($($arg )*)); })} -macro_rules! __ra_macro_fixture513 {($cmd : tt )=>{{# [ cfg ( trick_rust_analyzer_into_highlighting_interpolated_bits )] format_args ! ($cmd ); use $crate :: Cmd as __CMD ; let cmd : $crate :: Cmd = $crate :: __cmd ! ( __CMD $cmd ); cmd }}; } -macro_rules! __ra_macro_fixture514 {($reader : ident , $s : ident ;)=>{}; ($reader : ident , $s : ident ; $first : ident : $first_ty : ty $(, $rest : ident : $rest_ty : ty )*)=>{ reverse_decode ! ($reader , $s ; $($rest : $rest_ty ),*); let $first = <$first_ty >:: decode (& mut $reader , $s ); }} -macro_rules! __ra_macro_fixture515 {($kind : ident , $($ty : ty ),*)=>{ match $kind {$(stringify ! ($ty )=>{ let n : $ty = n . parse (). unwrap (); format ! ( concat ! ( "{}" , stringify ! ($ty )), n )})* _ => unimplemented ! ( "unknown args for typed_integer: n {}, kind {}" , n , $kind ), }}} -macro_rules! __ra_macro_fixture516 {()=>( panic ! ( "not implemented" )); ($($arg : tt )+)=>( panic ! ( "not implemented: {}" , $crate :: format_args ! ($($arg )+))); } -macro_rules! __ra_macro_fixture517 {($cond : expr )=>{{ let cond = !$crate :: always ! (!$cond ); cond }}; ($cond : expr , $fmt : literal $($arg : tt )*)=>{{ let cond = !$crate :: always ! (!$cond , $fmt $($arg )*); cond }}; } -macro_rules! __ra_macro_fixture518 {($cond : expr )=>{$crate :: always ! ($cond , "assertion failed: {}" , stringify ! ($cond ))}; ($cond : expr , $fmt : literal $($arg : tt )*)=>{{ let cond = $cond ; if cfg ! ( debug_assertions )|| $crate :: __FORCE { assert ! ( cond , $fmt $($arg )*); } if ! cond {$crate :: __log_error ! ($fmt $($arg )*); } cond }}; } -macro_rules! __ra_macro_fixture519 {($msg : literal $(,)?)=>{ return $crate :: private :: Err ($crate :: anyhow ! ($msg ))}; ($err : expr $(,)?)=>{ return $crate :: private :: Err ($crate :: anyhow ! ($err ))}; ($fmt : expr , $($arg : tt )*)=>{ return $crate :: private :: Err ($crate :: anyhow ! ($fmt , $($arg )*))}; } -macro_rules! __ra_macro_fixture520 {($msg : literal $(,)?)=>{$crate :: private :: new_adhoc ($msg )}; ($err : expr $(,)?)=>({ use $crate :: private :: kind ::*; match $err { error =>(& error ). anyhow_kind (). new ( error ), }}); ($fmt : expr , $($arg : tt )*)=>{$crate :: private :: new_adhoc ( format ! ($fmt , $($arg )*))}; } -macro_rules! __ra_macro_fixture521 {( target : $target : expr , $($arg : tt )+)=>( log ! ( target : $target , $crate :: Level :: Info , $($arg )+)); ($($arg : tt )+)=>( log ! ($crate :: Level :: Info , $($arg )+))} -macro_rules! __ra_macro_fixture522 {[$($sl : expr , $sc : expr ; $el : expr , $ec : expr =>$text : expr ),+]=>{ vec ! [$(TextDocumentContentChangeEvent { range : Some ( Range { start : Position { line : $sl , character : $sc }, end : Position { line : $el , character : $ec }, }), range_length : None , text : String :: from ($text ), }),+]}; } -macro_rules! __ra_macro_fixture523 {[$path : expr ]=>{$crate :: ExpectFile { path : std :: path :: PathBuf :: from ($path ), position : file ! (), }}; } -macro_rules! __ra_macro_fixture524 {($($key : literal : $value : tt ),*$(,)?)=>{{$(map . insert ($key . into (), serde_json :: json ! ($value )); )*}}; } -macro_rules! __ra_macro_fixture525 {($expr : expr , $or : expr )=>{ try_ ! ($expr ). unwrap_or ($or )}; } -macro_rules! __ra_macro_fixture526 {($expr : expr )=>{|| -> _ { Some ($expr )}()}; } -macro_rules! __ra_macro_fixture527 {($($arg : tt )*)=>($crate :: io :: _print ($crate :: format_args ! ($($arg )*))); } -macro_rules! __ra_macro_fixture528 {($fmt : literal , $($tt : tt ),*)=>{ mbe :: ExpandError :: ProcMacroError ( tt :: ExpansionError :: Unknown ( format ! ($fmt , $($tt ),*)))}; ($fmt : literal )=>{ mbe :: ExpandError :: ProcMacroError ( tt :: ExpansionError :: Unknown ($fmt . to_string ()))}} -macro_rules! __ra_macro_fixture529 {($($tt : tt )* )=>{$crate :: quote :: IntoTt :: to_subtree ($crate :: __quote ! ($($tt )*))}} -macro_rules! __ra_macro_fixture530 {()=>{ Vec ::< tt :: TokenTree >:: new ()}; (@ SUBTREE $delim : ident $($tt : tt )* )=>{{ let children = $crate :: __quote ! ($($tt )*); tt :: Subtree { delimiter : Some ( tt :: Delimiter { kind : tt :: DelimiterKind ::$delim , id : tt :: TokenId :: unspecified (), }), token_trees : $crate :: quote :: IntoTt :: to_tokens ( children ), }}}; (@ PUNCT $first : literal )=>{{ vec ! [ tt :: Leaf :: Punct ( tt :: Punct { char : $first , spacing : tt :: Spacing :: Alone , id : tt :: TokenId :: unspecified (), }). into ()]}}; (@ PUNCT $first : literal , $sec : literal )=>{{ vec ! [ tt :: Leaf :: Punct ( tt :: Punct { char : $first , spacing : tt :: Spacing :: Joint , id : tt :: TokenId :: unspecified (), }). into (), tt :: Leaf :: Punct ( tt :: Punct { char : $sec , spacing : tt :: Spacing :: Alone , id : tt :: TokenId :: unspecified (), }). into ()]}}; (# $first : ident $($tail : tt )* )=>{{ let token = $crate :: quote :: ToTokenTree :: to_token ($first ); let mut tokens = vec ! [ token . into ()]; let mut tail_tokens = $crate :: quote :: IntoTt :: to_tokens ($crate :: __quote ! ($($tail )*)); tokens . append (& mut tail_tokens ); tokens }}; (## $first : ident $($tail : tt )* )=>{{ let mut tokens = $first . into_iter (). map ($crate :: quote :: ToTokenTree :: to_token ). collect ::< Vec < tt :: TokenTree >> (); let mut tail_tokens = $crate :: quote :: IntoTt :: to_tokens ($crate :: __quote ! ($($tail )*)); tokens . append (& mut tail_tokens ); tokens }}; ({$($tt : tt )* })=>{$crate :: __quote ! (@ SUBTREE Brace $($tt )*)}; ([$($tt : tt )* ])=>{$crate :: __quote ! (@ SUBTREE Bracket $($tt )*)}; (($($tt : tt )* ))=>{$crate :: __quote ! (@ SUBTREE Parenthesis $($tt )*)}; ($tt : literal )=>{ vec ! [$crate :: quote :: ToTokenTree :: to_token ($tt ). into ()]}; ($tt : ident )=>{ vec ! [{ tt :: Leaf :: Ident ( tt :: Ident { text : stringify ! ($tt ). into (), id : tt :: TokenId :: unspecified (), }). into ()}]}; (-> )=>{$crate :: __quote ! (@ PUNCT '-' , '>' )}; (& )=>{$crate :: __quote ! (@ PUNCT '&' )}; (, )=>{$crate :: __quote ! (@ PUNCT ',' )}; (: )=>{$crate :: __quote ! (@ PUNCT ':' )}; (; )=>{$crate :: __quote ! (@ PUNCT ';' )}; (:: )=>{$crate :: __quote ! (@ PUNCT ':' , ':' )}; (. )=>{$crate :: __quote ! (@ PUNCT '.' )}; (< )=>{$crate :: __quote ! (@ PUNCT '<' )}; (> )=>{$crate :: __quote ! (@ PUNCT '>' )}; ($first : tt $($tail : tt )+ )=>{{ let mut tokens = $crate :: quote :: IntoTt :: to_tokens ($crate :: __quote ! ($first )); let mut tail_tokens = $crate :: quote :: IntoTt :: to_tokens ($crate :: __quote ! ($($tail )*)); tokens . append (& mut tail_tokens ); tokens }}; } -macro_rules! __ra_macro_fixture531 {($($name : ident )*)=>{$(if let Some ( it )= & self .$name { f . field ( stringify ! ($name ), it ); })*}} -macro_rules! __ra_macro_fixture532 {($fmt : expr )=>{ RenameError ( format ! ($fmt ))}; ($fmt : expr , $($arg : tt )+)=>{ RenameError ( format ! ($fmt , $($arg )+))}} -macro_rules! __ra_macro_fixture533 {($($tokens : tt )*)=>{ return Err ( format_err ! ($($tokens )*))}} -macro_rules! __ra_macro_fixture534 {()=>{$crate :: __private :: TokenStream :: new ()}; ($($tt : tt )*)=>{{ let mut _s = $crate :: __private :: TokenStream :: new (); $crate :: quote_each_token ! ( _s $($tt )*); _s }}; } -macro_rules! __ra_macro_fixture535 {($tokens : ident $($tts : tt )*)=>{$crate :: quote_tokens_with_context ! ($tokens (@ @ @ @ @ @ $($tts )*)(@ @ @ @ @ $($tts )* @)(@ @ @ @ $($tts )* @ @)(@ @ @ $(($tts ))* @ @ @)(@ @ $($tts )* @ @ @ @)(@ $($tts )* @ @ @ @ @)($($tts )* @ @ @ @ @ @)); }; } -macro_rules! __ra_macro_fixture536 {($tokens : ident ($($b3 : tt )*)($($b2 : tt )*)($($b1 : tt )*)($($curr : tt )*)($($a1 : tt )*)($($a2 : tt )*)($($a3 : tt )*))=>{$($crate :: quote_token_with_context ! ($tokens $b3 $b2 $b1 $curr $a1 $a2 $a3 ); )* }; } -macro_rules! __ra_macro_fixture537 {($tokens : ident $b3 : tt $b2 : tt $b1 : tt @ $a1 : tt $a2 : tt $a3 : tt )=>{}; ($tokens : ident $b3 : tt $b2 : tt $b1 : tt (#)($($inner : tt )* )* $a3 : tt )=>{{ use $crate :: __private :: ext ::*; let has_iter = $crate :: __private :: ThereIsNoIteratorInRepetition ; $crate :: pounded_var_names ! ( quote_bind_into_iter ! ( has_iter )()$($inner )*); let _: $crate :: __private :: HasIterator = has_iter ; while true {$crate :: pounded_var_names ! ( quote_bind_next_or_break ! ()()$($inner )*); $crate :: quote_each_token ! ($tokens $($inner )*); }}}; ($tokens : ident $b3 : tt $b2 : tt # (($($inner : tt )* ))* $a2 : tt $a3 : tt )=>{}; ($tokens : ident $b3 : tt # ($($inner : tt )* )(*)$a1 : tt $a2 : tt $a3 : tt )=>{}; ($tokens : ident $b3 : tt $b2 : tt $b1 : tt (#)($($inner : tt )* )$sep : tt *)=>{{ use $crate :: __private :: ext ::*; let mut _i = 0usize ; let has_iter = $crate :: __private :: ThereIsNoIteratorInRepetition ; $crate :: pounded_var_names ! ( quote_bind_into_iter ! ( has_iter )()$($inner )*); let _: $crate :: __private :: HasIterator = has_iter ; while true {$crate :: pounded_var_names ! ( quote_bind_next_or_break ! ()()$($inner )*); if _i > 0 {$crate :: quote_token ! ($tokens $sep ); } _i += 1 ; $crate :: quote_each_token ! ($tokens $($inner )*); }}}; ($tokens : ident $b3 : tt $b2 : tt # (($($inner : tt )* ))$sep : tt * $a3 : tt )=>{}; ($tokens : ident $b3 : tt # ($($inner : tt )* )($sep : tt )* $a2 : tt $a3 : tt )=>{}; ($tokens : ident # ($($inner : tt )* )* (*)$a1 : tt $a2 : tt $a3 : tt )=>{$crate :: quote_token ! ($tokens *); }; ($tokens : ident # ($($inner : tt )* )$sep : tt (*)$a1 : tt $a2 : tt $a3 : tt )=>{}; ($tokens : ident $b3 : tt $b2 : tt $b1 : tt (#)$var : ident $a2 : tt $a3 : tt )=>{$crate :: ToTokens :: to_tokens (&$var , & mut $tokens ); }; ($tokens : ident $b3 : tt $b2 : tt # ($var : ident )$a1 : tt $a2 : tt $a3 : tt )=>{}; ($tokens : ident $b3 : tt $b2 : tt $b1 : tt ($curr : tt )$a1 : tt $a2 : tt $a3 : tt )=>{$crate :: quote_token ! ($tokens $curr ); }; } -macro_rules! __ra_macro_fixture538 {($tokens : ident ($($inner : tt )* ))=>{$crate :: __private :: push_group (& mut $tokens , $crate :: __private :: Delimiter :: Parenthesis , $crate :: quote ! ($($inner )*), ); }; ($tokens : ident [$($inner : tt )* ])=>{$crate :: __private :: push_group (& mut $tokens , $crate :: __private :: Delimiter :: Bracket , $crate :: quote ! ($($inner )*), ); }; ($tokens : ident {$($inner : tt )* })=>{$crate :: __private :: push_group (& mut $tokens , $crate :: __private :: Delimiter :: Brace , $crate :: quote ! ($($inner )*), ); }; ($tokens : ident +)=>{$crate :: __private :: push_add (& mut $tokens ); }; ($tokens : ident +=)=>{$crate :: __private :: push_add_eq (& mut $tokens ); }; ($tokens : ident &)=>{$crate :: __private :: push_and (& mut $tokens ); }; ($tokens : ident &&)=>{$crate :: __private :: push_and_and (& mut $tokens ); }; ($tokens : ident &=)=>{$crate :: __private :: push_and_eq (& mut $tokens ); }; ($tokens : ident @)=>{$crate :: __private :: push_at (& mut $tokens ); }; ($tokens : ident !)=>{$crate :: __private :: push_bang (& mut $tokens ); }; ($tokens : ident ^)=>{$crate :: __private :: push_caret (& mut $tokens ); }; ($tokens : ident ^=)=>{$crate :: __private :: push_caret_eq (& mut $tokens ); }; ($tokens : ident :)=>{$crate :: __private :: push_colon (& mut $tokens ); }; ($tokens : ident ::)=>{$crate :: __private :: push_colon2 (& mut $tokens ); }; ($tokens : ident ,)=>{$crate :: __private :: push_comma (& mut $tokens ); }; ($tokens : ident /)=>{$crate :: __private :: push_div (& mut $tokens ); }; ($tokens : ident /=)=>{$crate :: __private :: push_div_eq (& mut $tokens ); }; ($tokens : ident .)=>{$crate :: __private :: push_dot (& mut $tokens ); }; ($tokens : ident ..)=>{$crate :: __private :: push_dot2 (& mut $tokens ); }; ($tokens : ident ...)=>{$crate :: __private :: push_dot3 (& mut $tokens ); }; ($tokens : ident ..=)=>{$crate :: __private :: push_dot_dot_eq (& mut $tokens ); }; ($tokens : ident =)=>{$crate :: __private :: push_eq (& mut $tokens ); }; ($tokens : ident ==)=>{$crate :: __private :: push_eq_eq (& mut $tokens ); }; ($tokens : ident >=)=>{$crate :: __private :: push_ge (& mut $tokens ); }; ($tokens : ident >)=>{$crate :: __private :: push_gt (& mut $tokens ); }; ($tokens : ident <=)=>{$crate :: __private :: push_le (& mut $tokens ); }; ($tokens : ident <)=>{$crate :: __private :: push_lt (& mut $tokens ); }; ($tokens : ident *=)=>{$crate :: __private :: push_mul_eq (& mut $tokens ); }; ($tokens : ident !=)=>{$crate :: __private :: push_ne (& mut $tokens ); }; ($tokens : ident |)=>{$crate :: __private :: push_or (& mut $tokens ); }; ($tokens : ident |=)=>{$crate :: __private :: push_or_eq (& mut $tokens ); }; ($tokens : ident ||)=>{$crate :: __private :: push_or_or (& mut $tokens ); }; ($tokens : ident #)=>{$crate :: __private :: push_pound (& mut $tokens ); }; ($tokens : ident ?)=>{$crate :: __private :: push_question (& mut $tokens ); }; ($tokens : ident ->)=>{$crate :: __private :: push_rarrow (& mut $tokens ); }; ($tokens : ident <-)=>{$crate :: __private :: push_larrow (& mut $tokens ); }; ($tokens : ident %)=>{$crate :: __private :: push_rem (& mut $tokens ); }; ($tokens : ident %=)=>{$crate :: __private :: push_rem_eq (& mut $tokens ); }; ($tokens : ident =>)=>{$crate :: __private :: push_fat_arrow (& mut $tokens ); }; ($tokens : ident ;)=>{$crate :: __private :: push_semi (& mut $tokens ); }; ($tokens : ident <<)=>{$crate :: __private :: push_shl (& mut $tokens ); }; ($tokens : ident <<=)=>{$crate :: __private :: push_shl_eq (& mut $tokens ); }; ($tokens : ident >>)=>{$crate :: __private :: push_shr (& mut $tokens ); }; ($tokens : ident >>=)=>{$crate :: __private :: push_shr_eq (& mut $tokens ); }; ($tokens : ident *)=>{$crate :: __private :: push_star (& mut $tokens ); }; ($tokens : ident -)=>{$crate :: __private :: push_sub (& mut $tokens ); }; ($tokens : ident -=)=>{$crate :: __private :: push_sub_eq (& mut $tokens ); }; ($tokens : ident $ident : ident )=>{$crate :: __private :: push_ident (& mut $tokens , stringify ! ($ident )); }; ($tokens : ident $other : tt )=>{$crate :: __private :: parse (& mut $tokens , stringify ! ($other )); }; } -macro_rules! __ra_macro_fixture539 {($call : ident ! $extra : tt $($tts : tt )*)=>{$crate :: pounded_var_names_with_context ! ($call ! $extra (@ $($tts )*)($($tts )* @))}; } -macro_rules! __ra_macro_fixture540 {($call : ident ! $extra : tt ($($b1 : tt )*)($($curr : tt )*))=>{$($crate :: pounded_var_with_context ! ($call ! $extra $b1 $curr ); )* }; } -macro_rules! __ra_macro_fixture541 {($call : ident ! $extra : tt $b1 : tt ($($inner : tt )* ))=>{$crate :: pounded_var_names ! ($call ! $extra $($inner )*); }; ($call : ident ! $extra : tt $b1 : tt [$($inner : tt )* ])=>{$crate :: pounded_var_names ! ($call ! $extra $($inner )*); }; ($call : ident ! $extra : tt $b1 : tt {$($inner : tt )* })=>{$crate :: pounded_var_names ! ($call ! $extra $($inner )*); }; ($call : ident ! ($($extra : tt )*)# $var : ident )=>{$crate ::$call ! ($($extra )* $var ); }; ($call : ident ! $extra : tt $b1 : tt $curr : tt )=>{}; } -macro_rules! __ra_macro_fixture542 {($has_iter : ident $var : ident )=>{# [ allow ( unused_mut )] let ( mut $var , i )= $var . quote_into_iter (); let $has_iter = $has_iter | i ; }; } -macro_rules! __ra_macro_fixture543 {($var : ident )=>{ let $var = match $var . next (){ Some ( _x )=>$crate :: __private :: RepInterp ( _x ), None => break , }; }; } -macro_rules! __ra_macro_fixture544 {($fmt : expr )=>{$crate :: format_ident_impl ! ([:: std :: option :: Option :: None , $fmt ])}; ($fmt : expr , $($rest : tt )*)=>{$crate :: format_ident_impl ! ([:: std :: option :: Option :: None , $fmt ]$($rest )*)}; } -macro_rules! __ra_macro_fixture545 {([$span : expr , $($fmt : tt )*])=>{$crate :: __private :: mk_ident (& format ! ($($fmt )*), $span )}; ([$old : expr , $($fmt : tt )*] span = $span : expr )=>{$crate :: format_ident_impl ! ([$old , $($fmt )*] span = $span ,)}; ([$old : expr , $($fmt : tt )*] span = $span : expr , $($rest : tt )*)=>{$crate :: format_ident_impl ! ([:: std :: option :: Option :: Some ::<$crate :: __private :: Span > ($span ), $($fmt )* ]$($rest )*)}; ([$span : expr , $($fmt : tt )*]$name : ident = $arg : expr )=>{$crate :: format_ident_impl ! ([$span , $($fmt )*]$name = $arg ,)}; ([$span : expr , $($fmt : tt )*]$name : ident = $arg : expr , $($rest : tt )*)=>{ match $crate :: __private :: IdentFragmentAdapter (&$arg ){ arg =>$crate :: format_ident_impl ! ([$span . or ( arg . span ()), $($fmt )*, $name = arg ]$($rest )*), }}; ([$span : expr , $($fmt : tt )*]$arg : expr )=>{$crate :: format_ident_impl ! ([$span , $($fmt )*]$arg ,)}; ([$span : expr , $($fmt : tt )*]$arg : expr , $($rest : tt )*)=>{ match $crate :: __private :: IdentFragmentAdapter (&$arg ){ arg =>$crate :: format_ident_impl ! ([$span . or ( arg . span ()), $($fmt )*, arg ]$($rest )*), }}; } -macro_rules! __ra_macro_fixture546 {()=>( panic ! ( "not yet implemented" )); ($($arg : tt )+)=>( panic ! ( "not yet implemented: {}" , $crate :: format_args ! ($($arg )+))); } -macro_rules! __ra_macro_fixture547 {($($name : expr ),+ $(,)?)=>{{ let mut v = ArrayVec ::< [ LangItemTarget ; 2 ]>:: new (); $(v . extend ( db . lang_item ( cur_crate , $name . into ())); )+ v }}; } -macro_rules! __ra_macro_fixture548 {($ctor : pat , $param : pat )=>{ crate :: Ty :: Apply ( crate :: ApplicationTy { ctor : $ctor , parameters : $param })}; ($ctor : pat )=>{ ty_app ! ($ctor , _)}; } -macro_rules! __ra_macro_fixture549 {(@ one $x : expr )=>( 1usize ); ($elem : expr ; $n : expr )=>({$crate :: SmallVec :: from_elem ($elem , $n )}); ($($x : expr ),*$(,)*)=>({ let count = 0usize $(+ $crate :: smallvec ! (@ one $x ))*; # [ allow ( unused_mut )] let mut vec = $crate :: SmallVec :: new (); if count <= vec . inline_size (){$(vec . push ($x );)* vec } else {$crate :: SmallVec :: from_vec ($crate :: alloc :: vec ! [$($x ,)*])}}); } -macro_rules! __ra_macro_fixture550 {($($q : path )*)=>{$(let before = memory_usage (). allocated ; $q . in_db ( self ). sweep ( sweep ); let after = memory_usage (). allocated ; let q : $q = Default :: default (); let name = format ! ( "{:?}" , q ); acc . push (( name , before - after )); let before = memory_usage (). allocated ; $q . in_db ( self ). sweep ( sweep . discard_everything ()); let after = memory_usage (). allocated ; let q : $q = Default :: default (); let name = format ! ( "{:?} (deps)" , q ); acc . push (( name , before - after )); let before = memory_usage (). allocated ; $q . in_db ( self ). purge (); let after = memory_usage (). allocated ; let q : $q = Default :: default (); let name = format ! ( "{:?} (purge)" , q ); acc . push (( name , before - after )); )*}} -macro_rules! __ra_macro_fixture551 {($($arg : tt )*)=>( if $crate :: cfg ! ( debug_assertions ){$crate :: assert ! ($($arg )*); })} -macro_rules! __ra_macro_fixture552 {()=>{{ let anchor = match self . l_curly_token (){ Some ( it )=> it . into (), None => return self . clone (), }; InsertPosition :: After ( anchor )}}; } -macro_rules! __ra_macro_fixture553 {($anchor : expr )=>{ if let Some ( comma )= $anchor . syntax (). siblings_with_tokens ( Direction :: Next ). find (| it | it . kind ()== T ! [,]){ InsertPosition :: After ( comma )} else { to_insert . insert ( 0 , make :: token ( T ! [,]). into ()); InsertPosition :: After ($anchor . syntax (). clone (). into ())}}; } -macro_rules! __ra_macro_fixture554 {($anchor : expr )=>{ if let Some ( comma )= $anchor . syntax (). siblings_with_tokens ( Direction :: Next ). find (| it | it . kind ()== T ! [,]){ InsertPosition :: After ( comma )} else { to_insert . insert ( 0 , make :: token ( T ! [,]). into ()); InsertPosition :: After ($anchor . syntax (). clone (). into ())}}; } -macro_rules! __ra_macro_fixture555 {()=>{{ let anchor = match self . l_angle_token (){ Some ( it )=> it . into (), None => return self . clone (), }; InsertPosition :: After ( anchor )}}; } -macro_rules! __ra_macro_fixture556 {()=>{ for _ in 0 .. level { buf . push_str ( " " ); }}; } -macro_rules! __ra_macro_fixture557 {()=>{ ExpandError :: BindingError ( format ! ( "" ))}; ($($tt : tt )*)=>{ ExpandError :: BindingError ( format ! ($($tt )*))}; } -macro_rules! __ra_macro_fixture558 {($($tt : tt )*)=>{ return Err ( err ! ($($tt )*))}; } -macro_rules! __ra_macro_fixture559 {($($tt : tt )*)=>{ ParseError :: UnexpectedToken (($($tt )*). to_string ())}; } diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml deleted file mode 100644 index f02a51ab6c47f..0000000000000 --- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "base-db" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -salsa = "0.17.0-pre.2" -rustc-hash = "1.1.0" - -syntax = { path = "../syntax", version = "0.0.0" } -stdx = { path = "../stdx", version = "0.0.0" } -cfg = { path = "../cfg", version = "0.0.0" } -profile = { path = "../profile", version = "0.0.0" } -tt = { path = "../tt", version = "0.0.0" } -test-utils = { path = "../test-utils", version = "0.0.0" } -vfs = { path = "../vfs", version = "0.0.0" } diff --git a/src/tools/rust-analyzer/crates/base-db/src/change.rs b/src/tools/rust-analyzer/crates/base-db/src/change.rs deleted file mode 100644 index b57f2345767d0..0000000000000 --- a/src/tools/rust-analyzer/crates/base-db/src/change.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! Defines a unit of change that can applied to the database to get the next -//! state. Changes are transactional. - -use std::{fmt, sync::Arc}; - -use salsa::Durability; -use vfs::FileId; - -use crate::{CrateGraph, SourceDatabaseExt, SourceRoot, SourceRootId}; - -/// Encapsulate a bunch of raw `.set` calls on the database. -#[derive(Default)] -pub struct Change { - pub roots: Option>, - pub files_changed: Vec<(FileId, Option>)>, - pub crate_graph: Option, -} - -impl fmt::Debug for Change { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut d = fmt.debug_struct("Change"); - if let Some(roots) = &self.roots { - d.field("roots", roots); - } - if !self.files_changed.is_empty() { - d.field("files_changed", &self.files_changed.len()); - } - if self.crate_graph.is_some() { - d.field("crate_graph", &self.crate_graph); - } - d.finish() - } -} - -impl Change { - pub fn new() -> Change { - Change::default() - } - - pub fn set_roots(&mut self, roots: Vec) { - self.roots = Some(roots); - } - - pub fn change_file(&mut self, file_id: FileId, new_text: Option>) { - self.files_changed.push((file_id, new_text)) - } - - pub fn set_crate_graph(&mut self, graph: CrateGraph) { - self.crate_graph = Some(graph); - } - - pub fn apply(self, db: &mut dyn SourceDatabaseExt) { - let _p = profile::span("RootDatabase::apply_change"); - if let Some(roots) = self.roots { - for (idx, root) in roots.into_iter().enumerate() { - let root_id = SourceRootId(idx as u32); - let durability = durability(&root); - for file_id in root.iter() { - db.set_file_source_root_with_durability(file_id, root_id, durability); - } - db.set_source_root_with_durability(root_id, Arc::new(root), durability); - } - } - - for (file_id, text) in self.files_changed { - let source_root_id = db.file_source_root(file_id); - let source_root = db.source_root(source_root_id); - let durability = durability(&source_root); - // XXX: can't actually remove the file, just reset the text - let text = text.unwrap_or_default(); - db.set_file_text_with_durability(file_id, text, durability) - } - if let Some(crate_graph) = self.crate_graph { - db.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH) - } - } -} - -fn durability(source_root: &SourceRoot) -> Durability { - if source_root.is_library { - Durability::HIGH - } else { - Durability::LOW - } -} diff --git a/src/tools/rust-analyzer/crates/base-db/src/fixture.rs b/src/tools/rust-analyzer/crates/base-db/src/fixture.rs deleted file mode 100644 index 8e6e6a11abda8..0000000000000 --- a/src/tools/rust-analyzer/crates/base-db/src/fixture.rs +++ /dev/null @@ -1,494 +0,0 @@ -//! A set of high-level utility fixture methods to use in tests. -use std::{mem, str::FromStr, sync::Arc}; - -use cfg::CfgOptions; -use rustc_hash::FxHashMap; -use test_utils::{ - extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER, ESCAPED_CURSOR_MARKER, -}; -use tt::Subtree; -use vfs::{file_set::FileSet, VfsPath}; - -use crate::{ - input::{CrateName, CrateOrigin, LangCrateOrigin}, - Change, CrateDisplayName, CrateGraph, CrateId, Dependency, Edition, Env, FileId, FilePosition, - FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, SourceDatabaseExt, - SourceRoot, SourceRootId, -}; - -pub const WORKSPACE: SourceRootId = SourceRootId(0); - -pub trait WithFixture: Default + SourceDatabaseExt + 'static { - fn with_single_file(ra_fixture: &str) -> (Self, FileId) { - let fixture = ChangeFixture::parse(ra_fixture); - let mut db = Self::default(); - fixture.change.apply(&mut db); - assert_eq!(fixture.files.len(), 1); - (db, fixture.files[0]) - } - - fn with_many_files(ra_fixture: &str) -> (Self, Vec) { - let fixture = ChangeFixture::parse(ra_fixture); - let mut db = Self::default(); - fixture.change.apply(&mut db); - assert!(fixture.file_position.is_none()); - (db, fixture.files) - } - - fn with_files(ra_fixture: &str) -> Self { - let fixture = ChangeFixture::parse(ra_fixture); - let mut db = Self::default(); - fixture.change.apply(&mut db); - assert!(fixture.file_position.is_none()); - db - } - - fn with_files_extra_proc_macros( - ra_fixture: &str, - proc_macros: Vec<(String, ProcMacro)>, - ) -> Self { - let fixture = ChangeFixture::parse_with_proc_macros(ra_fixture, proc_macros); - let mut db = Self::default(); - fixture.change.apply(&mut db); - assert!(fixture.file_position.is_none()); - db - } - - fn with_position(ra_fixture: &str) -> (Self, FilePosition) { - let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture); - let offset = range_or_offset.expect_offset(); - (db, FilePosition { file_id, offset }) - } - - fn with_range(ra_fixture: &str) -> (Self, FileRange) { - let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture); - let range = range_or_offset.expect_range(); - (db, FileRange { file_id, range }) - } - - fn with_range_or_offset(ra_fixture: &str) -> (Self, FileId, RangeOrOffset) { - let fixture = ChangeFixture::parse(ra_fixture); - let mut db = Self::default(); - fixture.change.apply(&mut db); - let (file_id, range_or_offset) = fixture - .file_position - .expect("Could not find file position in fixture. Did you forget to add an `$0`?"); - (db, file_id, range_or_offset) - } - - fn test_crate(&self) -> CrateId { - let crate_graph = self.crate_graph(); - let mut it = crate_graph.iter(); - let res = it.next().unwrap(); - assert!(it.next().is_none()); - res - } -} - -impl WithFixture for DB {} - -pub struct ChangeFixture { - pub file_position: Option<(FileId, RangeOrOffset)>, - pub files: Vec, - pub change: Change, -} - -impl ChangeFixture { - pub fn parse(ra_fixture: &str) -> ChangeFixture { - Self::parse_with_proc_macros(ra_fixture, Vec::new()) - } - - pub fn parse_with_proc_macros( - ra_fixture: &str, - mut proc_macros: Vec<(String, ProcMacro)>, - ) -> ChangeFixture { - let (mini_core, proc_macro_names, fixture) = Fixture::parse(ra_fixture); - let mut change = Change::new(); - - let mut files = Vec::new(); - let mut crate_graph = CrateGraph::default(); - let mut crates = FxHashMap::default(); - let mut crate_deps = Vec::new(); - let mut default_crate_root: Option = None; - let mut default_cfg = CfgOptions::default(); - - let mut file_set = FileSet::default(); - let mut current_source_root_kind = SourceRootKind::Local; - let source_root_prefix = "/".to_string(); - let mut file_id = FileId(0); - let mut roots = Vec::new(); - - let mut file_position = None; - - for entry in fixture { - let text = if entry.text.contains(CURSOR_MARKER) { - if entry.text.contains(ESCAPED_CURSOR_MARKER) { - entry.text.replace(ESCAPED_CURSOR_MARKER, CURSOR_MARKER) - } else { - let (range_or_offset, text) = extract_range_or_offset(&entry.text); - assert!(file_position.is_none()); - file_position = Some((file_id, range_or_offset)); - text - } - } else { - entry.text.clone() - }; - - let meta = FileMeta::from(entry); - assert!(meta.path.starts_with(&source_root_prefix)); - if !meta.deps.is_empty() { - assert!(meta.krate.is_some(), "can't specify deps without naming the crate") - } - - if let Some(kind) = &meta.introduce_new_source_root { - let root = match current_source_root_kind { - SourceRootKind::Local => SourceRoot::new_local(mem::take(&mut file_set)), - SourceRootKind::Library => SourceRoot::new_library(mem::take(&mut file_set)), - }; - roots.push(root); - current_source_root_kind = *kind; - } - - if let Some((krate, origin, version)) = meta.krate { - let crate_name = CrateName::normalize_dashes(&krate); - let crate_id = crate_graph.add_crate_root( - file_id, - meta.edition, - Some(crate_name.clone().into()), - version, - meta.cfg.clone(), - meta.cfg, - meta.env, - Ok(Vec::new()), - false, - origin, - ); - let prev = crates.insert(crate_name.clone(), crate_id); - assert!(prev.is_none()); - for dep in meta.deps { - let prelude = meta.extern_prelude.contains(&dep); - let dep = CrateName::normalize_dashes(&dep); - crate_deps.push((crate_name.clone(), dep, prelude)) - } - } else if meta.path == "/main.rs" || meta.path == "/lib.rs" { - assert!(default_crate_root.is_none()); - default_crate_root = Some(file_id); - default_cfg = meta.cfg; - } - - change.change_file(file_id, Some(Arc::new(text))); - let path = VfsPath::new_virtual_path(meta.path); - file_set.insert(file_id, path); - files.push(file_id); - file_id.0 += 1; - } - - if crates.is_empty() { - let crate_root = default_crate_root - .expect("missing default crate root, specify a main.rs or lib.rs"); - crate_graph.add_crate_root( - crate_root, - Edition::CURRENT, - Some(CrateName::new("test").unwrap().into()), - None, - default_cfg.clone(), - default_cfg, - Env::default(), - Ok(Vec::new()), - false, - CrateOrigin::CratesIo { repo: None }, - ); - } else { - for (from, to, prelude) in crate_deps { - let from_id = crates[&from]; - let to_id = crates[&to]; - crate_graph - .add_dep( - from_id, - Dependency::with_prelude(CrateName::new(&to).unwrap(), to_id, prelude), - ) - .unwrap(); - } - } - - if let Some(mini_core) = mini_core { - let core_file = file_id; - file_id.0 += 1; - - let mut fs = FileSet::default(); - fs.insert(core_file, VfsPath::new_virtual_path("/sysroot/core/lib.rs".to_string())); - roots.push(SourceRoot::new_library(fs)); - - change.change_file(core_file, Some(Arc::new(mini_core.source_code()))); - - let all_crates = crate_graph.crates_in_topological_order(); - - let core_crate = crate_graph.add_crate_root( - core_file, - Edition::Edition2021, - Some(CrateDisplayName::from_canonical_name("core".to_string())), - None, - CfgOptions::default(), - CfgOptions::default(), - Env::default(), - Ok(Vec::new()), - false, - CrateOrigin::Lang(LangCrateOrigin::Core), - ); - - for krate in all_crates { - crate_graph - .add_dep(krate, Dependency::new(CrateName::new("core").unwrap(), core_crate)) - .unwrap(); - } - } - - if !proc_macro_names.is_empty() { - let proc_lib_file = file_id; - file_id.0 += 1; - - proc_macros.extend(default_test_proc_macros()); - let (proc_macro, source) = filter_test_proc_macros(&proc_macro_names, proc_macros); - let mut fs = FileSet::default(); - fs.insert( - proc_lib_file, - VfsPath::new_virtual_path("/sysroot/proc_macros/lib.rs".to_string()), - ); - roots.push(SourceRoot::new_library(fs)); - - change.change_file(proc_lib_file, Some(Arc::new(source))); - - let all_crates = crate_graph.crates_in_topological_order(); - - let proc_macros_crate = crate_graph.add_crate_root( - proc_lib_file, - Edition::Edition2021, - Some(CrateDisplayName::from_canonical_name("proc_macros".to_string())), - None, - CfgOptions::default(), - CfgOptions::default(), - Env::default(), - Ok(proc_macro), - true, - CrateOrigin::CratesIo { repo: None }, - ); - - for krate in all_crates { - crate_graph - .add_dep( - krate, - Dependency::new(CrateName::new("proc_macros").unwrap(), proc_macros_crate), - ) - .unwrap(); - } - } - - let root = match current_source_root_kind { - SourceRootKind::Local => SourceRoot::new_local(mem::take(&mut file_set)), - SourceRootKind::Library => SourceRoot::new_library(mem::take(&mut file_set)), - }; - roots.push(root); - change.set_roots(roots); - change.set_crate_graph(crate_graph); - - ChangeFixture { file_position, files, change } - } -} - -fn default_test_proc_macros() -> [(String, ProcMacro); 4] { - [ - ( - r#" -#[proc_macro_attribute] -pub fn identity(_attr: TokenStream, item: TokenStream) -> TokenStream { - item -} -"# - .into(), - ProcMacro { - name: "identity".into(), - kind: crate::ProcMacroKind::Attr, - expander: Arc::new(IdentityProcMacroExpander), - }, - ), - ( - r#" -#[proc_macro_derive(DeriveIdentity)] -pub fn derive_identity(item: TokenStream) -> TokenStream { - item -} -"# - .into(), - ProcMacro { - name: "DeriveIdentity".into(), - kind: crate::ProcMacroKind::CustomDerive, - expander: Arc::new(IdentityProcMacroExpander), - }, - ), - ( - r#" -#[proc_macro_attribute] -pub fn input_replace(attr: TokenStream, _item: TokenStream) -> TokenStream { - attr -} -"# - .into(), - ProcMacro { - name: "input_replace".into(), - kind: crate::ProcMacroKind::Attr, - expander: Arc::new(AttributeInputReplaceProcMacroExpander), - }, - ), - ( - r#" -#[proc_macro] -pub fn mirror(input: TokenStream) -> TokenStream { - input -} -"# - .into(), - ProcMacro { - name: "mirror".into(), - kind: crate::ProcMacroKind::FuncLike, - expander: Arc::new(MirrorProcMacroExpander), - }, - ), - ] -} - -fn filter_test_proc_macros( - proc_macro_names: &[String], - proc_macro_defs: Vec<(String, ProcMacro)>, -) -> (Vec, String) { - // The source here is only required so that paths to the macros exist and are resolvable. - let mut source = String::new(); - let mut proc_macros = Vec::new(); - - for (c, p) in proc_macro_defs { - if !proc_macro_names.iter().any(|name| name == &stdx::to_lower_snake_case(&p.name)) { - continue; - } - proc_macros.push(p); - source += &c; - } - - (proc_macros, source) -} - -#[derive(Debug, Clone, Copy)] -enum SourceRootKind { - Local, - Library, -} - -#[derive(Debug)] -struct FileMeta { - path: String, - krate: Option<(String, CrateOrigin, Option)>, - deps: Vec, - extern_prelude: Vec, - cfg: CfgOptions, - edition: Edition, - env: Env, - introduce_new_source_root: Option, -} - -fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option) { - if let Some((a, b)) = crate_str.split_once('@') { - let (version, origin) = match b.split_once(':') { - Some(("CratesIo", data)) => match data.split_once(',') { - Some((version, url)) => { - (version, CrateOrigin::CratesIo { repo: Some(url.to_owned()) }) - } - _ => panic!("Bad crates.io parameter: {}", data), - }, - _ => panic!("Bad string for crate origin: {}", b), - }; - (a.to_owned(), origin, Some(version.to_string())) - } else { - let crate_origin = match &*crate_str { - "std" => CrateOrigin::Lang(LangCrateOrigin::Std), - "core" => CrateOrigin::Lang(LangCrateOrigin::Core), - _ => CrateOrigin::CratesIo { repo: None }, - }; - (crate_str, crate_origin, None) - } -} - -impl From for FileMeta { - fn from(f: Fixture) -> FileMeta { - let mut cfg = CfgOptions::default(); - f.cfg_atoms.iter().for_each(|it| cfg.insert_atom(it.into())); - f.cfg_key_values.iter().for_each(|(k, v)| cfg.insert_key_value(k.into(), v.into())); - let deps = f.deps; - FileMeta { - path: f.path, - krate: f.krate.map(parse_crate), - extern_prelude: f.extern_prelude.unwrap_or_else(|| deps.clone()), - deps, - cfg, - edition: f.edition.as_ref().map_or(Edition::CURRENT, |v| Edition::from_str(v).unwrap()), - env: f.env.into_iter().collect(), - introduce_new_source_root: f.introduce_new_source_root.map(|kind| match &*kind { - "local" => SourceRootKind::Local, - "library" => SourceRootKind::Library, - invalid => panic!("invalid source root kind '{}'", invalid), - }), - } - } -} - -// Identity mapping -#[derive(Debug)] -struct IdentityProcMacroExpander; -impl ProcMacroExpander for IdentityProcMacroExpander { - fn expand( - &self, - subtree: &Subtree, - _: Option<&Subtree>, - _: &Env, - ) -> Result { - Ok(subtree.clone()) - } -} - -// Pastes the attribute input as its output -#[derive(Debug)] -struct AttributeInputReplaceProcMacroExpander; -impl ProcMacroExpander for AttributeInputReplaceProcMacroExpander { - fn expand( - &self, - _: &Subtree, - attrs: Option<&Subtree>, - _: &Env, - ) -> Result { - attrs - .cloned() - .ok_or_else(|| ProcMacroExpansionError::Panic("Expected attribute input".into())) - } -} - -#[derive(Debug)] -struct MirrorProcMacroExpander; -impl ProcMacroExpander for MirrorProcMacroExpander { - fn expand( - &self, - input: &Subtree, - _: Option<&Subtree>, - _: &Env, - ) -> Result { - fn traverse(input: &Subtree) -> Subtree { - let mut res = Subtree::default(); - res.delimiter = input.delimiter; - for tt in input.token_trees.iter().rev() { - let tt = match tt { - tt::TokenTree::Leaf(leaf) => tt::TokenTree::Leaf(leaf.clone()), - tt::TokenTree::Subtree(sub) => tt::TokenTree::Subtree(traverse(sub)), - }; - res.token_trees.push(tt); - } - res - } - Ok(traverse(input)) - } -} diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs deleted file mode 100644 index 9b5a10acfbeaf..0000000000000 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ /dev/null @@ -1,792 +0,0 @@ -//! This module specifies the input to rust-analyzer. In some sense, this is -//! **the** most important module, because all other fancy stuff is strictly -//! derived from this input. -//! -//! Note that neither this module, nor any other part of the analyzer's core do -//! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how -//! actual IO is done and lowered to input. - -use std::{fmt, iter::FromIterator, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc}; - -use cfg::CfgOptions; -use rustc_hash::{FxHashMap, FxHashSet}; -use syntax::SmolStr; -use tt::Subtree; -use vfs::{file_set::FileSet, FileId, VfsPath}; - -/// Files are grouped into source roots. A source root is a directory on the -/// file systems which is watched for changes. Typically it corresponds to a -/// Rust crate. Source roots *might* be nested: in this case, a file belongs to -/// the nearest enclosing source root. Paths to files are always relative to a -/// source root, and the analyzer does not know the root path of the source root at -/// all. So, a file from one source root can't refer to a file in another source -/// root by path. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct SourceRootId(pub u32); - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct SourceRoot { - /// Sysroot or crates.io library. - /// - /// Libraries are considered mostly immutable, this assumption is used to - /// optimize salsa's query structure - pub is_library: bool, - pub(crate) file_set: FileSet, -} - -impl SourceRoot { - pub fn new_local(file_set: FileSet) -> SourceRoot { - SourceRoot { is_library: false, file_set } - } - pub fn new_library(file_set: FileSet) -> SourceRoot { - SourceRoot { is_library: true, file_set } - } - pub fn path_for_file(&self, file: &FileId) -> Option<&VfsPath> { - self.file_set.path_for_file(file) - } - pub fn file_for_path(&self, path: &VfsPath) -> Option<&FileId> { - self.file_set.file_for_path(path) - } - pub fn iter(&self) -> impl Iterator + '_ { - self.file_set.iter() - } -} - -/// `CrateGraph` is a bit of information which turns a set of text files into a -/// number of Rust crates. -/// -/// Each crate is defined by the `FileId` of its root module, the set of enabled -/// `cfg` flags and the set of dependencies. -/// -/// Note that, due to cfg's, there might be several crates for a single `FileId`! -/// -/// For the purposes of analysis, a crate does not have a name. Instead, names -/// are specified on dependency edges. That is, a crate might be known under -/// different names in different dependent crates. -/// -/// Note that `CrateGraph` is build-system agnostic: it's a concept of the Rust -/// language proper, not a concept of the build system. In practice, we get -/// `CrateGraph` by lowering `cargo metadata` output. -/// -/// `CrateGraph` is `!Serialize` by design, see -/// -#[derive(Debug, Clone, Default /* Serialize, Deserialize */)] -pub struct CrateGraph { - arena: FxHashMap, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct CrateId(pub u32); - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct CrateName(SmolStr); - -impl CrateName { - /// Creates a crate name, checking for dashes in the string provided. - /// Dashes are not allowed in the crate names, - /// hence the input string is returned as `Err` for those cases. - pub fn new(name: &str) -> Result { - if name.contains('-') { - Err(name) - } else { - Ok(Self(SmolStr::new(name))) - } - } - - /// Creates a crate name, unconditionally replacing the dashes with underscores. - pub fn normalize_dashes(name: &str) -> CrateName { - Self(SmolStr::new(name.replace('-', "_"))) - } - - pub fn as_smol_str(&self) -> &SmolStr { - &self.0 - } -} - -impl fmt::Display for CrateName { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl ops::Deref for CrateName { - type Target = str; - fn deref(&self) -> &str { - &*self.0 - } -} - -/// Origin of the crates. It is used in emitting monikers. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum CrateOrigin { - /// Crates that are from crates.io official registry, - CratesIo { repo: Option }, - /// Crates that are provided by the language, like std, core, proc-macro, ... - Lang(LangCrateOrigin), -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum LangCrateOrigin { - Alloc, - Core, - ProcMacro, - Std, - Test, - Other, -} - -impl From<&str> for LangCrateOrigin { - fn from(s: &str) -> Self { - match s { - "alloc" => LangCrateOrigin::Alloc, - "core" => LangCrateOrigin::Core, - "proc-macro" => LangCrateOrigin::ProcMacro, - "std" => LangCrateOrigin::Std, - "test" => LangCrateOrigin::Test, - _ => LangCrateOrigin::Other, - } - } -} - -impl fmt::Display for LangCrateOrigin { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let text = match self { - LangCrateOrigin::Alloc => "alloc", - LangCrateOrigin::Core => "core", - LangCrateOrigin::ProcMacro => "proc_macro", - LangCrateOrigin::Std => "std", - LangCrateOrigin::Test => "test", - LangCrateOrigin::Other => "other", - }; - f.write_str(text) - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct CrateDisplayName { - // The name we use to display various paths (with `_`). - crate_name: CrateName, - // The name as specified in Cargo.toml (with `-`). - canonical_name: String, -} - -impl CrateDisplayName { - pub fn canonical_name(&self) -> &str { - &self.canonical_name - } - pub fn crate_name(&self) -> &CrateName { - &self.crate_name - } -} - -impl From for CrateDisplayName { - fn from(crate_name: CrateName) -> CrateDisplayName { - let canonical_name = crate_name.to_string(); - CrateDisplayName { crate_name, canonical_name } - } -} - -impl fmt::Display for CrateDisplayName { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.crate_name.fmt(f) - } -} - -impl ops::Deref for CrateDisplayName { - type Target = str; - fn deref(&self) -> &str { - &*self.crate_name - } -} - -impl CrateDisplayName { - pub fn from_canonical_name(canonical_name: String) -> CrateDisplayName { - let crate_name = CrateName::normalize_dashes(&canonical_name); - CrateDisplayName { crate_name, canonical_name } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct ProcMacroId(pub u32); - -#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] -pub enum ProcMacroKind { - CustomDerive, - FuncLike, - Attr, -} - -pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe { - fn expand( - &self, - subtree: &Subtree, - attrs: Option<&Subtree>, - env: &Env, - ) -> Result; -} - -pub enum ProcMacroExpansionError { - Panic(String), - /// Things like "proc macro server was killed by OOM". - System(String), -} - -pub type ProcMacroLoadResult = Result, String>; - -#[derive(Debug, Clone)] -pub struct ProcMacro { - pub name: SmolStr, - pub kind: ProcMacroKind, - pub expander: Arc, -} - -#[derive(Debug, Clone)] -pub struct CrateData { - pub root_file_id: FileId, - pub edition: Edition, - pub version: Option, - /// A name used in the package's project declaration: for Cargo projects, - /// its `[package].name` can be different for other project types or even - /// absent (a dummy crate for the code snippet, for example). - /// - /// For purposes of analysis, crates are anonymous (only names in - /// `Dependency` matters), this name should only be used for UI. - pub display_name: Option, - pub cfg_options: CfgOptions, - pub potential_cfg_options: CfgOptions, - pub env: Env, - pub dependencies: Vec, - pub proc_macro: ProcMacroLoadResult, - pub origin: CrateOrigin, - pub is_proc_macro: bool, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Edition { - Edition2015, - Edition2018, - Edition2021, -} - -impl Edition { - pub const CURRENT: Edition = Edition::Edition2018; -} - -#[derive(Default, Debug, Clone, PartialEq, Eq)] -pub struct Env { - entries: FxHashMap, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Dependency { - pub crate_id: CrateId, - pub name: CrateName, - prelude: bool, -} - -impl Dependency { - pub fn new(name: CrateName, crate_id: CrateId) -> Self { - Self { name, crate_id, prelude: true } - } - - pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool) -> Self { - Self { name, crate_id, prelude } - } - - /// Whether this dependency is to be added to the depending crate's extern prelude. - pub fn is_prelude(&self) -> bool { - self.prelude - } -} - -impl CrateGraph { - pub fn add_crate_root( - &mut self, - root_file_id: FileId, - edition: Edition, - display_name: Option, - version: Option, - cfg_options: CfgOptions, - potential_cfg_options: CfgOptions, - env: Env, - proc_macro: ProcMacroLoadResult, - is_proc_macro: bool, - origin: CrateOrigin, - ) -> CrateId { - let data = CrateData { - root_file_id, - edition, - version, - display_name, - cfg_options, - potential_cfg_options, - env, - proc_macro, - dependencies: Vec::new(), - origin, - is_proc_macro, - }; - let crate_id = CrateId(self.arena.len() as u32); - let prev = self.arena.insert(crate_id, data); - assert!(prev.is_none()); - crate_id - } - - pub fn add_dep( - &mut self, - from: CrateId, - dep: Dependency, - ) -> Result<(), CyclicDependenciesError> { - let _p = profile::span("add_dep"); - - // Check if adding a dep from `from` to `to` creates a cycle. To figure - // that out, look for a path in the *opposite* direction, from `to` to - // `from`. - if let Some(path) = self.find_path(&mut FxHashSet::default(), dep.crate_id, from) { - let path = path.into_iter().map(|it| (it, self[it].display_name.clone())).collect(); - let err = CyclicDependenciesError { path }; - assert!(err.from().0 == from && err.to().0 == dep.crate_id); - return Err(err); - } - - self.arena.get_mut(&from).unwrap().add_dep(dep); - Ok(()) - } - - pub fn is_empty(&self) -> bool { - self.arena.is_empty() - } - - pub fn iter(&self) -> impl Iterator + '_ { - self.arena.keys().copied() - } - - /// Returns an iterator over all transitive dependencies of the given crate, - /// including the crate itself. - pub fn transitive_deps(&self, of: CrateId) -> impl Iterator { - let mut worklist = vec![of]; - let mut deps = FxHashSet::default(); - - while let Some(krate) = worklist.pop() { - if !deps.insert(krate) { - continue; - } - - worklist.extend(self[krate].dependencies.iter().map(|dep| dep.crate_id)); - } - - deps.into_iter() - } - - /// Returns all transitive reverse dependencies of the given crate, - /// including the crate itself. - pub fn transitive_rev_deps(&self, of: CrateId) -> impl Iterator { - let mut worklist = vec![of]; - let mut rev_deps = FxHashSet::default(); - rev_deps.insert(of); - - let mut inverted_graph = FxHashMap::<_, Vec<_>>::default(); - self.arena.iter().for_each(|(&krate, data)| { - data.dependencies - .iter() - .for_each(|dep| inverted_graph.entry(dep.crate_id).or_default().push(krate)) - }); - - while let Some(krate) = worklist.pop() { - if let Some(krate_rev_deps) = inverted_graph.get(&krate) { - krate_rev_deps - .iter() - .copied() - .filter(|&rev_dep| rev_deps.insert(rev_dep)) - .for_each(|rev_dep| worklist.push(rev_dep)); - } - } - - rev_deps.into_iter() - } - - /// Returns all crates in the graph, sorted in topological order (ie. dependencies of a crate - /// come before the crate itself). - pub fn crates_in_topological_order(&self) -> Vec { - let mut res = Vec::new(); - let mut visited = FxHashSet::default(); - - for krate in self.arena.keys().copied() { - go(self, &mut visited, &mut res, krate); - } - - return res; - - fn go( - graph: &CrateGraph, - visited: &mut FxHashSet, - res: &mut Vec, - source: CrateId, - ) { - if !visited.insert(source) { - return; - } - for dep in graph[source].dependencies.iter() { - go(graph, visited, res, dep.crate_id) - } - res.push(source) - } - } - - // FIXME: this only finds one crate with the given root; we could have multiple - pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option { - let (&crate_id, _) = - self.arena.iter().find(|(_crate_id, data)| data.root_file_id == file_id)?; - Some(crate_id) - } - - /// Extends this crate graph by adding a complete disjoint second crate - /// graph. - /// - /// The ids of the crates in the `other` graph are shifted by the return - /// amount. - pub fn extend(&mut self, other: CrateGraph) -> u32 { - let start = self.arena.len() as u32; - self.arena.extend(other.arena.into_iter().map(|(id, mut data)| { - let new_id = id.shift(start); - for dep in &mut data.dependencies { - dep.crate_id = dep.crate_id.shift(start); - } - (new_id, data) - })); - start - } - - fn find_path( - &self, - visited: &mut FxHashSet, - from: CrateId, - to: CrateId, - ) -> Option> { - if !visited.insert(from) { - return None; - } - - if from == to { - return Some(vec![to]); - } - - for dep in &self[from].dependencies { - let crate_id = dep.crate_id; - if let Some(mut path) = self.find_path(visited, crate_id, to) { - path.push(from); - return Some(path); - } - } - - None - } - - // Work around for https://github.com/rust-lang/rust-analyzer/issues/6038. - // As hacky as it gets. - pub fn patch_cfg_if(&mut self) -> bool { - let cfg_if = self.hacky_find_crate("cfg_if"); - let std = self.hacky_find_crate("std"); - match (cfg_if, std) { - (Some(cfg_if), Some(std)) => { - self.arena.get_mut(&cfg_if).unwrap().dependencies.clear(); - self.arena - .get_mut(&std) - .unwrap() - .dependencies - .push(Dependency::new(CrateName::new("cfg_if").unwrap(), cfg_if)); - true - } - _ => false, - } - } - - fn hacky_find_crate(&self, display_name: &str) -> Option { - self.iter().find(|it| self[*it].display_name.as_deref() == Some(display_name)) - } -} - -impl ops::Index for CrateGraph { - type Output = CrateData; - fn index(&self, crate_id: CrateId) -> &CrateData { - &self.arena[&crate_id] - } -} - -impl CrateId { - fn shift(self, amount: u32) -> CrateId { - CrateId(self.0 + amount) - } -} - -impl CrateData { - fn add_dep(&mut self, dep: Dependency) { - self.dependencies.push(dep) - } -} - -impl FromStr for Edition { - type Err = ParseEditionError; - - fn from_str(s: &str) -> Result { - let res = match s { - "2015" => Edition::Edition2015, - "2018" => Edition::Edition2018, - "2021" => Edition::Edition2021, - _ => return Err(ParseEditionError { invalid_input: s.to_string() }), - }; - Ok(res) - } -} - -impl fmt::Display for Edition { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(match self { - Edition::Edition2015 => "2015", - Edition::Edition2018 => "2018", - Edition::Edition2021 => "2021", - }) - } -} - -impl FromIterator<(String, String)> for Env { - fn from_iter>(iter: T) -> Self { - Env { entries: FromIterator::from_iter(iter) } - } -} - -impl Env { - pub fn set(&mut self, env: &str, value: String) { - self.entries.insert(env.to_owned(), value); - } - - pub fn get(&self, env: &str) -> Option { - self.entries.get(env).cloned() - } - - pub fn iter(&self) -> impl Iterator { - self.entries.iter().map(|(k, v)| (k.as_str(), v.as_str())) - } -} - -#[derive(Debug)] -pub struct ParseEditionError { - invalid_input: String, -} - -impl fmt::Display for ParseEditionError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "invalid edition: {:?}", self.invalid_input) - } -} - -impl std::error::Error for ParseEditionError {} - -#[derive(Debug)] -pub struct CyclicDependenciesError { - path: Vec<(CrateId, Option)>, -} - -impl CyclicDependenciesError { - fn from(&self) -> &(CrateId, Option) { - self.path.first().unwrap() - } - fn to(&self) -> &(CrateId, Option) { - self.path.last().unwrap() - } -} - -impl fmt::Display for CyclicDependenciesError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let render = |(id, name): &(CrateId, Option)| match name { - Some(it) => format!("{}({:?})", it, id), - None => format!("{:?}", id), - }; - let path = self.path.iter().rev().map(render).collect::>().join(" -> "); - write!( - f, - "cyclic deps: {} -> {}, alternative path: {}", - render(self.from()), - render(self.to()), - path - ) - } -} - -#[cfg(test)] -mod tests { - use crate::CrateOrigin; - - use super::{CfgOptions, CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId}; - - #[test] - fn detect_cyclic_dependency_indirect() { - let mut graph = CrateGraph::default(); - let crate1 = graph.add_crate_root( - FileId(1u32), - Edition2018, - None, - None, - CfgOptions::default(), - CfgOptions::default(), - Env::default(), - Ok(Vec::new()), - false, - CrateOrigin::CratesIo { repo: None }, - ); - let crate2 = graph.add_crate_root( - FileId(2u32), - Edition2018, - None, - None, - CfgOptions::default(), - CfgOptions::default(), - Env::default(), - Ok(Vec::new()), - false, - CrateOrigin::CratesIo { repo: None }, - ); - let crate3 = graph.add_crate_root( - FileId(3u32), - Edition2018, - None, - None, - CfgOptions::default(), - CfgOptions::default(), - Env::default(), - Ok(Vec::new()), - false, - CrateOrigin::CratesIo { repo: None }, - ); - assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) - .is_ok()); - assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3)) - .is_ok()); - assert!(graph - .add_dep(crate3, Dependency::new(CrateName::new("crate1").unwrap(), crate1)) - .is_err()); - } - - #[test] - fn detect_cyclic_dependency_direct() { - let mut graph = CrateGraph::default(); - let crate1 = graph.add_crate_root( - FileId(1u32), - Edition2018, - None, - None, - CfgOptions::default(), - CfgOptions::default(), - Env::default(), - Ok(Vec::new()), - false, - CrateOrigin::CratesIo { repo: None }, - ); - let crate2 = graph.add_crate_root( - FileId(2u32), - Edition2018, - None, - None, - CfgOptions::default(), - CfgOptions::default(), - Env::default(), - Ok(Vec::new()), - false, - CrateOrigin::CratesIo { repo: None }, - ); - assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) - .is_ok()); - assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) - .is_err()); - } - - #[test] - fn it_works() { - let mut graph = CrateGraph::default(); - let crate1 = graph.add_crate_root( - FileId(1u32), - Edition2018, - None, - None, - CfgOptions::default(), - CfgOptions::default(), - Env::default(), - Ok(Vec::new()), - false, - CrateOrigin::CratesIo { repo: None }, - ); - let crate2 = graph.add_crate_root( - FileId(2u32), - Edition2018, - None, - None, - CfgOptions::default(), - CfgOptions::default(), - Env::default(), - Ok(Vec::new()), - false, - CrateOrigin::CratesIo { repo: None }, - ); - let crate3 = graph.add_crate_root( - FileId(3u32), - Edition2018, - None, - None, - CfgOptions::default(), - CfgOptions::default(), - Env::default(), - Ok(Vec::new()), - false, - CrateOrigin::CratesIo { repo: None }, - ); - assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) - .is_ok()); - assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3)) - .is_ok()); - } - - #[test] - fn dashes_are_normalized() { - let mut graph = CrateGraph::default(); - let crate1 = graph.add_crate_root( - FileId(1u32), - Edition2018, - None, - None, - CfgOptions::default(), - CfgOptions::default(), - Env::default(), - Ok(Vec::new()), - false, - CrateOrigin::CratesIo { repo: None }, - ); - let crate2 = graph.add_crate_root( - FileId(2u32), - Edition2018, - None, - None, - CfgOptions::default(), - CfgOptions::default(), - Env::default(), - Ok(Vec::new()), - false, - CrateOrigin::CratesIo { repo: None }, - ); - assert!(graph - .add_dep( - crate1, - Dependency::new(CrateName::normalize_dashes("crate-name-with-dashes"), crate2) - ) - .is_ok()); - assert_eq!( - graph[crate1].dependencies, - vec![Dependency::new(CrateName::new("crate_name_with_dashes").unwrap(), crate2)] - ); - } -} diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs deleted file mode 100644 index 2d0a95b09d9a1..0000000000000 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ /dev/null @@ -1,131 +0,0 @@ -//! base_db defines basic database traits. The concrete DB is defined by ide. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -mod input; -mod change; -pub mod fixture; - -use std::{panic, sync::Arc}; - -use rustc_hash::FxHashSet; -use syntax::{ast, Parse, SourceFile, TextRange, TextSize}; - -pub use crate::{ - change::Change, - input::{ - CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, - Edition, Env, LangCrateOrigin, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, - ProcMacroId, ProcMacroKind, ProcMacroLoadResult, SourceRoot, SourceRootId, - }, -}; -pub use salsa::{self, Cancelled}; -pub use vfs::{file_set::FileSet, AnchoredPath, AnchoredPathBuf, FileId, VfsPath}; - -#[macro_export] -macro_rules! impl_intern_key { - ($name:ident) => { - impl $crate::salsa::InternKey for $name { - fn from_intern_id(v: $crate::salsa::InternId) -> Self { - $name(v) - } - fn as_intern_id(&self) -> $crate::salsa::InternId { - self.0 - } - } - }; -} - -pub trait Upcast { - fn upcast(&self) -> &T; -} - -#[derive(Clone, Copy, Debug)] -pub struct FilePosition { - pub file_id: FileId, - pub offset: TextSize, -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] -pub struct FileRange { - pub file_id: FileId, - pub range: TextRange, -} - -pub const DEFAULT_LRU_CAP: usize = 128; - -pub trait FileLoader { - /// Text of the file. - fn file_text(&self, file_id: FileId) -> Arc; - fn resolve_path(&self, path: AnchoredPath<'_>) -> Option; - fn relevant_crates(&self, file_id: FileId) -> Arc>; -} - -/// Database which stores all significant input facts: source code and project -/// model. Everything else in rust-analyzer is derived from these queries. -#[salsa::query_group(SourceDatabaseStorage)] -pub trait SourceDatabase: FileLoader + std::fmt::Debug { - // Parses the file into the syntax tree. - #[salsa::invoke(parse_query)] - fn parse(&self, file_id: FileId) -> Parse; - - /// The crate graph. - #[salsa::input] - fn crate_graph(&self) -> Arc; -} - -fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse { - let _p = profile::span("parse_query").detail(|| format!("{:?}", file_id)); - let text = db.file_text(file_id); - SourceFile::parse(&*text) -} - -/// We don't want to give HIR knowledge of source roots, hence we extract these -/// methods into a separate DB. -#[salsa::query_group(SourceDatabaseExtStorage)] -pub trait SourceDatabaseExt: SourceDatabase { - #[salsa::input] - fn file_text(&self, file_id: FileId) -> Arc; - /// Path to a file, relative to the root of its source root. - /// Source root of the file. - #[salsa::input] - fn file_source_root(&self, file_id: FileId) -> SourceRootId; - /// Contents of the source root. - #[salsa::input] - fn source_root(&self, id: SourceRootId) -> Arc; - - fn source_root_crates(&self, id: SourceRootId) -> Arc>; -} - -fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc> { - let graph = db.crate_graph(); - let res = graph - .iter() - .filter(|&krate| { - let root_file = graph[krate].root_file_id; - db.file_source_root(root_file) == id - }) - .collect(); - Arc::new(res) -} - -/// Silly workaround for cyclic deps between the traits -pub struct FileLoaderDelegate(pub T); - -impl FileLoader for FileLoaderDelegate<&'_ T> { - fn file_text(&self, file_id: FileId) -> Arc { - SourceDatabaseExt::file_text(self.0, file_id) - } - fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { - // FIXME: this *somehow* should be platform agnostic... - let source_root = self.0.file_source_root(path.anchor); - let source_root = self.0.source_root(source_root); - source_root.file_set.resolve_path(path) - } - - fn relevant_crates(&self, file_id: FileId) -> Arc> { - let _p = profile::span("relevant_crates"); - 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/cfg/Cargo.toml b/src/tools/rust-analyzer/crates/cfg/Cargo.toml deleted file mode 100644 index c9664a83ab863..0000000000000 --- a/src/tools/rust-analyzer/crates/cfg/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "cfg" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -rustc-hash = "1.1.0" - -tt = { path = "../tt", version = "0.0.0" } - -[dev-dependencies] -mbe = { path = "../mbe" } -syntax = { path = "../syntax" } -expect-test = "1.4.0" -oorandom = "11.1.3" -# We depend on both individually instead of using `features = ["derive"]` to microoptimize the -# build graph: if the feature was enabled, syn would be built early on in the graph if `smolstr` -# supports `arbitrary`. This way, we avoid feature unification. -arbitrary = "1.1.0" -derive_arbitrary = "1.1.0" diff --git a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs deleted file mode 100644 index fd9e31ed3b4f5..0000000000000 --- a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs +++ /dev/null @@ -1,145 +0,0 @@ -//! The condition expression used in `#[cfg(..)]` attributes. -//! -//! See: - -use std::{fmt, slice::Iter as SliceIter}; - -use tt::SmolStr; - -/// A simple configuration value passed in from the outside. -#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] -pub enum CfgAtom { - /// eg. `#[cfg(test)]` - Flag(SmolStr), - /// eg. `#[cfg(target_os = "linux")]` - /// - /// Note that a key can have multiple values that are all considered "active" at the same time. - /// For example, `#[cfg(target_feature = "sse")]` and `#[cfg(target_feature = "sse2")]`. - KeyValue { key: SmolStr, value: SmolStr }, -} - -impl CfgAtom { - /// Returns `true` when the atom comes from the target specification. - /// - /// If this returns `true`, then changing this atom requires changing the compilation target. If - /// it returns `false`, the atom might come from a build script or the build system. - pub fn is_target_defined(&self) -> bool { - match self { - CfgAtom::Flag(flag) => matches!(&**flag, "unix" | "windows"), - CfgAtom::KeyValue { key, value: _ } => matches!( - &**key, - "target_arch" - | "target_os" - | "target_env" - | "target_family" - | "target_endian" - | "target_pointer_width" - | "target_vendor" // NOTE: `target_feature` is left out since it can be configured via `-Ctarget-feature` - ), - } - } -} - -impl fmt::Display for CfgAtom { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - CfgAtom::Flag(name) => name.fmt(f), - CfgAtom::KeyValue { key, value } => write!(f, "{} = {:?}", key, value), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(test, derive(derive_arbitrary::Arbitrary))] -pub enum CfgExpr { - Invalid, - Atom(CfgAtom), - All(Vec), - Any(Vec), - Not(Box), -} - -impl From for CfgExpr { - fn from(atom: CfgAtom) -> Self { - CfgExpr::Atom(atom) - } -} - -impl CfgExpr { - pub fn parse(tt: &tt::Subtree) -> CfgExpr { - next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid) - } - /// Fold the cfg by querying all basic `Atom` and `KeyValue` predicates. - pub fn fold(&self, query: &dyn Fn(&CfgAtom) -> bool) -> Option { - match self { - CfgExpr::Invalid => None, - CfgExpr::Atom(atom) => Some(query(atom)), - CfgExpr::All(preds) => { - preds.iter().try_fold(true, |s, pred| Some(s && pred.fold(query)?)) - } - CfgExpr::Any(preds) => { - preds.iter().try_fold(false, |s, pred| Some(s || pred.fold(query)?)) - } - CfgExpr::Not(pred) => pred.fold(query).map(|s| !s), - } - } -} - -fn next_cfg_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option { - let name = match it.next() { - None => return None, - Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) => ident.text.clone(), - Some(_) => return Some(CfgExpr::Invalid), - }; - - // Peek - let ret = match it.as_slice().first() { - Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) if punct.char == '=' => { - match it.as_slice().get(1) { - Some(tt::TokenTree::Leaf(tt::Leaf::Literal(literal))) => { - it.next(); - it.next(); - // FIXME: escape? raw string? - let value = - SmolStr::new(literal.text.trim_start_matches('"').trim_end_matches('"')); - CfgAtom::KeyValue { key: name, value }.into() - } - _ => return Some(CfgExpr::Invalid), - } - } - Some(tt::TokenTree::Subtree(subtree)) => { - it.next(); - let mut sub_it = subtree.token_trees.iter(); - let mut subs = std::iter::from_fn(|| next_cfg_expr(&mut sub_it)).collect(); - match name.as_str() { - "all" => CfgExpr::All(subs), - "any" => CfgExpr::Any(subs), - "not" => CfgExpr::Not(Box::new(subs.pop().unwrap_or(CfgExpr::Invalid))), - _ => CfgExpr::Invalid, - } - } - _ => CfgAtom::Flag(name).into(), - }; - - // Eat comma separator - if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = it.as_slice().first() { - if punct.char == ',' { - it.next(); - } - } - Some(ret) -} - -#[cfg(test)] -impl arbitrary::Arbitrary<'_> for CfgAtom { - fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result { - if u.arbitrary()? { - Ok(CfgAtom::Flag(String::arbitrary(u)?.into())) - } else { - Ok(CfgAtom::KeyValue { - key: String::arbitrary(u)?.into(), - value: String::arbitrary(u)?.into(), - }) - } - } -} diff --git a/src/tools/rust-analyzer/crates/cfg/src/dnf.rs b/src/tools/rust-analyzer/crates/cfg/src/dnf.rs deleted file mode 100644 index fd80e1ebe683b..0000000000000 --- a/src/tools/rust-analyzer/crates/cfg/src/dnf.rs +++ /dev/null @@ -1,345 +0,0 @@ -//! Disjunctive Normal Form construction. -//! -//! Algorithm from , -//! which would have been much easier to read if it used pattern matching. It's also missing the -//! entire "distribute ANDs over ORs" part, which is not trivial. Oh well. -//! -//! This is currently both messy and inefficient. Feel free to improve, there are unit tests. - -use std::fmt::{self, Write}; - -use rustc_hash::FxHashSet; - -use crate::{CfgAtom, CfgDiff, CfgExpr, CfgOptions, InactiveReason}; - -/// A `#[cfg]` directive in Disjunctive Normal Form (DNF). -pub struct DnfExpr { - conjunctions: Vec, -} - -struct Conjunction { - literals: Vec, -} - -struct Literal { - negate: bool, - var: Option, // None = Invalid -} - -impl DnfExpr { - pub fn new(expr: CfgExpr) -> Self { - let builder = Builder { expr: DnfExpr { conjunctions: Vec::new() } }; - - builder.lower(expr) - } - - /// Computes a list of present or absent atoms in `opts` that cause this expression to evaluate - /// to `false`. - /// - /// Note that flipping a subset of these atoms might be sufficient to make the whole expression - /// evaluate to `true`. For that, see `compute_enable_hints`. - /// - /// Returns `None` when `self` is already true, or contains errors. - pub fn why_inactive(&self, opts: &CfgOptions) -> Option { - let mut res = InactiveReason { enabled: Vec::new(), disabled: Vec::new() }; - - for conj in &self.conjunctions { - let mut conj_is_true = true; - for lit in &conj.literals { - let atom = lit.var.as_ref()?; - let enabled = opts.enabled.contains(atom); - if lit.negate == enabled { - // Literal is false, but needs to be true for this conjunction. - conj_is_true = false; - - if enabled { - res.enabled.push(atom.clone()); - } else { - res.disabled.push(atom.clone()); - } - } - } - - if conj_is_true { - // This expression is not actually inactive. - return None; - } - } - - res.enabled.sort_unstable(); - res.enabled.dedup(); - res.disabled.sort_unstable(); - res.disabled.dedup(); - Some(res) - } - - /// Returns `CfgDiff` objects that would enable this directive if applied to `opts`. - pub fn compute_enable_hints<'a>( - &'a self, - opts: &'a CfgOptions, - ) -> impl Iterator + 'a { - // A cfg is enabled if any of `self.conjunctions` evaluate to `true`. - - self.conjunctions.iter().filter_map(move |conj| { - let mut enable = FxHashSet::default(); - let mut disable = FxHashSet::default(); - for lit in &conj.literals { - let atom = lit.var.as_ref()?; - let enabled = opts.enabled.contains(atom); - if lit.negate && enabled { - disable.insert(atom.clone()); - } - if !lit.negate && !enabled { - enable.insert(atom.clone()); - } - } - - // Check that this actually makes `conj` true. - for lit in &conj.literals { - let atom = lit.var.as_ref()?; - let enabled = enable.contains(atom) - || (opts.enabled.contains(atom) && !disable.contains(atom)); - if enabled == lit.negate { - return None; - } - } - - if enable.is_empty() && disable.is_empty() { - return None; - } - - let mut diff = CfgDiff { - enable: enable.into_iter().collect(), - disable: disable.into_iter().collect(), - }; - - // Undo the FxHashMap randomization for consistent output. - diff.enable.sort_unstable(); - diff.disable.sort_unstable(); - - Some(diff) - }) - } -} - -impl fmt::Display for DnfExpr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.conjunctions.len() != 1 { - f.write_str("any(")?; - } - for (i, conj) in self.conjunctions.iter().enumerate() { - if i != 0 { - f.write_str(", ")?; - } - - conj.fmt(f)?; - } - if self.conjunctions.len() != 1 { - f.write_char(')')?; - } - - Ok(()) - } -} - -impl Conjunction { - fn new(parts: Vec) -> Self { - let mut literals = Vec::new(); - for part in parts { - match part { - CfgExpr::Invalid | CfgExpr::Atom(_) | CfgExpr::Not(_) => { - literals.push(Literal::new(part)); - } - CfgExpr::All(conj) => { - // Flatten. - literals.extend(Conjunction::new(conj).literals); - } - CfgExpr::Any(_) => unreachable!("disjunction in conjunction"), - } - } - - Self { literals } - } -} - -impl fmt::Display for Conjunction { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.literals.len() != 1 { - f.write_str("all(")?; - } - for (i, lit) in self.literals.iter().enumerate() { - if i != 0 { - f.write_str(", ")?; - } - - lit.fmt(f)?; - } - if self.literals.len() != 1 { - f.write_str(")")?; - } - - Ok(()) - } -} - -impl Literal { - fn new(expr: CfgExpr) -> Self { - match expr { - CfgExpr::Invalid => Self { negate: false, var: None }, - CfgExpr::Atom(atom) => Self { negate: false, var: Some(atom) }, - CfgExpr::Not(expr) => match *expr { - CfgExpr::Invalid => Self { negate: true, var: None }, - CfgExpr::Atom(atom) => Self { negate: true, var: Some(atom) }, - _ => unreachable!("non-atom {:?}", expr), - }, - CfgExpr::Any(_) | CfgExpr::All(_) => unreachable!("non-literal {:?}", expr), - } - } -} - -impl fmt::Display for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.negate { - write!(f, "not(")?; - } - - match &self.var { - Some(var) => var.fmt(f)?, - None => f.write_str("")?, - } - - if self.negate { - f.write_char(')')?; - } - - Ok(()) - } -} - -struct Builder { - expr: DnfExpr, -} - -impl Builder { - fn lower(mut self, expr: CfgExpr) -> DnfExpr { - let expr = make_nnf(expr); - let expr = make_dnf(expr); - - match expr { - CfgExpr::Invalid | CfgExpr::Atom(_) | CfgExpr::Not(_) => { - self.expr.conjunctions.push(Conjunction::new(vec![expr])); - } - CfgExpr::All(conj) => { - self.expr.conjunctions.push(Conjunction::new(conj)); - } - CfgExpr::Any(mut disj) => { - disj.reverse(); - while let Some(conj) = disj.pop() { - match conj { - CfgExpr::Invalid | CfgExpr::Atom(_) | CfgExpr::All(_) | CfgExpr::Not(_) => { - self.expr.conjunctions.push(Conjunction::new(vec![conj])); - } - CfgExpr::Any(inner_disj) => { - // Flatten. - disj.extend(inner_disj.into_iter().rev()); - } - } - } - } - } - - self.expr - } -} - -fn make_dnf(expr: CfgExpr) -> CfgExpr { - match expr { - CfgExpr::Invalid | CfgExpr::Atom(_) | CfgExpr::Not(_) => expr, - CfgExpr::Any(e) => flatten(CfgExpr::Any(e.into_iter().map(make_dnf).collect())), - CfgExpr::All(e) => { - let e = e.into_iter().map(make_dnf).collect::>(); - - flatten(CfgExpr::Any(distribute_conj(&e))) - } - } -} - -/// Turns a conjunction of expressions into a disjunction of expressions. -fn distribute_conj(conj: &[CfgExpr]) -> Vec { - fn go(out: &mut Vec, with: &mut Vec, rest: &[CfgExpr]) { - match rest { - [head, tail @ ..] => match head { - CfgExpr::Any(disj) => { - for part in disj { - with.push(part.clone()); - go(out, with, tail); - with.pop(); - } - } - _ => { - with.push(head.clone()); - go(out, with, tail); - with.pop(); - } - }, - _ => { - // Turn accumulated parts into a new conjunction. - out.push(CfgExpr::All(with.clone())); - } - } - } - - let mut out = Vec::new(); // contains only `all()` - let mut with = Vec::new(); - - go(&mut out, &mut with, conj); - - out -} - -fn make_nnf(expr: CfgExpr) -> CfgExpr { - match expr { - CfgExpr::Invalid | CfgExpr::Atom(_) => expr, - CfgExpr::Any(expr) => CfgExpr::Any(expr.into_iter().map(make_nnf).collect()), - CfgExpr::All(expr) => CfgExpr::All(expr.into_iter().map(make_nnf).collect()), - CfgExpr::Not(operand) => match *operand { - CfgExpr::Invalid | CfgExpr::Atom(_) => CfgExpr::Not(operand.clone()), // Original negated expr - CfgExpr::Not(expr) => { - // Remove double negation. - make_nnf(*expr) - } - // Convert negated conjunction/disjunction using DeMorgan's Law. - CfgExpr::Any(inner) => CfgExpr::All( - inner.into_iter().map(|expr| make_nnf(CfgExpr::Not(Box::new(expr)))).collect(), - ), - CfgExpr::All(inner) => CfgExpr::Any( - inner.into_iter().map(|expr| make_nnf(CfgExpr::Not(Box::new(expr)))).collect(), - ), - }, - } -} - -/// Collapses nested `any()` and `all()` predicates. -fn flatten(expr: CfgExpr) -> CfgExpr { - match expr { - CfgExpr::All(inner) => CfgExpr::All( - inner - .into_iter() - .flat_map(|e| match e { - CfgExpr::All(inner) => inner, - _ => vec![e], - }) - .collect(), - ), - CfgExpr::Any(inner) => CfgExpr::Any( - inner - .into_iter() - .flat_map(|e| match e { - CfgExpr::Any(inner) => inner, - _ => vec![e], - }) - .collect(), - ), - _ => expr, - } -} diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs deleted file mode 100644 index d78ef4fb11e7f..0000000000000 --- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs +++ /dev/null @@ -1,202 +0,0 @@ -//! cfg defines conditional compiling options, `cfg` attribute parser and evaluator - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -mod cfg_expr; -mod dnf; -#[cfg(test)] -mod tests; - -use std::fmt; - -use rustc_hash::FxHashSet; -use tt::SmolStr; - -pub use cfg_expr::{CfgAtom, CfgExpr}; -pub use dnf::DnfExpr; - -/// Configuration options used for conditional compilation on items with `cfg` attributes. -/// We have two kind of options in different namespaces: atomic options like `unix`, and -/// key-value options like `target_arch="x86"`. -/// -/// Note that for key-value options, one key can have multiple values (but not none). -/// `feature` is an example. We have both `feature="foo"` and `feature="bar"` if features -/// `foo` and `bar` are both enabled. And here, we store key-value options as a set of tuple -/// of key and value in `key_values`. -/// -/// See: -#[derive(Clone, PartialEq, Eq, Default)] -pub struct CfgOptions { - enabled: FxHashSet, -} - -impl fmt::Debug for CfgOptions { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut items = self - .enabled - .iter() - .map(|atom| match atom { - CfgAtom::Flag(it) => it.to_string(), - CfgAtom::KeyValue { key, value } => format!("{}={}", key, value), - }) - .collect::>(); - items.sort(); - f.debug_tuple("CfgOptions").field(&items).finish() - } -} - -impl CfgOptions { - pub fn check(&self, cfg: &CfgExpr) -> Option { - cfg.fold(&|atom| self.enabled.contains(atom)) - } - - pub fn insert_atom(&mut self, key: SmolStr) { - self.enabled.insert(CfgAtom::Flag(key)); - } - - pub fn insert_key_value(&mut self, key: SmolStr, value: SmolStr) { - self.enabled.insert(CfgAtom::KeyValue { key, value }); - } - - pub fn apply_diff(&mut self, diff: CfgDiff) { - for atom in diff.enable { - self.enabled.insert(atom); - } - - for atom in diff.disable { - self.enabled.remove(&atom); - } - } - - pub fn get_cfg_keys(&self) -> impl Iterator { - self.enabled.iter().map(|x| match x { - CfgAtom::Flag(key) => key, - CfgAtom::KeyValue { key, .. } => key, - }) - } - - pub fn get_cfg_values<'a>( - &'a self, - cfg_key: &'a str, - ) -> impl Iterator + 'a { - self.enabled.iter().filter_map(move |x| match x { - CfgAtom::KeyValue { key, value } if cfg_key == key => Some(value), - _ => None, - }) - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CfgDiff { - // Invariants: No duplicates, no atom that's both in `enable` and `disable`. - enable: Vec, - disable: Vec, -} - -impl CfgDiff { - /// Create a new CfgDiff. Will return None if the same item appears more than once in the set - /// of both. - pub fn new(enable: Vec, disable: Vec) -> Option { - let mut occupied = FxHashSet::default(); - for item in enable.iter().chain(disable.iter()) { - if !occupied.insert(item) { - // was present - return None; - } - } - - Some(CfgDiff { enable, disable }) - } - - /// Returns the total number of atoms changed by this diff. - pub fn len(&self) -> usize { - self.enable.len() + self.disable.len() - } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } -} - -impl fmt::Display for CfgDiff { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if !self.enable.is_empty() { - f.write_str("enable ")?; - for (i, atom) in self.enable.iter().enumerate() { - let sep = match i { - 0 => "", - _ if i == self.enable.len() - 1 => " and ", - _ => ", ", - }; - f.write_str(sep)?; - - atom.fmt(f)?; - } - - if !self.disable.is_empty() { - f.write_str("; ")?; - } - } - - if !self.disable.is_empty() { - f.write_str("disable ")?; - for (i, atom) in self.disable.iter().enumerate() { - let sep = match i { - 0 => "", - _ if i == self.enable.len() - 1 => " and ", - _ => ", ", - }; - f.write_str(sep)?; - - atom.fmt(f)?; - } - } - - Ok(()) - } -} - -pub struct InactiveReason { - enabled: Vec, - disabled: Vec, -} - -impl fmt::Display for InactiveReason { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if !self.enabled.is_empty() { - for (i, atom) in self.enabled.iter().enumerate() { - let sep = match i { - 0 => "", - _ if i == self.enabled.len() - 1 => " and ", - _ => ", ", - }; - f.write_str(sep)?; - - atom.fmt(f)?; - } - let is_are = if self.enabled.len() == 1 { "is" } else { "are" }; - write!(f, " {} enabled", is_are)?; - - if !self.disabled.is_empty() { - f.write_str(" and ")?; - } - } - - if !self.disabled.is_empty() { - for (i, atom) in self.disabled.iter().enumerate() { - let sep = match i { - 0 => "", - _ if i == self.disabled.len() - 1 => " and ", - _ => ", ", - }; - f.write_str(sep)?; - - atom.fmt(f)?; - } - let is_are = if self.disabled.len() == 1 { "is" } else { "are" }; - write!(f, " {} disabled", is_are)?; - } - - Ok(()) - } -} diff --git a/src/tools/rust-analyzer/crates/cfg/src/tests.rs b/src/tools/rust-analyzer/crates/cfg/src/tests.rs deleted file mode 100644 index bdc3f854e0866..0000000000000 --- a/src/tools/rust-analyzer/crates/cfg/src/tests.rs +++ /dev/null @@ -1,224 +0,0 @@ -use arbitrary::{Arbitrary, Unstructured}; -use expect_test::{expect, Expect}; -use mbe::syntax_node_to_token_tree; -use syntax::{ast, AstNode}; - -use crate::{CfgAtom, CfgExpr, CfgOptions, DnfExpr}; - -fn assert_parse_result(input: &str, expected: CfgExpr) { - let (tt, _) = { - let source_file = ast::SourceFile::parse(input).ok().unwrap(); - let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - syntax_node_to_token_tree(tt.syntax()) - }; - let cfg = CfgExpr::parse(&tt); - assert_eq!(cfg, expected); -} - -fn check_dnf(input: &str, expect: Expect) { - let (tt, _) = { - let source_file = ast::SourceFile::parse(input).ok().unwrap(); - let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - syntax_node_to_token_tree(tt.syntax()) - }; - let cfg = CfgExpr::parse(&tt); - let actual = format!("#![cfg({})]", DnfExpr::new(cfg)); - expect.assert_eq(&actual); -} - -fn check_why_inactive(input: &str, opts: &CfgOptions, expect: Expect) { - let (tt, _) = { - let source_file = ast::SourceFile::parse(input).ok().unwrap(); - let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - syntax_node_to_token_tree(tt.syntax()) - }; - let cfg = CfgExpr::parse(&tt); - let dnf = DnfExpr::new(cfg); - let why_inactive = dnf.why_inactive(opts).unwrap().to_string(); - expect.assert_eq(&why_inactive); -} - -#[track_caller] -fn check_enable_hints(input: &str, opts: &CfgOptions, expected_hints: &[&str]) { - let (tt, _) = { - let source_file = ast::SourceFile::parse(input).ok().unwrap(); - let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - syntax_node_to_token_tree(tt.syntax()) - }; - let cfg = CfgExpr::parse(&tt); - let dnf = DnfExpr::new(cfg); - let hints = dnf.compute_enable_hints(opts).map(|diff| diff.to_string()).collect::>(); - assert_eq!(hints, expected_hints); -} - -#[test] -fn test_cfg_expr_parser() { - assert_parse_result("#![cfg(foo)]", CfgAtom::Flag("foo".into()).into()); - assert_parse_result("#![cfg(foo,)]", CfgAtom::Flag("foo".into()).into()); - assert_parse_result( - "#![cfg(not(foo))]", - CfgExpr::Not(Box::new(CfgAtom::Flag("foo".into()).into())), - ); - assert_parse_result("#![cfg(foo(bar))]", CfgExpr::Invalid); - - // Only take the first - assert_parse_result(r#"#![cfg(foo, bar = "baz")]"#, CfgAtom::Flag("foo".into()).into()); - - assert_parse_result( - r#"#![cfg(all(foo, bar = "baz"))]"#, - CfgExpr::All(vec![ - CfgAtom::Flag("foo".into()).into(), - CfgAtom::KeyValue { key: "bar".into(), value: "baz".into() }.into(), - ]), - ); - - assert_parse_result( - r#"#![cfg(any(not(), all(), , bar = "baz",))]"#, - CfgExpr::Any(vec![ - CfgExpr::Not(Box::new(CfgExpr::Invalid)), - CfgExpr::All(vec![]), - CfgExpr::Invalid, - CfgAtom::KeyValue { key: "bar".into(), value: "baz".into() }.into(), - ]), - ); -} - -#[test] -fn smoke() { - check_dnf("#![cfg(test)]", expect![[r#"#![cfg(test)]"#]]); - check_dnf("#![cfg(not(test))]", expect![[r#"#![cfg(not(test))]"#]]); - check_dnf("#![cfg(not(not(test)))]", expect![[r#"#![cfg(test)]"#]]); - - check_dnf("#![cfg(all(a, b))]", expect![[r#"#![cfg(all(a, b))]"#]]); - check_dnf("#![cfg(any(a, b))]", expect![[r#"#![cfg(any(a, b))]"#]]); - - check_dnf("#![cfg(not(a))]", expect![[r#"#![cfg(not(a))]"#]]); -} - -#[test] -fn distribute() { - check_dnf("#![cfg(all(any(a, b), c))]", expect![[r#"#![cfg(any(all(a, c), all(b, c)))]"#]]); - check_dnf("#![cfg(all(c, any(a, b)))]", expect![[r#"#![cfg(any(all(c, a), all(c, b)))]"#]]); - check_dnf( - "#![cfg(all(any(a, b), any(c, d)))]", - expect![[r#"#![cfg(any(all(a, c), all(a, d), all(b, c), all(b, d)))]"#]], - ); - - check_dnf( - "#![cfg(all(any(a, b, c), any(d, e, f), g))]", - expect![[ - r#"#![cfg(any(all(a, d, g), all(a, e, g), all(a, f, g), all(b, d, g), all(b, e, g), all(b, f, g), all(c, d, g), all(c, e, g), all(c, f, g)))]"# - ]], - ); -} - -#[test] -fn demorgan() { - check_dnf("#![cfg(not(all(a, b)))]", expect![[r#"#![cfg(any(not(a), not(b)))]"#]]); - check_dnf("#![cfg(not(any(a, b)))]", expect![[r#"#![cfg(all(not(a), not(b)))]"#]]); - - check_dnf("#![cfg(not(all(not(a), b)))]", expect![[r#"#![cfg(any(a, not(b)))]"#]]); - check_dnf("#![cfg(not(any(a, not(b))))]", expect![[r#"#![cfg(all(not(a), b))]"#]]); -} - -#[test] -fn nested() { - check_dnf("#![cfg(all(any(a), not(all(any(b)))))]", expect![[r#"#![cfg(all(a, not(b)))]"#]]); - - check_dnf("#![cfg(any(any(a, b)))]", expect![[r#"#![cfg(any(a, b))]"#]]); - check_dnf("#![cfg(not(any(any(a, b))))]", expect![[r#"#![cfg(all(not(a), not(b)))]"#]]); - check_dnf("#![cfg(all(all(a, b)))]", expect![[r#"#![cfg(all(a, b))]"#]]); - check_dnf("#![cfg(not(all(all(a, b))))]", expect![[r#"#![cfg(any(not(a), not(b)))]"#]]); -} - -#[test] -fn regression() { - check_dnf("#![cfg(all(not(not(any(any(any()))))))]", expect![[r##"#![cfg(any())]"##]]); - check_dnf("#![cfg(all(any(all(any()))))]", expect![[r##"#![cfg(any())]"##]]); - check_dnf("#![cfg(all(all(any())))]", expect![[r##"#![cfg(any())]"##]]); - - check_dnf("#![cfg(all(all(any(), x)))]", expect![[r##"#![cfg(any())]"##]]); - check_dnf("#![cfg(all(all(any()), x))]", expect![[r##"#![cfg(any())]"##]]); - check_dnf("#![cfg(all(all(any(x))))]", expect![[r##"#![cfg(x)]"##]]); - check_dnf("#![cfg(all(all(any(x), x)))]", expect![[r##"#![cfg(all(x, x))]"##]]); -} - -#[test] -fn hints() { - let mut opts = CfgOptions::default(); - - check_enable_hints("#![cfg(test)]", &opts, &["enable test"]); - check_enable_hints("#![cfg(not(test))]", &opts, &[]); - - check_enable_hints("#![cfg(any(a, b))]", &opts, &["enable a", "enable b"]); - check_enable_hints("#![cfg(any(b, a))]", &opts, &["enable b", "enable a"]); - - check_enable_hints("#![cfg(all(a, b))]", &opts, &["enable a and b"]); - - opts.insert_atom("test".into()); - - check_enable_hints("#![cfg(test)]", &opts, &[]); - check_enable_hints("#![cfg(not(test))]", &opts, &["disable test"]); -} - -/// Tests that we don't suggest hints for cfgs that express an inconsistent formula. -#[test] -fn hints_impossible() { - let mut opts = CfgOptions::default(); - - check_enable_hints("#![cfg(all(test, not(test)))]", &opts, &[]); - - opts.insert_atom("test".into()); - - check_enable_hints("#![cfg(all(test, not(test)))]", &opts, &[]); -} - -#[test] -fn why_inactive() { - let mut opts = CfgOptions::default(); - opts.insert_atom("test".into()); - opts.insert_atom("test2".into()); - - check_why_inactive("#![cfg(a)]", &opts, expect![["a is disabled"]]); - check_why_inactive("#![cfg(not(test))]", &opts, expect![["test is enabled"]]); - - check_why_inactive( - "#![cfg(all(not(test), not(test2)))]", - &opts, - expect![["test and test2 are enabled"]], - ); - check_why_inactive("#![cfg(all(a, b))]", &opts, expect![["a and b are disabled"]]); - check_why_inactive( - "#![cfg(all(not(test), a))]", - &opts, - expect![["test is enabled and a is disabled"]], - ); - check_why_inactive( - "#![cfg(all(not(test), test2, a))]", - &opts, - expect![["test is enabled and a is disabled"]], - ); - check_why_inactive( - "#![cfg(all(not(test), not(test2), a))]", - &opts, - expect![["test and test2 are enabled and a is disabled"]], - ); -} - -#[test] -fn proptest() { - const REPEATS: usize = 512; - - let mut rng = oorandom::Rand32::new(123456789); - let mut buf = Vec::new(); - for _ in 0..REPEATS { - buf.clear(); - while buf.len() < 512 { - buf.extend(rng.rand_u32().to_ne_bytes()); - } - - let mut u = Unstructured::new(&buf); - let cfg = CfgExpr::arbitrary(&mut u).unwrap(); - DnfExpr::new(cfg); - } -} diff --git a/src/tools/rust-analyzer/crates/flycheck/Cargo.toml b/src/tools/rust-analyzer/crates/flycheck/Cargo.toml deleted file mode 100644 index d3d180ece512a..0000000000000 --- a/src/tools/rust-analyzer/crates/flycheck/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "flycheck" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -crossbeam-channel = "0.5.5" -tracing = "0.1.35" -cargo_metadata = "0.15.0" -serde = { version = "1.0.137", features = ["derive"] } -serde_json = "1.0.81" -jod-thread = "0.1.2" - -toolchain = { path = "../toolchain", version = "0.0.0" } -stdx = { path = "../stdx", version = "0.0.0" } -paths = { path = "../paths", version = "0.0.0" } diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs deleted file mode 100644 index 4e8bc881ae738..0000000000000 --- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs +++ /dev/null @@ -1,396 +0,0 @@ -//! Flycheck provides the functionality needed to run `cargo check` or -//! another compatible command (f.x. clippy) in a background thread and provide -//! LSP diagnostics based on the output of the command. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -use std::{ - fmt, io, - process::{ChildStderr, ChildStdout, Command, Stdio}, - time::Duration, -}; - -use crossbeam_channel::{never, select, unbounded, Receiver, Sender}; -use paths::AbsPathBuf; -use serde::Deserialize; -use stdx::{process::streaming_output, JodChild}; - -pub use cargo_metadata::diagnostic::{ - Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan, - DiagnosticSpanMacroExpansion, -}; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum FlycheckConfig { - CargoCommand { - command: String, - target_triple: Option, - all_targets: bool, - no_default_features: bool, - all_features: bool, - features: Vec, - extra_args: Vec, - }, - CustomCommand { - command: String, - args: Vec, - }, -} - -impl fmt::Display for FlycheckConfig { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - FlycheckConfig::CargoCommand { command, .. } => write!(f, "cargo {}", command), - FlycheckConfig::CustomCommand { command, args } => { - write!(f, "{} {}", command, args.join(" ")) - } - } - } -} - -/// Flycheck wraps the shared state and communication machinery used for -/// running `cargo check` (or other compatible command) and providing -/// diagnostics based on the output. -/// The spawned thread is shut down when this struct is dropped. -#[derive(Debug)] -pub struct FlycheckHandle { - // XXX: drop order is significant - sender: Sender, - _thread: jod_thread::JoinHandle, -} - -impl FlycheckHandle { - pub fn spawn( - id: usize, - sender: Box, - config: FlycheckConfig, - workspace_root: AbsPathBuf, - ) -> FlycheckHandle { - let actor = FlycheckActor::new(id, sender, config, workspace_root); - let (sender, receiver) = unbounded::(); - let thread = jod_thread::Builder::new() - .name("Flycheck".to_owned()) - .spawn(move || actor.run(receiver)) - .expect("failed to spawn thread"); - FlycheckHandle { sender, _thread: thread } - } - - /// Schedule a re-start of the cargo check worker. - pub fn update(&self) { - self.sender.send(Restart).unwrap(); - } -} - -pub enum Message { - /// Request adding a diagnostic with fixes included to a file - AddDiagnostic { workspace_root: AbsPathBuf, diagnostic: Diagnostic }, - - /// Request check progress notification to client - Progress { - /// Flycheck instance ID - id: usize, - progress: Progress, - }, -} - -impl fmt::Debug for Message { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Message::AddDiagnostic { workspace_root, diagnostic } => f - .debug_struct("AddDiagnostic") - .field("workspace_root", workspace_root) - .field("diagnostic_code", &diagnostic.code.as_ref().map(|it| &it.code)) - .finish(), - Message::Progress { id, progress } => { - f.debug_struct("Progress").field("id", id).field("progress", progress).finish() - } - } - } -} - -#[derive(Debug)] -pub enum Progress { - DidStart, - DidCheckCrate(String), - DidFinish(io::Result<()>), - DidCancel, -} - -struct Restart; - -struct FlycheckActor { - id: usize, - sender: Box, - config: FlycheckConfig, - workspace_root: AbsPathBuf, - /// CargoHandle exists to wrap around the communication needed to be able to - /// run `cargo check` without blocking. Currently the Rust standard library - /// doesn't provide a way to read sub-process output without blocking, so we - /// have to wrap sub-processes output handling in a thread and pass messages - /// back over a channel. - cargo_handle: Option, -} - -enum Event { - Restart(Restart), - CheckEvent(Option), -} - -impl FlycheckActor { - fn new( - id: usize, - sender: Box, - config: FlycheckConfig, - workspace_root: AbsPathBuf, - ) -> FlycheckActor { - FlycheckActor { id, sender, config, workspace_root, cargo_handle: None } - } - fn progress(&self, progress: Progress) { - self.send(Message::Progress { id: self.id, progress }); - } - fn next_event(&self, inbox: &Receiver) -> Option { - let check_chan = self.cargo_handle.as_ref().map(|cargo| &cargo.receiver); - select! { - recv(inbox) -> msg => msg.ok().map(Event::Restart), - recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())), - } - } - fn run(mut self, inbox: Receiver) { - while let Some(event) = self.next_event(&inbox) { - match event { - Event::Restart(Restart) => { - // Cancel the previously spawned process - self.cancel_check_process(); - while let Ok(Restart) = inbox.recv_timeout(Duration::from_millis(50)) {} - - let command = self.check_command(); - tracing::debug!(?command, "will restart flycheck"); - match CargoHandle::spawn(command) { - Ok(cargo_handle) => { - tracing::debug!( - command = ?self.check_command(), - "did restart flycheck" - ); - self.cargo_handle = Some(cargo_handle); - self.progress(Progress::DidStart); - } - Err(error) => { - tracing::error!( - command = ?self.check_command(), - %error, "failed to restart flycheck" - ); - } - } - } - Event::CheckEvent(None) => { - tracing::debug!("flycheck finished"); - - // Watcher finished - let cargo_handle = self.cargo_handle.take().unwrap(); - let res = cargo_handle.join(); - if res.is_err() { - tracing::error!( - "Flycheck failed to run the following command: {:?}", - self.check_command() - ); - } - self.progress(Progress::DidFinish(res)); - } - Event::CheckEvent(Some(message)) => match message { - CargoMessage::CompilerArtifact(msg) => { - self.progress(Progress::DidCheckCrate(msg.target.name)); - } - - CargoMessage::Diagnostic(msg) => { - self.send(Message::AddDiagnostic { - workspace_root: self.workspace_root.clone(), - diagnostic: msg, - }); - } - }, - } - } - // If we rerun the thread, we need to discard the previous check results first - self.cancel_check_process(); - } - - fn cancel_check_process(&mut self) { - if let Some(cargo_handle) = self.cargo_handle.take() { - cargo_handle.cancel(); - self.progress(Progress::DidCancel); - } - } - - fn check_command(&self) -> Command { - let mut cmd = match &self.config { - FlycheckConfig::CargoCommand { - command, - target_triple, - no_default_features, - all_targets, - all_features, - extra_args, - features, - } => { - let mut cmd = Command::new(toolchain::cargo()); - cmd.arg(command); - cmd.current_dir(&self.workspace_root); - cmd.args(&["--workspace", "--message-format=json", "--manifest-path"]) - .arg(self.workspace_root.join("Cargo.toml").as_os_str()); - - if let Some(target) = target_triple { - cmd.args(&["--target", target.as_str()]); - } - if *all_targets { - cmd.arg("--all-targets"); - } - if *all_features { - cmd.arg("--all-features"); - } else { - if *no_default_features { - cmd.arg("--no-default-features"); - } - if !features.is_empty() { - cmd.arg("--features"); - cmd.arg(features.join(" ")); - } - } - cmd.args(extra_args); - cmd - } - FlycheckConfig::CustomCommand { command, args } => { - let mut cmd = Command::new(command); - cmd.args(args); - cmd - } - }; - cmd.current_dir(&self.workspace_root); - cmd - } - - fn send(&self, check_task: Message) { - (self.sender)(check_task); - } -} - -/// A handle to a cargo process used for fly-checking. -struct CargoHandle { - /// The handle to the actual cargo process. As we cannot cancel directly from with - /// a read syscall dropping and therefor terminating the process is our best option. - child: JodChild, - thread: jod_thread::JoinHandle>, - receiver: Receiver, -} - -impl CargoHandle { - fn spawn(mut command: Command) -> std::io::Result { - command.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null()); - let mut child = JodChild::spawn(command)?; - - let stdout = child.stdout.take().unwrap(); - let stderr = child.stderr.take().unwrap(); - - let (sender, receiver) = unbounded(); - let actor = CargoActor::new(sender, stdout, stderr); - let thread = jod_thread::Builder::new() - .name("CargoHandle".to_owned()) - .spawn(move || actor.run()) - .expect("failed to spawn thread"); - Ok(CargoHandle { child, thread, receiver }) - } - - fn cancel(mut self) { - let _ = self.child.kill(); - let _ = self.child.wait(); - } - - fn join(mut self) -> io::Result<()> { - let _ = self.child.kill(); - let exit_status = self.child.wait()?; - let (read_at_least_one_message, error) = self.thread.join()?; - if read_at_least_one_message || exit_status.success() { - Ok(()) - } else { - Err(io::Error::new(io::ErrorKind::Other, format!( - "Cargo watcher failed, the command produced no valid metadata (exit code: {:?}):\n{}", - exit_status, error - ))) - } - } -} - -struct CargoActor { - sender: Sender, - stdout: ChildStdout, - stderr: ChildStderr, -} - -impl CargoActor { - fn new(sender: Sender, stdout: ChildStdout, stderr: ChildStderr) -> CargoActor { - CargoActor { sender, stdout, stderr } - } - - fn run(self) -> io::Result<(bool, String)> { - // We manually read a line at a time, instead of using serde's - // stream deserializers, because the deserializer cannot recover - // from an error, resulting in it getting stuck, because we try to - // be resilient against failures. - // - // Because cargo only outputs one JSON object per line, we can - // simply skip a line if it doesn't parse, which just ignores any - // erroneus output. - - let mut error = String::new(); - let mut read_at_least_one_message = false; - let output = streaming_output( - self.stdout, - self.stderr, - &mut |line| { - read_at_least_one_message = true; - - // Try to deserialize a message from Cargo or Rustc. - let mut deserializer = serde_json::Deserializer::from_str(line); - deserializer.disable_recursion_limit(); - if let Ok(message) = JsonMessage::deserialize(&mut deserializer) { - match message { - // Skip certain kinds of messages to only spend time on what's useful - JsonMessage::Cargo(message) => match message { - cargo_metadata::Message::CompilerArtifact(artifact) - if !artifact.fresh => - { - self.sender.send(CargoMessage::CompilerArtifact(artifact)).unwrap(); - } - cargo_metadata::Message::CompilerMessage(msg) => { - self.sender.send(CargoMessage::Diagnostic(msg.message)).unwrap(); - } - _ => (), - }, - JsonMessage::Rustc(message) => { - self.sender.send(CargoMessage::Diagnostic(message)).unwrap(); - } - } - } - }, - &mut |line| { - error.push_str(line); - error.push('\n'); - }, - ); - match output { - Ok(_) => Ok((read_at_least_one_message, error)), - Err(e) => Err(io::Error::new(e.kind(), format!("{:?}: {}", e, error))), - } - } -} - -enum CargoMessage { - CompilerArtifact(cargo_metadata::Artifact), - Diagnostic(Diagnostic), -} - -#[derive(Deserialize)] -#[serde(untagged)] -enum JsonMessage { - Cargo(cargo_metadata::Message), - Rustc(Diagnostic), -} diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml deleted file mode 100644 index e8cff2f3e6cd7..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml +++ /dev/null @@ -1,43 +0,0 @@ -[package] -name = "hir-def" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -anymap = "1.0.0-beta.2" -arrayvec = "0.7.2" -bitflags = "1.3.2" -cov-mark = "2.0.0-pre.1" -# We need to freeze the version of the crate, as the raw-api feature is considered unstable -dashmap = { version = "=5.3.4", features = ["raw-api"] } -drop_bomb = "0.1.5" -either = "1.7.0" -fst = { version = "0.4.7", default-features = false } -hashbrown = { version = "0.12.1", default-features = false } -indexmap = "1.9.1" -itertools = "0.10.3" -la-arena = { version = "0.3.0", path = "../../lib/la-arena" } -once_cell = "1.12.0" -rustc-hash = "1.1.0" -smallvec = "1.9.0" -tracing = "0.1.35" - -stdx = { path = "../stdx", version = "0.0.0" } -base-db = { path = "../base-db", version = "0.0.0" } -syntax = { path = "../syntax", version = "0.0.0" } -profile = { path = "../profile", version = "0.0.0" } -hir-expand = { path = "../hir-expand", version = "0.0.0" } -mbe = { path = "../mbe", version = "0.0.0" } -cfg = { path = "../cfg", version = "0.0.0" } -tt = { path = "../tt", version = "0.0.0" } -limit = { path = "../limit", version = "0.0.0" } - -[dev-dependencies] -test-utils = { path = "../test-utils" } -expect-test = "1.4.0" diff --git a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/adt.rs deleted file mode 100644 index 277135d6dc428..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs +++ /dev/null @@ -1,365 +0,0 @@ -//! Defines hir-level representation of structs, enums and unions - -use std::sync::Arc; - -use base_db::CrateId; -use either::Either; -use hir_expand::{ - name::{AsName, Name}, - InFile, -}; -use la_arena::{Arena, ArenaMap}; -use syntax::ast::{self, HasName, HasVisibility}; -use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}; - -use crate::{ - body::{CfgExpander, LowerCtx}, - db::DefDatabase, - intern::Interned, - item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId}, - src::HasChildSource, - src::HasSource, - trace::Trace, - type_ref::TypeRef, - visibility::RawVisibility, - EnumId, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId, VariantId, -}; -use cfg::CfgOptions; - -/// Note that we use `StructData` for unions as well! -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StructData { - pub name: Name, - pub variant_data: Arc, - pub repr: Option, - pub visibility: RawVisibility, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EnumData { - pub name: Name, - pub variants: Arena, - pub visibility: RawVisibility, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EnumVariantData { - pub name: Name, - pub variant_data: Arc, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum VariantData { - Record(Arena), - Tuple(Arena), - Unit, -} - -/// A single field of an enum variant or struct -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FieldData { - pub name: Name, - pub type_ref: Interned, - pub visibility: RawVisibility, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ReprKind { - Packed, - Other, -} - -fn repr_from_value( - db: &dyn DefDatabase, - krate: CrateId, - item_tree: &ItemTree, - of: AttrOwner, -) -> Option { - item_tree.attrs(db, krate, of).by_key("repr").tt_values().find_map(parse_repr_tt) -} - -fn parse_repr_tt(tt: &Subtree) -> Option { - match tt.delimiter { - Some(Delimiter { kind: DelimiterKind::Parenthesis, .. }) => {} - _ => return None, - } - - let mut it = tt.token_trees.iter(); - match it.next()? { - TokenTree::Leaf(Leaf::Ident(ident)) if ident.text == "packed" => Some(ReprKind::Packed), - _ => Some(ReprKind::Other), - } -} - -impl StructData { - pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc { - let loc = id.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); - let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone(); - - let strukt = &item_tree[loc.id.value]; - let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &strukt.fields, None); - Arc::new(StructData { - name: strukt.name.clone(), - variant_data: Arc::new(variant_data), - repr, - visibility: item_tree[strukt.visibility].clone(), - }) - } - pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc { - let loc = id.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); - let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone(); - - let union = &item_tree[loc.id.value]; - let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &union.fields, None); - - Arc::new(StructData { - name: union.name.clone(), - variant_data: Arc::new(variant_data), - repr, - visibility: item_tree[union.visibility].clone(), - }) - } -} - -impl EnumData { - pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc { - let loc = e.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let cfg_options = db.crate_graph()[krate].cfg_options.clone(); - - let enum_ = &item_tree[loc.id.value]; - let mut variants = Arena::new(); - for tree_id in enum_.variants.clone() { - if item_tree.attrs(db, krate, tree_id.into()).is_cfg_enabled(&cfg_options) { - let var = &item_tree[tree_id]; - let var_data = lower_fields( - db, - krate, - &item_tree, - &cfg_options, - &var.fields, - Some(enum_.visibility), - ); - - variants.alloc(EnumVariantData { - name: var.name.clone(), - variant_data: Arc::new(var_data), - }); - } - } - - Arc::new(EnumData { - name: enum_.name.clone(), - variants, - visibility: item_tree[enum_.visibility].clone(), - }) - } - - pub fn variant(&self, name: &Name) -> Option { - let (id, _) = self.variants.iter().find(|(_id, data)| &data.name == name)?; - Some(id) - } -} - -impl HasChildSource for EnumId { - type Value = ast::Variant; - fn child_source( - &self, - db: &dyn DefDatabase, - ) -> InFile> { - let src = self.lookup(db).source(db); - let mut trace = Trace::new_for_map(); - lower_enum(db, &mut trace, &src, self.lookup(db).container); - src.with_value(trace.into_map()) - } -} - -fn lower_enum( - db: &dyn DefDatabase, - trace: &mut Trace, - ast: &InFile, - module_id: ModuleId, -) { - let expander = CfgExpander::new(db, ast.file_id, module_id.krate); - let variants = ast - .value - .variant_list() - .into_iter() - .flat_map(|it| it.variants()) - .filter(|var| expander.is_cfg_enabled(db, var)); - for var in variants { - trace.alloc( - || var.clone(), - || EnumVariantData { - name: var.name().map_or_else(Name::missing, |it| it.as_name()), - variant_data: Arc::new(VariantData::new(db, ast.with_value(var.kind()), module_id)), - }, - ); - } -} - -impl VariantData { - fn new(db: &dyn DefDatabase, flavor: InFile, module_id: ModuleId) -> Self { - let mut expander = CfgExpander::new(db, flavor.file_id, module_id.krate); - let mut trace = Trace::new_for_arena(); - match lower_struct(db, &mut expander, &mut trace, &flavor) { - StructKind::Tuple => VariantData::Tuple(trace.into_arena()), - StructKind::Record => VariantData::Record(trace.into_arena()), - StructKind::Unit => VariantData::Unit, - } - } - - pub fn fields(&self) -> &Arena { - const EMPTY: &Arena = &Arena::new(); - match &self { - VariantData::Record(fields) | VariantData::Tuple(fields) => fields, - _ => EMPTY, - } - } - - pub fn field(&self, name: &Name) -> Option { - self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None }) - } - - pub fn kind(&self) -> StructKind { - match self { - VariantData::Record(_) => StructKind::Record, - VariantData::Tuple(_) => StructKind::Tuple, - VariantData::Unit => StructKind::Unit, - } - } -} - -impl HasChildSource for VariantId { - type Value = Either; - - fn child_source(&self, db: &dyn DefDatabase) -> InFile> { - let (src, module_id) = match self { - VariantId::EnumVariantId(it) => { - // I don't really like the fact that we call into parent source - // here, this might add to more queries then necessary. - let src = it.parent.child_source(db); - (src.map(|map| map[it.local_id].kind()), it.parent.lookup(db).container) - } - VariantId::StructId(it) => { - (it.lookup(db).source(db).map(|it| it.kind()), it.lookup(db).container) - } - VariantId::UnionId(it) => ( - it.lookup(db).source(db).map(|it| { - it.record_field_list() - .map(ast::StructKind::Record) - .unwrap_or(ast::StructKind::Unit) - }), - it.lookup(db).container, - ), - }; - let mut expander = CfgExpander::new(db, src.file_id, module_id.krate); - let mut trace = Trace::new_for_map(); - lower_struct(db, &mut expander, &mut trace, &src); - src.with_value(trace.into_map()) - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum StructKind { - Tuple, - Record, - Unit, -} - -fn lower_struct( - db: &dyn DefDatabase, - expander: &mut CfgExpander, - trace: &mut Trace>, - ast: &InFile, -) -> StructKind { - let ctx = LowerCtx::new(db, ast.file_id); - - match &ast.value { - ast::StructKind::Tuple(fl) => { - for (i, fd) in fl.fields().enumerate() { - if !expander.is_cfg_enabled(db, &fd) { - continue; - } - - trace.alloc( - || Either::Left(fd.clone()), - || FieldData { - name: Name::new_tuple_field(i), - type_ref: Interned::new(TypeRef::from_ast_opt(&ctx, fd.ty())), - visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), - }, - ); - } - StructKind::Tuple - } - ast::StructKind::Record(fl) => { - for fd in fl.fields() { - if !expander.is_cfg_enabled(db, &fd) { - continue; - } - - trace.alloc( - || Either::Right(fd.clone()), - || FieldData { - name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), - type_ref: Interned::new(TypeRef::from_ast_opt(&ctx, fd.ty())), - visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), - }, - ); - } - StructKind::Record - } - ast::StructKind::Unit => StructKind::Unit, - } -} - -fn lower_fields( - db: &dyn DefDatabase, - krate: CrateId, - item_tree: &ItemTree, - cfg_options: &CfgOptions, - fields: &Fields, - override_visibility: Option, -) -> VariantData { - match fields { - Fields::Record(flds) => { - let mut arena = Arena::new(); - for field_id in flds.clone() { - if item_tree.attrs(db, krate, field_id.into()).is_cfg_enabled(cfg_options) { - arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility)); - } - } - VariantData::Record(arena) - } - Fields::Tuple(flds) => { - let mut arena = Arena::new(); - for field_id in flds.clone() { - if item_tree.attrs(db, krate, field_id.into()).is_cfg_enabled(cfg_options) { - arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility)); - } - } - VariantData::Tuple(arena) - } - Fields::Unit => VariantData::Unit, - } -} - -fn lower_field( - item_tree: &ItemTree, - field: &Field, - override_visibility: Option, -) -> FieldData { - FieldData { - name: field.name.clone(), - type_ref: field.type_ref.clone(), - visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(), - } -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs deleted file mode 100644 index 8a6b6f3effd2e..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ /dev/null @@ -1,991 +0,0 @@ -//! A higher level attributes based on TokenTree, with also some shortcuts. - -use std::{fmt, hash::Hash, ops, sync::Arc}; - -use base_db::CrateId; -use cfg::{CfgExpr, CfgOptions}; -use either::Either; -use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; -use itertools::Itertools; -use la_arena::{ArenaMap, Idx, RawIdx}; -use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct}; -use smallvec::{smallvec, SmallVec}; -use syntax::{ - ast::{self, AstNode, HasAttrs, IsString}, - match_ast, AstPtr, AstToken, SmolStr, SyntaxNode, TextRange, TextSize, -}; -use tt::Subtree; - -use crate::{ - db::DefDatabase, - intern::Interned, - item_tree::{AttrOwner, Fields, ItemTreeId, ItemTreeNode}, - nameres::{ModuleOrigin, ModuleSource}, - path::{ModPath, PathKind}, - src::{HasChildSource, HasSource}, - AdtId, AttrDefId, EnumId, GenericParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroId, - VariantId, -}; - -/// Holds documentation -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Documentation(String); - -impl Documentation { - pub fn new(s: String) -> Self { - Documentation(s) - } - - pub fn as_str(&self) -> &str { - &self.0 - } -} - -impl From for String { - fn from(Documentation(string): Documentation) -> Self { - string - } -} - -/// Syntactical attributes, without filtering of `cfg_attr`s. -#[derive(Default, Debug, Clone, PartialEq, Eq)] -pub(crate) struct RawAttrs { - entries: Option>, -} - -#[derive(Default, Debug, Clone, PartialEq, Eq)] -pub struct Attrs(RawAttrs); - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct AttrsWithOwner { - attrs: Attrs, - owner: AttrDefId, -} - -impl ops::Deref for RawAttrs { - type Target = [Attr]; - - fn deref(&self) -> &[Attr] { - match &self.entries { - Some(it) => &*it, - None => &[], - } - } -} -impl Attrs { - pub fn get(&self, id: AttrId) -> Option<&Attr> { - (**self).iter().find(|attr| attr.id == id) - } -} - -impl ops::Deref for Attrs { - type Target = [Attr]; - - fn deref(&self) -> &[Attr] { - match &self.0.entries { - Some(it) => &*it, - None => &[], - } - } -} - -impl ops::Deref for AttrsWithOwner { - type Target = Attrs; - - fn deref(&self) -> &Attrs { - &self.attrs - } -} - -impl RawAttrs { - pub(crate) const EMPTY: Self = Self { entries: None }; - - pub(crate) fn new(db: &dyn DefDatabase, owner: &dyn ast::HasAttrs, hygiene: &Hygiene) -> Self { - let entries = collect_attrs(owner) - .filter_map(|(id, attr)| match attr { - Either::Left(attr) => { - attr.meta().and_then(|meta| Attr::from_src(db, meta, hygiene, id)) - } - Either::Right(comment) => comment.doc_comment().map(|doc| Attr { - id, - input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))), - path: Interned::new(ModPath::from(hir_expand::name!(doc))), - }), - }) - .collect::>(); - - Self { entries: if entries.is_empty() { None } else { Some(entries) } } - } - - fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn ast::HasAttrs>) -> Self { - let hygiene = Hygiene::new(db.upcast(), owner.file_id); - Self::new(db, owner.value, &hygiene) - } - - pub(crate) fn merge(&self, other: Self) -> Self { - // FIXME: This needs to fixup `AttrId`s - match (&self.entries, &other.entries) { - (None, None) => Self::EMPTY, - (Some(entries), None) | (None, Some(entries)) => { - Self { entries: Some(entries.clone()) } - } - (Some(a), Some(b)) => { - Self { entries: Some(a.iter().chain(b.iter()).cloned().collect()) } - } - } - } - - /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`. - pub(crate) fn filter(self, db: &dyn DefDatabase, krate: CrateId) -> Attrs { - let has_cfg_attrs = self.iter().any(|attr| { - attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr]) - }); - if !has_cfg_attrs { - return Attrs(self); - } - - let crate_graph = db.crate_graph(); - let new_attrs = self - .iter() - .flat_map(|attr| -> SmallVec<[_; 1]> { - let is_cfg_attr = - attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr]); - if !is_cfg_attr { - return smallvec![attr.clone()]; - } - - let subtree = match attr.token_tree_value() { - Some(it) => it, - _ => return smallvec![attr.clone()], - }; - - // Input subtree is: `(cfg, $(attr),+)` - // Split it up into a `cfg` subtree and the `attr` subtrees. - // FIXME: There should be a common API for this. - let mut parts = subtree.token_trees.split(|tt| { - matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. }))) - }); - let cfg = match parts.next() { - Some(it) => it, - None => return smallvec![], - }; - let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() }; - let cfg = CfgExpr::parse(&cfg); - let index = attr.id; - let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { - let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; - // FIXME hygiene - let hygiene = Hygiene::new_unhygienic(); - Attr::from_tt(db, &tree, &hygiene, index) - }); - - let cfg_options = &crate_graph[krate].cfg_options; - if cfg_options.check(&cfg) == Some(false) { - smallvec![] - } else { - cov_mark::hit!(cfg_attr_active); - - attrs.collect() - } - }) - .collect(); - - Attrs(RawAttrs { entries: Some(new_attrs) }) - } -} - -impl Attrs { - pub const EMPTY: Self = Self(RawAttrs::EMPTY); - - pub(crate) fn variants_attrs_query( - db: &dyn DefDatabase, - e: EnumId, - ) -> Arc> { - // FIXME: There should be some proper form of mapping between item tree enum variant ids and hir enum variant ids - let mut res = ArenaMap::default(); - - let loc = e.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let enum_ = &item_tree[loc.id.value]; - let crate_graph = db.crate_graph(); - let cfg_options = &crate_graph[krate].cfg_options; - - let mut idx = 0; - for variant in enum_.variants.clone() { - let attrs = item_tree.attrs(db, krate, variant.into()); - if attrs.is_cfg_enabled(cfg_options) { - res.insert(Idx::from_raw(RawIdx::from(idx)), attrs); - idx += 1; - } - } - - Arc::new(res) - } - - pub(crate) fn fields_attrs_query( - db: &dyn DefDatabase, - v: VariantId, - ) -> Arc> { - // FIXME: There should be some proper form of mapping between item tree field ids and hir field ids - let mut res = ArenaMap::default(); - - let crate_graph = db.crate_graph(); - let (fields, item_tree, krate) = match v { - VariantId::EnumVariantId(it) => { - let e = it.parent; - let loc = e.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let enum_ = &item_tree[loc.id.value]; - - let cfg_options = &crate_graph[krate].cfg_options; - let variant = 'tri: loop { - let mut idx = 0; - for variant in enum_.variants.clone() { - let attrs = item_tree.attrs(db, krate, variant.into()); - if attrs.is_cfg_enabled(cfg_options) { - if it.local_id == Idx::from_raw(RawIdx::from(idx)) { - break 'tri variant; - } - idx += 1; - } - } - return Arc::new(res); - }; - (item_tree[variant].fields.clone(), item_tree, krate) - } - VariantId::StructId(it) => { - let loc = it.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let struct_ = &item_tree[loc.id.value]; - (struct_.fields.clone(), item_tree, krate) - } - VariantId::UnionId(it) => { - let loc = it.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let union_ = &item_tree[loc.id.value]; - (union_.fields.clone(), item_tree, krate) - } - }; - - let fields = match fields { - Fields::Record(fields) | Fields::Tuple(fields) => fields, - Fields::Unit => return Arc::new(res), - }; - - let cfg_options = &crate_graph[krate].cfg_options; - - let mut idx = 0; - for field in fields { - let attrs = item_tree.attrs(db, krate, field.into()); - if attrs.is_cfg_enabled(cfg_options) { - res.insert(Idx::from_raw(RawIdx::from(idx)), attrs); - idx += 1; - } - } - - Arc::new(res) - } - - pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { - AttrQuery { attrs: self, key } - } -} - -impl Attrs { - pub fn cfg(&self) -> Option { - let mut cfgs = self.by_key("cfg").tt_values().map(CfgExpr::parse); - let first = cfgs.next()?; - match cfgs.next() { - Some(second) => { - let cfgs = [first, second].into_iter().chain(cfgs); - Some(CfgExpr::All(cfgs.collect())) - } - None => Some(first), - } - } - pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { - match self.cfg() { - None => true, - Some(cfg) => cfg_options.check(&cfg) != Some(false), - } - } - - pub fn lang(&self) -> Option<&SmolStr> { - self.by_key("lang").string_value() - } - - pub fn docs(&self) -> Option { - let docs = self.by_key("doc").attrs().filter_map(|attr| attr.string_value()); - let indent = doc_indent(self); - let mut buf = String::new(); - for doc in docs { - // str::lines doesn't yield anything for the empty string - if !doc.is_empty() { - buf.extend(Itertools::intersperse( - doc.lines().map(|line| { - line.char_indices() - .nth(indent) - .map_or(line, |(offset, _)| &line[offset..]) - .trim_end() - }), - "\n", - )); - } - buf.push('\n'); - } - buf.pop(); - if buf.is_empty() { - None - } else { - Some(Documentation(buf)) - } - } - - pub fn has_doc_hidden(&self) -> bool { - self.by_key("doc").tt_values().any(|tt| { - tt.delimiter_kind() == Some(DelimiterKind::Parenthesis) && - matches!(&*tt.token_trees, [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.text == "hidden") - }) - } - - pub fn is_proc_macro(&self) -> bool { - self.by_key("proc_macro").exists() - } - - pub fn is_proc_macro_attribute(&self) -> bool { - self.by_key("proc_macro_attribute").exists() - } - - pub fn is_proc_macro_derive(&self) -> bool { - self.by_key("proc_macro_derive").exists() - } -} - -impl AttrsWithOwner { - pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Self { - // FIXME: this should use `Trace` to avoid duplication in `source_map` below - let raw_attrs = match def { - AttrDefId::ModuleId(module) => { - let def_map = module.def_map(db); - let mod_data = &def_map[module.local_id]; - - match mod_data.origin { - ModuleOrigin::File { definition, declaration_tree_id, .. } => { - let decl_attrs = declaration_tree_id - .item_tree(db) - .raw_attrs(AttrOwner::ModItem(declaration_tree_id.value.into())) - .clone(); - let tree = db.file_item_tree(definition.into()); - let def_attrs = tree.raw_attrs(AttrOwner::TopLevel).clone(); - decl_attrs.merge(def_attrs) - } - ModuleOrigin::CrateRoot { definition } => { - let tree = db.file_item_tree(definition.into()); - tree.raw_attrs(AttrOwner::TopLevel).clone() - } - ModuleOrigin::Inline { definition_tree_id, .. } => definition_tree_id - .item_tree(db) - .raw_attrs(AttrOwner::ModItem(definition_tree_id.value.into())) - .clone(), - ModuleOrigin::BlockExpr { block } => RawAttrs::from_attrs_owner( - db, - InFile::new(block.file_id, block.to_node(db.upcast())) - .as_ref() - .map(|it| it as &dyn ast::HasAttrs), - ), - } - } - AttrDefId::FieldId(it) => { - return Self { attrs: db.fields_attrs(it.parent)[it.local_id].clone(), owner: def }; - } - AttrDefId::EnumVariantId(it) => { - return Self { - attrs: db.variants_attrs(it.parent)[it.local_id].clone(), - owner: def, - }; - } - AttrDefId::AdtId(it) => match it { - AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db), - }, - AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AttrDefId::MacroId(it) => match it { - MacroId::Macro2Id(it) => attrs_from_item_tree(it.lookup(db).id, db), - MacroId::MacroRulesId(it) => attrs_from_item_tree(it.lookup(db).id, db), - MacroId::ProcMacroId(it) => attrs_from_item_tree(it.lookup(db).id, db), - }, - AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AttrDefId::GenericParamId(it) => match it { - GenericParamId::ConstParamId(it) => { - let src = it.parent().child_source(db); - RawAttrs::from_attrs_owner( - db, - src.with_value(src.value[it.local_id()].as_ref().either( - |it| match it { - ast::TypeOrConstParam::Type(it) => it as _, - ast::TypeOrConstParam::Const(it) => it as _, - }, - |it| it as _, - )), - ) - } - GenericParamId::TypeParamId(it) => { - let src = it.parent().child_source(db); - RawAttrs::from_attrs_owner( - db, - src.with_value(src.value[it.local_id()].as_ref().either( - |it| match it { - ast::TypeOrConstParam::Type(it) => it as _, - ast::TypeOrConstParam::Const(it) => it as _, - }, - |it| it as _, - )), - ) - } - GenericParamId::LifetimeParamId(it) => { - let src = it.parent.child_source(db); - RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id])) - } - }, - AttrDefId::ExternBlockId(it) => attrs_from_item_tree(it.lookup(db).id, db), - }; - - let attrs = raw_attrs.filter(db, def.krate(db)); - Self { attrs, owner: def } - } - - pub fn source_map(&self, db: &dyn DefDatabase) -> AttrSourceMap { - let owner = match self.owner { - AttrDefId::ModuleId(module) => { - // Modules can have 2 attribute owners (the `mod x;` item, and the module file itself). - - let def_map = module.def_map(db); - let mod_data = &def_map[module.local_id]; - match mod_data.declaration_source(db) { - Some(it) => { - let mut map = AttrSourceMap::new(InFile::new(it.file_id, &it.value)); - if let InFile { file_id, value: ModuleSource::SourceFile(file) } = - mod_data.definition_source(db) - { - map.append_module_inline_attrs(AttrSourceMap::new(InFile::new( - file_id, &file, - ))); - } - return map; - } - None => { - let InFile { file_id, value } = mod_data.definition_source(db); - let attrs_owner = match &value { - ModuleSource::SourceFile(file) => file as &dyn ast::HasAttrs, - ModuleSource::Module(module) => module as &dyn ast::HasAttrs, - ModuleSource::BlockExpr(block) => block as &dyn ast::HasAttrs, - }; - return AttrSourceMap::new(InFile::new(file_id, attrs_owner)); - } - } - } - AttrDefId::FieldId(id) => { - let map = db.fields_attrs_source_map(id.parent); - let file_id = id.parent.file_id(db); - let root = db.parse_or_expand(file_id).unwrap(); - let owner = match &map[id.local_id] { - Either::Left(it) => ast::AnyHasAttrs::new(it.to_node(&root)), - Either::Right(it) => ast::AnyHasAttrs::new(it.to_node(&root)), - }; - InFile::new(file_id, owner) - } - AttrDefId::AdtId(adt) => match adt { - AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AdtId::UnionId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - }, - AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AttrDefId::EnumVariantId(id) => { - let map = db.variants_attrs_source_map(id.parent); - let file_id = id.parent.lookup(db).id.file_id(); - let root = db.parse_or_expand(file_id).unwrap(); - InFile::new(file_id, ast::AnyHasAttrs::new(map[id.local_id].to_node(&root))) - } - AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AttrDefId::TypeAliasId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AttrDefId::MacroId(id) => match id { - MacroId::Macro2Id(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - MacroId::MacroRulesId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - MacroId::ProcMacroId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - }, - AttrDefId::ImplId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AttrDefId::GenericParamId(id) => match id { - GenericParamId::ConstParamId(id) => { - id.parent().child_source(db).map(|source| match &source[id.local_id()] { - Either::Left(ast::TypeOrConstParam::Type(id)) => { - ast::AnyHasAttrs::new(id.clone()) - } - Either::Left(ast::TypeOrConstParam::Const(id)) => { - ast::AnyHasAttrs::new(id.clone()) - } - Either::Right(id) => ast::AnyHasAttrs::new(id.clone()), - }) - } - GenericParamId::TypeParamId(id) => { - id.parent().child_source(db).map(|source| match &source[id.local_id()] { - Either::Left(ast::TypeOrConstParam::Type(id)) => { - ast::AnyHasAttrs::new(id.clone()) - } - Either::Left(ast::TypeOrConstParam::Const(id)) => { - ast::AnyHasAttrs::new(id.clone()) - } - Either::Right(id) => ast::AnyHasAttrs::new(id.clone()), - }) - } - GenericParamId::LifetimeParamId(id) => id - .parent - .child_source(db) - .map(|source| ast::AnyHasAttrs::new(source[id.local_id].clone())), - }, - AttrDefId::ExternBlockId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - }; - - AttrSourceMap::new(owner.as_ref().map(|node| node as &dyn HasAttrs)) - } - - pub fn docs_with_rangemap( - &self, - db: &dyn DefDatabase, - ) -> Option<(Documentation, DocsRangeMap)> { - let docs = - self.by_key("doc").attrs().filter_map(|attr| attr.string_value().map(|s| (s, attr.id))); - let indent = doc_indent(self); - let mut buf = String::new(); - let mut mapping = Vec::new(); - for (doc, idx) in docs { - if !doc.is_empty() { - let mut base_offset = 0; - for raw_line in doc.split('\n') { - let line = raw_line.trim_end(); - let line_len = line.len(); - let (offset, line) = match line.char_indices().nth(indent) { - Some((offset, _)) => (offset, &line[offset..]), - None => (0, line), - }; - let buf_offset = buf.len(); - buf.push_str(line); - mapping.push(( - TextRange::new(buf_offset.try_into().ok()?, buf.len().try_into().ok()?), - idx, - TextRange::at( - (base_offset + offset).try_into().ok()?, - line_len.try_into().ok()?, - ), - )); - buf.push('\n'); - base_offset += raw_line.len() + 1; - } - } else { - buf.push('\n'); - } - } - buf.pop(); - if buf.is_empty() { - None - } else { - Some((Documentation(buf), DocsRangeMap { mapping, source_map: self.source_map(db) })) - } - } -} - -fn doc_indent(attrs: &Attrs) -> usize { - attrs - .by_key("doc") - .attrs() - .filter_map(|attr| attr.string_value()) - .flat_map(|s| s.lines()) - .filter(|line| !line.chars().all(|c| c.is_whitespace())) - .map(|line| line.chars().take_while(|c| c.is_whitespace()).count()) - .min() - .unwrap_or(0) -} - -fn inner_attributes( - syntax: &SyntaxNode, -) -> Option>> { - let node = match_ast! { - match syntax { - ast::SourceFile(_) => syntax.clone(), - ast::ExternBlock(it) => it.extern_item_list()?.syntax().clone(), - ast::Fn(it) => it.body()?.stmt_list()?.syntax().clone(), - ast::Impl(it) => it.assoc_item_list()?.syntax().clone(), - ast::Module(it) => it.item_list()?.syntax().clone(), - ast::BlockExpr(it) => { - use syntax::SyntaxKind::{BLOCK_EXPR , EXPR_STMT}; - // Block expressions accept outer and inner attributes, but only when they are the outer - // expression of an expression statement or the final expression of another block expression. - let may_carry_attributes = matches!( - it.syntax().parent().map(|it| it.kind()), - Some(BLOCK_EXPR | EXPR_STMT) - ); - if !may_carry_attributes { - return None - } - syntax.clone() - }, - _ => return None, - } - }; - - let attrs = ast::AttrDocCommentIter::from_syntax_node(&node).filter(|el| match el { - Either::Left(attr) => attr.kind().is_inner(), - Either::Right(comment) => comment.is_inner(), - }); - Some(attrs) -} - -#[derive(Debug)] -pub struct AttrSourceMap { - source: Vec>, - file_id: HirFileId, - /// If this map is for a module, this will be the [`HirFileId`] of the module's definition site, - /// while `file_id` will be the one of the module declaration site. - /// The usize is the index into `source` from which point on the entries reside in the def site - /// file. - mod_def_site_file_id: Option<(HirFileId, usize)>, -} - -impl AttrSourceMap { - fn new(owner: InFile<&dyn ast::HasAttrs>) -> Self { - Self { - source: collect_attrs(owner.value).map(|(_, it)| it).collect(), - file_id: owner.file_id, - mod_def_site_file_id: None, - } - } - - /// Append a second source map to this one, this is required for modules, whose outline and inline - /// attributes can reside in different files - fn append_module_inline_attrs(&mut self, other: Self) { - assert!(self.mod_def_site_file_id.is_none() && other.mod_def_site_file_id.is_none()); - let len = self.source.len(); - self.source.extend(other.source); - if other.file_id != self.file_id { - self.mod_def_site_file_id = Some((other.file_id, len)); - } - } - - /// Maps the lowered `Attr` back to its original syntax node. - /// - /// `attr` must come from the `owner` used for AttrSourceMap - /// - /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of - /// the attribute represented by `Attr`. - pub fn source_of(&self, attr: &Attr) -> InFile<&Either> { - self.source_of_id(attr.id) - } - - fn source_of_id(&self, id: AttrId) -> InFile<&Either> { - let ast_idx = id.ast_index as usize; - let file_id = match self.mod_def_site_file_id { - Some((file_id, def_site_cut)) if def_site_cut <= ast_idx => file_id, - _ => self.file_id, - }; - - self.source - .get(ast_idx) - .map(|it| InFile::new(file_id, it)) - .unwrap_or_else(|| panic!("cannot find attr at index {:?}", id)) - } -} - -/// A struct to map text ranges from [`Documentation`] back to TextRanges in the syntax tree. -#[derive(Debug)] -pub struct DocsRangeMap { - source_map: AttrSourceMap, - // (docstring-line-range, attr_index, attr-string-range) - // a mapping from the text range of a line of the [`Documentation`] to the attribute index and - // the original (untrimmed) syntax doc line - mapping: Vec<(TextRange, AttrId, TextRange)>, -} - -impl DocsRangeMap { - /// Maps a [`TextRange`] relative to the documentation string back to its AST range - pub fn map(&self, range: TextRange) -> Option> { - let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?; - let (line_docs_range, idx, original_line_src_range) = self.mapping[found]; - if !line_docs_range.contains_range(range) { - return None; - } - - let relative_range = range - line_docs_range.start(); - - let InFile { file_id, value: source } = self.source_map.source_of_id(idx); - match source { - Either::Left(attr) => { - let string = get_doc_string_in_attr(attr)?; - let text_range = string.open_quote_text_range()?; - let range = TextRange::at( - text_range.end() + original_line_src_range.start() + relative_range.start(), - string.syntax().text_range().len().min(range.len()), - ); - Some(InFile { file_id, value: range }) - } - Either::Right(comment) => { - let text_range = comment.syntax().text_range(); - let range = TextRange::at( - text_range.start() - + TextSize::try_from(comment.prefix().len()).ok()? - + original_line_src_range.start() - + relative_range.start(), - text_range.len().min(range.len()), - ); - Some(InFile { file_id, value: range }) - } - } - } -} - -fn get_doc_string_in_attr(it: &ast::Attr) -> Option { - match it.expr() { - // #[doc = lit] - Some(ast::Expr::Literal(lit)) => match lit.kind() { - ast::LiteralKind::String(it) => Some(it), - _ => None, - }, - // #[cfg_attr(..., doc = "", ...)] - None => { - // FIXME: See highlight injection for what to do here - None - } - _ => None, - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct AttrId { - pub(crate) ast_index: u32, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Attr { - pub(crate) id: AttrId, - pub(crate) path: Interned, - pub(crate) input: Option>, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum AttrInput { - /// `#[attr = "string"]` - Literal(SmolStr), - /// `#[attr(subtree)]` - TokenTree(tt::Subtree, mbe::TokenMap), -} - -impl fmt::Display for AttrInput { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - AttrInput::Literal(lit) => write!(f, " = \"{}\"", lit.escape_debug()), - AttrInput::TokenTree(subtree, _) => subtree.fmt(f), - } - } -} - -impl Attr { - fn from_src( - db: &dyn DefDatabase, - ast: ast::Meta, - hygiene: &Hygiene, - id: AttrId, - ) -> Option { - let path = Interned::new(ModPath::from_src(db.upcast(), ast.path()?, hygiene)?); - let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { - let value = match lit.kind() { - ast::LiteralKind::String(string) => string.value()?.into(), - _ => lit.syntax().first_token()?.text().trim_matches('"').into(), - }; - Some(Interned::new(AttrInput::Literal(value))) - } else if let Some(tt) = ast.token_tree() { - let (tree, map) = syntax_node_to_token_tree(tt.syntax()); - Some(Interned::new(AttrInput::TokenTree(tree, map))) - } else { - None - }; - Some(Attr { id, path, input }) - } - - fn from_tt( - db: &dyn DefDatabase, - tt: &tt::Subtree, - hygiene: &Hygiene, - id: AttrId, - ) -> Option { - let (parse, _) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MetaItem); - let ast = ast::Meta::cast(parse.syntax_node())?; - - Self::from_src(db, ast, hygiene, id) - } - - pub fn path(&self) -> &ModPath { - &self.path - } -} - -impl Attr { - /// #[path = "string"] - pub fn string_value(&self) -> Option<&SmolStr> { - match self.input.as_deref()? { - AttrInput::Literal(it) => Some(it), - _ => None, - } - } - - /// #[path(ident)] - pub fn single_ident_value(&self) -> Option<&tt::Ident> { - match self.input.as_deref()? { - AttrInput::TokenTree(subtree, _) => match &*subtree.token_trees { - [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] => Some(ident), - _ => None, - }, - _ => None, - } - } - - /// #[path TokenTree] - pub fn token_tree_value(&self) -> Option<&Subtree> { - match self.input.as_deref()? { - AttrInput::TokenTree(subtree, _) => Some(subtree), - _ => None, - } - } - - /// Parses this attribute as a token tree consisting of comma separated paths. - pub fn parse_path_comma_token_tree(&self) -> Option + '_> { - let args = self.token_tree_value()?; - - if args.delimiter_kind() != Some(DelimiterKind::Parenthesis) { - return None; - } - let paths = args - .token_trees - .split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. })))) - .filter_map(|tts| { - if tts.is_empty() { - return None; - } - let segments = tts.iter().filter_map(|tt| match tt { - tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => Some(id.as_name()), - _ => None, - }); - Some(ModPath::from_segments(PathKind::Plain, segments)) - }); - - Some(paths) - } -} - -#[derive(Debug, Clone, Copy)] -pub struct AttrQuery<'attr> { - attrs: &'attr Attrs, - key: &'static str, -} - -impl<'attr> AttrQuery<'attr> { - pub fn tt_values(self) -> impl Iterator { - self.attrs().filter_map(|attr| attr.token_tree_value()) - } - - pub fn string_value(self) -> Option<&'attr SmolStr> { - self.attrs().find_map(|attr| attr.string_value()) - } - - pub fn exists(self) -> bool { - self.attrs().next().is_some() - } - - pub fn attrs(self) -> impl Iterator + Clone { - let key = self.key; - self.attrs - .iter() - .filter(move |attr| attr.path.as_ident().map_or(false, |s| s.to_smol_str() == key)) - } - - /// Find string value for a specific key inside token tree - /// - /// ```ignore - /// #[doc(html_root_url = "url")] - /// ^^^^^^^^^^^^^ key - /// ``` - pub fn find_string_value_in_tt(self, key: &'attr str) -> Option<&SmolStr> { - self.tt_values().find_map(|tt| { - let name = tt.token_trees.iter() - .skip_while(|tt| !matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { text, ..} )) if text == key)) - .nth(2); - - match name { - Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal{ref text, ..}))) => Some(text), - _ => None - } - }) - } -} - -fn attrs_from_item_tree(id: ItemTreeId, db: &dyn DefDatabase) -> RawAttrs { - let tree = id.item_tree(db); - let mod_item = N::id_to_mod_item(id.value); - tree.raw_attrs(mod_item.into()).clone() -} - -fn collect_attrs( - owner: &dyn ast::HasAttrs, -) -> impl Iterator)> { - let inner_attrs = inner_attributes(owner.syntax()).into_iter().flatten(); - let outer_attrs = - ast::AttrDocCommentIter::from_syntax_node(owner.syntax()).filter(|el| match el { - Either::Left(attr) => attr.kind().is_outer(), - Either::Right(comment) => comment.is_outer(), - }); - outer_attrs - .chain(inner_attrs) - .enumerate() - .map(|(id, attr)| (AttrId { ast_index: id as u32 }, attr)) -} - -pub(crate) fn variants_attrs_source_map( - db: &dyn DefDatabase, - def: EnumId, -) -> Arc>> { - let mut res = ArenaMap::default(); - let child_source = def.child_source(db); - - for (idx, variant) in child_source.value.iter() { - res.insert(idx, AstPtr::new(variant)); - } - - Arc::new(res) -} - -pub(crate) fn fields_attrs_source_map( - db: &dyn DefDatabase, - def: VariantId, -) -> Arc, AstPtr>>> { - let mut res = ArenaMap::default(); - let child_source = def.child_source(db); - - for (idx, variant) in child_source.value.iter() { - res.insert( - idx, - variant - .as_ref() - .either(|l| Either::Left(AstPtr::new(l)), |r| Either::Right(AstPtr::new(r))), - ); - } - - Arc::new(res) -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs deleted file mode 100644 index 080a307b1f8a4..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ /dev/null @@ -1,471 +0,0 @@ -//! Defines `Body`: a lowered representation of bodies of functions, statics and -//! consts. -mod lower; -#[cfg(test)] -mod tests; -pub mod scope; - -use std::{ops::Index, sync::Arc}; - -use base_db::CrateId; -use cfg::{CfgExpr, CfgOptions}; -use drop_bomb::DropBomb; -use either::Either; -use hir_expand::{hygiene::Hygiene, ExpandError, ExpandResult, HirFileId, InFile, MacroCallId}; -use la_arena::{Arena, ArenaMap}; -use limit::Limit; -use profile::Count; -use rustc_hash::FxHashMap; -use syntax::{ast, AstPtr, SyntaxNodePtr}; - -use crate::{ - attr::{Attrs, RawAttrs}, - db::DefDatabase, - expr::{dummy_expr_id, Expr, ExprId, Label, LabelId, Pat, PatId}, - item_scope::BuiltinShadowMode, - macro_id_to_def_id, - nameres::DefMap, - path::{ModPath, Path}, - src::HasSource, - AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, ModuleId, - UnresolvedMacro, -}; - -pub use lower::LowerCtx; - -/// A subset of Expander that only deals with cfg attributes. We only need it to -/// avoid cyclic queries in crate def map during enum processing. -#[derive(Debug)] -pub(crate) struct CfgExpander { - cfg_options: CfgOptions, - hygiene: Hygiene, - krate: CrateId, -} - -#[derive(Debug)] -pub struct Expander { - cfg_expander: CfgExpander, - def_map: Arc, - current_file_id: HirFileId, - module: LocalModuleId, - recursion_limit: usize, -} - -impl CfgExpander { - pub(crate) fn new( - db: &dyn DefDatabase, - current_file_id: HirFileId, - krate: CrateId, - ) -> CfgExpander { - let hygiene = Hygiene::new(db.upcast(), current_file_id); - let cfg_options = db.crate_graph()[krate].cfg_options.clone(); - CfgExpander { cfg_options, hygiene, krate } - } - - pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs { - RawAttrs::new(db, owner, &self.hygiene).filter(db, self.krate) - } - - pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> bool { - let attrs = self.parse_attrs(db, owner); - attrs.is_cfg_enabled(&self.cfg_options) - } -} - -impl Expander { - pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander { - let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); - let def_map = module.def_map(db); - Expander { - cfg_expander, - def_map, - current_file_id, - module: module.local_id, - recursion_limit: 0, - } - } - - pub fn enter_expand( - &mut self, - db: &dyn DefDatabase, - macro_call: ast::MacroCall, - ) -> Result>, UnresolvedMacro> { - if self.recursion_limit(db).check(self.recursion_limit + 1).is_err() { - cov_mark::hit!(your_stack_belongs_to_me); - return Ok(ExpandResult::only_err(ExpandError::Other( - "reached recursion limit during macro expansion".into(), - ))); - } - - let macro_call = InFile::new(self.current_file_id, ¯o_call); - - let resolver = - |path| self.resolve_path_as_macro(db, &path).map(|it| macro_id_to_def_id(db, it)); - - let mut err = None; - let call_id = - macro_call.as_call_id_with_errors(db, self.def_map.krate(), resolver, &mut |e| { - err.get_or_insert(e); - })?; - let call_id = match call_id { - Ok(it) => it, - Err(_) => { - return Ok(ExpandResult { value: None, err }); - } - }; - - Ok(self.enter_expand_inner(db, call_id, err)) - } - - pub fn enter_expand_id( - &mut self, - db: &dyn DefDatabase, - call_id: MacroCallId, - ) -> ExpandResult> { - self.enter_expand_inner(db, call_id, None) - } - - fn enter_expand_inner( - &mut self, - db: &dyn DefDatabase, - call_id: MacroCallId, - mut err: Option, - ) -> ExpandResult> { - if err.is_none() { - err = db.macro_expand_error(call_id); - } - - let file_id = call_id.as_file(); - - let raw_node = match db.parse_or_expand(file_id) { - Some(it) => it, - None => { - // Only `None` if the macro expansion produced no usable AST. - if err.is_none() { - tracing::warn!("no error despite `parse_or_expand` failing"); - } - - return ExpandResult::only_err(err.unwrap_or_else(|| { - ExpandError::Other("failed to parse macro invocation".into()) - })); - } - }; - - let node = match T::cast(raw_node) { - Some(it) => it, - None => { - // This can happen without being an error, so only forward previous errors. - return ExpandResult { value: None, err }; - } - }; - - tracing::debug!("macro expansion {:#?}", node.syntax()); - - self.recursion_limit += 1; - let mark = - Mark { file_id: self.current_file_id, bomb: DropBomb::new("expansion mark dropped") }; - self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); - self.current_file_id = file_id; - - ExpandResult { value: Some((mark, node)), err } - } - - pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { - self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); - self.current_file_id = mark.file_id; - self.recursion_limit -= 1; - mark.bomb.defuse(); - } - - pub(crate) fn to_source(&self, value: T) -> InFile { - InFile { file_id: self.current_file_id, value } - } - - pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs { - self.cfg_expander.parse_attrs(db, owner) - } - - pub(crate) fn cfg_options(&self) -> &CfgOptions { - &self.cfg_expander.cfg_options - } - - pub fn current_file_id(&self) -> HirFileId { - self.current_file_id - } - - fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option { - let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene); - Path::from_src(path, &ctx) - } - - fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { - self.def_map.resolve_path(db, self.module, path, BuiltinShadowMode::Other).0.take_macros() - } - - fn recursion_limit(&self, db: &dyn DefDatabase) -> Limit { - let limit = db.crate_limits(self.cfg_expander.krate).recursion_limit as _; - - #[cfg(not(test))] - return Limit::new(limit); - - // Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug - #[cfg(test)] - return Limit::new(std::cmp::min(32, limit)); - } -} - -#[derive(Debug)] -pub struct Mark { - file_id: HirFileId, - bomb: DropBomb, -} - -/// The body of an item (function, const etc.). -#[derive(Debug, Eq, PartialEq)] -pub struct Body { - pub exprs: Arena, - pub pats: Arena, - pub or_pats: FxHashMap>, - pub labels: Arena , - VecStrategy, - RangedParams1; - args => { - let product_unpack![range, a] = args; - vec(any_with::(a), range) - } -); -"#, - expect![[r#" -macro_rules! arbitrary { - ([$($bounds : tt)*] $typ: ty, $strat: ty, $params: ty; - $args: ident => $logic: expr) => { - impl<$($bounds)*> $crate::arbitrary::Arbitrary for $typ { - type Parameters = $params; - type Strategy = $strat; - fn arbitrary_with($args: Self::Parameters) -> Self::Strategy { - $logic - } - } - }; -} - -impl $crate::arbitrary::Arbitrary for Vec { - type Parameters = RangedParams1; - type Strategy = VecStrategy; - fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { { - let product_unpack![range, a] = args; - vec(any_with::(a), range) - } - } -} -"#]], - ); -} - -#[test] -fn test_old_ridl() { - // This is from winapi 2.8, which do not have a link from github. - check( - r#" -#[macro_export] -macro_rules! RIDL { - (interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) - {$( - fn $method:ident(&mut self $(,$p:ident : $t:ty)*) -> $rtr:ty - ),+} - ) => { - impl $interface { - $(pub unsafe fn $method(&mut self) -> $rtr { - ((*self.lpVtbl).$method)(self $(,$p)*) - })+ - } - }; -} - -RIDL!{interface ID3D11Asynchronous(ID3D11AsynchronousVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { - fn GetDataSize(&mut self) -> UINT -}} -"#, - expect![[r##" -#[macro_export] -macro_rules! RIDL { - (interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) - {$( - fn $method:ident(&mut self $(,$p:ident : $t:ty)*) -> $rtr:ty - ),+} - ) => { - impl $interface { - $(pub unsafe fn $method(&mut self) -> $rtr { - ((*self.lpVtbl).$method)(self $(,$p)*) - })+ - } - }; -} - -impl ID3D11Asynchronous { - pub unsafe fn GetDataSize(&mut self ) -> UINT { - ((*self .lpVtbl).GetDataSize)(self ) - } -} -"##]], - ); -} - -#[test] -fn test_quick_error() { - check( - r#" -macro_rules! quick_error { - (SORT [enum $name:ident $( #[$meta:meta] )*] - items [$($( #[$imeta:meta] )* - => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] - {$( $ifuncs:tt )*} )* ] - buf [ ] - queue [ ] - ) => { - quick_error!(ENUMINITION [enum $name $( #[$meta] )*] - body [] - queue [$( - $( #[$imeta] )* - => - $iitem: $imode [$( $ivar: $ityp ),*] - )*] - ); - }; -} -quick_error ! ( - SORT - [enum Wrapped #[derive(Debug)]] - items [ - => One: UNIT [] {} - => Two: TUPLE [s :String] {display ("two: {}" , s) from ()} ] - buf [ ] - queue [ ] -); - -"#, - expect![[r##" -macro_rules! quick_error { - (SORT [enum $name:ident $( #[$meta:meta] )*] - items [$($( #[$imeta:meta] )* - => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] - {$( $ifuncs:tt )*} )* ] - buf [ ] - queue [ ] - ) => { - quick_error!(ENUMINITION [enum $name $( #[$meta] )*] - body [] - queue [$( - $( #[$imeta] )* - => - $iitem: $imode [$( $ivar: $ityp ),*] - )*] - ); - }; -} -quick_error!(ENUMINITION[enum Wrapped#[derive(Debug)]]body[]queue[ = > One: UNIT[] = > Two: TUPLE[s: String]]); - -"##]], - ) -} - -#[test] -fn test_empty_repeat_vars_in_empty_repeat_vars() { - check( - r#" -macro_rules! delegate_impl { - ([$self_type:ident, $self_wrap:ty, $self_map:ident] - pub trait $name:ident $(: $sup:ident)* $(+ $more_sup:ident)* { - - $( - @escape [type $assoc_name_ext:ident] - )* - $( - @section type - $( - $(#[$_assoc_attr:meta])* - type $assoc_name:ident $(: $assoc_bound:ty)*; - )+ - )* - $( - @section self - $( - $(#[$_method_attr:meta])* - fn $method_name:ident(self $(: $self_selftype:ty)* $(,$marg:ident : $marg_ty:ty)*) -> $mret:ty; - )+ - )* - $( - @section nodelegate - $($tail:tt)* - )* - }) => { - impl<> $name for $self_wrap where $self_type: $name { - $( - $( - fn $method_name(self $(: $self_selftype)* $(,$marg: $marg_ty)*) -> $mret { - $self_map!(self).$method_name($($marg),*) - } - )* - )* - } - } -} -delegate_impl ! { - [G, &'a mut G, deref] pub trait Data: GraphBase {@section type type NodeWeight;} -} -"#, - expect![[r##" -macro_rules! delegate_impl { - ([$self_type:ident, $self_wrap:ty, $self_map:ident] - pub trait $name:ident $(: $sup:ident)* $(+ $more_sup:ident)* { - - $( - @escape [type $assoc_name_ext:ident] - )* - $( - @section type - $( - $(#[$_assoc_attr:meta])* - type $assoc_name:ident $(: $assoc_bound:ty)*; - )+ - )* - $( - @section self - $( - $(#[$_method_attr:meta])* - fn $method_name:ident(self $(: $self_selftype:ty)* $(,$marg:ident : $marg_ty:ty)*) -> $mret:ty; - )+ - )* - $( - @section nodelegate - $($tail:tt)* - )* - }) => { - impl<> $name for $self_wrap where $self_type: $name { - $( - $( - fn $method_name(self $(: $self_selftype)* $(,$marg: $marg_ty)*) -> $mret { - $self_map!(self).$method_name($($marg),*) - } - )* - )* - } - } -} -impl <> Data for & 'amut G where G: Data {} -"##]], - ); -} - -#[test] -fn test_issue_2520() { - check( - r#" -macro_rules! my_macro { - { - ( $( - $( [] $sname:ident : $stype:ty )? - $( [$expr:expr] $nname:ident : $ntype:ty )? - ),* ) - } => {ok!( - Test { - $( - $( $sname, )? - )* - } - );}; -} - -my_macro! { - ([] p1: u32, [|_| S0K0] s: S0K0, [] k0: i32) -} - "#, - expect![[r#" -macro_rules! my_macro { - { - ( $( - $( [] $sname:ident : $stype:ty )? - $( [$expr:expr] $nname:ident : $ntype:ty )? - ),* ) - } => {ok!( - Test { - $( - $( $sname, )? - )* - } - );}; -} - -ok!(Test { - p1, k0, -} -); - "#]], - ); -} - -#[test] -fn test_repeat_bad_var() { - // FIXME: the second rule of the macro should be removed and an error about - // `$( $c )+` raised - check( - r#" -macro_rules! foo { - ($( $b:ident )+) => { ok!($( $c )+); }; - ($( $b:ident )+) => { ok!($( $b )+); } -} - -foo!(b0 b1); -"#, - expect![[r#" -macro_rules! foo { - ($( $b:ident )+) => { ok!($( $c )+); }; - ($( $b:ident )+) => { ok!($( $b )+); } -} - -ok!(b0 b1); -"#]], - ); -} - -#[test] -fn test_issue_3861() { - // This is should (and does) produce a parse error. It used to infinite loop - // instead. - check( - r#" -macro_rules! rgb_color { - ($p:expr, $t:ty) => { - pub fn new() { - let _ = 0 as $t << $p; - } - }; -} -// +tree +errors -rgb_color!(8 + 8, u32); -"#, - expect![[r#" -macro_rules! rgb_color { - ($p:expr, $t:ty) => { - pub fn new() { - let _ = 0 as $t << $p; - } - }; -} -/* parse error: expected type */ -/* parse error: expected R_PAREN */ -/* parse error: expected R_ANGLE */ -/* parse error: expected COMMA */ -/* parse error: expected R_ANGLE */ -/* parse error: expected SEMICOLON */ -/* parse error: expected SEMICOLON */ -/* parse error: expected expression */ -pub fn new() { - let _ = 0as u32<<(8+8); -} -// MACRO_ITEMS@0..31 -// FN@0..31 -// VISIBILITY@0..3 -// PUB_KW@0..3 "pub" -// FN_KW@3..5 "fn" -// NAME@5..8 -// IDENT@5..8 "new" -// PARAM_LIST@8..10 -// L_PAREN@8..9 "(" -// R_PAREN@9..10 ")" -// BLOCK_EXPR@10..31 -// STMT_LIST@10..31 -// L_CURLY@10..11 "{" -// LET_STMT@11..27 -// LET_KW@11..14 "let" -// WILDCARD_PAT@14..15 -// UNDERSCORE@14..15 "_" -// EQ@15..16 "=" -// CAST_EXPR@16..27 -// LITERAL@16..17 -// INT_NUMBER@16..17 "0" -// AS_KW@17..19 "as" -// PATH_TYPE@19..27 -// PATH@19..27 -// PATH_SEGMENT@19..27 -// NAME_REF@19..22 -// IDENT@19..22 "u32" -// GENERIC_ARG_LIST@22..27 -// L_ANGLE@22..23 "<" -// TYPE_ARG@23..27 -// DYN_TRAIT_TYPE@23..27 -// TYPE_BOUND_LIST@23..27 -// TYPE_BOUND@23..26 -// PATH_TYPE@23..26 -// PATH@23..26 -// PATH_SEGMENT@23..26 -// L_ANGLE@23..24 "<" -// PAREN_TYPE@24..26 -// L_PAREN@24..25 "(" -// ERROR@25..26 -// INT_NUMBER@25..26 "8" -// PLUS@26..27 "+" -// EXPR_STMT@27..28 -// LITERAL@27..28 -// INT_NUMBER@27..28 "8" -// ERROR@28..29 -// R_PAREN@28..29 ")" -// SEMICOLON@29..30 ";" -// R_CURLY@30..31 "}" - -"#]], - ); -} - -#[test] -fn test_no_space_after_semi_colon() { - check( - r#" -macro_rules! with_std { - ($($i:item)*) => ($(#[cfg(feature = "std")]$i)*) -} - -with_std! {mod m;mod f;} -"#, - expect![[r##" -macro_rules! with_std { - ($($i:item)*) => ($(#[cfg(feature = "std")]$i)*) -} - -#[cfg(feature = "std")] mod m; -#[cfg(feature = "std")] mod f; -"##]], - ) -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs deleted file mode 100644 index 0710b1ac3d696..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs +++ /dev/null @@ -1,200 +0,0 @@ -//! Unlike rustc, rust-analyzer's syntax tree are not "made of" token trees. -//! Rather, token trees are an explicit bridge between the parser and -//! (procedural or declarative) macros. -//! -//! This module tests tt <-> syntax tree conversion specifically. In particular, -//! it, among other things, check that we convert `tt` to the right kind of -//! syntax node depending on the macro call-site. -use expect_test::expect; - -use crate::macro_expansion_tests::check; - -#[test] -fn round_trips_compound_tokens() { - check( - r#" -macro_rules! m { - () => { type qual: ::T = qual::T; } -} -m!(); -"#, - expect![[r#" -macro_rules! m { - () => { type qual: ::T = qual::T; } -} -type qual: ::T = qual::T; -"#]], - ) -} - -#[test] -fn round_trips_literals() { - check( - r#" -macro_rules! m { - () => { - let _ = 'c'; - let _ = 1000; - let _ = 12E+99_f64; - let _ = "rust1"; - let _ = -92; - } -} -fn f() { - m!() -} -"#, - expect![[r#" -macro_rules! m { - () => { - let _ = 'c'; - let _ = 1000; - let _ = 12E+99_f64; - let _ = "rust1"; - let _ = -92; - } -} -fn f() { - let _ = 'c'; - let _ = 1000; - let _ = 12E+99_f64; - let _ = "rust1"; - let _ = -92; -} -"#]], - ); -} - -#[test] -fn roundtrip_lifetime() { - check( - r#" -macro_rules! m { - ($($t:tt)*) => { $($t)*} -} -m!(static bar: &'static str = "hello";); -"#, - expect![[r#" -macro_rules! m { - ($($t:tt)*) => { $($t)*} -} -static bar: & 'static str = "hello"; -"#]], - ); -} - -#[test] -fn broken_parenthesis_sequence() { - check( - r#" -macro_rules! m1 { ($x:ident) => { ($x } } -macro_rules! m2 { ($x:ident) => {} } - -m1!(); -m2!(x -"#, - expect![[r#" -macro_rules! m1 { ($x:ident) => { ($x } } -macro_rules! m2 { ($x:ident) => {} } - -/* error: invalid macro definition: expected subtree */ -/* error: Failed to lower macro args to token tree */ -"#]], - ) -} - -#[test] -fn expansion_does_not_parse_as_expression() { - check( - r#" -macro_rules! stmts { - () => { fn foo() {} } -} - -fn f() { let _ = stmts!/*+errors*/(); } -"#, - expect![[r#" -macro_rules! stmts { - () => { fn foo() {} } -} - -fn f() { let _ = /* parse error: expected expression */ -fn foo() {}; } -"#]], - ) -} - -#[test] -fn broken_pat() { - check( - r#" -macro_rules! m1 { () => (Some(x) left overs) } -macro_rules! m2 { () => ($) } - -fn main() { - let m1!() = (); - let m2!/*+errors*/() = (); -} -"#, - expect![[r#" -macro_rules! m1 { () => (Some(x) left overs) } -macro_rules! m2 { () => ($) } - -fn main() { - let Some(x)left overs = (); - let /* parse error: expected pattern */ -$ = (); -} -"#]], - ) -} - -#[test] -fn float_literal_in_tt() { - check( - r#" -macro_rules! constant { - ($( $ret:expr; )*) => {}; -} -macro_rules! float_const_impl { - () => ( constant!(0.3; 3.3;); ); -} -float_const_impl! {} -"#, - expect![[r#" -macro_rules! constant { - ($( $ret:expr; )*) => {}; -} -macro_rules! float_const_impl { - () => ( constant!(0.3; 3.3;); ); -} -constant!(0.3; -3.3; -); -"#]], - ); -} - -#[test] -fn float_literal_in_output() { - check( - r#" -macro_rules! constant { - ($e:expr ;) => {$e}; -} - -const _: () = constant!(0.0;); -const _: () = constant!(0.;); -const _: () = constant!(0e0;); -"#, - expect![[r#" -macro_rules! constant { - ($e:expr ;) => {$e}; -} - -const _: () = 0.0; -const _: () = 0.; -const _: () = 0e0; -"#]], - ); -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs deleted file mode 100644 index 72c44a0fbcb21..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! Tests for user-defined procedural macros. -//! -//! Note `//- proc_macros: identity` fixture metas in tests -- we don't use real -//! proc-macros here, as that would be slow. Instead, we use several hard-coded -//! in-memory macros. -use expect_test::expect; - -use crate::macro_expansion_tests::check; - -#[test] -fn attribute_macro_attr_censoring() { - cov_mark::check!(attribute_macro_attr_censoring); - check( - r#" -//- proc_macros: identity -#[attr1] #[proc_macros::identity] #[attr2] -struct S; -"#, - expect![[r##" -#[attr1] #[proc_macros::identity] #[attr2] -struct S; - -#[attr1] -#[attr2] struct S;"##]], - ); -} - -#[test] -fn derive_censoring() { - cov_mark::check!(derive_censoring); - check( - r#" -//- proc_macros: derive_identity -//- minicore:derive -#[attr1] -#[derive(Foo)] -#[derive(proc_macros::DeriveIdentity)] -#[derive(Bar)] -#[attr2] -struct S; -"#, - expect![[r##" -#[attr1] -#[derive(Foo)] -#[derive(proc_macros::DeriveIdentity)] -#[derive(Bar)] -#[attr2] -struct S; - -#[attr1] -#[derive(Bar)] -#[attr2] struct S;"##]], - ); -} - -#[test] -fn attribute_macro_syntax_completion_1() { - // this is just the case where the input is actually valid - check( - r#" -//- proc_macros: identity_when_valid -#[proc_macros::identity_when_valid] -fn foo() { bar.baz(); blub } -"#, - expect![[r##" -#[proc_macros::identity_when_valid] -fn foo() { bar.baz(); blub } - -fn foo() { - bar.baz(); - blub -}"##]], - ); -} - -#[test] -fn attribute_macro_syntax_completion_2() { - // common case of dot completion while typing - check( - r#" -//- proc_macros: identity_when_valid -#[proc_macros::identity_when_valid] -fn foo() { bar.; blub } -"#, - expect![[r##" -#[proc_macros::identity_when_valid] -fn foo() { bar.; blub } - -fn foo() { - bar. ; - blub -}"##]], - ); -} - -#[test] -fn float_parsing_panic() { - // Regression test for https://github.com/rust-lang/rust-analyzer/issues/12211 - check( - r#" -//- proc_macros: identity -macro_rules! id { - ($($t:tt)*) => { - $($t)* - }; -} -id /*+errors*/! { - #[proc_macros::identity] - impl Foo for WrapBj { - async fn foo(&self) { - self.0. id().await; - } - } -} -"#, - expect![[r##" -macro_rules! id { - ($($t:tt)*) => { - $($t)* - }; -} -/* parse error: expected SEMICOLON */ -#[proc_macros::identity] impl Foo for WrapBj { - async fn foo(&self ) { - self .0.id().await ; - } -} -"##]], - ); -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs deleted file mode 100644 index 6eb530ecc5420..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ /dev/null @@ -1,545 +0,0 @@ -//! This module implements import-resolution/macro expansion algorithm. -//! -//! The result of this module is `DefMap`: a data structure which contains: -//! -//! * a tree of modules for the crate -//! * for each module, a set of items visible in the module (directly declared -//! or imported) -//! -//! Note that `DefMap` contains fully macro expanded code. -//! -//! Computing `DefMap` can be partitioned into several logically -//! independent "phases". The phases are mutually recursive though, there's no -//! strict ordering. -//! -//! ## Collecting RawItems -//! -//! 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). -//! -//! ## Collecting Modules -//! -//! This happens in the `collector` module. In this phase, we recursively walk -//! tree of modules, collect raw items from submodules, populate module scopes -//! with defined items (so, we assign item ids in this phase) and record the set -//! of unresolved imports and macros. -//! -//! While we walk tree of modules, we also record macro_rules definitions and -//! expand calls to macro_rules defined macros. -//! -//! ## Resolving Imports -//! -//! We maintain a list of currently unresolved imports. On every iteration, we -//! try to resolve some imports from this list. If the import is resolved, we -//! record it, by adding an item to current module scope and, if necessary, by -//! recursively populating glob imports. -//! -//! ## Resolving Macros -//! -//! macro_rules from the same crate use a global mutable namespace. We expand -//! them immediately, when we collect modules. -//! -//! Macros from other crates (including proc-macros) can be used with -//! `foo::bar!` syntax. We handle them similarly to imports. There's a list of -//! unexpanded macros. On every iteration, we try to resolve each macro call -//! path and, upon success, we run macro expansion and "collect module" phase on -//! the result - -pub mod attr_resolution; -pub mod proc_macro; -pub mod diagnostics; -mod collector; -mod mod_resolution; -mod path_resolution; - -#[cfg(test)] -mod tests; - -use std::{cmp::Ord, ops::Deref, sync::Arc}; - -use base_db::{CrateId, Edition, FileId}; -use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId}; -use itertools::Itertools; -use la_arena::Arena; -use profile::Count; -use rustc_hash::FxHashMap; -use stdx::format_to; -use syntax::{ast, SmolStr}; - -use crate::{ - db::DefDatabase, - item_scope::{BuiltinShadowMode, ItemScope}, - item_tree::{ItemTreeId, Mod, TreeId}, - nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, - path::ModPath, - per_ns::PerNs, - visibility::Visibility, - AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, MacroId, ModuleId, ProcMacroId, -}; - -/// Contains the results of (early) name resolution. -/// -/// A `DefMap` stores the module tree and the definitions that are in scope in every module after -/// item-level macros have been expanded. -/// -/// Every crate has a primary `DefMap` whose root is the crate's main file (`main.rs`/`lib.rs`), -/// computed by the `crate_def_map` query. Additionally, every block expression introduces the -/// opportunity to write arbitrary item and module hierarchies, and thus gets its own `DefMap` that -/// is computed by the `block_def_map` query. -#[derive(Debug, PartialEq, Eq)] -pub struct DefMap { - _c: Count, - block: Option, - root: LocalModuleId, - modules: Arena, - krate: CrateId, - /// The prelude module for this crate. This either comes from an import - /// marked with the `prelude_import` attribute, or (in the normal case) from - /// a dependency (`std` or `core`). - prelude: Option, - extern_prelude: FxHashMap, - - /// Side table for resolving derive helpers. - exported_derives: FxHashMap>, - fn_proc_macro_mapping: FxHashMap, - /// The error that occurred when failing to load the proc-macro dll. - proc_macro_loading_error: Option>, - /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper - /// attributes. - derive_helpers_in_scope: FxHashMap, Vec<(Name, MacroId, MacroCallId)>>, - - /// Custom attributes registered with `#![register_attr]`. - registered_attrs: Vec, - /// Custom tool modules registered with `#![register_tool]`. - registered_tools: Vec, - - edition: Edition, - recursion_limit: Option, - diagnostics: Vec, -} - -/// For `DefMap`s computed for a block expression, this stores its location in the parent map. -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -struct BlockInfo { - /// The `BlockId` this `DefMap` was created from. - block: BlockId, - /// The containing module. - parent: ModuleId, -} - -impl std::ops::Index for DefMap { - type Output = ModuleData; - fn index(&self, id: LocalModuleId) -> &ModuleData { - &self.modules[id] - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub enum ModuleOrigin { - CrateRoot { - definition: FileId, - }, - /// Note that non-inline modules, by definition, live inside non-macro file. - File { - is_mod_rs: bool, - declaration: AstId, - declaration_tree_id: ItemTreeId, - definition: FileId, - }, - Inline { - definition_tree_id: ItemTreeId, - definition: AstId, - }, - /// Pseudo-module introduced by a block scope (contains only inner items). - BlockExpr { - block: AstId, - }, -} - -impl ModuleOrigin { - pub fn declaration(&self) -> Option> { - match self { - ModuleOrigin::File { declaration: module, .. } - | ModuleOrigin::Inline { definition: module, .. } => Some(*module), - ModuleOrigin::CrateRoot { .. } | ModuleOrigin::BlockExpr { .. } => None, - } - } - - pub fn file_id(&self) -> Option { - match self { - ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => { - Some(*definition) - } - _ => None, - } - } - - pub fn is_inline(&self) -> bool { - match self { - ModuleOrigin::Inline { .. } | ModuleOrigin::BlockExpr { .. } => true, - ModuleOrigin::CrateRoot { .. } | ModuleOrigin::File { .. } => false, - } - } - - /// Returns a node which defines this module. - /// That is, a file or a `mod foo {}` with items. - fn definition_source(&self, db: &dyn DefDatabase) -> InFile { - match self { - ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => { - let file_id = *definition; - let sf = db.parse(file_id).tree(); - InFile::new(file_id.into(), ModuleSource::SourceFile(sf)) - } - ModuleOrigin::Inline { definition, .. } => InFile::new( - definition.file_id, - ModuleSource::Module(definition.to_node(db.upcast())), - ), - ModuleOrigin::BlockExpr { block } => { - InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db.upcast()))) - } - } - } -} - -#[derive(Debug, PartialEq, Eq)] -pub struct ModuleData { - /// Where does this module come from? - pub origin: ModuleOrigin, - /// Declared visibility of this module. - pub visibility: Visibility, - - pub parent: Option, - pub children: FxHashMap, - pub scope: ItemScope, -} - -impl DefMap { - pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc { - let _p = profile::span("crate_def_map_query").detail(|| { - db.crate_graph()[krate].display_name.as_deref().unwrap_or_default().to_string() - }); - - let crate_graph = db.crate_graph(); - - let edition = crate_graph[krate].edition; - let origin = ModuleOrigin::CrateRoot { definition: crate_graph[krate].root_file_id }; - let def_map = DefMap::empty(krate, edition, ModuleData::new(origin, Visibility::Public)); - let def_map = collector::collect_defs( - db, - def_map, - TreeId::new(crate_graph[krate].root_file_id.into(), None), - ); - - Arc::new(def_map) - } - - pub(crate) fn block_def_map_query( - db: &dyn DefDatabase, - block_id: BlockId, - ) -> Option> { - let block: BlockLoc = db.lookup_intern_block(block_id); - - let tree_id = TreeId::new(block.ast_id.file_id, Some(block_id)); - let item_tree = tree_id.item_tree(db); - if item_tree.top_level_items().is_empty() { - return None; - } - - let parent_map = block.module.def_map(db); - let krate = block.module.krate; - let local_id = LocalModuleId::from_raw(la_arena::RawIdx::from(0)); - // NB: we use `None` as block here, which would be wrong for implicit - // modules declared by blocks with items. At the moment, we don't use - // this visibility for anything outside IDE, so that's probably OK. - let visibility = Visibility::Module(ModuleId { krate, local_id, block: None }); - let module_data = - ModuleData::new(ModuleOrigin::BlockExpr { block: block.ast_id }, visibility); - - let mut def_map = DefMap::empty(krate, parent_map.edition, module_data); - def_map.block = Some(BlockInfo { block: block_id, parent: block.module }); - - let def_map = collector::collect_defs(db, def_map, tree_id); - Some(Arc::new(def_map)) - } - - fn empty(krate: CrateId, edition: Edition, module_data: ModuleData) -> DefMap { - let mut modules: Arena = Arena::default(); - let root = modules.alloc(module_data); - - DefMap { - _c: Count::new(), - block: None, - krate, - edition, - recursion_limit: None, - extern_prelude: FxHashMap::default(), - exported_derives: FxHashMap::default(), - fn_proc_macro_mapping: FxHashMap::default(), - proc_macro_loading_error: None, - derive_helpers_in_scope: FxHashMap::default(), - prelude: None, - root, - modules, - registered_attrs: Vec::new(), - registered_tools: Vec::new(), - diagnostics: Vec::new(), - } - } - - pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator + '_ { - self.modules - .iter() - .filter(move |(_id, data)| data.origin.file_id() == Some(file_id)) - .map(|(id, _data)| id) - } - - pub fn modules(&self) -> impl Iterator + '_ { - self.modules.iter() - } - - pub fn derive_helpers_in_scope( - &self, - id: AstId, - ) -> Option<&[(Name, MacroId, MacroCallId)]> { - self.derive_helpers_in_scope.get(&id.map(|it| it.upcast())).map(Deref::deref) - } - - pub fn registered_tools(&self) -> &[SmolStr] { - &self.registered_tools - } - - pub fn registered_attrs(&self) -> &[SmolStr] { - &self.registered_attrs - } - - pub fn root(&self) -> LocalModuleId { - self.root - } - - pub fn fn_as_proc_macro(&self, id: FunctionId) -> Option { - self.fn_proc_macro_mapping.get(&id).copied() - } - - pub fn proc_macro_loading_error(&self) -> Option<&str> { - self.proc_macro_loading_error.as_deref() - } - - pub(crate) fn krate(&self) -> CrateId { - self.krate - } - - pub(crate) fn block_id(&self) -> Option { - self.block.as_ref().map(|block| block.block) - } - - pub(crate) fn prelude(&self) -> Option { - self.prelude - } - - pub(crate) fn extern_prelude(&self) -> impl Iterator + '_ { - self.extern_prelude.iter() - } - - pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId { - let block = self.block.as_ref().map(|b| b.block); - ModuleId { krate: self.krate, local_id, block } - } - - pub(crate) fn crate_root(&self, db: &dyn DefDatabase) -> ModuleId { - self.with_ancestor_maps(db, self.root, &mut |def_map, _module| { - if def_map.block.is_none() { Some(def_map.module_id(def_map.root)) } else { None } - }) - .expect("DefMap chain without root") - } - - pub(crate) fn resolve_path( - &self, - db: &dyn DefDatabase, - original_module: LocalModuleId, - path: &ModPath, - shadow: BuiltinShadowMode, - ) -> (PerNs, Option) { - let res = - self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow); - (res.resolved_def, res.segment_index) - } - - pub(crate) fn resolve_path_locally( - &self, - db: &dyn DefDatabase, - original_module: LocalModuleId, - path: &ModPath, - shadow: BuiltinShadowMode, - ) -> (PerNs, Option) { - let res = self.resolve_path_fp_with_macro_single( - db, - ResolveMode::Other, - original_module, - path, - shadow, - ); - (res.resolved_def, res.segment_index) - } - - /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module. - /// - /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns - /// `None`, iteration continues. - pub fn with_ancestor_maps( - &self, - db: &dyn DefDatabase, - local_mod: LocalModuleId, - f: &mut dyn FnMut(&DefMap, LocalModuleId) -> Option, - ) -> Option { - if let Some(it) = f(self, local_mod) { - return Some(it); - } - let mut block = self.block; - while let Some(block_info) = block { - let parent = block_info.parent.def_map(db); - if let Some(it) = f(&parent, block_info.parent.local_id) { - return Some(it); - } - block = parent.block; - } - - None - } - - /// If this `DefMap` is for a block expression, returns the module containing the block (which - /// might again be a block, or a module inside a block). - pub fn parent(&self) -> Option { - Some(self.block?.parent) - } - - /// Returns the module containing `local_mod`, either the parent `mod`, or the module containing - /// the block, if `self` corresponds to a block expression. - pub fn containing_module(&self, local_mod: LocalModuleId) -> Option { - match &self[local_mod].parent { - Some(parent) => Some(self.module_id(*parent)), - None => self.block.as_ref().map(|block| block.parent), - } - } - - // FIXME: this can use some more human-readable format (ideally, an IR - // even), as this should be a great debugging aid. - pub fn dump(&self, db: &dyn DefDatabase) -> String { - let mut buf = String::new(); - let mut arc; - let mut current_map = self; - while let Some(block) = ¤t_map.block { - go(&mut buf, current_map, "block scope", current_map.root); - buf.push('\n'); - arc = block.parent.def_map(db); - current_map = &*arc; - } - go(&mut buf, current_map, "crate", current_map.root); - return buf; - - fn go(buf: &mut String, map: &DefMap, path: &str, module: LocalModuleId) { - format_to!(buf, "{}\n", path); - - map.modules[module].scope.dump(buf); - - for (name, child) in - map.modules[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0)) - { - let path = format!("{}::{}", path, name); - buf.push('\n'); - go(buf, map, &path, *child); - } - } - } - - pub fn dump_block_scopes(&self, db: &dyn DefDatabase) -> String { - let mut buf = String::new(); - let mut arc; - let mut current_map = self; - while let Some(block) = ¤t_map.block { - format_to!(buf, "{:?} in {:?}\n", block.block, block.parent); - arc = block.parent.def_map(db); - current_map = &*arc; - } - - format_to!(buf, "crate scope\n"); - buf - } - - fn shrink_to_fit(&mut self) { - // Exhaustive match to require handling new fields. - let Self { - _c: _, - exported_derives, - extern_prelude, - diagnostics, - modules, - registered_attrs, - registered_tools, - fn_proc_macro_mapping, - derive_helpers_in_scope, - proc_macro_loading_error: _, - block: _, - edition: _, - recursion_limit: _, - krate: _, - prelude: _, - root: _, - } = self; - - extern_prelude.shrink_to_fit(); - exported_derives.shrink_to_fit(); - diagnostics.shrink_to_fit(); - modules.shrink_to_fit(); - registered_attrs.shrink_to_fit(); - registered_tools.shrink_to_fit(); - fn_proc_macro_mapping.shrink_to_fit(); - derive_helpers_in_scope.shrink_to_fit(); - for (_, module) in modules.iter_mut() { - module.children.shrink_to_fit(); - module.scope.shrink_to_fit(); - } - } - - /// Get a reference to the def map's diagnostics. - pub fn diagnostics(&self) -> &[DefDiagnostic] { - self.diagnostics.as_slice() - } - - pub fn recursion_limit(&self) -> Option { - self.recursion_limit - } -} - -impl ModuleData { - pub(crate) fn new(origin: ModuleOrigin, visibility: Visibility) -> Self { - ModuleData { - origin, - visibility, - parent: None, - children: FxHashMap::default(), - scope: ItemScope::default(), - } - } - - /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. - pub fn definition_source(&self, db: &dyn DefDatabase) -> InFile { - self.origin.definition_source(db) - } - - /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. - /// `None` for the crate root or block. - pub fn declaration_source(&self, db: &dyn DefDatabase) -> Option> { - let decl = self.origin.declaration()?; - let value = decl.to_node(db.upcast()); - Some(InFile { file_id: decl.file_id, value }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ModuleSource { - SourceFile(ast::SourceFile), - Module(ast::Module), - BlockExpr(ast::BlockExpr), -} 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 deleted file mode 100644 index 3650204ee9d73..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! Post-nameres attribute resolution. - -use hir_expand::MacroCallId; -use syntax::{ast, SmolStr}; - -use crate::{ - attr::Attr, - attr_macro_as_call_id, builtin_attr, - db::DefDatabase, - item_scope::BuiltinShadowMode, - macro_id_to_def_id, - nameres::path_resolution::ResolveMode, - path::{ModPath, PathKind}, - AstIdWithPath, LocalModuleId, UnresolvedMacro, -}; - -use super::DefMap; - -pub enum ResolvedAttr { - /// Attribute resolved to an attribute macro. - Macro(MacroCallId), - /// Attribute resolved to something else that does not require expansion. - Other, -} - -impl DefMap { - pub(crate) fn resolve_attr_macro( - &self, - db: &dyn DefDatabase, - original_module: LocalModuleId, - ast_id: AstIdWithPath, - attr: &Attr, - ) -> Result { - // NB: does not currently work for derive helpers as they aren't recorded in the `DefMap` - - if self.is_builtin_or_registered_attr(&ast_id.path) { - return Ok(ResolvedAttr::Other); - } - - let resolved_res = self.resolve_path_fp_with_macro( - db, - ResolveMode::Other, - original_module, - &ast_id.path, - BuiltinShadowMode::Module, - ); - let def = match resolved_res.resolved_def.take_macros() { - Some(def) => { - if def.is_attribute(db) { - def - } else { - return Ok(ResolvedAttr::Other); - } - } - None => return Err(UnresolvedMacro { path: ast_id.path }), - }; - - Ok(ResolvedAttr::Macro(attr_macro_as_call_id( - db, - &ast_id, - attr, - self.krate, - macro_id_to_def_id(db, def), - false, - ))) - } - - pub(crate) fn is_builtin_or_registered_attr(&self, path: &ModPath) -> bool { - if path.kind != PathKind::Plain { - return false; - } - - let segments = path.segments(); - - if let Some(name) = segments.first() { - let name = name.to_smol_str(); - let pred = |n: &_| *n == name; - - let registered = self.registered_tools.iter().map(SmolStr::as_str); - let is_tool = builtin_attr::TOOL_MODULES.iter().copied().chain(registered).any(pred); - // FIXME: tool modules can be shadowed by actual modules - if is_tool { - return true; - } - - if segments.len() == 1 { - let registered = self.registered_attrs.iter().map(SmolStr::as_str); - let is_inert = builtin_attr::INERT_ATTRIBUTES - .iter() - .map(|it| it.name) - .chain(registered) - .any(pred); - return is_inert; - } - } - false - } -} 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 deleted file mode 100644 index f394c541719f3..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ /dev/null @@ -1,2201 +0,0 @@ -//! The core of the module-level name resolution algorithm. -//! -//! `DefCollector::collect` contains the fixed-point iteration loop which -//! resolves imports and expands macros. - -use std::{iter, mem}; - -use base_db::{CrateId, Edition, FileId}; -use cfg::{CfgExpr, CfgOptions}; -use either::Either; -use hir_expand::{ - ast_id_map::FileAstId, - builtin_attr_macro::find_builtin_attr, - builtin_derive_macro::find_builtin_derive, - builtin_fn_macro::find_builtin_macro, - name::{name, AsName, Name}, - proc_macro::ProcMacroExpander, - ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, - MacroDefKind, -}; -use itertools::{izip, Itertools}; -use la_arena::Idx; -use limit::Limit; -use rustc_hash::{FxHashMap, FxHashSet}; -use stdx::always; -use syntax::{ast, SmolStr}; - -use crate::{ - attr::{Attr, AttrId, Attrs}, - attr_macro_as_call_id, - db::DefDatabase, - derive_macro_as_call_id, - item_scope::{ImportType, PerNsGlobImports}, - item_tree::{ - self, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode, MacroCall, - MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId, - }, - macro_call_as_call_id, macro_id_to_def_id, - nameres::{ - diagnostics::DefDiagnostic, - mod_resolution::ModDir, - path_resolution::ReachedFixedPoint, - proc_macro::{ProcMacroDef, ProcMacroKind}, - BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode, - }, - path::{ImportAlias, ModPath, PathKind}, - per_ns::PerNs, - visibility::{RawVisibility, Visibility}, - AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionId, - FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc, - MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId, - ProcMacroLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, -}; - -static GLOB_RECURSION_LIMIT: Limit = Limit::new(100); -static EXPANSION_DEPTH_LIMIT: Limit = Limit::new(128); -static FIXED_POINT_LIMIT: Limit = Limit::new(8192); - -pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: TreeId) -> DefMap { - let crate_graph = db.crate_graph(); - - let mut deps = FxHashMap::default(); - // populate external prelude and dependency list - let krate = &crate_graph[def_map.krate]; - for dep in &krate.dependencies { - tracing::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); - let dep_def_map = db.crate_def_map(dep.crate_id); - let dep_root = dep_def_map.module_id(dep_def_map.root); - - deps.insert(dep.as_name(), dep_root.into()); - - if dep.is_prelude() && !tree_id.is_block() { - def_map.extern_prelude.insert(dep.as_name(), dep_root); - } - } - - let cfg_options = &krate.cfg_options; - let proc_macros = match &krate.proc_macro { - Ok(proc_macros) => { - 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(), id: tt::TokenId::unspecified() }; - ( - name.as_name(), - ProcMacroExpander::new(def_map.krate, base_db::ProcMacroId(idx as u32)), - ) - }) - .collect() - } - Err(e) => { - def_map.proc_macro_loading_error = Some(e.clone().into_boxed_str()); - Vec::new() - } - }; - let is_proc_macro = krate.is_proc_macro; - - let mut collector = DefCollector { - db, - def_map, - deps, - glob_imports: FxHashMap::default(), - unresolved_imports: Vec::new(), - indeterminate_imports: Vec::new(), - unresolved_macros: Vec::new(), - mod_dirs: FxHashMap::default(), - cfg_options, - proc_macros, - from_glob_import: Default::default(), - skip_attrs: Default::default(), - is_proc_macro, - }; - if tree_id.is_block() { - collector.seed_with_inner(tree_id); - } else { - collector.seed_with_top_level(); - } - collector.collect(); - let mut def_map = collector.finish(); - def_map.shrink_to_fit(); - def_map -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -enum PartialResolvedImport { - /// None of any namespaces is resolved - Unresolved, - /// One of namespaces is resolved - Indeterminate(PerNs), - /// All namespaces are resolved, OR it comes from other crate - Resolved(PerNs), -} - -impl PartialResolvedImport { - fn namespaces(self) -> PerNs { - match self { - PartialResolvedImport::Unresolved => PerNs::none(), - PartialResolvedImport::Indeterminate(ns) | PartialResolvedImport::Resolved(ns) => ns, - } - } -} - -#[derive(Clone, Debug, Eq, PartialEq)] -enum ImportSource { - Import { id: ItemTreeId, use_tree: Idx }, - ExternCrate(ItemTreeId), -} - -#[derive(Debug, Eq, PartialEq)] -struct Import { - path: ModPath, - alias: Option, - visibility: RawVisibility, - kind: ImportKind, - is_prelude: bool, - is_extern_crate: bool, - is_macro_use: bool, - source: ImportSource, -} - -impl Import { - fn from_use( - db: &dyn DefDatabase, - krate: CrateId, - tree: &ItemTree, - id: ItemTreeId, - ) -> Vec { - let it = &tree[id.value]; - let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into()); - let visibility = &tree[it.visibility]; - let is_prelude = attrs.by_key("prelude_import").exists(); - - let mut res = Vec::new(); - it.use_tree.expand(|idx, path, kind, alias| { - res.push(Self { - path, - alias, - visibility: visibility.clone(), - kind, - is_prelude, - is_extern_crate: false, - is_macro_use: false, - source: ImportSource::Import { id, use_tree: idx }, - }); - }); - res - } - - fn from_extern_crate( - db: &dyn DefDatabase, - krate: CrateId, - tree: &ItemTree, - id: ItemTreeId, - ) -> Self { - let it = &tree[id.value]; - let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into()); - let visibility = &tree[it.visibility]; - Self { - path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())), - alias: it.alias.clone(), - visibility: visibility.clone(), - kind: ImportKind::Plain, - is_prelude: false, - is_extern_crate: true, - is_macro_use: attrs.by_key("macro_use").exists(), - source: ImportSource::ExternCrate(id), - } - } -} - -#[derive(Debug, Eq, PartialEq)] -struct ImportDirective { - module_id: LocalModuleId, - import: Import, - status: PartialResolvedImport, -} - -#[derive(Clone, Debug, Eq, PartialEq)] -struct MacroDirective { - module_id: LocalModuleId, - depth: usize, - kind: MacroDirectiveKind, - container: ItemContainerId, -} - -#[derive(Clone, Debug, Eq, PartialEq)] -enum MacroDirectiveKind { - FnLike { ast_id: AstIdWithPath, expand_to: ExpandTo }, - Derive { ast_id: AstIdWithPath, derive_attr: AttrId, derive_pos: usize }, - Attr { ast_id: AstIdWithPath, attr: Attr, mod_item: ModItem, tree: TreeId }, -} - -/// Walks the tree of module recursively -struct DefCollector<'a> { - db: &'a dyn DefDatabase, - def_map: DefMap, - deps: FxHashMap, - glob_imports: FxHashMap>, - unresolved_imports: Vec, - indeterminate_imports: Vec, - unresolved_macros: Vec, - mod_dirs: FxHashMap, - cfg_options: &'a CfgOptions, - /// List of procedural macros defined by this crate. This is read from the dynamic library - /// built by the build system, and is the list of proc. macros we can actually expand. It is - /// empty when proc. macro support is disabled (in which case we still do name resolution for - /// them). - proc_macros: Vec<(Name, ProcMacroExpander)>, - is_proc_macro: bool, - from_glob_import: PerNsGlobImports, - /// If we fail to resolve an attribute on a `ModItem`, we fall back to ignoring the attribute. - /// This map is used to skip all attributes up to and including the one that failed to resolve, - /// in order to not expand them twice. - /// - /// This also stores the attributes to skip when we resolve derive helpers and non-macro - /// non-builtin attributes in general. - skip_attrs: FxHashMap, AttrId>, -} - -impl DefCollector<'_> { - fn seed_with_top_level(&mut self) { - let _p = profile::span("seed_with_top_level"); - - let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; - let item_tree = self.db.file_item_tree(file_id.into()); - let module_id = self.def_map.root; - - let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate); - if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) { - self.inject_prelude(&attrs); - - // Process other crate-level attributes. - for attr in &*attrs { - let attr_name = match attr.path.as_ident() { - Some(name) => name, - None => continue, - }; - - if *attr_name == hir_expand::name![recursion_limit] { - if let Some(limit) = attr.string_value() { - if let Ok(limit) = limit.parse() { - self.def_map.recursion_limit = Some(limit); - } - } - continue; - } - - if *attr_name == hir_expand::name![crate_type] { - if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) { - self.is_proc_macro = true; - } - continue; - } - - let attr_is_register_like = *attr_name == hir_expand::name![register_attr] - || *attr_name == hir_expand::name![register_tool]; - if !attr_is_register_like { - continue; - } - - let registered_name = match attr.single_ident_value() { - Some(ident) => ident.as_name(), - _ => continue, - }; - - if *attr_name == hir_expand::name![register_attr] { - self.def_map.registered_attrs.push(registered_name.to_smol_str()); - cov_mark::hit!(register_attr); - } else { - self.def_map.registered_tools.push(registered_name.to_smol_str()); - cov_mark::hit!(register_tool); - } - } - - ModCollector { - def_collector: self, - macro_depth: 0, - module_id, - tree_id: TreeId::new(file_id.into(), None), - item_tree: &item_tree, - mod_dir: ModDir::root(), - } - .collect_in_top_module(item_tree.top_level_items()); - } - } - - fn seed_with_inner(&mut self, tree_id: TreeId) { - let item_tree = tree_id.item_tree(self.db); - let module_id = self.def_map.root; - - let is_cfg_enabled = item_tree - .top_level_attrs(self.db, self.def_map.krate) - .cfg() - .map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)); - if is_cfg_enabled { - ModCollector { - def_collector: self, - macro_depth: 0, - module_id, - tree_id, - item_tree: &item_tree, - mod_dir: ModDir::root(), - } - .collect_in_top_module(item_tree.top_level_items()); - } - } - - fn resolution_loop(&mut self) { - let _p = profile::span("DefCollector::resolution_loop"); - - // main name resolution fixed-point loop. - let mut i = 0; - 'resolve_attr: loop { - 'resolve_macros: loop { - self.db.unwind_if_cancelled(); - - { - let _p = profile::span("resolve_imports loop"); - - 'resolve_imports: loop { - if self.resolve_imports() == ReachedFixedPoint::Yes { - break 'resolve_imports; - } - } - } - if self.resolve_macros() == ReachedFixedPoint::Yes { - break 'resolve_macros; - } - - i += 1; - if FIXED_POINT_LIMIT.check(i).is_err() { - tracing::error!("name resolution is stuck"); - break 'resolve_attr; - } - } - - if self.reseed_with_unresolved_attribute() == ReachedFixedPoint::Yes { - break 'resolve_attr; - } - } - } - - fn collect(&mut self) { - let _p = profile::span("DefCollector::collect"); - - self.resolution_loop(); - - // Resolve all indeterminate resolved imports again - // As some of the macros will expand newly import shadowing partial resolved imports - // FIXME: We maybe could skip this, if we handle the indeterminate imports in `resolve_imports` - // correctly - let partial_resolved = self.indeterminate_imports.drain(..).map(|directive| { - ImportDirective { status: PartialResolvedImport::Unresolved, ..directive } - }); - self.unresolved_imports.extend(partial_resolved); - self.resolve_imports(); - - let unresolved_imports = mem::take(&mut self.unresolved_imports); - // show unresolved imports in completion, etc - for directive in &unresolved_imports { - self.record_resolved_import(directive); - } - self.unresolved_imports = unresolved_imports; - - if self.is_proc_macro { - // A crate exporting procedural macros is not allowed to export anything else. - // - // Additionally, while the proc macro entry points must be `pub`, they are not publicly - // exported in type/value namespace. This function reduces the visibility of all items - // in the crate root that aren't proc macros. - let root = self.def_map.root; - let module_id = self.def_map.module_id(root); - let root = &mut self.def_map.modules[root]; - root.scope.censor_non_proc_macros(module_id); - } - } - - /// When the fixed-point loop reaches a stable state, we might still have - /// some unresolved attributes left over. This takes one of them, and feeds - /// the item it's applied to back into name resolution. - /// - /// This effectively ignores the fact that the macro is there and just treats the items as - /// normal code. - /// - /// This improves UX for unresolved attributes, and replicates the - /// behavior before we supported proc. attribute macros. - fn reseed_with_unresolved_attribute(&mut self) -> ReachedFixedPoint { - cov_mark::hit!(unresolved_attribute_fallback); - - let unresolved_attr = - self.unresolved_macros.iter().enumerate().find_map(|(idx, directive)| match &directive - .kind - { - MacroDirectiveKind::Attr { ast_id, mod_item, attr, tree } => { - self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call( - directive.module_id, - MacroCallKind::Attr { - ast_id: ast_id.ast_id, - attr_args: Default::default(), - invoc_attr_index: attr.id.ast_index, - is_derive: false, - }, - attr.path().clone(), - )); - - self.skip_attrs.insert(ast_id.ast_id.with_value(*mod_item), attr.id); - - Some((idx, directive, *mod_item, *tree)) - } - _ => None, - }); - - match unresolved_attr { - Some((pos, &MacroDirective { module_id, depth, container, .. }, mod_item, tree_id)) => { - let item_tree = &tree_id.item_tree(self.db); - let mod_dir = self.mod_dirs[&module_id].clone(); - ModCollector { - def_collector: self, - macro_depth: depth, - module_id, - tree_id, - item_tree, - mod_dir, - } - .collect(&[mod_item], container); - - self.unresolved_macros.swap_remove(pos); - // Continue name resolution with the new data. - ReachedFixedPoint::No - } - None => ReachedFixedPoint::Yes, - } - } - - fn inject_prelude(&mut self, crate_attrs: &Attrs) { - // See compiler/rustc_builtin_macros/src/standard_library_imports.rs - - if crate_attrs.by_key("no_core").exists() { - // libcore does not get a prelude. - return; - } - - let krate = if crate_attrs.by_key("no_std").exists() { - name![core] - } else { - let std = name![std]; - if self.def_map.extern_prelude().any(|(name, _)| *name == std) { - std - } else { - // If `std` does not exist for some reason, fall back to core. This mostly helps - // keep r-a's own tests minimal. - name![core] - } - }; - - let edition = match self.def_map.edition { - Edition::Edition2015 => name![rust_2015], - Edition::Edition2018 => name![rust_2018], - Edition::Edition2021 => name![rust_2021], - }; - - let path_kind = if self.def_map.edition == Edition::Edition2015 { - PathKind::Plain - } else { - PathKind::Abs - }; - let path = - ModPath::from_segments(path_kind, [krate.clone(), name![prelude], edition].into_iter()); - // Fall back to the older `std::prelude::v1` for compatibility with Rust <1.52.0 - // FIXME remove this fallback - let fallback_path = - ModPath::from_segments(path_kind, [krate, name![prelude], name![v1]].into_iter()); - - for path in &[path, fallback_path] { - let (per_ns, _) = self.def_map.resolve_path( - self.db, - self.def_map.root, - path, - BuiltinShadowMode::Other, - ); - - match per_ns.types { - Some((ModuleDefId::ModuleId(m), _)) => { - self.def_map.prelude = Some(m); - return; - } - types => { - tracing::debug!( - "could not resolve prelude path `{}` to module (resolved to {:?})", - path, - types - ); - } - } - } - } - - /// Adds a definition of procedural macro `name` to the root module. - /// - /// # Notes on procedural macro resolution - /// - /// Procedural macro functionality is provided by the build system: It has to build the proc - /// macro and pass the resulting dynamic library to rust-analyzer. - /// - /// When procedural macro support is enabled, the list of proc macros exported by a crate is - /// known before we resolve names in the crate. This list is stored in `self.proc_macros` and is - /// derived from the dynamic library. - /// - /// However, we *also* would like to be able to at least *resolve* macros on our own, without - /// help by the build system. So, when the macro isn't found in `self.proc_macros`, we instead - /// use a dummy expander that always errors. This comes with the drawback of macros potentially - /// going out of sync with what the build system sees (since we resolve using VFS state, but - /// Cargo builds only on-disk files). We could and probably should add diagnostics for that. - fn export_proc_macro( - &mut self, - def: ProcMacroDef, - id: ItemTreeId, - fn_id: FunctionId, - module_id: ModuleId, - ) { - let kind = def.kind.to_basedb_kind(); - let (expander, kind) = match self.proc_macros.iter().find(|(n, _)| n == &def.name) { - Some(&(_, expander)) => (expander, kind), - None => (ProcMacroExpander::dummy(self.def_map.krate), kind), - }; - - let proc_macro_id = - ProcMacroLoc { container: module_id, id, expander, kind }.intern(self.db); - self.define_proc_macro(def.name.clone(), proc_macro_id); - if let ProcMacroKind::CustomDerive { helpers } = def.kind { - self.def_map - .exported_derives - .insert(macro_id_to_def_id(self.db, proc_macro_id.into()), helpers); - } - self.def_map.fn_proc_macro_mapping.insert(fn_id, proc_macro_id); - } - - /// Define a macro with `macro_rules`. - /// - /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`, - /// then it is also defined in the root module scope. - /// You can `use` or invoke it by `crate::macro_name` anywhere, before or after the definition. - /// - /// It is surprising that the macro will never be in the current module scope. - /// These code fails with "unresolved import/macro", - /// ```rust,compile_fail - /// mod m { macro_rules! foo { () => {} } } - /// use m::foo as bar; - /// ``` - /// - /// ```rust,compile_fail - /// macro_rules! foo { () => {} } - /// self::foo!(); - /// crate::foo!(); - /// ``` - /// - /// Well, this code compiles, because the plain path `foo` in `use` is searched - /// in the legacy textual scope only. - /// ```rust - /// macro_rules! foo { () => {} } - /// use foo as bar; - /// ``` - fn define_macro_rules( - &mut self, - module_id: LocalModuleId, - name: Name, - macro_: MacroRulesId, - export: bool, - ) { - // Textual scoping - self.define_legacy_macro(module_id, name.clone(), macro_.into()); - - // Module scoping - // In Rust, `#[macro_export]` macros are unconditionally visible at the - // crate root, even if the parent modules is **not** visible. - if export { - let module_id = self.def_map.root; - self.def_map.modules[module_id].scope.declare(macro_.into()); - self.update( - module_id, - &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))], - Visibility::Public, - ImportType::Named, - ); - } - } - - /// Define a legacy textual scoped macro in module - /// - /// We use a map `legacy_macros` to store all legacy textual scoped macros visible per module. - /// It will clone all macros from parent legacy scope, whose definition is prior to - /// the definition of current module. - /// And also, `macro_use` on a module will import all legacy macros visible inside to - /// current legacy scope, with possible shadowing. - fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroId) { - // Always shadowing - self.def_map.modules[module_id].scope.define_legacy_macro(name, mac); - } - - /// Define a macro 2.0 macro - /// - /// The scoped of macro 2.0 macro is equal to normal function - fn define_macro_def( - &mut self, - module_id: LocalModuleId, - name: Name, - macro_: Macro2Id, - vis: &RawVisibility, - ) { - let vis = - self.def_map.resolve_visibility(self.db, module_id, vis).unwrap_or(Visibility::Public); - self.def_map.modules[module_id].scope.declare(macro_.into()); - self.update( - module_id, - &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))], - vis, - ImportType::Named, - ); - } - - /// Define a proc macro - /// - /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped. - /// And unconditionally exported. - fn define_proc_macro(&mut self, name: Name, macro_: ProcMacroId) { - let module_id = self.def_map.root; - self.def_map.modules[module_id].scope.declare(macro_.into()); - self.update( - module_id, - &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))], - Visibility::Public, - ImportType::Named, - ); - } - - /// Import macros from `#[macro_use] extern crate`. - fn import_macros_from_extern_crate( - &mut self, - current_module_id: LocalModuleId, - extern_crate: &item_tree::ExternCrate, - ) { - tracing::debug!( - "importing macros from extern crate: {:?} ({:?})", - extern_crate, - self.def_map.edition, - ); - - if let Some(m) = self.resolve_extern_crate(&extern_crate.name) { - if m == self.def_map.module_id(current_module_id) { - cov_mark::hit!(ignore_macro_use_extern_crate_self); - return; - } - - cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use); - self.import_all_macros_exported(current_module_id, m.krate); - } - } - - /// Import all exported macros from another crate - /// - /// Exported macros are just all macros in the root module scope. - /// Note that it contains not only all `#[macro_export]` macros, but also all aliases - /// created by `use` in the root module, ignoring the visibility of `use`. - fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) { - let def_map = self.db.crate_def_map(krate); - for (name, def) in def_map[def_map.root].scope.macros() { - // `#[macro_use]` brings macros into legacy scope. Yes, even non-`macro_rules!` macros. - self.define_legacy_macro(current_module_id, name.clone(), def); - } - } - - /// Tries to resolve every currently unresolved import. - fn resolve_imports(&mut self) -> ReachedFixedPoint { - let mut res = ReachedFixedPoint::Yes; - let imports = mem::take(&mut self.unresolved_imports); - - self.unresolved_imports = imports - .into_iter() - .filter_map(|mut directive| { - directive.status = self.resolve_import(directive.module_id, &directive.import); - match directive.status { - PartialResolvedImport::Indeterminate(_) => { - self.record_resolved_import(&directive); - self.indeterminate_imports.push(directive); - res = ReachedFixedPoint::No; - None - } - PartialResolvedImport::Resolved(_) => { - self.record_resolved_import(&directive); - res = ReachedFixedPoint::No; - None - } - PartialResolvedImport::Unresolved => Some(directive), - } - }) - .collect(); - res - } - - fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport { - let _p = profile::span("resolve_import").detail(|| format!("{}", import.path)); - tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); - if import.is_extern_crate { - let name = import - .path - .as_ident() - .expect("extern crate should have been desugared to one-element path"); - - let res = self.resolve_extern_crate(name); - - match res { - Some(res) => { - PartialResolvedImport::Resolved(PerNs::types(res.into(), Visibility::Public)) - } - None => PartialResolvedImport::Unresolved, - } - } else { - let res = self.def_map.resolve_path_fp_with_macro( - self.db, - ResolveMode::Import, - module_id, - &import.path, - BuiltinShadowMode::Module, - ); - - let def = res.resolved_def; - if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() { - return PartialResolvedImport::Unresolved; - } - - if let Some(krate) = res.krate { - if krate != self.def_map.krate { - return PartialResolvedImport::Resolved( - def.filter_visibility(|v| matches!(v, Visibility::Public)), - ); - } - } - - // Check whether all namespace is resolved - if def.take_types().is_some() - && def.take_values().is_some() - && def.take_macros().is_some() - { - PartialResolvedImport::Resolved(def) - } else { - PartialResolvedImport::Indeterminate(def) - } - } - } - - fn resolve_extern_crate(&self, name: &Name) -> Option { - if *name == name!(self) { - cov_mark::hit!(extern_crate_self_as); - let root = match self.def_map.block { - Some(_) => { - let def_map = self.def_map.crate_root(self.db).def_map(self.db); - def_map.module_id(def_map.root()) - } - None => self.def_map.module_id(self.def_map.root()), - }; - Some(root) - } else { - self.deps.get(name).copied() - } - } - - fn record_resolved_import(&mut self, directive: &ImportDirective) { - let _p = profile::span("record_resolved_import"); - - let module_id = directive.module_id; - let import = &directive.import; - let mut def = directive.status.namespaces(); - let vis = self - .def_map - .resolve_visibility(self.db, module_id, &directive.import.visibility) - .unwrap_or(Visibility::Public); - - match import.kind { - ImportKind::Plain | ImportKind::TypeOnly => { - let name = match &import.alias { - Some(ImportAlias::Alias(name)) => Some(name), - Some(ImportAlias::Underscore) => None, - None => match import.path.segments().last() { - Some(last_segment) => Some(last_segment), - None => { - cov_mark::hit!(bogus_paths); - return; - } - }, - }; - - if import.kind == ImportKind::TypeOnly { - def.values = None; - def.macros = None; - } - - tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); - - // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 - if import.is_extern_crate && module_id == self.def_map.root { - if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name) - { - self.def_map.extern_prelude.insert(name.clone(), def); - } - } - - self.update(module_id, &[(name.cloned(), def)], vis, ImportType::Named); - } - ImportKind::Glob => { - tracing::debug!("glob import: {:?}", import); - match def.take_types() { - Some(ModuleDefId::ModuleId(m)) => { - if import.is_prelude { - // Note: This dodgily overrides the injected prelude. The rustc - // implementation seems to work the same though. - cov_mark::hit!(std_prelude); - self.def_map.prelude = Some(m); - } else if m.krate != self.def_map.krate { - cov_mark::hit!(glob_across_crates); - // glob import from other crate => we can just import everything once - let item_map = m.def_map(self.db); - let scope = &item_map[m.local_id].scope; - - // Module scoped macros is included - let items = scope - .resolutions() - // only keep visible names... - .map(|(n, res)| { - (n, res.filter_visibility(|v| v.is_visible_from_other_crate())) - }) - .filter(|(_, res)| !res.is_none()) - .collect::>(); - - self.update(module_id, &items, vis, ImportType::Glob); - } else { - // glob import from same crate => we do an initial - // import, and then need to propagate any further - // additions - let def_map; - let scope = if m.block == self.def_map.block_id() { - &self.def_map[m.local_id].scope - } else { - def_map = m.def_map(self.db); - &def_map[m.local_id].scope - }; - - // Module scoped macros is included - let items = scope - .resolutions() - // only keep visible names... - .map(|(n, res)| { - ( - n, - res.filter_visibility(|v| { - v.is_visible_from_def_map( - self.db, - &self.def_map, - module_id, - ) - }), - ) - }) - .filter(|(_, res)| !res.is_none()) - .collect::>(); - - self.update(module_id, &items, vis, ImportType::Glob); - // record the glob import in case we add further items - let glob = self.glob_imports.entry(m.local_id).or_default(); - if !glob.iter().any(|(mid, _)| *mid == module_id) { - glob.push((module_id, vis)); - } - } - } - Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { - cov_mark::hit!(glob_enum); - // glob import from enum => just import all the variants - - // XXX: urgh, so this works by accident! Here, we look at - // the enum data, and, in theory, this might require us to - // look back at the crate_def_map, creating a cycle. For - // example, `enum E { crate::some_macro!(); }`. Luckily, the - // only kind of macro that is allowed inside enum is a - // `cfg_macro`, and we don't need to run name resolution for - // it, but this is sheer luck! - let enum_data = self.db.enum_data(e); - let resolutions = enum_data - .variants - .iter() - .map(|(local_id, variant_data)| { - let name = variant_data.name.clone(); - let variant = EnumVariantId { parent: e, local_id }; - let res = PerNs::both(variant.into(), variant.into(), vis); - (Some(name), res) - }) - .collect::>(); - self.update(module_id, &resolutions, vis, ImportType::Glob); - } - Some(d) => { - tracing::debug!("glob import {:?} from non-module/enum {:?}", import, d); - } - None => { - tracing::debug!("glob import {:?} didn't resolve as type", import); - } - } - } - } - } - - fn update( - &mut self, - module_id: LocalModuleId, - resolutions: &[(Option, PerNs)], - vis: Visibility, - import_type: ImportType, - ) { - self.db.unwind_if_cancelled(); - self.update_recursive(module_id, resolutions, vis, import_type, 0) - } - - fn update_recursive( - &mut self, - module_id: LocalModuleId, - resolutions: &[(Option, PerNs)], - // All resolutions are imported with this visibility; the visibilities in - // the `PerNs` values are ignored and overwritten - vis: Visibility, - import_type: ImportType, - depth: usize, - ) { - if GLOB_RECURSION_LIMIT.check(depth).is_err() { - // prevent stack overflows (but this shouldn't be possible) - panic!("infinite recursion in glob imports!"); - } - let mut changed = false; - - for (name, res) in resolutions { - match name { - Some(name) => { - let scope = &mut self.def_map.modules[module_id].scope; - changed |= scope.push_res_with_import( - &mut self.from_glob_import, - (module_id, name.clone()), - res.with_visibility(vis), - import_type, - ); - } - None => { - let tr = match res.take_types() { - Some(ModuleDefId::TraitId(tr)) => tr, - Some(other) => { - tracing::debug!("non-trait `_` import of {:?}", other); - continue; - } - None => continue, - }; - let old_vis = self.def_map.modules[module_id].scope.unnamed_trait_vis(tr); - let should_update = match old_vis { - None => true, - Some(old_vis) => { - let max_vis = old_vis.max(vis, &self.def_map).unwrap_or_else(|| { - panic!("`Tr as _` imports with unrelated visibilities {:?} and {:?} (trait {:?})", old_vis, vis, tr); - }); - - if max_vis == old_vis { - false - } else { - cov_mark::hit!(upgrade_underscore_visibility); - true - } - } - }; - - if should_update { - changed = true; - self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis); - } - } - } - } - - if !changed { - return; - } - let glob_imports = self - .glob_imports - .get(&module_id) - .into_iter() - .flatten() - .filter(|(glob_importing_module, _)| { - // we know all resolutions have the same visibility (`vis`), so we - // just need to check that once - vis.is_visible_from_def_map(self.db, &self.def_map, *glob_importing_module) - }) - .cloned() - .collect::>(); - - for (glob_importing_module, glob_import_vis) in glob_imports { - self.update_recursive( - glob_importing_module, - resolutions, - glob_import_vis, - ImportType::Glob, - depth + 1, - ); - } - } - - fn resolve_macros(&mut self) -> ReachedFixedPoint { - let mut macros = mem::take(&mut self.unresolved_macros); - let mut resolved = Vec::new(); - let mut push_resolved = |directive: &MacroDirective, call_id| { - resolved.push((directive.module_id, directive.depth, directive.container, call_id)); - }; - let mut res = ReachedFixedPoint::Yes; - macros.retain(|directive| { - let resolver2 = |path| { - let resolved_res = self.def_map.resolve_path_fp_with_macro( - self.db, - ResolveMode::Other, - directive.module_id, - &path, - BuiltinShadowMode::Module, - ); - resolved_res - .resolved_def - .take_macros() - .map(|it| (it, macro_id_to_def_id(self.db, it))) - }; - let resolver = |path| resolver2(path).map(|(_, it)| it); - - match &directive.kind { - MacroDirectiveKind::FnLike { ast_id, expand_to } => { - let call_id = macro_call_as_call_id( - self.db, - ast_id, - *expand_to, - self.def_map.krate, - &resolver, - &mut |_err| (), - ); - if let Ok(Ok(call_id)) = call_id { - push_resolved(directive, call_id); - res = ReachedFixedPoint::No; - return false; - } - } - MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos } => { - let id = derive_macro_as_call_id( - self.db, - ast_id, - *derive_attr, - *derive_pos as u32, - self.def_map.krate, - &resolver2, - ); - - if let Ok((macro_id, def_id, call_id)) = id { - self.def_map.modules[directive.module_id].scope.set_derive_macro_invoc( - ast_id.ast_id, - call_id, - *derive_attr, - *derive_pos, - ); - // Record its helper attributes. - if def_id.krate != self.def_map.krate { - let def_map = self.db.crate_def_map(def_id.krate); - if let Some(helpers) = def_map.exported_derives.get(&def_id) { - self.def_map - .derive_helpers_in_scope - .entry(ast_id.ast_id.map(|it| it.upcast())) - .or_default() - .extend(izip!( - helpers.iter().cloned(), - iter::repeat(macro_id), - iter::repeat(call_id), - )); - } - } - - push_resolved(directive, call_id); - res = ReachedFixedPoint::No; - return false; - } - } - MacroDirectiveKind::Attr { ast_id: file_ast_id, mod_item, attr, tree } => { - let &AstIdWithPath { ast_id, ref path } = file_ast_id; - let file_id = ast_id.file_id; - - let mut recollect_without = |collector: &mut Self| { - // Remove the original directive since we resolved it. - let mod_dir = collector.mod_dirs[&directive.module_id].clone(); - collector.skip_attrs.insert(InFile::new(file_id, *mod_item), attr.id); - - let item_tree = tree.item_tree(self.db); - ModCollector { - def_collector: collector, - macro_depth: directive.depth, - module_id: directive.module_id, - tree_id: *tree, - item_tree: &item_tree, - mod_dir, - } - .collect(&[*mod_item], directive.container); - res = ReachedFixedPoint::No; - false - }; - - if let Some(ident) = path.as_ident() { - if let Some(helpers) = self.def_map.derive_helpers_in_scope.get(&ast_id) { - if helpers.iter().any(|(it, ..)| it == ident) { - cov_mark::hit!(resolved_derive_helper); - // Resolved to derive helper. Collect the item's attributes again, - // starting after the derive helper. - return recollect_without(self); - } - } - } - - let def = match resolver(path.clone()) { - Some(def) if def.is_attribute() => def, - _ => return true, - }; - if matches!( - def, - MacroDefId { kind:MacroDefKind::BuiltInAttr(expander, _),.. } - if expander.is_derive() - ) { - // Resolved to `#[derive]` - - let item_tree = tree.item_tree(self.db); - let ast_adt_id: FileAstId = match *mod_item { - ModItem::Struct(strukt) => item_tree[strukt].ast_id().upcast(), - ModItem::Union(union) => item_tree[union].ast_id().upcast(), - ModItem::Enum(enum_) => item_tree[enum_].ast_id().upcast(), - _ => { - let diag = DefDiagnostic::invalid_derive_target( - directive.module_id, - ast_id, - attr.id, - ); - self.def_map.diagnostics.push(diag); - return recollect_without(self); - } - }; - let ast_id = ast_id.with_value(ast_adt_id); - - match attr.parse_path_comma_token_tree() { - Some(derive_macros) => { - let mut len = 0; - for (idx, path) in derive_macros.enumerate() { - let ast_id = AstIdWithPath::new(file_id, ast_id.value, path); - self.unresolved_macros.push(MacroDirective { - module_id: directive.module_id, - depth: directive.depth + 1, - kind: MacroDirectiveKind::Derive { - ast_id, - derive_attr: attr.id, - derive_pos: idx, - }, - container: directive.container, - }); - len = idx; - } - - // We treat the #[derive] macro as an attribute call, but we do not resolve it for nameres collection. - // This is just a trick to be able to resolve the input to derives as proper paths. - // 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, - true, - ); - self.def_map.modules[directive.module_id] - .scope - .init_derive_attribute(ast_id, attr.id, call_id, len + 1); - } - None => { - let diag = DefDiagnostic::malformed_derive( - directive.module_id, - ast_id, - attr.id, - ); - self.def_map.diagnostics.push(diag); - } - } - - return recollect_without(self); - } - - // Not resolved to a derive helper or the derive attribute, so try to treat as a normal attribute. - let call_id = attr_macro_as_call_id( - self.db, - file_ast_id, - attr, - self.def_map.krate, - def, - false, - ); - let loc: MacroCallLoc = self.db.lookup_intern_macro_call(call_id); - - // If proc attribute macro expansion is disabled, skip expanding it here - if !self.db.enable_proc_attr_macros() { - self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro( - directive.module_id, - loc.kind, - loc.def.krate, - )); - 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!( - loc.def.kind, - MacroDefKind::BuiltInAttr(expander, _) - if expander.is_test() || expander.is_bench() - ) { - return recollect_without(self); - } - - if let MacroDefKind::ProcMacro(exp, ..) = loc.def.kind { - if exp.is_dummy() { - // If there's no expander for the proc macro (e.g. - // because proc macros are disabled, or building the - // proc macro crate failed), report this and skip - // expansion like we would if it was disabled - self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro( - directive.module_id, - loc.kind, - loc.def.krate, - )); - - return recollect_without(self); - } - } - - self.def_map.modules[directive.module_id] - .scope - .add_attr_macro_invoc(ast_id, call_id); - - push_resolved(directive, call_id); - res = ReachedFixedPoint::No; - return false; - } - } - - true - }); - // Attribute resolution can add unresolved macro invocations, so concatenate the lists. - self.unresolved_macros.extend(macros); - - for (module_id, depth, container, macro_call_id) in resolved { - self.collect_macro_expansion(module_id, macro_call_id, depth, container); - } - - res - } - - fn collect_macro_expansion( - &mut self, - module_id: LocalModuleId, - macro_call_id: MacroCallId, - depth: usize, - container: ItemContainerId, - ) { - if EXPANSION_DEPTH_LIMIT.check(depth).is_err() { - cov_mark::hit!(macro_expansion_overflow); - tracing::warn!("macro expansion is too deep"); - return; - } - let file_id = macro_call_id.as_file(); - - // First, fetch the raw expansion result for purposes of error reporting. This goes through - // `macro_expand_error` to avoid depending on the full expansion result (to improve - // incrementality). - let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id); - let err = self.db.macro_expand_error(macro_call_id); - if let Some(err) = err { - let diag = match err { - hir_expand::ExpandError::UnresolvedProcMacro(krate) => { - always!(krate == loc.def.krate); - // Missing proc macros are non-fatal, so they are handled specially. - DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone(), loc.def.krate) - } - _ => DefDiagnostic::macro_error(module_id, loc.kind.clone(), err.to_string()), - }; - - self.def_map.diagnostics.push(diag); - } - - // Then, fetch and process the item tree. This will reuse the expansion result from above. - let item_tree = self.db.file_item_tree(file_id); - let mod_dir = self.mod_dirs[&module_id].clone(); - ModCollector { - def_collector: &mut *self, - macro_depth: depth, - tree_id: TreeId::new(file_id, None), - module_id, - item_tree: &item_tree, - mod_dir, - } - .collect(item_tree.top_level_items(), container); - } - - fn finish(mut self) -> DefMap { - // Emit diagnostics for all remaining unexpanded macros. - - let _p = profile::span("DefCollector::finish"); - - for directive in &self.unresolved_macros { - match &directive.kind { - MacroDirectiveKind::FnLike { ast_id, expand_to } => { - let macro_call_as_call_id = macro_call_as_call_id( - self.db, - ast_id, - *expand_to, - self.def_map.krate, - |path| { - let resolved_res = self.def_map.resolve_path_fp_with_macro( - self.db, - ResolveMode::Other, - directive.module_id, - &path, - BuiltinShadowMode::Module, - ); - resolved_res - .resolved_def - .take_macros() - .map(|it| macro_id_to_def_id(self.db, it)) - }, - &mut |_| (), - ); - if let Err(UnresolvedMacro { path }) = macro_call_as_call_id { - self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call( - directive.module_id, - MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: *expand_to }, - path, - )); - } - } - MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos } => { - self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call( - directive.module_id, - MacroCallKind::Derive { - ast_id: ast_id.ast_id, - derive_attr_index: derive_attr.ast_index, - derive_index: *derive_pos as u32, - }, - ast_id.path.clone(), - )); - } - // These are diagnosed by `reseed_with_unresolved_attribute`, as that function consumes them - MacroDirectiveKind::Attr { .. } => {} - } - } - - // Emit diagnostics for all remaining unresolved imports. - - // We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't - // resolve. We first emit diagnostics for unresolved extern crates and collect the missing - // crate names. Then we emit diagnostics for unresolved imports, but only if the import - // doesn't start with an unresolved crate's name. Due to renaming and reexports, this is a - // heuristic, but it works in practice. - let mut diagnosed_extern_crates = FxHashSet::default(); - for directive in &self.unresolved_imports { - if let ImportSource::ExternCrate(krate) = directive.import.source { - let item_tree = krate.item_tree(self.db); - let extern_crate = &item_tree[krate.value]; - - diagnosed_extern_crates.insert(extern_crate.name.clone()); - - self.def_map.diagnostics.push(DefDiagnostic::unresolved_extern_crate( - directive.module_id, - InFile::new(krate.file_id(), extern_crate.ast_id), - )); - } - } - - for directive in &self.unresolved_imports { - if let ImportSource::Import { id: import, use_tree } = directive.import.source { - if matches!( - (directive.import.path.segments().first(), &directive.import.path.kind), - (Some(krate), PathKind::Plain | PathKind::Abs) if diagnosed_extern_crates.contains(krate) - ) { - continue; - } - - self.def_map.diagnostics.push(DefDiagnostic::unresolved_import( - directive.module_id, - import, - use_tree, - )); - } - } - - self.def_map - } -} - -/// Walks a single module, populating defs, imports and macros -struct ModCollector<'a, 'b> { - def_collector: &'a mut DefCollector<'b>, - macro_depth: usize, - module_id: LocalModuleId, - tree_id: TreeId, - item_tree: &'a ItemTree, - mod_dir: ModDir, -} - -impl ModCollector<'_, '_> { - fn collect_in_top_module(&mut self, items: &[ModItem]) { - let module = self.def_collector.def_map.module_id(self.module_id); - self.collect(items, module.into()) - } - - fn collect(&mut self, items: &[ModItem], container: ItemContainerId) { - let krate = self.def_collector.def_map.krate; - - // Note: don't assert that inserted value is fresh: it's simply not true - // for macros. - self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone()); - - // Prelude module is always considered to be `#[macro_use]`. - if let Some(prelude_module) = self.def_collector.def_map.prelude { - if prelude_module.krate != krate { - cov_mark::hit!(prelude_is_macro_use); - self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); - } - } - - // This should be processed eagerly instead of deferred to resolving. - // `#[macro_use] extern crate` is hoisted to imports macros before collecting - // any other items. - for &item in items { - let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into()); - if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) { - if let ModItem::ExternCrate(id) = item { - let import = &self.item_tree[id]; - let attrs = self.item_tree.attrs( - self.def_collector.db, - krate, - ModItem::from(id).into(), - ); - if attrs.by_key("macro_use").exists() { - self.def_collector.import_macros_from_extern_crate(self.module_id, import); - } - } - } - } - - for &item in items { - let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into()); - if let Some(cfg) = attrs.cfg() { - if !self.is_cfg_enabled(&cfg) { - self.emit_unconfigured_diagnostic(item, &cfg); - continue; - } - } - - if let Err(()) = self.resolve_attributes(&attrs, item, container) { - // Do not process the item. It has at least one non-builtin attribute, so the - // fixed-point algorithm is required to resolve the rest of them. - continue; - } - - let db = self.def_collector.db; - let module = self.def_collector.def_map.module_id(self.module_id); - let def_map = &mut self.def_collector.def_map; - let update_def = - |def_collector: &mut DefCollector<'_>, id, name: &Name, vis, has_constructor| { - def_collector.def_map.modules[self.module_id].scope.declare(id); - def_collector.update( - self.module_id, - &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))], - vis, - ImportType::Named, - ) - }; - let resolve_vis = |def_map: &DefMap, visibility| { - def_map - .resolve_visibility(db, self.module_id, visibility) - .unwrap_or(Visibility::Public) - }; - - match item { - ModItem::Mod(m) => self.collect_module(m, &attrs), - ModItem::Import(import_id) => { - let imports = Import::from_use( - db, - krate, - self.item_tree, - ItemTreeId::new(self.tree_id, import_id), - ); - self.def_collector.unresolved_imports.extend(imports.into_iter().map( - |import| ImportDirective { - module_id: self.module_id, - import, - status: PartialResolvedImport::Unresolved, - }, - )); - } - ModItem::ExternCrate(import_id) => { - self.def_collector.unresolved_imports.push(ImportDirective { - module_id: self.module_id, - import: Import::from_extern_crate( - db, - krate, - self.item_tree, - ItemTreeId::new(self.tree_id, import_id), - ), - status: PartialResolvedImport::Unresolved, - }) - } - ModItem::ExternBlock(block) => self.collect( - &self.item_tree[block].children, - ItemContainerId::ExternBlockId( - ExternBlockLoc { - container: module, - id: ItemTreeId::new(self.tree_id, block), - } - .intern(db), - ), - ), - ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac], container), - ModItem::MacroRules(id) => self.collect_macro_rules(id, module), - ModItem::MacroDef(id) => self.collect_macro_def(id, module), - ModItem::Impl(imp) => { - let impl_id = - ImplLoc { container: module, id: ItemTreeId::new(self.tree_id, imp) } - .intern(db); - self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id) - } - ModItem::Function(id) => { - let it = &self.item_tree[id]; - let fn_id = - FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db); - - let vis = resolve_vis(def_map, &self.item_tree[it.visibility]); - if self.def_collector.is_proc_macro { - if self.module_id == def_map.root { - if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) { - let crate_root = def_map.module_id(def_map.root); - self.def_collector.export_proc_macro( - proc_macro, - ItemTreeId::new(self.tree_id, id), - fn_id, - crate_root, - ); - } - } - } - - update_def(self.def_collector, fn_id.into(), &it.name, vis, false); - } - ModItem::Struct(id) => { - let it = &self.item_tree[id]; - - let vis = resolve_vis(def_map, &self.item_tree[it.visibility]); - update_def( - self.def_collector, - StructLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } - .intern(db) - .into(), - &it.name, - vis, - !matches!(it.fields, Fields::Record(_)), - ); - } - ModItem::Union(id) => { - let it = &self.item_tree[id]; - - let vis = resolve_vis(def_map, &self.item_tree[it.visibility]); - update_def( - self.def_collector, - UnionLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } - .intern(db) - .into(), - &it.name, - vis, - false, - ); - } - ModItem::Enum(id) => { - let it = &self.item_tree[id]; - - let vis = resolve_vis(def_map, &self.item_tree[it.visibility]); - update_def( - self.def_collector, - EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } - .intern(db) - .into(), - &it.name, - vis, - false, - ); - } - ModItem::Const(id) => { - let it = &self.item_tree[id]; - let const_id = - ConstLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db); - - match &it.name { - Some(name) => { - let vis = resolve_vis(def_map, &self.item_tree[it.visibility]); - update_def(self.def_collector, const_id.into(), name, vis, false); - } - None => { - // const _: T = ...; - self.def_collector.def_map.modules[self.module_id] - .scope - .define_unnamed_const(const_id); - } - } - } - ModItem::Static(id) => { - let it = &self.item_tree[id]; - - let vis = resolve_vis(def_map, &self.item_tree[it.visibility]); - update_def( - self.def_collector, - StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) } - .intern(db) - .into(), - &it.name, - vis, - false, - ); - } - ModItem::Trait(id) => { - let it = &self.item_tree[id]; - - let vis = resolve_vis(def_map, &self.item_tree[it.visibility]); - update_def( - self.def_collector, - TraitLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } - .intern(db) - .into(), - &it.name, - vis, - false, - ); - } - ModItem::TypeAlias(id) => { - let it = &self.item_tree[id]; - - let vis = resolve_vis(def_map, &self.item_tree[it.visibility]); - update_def( - self.def_collector, - TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) } - .intern(db) - .into(), - &it.name, - vis, - false, - ); - } - } - } - } - - fn collect_module(&mut self, module_id: FileItemTreeId, attrs: &Attrs) { - let path_attr = attrs.by_key("path").string_value(); - let is_macro_use = attrs.by_key("macro_use").exists(); - let module = &self.item_tree[module_id]; - match &module.kind { - // inline module, just recurse - ModKind::Inline { items } => { - let module_id = self.push_child_module( - module.name.clone(), - AstId::new(self.file_id(), module.ast_id), - None, - &self.item_tree[module.visibility], - module_id, - ); - - if let Some(mod_dir) = self.mod_dir.descend_into_definition(&module.name, path_attr) - { - ModCollector { - def_collector: &mut *self.def_collector, - macro_depth: self.macro_depth, - module_id, - tree_id: self.tree_id, - item_tree: self.item_tree, - mod_dir, - } - .collect_in_top_module(&*items); - if is_macro_use { - self.import_all_legacy_macros(module_id); - } - } - } - // out of line module, resolve, parse and recurse - ModKind::Outline => { - let ast_id = AstId::new(self.tree_id.file_id(), module.ast_id); - let db = self.def_collector.db; - match self.mod_dir.resolve_declaration(db, self.file_id(), &module.name, path_attr) - { - Ok((file_id, is_mod_rs, mod_dir)) => { - let item_tree = db.file_item_tree(file_id.into()); - let krate = self.def_collector.def_map.krate; - let is_enabled = item_tree - .top_level_attrs(db, krate) - .cfg() - .map_or(true, |cfg| self.is_cfg_enabled(&cfg)); - if is_enabled { - let module_id = self.push_child_module( - module.name.clone(), - ast_id, - Some((file_id, is_mod_rs)), - &self.item_tree[module.visibility], - module_id, - ); - ModCollector { - def_collector: self.def_collector, - macro_depth: self.macro_depth, - module_id, - tree_id: TreeId::new(file_id.into(), None), - item_tree: &item_tree, - mod_dir, - } - .collect_in_top_module(item_tree.top_level_items()); - let is_macro_use = is_macro_use - || item_tree - .top_level_attrs(db, krate) - .by_key("macro_use") - .exists(); - if is_macro_use { - self.import_all_legacy_macros(module_id); - } - } - } - Err(candidates) => { - self.push_child_module( - module.name.clone(), - ast_id, - None, - &self.item_tree[module.visibility], - module_id, - ); - self.def_collector.def_map.diagnostics.push( - DefDiagnostic::unresolved_module(self.module_id, ast_id, candidates), - ); - } - }; - } - } - } - - fn push_child_module( - &mut self, - name: Name, - declaration: AstId, - definition: Option<(FileId, bool)>, - visibility: &crate::visibility::RawVisibility, - mod_tree_id: FileItemTreeId, - ) -> LocalModuleId { - let def_map = &mut self.def_collector.def_map; - let vis = def_map - .resolve_visibility(self.def_collector.db, self.module_id, visibility) - .unwrap_or(Visibility::Public); - let modules = &mut def_map.modules; - let origin = match definition { - None => ModuleOrigin::Inline { - definition: declaration, - definition_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id), - }, - Some((definition, is_mod_rs)) => ModuleOrigin::File { - declaration, - definition, - is_mod_rs, - declaration_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id), - }, - }; - - let res = modules.alloc(ModuleData::new(origin, vis)); - modules[res].parent = Some(self.module_id); - for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() { - for &mac in &mac { - modules[res].scope.define_legacy_macro(name.clone(), mac); - } - } - modules[self.module_id].children.insert(name.clone(), res); - - let module = def_map.module_id(res); - let def = ModuleDefId::from(module); - - def_map.modules[self.module_id].scope.declare(def); - self.def_collector.update( - self.module_id, - &[(Some(name), PerNs::from_def(def, vis, false))], - vis, - ImportType::Named, - ); - res - } - - /// Resolves attributes on an item. - /// - /// Returns `Err` when some attributes could not be resolved to builtins and have been - /// registered as unresolved. - /// - /// If `ignore_up_to` is `Some`, attributes preceding and including that attribute will be - /// assumed to be resolved already. - fn resolve_attributes( - &mut self, - attrs: &Attrs, - mod_item: ModItem, - container: ItemContainerId, - ) -> Result<(), ()> { - let mut ignore_up_to = - self.def_collector.skip_attrs.get(&InFile::new(self.file_id(), mod_item)).copied(); - let iter = attrs - .iter() - .dedup_by(|a, b| { - // FIXME: this should not be required, all attributes on an item should have a - // unique ID! - // Still, this occurs because `#[cfg_attr]` can "expand" to multiple attributes: - // #[cfg_attr(not(off), unresolved, unresolved)] - // struct S; - // We should come up with a different way to ID attributes. - a.id == b.id - }) - .skip_while(|attr| match ignore_up_to { - Some(id) if attr.id == id => { - ignore_up_to = None; - true - } - Some(_) => true, - None => false, - }); - - for attr in iter { - if self.def_collector.def_map.is_builtin_or_registered_attr(&attr.path) { - continue; - } - tracing::debug!("non-builtin attribute {}", attr.path); - - let ast_id = AstIdWithPath::new( - self.file_id(), - mod_item.ast_id(self.item_tree), - attr.path.as_ref().clone(), - ); - self.def_collector.unresolved_macros.push(MacroDirective { - module_id: self.module_id, - depth: self.macro_depth + 1, - kind: MacroDirectiveKind::Attr { - ast_id, - attr: attr.clone(), - mod_item, - tree: self.tree_id, - }, - container, - }); - - return Err(()); - } - - Ok(()) - } - - fn collect_macro_rules(&mut self, id: FileItemTreeId, module: ModuleId) { - let krate = self.def_collector.def_map.krate; - let mac = &self.item_tree[id]; - let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); - let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast()); - - let export_attr = attrs.by_key("macro_export"); - - let is_export = export_attr.exists(); - let local_inner = if is_export { - export_attr.tt_values().flat_map(|it| &it.token_trees).any(|it| match it { - tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { - ident.text.contains("local_inner_macros") - } - _ => false, - }) - } else { - false - }; - - // Case 1: builtin macros - let expander = if attrs.by_key("rustc_builtin_macro").exists() { - // `#[rustc_builtin_macro = "builtin_name"]` overrides the `macro_rules!` name. - 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.clone(), id: tt::TokenId::unspecified() }.as_name(); - &name - } - None => { - let explicit_name = - attrs.by_key("rustc_builtin_macro").tt_values().next().and_then(|tt| { - match tt.token_trees.first() { - Some(tt::TokenTree::Leaf(tt::Leaf::Ident(name))) => Some(name), - _ => None, - } - }); - match explicit_name { - Some(ident) => { - name = ident.as_name(); - &name - } - None => &mac.name, - } - } - }; - match find_builtin_macro(name) { - Some(Either::Left(it)) => MacroExpander::BuiltIn(it), - Some(Either::Right(it)) => MacroExpander::BuiltInEager(it), - None => { - self.def_collector - .def_map - .diagnostics - .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id)); - return; - } - } - } else { - // Case 2: normal `macro_rules!` macro - MacroExpander::Declarative - }; - - let macro_id = MacroRulesLoc { - container: module, - id: ItemTreeId::new(self.tree_id, id), - local_inner, - expander, - } - .intern(self.def_collector.db); - self.def_collector.define_macro_rules( - self.module_id, - mac.name.clone(), - macro_id, - is_export, - ); - } - - fn collect_macro_def(&mut self, id: FileItemTreeId, module: ModuleId) { - let krate = self.def_collector.def_map.krate; - let mac = &self.item_tree[id]; - let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast()); - - // Case 1: builtin macros - let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); - let expander = if attrs.by_key("rustc_builtin_macro").exists() { - if let Some(expander) = find_builtin_macro(&mac.name) { - match expander { - Either::Left(it) => MacroExpander::BuiltIn(it), - Either::Right(it) => MacroExpander::BuiltInEager(it), - } - } else if let Some(expander) = find_builtin_derive(&mac.name) { - MacroExpander::BuiltInDerive(expander) - } else if let Some(expander) = find_builtin_attr(&mac.name) { - MacroExpander::BuiltInAttr(expander) - } else { - self.def_collector - .def_map - .diagnostics - .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id)); - return; - } - } else { - // Case 2: normal `macro` - MacroExpander::Declarative - }; - - let macro_id = - Macro2Loc { container: module, id: ItemTreeId::new(self.tree_id, id), expander } - .intern(self.def_collector.db); - self.def_collector.define_macro_def( - self.module_id, - mac.name.clone(), - macro_id, - &self.item_tree[mac.visibility], - ); - } - - fn collect_macro_call(&mut self, mac: &MacroCall, container: ItemContainerId) { - let ast_id = AstIdWithPath::new(self.file_id(), mac.ast_id, ModPath::clone(&mac.path)); - - // Case 1: try to resolve in legacy scope and expand macro_rules - let mut error = None; - match macro_call_as_call_id( - self.def_collector.db, - &ast_id, - mac.expand_to, - self.def_collector.def_map.krate, - |path| { - path.as_ident().and_then(|name| { - self.def_collector.def_map.with_ancestor_maps( - self.def_collector.db, - self.module_id, - &mut |map, module| { - map[module] - .scope - .get_legacy_macro(name) - .and_then(|it| it.last()) - .map(|&it| macro_id_to_def_id(self.def_collector.db, it.into())) - }, - ) - }) - }, - &mut |err| { - error.get_or_insert(err); - }, - ) { - Ok(Ok(macro_call_id)) => { - // Legacy macros need to be expanded immediately, so that any macros they produce - // are in scope. - self.def_collector.collect_macro_expansion( - self.module_id, - macro_call_id, - self.macro_depth + 1, - container, - ); - - if let Some(err) = error { - self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error( - self.module_id, - MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: mac.expand_to }, - err.to_string(), - )); - } - - return; - } - Ok(Err(_)) => { - // Built-in macro failed eager expansion. - - self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error( - self.module_id, - MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: mac.expand_to }, - error.unwrap().to_string(), - )); - return; - } - Err(UnresolvedMacro { .. }) => (), - } - - // Case 2: resolve in module scope, expand during name resolution. - self.def_collector.unresolved_macros.push(MacroDirective { - module_id: self.module_id, - depth: self.macro_depth + 1, - kind: MacroDirectiveKind::FnLike { ast_id, expand_to: mac.expand_to }, - container, - }); - } - - fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) { - let macros = self.def_collector.def_map[module_id].scope.collect_legacy_macros(); - for (name, macs) in macros { - macs.last().map(|&mac| { - self.def_collector.define_legacy_macro(self.module_id, name.clone(), mac) - }); - } - } - - fn is_cfg_enabled(&self, cfg: &CfgExpr) -> bool { - self.def_collector.cfg_options.check(cfg) != Some(false) - } - - fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) { - let ast_id = item.ast_id(self.item_tree); - - let ast_id = InFile::new(self.file_id(), ast_id); - self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code( - self.module_id, - ast_id, - cfg.clone(), - self.def_collector.cfg_options.clone(), - )); - } - - fn file_id(&self) -> HirFileId { - self.tree_id.file_id() - } -} - -#[cfg(test)] -mod tests { - use crate::{db::DefDatabase, test_db::TestDB}; - use base_db::{fixture::WithFixture, SourceDatabase}; - - use super::*; - - fn do_collect_defs(db: &dyn DefDatabase, def_map: DefMap) -> DefMap { - let mut collector = DefCollector { - db, - def_map, - deps: FxHashMap::default(), - glob_imports: FxHashMap::default(), - unresolved_imports: Vec::new(), - indeterminate_imports: Vec::new(), - unresolved_macros: Vec::new(), - mod_dirs: FxHashMap::default(), - cfg_options: &CfgOptions::default(), - proc_macros: Default::default(), - from_glob_import: Default::default(), - skip_attrs: Default::default(), - is_proc_macro: false, - }; - collector.seed_with_top_level(); - collector.collect(); - collector.def_map - } - - fn do_resolve(not_ra_fixture: &str) -> DefMap { - let (db, file_id) = TestDB::with_single_file(not_ra_fixture); - let krate = db.test_crate(); - - let edition = db.crate_graph()[krate].edition; - let module_origin = ModuleOrigin::CrateRoot { definition: file_id }; - let def_map = - DefMap::empty(krate, edition, ModuleData::new(module_origin, Visibility::Public)); - do_collect_defs(&db, def_map) - } - - #[test] - fn test_macro_expand_will_stop_1() { - do_resolve( - r#" -macro_rules! foo { - ($($ty:ty)*) => { foo!($($ty)*); } -} -foo!(KABOOM); -"#, - ); - do_resolve( - r#" -macro_rules! foo { - ($($ty:ty)*) => { foo!(() $($ty)*); } -} -foo!(KABOOM); -"#, - ); - } - - #[ignore] - #[test] - fn test_macro_expand_will_stop_2() { - // FIXME: this test does succeed, but takes quite a while: 90 seconds in - // the release mode. That's why the argument is not an ra_fixture -- - // otherwise injection highlighting gets stuck. - // - // We need to find a way to fail this faster. - do_resolve( - r#" -macro_rules! foo { - ($($ty:ty)*) => { foo!($($ty)* $($ty)*); } -} -foo!(KABOOM); -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs deleted file mode 100644 index 0d01f6d0aba34..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs +++ /dev/null @@ -1,137 +0,0 @@ -//! Diagnostics emitted during DefMap construction. - -use base_db::CrateId; -use cfg::{CfgExpr, CfgOptions}; -use hir_expand::MacroCallKind; -use la_arena::Idx; -use syntax::ast; - -use crate::{ - attr::AttrId, - item_tree::{self, ItemTreeId}, - nameres::LocalModuleId, - path::ModPath, - AstId, -}; - -#[derive(Debug, PartialEq, Eq)] -pub enum DefDiagnosticKind { - UnresolvedModule { ast: AstId, candidates: Box<[String]> }, - - UnresolvedExternCrate { ast: AstId }, - - UnresolvedImport { id: ItemTreeId, index: Idx }, - - UnconfiguredCode { ast: AstId, cfg: CfgExpr, opts: CfgOptions }, - - UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId }, - - UnresolvedMacroCall { ast: MacroCallKind, path: ModPath }, - - MacroError { ast: MacroCallKind, message: String }, - - UnimplementedBuiltinMacro { ast: AstId }, - - InvalidDeriveTarget { ast: AstId, id: u32 }, - - MalformedDerive { ast: AstId, id: u32 }, -} - -#[derive(Debug, PartialEq, Eq)] -pub struct DefDiagnostic { - pub in_module: LocalModuleId, - pub kind: DefDiagnosticKind, -} - -impl DefDiagnostic { - pub(super) fn unresolved_module( - container: LocalModuleId, - declaration: AstId, - candidates: Box<[String]>, - ) -> Self { - Self { - in_module: container, - kind: DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates }, - } - } - - pub(super) fn unresolved_extern_crate( - container: LocalModuleId, - declaration: AstId, - ) -> Self { - Self { - in_module: container, - kind: DefDiagnosticKind::UnresolvedExternCrate { ast: declaration }, - } - } - - pub(super) fn unresolved_import( - container: LocalModuleId, - id: ItemTreeId, - index: Idx, - ) -> Self { - Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } } - } - - pub(super) fn unconfigured_code( - container: LocalModuleId, - ast: AstId, - cfg: CfgExpr, - opts: CfgOptions, - ) -> Self { - Self { in_module: container, kind: DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } } - } - - pub(super) fn unresolved_proc_macro( - container: LocalModuleId, - ast: MacroCallKind, - krate: CrateId, - ) -> Self { - Self { in_module: container, kind: DefDiagnosticKind::UnresolvedProcMacro { ast, krate } } - } - - pub(super) fn macro_error( - container: LocalModuleId, - ast: MacroCallKind, - message: String, - ) -> Self { - Self { in_module: container, kind: DefDiagnosticKind::MacroError { ast, message } } - } - - pub(super) fn unresolved_macro_call( - container: LocalModuleId, - ast: MacroCallKind, - path: ModPath, - ) -> Self { - Self { in_module: container, kind: DefDiagnosticKind::UnresolvedMacroCall { ast, path } } - } - - pub(super) fn unimplemented_builtin_macro( - container: LocalModuleId, - ast: AstId, - ) -> Self { - Self { in_module: container, kind: DefDiagnosticKind::UnimplementedBuiltinMacro { ast } } - } - - pub(super) fn invalid_derive_target( - container: LocalModuleId, - ast: AstId, - id: AttrId, - ) -> Self { - Self { - in_module: container, - kind: DefDiagnosticKind::InvalidDeriveTarget { ast, id: id.ast_index }, - } - } - - pub(super) fn malformed_derive( - container: LocalModuleId, - ast: AstId, - id: AttrId, - ) -> Self { - Self { - in_module: container, - kind: DefDiagnosticKind::MalformedDerive { ast, id: id.ast_index }, - } - } -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs deleted file mode 100644 index 52a620fe22f6e..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs +++ /dev/null @@ -1,161 +0,0 @@ -//! This module resolves `mod foo;` declaration to file. -use arrayvec::ArrayVec; -use base_db::{AnchoredPath, FileId}; -use hir_expand::name::Name; -use limit::Limit; -use syntax::SmolStr; - -use crate::{db::DefDatabase, HirFileId}; - -const MOD_DEPTH_LIMIT: Limit = Limit::new(32); - -#[derive(Clone, Debug)] -pub(super) struct ModDir { - /// `` for `mod.rs`, `lib.rs` - /// `foo/` for `foo.rs` - /// `foo/bar/` for `mod bar { mod x; }` nested in `foo.rs` - /// Invariant: path.is_empty() || path.ends_with('/') - dir_path: DirPath, - /// inside `./foo.rs`, mods with `#[path]` should *not* be relative to `./foo/` - root_non_dir_owner: bool, - depth: u32, -} - -impl ModDir { - pub(super) fn root() -> ModDir { - ModDir { dir_path: DirPath::empty(), root_non_dir_owner: false, depth: 0 } - } - - pub(super) fn descend_into_definition( - &self, - name: &Name, - attr_path: Option<&SmolStr>, - ) -> Option { - let path = match attr_path.map(SmolStr::as_str) { - None => { - let mut path = self.dir_path.clone(); - path.push(&name.to_smol_str()); - path - } - Some(attr_path) => { - let mut path = self.dir_path.join_attr(attr_path, self.root_non_dir_owner); - if !(path.is_empty() || path.ends_with('/')) { - path.push('/') - } - DirPath::new(path) - } - }; - self.child(path, false) - } - - fn child(&self, dir_path: DirPath, root_non_dir_owner: bool) -> Option { - let depth = self.depth + 1; - if MOD_DEPTH_LIMIT.check(depth as usize).is_err() { - tracing::error!("MOD_DEPTH_LIMIT exceeded"); - cov_mark::hit!(circular_mods); - return None; - } - Some(ModDir { dir_path, root_non_dir_owner, depth }) - } - - pub(super) fn resolve_declaration( - &self, - db: &dyn DefDatabase, - file_id: HirFileId, - name: &Name, - attr_path: Option<&SmolStr>, - ) -> Result<(FileId, bool, ModDir), Box<[String]>> { - let orig_file_id = file_id.original_file(db.upcast()); - - let mut candidate_files = ArrayVec::<_, 2>::new(); - match attr_path { - Some(attr_path) => { - candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner)) - } - None if file_id.is_include_macro(db.upcast()) => { - candidate_files.push(format!("{}.rs", name)); - candidate_files.push(format!("{}/mod.rs", name)); - } - None => { - candidate_files.push(format!("{}{}.rs", self.dir_path.0, name)); - candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name)); - } - }; - - for candidate in candidate_files.iter() { - let path = AnchoredPath { anchor: orig_file_id, path: candidate.as_str() }; - if let Some(file_id) = db.resolve_path(path) { - let is_mod_rs = candidate.ends_with("/mod.rs"); - - let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() { - (DirPath::empty(), false) - } else { - (DirPath::new(format!("{}/", name)), true) - }; - if let Some(mod_dir) = self.child(dir_path, root_non_dir_owner) { - return Ok((file_id, is_mod_rs, mod_dir)); - } - } - } - Err(candidate_files.into_iter().collect()) - } -} - -#[derive(Clone, Debug)] -struct DirPath(String); - -impl DirPath { - fn assert_invariant(&self) { - assert!(self.0.is_empty() || self.0.ends_with('/')); - } - fn new(repr: String) -> DirPath { - let res = DirPath(repr); - res.assert_invariant(); - res - } - fn empty() -> DirPath { - DirPath::new(String::new()) - } - fn push(&mut self, name: &str) { - self.0.push_str(name); - self.0.push('/'); - self.assert_invariant(); - } - fn parent(&self) -> Option<&str> { - if self.0.is_empty() { - return None; - }; - let idx = - self.0[..self.0.len() - '/'.len_utf8()].rfind('/').map_or(0, |it| it + '/'.len_utf8()); - Some(&self.0[..idx]) - } - /// So this is the case which doesn't really work I think if we try to be - /// 100% platform agnostic: - /// - /// ``` - /// mod a { - /// #[path="C://sad/face"] - /// mod b { mod c; } - /// } - /// ``` - /// - /// Here, we need to join logical dir path to a string path from an - /// attribute. Ideally, we should somehow losslessly communicate the whole - /// construction to `FileLoader`. - fn join_attr(&self, mut attr: &str, relative_to_parent: bool) -> String { - let base = if relative_to_parent { self.parent().unwrap() } else { &self.0 }; - - if attr.starts_with("./") { - attr = &attr["./".len()..]; - } - let tmp; - let attr = if attr.contains('\\') { - tmp = attr.replace('\\', "/"); - &tmp - } else { - attr - }; - let res = format!("{}{}", base, attr); - res - } -} 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 deleted file mode 100644 index c579bc9194c30..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs +++ /dev/null @@ -1,448 +0,0 @@ -//! This modules implements a function to resolve a path `foo::bar::baz` to a -//! def, which is used within the name resolution. -//! -//! When name resolution is finished, the result of resolving a path is either -//! `Some(def)` or `None`. However, when we are in process of resolving imports -//! or macros, there's a third possibility: -//! -//! I can't resolve this path right now, but I might be resolve this path -//! later, when more macros are expanded. -//! -//! `ReachedFixedPoint` signals about this. - -use base_db::Edition; -use hir_expand::name::Name; - -use crate::{ - db::DefDatabase, - item_scope::BUILTIN_SCOPE, - nameres::{BuiltinShadowMode, DefMap}, - path::{ModPath, PathKind}, - per_ns::PerNs, - visibility::{RawVisibility, Visibility}, - AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, -}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(super) enum ResolveMode { - Import, - Other, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(super) enum ReachedFixedPoint { - Yes, - No, -} - -#[derive(Debug, Clone)] -pub(super) struct ResolvePathResult { - pub(super) resolved_def: PerNs, - pub(super) segment_index: Option, - pub(super) reached_fixedpoint: ReachedFixedPoint, - pub(super) krate: Option, -} - -impl ResolvePathResult { - fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { - ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None, None) - } - - fn with( - resolved_def: PerNs, - reached_fixedpoint: ReachedFixedPoint, - segment_index: Option, - krate: Option, - ) -> ResolvePathResult { - ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, krate } - } -} - -impl DefMap { - pub(super) fn resolve_name_in_extern_prelude( - &self, - db: &dyn DefDatabase, - name: &Name, - ) -> Option { - match self.block { - Some(_) => self.crate_root(db).def_map(db).extern_prelude.get(name).copied(), - None => self.extern_prelude.get(name).copied(), - } - } - - pub(crate) fn resolve_visibility( - &self, - db: &dyn DefDatabase, - original_module: LocalModuleId, - visibility: &RawVisibility, - ) -> Option { - let mut vis = match visibility { - RawVisibility::Module(path) => { - let (result, remaining) = - self.resolve_path(db, original_module, path, BuiltinShadowMode::Module); - if remaining.is_some() { - return None; - } - let types = result.take_types()?; - match types { - ModuleDefId::ModuleId(m) => Visibility::Module(m), - _ => { - // error: visibility needs to refer to module - return None; - } - } - } - RawVisibility::Public => Visibility::Public, - }; - - // In block expressions, `self` normally refers to the containing non-block module, and - // `super` to its parent (etc.). However, visibilities must only refer to a module in the - // DefMap they're written in, so we restrict them when that happens. - if let Visibility::Module(m) = vis { - if self.block_id() != m.block { - cov_mark::hit!(adjust_vis_in_block_def_map); - vis = Visibility::Module(self.module_id(self.root())); - tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis); - } - } - - Some(vis) - } - - // Returns Yes if we are sure that additions to `ItemMap` wouldn't change - // the result. - pub(super) fn resolve_path_fp_with_macro( - &self, - db: &dyn DefDatabase, - mode: ResolveMode, - mut original_module: LocalModuleId, - path: &ModPath, - shadow: BuiltinShadowMode, - ) -> ResolvePathResult { - let mut result = ResolvePathResult::empty(ReachedFixedPoint::No); - - let mut arc; - let mut current_map = self; - loop { - let new = current_map.resolve_path_fp_with_macro_single( - db, - mode, - original_module, - path, - shadow, - ); - - // Merge `new` into `result`. - result.resolved_def = result.resolved_def.or(new.resolved_def); - if result.reached_fixedpoint == ReachedFixedPoint::No { - result.reached_fixedpoint = new.reached_fixedpoint; - } - // FIXME: this doesn't seem right; what if the different namespace resolutions come from different crates? - result.krate = result.krate.or(new.krate); - result.segment_index = match (result.segment_index, new.segment_index) { - (Some(idx), None) => Some(idx), - (Some(old), Some(new)) => Some(old.max(new)), - (None, new) => new, - }; - - match ¤t_map.block { - Some(block) => { - original_module = block.parent.local_id; - arc = block.parent.def_map(db); - current_map = &*arc; - } - None => return result, - } - } - } - - pub(super) fn resolve_path_fp_with_macro_single( - &self, - db: &dyn DefDatabase, - mode: ResolveMode, - original_module: LocalModuleId, - path: &ModPath, - shadow: BuiltinShadowMode, - ) -> ResolvePathResult { - let graph = db.crate_graph(); - let _cx = stdx::panic_context::enter(format!( - "DefMap {:?} crate_name={:?} block={:?} path={}", - self.krate, graph[self.krate].display_name, self.block, path - )); - - let mut segments = path.segments().iter().enumerate(); - let mut curr_per_ns: PerNs = match path.kind { - PathKind::DollarCrate(krate) => { - if krate == self.krate { - cov_mark::hit!(macro_dollar_crate_self); - PerNs::types(self.crate_root(db).into(), Visibility::Public) - } else { - let def_map = db.crate_def_map(krate); - let module = def_map.module_id(def_map.root); - cov_mark::hit!(macro_dollar_crate_other); - PerNs::types(module.into(), Visibility::Public) - } - } - PathKind::Crate => PerNs::types(self.crate_root(db).into(), Visibility::Public), - // plain import or absolute path in 2015: crate-relative with - // fallback to extern prelude (with the simplification in - // rust-lang/rust#57745) - // FIXME there must be a nicer way to write this condition - PathKind::Plain | PathKind::Abs - if self.edition == Edition::Edition2015 - && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => - { - let (_, segment) = match segments.next() { - Some((idx, segment)) => (idx, segment), - None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), - }; - tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment); - self.resolve_name_in_crate_root_or_extern_prelude(db, segment) - } - PathKind::Plain => { - let (_, segment) = match segments.next() { - Some((idx, segment)) => (idx, segment), - None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), - }; - // The first segment may be a builtin type. If the path has more - // than one segment, we first try resolving it as a module - // anyway. - // FIXME: If the next segment doesn't resolve in the module and - // BuiltinShadowMode wasn't Module, then we need to try - // resolving it as a builtin. - let prefer_module = - if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module }; - - tracing::debug!("resolving {:?} in module", segment); - self.resolve_name_in_module(db, original_module, segment, prefer_module) - } - PathKind::Super(lvl) => { - let mut module = original_module; - for i in 0..lvl { - match self.modules[module].parent { - Some(it) => module = it, - None => match &self.block { - Some(block) => { - // Look up remaining path in parent `DefMap` - let new_path = ModPath::from_segments( - PathKind::Super(lvl - i), - path.segments().to_vec(), - ); - tracing::debug!( - "`super` path: {} -> {} in parent map", - path, - new_path - ); - return block.parent.def_map(db).resolve_path_fp_with_macro( - db, - mode, - block.parent.local_id, - &new_path, - shadow, - ); - } - None => { - tracing::debug!("super path in root module"); - return ResolvePathResult::empty(ReachedFixedPoint::Yes); - } - }, - } - } - - // Resolve `self` to the containing crate-rooted module if we're a block - self.with_ancestor_maps(db, module, &mut |def_map, module| { - if def_map.block.is_some() { - None // keep ascending - } else { - Some(PerNs::types(def_map.module_id(module).into(), Visibility::Public)) - } - }) - .expect("block DefMap not rooted in crate DefMap") - } - PathKind::Abs => { - // 2018-style absolute path -- only extern prelude - let segment = match segments.next() { - Some((_, segment)) => segment, - None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), - }; - if let Some(&def) = self.extern_prelude.get(segment) { - tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def); - PerNs::types(def.into(), Visibility::Public) - } else { - return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude - } - } - }; - - for (i, segment) in segments { - let (curr, vis) = match curr_per_ns.take_types_vis() { - Some(r) => r, - None => { - // we still have path segments left, but the path so far - // didn't resolve in the types namespace => no resolution - // (don't break here because `curr_per_ns` might contain - // something in the value namespace, and it would be wrong - // to return that) - return ResolvePathResult::empty(ReachedFixedPoint::No); - } - }; - // resolve segment in curr - - curr_per_ns = match curr { - ModuleDefId::ModuleId(module) => { - if module.krate != self.krate { - let path = ModPath::from_segments( - PathKind::Super(0), - path.segments()[i..].iter().cloned(), - ); - tracing::debug!("resolving {:?} in other crate", path); - let defp_map = module.def_map(db); - let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow); - return ResolvePathResult::with( - def, - ReachedFixedPoint::Yes, - s.map(|s| s + i), - Some(module.krate), - ); - } - - let def_map; - let module_data = if module.block == self.block_id() { - &self[module.local_id] - } else { - def_map = module.def_map(db); - &def_map[module.local_id] - }; - - // Since it is a qualified path here, it should not contains legacy macros - module_data.scope.get(segment) - } - ModuleDefId::AdtId(AdtId::EnumId(e)) => { - // enum variant - cov_mark::hit!(can_import_enum_variant); - let enum_data = db.enum_data(e); - match enum_data.variant(segment) { - Some(local_id) => { - let variant = EnumVariantId { parent: e, local_id }; - match &*enum_data.variants[local_id].variant_data { - crate::adt::VariantData::Record(_) => { - PerNs::types(variant.into(), Visibility::Public) - } - crate::adt::VariantData::Tuple(_) - | crate::adt::VariantData::Unit => { - PerNs::both(variant.into(), variant.into(), Visibility::Public) - } - } - } - None => { - return ResolvePathResult::with( - PerNs::types(e.into(), vis), - ReachedFixedPoint::Yes, - Some(i), - Some(self.krate), - ); - } - } - } - s => { - // could be an inherent method call in UFCS form - // (`Struct::method`), or some other kind of associated item - tracing::debug!( - "path segment {:?} resolved to non-module {:?}, but is not last", - segment, - curr, - ); - - return ResolvePathResult::with( - PerNs::types(s, vis), - ReachedFixedPoint::Yes, - Some(i), - Some(self.krate), - ); - } - }; - } - - ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate)) - } - - fn resolve_name_in_module( - &self, - db: &dyn DefDatabase, - module: LocalModuleId, - name: &Name, - shadow: BuiltinShadowMode, - ) -> PerNs { - // Resolve in: - // - legacy scope of macro - // - current module / scope - // - extern prelude - // - std prelude - let from_legacy_macro = self[module] - .scope - .get_legacy_macro(name) - // FIXME: shadowing - .and_then(|it| it.last()) - .map_or_else(PerNs::none, |&m| PerNs::macros(m.into(), Visibility::Public)); - let from_scope = self[module].scope.get(name); - let from_builtin = match self.block { - Some(_) => { - // Only resolve to builtins in the root `DefMap`. - PerNs::none() - } - None => BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none), - }; - let from_scope_or_builtin = match shadow { - BuiltinShadowMode::Module => from_scope.or(from_builtin), - BuiltinShadowMode::Other => match from_scope.take_types() { - Some(ModuleDefId::ModuleId(_)) => from_builtin.or(from_scope), - Some(_) | None => from_scope.or(from_builtin), - }, - }; - let from_extern_prelude = self - .extern_prelude - .get(name) - .map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public)); - - let from_prelude = self.resolve_in_prelude(db, name); - - from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude) - } - - fn resolve_name_in_crate_root_or_extern_prelude( - &self, - db: &dyn DefDatabase, - name: &Name, - ) -> PerNs { - let arc; - let crate_def_map = match self.block { - Some(_) => { - arc = self.crate_root(db).def_map(db); - &arc - } - None => self, - }; - let from_crate_root = crate_def_map[crate_def_map.root].scope.get(name); - let from_extern_prelude = self - .resolve_name_in_extern_prelude(db, name) - .map_or(PerNs::none(), |it| PerNs::types(it.into(), Visibility::Public)); - - from_crate_root.or(from_extern_prelude) - } - - fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs { - if let Some(prelude) = self.prelude { - let keep; - let def_map = if prelude.krate == self.krate { - self - } else { - // Extend lifetime - keep = prelude.def_map(db); - &keep - }; - def_map[prelude.local_id].scope.get(name) - } else { - PerNs::none() - } - } -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs deleted file mode 100644 index 5089ef2d81717..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! Nameres-specific procedural macro data and helpers. - -use hir_expand::name::{AsName, Name}; -use tt::{Leaf, TokenTree}; - -use crate::attr::Attrs; - -#[derive(Debug, PartialEq, Eq)] -pub struct ProcMacroDef { - pub name: Name, - pub kind: ProcMacroKind, -} - -#[derive(Debug, PartialEq, Eq)] -pub enum ProcMacroKind { - CustomDerive { helpers: Box<[Name]> }, - FnLike, - Attr, -} - -impl ProcMacroKind { - pub(super) fn to_basedb_kind(&self) -> base_db::ProcMacroKind { - match self { - ProcMacroKind::CustomDerive { .. } => base_db::ProcMacroKind::CustomDerive, - ProcMacroKind::FnLike => base_db::ProcMacroKind::FuncLike, - ProcMacroKind::Attr => base_db::ProcMacroKind::Attr, - } - } -} - -impl Attrs { - #[rustfmt::skip] - pub fn parse_proc_macro_decl(&self, func_name: &Name) -> Option { - if self.is_proc_macro() { - Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::FnLike }) - } else if self.is_proc_macro_attribute() { - Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Attr }) - } else if self.by_key("proc_macro_derive").exists() { - let derive = self.by_key("proc_macro_derive").tt_values().next()?; - - match &*derive.token_trees { - // `#[proc_macro_derive(Trait)]` - [TokenTree::Leaf(Leaf::Ident(trait_name))] => Some(ProcMacroDef { - name: trait_name.as_name(), - kind: ProcMacroKind::CustomDerive { helpers: Box::new([]) }, - }), - - // `#[proc_macro_derive(Trait, attibutes(helper1, helper2, ...))]` - [ - TokenTree::Leaf(Leaf::Ident(trait_name)), - TokenTree::Leaf(Leaf::Punct(comma)), - TokenTree::Leaf(Leaf::Ident(attributes)), - TokenTree::Subtree(helpers) - ] if comma.char == ',' && attributes.text == "attributes" => - { - let helpers = helpers.token_trees.iter() - .filter(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Punct(comma)) if comma.char == ',')) - .map(|tt| { - match tt { - TokenTree::Leaf(Leaf::Ident(helper)) => Some(helper.as_name()), - _ => None - } - }) - .collect::>>()?; - - Some(ProcMacroDef { - name: trait_name.as_name(), - kind: ProcMacroKind::CustomDerive { helpers }, - }) - } - - _ => { - tracing::trace!("malformed `#[proc_macro_derive]`: {}", derive); - None - } - } - } else { - None - } - } -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs deleted file mode 100644 index 70dd2eb3ade69..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs +++ /dev/null @@ -1,933 +0,0 @@ -mod globs; -mod incremental; -mod macros; -mod mod_resolution; -mod primitives; - -use std::sync::Arc; - -use base_db::{fixture::WithFixture, SourceDatabase}; -use expect_test::{expect, Expect}; - -use crate::{db::DefDatabase, test_db::TestDB}; - -use super::DefMap; - -fn compute_crate_def_map(ra_fixture: &str) -> Arc { - let db = TestDB::with_files(ra_fixture); - let krate = db.crate_graph().iter().next().unwrap(); - db.crate_def_map(krate) -} - -fn render_crate_def_map(ra_fixture: &str) -> String { - let db = TestDB::with_files(ra_fixture); - let krate = db.crate_graph().iter().next().unwrap(); - db.crate_def_map(krate).dump(&db) -} - -fn check(ra_fixture: &str, expect: Expect) { - let actual = render_crate_def_map(ra_fixture); - expect.assert_eq(&actual); -} - -#[test] -fn crate_def_map_smoke_test() { - check( - r#" -//- /lib.rs -mod foo; -struct S; -use crate::foo::bar::E; -use self::E::V; - -//- /foo/mod.rs -pub mod bar; -fn f() {} - -//- /foo/bar.rs -pub struct Baz; - -union U { to_be: bool, not_to_be: u8 } -enum E { V } - -extern { - type Ext; - static EXT: u8; - fn ext(); -} -"#, - expect![[r#" - crate - E: t - S: t v - V: t v - foo: t - - crate::foo - bar: t - f: v - - crate::foo::bar - Baz: t v - E: t - EXT: v - Ext: t - U: t - ext: v - "#]], - ); -} - -#[test] -fn crate_def_map_super_super() { - check( - r#" -mod a { - const A: usize = 0; - mod b { - const B: usize = 0; - mod c { - use super::super::*; - } - } -} -"#, - expect![[r#" - crate - a: t - - crate::a - A: v - b: t - - crate::a::b - B: v - c: t - - crate::a::b::c - A: v - b: t - "#]], - ); -} - -#[test] -fn crate_def_map_fn_mod_same_name() { - check( - r#" -mod m { - pub mod z {} - pub fn z() {} -} -"#, - expect![[r#" - crate - m: t - - crate::m - z: t v - - crate::m::z - "#]], - ); -} - -#[test] -fn bogus_paths() { - cov_mark::check!(bogus_paths); - check( - r#" -//- /lib.rs -mod foo; -struct S; -use self; - -//- /foo/mod.rs -use super; -use crate; -"#, - expect![[r#" - crate - S: t v - foo: t - - crate::foo - "#]], - ); -} - -#[test] -fn use_as() { - check( - r#" -//- /lib.rs -mod foo; -use crate::foo::Baz as Foo; - -//- /foo/mod.rs -pub struct Baz; -"#, - expect![[r#" - crate - Foo: t v - foo: t - - crate::foo - Baz: t v - "#]], - ); -} - -#[test] -fn use_trees() { - check( - r#" -//- /lib.rs -mod foo; -use crate::foo::bar::{Baz, Quux}; - -//- /foo/mod.rs -pub mod bar; - -//- /foo/bar.rs -pub struct Baz; -pub enum Quux {}; -"#, - expect![[r#" - crate - Baz: t v - Quux: t - foo: t - - crate::foo - bar: t - - crate::foo::bar - Baz: t v - Quux: t - "#]], - ); -} - -#[test] -fn re_exports() { - check( - r#" -//- /lib.rs -mod foo; -use self::foo::Baz; - -//- /foo/mod.rs -pub mod bar; -pub use self::bar::Baz; - -//- /foo/bar.rs -pub struct Baz; -"#, - expect![[r#" - crate - Baz: t v - foo: t - - crate::foo - Baz: t v - bar: t - - crate::foo::bar - Baz: t v - "#]], - ); -} - -#[test] -fn std_prelude() { - cov_mark::check!(std_prelude); - check( - r#" -//- /main.rs crate:main deps:test_crate -#[prelude_import] -use ::test_crate::prelude::*; - -use Foo::*; - -//- /lib.rs crate:test_crate -pub mod prelude; - -//- /prelude.rs -pub enum Foo { Bar, Baz } -"#, - expect![[r#" - crate - Bar: t v - Baz: t v - "#]], - ); -} - -#[test] -fn can_import_enum_variant() { - cov_mark::check!(can_import_enum_variant); - check( - r#" -enum E { V } -use self::E::V; -"#, - expect![[r#" - crate - E: t - V: t v - "#]], - ); -} - -#[test] -fn edition_2015_imports() { - check( - r#" -//- /main.rs crate:main deps:other_crate edition:2015 -mod foo; -mod bar; - -//- /bar.rs -struct Bar; - -//- /foo.rs -use bar::Bar; -use other_crate::FromLib; - -//- /lib.rs crate:other_crate edition:2018 -pub struct FromLib; -"#, - expect![[r#" - crate - bar: t - foo: t - - crate::bar - Bar: t v - - crate::foo - Bar: t v - FromLib: t v - "#]], - ); -} - -#[test] -fn item_map_using_self() { - check( - r#" -//- /lib.rs -mod foo; -use crate::foo::bar::Baz::{self}; - -//- /foo/mod.rs -pub mod bar; - -//- /foo/bar.rs -pub struct Baz; -"#, - expect![[r#" - crate - Baz: t - foo: t - - crate::foo - bar: t - - crate::foo::bar - Baz: t v - "#]], - ); -} - -#[test] -fn item_map_across_crates() { - check( - r#" -//- /main.rs crate:main deps:test_crate -use test_crate::Baz; - -//- /lib.rs crate:test_crate -pub struct Baz; -"#, - expect![[r#" - crate - Baz: t v - "#]], - ); -} - -#[test] -fn extern_crate_rename() { - check( - r#" -//- /main.rs crate:main deps:alloc -extern crate alloc as alloc_crate; -mod alloc; -mod sync; - -//- /sync.rs -use alloc_crate::Arc; - -//- /lib.rs crate:alloc -pub struct Arc; -"#, - expect![[r#" - crate - alloc: t - alloc_crate: t - sync: t - - crate::alloc - - crate::sync - Arc: t v - "#]], - ); -} - -#[test] -fn extern_crate_rename_2015_edition() { - check( - r#" -//- /main.rs crate:main deps:alloc edition:2015 -extern crate alloc as alloc_crate; -mod alloc; -mod sync; - -//- /sync.rs -use alloc_crate::Arc; - -//- /lib.rs crate:alloc -pub struct Arc; -"#, - expect![[r#" - crate - alloc: t - alloc_crate: t - sync: t - - crate::alloc - - crate::sync - Arc: t v - "#]], - ); -} - -#[test] -fn macro_use_extern_crate_self() { - cov_mark::check!(ignore_macro_use_extern_crate_self); - check( - r#" -//- /main.rs crate:main -#[macro_use] -extern crate self as bla; -"#, - expect![[r#" - crate - bla: t - "#]], - ); -} - -#[test] -fn reexport_across_crates() { - check( - r#" -//- /main.rs crate:main deps:test_crate -use test_crate::Baz; - -//- /lib.rs crate:test_crate -pub use foo::Baz; -mod foo; - -//- /foo.rs -pub struct Baz; -"#, - expect![[r#" - crate - Baz: t v - "#]], - ); -} - -#[test] -fn values_dont_shadow_extern_crates() { - check( - r#" -//- /main.rs crate:main deps:foo -fn foo() {} -use foo::Bar; - -//- /foo/lib.rs crate:foo -pub struct Bar; -"#, - expect![[r#" - crate - Bar: t v - foo: v - "#]], - ); -} - -#[test] -fn no_std_prelude() { - check( - r#" - //- /main.rs crate:main deps:core,std - #![cfg_attr(not(never), no_std)] - use Rust; - - //- /core.rs crate:core - pub mod prelude { - pub mod rust_2018 { - pub struct Rust; - } - } - //- /std.rs crate:std deps:core - pub mod prelude { - pub mod rust_2018 { - } - } - "#, - expect![[r#" - crate - Rust: t v - "#]], - ); -} - -#[test] -fn edition_specific_preludes() { - // We can't test the 2015 prelude here since you can't reexport its contents with 2015's - // absolute paths. - - check( - r#" - //- /main.rs edition:2018 crate:main deps:std - use Rust2018; - - //- /std.rs crate:std - pub mod prelude { - pub mod rust_2018 { - pub struct Rust2018; - } - } - "#, - expect![[r#" - crate - Rust2018: t v - "#]], - ); - check( - r#" - //- /main.rs edition:2021 crate:main deps:std - use Rust2021; - - //- /std.rs crate:std - pub mod prelude { - pub mod rust_2021 { - pub struct Rust2021; - } - } - "#, - expect![[r#" - crate - Rust2021: t v - "#]], - ); -} - -#[test] -fn std_prelude_takes_precedence_above_core_prelude() { - check( - r#" -//- /main.rs crate:main deps:core,std -use {Foo, Bar}; - -//- /std.rs crate:std deps:core -pub mod prelude { - pub mod rust_2018 { - pub struct Foo; - pub use core::prelude::rust_2018::Bar; - } -} - -//- /core.rs crate:core -pub mod prelude { - pub mod rust_2018 { - pub struct Bar; - } -} -"#, - expect![[r#" - crate - Bar: t v - Foo: t v - "#]], - ); -} - -#[test] -fn cfg_not_test() { - check( - r#" -//- /main.rs crate:main deps:std -use {Foo, Bar, Baz}; - -//- /lib.rs crate:std -pub mod prelude { - pub mod rust_2018 { - #[cfg(test)] - pub struct Foo; - #[cfg(not(test))] - pub struct Bar; - #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] - pub struct Baz; - } -} -"#, - expect![[r#" - crate - Bar: t v - Baz: _ - Foo: _ - "#]], - ); -} - -#[test] -fn cfg_test() { - check( - r#" -//- /main.rs crate:main deps:std -use {Foo, Bar, Baz}; - -//- /lib.rs crate:std cfg:test,feature=foo,feature=bar,opt=42 -pub mod prelude { - pub mod rust_2018 { - #[cfg(test)] - pub struct Foo; - #[cfg(not(test))] - pub struct Bar; - #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] - pub struct Baz; - } -} -"#, - expect![[r#" - crate - Bar: _ - Baz: t v - Foo: t v - "#]], - ); -} - -#[test] -fn infer_multiple_namespace() { - check( - r#" -//- /main.rs -mod a { - pub type T = (); - pub use crate::b::*; -} - -use crate::a::T; - -mod b { - pub const T: () = (); -} -"#, - expect![[r#" - crate - T: t v - a: t - b: t - - crate::a - T: t v - - crate::b - T: v - "#]], - ); -} - -#[test] -fn underscore_import() { - check( - r#" -//- /main.rs -use tr::Tr as _; -use tr::Tr2 as _; - -mod tr { - pub trait Tr {} - pub trait Tr2 {} -} - "#, - expect![[r#" - crate - _: t - _: t - tr: t - - crate::tr - Tr: t - Tr2: t - "#]], - ); -} - -#[test] -fn underscore_reexport() { - check( - r#" -//- /main.rs -mod tr { - pub trait PubTr {} - pub trait PrivTr {} -} -mod reex { - use crate::tr::PrivTr as _; - pub use crate::tr::PubTr as _; -} -use crate::reex::*; - "#, - expect![[r#" - crate - _: t - reex: t - tr: t - - crate::reex - _: t - _: t - - crate::tr - PrivTr: t - PubTr: t - "#]], - ); -} - -#[test] -fn underscore_pub_crate_reexport() { - cov_mark::check!(upgrade_underscore_visibility); - check( - r#" -//- /main.rs crate:main deps:lib -use lib::*; - -//- /lib.rs crate:lib -use tr::Tr as _; -pub use tr::Tr as _; - -mod tr { - pub trait Tr {} -} - "#, - expect![[r#" - crate - _: t - "#]], - ); -} - -#[test] -fn underscore_nontrait() { - check( - r#" -//- /main.rs -mod m { - pub struct Struct; - pub enum Enum {} - pub const CONST: () = (); -} -use crate::m::{Struct as _, Enum as _, CONST as _}; - "#, - expect![[r#" - crate - m: t - - crate::m - CONST: v - Enum: t - Struct: t v - "#]], - ); -} - -#[test] -fn underscore_name_conflict() { - check( - r#" -//- /main.rs -struct Tr; - -use tr::Tr as _; - -mod tr { - pub trait Tr {} -} - "#, - expect![[r#" - crate - _: t - Tr: t v - tr: t - - crate::tr - Tr: t - "#]], - ); -} - -#[test] -fn cfg_the_entire_crate() { - check( - r#" -//- /main.rs -#![cfg(never)] - -pub struct S; -pub enum E {} -pub fn f() {} - "#, - expect![[r#" - crate - "#]], - ); -} - -#[test] -fn use_crate_as() { - check( - r#" -use crate as foo; - -use foo::bar as baz; - -fn bar() {} - "#, - expect![[r#" - crate - bar: v - baz: v - foo: t - "#]], - ); -} - -#[test] -fn self_imports_only_types() { - check( - r#" -//- /main.rs -mod m { - pub macro S() {} - pub struct S; -} - -use self::m::S::{self}; - "#, - expect![[r#" - crate - S: t - m: t - - crate::m - S: t v m - "#]], - ); -} - -#[test] -fn import_from_extern_crate_only_imports_public_items() { - check( - r#" -//- /lib.rs crate:lib deps:settings,macros -use macros::settings; -use settings::Settings; -//- /settings.rs crate:settings -pub struct Settings; -//- /macros.rs crate:macros -mod settings {} -pub const settings: () = (); - "#, - expect![[r#" - crate - Settings: t v - settings: v - "#]], - ) -} - -#[test] -fn non_prelude_deps() { - check( - r#" -//- /lib.rs crate:lib deps:dep extern-prelude: -use dep::Struct; -//- /dep.rs crate:dep -pub struct Struct; - "#, - expect![[r#" - crate - Struct: _ - "#]], - ); - check( - r#" -//- /lib.rs crate:lib deps:dep extern-prelude: -extern crate dep; -use dep::Struct; -//- /dep.rs crate:dep -pub struct Struct; - "#, - expect![[r#" - crate - Struct: t v - dep: t - "#]], - ); -} - -#[test] -fn braced_supers_in_use_tree() { - cov_mark::check!(concat_super_mod_paths); - check( - r#" -mod some_module { - pub fn unknown_func() {} -} - -mod other_module { - mod some_submodule { - use { super::{ super::unknown_func, }, }; - } -} - -use some_module::unknown_func; - "#, - expect![[r#" - crate - other_module: t - some_module: t - unknown_func: v - - crate::other_module - some_submodule: t - - crate::other_module::some_submodule - unknown_func: v - - crate::some_module - unknown_func: v - "#]], - ) -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs deleted file mode 100644 index b2a6a592cf38b..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs +++ /dev/null @@ -1,338 +0,0 @@ -use super::*; - -#[test] -fn glob_1() { - check( - r#" -//- /lib.rs -mod foo; -use foo::*; - -//- /foo/mod.rs -pub mod bar; -pub use self::bar::Baz; -pub struct Foo; - -//- /foo/bar.rs -pub struct Baz; -"#, - expect![[r#" - crate - Baz: t v - Foo: t v - bar: t - foo: t - - crate::foo - Baz: t v - Foo: t v - bar: t - - crate::foo::bar - Baz: t v - "#]], - ); -} - -#[test] -fn glob_2() { - check( - r#" -//- /lib.rs -mod foo; -use foo::*; - -//- /foo/mod.rs -pub mod bar; -pub use self::bar::*; -pub struct Foo; - -//- /foo/bar.rs -pub struct Baz; -pub use super::*; -"#, - expect![[r#" - crate - Baz: t v - Foo: t v - bar: t - foo: t - - crate::foo - Baz: t v - Foo: t v - bar: t - - crate::foo::bar - Baz: t v - Foo: t v - bar: t - "#]], - ); -} - -#[test] -fn glob_privacy_1() { - check( - r" -//- /lib.rs -mod foo; -use foo::*; - -//- /foo/mod.rs -pub mod bar; -pub use self::bar::*; -struct PrivateStructFoo; - -//- /foo/bar.rs -pub struct Baz; -struct PrivateStructBar; -pub use super::*; -", - expect![[r#" - crate - Baz: t v - bar: t - foo: t - - crate::foo - Baz: t v - PrivateStructFoo: t v - bar: t - - crate::foo::bar - Baz: t v - PrivateStructBar: t v - PrivateStructFoo: t v - bar: t - "#]], - ); -} - -#[test] -fn glob_privacy_2() { - check( - r" -//- /lib.rs -mod foo; -use foo::*; -use foo::bar::*; - -//- /foo/mod.rs -mod bar; -fn Foo() {}; -pub struct Foo {}; - -//- /foo/bar.rs -pub(super) struct PrivateBaz; -struct PrivateBar; -pub(crate) struct PubCrateStruct; -", - expect![[r#" - crate - Foo: t - PubCrateStruct: t v - foo: t - - crate::foo - Foo: t v - bar: t - - crate::foo::bar - PrivateBar: t v - PrivateBaz: t v - PubCrateStruct: t v - "#]], - ); -} - -#[test] -fn glob_across_crates() { - cov_mark::check!(glob_across_crates); - check( - r#" -//- /main.rs crate:main deps:test_crate -use test_crate::*; - -//- /lib.rs crate:test_crate -pub struct Baz; -"#, - expect![[r#" - crate - Baz: t v - "#]], - ); -} - -#[test] -fn glob_privacy_across_crates() { - check( - r#" -//- /main.rs crate:main deps:test_crate -use test_crate::*; - -//- /lib.rs crate:test_crate -pub struct Baz; -struct Foo; -"#, - expect![[r#" - crate - Baz: t v - "#]], - ); -} - -#[test] -fn glob_enum() { - cov_mark::check!(glob_enum); - check( - r#" -enum Foo { Bar, Baz } -use self::Foo::*; -"#, - expect![[r#" - crate - Bar: t v - Baz: t v - Foo: t - "#]], - ); -} - -#[test] -fn glob_enum_group() { - cov_mark::check!(glob_enum_group); - check( - r#" -enum Foo { Bar, Baz } -use self::Foo::{*}; -"#, - expect![[r#" - crate - Bar: t v - Baz: t v - Foo: t - "#]], - ); -} - -#[test] -fn glob_shadowed_def() { - cov_mark::check!(import_shadowed); - check( - r#" -//- /lib.rs -mod foo; -mod bar; -use foo::*; -use bar::baz; -use baz::Bar; - -//- /foo.rs -pub mod baz { pub struct Foo; } - -//- /bar.rs -pub mod baz { pub struct Bar; } -"#, - expect![[r#" - crate - Bar: t v - bar: t - baz: t - foo: t - - crate::bar - baz: t - - crate::bar::baz - Bar: t v - - crate::foo - baz: t - - crate::foo::baz - Foo: t v - "#]], - ); -} - -#[test] -fn glob_shadowed_def_reversed() { - check( - r#" -//- /lib.rs -mod foo; -mod bar; -use bar::baz; -use foo::*; -use baz::Bar; - -//- /foo.rs -pub mod baz { pub struct Foo; } - -//- /bar.rs -pub mod baz { pub struct Bar; } -"#, - expect![[r#" - crate - Bar: t v - bar: t - baz: t - foo: t - - crate::bar - baz: t - - crate::bar::baz - Bar: t v - - crate::foo - baz: t - - crate::foo::baz - Foo: t v - "#]], - ); -} - -#[test] -fn glob_shadowed_def_dependencies() { - check( - r#" -mod a { pub mod foo { pub struct X; } } -mod b { pub use super::a::foo; } -mod c { pub mod foo { pub struct Y; } } -mod d { - use super::c::foo; - use super::b::*; - use foo::Y; -} -"#, - expect![[r#" - crate - a: t - b: t - c: t - d: t - - crate::a - foo: t - - crate::a::foo - X: t v - - crate::b - foo: t - - crate::c - foo: t - - crate::c::foo - Y: t v - - crate::d - Y: t v - foo: t - "#]], - ); -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs deleted file mode 100644 index 2e8cb3621fce6..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs +++ /dev/null @@ -1,237 +0,0 @@ -use std::sync::Arc; - -use base_db::SourceDatabaseExt; - -use crate::{AdtId, ModuleDefId}; - -use super::*; - -fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change: &str) { - let (mut db, pos) = TestDB::with_position(ra_fixture_initial); - let krate = db.test_crate(); - { - let events = db.log_executed(|| { - db.crate_def_map(krate); - }); - assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) - } - db.set_file_text(pos.file_id, Arc::new(ra_fixture_change.to_string())); - - { - let events = db.log_executed(|| { - db.crate_def_map(krate); - }); - assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) - } -} - -#[test] -fn typing_inside_a_function_should_not_invalidate_def_map() { - check_def_map_is_not_recomputed( - r" - //- /lib.rs - mod foo;$0 - - use crate::foo::bar::Baz; - - enum E { A, B } - use E::*; - - fn foo() -> i32 { - 1 + 1 - } - - #[cfg(never)] - fn no() {} - //- /foo/mod.rs - pub mod bar; - - //- /foo/bar.rs - pub struct Baz; - ", - r" - mod foo; - - use crate::foo::bar::Baz; - - enum E { A, B } - use E::*; - - fn foo() -> i32 { 92 } - - #[cfg(never)] - fn no() {} - ", - ); -} - -#[test] -fn typing_inside_a_macro_should_not_invalidate_def_map() { - let (mut db, pos) = TestDB::with_position( - r" - //- /lib.rs - macro_rules! m { - ($ident:ident) => { - fn f() { - $ident + $ident; - }; - } - } - mod foo; - - //- /foo/mod.rs - pub mod bar; - - //- /foo/bar.rs - $0 - m!(X); - ", - ); - let krate = db.test_crate(); - { - let events = db.log_executed(|| { - let crate_def_map = db.crate_def_map(krate); - let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); - assert_eq!(module_data.scope.resolutions().count(), 1); - }); - assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) - } - db.set_file_text(pos.file_id, Arc::new("m!(Y);".to_string())); - - { - let events = db.log_executed(|| { - let crate_def_map = db.crate_def_map(krate); - let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); - assert_eq!(module_data.scope.resolutions().count(), 1); - }); - assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) - } -} - -#[test] -fn typing_inside_a_function_should_not_invalidate_expansions() { - let (mut db, pos) = TestDB::with_position( - r#" -//- /lib.rs -macro_rules! m { - ($ident:ident) => { - fn $ident() { }; - } -} -mod foo; - -//- /foo/mod.rs -pub mod bar; - -//- /foo/bar.rs -m!(X); -fn quux() { 1$0 } -m!(Y); -m!(Z); -"#, - ); - let krate = db.test_crate(); - { - let events = db.log_executed(|| { - let crate_def_map = db.crate_def_map(krate); - let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); - assert_eq!(module_data.scope.resolutions().count(), 4); - }); - let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); - assert_eq!(n_recalculated_item_trees, 6); - let n_reparsed_macros = - events.iter().filter(|it| it.contains("parse_macro_expansion")).count(); - assert_eq!(n_reparsed_macros, 3); - } - - let new_text = r#" -m!(X); -fn quux() { 92 } -m!(Y); -m!(Z); -"#; - db.set_file_text(pos.file_id, Arc::new(new_text.to_string())); - - { - let events = db.log_executed(|| { - let crate_def_map = db.crate_def_map(krate); - let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); - assert_eq!(module_data.scope.resolutions().count(), 4); - }); - let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); - assert_eq!(n_recalculated_item_trees, 1); - let n_reparsed_macros = - events.iter().filter(|it| it.contains("parse_macro_expansion")).count(); - assert_eq!(n_reparsed_macros, 0); - } -} - -#[test] -fn item_tree_prevents_reparsing() { - // The `ItemTree` is used by both name resolution and the various queries in `adt.rs` and - // `data.rs`. After computing the `ItemTree` and deleting the parse tree, we should be able to - // run those other queries without triggering a reparse. - - let (db, pos) = TestDB::with_position( - r#" -pub struct S; -pub union U {} -pub enum E { - Variant, -} -pub fn f(_: S) { $0 } -pub trait Tr {} -impl Tr for () {} -pub const C: u8 = 0; -pub static ST: u8 = 0; -pub type Ty = (); -"#, - ); - let krate = db.test_crate(); - { - let events = db.log_executed(|| { - db.file_item_tree(pos.file_id.into()); - }); - let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); - assert_eq!(n_calculated_item_trees, 1); - let n_parsed_files = events.iter().filter(|it| it.contains("parse(")).count(); - assert_eq!(n_parsed_files, 1); - } - - // Delete the parse tree. - base_db::ParseQuery.in_db(&db).purge(); - - { - let events = db.log_executed(|| { - let crate_def_map = db.crate_def_map(krate); - let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); - assert_eq!(module_data.scope.resolutions().count(), 8); - assert_eq!(module_data.scope.impls().count(), 1); - - for imp in module_data.scope.impls() { - db.impl_data(imp); - } - - for (_, res) in module_data.scope.resolutions() { - match res.values.or(res.types).unwrap().0 { - ModuleDefId::FunctionId(f) => drop(db.function_data(f)), - ModuleDefId::AdtId(adt) => match adt { - AdtId::StructId(it) => drop(db.struct_data(it)), - AdtId::UnionId(it) => drop(db.union_data(it)), - AdtId::EnumId(it) => drop(db.enum_data(it)), - }, - ModuleDefId::ConstId(it) => drop(db.const_data(it)), - ModuleDefId::StaticId(it) => drop(db.static_data(it)), - ModuleDefId::TraitId(it) => drop(db.trait_data(it)), - ModuleDefId::TypeAliasId(it) => drop(db.type_alias_data(it)), - ModuleDefId::EnumVariantId(_) - | ModuleDefId::ModuleId(_) - | ModuleDefId::MacroId(_) - | ModuleDefId::BuiltinType(_) => unreachable!(), - } - } - }); - let n_reparsed_files = events.iter().filter(|it| it.contains("parse(")).count(); - assert_eq!(n_reparsed_files, 0); - } -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs deleted file mode 100644 index 3ece1379ad774..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs +++ /dev/null @@ -1,1187 +0,0 @@ -use super::*; -use itertools::Itertools; - -#[test] -fn macro_rules_are_globally_visible() { - check( - r#" -//- /lib.rs -macro_rules! structs { - ($($i:ident),*) => { - $(struct $i { field: u32 } )* - } -} -structs!(Foo); -mod nested; - -//- /nested.rs -structs!(Bar, Baz); -"#, - expect![[r#" - crate - Foo: t - nested: t - - crate::nested - Bar: t - Baz: t - "#]], - ); -} - -#[test] -fn macro_rules_can_define_modules() { - check( - r#" -//- /lib.rs -macro_rules! m { - ($name:ident) => { mod $name; } -} -m!(n1); -mod m { m!(n3) } - -//- /n1.rs -m!(n2) -//- /n1/n2.rs -struct X; -//- /m/n3.rs -struct Y; -"#, - expect![[r#" - crate - m: t - n1: t - - crate::m - n3: t - - crate::m::n3 - Y: t v - - crate::n1 - n2: t - - crate::n1::n2 - X: t v - "#]], - ); -} - -#[test] -fn macro_rules_from_other_crates_are_visible() { - check( - r#" -//- /main.rs crate:main deps:foo -foo::structs!(Foo, Bar) -mod bar; - -//- /bar.rs -use crate::*; - -//- /lib.rs crate:foo -#[macro_export] -macro_rules! structs { - ($($i:ident),*) => { - $(struct $i { field: u32 } )* - } -} -"#, - expect![[r#" - crate - Bar: t - Foo: t - bar: t - - crate::bar - Bar: t - Foo: t - bar: t - "#]], - ); -} - -#[test] -fn macro_rules_export_with_local_inner_macros_are_visible() { - check( - r#" -//- /main.rs crate:main deps:foo -foo::structs!(Foo, Bar) -mod bar; - -//- /bar.rs -use crate::*; - -//- /lib.rs crate:foo -#[macro_export(local_inner_macros)] -macro_rules! structs { - ($($i:ident),*) => { - $(struct $i { field: u32 } )* - } -} -"#, - expect![[r#" - crate - Bar: t - Foo: t - bar: t - - crate::bar - Bar: t - Foo: t - bar: t - "#]], - ); -} - -#[test] -fn local_inner_macros_makes_local_macros_usable() { - check( - r#" -//- /main.rs crate:main deps:foo -foo::structs!(Foo, Bar); -mod bar; - -//- /bar.rs -use crate::*; - -//- /lib.rs crate:foo -#[macro_export(local_inner_macros)] -macro_rules! structs { - ($($i:ident),*) => { - inner!($($i),*); - } -} -#[macro_export] -macro_rules! inner { - ($($i:ident),*) => { - $(struct $i { field: u32 } )* - } -} -"#, - expect![[r#" - crate - Bar: t - Foo: t - bar: t - - crate::bar - Bar: t - Foo: t - bar: t - "#]], - ); -} - -#[test] -fn unexpanded_macro_should_expand_by_fixedpoint_loop() { - check( - r#" -//- /main.rs crate:main deps:foo -macro_rules! baz { - () => { - use foo::bar; - } -} -foo!(); -bar!(); -baz!(); - -//- /lib.rs crate:foo -#[macro_export] -macro_rules! foo { - () => { - struct Foo { field: u32 } - } -} -#[macro_export] -macro_rules! bar { - () => { - use foo::foo; - } -} -"#, - expect![[r#" - crate - Foo: t - bar: m - foo: m - "#]], - ); -} - -#[test] -fn macro_rules_from_other_crates_are_visible_with_macro_use() { - cov_mark::check!(macro_rules_from_other_crates_are_visible_with_macro_use); - check( - r#" -//- /main.rs crate:main deps:foo -structs!(Foo); -structs_priv!(Bar); -structs_not_exported!(MacroNotResolved1); -crate::structs!(MacroNotResolved2); - -mod bar; - -#[macro_use] -extern crate foo; - -//- /bar.rs -structs!(Baz); -crate::structs!(MacroNotResolved3); - -//- /lib.rs crate:foo -#[macro_export] -macro_rules! structs { - ($i:ident) => { struct $i; } -} - -macro_rules! structs_not_exported { - ($i:ident) => { struct $i; } -} - -mod priv_mod { - #[macro_export] - macro_rules! structs_priv { - ($i:ident) => { struct $i; } - } -} -"#, - expect![[r#" - crate - Bar: t v - Foo: t v - bar: t - foo: t - - crate::bar - Baz: t v - "#]], - ); -} - -#[test] -fn prelude_is_macro_use() { - cov_mark::check!(prelude_is_macro_use); - check( - r#" -//- /main.rs crate:main deps:std -structs!(Foo); -structs_priv!(Bar); -structs_outside!(Out); -crate::structs!(MacroNotResolved2); - -mod bar; - -//- /bar.rs -structs!(Baz); -crate::structs!(MacroNotResolved3); - -//- /lib.rs crate:std -pub mod prelude { - pub mod rust_2018 { - #[macro_export] - macro_rules! structs { - ($i:ident) => { struct $i; } - } - - mod priv_mod { - #[macro_export] - macro_rules! structs_priv { - ($i:ident) => { struct $i; } - } - } - } -} - -#[macro_export] -macro_rules! structs_outside { - ($i:ident) => { struct $i; } -} -"#, - expect![[r#" - crate - Bar: t v - Foo: t v - Out: t v - bar: t - - crate::bar - Baz: t v - "#]], - ); -} - -#[test] -fn prelude_cycle() { - check( - r#" -#[prelude_import] -use self::prelude::*; - -declare_mod!(); - -mod prelude { - macro_rules! declare_mod { - () => (mod foo {}) - } -} -"#, - expect![[r#" - crate - prelude: t - - crate::prelude - "#]], - ); -} - -#[test] -fn legacy_macro_use_before_def() { - check( - r#" -m!(); - -macro_rules! m { - () => { - struct S; - } -} -"#, - expect![[r#" - crate - S: t v - "#]], - ); - // FIXME: should not expand. legacy macro scoping is not implemented. -} - -#[test] -fn plain_macros_are_legacy_textual_scoped() { - check( - r#" -//- /main.rs -mod m1; -bar!(NotFoundNotMacroUse); - -mod m2 { foo!(NotFoundBeforeInside2); } - -macro_rules! foo { - ($x:ident) => { struct $x; } -} -foo!(Ok); - -mod m3; -foo!(OkShadowStop); -bar!(NotFoundMacroUseStop); - -#[macro_use] -mod m5 { - #[macro_use] - mod m6 { - macro_rules! foo { - ($x:ident) => { fn $x() {} } - } - } -} -foo!(ok_double_macro_use_shadow); - -baz!(NotFoundBefore); -#[macro_use] -mod m7 { - macro_rules! baz { - ($x:ident) => { struct $x; } - } -} -baz!(OkAfter); - -//- /m1.rs -foo!(NotFoundBeforeInside1); -macro_rules! bar { - ($x:ident) => { struct $x; } -} - -//- /m3/mod.rs -foo!(OkAfterInside); -macro_rules! foo { - ($x:ident) => { fn $x() {} } -} -foo!(ok_shadow); - -#[macro_use] -mod m4; -bar!(OkMacroUse); - -mod m5; -baz!(OkMacroUseInner); - -//- /m3/m4.rs -foo!(ok_shadow_deep); -macro_rules! bar { - ($x:ident) => { struct $x; } -} -//- /m3/m5.rs -#![macro_use] -macro_rules! baz { - ($x:ident) => { struct $x; } -} - - -"#, - expect![[r#" - crate - NotFoundBefore: t v - Ok: t v - OkAfter: t v - OkShadowStop: t v - m1: t - m2: t - m3: t - m5: t - m7: t - ok_double_macro_use_shadow: v - - crate::m1 - - crate::m2 - - crate::m3 - OkAfterInside: t v - OkMacroUse: t v - OkMacroUseInner: t v - m4: t - m5: t - ok_shadow: v - - crate::m3::m4 - ok_shadow_deep: v - - crate::m3::m5 - - crate::m5 - m6: t - - crate::m5::m6 - - crate::m7 - "#]], - ); - // FIXME: should not see `NotFoundBefore` -} - -#[test] -fn type_value_macro_live_in_different_scopes() { - check( - r#" -#[macro_export] -macro_rules! foo { - ($x:ident) => { type $x = (); } -} - -foo!(foo); -use foo as bar; - -use self::foo as baz; -fn baz() {} -"#, - expect![[r#" - crate - bar: t m - baz: t v m - foo: t m - "#]], - ); -} - -#[test] -fn macro_use_can_be_aliased() { - check( - r#" -//- /main.rs crate:main deps:foo -#[macro_use] -extern crate foo; - -foo!(Direct); -bar!(Alias); - -//- /lib.rs crate:foo -use crate::foo as bar; - -mod m { - #[macro_export] - macro_rules! foo { - ($x:ident) => { struct $x; } - } -} -"#, - expect![[r#" - crate - Alias: t v - Direct: t v - foo: t - "#]], - ); -} - -#[test] -fn path_qualified_macros() { - check( - r#" -macro_rules! foo { - ($x:ident) => { struct $x; } -} - -crate::foo!(NotResolved); - -crate::bar!(OkCrate); -bar!(OkPlain); -alias1!(NotHere); -m::alias1!(OkAliasPlain); -m::alias2!(OkAliasSuper); -m::alias3!(OkAliasCrate); -not_found!(NotFound); - -mod m { - #[macro_export] - macro_rules! bar { - ($x:ident) => { struct $x; } - } - pub use bar as alias1; - pub use super::bar as alias2; - pub use crate::bar as alias3; - pub use self::bar as not_found; -} -"#, - expect![[r#" - crate - OkAliasCrate: t v - OkAliasPlain: t v - OkAliasSuper: t v - OkCrate: t v - OkPlain: t v - bar: m - m: t - - crate::m - alias1: m - alias2: m - alias3: m - not_found: _ - "#]], - ); -} - -#[test] -fn macro_dollar_crate_is_correct_in_item() { - cov_mark::check!(macro_dollar_crate_self); - check( - r#" -//- /main.rs crate:main deps:foo -#[macro_use] -extern crate foo; - -#[macro_use] -mod m { - macro_rules! current { - () => { - use $crate::Foo as FooSelf; - } - } -} - -struct Foo; - -current!(); -not_current1!(); -foo::not_current2!(); - -//- /lib.rs crate:foo -mod m { - #[macro_export] - macro_rules! not_current1 { - () => { - use $crate::Bar; - } - } -} - -#[macro_export] -macro_rules! not_current2 { - () => { - use $crate::Baz; - } -} - -pub struct Bar; -pub struct Baz; -"#, - expect![[r#" - crate - Bar: t v - Baz: t v - Foo: t v - FooSelf: t v - foo: t - m: t - - crate::m - "#]], - ); -} - -#[test] -fn macro_dollar_crate_is_correct_in_indirect_deps() { - cov_mark::check!(macro_dollar_crate_other); - // From std - check( - r#" -//- /main.rs crate:main deps:std -foo!(); - -//- /std.rs crate:std deps:core -pub use core::foo; - -pub mod prelude { - pub mod rust_2018 {} -} - -#[macro_use] -mod std_macros; - -//- /core.rs crate:core -#[macro_export] -macro_rules! foo { - () => { - use $crate::bar; - } -} - -pub struct bar; -"#, - expect![[r#" - crate - bar: t v - "#]], - ); -} - -#[test] -fn expand_derive() { - let map = compute_crate_def_map( - r#" -//- /main.rs crate:main deps:core -use core::Copy; - -#[core::derive(Copy, core::Clone)] -struct Foo; - -//- /core.rs crate:core -#[rustc_builtin_macro] -pub macro derive($item:item) {} -#[rustc_builtin_macro] -pub macro Copy {} -#[rustc_builtin_macro] -pub macro Clone {} -"#, - ); - assert_eq!(map.modules[map.root].scope.impls().len(), 2); -} - -#[test] -fn resolve_builtin_derive() { - check( - r#" -//- /main.rs crate:main deps:core -use core::*; - -//- /core.rs crate:core -#[rustc_builtin_macro] -pub macro Clone {} - -pub trait Clone {} -"#, - expect![[r#" - crate - Clone: t m - "#]], - ); -} - -#[test] -fn builtin_derive_with_unresolved_attributes_fall_back() { - // Tests that we still resolve derives after ignoring an unresolved attribute. - cov_mark::check!(unresolved_attribute_fallback); - let map = compute_crate_def_map( - r#" -//- /main.rs crate:main deps:core -use core::{Clone, derive}; - -#[derive(Clone)] -#[unresolved] -struct Foo; - -//- /core.rs crate:core -#[rustc_builtin_macro] -pub macro derive($item:item) {} -#[rustc_builtin_macro] -pub macro Clone {} -"#, - ); - assert_eq!(map.modules[map.root].scope.impls().len(), 1); -} - -#[test] -fn unresolved_attributes_fall_back_track_per_file_moditems() { - // Tests that we track per-file ModItems when ignoring an unresolved attribute. - // Just tracking the `ModItem` leads to `Foo` getting ignored. - - check( - r#" - //- /main.rs crate:main - - mod submod; - - #[unresolved] - struct Foo; - - //- /submod.rs - #[unresolved] - struct Bar; - "#, - expect![[r#" - crate - Foo: t v - submod: t - - crate::submod - Bar: t v - "#]], - ); -} - -#[test] -fn unresolved_attrs_extern_block_hang() { - // Regression test for https://github.com/rust-lang/rust-analyzer/issues/8905 - check( - r#" -#[unresolved] -extern "C" { - #[unresolved] - fn f(); -} - "#, - expect![[r#" - crate - f: v - "#]], - ); -} - -#[test] -fn macros_in_extern_block() { - check( - r#" -macro_rules! m { - () => { static S: u8; }; -} - -extern { - m!(); -} - "#, - expect![[r#" - crate - S: v - "#]], - ); -} - -#[test] -fn resolves_derive_helper() { - cov_mark::check!(resolved_derive_helper); - check( - r#" -//- /main.rs crate:main deps:proc -#[rustc_builtin_macro] -pub macro derive($item:item) {} - -#[derive(proc::Derive)] -#[helper] -#[unresolved] -struct S; - -//- /proc.rs crate:proc -#![crate_type="proc-macro"] -#[proc_macro_derive(Derive, attributes(helper))] -fn derive() {} - "#, - expect![[r#" - crate - S: t v - derive: m - "#]], - ); -} - -#[test] -fn unresolved_attr_with_cfg_attr_hang() { - // Another regression test for https://github.com/rust-lang/rust-analyzer/issues/8905 - check( - r#" -#[cfg_attr(not(off), unresolved, unresolved)] -struct S; - "#, - expect![[r#" - crate - S: t v - "#]], - ); -} - -#[test] -fn macro_expansion_overflow() { - cov_mark::check!(macro_expansion_overflow); - check( - r#" -macro_rules! a { - ($e:expr; $($t:tt)*) => { - b!(static = (); $($t)*); - }; - () => {}; -} - -macro_rules! b { - (static = $e:expr; $($t:tt)*) => { - a!($e; $($t)*); - }; - () => {}; -} - -b! { static = #[] ();} -"#, - expect![[r#" - crate - "#]], - ); -} - -#[test] -fn macros_defining_macros() { - check( - r#" -macro_rules! item { - ($item:item) => { $item } -} - -item! { - macro_rules! indirect_macro { () => { struct S {} } } -} - -indirect_macro!(); - "#, - expect![[r#" - crate - S: t - "#]], - ); -} - -#[test] -fn resolves_proc_macros() { - check( - r#" -#![crate_type="proc-macro"] -struct TokenStream; - -#[proc_macro] -pub fn function_like_macro(args: TokenStream) -> TokenStream { - args -} - -#[proc_macro_attribute] -pub fn attribute_macro(_args: TokenStream, item: TokenStream) -> TokenStream { - item -} - -#[proc_macro_derive(DummyTrait)] -pub fn derive_macro(_item: TokenStream) -> TokenStream { - TokenStream -} - -#[proc_macro_derive(AnotherTrait, attributes(helper_attr))] -pub fn derive_macro_2(_item: TokenStream) -> TokenStream { - TokenStream -} -"#, - expect![[r#" - crate - AnotherTrait: m - DummyTrait: m - TokenStream: t v - attribute_macro: v m - derive_macro: v - derive_macro_2: v - function_like_macro: v m - "#]], - ); -} - -#[test] -fn proc_macro_censoring() { - // Make sure that only proc macros are publicly exported from proc-macro crates. - - check( - r#" -//- /main.rs crate:main deps:macros -pub use macros::*; - -//- /macros.rs crate:macros -#![crate_type="proc-macro"] -pub struct TokenStream; - -#[proc_macro] -pub fn function_like_macro(args: TokenStream) -> TokenStream { - args -} - -#[proc_macro_attribute] -pub fn attribute_macro(_args: TokenStream, item: TokenStream) -> TokenStream { - item -} - -#[proc_macro_derive(DummyTrait)] -pub fn derive_macro(_item: TokenStream) -> TokenStream { - TokenStream -} - -#[macro_export] -macro_rules! mbe { - () => {}; -} -"#, - expect![[r#" - crate - DummyTrait: m - attribute_macro: m - function_like_macro: m - "#]], - ); -} - -#[test] -fn collects_derive_helpers() { - let def_map = compute_crate_def_map( - r#" -#![crate_type="proc-macro"] -struct TokenStream; - -#[proc_macro_derive(AnotherTrait, attributes(helper_attr))] -pub fn derive_macro_2(_item: TokenStream) -> TokenStream { - TokenStream -} -"#, - ); - - assert_eq!(def_map.exported_derives.len(), 1); - match def_map.exported_derives.values().next() { - Some(helpers) => match &**helpers { - [attr] => assert_eq!(attr.to_string(), "helper_attr"), - _ => unreachable!(), - }, - _ => unreachable!(), - } -} - -#[test] -fn resolve_macro_def() { - check( - r#" -pub macro structs($($i:ident),*) { - $(struct $i { field: u32 } )* -} -structs!(Foo); -"#, - expect![[r#" - crate - Foo: t - structs: m - "#]], - ); -} - -#[test] -fn macro_in_prelude() { - check( - r#" -//- /lib.rs crate:lib deps:std -global_asm!(); - -//- /std.rs crate:std -pub mod prelude { - pub mod rust_2018 { - pub macro global_asm() { - pub struct S; - } - } -} - "#, - expect![[r#" - crate - S: t v - "#]], - ) -} - -#[test] -fn issue9358_bad_macro_stack_overflow() { - cov_mark::check!(issue9358_bad_macro_stack_overflow); - check( - r#" -macro_rules! m { - ($cond:expr) => { m!($cond, stringify!($cond)) }; - ($cond:expr, $($arg:tt)*) => { $cond }; -} -m!( -"#, - expect![[r#" - crate - "#]], - ) -} - -#[test] -fn eager_macro_correctly_resolves_contents() { - // Eager macros resolve any contained macros when expanded. This should work correctly with the - // usual name resolution rules, so both of these `include!`s should include the right file. - - check( - r#" -//- /lib.rs -#[rustc_builtin_macro] -macro_rules! include { () => {} } - -include!(inner_a!()); -include!(crate::inner_b!()); - -#[macro_export] -macro_rules! inner_a { - () => { "inc_a.rs" }; -} -#[macro_export] -macro_rules! inner_b { - () => { "inc_b.rs" }; -} -//- /inc_a.rs -struct A; -//- /inc_b.rs -struct B; -"#, - expect![[r#" - crate - A: t v - B: t v - inner_a: m - inner_b: m - "#]], - ); -} - -#[test] -fn eager_macro_correctly_resolves_dollar_crate() { - // MBE -> eager -> $crate::mbe - check( - r#" -//- /lib.rs -#[rustc_builtin_macro] -macro_rules! include { () => {} } - -#[macro_export] -macro_rules! inner { - () => { "inc.rs" }; -} - -macro_rules! m { - () => { include!($crate::inner!()); }; -} - -m!(); - -//- /inc.rs -struct A; -"#, - expect![[r#" - crate - A: t v - inner: m - "#]], - ); - // eager -> MBE -> $crate::mbe - check( - r#" -//- /lib.rs -#[rustc_builtin_macro] -macro_rules! include { () => {} } - -#[macro_export] -macro_rules! inner { - () => { "inc.rs" }; -} - -macro_rules! n { - () => { - $crate::inner!() - }; -} - -include!(n!()); - -//- /inc.rs -struct A; -"#, - expect![[r#" - crate - A: t v - inner: m - "#]], - ); -} - -#[test] -fn macro_use_imports_all_macro_types() { - let def_map = compute_crate_def_map( - r#" -//- /main.rs crate:main deps:lib -#[macro_use] -extern crate lib; - -//- /lib.rs crate:lib deps:proc -pub use proc::*; - -#[macro_export] -macro_rules! legacy { () => () } - -pub macro macro20 {} - -//- /proc.rs crate:proc -#![crate_type="proc-macro"] - -struct TokenStream; - -#[proc_macro_attribute] -fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a } - "#, - ); - - let root = &def_map[def_map.root()].scope; - let actual = root - .legacy_macros() - .sorted_by(|a, b| std::cmp::Ord::cmp(&a.0, &b.0)) - .map(|(name, _)| format!("{name}\n")) - .collect::(); - - expect![[r#" - legacy - macro20 - proc_attr - "#]] - .assert_eq(&actual); -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs deleted file mode 100644 index 79a74873b4a47..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs +++ /dev/null @@ -1,843 +0,0 @@ -use super::*; - -#[test] -fn name_res_works_for_broken_modules() { - cov_mark::check!(name_res_works_for_broken_modules); - check( - r" -//- /lib.rs -mod foo // no `;`, no body -use self::foo::Baz; - -//- /foo/mod.rs -pub mod bar; -pub use self::bar::Baz; - -//- /foo/bar.rs -pub struct Baz; -", - expect![[r#" - crate - Baz: _ - foo: t - - crate::foo - "#]], - ); -} - -#[test] -fn nested_module_resolution() { - check( - r#" -//- /lib.rs -mod n1; - -//- /n1.rs -mod n2; - -//- /n1/n2.rs -struct X; -"#, - expect![[r#" - crate - n1: t - - crate::n1 - n2: t - - crate::n1::n2 - X: t v - "#]], - ); -} - -#[test] -fn nested_module_resolution_2() { - check( - r#" -//- /lib.rs -mod prelude; -mod iter; - -//- /prelude.rs -pub use crate::iter::Iterator; - -//- /iter.rs -pub use self::traits::Iterator; -mod traits; - -//- /iter/traits.rs -pub use self::iterator::Iterator; -mod iterator; - -//- /iter/traits/iterator.rs -pub trait Iterator; -"#, - expect![[r#" - crate - iter: t - prelude: t - - crate::iter - Iterator: t - traits: t - - crate::iter::traits - Iterator: t - iterator: t - - crate::iter::traits::iterator - Iterator: t - - crate::prelude - Iterator: t - "#]], - ); -} - -#[test] -fn module_resolution_works_for_non_standard_filenames() { - check( - r#" -//- /my_library.rs crate:my_library -mod foo; -use self::foo::Bar; - -//- /foo/mod.rs -pub struct Bar; -"#, - expect![[r#" - crate - Bar: t v - foo: t - - crate::foo - Bar: t v - "#]], - ); -} - -#[test] -fn module_resolution_works_for_raw_modules() { - check( - r#" -//- /lib.rs -mod r#async; -use self::r#async::Bar; - -//- /async.rs -pub struct Bar; -"#, - expect![[r#" - crate - Bar: t v - async: t - - crate::async - Bar: t v - "#]], - ); -} - -#[test] -fn module_resolution_decl_path() { - check( - r#" -//- /lib.rs -#[path = "bar/baz/foo.rs"] -mod foo; -use self::foo::Bar; - -//- /bar/baz/foo.rs -pub struct Bar; -"#, - expect![[r#" - crate - Bar: t v - foo: t - - crate::foo - Bar: t v - "#]], - ); -} - -#[test] -fn module_resolution_module_with_path_in_mod_rs() { - check( - r#" -//- /main.rs -mod foo; - -//- /foo/mod.rs -#[path = "baz.rs"] -pub mod bar; -use self::bar::Baz; - -//- /foo/baz.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - Baz: t v - bar: t - - crate::foo::bar - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_module_with_path_non_crate_root() { - check( - r#" -//- /main.rs -mod foo; - -//- /foo.rs -#[path = "baz.rs"] -pub mod bar; -use self::bar::Baz; - -//- /baz.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - Baz: t v - bar: t - - crate::foo::bar - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_module_decl_path_super() { - check( - r#" -//- /main.rs -#[path = "bar/baz/module.rs"] -mod foo; -pub struct Baz; - -//- /bar/baz/module.rs -use super::Baz; -"#, - expect![[r#" - crate - Baz: t v - foo: t - - crate::foo - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_explicit_path_mod_rs() { - check( - r#" -//- /main.rs -#[path = "module/mod.rs"] -mod foo; - -//- /module/mod.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_relative_path() { - check( - r#" -//- /main.rs -mod foo; - -//- /foo.rs -#[path = "./sub.rs"] -pub mod foo_bar; - -//- /sub.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - foo_bar: t - - crate::foo::foo_bar - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_relative_path_2() { - check( - r#" -//- /main.rs -mod foo; - -//- /foo/mod.rs -#[path="../sub.rs"] -pub mod foo_bar; - -//- /sub.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - foo_bar: t - - crate::foo::foo_bar - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_relative_path_outside_root() { - check( - r#" -//- /a/b/c/d/e/main.rs crate:main -#[path="../../../../../outside.rs"] -mod foo; - -//- /outside.rs -mod bar; - -//- /bar.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - bar: t - - crate::foo::bar - Baz: t v -"#]], - ); -} - -#[test] -fn module_resolution_explicit_path_mod_rs_2() { - check( - r#" -//- /main.rs -#[path = "module/bar/mod.rs"] -mod foo; - -//- /module/bar/mod.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_explicit_path_mod_rs_with_win_separator() { - check( - r#" -//- /main.rs -#[path = r"module\bar\mod.rs"] -mod foo; - -//- /module/bar/mod.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_decl_inside_inline_module_with_path_attribute() { - check( - r#" -//- /main.rs -#[path = "models"] -mod foo { mod bar; } - -//- /models/bar.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - bar: t - - crate::foo::bar - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_decl_inside_inline_module() { - check( - r#" -//- /main.rs -mod foo { mod bar; } - -//- /foo/bar.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - bar: t - - crate::foo::bar - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_decl_inside_inline_module_2_with_path_attribute() { - check( - r#" -//- /main.rs -#[path = "models/db"] -mod foo { mod bar; } - -//- /models/db/bar.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - bar: t - - crate::foo::bar - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_decl_inside_inline_module_3() { - check( - r#" -//- /main.rs -#[path = "models/db"] -mod foo { - #[path = "users.rs"] - mod bar; -} - -//- /models/db/users.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - bar: t - - crate::foo::bar - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_decl_inside_inline_module_empty_path() { - check( - r#" -//- /main.rs -#[path = ""] -mod foo { - #[path = "users.rs"] - mod bar; -} - -//- /users.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - bar: t - - crate::foo::bar - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_decl_empty_path() { - check( - r#" -//- /main.rs -#[path = ""] // Should try to read `/` (a directory) -mod foo; - -//- /foo.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - "#]], - ); -} - -#[test] -fn module_resolution_decl_inside_inline_module_relative_path() { - check( - r#" -//- /main.rs -#[path = "./models"] -mod foo { mod bar; } - -//- /models/bar.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - bar: t - - crate::foo::bar - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_decl_inside_inline_module_in_crate_root() { - check( - r#" -//- /main.rs -mod foo { - #[path = "baz.rs"] - mod bar; -} -use self::foo::bar::Baz; - -//- /foo/baz.rs -pub struct Baz; -"#, - expect![[r#" - crate - Baz: t v - foo: t - - crate::foo - bar: t - - crate::foo::bar - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_decl_inside_inline_module_in_mod_rs() { - check( - r#" -//- /main.rs -mod foo; - -//- /foo/mod.rs -mod bar { - #[path = "qwe.rs"] - pub mod baz; -} -use self::bar::baz::Baz; - -//- /foo/bar/qwe.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - Baz: t v - bar: t - - crate::foo::bar - baz: t - - crate::foo::bar::baz - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_decl_inside_inline_module_in_non_crate_root() { - check( - r#" -//- /main.rs -mod foo; - -//- /foo.rs -mod bar { - #[path = "qwe.rs"] - pub mod baz; -} -use self::bar::baz::Baz; - -//- /foo/bar/qwe.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - Baz: t v - bar: t - - crate::foo::bar - baz: t - - crate::foo::bar::baz - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() { - check( - r#" -//- /main.rs -mod foo; - -//- /foo.rs -#[path = "bar"] -mod bar { - pub mod baz; -} -use self::bar::baz::Baz; - -//- /bar/baz.rs -pub struct Baz; -"#, - expect![[r#" - crate - foo: t - - crate::foo - Baz: t v - bar: t - - crate::foo::bar - baz: t - - crate::foo::bar::baz - Baz: t v - "#]], - ); -} - -#[test] -fn module_resolution_decl_inside_module_in_non_crate_root_2() { - check( - r#" -//- /main.rs -#[path="module/m2.rs"] -mod module; - -//- /module/m2.rs -pub mod submod; - -//- /module/submod.rs -pub struct Baz; -"#, - expect![[r#" - crate - module: t - - crate::module - submod: t - - crate::module::submod - Baz: t v - "#]], - ); -} - -#[test] -fn nested_out_of_line_module() { - check( - r#" -//- /lib.rs -mod a { - mod b { - mod c; - } -} - -//- /a/b/c.rs -struct X; -"#, - expect![[r#" - crate - a: t - - crate::a - b: t - - crate::a::b - c: t - - crate::a::b::c - X: t v - "#]], - ); -} - -#[test] -fn nested_out_of_line_module_with_path() { - check( - r#" -//- /lib.rs -mod a { - #[path = "d/e"] - mod b { - mod c; - } -} - -//- /a/d/e/c.rs -struct X; -"#, - expect![[r#" - crate - a: t - - crate::a - b: t - - crate::a::b - c: t - - crate::a::b::c - X: t v - "#]], - ); -} - -#[test] -fn circular_mods() { - cov_mark::check!(circular_mods); - compute_crate_def_map( - r#" -//- /lib.rs -mod foo; -//- /foo.rs -#[path = "./foo.rs"] -mod foo; -"#, - ); - - compute_crate_def_map( - r#" -//- /lib.rs -mod foo; -//- /foo.rs -#[path = "./bar.rs"] -mod bar; -//- /bar.rs -#[path = "./foo.rs"] -mod foo; -"#, - ); -} - -#[test] -fn abs_path_ignores_local() { - check( - r#" -//- /main.rs crate:main deps:core -pub use ::core::hash::Hash; -pub mod core {} - -//- /lib.rs crate:core -pub mod hash { pub trait Hash {} } -"#, - expect![[r#" - crate - Hash: t - core: t - - crate::core - "#]], - ); -} - -#[test] -fn cfg_in_module_file() { - // Inner `#![cfg]` in a module file makes the whole module disappear. - check( - r#" -//- /main.rs -mod module; - -//- /module.rs -#![cfg(NEVER)] - -struct AlsoShoulntAppear; - "#, - expect![[r#" - crate - "#]], - ) -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/primitives.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/primitives.rs deleted file mode 100644 index 215e8952d9029..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/primitives.rs +++ /dev/null @@ -1,23 +0,0 @@ -use super::*; - -#[test] -fn primitive_reexport() { - check( - r#" -//- /lib.rs -mod foo; -use foo::int; - -//- /foo.rs -pub use i32 as int; -"#, - expect![[r#" - crate - foo: t - int: t - - crate::foo - int: t - "#]], - ); -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs deleted file mode 100644 index 2f13a9fbf0e40..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs +++ /dev/null @@ -1,222 +0,0 @@ -//! A desugared representation of paths like `crate::foo` or `::bar`. -mod lower; - -use std::{ - fmt::{self, Display}, - iter, -}; - -use crate::{ - body::LowerCtx, - intern::Interned, - type_ref::{ConstScalarOrPath, LifetimeRef}, -}; -use hir_expand::name::Name; -use syntax::ast; - -use crate::type_ref::{TypeBound, TypeRef}; - -pub use hir_expand::mod_path::{path, ModPath, PathKind}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ImportAlias { - /// Unnamed alias, as in `use Foo as _;` - Underscore, - /// Named alias - Alias(Name), -} - -impl Display for ImportAlias { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ImportAlias::Underscore => f.write_str("_"), - ImportAlias::Alias(name) => f.write_str(&name.to_smol_str()), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Path { - /// Type based path like `::foo`. - /// Note that paths like `::foo` are desugard to `Trait::::foo`. - type_anchor: Option>, - mod_path: Interned, - /// Invariant: the same len as `self.mod_path.segments` - generic_args: Box<[Option>]>, -} - -/// Generic arguments to a path segment (e.g. the `i32` in `Option`). This -/// also includes bindings of associated types, like in `Iterator`. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct GenericArgs { - pub args: Vec, - /// This specifies whether the args contain a Self type as the first - /// element. This is the case for path segments like ``, where - /// `T` is actually a type parameter for the path `Trait` specifying the - /// Self type. Otherwise, when we have a path `Trait`, the Self type - /// is left out. - pub has_self_type: bool, - /// Associated type bindings like in `Iterator`. - pub bindings: Vec, - /// Whether these generic args were desugared from `Trait(Arg) -> Output` - /// parenthesis notation typically used for the `Fn` traits. - pub desugared_from_fn: bool, -} - -/// An associated type binding like in `Iterator`. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct AssociatedTypeBinding { - /// The name of the associated type. - pub name: Name, - /// The type bound to this associated type (in `Item = T`, this would be the - /// `T`). This can be `None` if there are bounds instead. - pub type_ref: Option, - /// Bounds for the associated type, like in `Iterator`. (This is the unstable `associated_type_bounds` - /// feature.) - pub bounds: Vec>, -} - -/// A single generic argument. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum GenericArg { - Type(TypeRef), - Lifetime(LifetimeRef), - Const(ConstScalarOrPath), -} - -impl Path { - /// Converts an `ast::Path` to `Path`. Works with use trees. - /// It correctly handles `$crate` based path from macro call. - pub fn from_src(path: ast::Path, ctx: &LowerCtx<'_>) -> Option { - lower::lower_path(path, ctx) - } - - /// Converts a known mod path to `Path`. - pub fn from_known_path( - path: ModPath, - generic_args: impl Into>]>>, - ) -> Path { - let generic_args = generic_args.into(); - assert_eq!(path.len(), generic_args.len()); - Path { type_anchor: None, mod_path: Interned::new(path), generic_args } - } - - pub fn kind(&self) -> &PathKind { - &self.mod_path.kind - } - - pub fn type_anchor(&self) -> Option<&TypeRef> { - self.type_anchor.as_deref() - } - - pub fn segments(&self) -> PathSegments<'_> { - PathSegments { segments: self.mod_path.segments(), generic_args: &self.generic_args } - } - - pub fn mod_path(&self) -> &ModPath { - &self.mod_path - } - - pub fn qualifier(&self) -> Option { - if self.mod_path.is_ident() { - return None; - } - let res = Path { - type_anchor: self.type_anchor.clone(), - mod_path: Interned::new(ModPath::from_segments( - self.mod_path.kind, - self.mod_path.segments()[..self.mod_path.segments().len() - 1].iter().cloned(), - )), - generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec().into(), - }; - Some(res) - } - - pub fn is_self_type(&self) -> bool { - self.type_anchor.is_none() && *self.generic_args == [None] && self.mod_path.is_Self() - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct PathSegment<'a> { - pub name: &'a Name, - pub args_and_bindings: Option<&'a GenericArgs>, -} - -pub struct PathSegments<'a> { - segments: &'a [Name], - generic_args: &'a [Option>], -} - -impl<'a> PathSegments<'a> { - pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: &[] }; - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - pub fn len(&self) -> usize { - self.segments.len() - } - pub fn first(&self) -> Option> { - self.get(0) - } - pub fn last(&self) -> Option> { - self.get(self.len().checked_sub(1)?) - } - pub fn get(&self, idx: usize) -> Option> { - assert_eq!(self.segments.len(), self.generic_args.len()); - let res = PathSegment { - name: self.segments.get(idx)?, - args_and_bindings: self.generic_args.get(idx).unwrap().as_ref().map(|it| &**it), - }; - Some(res) - } - pub fn skip(&self, len: usize) -> PathSegments<'a> { - assert_eq!(self.segments.len(), self.generic_args.len()); - PathSegments { segments: &self.segments[len..], generic_args: &self.generic_args[len..] } - } - pub fn take(&self, len: usize) -> PathSegments<'a> { - assert_eq!(self.segments.len(), self.generic_args.len()); - PathSegments { segments: &self.segments[..len], generic_args: &self.generic_args[..len] } - } - pub fn iter(&self) -> impl Iterator> { - self.segments.iter().zip(self.generic_args.iter()).map(|(name, args)| PathSegment { - name, - args_and_bindings: args.as_ref().map(|it| &**it), - }) - } -} - -impl GenericArgs { - pub(crate) fn from_ast( - lower_ctx: &LowerCtx<'_>, - node: ast::GenericArgList, - ) -> Option { - lower::lower_generic_args(lower_ctx, node) - } - - pub(crate) fn empty() -> GenericArgs { - GenericArgs { - args: Vec::new(), - has_self_type: false, - bindings: Vec::new(), - desugared_from_fn: false, - } - } -} - -impl From for Path { - fn from(name: Name) -> Path { - Path { - type_anchor: None, - mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))), - generic_args: Box::new([None]), - } - } -} - -impl From for Box { - fn from(name: Name) -> Box { - Box::new(Path::from(name)) - } -} 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 deleted file mode 100644 index 0428f1a398b1a..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs +++ /dev/null @@ -1,230 +0,0 @@ -//! Transforms syntax into `Path` objects, ideally with accounting for hygiene - -use crate::{intern::Interned, type_ref::ConstScalarOrPath}; - -use either::Either; -use hir_expand::name::{name, AsName}; -use syntax::ast::{self, AstNode, HasTypeBounds}; - -use super::AssociatedTypeBinding; -use crate::{ - body::LowerCtx, - path::{GenericArg, GenericArgs, ModPath, Path, PathKind}, - type_ref::{LifetimeRef, TypeBound, TypeRef}, -}; - -/// Converts an `ast::Path` to `Path`. Works with use trees. -/// It correctly handles `$crate` based path from macro call. -pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option { - let mut kind = PathKind::Plain; - let mut type_anchor = None; - let mut segments = Vec::new(); - let mut generic_args = Vec::new(); - let hygiene = ctx.hygiene(); - loop { - let segment = path.segment()?; - - if segment.coloncolon_token().is_some() { - kind = PathKind::Abs; - } - - match segment.kind()? { - ast::PathSegmentKind::Name(name_ref) => { - // FIXME: this should just return name - match hygiene.name_ref_to_name(ctx.db.upcast(), name_ref) { - Either::Left(name) => { - let args = segment - .generic_arg_list() - .and_then(|it| lower_generic_args(ctx, it)) - .or_else(|| { - lower_generic_args_from_fn_path( - ctx, - segment.param_list(), - segment.ret_type(), - ) - }) - .map(Interned::new); - segments.push(name); - generic_args.push(args) - } - Either::Right(crate_id) => { - kind = PathKind::DollarCrate(crate_id); - break; - } - } - } - ast::PathSegmentKind::SelfTypeKw => { - segments.push(name![Self]); - generic_args.push(None) - } - ast::PathSegmentKind::Type { type_ref, trait_ref } => { - assert!(path.qualifier().is_none()); // this can only occur at the first segment - - let self_type = TypeRef::from_ast(ctx, type_ref?); - - match trait_ref { - // ::foo - None => { - type_anchor = Some(Interned::new(self_type)); - kind = PathKind::Plain; - } - // >::Foo desugars to Trait::Foo - Some(trait_ref) => { - let Path { mod_path, generic_args: path_generic_args, .. } = - Path::from_src(trait_ref.path()?, ctx)?; - let num_segments = mod_path.segments().len(); - kind = mod_path.kind; - - segments.extend(mod_path.segments().iter().cloned().rev()); - generic_args.extend(Vec::from(path_generic_args).into_iter().rev()); - - // Insert the type reference (T in the above example) as Self parameter for the trait - let last_segment = - generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?; - let mut args_inner = match last_segment { - Some(it) => it.as_ref().clone(), - None => GenericArgs::empty(), - }; - args_inner.has_self_type = true; - args_inner.args.insert(0, GenericArg::Type(self_type)); - *last_segment = Some(Interned::new(args_inner)); - } - } - } - ast::PathSegmentKind::CrateKw => { - kind = PathKind::Crate; - break; - } - ast::PathSegmentKind::SelfKw => { - // don't break out if `self` is the last segment of a path, this mean we got a - // use tree like `foo::{self}` which we want to resolve as `foo` - if !segments.is_empty() { - kind = PathKind::Super(0); - break; - } - } - ast::PathSegmentKind::SuperKw => { - let nested_super_count = if let PathKind::Super(n) = kind { n } else { 0 }; - kind = PathKind::Super(nested_super_count + 1); - } - } - path = match qualifier(&path) { - Some(it) => it, - None => break, - }; - } - segments.reverse(); - generic_args.reverse(); - - if segments.is_empty() && kind == PathKind::Plain && type_anchor.is_none() { - // plain empty paths don't exist, this means we got a single `self` segment as our path - kind = PathKind::Super(0); - } - - // handle local_inner_macros : - // Basically, even in rustc it is quite hacky: - // https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456 - // We follow what it did anyway :) - if segments.len() == 1 && kind == PathKind::Plain { - if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { - if let Some(crate_id) = hygiene.local_inner_macros(ctx.db.upcast(), path) { - kind = PathKind::DollarCrate(crate_id); - } - } - } - - let mod_path = Interned::new(ModPath::from_segments(kind, segments)); - return Some(Path { type_anchor, mod_path, generic_args: generic_args.into() }); - - fn qualifier(path: &ast::Path) -> Option { - if let Some(q) = path.qualifier() { - return Some(q); - } - // FIXME: this bottom up traversal is not too precise. - // Should we handle do a top-down analysis, recording results? - let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; - let use_tree = use_tree_list.parent_use_tree(); - use_tree.path() - } -} - -pub(super) fn lower_generic_args( - lower_ctx: &LowerCtx<'_>, - node: ast::GenericArgList, -) -> Option { - let mut args = Vec::new(); - let mut bindings = Vec::new(); - for generic_arg in node.generic_args() { - match generic_arg { - ast::GenericArg::TypeArg(type_arg) => { - let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.ty()); - args.push(GenericArg::Type(type_ref)); - } - ast::GenericArg::AssocTypeArg(assoc_type_arg) => { - if let Some(name_ref) = assoc_type_arg.name_ref() { - let name = name_ref.as_name(); - let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it)); - let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { - l.bounds() - .map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))) - .collect() - } else { - Vec::new() - }; - bindings.push(AssociatedTypeBinding { name, type_ref, bounds }); - } - } - ast::GenericArg::LifetimeArg(lifetime_arg) => { - if let Some(lifetime) = lifetime_arg.lifetime() { - let lifetime_ref = LifetimeRef::new(&lifetime); - args.push(GenericArg::Lifetime(lifetime_ref)) - } - } - ast::GenericArg::ConstArg(arg) => { - let arg = ConstScalarOrPath::from_expr_opt(arg.expr()); - args.push(GenericArg::Const(arg)) - } - } - } - - if args.is_empty() && bindings.is_empty() { - return None; - } - Some(GenericArgs { args, has_self_type: false, bindings, desugared_from_fn: false }) -} - -/// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) -/// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). -fn lower_generic_args_from_fn_path( - ctx: &LowerCtx<'_>, - params: Option, - ret_type: Option, -) -> Option { - let mut args = Vec::new(); - let mut bindings = Vec::new(); - let params = params?; - let mut param_types = Vec::new(); - for param in params.params() { - let type_ref = TypeRef::from_ast_opt(ctx, param.ty()); - param_types.push(type_ref); - } - let arg = GenericArg::Type(TypeRef::Tuple(param_types)); - args.push(arg); - if let Some(ret_type) = ret_type { - let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty()); - bindings.push(AssociatedTypeBinding { - name: name![Output], - type_ref: Some(type_ref), - bounds: Vec::new(), - }); - } else { - // -> () - let type_ref = TypeRef::Tuple(Vec::new()); - bindings.push(AssociatedTypeBinding { - name: name![Output], - type_ref: Some(type_ref), - bounds: Vec::new(), - }); - } - Some(GenericArgs { args, has_self_type: false, bindings, desugared_from_fn: true }) -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs deleted file mode 100644 index bf5bf10c4caaf..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs +++ /dev/null @@ -1,95 +0,0 @@ -//! In rust, it is possible to have a value, a type and a macro with the same -//! name without conflicts. -//! -//! `PerNs` (per namespace) captures this. - -use crate::{item_scope::ItemInNs, visibility::Visibility, MacroId, ModuleDefId}; - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct PerNs { - pub types: Option<(ModuleDefId, Visibility)>, - pub values: Option<(ModuleDefId, Visibility)>, - pub macros: Option<(MacroId, Visibility)>, -} - -impl Default for PerNs { - fn default() -> Self { - PerNs { types: None, values: None, macros: None } - } -} - -impl PerNs { - pub fn none() -> PerNs { - PerNs { types: None, values: None, macros: None } - } - - pub fn values(t: ModuleDefId, v: Visibility) -> PerNs { - PerNs { types: None, values: Some((t, v)), macros: None } - } - - pub fn types(t: ModuleDefId, v: Visibility) -> PerNs { - PerNs { types: Some((t, v)), values: None, macros: None } - } - - pub fn both(types: ModuleDefId, values: ModuleDefId, v: Visibility) -> PerNs { - PerNs { types: Some((types, v)), values: Some((values, v)), macros: None } - } - - pub fn macros(macro_: MacroId, v: Visibility) -> PerNs { - PerNs { types: None, values: None, macros: Some((macro_, v)) } - } - - pub fn is_none(&self) -> bool { - self.types.is_none() && self.values.is_none() && self.macros.is_none() - } - - pub fn take_types(self) -> Option { - self.types.map(|it| it.0) - } - - pub fn take_types_vis(self) -> Option<(ModuleDefId, Visibility)> { - self.types - } - - pub fn take_values(self) -> Option { - self.values.map(|it| it.0) - } - - pub fn take_macros(self) -> Option { - self.macros.map(|it| it.0) - } - - pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs { - let _p = profile::span("PerNs::filter_visibility"); - PerNs { - types: self.types.filter(|(_, v)| f(*v)), - values: self.values.filter(|(_, v)| f(*v)), - macros: self.macros.filter(|(_, v)| f(*v)), - } - } - - pub fn with_visibility(self, vis: Visibility) -> PerNs { - PerNs { - types: self.types.map(|(it, _)| (it, vis)), - values: self.values.map(|(it, _)| (it, vis)), - macros: self.macros.map(|(it, _)| (it, vis)), - } - } - - pub fn or(self, other: PerNs) -> PerNs { - PerNs { - types: self.types.or(other.types), - values: self.values.or(other.values), - macros: self.macros.or(other.macros), - } - } - - pub fn iter_items(self) -> impl Iterator { - let _p = profile::span("PerNs::iter_items"); - self.types - .map(|it| ItemInNs::Types(it.0)) - .into_iter() - .chain(self.values.map(|it| ItemInNs::Values(it.0)).into_iter()) - .chain(self.macros.map(|it| ItemInNs::Macros(it.0)).into_iter()) - } -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs deleted file mode 100644 index 3163fa0f93fa5..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ /dev/null @@ -1,912 +0,0 @@ -//! Name resolution façade. -use std::{hash::BuildHasherDefault, sync::Arc}; - -use base_db::CrateId; -use hir_expand::name::{name, Name}; -use indexmap::IndexMap; -use rustc_hash::FxHashSet; -use smallvec::{smallvec, SmallVec}; - -use crate::{ - body::scope::{ExprScopes, ScopeId}, - builtin_type::BuiltinType, - db::DefDatabase, - expr::{ExprId, LabelId, PatId}, - generics::{GenericParams, TypeOrConstParamData}, - intern::Interned, - item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, - nameres::DefMap, - path::{ModPath, PathKind}, - per_ns::PerNs, - visibility::{RawVisibility, Visibility}, - AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, - FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, - LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, - StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, VariantId, -}; - -#[derive(Debug, Clone)] -pub struct Resolver { - /// The stack of scopes, where the inner-most scope is the last item. - /// - /// When using, you generally want to process the scopes in reverse order, - /// there's `scopes` *method* for that. - /// - /// Invariant: There exists at least one Scope::ModuleScope at the start of the vec. - scopes: Vec, -} - -// FIXME how to store these best -#[derive(Debug, Clone)] -struct ModuleItemMap { - def_map: Arc, - module_id: LocalModuleId, -} - -#[derive(Debug, Clone)] -struct ExprScope { - owner: DefWithBodyId, - expr_scopes: Arc, - scope_id: ScopeId, -} - -#[derive(Debug, Clone)] -enum Scope { - /// All the items and imported names of a module - ModuleScope(ModuleItemMap), - /// Brings the generic parameters of an item into scope - GenericParams { def: GenericDefId, params: Interned }, - /// Brings `Self` in `impl` block into scope - ImplDefScope(ImplId), - /// Brings `Self` in enum, struct and union definitions into scope - AdtScope(AdtId), - /// Local bindings - ExprScope(ExprScope), -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum TypeNs { - SelfType(ImplId), - GenericParam(TypeParamId), - AdtId(AdtId), - AdtSelfType(AdtId), - // Yup, enum variants are added to the types ns, but any usage of variant as - // type is an error. - EnumVariantId(EnumVariantId), - TypeAliasId(TypeAliasId), - BuiltinType(BuiltinType), - TraitId(TraitId), - // Module belong to type ns, but the resolver is used when all module paths - // are fully resolved. - // ModuleId(ModuleId) -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ResolveValueResult { - ValueNs(ValueNs), - Partial(TypeNs, usize), -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ValueNs { - ImplSelf(ImplId), - LocalBinding(PatId), - FunctionId(FunctionId), - ConstId(ConstId), - StaticId(StaticId), - StructId(StructId), - EnumVariantId(EnumVariantId), - GenericParam(ConstParamId), -} - -impl Resolver { - /// Resolve known trait from std, like `std::futures::Future` - pub fn resolve_known_trait(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { - let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?; - match res { - ModuleDefId::TraitId(it) => Some(it), - _ => None, - } - } - - /// Resolve known struct from std, like `std::boxed::Box` - pub fn resolve_known_struct(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { - let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?; - match res { - ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it), - _ => None, - } - } - - /// Resolve known enum from std, like `std::result::Result` - pub fn resolve_known_enum(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { - let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?; - match res { - ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it), - _ => None, - } - } - - fn scopes(&self) -> impl Iterator { - self.scopes.iter().rev() - } - - fn resolve_module_path( - &self, - db: &dyn DefDatabase, - path: &ModPath, - shadow: BuiltinShadowMode, - ) -> PerNs { - let (item_map, module) = self.module_scope(); - let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow); - if segment_index.is_some() { - return PerNs::none(); - } - module_res - } - - pub fn resolve_module_path_in_items(&self, db: &dyn DefDatabase, path: &ModPath) -> PerNs { - self.resolve_module_path(db, path, BuiltinShadowMode::Module) - } - - // FIXME: This shouldn't exist - pub fn resolve_module_path_in_trait_assoc_items( - &self, - db: &dyn DefDatabase, - path: &ModPath, - ) -> Option { - let (item_map, module) = self.module_scope(); - let (module_res, idx) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module); - match module_res.take_types()? { - ModuleDefId::TraitId(it) => { - let idx = idx?; - let unresolved = &path.segments()[idx..]; - let assoc = match unresolved { - [it] => it, - _ => return None, - }; - let &(_, assoc) = db.trait_data(it).items.iter().find(|(n, _)| n == assoc)?; - Some(match assoc { - AssocItemId::FunctionId(it) => PerNs::values(it.into(), Visibility::Public), - AssocItemId::ConstId(it) => PerNs::values(it.into(), Visibility::Public), - AssocItemId::TypeAliasId(it) => PerNs::types(it.into(), Visibility::Public), - }) - } - _ => None, - } - } - - pub fn resolve_path_in_type_ns( - &self, - db: &dyn DefDatabase, - path: &ModPath, - ) -> Option<(TypeNs, Option)> { - let first_name = path.segments().first()?; - let skip_to_mod = path.kind != PathKind::Plain; - for scope in self.scopes() { - match scope { - Scope::ExprScope(_) => continue, - Scope::GenericParams { .. } | Scope::ImplDefScope(_) if skip_to_mod => continue, - - Scope::GenericParams { params, def } => { - if let Some(id) = params.find_type_by_name(first_name, *def) { - let idx = if path.segments().len() == 1 { None } else { Some(1) }; - return Some((TypeNs::GenericParam(id), idx)); - } - } - Scope::ImplDefScope(impl_) => { - if first_name == &name![Self] { - let idx = if path.segments().len() == 1 { None } else { Some(1) }; - return Some((TypeNs::SelfType(*impl_), idx)); - } - } - Scope::AdtScope(adt) => { - if first_name == &name![Self] { - let idx = if path.segments().len() == 1 { None } else { Some(1) }; - return Some((TypeNs::AdtSelfType(*adt), idx)); - } - } - Scope::ModuleScope(m) => { - if let Some(res) = m.resolve_path_in_type_ns(db, path) { - return Some(res); - } - } - } - } - None - } - - pub fn resolve_path_in_type_ns_fully( - &self, - db: &dyn DefDatabase, - path: &ModPath, - ) -> Option { - let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?; - if unresolved.is_some() { - return None; - } - Some(res) - } - - pub fn resolve_visibility( - &self, - db: &dyn DefDatabase, - visibility: &RawVisibility, - ) -> Option { - match visibility { - RawVisibility::Module(_) => { - let (item_map, module) = self.module_scope(); - item_map.resolve_visibility(db, module, visibility) - } - RawVisibility::Public => Some(Visibility::Public), - } - } - - pub fn resolve_path_in_value_ns( - &self, - db: &dyn DefDatabase, - path: &ModPath, - ) -> Option { - let n_segments = path.segments().len(); - let tmp = name![self]; - let first_name = if path.is_self() { &tmp } else { path.segments().first()? }; - let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); - for scope in self.scopes() { - match scope { - Scope::AdtScope(_) - | Scope::ExprScope(_) - | Scope::GenericParams { .. } - | Scope::ImplDefScope(_) - if skip_to_mod => - { - continue - } - - Scope::ExprScope(scope) if n_segments <= 1 => { - let entry = scope - .expr_scopes - .entries(scope.scope_id) - .iter() - .find(|entry| entry.name() == first_name); - - if let Some(e) = entry { - return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat()))); - } - } - Scope::ExprScope(_) => continue, - - Scope::GenericParams { params, def } if n_segments > 1 => { - if let Some(id) = params.find_type_by_name(first_name, *def) { - let ty = TypeNs::GenericParam(id); - return Some(ResolveValueResult::Partial(ty, 1)); - } - } - Scope::GenericParams { params, def } if n_segments == 1 => { - if let Some(id) = params.find_const_by_name(first_name, *def) { - let val = ValueNs::GenericParam(id); - return Some(ResolveValueResult::ValueNs(val)); - } - } - Scope::GenericParams { .. } => continue, - - Scope::ImplDefScope(impl_) => { - if first_name == &name![Self] { - if n_segments > 1 { - let ty = TypeNs::SelfType(*impl_); - return Some(ResolveValueResult::Partial(ty, 1)); - } else { - return Some(ResolveValueResult::ValueNs(ValueNs::ImplSelf(*impl_))); - } - } - } - Scope::AdtScope(adt) => { - if n_segments == 1 { - // bare `Self` doesn't work in the value namespace in a struct/enum definition - continue; - } - if first_name == &name![Self] { - let ty = TypeNs::AdtSelfType(*adt); - return Some(ResolveValueResult::Partial(ty, 1)); - } - } - - Scope::ModuleScope(m) => { - if let Some(def) = m.resolve_path_in_value_ns(db, path) { - return Some(def); - } - } - } - } - - // If a path of the shape `u16::from_le_bytes` failed to resolve at all, then we fall back - // to resolving to the primitive type, to allow this to still work in the presence of - // `use core::u16;`. - if path.kind == PathKind::Plain && path.segments().len() > 1 { - match BuiltinType::by_name(&path.segments()[0]) { - Some(builtin) => { - return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1)); - } - None => {} - } - } - - None - } - - pub fn resolve_path_in_value_ns_fully( - &self, - db: &dyn DefDatabase, - path: &ModPath, - ) -> Option { - match self.resolve_path_in_value_ns(db, path)? { - ResolveValueResult::ValueNs(it) => Some(it), - ResolveValueResult::Partial(..) => None, - } - } - - pub fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { - let (item_map, module) = self.module_scope(); - item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros() - } - - /// Returns a set of names available in the current scope. - /// - /// Note that this is a somewhat fuzzy concept -- internally, the compiler - /// doesn't necessary follow a strict scoping discipline. Rather, it just - /// tells for each ident what it resolves to. - /// - /// A good example is something like `str::from_utf8`. From scopes point of - /// view, this code is erroneous -- both `str` module and `str` type occupy - /// the same type namespace. - /// - /// We don't try to model that super-correctly -- this functionality is - /// primarily exposed for completions. - /// - /// Note that in Rust one name can be bound to several items: - /// - /// ``` - /// macro_rules! t { () => (()) } - /// type t = t!(); - /// const t: t = t!() - /// ``` - /// - /// That's why we return a multimap. - /// - /// The shadowing is accounted for: in - /// - /// ``` - /// let x = 92; - /// { - /// let x = 92; - /// $0 - /// } - /// ``` - /// - /// there will be only one entry for `x` in the result. - /// - /// The result is ordered *roughly* from the innermost scope to the - /// outermost: when the name is introduced in two namespaces in two scopes, - /// we use the position of the first scope. - pub fn names_in_scope( - &self, - db: &dyn DefDatabase, - ) -> FxIndexMap> { - let mut res = ScopeNames::default(); - for scope in self.scopes() { - scope.process_names(&mut res, db); - } - res.map - } - - pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet { - let mut traits = FxHashSet::default(); - for scope in self.scopes() { - match scope { - Scope::ModuleScope(m) => { - if let Some(prelude) = m.def_map.prelude() { - let prelude_def_map = prelude.def_map(db); - traits.extend(prelude_def_map[prelude.local_id].scope.traits()); - } - traits.extend(m.def_map[m.module_id].scope.traits()); - - // Add all traits that are in scope because of the containing DefMaps - m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| { - if let Some(prelude) = def_map.prelude() { - let prelude_def_map = prelude.def_map(db); - traits.extend(prelude_def_map[prelude.local_id].scope.traits()); - } - traits.extend(def_map[module].scope.traits()); - None::<()> - }); - } - &Scope::ImplDefScope(impl_) => { - if let Some(target_trait) = &db.impl_data(impl_).target_trait { - if let Some(TypeNs::TraitId(trait_)) = - self.resolve_path_in_type_ns_fully(db, target_trait.path.mod_path()) - { - traits.insert(trait_); - } - } - } - _ => (), - } - } - traits - } - - fn module_scope(&self) -> (&DefMap, LocalModuleId) { - self.scopes() - .find_map(|scope| match scope { - Scope::ModuleScope(m) => Some((&*m.def_map, m.module_id)), - _ => None, - }) - .expect("module scope invariant violated") - } - - pub fn module(&self) -> ModuleId { - let (def_map, local_id) = self.module_scope(); - def_map.module_id(local_id) - } - - pub fn krate(&self) -> CrateId { - self.def_map().krate() - } - - pub fn def_map(&self) -> &DefMap { - self.scopes - .get(0) - .and_then(|scope| match scope { - Scope::ModuleScope(m) => Some(&m.def_map), - _ => None, - }) - .expect("module scope invariant violated") - } - - pub fn where_predicates_in_scope( - &self, - ) -> impl Iterator { - self.scopes() - .filter_map(|scope| match scope { - Scope::GenericParams { params, .. } => Some(params), - _ => None, - }) - .flat_map(|params| params.where_predicates.iter()) - } - - pub fn generic_def(&self) -> Option { - self.scopes().find_map(|scope| match scope { - Scope::GenericParams { def, .. } => Some(*def), - _ => None, - }) - } - - pub fn body_owner(&self) -> Option { - self.scopes().find_map(|scope| match scope { - Scope::ExprScope(it) => Some(it.owner), - _ => None, - }) - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum ScopeDef { - ModuleDef(ModuleDefId), - Unknown, - ImplSelfType(ImplId), - AdtSelfType(AdtId), - GenericParam(GenericParamId), - Local(PatId), - Label(LabelId), -} - -impl Scope { - fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) { - match self { - Scope::ModuleScope(m) => { - // FIXME: should we provide `self` here? - // f( - // Name::self_param(), - // PerNs::types(Resolution::Def { - // def: m.module.into(), - // }), - // ); - m.def_map[m.module_id].scope.entries().for_each(|(name, def)| { - acc.add_per_ns(name, def); - }); - m.def_map[m.module_id].scope.legacy_macros().for_each(|(name, macs)| { - macs.iter().for_each(|&mac| { - acc.add( - name, - ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac))), - ); - }) - }); - m.def_map.extern_prelude().for_each(|(name, &def)| { - acc.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def))); - }); - BUILTIN_SCOPE.iter().for_each(|(name, &def)| { - acc.add_per_ns(name, def); - }); - if let Some(prelude) = m.def_map.prelude() { - let prelude_def_map = prelude.def_map(db); - for (name, def) in prelude_def_map[prelude.local_id].scope.entries() { - acc.add_per_ns(name, def) - } - } - } - Scope::GenericParams { params, def: parent } => { - let parent = *parent; - for (local_id, param) in params.type_or_consts.iter() { - if let Some(name) = ¶m.name() { - let id = TypeOrConstParamId { parent, local_id }; - let data = &db.generic_params(parent).type_or_consts[local_id]; - acc.add( - name, - ScopeDef::GenericParam(match data { - TypeOrConstParamData::TypeParamData(_) => { - GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)) - } - TypeOrConstParamData::ConstParamData(_) => { - GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)) - } - }), - ); - } - } - for (local_id, param) in params.lifetimes.iter() { - let id = LifetimeParamId { parent, local_id }; - acc.add(¶m.name, ScopeDef::GenericParam(id.into())) - } - } - Scope::ImplDefScope(i) => { - acc.add(&name![Self], ScopeDef::ImplSelfType(*i)); - } - Scope::AdtScope(i) => { - acc.add(&name![Self], ScopeDef::AdtSelfType(*i)); - } - Scope::ExprScope(scope) => { - if let Some((label, name)) = scope.expr_scopes.label(scope.scope_id) { - acc.add(&name, ScopeDef::Label(label)) - } - scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { - acc.add_local(e.name(), e.pat()); - }); - } - } - } -} - -// needs arbitrary_self_types to be a method... or maybe move to the def? -pub fn resolver_for_expr(db: &dyn DefDatabase, owner: DefWithBodyId, expr_id: ExprId) -> Resolver { - let scopes = db.expr_scopes(owner); - resolver_for_scope(db, owner, scopes.scope_for(expr_id)) -} - -pub fn resolver_for_scope( - db: &dyn DefDatabase, - owner: DefWithBodyId, - scope_id: Option, -) -> Resolver { - let mut r = owner.resolver(db); - let scopes = db.expr_scopes(owner); - let scope_chain = scopes.scope_chain(scope_id).collect::>(); - r.scopes.reserve(scope_chain.len()); - - for scope in scope_chain.into_iter().rev() { - if let Some(block) = scopes.block(scope) { - if let Some(def_map) = db.block_def_map(block) { - let root = def_map.root(); - r = r.push_module_scope(def_map, root); - // FIXME: This adds as many module scopes as there are blocks, but resolving in each - // already traverses all parents, so this is O(n²). I think we could only store the - // innermost module scope instead? - } - } - - r = r.push_expr_scope(owner, Arc::clone(&scopes), scope); - } - r -} - -impl Resolver { - fn push_scope(mut self, scope: Scope) -> Resolver { - self.scopes.push(scope); - self - } - - fn push_generic_params_scope(self, db: &dyn DefDatabase, def: GenericDefId) -> Resolver { - let params = db.generic_params(def); - self.push_scope(Scope::GenericParams { def, params }) - } - - fn push_impl_def_scope(self, impl_def: ImplId) -> Resolver { - self.push_scope(Scope::ImplDefScope(impl_def)) - } - - fn push_module_scope(self, def_map: Arc, module_id: LocalModuleId) -> Resolver { - self.push_scope(Scope::ModuleScope(ModuleItemMap { def_map, module_id })) - } - - fn push_expr_scope( - self, - owner: DefWithBodyId, - expr_scopes: Arc, - scope_id: ScopeId, - ) -> Resolver { - self.push_scope(Scope::ExprScope(ExprScope { owner, expr_scopes, scope_id })) - } -} - -impl ModuleItemMap { - fn resolve_path_in_value_ns( - &self, - db: &dyn DefDatabase, - path: &ModPath, - ) -> Option { - let (module_def, idx) = - self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other); - match idx { - None => { - let value = to_value_ns(module_def)?; - Some(ResolveValueResult::ValueNs(value)) - } - Some(idx) => { - let ty = match module_def.take_types()? { - ModuleDefId::AdtId(it) => TypeNs::AdtId(it), - ModuleDefId::TraitId(it) => TypeNs::TraitId(it), - ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it), - ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), - - ModuleDefId::ModuleId(_) - | ModuleDefId::FunctionId(_) - | ModuleDefId::EnumVariantId(_) - | ModuleDefId::ConstId(_) - | ModuleDefId::MacroId(_) - | ModuleDefId::StaticId(_) => return None, - }; - Some(ResolveValueResult::Partial(ty, idx)) - } - } - } - - fn resolve_path_in_type_ns( - &self, - db: &dyn DefDatabase, - path: &ModPath, - ) -> Option<(TypeNs, Option)> { - let (module_def, idx) = - self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other); - let res = to_type_ns(module_def)?; - Some((res, idx)) - } -} - -fn to_value_ns(per_ns: PerNs) -> Option { - let res = match per_ns.take_values()? { - ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it), - ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it), - ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it), - ModuleDefId::ConstId(it) => ValueNs::ConstId(it), - ModuleDefId::StaticId(it) => ValueNs::StaticId(it), - - ModuleDefId::AdtId(AdtId::EnumId(_) | AdtId::UnionId(_)) - | ModuleDefId::TraitId(_) - | ModuleDefId::TypeAliasId(_) - | ModuleDefId::BuiltinType(_) - | ModuleDefId::MacroId(_) - | ModuleDefId::ModuleId(_) => return None, - }; - Some(res) -} - -fn to_type_ns(per_ns: PerNs) -> Option { - let res = match per_ns.take_types()? { - ModuleDefId::AdtId(it) => TypeNs::AdtId(it), - ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it), - - ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it), - ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), - - ModuleDefId::TraitId(it) => TypeNs::TraitId(it), - - ModuleDefId::FunctionId(_) - | ModuleDefId::ConstId(_) - | ModuleDefId::MacroId(_) - | ModuleDefId::StaticId(_) - | ModuleDefId::ModuleId(_) => return None, - }; - Some(res) -} - -type FxIndexMap = IndexMap>; -#[derive(Default)] -struct ScopeNames { - map: FxIndexMap>, -} - -impl ScopeNames { - fn add(&mut self, name: &Name, def: ScopeDef) { - let set = self.map.entry(name.clone()).or_default(); - if !set.contains(&def) { - set.push(def) - } - } - fn add_per_ns(&mut self, name: &Name, def: PerNs) { - if let &Some((ty, _)) = &def.types { - self.add(name, ScopeDef::ModuleDef(ty)) - } - if let &Some((def, _)) = &def.values { - self.add(name, ScopeDef::ModuleDef(def)) - } - if let &Some((mac, _)) = &def.macros { - self.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac))) - } - if def.is_none() { - self.add(name, ScopeDef::Unknown) - } - } - fn add_local(&mut self, name: &Name, pat: PatId) { - let set = self.map.entry(name.clone()).or_default(); - // XXX: hack, account for local (and only local) shadowing. - // - // This should be somewhat more principled and take namespaces into - // accounts, but, alas, scoping rules are a hoax. `str` type and `str` - // module can be both available in the same scope. - if set.iter().any(|it| matches!(it, &ScopeDef::Local(_))) { - cov_mark::hit!(shadowing_shows_single_completion); - return; - } - set.push(ScopeDef::Local(pat)) - } -} - -pub trait HasResolver: Copy { - /// Builds a resolver for type references inside this def. - fn resolver(self, db: &dyn DefDatabase) -> Resolver; -} - -impl HasResolver for ModuleId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - let mut def_map = self.def_map(db); - let mut modules: SmallVec<[_; 2]> = smallvec![(def_map.clone(), self.local_id)]; - while let Some(parent) = def_map.parent() { - def_map = parent.def_map(db); - modules.push((def_map.clone(), parent.local_id)); - } - let mut resolver = Resolver { scopes: Vec::with_capacity(modules.len()) }; - for (def_map, module) in modules.into_iter().rev() { - resolver = resolver.push_module_scope(def_map, module); - } - resolver - } -} - -impl HasResolver for TraitId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) - } -} - -impl + Copy> HasResolver for T { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - let def = self.into(); - def.module(db) - .resolver(db) - .push_generic_params_scope(db, def.into()) - .push_scope(Scope::AdtScope(def)) - } -} - -impl HasResolver for FunctionId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) - } -} - -impl HasResolver for ConstId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db) - } -} - -impl HasResolver for StaticId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db) - } -} - -impl HasResolver for TypeAliasId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) - } -} - -impl HasResolver for ImplId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db) - .container - .resolver(db) - .push_generic_params_scope(db, self.into()) - .push_impl_def_scope(self) - } -} - -impl HasResolver for ExternBlockId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - // Same as parent's - self.lookup(db).container.resolver(db) - } -} - -impl HasResolver for DefWithBodyId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - match self { - DefWithBodyId::ConstId(c) => c.resolver(db), - DefWithBodyId::FunctionId(f) => f.resolver(db), - DefWithBodyId::StaticId(s) => s.resolver(db), - } - } -} - -impl HasResolver for ItemContainerId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - match self { - ItemContainerId::ModuleId(it) => it.resolver(db), - ItemContainerId::TraitId(it) => it.resolver(db), - ItemContainerId::ImplId(it) => it.resolver(db), - ItemContainerId::ExternBlockId(it) => it.resolver(db), - } - } -} - -impl HasResolver for GenericDefId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - match self { - GenericDefId::FunctionId(inner) => inner.resolver(db), - GenericDefId::AdtId(adt) => adt.resolver(db), - GenericDefId::TraitId(inner) => inner.resolver(db), - GenericDefId::TypeAliasId(inner) => inner.resolver(db), - GenericDefId::ImplId(inner) => inner.resolver(db), - GenericDefId::EnumVariantId(inner) => inner.parent.resolver(db), - GenericDefId::ConstId(inner) => inner.resolver(db), - } - } -} - -impl HasResolver for VariantId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - match self { - VariantId::EnumVariantId(it) => it.parent.resolver(db), - VariantId::StructId(it) => it.resolver(db), - VariantId::UnionId(it) => it.resolver(db), - } - } -} - -impl HasResolver for MacroId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - match self { - MacroId::Macro2Id(it) => it.resolver(db), - MacroId::MacroRulesId(it) => it.resolver(db), - MacroId::ProcMacroId(it) => it.resolver(db), - } - } -} - -impl HasResolver for Macro2Id { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db) - } -} - -impl HasResolver for ProcMacroId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db) - } -} - -impl HasResolver for MacroRulesId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db) - } -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/src.rs b/src/tools/rust-analyzer/crates/hir-def/src/src.rs deleted file mode 100644 index f69356cac87d3..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/src.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! Utilities for mapping between hir IDs and the surface syntax. - -use hir_expand::InFile; -use la_arena::ArenaMap; -use syntax::ast; - -use crate::{ - db::DefDatabase, item_tree::ItemTreeNode, AssocItemLoc, ItemLoc, Macro2Loc, MacroRulesLoc, - ProcMacroLoc, -}; - -pub trait HasSource { - type Value; - fn source(&self, db: &dyn DefDatabase) -> InFile; -} - -impl HasSource for AssocItemLoc { - type Value = N::Source; - - fn source(&self, db: &dyn DefDatabase) -> InFile { - let tree = self.id.item_tree(db); - let ast_id_map = db.ast_id_map(self.id.file_id()); - let root = db.parse_or_expand(self.id.file_id()).unwrap(); - let node = &tree[self.id.value]; - - InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root)) - } -} - -impl HasSource for ItemLoc { - type Value = N::Source; - - fn source(&self, db: &dyn DefDatabase) -> InFile { - let tree = self.id.item_tree(db); - let ast_id_map = db.ast_id_map(self.id.file_id()); - let root = db.parse_or_expand(self.id.file_id()).unwrap(); - let node = &tree[self.id.value]; - - InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root)) - } -} - -impl HasSource for Macro2Loc { - type Value = ast::MacroDef; - - fn source(&self, db: &dyn DefDatabase) -> InFile { - let tree = self.id.item_tree(db); - let ast_id_map = db.ast_id_map(self.id.file_id()); - let root = db.parse_or_expand(self.id.file_id()).unwrap(); - let node = &tree[self.id.value]; - - InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root)) - } -} - -impl HasSource for MacroRulesLoc { - type Value = ast::MacroRules; - - fn source(&self, db: &dyn DefDatabase) -> InFile { - let tree = self.id.item_tree(db); - let ast_id_map = db.ast_id_map(self.id.file_id()); - let root = db.parse_or_expand(self.id.file_id()).unwrap(); - let node = &tree[self.id.value]; - - InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root)) - } -} - -impl HasSource for ProcMacroLoc { - type Value = ast::Fn; - - fn source(&self, db: &dyn DefDatabase) -> InFile { - let tree = self.id.item_tree(db); - let ast_id_map = db.ast_id_map(self.id.file_id()); - let root = db.parse_or_expand(self.id.file_id()).unwrap(); - let node = &tree[self.id.value]; - - InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root)) - } -} - -pub trait HasChildSource { - type Value; - fn child_source(&self, db: &dyn DefDatabase) -> InFile>; -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs deleted file mode 100644 index 9cdc18d6b66fd..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs +++ /dev/null @@ -1,245 +0,0 @@ -//! Database used for testing `hir_def`. - -use std::{ - fmt, panic, - sync::{Arc, Mutex}, -}; - -use base_db::{ - salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, FilePosition, - SourceDatabase, Upcast, -}; -use hir_expand::{db::AstDatabase, InFile}; -use rustc_hash::FxHashSet; -use syntax::{algo, ast, AstNode}; - -use crate::{ - db::DefDatabase, - nameres::{DefMap, ModuleSource}, - src::HasSource, - LocalModuleId, Lookup, ModuleDefId, ModuleId, -}; - -#[salsa::database( - base_db::SourceDatabaseExtStorage, - base_db::SourceDatabaseStorage, - hir_expand::db::AstDatabaseStorage, - crate::db::InternDatabaseStorage, - crate::db::DefDatabaseStorage -)] -pub(crate) struct TestDB { - storage: salsa::Storage, - events: Mutex>>, -} - -impl Default for TestDB { - fn default() -> Self { - let mut this = Self { storage: Default::default(), events: Default::default() }; - this.set_enable_proc_attr_macros(true); - this - } -} - -impl Upcast for TestDB { - fn upcast(&self) -> &(dyn AstDatabase + 'static) { - &*self - } -} - -impl Upcast for TestDB { - fn upcast(&self) -> &(dyn DefDatabase + 'static) { - &*self - } -} - -impl salsa::Database for TestDB { - fn salsa_event(&self, event: salsa::Event) { - let mut events = self.events.lock().unwrap(); - if let Some(events) = &mut *events { - events.push(event); - } - } -} - -impl fmt::Debug for TestDB { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TestDB").finish() - } -} - -impl panic::RefUnwindSafe for TestDB {} - -impl FileLoader for TestDB { - fn file_text(&self, file_id: FileId) -> Arc { - FileLoaderDelegate(self).file_text(file_id) - } - fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { - FileLoaderDelegate(self).resolve_path(path) - } - fn relevant_crates(&self, file_id: FileId) -> Arc> { - FileLoaderDelegate(self).relevant_crates(file_id) - } -} - -impl TestDB { - pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId { - for &krate in self.relevant_crates(file_id).iter() { - let crate_def_map = self.crate_def_map(krate); - for (local_id, data) in crate_def_map.modules() { - if data.origin.file_id() == Some(file_id) { - return crate_def_map.module_id(local_id); - } - } - } - panic!("Can't find module for file") - } - - pub(crate) fn module_at_position(&self, position: FilePosition) -> ModuleId { - let file_module = self.module_for_file(position.file_id); - let mut def_map = file_module.def_map(self); - let module = self.mod_at_position(&def_map, position); - - def_map = match self.block_at_position(&def_map, position) { - Some(it) => it, - None => return def_map.module_id(module), - }; - loop { - let new_map = self.block_at_position(&def_map, position); - match new_map { - Some(new_block) if !Arc::ptr_eq(&new_block, &def_map) => { - def_map = new_block; - } - _ => { - // FIXME: handle `mod` inside block expression - return def_map.module_id(def_map.root()); - } - } - } - } - - /// Finds the smallest/innermost module in `def_map` containing `position`. - fn mod_at_position(&self, def_map: &DefMap, position: FilePosition) -> LocalModuleId { - let mut size = None; - let mut res = def_map.root(); - for (module, data) in def_map.modules() { - let src = data.definition_source(self); - if src.file_id != position.file_id.into() { - continue; - } - - let range = match src.value { - ModuleSource::SourceFile(it) => it.syntax().text_range(), - ModuleSource::Module(it) => it.syntax().text_range(), - ModuleSource::BlockExpr(it) => it.syntax().text_range(), - }; - - if !range.contains(position.offset) { - continue; - } - - let new_size = match size { - None => range.len(), - Some(size) => { - if range.len() < size { - range.len() - } else { - size - } - } - }; - - if size != Some(new_size) { - cov_mark::hit!(submodule_in_testdb); - size = Some(new_size); - res = module; - } - } - - res - } - - fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option> { - // Find the smallest (innermost) function in `def_map` containing the cursor. - let mut size = None; - let mut fn_def = None; - for (_, module) in def_map.modules() { - let file_id = module.definition_source(self).file_id; - if file_id != position.file_id.into() { - continue; - } - for decl in module.scope.declarations() { - if let ModuleDefId::FunctionId(it) = decl { - let range = it.lookup(self).source(self).value.syntax().text_range(); - - if !range.contains(position.offset) { - continue; - } - - let new_size = match size { - None => range.len(), - Some(size) => { - if range.len() < size { - range.len() - } else { - size - } - } - }; - if size != Some(new_size) { - size = Some(new_size); - fn_def = Some(it); - } - } - } - } - - // Find the innermost block expression that has a `DefMap`. - let def_with_body = fn_def?.into(); - let (_, source_map) = self.body_with_source_map(def_with_body); - let scopes = self.expr_scopes(def_with_body); - let root = self.parse(position.file_id); - - let scope_iter = algo::ancestors_at_offset(&root.syntax_node(), position.offset) - .filter_map(|node| { - let block = ast::BlockExpr::cast(node)?; - let expr = ast::Expr::from(block); - let expr_id = source_map.node_expr(InFile::new(position.file_id.into(), &expr))?; - let scope = scopes.scope_for(expr_id).unwrap(); - Some(scope) - }); - - for scope in scope_iter { - let containing_blocks = - scopes.scope_chain(Some(scope)).filter_map(|scope| scopes.block(scope)); - - for block in containing_blocks { - if let Some(def_map) = self.block_def_map(block) { - return Some(def_map); - } - } - } - - None - } - - pub(crate) fn log(&self, f: impl FnOnce()) -> Vec { - *self.events.lock().unwrap() = Some(Vec::new()); - f(); - self.events.lock().unwrap().take().unwrap() - } - - pub(crate) fn log_executed(&self, f: impl FnOnce()) -> Vec { - let events = self.log(f); - events - .into_iter() - .filter_map(|e| match e.kind { - // This is pretty horrible, but `Debug` is the only way to inspect - // QueryDescriptor at the moment. - salsa::EventKind::WillExecute { database_key } => { - Some(format!("{:?}", database_key.debug(self))) - } - _ => None, - }) - .collect() - } -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/trace.rs b/src/tools/rust-analyzer/crates/hir-def/src/trace.rs deleted file mode 100644 index 6e6ceb8e47495..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/trace.rs +++ /dev/null @@ -1,51 +0,0 @@ -//! Trace is a pretty niche data structure which is used when lowering a CST -//! into HIR. -//! -//! Lowering process calculates two bits of information: -//! * the lowered syntax itself -//! * a mapping between lowered syntax and original syntax -//! -//! Due to the way salsa works, the mapping is usually hot lava, as it contains -//! absolute offsets. The `Trace` structure (inspired, at least in name, by -//! Kotlin's `BindingTrace`) allows use the same code to compute both -//! projections. -use la_arena::{Arena, ArenaMap, Idx, RawIdx}; - -pub(crate) struct Trace { - arena: Option>, - map: Option, V>>, - len: u32, -} - -impl Trace { - pub(crate) fn new_for_arena() -> Trace { - Trace { arena: Some(Arena::default()), map: None, len: 0 } - } - - pub(crate) fn new_for_map() -> Trace { - Trace { arena: None, map: Some(ArenaMap::default()), len: 0 } - } - - pub(crate) fn alloc(&mut self, value: impl FnOnce() -> V, data: impl FnOnce() -> T) -> Idx { - let id = if let Some(arena) = &mut self.arena { - arena.alloc(data()) - } else { - let id = Idx::::from_raw(RawIdx::from(self.len)); - self.len += 1; - id - }; - - if let Some(map) = &mut self.map { - map.insert(id, value()); - } - id - } - - pub(crate) fn into_arena(mut self) -> Arena { - self.arena.take().unwrap() - } - - pub(crate) fn into_map(mut self) -> ArenaMap, V> { - self.map.take().unwrap() - } -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs deleted file mode 100644 index 9248059627d2a..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs +++ /dev/null @@ -1,486 +0,0 @@ -//! HIR for references to types. Paths in these are not yet resolved. They can -//! be directly created from an ast::TypeRef, without further queries. - -use std::fmt::Write; - -use hir_expand::{ - name::{AsName, Name}, - AstId, -}; -use syntax::ast::{self, HasName}; - -use crate::{ - body::LowerCtx, - builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, - expr::Literal, - intern::Interned, - path::Path, -}; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum Mutability { - Shared, - Mut, -} - -impl Mutability { - pub fn from_mutable(mutable: bool) -> Mutability { - if mutable { - Mutability::Mut - } else { - Mutability::Shared - } - } - - pub fn as_keyword_for_ref(self) -> &'static str { - match self { - Mutability::Shared => "", - Mutability::Mut => "mut ", - } - } - - pub fn as_keyword_for_ptr(self) -> &'static str { - match self { - Mutability::Shared => "const ", - Mutability::Mut => "mut ", - } - } - - /// Returns `true` if the mutability is [`Mut`]. - /// - /// [`Mut`]: Mutability::Mut - #[must_use] - pub fn is_mut(&self) -> bool { - matches!(self, Self::Mut) - } - - /// Returns `true` if the mutability is [`Shared`]. - /// - /// [`Shared`]: Mutability::Shared - #[must_use] - pub fn is_shared(&self) -> bool { - matches!(self, Self::Shared) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum Rawness { - RawPtr, - Ref, -} - -impl Rawness { - pub fn from_raw(is_raw: bool) -> Rawness { - if is_raw { - Rawness::RawPtr - } else { - Rawness::Ref - } - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct TraitRef { - pub path: Path, -} - -impl TraitRef { - /// Converts an `ast::PathType` to a `hir::TraitRef`. - pub(crate) fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Option { - // FIXME: Use `Path::from_src` - match node { - ast::Type::PathType(path) => { - path.path().and_then(|it| ctx.lower_path(it)).map(|path| TraitRef { path }) - } - _ => None, - } - } -} - -/// Compare ty::Ty -/// -/// Note: Most users of `TypeRef` that end up in the salsa database intern it using -/// `Interned` to save space. But notably, nested `TypeRef`s are not interned, since that -/// does not seem to save any noticeable amount of memory. -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub enum TypeRef { - Never, - Placeholder, - Tuple(Vec), - Path(Path), - RawPtr(Box, Mutability), - Reference(Box, Option, Mutability), - // FIXME: for full const generics, the latter element (length) here is going to have to be an - // expression that is further lowered later in hir_ty. - Array(Box, ConstScalarOrPath), - Slice(Box), - /// A fn pointer. Last element of the vector is the return type. - Fn(Vec<(Option, TypeRef)>, bool /*varargs*/), - ImplTrait(Vec>), - DynTrait(Vec>), - Macro(AstId), - Error, -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct LifetimeRef { - pub name: Name, -} - -impl LifetimeRef { - pub(crate) fn new_name(name: Name) -> Self { - LifetimeRef { name } - } - - pub(crate) fn new(lifetime: &ast::Lifetime) -> Self { - LifetimeRef { name: Name::new_lifetime(lifetime) } - } - - pub fn missing() -> LifetimeRef { - LifetimeRef { name: Name::missing() } - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub enum TypeBound { - Path(Path, TraitBoundModifier), - ForLifetime(Box<[Name]>, Path), - Lifetime(LifetimeRef), - Error, -} - -/// A modifier on a bound, currently this is only used for `?Sized`, where the -/// modifier is `Maybe`. -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub enum TraitBoundModifier { - None, - Maybe, -} - -impl TypeRef { - /// Converts an `ast::TypeRef` to a `hir::TypeRef`. - pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Self { - match node { - ast::Type::ParenType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()), - ast::Type::TupleType(inner) => { - TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect()) - } - ast::Type::NeverType(..) => TypeRef::Never, - ast::Type::PathType(inner) => { - // FIXME: Use `Path::from_src` - inner - .path() - .and_then(|it| ctx.lower_path(it)) - .map(TypeRef::Path) - .unwrap_or(TypeRef::Error) - } - ast::Type::PtrType(inner) => { - let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty()); - let mutability = Mutability::from_mutable(inner.mut_token().is_some()); - TypeRef::RawPtr(Box::new(inner_ty), mutability) - } - ast::Type::ArrayType(inner) => { - // FIXME: This is a hack. We should probably reuse the machinery of - // `hir_def::body::lower` to lower this into an `Expr` and then evaluate it at the - // `hir_ty` level, which would allow knowing the type of: - // let v: [u8; 2 + 2] = [0u8; 4]; - let len = ConstScalarOrPath::from_expr_opt(inner.expr()); - TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len) - } - ast::Type::SliceType(inner) => { - TypeRef::Slice(Box::new(TypeRef::from_ast_opt(ctx, inner.ty()))) - } - ast::Type::RefType(inner) => { - let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty()); - let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(<)); - let mutability = Mutability::from_mutable(inner.mut_token().is_some()); - TypeRef::Reference(Box::new(inner_ty), lifetime, mutability) - } - ast::Type::InferType(_inner) => TypeRef::Placeholder, - ast::Type::FnPtrType(inner) => { - let ret_ty = inner - .ret_type() - .and_then(|rt| rt.ty()) - .map(|it| TypeRef::from_ast(ctx, it)) - .unwrap_or_else(|| TypeRef::Tuple(Vec::new())); - let mut is_varargs = false; - let mut params = if let Some(pl) = inner.param_list() { - if let Some(param) = pl.params().last() { - is_varargs = param.dotdotdot_token().is_some(); - } - - pl.params() - .map(|it| { - let type_ref = TypeRef::from_ast_opt(ctx, it.ty()); - let name = match it.pat() { - Some(ast::Pat::IdentPat(it)) => Some( - it.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing), - ), - _ => None, - }; - (name, type_ref) - }) - .collect() - } else { - Vec::new() - }; - params.push((None, ret_ty)); - TypeRef::Fn(params, is_varargs) - } - // for types are close enough for our purposes to the inner type for now... - ast::Type::ForType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()), - ast::Type::ImplTraitType(inner) => { - TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) - } - ast::Type::DynTraitType(inner) => { - TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) - } - ast::Type::MacroType(mt) => match mt.macro_call() { - Some(mc) => ctx.ast_id(ctx.db, &mc).map(TypeRef::Macro).unwrap_or(TypeRef::Error), - None => TypeRef::Error, - }, - } - } - - pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option) -> Self { - match node { - Some(node) => TypeRef::from_ast(ctx, node), - None => TypeRef::Error, - } - } - - pub(crate) fn unit() -> TypeRef { - TypeRef::Tuple(Vec::new()) - } - - pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) { - go(self, f); - - fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) { - f(type_ref); - match type_ref { - TypeRef::Fn(params, _) => { - params.iter().for_each(|(_, param_type)| go(param_type, f)) - } - TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)), - TypeRef::RawPtr(type_ref, _) - | TypeRef::Reference(type_ref, ..) - | TypeRef::Array(type_ref, _) - | TypeRef::Slice(type_ref) => go(type_ref, f), - TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { - for bound in bounds { - match bound.as_ref() { - TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { - go_path(path, f) - } - TypeBound::Lifetime(_) | TypeBound::Error => (), - } - } - } - TypeRef::Path(path) => go_path(path, f), - TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {} - }; - } - - fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) { - if let Some(type_ref) = path.type_anchor() { - go(type_ref, f); - } - for segment in path.segments().iter() { - if let Some(args_and_bindings) = segment.args_and_bindings { - for arg in &args_and_bindings.args { - match arg { - crate::path::GenericArg::Type(type_ref) => { - go(type_ref, f); - } - crate::path::GenericArg::Const(_) - | crate::path::GenericArg::Lifetime(_) => {} - } - } - for binding in &args_and_bindings.bindings { - if let Some(type_ref) = &binding.type_ref { - go(type_ref, f); - } - for bound in &binding.bounds { - match bound.as_ref() { - TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { - go_path(path, f) - } - TypeBound::Lifetime(_) | TypeBound::Error => (), - } - } - } - } - } - } - } -} - -pub(crate) fn type_bounds_from_ast( - lower_ctx: &LowerCtx<'_>, - type_bounds_opt: Option, -) -> Vec> { - if let Some(type_bounds) = type_bounds_opt { - type_bounds.bounds().map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))).collect() - } else { - vec![] - } -} - -impl TypeBound { - pub(crate) fn from_ast(ctx: &LowerCtx<'_>, node: ast::TypeBound) -> Self { - let lower_path_type = |path_type: ast::PathType| ctx.lower_path(path_type.path()?); - - match node.kind() { - ast::TypeBoundKind::PathType(path_type) => { - let m = match node.question_mark_token() { - Some(_) => TraitBoundModifier::Maybe, - None => TraitBoundModifier::None, - }; - lower_path_type(path_type) - .map(|p| TypeBound::Path(p, m)) - .unwrap_or(TypeBound::Error) - } - ast::TypeBoundKind::ForType(for_type) => { - let lt_refs = match for_type.generic_param_list() { - Some(gpl) => gpl - .lifetime_params() - .flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(<))) - .collect(), - None => Box::default(), - }; - let path = for_type.ty().and_then(|ty| match ty { - ast::Type::PathType(path_type) => lower_path_type(path_type), - _ => None, - }); - match path { - Some(p) => TypeBound::ForLifetime(lt_refs, p), - None => TypeBound::Error, - } - } - ast::TypeBoundKind::Lifetime(lifetime) => { - TypeBound::Lifetime(LifetimeRef::new(&lifetime)) - } - } - } - - pub fn as_path(&self) -> Option<(&Path, &TraitBoundModifier)> { - match self { - TypeBound::Path(p, m) => Some((p, m)), - TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)), - TypeBound::Lifetime(_) | TypeBound::Error => None, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ConstScalarOrPath { - Scalar(ConstScalar), - Path(Name), -} - -impl std::fmt::Display for ConstScalarOrPath { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ConstScalarOrPath::Scalar(s) => s.fmt(f), - ConstScalarOrPath::Path(n) => n.fmt(f), - } - } -} - -impl ConstScalarOrPath { - pub(crate) fn from_expr_opt(expr: Option) -> Self { - match expr { - Some(x) => Self::from_expr(x), - None => Self::Scalar(ConstScalar::Unknown), - } - } - - // FIXME: as per the comments on `TypeRef::Array`, this evaluation should not happen at this - // parse stage. - fn from_expr(expr: ast::Expr) -> Self { - match expr { - ast::Expr::PathExpr(p) => { - match p.path().and_then(|x| x.segment()).and_then(|x| x.name_ref()) { - Some(x) => Self::Path(x.as_name()), - None => Self::Scalar(ConstScalar::Unknown), - } - } - ast::Expr::PrefixExpr(prefix_expr) => match prefix_expr.op_kind() { - Some(ast::UnaryOp::Neg) => { - let unsigned = Self::from_expr_opt(prefix_expr.expr()); - // Add sign - match unsigned { - Self::Scalar(ConstScalar::UInt(num)) => { - Self::Scalar(ConstScalar::Int(-(num as i128))) - } - other => other, - } - } - _ => Self::from_expr_opt(prefix_expr.expr()), - }, - ast::Expr::Literal(literal) => Self::Scalar(match literal.kind() { - ast::LiteralKind::IntNumber(num) => { - num.value().map(ConstScalar::UInt).unwrap_or(ConstScalar::Unknown) - } - ast::LiteralKind::Char(c) => { - c.value().map(ConstScalar::Char).unwrap_or(ConstScalar::Unknown) - } - ast::LiteralKind::Bool(f) => ConstScalar::Bool(f), - _ => ConstScalar::Unknown, - }), - _ => Self::Scalar(ConstScalar::Unknown), - } - } -} - -/// A concrete constant value -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum ConstScalar { - Int(i128), - UInt(u128), - Bool(bool), - Char(char), - - /// Case of an unknown value that rustc might know but we don't - // FIXME: this is a hack to get around chalk not being able to represent unevaluatable - // constants - // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177 - // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348 - Unknown, -} - -impl ConstScalar { - pub fn builtin_type(&self) -> BuiltinType { - match self { - ConstScalar::UInt(_) | ConstScalar::Unknown => BuiltinType::Uint(BuiltinUint::U128), - ConstScalar::Int(_) => BuiltinType::Int(BuiltinInt::I128), - ConstScalar::Char(_) => BuiltinType::Char, - ConstScalar::Bool(_) => BuiltinType::Bool, - } - } -} - -impl From for ConstScalar { - fn from(literal: Literal) -> Self { - match literal { - Literal::Char(c) => Self::Char(c), - Literal::Bool(flag) => Self::Bool(flag), - Literal::Int(num, _) => Self::Int(num), - Literal::Uint(num, _) => Self::UInt(num), - _ => Self::Unknown, - } - } -} - -impl std::fmt::Display for ConstScalar { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - match self { - ConstScalar::Int(num) => num.fmt(f), - ConstScalar::UInt(num) => num.fmt(f), - ConstScalar::Bool(flag) => flag.fmt(f), - ConstScalar::Char(c) => write!(f, "'{c}'"), - ConstScalar::Unknown => f.write_char('_'), - } - } -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs deleted file mode 100644 index 6e22a877a9fa7..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ /dev/null @@ -1,242 +0,0 @@ -//! Defines hir-level representation of visibility (e.g. `pub` and `pub(crate)`). - -use std::{iter, sync::Arc}; - -use hir_expand::{hygiene::Hygiene, InFile}; -use la_arena::ArenaMap; -use syntax::ast; - -use crate::{ - db::DefDatabase, - nameres::DefMap, - path::{ModPath, PathKind}, - resolver::HasResolver, - ConstId, FunctionId, HasModule, LocalFieldId, ModuleId, VariantId, -}; - -/// Visibility of an item, not yet resolved. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum RawVisibility { - /// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is - /// equivalent to `pub(self)`. - Module(ModPath), - /// `pub`. - Public, -} - -impl RawVisibility { - pub(crate) const fn private() -> RawVisibility { - RawVisibility::Module(ModPath::from_kind(PathKind::Super(0))) - } - - pub(crate) fn from_ast( - db: &dyn DefDatabase, - node: InFile>, - ) -> RawVisibility { - Self::from_ast_with_hygiene(db, node.value, &Hygiene::new(db.upcast(), node.file_id)) - } - - pub(crate) fn from_ast_with_hygiene( - db: &dyn DefDatabase, - node: Option, - hygiene: &Hygiene, - ) -> RawVisibility { - Self::from_ast_with_hygiene_and_default(db, node, RawVisibility::private(), hygiene) - } - - pub(crate) fn from_ast_with_hygiene_and_default( - db: &dyn DefDatabase, - node: Option, - default: RawVisibility, - hygiene: &Hygiene, - ) -> RawVisibility { - let node = match node { - None => return default, - Some(node) => node, - }; - match node.kind() { - ast::VisibilityKind::In(path) => { - let path = ModPath::from_src(db.upcast(), path, hygiene); - let path = match path { - None => return RawVisibility::private(), - Some(path) => path, - }; - RawVisibility::Module(path) - } - ast::VisibilityKind::PubCrate => { - let path = ModPath::from_kind(PathKind::Crate); - RawVisibility::Module(path) - } - ast::VisibilityKind::PubSuper => { - let path = ModPath::from_kind(PathKind::Super(1)); - RawVisibility::Module(path) - } - ast::VisibilityKind::PubSelf => { - let path = ModPath::from_kind(PathKind::Plain); - RawVisibility::Module(path) - } - ast::VisibilityKind::Pub => RawVisibility::Public, - } - } - - pub fn resolve( - &self, - db: &dyn DefDatabase, - resolver: &crate::resolver::Resolver, - ) -> Visibility { - // we fall back to public visibility (i.e. fail open) if the path can't be resolved - resolver.resolve_visibility(db, self).unwrap_or(Visibility::Public) - } -} - -/// Visibility of an item, with the path resolved. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum Visibility { - /// Visibility is restricted to a certain module. - Module(ModuleId), - /// Visibility is unrestricted. - Public, -} - -impl Visibility { - pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool { - let to_module = match self { - Visibility::Module(m) => m, - Visibility::Public => return true, - }; - // if they're not in the same crate, it can't be visible - if from_module.krate != to_module.krate { - return false; - } - let def_map = from_module.def_map(db); - self.is_visible_from_def_map(db, &def_map, from_module.local_id) - } - - pub(crate) fn is_visible_from_other_crate(self) -> bool { - matches!(self, Visibility::Public) - } - - pub(crate) fn is_visible_from_def_map( - self, - db: &dyn DefDatabase, - def_map: &DefMap, - mut from_module: crate::LocalModuleId, - ) -> bool { - let mut to_module = match self { - Visibility::Module(m) => m, - Visibility::Public => return true, - }; - - // `to_module` might be the root module of a block expression. Those have the same - // visibility as the containing module (even though no items are directly nameable from - // there, getting this right is important for method resolution). - // In that case, we adjust the visibility of `to_module` to point to the containing module. - // Additional complication: `to_module` might be in `from_module`'s `DefMap`, which we're - // currently computing, so we must not call the `def_map` query for it. - let arc; - let to_module_def_map = - if to_module.krate == def_map.krate() && to_module.block == def_map.block_id() { - cov_mark::hit!(is_visible_from_same_block_def_map); - def_map - } else { - arc = to_module.def_map(db); - &arc - }; - let is_block_root = matches!(to_module.block, Some(_) if to_module_def_map[to_module.local_id].parent.is_none()); - if is_block_root { - to_module = to_module_def_map.containing_module(to_module.local_id).unwrap(); - } - - // from_module needs to be a descendant of to_module - let mut def_map = def_map; - let mut parent_arc; - loop { - if def_map.module_id(from_module) == to_module { - return true; - } - match def_map[from_module].parent { - Some(parent) => from_module = parent, - None => { - match def_map.parent() { - Some(module) => { - parent_arc = module.def_map(db); - def_map = &*parent_arc; - from_module = module.local_id; - } - // Reached the root module, nothing left to check. - None => return false, - } - } - } - } - } - - /// Returns the most permissive visibility of `self` and `other`. - /// - /// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only - /// visible in unrelated modules). - pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option { - match (self, other) { - (Visibility::Module(_) | Visibility::Public, Visibility::Public) - | (Visibility::Public, Visibility::Module(_)) => Some(Visibility::Public), - (Visibility::Module(mod_a), Visibility::Module(mod_b)) => { - if mod_a.krate != mod_b.krate { - return None; - } - - let mut a_ancestors = iter::successors(Some(mod_a.local_id), |&m| { - let parent_id = def_map[m].parent?; - Some(parent_id) - }); - let mut b_ancestors = iter::successors(Some(mod_b.local_id), |&m| { - let parent_id = def_map[m].parent?; - Some(parent_id) - }); - - if a_ancestors.any(|m| m == mod_b.local_id) { - // B is above A - return Some(Visibility::Module(mod_b)); - } - - if b_ancestors.any(|m| m == mod_a.local_id) { - // A is above B - return Some(Visibility::Module(mod_a)); - } - - None - } - } - } -} - -/// Resolve visibility of all specific fields of a struct or union variant. -pub(crate) fn field_visibilities_query( - db: &dyn DefDatabase, - variant_id: VariantId, -) -> Arc> { - let var_data = match variant_id { - VariantId::StructId(it) => db.struct_data(it).variant_data.clone(), - VariantId::UnionId(it) => db.union_data(it).variant_data.clone(), - VariantId::EnumVariantId(it) => { - db.enum_data(it.parent).variants[it.local_id].variant_data.clone() - } - }; - let resolver = variant_id.module(db).resolver(db); - let mut res = ArenaMap::default(); - for (field_id, field_data) in var_data.fields().iter() { - res.insert(field_id, field_data.visibility.resolve(db, &resolver)) - } - Arc::new(res) -} - -/// Resolve visibility of a function. -pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility { - let resolver = def.resolver(db); - db.function_data(def).visibility.resolve(db, &resolver) -} - -/// Resolve visibility of a const. -pub(crate) fn const_visibility_query(db: &dyn DefDatabase, def: ConstId) -> Visibility { - let resolver = def.resolver(db); - db.const_data(def).visibility.resolve(db, &resolver) -} diff --git a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml deleted file mode 100644 index dfd470ffca6ac..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -name = "hir-expand" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -cov-mark = "2.0.0-pre.1" -tracing = "0.1.35" -either = "1.7.0" -rustc-hash = "1.1.0" -la-arena = { version = "0.3.0", path = "../../lib/la-arena" } -itertools = "0.10.3" -hashbrown = { version = "0.12.1", features = [ - "inline-more", -], default-features = false } -smallvec = { version = "1.9.0", features = ["const_new"] } - -stdx = { path = "../stdx", version = "0.0.0" } -base-db = { path = "../base-db", version = "0.0.0" } -cfg = { path = "../cfg", version = "0.0.0" } -syntax = { path = "../syntax", version = "0.0.0" } -profile = { path = "../profile", version = "0.0.0" } -tt = { path = "../tt", version = "0.0.0" } -mbe = { path = "../mbe", version = "0.0.0" } -limit = { path = "../limit", version = "0.0.0" } - -[dev-dependencies] -expect-test = "1.4.0" diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs b/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs deleted file mode 100644 index c1ddef03ba3b4..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs +++ /dev/null @@ -1,181 +0,0 @@ -//! `AstIdMap` allows to create stable IDs for "large" syntax nodes like items -//! and macro calls. -//! -//! Specifically, it enumerates all items in a file and uses position of a an -//! item as an ID. That way, id's don't change unless the set of items itself -//! changes. - -use std::{ - any::type_name, - fmt, - hash::{BuildHasher, BuildHasherDefault, Hash, Hasher}, - marker::PhantomData, -}; - -use la_arena::{Arena, Idx}; -use profile::Count; -use rustc_hash::FxHasher; -use syntax::{ast, match_ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; - -/// `AstId` points to an AST node in a specific file. -pub struct FileAstId { - raw: ErasedFileAstId, - _ty: PhantomData N>, -} - -impl Clone for FileAstId { - fn clone(&self) -> FileAstId { - *self - } -} -impl Copy for FileAstId {} - -impl PartialEq for FileAstId { - fn eq(&self, other: &Self) -> bool { - self.raw == other.raw - } -} -impl Eq for FileAstId {} -impl Hash for FileAstId { - fn hash(&self, hasher: &mut H) { - self.raw.hash(hasher); - } -} - -impl fmt::Debug for FileAstId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "FileAstId::<{}>({})", type_name::(), self.raw.into_raw()) - } -} - -impl FileAstId { - // Can't make this a From implementation because of coherence - pub fn upcast(self) -> FileAstId - where - N: Into, - { - FileAstId { raw: self.raw, _ty: PhantomData } - } -} - -type ErasedFileAstId = Idx; - -/// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back. -#[derive(Default)] -pub struct AstIdMap { - /// Maps stable id to unstable ptr. - arena: Arena, - /// Reverse: map ptr to id. - map: hashbrown::HashMap, (), ()>, - _c: Count, -} - -impl fmt::Debug for AstIdMap { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("AstIdMap").field("arena", &self.arena).finish() - } -} - -impl PartialEq for AstIdMap { - fn eq(&self, other: &Self) -> bool { - self.arena == other.arena - } -} -impl Eq for AstIdMap {} - -impl AstIdMap { - pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap { - assert!(node.parent().is_none()); - let mut res = AstIdMap::default(); - // By walking the tree in breadth-first order we make sure that parents - // get lower ids then children. That is, adding a new child does not - // change parent's id. This means that, say, adding a new function to a - // trait does not change ids of top-level items, which helps caching. - bdfs(node, |it| { - match_ast! { - match it { - ast::Item(module_item) => { - res.alloc(module_item.syntax()); - true - }, - ast::BlockExpr(block) => { - res.alloc(block.syntax()); - true - }, - _ => false, - } - } - }); - res.map = hashbrown::HashMap::with_capacity_and_hasher(res.arena.len(), ()); - for (idx, ptr) in res.arena.iter() { - let hash = hash_ptr(ptr); - match res.map.raw_entry_mut().from_hash(hash, |idx2| *idx2 == idx) { - hashbrown::hash_map::RawEntryMut::Occupied(_) => unreachable!(), - hashbrown::hash_map::RawEntryMut::Vacant(entry) => { - entry.insert_with_hasher(hash, idx, (), |&idx| hash_ptr(&res.arena[idx])); - } - } - } - res - } - - pub fn ast_id(&self, item: &N) -> FileAstId { - let raw = self.erased_ast_id(item.syntax()); - FileAstId { raw, _ty: PhantomData } - } - fn erased_ast_id(&self, item: &SyntaxNode) -> ErasedFileAstId { - let ptr = SyntaxNodePtr::new(item); - let hash = hash_ptr(&ptr); - match self.map.raw_entry().from_hash(hash, |&idx| self.arena[idx] == ptr) { - Some((&idx, &())) => idx, - None => panic!( - "Can't find {:?} in AstIdMap:\n{:?}", - item, - self.arena.iter().map(|(_id, i)| i).collect::>(), - ), - } - } - - pub fn get(&self, id: FileAstId) -> AstPtr { - AstPtr::try_from_raw(self.arena[id.raw].clone()).unwrap() - } - - fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId { - self.arena.alloc(SyntaxNodePtr::new(item)) - } -} - -fn hash_ptr(ptr: &SyntaxNodePtr) -> u64 { - let mut hasher = BuildHasherDefault::::default().build_hasher(); - ptr.hash(&mut hasher); - hasher.finish() -} - -/// Walks the subtree in bdfs order, calling `f` for each node. What is bdfs -/// order? It is a mix of breadth-first and depth first orders. Nodes for which -/// `f` returns true are visited breadth-first, all the other nodes are explored -/// depth-first. -/// -/// In other words, the size of the bfs queue is bound by the number of "true" -/// nodes. -fn bdfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode) -> bool) { - let mut curr_layer = vec![node.clone()]; - let mut next_layer = vec![]; - while !curr_layer.is_empty() { - curr_layer.drain(..).for_each(|node| { - let mut preorder = node.preorder(); - while let Some(event) = preorder.next() { - match event { - syntax::WalkEvent::Enter(node) => { - if f(node.clone()) { - next_layer.extend(node.children()); - preorder.skip_subtree(); - } - } - syntax::WalkEvent::Leave(_) => {} - } - } - }); - std::mem::swap(&mut curr_layer, &mut next_layer); - } -} 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 deleted file mode 100644 index 0c886ac4da9db..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! Builtin attributes. - -use crate::{db::AstDatabase, name, ExpandResult, MacroCallId, MacroCallKind}; - -macro_rules! register_builtin { - ( $(($name:ident, $variant:ident) => $expand:ident),* ) => { - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - pub enum BuiltinAttrExpander { - $($variant),* - } - - impl BuiltinAttrExpander { - pub fn expand( - &self, - db: &dyn AstDatabase, - id: MacroCallId, - tt: &tt::Subtree, - ) -> ExpandResult { - let expander = match *self { - $( BuiltinAttrExpander::$variant => $expand, )* - }; - expander(db, id, tt) - } - - fn find_by_name(name: &name::Name) -> Option { - match name { - $( id if id == &name::name![$name] => Some(BuiltinAttrExpander::$variant), )* - _ => None, - } - } - } - - }; -} - -impl BuiltinAttrExpander { - pub fn is_derive(self) -> bool { - matches!(self, BuiltinAttrExpander::Derive) - } - pub fn is_test(self) -> bool { - matches!(self, BuiltinAttrExpander::Test) - } - pub fn is_bench(self) -> bool { - matches!(self, BuiltinAttrExpander::Bench) - } -} - -register_builtin! { - (bench, Bench) => dummy_attr_expand, - (cfg_accessible, CfgAccessible) => dummy_attr_expand, - (cfg_eval, CfgEval) => dummy_attr_expand, - (derive, Derive) => derive_attr_expand, - (global_allocator, GlobalAllocator) => dummy_attr_expand, - (test, Test) => dummy_attr_expand, - (test_case, TestCase) => dummy_attr_expand -} - -pub fn find_builtin_attr(ident: &name::Name) -> Option { - BuiltinAttrExpander::find_by_name(ident) -} - -fn dummy_attr_expand( - _db: &dyn AstDatabase, - _id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - ExpandResult::ok(tt.clone()) -} - -/// We generate a very specific expansion here, as we do not actually expand the `#[derive]` attribute -/// itself in name res, but we do want to expand it to something for the IDE layer, so that the input -/// derive attributes can be downmapped, and resolved as proper paths. -/// This is basically a hack, that simplifies the hacks we need in a lot of ide layer places to -/// somewhat inconsistently resolve derive attributes. -/// -/// As such, we expand `#[derive(Foo, bar::Bar)]` into -/// ``` -/// #[Foo] -/// #[bar::Bar] -/// (); -/// ``` -/// which allows fallback path resolution in hir::Semantics to properly identify our derives. -/// Since we do not expand the attribute in nameres though, we keep the original item. -/// -/// The ideal expansion here would be for the `#[derive]` to re-emit the annotated item and somehow -/// use the input paths in its output as well. -/// But that would bring two problems with it, for one every derive would duplicate the item token tree -/// wasting a lot of memory, and it would also require some way to use a path in a way that makes it -/// always resolve as a derive without nameres recollecting them. -/// So this hacky approach is a lot more friendly for us, though it does require a bit of support in -/// [`hir::Semantics`] to make this work. -fn derive_attr_expand( - db: &dyn AstDatabase, - id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let loc = db.lookup_intern_macro_call(id); - let derives = match &loc.kind { - MacroCallKind::Attr { attr_args, is_derive: true, .. } => &attr_args.0, - _ => return ExpandResult::ok(Default::default()), - }; - pseudo_derive_attr_expansion(tt, derives) -} - -pub fn pseudo_derive_attr_expansion( - tt: &tt::Subtree, - args: &tt::Subtree, -) -> ExpandResult { - let mk_leaf = |char| { - tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { - char, - spacing: tt::Spacing::Alone, - id: tt::TokenId::unspecified(), - })) - }; - - let mut token_trees = Vec::new(); - for tt in (&args.token_trees) - .split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', .. })))) - { - token_trees.push(mk_leaf('#')); - token_trees.push(mk_leaf('[')); - token_trees.extend(tt.iter().cloned()); - token_trees.push(mk_leaf(']')); - } - token_trees.push(mk_leaf('(')); - token_trees.push(mk_leaf(')')); - token_trees.push(mk_leaf(';')); - ExpandResult::ok(tt::Subtree { delimiter: tt.delimiter, token_trees }) -} diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs deleted file mode 100644 index 79989bc2e38b6..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs +++ /dev/null @@ -1,249 +0,0 @@ -//! Builtin derives. - -use base_db::{CrateOrigin, LangCrateOrigin}; -use tracing::debug; - -use syntax::{ - ast::{self, AstNode, HasGenericParams, HasModuleItem, HasName}, - match_ast, -}; -use tt::TokenId; - -use crate::{db::AstDatabase, name, quote, ExpandError, ExpandResult, MacroCallId}; - -macro_rules! register_builtin { - ( $($trait:ident => $expand:ident),* ) => { - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - pub enum BuiltinDeriveExpander { - $($trait),* - } - - impl BuiltinDeriveExpander { - pub fn expand( - &self, - db: &dyn AstDatabase, - id: MacroCallId, - tt: &tt::Subtree, - ) -> ExpandResult { - let expander = match *self { - $( BuiltinDeriveExpander::$trait => $expand, )* - }; - expander(db, id, tt) - } - - fn find_by_name(name: &name::Name) -> Option { - match name { - $( id if id == &name::name![$trait] => Some(BuiltinDeriveExpander::$trait), )* - _ => None, - } - } - } - - }; -} - -register_builtin! { - Copy => copy_expand, - Clone => clone_expand, - Default => default_expand, - Debug => debug_expand, - Hash => hash_expand, - Ord => ord_expand, - PartialOrd => partial_ord_expand, - Eq => eq_expand, - PartialEq => partial_eq_expand -} - -pub fn find_builtin_derive(ident: &name::Name) -> Option { - BuiltinDeriveExpander::find_by_name(ident) -} - -struct BasicAdtInfo { - name: tt::Ident, - type_or_const_params: usize, -} - -fn parse_adt(tt: &tt::Subtree) -> Result { - let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MacroItems); - let macro_items = ast::MacroItems::cast(parsed.syntax_node()).ok_or_else(|| { - debug!("derive node didn't parse"); - ExpandError::Other("invalid item definition".into()) - })?; - let item = macro_items.items().next().ok_or_else(|| { - debug!("no module item parsed"); - ExpandError::Other("no item found".into()) - })?; - let node = item.syntax(); - let (name, params) = match_ast! { - match node { - ast::Struct(it) => (it.name(), it.generic_param_list()), - ast::Enum(it) => (it.name(), it.generic_param_list()), - ast::Union(it) => (it.name(), it.generic_param_list()), - _ => { - debug!("unexpected node is {:?}", node); - return Err(ExpandError::Other("expected struct, enum or union".into())) - }, - } - }; - let name = name.ok_or_else(|| { - debug!("parsed item has no name"); - ExpandError::Other("missing name".into()) - })?; - let name_token_id = - token_map.token_by_range(name.syntax().text_range()).unwrap_or_else(TokenId::unspecified); - let name_token = tt::Ident { id: name_token_id, text: name.text().into() }; - let type_or_const_params = - params.map_or(0, |type_param_list| type_param_list.type_or_const_params().count()); - Ok(BasicAdtInfo { name: name_token, type_or_const_params }) -} - -fn make_type_args(n: usize, bound: Vec) -> Vec { - let mut result = Vec::::with_capacity(n * 2); - result.push( - tt::Leaf::Punct(tt::Punct { - char: '<', - spacing: tt::Spacing::Alone, - id: tt::TokenId::unspecified(), - }) - .into(), - ); - for i in 0..n { - if i > 0 { - result.push( - tt::Leaf::Punct(tt::Punct { - char: ',', - spacing: tt::Spacing::Alone, - id: tt::TokenId::unspecified(), - }) - .into(), - ); - } - result.push( - tt::Leaf::Ident(tt::Ident { - id: tt::TokenId::unspecified(), - text: format!("T{}", i).into(), - }) - .into(), - ); - result.extend(bound.iter().cloned()); - } - result.push( - tt::Leaf::Punct(tt::Punct { - char: '>', - spacing: tt::Spacing::Alone, - id: tt::TokenId::unspecified(), - }) - .into(), - ); - result -} - -fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResult { - let info = match parse_adt(tt) { - Ok(info) => info, - Err(e) => return ExpandResult::only_err(e), - }; - let name = info.name; - let trait_path_clone = trait_path.token_trees.clone(); - let bound = (quote! { : ##trait_path_clone }).token_trees; - let type_params = make_type_args(info.type_or_const_params, bound); - let type_args = make_type_args(info.type_or_const_params, Vec::new()); - let trait_path = trait_path.token_trees; - let expanded = quote! { - impl ##type_params ##trait_path for #name ##type_args {} - }; - ExpandResult::ok(expanded) -} - -fn find_builtin_crate(db: &dyn AstDatabase, id: MacroCallId) -> tt::TokenTree { - // FIXME: make hygiene works for builtin derive macro - // such that $crate can be used here. - let cg = db.crate_graph(); - let krate = db.lookup_intern_macro_call(id).krate; - - let tt = if matches!(cg[krate].origin, CrateOrigin::Lang(LangCrateOrigin::Core)) { - cov_mark::hit!(test_copy_expand_in_core); - quote! { crate } - } else { - quote! { core } - }; - - tt.token_trees[0].clone() -} - -fn copy_expand( - db: &dyn AstDatabase, - id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::marker::Copy }) -} - -fn clone_expand( - db: &dyn AstDatabase, - id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::clone::Clone }) -} - -fn default_expand( - db: &dyn AstDatabase, - id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::default::Default }) -} - -fn debug_expand( - db: &dyn AstDatabase, - id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::fmt::Debug }) -} - -fn hash_expand( - db: &dyn AstDatabase, - id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::hash::Hash }) -} - -fn eq_expand(db: &dyn AstDatabase, id: MacroCallId, tt: &tt::Subtree) -> ExpandResult { - let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::cmp::Eq }) -} - -fn partial_eq_expand( - db: &dyn AstDatabase, - id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::cmp::PartialEq }) -} - -fn ord_expand( - db: &dyn AstDatabase, - id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::cmp::Ord }) -} - -fn partial_ord_expand( - db: &dyn AstDatabase, - id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::cmp::PartialOrd }) -} 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 deleted file mode 100644 index 76da7c9f1ee82..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs +++ /dev/null @@ -1,669 +0,0 @@ -//! Builtin macro - -use base_db::{AnchoredPath, Edition, FileId}; -use cfg::CfgExpr; -use either::Either; -use mbe::{parse_exprs_with_sep, parse_to_token_tree}; -use syntax::{ - ast::{self, AstToken}, - SmolStr, -}; - -use crate::{db::AstDatabase, name, quote, ExpandError, ExpandResult, MacroCallId, MacroCallLoc}; - -macro_rules! register_builtin { - ( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => { - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - pub enum BuiltinFnLikeExpander { - $($kind),* - } - - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - pub enum EagerExpander { - $($e_kind),* - } - - impl BuiltinFnLikeExpander { - pub fn expand( - &self, - db: &dyn AstDatabase, - id: MacroCallId, - tt: &tt::Subtree, - ) -> ExpandResult { - let expander = match *self { - $( BuiltinFnLikeExpander::$kind => $expand, )* - }; - expander(db, id, tt) - } - } - - impl EagerExpander { - pub fn expand( - &self, - db: &dyn AstDatabase, - arg_id: MacroCallId, - tt: &tt::Subtree, - ) -> ExpandResult { - let expander = match *self { - $( EagerExpander::$e_kind => $e_expand, )* - }; - expander(db, arg_id, tt) - } - } - - fn find_by_name(ident: &name::Name) -> Option> { - match ident { - $( id if id == &name::name![$name] => Some(Either::Left(BuiltinFnLikeExpander::$kind)), )* - $( id if id == &name::name![$e_name] => Some(Either::Right(EagerExpander::$e_kind)), )* - _ => return None, - } - } - }; -} - -#[derive(Debug, Default)] -pub struct ExpandedEager { - pub(crate) subtree: tt::Subtree, - /// The included file ID of the include macro. - pub(crate) included_file: Option, -} - -impl ExpandedEager { - fn new(subtree: tt::Subtree) -> Self { - ExpandedEager { subtree, included_file: None } - } -} - -pub fn find_builtin_macro( - ident: &name::Name, -) -> Option> { - find_by_name(ident) -} - -register_builtin! { - LAZY: - (column, Column) => column_expand, - (file, File) => file_expand, - (line, Line) => line_expand, - (module_path, ModulePath) => module_path_expand, - (assert, Assert) => assert_expand, - (stringify, Stringify) => stringify_expand, - (format_args, FormatArgs) => format_args_expand, - (const_format_args, ConstFormatArgs) => format_args_expand, - // format_args_nl only differs in that it adds a newline in the end, - // so we use the same stub expansion for now - (format_args_nl, FormatArgsNl) => format_args_expand, - (llvm_asm, LlvmAsm) => asm_expand, - (asm, Asm) => asm_expand, - (global_asm, GlobalAsm) => global_asm_expand, - (cfg, Cfg) => cfg_expand, - (core_panic, CorePanic) => panic_expand, - (std_panic, StdPanic) => panic_expand, - (unreachable, Unreachable) => unreachable_expand, - (log_syntax, LogSyntax) => log_syntax_expand, - (trace_macros, TraceMacros) => trace_macros_expand, - - EAGER: - (compile_error, CompileError) => compile_error_expand, - (concat, Concat) => concat_expand, - (concat_idents, ConcatIdents) => concat_idents_expand, - (concat_bytes, ConcatBytes) => concat_bytes_expand, - (include, Include) => include_expand, - (include_bytes, IncludeBytes) => include_bytes_expand, - (include_str, IncludeStr) => include_str_expand, - (env, Env) => env_expand, - (option_env, OptionEnv) => option_env_expand -} - -const DOLLAR_CRATE: tt::Ident = - tt::Ident { text: SmolStr::new_inline("$crate"), id: tt::TokenId::unspecified() }; - -fn module_path_expand( - _db: &dyn AstDatabase, - _id: MacroCallId, - _tt: &tt::Subtree, -) -> ExpandResult { - // Just return a dummy result. - ExpandResult::ok(quote! { "module::path" }) -} - -fn line_expand( - _db: &dyn AstDatabase, - _id: MacroCallId, - _tt: &tt::Subtree, -) -> ExpandResult { - // dummy implementation for type-checking purposes - let line_num = 0; - let expanded = quote! { - #line_num - }; - - ExpandResult::ok(expanded) -} - -fn log_syntax_expand( - _db: &dyn AstDatabase, - _id: MacroCallId, - _tt: &tt::Subtree, -) -> ExpandResult { - ExpandResult::ok(quote! {}) -} - -fn trace_macros_expand( - _db: &dyn AstDatabase, - _id: MacroCallId, - _tt: &tt::Subtree, -) -> ExpandResult { - ExpandResult::ok(quote! {}) -} - -fn stringify_expand( - _db: &dyn AstDatabase, - _id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let pretty = tt::pretty(&tt.token_trees); - - let expanded = quote! { - #pretty - }; - - ExpandResult::ok(expanded) -} - -fn column_expand( - _db: &dyn AstDatabase, - _id: MacroCallId, - _tt: &tt::Subtree, -) -> ExpandResult { - // dummy implementation for type-checking purposes - let col_num = 0; - let expanded = quote! { - #col_num - }; - - ExpandResult::ok(expanded) -} - -fn assert_expand( - _db: &dyn AstDatabase, - _id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let args = parse_exprs_with_sep(tt, ','); - let expanded = match &*args { - [cond, panic_args @ ..] => { - let comma = tt::Subtree { - delimiter: None, - token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { - char: ',', - spacing: tt::Spacing::Alone, - id: tt::TokenId::unspecified(), - }))], - }; - let cond = cond.clone(); - let panic_args = itertools::Itertools::intersperse(panic_args.iter().cloned(), comma); - quote! {{ - if !#cond { - #DOLLAR_CRATE::panic!(##panic_args); - } - }} - } - [] => quote! {{}}, - }; - - ExpandResult::ok(expanded) -} - -fn file_expand( - _db: &dyn AstDatabase, - _id: MacroCallId, - _tt: &tt::Subtree, -) -> ExpandResult { - // FIXME: RA purposefully lacks knowledge of absolute file names - // so just return "". - let file_name = ""; - - let expanded = quote! { - #file_name - }; - - ExpandResult::ok(expanded) -} - -fn format_args_expand( - _db: &dyn AstDatabase, - _id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - // We expand `format_args!("", a1, a2)` to - // ``` - // std::fmt::Arguments::new_v1(&[], &[ - // std::fmt::ArgumentV1::new(&arg1,std::fmt::Display::fmt), - // std::fmt::ArgumentV1::new(&arg2,std::fmt::Display::fmt), - // ]) - // ```, - // which is still not really correct, but close enough for now - let mut args = parse_exprs_with_sep(tt, ','); - - if args.is_empty() { - return ExpandResult::only_err(mbe::ExpandError::NoMatchingRule.into()); - } - for arg in &mut args { - // Remove `key =`. - if matches!(arg.token_trees.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' && p.spacing != tt::Spacing::Joint) - { - arg.token_trees.drain(..2); - } - } - let _format_string = args.remove(0); - let arg_tts = args.into_iter().flat_map(|arg| { - quote! { std::fmt::ArgumentV1::new(&(#arg), std::fmt::Display::fmt), } - }.token_trees); - let expanded = quote! { - std::fmt::Arguments::new_v1(&[], &[##arg_tts]) - }; - ExpandResult::ok(expanded) -} - -fn asm_expand( - _db: &dyn AstDatabase, - _id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - // We expand all assembly snippets to `format_args!` invocations to get format syntax - // highlighting for them. - - let mut literals = Vec::new(); - for tt in tt.token_trees.chunks(2) { - match tt { - [tt::TokenTree::Leaf(tt::Leaf::Literal(lit))] - | [tt::TokenTree::Leaf(tt::Leaf::Literal(lit)), tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', id: _, spacing: _ }))] => - { - let krate = DOLLAR_CRATE.clone(); - literals.push(quote!(#krate::format_args!(#lit);)); - } - _ => break, - } - } - - let expanded = quote! {{ - ##literals - loop {} - }}; - ExpandResult::ok(expanded) -} - -fn global_asm_expand( - _db: &dyn AstDatabase, - _id: MacroCallId, - _tt: &tt::Subtree, -) -> ExpandResult { - // Expand to nothing (at item-level) - ExpandResult::ok(quote! {}) -} - -fn cfg_expand( - db: &dyn AstDatabase, - id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let loc = db.lookup_intern_macro_call(id); - let expr = CfgExpr::parse(tt); - let enabled = db.crate_graph()[loc.krate].cfg_options.check(&expr) != Some(false); - let expanded = if enabled { quote!(true) } else { quote!(false) }; - ExpandResult::ok(expanded) -} - -fn panic_expand( - db: &dyn AstDatabase, - id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let loc: MacroCallLoc = db.lookup_intern_macro_call(id); - // Expand to a macro call `$crate::panic::panic_{edition}` - let mut call = if db.crate_graph()[loc.krate].edition >= Edition::Edition2021 { - quote!(#DOLLAR_CRATE::panic::panic_2021!) - } else { - quote!(#DOLLAR_CRATE::panic::panic_2015!) - }; - - // Pass the original arguments - call.token_trees.push(tt::TokenTree::Subtree(tt.clone())); - ExpandResult::ok(call) -} - -fn unreachable_expand( - db: &dyn AstDatabase, - id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let loc: MacroCallLoc = db.lookup_intern_macro_call(id); - // Expand to a macro call `$crate::panic::unreachable_{edition}` - let mut call = if db.crate_graph()[loc.krate].edition >= Edition::Edition2021 { - quote!(#DOLLAR_CRATE::panic::unreachable_2021!) - } else { - quote!(#DOLLAR_CRATE::panic::unreachable_2015!) - }; - - // Pass the original arguments - call.token_trees.push(tt::TokenTree::Subtree(tt.clone())); - ExpandResult::ok(call) -} - -fn unquote_str(lit: &tt::Literal) -> Option { - let lit = ast::make::tokens::literal(&lit.to_string()); - let token = ast::String::cast(lit)?; - token.value().map(|it| it.into_owned()) -} - -fn unquote_byte_string(lit: &tt::Literal) -> Option> { - let lit = ast::make::tokens::literal(&lit.to_string()); - let token = ast::ByteString::cast(lit)?; - token.value().map(|it| it.into_owned()) -} - -fn compile_error_expand( - _db: &dyn AstDatabase, - _id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let err = match &*tt.token_trees { - [tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => { - let text = it.text.as_str(); - if text.starts_with('"') && text.ends_with('"') { - // FIXME: does not handle raw strings - ExpandError::Other(text[1..text.len() - 1].into()) - } else { - ExpandError::Other("`compile_error!` argument must be a string".into()) - } - } - _ => ExpandError::Other("`compile_error!` argument must be a string".into()), - }; - - ExpandResult { value: ExpandedEager::new(quote! {}), err: Some(err) } -} - -fn concat_expand( - _db: &dyn AstDatabase, - _arg_id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let mut err = None; - let mut text = String::new(); - for (i, mut t) in tt.token_trees.iter().enumerate() { - // FIXME: hack on top of a hack: `$e:expr` captures get surrounded in parentheses - // to ensure the right parsing order, so skip the parentheses here. Ideally we'd - // implement rustc's model. cc https://github.com/rust-lang/rust-analyzer/pull/10623 - if let tt::TokenTree::Subtree(tt::Subtree { delimiter: Some(delim), token_trees }) = t { - if let [tt] = &**token_trees { - if delim.kind == tt::DelimiterKind::Parenthesis { - t = tt; - } - } - } - - match t { - tt::TokenTree::Leaf(tt::Leaf::Literal(it)) if i % 2 == 0 => { - // concat works with string and char literals, so remove any quotes. - // It also works with integer, float and boolean literals, so just use the rest - // as-is. - let component = unquote_str(it).unwrap_or_else(|| it.text.to_string()); - text.push_str(&component); - } - // handle boolean literals - tt::TokenTree::Leaf(tt::Leaf::Ident(id)) - if i % 2 == 0 && (id.text == "true" || id.text == "false") => - { - text.push_str(id.text.as_str()); - } - tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (), - _ => { - err.get_or_insert(mbe::ExpandError::UnexpectedToken.into()); - } - } - } - ExpandResult { value: ExpandedEager::new(quote!(#text)), err } -} - -fn concat_bytes_expand( - _db: &dyn AstDatabase, - _arg_id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let mut bytes = Vec::new(); - let mut err = None; - for (i, t) in tt.token_trees.iter().enumerate() { - match t { - tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => { - let token = ast::make::tokens::literal(&lit.to_string()); - match token.kind() { - syntax::SyntaxKind::BYTE => bytes.push(token.text().to_string()), - syntax::SyntaxKind::BYTE_STRING => { - let components = unquote_byte_string(lit).unwrap_or_else(Vec::new); - components.into_iter().for_each(|x| bytes.push(x.to_string())); - } - _ => { - err.get_or_insert(mbe::ExpandError::UnexpectedToken.into()); - break; - } - } - } - tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (), - tt::TokenTree::Subtree(tree) - if tree.delimiter_kind() == Some(tt::DelimiterKind::Bracket) => - { - if let Err(e) = concat_bytes_expand_subtree(tree, &mut bytes) { - err.get_or_insert(e); - break; - } - } - _ => { - err.get_or_insert(mbe::ExpandError::UnexpectedToken.into()); - break; - } - } - } - let ident = tt::Ident { text: bytes.join(", ").into(), id: tt::TokenId::unspecified() }; - ExpandResult { value: ExpandedEager::new(quote!([#ident])), err } -} - -fn concat_bytes_expand_subtree( - tree: &tt::Subtree, - bytes: &mut Vec, -) -> Result<(), ExpandError> { - for (ti, tt) in tree.token_trees.iter().enumerate() { - match tt { - tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => { - let lit = ast::make::tokens::literal(&lit.to_string()); - match lit.kind() { - syntax::SyntaxKind::BYTE | syntax::SyntaxKind::INT_NUMBER => { - bytes.push(lit.text().to_string()) - } - _ => { - return Err(mbe::ExpandError::UnexpectedToken.into()); - } - } - } - tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if ti % 2 == 1 && punct.char == ',' => (), - _ => { - return Err(mbe::ExpandError::UnexpectedToken.into()); - } - } - } - Ok(()) -} - -fn concat_idents_expand( - _db: &dyn AstDatabase, - _arg_id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let mut err = None; - let mut ident = String::new(); - for (i, t) in tt.token_trees.iter().enumerate() { - match t { - tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => { - ident.push_str(id.text.as_str()); - } - tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (), - _ => { - err.get_or_insert(mbe::ExpandError::UnexpectedToken.into()); - } - } - } - let ident = tt::Ident { text: ident.into(), id: tt::TokenId::unspecified() }; - ExpandResult { value: ExpandedEager::new(quote!(#ident)), err } -} - -fn relative_file( - db: &dyn AstDatabase, - call_id: MacroCallId, - path_str: &str, - allow_recursion: bool, -) -> Result { - let call_site = call_id.as_file().original_file(db); - let path = AnchoredPath { anchor: call_site, path: path_str }; - let res = db - .resolve_path(path) - .ok_or_else(|| ExpandError::Other(format!("failed to load file `{path_str}`").into()))?; - // Prevent include itself - if res == call_site && !allow_recursion { - Err(ExpandError::Other(format!("recursive inclusion of `{path_str}`").into())) - } else { - Ok(res) - } -} - -fn parse_string(tt: &tt::Subtree) -> Result { - tt.token_trees - .get(0) - .and_then(|tt| match tt { - tt::TokenTree::Leaf(tt::Leaf::Literal(it)) => unquote_str(it), - _ => None, - }) - .ok_or(mbe::ExpandError::ConversionError.into()) -} - -fn include_expand( - db: &dyn AstDatabase, - arg_id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let res = (|| { - let path = parse_string(tt)?; - let file_id = relative_file(db, arg_id, &path, false)?; - - let subtree = - parse_to_token_tree(&db.file_text(file_id)).ok_or(mbe::ExpandError::ConversionError)?.0; - Ok((subtree, file_id)) - })(); - - match res { - Ok((subtree, file_id)) => { - ExpandResult::ok(ExpandedEager { subtree, included_file: Some(file_id) }) - } - Err(e) => ExpandResult::only_err(e), - } -} - -fn include_bytes_expand( - _db: &dyn AstDatabase, - _arg_id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - if let Err(e) = parse_string(tt) { - return ExpandResult::only_err(e); - } - - // FIXME: actually read the file here if the user asked for macro expansion - let res = tt::Subtree { - delimiter: None, - token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { - text: r#"b"""#.into(), - id: tt::TokenId::unspecified(), - }))], - }; - ExpandResult::ok(ExpandedEager::new(res)) -} - -fn include_str_expand( - db: &dyn AstDatabase, - arg_id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let path = match parse_string(tt) { - Ok(it) => it, - Err(e) => return ExpandResult::only_err(e), - }; - - // FIXME: we're not able to read excluded files (which is most of them because - // it's unusual to `include_str!` a Rust file), but we can return an empty string. - // Ideally, we'd be able to offer a precise expansion if the user asks for macro - // expansion. - let file_id = match relative_file(db, arg_id, &path, true) { - Ok(file_id) => file_id, - Err(_) => { - return ExpandResult::ok(ExpandedEager::new(quote!(""))); - } - }; - - let text = db.file_text(file_id); - let text = &*text; - - ExpandResult::ok(ExpandedEager::new(quote!(#text))) -} - -fn get_env_inner(db: &dyn AstDatabase, arg_id: MacroCallId, key: &str) -> Option { - let krate = db.lookup_intern_macro_call(arg_id).krate; - db.crate_graph()[krate].env.get(key) -} - -fn env_expand( - db: &dyn AstDatabase, - arg_id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let key = match parse_string(tt) { - Ok(it) => it, - Err(e) => return ExpandResult::only_err(e), - }; - - let mut err = None; - let s = get_env_inner(db, arg_id, &key).unwrap_or_else(|| { - // The only variable rust-analyzer ever sets is `OUT_DIR`, so only diagnose that to avoid - // unnecessary diagnostics for eg. `CARGO_PKG_NAME`. - if key == "OUT_DIR" { - err = Some(ExpandError::Other( - r#"`OUT_DIR` not set, enable "build scripts" to fix"#.into(), - )); - } - - // If the variable is unset, still return a dummy string to help type inference along. - // We cannot use an empty string here, because for - // `include!(concat!(env!("OUT_DIR"), "/foo.rs"))` will become - // `include!("foo.rs"), which might go to infinite loop - "__RA_UNIMPLEMENTED__".to_string() - }); - let expanded = quote! { #s }; - - ExpandResult { value: ExpandedEager::new(expanded), err } -} - -fn option_env_expand( - db: &dyn AstDatabase, - arg_id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let key = match parse_string(tt) { - Ok(it) => it, - Err(e) => return ExpandResult::only_err(e), - }; - - let expanded = match get_env_inner(db, arg_id, &key) { - None => quote! { std::option::Option::None::<&str> }, - Some(s) => quote! { std::option::Some(#s) }, - }; - - ExpandResult::ok(ExpandedEager::new(expanded)) -} diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs deleted file mode 100644 index bd60c3d26868c..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ /dev/null @@ -1,509 +0,0 @@ -//! Defines database & queries for macro expansion. - -use std::sync::Arc; - -use base_db::{salsa, SourceDatabase}; -use either::Either; -use limit::Limit; -use mbe::syntax_node_to_token_tree; -use rustc_hash::FxHashSet; -use syntax::{ - ast::{self, HasAttrs, HasDocComments}, - AstNode, GreenNode, Parse, SyntaxNode, SyntaxToken, T, -}; - -use crate::{ - ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion, fixup, - hygiene::HygieneFrame, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, - ExpandError, ExpandResult, ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, - MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, -}; - -/// Total limit on the number of tokens produced by any macro invocation. -/// -/// If an invocation produces more tokens than this limit, it will not be stored in the database and -/// an error will be emitted. -/// -/// Actual max for `analysis-stats .` at some point: 30672. -static TOKEN_LIMIT: Limit = Limit::new(524_288); - -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum TokenExpander { - /// Old-style `macro_rules` or the new macros 2.0 - DeclarativeMacro { mac: mbe::DeclarativeMacro, def_site_token_map: mbe::TokenMap }, - /// Stuff like `line!` and `file!`. - Builtin(BuiltinFnLikeExpander), - /// `global_allocator` and such. - BuiltinAttr(BuiltinAttrExpander), - /// `derive(Copy)` and such. - BuiltinDerive(BuiltinDeriveExpander), - /// The thing we love the most here in rust-analyzer -- procedural macros. - ProcMacro(ProcMacroExpander), -} - -impl TokenExpander { - fn expand( - &self, - db: &dyn AstDatabase, - id: MacroCallId, - tt: &tt::Subtree, - ) -> ExpandResult { - match self { - TokenExpander::DeclarativeMacro { mac, .. } => mac.expand(tt).map_err(Into::into), - TokenExpander::Builtin(it) => it.expand(db, id, tt).map_err(Into::into), - TokenExpander::BuiltinAttr(it) => it.expand(db, id, tt), - TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt), - TokenExpander::ProcMacro(_) => { - // We store the result in salsa db to prevent non-deterministic behavior in - // some proc-macro implementation - // See #4315 for details - db.expand_proc_macro(id) - } - } - } - - pub(crate) fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { - match self { - TokenExpander::DeclarativeMacro { mac, .. } => mac.map_id_down(id), - TokenExpander::Builtin(..) - | TokenExpander::BuiltinAttr(..) - | TokenExpander::BuiltinDerive(..) - | TokenExpander::ProcMacro(..) => id, - } - } - - pub(crate) fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) { - match self { - TokenExpander::DeclarativeMacro { mac, .. } => mac.map_id_up(id), - TokenExpander::Builtin(..) - | TokenExpander::BuiltinAttr(..) - | TokenExpander::BuiltinDerive(..) - | TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call), - } - } -} - -// FIXME: rename to ExpandDatabase -#[salsa::query_group(AstDatabaseStorage)] -pub trait AstDatabase: SourceDatabase { - fn ast_id_map(&self, file_id: HirFileId) -> Arc; - - /// Main public API -- parses a hir file, not caring whether it's a real - /// file or a macro expansion. - #[salsa::transparent] - fn parse_or_expand(&self, file_id: HirFileId) -> Option; - /// Implementation for the macro case. - fn parse_macro_expansion( - &self, - macro_file: MacroFile, - ) -> ExpandResult, Arc)>>; - - /// Macro ids. That's probably the tricksiest bit in rust-analyzer, and the - /// reason why we use salsa at all. - /// - /// We encode macro definitions into ids of macro calls, this what allows us - /// to be incremental. - #[salsa::interned] - fn intern_macro_call(&self, macro_call: MacroCallLoc) -> MacroCallId; - - /// Lowers syntactic macro call to a token tree representation. - #[salsa::transparent] - fn macro_arg( - &self, - id: MacroCallId, - ) -> Option>; - /// Extracts syntax node, corresponding to a macro call. That's a firewall - /// query, only typing in the macro call itself changes the returned - /// subtree. - fn macro_arg_text(&self, id: MacroCallId) -> Option; - /// Gets the expander for this macro. This compiles declarative macros, and - /// just fetches procedural ones. - fn macro_def(&self, id: MacroDefId) -> Result, mbe::ParseError>; - - /// Expand macro call to a token tree. This query is LRUed (we keep 128 or so results in memory) - fn macro_expand(&self, macro_call: MacroCallId) -> ExpandResult>>; - /// Special case of the previous query for procedural macros. We can't LRU - /// proc macros, since they are not deterministic in general, and - /// non-determinism breaks salsa in a very, very, very bad way. @edwin0cheng - /// heroically debugged this once! - fn expand_proc_macro(&self, call: MacroCallId) -> ExpandResult; - /// Firewall query that returns the error from the `macro_expand` query. - fn macro_expand_error(&self, macro_call: MacroCallId) -> Option; - - fn hygiene_frame(&self, file_id: HirFileId) -> Arc; -} - -/// This expands the given macro call, but with different arguments. This is -/// used for completion, where we want to see what 'would happen' if we insert a -/// token. The `token_to_map` mapped down into the expansion, with the mapped -/// token returned. -pub fn expand_speculative( - db: &dyn AstDatabase, - actual_macro_call: MacroCallId, - speculative_args: &SyntaxNode, - token_to_map: SyntaxToken, -) -> Option<(SyntaxNode, SyntaxToken)> { - let loc = db.lookup_intern_macro_call(actual_macro_call); - let macro_def = db.macro_def(loc.def).ok()?; - let token_range = token_to_map.text_range(); - - // Build the subtree and token mapping for the speculative args - let censor = censor_for_macro_input(&loc, speculative_args); - let mut fixups = fixup::fixup_syntax(speculative_args); - fixups.replace.extend(censor.into_iter().map(|node| (node.into(), Vec::new()))); - let (mut tt, spec_args_tmap, _) = mbe::syntax_node_to_token_tree_with_modifications( - speculative_args, - fixups.token_map, - fixups.next_id, - fixups.replace, - fixups.append, - ); - - let (attr_arg, token_id) = match loc.kind { - MacroCallKind::Attr { invoc_attr_index, is_derive, .. } => { - let attr = if is_derive { - // for pseudo-derive expansion we actually pass the attribute itself only - ast::Attr::cast(speculative_args.clone()) - } else { - // Attributes may have an input token tree, build the subtree and map for this as well - // then try finding a token id for our token if it is inside this input subtree. - let item = ast::Item::cast(speculative_args.clone())?; - item.doc_comments_and_attrs().nth(invoc_attr_index as usize).and_then(Either::left) - }?; - match attr.token_tree() { - Some(token_tree) => { - let (mut tree, map) = syntax_node_to_token_tree(attr.token_tree()?.syntax()); - tree.delimiter = None; - - let shift = mbe::Shift::new(&tt); - shift.shift_all(&mut tree); - - let token_id = if token_tree.syntax().text_range().contains_range(token_range) { - let attr_input_start = - token_tree.left_delimiter_token()?.text_range().start(); - let range = token_range.checked_sub(attr_input_start)?; - let token_id = shift.shift(map.token_by_range(range)?); - Some(token_id) - } else { - None - }; - (Some(tree), token_id) - } - _ => (None, None), - } - } - _ => (None, None), - }; - let token_id = match token_id { - Some(token_id) => token_id, - // token wasn't inside an attribute input so it has to be in the general macro input - None => { - let range = token_range.checked_sub(speculative_args.text_range().start())?; - let token_id = spec_args_tmap.token_by_range(range)?; - macro_def.map_id_down(token_id) - } - }; - - // Do the actual expansion, we need to directly expand the proc macro due to the attribute args - // 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, ..) => { - tt.delimiter = None; - expander.expand(db, loc.krate, &tt, attr_arg.as_ref()) - } - MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => { - pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?) - } - _ => macro_def.expand(db, actual_macro_call, &tt), - }; - - let expand_to = macro_expand_to(db, actual_macro_call); - fixup::reverse_fixups(&mut speculative_expansion.value, &spec_args_tmap, &fixups.undo_info); - let (node, rev_tmap) = token_tree_to_syntax_node(&speculative_expansion.value, expand_to); - - let range = rev_tmap.first_range_by_token(token_id, token_to_map.kind())?; - let token = node.syntax_node().covering_element(range).into_token()?; - Some((node.syntax_node(), token)) -} - -fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc { - let map = db.parse_or_expand(file_id).map(|it| AstIdMap::from_source(&it)).unwrap_or_default(); - Arc::new(map) -} - -fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option { - match file_id.0 { - HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), - HirFileIdRepr::MacroFile(macro_file) => { - // FIXME: Note how we convert from `Parse` to `SyntaxNode` here, - // forgetting about parse errors. - db.parse_macro_expansion(macro_file).value.map(|(it, _)| it.syntax_node()) - } - } -} - -fn parse_macro_expansion( - db: &dyn AstDatabase, - macro_file: MacroFile, -) -> ExpandResult, Arc)>> { - let _p = profile::span("parse_macro_expansion"); - let result = db.macro_expand(macro_file.macro_call_id); - - if let Some(err) = &result.err { - // Note: - // The final goal we would like to make all parse_macro success, - // such that the following log will not call anyway. - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - let node = loc.kind.to_node(db); - - // collect parent information for warning log - let parents = - std::iter::successors(loc.kind.file_id().call_node(db), |it| it.file_id.call_node(db)) - .map(|n| format!("{:#}", n.value)) - .collect::>() - .join("\n"); - - tracing::debug!( - "fail on macro_parse: (reason: {:?} macro_call: {:#}) parents: {}", - err, - node.value, - parents - ); - } - let tt = match result.value { - Some(tt) => tt, - None => return ExpandResult { value: None, err: result.err }, - }; - - let expand_to = macro_expand_to(db, macro_file.macro_call_id); - - tracing::debug!("expanded = {}", tt.as_debug_string()); - tracing::debug!("kind = {:?}", expand_to); - - let (parse, rev_token_map) = token_tree_to_syntax_node(&tt, expand_to); - - ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: result.err } -} - -fn macro_arg( - db: &dyn AstDatabase, - id: MacroCallId, -) -> Option> { - let arg = db.macro_arg_text(id)?; - let loc = db.lookup_intern_macro_call(id); - - let node = SyntaxNode::new_root(arg); - let censor = censor_for_macro_input(&loc, &node); - let mut fixups = fixup::fixup_syntax(&node); - fixups.replace.extend(censor.into_iter().map(|node| (node.into(), Vec::new()))); - let (mut tt, tmap, _) = mbe::syntax_node_to_token_tree_with_modifications( - &node, - fixups.token_map, - fixups.next_id, - fixups.replace, - fixups.append, - ); - - if loc.def.is_proc_macro() { - // proc macros expect their inputs without parentheses, MBEs expect it with them included - tt.delimiter = None; - } - - Some(Arc::new((tt, tmap, fixups.undo_info))) -} - -fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet { - (|| { - let censor = match loc.kind { - MacroCallKind::FnLike { .. } => return None, - MacroCallKind::Derive { derive_attr_index, .. } => { - cov_mark::hit!(derive_censoring); - ast::Item::cast(node.clone())? - .attrs() - .take(derive_attr_index as usize + 1) - // FIXME - .filter(|attr| attr.simple_name().as_deref() == Some("derive")) - .map(|it| it.syntax().clone()) - .collect() - } - MacroCallKind::Attr { is_derive: true, .. } => return None, - MacroCallKind::Attr { invoc_attr_index, .. } => { - cov_mark::hit!(attribute_macro_attr_censoring); - ast::Item::cast(node.clone())? - .doc_comments_and_attrs() - .nth(invoc_attr_index as usize) - .and_then(Either::left) - .map(|attr| attr.syntax().clone()) - .into_iter() - .collect() - } - }; - Some(censor) - })() - .unwrap_or_default() -} - -fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option { - let loc = db.lookup_intern_macro_call(id); - let arg = loc.kind.arg(db)?; - if matches!(loc.kind, MacroCallKind::FnLike { .. }) { - let first = arg.first_child_or_token().map_or(T![.], |it| it.kind()); - let last = arg.last_child_or_token().map_or(T![.], |it| it.kind()); - let well_formed_tt = - matches!((first, last), (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}'])); - if !well_formed_tt { - // Don't expand malformed (unbalanced) macro invocations. This is - // less than ideal, but trying to expand unbalanced macro calls - // sometimes produces pathological, deeply nested code which breaks - // all kinds of things. - // - // Some day, we'll have explicit recursion counters for all - // recursive things, at which point this code might be removed. - cov_mark::hit!(issue9358_bad_macro_stack_overflow); - return None; - } - } - Some(arg.green().into()) -} - -fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Result, mbe::ParseError> { - match id.kind { - MacroDefKind::Declarative(ast_id) => { - let (mac, def_site_token_map) = match ast_id.to_node(db) { - ast::Macro::MacroRules(macro_rules) => { - let arg = macro_rules - .token_tree() - .ok_or_else(|| mbe::ParseError::Expected("expected a token tree".into()))?; - let (tt, def_site_token_map) = mbe::syntax_node_to_token_tree(arg.syntax()); - let mac = mbe::DeclarativeMacro::parse_macro_rules(&tt)?; - (mac, def_site_token_map) - } - ast::Macro::MacroDef(macro_def) => { - let arg = macro_def - .body() - .ok_or_else(|| mbe::ParseError::Expected("expected a token tree".into()))?; - let (tt, def_site_token_map) = mbe::syntax_node_to_token_tree(arg.syntax()); - let mac = mbe::DeclarativeMacro::parse_macro2(&tt)?; - (mac, def_site_token_map) - } - }; - Ok(Arc::new(TokenExpander::DeclarativeMacro { mac, def_site_token_map })) - } - MacroDefKind::BuiltIn(expander, _) => Ok(Arc::new(TokenExpander::Builtin(expander))), - MacroDefKind::BuiltInAttr(expander, _) => { - Ok(Arc::new(TokenExpander::BuiltinAttr(expander))) - } - MacroDefKind::BuiltInDerive(expander, _) => { - Ok(Arc::new(TokenExpander::BuiltinDerive(expander))) - } - MacroDefKind::BuiltInEager(..) => { - // FIXME: Return a random error here just to make the types align. - // This obviously should do something real instead. - Err(mbe::ParseError::UnexpectedToken("unexpected eager macro".into())) - } - MacroDefKind::ProcMacro(expander, ..) => Ok(Arc::new(TokenExpander::ProcMacro(expander))), - } -} - -fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult>> { - let _p = profile::span("macro_expand"); - let loc: MacroCallLoc = db.lookup_intern_macro_call(id); - if let Some(eager) = &loc.eager { - return ExpandResult { - value: Some(eager.arg_or_expansion.clone()), - // FIXME: There could be errors here! - err: None, - }; - } - - let macro_arg = match db.macro_arg(id) { - Some(it) => it, - None => { - return ExpandResult::only_err(ExpandError::Other( - "Failed to lower macro args to token tree".into(), - )) - } - }; - - let expander = match db.macro_def(loc.def) { - Ok(it) => it, - // FIXME: This is weird -- we effectively report macro *definition* - // errors lazily, when we try to expand the macro. Instead, they should - // be reported at the definition site (when we construct a def map). - Err(err) => { - return ExpandResult::only_err(ExpandError::Other( - format!("invalid macro definition: {}", err).into(), - )) - } - }; - let ExpandResult { value: mut tt, err } = expander.expand(db, id, ¯o_arg.0); - // Set a hard limit for the expanded tt - let count = tt.count(); - if TOKEN_LIMIT.check(count).is_err() { - return ExpandResult::only_err(ExpandError::Other( - format!( - "macro invocation exceeds token limit: produced {} tokens, limit is {}", - count, - TOKEN_LIMIT.inner(), - ) - .into(), - )); - } - - fixup::reverse_fixups(&mut tt, ¯o_arg.1, ¯o_arg.2); - - ExpandResult { value: Some(Arc::new(tt)), err } -} - -fn macro_expand_error(db: &dyn AstDatabase, macro_call: MacroCallId) -> Option { - db.macro_expand(macro_call).err -} - -fn expand_proc_macro(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult { - let loc: MacroCallLoc = db.lookup_intern_macro_call(id); - let macro_arg = match db.macro_arg(id) { - Some(it) => it, - None => { - return ExpandResult::only_err(ExpandError::Other("No arguments for proc-macro".into())) - } - }; - - let expander = match loc.def.kind { - MacroDefKind::ProcMacro(expander, ..) => expander, - _ => unreachable!(), - }; - - let attr_arg = match &loc.kind { - MacroCallKind::Attr { attr_args, .. } => { - let mut attr_args = attr_args.0.clone(); - mbe::Shift::new(¯o_arg.0).shift_all(&mut attr_args); - Some(attr_args) - } - _ => None, - }; - - expander.expand(db, loc.krate, ¯o_arg.0, attr_arg.as_ref()) -} - -fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc { - Arc::new(HygieneFrame::new(db, file_id)) -} - -fn macro_expand_to(db: &dyn AstDatabase, id: MacroCallId) -> ExpandTo { - let loc: MacroCallLoc = db.lookup_intern_macro_call(id); - loc.kind.expand_to() -} - -fn token_tree_to_syntax_node( - tt: &tt::Subtree, - expand_to: ExpandTo, -) -> (Parse, mbe::TokenMap) { - let entry_point = match expand_to { - ExpandTo::Statements => mbe::TopEntryPoint::MacroStmts, - ExpandTo::Items => mbe::TopEntryPoint::MacroItems, - ExpandTo::Pattern => mbe::TopEntryPoint::Pattern, - ExpandTo::Type => mbe::TopEntryPoint::Type, - ExpandTo::Expr => mbe::TopEntryPoint::Expr, - }; - mbe::token_tree_to_syntax_node(tt, entry_point) -} diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs deleted file mode 100644 index 5fd099aea7d64..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs +++ /dev/null @@ -1,266 +0,0 @@ -//! Eager expansion related utils -//! -//! Here is a dump of a discussion from Vadim Petrochenkov about Eager Expansion and -//! Its name resolution : -//! -//! > Eagerly expanded macros (and also macros eagerly expanded by eagerly expanded macros, -//! > which actually happens in practice too!) are resolved at the location of the "root" macro -//! > that performs the eager expansion on its arguments. -//! > If some name cannot be resolved at the eager expansion time it's considered unresolved, -//! > even if becomes available later (e.g. from a glob import or other macro). -//! -//! > Eagerly expanded macros don't add anything to the module structure of the crate and -//! > don't build any speculative module structures, i.e. they are expanded in a "flat" -//! > way even if tokens in them look like modules. -//! -//! > In other words, it kinda works for simple cases for which it was originally intended, -//! > and we need to live with it because it's available on stable and widely relied upon. -//! -//! -//! See the full discussion : -use std::sync::Arc; - -use base_db::CrateId; -use syntax::{ted, SyntaxNode}; - -use crate::{ - ast::{self, AstNode}, - db::AstDatabase, - hygiene::Hygiene, - mod_path::ModPath, - EagerCallInfo, ExpandError, ExpandResult, ExpandTo, InFile, MacroCallId, MacroCallKind, - MacroCallLoc, MacroDefId, MacroDefKind, UnresolvedMacro, -}; - -#[derive(Debug)] -pub struct ErrorEmitted { - _private: (), -} - -pub trait ErrorSink { - fn emit(&mut self, err: ExpandError); - - fn option( - &mut self, - opt: Option, - error: impl FnOnce() -> ExpandError, - ) -> Result { - match opt { - Some(it) => Ok(it), - None => { - self.emit(error()); - Err(ErrorEmitted { _private: () }) - } - } - } - - fn option_with( - &mut self, - opt: impl FnOnce() -> Option, - error: impl FnOnce() -> ExpandError, - ) -> Result { - self.option(opt(), error) - } - - fn result(&mut self, res: Result) -> Result { - match res { - Ok(it) => Ok(it), - Err(e) => { - self.emit(e); - Err(ErrorEmitted { _private: () }) - } - } - } - - fn expand_result_option(&mut self, res: ExpandResult>) -> Result { - match (res.value, res.err) { - (None, Some(err)) => { - self.emit(err); - Err(ErrorEmitted { _private: () }) - } - (Some(value), opt_err) => { - if let Some(err) = opt_err { - self.emit(err); - } - Ok(value) - } - (None, None) => unreachable!("`ExpandResult` without value or error"), - } - } -} - -impl ErrorSink for &'_ mut dyn FnMut(ExpandError) { - fn emit(&mut self, err: ExpandError) { - self(err); - } -} - -pub fn expand_eager_macro( - db: &dyn AstDatabase, - krate: CrateId, - macro_call: InFile, - def: MacroDefId, - resolver: &dyn Fn(ModPath) -> Option, - diagnostic_sink: &mut dyn FnMut(ExpandError), -) -> Result, UnresolvedMacro> { - let hygiene = Hygiene::new(db, macro_call.file_id); - let parsed_args = macro_call - .value - .token_tree() - .map(|tt| mbe::syntax_node_to_token_tree(tt.syntax()).0) - .unwrap_or_default(); - - let ast_map = db.ast_id_map(macro_call.file_id); - let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(¯o_call.value)); - let expand_to = ExpandTo::from_call_site(¯o_call.value); - - // Note: - // When `lazy_expand` is called, its *parent* file must be already exists. - // Here we store an eager macro id for the argument expanded subtree here - // for that purpose. - let arg_id = db.intern_macro_call(MacroCallLoc { - def, - krate, - eager: Some(EagerCallInfo { - arg_or_expansion: Arc::new(parsed_args.clone()), - included_file: None, - }), - kind: MacroCallKind::FnLike { ast_id: call_id, expand_to: ExpandTo::Expr }, - }); - - let parsed_args = mbe::token_tree_to_syntax_node(&parsed_args, mbe::TopEntryPoint::Expr).0; - let result = match eager_macro_recur( - db, - &hygiene, - InFile::new(arg_id.as_file(), parsed_args.syntax_node()), - krate, - resolver, - diagnostic_sink, - ) { - Ok(Ok(it)) => it, - Ok(Err(err)) => return Ok(Err(err)), - Err(err) => return Err(err), - }; - let subtree = to_subtree(&result); - - if let MacroDefKind::BuiltInEager(eager, _) = def.kind { - let res = eager.expand(db, arg_id, &subtree); - if let Some(err) = res.err { - diagnostic_sink(err); - } - - let loc = MacroCallLoc { - def, - krate, - eager: Some(EagerCallInfo { - arg_or_expansion: Arc::new(res.value.subtree), - included_file: res.value.included_file, - }), - kind: MacroCallKind::FnLike { ast_id: call_id, expand_to }, - }; - - Ok(Ok(db.intern_macro_call(loc))) - } else { - panic!("called `expand_eager_macro` on non-eager macro def {:?}", def); - } -} - -fn to_subtree(node: &SyntaxNode) -> tt::Subtree { - let mut subtree = mbe::syntax_node_to_token_tree(node).0; - subtree.delimiter = None; - subtree -} - -fn lazy_expand( - db: &dyn AstDatabase, - def: &MacroDefId, - macro_call: InFile, - krate: CrateId, -) -> ExpandResult>> { - let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value); - - let expand_to = ExpandTo::from_call_site(¯o_call.value); - let id = def.as_lazy_macro( - db, - krate, - MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id), expand_to }, - ); - - let err = db.macro_expand_error(id); - let value = db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node)); - - ExpandResult { value, err } -} - -fn eager_macro_recur( - db: &dyn AstDatabase, - hygiene: &Hygiene, - curr: InFile, - krate: CrateId, - macro_resolver: &dyn Fn(ModPath) -> Option, - mut diagnostic_sink: &mut dyn FnMut(ExpandError), -) -> Result, UnresolvedMacro> { - let original = curr.value.clone_for_update(); - - let children = original.descendants().filter_map(ast::MacroCall::cast); - let mut replacements = Vec::new(); - - // Collect replacement - for child in children { - let def = match child.path().and_then(|path| ModPath::from_src(db, path, hygiene)) { - Some(path) => macro_resolver(path.clone()).ok_or_else(|| UnresolvedMacro { path })?, - None => { - diagnostic_sink(ExpandError::Other("malformed macro invocation".into())); - continue; - } - }; - let insert = match def.kind { - MacroDefKind::BuiltInEager(..) => { - let id = match expand_eager_macro( - db, - krate, - curr.with_value(child.clone()), - def, - macro_resolver, - diagnostic_sink, - ) { - Ok(Ok(it)) => it, - Ok(Err(err)) => return Ok(Err(err)), - Err(err) => return Err(err), - }; - db.parse_or_expand(id.as_file()) - .expect("successful macro expansion should be parseable") - .clone_for_update() - } - MacroDefKind::Declarative(_) - | MacroDefKind::BuiltIn(..) - | MacroDefKind::BuiltInAttr(..) - | MacroDefKind::BuiltInDerive(..) - | MacroDefKind::ProcMacro(..) => { - let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate); - let val = match diagnostic_sink.expand_result_option(res) { - Ok(it) => it, - Err(err) => return Ok(Err(err)), - }; - - // replace macro inside - let hygiene = Hygiene::new(db, val.file_id); - match eager_macro_recur(db, &hygiene, val, krate, macro_resolver, diagnostic_sink) { - Ok(Ok(it)) => it, - Ok(Err(err)) => return Ok(Err(err)), - Err(err) => return Err(err), - } - } - }; - - // check if the whole original syntax is replaced - if child.syntax() == &original { - return Ok(Ok(insert)); - } - - replacements.push((child, insert)); - } - - replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new)); - Ok(Ok(original)) -} diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs deleted file mode 100644 index 9999790fae727..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs +++ /dev/null @@ -1,382 +0,0 @@ -//! To make attribute macros work reliably when typing, we need to take care to -//! fix up syntax errors in the code we're passing to them. -use std::mem; - -use mbe::{SyntheticToken, SyntheticTokenId, TokenMap}; -use rustc_hash::FxHashMap; -use syntax::{ - ast::{self, AstNode}, - match_ast, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, -}; -use tt::Subtree; - -/// The result of calculating fixes for a syntax node -- a bunch of changes -/// (appending to and replacing nodes), the information that is needed to -/// reverse those changes afterwards, and a token map. -#[derive(Debug)] -pub(crate) struct SyntaxFixups { - pub(crate) append: FxHashMap>, - pub(crate) replace: FxHashMap>, - pub(crate) undo_info: SyntaxFixupUndoInfo, - pub(crate) token_map: TokenMap, - pub(crate) next_id: u32, -} - -/// This is the information needed to reverse the fixups. -#[derive(Debug, PartialEq, Eq)] -pub struct SyntaxFixupUndoInfo { - original: Vec, -} - -const EMPTY_ID: SyntheticTokenId = SyntheticTokenId(!0); - -pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups { - let mut append = FxHashMap::::default(); - let mut replace = FxHashMap::::default(); - let mut preorder = node.preorder(); - let mut original = Vec::new(); - let mut token_map = TokenMap::default(); - let mut next_id = 0; - while let Some(event) = preorder.next() { - let node = match event { - syntax::WalkEvent::Enter(node) => node, - syntax::WalkEvent::Leave(_) => continue, - }; - - if can_handle_error(&node) && has_error_to_handle(&node) { - // the node contains an error node, we have to completely replace it by something valid - let (original_tree, new_tmap, new_next_id) = - mbe::syntax_node_to_token_tree_with_modifications( - &node, - mem::take(&mut token_map), - next_id, - Default::default(), - Default::default(), - ); - token_map = new_tmap; - next_id = new_next_id; - let idx = original.len() as u32; - original.push(original_tree); - let replacement = SyntheticToken { - kind: SyntaxKind::IDENT, - text: "__ra_fixup".into(), - range: node.text_range(), - id: SyntheticTokenId(idx), - }; - replace.insert(node.clone().into(), vec![replacement]); - preorder.skip_subtree(); - continue; - } - - // In some other situations, we can fix things by just appending some tokens. - let end_range = TextRange::empty(node.text_range().end()); - match_ast! { - match node { - ast::FieldExpr(it) => { - if it.name_ref().is_none() { - // incomplete field access: some_expr.| - append.insert(node.clone().into(), vec![ - SyntheticToken { - kind: SyntaxKind::IDENT, - text: "__ra_fixup".into(), - range: end_range, - id: EMPTY_ID, - }, - ]); - } - }, - ast::ExprStmt(it) => { - if it.semicolon_token().is_none() { - append.insert(node.clone().into(), vec![ - SyntheticToken { - kind: SyntaxKind::SEMICOLON, - text: ";".into(), - range: end_range, - id: EMPTY_ID, - }, - ]); - } - }, - ast::LetStmt(it) => { - if it.semicolon_token().is_none() { - append.insert(node.clone().into(), vec![ - SyntheticToken { - kind: SyntaxKind::SEMICOLON, - text: ";".into(), - range: end_range, - id: EMPTY_ID, - }, - ]); - } - }, - ast::IfExpr(it) => { - if it.condition().is_none() { - // insert placeholder token after the if token - let if_token = match it.if_token() { - Some(t) => t, - None => continue, - }; - append.insert(if_token.into(), vec![ - SyntheticToken { - kind: SyntaxKind::IDENT, - text: "__ra_fixup".into(), - range: end_range, - id: EMPTY_ID, - }, - ]); - } - if it.then_branch().is_none() { - append.insert(node.clone().into(), vec![ - SyntheticToken { - kind: SyntaxKind::L_CURLY, - text: "{".into(), - range: end_range, - id: EMPTY_ID, - }, - SyntheticToken { - kind: SyntaxKind::R_CURLY, - text: "}".into(), - range: end_range, - id: EMPTY_ID, - }, - ]); - } - }, - // FIXME: foo:: - // FIXME: for, loop, match etc. - _ => (), - } - } - } - SyntaxFixups { - append, - replace, - token_map, - next_id, - undo_info: SyntaxFixupUndoInfo { original }, - } -} - -fn has_error(node: &SyntaxNode) -> bool { - node.children().any(|c| c.kind() == SyntaxKind::ERROR) -} - -fn can_handle_error(node: &SyntaxNode) -> bool { - ast::Expr::can_cast(node.kind()) -} - -fn has_error_to_handle(node: &SyntaxNode) -> bool { - has_error(node) || node.children().any(|c| !can_handle_error(&c) && has_error_to_handle(&c)) -} - -pub(crate) fn reverse_fixups( - tt: &mut Subtree, - token_map: &TokenMap, - undo_info: &SyntaxFixupUndoInfo, -) { - tt.token_trees.retain(|tt| match tt { - tt::TokenTree::Leaf(leaf) => { - token_map.synthetic_token_id(leaf.id()).is_none() - || token_map.synthetic_token_id(leaf.id()) != Some(EMPTY_ID) - } - tt::TokenTree::Subtree(st) => st.delimiter.map_or(true, |d| { - token_map.synthetic_token_id(d.id).is_none() - || token_map.synthetic_token_id(d.id) != Some(EMPTY_ID) - }), - }); - tt.token_trees.iter_mut().for_each(|tt| match tt { - tt::TokenTree::Subtree(tt) => reverse_fixups(tt, token_map, undo_info), - tt::TokenTree::Leaf(leaf) => { - if let Some(id) = token_map.synthetic_token_id(leaf.id()) { - let original = &undo_info.original[id.0 as usize]; - *tt = tt::TokenTree::Subtree(original.clone()); - } - } - }); -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use super::reverse_fixups; - - #[track_caller] - fn check(ra_fixture: &str, mut expect: Expect) { - let parsed = syntax::SourceFile::parse(ra_fixture); - let fixups = super::fixup_syntax(&parsed.syntax_node()); - let (mut tt, tmap, _) = mbe::syntax_node_to_token_tree_with_modifications( - &parsed.syntax_node(), - fixups.token_map, - fixups.next_id, - fixups.replace, - fixups.append, - ); - - let mut actual = tt.to_string(); - actual.push('\n'); - - expect.indent(false); - expect.assert_eq(&actual); - - // the fixed-up tree should be syntactically valid - let (parse, _) = mbe::token_tree_to_syntax_node(&tt, ::mbe::TopEntryPoint::MacroItems); - assert_eq!( - parse.errors(), - &[], - "parse has syntax errors. parse tree:\n{:#?}", - parse.syntax_node() - ); - - reverse_fixups(&mut tt, &tmap, &fixups.undo_info); - - // the fixed-up + reversed version should be equivalent to the original input - // (but token IDs don't matter) - let (original_as_tt, _) = mbe::syntax_node_to_token_tree(&parsed.syntax_node()); - assert_eq!(tt.to_string(), original_as_tt.to_string()); - } - - #[test] - fn incomplete_field_expr_1() { - check( - r#" -fn foo() { - a. -} -"#, - expect![[r#" -fn foo () {a . __ra_fixup} -"#]], - ) - } - - #[test] - fn incomplete_field_expr_2() { - check( - r#" -fn foo() { - a. ; -} -"#, - expect![[r#" -fn foo () {a . __ra_fixup ;} -"#]], - ) - } - - #[test] - fn incomplete_field_expr_3() { - check( - r#" -fn foo() { - a. ; - bar(); -} -"#, - expect![[r#" -fn foo () {a . __ra_fixup ; bar () ;} -"#]], - ) - } - - #[test] - fn incomplete_let() { - check( - r#" -fn foo() { - let x = a -} -"#, - expect![[r#" -fn foo () {let x = a ;} -"#]], - ) - } - - #[test] - fn incomplete_field_expr_in_let() { - check( - r#" -fn foo() { - let x = a. -} -"#, - expect![[r#" -fn foo () {let x = a . __ra_fixup ;} -"#]], - ) - } - - #[test] - fn field_expr_before_call() { - // another case that easily happens while typing - check( - r#" -fn foo() { - a.b - bar(); -} -"#, - expect![[r#" -fn foo () {a . b ; bar () ;} -"#]], - ) - } - - #[test] - fn extraneous_comma() { - check( - r#" -fn foo() { - bar(,); -} -"#, - expect![[r#" -fn foo () {__ra_fixup ;} -"#]], - ) - } - - #[test] - fn fixup_if_1() { - check( - r#" -fn foo() { - if a -} -"#, - expect![[r#" -fn foo () {if a {}} -"#]], - ) - } - - #[test] - fn fixup_if_2() { - check( - r#" -fn foo() { - if -} -"#, - expect![[r#" -fn foo () {if __ra_fixup {}} -"#]], - ) - } - - #[test] - fn fixup_if_3() { - check( - r#" -fn foo() { - if {} -} -"#, - // the {} gets parsed as the condition, I think? - expect![[r#" -fn foo () {if {} {}} -"#]], - ) - } -} diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs deleted file mode 100644 index d60734372c0ce..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs +++ /dev/null @@ -1,256 +0,0 @@ -//! This modules handles hygiene information. -//! -//! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at -//! this moment, this is horribly incomplete and handles only `$crate`. -use std::sync::Arc; - -use base_db::CrateId; -use db::TokenExpander; -use either::Either; -use mbe::Origin; -use syntax::{ - ast::{self, HasDocComments}, - AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize, -}; - -use crate::{ - db::{self, AstDatabase}, - fixup, - name::{AsName, Name}, - HirFileId, HirFileIdRepr, InFile, MacroCallKind, MacroCallLoc, MacroDefKind, MacroFile, -}; - -#[derive(Clone, Debug)] -pub struct Hygiene { - frames: Option, -} - -impl Hygiene { - pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene { - Hygiene { frames: Some(HygieneFrames::new(db, file_id)) } - } - - pub fn new_unhygienic() -> Hygiene { - Hygiene { frames: None } - } - - // FIXME: this should just return name - pub fn name_ref_to_name( - &self, - db: &dyn AstDatabase, - name_ref: ast::NameRef, - ) -> Either { - if let Some(frames) = &self.frames { - if name_ref.text() == "$crate" { - if let Some(krate) = frames.root_crate(db, name_ref.syntax()) { - return Either::Right(krate); - } - } - } - - Either::Left(name_ref.as_name()) - } - - pub fn local_inner_macros(&self, db: &dyn AstDatabase, path: ast::Path) -> Option { - let mut token = path.syntax().first_token()?.text_range(); - let frames = self.frames.as_ref()?; - let mut current = &frames.0; - - loop { - let (mapped, origin) = current.expansion.as_ref()?.map_ident_up(db, token)?; - if origin == Origin::Def { - return if current.local_inner { - frames.root_crate(db, path.syntax()) - } else { - None - }; - } - current = current.call_site.as_ref()?; - token = mapped.value; - } - } -} - -#[derive(Clone, Debug)] -struct HygieneFrames(Arc); - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct HygieneFrame { - expansion: Option, - - // Indicate this is a local inner macro - local_inner: bool, - krate: Option, - - call_site: Option>, - def_site: Option>, -} - -impl HygieneFrames { - fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Self { - // Note that this intentionally avoids the `hygiene_frame` query to avoid blowing up memory - // usage. The query is only helpful for nested `HygieneFrame`s as it avoids redundant work. - HygieneFrames(Arc::new(HygieneFrame::new(db, file_id))) - } - - fn root_crate(&self, db: &dyn AstDatabase, node: &SyntaxNode) -> Option { - let mut token = node.first_token()?.text_range(); - let mut result = self.0.krate; - let mut current = self.0.clone(); - - while let Some((mapped, origin)) = - current.expansion.as_ref().and_then(|it| it.map_ident_up(db, token)) - { - result = current.krate; - - let site = match origin { - Origin::Def => ¤t.def_site, - Origin::Call => ¤t.call_site, - }; - - let site = match site { - None => break, - Some(it) => it, - }; - - current = site.clone(); - token = mapped.value; - } - - result - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct HygieneInfo { - file: MacroFile, - /// The start offset of the `macro_rules!` arguments or attribute input. - attr_input_or_mac_def_start: Option>, - - macro_def: Arc, - macro_arg: Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>, - macro_arg_shift: mbe::Shift, - exp_map: Arc, -} - -impl HygieneInfo { - fn map_ident_up( - &self, - db: &dyn AstDatabase, - token: TextRange, - ) -> Option<(InFile, Origin)> { - let token_id = self.exp_map.token_by_range(token)?; - let (mut token_id, origin) = self.macro_def.map_id_up(token_id); - - let loc = db.lookup_intern_macro_call(self.file.macro_call_id); - - let (token_map, tt) = match &loc.kind { - MacroCallKind::Attr { attr_args, .. } => match self.macro_arg_shift.unshift(token_id) { - Some(unshifted) => { - token_id = unshifted; - (&attr_args.1, self.attr_input_or_mac_def_start?) - } - None => ( - &self.macro_arg.1, - InFile::new(loc.kind.file_id(), loc.kind.arg(db)?.text_range().start()), - ), - }, - _ => match origin { - mbe::Origin::Call => ( - &self.macro_arg.1, - InFile::new(loc.kind.file_id(), loc.kind.arg(db)?.text_range().start()), - ), - mbe::Origin::Def => match (&*self.macro_def, &self.attr_input_or_mac_def_start) { - (TokenExpander::DeclarativeMacro { def_site_token_map, .. }, Some(tt)) => { - (def_site_token_map, *tt) - } - _ => panic!("`Origin::Def` used with non-`macro_rules!` macro"), - }, - }, - }; - - let range = token_map.first_range_by_token(token_id, SyntaxKind::IDENT)?; - Some((tt.with_value(range + tt.value), origin)) - } -} - -fn make_hygiene_info( - db: &dyn AstDatabase, - macro_file: MacroFile, - loc: &MacroCallLoc, -) -> Option { - 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(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, .. } => { - let tt = ast_id - .to_node(db) - .doc_comments_and_attrs() - .nth(invoc_attr_index as usize) - .and_then(Either::left)? - .token_tree()?; - Some(InFile::new(ast_id.file_id, tt)) - } - _ => None, - }); - - let macro_def = db.macro_def(loc.def).ok()?; - let (_, exp_map) = db.parse_macro_expansion(macro_file).value?; - let macro_arg = db.macro_arg(macro_file.macro_call_id)?; - - Some(HygieneInfo { - file: macro_file, - attr_input_or_mac_def_start: attr_input_or_mac_def - .map(|it| it.map(|tt| tt.syntax().text_range().start())), - macro_arg_shift: mbe::Shift::new(¯o_arg.0), - macro_arg, - macro_def, - exp_map, - }) -} - -impl HygieneFrame { - pub(crate) fn new(db: &dyn AstDatabase, file_id: HirFileId) -> HygieneFrame { - let (info, krate, local_inner) = match file_id.0 { - HirFileIdRepr::FileId(_) => (None, None, false), - HirFileIdRepr::MacroFile(macro_file) => { - let loc = db.lookup_intern_macro_call(macro_file.macro_call_id); - let info = - make_hygiene_info(db, macro_file, &loc).map(|info| (loc.kind.file_id(), info)); - match loc.def.kind { - MacroDefKind::Declarative(_) => { - (info, Some(loc.def.krate), loc.def.local_inner) - } - MacroDefKind::BuiltIn(..) => (info, Some(loc.def.krate), false), - MacroDefKind::BuiltInAttr(..) => (info, None, false), - MacroDefKind::BuiltInDerive(..) => (info, None, false), - MacroDefKind::BuiltInEager(..) => (info, None, false), - MacroDefKind::ProcMacro(..) => (info, None, false), - } - } - }; - - let (calling_file, info) = match info { - None => { - return HygieneFrame { - expansion: None, - local_inner, - krate, - call_site: None, - def_site: None, - }; - } - Some(it) => it, - }; - - let def_site = info.attr_input_or_mac_def_start.map(|it| db.hygiene_frame(it.file_id)); - let call_site = Some(db.hygiene_frame(calling_file)); - - HygieneFrame { expansion: Some(info), local_inner, krate, call_site, def_site } - } -} diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs deleted file mode 100644 index 252293090bb0c..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ /dev/null @@ -1,1000 +0,0 @@ -//! `hir_expand` deals with macro expansion. -//! -//! Specifically, it implements a concept of `MacroFile` -- a file whose syntax -//! tree originates not from the text of some `FileId`, but from some macro -//! expansion. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -pub mod db; -pub mod ast_id_map; -pub mod name; -pub mod hygiene; -pub mod builtin_attr_macro; -pub mod builtin_derive_macro; -pub mod builtin_fn_macro; -pub mod proc_macro; -pub mod quote; -pub mod eager; -pub mod mod_path; -mod fixup; - -pub use mbe::{Origin, ValueResult}; - -use std::{fmt, hash::Hash, iter, sync::Arc}; - -use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange, ProcMacroKind}; -use either::Either; -use syntax::{ - algo::{self, skip_trivia_token}, - ast::{self, AstNode, HasDocComments}, - Direction, SyntaxNode, SyntaxToken, -}; - -use crate::{ - ast_id_map::FileAstId, - builtin_attr_macro::BuiltinAttrExpander, - builtin_derive_macro::BuiltinDeriveExpander, - builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander}, - db::TokenExpander, - mod_path::ModPath, - proc_macro::ProcMacroExpander, -}; - -pub type ExpandResult = ValueResult; - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum ExpandError { - UnresolvedProcMacro(CrateId), - Mbe(mbe::ExpandError), - Other(Box), -} - -impl From for ExpandError { - fn from(mbe: mbe::ExpandError) -> Self { - Self::Mbe(mbe) - } -} - -impl fmt::Display for ExpandError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ExpandError::UnresolvedProcMacro(_) => f.write_str("unresolved proc-macro"), - ExpandError::Mbe(it) => it.fmt(f), - ExpandError::Other(it) => f.write_str(it), - } - } -} - -/// Input to the analyzer is a set of files, where each file is identified by -/// `FileId` and contains source code. However, another source of source code in -/// Rust are macros: each macro can be thought of as producing a "temporary -/// file". To assign an id to such a file, we use the id of the macro call that -/// produced the file. So, a `HirFileId` is either a `FileId` (source code -/// written by user), or a `MacroCallId` (source code produced by macro). -/// -/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file -/// containing the call plus the offset of the macro call in the file. Note that -/// this is a recursive definition! However, the size_of of `HirFileId` is -/// finite (because everything bottoms out at the real `FileId`) and small -/// (`MacroCallId` uses the location interning. You can check details here: -/// ). -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct HirFileId(HirFileIdRepr); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -enum HirFileIdRepr { - FileId(FileId), - MacroFile(MacroFile), -} - -impl From for HirFileId { - fn from(id: FileId) -> Self { - HirFileId(HirFileIdRepr::FileId(id)) - } -} - -impl From for HirFileId { - fn from(id: MacroFile) -> Self { - HirFileId(HirFileIdRepr::MacroFile(id)) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct MacroFile { - pub macro_call_id: MacroCallId, -} - -/// `MacroCallId` identifies a particular macro invocation, like -/// `println!("Hello, {}", world)`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct MacroCallId(salsa::InternId); -impl_intern_key!(MacroCallId); - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct MacroCallLoc { - pub def: MacroDefId, - pub(crate) krate: CrateId, - eager: Option, - pub kind: MacroCallKind, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct MacroDefId { - pub krate: CrateId, - pub kind: MacroDefKind, - pub local_inner: bool, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum MacroDefKind { - Declarative(AstId), - BuiltIn(BuiltinFnLikeExpander, AstId), - // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander - BuiltInAttr(BuiltinAttrExpander, AstId), - BuiltInDerive(BuiltinDeriveExpander, AstId), - BuiltInEager(EagerExpander, AstId), - ProcMacro(ProcMacroExpander, ProcMacroKind, AstId), -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -struct EagerCallInfo { - /// NOTE: This can be *either* the expansion result, *or* the argument to the eager macro! - arg_or_expansion: Arc, - included_file: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum MacroCallKind { - FnLike { - ast_id: AstId, - expand_to: ExpandTo, - }, - Derive { - ast_id: AstId, - /// Syntactical index of the invoking `#[derive]` attribute. - /// - /// Outer attributes are counted first, then inner attributes. This does not support - /// out-of-line modules, which may have attributes spread across 2 files! - derive_attr_index: u32, - /// Index of the derive macro in the derive attribute - derive_index: u32, - }, - Attr { - ast_id: AstId, - attr_args: Arc<(tt::Subtree, mbe::TokenMap)>, - /// Syntactical index of the invoking `#[attribute]`. - /// - /// Outer attributes are counted first, then inner attributes. This does not support - /// out-of-line modules, which may have attributes spread across 2 files! - invoc_attr_index: u32, - /// Whether this attribute is the `#[derive]` attribute. - is_derive: bool, - }, -} - -impl HirFileId { - /// For macro-expansion files, returns the file original source file the - /// expansion originated from. - pub fn original_file(self, db: &dyn db::AstDatabase) -> FileId { - let mut file_id = self; - loop { - match file_id.0 { - HirFileIdRepr::FileId(id) => break id, - HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => { - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_call_id); - file_id = match loc.eager { - Some(EagerCallInfo { included_file: Some(file), .. }) => file.into(), - _ => loc.kind.file_id(), - }; - } - } - } - } - - pub fn expansion_level(self, db: &dyn db::AstDatabase) -> u32 { - let mut level = 0; - let mut curr = self; - while let HirFileIdRepr::MacroFile(macro_file) = curr.0 { - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - - level += 1; - curr = loc.kind.file_id(); - } - level - } - - /// If this is a macro call, returns the syntax node of the call. - pub fn call_node(self, db: &dyn db::AstDatabase) -> Option> { - match self.0 { - HirFileIdRepr::FileId(_) => None, - HirFileIdRepr::MacroFile(macro_file) => { - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - Some(loc.kind.to_node(db)) - } - } - } - - /// If this is a macro call, returns the syntax node of the very first macro call this file resides in. - pub fn original_call_node(self, db: &dyn db::AstDatabase) -> Option<(FileId, SyntaxNode)> { - let mut call = match self.0 { - HirFileIdRepr::FileId(_) => return None, - HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => { - db.lookup_intern_macro_call(macro_call_id).kind.to_node(db) - } - }; - loop { - match call.file_id.0 { - HirFileIdRepr::FileId(file_id) => break Some((file_id, call.value)), - HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => { - call = db.lookup_intern_macro_call(macro_call_id).kind.to_node(db); - } - } - } - } - - /// Return expansion information if it is a macro-expansion file - pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option { - match self.0 { - HirFileIdRepr::FileId(_) => None, - HirFileIdRepr::MacroFile(macro_file) => { - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - - let arg_tt = loc.kind.arg(db)?; - - let macro_def = db.macro_def(loc.def).ok()?; - let (parse, exp_map) = db.parse_macro_expansion(macro_file).value?; - let macro_arg = db.macro_arg(macro_file.macro_call_id)?; - - 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, .. } => { - let tt = ast_id - .to_node(db) - .doc_comments_and_attrs() - .nth(invoc_attr_index as usize) - .and_then(Either::left)? - .token_tree()?; - Some(InFile::new(ast_id.file_id, tt)) - } - _ => None, - }); - - Some(ExpansionInfo { - expanded: InFile::new(self, parse.syntax_node()), - arg: InFile::new(loc.kind.file_id(), arg_tt), - attr_input_or_mac_def, - macro_arg_shift: mbe::Shift::new(¯o_arg.0), - macro_arg, - macro_def, - exp_map, - }) - } - } - } - - /// Indicate it is macro file generated for builtin derive - pub fn is_builtin_derive(&self, db: &dyn db::AstDatabase) -> Option> { - match self.0 { - HirFileIdRepr::FileId(_) => None, - HirFileIdRepr::MacroFile(macro_file) => { - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - let attr = match loc.def.kind { - MacroDefKind::BuiltInDerive(..) => loc.kind.to_node(db), - _ => return None, - }; - Some(attr.with_value(ast::Attr::cast(attr.value.clone())?)) - } - } - } - - pub fn is_custom_derive(&self, db: &dyn db::AstDatabase) -> bool { - match self.0 { - HirFileIdRepr::FileId(_) => false, - HirFileIdRepr::MacroFile(macro_file) => { - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - matches!(loc.def.kind, MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _)) - } - } - } - - /// Return whether this file is an include macro - pub fn is_include_macro(&self, db: &dyn db::AstDatabase) -> bool { - match self.0 { - HirFileIdRepr::MacroFile(macro_file) => { - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - matches!(loc.eager, Some(EagerCallInfo { included_file: Some(_), .. })) - } - _ => false, - } - } - - /// Return whether this file is an attr macro - pub fn is_attr_macro(&self, db: &dyn db::AstDatabase) -> bool { - match self.0 { - HirFileIdRepr::MacroFile(macro_file) => { - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - matches!(loc.kind, MacroCallKind::Attr { .. }) - } - _ => false, - } - } - - /// Return whether this file is the pseudo expansion of the derive attribute. - /// See [`crate::builtin_attr_macro::derive_attr_expand`]. - pub fn is_derive_attr_pseudo_expansion(&self, db: &dyn db::AstDatabase) -> bool { - match self.0 { - HirFileIdRepr::MacroFile(macro_file) => { - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - matches!(loc.kind, MacroCallKind::Attr { is_derive: true, .. }) - } - _ => false, - } - } - - pub fn is_macro(self) -> bool { - matches!(self.0, HirFileIdRepr::MacroFile(_)) - } - - pub fn macro_file(self) -> Option { - match self.0 { - HirFileIdRepr::FileId(_) => None, - HirFileIdRepr::MacroFile(m) => Some(m), - } - } -} - -impl MacroDefId { - pub fn as_lazy_macro( - self, - db: &dyn db::AstDatabase, - krate: CrateId, - kind: MacroCallKind, - ) -> MacroCallId { - db.intern_macro_call(MacroCallLoc { def: self, krate, eager: None, kind }) - } - - pub fn ast_id(&self) -> Either, AstId> { - let id = match self.kind { - MacroDefKind::ProcMacro(.., id) => return Either::Right(id), - MacroDefKind::Declarative(id) - | MacroDefKind::BuiltIn(_, id) - | MacroDefKind::BuiltInAttr(_, id) - | MacroDefKind::BuiltInDerive(_, id) - | MacroDefKind::BuiltInEager(_, id) => id, - }; - Either::Left(id) - } - - pub fn is_proc_macro(&self) -> bool { - matches!(self.kind, MacroDefKind::ProcMacro(..)) - } - - pub fn is_attribute(&self) -> bool { - matches!( - self.kind, - MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, ProcMacroKind::Attr, _) - ) - } -} - -// FIXME: attribute indices do not account for `cfg_attr`, which means that we'll strip the whole -// `cfg_attr` instead of just one of the attributes it expands to - -impl MacroCallKind { - /// Returns the file containing the macro invocation. - fn file_id(&self) -> HirFileId { - match *self { - MacroCallKind::FnLike { ast_id: InFile { file_id, .. }, .. } - | MacroCallKind::Derive { ast_id: InFile { file_id, .. }, .. } - | MacroCallKind::Attr { ast_id: InFile { file_id, .. }, .. } => file_id, - } - } - - pub fn to_node(&self, db: &dyn db::AstDatabase) -> InFile { - match self { - MacroCallKind::FnLike { ast_id, .. } => { - ast_id.with_value(ast_id.to_node(db).syntax().clone()) - } - MacroCallKind::Derive { ast_id, derive_attr_index, .. } => { - // FIXME: handle `cfg_attr` - ast_id.with_value(ast_id.to_node(db)).map(|it| { - it.doc_comments_and_attrs() - .nth(*derive_attr_index as usize) - .and_then(|it| match it { - Either::Left(attr) => Some(attr.syntax().clone()), - Either::Right(_) => None, - }) - .unwrap_or_else(|| it.syntax().clone()) - }) - } - MacroCallKind::Attr { ast_id, is_derive: true, invoc_attr_index, .. } => { - // FIXME: handle `cfg_attr` - ast_id.with_value(ast_id.to_node(db)).map(|it| { - it.doc_comments_and_attrs() - .nth(*invoc_attr_index as usize) - .and_then(|it| match it { - Either::Left(attr) => Some(attr.syntax().clone()), - Either::Right(_) => None, - }) - .unwrap_or_else(|| it.syntax().clone()) - }) - } - MacroCallKind::Attr { ast_id, .. } => { - ast_id.with_value(ast_id.to_node(db).syntax().clone()) - } - } - } - - /// Returns the original file range that best describes the location of this macro call. - /// - /// Unlike `MacroCallKind::original_call_range`, this also spans the item of attributes and derives. - pub fn original_call_range_with_body(self, db: &dyn db::AstDatabase) -> FileRange { - let mut kind = self; - let file_id = loop { - match kind.file_id().0 { - HirFileIdRepr::MacroFile(file) => { - kind = db.lookup_intern_macro_call(file.macro_call_id).kind; - } - HirFileIdRepr::FileId(file_id) => break file_id, - } - }; - - let range = match kind { - MacroCallKind::FnLike { ast_id, .. } => ast_id.to_node(db).syntax().text_range(), - MacroCallKind::Derive { ast_id, .. } => ast_id.to_node(db).syntax().text_range(), - MacroCallKind::Attr { ast_id, .. } => ast_id.to_node(db).syntax().text_range(), - }; - - FileRange { range, file_id } - } - - /// Returns the original file range that best describes the location of this macro call. - /// - /// Here we try to roughly match what rustc does to improve diagnostics: fn-like macros - /// get the whole `ast::MacroCall`, attribute macros get the attribute's range, and derives - /// get only the specific derive that is being referred to. - pub fn original_call_range(self, db: &dyn db::AstDatabase) -> FileRange { - let mut kind = self; - let file_id = loop { - match kind.file_id().0 { - HirFileIdRepr::MacroFile(file) => { - kind = db.lookup_intern_macro_call(file.macro_call_id).kind; - } - HirFileIdRepr::FileId(file_id) => break file_id, - } - }; - - let range = match kind { - MacroCallKind::FnLike { ast_id, .. } => ast_id.to_node(db).syntax().text_range(), - MacroCallKind::Derive { ast_id, derive_attr_index, .. } => { - // FIXME: should be the range of the macro name, not the whole derive - ast_id - .to_node(db) - .doc_comments_and_attrs() - .nth(derive_attr_index as usize) - .expect("missing derive") - .expect_left("derive is a doc comment?") - .syntax() - .text_range() - } - MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => ast_id - .to_node(db) - .doc_comments_and_attrs() - .nth(invoc_attr_index as usize) - .expect("missing attribute") - .expect_left("attribute macro is a doc comment?") - .syntax() - .text_range(), - }; - - FileRange { range, file_id } - } - - fn arg(&self, db: &dyn db::AstDatabase) -> Option { - match self { - MacroCallKind::FnLike { ast_id, .. } => { - Some(ast_id.to_node(db).token_tree()?.syntax().clone()) - } - MacroCallKind::Derive { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()), - MacroCallKind::Attr { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()), - } - } - - fn expand_to(&self) -> ExpandTo { - match self { - MacroCallKind::FnLike { expand_to, .. } => *expand_to, - MacroCallKind::Derive { .. } => ExpandTo::Items, - MacroCallKind::Attr { is_derive: true, .. } => ExpandTo::Statements, - MacroCallKind::Attr { .. } => ExpandTo::Items, // is this always correct? - } - } -} - -impl MacroCallId { - pub fn as_file(self) -> HirFileId { - MacroFile { macro_call_id: self }.into() - } -} - -/// ExpansionInfo mainly describes how to map text range between src and expanded macro -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ExpansionInfo { - expanded: InFile, - /// The argument TokenTree or item for attributes - arg: InFile, - /// The `macro_rules!` or attribute input. - attr_input_or_mac_def: Option>, - - macro_def: Arc, - macro_arg: Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>, - /// A shift built from `macro_arg`'s subtree, relevant for attributes as the item is the macro arg - /// and as such we need to shift tokens if they are part of an attributes input instead of their item. - macro_arg_shift: mbe::Shift, - exp_map: Arc, -} - -impl ExpansionInfo { - pub fn expanded(&self) -> InFile { - self.expanded.clone() - } - - pub fn call_node(&self) -> Option> { - Some(self.arg.with_value(self.arg.value.parent()?)) - } - - /// Map a token down from macro input into the macro expansion. - /// - /// The inner workings of this function differ slightly depending on the type of macro we are dealing with: - /// - declarative: - /// For declarative macros, we need to accommodate for the macro definition site(which acts as a second unchanging input) - /// , as tokens can mapped in and out of it. - /// To do this we shift all ids in the expansion by the maximum id of the definition site giving us an easy - /// way to map all the tokens. - /// - attribute: - /// Attributes have two different inputs, the input tokentree in the attribute node and the item - /// the attribute is annotating. Similarly as for declarative macros we need to do a shift here - /// as well. Currently this is done by shifting the attribute input by the maximum id of the item. - /// - function-like and derives: - /// Both of these only have one simple call site input so no special handling is required here. - pub fn map_token_down( - &self, - db: &dyn db::AstDatabase, - item: Option, - token: InFile<&SyntaxToken>, - ) -> Option> + '_> { - assert_eq!(token.file_id, self.arg.file_id); - let token_id_in_attr_input = if let Some(item) = item { - // check if we are mapping down in an attribute input - // this is a special case as attributes can have two inputs - let call_id = self.expanded.file_id.macro_file()?.macro_call_id; - let loc = db.lookup_intern_macro_call(call_id); - - let token_range = token.value.text_range(); - match &loc.kind { - MacroCallKind::Attr { attr_args, invoc_attr_index, is_derive, .. } => { - let attr = item - .doc_comments_and_attrs() - .nth(*invoc_attr_index as usize) - .and_then(Either::left)?; - match attr.token_tree() { - Some(token_tree) - if token_tree.syntax().text_range().contains_range(token_range) => - { - let attr_input_start = - token_tree.left_delimiter_token()?.text_range().start(); - let relative_range = - token.value.text_range().checked_sub(attr_input_start)?; - // shift by the item's tree's max id - let token_id = attr_args.1.token_by_range(relative_range)?; - let token_id = if *is_derive { - // we do not shift for `#[derive]`, as we only need to downmap the derive attribute tokens - token_id - } else { - self.macro_arg_shift.shift(token_id) - }; - Some(token_id) - } - _ => None, - } - } - _ => None, - } - } else { - None - }; - - let token_id = match token_id_in_attr_input { - Some(token_id) => token_id, - // the token is not inside an attribute's input so do the lookup in the macro_arg as ususal - None => { - let relative_range = - token.value.text_range().checked_sub(self.arg.value.text_range().start())?; - let token_id = self.macro_arg.1.token_by_range(relative_range)?; - // conditionally shift the id by a declaratives macro definition - self.macro_def.map_id_down(token_id) - } - }; - - let tokens = self - .exp_map - .ranges_by_token(token_id, token.value.kind()) - .flat_map(move |range| self.expanded.value.covering_element(range).into_token()); - - Some(tokens.map(move |token| self.expanded.with_value(token))) - } - - /// Map a token up out of the expansion it resides in into the arguments of the macro call of the expansion. - pub fn map_token_up( - &self, - db: &dyn db::AstDatabase, - token: InFile<&SyntaxToken>, - ) -> Option<(InFile, Origin)> { - // Fetch the id through its text range, - let token_id = self.exp_map.token_by_range(token.value.text_range())?; - // conditionally unshifting the id to accommodate for macro-rules def site - let (mut token_id, origin) = self.macro_def.map_id_up(token_id); - - let call_id = self.expanded.file_id.macro_file()?.macro_call_id; - let loc = db.lookup_intern_macro_call(call_id); - - // Attributes are a bit special for us, they have two inputs, the input tokentree and the annotated item. - let (token_map, tt) = match &loc.kind { - MacroCallKind::Attr { attr_args, is_derive: true, .. } => { - (&attr_args.1, self.attr_input_or_mac_def.clone()?.syntax().cloned()) - } - MacroCallKind::Attr { attr_args, .. } => { - // try unshifting the the token id, if unshifting fails, the token resides in the non-item attribute input - // note that the `TokenExpander::map_id_up` earlier only unshifts for declarative macros, so we don't double unshift with this - match self.macro_arg_shift.unshift(token_id) { - Some(unshifted) => { - token_id = unshifted; - (&attr_args.1, self.attr_input_or_mac_def.clone()?.syntax().cloned()) - } - None => (&self.macro_arg.1, self.arg.clone()), - } - } - _ => match origin { - mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()), - mbe::Origin::Def => match (&*self.macro_def, &self.attr_input_or_mac_def) { - (TokenExpander::DeclarativeMacro { def_site_token_map, .. }, Some(tt)) => { - (def_site_token_map, tt.syntax().cloned()) - } - _ => panic!("`Origin::Def` used with non-`macro_rules!` macro"), - }, - }, - }; - - let range = token_map.first_range_by_token(token_id, token.value.kind())?; - let token = - tt.value.covering_element(range + tt.value.text_range().start()).into_token()?; - Some((tt.with_value(token), origin)) - } -} - -/// `AstId` points to an AST node in any file. -/// -/// It is stable across reparses, and can be used as salsa key/value. -pub type AstId = InFile>; - -impl AstId { - pub fn to_node(&self, db: &dyn db::AstDatabase) -> N { - let root = db.parse_or_expand(self.file_id).unwrap(); - db.ast_id_map(self.file_id).get(self.value).to_node(&root) - } -} - -/// `InFile` stores a value of `T` inside a particular file/syntax tree. -/// -/// Typical usages are: -/// -/// * `InFile` -- syntax node in a file -/// * `InFile` -- ast node in a file -/// * `InFile` -- offset in a file -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub struct InFile { - pub file_id: HirFileId, - pub value: T, -} - -impl InFile { - pub fn new(file_id: HirFileId, value: T) -> InFile { - InFile { file_id, value } - } - - pub fn with_value(&self, value: U) -> InFile { - InFile::new(self.file_id, value) - } - - pub fn map U, U>(self, f: F) -> InFile { - InFile::new(self.file_id, f(self.value)) - } - - pub fn as_ref(&self) -> InFile<&T> { - self.with_value(&self.value) - } - - pub fn file_syntax(&self, db: &dyn db::AstDatabase) -> SyntaxNode { - db.parse_or_expand(self.file_id).expect("source created from invalid file") - } -} - -impl InFile<&T> { - pub fn cloned(&self) -> InFile { - self.with_value(self.value.clone()) - } -} - -impl InFile> { - pub fn transpose(self) -> Option> { - let value = self.value?; - Some(InFile::new(self.file_id, value)) - } -} - -impl<'a> InFile<&'a SyntaxNode> { - pub fn ancestors_with_macros( - self, - db: &dyn db::AstDatabase, - ) -> impl Iterator> + Clone + '_ { - iter::successors(Some(self.cloned()), move |node| match node.value.parent() { - Some(parent) => Some(node.with_value(parent)), - None => node.file_id.call_node(db), - }) - } - - /// Skips the attributed item that caused the macro invocation we are climbing up - pub fn ancestors_with_macros_skip_attr_item( - self, - db: &dyn db::AstDatabase, - ) -> impl Iterator> + '_ { - let succ = move |node: &InFile| match node.value.parent() { - Some(parent) => Some(node.with_value(parent)), - None => { - let parent_node = node.file_id.call_node(db)?; - if node.file_id.is_attr_macro(db) { - // macro call was an attributed item, skip it - // FIXME: does this fail if this is a direct expansion of another macro? - parent_node.map(|node| node.parent()).transpose() - } else { - Some(parent_node) - } - } - }; - 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. - /// For the entire item `InFile::use original_file_range_full`. - pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange { - match self.file_id.0 { - HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() }, - HirFileIdRepr::MacroFile(mac_file) => { - if let Some(res) = self.original_file_range_opt(db) { - return res; - } - // Fall back to whole macro call. - let loc = db.lookup_intern_macro_call(mac_file.macro_call_id); - loc.kind.original_call_range(db) - } - } - } - - /// Attempts to map the syntax node back up its macro calls. - pub fn original_file_range_opt(self, db: &dyn db::AstDatabase) -> Option { - match ascend_node_border_tokens(db, self) { - Some(InFile { file_id, value: (first, last) }) => { - let original_file = file_id.original_file(db); - let range = first.text_range().cover(last.text_range()); - if file_id != original_file.into() { - tracing::error!("Failed mapping up more for {:?}", range); - return None; - } - Some(FileRange { file_id: original_file, range }) - } - _ if !self.file_id.is_macro() => Some(FileRange { - file_id: self.file_id.original_file(db), - range: self.value.text_range(), - }), - _ => None, - } - } -} - -impl InFile { - pub fn upmap(self, db: &dyn db::AstDatabase) -> Option> { - let expansion = self.file_id.expansion_info(db)?; - expansion.map_token_up(db, self.as_ref()).map(|(it, _)| it) - } - - /// Falls back to the macro call range if the node cannot be mapped up fully. - pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange { - match self.file_id.0 { - HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() }, - HirFileIdRepr::MacroFile(mac_file) => { - if let Some(res) = self.original_file_range_opt(db) { - return res; - } - // Fall back to whole macro call. - let loc = db.lookup_intern_macro_call(mac_file.macro_call_id); - loc.kind.original_call_range(db) - } - } - } - - /// Attempts to map the syntax node back up its macro calls. - pub fn original_file_range_opt(self, db: &dyn db::AstDatabase) -> Option { - match self.file_id.0 { - HirFileIdRepr::FileId(file_id) => { - Some(FileRange { file_id, range: self.value.text_range() }) - } - HirFileIdRepr::MacroFile(_) => { - let expansion = self.file_id.expansion_info(db)?; - let InFile { file_id, value } = ascend_call_token(db, &expansion, self)?; - let original_file = file_id.original_file(db); - if file_id != original_file.into() { - return None; - } - Some(FileRange { file_id: original_file, range: value.text_range() }) - } - } - } - - pub fn ancestors_with_macros( - self, - db: &dyn db::AstDatabase, - ) -> impl Iterator> + '_ { - self.value.parent().into_iter().flat_map({ - let file_id = self.file_id; - move |parent| InFile::new(file_id, &parent).ancestors_with_macros(db) - }) - } -} - -fn ascend_node_border_tokens( - db: &dyn db::AstDatabase, - InFile { file_id, value: node }: InFile<&SyntaxNode>, -) -> Option> { - let expansion = file_id.expansion_info(db)?; - - let first_token = |node: &SyntaxNode| skip_trivia_token(node.first_token()?, Direction::Next); - let last_token = |node: &SyntaxNode| skip_trivia_token(node.last_token()?, Direction::Prev); - - let first = first_token(node)?; - let last = last_token(node)?; - let first = ascend_call_token(db, &expansion, InFile::new(file_id, first))?; - let last = ascend_call_token(db, &expansion, InFile::new(file_id, last))?; - (first.file_id == last.file_id).then(|| InFile::new(first.file_id, (first.value, last.value))) -} - -fn ascend_call_token( - db: &dyn db::AstDatabase, - expansion: &ExpansionInfo, - token: InFile, -) -> Option> { - let mut mapping = expansion.map_token_up(db, token.as_ref())?; - while let (mapped, Origin::Call) = mapping { - match mapped.file_id.expansion_info(db) { - Some(info) => mapping = info.map_token_up(db, mapped.as_ref())?, - None => return Some(mapped), - } - } - None -} - -impl InFile { - pub fn descendants(self) -> impl Iterator> { - self.value.syntax().descendants().filter_map(T::cast).map(move |n| self.with_value(n)) - } - - pub fn original_ast_node(self, db: &dyn db::AstDatabase) -> Option> { - // This kind of upmapping can only be achieved in attribute expanded files, - // as we don't have node inputs otherwise and therefor can't find an `N` node in the input - if !self.file_id.is_macro() { - return Some(self); - } else if !self.file_id.is_attr_macro(db) { - return None; - } - - if let Some(InFile { file_id, value: (first, last) }) = - ascend_node_border_tokens(db, self.syntax()) - { - if file_id.is_macro() { - let range = first.text_range().cover(last.text_range()); - tracing::error!("Failed mapping out of macro file for {:?}", range); - return None; - } - // FIXME: This heuristic is brittle and with the right macro may select completely unrelated nodes - let anc = algo::least_common_ancestor(&first.parent()?, &last.parent()?)?; - let value = anc.ancestors().find_map(N::cast)?; - return Some(InFile::new(file_id, value)); - } - None - } - - pub fn syntax(&self) -> InFile<&SyntaxNode> { - self.with_value(self.value.syntax()) - } -} - -/// In Rust, macros expand token trees to token trees. When we want to turn a -/// token tree into an AST node, we need to figure out what kind of AST node we -/// want: something like `foo` can be a type, an expression, or a pattern. -/// -/// Naively, one would think that "what this expands to" is a property of a -/// particular macro: macro `m1` returns an item, while macro `m2` returns an -/// expression, etc. That's not the case -- macros are polymorphic in the -/// result, and can expand to any type of the AST node. -/// -/// What defines the actual AST node is the syntactic context of the macro -/// invocation. As a contrived example, in `let T![*] = T![*];` the first `T` -/// expands to a pattern, while the second one expands to an expression. -/// -/// `ExpandTo` captures this bit of information about a particular macro call -/// site. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum ExpandTo { - Statements, - Items, - Pattern, - Type, - Expr, -} - -impl ExpandTo { - pub fn from_call_site(call: &ast::MacroCall) -> ExpandTo { - use syntax::SyntaxKind::*; - - let syn = call.syntax(); - - let parent = match syn.parent() { - Some(it) => it, - None => return ExpandTo::Statements, - }; - - // FIXME: macros in statement position are treated as expression statements, they should - // probably be their own statement kind. The *grand*parent indicates what's valid. - if parent.kind() == MACRO_EXPR - && parent - .parent() - .map_or(true, |p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS)) - { - return ExpandTo::Statements; - } - - match parent.kind() { - MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => ExpandTo::Items, - MACRO_STMTS | EXPR_STMT | STMT_LIST => ExpandTo::Statements, - MACRO_PAT => ExpandTo::Pattern, - MACRO_TYPE => ExpandTo::Type, - - ARG_LIST | ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BREAK_EXPR | CALL_EXPR | CAST_EXPR - | CLOSURE_EXPR | FIELD_EXPR | FOR_EXPR | IF_EXPR | INDEX_EXPR | LET_EXPR - | MATCH_ARM | MATCH_EXPR | MATCH_GUARD | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR - | PREFIX_EXPR | RANGE_EXPR | RECORD_EXPR_FIELD | REF_EXPR | RETURN_EXPR | TRY_EXPR - | TUPLE_EXPR | WHILE_EXPR | MACRO_EXPR => ExpandTo::Expr, - _ => { - // Unknown , Just guess it is `Items` - ExpandTo::Items - } - } - } -} - -#[derive(Debug)] -pub struct UnresolvedMacro { - pub path: ModPath, -} 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 deleted file mode 100644 index fea09521e87cb..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ /dev/null @@ -1,276 +0,0 @@ -//! A lowering for `use`-paths (more generally, paths without angle-bracketed segments). - -use std::{ - fmt::{self, Display}, - iter, -}; - -use crate::{ - db::AstDatabase, - hygiene::Hygiene, - name::{known, Name}, -}; -use base_db::CrateId; -use either::Either; -use smallvec::SmallVec; -use syntax::{ast, AstNode}; - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct ModPath { - pub kind: PathKind, - segments: SmallVec<[Name; 1]>, -} - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct EscapedModPath<'a>(&'a ModPath); - -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum PathKind { - Plain, - /// `self::` is `Super(0)` - Super(u8), - Crate, - /// Absolute path (::foo) - Abs, - /// `$crate` from macro expansion - DollarCrate(CrateId), -} - -impl ModPath { - pub fn from_src(db: &dyn AstDatabase, path: ast::Path, hygiene: &Hygiene) -> Option { - convert_path(db, None, path, hygiene) - } - - pub fn from_segments(kind: PathKind, segments: impl IntoIterator) -> ModPath { - let segments = segments.into_iter().collect(); - ModPath { kind, segments } - } - - /// Creates a `ModPath` from a `PathKind`, with no extra path segments. - pub const fn from_kind(kind: PathKind) -> ModPath { - ModPath { kind, segments: SmallVec::new_const() } - } - - pub fn segments(&self) -> &[Name] { - &self.segments - } - - pub fn push_segment(&mut self, segment: Name) { - self.segments.push(segment); - } - - pub fn pop_segment(&mut self) -> Option { - self.segments.pop() - } - - /// Returns the number of segments in the path (counting special segments like `$crate` and - /// `super`). - pub fn len(&self) -> usize { - self.segments.len() - + match self.kind { - PathKind::Plain => 0, - PathKind::Super(i) => i as usize, - PathKind::Crate => 1, - PathKind::Abs => 0, - PathKind::DollarCrate(_) => 1, - } - } - - pub fn is_ident(&self) -> bool { - self.as_ident().is_some() - } - - pub fn is_self(&self) -> bool { - self.kind == PathKind::Super(0) && self.segments.is_empty() - } - - #[allow(non_snake_case)] - pub fn is_Self(&self) -> bool { - self.kind == PathKind::Plain - && matches!(&*self.segments, [name] if *name == known::SELF_TYPE) - } - - /// If this path is a single identifier, like `foo`, return its name. - pub fn as_ident(&self) -> Option<&Name> { - if self.kind != PathKind::Plain { - return None; - } - - match &*self.segments { - [name] => Some(name), - _ => None, - } - } - - pub fn escaped(&self) -> EscapedModPath<'_> { - EscapedModPath(self) - } - - fn _fmt(&self, f: &mut fmt::Formatter<'_>, escaped: bool) -> fmt::Result { - let mut first_segment = true; - let mut add_segment = |s| -> fmt::Result { - if !first_segment { - f.write_str("::")?; - } - first_segment = false; - f.write_str(s)?; - Ok(()) - }; - match self.kind { - PathKind::Plain => {} - PathKind::Super(0) => add_segment("self")?, - PathKind::Super(n) => { - for _ in 0..n { - add_segment("super")?; - } - } - PathKind::Crate => add_segment("crate")?, - PathKind::Abs => add_segment("")?, - PathKind::DollarCrate(_) => add_segment("$crate")?, - } - for segment in &self.segments { - if !first_segment { - f.write_str("::")?; - } - first_segment = false; - if escaped { - segment.escaped().fmt(f)? - } else { - segment.fmt(f)? - }; - } - Ok(()) - } -} - -impl Display for ModPath { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self._fmt(f, false) - } -} - -impl<'a> Display for EscapedModPath<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0._fmt(f, true) - } -} - -impl From for ModPath { - fn from(name: Name) -> ModPath { - ModPath::from_segments(PathKind::Plain, iter::once(name)) - } -} - -fn convert_path( - db: &dyn AstDatabase, - prefix: Option, - path: ast::Path, - hygiene: &Hygiene, -) -> Option { - let prefix = match path.qualifier() { - Some(qual) => Some(convert_path(db, prefix, qual, hygiene)?), - None => prefix, - }; - - let segment = path.segment()?; - let mut mod_path = match segment.kind()? { - ast::PathSegmentKind::Name(name_ref) => { - match hygiene.name_ref_to_name(db, name_ref) { - Either::Left(name) => { - // no type args in use - let mut res = prefix.unwrap_or_else(|| { - ModPath::from_kind( - segment.coloncolon_token().map_or(PathKind::Plain, |_| PathKind::Abs), - ) - }); - res.segments.push(name); - res - } - Either::Right(crate_id) => { - return Some(ModPath::from_segments( - PathKind::DollarCrate(crate_id), - iter::empty(), - )) - } - } - } - ast::PathSegmentKind::SelfTypeKw => { - if prefix.is_some() { - return None; - } - ModPath::from_segments(PathKind::Plain, Some(known::SELF_TYPE)) - } - ast::PathSegmentKind::CrateKw => { - if prefix.is_some() { - return None; - } - ModPath::from_segments(PathKind::Crate, iter::empty()) - } - ast::PathSegmentKind::SelfKw => { - if prefix.is_some() { - return None; - } - ModPath::from_segments(PathKind::Super(0), iter::empty()) - } - ast::PathSegmentKind::SuperKw => { - let nested_super_count = match prefix.map(|p| p.kind) { - Some(PathKind::Super(n)) => n, - Some(_) => return None, - None => 0, - }; - - ModPath::from_segments(PathKind::Super(nested_super_count + 1), iter::empty()) - } - ast::PathSegmentKind::Type { .. } => { - // not allowed in imports - return None; - } - }; - - // handle local_inner_macros : - // Basically, even in rustc it is quite hacky: - // https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456 - // We follow what it did anyway :) - if mod_path.segments.len() == 1 && mod_path.kind == PathKind::Plain { - if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { - if let Some(crate_id) = hygiene.local_inner_macros(db, path) { - mod_path.kind = PathKind::DollarCrate(crate_id); - } - } - } - - Some(mod_path) -} - -pub use crate::name as __name; - -#[macro_export] -macro_rules! __known_path { - (core::iter::IntoIterator) => {}; - (core::iter::Iterator) => {}; - (core::result::Result) => {}; - (core::option::Option) => {}; - (core::ops::Range) => {}; - (core::ops::RangeFrom) => {}; - (core::ops::RangeFull) => {}; - (core::ops::RangeTo) => {}; - (core::ops::RangeToInclusive) => {}; - (core::ops::RangeInclusive) => {}; - (core::future::Future) => {}; - (core::ops::Try) => {}; - ($path:path) => { - compile_error!("Please register your known path in the path module") - }; -} - -#[macro_export] -macro_rules! __path { - ($start:ident $(:: $seg:ident)*) => ({ - $crate::__known_path!($start $(:: $seg)*); - $crate::mod_path::ModPath::from_segments($crate::mod_path::PathKind::Abs, vec![ - $crate::mod_path::__name![$start], $($crate::mod_path::__name![$seg],)* - ]) - }); -} - -pub use crate::__path as path; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs deleted file mode 100644 index 85b0a7735fe94..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ /dev/null @@ -1,433 +0,0 @@ -//! See [`Name`]. - -use std::fmt; - -use syntax::{ast, SmolStr, SyntaxKind}; - -/// `Name` is a wrapper around string, which is used in hir for both references -/// and declarations. In theory, names should also carry hygiene info, but we are -/// not there yet! -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Name(Repr); - -/// `EscapedName` will add a prefix "r#" to the wrapped `Name` when it is a raw identifier -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct EscapedName<'a>(&'a Name); - -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -enum Repr { - Text(SmolStr), - TupleField(usize), -} - -impl fmt::Display for Name { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self.0 { - Repr::Text(text) => fmt::Display::fmt(&text, f), - Repr::TupleField(idx) => fmt::Display::fmt(&idx, f), - } - } -} - -fn is_raw_identifier(name: &str) -> bool { - let is_keyword = SyntaxKind::from_keyword(name).is_some(); - is_keyword && !matches!(name, "self" | "crate" | "super" | "Self") -} - -impl<'a> fmt::Display for EscapedName<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self.0 .0 { - Repr::Text(text) => { - if is_raw_identifier(text) { - write!(f, "r#{}", &text) - } else { - fmt::Display::fmt(&text, f) - } - } - Repr::TupleField(idx) => fmt::Display::fmt(&idx, f), - } - } -} - -impl<'a> EscapedName<'a> { - pub fn is_escaped(&self) -> bool { - match &self.0 .0 { - Repr::Text(it) => is_raw_identifier(&it), - Repr::TupleField(_) => false, - } - } - - /// Returns the textual representation of this name as a [`SmolStr`]. - /// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in - /// the general case. - pub fn to_smol_str(&self) -> SmolStr { - match &self.0 .0 { - Repr::Text(it) => { - if is_raw_identifier(&it) { - SmolStr::from_iter(["r#", &it]) - } else { - it.clone() - } - } - Repr::TupleField(it) => SmolStr::new(&it.to_string()), - } - } -} - -impl Name { - /// Note: this is private to make creating name from random string hard. - /// Hopefully, this should allow us to integrate hygiene cleaner in the - /// future, and to switch to interned representation of names. - const fn new_text(text: SmolStr) -> Name { - Name(Repr::Text(text)) - } - - pub fn new_tuple_field(idx: usize) -> Name { - Name(Repr::TupleField(idx)) - } - - pub fn new_lifetime(lt: &ast::Lifetime) -> Name { - Self::new_text(lt.text().into()) - } - - /// Shortcut to create inline plain text name - const fn new_inline(text: &str) -> Name { - Name::new_text(SmolStr::new_inline(text)) - } - - /// Resolve a name from the text of token. - fn resolve(raw_text: &str) -> Name { - match raw_text.strip_prefix("r#") { - Some(text) => Name::new_text(SmolStr::new(text)), - None => Name::new_text(raw_text.into()), - } - } - - /// A fake name for things missing in the source code. - /// - /// For example, `impl Foo for {}` should be treated as a trait impl for a - /// type with a missing name. Similarly, `struct S { : u32 }` should have a - /// single field with a missing name. - /// - /// Ideally, we want a `gensym` semantics for missing names -- each missing - /// name is equal only to itself. It's not clear how to implement this in - /// salsa though, so we punt on that bit for a moment. - pub const fn missing() -> Name { - Name::new_inline("[missing name]") - } - - /// Returns the tuple index this name represents if it is a tuple field. - pub fn as_tuple_index(&self) -> Option { - match self.0 { - Repr::TupleField(idx) => Some(idx), - _ => None, - } - } - - /// Returns the text this name represents if it isn't a tuple field. - pub fn as_text(&self) -> Option { - match &self.0 { - Repr::Text(it) => Some(it.clone()), - _ => None, - } - } - - /// Returns the textual representation of this name as a [`SmolStr`]. - /// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in - /// the general case. - pub fn to_smol_str(&self) -> SmolStr { - match &self.0 { - Repr::Text(it) => it.clone(), - Repr::TupleField(it) => SmolStr::new(&it.to_string()), - } - } - - pub fn escaped(&self) -> EscapedName<'_> { - EscapedName(self) - } -} - -pub trait AsName { - fn as_name(&self) -> Name; -} - -impl AsName for ast::NameRef { - fn as_name(&self) -> Name { - match self.as_tuple_field() { - Some(idx) => Name::new_tuple_field(idx), - None => Name::resolve(&self.text()), - } - } -} - -impl AsName for ast::Name { - fn as_name(&self) -> Name { - Name::resolve(&self.text()) - } -} - -impl AsName for ast::NameOrNameRef { - fn as_name(&self) -> Name { - match self { - ast::NameOrNameRef::Name(it) => it.as_name(), - ast::NameOrNameRef::NameRef(it) => it.as_name(), - } - } -} - -impl AsName for tt::Ident { - fn as_name(&self) -> Name { - Name::resolve(&self.text) - } -} - -impl AsName for ast::FieldKind { - fn as_name(&self) -> Name { - match self { - ast::FieldKind::Name(nr) => nr.as_name(), - ast::FieldKind::Index(idx) => { - let idx = idx.text().parse::().unwrap_or(0); - Name::new_tuple_field(idx) - } - } - } -} - -impl AsName for base_db::Dependency { - fn as_name(&self) -> Name { - Name::new_text(SmolStr::new(&*self.name)) - } -} - -pub mod known { - macro_rules! known_names { - ($($ident:ident),* $(,)?) => { - $( - #[allow(bad_style)] - pub const $ident: super::Name = - super::Name::new_inline(stringify!($ident)); - )* - }; - } - - known_names!( - // Primitives - isize, - i8, - i16, - i32, - i64, - i128, - usize, - u8, - u16, - u32, - u64, - u128, - f32, - f64, - bool, - char, - str, - // Special names - macro_rules, - doc, - cfg, - cfg_attr, - register_attr, - register_tool, - // Components of known path (value or mod name) - std, - core, - alloc, - iter, - ops, - future, - result, - boxed, - option, - prelude, - rust_2015, - rust_2018, - rust_2021, - v1, - // Components of known path (type name) - Iterator, - IntoIterator, - Item, - Try, - Ok, - Future, - Result, - Option, - Output, - Target, - Box, - RangeFrom, - RangeFull, - RangeInclusive, - RangeToInclusive, - RangeTo, - Range, - Neg, - Not, - None, - Index, - // Components of known path (function name) - filter_map, - next, - iter_mut, - len, - is_empty, - new, - // Builtin macros - asm, - assert, - column, - compile_error, - concat_idents, - concat_bytes, - concat, - const_format_args, - core_panic, - env, - file, - format_args_nl, - format_args, - global_asm, - include_bytes, - include_str, - include, - line, - llvm_asm, - log_syntax, - module_path, - option_env, - std_panic, - stringify, - trace_macros, - unreachable, - // Builtin derives - Copy, - Clone, - Default, - Debug, - Hash, - Ord, - PartialOrd, - Eq, - PartialEq, - // Builtin attributes - bench, - cfg_accessible, - cfg_eval, - crate_type, - derive, - global_allocator, - test, - test_case, - recursion_limit, - // Safe intrinsics - abort, - add_with_overflow, - black_box, - bitreverse, - bswap, - caller_location, - ctlz, - ctpop, - cttz, - discriminant_value, - forget, - likely, - maxnumf32, - maxnumf64, - min_align_of_val, - min_align_of, - minnumf32, - minnumf64, - mul_with_overflow, - needs_drop, - ptr_guaranteed_eq, - ptr_guaranteed_ne, - rotate_left, - rotate_right, - rustc_peek, - saturating_add, - saturating_sub, - size_of_val, - size_of, - sub_with_overflow, - type_id, - type_name, - unlikely, - variant_count, - wrapping_add, - wrapping_mul, - wrapping_sub, - // known methods of lang items - eq, - ne, - ge, - gt, - le, - lt, - // lang items - add_assign, - add, - bitand_assign, - bitand, - bitor_assign, - bitor, - bitxor_assign, - bitxor, - deref_mut, - deref, - div_assign, - div, - fn_mut, - fn_once, - future_trait, - index, - index_mut, - mul_assign, - mul, - neg, - not, - owned_box, - partial_ord, - r#fn, - rem_assign, - rem, - shl_assign, - shl, - shr_assign, - shr, - sub_assign, - sub, - ); - - // self/Self cannot be used as an identifier - pub const SELF_PARAM: super::Name = super::Name::new_inline("self"); - pub const SELF_TYPE: super::Name = super::Name::new_inline("Self"); - - pub const STATIC_LIFETIME: super::Name = super::Name::new_inline("'static"); - - #[macro_export] - macro_rules! name { - (self) => { - $crate::name::known::SELF_PARAM - }; - (Self) => { - $crate::name::known::SELF_TYPE - }; - ('static) => { - $crate::name::known::STATIC_LIFETIME - }; - ($ident:ident) => { - $crate::name::known::$ident - }; - } -} - -pub use crate::name; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs deleted file mode 100644 index 5afdcc0e66dbc..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! Proc Macro Expander stub - -use base_db::{CrateId, ProcMacroExpansionError, ProcMacroId, ProcMacroKind}; -use stdx::never; - -use crate::{db::AstDatabase, ExpandError, ExpandResult}; - -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub struct ProcMacroExpander { - krate: CrateId, - proc_macro_id: Option, -} - -impl ProcMacroExpander { - pub fn new(krate: CrateId, proc_macro_id: ProcMacroId) -> Self { - Self { krate, proc_macro_id: Some(proc_macro_id) } - } - - pub fn dummy(krate: CrateId) -> Self { - // FIXME: Should store the name for better errors - Self { krate, proc_macro_id: None } - } - - pub fn is_dummy(&self) -> bool { - self.proc_macro_id.is_none() - } - - pub fn expand( - self, - db: &dyn AstDatabase, - calling_crate: CrateId, - tt: &tt::Subtree, - attr_arg: Option<&tt::Subtree>, - ) -> ExpandResult { - match self.proc_macro_id { - Some(id) => { - let krate_graph = db.crate_graph(); - let proc_macros = match &krate_graph[self.krate].proc_macro { - Ok(proc_macros) => proc_macros, - Err(_) => { - never!("Non-dummy expander even though there are no proc macros"); - return ExpandResult::only_err(ExpandError::Other("Internal error".into())); - } - }; - let proc_macro = match proc_macros.get(id.0 as usize) { - Some(proc_macro) => proc_macro, - None => { - never!( - "Proc macro index out of bounds: the length is {} but the index is {}", - proc_macros.len(), - id.0 - ); - return ExpandResult::only_err(ExpandError::Other("Internal error".into())); - } - }; - - // Proc macros have access to the environment variables of the invoking crate. - let env = &krate_graph[calling_crate].env; - match proc_macro.expander.expand(tt, attr_arg, env) { - Ok(t) => ExpandResult::ok(t), - Err(err) => match err { - // Don't discard the item in case something unexpected happened while expanding attributes - ProcMacroExpansionError::System(text) - if proc_macro.kind == ProcMacroKind::Attr => - { - ExpandResult { - value: tt.clone(), - err: Some(ExpandError::Other(text.into())), - } - } - ProcMacroExpansionError::System(text) - | ProcMacroExpansionError::Panic(text) => { - ExpandResult::only_err(ExpandError::Other(text.into())) - } - }, - } - } - None => ExpandResult::only_err(ExpandError::UnresolvedProcMacro(self.krate)), - } - } -} diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs deleted file mode 100644 index 82f410ecda91d..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs +++ /dev/null @@ -1,284 +0,0 @@ -//! A simplified version of quote-crate like quasi quote macro - -// A helper macro quote macro -// FIXME: -// 1. Not all puncts are handled -// 2. #()* pattern repetition not supported now -// * But we can do it manually, see `test_quote_derive_copy_hack` -#[doc(hidden)] -#[macro_export] -macro_rules! __quote { - () => { - Vec::::new() - }; - - ( @SUBTREE $delim:ident $($tt:tt)* ) => { - { - let children = $crate::__quote!($($tt)*); - tt::Subtree { - delimiter: Some(tt::Delimiter { - kind: tt::DelimiterKind::$delim, - id: tt::TokenId::unspecified(), - }), - token_trees: $crate::quote::IntoTt::to_tokens(children), - } - } - }; - - ( @PUNCT $first:literal ) => { - { - vec![ - tt::Leaf::Punct(tt::Punct { - char: $first, - spacing: tt::Spacing::Alone, - id: tt::TokenId::unspecified(), - }).into() - ] - } - }; - - ( @PUNCT $first:literal, $sec:literal ) => { - { - vec![ - tt::Leaf::Punct(tt::Punct { - char: $first, - spacing: tt::Spacing::Joint, - id: tt::TokenId::unspecified(), - }).into(), - tt::Leaf::Punct(tt::Punct { - char: $sec, - spacing: tt::Spacing::Alone, - id: tt::TokenId::unspecified(), - }).into() - ] - } - }; - - // hash variable - ( # $first:ident $($tail:tt)* ) => { - { - let token = $crate::quote::ToTokenTree::to_token($first); - let mut tokens = vec![token.into()]; - let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*)); - tokens.append(&mut tail_tokens); - tokens - } - }; - - ( ## $first:ident $($tail:tt)* ) => { - { - let mut tokens = $first.into_iter().map($crate::quote::ToTokenTree::to_token).collect::>(); - let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*)); - tokens.append(&mut tail_tokens); - tokens - } - }; - - // Brace - ( { $($tt:tt)* } ) => { $crate::__quote!(@SUBTREE Brace $($tt)*) }; - // Bracket - ( [ $($tt:tt)* ] ) => { $crate::__quote!(@SUBTREE Bracket $($tt)*) }; - // Parenthesis - ( ( $($tt:tt)* ) ) => { $crate::__quote!(@SUBTREE Parenthesis $($tt)*) }; - - // Literal - ( $tt:literal ) => { vec![$crate::quote::ToTokenTree::to_token($tt).into()] }; - // Ident - ( $tt:ident ) => { - vec![ { - tt::Leaf::Ident(tt::Ident { - text: stringify!($tt).into(), - id: tt::TokenId::unspecified(), - }).into() - }] - }; - - // Puncts - // FIXME: Not all puncts are handled - ( -> ) => {$crate::__quote!(@PUNCT '-', '>')}; - ( & ) => {$crate::__quote!(@PUNCT '&')}; - ( , ) => {$crate::__quote!(@PUNCT ',')}; - ( : ) => {$crate::__quote!(@PUNCT ':')}; - ( ; ) => {$crate::__quote!(@PUNCT ';')}; - ( :: ) => {$crate::__quote!(@PUNCT ':', ':')}; - ( . ) => {$crate::__quote!(@PUNCT '.')}; - ( < ) => {$crate::__quote!(@PUNCT '<')}; - ( > ) => {$crate::__quote!(@PUNCT '>')}; - ( ! ) => {$crate::__quote!(@PUNCT '!')}; - - ( $first:tt $($tail:tt)+ ) => { - { - let mut tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($first)); - let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*)); - - tokens.append(&mut tail_tokens); - tokens - } - }; -} - -/// FIXME: -/// It probably should implement in proc-macro -#[macro_export] -macro_rules! quote { - ( $($tt:tt)* ) => { - $crate::quote::IntoTt::to_subtree($crate::__quote!($($tt)*)) - } -} - -pub(crate) trait IntoTt { - fn to_subtree(self) -> tt::Subtree; - fn to_tokens(self) -> Vec; -} - -impl IntoTt for Vec { - fn to_subtree(self) -> tt::Subtree { - tt::Subtree { delimiter: None, token_trees: self } - } - - fn to_tokens(self) -> Vec { - self - } -} - -impl IntoTt for tt::Subtree { - fn to_subtree(self) -> tt::Subtree { - self - } - - fn to_tokens(self) -> Vec { - vec![tt::TokenTree::Subtree(self)] - } -} - -pub(crate) trait ToTokenTree { - fn to_token(self) -> tt::TokenTree; -} - -impl ToTokenTree for tt::TokenTree { - fn to_token(self) -> tt::TokenTree { - self - } -} - -impl ToTokenTree for tt::Subtree { - fn to_token(self) -> tt::TokenTree { - self.into() - } -} - -macro_rules! impl_to_to_tokentrees { - ($($ty:ty => $this:ident $im:block);*) => { - $( - impl ToTokenTree for $ty { - fn to_token($this) -> tt::TokenTree { - let leaf: tt::Leaf = $im.into(); - leaf.into() - } - } - - impl ToTokenTree for &$ty { - fn to_token($this) -> tt::TokenTree { - let leaf: tt::Leaf = $im.clone().into(); - leaf.into() - } - } - )* - } -} - -impl_to_to_tokentrees! { - u32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} }; - usize => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} }; - i32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} }; - bool => self { tt::Ident{text: self.to_string().into(), id: tt::TokenId::unspecified()} }; - tt::Leaf => self { self }; - tt::Literal => self { self }; - tt::Ident => self { self }; - tt::Punct => self { self }; - &str => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}}; - String => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}} -} - -#[cfg(test)] -mod tests { - #[test] - fn test_quote_delimiters() { - assert_eq!(quote!({}).to_string(), "{}"); - assert_eq!(quote!(()).to_string(), "()"); - assert_eq!(quote!([]).to_string(), "[]"); - } - - #[test] - fn test_quote_idents() { - assert_eq!(quote!(32).to_string(), "32"); - assert_eq!(quote!(struct).to_string(), "struct"); - } - - #[test] - fn test_quote_hash_simple_literal() { - let a = 20; - assert_eq!(quote!(#a).to_string(), "20"); - let s: String = "hello".into(); - assert_eq!(quote!(#s).to_string(), "\"hello\""); - } - - fn mk_ident(name: &str) -> tt::Ident { - tt::Ident { text: name.into(), id: tt::TokenId::unspecified() } - } - - #[test] - fn test_quote_hash_token_tree() { - let a = mk_ident("hello"); - - let quoted = quote!(#a); - assert_eq!(quoted.to_string(), "hello"); - let t = format!("{:?}", quoted); - assert_eq!(t, "SUBTREE $\n IDENT hello 4294967295"); - } - - #[test] - fn test_quote_simple_derive_copy() { - let name = mk_ident("Foo"); - - let quoted = quote! { - impl Clone for #name { - fn clone(&self) -> Self { - Self {} - } - } - }; - - assert_eq!(quoted.to_string(), "impl Clone for Foo {fn clone (& self) -> Self {Self {}}}"); - } - - #[test] - fn test_quote_derive_copy_hack() { - // Assume the given struct is: - // struct Foo { - // name: String, - // id: u32, - // } - let struct_name = mk_ident("Foo"); - let fields = [mk_ident("name"), mk_ident("id")]; - let fields = fields.iter().flat_map(|it| quote!(#it: self.#it.clone(), ).token_trees); - - let list = tt::Subtree { - delimiter: Some(tt::Delimiter { - kind: tt::DelimiterKind::Brace, - id: tt::TokenId::unspecified(), - }), - token_trees: fields.collect(), - }; - - let quoted = quote! { - impl Clone for #struct_name { - fn clone(&self) -> Self { - Self #list - } - } - }; - - assert_eq!(quoted.to_string(), "impl Clone for Foo {fn clone (& self) -> Self {Self {name : self . name . clone () , id : self . id . clone () ,}}}"); - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml deleted file mode 100644 index 5cd444c1ad3bd..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ /dev/null @@ -1,44 +0,0 @@ -[package] -name = "hir-ty" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -cov-mark = "2.0.0-pre.1" -itertools = "0.10.3" -arrayvec = "0.7.2" -smallvec = "1.9.0" -ena = "0.14.0" -tracing = "0.1.35" -rustc-hash = "1.1.0" -scoped-tls = "1.0.0" -chalk-solve = { version = "0.83.0", default-features = false } -chalk-ir = "0.83.0" -chalk-recursive = { version = "0.83.0", default-features = false } -la-arena = { version = "0.3.0", path = "../../lib/la-arena" } -once_cell = "1.12.0" -typed-arena = "2.0.1" - -stdx = { path = "../stdx", version = "0.0.0" } -hir-def = { path = "../hir-def", version = "0.0.0" } -hir-expand = { path = "../hir-expand", version = "0.0.0" } -base-db = { path = "../base-db", version = "0.0.0" } -profile = { path = "../profile", version = "0.0.0" } -syntax = { path = "../syntax", version = "0.0.0" } -limit = { path = "../limit", version = "0.0.0" } - -[dev-dependencies] -test-utils = { path = "../test-utils" } -expect-test = "1.4.0" -tracing = "0.1.35" -tracing-subscriber = { version = "0.3.14", default-features = false, features = [ - "env-filter", - "registry", -] } -tracing-tree = "0.2.1" diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs deleted file mode 100644 index b6f226dbfd20d..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ /dev/null @@ -1,145 +0,0 @@ -//! In certain situations, rust automatically inserts derefs as necessary: for -//! example, field accesses `foo.bar` still work when `foo` is actually a -//! reference to a type with the field `bar`. This is an approximation of the -//! logic in rustc (which lives in librustc_typeck/check/autoderef.rs). - -use std::sync::Arc; - -use chalk_ir::cast::Cast; -use hir_expand::name::name; -use limit::Limit; -use syntax::SmolStr; - -use crate::{ - db::HirDatabase, infer::unify::InferenceTable, Canonical, Goal, Interner, ProjectionTyExt, - TraitEnvironment, Ty, TyBuilder, TyKind, -}; - -static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10); - -pub(crate) enum AutoderefKind { - Builtin, - Overloaded, -} - -pub(crate) struct Autoderef<'a, 'db> { - pub(crate) table: &'a mut InferenceTable<'db>, - ty: Ty, - at_start: bool, - steps: Vec<(AutoderefKind, Ty)>, -} - -impl<'a, 'db> Autoderef<'a, 'db> { - pub(crate) fn new(table: &'a mut InferenceTable<'db>, ty: Ty) -> Self { - let ty = table.resolve_ty_shallow(&ty); - Autoderef { table, ty, at_start: true, steps: Vec::new() } - } - - pub(crate) fn step_count(&self) -> usize { - self.steps.len() - } - - pub(crate) fn steps(&self) -> &[(AutoderefKind, Ty)] { - &self.steps - } - - pub(crate) fn final_ty(&self) -> Ty { - self.ty.clone() - } -} - -impl Iterator for Autoderef<'_, '_> { - type Item = (Ty, usize); - - fn next(&mut self) -> Option { - if self.at_start { - self.at_start = false; - return Some((self.ty.clone(), 0)); - } - - if AUTODEREF_RECURSION_LIMIT.check(self.steps.len() + 1).is_err() { - return None; - } - - let (kind, new_ty) = autoderef_step(self.table, self.ty.clone())?; - - self.steps.push((kind, self.ty.clone())); - self.ty = new_ty; - - Some((self.ty.clone(), self.step_count())) - } -} - -pub(crate) fn autoderef_step( - table: &mut InferenceTable<'_>, - ty: Ty, -) -> Option<(AutoderefKind, Ty)> { - if let Some(derefed) = builtin_deref(&ty) { - Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed))) - } else { - Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?)) - } -} - -// FIXME: replace uses of this with Autoderef above -pub fn autoderef<'a>( - db: &'a dyn HirDatabase, - env: Arc, - ty: Canonical, -) -> impl Iterator> + 'a { - let mut table = InferenceTable::new(db, env); - let ty = table.instantiate_canonical(ty); - let mut autoderef = Autoderef::new(&mut table, ty); - let mut v = Vec::new(); - while let Some((ty, _steps)) = autoderef.next() { - v.push(autoderef.table.canonicalize(ty).value); - } - v.into_iter() -} - -pub(crate) fn deref(table: &mut InferenceTable<'_>, ty: Ty) -> Option { - let _p = profile::span("deref"); - autoderef_step(table, ty).map(|(_, ty)| ty) -} - -fn builtin_deref(ty: &Ty) -> Option<&Ty> { - match ty.kind(Interner) { - TyKind::Ref(.., ty) => Some(ty), - TyKind::Raw(.., ty) => Some(ty), - _ => None, - } -} - -fn deref_by_trait(table: &mut InferenceTable<'_>, ty: Ty) -> Option { - let _p = profile::span("deref_by_trait"); - if table.resolve_ty_shallow(&ty).inference_var(Interner).is_some() { - // don't try to deref unknown variables - return None; - } - - let db = table.db; - let deref_trait = db - .lang_item(table.trait_env.krate, SmolStr::new_inline("deref")) - .and_then(|l| l.as_trait())?; - let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?; - - let projection = { - let b = TyBuilder::assoc_type_projection(db, target); - if b.remaining() != 1 { - // the Target type + Deref trait should only have one generic parameter, - // namely Deref's Self type - return None; - } - b.push(ty).build() - }; - - // Check that the type implements Deref at all - let trait_ref = projection.trait_ref(db); - let implements_goal: Goal = trait_ref.cast(Interner); - table.try_obligation(implements_goal.clone())?; - - table.register_obligation(implements_goal); - - let result = table.normalize_projection_ty(projection); - Some(table.resolve_ty_shallow(&result)) -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs deleted file mode 100644 index 94d7806cb6e8f..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs +++ /dev/null @@ -1,311 +0,0 @@ -//! `TyBuilder`, a helper for building instances of `Ty` and related types. - -use std::iter; - -use chalk_ir::{ - cast::{Cast, CastTo, Caster}, - fold::TypeFoldable, - interner::HasInterner, - AdtId, BoundVar, DebruijnIndex, Scalar, -}; -use hir_def::{ - builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, GenericDefId, TraitId, - TypeAliasId, -}; -use smallvec::SmallVec; - -use crate::{ - consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive, - to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData, - ConstValue, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty, - TyDefId, TyExt, TyKind, ValueTyDefId, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ParamKind { - Type, - Const(Ty), -} - -/// This is a builder for `Ty` or anything that needs a `Substitution`. -pub struct TyBuilder { - /// The `data` field is used to keep track of what we're building (e.g. an - /// ADT, a `TraitRef`, ...). - data: D, - vec: SmallVec<[GenericArg; 2]>, - param_kinds: SmallVec<[ParamKind; 2]>, -} - -impl TyBuilder { - fn with_data(self, data: B) -> TyBuilder { - TyBuilder { data, param_kinds: self.param_kinds, vec: self.vec } - } -} - -impl TyBuilder { - fn new(data: D, param_kinds: SmallVec<[ParamKind; 2]>) -> TyBuilder { - TyBuilder { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds } - } - - fn build_internal(self) -> (D, Substitution) { - assert_eq!(self.vec.len(), self.param_kinds.len()); - for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) { - self.assert_match_kind(a, e); - } - let subst = Substitution::from_iter(Interner, self.vec); - (self.data, subst) - } - - pub fn push(mut self, arg: impl CastTo) -> Self { - let arg = arg.cast(Interner); - let expected_kind = &self.param_kinds[self.vec.len()]; - let arg_kind = match arg.data(Interner) { - chalk_ir::GenericArgData::Ty(_) => ParamKind::Type, - chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"), - chalk_ir::GenericArgData::Const(c) => { - let c = c.data(Interner); - ParamKind::Const(c.ty.clone()) - } - }; - assert_eq!(*expected_kind, arg_kind); - self.vec.push(arg); - self - } - - pub fn remaining(&self) -> usize { - self.param_kinds.len() - self.vec.len() - } - - pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self { - // self.fill is inlined to make borrow checker happy - let mut this = self; - let other = this.param_kinds.iter().skip(this.vec.len()); - let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind { - ParamKind::Type => { - GenericArgData::Ty(TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner)) - .intern(Interner) - } - ParamKind::Const(ty) => GenericArgData::Const( - ConstData { - value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)), - ty: ty.clone(), - } - .intern(Interner), - ) - .intern(Interner), - }); - this.vec.extend(filler.take(this.remaining()).casted(Interner)); - assert_eq!(this.remaining(), 0); - this - } - - pub fn fill_with_unknown(self) -> Self { - // self.fill is inlined to make borrow checker happy - let mut this = self; - let filler = this.param_kinds.iter().skip(this.vec.len()).map(|x| match x { - ParamKind::Type => GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner), - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), - }); - this.vec.extend(filler.casted(Interner)); - assert_eq!(this.remaining(), 0); - this - } - - pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self { - self.fill(|x| match x { - ParamKind::Type => GenericArgData::Ty(table.new_type_var()).intern(Interner), - ParamKind::Const(ty) => { - GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner) - } - }) - } - - pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self { - self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler)); - assert_eq!(self.remaining(), 0); - self - } - - pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self { - assert!(self.vec.is_empty()); - assert!(parent_substs.len(Interner) <= self.param_kinds.len()); - self.extend(parent_substs.iter(Interner).cloned()); - self - } - - fn extend(&mut self, it: impl Iterator + Clone) { - for x in it.clone().zip(self.param_kinds.iter().skip(self.vec.len())) { - self.assert_match_kind(&x.0, &x.1); - } - self.vec.extend(it); - } - - fn assert_match_kind(&self, a: &chalk_ir::GenericArg, e: &ParamKind) { - match (a.data(Interner), e) { - (chalk_ir::GenericArgData::Ty(_), ParamKind::Type) - | (chalk_ir::GenericArgData::Const(_), ParamKind::Const(_)) => (), - _ => panic!("Mismatched kinds: {:?}, {:?}, {:?}", a, self.vec, self.param_kinds), - } - } -} - -impl TyBuilder<()> { - pub fn unit() -> Ty { - TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner) - } - - pub fn usize() -> Ty { - TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner) - } - - pub fn fn_ptr(sig: CallableSig) -> Ty { - TyKind::Function(sig.to_fn_ptr()).intern(Interner) - } - - pub fn builtin(builtin: BuiltinType) -> Ty { - match builtin { - BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(Interner), - BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(Interner), - BuiltinType::Str => TyKind::Str.intern(Interner), - BuiltinType::Int(t) => { - TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(t))).intern(Interner) - } - BuiltinType::Uint(t) => { - TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(t))).intern(Interner) - } - BuiltinType::Float(t) => { - TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(t))).intern(Interner) - } - } - } - - pub fn slice(argument: Ty) -> Ty { - TyKind::Slice(argument).intern(Interner) - } - - pub fn placeholder_subst(db: &dyn HirDatabase, def: impl Into) -> Substitution { - let params = generics(db.upcast(), def.into()); - params.placeholder_subst(db) - } - - pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into) -> TyBuilder<()> { - let def = def.into(); - let params = generics(db.upcast(), def); - TyBuilder::new( - (), - params - .iter() - .map(|(id, data)| match data { - TypeOrConstParamData::TypeParamData(_) => ParamKind::Type, - TypeOrConstParamData::ConstParamData(_) => { - ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id))) - } - }) - .collect(), - ) - } - - pub fn build(self) -> Substitution { - let ((), subst) = self.build_internal(); - subst - } -} - -impl TyBuilder { - pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder { - TyBuilder::subst_for_def(db, def).with_data(def) - } - - pub fn fill_with_defaults( - mut self, - db: &dyn HirDatabase, - mut fallback: impl FnMut() -> Ty, - ) -> Self { - let defaults = db.generic_defaults(self.data.into()); - for default_ty in defaults.iter().skip(self.vec.len()) { - if let GenericArgData::Ty(x) = default_ty.skip_binders().data(Interner) { - if x.is_unknown() { - self.vec.push(fallback().cast(Interner)); - continue; - } - }; - // each default can depend on the previous parameters - let subst_so_far = Substitution::from_iter(Interner, self.vec.clone()); - self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner)); - } - self - } - - pub fn build(self) -> Ty { - let (adt, subst) = self.build_internal(); - TyKind::Adt(AdtId(adt), subst).intern(Interner) - } -} - -pub struct Tuple(usize); -impl TyBuilder { - pub fn tuple(size: usize) -> TyBuilder { - TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect()) - } - - pub fn build(self) -> Ty { - let (Tuple(size), subst) = self.build_internal(); - TyKind::Tuple(size, subst).intern(Interner) - } -} - -impl TyBuilder { - pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder { - TyBuilder::subst_for_def(db, def).with_data(def) - } - - pub fn build(self) -> TraitRef { - let (trait_id, substitution) = self.build_internal(); - TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution } - } -} - -impl TyBuilder { - pub fn assoc_type_projection(db: &dyn HirDatabase, def: TypeAliasId) -> TyBuilder { - TyBuilder::subst_for_def(db, def).with_data(def) - } - - pub fn build(self) -> ProjectionTy { - let (type_alias, substitution) = self.build_internal(); - ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), substitution } - } -} - -impl + TypeFoldable> TyBuilder> { - fn subst_binders(b: Binders) -> Self { - let param_kinds = b - .binders - .iter(Interner) - .map(|x| match x { - chalk_ir::VariableKind::Ty(_) => ParamKind::Type, - chalk_ir::VariableKind::Lifetime => panic!("Got lifetime parameter"), - chalk_ir::VariableKind::Const(ty) => ParamKind::Const(ty.clone()), - }) - .collect(); - TyBuilder::new(b, param_kinds) - } - - pub fn build(self) -> T { - let (b, subst) = self.build_internal(); - b.substitute(Interner, &subst) - } -} - -impl TyBuilder> { - pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder> { - TyBuilder::subst_binders(db.ty(def)) - } - - pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder> { - TyBuilder::subst_binders(db.impl_self_ty(def)) - } - - pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder> { - TyBuilder::subst_binders(db.value_ty(def)) - } -} 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 deleted file mode 100644 index faec99c7d33c1..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ /dev/null @@ -1,799 +0,0 @@ -//! The implementation of `RustIrDatabase` for Chalk, which provides information -//! about the code that Chalk needs. -use std::sync::Arc; - -use cov_mark::hit; -use syntax::SmolStr; -use tracing::debug; - -use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds}; -use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait}; - -use base_db::CrateId; -use hir_def::{ - lang_item::{lang_attr, LangItemTarget}, - AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId, -}; -use hir_expand::name::name; - -use crate::{ - db::HirDatabase, - display::HirDisplay, - from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, 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, - AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, Interner, ProjectionTy, - ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, - TyExt, TyKind, WhereClause, -}; - -pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum; -pub(crate) type TraitDatum = chalk_solve::rust_ir::TraitDatum; -pub(crate) type StructDatum = chalk_solve::rust_ir::AdtDatum; -pub(crate) type ImplDatum = chalk_solve::rust_ir::ImplDatum; -pub(crate) type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum; - -pub(crate) type AssocTypeId = chalk_ir::AssocTypeId; -pub(crate) type TraitId = chalk_ir::TraitId; -pub(crate) type AdtId = chalk_ir::AdtId; -pub(crate) type ImplId = chalk_ir::ImplId; -pub(crate) type AssociatedTyValueId = chalk_solve::rust_ir::AssociatedTyValueId; -pub(crate) type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue; -pub(crate) type FnDefDatum = chalk_solve::rust_ir::FnDefDatum; -pub(crate) type Variances = chalk_ir::Variances; - -impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { - fn associated_ty_data(&self, id: AssocTypeId) -> Arc { - self.db.associated_ty_data(id) - } - fn trait_datum(&self, trait_id: TraitId) -> Arc { - self.db.trait_datum(self.krate, trait_id) - } - fn adt_datum(&self, struct_id: AdtId) -> Arc { - self.db.struct_datum(self.krate, struct_id) - } - fn adt_repr(&self, _struct_id: AdtId) -> Arc> { - // FIXME: keep track of these - Arc::new(rust_ir::AdtRepr { c: false, packed: false, int: None }) - } - fn discriminant_type(&self, _ty: chalk_ir::Ty) -> chalk_ir::Ty { - // FIXME: keep track of this - chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::U32)).intern(Interner) - } - fn impl_datum(&self, impl_id: ImplId) -> Arc { - self.db.impl_datum(self.krate, impl_id) - } - - fn fn_def_datum( - &self, - fn_def_id: chalk_ir::FnDefId, - ) -> Arc> { - self.db.fn_def_datum(self.krate, fn_def_id) - } - - fn impls_for_trait( - &self, - trait_id: TraitId, - parameters: &[chalk_ir::GenericArg], - binders: &CanonicalVarKinds, - ) -> Vec { - debug!("impls_for_trait {:?}", trait_id); - let trait_: hir_def::TraitId = from_chalk_trait_id(trait_id); - - let ty: Ty = parameters[0].assert_ty_ref(Interner).clone(); - - fn binder_kind( - ty: &Ty, - binders: &CanonicalVarKinds, - ) -> Option { - if let TyKind::BoundVar(bv) = ty.kind(Interner) { - let binders = binders.as_slice(Interner); - if bv.debruijn == DebruijnIndex::INNERMOST { - if let chalk_ir::VariableKind::Ty(tk) = binders[bv.index].kind { - return Some(tk); - } - } - } - None - } - - let self_ty_fp = TyFingerprint::for_trait_impl(&ty); - let fps: &[TyFingerprint] = match binder_kind(&ty, binders) { - Some(chalk_ir::TyVariableKind::Integer) => &ALL_INT_FPS, - Some(chalk_ir::TyVariableKind::Float) => &ALL_FLOAT_FPS, - _ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]), - }; - - fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option> { - let block = module.containing_block()?; - hit!(block_local_impls); - db.trait_impls_in_block(block) - } - - // Note: Since we're using impls_for_trait, only impls where the trait - // can be resolved should ever reach Chalk. impl_datum relies on that - // and will panic if the trait can't be resolved. - let in_deps = self.db.trait_impls_in_deps(self.krate); - let in_self = self.db.trait_impls_in_crate(self.krate); - let trait_module = trait_.module(self.db.upcast()); - let type_module = match self_ty_fp { - Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())), - Some(TyFingerprint::ForeignType(type_id)) => { - Some(from_foreign_def_id(type_id).module(self.db.upcast())) - } - Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())), - _ => None, - }; - let impl_maps = [ - Some(in_deps), - Some(in_self), - local_impls(self.db, trait_module), - type_module.and_then(|m| local_impls(self.db, m)), - ]; - - let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db); - - let result: Vec<_> = if fps.is_empty() { - debug!("Unrestricted search for {:?} impls...", trait_); - impl_maps - .iter() - .filter_map(|o| o.as_ref()) - .flat_map(|impls| impls.for_trait(trait_).map(id_to_chalk)) - .collect() - } else { - impl_maps - .iter() - .filter_map(|o| o.as_ref()) - .flat_map(|impls| { - fps.iter().flat_map(move |fp| { - impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk) - }) - }) - .collect() - }; - - debug!("impls_for_trait returned {} impls", result.len()); - result - } - fn impl_provided_for(&self, auto_trait_id: TraitId, kind: &chalk_ir::TyKind) -> bool { - debug!("impl_provided_for {:?}, {:?}", auto_trait_id, kind); - false // FIXME - } - fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc { - self.db.associated_ty_value(self.krate, id) - } - - fn custom_clauses(&self) -> Vec> { - vec![] - } - fn local_impls_to_coherence_check(&self, _trait_id: TraitId) -> Vec { - // We don't do coherence checking (yet) - unimplemented!() - } - fn interner(&self) -> Interner { - Interner - } - fn well_known_trait_id( - &self, - well_known_trait: rust_ir::WellKnownTrait, - ) -> Option> { - let lang_attr = lang_attr_from_well_known_trait(well_known_trait); - let trait_ = match self.db.lang_item(self.krate, lang_attr.into()) { - Some(LangItemTarget::TraitId(trait_)) => trait_, - _ => return None, - }; - Some(to_chalk_trait_id(trait_)) - } - - fn program_clauses_for_env( - &self, - environment: &chalk_ir::Environment, - ) -> chalk_ir::ProgramClauses { - self.db.program_clauses_for_chalk_env(self.krate, environment.clone()) - } - - fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId) -> Arc { - let full_id = self.db.lookup_intern_impl_trait_id(id.into()); - let bound = match full_id { - crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => { - let datas = self - .db - .return_type_impl_traits(func) - .expect("impl trait id without impl traits"); - let (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders(); - let data = &datas.impl_traits[idx as usize]; - let bound = OpaqueTyDatumBound { - bounds: make_single_type_binders(data.bounds.skip_binders().to_vec()), - where_clauses: chalk_ir::Binders::empty(Interner, vec![]), - }; - chalk_ir::Binders::new(binders, bound) - } - crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => { - if let Some((future_trait, future_output)) = self - .db - .lang_item(self.krate, SmolStr::new_inline("future_trait")) - .and_then(|item| item.as_trait()) - .and_then(|trait_| { - let alias = - self.db.trait_data(trait_).associated_type_by_name(&name![Output])?; - Some((trait_, alias)) - }) - { - // Making up Symbol’s value as variable is void: AsyncBlock: - // - // |--------------------OpaqueTyDatum-------------------| - // |-------------OpaqueTyDatumBound--------------| - // for [Future, Future::Output = T] - // ^1 ^0 ^0 ^0 ^1 - let impl_bound = WhereClause::Implemented(TraitRef { - trait_id: to_chalk_trait_id(future_trait), - // Self type as the first parameter. - substitution: Substitution::from1( - Interner, - TyKind::BoundVar(BoundVar { - debruijn: DebruijnIndex::INNERMOST, - index: 0, - }) - .intern(Interner), - ), - }); - let mut binder = vec![]; - binder.push(crate::wrap_empty_binders(impl_bound)); - let sized_trait = self - .db - .lang_item(self.krate, SmolStr::new_inline("sized")) - .and_then(|item| item.as_trait()); - if let Some(sized_trait_) = sized_trait { - let sized_bound = WhereClause::Implemented(TraitRef { - trait_id: to_chalk_trait_id(sized_trait_), - // Self type as the first parameter. - substitution: Substitution::from1( - Interner, - TyKind::BoundVar(BoundVar { - debruijn: DebruijnIndex::INNERMOST, - index: 0, - }) - .intern(Interner), - ), - }); - binder.push(crate::wrap_empty_binders(sized_bound)); - } - let proj_bound = WhereClause::AliasEq(AliasEq { - alias: AliasTy::Projection(ProjectionTy { - associated_ty_id: to_assoc_type_id(future_output), - // Self type as the first parameter. - substitution: Substitution::from1( - Interner, - TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)) - .intern(Interner), - ), - }), - // The parameter of the opaque type. - ty: TyKind::BoundVar(BoundVar { debruijn: DebruijnIndex::ONE, index: 0 }) - .intern(Interner), - }); - binder.push(crate::wrap_empty_binders(proj_bound)); - let bound = OpaqueTyDatumBound { - bounds: make_single_type_binders(binder), - where_clauses: chalk_ir::Binders::empty(Interner, vec![]), - }; - // The opaque type has 1 parameter. - make_single_type_binders(bound) - } else { - // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback. - let bound = OpaqueTyDatumBound { - bounds: chalk_ir::Binders::empty(Interner, vec![]), - where_clauses: chalk_ir::Binders::empty(Interner, vec![]), - }; - // The opaque type has 1 parameter. - make_single_type_binders(bound) - } - } - }; - - Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound }) - } - - fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId) -> chalk_ir::Ty { - // FIXME: actually provide the hidden type; it is relevant for auto traits - TyKind::Error.intern(Interner) - } - - fn is_object_safe(&self, _trait_id: chalk_ir::TraitId) -> bool { - // FIXME: implement actual object safety - true - } - - fn closure_kind( - &self, - _closure_id: chalk_ir::ClosureId, - _substs: &chalk_ir::Substitution, - ) -> rust_ir::ClosureKind { - // Fn is the closure kind that implements all three traits - rust_ir::ClosureKind::Fn - } - fn closure_inputs_and_output( - &self, - _closure_id: chalk_ir::ClosureId, - substs: &chalk_ir::Substitution, - ) -> chalk_ir::Binders> { - let sig_ty = substs.at(Interner, 0).assert_ty_ref(Interner).clone(); - let sig = &sig_ty.callable_sig(self.db).expect("first closure param should be fn ptr"); - let io = rust_ir::FnDefInputsAndOutputDatum { - argument_types: sig.params().to_vec(), - return_type: sig.ret().clone(), - }; - chalk_ir::Binders::empty(Interner, io.shifted_in(Interner)) - } - fn closure_upvars( - &self, - _closure_id: chalk_ir::ClosureId, - _substs: &chalk_ir::Substitution, - ) -> chalk_ir::Binders> { - let ty = TyBuilder::unit(); - chalk_ir::Binders::empty(Interner, ty) - } - fn closure_fn_substitution( - &self, - _closure_id: chalk_ir::ClosureId, - _substs: &chalk_ir::Substitution, - ) -> chalk_ir::Substitution { - Substitution::empty(Interner) - } - - fn trait_name(&self, trait_id: chalk_ir::TraitId) -> String { - let id = from_chalk_trait_id(trait_id); - self.db.trait_data(id).name.to_string() - } - fn adt_name(&self, chalk_ir::AdtId(adt_id): AdtId) -> String { - match adt_id { - hir_def::AdtId::StructId(id) => self.db.struct_data(id).name.to_string(), - hir_def::AdtId::EnumId(id) => self.db.enum_data(id).name.to_string(), - hir_def::AdtId::UnionId(id) => self.db.union_data(id).name.to_string(), - } - } - fn adt_size_align(&self, _id: chalk_ir::AdtId) -> Arc { - // FIXME - Arc::new(rust_ir::AdtSizeAlign::from_one_zst(false)) - } - fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId) -> String { - let id = self.db.associated_ty_data(assoc_ty_id).name; - self.db.type_alias_data(id).name.to_string() - } - fn opaque_type_name(&self, opaque_ty_id: chalk_ir::OpaqueTyId) -> String { - format!("Opaque_{}", opaque_ty_id.0) - } - fn fn_def_name(&self, fn_def_id: chalk_ir::FnDefId) -> String { - format!("fn_{}", fn_def_id.0) - } - fn generator_datum( - &self, - _: chalk_ir::GeneratorId, - ) -> std::sync::Arc> { - // FIXME - unimplemented!() - } - fn generator_witness_datum( - &self, - _: chalk_ir::GeneratorId, - ) -> std::sync::Arc> { - // FIXME - unimplemented!() - } - - fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase { - &self.db - } -} - -impl<'a> chalk_ir::UnificationDatabase for &'a dyn HirDatabase { - fn fn_def_variance( - &self, - fn_def_id: chalk_ir::FnDefId, - ) -> chalk_ir::Variances { - HirDatabase::fn_def_variance(*self, fn_def_id) - } - - fn adt_variance(&self, adt_id: chalk_ir::AdtId) -> chalk_ir::Variances { - HirDatabase::adt_variance(*self, adt_id) - } -} - -pub(crate) fn program_clauses_for_chalk_env_query( - db: &dyn HirDatabase, - krate: CrateId, - environment: chalk_ir::Environment, -) -> chalk_ir::ProgramClauses { - chalk_solve::program_clauses_for_env(&ChalkContext { db, krate }, &environment) -} - -pub(crate) fn associated_ty_data_query( - db: &dyn HirDatabase, - id: AssocTypeId, -) -> Arc { - debug!("associated_ty_data {:?}", id); - let type_alias: TypeAliasId = from_assoc_type_id(id); - let trait_ = match type_alias.lookup(db.upcast()).container { - ItemContainerId::TraitId(t) => t, - _ => panic!("associated type not in trait"), - }; - - // 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) - .with_type_param_mode(crate::lower::ParamLoweringMode::Variable); - let pro_ty = TyBuilder::assoc_type_projection(db, type_alias) - .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, 0) - .build(); - let self_ty = TyKind::Alias(AliasTy::Projection(pro_ty)).intern(Interner); - let mut bounds: Vec<_> = type_alias_data - .bounds - .iter() - .flat_map(|bound| ctx.lower_type_bound(bound, self_ty.clone(), false)) - .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty)) - .collect(); - - if !ctx.unsized_types.borrow().contains(&self_ty) { - let sized_trait = db - .lang_item(resolver.krate(), SmolStr::new_inline("sized")) - .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id)); - let sized_bound = sized_trait.into_iter().map(|sized_trait| { - let trait_bound = - rust_ir::TraitBound { trait_id: sized_trait, args_no_self: Default::default() }; - let inline_bound = rust_ir::InlineBound::TraitBound(trait_bound); - chalk_ir::Binders::empty(Interner, inline_bound) - }); - bounds.extend(sized_bound); - bounds.shrink_to_fit(); - } - - // FIXME: Re-enable where clauses on associated types when an upstream chalk bug is fixed. - // (rust-analyzer#9052) - // let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); - let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses: vec![] }; - let datum = AssociatedTyDatum { - trait_id: to_chalk_trait_id(trait_), - id, - name: type_alias, - binders: make_binders(db, &generic_params, bound_data), - }; - Arc::new(datum) -} - -pub(crate) fn trait_datum_query( - db: &dyn HirDatabase, - krate: CrateId, - trait_id: TraitId, -) -> Arc { - debug!("trait_datum {:?}", trait_id); - let trait_ = from_chalk_trait_id(trait_id); - let trait_data = db.trait_data(trait_); - debug!("trait {:?} = {:?}", trait_id, trait_data.name); - let generic_params = generics(db.upcast(), trait_.into()); - let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let flags = rust_ir::TraitFlags { - auto: trait_data.is_auto, - upstream: trait_.lookup(db.upcast()).container.krate() != krate, - non_enumerable: true, - coinductive: false, // only relevant for Chalk testing - // FIXME: set these flags correctly - marker: false, - fundamental: false, - }; - let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars); - let associated_ty_ids = trait_data.associated_types().map(to_assoc_type_id).collect(); - let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses }; - let well_known = - lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name)); - let trait_datum = TraitDatum { - id: trait_id, - binders: make_binders(db, &generic_params, trait_datum_bound), - flags, - associated_ty_ids, - well_known, - }; - Arc::new(trait_datum) -} - -fn well_known_trait_from_lang_attr(name: &str) -> Option { - Some(match name { - "clone" => WellKnownTrait::Clone, - "coerce_unsized" => WellKnownTrait::CoerceUnsized, - "copy" => WellKnownTrait::Copy, - "discriminant_kind" => WellKnownTrait::DiscriminantKind, - "dispatch_from_dyn" => WellKnownTrait::DispatchFromDyn, - "drop" => WellKnownTrait::Drop, - "fn" => WellKnownTrait::Fn, - "fn_mut" => WellKnownTrait::FnMut, - "fn_once" => WellKnownTrait::FnOnce, - "generator" => WellKnownTrait::Generator, - "sized" => WellKnownTrait::Sized, - "unpin" => WellKnownTrait::Unpin, - "unsize" => WellKnownTrait::Unsize, - _ => return None, - }) -} - -fn lang_attr_from_well_known_trait(attr: WellKnownTrait) -> &'static str { - match attr { - WellKnownTrait::Clone => "clone", - WellKnownTrait::CoerceUnsized => "coerce_unsized", - WellKnownTrait::Copy => "copy", - WellKnownTrait::DiscriminantKind => "discriminant_kind", - WellKnownTrait::DispatchFromDyn => "dispatch_from_dyn", - WellKnownTrait::Drop => "drop", - WellKnownTrait::Fn => "fn", - WellKnownTrait::FnMut => "fn_mut", - WellKnownTrait::FnOnce => "fn_once", - WellKnownTrait::Generator => "generator", - WellKnownTrait::Sized => "sized", - WellKnownTrait::Unpin => "unpin", - WellKnownTrait::Unsize => "unsize", - } -} - -pub(crate) fn struct_datum_query( - db: &dyn HirDatabase, - krate: CrateId, - struct_id: AdtId, -) -> Arc { - debug!("struct_datum {:?}", struct_id); - let chalk_ir::AdtId(adt_id) = struct_id; - let generic_params = generics(db.upcast(), adt_id.into()); - let upstream = adt_id.module(db.upcast()).krate() != krate; - let where_clauses = { - let generic_params = generics(db.upcast(), adt_id.into()); - let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST); - convert_where_clauses(db, adt_id.into(), &bound_vars) - }; - let flags = rust_ir::AdtFlags { - upstream, - // FIXME set fundamental and phantom_data flags correctly - fundamental: false, - phantom_data: false, - }; - // FIXME provide enum variants properly (for auto traits) - let variant = rust_ir::AdtVariantDatum { - fields: Vec::new(), // FIXME add fields (only relevant for auto traits), - }; - let struct_datum_bound = rust_ir::AdtDatumBound { variants: vec![variant], where_clauses }; - let struct_datum = StructDatum { - // FIXME set ADT kind - kind: rust_ir::AdtKind::Struct, - id: struct_id, - binders: make_binders(db, &generic_params, struct_datum_bound), - flags, - }; - Arc::new(struct_datum) -} - -pub(crate) fn impl_datum_query( - db: &dyn HirDatabase, - krate: CrateId, - impl_id: ImplId, -) -> Arc { - let _p = profile::span("impl_datum"); - debug!("impl_datum {:?}", impl_id); - let impl_: hir_def::ImplId = from_chalk(db, impl_id); - impl_def_datum(db, krate, impl_id, impl_) -} - -fn impl_def_datum( - db: &dyn HirDatabase, - krate: CrateId, - chalk_id: ImplId, - impl_id: hir_def::ImplId, -) -> Arc { - let trait_ref = db - .impl_trait(impl_id) - // ImplIds for impls where the trait ref can't be resolved should never reach Chalk - .expect("invalid impl passed to Chalk") - .into_value_and_skipped_binders() - .0; - let impl_data = db.impl_data(impl_id); - - let generic_params = generics(db.upcast(), impl_id.into()); - let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let trait_ = trait_ref.hir_trait_id(); - let impl_type = if impl_id.lookup(db.upcast()).container.krate() == krate { - rust_ir::ImplType::Local - } else { - rust_ir::ImplType::External - }; - let where_clauses = convert_where_clauses(db, impl_id.into(), &bound_vars); - let negative = impl_data.is_negative; - debug!( - "impl {:?}: {}{} where {:?}", - chalk_id, - if negative { "!" } else { "" }, - trait_ref.display(db), - where_clauses - ); - - let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive }; - - let impl_datum_bound = rust_ir::ImplDatumBound { trait_ref, where_clauses }; - let trait_data = db.trait_data(trait_); - let associated_ty_value_ids = impl_data - .items - .iter() - .filter_map(|item| match item { - AssocItemId::TypeAliasId(type_alias) => Some(*type_alias), - _ => None, - }) - .filter(|&type_alias| { - // don't include associated types that don't exist in the trait - let name = &db.type_alias_data(type_alias).name; - trait_data.associated_type_by_name(name).is_some() - }) - .map(|type_alias| TypeAliasAsValue(type_alias).to_chalk(db)) - .collect(); - debug!("impl_datum: {:?}", impl_datum_bound); - let impl_datum = ImplDatum { - binders: make_binders(db, &generic_params, impl_datum_bound), - impl_type, - polarity, - associated_ty_value_ids, - }; - Arc::new(impl_datum) -} - -pub(crate) fn associated_ty_value_query( - db: &dyn HirDatabase, - krate: CrateId, - id: AssociatedTyValueId, -) -> Arc { - let type_alias: TypeAliasAsValue = from_chalk(db, id); - type_alias_associated_ty_value(db, krate, type_alias.0) -} - -fn type_alias_associated_ty_value( - db: &dyn HirDatabase, - _krate: CrateId, - type_alias: TypeAliasId, -) -> Arc { - let type_alias_data = db.type_alias_data(type_alias); - let impl_id = match type_alias.lookup(db.upcast()).container { - ItemContainerId::ImplId(it) => it, - _ => panic!("assoc ty value should be in impl"), - }; - - let trait_ref = db - .impl_trait(impl_id) - .expect("assoc ty value should not exist") - .into_value_and_skipped_binders() - .0; // we don't return any assoc ty values if the impl'd trait can't be resolved - - let assoc_ty = db - .trait_data(trait_ref.hir_trait_id()) - .associated_type_by_name(&type_alias_data.name) - .expect("assoc ty value should not exist"); // validated when building the impl data as well - let (ty, binders) = db.ty(type_alias.into()).into_value_and_skipped_binders(); - let value_bound = rust_ir::AssociatedTyValueBound { ty }; - let value = rust_ir::AssociatedTyValue { - impl_id: impl_id.to_chalk(db), - associated_ty_id: to_assoc_type_id(assoc_ty), - value: chalk_ir::Binders::new(binders, value_bound), - }; - Arc::new(value) -} - -pub(crate) fn fn_def_datum_query( - db: &dyn HirDatabase, - _krate: CrateId, - fn_def_id: FnDefId, -) -> Arc { - let callable_def: CallableDefId = from_chalk(db, fn_def_id); - let generic_params = generics(db.upcast(), callable_def.into()); - let (sig, binders) = db.callable_item_signature(callable_def).into_value_and_skipped_binders(); - let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars); - let bound = rust_ir::FnDefDatumBound { - // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway - inputs_and_output: chalk_ir::Binders::empty( - Interner, - rust_ir::FnDefInputsAndOutputDatum { - argument_types: sig.params().to_vec(), - return_type: sig.ret().clone(), - } - .shifted_in(Interner), - ), - where_clauses, - }; - let datum = FnDefDatum { - id: fn_def_id, - sig: chalk_ir::FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: sig.is_varargs }, - binders: chalk_ir::Binders::new(binders, bound), - }; - Arc::new(datum) -} - -pub(crate) fn fn_def_variance_query(db: &dyn HirDatabase, fn_def_id: FnDefId) -> Variances { - let callable_def: CallableDefId = from_chalk(db, fn_def_id); - let generic_params = generics(db.upcast(), callable_def.into()); - Variances::from_iter( - Interner, - std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()), - ) -} - -pub(crate) fn adt_variance_query( - db: &dyn HirDatabase, - chalk_ir::AdtId(adt_id): AdtId, -) -> Variances { - let generic_params = generics(db.upcast(), adt_id.into()); - Variances::from_iter( - Interner, - std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()), - ) -} - -pub(super) fn convert_where_clauses( - db: &dyn HirDatabase, - def: GenericDefId, - substs: &Substitution, -) -> Vec> { - let generic_predicates = db.generic_predicates(def); - let mut result = Vec::with_capacity(generic_predicates.len()); - for pred in generic_predicates.iter() { - result.push(pred.clone().substitute(Interner, substs)); - } - result -} - -pub(super) fn generic_predicate_to_inline_bound( - db: &dyn HirDatabase, - pred: &QuantifiedWhereClause, - self_ty: &Ty, -) -> Option>> { - // An InlineBound is like a GenericPredicate, except the self type is left out. - // We don't have a special type for this, but Chalk does. - let self_ty_shifted_in = self_ty.clone().shifted_in_from(Interner, DebruijnIndex::ONE); - let (pred, binders) = pred.as_ref().into_value_and_skipped_binders(); - match pred { - WhereClause::Implemented(trait_ref) => { - if trait_ref.self_type_parameter(Interner) != self_ty_shifted_in { - // we can only convert predicates back to type bounds if they - // have the expected self type - return None; - } - let args_no_self = trait_ref.substitution.as_slice(Interner)[1..] - .iter() - .map(|ty| ty.clone().cast(Interner)) - .collect(); - let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self }; - Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound))) - } - WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => { - if projection_ty.self_type_parameter(Interner) != self_ty_shifted_in { - return None; - } - let trait_ = projection_ty.trait_(db); - let args_no_self = projection_ty.substitution.as_slice(Interner)[1..] - .iter() - .map(|ty| ty.clone().cast(Interner)) - .collect(); - let alias_eq_bound = rust_ir::AliasEqBound { - value: ty.clone(), - trait_bound: rust_ir::TraitBound { - trait_id: to_chalk_trait_id(trait_), - args_no_self, - }, - associated_ty_id: projection_ty.associated_ty_id, - parameters: Vec::new(), // FIXME we don't support generic associated types yet - }; - Some(chalk_ir::Binders::new( - binders, - rust_ir::InlineBound::AliasEqBound(alias_eq_bound), - )) - } - _ => None, - } -} 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 deleted file mode 100644 index b0885ab003f71..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs +++ /dev/null @@ -1,353 +0,0 @@ -//! Various extensions traits for Chalk types. - -use chalk_ir::{FloatTy, IntTy, Mutability, Scalar, UintTy}; -use hir_def::{ - builtin_type::{BuiltinFloat, BuiltinInt, BuiltinType, BuiltinUint}, - generics::TypeOrConstParamData, - type_ref::Rawness, - FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId, -}; -use syntax::SmolStr; - -use crate::{ - db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, - from_placeholder_idx, to_chalk_trait_id, AdtId, AliasEq, AliasTy, Binders, CallableDefId, - CallableSig, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause, - Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause, -}; - -pub trait TyExt { - fn is_unit(&self) -> bool; - fn is_never(&self) -> bool; - fn is_unknown(&self) -> bool; - fn is_ty_var(&self) -> bool; - - fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>; - fn as_builtin(&self) -> Option; - fn as_tuple(&self) -> Option<&Substitution>; - fn as_fn_def(&self, db: &dyn HirDatabase) -> Option; - fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>; - fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)>; - fn as_generic_def(&self, db: &dyn HirDatabase) -> Option; - - fn callable_def(&self, db: &dyn HirDatabase) -> Option; - fn callable_sig(&self, db: &dyn HirDatabase) -> Option; - - fn strip_references(&self) -> &Ty; - - /// If this is a `dyn Trait`, returns that trait. - fn dyn_trait(&self) -> Option; - - fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option>; - fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option; - - /// FIXME: Get rid of this, it's not a good abstraction - fn equals_ctor(&self, other: &Ty) -> bool; -} - -impl TyExt for Ty { - fn is_unit(&self) -> bool { - matches!(self.kind(Interner), TyKind::Tuple(0, _)) - } - - fn is_never(&self) -> bool { - matches!(self.kind(Interner), TyKind::Never) - } - - fn is_unknown(&self) -> bool { - matches!(self.kind(Interner), TyKind::Error) - } - - fn is_ty_var(&self) -> bool { - matches!(self.kind(Interner), TyKind::InferenceVar(_, _)) - } - - fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> { - match self.kind(Interner) { - TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)), - _ => None, - } - } - - fn as_builtin(&self) -> Option { - match self.kind(Interner) { - TyKind::Str => Some(BuiltinType::Str), - TyKind::Scalar(Scalar::Bool) => Some(BuiltinType::Bool), - TyKind::Scalar(Scalar::Char) => Some(BuiltinType::Char), - TyKind::Scalar(Scalar::Float(fty)) => Some(BuiltinType::Float(match fty { - FloatTy::F64 => BuiltinFloat::F64, - FloatTy::F32 => BuiltinFloat::F32, - })), - TyKind::Scalar(Scalar::Int(ity)) => Some(BuiltinType::Int(match ity { - IntTy::Isize => BuiltinInt::Isize, - IntTy::I8 => BuiltinInt::I8, - IntTy::I16 => BuiltinInt::I16, - IntTy::I32 => BuiltinInt::I32, - IntTy::I64 => BuiltinInt::I64, - IntTy::I128 => BuiltinInt::I128, - })), - TyKind::Scalar(Scalar::Uint(ity)) => Some(BuiltinType::Uint(match ity { - UintTy::Usize => BuiltinUint::Usize, - UintTy::U8 => BuiltinUint::U8, - UintTy::U16 => BuiltinUint::U16, - UintTy::U32 => BuiltinUint::U32, - UintTy::U64 => BuiltinUint::U64, - UintTy::U128 => BuiltinUint::U128, - })), - _ => None, - } - } - - fn as_tuple(&self) -> Option<&Substitution> { - match self.kind(Interner) { - TyKind::Tuple(_, substs) => Some(substs), - _ => None, - } - } - - fn as_fn_def(&self, db: &dyn HirDatabase) -> Option { - match self.callable_def(db) { - Some(CallableDefId::FunctionId(func)) => Some(func), - Some(CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_)) | None => None, - } - } - fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)> { - match self.kind(Interner) { - TyKind::Ref(mutability, lifetime, ty) => Some((ty, lifetime.clone(), *mutability)), - _ => None, - } - } - - fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> { - match self.kind(Interner) { - TyKind::Ref(mutability, _, ty) => Some((ty, Rawness::Ref, *mutability)), - TyKind::Raw(mutability, ty) => Some((ty, Rawness::RawPtr, *mutability)), - _ => None, - } - } - - fn as_generic_def(&self, db: &dyn HirDatabase) -> Option { - match *self.kind(Interner) { - TyKind::Adt(AdtId(adt), ..) => Some(adt.into()), - TyKind::FnDef(callable, ..) => { - Some(db.lookup_intern_callable_def(callable.into()).into()) - } - TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()), - TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()), - _ => None, - } - } - - fn callable_def(&self, db: &dyn HirDatabase) -> Option { - match self.kind(Interner) { - &TyKind::FnDef(def, ..) => Some(db.lookup_intern_callable_def(def.into())), - _ => None, - } - } - - fn callable_sig(&self, db: &dyn HirDatabase) -> Option { - match self.kind(Interner) { - TyKind::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)), - TyKind::FnDef(def, parameters) => { - let callable_def = db.lookup_intern_callable_def((*def).into()); - let sig = db.callable_item_signature(callable_def); - Some(sig.substitute(Interner, ¶meters)) - } - TyKind::Closure(.., substs) => { - let sig_param = substs.at(Interner, 0).assert_ty_ref(Interner); - sig_param.callable_sig(db) - } - _ => None, - } - } - - fn dyn_trait(&self) -> Option { - let trait_ref = match self.kind(Interner) { - TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| { - match b.skip_binders() { - WhereClause::Implemented(trait_ref) => Some(trait_ref), - _ => None, - } - }), - _ => None, - }?; - Some(from_chalk_trait_id(trait_ref.trait_id)) - } - - fn strip_references(&self) -> &Ty { - let mut t: &Ty = self; - while let TyKind::Ref(_mutability, _lifetime, ty) = t.kind(Interner) { - t = ty; - } - t - } - - fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option> { - match self.kind(Interner) { - TyKind::OpaqueType(opaque_ty_id, subst) => { - match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) { - ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => { - let krate = def.module(db.upcast()).krate(); - if let Some(future_trait) = db - .lang_item(krate, SmolStr::new_inline("future_trait")) - .and_then(|item| item.as_trait()) - { - // This is only used by type walking. - // Parameters will be walked outside, and projection predicate is not used. - // So just provide the Future trait. - let impl_bound = Binders::empty( - Interner, - WhereClause::Implemented(TraitRef { - trait_id: to_chalk_trait_id(future_trait), - substitution: Substitution::empty(Interner), - }), - ); - Some(vec![impl_bound]) - } else { - None - } - } - ImplTraitId::ReturnTypeImplTrait(func, idx) => { - db.return_type_impl_traits(func).map(|it| { - let data = (*it) - .as_ref() - .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); - data.substitute(Interner, &subst).into_value_and_skipped_binders().0 - }) - } - } - } - TyKind::Alias(AliasTy::Opaque(opaque_ty)) => { - let predicates = match db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into()) - { - ImplTraitId::ReturnTypeImplTrait(func, idx) => { - db.return_type_impl_traits(func).map(|it| { - let data = (*it) - .as_ref() - .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); - data.substitute(Interner, &opaque_ty.substitution) - }) - } - // It always has an parameter for Future::Output type. - ImplTraitId::AsyncBlockTypeImplTrait(..) => unreachable!(), - }; - - predicates.map(|it| it.into_value_and_skipped_binders().0) - } - TyKind::Placeholder(idx) => { - let id = from_placeholder_idx(db, *idx); - let generic_params = db.generic_params(id.parent); - let param_data = &generic_params.type_or_consts[id.local_id]; - match param_data { - TypeOrConstParamData::TypeParamData(p) => match p.provenance { - hir_def::generics::TypeParamProvenance::ArgumentImplTrait => { - let substs = TyBuilder::placeholder_subst(db, id.parent); - let predicates = db - .generic_predicates(id.parent) - .iter() - .map(|pred| pred.clone().substitute(Interner, &substs)) - .filter(|wc| match &wc.skip_binders() { - WhereClause::Implemented(tr) => { - &tr.self_type_parameter(Interner) == self - } - WhereClause::AliasEq(AliasEq { - alias: AliasTy::Projection(proj), - ty: _, - }) => &proj.self_type_parameter(Interner) == self, - _ => false, - }) - .collect::>(); - - Some(predicates) - } - _ => None, - }, - _ => None, - } - } - _ => None, - } - } - - fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option { - match self.kind(Interner) { - TyKind::AssociatedType(id, ..) => { - match from_assoc_type_id(*id).lookup(db.upcast()).container { - ItemContainerId::TraitId(trait_id) => Some(trait_id), - _ => None, - } - } - TyKind::Alias(AliasTy::Projection(projection_ty)) => { - match from_assoc_type_id(projection_ty.associated_ty_id) - .lookup(db.upcast()) - .container - { - ItemContainerId::TraitId(trait_id) => Some(trait_id), - _ => None, - } - } - _ => None, - } - } - - fn equals_ctor(&self, other: &Ty) -> bool { - match (self.kind(Interner), other.kind(Interner)) { - (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2, - (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_, _), TyKind::Array(_, _)) => { - true - } - (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2, - (TyKind::OpaqueType(ty_id, ..), TyKind::OpaqueType(ty_id2, ..)) => ty_id == ty_id2, - (TyKind::AssociatedType(ty_id, ..), TyKind::AssociatedType(ty_id2, ..)) => { - ty_id == ty_id2 - } - (TyKind::Foreign(ty_id, ..), TyKind::Foreign(ty_id2, ..)) => ty_id == ty_id2, - (TyKind::Closure(id1, _), TyKind::Closure(id2, _)) => id1 == id2, - (TyKind::Ref(mutability, ..), TyKind::Ref(mutability2, ..)) - | (TyKind::Raw(mutability, ..), TyKind::Raw(mutability2, ..)) => { - mutability == mutability2 - } - ( - TyKind::Function(FnPointer { num_binders, sig, .. }), - TyKind::Function(FnPointer { num_binders: num_binders2, sig: sig2, .. }), - ) => num_binders == num_binders2 && sig == sig2, - (TyKind::Tuple(cardinality, _), TyKind::Tuple(cardinality2, _)) => { - cardinality == cardinality2 - } - (TyKind::Str, TyKind::Str) | (TyKind::Never, TyKind::Never) => true, - (TyKind::Scalar(scalar), TyKind::Scalar(scalar2)) => scalar == scalar2, - _ => false, - } - } -} - -pub trait ProjectionTyExt { - fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef; - fn trait_(&self, db: &dyn HirDatabase) -> TraitId; -} - -impl ProjectionTyExt for ProjectionTy { - fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef { - TraitRef { - trait_id: to_chalk_trait_id(self.trait_(db)), - substitution: self.substitution.clone(), - } - } - - fn trait_(&self, db: &dyn HirDatabase) -> TraitId { - match from_assoc_type_id(self.associated_ty_id).lookup(db.upcast()).container { - ItemContainerId::TraitId(it) => it, - _ => panic!("projection ty without parent trait"), - } - } -} - -pub trait TraitRefExt { - fn hir_trait_id(&self) -> TraitId; -} - -impl TraitRefExt for TraitRef { - fn hir_trait_id(&self) -> TraitId { - from_chalk_trait_id(self.trait_id) - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs deleted file mode 100644 index 0495a4e64caca..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ /dev/null @@ -1,469 +0,0 @@ -//! Constant evaluation details - -use std::{ - collections::HashMap, - convert::TryInto, - fmt::{Display, Write}, -}; - -use chalk_ir::{BoundVar, DebruijnIndex, GenericArgData, IntTy, Scalar}; -use hir_def::{ - expr::{ArithOp, BinaryOp, Expr, ExprId, Literal, Pat, PatId}, - path::ModPath, - resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs}, - type_ref::ConstScalar, - ConstId, DefWithBodyId, -}; -use la_arena::{Arena, Idx}; -use stdx::never; - -use crate::{ - db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode, to_placeholder_idx, - utils::Generics, Const, ConstData, ConstValue, GenericArg, InferenceResult, Interner, Ty, - TyBuilder, TyKind, -}; - -/// Extension trait for [`Const`] -pub trait ConstExt { - /// Is a [`Const`] unknown? - fn is_unknown(&self) -> bool; -} - -impl ConstExt for Const { - fn is_unknown(&self) -> bool { - match self.data(Interner).value { - // interned Unknown - chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { - interned: ConstScalar::Unknown, - }) => true, - - // interned concrete anything else - chalk_ir::ConstValue::Concrete(..) => false, - - _ => { - tracing::error!( - "is_unknown was called on a non-concrete constant value! {:?}", - self - ); - true - } - } - } -} - -pub struct ConstEvalCtx<'a> { - pub db: &'a dyn HirDatabase, - pub owner: DefWithBodyId, - pub exprs: &'a Arena, - pub pats: &'a Arena, - pub local_data: HashMap, - infer: &'a InferenceResult, -} - -impl ConstEvalCtx<'_> { - fn expr_ty(&mut self, expr: ExprId) -> Ty { - self.infer[expr].clone() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ConstEvalError { - NotSupported(&'static str), - SemanticError(&'static str), - Loop, - IncompleteExpr, - Panic(String), -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ComputedExpr { - Literal(Literal), - Tuple(Box<[ComputedExpr]>), -} - -impl Display for ComputedExpr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ComputedExpr::Literal(l) => match l { - Literal::Int(x, _) => { - if *x >= 10 { - write!(f, "{} ({:#X})", x, x) - } else { - x.fmt(f) - } - } - Literal::Uint(x, _) => { - if *x >= 10 { - write!(f, "{} ({:#X})", x, x) - } else { - x.fmt(f) - } - } - Literal::Float(x, _) => x.fmt(f), - Literal::Bool(x) => x.fmt(f), - Literal::Char(x) => std::fmt::Debug::fmt(x, f), - Literal::String(x) => std::fmt::Debug::fmt(x, f), - Literal::ByteString(x) => std::fmt::Debug::fmt(x, f), - }, - ComputedExpr::Tuple(t) => { - f.write_char('(')?; - for x in &**t { - x.fmt(f)?; - f.write_str(", ")?; - } - f.write_char(')') - } - } - } -} - -fn scalar_max(scalar: &Scalar) -> i128 { - match scalar { - Scalar::Bool => 1, - Scalar::Char => u32::MAX as i128, - Scalar::Int(x) => match x { - IntTy::Isize => isize::MAX as i128, - IntTy::I8 => i8::MAX as i128, - IntTy::I16 => i16::MAX as i128, - IntTy::I32 => i32::MAX as i128, - IntTy::I64 => i64::MAX as i128, - IntTy::I128 => i128::MAX as i128, - }, - Scalar::Uint(x) => match x { - chalk_ir::UintTy::Usize => usize::MAX as i128, - chalk_ir::UintTy::U8 => u8::MAX as i128, - chalk_ir::UintTy::U16 => u16::MAX as i128, - chalk_ir::UintTy::U32 => u32::MAX as i128, - chalk_ir::UintTy::U64 => u64::MAX as i128, - chalk_ir::UintTy::U128 => i128::MAX as i128, // ignore too big u128 for now - }, - Scalar::Float(_) => 0, - } -} - -fn is_valid(scalar: &Scalar, value: i128) -> bool { - if value < 0 { - !matches!(scalar, Scalar::Uint(_)) && -scalar_max(scalar) - 1 <= value - } else { - value <= scalar_max(scalar) - } -} - -pub fn eval_const( - expr_id: ExprId, - ctx: &mut ConstEvalCtx<'_>, -) -> Result { - let expr = &ctx.exprs[expr_id]; - match expr { - Expr::Missing => Err(ConstEvalError::IncompleteExpr), - Expr::Literal(l) => Ok(ComputedExpr::Literal(l.clone())), - &Expr::UnaryOp { expr, op } => { - let ty = &ctx.expr_ty(expr); - let ev = eval_const(expr, ctx)?; - match op { - hir_def::expr::UnaryOp::Deref => Err(ConstEvalError::NotSupported("deref")), - hir_def::expr::UnaryOp::Not => { - let v = match ev { - ComputedExpr::Literal(Literal::Bool(b)) => { - return Ok(ComputedExpr::Literal(Literal::Bool(!b))) - } - ComputedExpr::Literal(Literal::Int(v, _)) => v, - ComputedExpr::Literal(Literal::Uint(v, _)) => v - .try_into() - .map_err(|_| ConstEvalError::NotSupported("too big u128"))?, - _ => return Err(ConstEvalError::NotSupported("this kind of operator")), - }; - let r = match ty.kind(Interner) { - TyKind::Scalar(Scalar::Uint(x)) => match x { - chalk_ir::UintTy::U8 => !(v as u8) as i128, - chalk_ir::UintTy::U16 => !(v as u16) as i128, - chalk_ir::UintTy::U32 => !(v as u32) as i128, - chalk_ir::UintTy::U64 => !(v as u64) as i128, - chalk_ir::UintTy::U128 => { - return Err(ConstEvalError::NotSupported("negation of u128")) - } - chalk_ir::UintTy::Usize => !(v as usize) as i128, - }, - TyKind::Scalar(Scalar::Int(x)) => match x { - chalk_ir::IntTy::I8 => !(v as i8) as i128, - chalk_ir::IntTy::I16 => !(v as i16) as i128, - chalk_ir::IntTy::I32 => !(v as i32) as i128, - chalk_ir::IntTy::I64 => !(v as i64) as i128, - chalk_ir::IntTy::I128 => !v, - chalk_ir::IntTy::Isize => !(v as isize) as i128, - }, - _ => return Err(ConstEvalError::NotSupported("unreachable?")), - }; - Ok(ComputedExpr::Literal(Literal::Int(r, None))) - } - hir_def::expr::UnaryOp::Neg => { - let v = match ev { - ComputedExpr::Literal(Literal::Int(v, _)) => v, - ComputedExpr::Literal(Literal::Uint(v, _)) => v - .try_into() - .map_err(|_| ConstEvalError::NotSupported("too big u128"))?, - _ => return Err(ConstEvalError::NotSupported("this kind of operator")), - }; - Ok(ComputedExpr::Literal(Literal::Int( - v.checked_neg().ok_or_else(|| { - ConstEvalError::Panic("overflow in negation".to_string()) - })?, - None, - ))) - } - } - } - &Expr::BinaryOp { lhs, rhs, op } => { - let ty = &ctx.expr_ty(lhs); - let lhs = eval_const(lhs, ctx)?; - let rhs = eval_const(rhs, ctx)?; - let op = op.ok_or(ConstEvalError::IncompleteExpr)?; - let v1 = match lhs { - ComputedExpr::Literal(Literal::Int(v, _)) => v, - ComputedExpr::Literal(Literal::Uint(v, _)) => { - v.try_into().map_err(|_| ConstEvalError::NotSupported("too big u128"))? - } - _ => return Err(ConstEvalError::NotSupported("this kind of operator")), - }; - let v2 = match rhs { - ComputedExpr::Literal(Literal::Int(v, _)) => v, - ComputedExpr::Literal(Literal::Uint(v, _)) => { - v.try_into().map_err(|_| ConstEvalError::NotSupported("too big u128"))? - } - _ => return Err(ConstEvalError::NotSupported("this kind of operator")), - }; - match op { - BinaryOp::ArithOp(b) => { - let panic_arith = ConstEvalError::Panic( - "attempt to run invalid arithmetic operation".to_string(), - ); - let r = match b { - ArithOp::Add => v1.checked_add(v2).ok_or_else(|| panic_arith.clone())?, - ArithOp::Mul => v1.checked_mul(v2).ok_or_else(|| panic_arith.clone())?, - ArithOp::Sub => v1.checked_sub(v2).ok_or_else(|| panic_arith.clone())?, - ArithOp::Div => v1.checked_div(v2).ok_or_else(|| panic_arith.clone())?, - ArithOp::Rem => v1.checked_rem(v2).ok_or_else(|| panic_arith.clone())?, - ArithOp::Shl => v1 - .checked_shl(v2.try_into().map_err(|_| panic_arith.clone())?) - .ok_or_else(|| panic_arith.clone())?, - ArithOp::Shr => v1 - .checked_shr(v2.try_into().map_err(|_| panic_arith.clone())?) - .ok_or_else(|| panic_arith.clone())?, - ArithOp::BitXor => v1 ^ v2, - ArithOp::BitOr => v1 | v2, - ArithOp::BitAnd => v1 & v2, - }; - if let TyKind::Scalar(s) = ty.kind(Interner) { - if !is_valid(s, r) { - return Err(panic_arith); - } - } - Ok(ComputedExpr::Literal(Literal::Int(r, None))) - } - BinaryOp::LogicOp(_) => Err(ConstEvalError::SemanticError("logic op on numbers")), - _ => Err(ConstEvalError::NotSupported("bin op on this operators")), - } - } - Expr::Block { statements, tail, .. } => { - let mut prev_values = HashMap::>::default(); - for statement in &**statements { - match *statement { - hir_def::expr::Statement::Let { pat: pat_id, initializer, .. } => { - let pat = &ctx.pats[pat_id]; - match pat { - Pat::Bind { subpat, .. } if subpat.is_none() => (), - _ => { - return Err(ConstEvalError::NotSupported("complex patterns in let")) - } - }; - let value = match initializer { - Some(x) => eval_const(x, ctx)?, - None => continue, - }; - if !prev_values.contains_key(&pat_id) { - let prev = ctx.local_data.insert(pat_id, value); - prev_values.insert(pat_id, prev); - } else { - ctx.local_data.insert(pat_id, value); - } - } - hir_def::expr::Statement::Expr { .. } => { - return Err(ConstEvalError::NotSupported("this kind of statement")) - } - } - } - let r = match tail { - &Some(x) => eval_const(x, ctx), - None => Ok(ComputedExpr::Tuple(Box::new([]))), - }; - // clean up local data, so caller will receive the exact map that passed to us - for (name, val) in prev_values { - match val { - Some(x) => ctx.local_data.insert(name, x), - None => ctx.local_data.remove(&name), - }; - } - r - } - Expr::Path(p) => { - let resolver = resolver_for_expr(ctx.db.upcast(), ctx.owner, expr_id); - let pr = resolver - .resolve_path_in_value_ns(ctx.db.upcast(), p.mod_path()) - .ok_or(ConstEvalError::SemanticError("unresolved path"))?; - let pr = match pr { - ResolveValueResult::ValueNs(v) => v, - ResolveValueResult::Partial(..) => { - return match ctx - .infer - .assoc_resolutions_for_expr(expr_id) - .ok_or(ConstEvalError::SemanticError("unresolved assoc item"))? - { - hir_def::AssocItemId::FunctionId(_) => { - Err(ConstEvalError::NotSupported("assoc function")) - } - hir_def::AssocItemId::ConstId(c) => ctx.db.const_eval(c), - hir_def::AssocItemId::TypeAliasId(_) => { - Err(ConstEvalError::NotSupported("assoc type alias")) - } - } - } - }; - match pr { - ValueNs::LocalBinding(pat_id) => { - let r = ctx - .local_data - .get(&pat_id) - .ok_or(ConstEvalError::NotSupported("Unexpected missing local"))?; - Ok(r.clone()) - } - ValueNs::ConstId(id) => ctx.db.const_eval(id), - ValueNs::GenericParam(_) => { - Err(ConstEvalError::NotSupported("const generic without substitution")) - } - _ => Err(ConstEvalError::NotSupported("path that are not const or local")), - } - } - _ => Err(ConstEvalError::NotSupported("This kind of expression")), - } -} - -pub(crate) fn path_to_const( - db: &dyn HirDatabase, - resolver: &Resolver, - path: &ModPath, - mode: ParamLoweringMode, - args_lazy: impl FnOnce() -> Generics, - debruijn: DebruijnIndex, -) -> Option { - match resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) { - Some(ValueNs::GenericParam(p)) => { - let ty = db.const_param_ty(p); - let args = args_lazy(); - let value = match mode { - ParamLoweringMode::Placeholder => { - ConstValue::Placeholder(to_placeholder_idx(db, p.into())) - } - ParamLoweringMode::Variable => match args.param_idx(p.into()) { - Some(x) => ConstValue::BoundVar(BoundVar::new(debruijn, x)), - None => { - never!( - "Generic list doesn't contain this param: {:?}, {}, {:?}", - args, - path, - p - ); - return None; - } - }, - }; - Some(ConstData { ty, value }.intern(Interner)) - } - _ => None, - } -} - -pub fn unknown_const(ty: Ty) -> Const { - ConstData { - ty, - value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: ConstScalar::Unknown }), - } - .intern(Interner) -} - -pub fn unknown_const_as_generic(ty: Ty) -> GenericArg { - GenericArgData::Const(unknown_const(ty)).intern(Interner) -} - -/// Interns a constant scalar with the given type -pub fn intern_const_scalar(value: ConstScalar, ty: Ty) -> Const { - ConstData { ty, value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: value }) } - .intern(Interner) -} - -/// Interns a possibly-unknown target usize -pub fn usize_const(value: Option) -> Const { - intern_const_scalar(value.map_or(ConstScalar::Unknown, ConstScalar::UInt), TyBuilder::usize()) -} - -pub(crate) fn const_eval_recover( - _: &dyn HirDatabase, - _: &[String], - _: &ConstId, -) -> Result { - Err(ConstEvalError::Loop) -} - -pub(crate) fn const_eval_query( - db: &dyn HirDatabase, - const_id: ConstId, -) -> Result { - let def = const_id.into(); - let body = db.body(def); - let infer = &db.infer(def); - let result = eval_const( - body.body_expr, - &mut ConstEvalCtx { - db, - owner: const_id.into(), - exprs: &body.exprs, - pats: &body.pats, - local_data: HashMap::default(), - infer, - }, - ); - result -} - -pub(crate) fn eval_to_const<'a>( - expr: Idx, - mode: ParamLoweringMode, - ctx: &mut InferenceContext<'a>, - args: impl FnOnce() -> Generics, - debruijn: DebruijnIndex, -) -> Const { - if let Expr::Path(p) = &ctx.body.exprs[expr] { - let db = ctx.db; - let resolver = &ctx.resolver; - if let Some(c) = path_to_const(db, resolver, p.mod_path(), mode, args, debruijn) { - return c; - } - } - let body = ctx.body.clone(); - let mut ctx = ConstEvalCtx { - db: ctx.db, - owner: ctx.owner, - exprs: &body.exprs, - pats: &body.pats, - local_data: HashMap::default(), - infer: &ctx.result, - }; - let computed_expr = eval_const(expr, &mut ctx); - let const_scalar = match computed_expr { - Ok(ComputedExpr::Literal(literal)) => literal.into(), - _ => ConstScalar::Unknown, - }; - intern_const_scalar(const_scalar, TyBuilder::usize()) -} - -#[cfg(test)] -mod tests; 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 deleted file mode 100644 index 4a052851afd14..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ /dev/null @@ -1,148 +0,0 @@ -use base_db::fixture::WithFixture; -use hir_def::{db::DefDatabase, expr::Literal}; - -use crate::{consteval::ComputedExpr, db::HirDatabase, test_db::TestDB}; - -use super::ConstEvalError; - -fn check_fail(ra_fixture: &str, error: ConstEvalError) { - assert_eq!(eval_goal(ra_fixture), Err(error)); -} - -fn check_number(ra_fixture: &str, answer: i128) { - let r = eval_goal(ra_fixture).unwrap(); - match r { - ComputedExpr::Literal(Literal::Int(r, _)) => assert_eq!(r, answer), - ComputedExpr::Literal(Literal::Uint(r, _)) => assert_eq!(r, answer as u128), - x => panic!("Expected number but found {:?}", x), - } -} - -fn eval_goal(ra_fixture: &str) -> Result { - let (db, file_id) = TestDB::with_single_file(ra_fixture); - let module_id = db.module_for_file(file_id); - let def_map = module_id.def_map(&db); - let scope = &def_map[module_id.local_id].scope; - let const_id = scope - .declarations() - .into_iter() - .find_map(|x| match x { - hir_def::ModuleDefId::ConstId(x) => { - if db.const_data(x).name.as_ref()?.to_string() == "GOAL" { - Some(x) - } else { - None - } - } - _ => None, - }) - .unwrap(); - db.const_eval(const_id) -} - -#[test] -fn add() { - check_number(r#"const GOAL: usize = 2 + 2;"#, 4); -} - -#[test] -fn bit_op() { - check_number(r#"const GOAL: u8 = !0 & !(!0 >> 1)"#, 128); - check_number(r#"const GOAL: i8 = !0 & !(!0 >> 1)"#, 0); - // FIXME: rustc evaluate this to -128 - check_fail( - r#"const GOAL: i8 = 1 << 7"#, - ConstEvalError::Panic("attempt to run invalid arithmetic operation".to_string()), - ); - check_fail( - r#"const GOAL: i8 = 1 << 8"#, - ConstEvalError::Panic("attempt to run invalid arithmetic operation".to_string()), - ); -} - -#[test] -fn locals() { - check_number( - r#" - const GOAL: usize = { - let a = 3 + 2; - let b = a * a; - b - }; - "#, - 25, - ); -} - -#[test] -fn consts() { - check_number( - r#" - const F1: i32 = 1; - const F3: i32 = 3 * F2; - const F2: i32 = 2 * F1; - const GOAL: i32 = F3; - "#, - 6, - ); -} - -#[test] -fn const_loop() { - check_fail( - r#" - const F1: i32 = 1 * F3; - const F3: i32 = 3 * F2; - const F2: i32 = 2 * F1; - const GOAL: i32 = F3; - "#, - ConstEvalError::Loop, - ); -} - -#[test] -fn const_impl_assoc() { - check_number( - r#" - struct U5; - impl U5 { - const VAL: usize = 5; - } - const GOAL: usize = U5::VAL; - "#, - 5, - ); -} - -#[test] -fn const_generic_subst() { - // FIXME: this should evaluate to 5 - check_fail( - r#" - struct Adder; - impl Adder { - const VAL: usize = N + M; - } - const GOAL: usize = Adder::<2, 3>::VAL; - "#, - ConstEvalError::NotSupported("const generic without substitution"), - ); -} - -#[test] -fn const_trait_assoc() { - // FIXME: this should evaluate to 0 - check_fail( - r#" - struct U0; - trait ToConst { - const VAL: usize; - } - impl ToConst for U0 { - const VAL: usize = 0; - } - const GOAL: usize = U0::VAL; - "#, - ConstEvalError::IncompleteExpr, - ); -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs deleted file mode 100644 index b385b1cafaefd..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ /dev/null @@ -1,225 +0,0 @@ -//! The home of `HirDatabase`, which is the Salsa database containing all the -//! type inference-related queries. - -use std::sync::Arc; - -use arrayvec::ArrayVec; -use base_db::{impl_intern_key, salsa, CrateId, Upcast}; -use hir_def::{ - db::DefDatabase, expr::ExprId, BlockId, ConstId, ConstParamId, DefWithBodyId, FunctionId, - GenericDefId, ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId, -}; -use la_arena::ArenaMap; - -use crate::{ - chalk_db, - consteval::{ComputedExpr, ConstEvalError}, - method_resolution::{InherentImpls, TraitImpls, TyFingerprint}, - Binders, CallableDefId, FnDefId, GenericArg, ImplTraitId, InferenceResult, Interner, PolyFnSig, - QuantifiedWhereClause, ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId, -}; -use hir_expand::name::Name; - -#[salsa::query_group(HirDatabaseStorage)] -pub trait HirDatabase: DefDatabase + Upcast { - #[salsa::invoke(infer_wait)] - #[salsa::transparent] - fn infer(&self, def: DefWithBodyId) -> Arc; - - #[salsa::invoke(crate::infer::infer_query)] - fn infer_query(&self, def: DefWithBodyId) -> Arc; - - #[salsa::invoke(crate::lower::ty_query)] - #[salsa::cycle(crate::lower::ty_recover)] - fn ty(&self, def: TyDefId) -> Binders; - - #[salsa::invoke(crate::lower::value_ty_query)] - fn value_ty(&self, def: ValueTyDefId) -> Binders; - - #[salsa::invoke(crate::lower::impl_self_ty_query)] - #[salsa::cycle(crate::lower::impl_self_ty_recover)] - fn impl_self_ty(&self, def: ImplId) -> Binders; - - #[salsa::invoke(crate::lower::const_param_ty_query)] - fn const_param_ty(&self, def: ConstParamId) -> Ty; - - #[salsa::invoke(crate::consteval::const_eval_query)] - #[salsa::cycle(crate::consteval::const_eval_recover)] - fn const_eval(&self, def: ConstId) -> Result; - - #[salsa::invoke(crate::lower::impl_trait_query)] - fn impl_trait(&self, def: ImplId) -> Option>; - - #[salsa::invoke(crate::lower::field_types_query)] - fn field_types(&self, var: VariantId) -> Arc>>; - - #[salsa::invoke(crate::lower::callable_item_sig)] - fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig; - - #[salsa::invoke(crate::lower::return_type_impl_traits)] - fn return_type_impl_traits( - &self, - def: FunctionId, - ) -> Option>>; - - #[salsa::invoke(crate::lower::generic_predicates_for_param_query)] - #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)] - fn generic_predicates_for_param( - &self, - def: GenericDefId, - param_id: TypeOrConstParamId, - assoc_name: Option, - ) -> Arc<[Binders]>; - - #[salsa::invoke(crate::lower::generic_predicates_query)] - fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders]>; - - #[salsa::invoke(crate::lower::trait_environment_query)] - fn trait_environment(&self, def: GenericDefId) -> Arc; - - #[salsa::invoke(crate::lower::generic_defaults_query)] - #[salsa::cycle(crate::lower::generic_defaults_recover)] - fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders]>; - - #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)] - fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc; - - #[salsa::invoke(InherentImpls::inherent_impls_in_block_query)] - fn inherent_impls_in_block(&self, block: BlockId) -> Option>; - - /// Collects all crates in the dependency graph that have impls for the - /// given fingerprint. This is only used for primitive types; for - /// user-defined types we just look at the crate where the type is defined. - #[salsa::invoke(crate::method_resolution::inherent_impl_crates_query)] - fn inherent_impl_crates(&self, krate: CrateId, fp: TyFingerprint) -> ArrayVec; - - #[salsa::invoke(TraitImpls::trait_impls_in_crate_query)] - fn trait_impls_in_crate(&self, krate: CrateId) -> Arc; - - #[salsa::invoke(TraitImpls::trait_impls_in_block_query)] - fn trait_impls_in_block(&self, krate: BlockId) -> Option>; - - #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)] - fn trait_impls_in_deps(&self, krate: CrateId) -> Arc; - - // Interned IDs for Chalk integration - #[salsa::interned] - fn intern_callable_def(&self, callable_def: CallableDefId) -> InternedCallableDefId; - #[salsa::interned] - fn intern_type_or_const_param_id( - &self, - param_id: TypeOrConstParamId, - ) -> InternedTypeOrConstParamId; - #[salsa::interned] - fn intern_lifetime_param_id(&self, param_id: LifetimeParamId) -> InternedLifetimeParamId; - #[salsa::interned] - fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId; - #[salsa::interned] - fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId; - - #[salsa::invoke(chalk_db::associated_ty_data_query)] - fn associated_ty_data(&self, id: chalk_db::AssocTypeId) -> Arc; - - #[salsa::invoke(chalk_db::trait_datum_query)] - fn trait_datum(&self, krate: CrateId, trait_id: chalk_db::TraitId) - -> Arc; - - #[salsa::invoke(chalk_db::struct_datum_query)] - fn struct_datum( - &self, - krate: CrateId, - struct_id: chalk_db::AdtId, - ) -> Arc; - - #[salsa::invoke(chalk_db::impl_datum_query)] - fn impl_datum(&self, krate: CrateId, impl_id: chalk_db::ImplId) -> Arc; - - #[salsa::invoke(chalk_db::fn_def_datum_query)] - fn fn_def_datum(&self, krate: CrateId, fn_def_id: FnDefId) -> Arc; - - #[salsa::invoke(chalk_db::fn_def_variance_query)] - fn fn_def_variance(&self, fn_def_id: FnDefId) -> chalk_db::Variances; - - #[salsa::invoke(chalk_db::adt_variance_query)] - fn adt_variance(&self, adt_id: chalk_db::AdtId) -> chalk_db::Variances; - - #[salsa::invoke(chalk_db::associated_ty_value_query)] - fn associated_ty_value( - &self, - krate: CrateId, - id: chalk_db::AssociatedTyValueId, - ) -> Arc; - - #[salsa::invoke(trait_solve_wait)] - #[salsa::transparent] - fn trait_solve( - &self, - krate: CrateId, - goal: crate::Canonical>, - ) -> Option; - - #[salsa::invoke(crate::traits::trait_solve_query)] - fn trait_solve_query( - &self, - krate: CrateId, - goal: crate::Canonical>, - ) -> Option; - - #[salsa::invoke(chalk_db::program_clauses_for_chalk_env_query)] - fn program_clauses_for_chalk_env( - &self, - krate: CrateId, - env: chalk_ir::Environment, - ) -> chalk_ir::ProgramClauses; -} - -fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { - let _p = profile::span("infer:wait").detail(|| match def { - DefWithBodyId::FunctionId(it) => db.function_data(it).name.to_string(), - DefWithBodyId::StaticId(it) => db.static_data(it).name.clone().to_string(), - DefWithBodyId::ConstId(it) => { - db.const_data(it).name.clone().unwrap_or_else(Name::missing).to_string() - } - }); - db.infer_query(def) -} - -fn trait_solve_wait( - db: &dyn HirDatabase, - krate: CrateId, - goal: crate::Canonical>, -) -> Option { - let _p = profile::span("trait_solve::wait"); - db.trait_solve_query(krate, goal) -} - -#[test] -fn hir_database_is_object_safe() { - fn _assert_object_safe(_: &dyn HirDatabase) {} -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct InternedTypeOrConstParamId(salsa::InternId); -impl_intern_key!(InternedTypeOrConstParamId); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct InternedLifetimeParamId(salsa::InternId); -impl_intern_key!(InternedLifetimeParamId); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct InternedConstParamId(salsa::InternId); -impl_intern_key!(InternedConstParamId); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct InternedOpaqueTyId(salsa::InternId); -impl_intern_key!(InternedOpaqueTyId); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct InternedClosureId(salsa::InternId); -impl_intern_key!(InternedClosureId); - -/// This exists just for Chalk, because Chalk just has a single `FnDefId` where -/// we have different IDs for struct and enum variant constructors. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] -pub struct InternedCallableDefId(salsa::InternId); -impl_intern_key!(InternedCallableDefId); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs deleted file mode 100644 index 37eb06be1d3d1..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! Type inference-based diagnostics. -mod expr; -mod match_check; -mod unsafe_check; -mod decl_check; - -pub use crate::diagnostics::{ - decl_check::{incorrect_case, IncorrectCase}, - expr::{ - record_literal_missing_fields, record_pattern_missing_fields, BodyValidationDiagnostic, - }, - unsafe_check::{missing_unsafe, unsafe_expressions, UnsafeExpr}, -}; 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 deleted file mode 100644 index f7031a8546a29..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ /dev/null @@ -1,701 +0,0 @@ -//! Provides validators for names of declarations. -//! -//! This includes the following items: -//! -//! - variable bindings (e.g. `let x = foo();`) -//! - struct fields (e.g. `struct Foo { field: u8 }`) -//! - enum variants (e.g. `enum Foo { Variant { field: u8 } }`) -//! - function/method arguments (e.g. `fn foo(arg: u8)`) -//! - constants (e.g. `const FOO: u8 = 10;`) -//! - static items (e.g. `static FOO: u8 = 10;`) -//! - match arm bindings (e.g. `foo @ Some(_)`) - -mod case_conv; - -use std::fmt; - -use base_db::CrateId; -use hir_def::{ - adt::VariantData, - expr::{Pat, PatId}, - src::HasSource, - AdtId, AttrDefId, ConstId, EnumId, FunctionId, ItemContainerId, Lookup, ModuleDefId, StaticId, - StructId, -}; -use hir_expand::{ - name::{AsName, Name}, - HirFileId, -}; -use stdx::{always, never}; -use syntax::{ - ast::{self, HasName}, - AstNode, AstPtr, -}; - -use crate::db::HirDatabase; - -use self::case_conv::{to_camel_case, to_lower_snake_case, to_upper_snake_case}; - -mod allow { - pub(super) const BAD_STYLE: &str = "bad_style"; - pub(super) const NONSTANDARD_STYLE: &str = "nonstandard_style"; - pub(super) const NON_SNAKE_CASE: &str = "non_snake_case"; - pub(super) const NON_UPPER_CASE_GLOBAL: &str = "non_upper_case_globals"; - pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types"; -} - -pub fn incorrect_case( - db: &dyn HirDatabase, - krate: CrateId, - owner: ModuleDefId, -) -> Vec { - let _p = profile::span("validate_module_item"); - let mut validator = DeclValidator::new(db, krate); - validator.validate_item(owner); - validator.sink -} - -#[derive(Debug)] -pub enum CaseType { - // `some_var` - LowerSnakeCase, - // `SOME_CONST` - UpperSnakeCase, - // `SomeStruct` - UpperCamelCase, -} - -impl fmt::Display for CaseType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let repr = match self { - CaseType::LowerSnakeCase => "snake_case", - CaseType::UpperSnakeCase => "UPPER_SNAKE_CASE", - CaseType::UpperCamelCase => "CamelCase", - }; - - repr.fmt(f) - } -} - -#[derive(Debug)] -pub enum IdentType { - Constant, - Enum, - Field, - Function, - Parameter, - StaticVariable, - Structure, - Variable, - Variant, -} - -impl fmt::Display for IdentType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let repr = match self { - IdentType::Constant => "Constant", - IdentType::Enum => "Enum", - IdentType::Field => "Field", - IdentType::Function => "Function", - IdentType::Parameter => "Parameter", - IdentType::StaticVariable => "Static variable", - IdentType::Structure => "Structure", - IdentType::Variable => "Variable", - IdentType::Variant => "Variant", - }; - - repr.fmt(f) - } -} - -#[derive(Debug)] -pub struct IncorrectCase { - pub file: HirFileId, - pub ident: AstPtr, - pub expected_case: CaseType, - pub ident_type: IdentType, - pub ident_text: String, - pub suggested_text: String, -} - -pub(super) struct DeclValidator<'a> { - db: &'a dyn HirDatabase, - krate: CrateId, - pub(super) sink: Vec, -} - -#[derive(Debug)] -struct Replacement { - current_name: Name, - suggested_text: String, - expected_case: CaseType, -} - -impl<'a> DeclValidator<'a> { - pub(super) fn new(db: &'a dyn HirDatabase, krate: CrateId) -> DeclValidator<'a> { - DeclValidator { db, krate, sink: Vec::new() } - } - - pub(super) fn validate_item(&mut self, item: ModuleDefId) { - match item { - ModuleDefId::FunctionId(func) => self.validate_func(func), - ModuleDefId::AdtId(adt) => self.validate_adt(adt), - ModuleDefId::ConstId(const_id) => self.validate_const(const_id), - ModuleDefId::StaticId(static_id) => self.validate_static(static_id), - _ => (), - } - } - - fn validate_adt(&mut self, adt: AdtId) { - match adt { - AdtId::StructId(struct_id) => self.validate_struct(struct_id), - AdtId::EnumId(enum_id) => self.validate_enum(enum_id), - AdtId::UnionId(_) => { - // FIXME: Unions aren't yet supported by this validator. - } - } - } - - /// Checks whether not following the convention is allowed for this item. - fn allowed(&self, id: AttrDefId, allow_name: &str, recursing: bool) -> bool { - let is_allowed = |def_id| { - let attrs = self.db.attrs(def_id); - // don't bug the user about directly no_mangle annotated stuff, they can't do anything about it - (!recursing && attrs.by_key("no_mangle").exists()) - || attrs.by_key("allow").tt_values().any(|tt| { - let allows = tt.to_string(); - allows.contains(allow_name) - || allows.contains(allow::BAD_STYLE) - || allows.contains(allow::NONSTANDARD_STYLE) - }) - }; - - is_allowed(id) - // go upwards one step or give up - || match id { - AttrDefId::ModuleId(m) => m.containing_module(self.db.upcast()).map(|v| v.into()), - AttrDefId::FunctionId(f) => Some(f.lookup(self.db.upcast()).container.into()), - AttrDefId::StaticId(sid) => Some(sid.lookup(self.db.upcast()).container.into()), - AttrDefId::ConstId(cid) => Some(cid.lookup(self.db.upcast()).container.into()), - AttrDefId::TraitId(tid) => Some(tid.lookup(self.db.upcast()).container.into()), - AttrDefId::ImplId(iid) => Some(iid.lookup(self.db.upcast()).container.into()), - AttrDefId::ExternBlockId(id) => Some(id.lookup(self.db.upcast()).container.into()), - // These warnings should not explore macro definitions at all - AttrDefId::MacroId(_) => None, - AttrDefId::AdtId(aid) => match aid { - AdtId::StructId(sid) => Some(sid.lookup(self.db.upcast()).container.into()), - AdtId::EnumId(eid) => Some(eid.lookup(self.db.upcast()).container.into()), - // Unions aren't yet supported - AdtId::UnionId(_) => None, - }, - AttrDefId::FieldId(_) => None, - AttrDefId::EnumVariantId(_) => None, - AttrDefId::TypeAliasId(_) => None, - AttrDefId::GenericParamId(_) => None, - } - .map(|mid| self.allowed(mid, allow_name, true)) - .unwrap_or(false) - } - - fn validate_func(&mut self, func: FunctionId) { - let data = self.db.function_data(func); - if matches!(func.lookup(self.db.upcast()).container, ItemContainerId::ExternBlockId(_)) { - cov_mark::hit!(extern_func_incorrect_case_ignored); - return; - } - - let body = self.db.body(func.into()); - - // Recursively validate inner scope items, such as static variables and constants. - for (_, block_def_map) in body.blocks(self.db.upcast()) { - for (_, module) in block_def_map.modules() { - for def_id in module.scope.declarations() { - let mut validator = DeclValidator::new(self.db, self.krate); - validator.validate_item(def_id); - } - } - } - - // Check whether non-snake case identifiers are allowed for this function. - if self.allowed(func.into(), allow::NON_SNAKE_CASE, false) { - return; - } - - // Check the function name. - let function_name = data.name.to_string(); - let fn_name_replacement = to_lower_snake_case(&function_name).map(|new_name| Replacement { - current_name: data.name.clone(), - suggested_text: new_name, - expected_case: CaseType::LowerSnakeCase, - }); - - // Check the patterns inside the function body. - // This includes function parameters. - let pats_replacements = body - .pats - .iter() - .filter_map(|(id, pat)| match pat { - Pat::Bind { name, .. } => Some((id, name)), - _ => None, - }) - .filter_map(|(id, bind_name)| { - Some(( - id, - Replacement { - current_name: bind_name.clone(), - suggested_text: to_lower_snake_case(&bind_name.to_string())?, - expected_case: CaseType::LowerSnakeCase, - }, - )) - }) - .collect(); - - // If there is at least one element to spawn a warning on, go to the source map and generate a warning. - if let Some(fn_name_replacement) = fn_name_replacement { - self.create_incorrect_case_diagnostic_for_func(func, fn_name_replacement); - } - - self.create_incorrect_case_diagnostic_for_variables(func, pats_replacements); - } - - /// Given the information about incorrect names in the function declaration, looks up into the source code - /// for exact locations and adds diagnostics into the sink. - fn create_incorrect_case_diagnostic_for_func( - &mut self, - func: FunctionId, - fn_name_replacement: Replacement, - ) { - let fn_loc = func.lookup(self.db.upcast()); - let fn_src = fn_loc.source(self.db.upcast()); - - // Diagnostic for function name. - let ast_ptr = match fn_src.value.name() { - Some(name) => name, - None => { - never!( - "Replacement ({:?}) was generated for a function without a name: {:?}", - fn_name_replacement, - fn_src - ); - return; - } - }; - - let diagnostic = IncorrectCase { - file: fn_src.file_id, - ident_type: IdentType::Function, - ident: AstPtr::new(&ast_ptr), - expected_case: fn_name_replacement.expected_case, - ident_text: fn_name_replacement.current_name.to_string(), - suggested_text: fn_name_replacement.suggested_text, - }; - - self.sink.push(diagnostic); - } - - /// Given the information about incorrect variable names, looks up into the source code - /// for exact locations and adds diagnostics into the sink. - fn create_incorrect_case_diagnostic_for_variables( - &mut self, - func: FunctionId, - pats_replacements: Vec<(PatId, Replacement)>, - ) { - // XXX: only look at source_map if we do have missing fields - if pats_replacements.is_empty() { - return; - } - - let (_, source_map) = self.db.body_with_source_map(func.into()); - - for (id, replacement) in pats_replacements { - if let Ok(source_ptr) = source_map.pat_syntax(id) { - if let Some(expr) = source_ptr.value.as_ref().left() { - let root = source_ptr.file_syntax(self.db.upcast()); - if let ast::Pat::IdentPat(ident_pat) = expr.to_node(&root) { - let parent = match ident_pat.syntax().parent() { - Some(parent) => parent, - None => continue, - }; - let name_ast = match ident_pat.name() { - Some(name_ast) => name_ast, - None => continue, - }; - - let is_param = ast::Param::can_cast(parent.kind()); - - // We have to check that it's either `let var = ...` or `var @ Variant(_)` statement, - // because e.g. match arms are patterns as well. - // In other words, we check that it's a named variable binding. - let is_binding = ast::LetStmt::can_cast(parent.kind()) - || (ast::MatchArm::can_cast(parent.kind()) - && ident_pat.at_token().is_some()); - if !(is_param || is_binding) { - // This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm. - continue; - } - - let ident_type = - if is_param { IdentType::Parameter } else { IdentType::Variable }; - - let diagnostic = IncorrectCase { - file: source_ptr.file_id, - ident_type, - ident: AstPtr::new(&name_ast), - expected_case: replacement.expected_case, - ident_text: replacement.current_name.to_string(), - suggested_text: replacement.suggested_text, - }; - - self.sink.push(diagnostic); - } - } - } - } - } - - fn validate_struct(&mut self, struct_id: StructId) { - let data = self.db.struct_data(struct_id); - - let non_camel_case_allowed = - self.allowed(struct_id.into(), allow::NON_CAMEL_CASE_TYPES, false); - let non_snake_case_allowed = self.allowed(struct_id.into(), allow::NON_SNAKE_CASE, false); - - // Check the structure name. - let struct_name = data.name.to_string(); - let struct_name_replacement = if !non_camel_case_allowed { - to_camel_case(&struct_name).map(|new_name| Replacement { - current_name: data.name.clone(), - suggested_text: new_name, - expected_case: CaseType::UpperCamelCase, - }) - } else { - None - }; - - // Check the field names. - let mut struct_fields_replacements = Vec::new(); - - if !non_snake_case_allowed { - if let VariantData::Record(fields) = data.variant_data.as_ref() { - for (_, field) in fields.iter() { - let field_name = field.name.to_string(); - if let Some(new_name) = to_lower_snake_case(&field_name) { - let replacement = Replacement { - current_name: field.name.clone(), - suggested_text: new_name, - expected_case: CaseType::LowerSnakeCase, - }; - struct_fields_replacements.push(replacement); - } - } - } - } - - // If there is at least one element to spawn a warning on, go to the source map and generate a warning. - self.create_incorrect_case_diagnostic_for_struct( - struct_id, - struct_name_replacement, - struct_fields_replacements, - ); - } - - /// Given the information about incorrect names in the struct declaration, looks up into the source code - /// for exact locations and adds diagnostics into the sink. - fn create_incorrect_case_diagnostic_for_struct( - &mut self, - struct_id: StructId, - struct_name_replacement: Option, - struct_fields_replacements: Vec, - ) { - // XXX: Only look at sources if we do have incorrect names. - if struct_name_replacement.is_none() && struct_fields_replacements.is_empty() { - return; - } - - let struct_loc = struct_id.lookup(self.db.upcast()); - let struct_src = struct_loc.source(self.db.upcast()); - - if let Some(replacement) = struct_name_replacement { - let ast_ptr = match struct_src.value.name() { - Some(name) => name, - None => { - never!( - "Replacement ({:?}) was generated for a structure without a name: {:?}", - replacement, - struct_src - ); - return; - } - }; - - let diagnostic = IncorrectCase { - file: struct_src.file_id, - ident_type: IdentType::Structure, - ident: AstPtr::new(&ast_ptr), - expected_case: replacement.expected_case, - ident_text: replacement.current_name.to_string(), - suggested_text: replacement.suggested_text, - }; - - self.sink.push(diagnostic); - } - - let struct_fields_list = match struct_src.value.field_list() { - Some(ast::FieldList::RecordFieldList(fields)) => fields, - _ => { - always!( - struct_fields_replacements.is_empty(), - "Replacements ({:?}) were generated for a structure fields which had no fields list: {:?}", - struct_fields_replacements, - struct_src - ); - return; - } - }; - let mut struct_fields_iter = struct_fields_list.fields(); - for field_to_rename in struct_fields_replacements { - // We assume that parameters in replacement are in the same order as in the - // actual params list, but just some of them (ones that named correctly) are skipped. - let ast_ptr = loop { - match struct_fields_iter.next().and_then(|field| field.name()) { - Some(field_name) => { - if field_name.as_name() == field_to_rename.current_name { - break field_name; - } - } - None => { - never!( - "Replacement ({:?}) was generated for a structure field which was not found: {:?}", - field_to_rename, struct_src - ); - return; - } - } - }; - - let diagnostic = IncorrectCase { - file: struct_src.file_id, - ident_type: IdentType::Field, - ident: AstPtr::new(&ast_ptr), - expected_case: field_to_rename.expected_case, - ident_text: field_to_rename.current_name.to_string(), - suggested_text: field_to_rename.suggested_text, - }; - - self.sink.push(diagnostic); - } - } - - fn validate_enum(&mut self, enum_id: EnumId) { - let data = self.db.enum_data(enum_id); - - // Check whether non-camel case names are allowed for this enum. - if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES, false) { - return; - } - - // Check the enum name. - let enum_name = data.name.to_string(); - let enum_name_replacement = to_camel_case(&enum_name).map(|new_name| Replacement { - current_name: data.name.clone(), - suggested_text: new_name, - expected_case: CaseType::UpperCamelCase, - }); - - // Check the field names. - let enum_fields_replacements = data - .variants - .iter() - .filter_map(|(_, variant)| { - Some(Replacement { - current_name: variant.name.clone(), - suggested_text: to_camel_case(&variant.name.to_string())?, - expected_case: CaseType::UpperCamelCase, - }) - }) - .collect(); - - // If there is at least one element to spawn a warning on, go to the source map and generate a warning. - self.create_incorrect_case_diagnostic_for_enum( - enum_id, - enum_name_replacement, - enum_fields_replacements, - ) - } - - /// Given the information about incorrect names in the struct declaration, looks up into the source code - /// for exact locations and adds diagnostics into the sink. - fn create_incorrect_case_diagnostic_for_enum( - &mut self, - enum_id: EnumId, - enum_name_replacement: Option, - enum_variants_replacements: Vec, - ) { - // XXX: only look at sources if we do have incorrect names - if enum_name_replacement.is_none() && enum_variants_replacements.is_empty() { - return; - } - - let enum_loc = enum_id.lookup(self.db.upcast()); - let enum_src = enum_loc.source(self.db.upcast()); - - if let Some(replacement) = enum_name_replacement { - let ast_ptr = match enum_src.value.name() { - Some(name) => name, - None => { - never!( - "Replacement ({:?}) was generated for a enum without a name: {:?}", - replacement, - enum_src - ); - return; - } - }; - - let diagnostic = IncorrectCase { - file: enum_src.file_id, - ident_type: IdentType::Enum, - ident: AstPtr::new(&ast_ptr), - expected_case: replacement.expected_case, - ident_text: replacement.current_name.to_string(), - suggested_text: replacement.suggested_text, - }; - - self.sink.push(diagnostic); - } - - let enum_variants_list = match enum_src.value.variant_list() { - Some(variants) => variants, - _ => { - always!( - enum_variants_replacements.is_empty(), - "Replacements ({:?}) were generated for a enum variants which had no fields list: {:?}", - enum_variants_replacements, - enum_src - ); - return; - } - }; - let mut enum_variants_iter = enum_variants_list.variants(); - for variant_to_rename in enum_variants_replacements { - // We assume that parameters in replacement are in the same order as in the - // actual params list, but just some of them (ones that named correctly) are skipped. - let ast_ptr = loop { - match enum_variants_iter.next().and_then(|v| v.name()) { - Some(variant_name) => { - if variant_name.as_name() == variant_to_rename.current_name { - break variant_name; - } - } - None => { - never!( - "Replacement ({:?}) was generated for a enum variant which was not found: {:?}", - variant_to_rename, enum_src - ); - return; - } - } - }; - - let diagnostic = IncorrectCase { - file: enum_src.file_id, - ident_type: IdentType::Variant, - ident: AstPtr::new(&ast_ptr), - expected_case: variant_to_rename.expected_case, - ident_text: variant_to_rename.current_name.to_string(), - suggested_text: variant_to_rename.suggested_text, - }; - - self.sink.push(diagnostic); - } - } - - fn validate_const(&mut self, const_id: ConstId) { - let data = self.db.const_data(const_id); - - if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) { - return; - } - - let name = match &data.name { - Some(name) => name, - None => return, - }; - - let const_name = name.to_string(); - let replacement = if let Some(new_name) = to_upper_snake_case(&const_name) { - Replacement { - current_name: name.clone(), - suggested_text: new_name, - expected_case: CaseType::UpperSnakeCase, - } - } else { - // Nothing to do here. - return; - }; - - let const_loc = const_id.lookup(self.db.upcast()); - let const_src = const_loc.source(self.db.upcast()); - - let ast_ptr = match const_src.value.name() { - Some(name) => name, - None => return, - }; - - let diagnostic = IncorrectCase { - file: const_src.file_id, - ident_type: IdentType::Constant, - ident: AstPtr::new(&ast_ptr), - expected_case: replacement.expected_case, - ident_text: replacement.current_name.to_string(), - suggested_text: replacement.suggested_text, - }; - - self.sink.push(diagnostic); - } - - fn validate_static(&mut self, static_id: StaticId) { - let data = self.db.static_data(static_id); - if data.is_extern { - cov_mark::hit!(extern_static_incorrect_case_ignored); - return; - } - - if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) { - return; - } - - let name = &data.name; - - let static_name = name.to_string(); - let replacement = if let Some(new_name) = to_upper_snake_case(&static_name) { - Replacement { - current_name: name.clone(), - suggested_text: new_name, - expected_case: CaseType::UpperSnakeCase, - } - } else { - // Nothing to do here. - return; - }; - - let static_loc = static_id.lookup(self.db.upcast()); - let static_src = static_loc.source(self.db.upcast()); - - let ast_ptr = match static_src.value.name() { - Some(name) => name, - None => return, - }; - - let diagnostic = IncorrectCase { - file: static_src.file_id, - ident_type: IdentType::StaticVariable, - ident: AstPtr::new(&ast_ptr), - expected_case: replacement.expected_case, - ident_text: replacement.current_name.to_string(), - suggested_text: replacement.suggested_text, - }; - - self.sink.push(diagnostic); - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs deleted file mode 100644 index 88d607194f756..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs +++ /dev/null @@ -1,199 +0,0 @@ -//! Functions for string case manipulation, such as detecting the identifier case, -//! and converting it into appropriate form. - -// Code that was taken from rustc was taken at commit 89fdb30, -// from file /compiler/rustc_lint/src/nonstandard_style.rs - -/// Converts an identifier to an UpperCamelCase form. -/// Returns `None` if the string is already in UpperCamelCase. -pub(crate) fn to_camel_case(ident: &str) -> Option { - if is_camel_case(ident) { - return None; - } - - // Taken from rustc. - let ret = ident - .trim_matches('_') - .split('_') - .filter(|component| !component.is_empty()) - .map(|component| { - let mut camel_cased_component = String::with_capacity(component.len()); - - let mut new_word = true; - let mut prev_is_lower_case = true; - - for c in component.chars() { - // Preserve the case if an uppercase letter follows a lowercase letter, so that - // `camelCase` is converted to `CamelCase`. - if prev_is_lower_case && c.is_uppercase() { - new_word = true; - } - - if new_word { - camel_cased_component.extend(c.to_uppercase()); - } else { - camel_cased_component.extend(c.to_lowercase()); - } - - prev_is_lower_case = c.is_lowercase(); - new_word = false; - } - - camel_cased_component - }) - .fold((String::new(), None), |(acc, prev): (_, Option), next| { - // separate two components with an underscore if their boundary cannot - // be distinguished using an uppercase/lowercase case distinction - let join = prev - .and_then(|prev| { - let f = next.chars().next()?; - let l = prev.chars().last()?; - Some(!char_has_case(l) && !char_has_case(f)) - }) - .unwrap_or(false); - (acc + if join { "_" } else { "" } + &next, Some(next)) - }) - .0; - Some(ret) -} - -/// Converts an identifier to a lower_snake_case form. -/// Returns `None` if the string is already in lower_snake_case. -pub(crate) fn to_lower_snake_case(ident: &str) -> Option { - if is_lower_snake_case(ident) { - return None; - } else if is_upper_snake_case(ident) { - return Some(ident.to_lowercase()); - } - - Some(stdx::to_lower_snake_case(ident)) -} - -/// Converts an identifier to an UPPER_SNAKE_CASE form. -/// Returns `None` if the string is already is UPPER_SNAKE_CASE. -pub(crate) fn to_upper_snake_case(ident: &str) -> Option { - if is_upper_snake_case(ident) { - return None; - } else if is_lower_snake_case(ident) { - return Some(ident.to_uppercase()); - } - - Some(stdx::to_upper_snake_case(ident)) -} - -// Taken from rustc. -// Modified by replacing the use of unstable feature `array_windows`. -fn is_camel_case(name: &str) -> bool { - let name = name.trim_matches('_'); - if name.is_empty() { - return true; - } - - let mut fst = None; - // start with a non-lowercase letter rather than non-uppercase - // ones (some scripts don't have a concept of upper/lowercase) - name.chars().next().map_or(true, |c| !c.is_lowercase()) - && !name.contains("__") - && !name.chars().any(|snd| { - let ret = match fst { - None => false, - Some(fst) => char_has_case(fst) && snd == '_' || char_has_case(snd) && fst == '_', - }; - fst = Some(snd); - - ret - }) -} - -fn is_lower_snake_case(ident: &str) -> bool { - is_snake_case(ident, char::is_uppercase) -} - -fn is_upper_snake_case(ident: &str) -> bool { - is_snake_case(ident, char::is_lowercase) -} - -// Taken from rustc. -// Modified to allow checking for both upper and lower snake case. -fn is_snake_case bool>(ident: &str, wrong_case: F) -> bool { - if ident.is_empty() { - return true; - } - let ident = ident.trim_matches('_'); - - let mut allow_underscore = true; - ident.chars().all(|c| { - allow_underscore = match c { - '_' if !allow_underscore => return false, - '_' => false, - // It would be more obvious to check for the correct case, - // but some characters do not have a case. - c if !wrong_case(c) => true, - _ => return false, - }; - true - }) -} - -// Taken from rustc. -fn char_has_case(c: char) -> bool { - c.is_lowercase() || c.is_uppercase() -} - -#[cfg(test)] -mod tests { - use super::*; - use expect_test::{expect, Expect}; - - fn check Option>(fun: F, input: &str, expect: Expect) { - // `None` is translated to empty string, meaning that there is nothing to fix. - let output = fun(input).unwrap_or_default(); - - expect.assert_eq(&output); - } - - #[test] - fn test_to_lower_snake_case() { - check(to_lower_snake_case, "lower_snake_case", expect![[""]]); - check(to_lower_snake_case, "UPPER_SNAKE_CASE", expect![["upper_snake_case"]]); - check(to_lower_snake_case, "Weird_Case", expect![["weird_case"]]); - check(to_lower_snake_case, "CamelCase", expect![["camel_case"]]); - check(to_lower_snake_case, "lowerCamelCase", expect![["lower_camel_case"]]); - check(to_lower_snake_case, "a", expect![[""]]); - check(to_lower_snake_case, "abc", expect![[""]]); - check(to_lower_snake_case, "foo__bar", expect![["foo_bar"]]); - } - - #[test] - fn test_to_camel_case() { - check(to_camel_case, "CamelCase", expect![[""]]); - check(to_camel_case, "CamelCase_", expect![[""]]); - check(to_camel_case, "_CamelCase", expect![[""]]); - check(to_camel_case, "lowerCamelCase", expect![["LowerCamelCase"]]); - check(to_camel_case, "lower_snake_case", expect![["LowerSnakeCase"]]); - check(to_camel_case, "UPPER_SNAKE_CASE", expect![["UpperSnakeCase"]]); - check(to_camel_case, "Weird_Case", expect![["WeirdCase"]]); - check(to_camel_case, "name", expect![["Name"]]); - check(to_camel_case, "A", expect![[""]]); - check(to_camel_case, "AABB", expect![[""]]); - // Taken from rustc: /compiler/rustc_lint/src/nonstandard_style/tests.rs - check(to_camel_case, "X86_64", expect![[""]]); - check(to_camel_case, "x86__64", expect![["X86_64"]]); - check(to_camel_case, "Abc_123", expect![["Abc123"]]); - check(to_camel_case, "A1_b2_c3", expect![["A1B2C3"]]); - } - - #[test] - fn test_to_upper_snake_case() { - check(to_upper_snake_case, "UPPER_SNAKE_CASE", expect![[""]]); - check(to_upper_snake_case, "lower_snake_case", expect![["LOWER_SNAKE_CASE"]]); - check(to_upper_snake_case, "Weird_Case", expect![["WEIRD_CASE"]]); - check(to_upper_snake_case, "CamelCase", expect![["CAMEL_CASE"]]); - check(to_upper_snake_case, "lowerCamelCase", expect![["LOWER_CAMEL_CASE"]]); - check(to_upper_snake_case, "A", expect![[""]]); - check(to_upper_snake_case, "ABC", expect![[""]]); - check(to_upper_snake_case, "X86_64", expect![[""]]); - check(to_upper_snake_case, "FOO_BAr", expect![["FOO_BAR"]]); - check(to_upper_snake_case, "FOO__BAR", expect![["FOO_BAR"]]); - } -} 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 deleted file mode 100644 index 642e03edd2306..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ /dev/null @@ -1,416 +0,0 @@ -//! Various diagnostics for expressions that are collected together in one pass -//! through the body using inference results: mismatched arg counts, missing -//! fields, etc. - -use std::fmt; -use std::sync::Arc; - -use hir_def::{path::path, resolver::HasResolver, AdtId, AssocItemId, DefWithBodyId, HasModule}; -use hir_expand::name; -use itertools::Either; -use itertools::Itertools; -use rustc_hash::FxHashSet; -use typed_arena::Arena; - -use crate::{ - db::HirDatabase, - diagnostics::match_check::{ - self, - deconstruct_pat::DeconstructedPat, - usefulness::{compute_match_usefulness, MatchCheckCtx}, - }, - display::HirDisplay, - InferenceResult, Ty, TyExt, -}; - -pub(crate) use hir_def::{ - body::Body, - expr::{Expr, ExprId, MatchArm, Pat, PatId}, - LocalFieldId, VariantId, -}; - -pub enum BodyValidationDiagnostic { - RecordMissingFields { - record: Either, - variant: VariantId, - missed_fields: Vec, - }, - ReplaceFilterMapNextWithFindMap { - method_call_expr: ExprId, - }, - MissingMatchArms { - match_expr: ExprId, - uncovered_patterns: String, - }, -} - -impl BodyValidationDiagnostic { - pub fn collect(db: &dyn HirDatabase, owner: DefWithBodyId) -> Vec { - let _p = profile::span("BodyValidationDiagnostic::collect"); - let infer = db.infer(owner); - let mut validator = ExprValidator::new(owner, infer); - validator.validate_body(db); - validator.diagnostics - } -} - -struct ExprValidator { - owner: DefWithBodyId, - infer: Arc, - pub(super) diagnostics: Vec, -} - -impl ExprValidator { - fn new(owner: DefWithBodyId, infer: Arc) -> ExprValidator { - ExprValidator { owner, infer, diagnostics: Vec::new() } - } - - fn validate_body(&mut self, db: &dyn HirDatabase) { - let body = db.body(self.owner); - let mut filter_map_next_checker = None; - - for (id, expr) in body.exprs.iter() { - if let Some((variant, missed_fields, true)) = - record_literal_missing_fields(db, &self.infer, id, expr) - { - self.diagnostics.push(BodyValidationDiagnostic::RecordMissingFields { - record: Either::Left(id), - variant, - missed_fields, - }); - } - - match expr { - Expr::Match { expr, arms } => { - self.validate_match(id, *expr, arms, db, self.infer.clone()); - } - Expr::Call { .. } | Expr::MethodCall { .. } => { - self.validate_call(db, id, expr, &mut filter_map_next_checker); - } - _ => {} - } - } - for (id, pat) in body.pats.iter() { - if let Some((variant, missed_fields, true)) = - record_pattern_missing_fields(db, &self.infer, id, pat) - { - self.diagnostics.push(BodyValidationDiagnostic::RecordMissingFields { - record: Either::Right(id), - variant, - missed_fields, - }); - } - } - } - - fn validate_call( - &mut self, - db: &dyn HirDatabase, - call_id: ExprId, - expr: &Expr, - filter_map_next_checker: &mut Option, - ) { - // Check that the number of arguments matches the number of parameters. - - // FIXME: Due to shortcomings in the current type system implementation, only emit this - // diagnostic if there are no type mismatches in the containing function. - if self.infer.expr_type_mismatches().next().is_some() { - return; - } - - match expr { - Expr::MethodCall { receiver, .. } => { - let (callee, _) = match self.infer.method_resolution(call_id) { - Some(it) => it, - None => return, - }; - - if filter_map_next_checker - .get_or_insert_with(|| { - FilterMapNextChecker::new(&self.owner.resolver(db.upcast()), db) - }) - .check(call_id, receiver, &callee) - .is_some() - { - self.diagnostics.push( - BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { - method_call_expr: call_id, - }, - ); - } - } - _ => return, - }; - } - - fn validate_match( - &mut self, - id: ExprId, - match_expr: ExprId, - arms: &[MatchArm], - db: &dyn HirDatabase, - infer: Arc, - ) { - let body = db.body(self.owner); - - let match_expr_ty = &infer[match_expr]; - if match_expr_ty.is_unknown() { - return; - } - - let pattern_arena = Arena::new(); - let cx = MatchCheckCtx { - module: self.owner.module(db.upcast()), - body: self.owner, - db, - pattern_arena: &pattern_arena, - }; - - let mut m_arms = Vec::with_capacity(arms.len()); - let mut has_lowering_errors = false; - for arm in arms { - if let Some(pat_ty) = infer.type_of_pat.get(arm.pat) { - // We only include patterns whose type matches the type - // of the match expression. If we had an InvalidMatchArmPattern - // diagnostic or similar we could raise that in an else - // block here. - // - // When comparing the types, we also have to consider that rustc - // will automatically de-reference the match expression type if - // necessary. - // - // FIXME we should use the type checker for this. - if (pat_ty == match_expr_ty - || match_expr_ty - .as_reference() - .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty) - .unwrap_or(false)) - && types_of_subpatterns_do_match(arm.pat, &body, &infer) - { - // If we had a NotUsefulMatchArm diagnostic, we could - // check the usefulness of each pattern as we added it - // to the matrix here. - let m_arm = match_check::MatchArm { - pat: self.lower_pattern(&cx, arm.pat, db, &body, &mut has_lowering_errors), - has_guard: arm.guard.is_some(), - }; - m_arms.push(m_arm); - if !has_lowering_errors { - continue; - } - } - } - - // If we can't resolve the type of a pattern, or the pattern type doesn't - // fit the match expression, we skip this diagnostic. Skipping the entire - // diagnostic rather than just not including this match arm is preferred - // to avoid the chance of false positives. - cov_mark::hit!(validate_match_bailed_out); - return; - } - - let report = compute_match_usefulness(&cx, &m_arms, match_expr_ty); - - // FIXME Report unreacheble arms - // https://github.com/rust-lang/rust/blob/f31622a50/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200 - - let witnesses = report.non_exhaustiveness_witnesses; - if !witnesses.is_empty() { - self.diagnostics.push(BodyValidationDiagnostic::MissingMatchArms { - match_expr: id, - uncovered_patterns: missing_match_arms(&cx, match_expr_ty, witnesses, arms), - }); - } - } - - fn lower_pattern<'p>( - &self, - cx: &MatchCheckCtx<'_, 'p>, - pat: PatId, - db: &dyn HirDatabase, - body: &Body, - have_errors: &mut bool, - ) -> &'p DeconstructedPat<'p> { - let mut patcx = match_check::PatCtxt::new(db, &self.infer, body); - let pattern = patcx.lower_pattern(pat); - let pattern = cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern)); - if !patcx.errors.is_empty() { - *have_errors = true; - } - pattern - } -} - -struct FilterMapNextChecker { - filter_map_function_id: Option, - next_function_id: Option, - prev_filter_map_expr_id: Option, -} - -impl FilterMapNextChecker { - fn new(resolver: &hir_def::resolver::Resolver, db: &dyn HirDatabase) -> Self { - // Find and store the FunctionIds for Iterator::filter_map and Iterator::next - let iterator_path = path![core::iter::Iterator]; - let mut filter_map_function_id = None; - let mut next_function_id = None; - - if let Some(iterator_trait_id) = resolver.resolve_known_trait(db.upcast(), &iterator_path) { - let iterator_trait_items = &db.trait_data(iterator_trait_id).items; - for item in iterator_trait_items.iter() { - if let (name, AssocItemId::FunctionId(id)) = item { - if *name == name![filter_map] { - filter_map_function_id = Some(*id); - } - if *name == name![next] { - next_function_id = Some(*id); - } - } - if filter_map_function_id.is_some() && next_function_id.is_some() { - break; - } - } - } - Self { filter_map_function_id, next_function_id, prev_filter_map_expr_id: None } - } - - // check for instances of .filter_map(..).next() - fn check( - &mut self, - current_expr_id: ExprId, - receiver_expr_id: &ExprId, - function_id: &hir_def::FunctionId, - ) -> Option<()> { - if *function_id == self.filter_map_function_id? { - self.prev_filter_map_expr_id = Some(current_expr_id); - return None; - } - - if *function_id == self.next_function_id? { - if let Some(prev_filter_map_expr_id) = self.prev_filter_map_expr_id { - if *receiver_expr_id == prev_filter_map_expr_id { - return Some(()); - } - } - } - - self.prev_filter_map_expr_id = None; - None - } -} - -pub fn record_literal_missing_fields( - db: &dyn HirDatabase, - infer: &InferenceResult, - id: ExprId, - expr: &Expr, -) -> Option<(VariantId, Vec, /*exhaustive*/ bool)> { - let (fields, exhaustive) = match expr { - Expr::RecordLit { fields, spread, ellipsis, is_assignee_expr, .. } => { - let exhaustive = if *is_assignee_expr { !*ellipsis } else { spread.is_none() }; - (fields, exhaustive) - } - _ => return None, - }; - - let variant_def = infer.variant_resolution_for_expr(id)?; - if let VariantId::UnionId(_) = variant_def { - return None; - } - - let variant_data = variant_def.variant_data(db.upcast()); - - let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); - let missed_fields: Vec = variant_data - .fields() - .iter() - .filter_map(|(f, d)| if specified_fields.contains(&d.name) { None } else { Some(f) }) - .collect(); - if missed_fields.is_empty() { - return None; - } - Some((variant_def, missed_fields, exhaustive)) -} - -pub fn record_pattern_missing_fields( - db: &dyn HirDatabase, - infer: &InferenceResult, - id: PatId, - pat: &Pat, -) -> Option<(VariantId, Vec, /*exhaustive*/ bool)> { - let (fields, exhaustive) = match pat { - Pat::Record { path: _, args, ellipsis } => (args, !ellipsis), - _ => return None, - }; - - let variant_def = infer.variant_resolution_for_pat(id)?; - if let VariantId::UnionId(_) = variant_def { - return None; - } - - let variant_data = variant_def.variant_data(db.upcast()); - - let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); - let missed_fields: Vec = variant_data - .fields() - .iter() - .filter_map(|(f, d)| if specified_fields.contains(&d.name) { None } else { Some(f) }) - .collect(); - if missed_fields.is_empty() { - return None; - } - Some((variant_def, missed_fields, exhaustive)) -} - -fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResult) -> bool { - fn walk(pat: PatId, body: &Body, infer: &InferenceResult, has_type_mismatches: &mut bool) { - match infer.type_mismatch_for_pat(pat) { - Some(_) => *has_type_mismatches = true, - None => { - body[pat].walk_child_pats(|subpat| walk(subpat, body, infer, has_type_mismatches)) - } - } - } - - let mut has_type_mismatches = false; - walk(pat, body, infer, &mut has_type_mismatches); - !has_type_mismatches -} - -fn missing_match_arms<'p>( - cx: &MatchCheckCtx<'_, 'p>, - scrut_ty: &Ty, - witnesses: Vec>, - arms: &[MatchArm], -) -> String { - struct DisplayWitness<'a, 'p>(&'a DeconstructedPat<'p>, &'a MatchCheckCtx<'a, 'p>); - impl<'a, 'p> fmt::Display for DisplayWitness<'a, 'p> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let DisplayWitness(witness, cx) = *self; - let pat = witness.to_pat(cx); - write!(f, "{}", pat.display(cx.db)) - } - } - - let non_empty_enum = match scrut_ty.as_adt() { - Some((AdtId::EnumId(e), _)) => !cx.db.enum_data(e).variants.is_empty(), - _ => false, - }; - if arms.is_empty() && !non_empty_enum { - format!("type `{}` is non-empty", scrut_ty.display(cx.db)) - } else { - let pat_display = |witness| DisplayWitness(witness, cx); - const LIMIT: usize = 3; - match &*witnesses { - [witness] => format!("`{}` not covered", pat_display(witness)), - [head @ .., tail] if head.len() < LIMIT => { - let head = head.iter().map(pat_display); - format!("`{}` and `{}` not covered", head.format("`, `"), pat_display(tail)) - } - _ => { - let (head, tail) = witnesses.split_at(LIMIT); - let head = head.iter().map(pat_display); - format!("`{}` and {} more not covered", head.format("`, `"), tail.len()) - } - } - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs deleted file mode 100644 index d51ad72bd27b1..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs +++ /dev/null @@ -1,508 +0,0 @@ -//! Validation of matches. -//! -//! This module provides lowering from [hir_def::expr::Pat] to [self::Pat] and match -//! checking algorithm. -//! -//! It is modeled on the rustc module `rustc_mir_build::thir::pattern`. - -mod pat_util; - -pub(crate) mod deconstruct_pat; -pub(crate) mod usefulness; - -use chalk_ir::Mutability; -use hir_def::{ - adt::VariantData, body::Body, expr::PatId, AdtId, EnumVariantId, HasModule, LocalFieldId, - VariantId, -}; -use hir_expand::name::{name, Name}; -use stdx::{always, never}; - -use crate::{ - db::HirDatabase, - display::{HirDisplay, HirDisplayError, HirFormatter}, - infer::BindingMode, - InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, -}; - -use self::pat_util::EnumerateAndAdjustIterator; - -pub(crate) use self::usefulness::MatchArm; - -#[derive(Clone, Debug)] -pub(crate) enum PatternError { - Unimplemented, - UnexpectedType, - UnresolvedVariant, - MissingField, - ExtraFields, -} - -#[derive(Clone, Debug, PartialEq)] -pub(crate) struct FieldPat { - pub(crate) field: LocalFieldId, - pub(crate) pattern: Pat, -} - -#[derive(Clone, Debug, PartialEq)] -pub(crate) struct Pat { - pub(crate) ty: Ty, - pub(crate) kind: Box, -} - -/// Close relative to `rustc_mir_build::thir::pattern::PatKind` -#[derive(Clone, Debug, PartialEq)] -pub(crate) enum PatKind { - Wild, - - /// `x`, `ref x`, `x @ P`, etc. - Binding { - name: Name, - subpattern: Option, - }, - - /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with - /// multiple variants. - Variant { - substs: Substitution, - enum_variant: EnumVariantId, - subpatterns: Vec, - }, - - /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with - /// a single variant. - Leaf { - subpatterns: Vec, - }, - - /// `box P`, `&P`, `&mut P`, etc. - Deref { - subpattern: Pat, - }, - - // FIXME: for now, only bool literals are implemented - LiteralBool { - value: bool, - }, - - /// An or-pattern, e.g. `p | q`. - /// Invariant: `pats.len() >= 2`. - Or { - pats: Vec, - }, -} - -pub(crate) struct PatCtxt<'a> { - db: &'a dyn HirDatabase, - infer: &'a InferenceResult, - body: &'a Body, - pub(crate) errors: Vec, -} - -impl<'a> PatCtxt<'a> { - pub(crate) fn new(db: &'a dyn HirDatabase, infer: &'a InferenceResult, body: &'a Body) -> Self { - Self { db, infer, body, errors: Vec::new() } - } - - pub(crate) fn lower_pattern(&mut self, pat: PatId) -> Pat { - // XXX(iDawer): Collecting pattern adjustments feels imprecise to me. - // When lowering of & and box patterns are implemented this should be tested - // in a manner of `match_ergonomics_issue_9095` test. - // Pattern adjustment is part of RFC 2005-match-ergonomics. - // More info https://github.com/rust-lang/rust/issues/42640#issuecomment-313535089 - let unadjusted_pat = self.lower_pattern_unadjusted(pat); - self.infer.pat_adjustments.get(&pat).map(|it| &**it).unwrap_or_default().iter().rev().fold( - unadjusted_pat, - |subpattern, ref_ty| Pat { - ty: ref_ty.clone(), - kind: Box::new(PatKind::Deref { subpattern }), - }, - ) - } - - fn lower_pattern_unadjusted(&mut self, pat: PatId) -> Pat { - let mut ty = &self.infer[pat]; - let variant = self.infer.variant_resolution_for_pat(pat); - - let kind = match self.body[pat] { - hir_def::expr::Pat::Wild => PatKind::Wild, - - hir_def::expr::Pat::Lit(expr) => self.lower_lit(expr), - - hir_def::expr::Pat::Path(ref path) => { - return self.lower_path(pat, path); - } - - hir_def::expr::Pat::Tuple { ref args, ellipsis } => { - let arity = match *ty.kind(Interner) { - TyKind::Tuple(arity, _) => arity, - _ => { - never!("unexpected type for tuple pattern: {:?}", ty); - self.errors.push(PatternError::UnexpectedType); - return Pat { ty: ty.clone(), kind: PatKind::Wild.into() }; - } - }; - let subpatterns = self.lower_tuple_subpats(args, arity, ellipsis); - PatKind::Leaf { subpatterns } - } - - hir_def::expr::Pat::Bind { ref name, subpat, .. } => { - let bm = self.infer.pat_binding_modes[&pat]; - match (bm, ty.kind(Interner)) { - (BindingMode::Ref(_), TyKind::Ref(.., rty)) => ty = rty, - (BindingMode::Ref(_), _) => { - never!("`ref {}` has wrong type {:?}", name, ty); - self.errors.push(PatternError::UnexpectedType); - return Pat { ty: ty.clone(), kind: PatKind::Wild.into() }; - } - _ => (), - } - PatKind::Binding { name: name.clone(), subpattern: self.lower_opt_pattern(subpat) } - } - - hir_def::expr::Pat::TupleStruct { ref args, ellipsis, .. } if variant.is_some() => { - let expected_len = variant.unwrap().variant_data(self.db.upcast()).fields().len(); - let subpatterns = self.lower_tuple_subpats(args, expected_len, ellipsis); - self.lower_variant_or_leaf(pat, ty, subpatterns) - } - - hir_def::expr::Pat::Record { ref args, .. } if variant.is_some() => { - let variant_data = variant.unwrap().variant_data(self.db.upcast()); - let subpatterns = args - .iter() - .map(|field| { - // XXX(iDawer): field lookup is inefficient - variant_data.field(&field.name).map(|lfield_id| FieldPat { - field: lfield_id, - pattern: self.lower_pattern(field.pat), - }) - }) - .collect(); - match subpatterns { - Some(subpatterns) => self.lower_variant_or_leaf(pat, ty, subpatterns), - None => { - self.errors.push(PatternError::MissingField); - PatKind::Wild - } - } - } - hir_def::expr::Pat::TupleStruct { .. } | hir_def::expr::Pat::Record { .. } => { - self.errors.push(PatternError::UnresolvedVariant); - PatKind::Wild - } - - hir_def::expr::Pat::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) }, - - _ => { - self.errors.push(PatternError::Unimplemented); - PatKind::Wild - } - }; - - Pat { ty: ty.clone(), kind: Box::new(kind) } - } - - fn lower_tuple_subpats( - &mut self, - pats: &[PatId], - expected_len: usize, - ellipsis: Option, - ) -> Vec { - if pats.len() > expected_len { - self.errors.push(PatternError::ExtraFields); - return Vec::new(); - } - - pats.iter() - .enumerate_and_adjust(expected_len, ellipsis) - .map(|(i, &subpattern)| FieldPat { - field: LocalFieldId::from_raw((i as u32).into()), - pattern: self.lower_pattern(subpattern), - }) - .collect() - } - - fn lower_patterns(&mut self, pats: &[PatId]) -> Vec { - pats.iter().map(|&p| self.lower_pattern(p)).collect() - } - - fn lower_opt_pattern(&mut self, pat: Option) -> Option { - pat.map(|p| self.lower_pattern(p)) - } - - fn lower_variant_or_leaf( - &mut self, - pat: PatId, - ty: &Ty, - subpatterns: Vec, - ) -> PatKind { - let kind = match self.infer.variant_resolution_for_pat(pat) { - Some(variant_id) => { - if let VariantId::EnumVariantId(enum_variant) = variant_id { - let substs = match ty.kind(Interner) { - TyKind::Adt(_, substs) => substs.clone(), - kind => { - always!( - matches!(kind, TyKind::FnDef(..) | TyKind::Error), - "inappropriate type for def: {:?}", - ty - ); - self.errors.push(PatternError::UnexpectedType); - return PatKind::Wild; - } - }; - PatKind::Variant { substs, enum_variant, subpatterns } - } else { - PatKind::Leaf { subpatterns } - } - } - None => { - self.errors.push(PatternError::UnresolvedVariant); - PatKind::Wild - } - }; - kind - } - - fn lower_path(&mut self, pat: PatId, _path: &hir_def::path::Path) -> Pat { - let ty = &self.infer[pat]; - - let pat_from_kind = |kind| Pat { ty: ty.clone(), kind: Box::new(kind) }; - - match self.infer.variant_resolution_for_pat(pat) { - Some(_) => pat_from_kind(self.lower_variant_or_leaf(pat, ty, Vec::new())), - None => { - self.errors.push(PatternError::UnresolvedVariant); - pat_from_kind(PatKind::Wild) - } - } - } - - fn lower_lit(&mut self, expr: hir_def::expr::ExprId) -> PatKind { - use hir_def::expr::{Expr, Literal::Bool}; - - match self.body[expr] { - Expr::Literal(Bool(value)) => PatKind::LiteralBool { value }, - _ => { - self.errors.push(PatternError::Unimplemented); - PatKind::Wild - } - } - } -} - -impl HirDisplay for Pat { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match &*self.kind { - PatKind::Wild => write!(f, "_"), - PatKind::Binding { name, subpattern } => { - write!(f, "{name}")?; - if let Some(subpattern) = subpattern { - write!(f, " @ ")?; - subpattern.hir_fmt(f)?; - } - Ok(()) - } - PatKind::Variant { subpatterns, .. } | PatKind::Leaf { subpatterns } => { - let variant = match *self.kind { - PatKind::Variant { enum_variant, .. } => Some(VariantId::from(enum_variant)), - _ => self.ty.as_adt().and_then(|(adt, _)| match adt { - AdtId::StructId(s) => Some(s.into()), - AdtId::UnionId(u) => Some(u.into()), - AdtId::EnumId(_) => None, - }), - }; - - if let Some(variant) = variant { - match variant { - VariantId::EnumVariantId(v) => { - let data = f.db.enum_data(v.parent); - write!(f, "{}", data.variants[v.local_id].name)?; - } - VariantId::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?, - VariantId::UnionId(u) => write!(f, "{}", f.db.union_data(u).name)?, - }; - - let variant_data = variant.variant_data(f.db.upcast()); - if let VariantData::Record(rec_fields) = &*variant_data { - write!(f, " {{ ")?; - - let mut printed = 0; - let subpats = subpatterns - .iter() - .filter(|p| !matches!(*p.pattern.kind, PatKind::Wild)) - .map(|p| { - printed += 1; - WriteWith(move |f| { - write!(f, "{}: ", rec_fields[p.field].name)?; - p.pattern.hir_fmt(f) - }) - }); - f.write_joined(subpats, ", ")?; - - if printed < rec_fields.len() { - write!(f, "{}..", if printed > 0 { ", " } else { "" })?; - } - - return write!(f, " }}"); - } - } - - let num_fields = variant - .map_or(subpatterns.len(), |v| v.variant_data(f.db.upcast()).fields().len()); - if num_fields != 0 || variant.is_none() { - write!(f, "(")?; - let subpats = (0..num_fields).map(|i| { - WriteWith(move |f| { - let fid = LocalFieldId::from_raw((i as u32).into()); - if let Some(p) = subpatterns.get(i) { - if p.field == fid { - return p.pattern.hir_fmt(f); - } - } - if let Some(p) = subpatterns.iter().find(|p| p.field == fid) { - p.pattern.hir_fmt(f) - } else { - write!(f, "_") - } - }) - }); - f.write_joined(subpats, ", ")?; - if let (TyKind::Tuple(..), 1) = (self.ty.kind(Interner), num_fields) { - write!(f, ",")?; - } - write!(f, ")")?; - } - - Ok(()) - } - PatKind::Deref { subpattern } => { - match self.ty.kind(Interner) { - TyKind::Adt(adt, _) if is_box(adt.0, f.db) => write!(f, "box ")?, - &TyKind::Ref(mutbl, ..) => { - write!(f, "&{}", if mutbl == Mutability::Mut { "mut " } else { "" })? - } - _ => never!("{:?} is a bad Deref pattern type", self.ty), - } - subpattern.hir_fmt(f) - } - PatKind::LiteralBool { value } => write!(f, "{}", value), - PatKind::Or { pats } => f.write_joined(pats.iter(), " | "), - } - } -} - -struct WriteWith(F) -where - F: Fn(&mut HirFormatter<'_>) -> Result<(), HirDisplayError>; - -impl HirDisplay for WriteWith -where - F: Fn(&mut HirFormatter<'_>) -> Result<(), HirDisplayError>, -{ - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - (self.0)(f) - } -} - -fn is_box(adt: AdtId, db: &dyn HirDatabase) -> bool { - let owned_box = name![owned_box].to_smol_str(); - let krate = adt.module(db.upcast()).krate(); - let box_adt = db.lang_item(krate, owned_box).and_then(|it| it.as_struct()).map(AdtId::from); - Some(adt) == box_adt -} - -pub(crate) trait PatternFoldable: Sized { - fn fold_with(&self, folder: &mut F) -> Self { - self.super_fold_with(folder) - } - - fn super_fold_with(&self, folder: &mut F) -> Self; -} - -pub(crate) trait PatternFolder: Sized { - fn fold_pattern(&mut self, pattern: &Pat) -> Pat { - pattern.super_fold_with(self) - } - - fn fold_pattern_kind(&mut self, kind: &PatKind) -> PatKind { - kind.super_fold_with(self) - } -} - -impl PatternFoldable for Box { - fn super_fold_with(&self, folder: &mut F) -> Self { - let content: T = (**self).fold_with(folder); - Box::new(content) - } -} - -impl PatternFoldable for Vec { - fn super_fold_with(&self, folder: &mut F) -> Self { - self.iter().map(|t| t.fold_with(folder)).collect() - } -} - -impl PatternFoldable for Option { - fn super_fold_with(&self, folder: &mut F) -> Self { - self.as_ref().map(|t| t.fold_with(folder)) - } -} - -macro_rules! clone_impls { - ($($ty:ty),+) => { - $( - impl PatternFoldable for $ty { - fn super_fold_with(&self, _: &mut F) -> Self { - Clone::clone(self) - } - } - )+ - } -} - -clone_impls! { LocalFieldId, Ty, Substitution, EnumVariantId } - -impl PatternFoldable for FieldPat { - fn super_fold_with(&self, folder: &mut F) -> Self { - FieldPat { field: self.field.fold_with(folder), pattern: self.pattern.fold_with(folder) } - } -} - -impl PatternFoldable for Pat { - fn fold_with(&self, folder: &mut F) -> Self { - folder.fold_pattern(self) - } - - fn super_fold_with(&self, folder: &mut F) -> Self { - Pat { ty: self.ty.fold_with(folder), kind: self.kind.fold_with(folder) } - } -} - -impl PatternFoldable for PatKind { - fn fold_with(&self, folder: &mut F) -> Self { - folder.fold_pattern_kind(self) - } - - fn super_fold_with(&self, folder: &mut F) -> Self { - match self { - PatKind::Wild => PatKind::Wild, - PatKind::Binding { name, subpattern } => { - PatKind::Binding { name: name.clone(), subpattern: subpattern.fold_with(folder) } - } - PatKind::Variant { substs, enum_variant, subpatterns } => PatKind::Variant { - substs: substs.fold_with(folder), - enum_variant: enum_variant.fold_with(folder), - subpatterns: subpatterns.fold_with(folder), - }, - PatKind::Leaf { subpatterns } => { - PatKind::Leaf { subpatterns: subpatterns.fold_with(folder) } - } - PatKind::Deref { subpattern } => { - PatKind::Deref { subpattern: subpattern.fold_with(folder) } - } - &PatKind::LiteralBool { value } => PatKind::LiteralBool { value }, - PatKind::Or { pats } => PatKind::Or { pats: pats.fold_with(folder) }, - } - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs deleted file mode 100644 index bbbe539c13fbe..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs +++ /dev/null @@ -1,1094 +0,0 @@ -//! [`super::usefulness`] explains most of what is happening in this file. As explained there, -//! values and patterns are made from constructors applied to fields. This file defines a -//! `Constructor` enum, a `Fields` struct, and various operations to manipulate them and convert -//! them from/to patterns. -//! -//! There's one idea that is not detailed in [`super::usefulness`] because the details are not -//! needed there: _constructor splitting_. -//! -//! # Constructor splitting -//! -//! The idea is as follows: given a constructor `c` and a matrix, we want to specialize in turn -//! with all the value constructors that are covered by `c`, and compute usefulness for each. -//! Instead of listing all those constructors (which is intractable), we group those value -//! constructors together as much as possible. Example: -//! -//! ``` -//! match (0, false) { -//! (0 ..=100, true) => {} // `p_1` -//! (50..=150, false) => {} // `p_2` -//! (0 ..=200, _) => {} // `q` -//! } -//! ``` -//! -//! The naive approach would try all numbers in the range `0..=200`. But we can be a lot more -//! clever: `0` and `1` for example will match the exact same rows, and return equivalent -//! witnesses. In fact all of `0..50` would. We can thus restrict our exploration to 4 -//! constructors: `0..50`, `50..=100`, `101..=150` and `151..=200`. That is enough and infinitely -//! more tractable. -//! -//! We capture this idea in a function `split(p_1 ... p_n, c)` which returns a list of constructors -//! `c'` covered by `c`. Given such a `c'`, we require that all value ctors `c''` covered by `c'` -//! return an equivalent set of witnesses after specializing and computing usefulness. -//! In the example above, witnesses for specializing by `c''` covered by `0..50` will only differ -//! in their first element. -//! -//! We usually also ask that the `c'` together cover all of the original `c`. However we allow -//! skipping some constructors as long as it doesn't change whether the resulting list of witnesses -//! is empty of not. We use this in the wildcard `_` case. -//! -//! Splitting is implemented in the [`Constructor::split`] function. We don't do splitting for -//! or-patterns; instead we just try the alternatives one-by-one. For details on splitting -//! wildcards, see [`SplitWildcard`]; for integer ranges, see [`SplitIntRange`]. - -use std::{ - cell::Cell, - cmp::{max, min}, - iter::once, - ops::RangeInclusive, -}; - -use hir_def::{EnumVariantId, HasModule, LocalFieldId, VariantId}; -use smallvec::{smallvec, SmallVec}; -use stdx::never; - -use crate::{infer::normalize, AdtId, Interner, Scalar, Ty, TyExt, TyKind}; - -use super::{ - is_box, - usefulness::{helper::Captures, MatchCheckCtx, PatCtxt}, - FieldPat, Pat, PatKind, -}; - -use self::Constructor::*; - -/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns. -fn expand_or_pat(pat: &Pat) -> Vec<&Pat> { - fn expand<'p>(pat: &'p Pat, vec: &mut Vec<&'p Pat>) { - if let PatKind::Or { pats } = pat.kind.as_ref() { - for pat in pats { - expand(pat, vec); - } - } else { - vec.push(pat) - } - } - - let mut pats = Vec::new(); - expand(pat, &mut pats); - pats -} - -/// [Constructor] uses this in umimplemented variants. -/// It allows porting match expressions from upstream algorithm without losing semantics. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub(super) enum Void {} - -/// An inclusive interval, used for precise integer exhaustiveness checking. -/// `IntRange`s always store a contiguous range. This means that values are -/// encoded such that `0` encodes the minimum value for the integer, -/// regardless of the signedness. -/// For example, the pattern `-128..=127i8` is encoded as `0..=255`. -/// This makes comparisons and arithmetic on interval endpoints much more -/// straightforward. See `signed_bias` for details. -/// -/// `IntRange` is never used to encode an empty range or a "range" that wraps -/// around the (offset) space: i.e., `range.lo <= range.hi`. -#[derive(Clone, Debug, PartialEq, Eq)] -pub(super) struct IntRange { - range: RangeInclusive, -} - -impl IntRange { - #[inline] - fn is_integral(ty: &Ty) -> bool { - matches!( - ty.kind(Interner), - TyKind::Scalar(Scalar::Char | Scalar::Int(_) | Scalar::Uint(_) | Scalar::Bool) - ) - } - - fn is_singleton(&self) -> bool { - self.range.start() == self.range.end() - } - - fn boundaries(&self) -> (u128, u128) { - (*self.range.start(), *self.range.end()) - } - - #[inline] - fn from_bool(value: bool) -> IntRange { - let val = value as u128; - IntRange { range: val..=val } - } - - #[inline] - fn from_range(lo: u128, hi: u128, scalar_ty: Scalar) -> IntRange { - match scalar_ty { - Scalar::Bool => IntRange { range: lo..=hi }, - _ => unimplemented!(), - } - } - - fn is_subrange(&self, other: &Self) -> bool { - other.range.start() <= self.range.start() && self.range.end() <= other.range.end() - } - - fn intersection(&self, other: &Self) -> Option { - let (lo, hi) = self.boundaries(); - let (other_lo, other_hi) = other.boundaries(); - if lo <= other_hi && other_lo <= hi { - Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi) }) - } else { - None - } - } - - fn to_pat(&self, _cx: &MatchCheckCtx<'_, '_>, ty: Ty) -> Pat { - match ty.kind(Interner) { - TyKind::Scalar(Scalar::Bool) => { - let kind = match self.boundaries() { - (0, 0) => PatKind::LiteralBool { value: false }, - (1, 1) => PatKind::LiteralBool { value: true }, - (0, 1) => PatKind::Wild, - (lo, hi) => { - never!("bad range for bool pattern: {}..={}", lo, hi); - PatKind::Wild - } - }; - Pat { ty, kind: kind.into() } - } - _ => unimplemented!(), - } - } - - /// See `Constructor::is_covered_by` - fn is_covered_by(&self, other: &Self) -> bool { - if self.intersection(other).is_some() { - // Constructor splitting should ensure that all intersections we encounter are actually - // inclusions. - assert!(self.is_subrange(other)); - true - } else { - false - } - } -} - -/// Represents a border between 2 integers. Because the intervals spanning borders must be able to -/// cover every integer, we need to be able to represent 2^128 + 1 such borders. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -enum IntBorder { - JustBefore(u128), - AfterMax, -} - -/// A range of integers that is partitioned into disjoint subranges. This does constructor -/// splitting for integer ranges as explained at the top of the file. -/// -/// This is fed multiple ranges, and returns an output that covers the input, but is split so that -/// the only intersections between an output range and a seen range are inclusions. No output range -/// straddles the boundary of one of the inputs. -/// -/// The following input: -/// ``` -/// |-------------------------| // `self` -/// |------| |----------| |----| -/// |-------| |-------| -/// ``` -/// would be iterated over as follows: -/// ``` -/// ||---|--||-|---|---|---|--| -/// ``` -#[derive(Debug, Clone)] -struct SplitIntRange { - /// The range we are splitting - range: IntRange, - /// The borders of ranges we have seen. They are all contained within `range`. This is kept - /// sorted. - borders: Vec, -} - -impl SplitIntRange { - fn new(range: IntRange) -> Self { - SplitIntRange { range, borders: Vec::new() } - } - - /// Internal use - fn to_borders(r: IntRange) -> [IntBorder; 2] { - use IntBorder::*; - let (lo, hi) = r.boundaries(); - let lo = JustBefore(lo); - let hi = match hi.checked_add(1) { - Some(m) => JustBefore(m), - None => AfterMax, - }; - [lo, hi] - } - - /// Add ranges relative to which we split. - fn split(&mut self, ranges: impl Iterator) { - let this_range = &self.range; - let included_ranges = ranges.filter_map(|r| this_range.intersection(&r)); - let included_borders = included_ranges.flat_map(|r| { - let borders = Self::to_borders(r); - once(borders[0]).chain(once(borders[1])) - }); - self.borders.extend(included_borders); - self.borders.sort_unstable(); - } - - /// Iterate over the contained ranges. - fn iter(&self) -> impl Iterator + '_ { - use IntBorder::*; - - let self_range = Self::to_borders(self.range.clone()); - // Start with the start of the range. - let mut prev_border = self_range[0]; - self.borders - .iter() - .copied() - // End with the end of the range. - .chain(once(self_range[1])) - // List pairs of adjacent borders. - .map(move |border| { - let ret = (prev_border, border); - prev_border = border; - ret - }) - // Skip duplicates. - .filter(|(prev_border, border)| prev_border != border) - // Finally, convert to ranges. - .map(|(prev_border, border)| { - let range = match (prev_border, border) { - (JustBefore(n), JustBefore(m)) if n < m => n..=(m - 1), - (JustBefore(n), AfterMax) => n..=u128::MAX, - _ => unreachable!(), // Ruled out by the sorting and filtering we did - }; - IntRange { range } - }) - } -} - -/// A constructor for array and slice patterns. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub(super) struct Slice { - _unimplemented: Void, -} - -impl Slice { - fn arity(self) -> usize { - match self._unimplemented {} - } - - /// See `Constructor::is_covered_by` - fn is_covered_by(self, _other: Self) -> bool { - match self._unimplemented {} - } -} - -/// A value can be decomposed into a constructor applied to some fields. This struct represents -/// the constructor. See also `Fields`. -/// -/// `pat_constructor` retrieves the constructor corresponding to a pattern. -/// `specialize_constructor` returns the list of fields corresponding to a pattern, given a -/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and -/// `Fields`. -#[allow(dead_code)] -#[derive(Clone, Debug, PartialEq)] -pub(super) enum Constructor { - /// The constructor for patterns that have a single constructor, like tuples, struct patterns - /// and fixed-length arrays. - Single, - /// Enum variants. - Variant(EnumVariantId), - /// Ranges of integer literal values (`2`, `2..=5` or `2..5`). - IntRange(IntRange), - /// Ranges of floating-point literal values (`2.0..=5.2`). - FloatRange(Void), - /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately. - Str(Void), - /// Array and slice patterns. - Slice(Slice), - /// Constants that must not be matched structurally. They are treated as black - /// boxes for the purposes of exhaustiveness: we must not inspect them, and they - /// don't count towards making a match exhaustive. - Opaque, - /// Fake extra constructor for enums that aren't allowed to be matched exhaustively. Also used - /// for those types for which we cannot list constructors explicitly, like `f64` and `str`. - NonExhaustive, - /// Stands for constructors that are not seen in the matrix, as explained in the documentation - /// for [`SplitWildcard`]. The carried `bool` is used for the `non_exhaustive_omitted_patterns` - /// lint. - Missing { nonexhaustive_enum_missing_real_variants: bool }, - /// Wildcard pattern. - Wildcard, - /// Or-pattern. - Or, -} - -impl Constructor { - pub(super) fn is_wildcard(&self) -> bool { - matches!(self, Wildcard) - } - - pub(super) fn is_non_exhaustive(&self) -> bool { - matches!(self, NonExhaustive) - } - - fn as_int_range(&self) -> Option<&IntRange> { - match self { - IntRange(range) => Some(range), - _ => None, - } - } - - fn as_slice(&self) -> Option { - match self { - Slice(slice) => Some(*slice), - _ => None, - } - } - - pub(super) fn is_unstable_variant(&self, _pcx: PatCtxt<'_, '_>) -> bool { - false //FIXME: implement this - } - - pub(super) fn is_doc_hidden_variant(&self, _pcx: PatCtxt<'_, '_>) -> bool { - false //FIXME: implement this - } - - fn variant_id_for_adt(&self, adt: hir_def::AdtId) -> VariantId { - match *self { - Variant(id) => id.into(), - Single => { - assert!(!matches!(adt, hir_def::AdtId::EnumId(_))); - match adt { - hir_def::AdtId::EnumId(_) => unreachable!(), - hir_def::AdtId::StructId(id) => id.into(), - hir_def::AdtId::UnionId(id) => id.into(), - } - } - _ => panic!("bad constructor {:?} for adt {:?}", self, adt), - } - } - - /// The number of fields for this constructor. This must be kept in sync with - /// `Fields::wildcards`. - pub(super) fn arity(&self, pcx: PatCtxt<'_, '_>) -> usize { - match self { - Single | Variant(_) => match *pcx.ty.kind(Interner) { - TyKind::Tuple(arity, ..) => arity, - TyKind::Ref(..) => 1, - TyKind::Adt(adt, ..) => { - if is_box(adt.0, pcx.cx.db) { - // The only legal patterns of type `Box` (outside `std`) are `_` and box - // patterns. If we're here we can assume this is a box pattern. - 1 - } else { - let variant = self.variant_id_for_adt(adt.0); - Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant).count() - } - } - _ => { - never!("Unexpected type for `Single` constructor: {:?}", pcx.ty); - 0 - } - }, - Slice(slice) => slice.arity(), - Str(..) - | FloatRange(..) - | IntRange(..) - | NonExhaustive - | Opaque - | Missing { .. } - | Wildcard => 0, - Or => { - never!("The `Or` constructor doesn't have a fixed arity"); - 0 - } - } - } - - /// Some constructors (namely `Wildcard`, `IntRange` and `Slice`) actually stand for a set of actual - /// constructors (like variants, integers or fixed-sized slices). When specializing for these - /// constructors, we want to be specialising for the actual underlying constructors. - /// Naively, we would simply return the list of constructors they correspond to. We instead are - /// more clever: if there are constructors that we know will behave the same wrt the current - /// matrix, we keep them grouped. For example, all slices of a sufficiently large length - /// will either be all useful or all non-useful with a given matrix. - /// - /// See the branches for details on how the splitting is done. - /// - /// This function may discard some irrelevant constructors if this preserves behavior and - /// diagnostics. Eg. for the `_` case, we ignore the constructors already present in the - /// matrix, unless all of them are. - pub(super) fn split<'a>( - &self, - pcx: PatCtxt<'_, '_>, - ctors: impl Iterator + Clone, - ) -> SmallVec<[Self; 1]> { - match self { - Wildcard => { - let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx, ctors); - split_wildcard.into_ctors(pcx) - } - // Fast-track if the range is trivial. In particular, we don't do the overlapping - // ranges check. - IntRange(ctor_range) if !ctor_range.is_singleton() => { - let mut split_range = SplitIntRange::new(ctor_range.clone()); - let int_ranges = ctors.filter_map(|ctor| ctor.as_int_range()); - split_range.split(int_ranges.cloned()); - split_range.iter().map(IntRange).collect() - } - Slice(slice) => match slice._unimplemented {}, - // Any other constructor can be used unchanged. - _ => smallvec![self.clone()], - } - } - - /// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`. - /// For the simple cases, this is simply checking for equality. For the "grouped" constructors, - /// this checks for inclusion. - // We inline because this has a single call site in `Matrix::specialize_constructor`. - #[inline] - pub(super) fn is_covered_by(&self, _pcx: PatCtxt<'_, '_>, other: &Self) -> bool { - // This must be kept in sync with `is_covered_by_any`. - match (self, other) { - // Wildcards cover anything - (_, Wildcard) => true, - // The missing ctors are not covered by anything in the matrix except wildcards. - (Missing { .. } | Wildcard, _) => false, - - (Single, Single) => true, - (Variant(self_id), Variant(other_id)) => self_id == other_id, - - (IntRange(self_range), IntRange(other_range)) => self_range.is_covered_by(other_range), - (FloatRange(void), FloatRange(..)) => match *void {}, - (Str(void), Str(..)) => match *void {}, - (Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice), - - // We are trying to inspect an opaque constant. Thus we skip the row. - (Opaque, _) | (_, Opaque) => false, - // Only a wildcard pattern can match the special extra constructor. - (NonExhaustive, _) => false, - - _ => { - never!("trying to compare incompatible constructors {:?} and {:?}", self, other); - // Continue with 'whatever is covered' supposed to result in false no-error diagnostic. - true - } - } - } - - /// Faster version of `is_covered_by` when applied to many constructors. `used_ctors` is - /// assumed to be built from `matrix.head_ctors()` with wildcards filtered out, and `self` is - /// assumed to have been split from a wildcard. - fn is_covered_by_any(&self, _pcx: PatCtxt<'_, '_>, used_ctors: &[Constructor]) -> bool { - if used_ctors.is_empty() { - return false; - } - - // This must be kept in sync with `is_covered_by`. - match self { - // If `self` is `Single`, `used_ctors` cannot contain anything else than `Single`s. - Single => !used_ctors.is_empty(), - Variant(_) => used_ctors.iter().any(|c| c == self), - IntRange(range) => used_ctors - .iter() - .filter_map(|c| c.as_int_range()) - .any(|other| range.is_covered_by(other)), - Slice(slice) => used_ctors - .iter() - .filter_map(|c| c.as_slice()) - .any(|other| slice.is_covered_by(other)), - // This constructor is never covered by anything else - NonExhaustive => false, - Str(..) | FloatRange(..) | Opaque | Missing { .. } | Wildcard | Or => { - never!("found unexpected ctor in all_ctors: {:?}", self); - true - } - } - } -} - -/// A wildcard constructor that we split relative to the constructors in the matrix, as explained -/// at the top of the file. -/// -/// A constructor that is not present in the matrix rows will only be covered by the rows that have -/// wildcards. Thus we can group all of those constructors together; we call them "missing -/// constructors". Splitting a wildcard would therefore list all present constructors individually -/// (or grouped if they are integers or slices), and then all missing constructors together as a -/// group. -/// -/// However we can go further: since any constructor will match the wildcard rows, and having more -/// rows can only reduce the amount of usefulness witnesses, we can skip the present constructors -/// and only try the missing ones. -/// This will not preserve the whole list of witnesses, but will preserve whether the list is empty -/// or not. In fact this is quite natural from the point of view of diagnostics too. This is done -/// in `to_ctors`: in some cases we only return `Missing`. -#[derive(Debug)] -pub(super) struct SplitWildcard { - /// Constructors seen in the matrix. - matrix_ctors: Vec, - /// All the constructors for this type - all_ctors: SmallVec<[Constructor; 1]>, -} - -impl SplitWildcard { - pub(super) fn new(pcx: PatCtxt<'_, '_>) -> Self { - let cx = pcx.cx; - let make_range = |start, end, scalar| IntRange(IntRange::from_range(start, end, scalar)); - - // Unhandled types are treated as non-exhaustive. Being explicit here instead of falling - // to catchall arm to ease further implementation. - let unhandled = || smallvec![NonExhaustive]; - - // This determines the set of all possible constructors for the type `pcx.ty`. For numbers, - // arrays and slices we use ranges and variable-length slices when appropriate. - // - // If the `exhaustive_patterns` feature is enabled, we make sure to omit constructors that - // are statically impossible. E.g., for `Option`, we do not include `Some(_)` in the - // returned list of constructors. - // Invariant: this is empty if and only if the type is uninhabited (as determined by - // `cx.is_uninhabited()`). - let all_ctors = match pcx.ty.kind(Interner) { - TyKind::Scalar(Scalar::Bool) => smallvec![make_range(0, 1, Scalar::Bool)], - // TyKind::Array(..) if ... => unhandled(), - TyKind::Array(..) | TyKind::Slice(..) => unhandled(), - &TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ..) => { - let enum_data = cx.db.enum_data(enum_id); - - // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an - // additional "unknown" constructor. - // There is no point in enumerating all possible variants, because the user can't - // actually match against them all themselves. So we always return only the fictitious - // constructor. - // E.g., in an example like: - // - // ``` - // let err: io::ErrorKind = ...; - // match err { - // io::ErrorKind::NotFound => {}, - // } - // ``` - // - // we don't want to show every possible IO error, but instead have only `_` as the - // witness. - let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty); - - let is_exhaustive_pat_feature = cx.feature_exhaustive_patterns(); - - // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it - // as though it had an "unknown" constructor to avoid exposing its emptiness. The - // exception is if the pattern is at the top level, because we want empty matches to be - // considered exhaustive. - let is_secretly_empty = enum_data.variants.is_empty() - && !is_exhaustive_pat_feature - && !pcx.is_top_level; - - let mut ctors: SmallVec<[_; 1]> = enum_data - .variants - .iter() - .filter(|&(_, _v)| { - // If `exhaustive_patterns` is enabled, we exclude variants known to be - // uninhabited. - let is_uninhabited = is_exhaustive_pat_feature - && unimplemented!("after MatchCheckCtx.feature_exhaustive_patterns()"); - !is_uninhabited - }) - .map(|(local_id, _)| Variant(EnumVariantId { parent: enum_id, local_id })) - .collect(); - - if is_secretly_empty || is_declared_nonexhaustive { - ctors.push(NonExhaustive); - } - ctors - } - TyKind::Scalar(Scalar::Char) => unhandled(), - TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(), - TyKind::Never if !cx.feature_exhaustive_patterns() && !pcx.is_top_level => { - smallvec![NonExhaustive] - } - TyKind::Never => SmallVec::new(), - _ if cx.is_uninhabited(pcx.ty) => SmallVec::new(), - TyKind::Adt(..) | TyKind::Tuple(..) | TyKind::Ref(..) => smallvec![Single], - // This type is one for which we cannot list constructors, like `str` or `f64`. - _ => smallvec![NonExhaustive], - }; - - SplitWildcard { matrix_ctors: Vec::new(), all_ctors } - } - - /// Pass a set of constructors relative to which to split this one. Don't call twice, it won't - /// do what you want. - pub(super) fn split<'a>( - &mut self, - pcx: PatCtxt<'_, '_>, - ctors: impl Iterator + Clone, - ) { - // Since `all_ctors` never contains wildcards, this won't recurse further. - self.all_ctors = - self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx, ctors.clone())).collect(); - self.matrix_ctors = ctors.filter(|c| !c.is_wildcard()).cloned().collect(); - } - - /// Whether there are any value constructors for this type that are not present in the matrix. - fn any_missing(&self, pcx: PatCtxt<'_, '_>) -> bool { - self.iter_missing(pcx).next().is_some() - } - - /// Iterate over the constructors for this type that are not present in the matrix. - pub(super) fn iter_missing<'a, 'p>( - &'a self, - pcx: PatCtxt<'a, 'p>, - ) -> impl Iterator + Captures<'p> { - self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.matrix_ctors)) - } - - /// Return the set of constructors resulting from splitting the wildcard. As explained at the - /// top of the file, if any constructors are missing we can ignore the present ones. - fn into_ctors(self, pcx: PatCtxt<'_, '_>) -> SmallVec<[Constructor; 1]> { - if self.any_missing(pcx) { - // Some constructors are missing, thus we can specialize with the special `Missing` - // constructor, which stands for those constructors that are not seen in the matrix, - // and matches the same rows as any of them (namely the wildcard rows). See the top of - // the file for details. - // However, when all constructors are missing we can also specialize with the full - // `Wildcard` constructor. The difference will depend on what we want in diagnostics. - - // If some constructors are missing, we typically want to report those constructors, - // e.g.: - // ``` - // enum Direction { N, S, E, W } - // let Direction::N = ...; - // ``` - // we can report 3 witnesses: `S`, `E`, and `W`. - // - // However, if the user didn't actually specify a constructor - // in this arm, e.g., in - // ``` - // let x: (Direction, Direction, bool) = ...; - // let (_, _, false) = x; - // ``` - // we don't want to show all 16 possible witnesses `(, , - // true)` - we are satisfied with `(_, _, true)`. So if all constructors are missing we - // prefer to report just a wildcard `_`. - // - // The exception is: if we are at the top-level, for example in an empty match, we - // sometimes prefer reporting the list of constructors instead of just `_`. - let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty); - let ctor = if !self.matrix_ctors.is_empty() || report_when_all_missing { - if pcx.is_non_exhaustive { - Missing { - nonexhaustive_enum_missing_real_variants: self - .iter_missing(pcx) - .any(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx))), - } - } else { - Missing { nonexhaustive_enum_missing_real_variants: false } - } - } else { - Wildcard - }; - return smallvec![ctor]; - } - - // All the constructors are present in the matrix, so we just go through them all. - self.all_ctors - } -} - -/// A value can be decomposed into a constructor applied to some fields. This struct represents -/// those fields, generalized to allow patterns in each field. See also `Constructor`. -/// -/// This is constructed for a constructor using [`Fields::wildcards()`]. The idea is that -/// [`Fields::wildcards()`] constructs a list of fields where all entries are wildcards, and then -/// given a pattern we fill some of the fields with its subpatterns. -/// In the following example `Fields::wildcards` returns `[_, _, _, _]`. Then in -/// `extract_pattern_arguments` we fill some of the entries, and the result is -/// `[Some(0), _, _, _]`. -/// ```rust -/// let x: [Option; 4] = foo(); -/// match x { -/// [Some(0), ..] => {} -/// } -/// ``` -/// -/// Note that the number of fields of a constructor may not match the fields declared in the -/// original struct/variant. This happens if a private or `non_exhaustive` field is uninhabited, -/// because the code mustn't observe that it is uninhabited. In that case that field is not -/// included in `fields`. For that reason, when you have a `mir::Field` you must use -/// `index_with_declared_idx`. -#[derive(Clone, Copy)] -pub(super) struct Fields<'p> { - fields: &'p [DeconstructedPat<'p>], -} - -impl<'p> Fields<'p> { - fn empty() -> Self { - Fields { fields: &[] } - } - - fn singleton(cx: &MatchCheckCtx<'_, 'p>, field: DeconstructedPat<'p>) -> Self { - let field = cx.pattern_arena.alloc(field); - Fields { fields: std::slice::from_ref(field) } - } - - pub(super) fn from_iter( - cx: &MatchCheckCtx<'_, 'p>, - fields: impl IntoIterator>, - ) -> Self { - let fields: &[_] = cx.pattern_arena.alloc_extend(fields); - Fields { fields } - } - - fn wildcards_from_tys(cx: &MatchCheckCtx<'_, 'p>, tys: impl IntoIterator) -> Self { - Fields::from_iter(cx, tys.into_iter().map(DeconstructedPat::wildcard)) - } - - // In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide - // uninhabited fields in order not to reveal the uninhabitedness of the whole variant. - // This lists the fields we keep along with their types. - fn list_variant_nonhidden_fields<'a>( - cx: &'a MatchCheckCtx<'a, 'p>, - ty: &'a Ty, - variant: VariantId, - ) -> impl Iterator + Captures<'a> + Captures<'p> { - let (adt, substs) = ty.as_adt().unwrap(); - - let adt_is_local = variant.module(cx.db.upcast()).krate() == cx.module.krate(); - // Whether we must not match the fields of this variant exhaustively. - let is_non_exhaustive = is_field_list_non_exhaustive(variant, cx) && !adt_is_local; - - let visibility = cx.db.field_visibilities(variant); - let field_ty = cx.db.field_types(variant); - let fields_len = variant.variant_data(cx.db.upcast()).fields().len() as u32; - - (0..fields_len).map(|idx| LocalFieldId::from_raw(idx.into())).filter_map(move |fid| { - let ty = field_ty[fid].clone().substitute(Interner, substs); - let ty = normalize(cx.db, cx.body, ty); - let is_visible = matches!(adt, hir_def::AdtId::EnumId(..)) - || visibility[fid].is_visible_from(cx.db.upcast(), cx.module); - let is_uninhabited = cx.is_uninhabited(&ty); - - if is_uninhabited && (!is_visible || is_non_exhaustive) { - None - } else { - Some((fid, ty)) - } - }) - } - - /// Creates a new list of wildcard fields for a given constructor. The result must have a - /// length of `constructor.arity()`. - pub(crate) fn wildcards( - cx: &MatchCheckCtx<'_, 'p>, - ty: &Ty, - constructor: &Constructor, - ) -> Self { - let ret = match constructor { - Single | Variant(_) => match ty.kind(Interner) { - TyKind::Tuple(_, substs) => { - let tys = substs.iter(Interner).map(|ty| ty.assert_ty_ref(Interner)); - Fields::wildcards_from_tys(cx, tys.cloned()) - } - TyKind::Ref(.., rty) => Fields::wildcards_from_tys(cx, once(rty.clone())), - &TyKind::Adt(AdtId(adt), ref substs) => { - if is_box(adt, cx.db) { - // The only legal patterns of type `Box` (outside `std`) are `_` and box - // patterns. If we're here we can assume this is a box pattern. - let subst_ty = substs.at(Interner, 0).assert_ty_ref(Interner).clone(); - Fields::wildcards_from_tys(cx, once(subst_ty)) - } else { - let variant = constructor.variant_id_for_adt(adt); - let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant) - .map(|(_, ty)| ty); - Fields::wildcards_from_tys(cx, tys) - } - } - ty_kind => { - never!("Unexpected type for `Single` constructor: {:?}", ty_kind); - Fields::wildcards_from_tys(cx, once(ty.clone())) - } - }, - Slice(slice) => match slice._unimplemented {}, - Str(..) - | FloatRange(..) - | IntRange(..) - | NonExhaustive - | Opaque - | Missing { .. } - | Wildcard => Fields::empty(), - Or => { - never!("called `Fields::wildcards` on an `Or` ctor"); - Fields::empty() - } - }; - ret - } - - /// Returns the list of patterns. - pub(super) fn iter_patterns<'a>( - &'a self, - ) -> impl Iterator> + Captures<'a> { - self.fields.iter() - } -} - -/// Values and patterns can be represented as a constructor applied to some fields. This represents -/// a pattern in this form. -/// This also keeps track of whether the pattern has been found reachable during analysis. For this -/// reason we should be careful not to clone patterns for which we care about that. Use -/// `clone_and_forget_reachability` if you're sure. -pub(crate) struct DeconstructedPat<'p> { - ctor: Constructor, - fields: Fields<'p>, - ty: Ty, - reachable: Cell, -} - -impl<'p> DeconstructedPat<'p> { - pub(super) fn wildcard(ty: Ty) -> Self { - Self::new(Wildcard, Fields::empty(), ty) - } - - pub(super) fn new(ctor: Constructor, fields: Fields<'p>, ty: Ty) -> Self { - DeconstructedPat { ctor, fields, ty, reachable: Cell::new(false) } - } - - /// Construct a pattern that matches everything that starts with this constructor. - /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern - /// `Some(_)`. - pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p>, ctor: Constructor) -> Self { - let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor); - DeconstructedPat::new(ctor, fields, pcx.ty.clone()) - } - - /// Clone this value. This method emphasizes that cloning loses reachability information and - /// should be done carefully. - pub(super) fn clone_and_forget_reachability(&self) -> Self { - DeconstructedPat::new(self.ctor.clone(), self.fields, self.ty.clone()) - } - - pub(crate) fn from_pat(cx: &MatchCheckCtx<'_, 'p>, pat: &Pat) -> Self { - let mkpat = |pat| DeconstructedPat::from_pat(cx, pat); - let ctor; - let fields; - match pat.kind.as_ref() { - PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat), - PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { - ctor = Wildcard; - fields = Fields::empty(); - } - PatKind::Deref { subpattern } => { - ctor = Single; - fields = Fields::singleton(cx, mkpat(subpattern)); - } - PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => { - match pat.ty.kind(Interner) { - TyKind::Tuple(_, substs) => { - ctor = Single; - let mut wilds: SmallVec<[_; 2]> = substs - .iter(Interner) - .map(|arg| arg.assert_ty_ref(Interner).clone()) - .map(DeconstructedPat::wildcard) - .collect(); - for pat in subpatterns { - let idx: u32 = pat.field.into_raw().into(); - wilds[idx as usize] = mkpat(&pat.pattern); - } - fields = Fields::from_iter(cx, wilds) - } - TyKind::Adt(adt, substs) if is_box(adt.0, cx.db) => { - // The only legal patterns of type `Box` (outside `std`) are `_` and box - // patterns. If we're here we can assume this is a box pattern. - // FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_, - // _)` or a box pattern. As a hack to avoid an ICE with the former, we - // ignore other fields than the first one. This will trigger an error later - // anyway. - // See https://github.com/rust-lang/rust/issues/82772 , - // explanation: https://github.com/rust-lang/rust/pull/82789#issuecomment-796921977 - // The problem is that we can't know from the type whether we'll match - // normally or through box-patterns. We'll have to figure out a proper - // solution when we introduce generalized deref patterns. Also need to - // prevent mixing of those two options. - let pat = - subpatterns.iter().find(|pat| pat.field.into_raw() == 0u32.into()); - let field = if let Some(pat) = pat { - mkpat(&pat.pattern) - } else { - let ty = substs.at(Interner, 0).assert_ty_ref(Interner).clone(); - DeconstructedPat::wildcard(ty) - }; - ctor = Single; - fields = Fields::singleton(cx, field) - } - &TyKind::Adt(adt, _) => { - ctor = match pat.kind.as_ref() { - PatKind::Leaf { .. } => Single, - PatKind::Variant { enum_variant, .. } => Variant(*enum_variant), - _ => { - never!(); - Wildcard - } - }; - let variant = ctor.variant_id_for_adt(adt.0); - let fields_len = variant.variant_data(cx.db.upcast()).fields().len(); - // For each field in the variant, we store the relevant index into `self.fields` if any. - let mut field_id_to_id: Vec> = vec![None; fields_len]; - let tys = Fields::list_variant_nonhidden_fields(cx, &pat.ty, variant) - .enumerate() - .map(|(i, (fid, ty))| { - let field_idx: u32 = fid.into_raw().into(); - field_id_to_id[field_idx as usize] = Some(i); - ty - }); - let mut wilds: SmallVec<[_; 2]> = - tys.map(DeconstructedPat::wildcard).collect(); - for pat in subpatterns { - let field_idx: u32 = pat.field.into_raw().into(); - if let Some(i) = field_id_to_id[field_idx as usize] { - wilds[i] = mkpat(&pat.pattern); - } - } - fields = Fields::from_iter(cx, wilds); - } - _ => { - never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty); - ctor = Wildcard; - fields = Fields::empty(); - } - } - } - &PatKind::LiteralBool { value } => { - ctor = IntRange(IntRange::from_bool(value)); - fields = Fields::empty(); - } - PatKind::Or { .. } => { - ctor = Or; - let pats: SmallVec<[_; 2]> = expand_or_pat(pat).into_iter().map(mkpat).collect(); - fields = Fields::from_iter(cx, pats) - } - } - DeconstructedPat::new(ctor, fields, pat.ty.clone()) - } - - pub(crate) fn to_pat(&self, cx: &MatchCheckCtx<'_, 'p>) -> Pat { - let mut subpatterns = self.iter_fields().map(|p| p.to_pat(cx)); - let pat = match &self.ctor { - Single | Variant(_) => match self.ty.kind(Interner) { - TyKind::Tuple(..) => PatKind::Leaf { - subpatterns: subpatterns - .zip(0u32..) - .map(|(p, i)| FieldPat { - field: LocalFieldId::from_raw(i.into()), - pattern: p, - }) - .collect(), - }, - TyKind::Adt(adt, _) if is_box(adt.0, cx.db) => { - // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside - // of `std`). So this branch is only reachable when the feature is enabled and - // the pattern is a box pattern. - PatKind::Deref { subpattern: subpatterns.next().unwrap() } - } - TyKind::Adt(adt, substs) => { - let variant = self.ctor.variant_id_for_adt(adt.0); - let subpatterns = Fields::list_variant_nonhidden_fields(cx, self.ty(), variant) - .zip(subpatterns) - .map(|((field, _ty), pattern)| FieldPat { field, pattern }) - .collect(); - - if let VariantId::EnumVariantId(enum_variant) = variant { - PatKind::Variant { substs: substs.clone(), enum_variant, subpatterns } - } else { - PatKind::Leaf { subpatterns } - } - } - // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should - // be careful to reconstruct the correct constant pattern here. However a string - // literal pattern will never be reported as a non-exhaustiveness witness, so we - // ignore this issue. - TyKind::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, - _ => { - never!("unexpected ctor for type {:?} {:?}", self.ctor, self.ty); - PatKind::Wild - } - }, - &Slice(slice) => match slice._unimplemented {}, - &Str(void) => match void {}, - &FloatRange(void) => match void {}, - IntRange(range) => return range.to_pat(cx, self.ty.clone()), - Wildcard | NonExhaustive => PatKind::Wild, - Missing { .. } => { - never!( - "trying to convert a `Missing` constructor into a `Pat`; this is a bug, \ - `Missing` should have been processed in `apply_constructors`" - ); - PatKind::Wild - } - Opaque | Or => { - never!("can't convert to pattern: {:?}", self.ctor); - PatKind::Wild - } - }; - Pat { ty: self.ty.clone(), kind: Box::new(pat) } - } - - pub(super) fn is_or_pat(&self) -> bool { - matches!(self.ctor, Or) - } - - pub(super) fn ctor(&self) -> &Constructor { - &self.ctor - } - - pub(super) fn ty(&self) -> &Ty { - &self.ty - } - - pub(super) fn iter_fields<'a>(&'a self) -> impl Iterator> + 'a { - self.fields.iter_patterns() - } - - /// Specialize this pattern with a constructor. - /// `other_ctor` can be different from `self.ctor`, but must be covered by it. - pub(super) fn specialize<'a>( - &'a self, - cx: &MatchCheckCtx<'_, 'p>, - other_ctor: &Constructor, - ) -> SmallVec<[&'p DeconstructedPat<'p>; 2]> { - match (&self.ctor, other_ctor) { - (Wildcard, _) => { - // We return a wildcard for each field of `other_ctor`. - Fields::wildcards(cx, &self.ty, other_ctor).iter_patterns().collect() - } - (Slice(self_slice), Slice(other_slice)) - if self_slice.arity() != other_slice.arity() => - { - match self_slice._unimplemented {} - } - _ => self.fields.iter_patterns().collect(), - } - } - - /// We keep track for each pattern if it was ever reachable during the analysis. This is used - /// with `unreachable_spans` to report unreachable subpatterns arising from or patterns. - pub(super) fn set_reachable(&self) { - self.reachable.set(true) - } - pub(super) fn is_reachable(&self) -> bool { - self.reachable.get() - } -} - -fn is_field_list_non_exhaustive(variant_id: VariantId, cx: &MatchCheckCtx<'_, '_>) -> bool { - let attr_def_id = match variant_id { - VariantId::EnumVariantId(id) => id.into(), - VariantId::StructId(id) => id.into(), - VariantId::UnionId(id) => id.into(), - }; - cx.db.attrs(attr_def_id).by_key("non_exhaustive").exists() -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_util.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_util.rs deleted file mode 100644 index b89b4f2bfb7d9..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_util.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! Pattern untilities. -//! -//! Originates from `rustc_hir::pat_util` - -use std::iter::{Enumerate, ExactSizeIterator}; - -pub(crate) struct EnumerateAndAdjust { - enumerate: Enumerate, - gap_pos: usize, - gap_len: usize, -} - -impl Iterator for EnumerateAndAdjust -where - I: Iterator, -{ - type Item = (usize, ::Item); - - fn next(&mut self) -> Option<(usize, ::Item)> { - self.enumerate - .next() - .map(|(i, elem)| (if i < self.gap_pos { i } else { i + self.gap_len }, elem)) - } - - fn size_hint(&self) -> (usize, Option) { - self.enumerate.size_hint() - } -} - -pub(crate) trait EnumerateAndAdjustIterator { - fn enumerate_and_adjust( - self, - expected_len: usize, - gap_pos: Option, - ) -> EnumerateAndAdjust - where - Self: Sized; -} - -impl EnumerateAndAdjustIterator for T { - fn enumerate_and_adjust( - self, - expected_len: usize, - gap_pos: Option, - ) -> EnumerateAndAdjust - where - Self: Sized, - { - let actual_len = self.len(); - EnumerateAndAdjust { - enumerate: self.enumerate(), - gap_pos: gap_pos.unwrap_or(expected_len), - gap_len: expected_len - actual_len, - } - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/usefulness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/usefulness.rs deleted file mode 100644 index 1221327b9510a..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/usefulness.rs +++ /dev/null @@ -1,811 +0,0 @@ -//! Based on rust-lang/rust (last sync f31622a50 2021-11-12) -//! -//! -//! ----- -//! -//! This file includes the logic for exhaustiveness and reachability checking for pattern-matching. -//! Specifically, given a list of patterns for a type, we can tell whether: -//! (a) each pattern is reachable (reachability) -//! (b) the patterns cover every possible value for the type (exhaustiveness) -//! -//! The algorithm implemented here is a modified version of the one described in [this -//! paper](http://moscova.inria.fr/~maranget/papers/warn/index.html). We have however generalized -//! it to accommodate the variety of patterns that Rust supports. We thus explain our version here, -//! without being as rigorous. -//! -//! -//! # Summary -//! -//! The core of the algorithm is the notion of "usefulness". A pattern `q` is said to be *useful* -//! relative to another pattern `p` of the same type if there is a value that is matched by `q` and -//! not matched by `p`. This generalizes to many `p`s: `q` is useful w.r.t. a list of patterns -//! `p_1 .. p_n` if there is a value that is matched by `q` and by none of the `p_i`. We write -//! `usefulness(p_1 .. p_n, q)` for a function that returns a list of such values. The aim of this -//! file is to compute it efficiently. -//! -//! This is enough to compute reachability: a pattern in a `match` expression is reachable iff it -//! is useful w.r.t. the patterns above it: -//! ```rust -//! match x { -//! Some(_) => ..., -//! None => ..., // reachable: `None` is matched by this but not the branch above -//! Some(0) => ..., // unreachable: all the values this matches are already matched by -//! // `Some(_)` above -//! } -//! ``` -//! -//! This is also enough to compute exhaustiveness: a match is exhaustive iff the wildcard `_` -//! pattern is _not_ useful w.r.t. the patterns in the match. The values returned by `usefulness` -//! are used to tell the user which values are missing. -//! ```rust -//! match x { -//! Some(0) => ..., -//! None => ..., -//! // not exhaustive: `_` is useful because it matches `Some(1)` -//! } -//! ``` -//! -//! The entrypoint of this file is the [`compute_match_usefulness`] function, which computes -//! reachability for each match branch and exhaustiveness for the whole match. -//! -//! -//! # Constructors and fields -//! -//! Note: we will often abbreviate "constructor" as "ctor". -//! -//! The idea that powers everything that is done in this file is the following: a (matcheable) -//! value is made from a constructor applied to a number of subvalues. Examples of constructors are -//! `Some`, `None`, `(,)` (the 2-tuple constructor), `Foo {..}` (the constructor for a struct -//! `Foo`), and `2` (the constructor for the number `2`). This is natural when we think of -//! pattern-matching, and this is the basis for what follows. -//! -//! Some of the ctors listed above might feel weird: `None` and `2` don't take any arguments. -//! That's ok: those are ctors that take a list of 0 arguments; they are the simplest case of -//! ctors. We treat `2` as a ctor because `u64` and other number types behave exactly like a huge -//! `enum`, with one variant for each number. This allows us to see any matcheable value as made up -//! from a tree of ctors, each having a set number of children. For example: `Foo { bar: None, -//! baz: Ok(0) }` is made from 4 different ctors, namely `Foo{..}`, `None`, `Ok` and `0`. -//! -//! This idea can be extended to patterns: they are also made from constructors applied to fields. -//! A pattern for a given type is allowed to use all the ctors for values of that type (which we -//! call "value constructors"), but there are also pattern-only ctors. The most important one is -//! the wildcard (`_`), and the others are integer ranges (`0..=10`), variable-length slices (`[x, -//! ..]`), and or-patterns (`Ok(0) | Err(_)`). Examples of valid patterns are `42`, `Some(_)`, `Foo -//! { bar: Some(0) | None, baz: _ }`. Note that a binder in a pattern (e.g. `Some(x)`) matches the -//! same values as a wildcard (e.g. `Some(_)`), so we treat both as wildcards. -//! -//! From this deconstruction we can compute whether a given value matches a given pattern; we -//! simply look at ctors one at a time. Given a pattern `p` and a value `v`, we want to compute -//! `matches!(v, p)`. It's mostly straightforward: we compare the head ctors and when they match -//! we compare their fields recursively. A few representative examples: -//! -//! - `matches!(v, _) := true` -//! - `matches!((v0, v1), (p0, p1)) := matches!(v0, p0) && matches!(v1, p1)` -//! - `matches!(Foo { bar: v0, baz: v1 }, Foo { bar: p0, baz: p1 }) := matches!(v0, p0) && matches!(v1, p1)` -//! - `matches!(Ok(v0), Ok(p0)) := matches!(v0, p0)` -//! - `matches!(Ok(v0), Err(p0)) := false` (incompatible variants) -//! - `matches!(v, 1..=100) := matches!(v, 1) || ... || matches!(v, 100)` -//! - `matches!([v0], [p0, .., p1]) := false` (incompatible lengths) -//! - `matches!([v0, v1, v2], [p0, .., p1]) := matches!(v0, p0) && matches!(v2, p1)` -//! - `matches!(v, p0 | p1) := matches!(v, p0) || matches!(v, p1)` -//! -//! Constructors, fields and relevant operations are defined in the [`super::deconstruct_pat`] module. -//! -//! Note: this constructors/fields distinction may not straightforwardly apply to every Rust type. -//! For example a value of type `Rc` can't be deconstructed that way, and `&str` has an -//! infinitude of constructors. There are also subtleties with visibility of fields and -//! uninhabitedness and various other things. The constructors idea can be extended to handle most -//! of these subtleties though; caveats are documented where relevant throughout the code. -//! -//! Whether constructors cover each other is computed by [`Constructor::is_covered_by`]. -//! -//! -//! # Specialization -//! -//! Recall that we wish to compute `usefulness(p_1 .. p_n, q)`: given a list of patterns `p_1 .. -//! p_n` and a pattern `q`, all of the same type, we want to find a list of values (called -//! "witnesses") that are matched by `q` and by none of the `p_i`. We obviously don't just -//! enumerate all possible values. From the discussion above we see that we can proceed -//! ctor-by-ctor: for each value ctor of the given type, we ask "is there a value that starts with -//! this constructor and matches `q` and none of the `p_i`?". As we saw above, there's a lot we can -//! say from knowing only the first constructor of our candidate value. -//! -//! Let's take the following example: -//! ``` -//! match x { -//! Enum::Variant1(_) => {} // `p1` -//! Enum::Variant2(None, 0) => {} // `p2` -//! Enum::Variant2(Some(_), 0) => {} // `q` -//! } -//! ``` -//! -//! We can easily see that if our candidate value `v` starts with `Variant1` it will not match `q`. -//! If `v = Variant2(v0, v1)` however, whether or not it matches `p2` and `q` will depend on `v0` -//! and `v1`. In fact, such a `v` will be a witness of usefulness of `q` exactly when the tuple -//! `(v0, v1)` is a witness of usefulness of `q'` in the following reduced match: -//! -//! ``` -//! match x { -//! (None, 0) => {} // `p2'` -//! (Some(_), 0) => {} // `q'` -//! } -//! ``` -//! -//! This motivates a new step in computing usefulness, that we call _specialization_. -//! Specialization consist of filtering a list of patterns for those that match a constructor, and -//! then looking into the constructor's fields. This enables usefulness to be computed recursively. -//! -//! Instead of acting on a single pattern in each row, we will consider a list of patterns for each -//! row, and we call such a list a _pattern-stack_. The idea is that we will specialize the -//! leftmost pattern, which amounts to popping the constructor and pushing its fields, which feels -//! like a stack. We note a pattern-stack simply with `[p_1 ... p_n]`. -//! Here's a sequence of specializations of a list of pattern-stacks, to illustrate what's -//! happening: -//! ``` -//! [Enum::Variant1(_)] -//! [Enum::Variant2(None, 0)] -//! [Enum::Variant2(Some(_), 0)] -//! //==>> specialize with `Variant2` -//! [None, 0] -//! [Some(_), 0] -//! //==>> specialize with `Some` -//! [_, 0] -//! //==>> specialize with `true` (say the type was `bool`) -//! [0] -//! //==>> specialize with `0` -//! [] -//! ``` -//! -//! The function `specialize(c, p)` takes a value constructor `c` and a pattern `p`, and returns 0 -//! or more pattern-stacks. If `c` does not match the head constructor of `p`, it returns nothing; -//! otherwise if returns the fields of the constructor. This only returns more than one -//! pattern-stack if `p` has a pattern-only constructor. -//! -//! - Specializing for the wrong constructor returns nothing -//! -//! `specialize(None, Some(p0)) := []` -//! -//! - Specializing for the correct constructor returns a single row with the fields -//! -//! `specialize(Variant1, Variant1(p0, p1, p2)) := [[p0, p1, p2]]` -//! -//! `specialize(Foo{..}, Foo { bar: p0, baz: p1 }) := [[p0, p1]]` -//! -//! - For or-patterns, we specialize each branch and concatenate the results -//! -//! `specialize(c, p0 | p1) := specialize(c, p0) ++ specialize(c, p1)` -//! -//! - We treat the other pattern constructors as if they were a large or-pattern of all the -//! possibilities: -//! -//! `specialize(c, _) := specialize(c, Variant1(_) | Variant2(_, _) | ...)` -//! -//! `specialize(c, 1..=100) := specialize(c, 1 | ... | 100)` -//! -//! `specialize(c, [p0, .., p1]) := specialize(c, [p0, p1] | [p0, _, p1] | [p0, _, _, p1] | ...)` -//! -//! - If `c` is a pattern-only constructor, `specialize` is defined on a case-by-case basis. See -//! the discussion about constructor splitting in [`super::deconstruct_pat`]. -//! -//! -//! We then extend this function to work with pattern-stacks as input, by acting on the first -//! column and keeping the other columns untouched. -//! -//! Specialization for the whole matrix is done in [`Matrix::specialize_constructor`]. Note that -//! or-patterns in the first column are expanded before being stored in the matrix. Specialization -//! for a single patstack is done from a combination of [`Constructor::is_covered_by`] and -//! [`PatStack::pop_head_constructor`]. The internals of how it's done mostly live in the -//! [`Fields`] struct. -//! -//! -//! # Computing usefulness -//! -//! We now have all we need to compute usefulness. The inputs to usefulness are a list of -//! pattern-stacks `p_1 ... p_n` (one per row), and a new pattern_stack `q`. The paper and this -//! file calls the list of patstacks a _matrix_. They must all have the same number of columns and -//! the patterns in a given column must all have the same type. `usefulness` returns a (possibly -//! empty) list of witnesses of usefulness. These witnesses will also be pattern-stacks. -//! -//! - base case: `n_columns == 0`. -//! Since a pattern-stack functions like a tuple of patterns, an empty one functions like the -//! unit type. Thus `q` is useful iff there are no rows above it, i.e. if `n == 0`. -//! -//! - inductive case: `n_columns > 0`. -//! We need a way to list the constructors we want to try. We will be more clever in the next -//! section but for now assume we list all value constructors for the type of the first column. -//! -//! - for each such ctor `c`: -//! -//! - for each `q'` returned by `specialize(c, q)`: -//! -//! - we compute `usefulness(specialize(c, p_1) ... specialize(c, p_n), q')` -//! -//! - for each witness found, we revert specialization by pushing the constructor `c` on top. -//! -//! - We return the concatenation of all the witnesses found, if any. -//! -//! Example: -//! ``` -//! [Some(true)] // p_1 -//! [None] // p_2 -//! [Some(_)] // q -//! //==>> try `None`: `specialize(None, q)` returns nothing -//! //==>> try `Some`: `specialize(Some, q)` returns a single row -//! [true] // p_1' -//! [_] // q' -//! //==>> try `true`: `specialize(true, q')` returns a single row -//! [] // p_1'' -//! [] // q'' -//! //==>> base case; `n != 0` so `q''` is not useful. -//! //==>> go back up a step -//! [true] // p_1' -//! [_] // q' -//! //==>> try `false`: `specialize(false, q')` returns a single row -//! [] // q'' -//! //==>> base case; `n == 0` so `q''` is useful. We return the single witness `[]` -//! witnesses: -//! [] -//! //==>> undo the specialization with `false` -//! witnesses: -//! [false] -//! //==>> undo the specialization with `Some` -//! witnesses: -//! [Some(false)] -//! //==>> we have tried all the constructors. The output is the single witness `[Some(false)]`. -//! ``` -//! -//! This computation is done in [`is_useful`]. In practice we don't care about the list of -//! witnesses when computing reachability; we only need to know whether any exist. We do keep the -//! witnesses when computing exhaustiveness to report them to the user. -//! -//! -//! # Making usefulness tractable: constructor splitting -//! -//! We're missing one last detail: which constructors do we list? Naively listing all value -//! constructors cannot work for types like `u64` or `&str`, so we need to be more clever. The -//! first obvious insight is that we only want to list constructors that are covered by the head -//! constructor of `q`. If it's a value constructor, we only try that one. If it's a pattern-only -//! constructor, we use the final clever idea for this algorithm: _constructor splitting_, where we -//! group together constructors that behave the same. -//! -//! The details are not necessary to understand this file, so we explain them in -//! [`super::deconstruct_pat`]. Splitting is done by the [`Constructor::split`] function. - -use std::iter::once; - -use hir_def::{AdtId, DefWithBodyId, HasModule, ModuleId}; -use smallvec::{smallvec, SmallVec}; -use typed_arena::Arena; - -use crate::{db::HirDatabase, Ty, TyExt}; - -use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard}; - -use self::{helper::Captures, ArmType::*, Usefulness::*}; - -pub(crate) struct MatchCheckCtx<'a, 'p> { - pub(crate) module: ModuleId, - pub(crate) body: DefWithBodyId, - pub(crate) db: &'a dyn HirDatabase, - /// Lowered patterns from arms plus generated by the check. - pub(crate) pattern_arena: &'p Arena>, -} - -impl<'a, 'p> MatchCheckCtx<'a, 'p> { - pub(super) fn is_uninhabited(&self, _ty: &Ty) -> bool { - // FIXME(iDawer) implement exhaustive_patterns feature. More info in: - // Tracking issue for RFC 1872: exhaustive_patterns feature https://github.com/rust-lang/rust/issues/51085 - false - } - - /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. - pub(super) fn is_foreign_non_exhaustive_enum(&self, ty: &Ty) -> bool { - match ty.as_adt() { - Some((adt @ AdtId::EnumId(_), _)) => { - let has_non_exhaustive_attr = - self.db.attrs(adt.into()).by_key("non_exhaustive").exists(); - let is_local = adt.module(self.db.upcast()).krate() == self.module.krate(); - has_non_exhaustive_attr && !is_local - } - _ => false, - } - } - - // Rust feature described as "Allows exhaustive pattern matching on types that contain uninhabited types." - pub(super) fn feature_exhaustive_patterns(&self) -> bool { - // FIXME see MatchCheckCtx::is_uninhabited - false - } -} - -#[derive(Copy, Clone)] -pub(super) struct PatCtxt<'a, 'p> { - pub(super) cx: &'a MatchCheckCtx<'a, 'p>, - /// Type of the current column under investigation. - pub(super) ty: &'a Ty, - /// Whether the current pattern is the whole pattern as found in a match arm, or if it's a - /// subpattern. - pub(super) is_top_level: bool, - /// Whether the current pattern is from a `non_exhaustive` enum. - pub(super) is_non_exhaustive: bool, -} - -/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]` -/// works well. -#[derive(Clone)] -pub(super) struct PatStack<'p> { - pats: SmallVec<[&'p DeconstructedPat<'p>; 2]>, -} - -impl<'p> PatStack<'p> { - fn from_pattern(pat: &'p DeconstructedPat<'p>) -> Self { - Self::from_vec(smallvec![pat]) - } - - fn from_vec(vec: SmallVec<[&'p DeconstructedPat<'p>; 2]>) -> Self { - PatStack { pats: vec } - } - - fn is_empty(&self) -> bool { - self.pats.is_empty() - } - - fn len(&self) -> usize { - self.pats.len() - } - - fn head(&self) -> &'p DeconstructedPat<'p> { - self.pats[0] - } - - // Recursively expand the first pattern into its subpatterns. Only useful if the pattern is an - // or-pattern. Panics if `self` is empty. - fn expand_or_pat(&self) -> impl Iterator> + Captures<'_> { - self.head().iter_fields().map(move |pat| { - let mut new_patstack = PatStack::from_pattern(pat); - new_patstack.pats.extend_from_slice(&self.pats[1..]); - new_patstack - }) - } - - /// This computes `S(self.head().ctor(), self)`. See top of the file for explanations. - /// - /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing - /// fields filled with wild patterns. - /// - /// This is roughly the inverse of `Constructor::apply`. - fn pop_head_constructor(&self, cx: &MatchCheckCtx<'_, 'p>, ctor: &Constructor) -> PatStack<'p> { - // We pop the head pattern and push the new fields extracted from the arguments of - // `self.head()`. - let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(cx, ctor); - new_fields.extend_from_slice(&self.pats[1..]); - PatStack::from_vec(new_fields) - } -} - -/// A 2D matrix. -#[derive(Clone)] -pub(super) struct Matrix<'p> { - patterns: Vec>, -} - -impl<'p> Matrix<'p> { - fn empty() -> Self { - Matrix { patterns: vec![] } - } - - /// Number of columns of this matrix. `None` is the matrix is empty. - pub(super) fn _column_count(&self) -> Option { - self.patterns.get(0).map(|r| r.len()) - } - - /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively - /// expands it. - fn push(&mut self, row: PatStack<'p>) { - if !row.is_empty() && row.head().is_or_pat() { - self.patterns.extend(row.expand_or_pat()); - } else { - self.patterns.push(row); - } - } - - /// Iterate over the first component of each row - fn heads(&self) -> impl Iterator> + Clone + Captures<'_> { - self.patterns.iter().map(|r| r.head()) - } - - /// This computes `S(constructor, self)`. See top of the file for explanations. - fn specialize_constructor(&self, pcx: PatCtxt<'_, 'p>, ctor: &Constructor) -> Matrix<'p> { - let mut matrix = Matrix::empty(); - for row in &self.patterns { - if ctor.is_covered_by(pcx, row.head().ctor()) { - let new_row = row.pop_head_constructor(pcx.cx, ctor); - matrix.push(new_row); - } - } - matrix - } -} - -/// This carries the results of computing usefulness, as described at the top of the file. When -/// checking usefulness of a match branch, we use the `NoWitnesses` variant, which also keeps track -/// of potential unreachable sub-patterns (in the presence of or-patterns). When checking -/// exhaustiveness of a whole match, we use the `WithWitnesses` variant, which carries a list of -/// witnesses of non-exhaustiveness when there are any. -/// Which variant to use is dictated by `ArmType`. -enum Usefulness<'p> { - /// If we don't care about witnesses, simply remember if the pattern was useful. - NoWitnesses { useful: bool }, - /// Carries a list of witnesses of non-exhaustiveness. If empty, indicates that the whole - /// pattern is unreachable. - WithWitnesses(Vec>), -} - -impl<'p> Usefulness<'p> { - fn new_useful(preference: ArmType) -> Self { - match preference { - // A single (empty) witness of reachability. - FakeExtraWildcard => WithWitnesses(vec![Witness(vec![])]), - RealArm => NoWitnesses { useful: true }, - } - } - fn new_not_useful(preference: ArmType) -> Self { - match preference { - FakeExtraWildcard => WithWitnesses(vec![]), - RealArm => NoWitnesses { useful: false }, - } - } - - fn is_useful(&self) -> bool { - match self { - Usefulness::NoWitnesses { useful } => *useful, - Usefulness::WithWitnesses(witnesses) => !witnesses.is_empty(), - } - } - - /// Combine usefulnesses from two branches. This is an associative operation. - fn extend(&mut self, other: Self) { - match (&mut *self, other) { - (WithWitnesses(_), WithWitnesses(o)) if o.is_empty() => {} - (WithWitnesses(s), WithWitnesses(o)) if s.is_empty() => *self = WithWitnesses(o), - (WithWitnesses(s), WithWitnesses(o)) => s.extend(o), - (NoWitnesses { useful: s_useful }, NoWitnesses { useful: o_useful }) => { - *s_useful = *s_useful || o_useful - } - _ => unreachable!(), - } - } - - /// After calculating usefulness after a specialization, call this to reconstruct a usefulness - /// that makes sense for the matrix pre-specialization. This new usefulness can then be merged - /// with the results of specializing with the other constructors. - fn apply_constructor( - self, - pcx: PatCtxt<'_, 'p>, - matrix: &Matrix<'p>, - ctor: &Constructor, - ) -> Self { - match self { - NoWitnesses { .. } => self, - WithWitnesses(ref witnesses) if witnesses.is_empty() => self, - WithWitnesses(witnesses) => { - let new_witnesses = if let Constructor::Missing { .. } = ctor { - // We got the special `Missing` constructor, so each of the missing constructors - // gives a new pattern that is not caught by the match. We list those patterns. - let new_patterns = if pcx.is_non_exhaustive { - // Here we don't want the user to try to list all variants, we want them to add - // a wildcard, so we only suggest that. - vec![DeconstructedPat::wildcard(pcx.ty.clone())] - } else { - let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); - - // This lets us know if we skipped any variants because they are marked - // `doc(hidden)` or they are unstable feature gate (only stdlib types). - let mut hide_variant_show_wild = false; - // Construct for each missing constructor a "wild" version of this - // constructor, that matches everything that can be built with - // it. For example, if `ctor` is a `Constructor::Variant` for - // `Option::Some`, we get the pattern `Some(_)`. - let mut new: Vec> = split_wildcard - .iter_missing(pcx) - .filter_map(|missing_ctor| { - // Check if this variant is marked `doc(hidden)` - if missing_ctor.is_doc_hidden_variant(pcx) - || missing_ctor.is_unstable_variant(pcx) - { - hide_variant_show_wild = true; - return None; - } - Some(DeconstructedPat::wild_from_ctor(pcx, missing_ctor.clone())) - }) - .collect(); - - if hide_variant_show_wild { - new.push(DeconstructedPat::wildcard(pcx.ty.clone())) - } - - new - }; - - witnesses - .into_iter() - .flat_map(|witness| { - new_patterns.iter().map(move |pat| { - Witness( - witness - .0 - .iter() - .chain(once(pat)) - .map(DeconstructedPat::clone_and_forget_reachability) - .collect(), - ) - }) - }) - .collect() - } else { - witnesses - .into_iter() - .map(|witness| witness.apply_constructor(pcx, ctor)) - .collect() - }; - WithWitnesses(new_witnesses) - } - } - } -} - -#[derive(Copy, Clone, Debug)] -enum ArmType { - FakeExtraWildcard, - RealArm, -} - -/// A witness of non-exhaustiveness for error reporting, represented -/// as a list of patterns (in reverse order of construction) with -/// wildcards inside to represent elements that can take any inhabitant -/// of the type as a value. -/// -/// A witness against a list of patterns should have the same types -/// and length as the pattern matched against. Because Rust `match` -/// is always against a single pattern, at the end the witness will -/// have length 1, but in the middle of the algorithm, it can contain -/// multiple patterns. -/// -/// For example, if we are constructing a witness for the match against -/// -/// ``` -/// struct Pair(Option<(u32, u32)>, bool); -/// -/// match (p: Pair) { -/// Pair(None, _) => {} -/// Pair(_, false) => {} -/// } -/// ``` -/// -/// We'll perform the following steps: -/// 1. Start with an empty witness -/// `Witness(vec![])` -/// 2. Push a witness `true` against the `false` -/// `Witness(vec![true])` -/// 3. Push a witness `Some(_)` against the `None` -/// `Witness(vec![true, Some(_)])` -/// 4. Apply the `Pair` constructor to the witnesses -/// `Witness(vec![Pair(Some(_), true)])` -/// -/// The final `Pair(Some(_), true)` is then the resulting witness. -pub(crate) struct Witness<'p>(Vec>); - -impl<'p> Witness<'p> { - /// Asserts that the witness contains a single pattern, and returns it. - fn single_pattern(self) -> DeconstructedPat<'p> { - assert_eq!(self.0.len(), 1); - self.0.into_iter().next().unwrap() - } - - /// Constructs a partial witness for a pattern given a list of - /// patterns expanded by the specialization step. - /// - /// When a pattern P is discovered to be useful, this function is used bottom-up - /// to reconstruct a complete witness, e.g., a pattern P' that covers a subset - /// of values, V, where each value in that set is not covered by any previously - /// used patterns and is covered by the pattern P'. Examples: - /// - /// left_ty: tuple of 3 elements - /// pats: [10, 20, _] => (10, 20, _) - /// - /// left_ty: struct X { a: (bool, &'static str), b: usize} - /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 } - fn apply_constructor(mut self, pcx: PatCtxt<'_, 'p>, ctor: &Constructor) -> Self { - let pat = { - let len = self.0.len(); - let arity = ctor.arity(pcx); - let pats = self.0.drain((len - arity)..).rev(); - let fields = Fields::from_iter(pcx.cx, pats); - DeconstructedPat::new(ctor.clone(), fields, pcx.ty.clone()) - }; - - self.0.push(pat); - - self - } -} - -/// Algorithm from . -/// The algorithm from the paper has been modified to correctly handle empty -/// types. The changes are: -/// (0) We don't exit early if the pattern matrix has zero rows. We just -/// continue to recurse over columns. -/// (1) all_constructors will only return constructors that are statically -/// possible. E.g., it will only return `Ok` for `Result`. -/// -/// This finds whether a (row) vector `v` of patterns is 'useful' in relation -/// to a set of such vectors `m` - this is defined as there being a set of -/// inputs that will match `v` but not any of the sets in `m`. -/// -/// All the patterns at each column of the `matrix ++ v` matrix must have the same type. -/// -/// This is used both for reachability checking (if a pattern isn't useful in -/// relation to preceding patterns, it is not reachable) and exhaustiveness -/// checking (if a wildcard pattern is useful in relation to a matrix, the -/// matrix isn't exhaustive). -/// -/// `is_under_guard` is used to inform if the pattern has a guard. If it -/// has one it must not be inserted into the matrix. This shouldn't be -/// relied on for soundness. -fn is_useful<'p>( - cx: &MatchCheckCtx<'_, 'p>, - matrix: &Matrix<'p>, - v: &PatStack<'p>, - witness_preference: ArmType, - is_under_guard: bool, - is_top_level: bool, -) -> Usefulness<'p> { - let Matrix { patterns: rows, .. } = matrix; - - // The base case. We are pattern-matching on () and the return value is - // based on whether our matrix has a row or not. - // NOTE: This could potentially be optimized by checking rows.is_empty() - // first and then, if v is non-empty, the return value is based on whether - // the type of the tuple we're checking is inhabited or not. - if v.is_empty() { - let ret = if rows.is_empty() { - Usefulness::new_useful(witness_preference) - } else { - Usefulness::new_not_useful(witness_preference) - }; - return ret; - } - - debug_assert!(rows.iter().all(|r| r.len() == v.len())); - - let ty = v.head().ty(); - let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty); - let pcx = PatCtxt { cx, ty, is_top_level, is_non_exhaustive }; - - // If the first pattern is an or-pattern, expand it. - let mut ret = Usefulness::new_not_useful(witness_preference); - if v.head().is_or_pat() { - // We try each or-pattern branch in turn. - let mut matrix = matrix.clone(); - for v in v.expand_or_pat() { - let usefulness = is_useful(cx, &matrix, &v, witness_preference, is_under_guard, false); - ret.extend(usefulness); - // If pattern has a guard don't add it to the matrix. - if !is_under_guard { - // We push the already-seen patterns into the matrix in order to detect redundant - // branches like `Some(_) | Some(0)`. - matrix.push(v); - } - } - } else { - let v_ctor = v.head().ctor(); - - // FIXME: implement `overlapping_range_endpoints` lint - - // We split the head constructor of `v`. - let split_ctors = v_ctor.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); - // For each constructor, we compute whether there's a value that starts with it that would - // witness the usefulness of `v`. - let start_matrix = matrix; - for ctor in split_ctors { - // We cache the result of `Fields::wildcards` because it is used a lot. - let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor); - let v = v.pop_head_constructor(cx, &ctor); - let usefulness = - is_useful(cx, &spec_matrix, &v, witness_preference, is_under_guard, false); - let usefulness = usefulness.apply_constructor(pcx, start_matrix, &ctor); - - // FIXME: implement `non_exhaustive_omitted_patterns` lint - - ret.extend(usefulness); - } - }; - - if ret.is_useful() { - v.head().set_reachable(); - } - - ret -} - -/// The arm of a match expression. -#[derive(Clone, Copy)] -pub(crate) struct MatchArm<'p> { - pub(crate) pat: &'p DeconstructedPat<'p>, - pub(crate) has_guard: bool, -} - -/// Indicates whether or not a given arm is reachable. -#[derive(Clone, Debug)] -pub(crate) enum Reachability { - /// The arm is reachable. This additionally carries a set of or-pattern branches that have been - /// found to be unreachable despite the overall arm being reachable. Used only in the presence - /// of or-patterns, otherwise it stays empty. - // FIXME: store ureachable subpattern IDs - Reachable, - /// The arm is unreachable. - Unreachable, -} - -/// The output of checking a match for exhaustiveness and arm reachability. -pub(crate) struct UsefulnessReport<'p> { - /// For each arm of the input, whether that arm is reachable after the arms above it. - pub(crate) _arm_usefulness: Vec<(MatchArm<'p>, Reachability)>, - /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of - /// exhaustiveness. - pub(crate) non_exhaustiveness_witnesses: Vec>, -} - -/// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which -/// of its arms are reachable. -/// -/// Note: the input patterns must have been lowered through -/// `check_match::MatchVisitor::lower_pattern`. -pub(crate) fn compute_match_usefulness<'p>( - cx: &MatchCheckCtx<'_, 'p>, - arms: &[MatchArm<'p>], - scrut_ty: &Ty, -) -> UsefulnessReport<'p> { - let mut matrix = Matrix::empty(); - let arm_usefulness = arms - .iter() - .copied() - .map(|arm| { - let v = PatStack::from_pattern(arm.pat); - is_useful(cx, &matrix, &v, RealArm, arm.has_guard, true); - if !arm.has_guard { - matrix.push(v); - } - let reachability = if arm.pat.is_reachable() { - Reachability::Reachable - } else { - Reachability::Unreachable - }; - (arm, reachability) - }) - .collect(); - - let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty.clone())); - let v = PatStack::from_pattern(wild_pattern); - let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, false, true); - let non_exhaustiveness_witnesses = match usefulness { - WithWitnesses(pats) => pats.into_iter().map(Witness::single_pattern).collect(), - NoWitnesses { .. } => panic!("bug"), - }; - UsefulnessReport { _arm_usefulness: arm_usefulness, non_exhaustiveness_witnesses } -} - -pub(crate) mod helper { - // Copy-pasted from rust/compiler/rustc_data_structures/src/captures.rs - /// "Signaling" trait used in impl trait to tag lifetimes that you may - /// need to capture but don't really need for other reasons. - /// Basically a workaround; see [this comment] for details. - /// - /// [this comment]: https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999 - // FIXME(eddyb) false positive, the lifetime parameter is "phantom" but needed. - #[allow(unused_lifetimes)] - pub(crate) trait Captures<'a> {} - - impl<'a, T: ?Sized> Captures<'a> for T {} -} 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 deleted file mode 100644 index 161b19a739ce4..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ /dev/null @@ -1,104 +0,0 @@ -//! Provides validations for unsafe code. Currently checks if unsafe functions are missing -//! unsafe blocks. - -use hir_def::{ - body::Body, - expr::{Expr, ExprId, UnaryOp}, - resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, - DefWithBodyId, -}; - -use crate::{ - db::HirDatabase, utils::is_fn_unsafe_to_call, InferenceResult, Interner, TyExt, TyKind, -}; - -pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec { - let infer = db.infer(def); - let mut res = Vec::new(); - - let is_unsafe = match def { - DefWithBodyId::FunctionId(it) => db.function_data(it).has_unsafe_kw(), - DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false, - }; - if is_unsafe { - return res; - } - - let body = db.body(def); - unsafe_expressions(db, &infer, def, &body, body.body_expr, &mut |expr| { - if !expr.inside_unsafe_block { - res.push(expr.expr); - } - }); - - res -} - -pub struct UnsafeExpr { - pub expr: ExprId, - pub inside_unsafe_block: bool, -} - -// FIXME: Move this out, its not a diagnostic only thing anymore, and handle unsafe pattern accesses as well -pub fn unsafe_expressions( - db: &dyn HirDatabase, - infer: &InferenceResult, - def: DefWithBodyId, - body: &Body, - current: ExprId, - unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr), -) { - walk_unsafe(db, infer, def, body, current, false, unsafe_expr_cb) -} - -fn walk_unsafe( - db: &dyn HirDatabase, - infer: &InferenceResult, - def: DefWithBodyId, - body: &Body, - current: ExprId, - inside_unsafe_block: bool, - unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr), -) { - let expr = &body.exprs[current]; - match expr { - &Expr::Call { callee, .. } => { - if let Some(func) = infer[callee].as_fn_def(db) { - if is_fn_unsafe_to_call(db, func) { - unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block }); - } - } - } - Expr::Path(path) => { - let resolver = resolver_for_expr(db.upcast(), def, current); - let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path.mod_path()); - if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial { - if db.static_data(id).mutable { - unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block }); - } - } - } - Expr::MethodCall { .. } => { - if infer - .method_resolution(current) - .map(|(func, _)| is_fn_unsafe_to_call(db, func)) - .unwrap_or(false) - { - unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block }); - } - } - Expr::UnaryOp { expr, op: UnaryOp::Deref } => { - if let TyKind::Raw(..) = &infer[*expr].kind(Interner) { - unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block }); - } - } - Expr::Unsafe { body: child } => { - return walk_unsafe(db, infer, def, body, *child, true, unsafe_expr_cb); - } - _ => {} - } - - expr.walk_child_exprs(|child| { - walk_unsafe(db, infer, def, body, child, inside_unsafe_block, unsafe_expr_cb); - }); -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs deleted file mode 100644 index d2f9c2b8b1e1d..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ /dev/null @@ -1,1315 +0,0 @@ -//! The `HirDisplay` trait, which serves two purposes: Turning various bits from -//! HIR back into source code, and just displaying them for debugging/testing -//! purposes. - -use std::fmt::{self, Debug}; - -use base_db::CrateId; -use chalk_ir::BoundVar; -use hir_def::{ - body, - db::DefDatabase, - find_path, - generics::{TypeOrConstParamData, TypeParamProvenance}, - intern::{Internable, Interned}, - item_scope::ItemInNs, - path::{Path, PathKind}, - type_ref::{ConstScalar, TraitBoundModifier, TypeBound, TypeRef}, - visibility::Visibility, - HasModule, ItemContainerId, Lookup, ModuleId, TraitId, -}; -use hir_expand::{hygiene::Hygiene, name::Name}; -use itertools::Itertools; -use syntax::SmolStr; - -use crate::{ - db::HirDatabase, - from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx, - mapping::from_chalk, - primitive, subst_prefix, to_assoc_type_id, - utils::{self, generics}, - AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstValue, DomainGoal, - GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability, - OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar, Substitution, TraitRef, - TraitRefExt, Ty, TyExt, TyKind, WhereClause, -}; - -pub struct HirFormatter<'a> { - pub db: &'a dyn HirDatabase, - fmt: &'a mut dyn fmt::Write, - buf: String, - curr_size: usize, - pub(crate) max_size: Option, - omit_verbose_types: bool, - display_target: DisplayTarget, -} - -pub trait HirDisplay { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>; - - /// Returns a `Display`able type that is human-readable. - fn into_displayable<'a>( - &'a self, - db: &'a dyn HirDatabase, - max_size: Option, - omit_verbose_types: bool, - display_target: DisplayTarget, - ) -> HirDisplayWrapper<'a, Self> - where - Self: Sized, - { - assert!( - !matches!(display_target, DisplayTarget::SourceCode { .. }), - "HirDisplayWrapper cannot fail with DisplaySourceCodeError, use HirDisplay::hir_fmt directly instead" - ); - HirDisplayWrapper { db, t: self, max_size, omit_verbose_types, display_target } - } - - /// Returns a `Display`able type that is human-readable. - /// Use this for showing types to the user (e.g. diagnostics) - fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self> - where - Self: Sized, - { - HirDisplayWrapper { - db, - t: self, - max_size: None, - omit_verbose_types: false, - display_target: DisplayTarget::Diagnostics, - } - } - - /// Returns a `Display`able type that is human-readable and tries to be succinct. - /// Use this for showing types to the user where space is constrained (e.g. doc popups) - fn display_truncated<'a>( - &'a self, - db: &'a dyn HirDatabase, - max_size: Option, - ) -> HirDisplayWrapper<'a, Self> - where - Self: Sized, - { - HirDisplayWrapper { - db, - t: self, - max_size, - omit_verbose_types: true, - display_target: DisplayTarget::Diagnostics, - } - } - - /// Returns a String representation of `self` that can be inserted into the given module. - /// Use this when generating code (e.g. assists) - fn display_source_code<'a>( - &'a self, - db: &'a dyn HirDatabase, - module_id: ModuleId, - ) -> Result { - let mut result = String::new(); - match self.hir_fmt(&mut HirFormatter { - db, - fmt: &mut result, - buf: String::with_capacity(20), - curr_size: 0, - max_size: None, - omit_verbose_types: false, - display_target: DisplayTarget::SourceCode { module_id }, - }) { - Ok(()) => {} - Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"), - Err(HirDisplayError::DisplaySourceCodeError(e)) => return Err(e), - }; - Ok(result) - } - - /// Returns a String representation of `self` for test purposes - fn display_test<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self> - where - Self: Sized, - { - HirDisplayWrapper { - db, - t: self, - max_size: None, - omit_verbose_types: false, - display_target: DisplayTarget::Test, - } - } -} - -impl<'a> HirFormatter<'a> { - pub fn write_joined( - &mut self, - iter: impl IntoIterator, - sep: &str, - ) -> Result<(), HirDisplayError> { - let mut first = true; - for e in iter { - if !first { - write!(self, "{}", sep)?; - } - first = false; - - // Abbreviate multiple omitted types with a single ellipsis. - if self.should_truncate() { - return write!(self, "{}", TYPE_HINT_TRUNCATION); - } - - e.hir_fmt(self)?; - } - Ok(()) - } - - /// This allows using the `write!` macro directly with a `HirFormatter`. - pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), HirDisplayError> { - // We write to a buffer first to track output size - self.buf.clear(); - fmt::write(&mut self.buf, args)?; - self.curr_size += self.buf.len(); - - // Then we write to the internal formatter from the buffer - self.fmt.write_str(&self.buf).map_err(HirDisplayError::from) - } - - pub fn write_str(&mut self, s: &str) -> Result<(), HirDisplayError> { - self.fmt.write_str(s)?; - Ok(()) - } - - pub fn write_char(&mut self, c: char) -> Result<(), HirDisplayError> { - self.fmt.write_char(c)?; - Ok(()) - } - - pub fn should_truncate(&self) -> bool { - match self.max_size { - Some(max_size) => self.curr_size >= max_size, - None => false, - } - } - - pub fn omit_verbose_types(&self) -> bool { - self.omit_verbose_types - } -} - -#[derive(Clone, Copy)] -pub enum DisplayTarget { - /// Display types for inlays, doc popups, autocompletion, etc... - /// Showing `{unknown}` or not qualifying paths is fine here. - /// There's no reason for this to fail. - Diagnostics, - /// Display types for inserting them in source files. - /// The generated code should compile, so paths need to be qualified. - SourceCode { module_id: ModuleId }, - /// Only for test purpose to keep real types - Test, -} - -impl DisplayTarget { - fn is_source_code(&self) -> bool { - matches!(self, Self::SourceCode { .. }) - } - fn is_test(&self) -> bool { - matches!(self, Self::Test) - } -} - -#[derive(Debug)] -pub enum DisplaySourceCodeError { - PathNotFound, - UnknownType, - Closure, -} - -pub enum HirDisplayError { - /// Errors that can occur when generating source code - DisplaySourceCodeError(DisplaySourceCodeError), - /// `FmtError` is required to be compatible with std::fmt::Display - FmtError, -} -impl From for HirDisplayError { - fn from(_: fmt::Error) -> Self { - Self::FmtError - } -} - -pub struct HirDisplayWrapper<'a, T> { - db: &'a dyn HirDatabase, - t: &'a T, - max_size: Option, - omit_verbose_types: bool, - display_target: DisplayTarget, -} - -impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T> -where - T: HirDisplay, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.t.hir_fmt(&mut HirFormatter { - db: self.db, - fmt: f, - buf: String::with_capacity(20), - curr_size: 0, - max_size: self.max_size, - omit_verbose_types: self.omit_verbose_types, - display_target: self.display_target, - }) { - Ok(()) => Ok(()), - Err(HirDisplayError::FmtError) => Err(fmt::Error), - Err(HirDisplayError::DisplaySourceCodeError(_)) => { - // This should never happen - panic!("HirDisplay::hir_fmt failed with DisplaySourceCodeError when calling Display::fmt!") - } - } - } -} - -const TYPE_HINT_TRUNCATION: &str = "…"; - -impl HirDisplay for &'_ T { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - HirDisplay::hir_fmt(*self, f) - } -} - -impl HirDisplay for Interned { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - HirDisplay::hir_fmt(self.as_ref(), f) - } -} - -impl HirDisplay for ProjectionTy { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - if f.should_truncate() { - return write!(f, "{}", TYPE_HINT_TRUNCATION); - } - - let trait_ = f.db.trait_data(self.trait_(f.db)); - write!(f, "<")?; - self.self_type_parameter(Interner).hir_fmt(f)?; - write!(f, " as {}", trait_.name)?; - if self.substitution.len(Interner) > 1 { - write!(f, "<")?; - f.write_joined(&self.substitution.as_slice(Interner)[1..], ", ")?; - write!(f, ">")?; - } - write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?; - Ok(()) - } -} - -impl HirDisplay for OpaqueTy { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - if f.should_truncate() { - return write!(f, "{}", TYPE_HINT_TRUNCATION); - } - - self.substitution.at(Interner, 0).hir_fmt(f) - } -} - -impl HirDisplay for GenericArg { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match self.interned() { - crate::GenericArgData::Ty(ty) => ty.hir_fmt(f), - crate::GenericArgData::Lifetime(lt) => lt.hir_fmt(f), - crate::GenericArgData::Const(c) => c.hir_fmt(f), - } - } -} - -impl HirDisplay for Const { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - let data = self.interned(); - match data.value { - ConstValue::BoundVar(idx) => idx.hir_fmt(f), - ConstValue::InferenceVar(..) => write!(f, "#c#"), - ConstValue::Placeholder(idx) => { - let id = from_placeholder_idx(f.db, idx); - let generics = generics(f.db.upcast(), id.parent); - let param_data = &generics.params.type_or_consts[id.local_id]; - write!(f, "{}", param_data.name().unwrap()) - } - ConstValue::Concrete(c) => write!(f, "{}", c.interned), - } - } -} - -impl HirDisplay for BoundVar { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "?{}.{}", self.debruijn.depth(), self.index) - } -} - -impl HirDisplay for Ty { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - if f.should_truncate() { - return write!(f, "{}", TYPE_HINT_TRUNCATION); - } - - match self.kind(Interner) { - TyKind::Never => write!(f, "!")?, - TyKind::Str => write!(f, "str")?, - TyKind::Scalar(Scalar::Bool) => write!(f, "bool")?, - TyKind::Scalar(Scalar::Char) => write!(f, "char")?, - &TyKind::Scalar(Scalar::Float(t)) => write!(f, "{}", primitive::float_ty_to_string(t))?, - &TyKind::Scalar(Scalar::Int(t)) => write!(f, "{}", primitive::int_ty_to_string(t))?, - &TyKind::Scalar(Scalar::Uint(t)) => write!(f, "{}", primitive::uint_ty_to_string(t))?, - TyKind::Slice(t) => { - write!(f, "[")?; - t.hir_fmt(f)?; - write!(f, "]")?; - } - TyKind::Array(t, c) => { - write!(f, "[")?; - t.hir_fmt(f)?; - write!(f, "; ")?; - c.hir_fmt(f)?; - write!(f, "]")?; - } - TyKind::Raw(m, t) | TyKind::Ref(m, _, t) => { - if matches!(self.kind(Interner), TyKind::Raw(..)) { - write!( - f, - "*{}", - match m { - Mutability::Not => "const ", - Mutability::Mut => "mut ", - } - )?; - } else { - write!( - f, - "&{}", - match m { - Mutability::Not => "", - Mutability::Mut => "mut ", - } - )?; - } - - // FIXME: all this just to decide whether to use parentheses... - let contains_impl_fn = |bounds: &[QuantifiedWhereClause]| { - bounds.iter().any(|bound| { - if let WhereClause::Implemented(trait_ref) = bound.skip_binders() { - let trait_ = trait_ref.hir_trait_id(); - fn_traits(f.db.upcast(), trait_).any(|it| it == trait_) - } else { - false - } - }) - }; - let (preds_to_print, has_impl_fn_pred) = match t.kind(Interner) { - TyKind::Dyn(dyn_ty) if dyn_ty.bounds.skip_binders().interned().len() > 1 => { - let bounds = dyn_ty.bounds.skip_binders().interned(); - (bounds.len(), contains_impl_fn(bounds)) - } - TyKind::Alias(AliasTy::Opaque(OpaqueTy { - opaque_ty_id, - substitution: parameters, - })) - | TyKind::OpaqueType(opaque_ty_id, parameters) => { - let impl_trait_id = - f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into()); - if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id { - let datas = - f.db.return_type_impl_traits(func) - .expect("impl trait id without data"); - let data = (*datas) - .as_ref() - .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); - let bounds = data.substitute(Interner, parameters); - let mut len = bounds.skip_binders().len(); - - // Don't count Sized but count when it absent - // (i.e. when explicit ?Sized bound is set). - let default_sized = SizedByDefault::Sized { - anchor: func.lookup(f.db.upcast()).module(f.db.upcast()).krate(), - }; - let sized_bounds = bounds - .skip_binders() - .iter() - .filter(|b| { - matches!( - b.skip_binders(), - WhereClause::Implemented(trait_ref) - if default_sized.is_sized_trait( - trait_ref.hir_trait_id(), - f.db.upcast(), - ), - ) - }) - .count(); - match sized_bounds { - 0 => len += 1, - _ => { - len = len.saturating_sub(sized_bounds); - } - } - - (len, contains_impl_fn(bounds.skip_binders())) - } else { - (0, false) - } - } - _ => (0, false), - }; - - if has_impl_fn_pred && preds_to_print <= 2 { - return t.hir_fmt(f); - } - - if preds_to_print > 1 { - write!(f, "(")?; - t.hir_fmt(f)?; - write!(f, ")")?; - } else { - t.hir_fmt(f)?; - } - } - TyKind::Tuple(_, substs) => { - if substs.len(Interner) == 1 { - write!(f, "(")?; - substs.at(Interner, 0).hir_fmt(f)?; - write!(f, ",)")?; - } else { - write!(f, "(")?; - f.write_joined(&*substs.as_slice(Interner), ", ")?; - write!(f, ")")?; - } - } - TyKind::Function(fn_ptr) => { - let sig = CallableSig::from_fn_ptr(fn_ptr); - sig.hir_fmt(f)?; - } - TyKind::FnDef(def, parameters) => { - let def = from_chalk(f.db, *def); - let sig = f.db.callable_item_signature(def).substitute(Interner, parameters); - match def { - CallableDefId::FunctionId(ff) => { - write!(f, "fn {}", f.db.function_data(ff).name)? - } - CallableDefId::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?, - CallableDefId::EnumVariantId(e) => { - write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)? - } - }; - if parameters.len(Interner) > 0 { - let generics = generics(f.db.upcast(), def.into()); - let (parent_params, self_param, type_params, const_params, _impl_trait_params) = - generics.provenance_split(); - let total_len = parent_params + self_param + type_params + const_params; - // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? - if total_len > 0 { - write!(f, "<")?; - f.write_joined(¶meters.as_slice(Interner)[..total_len], ", ")?; - write!(f, ">")?; - } - } - write!(f, "(")?; - f.write_joined(sig.params(), ", ")?; - write!(f, ")")?; - let ret = sig.ret(); - if !ret.is_unit() { - write!(f, " -> ")?; - ret.hir_fmt(f)?; - } - } - TyKind::Adt(AdtId(def_id), parameters) => { - match f.display_target { - DisplayTarget::Diagnostics | DisplayTarget::Test => { - let name = match *def_id { - hir_def::AdtId::StructId(it) => f.db.struct_data(it).name.clone(), - hir_def::AdtId::UnionId(it) => f.db.union_data(it).name.clone(), - hir_def::AdtId::EnumId(it) => f.db.enum_data(it).name.clone(), - }; - write!(f, "{}", name)?; - } - DisplayTarget::SourceCode { module_id } => { - if let Some(path) = find_path::find_path( - f.db.upcast(), - ItemInNs::Types((*def_id).into()), - module_id, - ) { - write!(f, "{}", path)?; - } else { - return Err(HirDisplayError::DisplaySourceCodeError( - DisplaySourceCodeError::PathNotFound, - )); - } - } - } - - if parameters.len(Interner) > 0 { - let parameters_to_write = if f.display_target.is_source_code() - || f.omit_verbose_types() - { - match self - .as_generic_def(f.db) - .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) - .filter(|defaults| !defaults.is_empty()) - { - None => parameters.as_slice(Interner), - Some(default_parameters) => { - fn should_show( - parameter: &GenericArg, - default_parameters: &[Binders], - i: usize, - parameters: &Substitution, - ) -> bool { - if parameter.ty(Interner).map(|x| x.kind(Interner)) - == Some(&TyKind::Error) - { - return true; - } - if let Some(ConstValue::Concrete(c)) = - parameter.constant(Interner).map(|x| x.data(Interner).value) - { - if c.interned == ConstScalar::Unknown { - return true; - } - } - let default_parameter = match default_parameters.get(i) { - Some(x) => x, - None => return true, - }; - let actual_default = default_parameter - .clone() - .substitute(Interner, &subst_prefix(parameters, i)); - parameter != &actual_default - } - let mut default_from = 0; - for (i, parameter) in parameters.iter(Interner).enumerate() { - if should_show(parameter, &default_parameters, i, parameters) { - default_from = i + 1; - } - } - ¶meters.as_slice(Interner)[0..default_from] - } - } - } else { - parameters.as_slice(Interner) - }; - if !parameters_to_write.is_empty() { - write!(f, "<")?; - - if f.display_target.is_source_code() { - let mut first = true; - for generic_arg in parameters_to_write { - if !first { - write!(f, ", ")?; - } - first = false; - - if generic_arg.ty(Interner).map(|ty| ty.kind(Interner)) - == Some(&TyKind::Error) - { - write!(f, "_")?; - } else { - generic_arg.hir_fmt(f)?; - } - } - } else { - f.write_joined(parameters_to_write, ", ")?; - } - - write!(f, ">")?; - } - } - } - TyKind::AssociatedType(assoc_type_id, parameters) => { - let type_alias = from_assoc_type_id(*assoc_type_id); - let trait_ = match type_alias.lookup(f.db.upcast()).container { - ItemContainerId::TraitId(it) => it, - _ => panic!("not an associated type"), - }; - let trait_ = f.db.trait_data(trait_); - let type_alias_data = f.db.type_alias_data(type_alias); - - // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types) - if f.display_target.is_test() { - write!(f, "{}::{}", trait_.name, type_alias_data.name)?; - if parameters.len(Interner) > 0 { - write!(f, "<")?; - f.write_joined(&*parameters.as_slice(Interner), ", ")?; - write!(f, ">")?; - } - } else { - let projection_ty = ProjectionTy { - associated_ty_id: to_assoc_type_id(type_alias), - substitution: parameters.clone(), - }; - - projection_ty.hir_fmt(f)?; - } - } - TyKind::Foreign(type_alias) => { - let type_alias = f.db.type_alias_data(from_foreign_def_id(*type_alias)); - write!(f, "{}", type_alias.name)?; - } - TyKind::OpaqueType(opaque_ty_id, parameters) => { - let impl_trait_id = f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into()); - match impl_trait_id { - ImplTraitId::ReturnTypeImplTrait(func, idx) => { - let datas = - f.db.return_type_impl_traits(func).expect("impl trait id without data"); - let data = (*datas) - .as_ref() - .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); - let bounds = data.substitute(Interner, ¶meters); - let krate = func.lookup(f.db.upcast()).module(f.db.upcast()).krate(); - write_bounds_like_dyn_trait_with_prefix( - "impl", - bounds.skip_binders(), - SizedByDefault::Sized { anchor: krate }, - f, - )?; - // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution - } - ImplTraitId::AsyncBlockTypeImplTrait(..) => { - write!(f, "impl Future")?; - } - } - } - TyKind::Closure(.., substs) => { - if f.display_target.is_source_code() { - return Err(HirDisplayError::DisplaySourceCodeError( - DisplaySourceCodeError::Closure, - )); - } - let sig = substs.at(Interner, 0).assert_ty_ref(Interner).callable_sig(f.db); - if let Some(sig) = sig { - if sig.params().is_empty() { - write!(f, "||")?; - } else if f.should_truncate() { - write!(f, "|{}|", TYPE_HINT_TRUNCATION)?; - } else { - write!(f, "|")?; - f.write_joined(sig.params(), ", ")?; - write!(f, "|")?; - }; - - write!(f, " -> ")?; - sig.ret().hir_fmt(f)?; - } else { - write!(f, "{{closure}}")?; - } - } - TyKind::Placeholder(idx) => { - let id = from_placeholder_idx(f.db, *idx); - let generics = generics(f.db.upcast(), id.parent); - let param_data = &generics.params.type_or_consts[id.local_id]; - match param_data { - TypeOrConstParamData::TypeParamData(p) => match p.provenance { - TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { - write!(f, "{}", p.name.clone().unwrap_or_else(Name::missing))? - } - TypeParamProvenance::ArgumentImplTrait => { - let substs = generics.placeholder_subst(f.db); - let bounds = - f.db.generic_predicates(id.parent) - .iter() - .map(|pred| pred.clone().substitute(Interner, &substs)) - .filter(|wc| match &wc.skip_binders() { - WhereClause::Implemented(tr) => { - &tr.self_type_parameter(Interner) == self - } - WhereClause::AliasEq(AliasEq { - alias: AliasTy::Projection(proj), - ty: _, - }) => &proj.self_type_parameter(Interner) == self, - _ => false, - }) - .collect::>(); - let krate = id.parent.module(f.db.upcast()).krate(); - write_bounds_like_dyn_trait_with_prefix( - "impl", - &bounds, - SizedByDefault::Sized { anchor: krate }, - f, - )?; - } - }, - TypeOrConstParamData::ConstParamData(p) => { - write!(f, "{}", p.name)?; - } - } - } - TyKind::BoundVar(idx) => idx.hir_fmt(f)?, - TyKind::Dyn(dyn_ty) => { - write_bounds_like_dyn_trait_with_prefix( - "dyn", - dyn_ty.bounds.skip_binders().interned(), - SizedByDefault::NotSized, - f, - )?; - } - TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?, - TyKind::Alias(AliasTy::Opaque(opaque_ty)) => { - let impl_trait_id = f.db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into()); - match impl_trait_id { - ImplTraitId::ReturnTypeImplTrait(func, idx) => { - let datas = - f.db.return_type_impl_traits(func).expect("impl trait id without data"); - let data = (*datas) - .as_ref() - .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); - let bounds = data.substitute(Interner, &opaque_ty.substitution); - let krate = func.lookup(f.db.upcast()).module(f.db.upcast()).krate(); - write_bounds_like_dyn_trait_with_prefix( - "impl", - bounds.skip_binders(), - SizedByDefault::Sized { anchor: krate }, - f, - )?; - } - ImplTraitId::AsyncBlockTypeImplTrait(..) => { - write!(f, "{{async block}}")?; - } - }; - } - TyKind::Error => { - if f.display_target.is_source_code() { - return Err(HirDisplayError::DisplaySourceCodeError( - DisplaySourceCodeError::UnknownType, - )); - } - write!(f, "{{unknown}}")?; - } - TyKind::InferenceVar(..) => write!(f, "_")?, - TyKind::Generator(..) => write!(f, "{{generator}}")?, - TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?, - } - Ok(()) - } -} - -impl HirDisplay for CallableSig { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "fn(")?; - f.write_joined(self.params(), ", ")?; - if self.is_varargs { - if self.params().is_empty() { - write!(f, "...")?; - } else { - write!(f, ", ...")?; - } - } - write!(f, ")")?; - let ret = self.ret(); - if !ret.is_unit() { - write!(f, " -> ")?; - ret.hir_fmt(f)?; - } - Ok(()) - } -} - -fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator { - let krate = trait_.lookup(db).container.krate(); - utils::fn_traits(db, krate) -} - -#[derive(Clone, Copy, PartialEq, Eq)] -pub enum SizedByDefault { - NotSized, - Sized { anchor: CrateId }, -} - -impl SizedByDefault { - fn is_sized_trait(self, trait_: TraitId, db: &dyn DefDatabase) -> bool { - match self { - Self::NotSized => false, - Self::Sized { anchor } => { - let sized_trait = db - .lang_item(anchor, SmolStr::new_inline("sized")) - .and_then(|lang_item| lang_item.as_trait()); - Some(trait_) == sized_trait - } - } - } -} - -pub fn write_bounds_like_dyn_trait_with_prefix( - prefix: &str, - predicates: &[QuantifiedWhereClause], - default_sized: SizedByDefault, - f: &mut HirFormatter<'_>, -) -> Result<(), HirDisplayError> { - write!(f, "{}", prefix)?; - if !predicates.is_empty() - || predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. }) - { - write!(f, " ")?; - write_bounds_like_dyn_trait(predicates, default_sized, f) - } else { - Ok(()) - } -} - -fn write_bounds_like_dyn_trait( - predicates: &[QuantifiedWhereClause], - default_sized: SizedByDefault, - f: &mut HirFormatter<'_>, -) -> Result<(), HirDisplayError> { - // Note: This code is written to produce nice results (i.e. - // corresponding to surface Rust) for types that can occur in - // actual Rust. It will have weird results if the predicates - // aren't as expected (i.e. self types = $0, projection - // predicates for a certain trait come after the Implemented - // predicate for that trait). - let mut first = true; - let mut angle_open = false; - let mut is_fn_trait = false; - let mut is_sized = false; - for p in predicates.iter() { - match p.skip_binders() { - WhereClause::Implemented(trait_ref) => { - let trait_ = trait_ref.hir_trait_id(); - if default_sized.is_sized_trait(trait_, f.db.upcast()) { - is_sized = true; - if matches!(default_sized, SizedByDefault::Sized { .. }) { - // Don't print +Sized, but rather +?Sized if absent. - continue; - } - } - if !is_fn_trait { - is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_); - } - if !is_fn_trait && angle_open { - write!(f, ">")?; - angle_open = false; - } - if !first { - write!(f, " + ")?; - } - // We assume that the self type is ^0.0 (i.e. the - // existential) here, which is the only thing that's - // possible in actual Rust, and hence don't print it - write!(f, "{}", f.db.trait_data(trait_).name)?; - if let [_, params @ ..] = &*trait_ref.substitution.as_slice(Interner) { - if is_fn_trait { - if let Some(args) = - params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple()) - { - write!(f, "(")?; - f.write_joined(args.as_slice(Interner), ", ")?; - write!(f, ")")?; - } - } else if !params.is_empty() { - write!(f, "<")?; - f.write_joined(params, ", ")?; - // there might be assoc type bindings, so we leave the angle brackets open - angle_open = true; - } - } - } - WhereClause::AliasEq(alias_eq) if is_fn_trait => { - is_fn_trait = false; - if !alias_eq.ty.is_unit() { - write!(f, " -> ")?; - alias_eq.ty.hir_fmt(f)?; - } - } - WhereClause::AliasEq(AliasEq { ty, alias }) => { - // in types in actual Rust, these will always come - // after the corresponding Implemented predicate - if angle_open { - write!(f, ", ")?; - } else { - write!(f, "<")?; - angle_open = true; - } - if let AliasTy::Projection(proj) = alias { - let type_alias = - f.db.type_alias_data(from_assoc_type_id(proj.associated_ty_id)); - write!(f, "{} = ", type_alias.name)?; - } - ty.hir_fmt(f)?; - } - - // FIXME implement these - WhereClause::LifetimeOutlives(_) => {} - WhereClause::TypeOutlives(_) => {} - } - first = false; - } - if angle_open { - write!(f, ">")?; - } - if matches!(default_sized, SizedByDefault::Sized { .. }) { - if !is_sized { - write!(f, "{}?Sized", if first { "" } else { " + " })?; - } else if first { - write!(f, "Sized")?; - } - } - Ok(()) -} - -fn fmt_trait_ref( - tr: &TraitRef, - f: &mut HirFormatter<'_>, - use_as: bool, -) -> Result<(), HirDisplayError> { - if f.should_truncate() { - return write!(f, "{}", TYPE_HINT_TRUNCATION); - } - - tr.self_type_parameter(Interner).hir_fmt(f)?; - if use_as { - write!(f, " as ")?; - } else { - write!(f, ": ")?; - } - write!(f, "{}", f.db.trait_data(tr.hir_trait_id()).name)?; - if tr.substitution.len(Interner) > 1 { - write!(f, "<")?; - f.write_joined(&tr.substitution.as_slice(Interner)[1..], ", ")?; - write!(f, ">")?; - } - Ok(()) -} - -impl HirDisplay for TraitRef { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - fmt_trait_ref(self, f, false) - } -} - -impl HirDisplay for WhereClause { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - if f.should_truncate() { - return write!(f, "{}", TYPE_HINT_TRUNCATION); - } - - match self { - WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, - WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => { - write!(f, "<")?; - fmt_trait_ref(&projection_ty.trait_ref(f.db), f, true)?; - write!( - f, - ">::{} = ", - f.db.type_alias_data(from_assoc_type_id(projection_ty.associated_ty_id)).name, - )?; - ty.hir_fmt(f)?; - } - WhereClause::AliasEq(_) => write!(f, "{{error}}")?, - - // FIXME implement these - WhereClause::TypeOutlives(..) => {} - WhereClause::LifetimeOutlives(..) => {} - } - Ok(()) - } -} - -impl HirDisplay for LifetimeOutlives { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - self.a.hir_fmt(f)?; - write!(f, ": ")?; - self.b.hir_fmt(f) - } -} - -impl HirDisplay for Lifetime { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - self.interned().hir_fmt(f) - } -} - -impl HirDisplay for LifetimeData { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match self { - LifetimeData::BoundVar(idx) => idx.hir_fmt(f), - LifetimeData::InferenceVar(_) => write!(f, "_"), - 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.lifetimes[id.local_id]; - write!(f, "{}", param_data.name) - } - LifetimeData::Static => write!(f, "'static"), - LifetimeData::Empty(_) => Ok(()), - LifetimeData::Erased => Ok(()), - LifetimeData::Phantom(_, _) => Ok(()), - } - } -} - -impl HirDisplay for DomainGoal { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match self { - DomainGoal::Holds(wc) => { - write!(f, "Holds(")?; - wc.hir_fmt(f)?; - write!(f, ")")?; - } - _ => write!(f, "?")?, - } - Ok(()) - } -} - -pub fn write_visibility( - module_id: ModuleId, - vis: Visibility, - f: &mut HirFormatter<'_>, -) -> Result<(), HirDisplayError> { - match vis { - Visibility::Public => write!(f, "pub "), - Visibility::Module(vis_id) => { - let def_map = module_id.def_map(f.db.upcast()); - let root_module_id = def_map.module_id(def_map.root()); - if vis_id == module_id { - // pub(self) or omitted - Ok(()) - } else if root_module_id == vis_id { - write!(f, "pub(crate) ") - } else if module_id.containing_module(f.db.upcast()) == Some(vis_id) { - write!(f, "pub(super) ") - } else { - write!(f, "pub(in ...) ") - } - } - } -} - -impl HirDisplay for TypeRef { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match self { - TypeRef::Never => write!(f, "!")?, - TypeRef::Placeholder => write!(f, "_")?, - TypeRef::Tuple(elems) => { - write!(f, "(")?; - f.write_joined(elems, ", ")?; - if elems.len() == 1 { - write!(f, ",")?; - } - write!(f, ")")?; - } - TypeRef::Path(path) => path.hir_fmt(f)?, - TypeRef::RawPtr(inner, mutability) => { - let mutability = match mutability { - hir_def::type_ref::Mutability::Shared => "*const ", - hir_def::type_ref::Mutability::Mut => "*mut ", - }; - write!(f, "{}", mutability)?; - inner.hir_fmt(f)?; - } - TypeRef::Reference(inner, lifetime, mutability) => { - let mutability = match mutability { - hir_def::type_ref::Mutability::Shared => "", - hir_def::type_ref::Mutability::Mut => "mut ", - }; - write!(f, "&")?; - if let Some(lifetime) = lifetime { - write!(f, "{} ", lifetime.name)?; - } - write!(f, "{}", mutability)?; - inner.hir_fmt(f)?; - } - TypeRef::Array(inner, len) => { - write!(f, "[")?; - inner.hir_fmt(f)?; - write!(f, "; {}]", len)?; - } - TypeRef::Slice(inner) => { - write!(f, "[")?; - inner.hir_fmt(f)?; - write!(f, "]")?; - } - TypeRef::Fn(parameters, is_varargs) => { - // FIXME: Function pointer qualifiers. - write!(f, "fn(")?; - if let Some(((_, return_type), function_parameters)) = parameters.split_last() { - for index in 0..function_parameters.len() { - let (param_name, param_type) = &function_parameters[index]; - if let Some(name) = param_name { - write!(f, "{}: ", name)?; - } - - param_type.hir_fmt(f)?; - - if index != function_parameters.len() - 1 { - write!(f, ", ")?; - } - } - if *is_varargs { - write!(f, "{}...", if parameters.len() == 1 { "" } else { ", " })?; - } - write!(f, ")")?; - match &return_type { - TypeRef::Tuple(tup) if tup.is_empty() => {} - _ => { - write!(f, " -> ")?; - return_type.hir_fmt(f)?; - } - } - } - } - TypeRef::ImplTrait(bounds) => { - write!(f, "impl ")?; - f.write_joined(bounds, " + ")?; - } - TypeRef::DynTrait(bounds) => { - write!(f, "dyn ")?; - f.write_joined(bounds, " + ")?; - } - TypeRef::Macro(macro_call) => { - let macro_call = macro_call.to_node(f.db.upcast()); - let ctx = body::LowerCtx::with_hygiene(f.db.upcast(), &Hygiene::new_unhygienic()); - match macro_call.path() { - Some(path) => match Path::from_src(path, &ctx) { - Some(path) => path.hir_fmt(f)?, - None => write!(f, "{{macro}}")?, - }, - None => write!(f, "{{macro}}")?, - } - write!(f, "!(..)")?; - } - TypeRef::Error => write!(f, "{{error}}")?, - } - Ok(()) - } -} - -impl HirDisplay for TypeBound { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match self { - TypeBound::Path(path, modifier) => { - match modifier { - TraitBoundModifier::None => (), - TraitBoundModifier::Maybe => write!(f, "?")?, - } - path.hir_fmt(f) - } - TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name), - TypeBound::ForLifetime(lifetimes, path) => { - write!(f, "for<{}> ", lifetimes.iter().format(", "))?; - path.hir_fmt(f) - } - TypeBound::Error => write!(f, "{{error}}"), - } - } -} - -impl HirDisplay for Path { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match (self.type_anchor(), self.kind()) { - (Some(anchor), _) => { - write!(f, "<")?; - anchor.hir_fmt(f)?; - write!(f, ">")?; - } - (_, PathKind::Plain) => {} - (_, PathKind::Abs) => {} - (_, PathKind::Crate) => write!(f, "crate")?, - (_, PathKind::Super(0)) => write!(f, "self")?, - (_, PathKind::Super(n)) => { - for i in 0..*n { - if i > 0 { - write!(f, "::")?; - } - write!(f, "super")?; - } - } - (_, PathKind::DollarCrate(id)) => { - // Resolve `$crate` to the crate's display name. - // FIXME: should use the dependency name instead if available, but that depends on - // the crate invoking `HirDisplay` - let crate_graph = f.db.crate_graph(); - let name = crate_graph[*id] - .display_name - .as_ref() - .map(|name| name.canonical_name()) - .unwrap_or("$crate"); - write!(f, "{name}")? - } - } - - for (seg_idx, segment) in self.segments().iter().enumerate() { - if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 { - write!(f, "::")?; - } - write!(f, "{}", segment.name)?; - if let Some(generic_args) = segment.args_and_bindings { - // We should be in type context, so format as `Foo` instead of `Foo::`. - // Do we actually format expressions? - if generic_args.desugared_from_fn { - // First argument will be a tuple, which already includes the parentheses. - // If the tuple only contains 1 item, write it manually to avoid the trailing `,`. - if let hir_def::path::GenericArg::Type(TypeRef::Tuple(v)) = - &generic_args.args[0] - { - if v.len() == 1 { - write!(f, "(")?; - v[0].hir_fmt(f)?; - write!(f, ")")?; - } else { - generic_args.args[0].hir_fmt(f)?; - } - } - if let Some(ret) = &generic_args.bindings[0].type_ref { - if !matches!(ret, TypeRef::Tuple(v) if v.is_empty()) { - write!(f, " -> ")?; - ret.hir_fmt(f)?; - } - } - return Ok(()); - } - - write!(f, "<")?; - let mut first = true; - for arg in &generic_args.args { - if first { - first = false; - if generic_args.has_self_type { - // FIXME: Convert to `` form. - write!(f, "Self = ")?; - } - } else { - write!(f, ", ")?; - } - arg.hir_fmt(f)?; - } - for binding in &generic_args.bindings { - if first { - first = false; - } else { - write!(f, ", ")?; - } - write!(f, "{}", binding.name)?; - match &binding.type_ref { - Some(ty) => { - write!(f, " = ")?; - ty.hir_fmt(f)? - } - None => { - write!(f, ": ")?; - f.write_joined(&binding.bounds, " + ")?; - } - } - } - write!(f, ">")?; - } - } - Ok(()) - } -} - -impl HirDisplay for hir_def::path::GenericArg { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match self { - hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f), - hir_def::path::GenericArg::Const(c) => write!(f, "{}", c), - hir_def::path::GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name), - } - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs deleted file mode 100644 index 46eeea0e6fc4e..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ /dev/null @@ -1,1088 +0,0 @@ -//! Type inference, i.e. the process of walking through the code and determining -//! the type of each expression and pattern. -//! -//! For type inference, compare the implementations in rustc (the various -//! check_* methods in librustc_typeck/check/mod.rs are a good entry point) and -//! IntelliJ-Rust (org.rust.lang.core.types.infer). Our entry point for -//! inference here is the `infer` function, which infers the types of all -//! expressions in a given function. -//! -//! During inference, types (i.e. the `Ty` struct) can contain type 'variables' -//! which represent currently unknown types; as we walk through the expressions, -//! we might determine that certain variables need to be equal to each other, or -//! to certain types. To record this, we use the union-find implementation from -//! the `ena` crate, which is extracted from rustc. - -use std::ops::Index; -use std::sync::Arc; - -use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags}; -use hir_def::{ - body::Body, - data::{ConstData, StaticData}, - expr::{BindingAnnotation, ExprId, PatId}, - lang_item::LangItemTarget, - path::{path, Path}, - resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, - type_ref::TypeRef, - AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup, - TraitId, TypeAliasId, VariantId, -}; -use hir_expand::name::{name, Name}; -use itertools::Either; -use la_arena::ArenaMap; -use rustc_hash::FxHashMap; -use stdx::{always, impl_from}; - -use crate::{ - db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany, - lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal, - GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, Substitution, - TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, -}; - -// This lint has a false positive here. See the link below for details. -// -// https://github.com/rust-lang/rust/issues/57411 -#[allow(unreachable_pub)] -pub use coerce::could_coerce; -#[allow(unreachable_pub)] -pub use unify::could_unify; - -pub(crate) mod unify; -mod path; -mod expr; -mod pat; -mod coerce; -mod closure; - -/// The entry point of type inference. -pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { - let _p = profile::span("infer_query"); - let resolver = def.resolver(db.upcast()); - let body = db.body(def); - let mut ctx = InferenceContext::new(db, def, &body, resolver); - - match def { - DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)), - DefWithBodyId::FunctionId(f) => ctx.collect_fn(f), - DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)), - } - - ctx.infer_body(); - - Arc::new(ctx.resolve_all()) -} - -/// Fully normalize all the types found within `ty` in context of `owner` body definition. -/// -/// This is appropriate to use only after type-check: it assumes -/// that normalization will succeed, for example. -pub(crate) fn normalize(db: &dyn HirDatabase, owner: DefWithBodyId, ty: Ty) -> Ty { - if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION) { - return ty; - } - let krate = owner.module(db.upcast()).krate(); - let trait_env = owner - .as_generic_def_id() - .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d)); - let mut table = unify::InferenceTable::new(db, trait_env); - - let ty_with_vars = table.normalize_associated_types_in(ty); - table.resolve_obligations_as_possible(); - table.propagate_diverging_flag(); - table.resolve_completely(ty_with_vars) -} - -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -enum ExprOrPatId { - ExprId(ExprId), - PatId(PatId), -} -impl_from!(ExprId, PatId for ExprOrPatId); - -/// Binding modes inferred for patterns. -/// -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum BindingMode { - Move, - Ref(Mutability), -} - -impl BindingMode { - fn convert(annotation: BindingAnnotation) -> BindingMode { - match annotation { - BindingAnnotation::Unannotated | BindingAnnotation::Mutable => BindingMode::Move, - BindingAnnotation::Ref => BindingMode::Ref(Mutability::Not), - BindingAnnotation::RefMut => BindingMode::Ref(Mutability::Mut), - } - } -} - -impl Default for BindingMode { - fn default() -> Self { - BindingMode::Move - } -} - -/// Used to generalize patterns and assignee expressions. -trait PatLike: Into + Copy { - type BindingMode: Copy; - - fn infer( - this: &mut InferenceContext<'_>, - id: Self, - expected_ty: &Ty, - default_bm: Self::BindingMode, - ) -> Ty; -} - -impl PatLike for ExprId { - type BindingMode = (); - - fn infer( - this: &mut InferenceContext<'_>, - id: Self, - expected_ty: &Ty, - _: Self::BindingMode, - ) -> Ty { - this.infer_assignee_expr(id, expected_ty) - } -} - -impl PatLike for PatId { - type BindingMode = BindingMode; - - fn infer( - this: &mut InferenceContext<'_>, - id: Self, - expected_ty: &Ty, - default_bm: Self::BindingMode, - ) -> Ty { - this.infer_pat(id, expected_ty, default_bm) - } -} - -#[derive(Debug)] -pub(crate) struct InferOk { - value: T, - goals: Vec>, -} - -impl InferOk { - fn map(self, f: impl FnOnce(T) -> U) -> InferOk { - InferOk { value: f(self.value), goals: self.goals } - } -} - -#[derive(Debug)] -pub(crate) struct TypeError; -pub(crate) type InferResult = Result, TypeError>; - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum InferenceDiagnostic { - NoSuchField { expr: ExprId }, - BreakOutsideOfLoop { expr: ExprId }, - MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize }, -} - -/// A mismatch between an expected and an inferred type. -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct TypeMismatch { - pub expected: Ty, - pub actual: Ty, -} - -#[derive(Clone, PartialEq, Eq, Debug)] -struct InternedStandardTypes { - unknown: Ty, - bool_: Ty, - unit: Ty, -} - -impl Default for InternedStandardTypes { - fn default() -> Self { - InternedStandardTypes { - unknown: TyKind::Error.intern(Interner), - bool_: TyKind::Scalar(Scalar::Bool).intern(Interner), - unit: TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner), - } - } -} -/// Represents coercing a value to a different type of value. -/// -/// We transform values by following a number of `Adjust` steps in order. -/// See the documentation on variants of `Adjust` for more details. -/// -/// Here are some common scenarios: -/// -/// 1. The simplest cases are where a pointer is not adjusted fat vs thin. -/// Here the pointer will be dereferenced N times (where a dereference can -/// happen to raw or borrowed pointers or any smart pointer which implements -/// Deref, including Box<_>). The types of dereferences is given by -/// `autoderefs`. It can then be auto-referenced zero or one times, indicated -/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is -/// `false`. -/// -/// 2. A thin-to-fat coercion involves unsizing the underlying data. We start -/// with a thin pointer, deref a number of times, unsize the underlying data, -/// then autoref. The 'unsize' phase may change a fixed length array to a -/// dynamically sized one, a concrete object to a trait object, or statically -/// sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is -/// represented by: -/// -/// ``` -/// Deref(None) -> [i32; 4], -/// Borrow(AutoBorrow::Ref) -> &[i32; 4], -/// Unsize -> &[i32], -/// ``` -/// -/// Note that for a struct, the 'deep' unsizing of the struct is not recorded. -/// E.g., `struct Foo { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> -/// The autoderef and -ref are the same as in the above example, but the type -/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about -/// the underlying conversions from `[i32; 4]` to `[i32]`. -/// -/// 3. Coercing a `Box` to `Box` is an interesting special case. In -/// that case, we have the pointer we need coming in, so there are no -/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. -/// At some point, of course, `Box` should move out of the compiler, in which -/// case this is analogous to transforming a struct. E.g., Box<[i32; 4]> -> -/// Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Adjustment { - pub kind: Adjust, - pub target: Ty, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum Adjust { - /// Go from ! to any type. - NeverToAny, - /// Dereference once, producing a place. - Deref(Option), - /// Take the address and produce either a `&` or `*` pointer. - Borrow(AutoBorrow), - Pointer(PointerCast), -} - -/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)` -/// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`. -/// The target type is `U` in both cases, with the region and mutability -/// being those shared by both the receiver and the returned reference. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OverloadedDeref(pub Mutability); - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum AutoBorrow { - /// Converts from T to &T. - Ref(Mutability), - /// Converts from T to *T. - RawPtr(Mutability), -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum PointerCast { - /// Go from a fn-item type to a fn-pointer type. - ReifyFnPointer, - - /// Go from a safe fn pointer to an unsafe fn pointer. - UnsafeFnPointer, - - /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer. - /// It cannot convert a closure that requires unsafe. - ClosureFnPointer(Safety), - - /// Go from a mut raw pointer to a const raw pointer. - MutToConstPointer, - - #[allow(dead_code)] - /// Go from `*const [T; N]` to `*const T` - ArrayToPointer, - - /// Unsize a pointer/reference value, e.g., `&[T; n]` to - /// `&[T]`. Note that the source could be a thin or fat pointer. - /// This will do things like convert thin pointers to fat - /// pointers, or convert structs containing thin pointers to - /// structs containing fat pointers, or convert between fat - /// pointers. We don't store the details of how the transform is - /// done (in fact, we don't know that, because it might depend on - /// the precise type parameters). We just store the target - /// type. Codegen backends and miri figure out what has to be done - /// based on the precise source/target type at hand. - Unsize, -} - -/// The result of type inference: A mapping from expressions and patterns to types. -#[derive(Clone, PartialEq, Eq, Debug, Default)] -pub struct InferenceResult { - /// For each method call expr, records the function it resolves to. - method_resolutions: FxHashMap, - /// For each field access expr, records the field it resolves to. - field_resolutions: FxHashMap, - /// For each struct literal or pattern, records the variant it resolves to. - variant_resolutions: FxHashMap, - /// For each associated item record what it resolves to - assoc_resolutions: FxHashMap, - pub diagnostics: Vec, - pub type_of_expr: ArenaMap, - /// For each pattern record the type it resolves to. - /// - /// **Note**: When a pattern type is resolved it may still contain - /// unresolved or missing subpatterns or subpatterns of mismatched types. - pub type_of_pat: ArenaMap, - type_mismatches: FxHashMap, - /// Interned Unknown to return references to. - standard_types: InternedStandardTypes, - /// Stores the types which were implicitly dereferenced in pattern binding modes. - pub pat_adjustments: FxHashMap>, - pub pat_binding_modes: FxHashMap, - pub expr_adjustments: FxHashMap>, -} - -impl InferenceResult { - pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, Substitution)> { - self.method_resolutions.get(&expr).cloned() - } - pub fn field_resolution(&self, expr: ExprId) -> Option { - self.field_resolutions.get(&expr).copied() - } - pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option { - self.variant_resolutions.get(&id.into()).copied() - } - pub fn variant_resolution_for_pat(&self, id: PatId) -> Option { - self.variant_resolutions.get(&id.into()).copied() - } - pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option { - self.assoc_resolutions.get(&id.into()).copied() - } - pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option { - self.assoc_resolutions.get(&id.into()).copied() - } - pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> { - self.type_mismatches.get(&expr.into()) - } - pub fn type_mismatch_for_pat(&self, pat: PatId) -> Option<&TypeMismatch> { - self.type_mismatches.get(&pat.into()) - } - pub fn expr_type_mismatches(&self) -> impl Iterator { - self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat { - ExprOrPatId::ExprId(expr) => Some((expr, mismatch)), - _ => None, - }) - } - pub fn pat_type_mismatches(&self) -> impl Iterator { - self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat { - ExprOrPatId::PatId(pat) => Some((pat, mismatch)), - _ => None, - }) - } -} - -impl Index for InferenceResult { - type Output = Ty; - - fn index(&self, expr: ExprId) -> &Ty { - self.type_of_expr.get(expr).unwrap_or(&self.standard_types.unknown) - } -} - -impl Index for InferenceResult { - type Output = Ty; - - fn index(&self, pat: PatId) -> &Ty { - self.type_of_pat.get(pat).unwrap_or(&self.standard_types.unknown) - } -} - -/// The inference context contains all information needed during type inference. -#[derive(Clone, Debug)] -pub(crate) struct InferenceContext<'a> { - pub(crate) db: &'a dyn HirDatabase, - pub(crate) owner: DefWithBodyId, - pub(crate) body: &'a Body, - pub(crate) resolver: Resolver, - table: unify::InferenceTable<'a>, - trait_env: Arc, - pub(crate) result: InferenceResult, - /// The return type of the function being inferred, the closure or async block if we're - /// currently within one. - /// - /// We might consider using a nested inference context for checking - /// closures, but currently this is the only field that will change there, - /// so it doesn't make sense. - return_ty: Ty, - diverges: Diverges, - breakables: Vec, -} - -#[derive(Clone, Debug)] -struct BreakableContext { - may_break: bool, - coerce: CoerceMany, - label: Option, -} - -fn find_breakable<'c>( - ctxs: &'c mut [BreakableContext], - label: Option<&name::Name>, -) -> Option<&'c mut BreakableContext> { - match label { - Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label), - None => ctxs.last_mut(), - } -} - -impl<'a> InferenceContext<'a> { - fn new( - db: &'a dyn HirDatabase, - owner: DefWithBodyId, - body: &'a Body, - resolver: Resolver, - ) -> Self { - let krate = owner.module(db.upcast()).krate(); - let trait_env = owner - .as_generic_def_id() - .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d)); - InferenceContext { - result: InferenceResult::default(), - table: unify::InferenceTable::new(db, trait_env.clone()), - trait_env, - return_ty: TyKind::Error.intern(Interner), // set in collect_fn_signature - db, - owner, - body, - resolver, - diverges: Diverges::Maybe, - breakables: Vec::new(), - } - } - - fn resolve_all(self) -> InferenceResult { - let InferenceContext { mut table, mut result, .. } = self; - - // FIXME resolve obligations as well (use Guidance if necessary) - table.resolve_obligations_as_possible(); - - // make sure diverging type variables are marked as such - table.propagate_diverging_flag(); - for ty in result.type_of_expr.values_mut() { - *ty = table.resolve_completely(ty.clone()); - } - for ty in result.type_of_pat.values_mut() { - *ty = table.resolve_completely(ty.clone()); - } - for mismatch in result.type_mismatches.values_mut() { - mismatch.expected = table.resolve_completely(mismatch.expected.clone()); - mismatch.actual = table.resolve_completely(mismatch.actual.clone()); - } - for (_, subst) in result.method_resolutions.values_mut() { - *subst = table.resolve_completely(subst.clone()); - } - for adjustment in result.expr_adjustments.values_mut().flatten() { - adjustment.target = table.resolve_completely(adjustment.target.clone()); - } - for adjustment in result.pat_adjustments.values_mut().flatten() { - *adjustment = table.resolve_completely(adjustment.clone()); - } - result - } - - fn collect_const(&mut self, data: &ConstData) { - self.return_ty = self.make_ty(&data.type_ref); - } - - fn collect_static(&mut self, data: &StaticData) { - self.return_ty = self.make_ty(&data.type_ref); - } - - fn collect_fn(&mut self, func: FunctionId) { - let data = self.db.function_data(func); - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) - .with_impl_trait_mode(ImplTraitLoweringMode::Param); - let param_tys = - data.params.iter().map(|(_, type_ref)| ctx.lower_ty(type_ref)).collect::>(); - for (ty, pat) in param_tys.into_iter().zip(self.body.params.iter()) { - let ty = self.insert_type_vars(ty); - let ty = self.normalize_associated_types_in(ty); - - self.infer_pat(*pat, &ty, BindingMode::default()); - } - let error_ty = &TypeRef::Error; - let return_ty = if data.has_async_kw() { - data.async_ret_type.as_deref().unwrap_or(error_ty) - } else { - &*data.ret_type - }; - let return_ty = self.make_ty_with_mode(return_ty, ImplTraitLoweringMode::Opaque); - self.return_ty = return_ty; - - if let Some(rpits) = self.db.return_type_impl_traits(func) { - // RPIT opaque types use substitution of their parent function. - let fn_placeholders = TyBuilder::placeholder_subst(self.db, func); - self.return_ty = fold_tys( - self.return_ty.clone(), - |ty, _| { - let opaque_ty_id = match ty.kind(Interner) { - TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id, - _ => return ty, - }; - let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) { - ImplTraitId::ReturnTypeImplTrait(_, idx) => idx, - _ => unreachable!(), - }; - let bounds = (*rpits).map_ref(|rpits| { - rpits.impl_traits[idx as usize].bounds.map_ref(|it| it.into_iter()) - }); - let var = self.table.new_type_var(); - let var_subst = Substitution::from1(Interner, var.clone()); - for bound in bounds { - let predicate = - bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders); - let (var_predicate, binders) = predicate - .substitute(Interner, &var_subst) - .into_value_and_skipped_binders(); - always!(binders.len(Interner) == 0); // quantified where clauses not yet handled - self.push_obligation(var_predicate.cast(Interner)); - } - var - }, - DebruijnIndex::INNERMOST, - ); - } - } - - fn infer_body(&mut self) { - self.infer_expr_coerce(self.body.body_expr, &Expectation::has_type(self.return_ty.clone())); - } - - fn write_expr_ty(&mut self, expr: ExprId, ty: Ty) { - self.result.type_of_expr.insert(expr, ty); - } - - fn write_expr_adj(&mut self, expr: ExprId, adjustments: Vec) { - self.result.expr_adjustments.insert(expr, adjustments); - } - - fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) { - self.result.method_resolutions.insert(expr, (func, subst)); - } - - fn write_variant_resolution(&mut self, id: ExprOrPatId, variant: VariantId) { - self.result.variant_resolutions.insert(id, variant); - } - - fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItemId) { - self.result.assoc_resolutions.insert(id, item); - } - - fn write_pat_ty(&mut self, pat: PatId, ty: Ty) { - self.result.type_of_pat.insert(pat, ty); - } - - fn push_diagnostic(&mut self, diagnostic: InferenceDiagnostic) { - self.result.diagnostics.push(diagnostic); - } - - fn make_ty_with_mode( - &mut self, - type_ref: &TypeRef, - impl_trait_mode: ImplTraitLoweringMode, - ) -> Ty { - // FIXME use right resolver for block - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) - .with_impl_trait_mode(impl_trait_mode); - let ty = ctx.lower_ty(type_ref); - let ty = self.insert_type_vars(ty); - self.normalize_associated_types_in(ty) - } - - fn make_ty(&mut self, type_ref: &TypeRef) -> Ty { - self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed) - } - - fn err_ty(&self) -> Ty { - self.result.standard_types.unknown.clone() - } - - /// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it. - fn insert_const_vars_shallow(&mut self, c: Const) -> Const { - let data = c.data(Interner); - match data.value { - ConstValue::Concrete(cc) => match cc.interned { - hir_def::type_ref::ConstScalar::Unknown => { - self.table.new_const_var(data.ty.clone()) - } - _ => c, - }, - _ => c, - } - } - - /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. - fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { - match ty.kind(Interner) { - TyKind::Error => self.table.new_type_var(), - TyKind::InferenceVar(..) => { - let ty_resolved = self.resolve_ty_shallow(&ty); - if ty_resolved.is_unknown() { - self.table.new_type_var() - } else { - ty - } - } - _ => ty, - } - } - - fn insert_type_vars(&mut self, ty: Ty) -> Ty { - fold_tys_and_consts( - ty, - |x, _| match x { - Either::Left(ty) => Either::Left(self.insert_type_vars_shallow(ty)), - Either::Right(c) => Either::Right(self.insert_const_vars_shallow(c)), - }, - DebruijnIndex::INNERMOST, - ) - } - - fn resolve_obligations_as_possible(&mut self) { - self.table.resolve_obligations_as_possible(); - } - - fn push_obligation(&mut self, o: DomainGoal) { - self.table.register_obligation(o.cast(Interner)); - } - - fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { - self.table.unify(ty1, ty2) - } - - /// Recurses through the given type, normalizing associated types mentioned - /// in it by replacing them by type variables and registering obligations to - /// resolve later. This should be done once for every type we get from some - /// type annotation (e.g. from a let type annotation, field type or function - /// call). `make_ty` handles this already, but e.g. for field types we need - /// to do it as well. - fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { - self.table.normalize_associated_types_in(ty) - } - - fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty { - self.resolve_obligations_as_possible(); - self.table.resolve_ty_shallow(ty) - } - - fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option) -> Ty { - self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[]) - } - - fn resolve_associated_type_with_params( - &mut self, - inner_ty: Ty, - assoc_ty: Option, - params: &[GenericArg], - ) -> Ty { - match assoc_ty { - Some(res_assoc_ty) => { - let trait_ = match res_assoc_ty.lookup(self.db.upcast()).container { - hir_def::ItemContainerId::TraitId(trait_) => trait_, - _ => panic!("resolve_associated_type called with non-associated type"), - }; - let ty = self.table.new_type_var(); - let mut param_iter = params.iter().cloned(); - let trait_ref = TyBuilder::trait_ref(self.db, trait_) - .push(inner_ty) - .fill(|_| param_iter.next().unwrap()) - .build(); - let alias_eq = AliasEq { - alias: AliasTy::Projection(ProjectionTy { - associated_ty_id: to_assoc_type_id(res_assoc_ty), - substitution: trait_ref.substitution.clone(), - }), - ty: ty.clone(), - }; - self.push_obligation(trait_ref.cast(Interner)); - self.push_obligation(alias_eq.cast(Interner)); - ty - } - None => self.err_ty(), - } - } - - fn resolve_variant(&mut self, path: Option<&Path>, value_ns: bool) -> (Ty, Option) { - let path = match path { - Some(path) => path, - None => return (self.err_ty(), None), - }; - let resolver = &self.resolver; - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); - // FIXME: this should resolve assoc items as well, see this example: - // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 - let (resolution, unresolved) = if value_ns { - match resolver.resolve_path_in_value_ns(self.db.upcast(), path.mod_path()) { - Some(ResolveValueResult::ValueNs(value)) => match value { - ValueNs::EnumVariantId(var) => { - let substs = ctx.substs_from_path(path, var.into(), true); - let ty = self.db.ty(var.parent.into()); - let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); - return (ty, Some(var.into())); - } - ValueNs::StructId(strukt) => { - let substs = ctx.substs_from_path(path, strukt.into(), true); - let ty = self.db.ty(strukt.into()); - let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); - return (ty, Some(strukt.into())); - } - _ => return (self.err_ty(), None), - }, - Some(ResolveValueResult::Partial(typens, unresolved)) => (typens, Some(unresolved)), - None => return (self.err_ty(), None), - } - } else { - match resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) { - Some(it) => it, - None => return (self.err_ty(), None), - } - }; - return match resolution { - TypeNs::AdtId(AdtId::StructId(strukt)) => { - let substs = ctx.substs_from_path(path, strukt.into(), true); - let ty = self.db.ty(strukt.into()); - let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); - forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) - } - TypeNs::AdtId(AdtId::UnionId(u)) => { - let substs = ctx.substs_from_path(path, u.into(), true); - let ty = self.db.ty(u.into()); - let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); - forbid_unresolved_segments((ty, Some(u.into())), unresolved) - } - TypeNs::EnumVariantId(var) => { - let substs = ctx.substs_from_path(path, var.into(), true); - let ty = self.db.ty(var.parent.into()); - let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); - forbid_unresolved_segments((ty, Some(var.into())), unresolved) - } - TypeNs::SelfType(impl_id) => { - let generics = crate::utils::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); - self.resolve_variant_on_alias(ty, unresolved, path) - } - TypeNs::TypeAliasId(it) => { - let ty = TyBuilder::def_ty(self.db, it.into()) - .fill_with_inference_vars(&mut self.table) - .build(); - self.resolve_variant_on_alias(ty, unresolved, path) - } - TypeNs::AdtSelfType(_) => { - // FIXME this could happen in array size expressions, once we're checking them - (self.err_ty(), None) - } - TypeNs::GenericParam(_) => { - // FIXME potentially resolve assoc type - (self.err_ty(), None) - } - TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::TraitId(_) => { - // FIXME diagnostic - (self.err_ty(), None) - } - }; - - fn forbid_unresolved_segments( - result: (Ty, Option), - unresolved: Option, - ) -> (Ty, Option) { - if unresolved.is_none() { - result - } else { - // FIXME diagnostic - (TyKind::Error.intern(Interner), None) - } - } - } - - fn resolve_variant_on_alias( - &mut self, - ty: Ty, - unresolved: Option, - path: &Path, - ) -> (Ty, Option) { - let remaining = unresolved.map(|x| path.segments().skip(x).len()).filter(|x| x > &0); - match remaining { - None => { - let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id { - AdtId::StructId(s) => Some(VariantId::StructId(s)), - AdtId::UnionId(u) => Some(VariantId::UnionId(u)), - AdtId::EnumId(_) => { - // FIXME Error E0071, expected struct, variant or union type, found enum `Foo` - None - } - }); - (ty, variant) - } - Some(1) => { - let segment = path.mod_path().segments().last().unwrap(); - // this could be an enum variant or associated type - if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() { - let enum_data = self.db.enum_data(enum_id); - if let Some(local_id) = enum_data.variant(segment) { - let variant = EnumVariantId { parent: enum_id, local_id }; - return (ty, Some(variant.into())); - } - } - // FIXME potentially resolve assoc type - (self.err_ty(), None) - } - Some(_) => { - // FIXME diagnostic - (self.err_ty(), None) - } - } - } - - fn resolve_lang_item(&self, name: Name) -> Option { - let krate = self.resolver.krate(); - self.db.lang_item(krate, name.to_smol_str()) - } - - fn resolve_into_iter_item(&self) -> Option { - let path = path![core::iter::IntoIterator]; - let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; - self.db.trait_data(trait_).associated_type_by_name(&name![Item]) - } - - fn resolve_ops_try_ok(&self) -> Option { - // FIXME resolve via lang_item once try v2 is stable - let path = path![core::ops::Try]; - let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; - let trait_data = self.db.trait_data(trait_); - trait_data - // FIXME remove once try v2 is stable - .associated_type_by_name(&name![Ok]) - .or_else(|| trait_data.associated_type_by_name(&name![Output])) - } - - fn resolve_ops_neg_output(&self) -> Option { - let trait_ = self.resolve_lang_item(name![neg])?.as_trait()?; - self.db.trait_data(trait_).associated_type_by_name(&name![Output]) - } - - fn resolve_ops_not_output(&self) -> Option { - let trait_ = self.resolve_lang_item(name![not])?.as_trait()?; - self.db.trait_data(trait_).associated_type_by_name(&name![Output]) - } - - fn resolve_future_future_output(&self) -> Option { - let trait_ = self.resolve_lang_item(name![future_trait])?.as_trait()?; - self.db.trait_data(trait_).associated_type_by_name(&name![Output]) - } - - fn resolve_boxed_box(&self) -> Option { - let struct_ = self.resolve_lang_item(name![owned_box])?.as_struct()?; - Some(struct_.into()) - } - - fn resolve_range_full(&self) -> Option { - let path = path![core::ops::RangeFull]; - let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; - Some(struct_.into()) - } - - fn resolve_range(&self) -> Option { - let path = path![core::ops::Range]; - let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; - Some(struct_.into()) - } - - fn resolve_range_inclusive(&self) -> Option { - let path = path![core::ops::RangeInclusive]; - let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; - Some(struct_.into()) - } - - fn resolve_range_from(&self) -> Option { - let path = path![core::ops::RangeFrom]; - let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; - Some(struct_.into()) - } - - fn resolve_range_to(&self) -> Option { - let path = path![core::ops::RangeTo]; - let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; - Some(struct_.into()) - } - - fn resolve_range_to_inclusive(&self) -> Option { - let path = path![core::ops::RangeToInclusive]; - let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; - Some(struct_.into()) - } - - fn resolve_ops_index(&self) -> Option { - self.resolve_lang_item(name![index])?.as_trait() - } - - fn resolve_ops_index_output(&self) -> Option { - let trait_ = self.resolve_ops_index()?; - self.db.trait_data(trait_).associated_type_by_name(&name![Output]) - } -} - -/// When inferring an expression, we propagate downward whatever type hint we -/// are able in the form of an `Expectation`. -#[derive(Clone, PartialEq, Eq, Debug)] -pub(crate) enum Expectation { - None, - HasType(Ty), - // Castable(Ty), // rustc has this, we currently just don't propagate an expectation for casts - RValueLikeUnsized(Ty), -} - -impl Expectation { - /// The expectation that the type of the expression needs to equal the given - /// type. - fn has_type(ty: Ty) -> Self { - if ty.is_unknown() { - // FIXME: get rid of this? - Expectation::None - } else { - Expectation::HasType(ty) - } - } - - fn from_option(ty: Option) -> Self { - ty.map_or(Expectation::None, Expectation::HasType) - } - - /// The following explanation is copied straight from rustc: - /// Provides an expectation for an rvalue expression given an *optional* - /// hint, which is not required for type safety (the resulting type might - /// be checked higher up, as is the case with `&expr` and `box expr`), but - /// is useful in determining the concrete type. - /// - /// The primary use case is where the expected type is a fat pointer, - /// like `&[isize]`. For example, consider the following statement: - /// - /// let x: &[isize] = &[1, 2, 3]; - /// - /// In this case, the expected type for the `&[1, 2, 3]` expression is - /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the - /// expectation `ExpectHasType([isize])`, that would be too strong -- - /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`. - /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced - /// to the type `&[isize]`. Therefore, we propagate this more limited hint, - /// which still is useful, because it informs integer literals and the like. - /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169 - /// for examples of where this comes up,. - fn rvalue_hint(table: &mut unify::InferenceTable<'_>, ty: Ty) -> Self { - // FIXME: do struct_tail_without_normalization - match table.resolve_ty_shallow(&ty).kind(Interner) { - TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => Expectation::RValueLikeUnsized(ty), - _ => Expectation::has_type(ty), - } - } - - /// This expresses no expectation on the type. - fn none() -> Self { - Expectation::None - } - - fn resolve(&self, table: &mut unify::InferenceTable<'_>) -> Expectation { - match self { - Expectation::None => Expectation::None, - Expectation::HasType(t) => Expectation::HasType(table.resolve_ty_shallow(t)), - Expectation::RValueLikeUnsized(t) => { - Expectation::RValueLikeUnsized(table.resolve_ty_shallow(t)) - } - } - } - - fn to_option(&self, table: &mut unify::InferenceTable<'_>) -> Option { - match self.resolve(table) { - Expectation::None => None, - Expectation::HasType(t) | - // Expectation::Castable(t) | - Expectation::RValueLikeUnsized(t) => Some(t), - } - } - - fn only_has_type(&self, table: &mut unify::InferenceTable<'_>) -> Option { - match self { - Expectation::HasType(t) => Some(table.resolve_ty_shallow(t)), - // Expectation::Castable(_) | - Expectation::RValueLikeUnsized(_) | Expectation::None => None, - } - } - - /// Comment copied from rustc: - /// Disregard "castable to" expectations because they - /// can lead us astray. Consider for example `if cond - /// {22} else {c} as u8` -- if we propagate the - /// "castable to u8" constraint to 22, it will pick the - /// type 22u8, which is overly constrained (c might not - /// be a u8). In effect, the problem is that the - /// "castable to" expectation is not the tightest thing - /// we can say, so we want to drop it in this case. - /// The tightest thing we can say is "must unify with - /// else branch". Note that in the case of a "has type" - /// constraint, this limitation does not hold. - /// - /// If the expected type is just a type variable, then don't use - /// an expected type. Otherwise, we might write parts of the type - /// when checking the 'then' block which are incompatible with the - /// 'else' branch. - fn adjust_for_branches(&self, table: &mut unify::InferenceTable<'_>) -> Expectation { - match self { - Expectation::HasType(ety) => { - let ety = table.resolve_ty_shallow(ety); - if !ety.is_ty_var() { - Expectation::HasType(ety) - } else { - Expectation::None - } - } - Expectation::RValueLikeUnsized(ety) => Expectation::RValueLikeUnsized(ety.clone()), - _ => Expectation::None, - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -enum Diverges { - Maybe, - Always, -} - -impl Diverges { - fn is_always(self) -> bool { - self == Diverges::Always - } -} - -impl std::ops::BitAnd for Diverges { - type Output = Self; - fn bitand(self, other: Self) -> Self { - std::cmp::min(self, other) - } -} - -impl std::ops::BitOr for Diverges { - type Output = Self; - fn bitor(self, other: Self) -> Self { - std::cmp::max(self, other) - } -} - -impl std::ops::BitAndAssign for Diverges { - fn bitand_assign(&mut self, other: Self) { - *self = *self & other; - } -} - -impl std::ops::BitOrAssign for Diverges { - fn bitor_assign(&mut self, other: Self) { - *self = *self | other; - } -} 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 deleted file mode 100644 index 3ead929098bcc..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ /dev/null @@ -1,82 +0,0 @@ -//! Inference of closure parameter types based on the closure's expected type. - -use chalk_ir::{cast::Cast, AliasEq, AliasTy, FnSubst, WhereClause}; -use hir_def::{expr::ExprId, HasModule}; -use smallvec::SmallVec; - -use crate::{ - to_chalk_trait_id, utils, ChalkTraitId, DynTy, FnPointer, FnSig, Interner, Substitution, Ty, - TyExt, TyKind, -}; - -use super::{Expectation, InferenceContext}; - -impl InferenceContext<'_> { - pub(super) fn deduce_closure_type_from_expectations( - &mut self, - closure_expr: ExprId, - closure_ty: &Ty, - sig_ty: &Ty, - expectation: &Expectation, - ) { - let expected_ty = match expectation.to_option(&mut self.table) { - Some(ty) => ty, - None => return, - }; - - // Deduction from where-clauses in scope, as well as fn-pointer coercion are handled here. - let _ = self.coerce(Some(closure_expr), closure_ty, &expected_ty); - - // Deduction based on the expected `dyn Fn` is done separately. - if let TyKind::Dyn(dyn_ty) = expected_ty.kind(Interner) { - if let Some(sig) = self.deduce_sig_from_dyn_ty(dyn_ty) { - let expected_sig_ty = TyKind::Function(sig).intern(Interner); - - self.unify(sig_ty, &expected_sig_ty); - } - } - } - - fn deduce_sig_from_dyn_ty(&self, dyn_ty: &DynTy) -> Option { - // Search for a predicate like `<$self as FnX>::Output == Ret` - - let fn_traits: SmallVec<[ChalkTraitId; 3]> = - utils::fn_traits(self.db.upcast(), self.owner.module(self.db.upcast()).krate()) - .map(to_chalk_trait_id) - .collect(); - - let self_ty = TyKind::Error.intern(Interner); - let bounds = dyn_ty.bounds.clone().substitute(Interner, &[self_ty.cast(Interner)]); - for bound in bounds.iter(Interner) { - // NOTE(skip_binders): the extracted types are rebound by the returned `FnPointer` - if let WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection), ty }) = - bound.skip_binders() - { - let assoc_data = self.db.associated_ty_data(projection.associated_ty_id); - if !fn_traits.contains(&assoc_data.trait_id) { - return None; - } - - // Skip `Self`, get the type argument. - let arg = projection.substitution.as_slice(Interner).get(1)?; - if let Some(subst) = arg.ty(Interner)?.as_tuple() { - let generic_args = subst.as_slice(Interner); - let mut sig_tys = Vec::new(); - for arg in generic_args { - sig_tys.push(arg.ty(Interner)?.clone()); - } - sig_tys.push(ty.clone()); - - cov_mark::hit!(dyn_fn_param_informs_call_site_closure_signature); - return Some(FnPointer { - num_binders: bound.len(Interner), - sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false }, - substitution: FnSubst(Substitution::from_iter(Interner, sig_tys)), - }); - } - } - } - - None - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs deleted file mode 100644 index f54440bf5b372..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs +++ /dev/null @@ -1,673 +0,0 @@ -//! Coercion logic. Coercions are certain type conversions that can implicitly -//! happen in certain places, e.g. weakening `&mut` to `&` or deref coercions -//! like going from `&Vec` to `&[T]`. -//! -//! See and -//! `librustc_typeck/check/coercion.rs`. - -use std::{iter, sync::Arc}; - -use chalk_ir::{cast::Cast, BoundVar, Goal, Mutability, TyVariableKind}; -use hir_def::{expr::ExprId, lang_item::LangItemTarget}; -use stdx::always; -use syntax::SmolStr; - -use crate::{ - autoderef::{Autoderef, AutoderefKind}, - db::HirDatabase, - infer::{ - Adjust, Adjustment, AutoBorrow, InferOk, InferenceContext, OverloadedDeref, PointerCast, - TypeError, TypeMismatch, - }, - static_lifetime, Canonical, DomainGoal, FnPointer, FnSig, Guidance, InEnvironment, Interner, - Solution, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, -}; - -use super::unify::InferenceTable; - -pub(crate) type CoerceResult = Result, Ty)>, TypeError>; - -/// Do not require any adjustments, i.e. coerce `x -> x`. -fn identity(_: Ty) -> Vec { - vec![] -} - -fn simple(kind: Adjust) -> impl FnOnce(Ty) -> Vec { - move |target| vec![Adjustment { kind, target }] -} - -/// This always returns `Ok(...)`. -fn success( - adj: Vec, - target: Ty, - goals: Vec>>, -) -> CoerceResult { - Ok(InferOk { goals, value: (adj, target) }) -} - -#[derive(Clone, Debug)] -pub(super) struct CoerceMany { - expected_ty: Ty, -} - -impl CoerceMany { - pub(super) fn new(expected: Ty) -> Self { - CoerceMany { expected_ty: expected } - } - - /// Merge two types from different branches, with possible coercion. - /// - /// Mostly this means trying to coerce one to the other, but - /// - if we have two function types for different functions or closures, we need to - /// coerce both to function pointers; - /// - if we were concerned with lifetime subtyping, we'd need to look for a - /// least upper bound. - pub(super) fn coerce( - &mut self, - ctx: &mut InferenceContext<'_>, - expr: Option, - expr_ty: &Ty, - ) { - let expr_ty = ctx.resolve_ty_shallow(expr_ty); - self.expected_ty = ctx.resolve_ty_shallow(&self.expected_ty); - - // Special case: two function types. Try to coerce both to - // pointers to have a chance at getting a match. See - // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 - let sig = match (self.expected_ty.kind(Interner), expr_ty.kind(Interner)) { - (TyKind::FnDef(..) | TyKind::Closure(..), TyKind::FnDef(..) | TyKind::Closure(..)) => { - // FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure, - // we should be coercing the closure to a fn pointer of the safety of the FnDef - cov_mark::hit!(coerce_fn_reification); - let sig = - self.expected_ty.callable_sig(ctx.db).expect("FnDef without callable sig"); - Some(sig) - } - _ => None, - }; - if let Some(sig) = sig { - let target_ty = TyKind::Function(sig.to_fn_ptr()).intern(Interner); - let result1 = ctx.table.coerce_inner(self.expected_ty.clone(), &target_ty); - let result2 = ctx.table.coerce_inner(expr_ty.clone(), &target_ty); - if let (Ok(result1), Ok(result2)) = (result1, result2) { - ctx.table.register_infer_ok(result1); - ctx.table.register_infer_ok(result2); - return self.expected_ty = target_ty; - } - } - - // It might not seem like it, but order is important here: If the expected - // type is a type variable and the new one is `!`, trying it the other - // way around first would mean we make the type variable `!`, instead of - // just marking it as possibly diverging. - if ctx.coerce(expr, &expr_ty, &self.expected_ty).is_ok() { - /* self.expected_ty is already correct */ - } else if ctx.coerce(expr, &self.expected_ty, &expr_ty).is_ok() { - self.expected_ty = expr_ty; - } else { - if let Some(id) = expr { - ctx.result.type_mismatches.insert( - id.into(), - TypeMismatch { expected: self.expected_ty.clone(), actual: expr_ty }, - ); - } - cov_mark::hit!(coerce_merge_fail_fallback); - /* self.expected_ty is already correct */ - } - } - - pub(super) fn complete(self) -> Ty { - self.expected_ty - } -} - -pub fn could_coerce( - db: &dyn HirDatabase, - env: Arc, - tys: &Canonical<(Ty, Ty)>, -) -> bool { - coerce(db, env, tys).is_ok() -} - -pub(crate) fn coerce( - db: &dyn HirDatabase, - env: Arc, - tys: &Canonical<(Ty, Ty)>, -) -> Result<(Vec, Ty), TypeError> { - let mut table = InferenceTable::new(db, env); - let vars = table.fresh_subst(tys.binders.as_slice(Interner)); - let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner); - let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner); - let (adjustments, ty) = table.coerce(&ty1_with_vars, &ty2_with_vars)?; - // default any type vars that weren't unified back to their original bound vars - // (kind of hacky) - let find_var = |iv| { - vars.iter(Interner).position(|v| match v.interned() { - chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(Interner), - chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(Interner), - chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner), - } == Some(iv)) - }; - let fallback = |iv, kind, default, binder| match kind { - chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv) - .map_or(default, |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner)), - chalk_ir::VariableKind::Lifetime => find_var(iv) - .map_or(default, |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner)), - chalk_ir::VariableKind::Const(ty) => find_var(iv) - .map_or(default, |i| BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner)), - }; - // FIXME also map the types in the adjustments - Ok((adjustments, table.resolve_with_fallback(ty, &fallback))) -} - -impl<'a> InferenceContext<'a> { - /// Unify two types, but may coerce the first one to the second one - /// using "implicit coercion rules" if needed. - pub(super) fn coerce( - &mut self, - expr: Option, - from_ty: &Ty, - to_ty: &Ty, - ) -> Result { - let from_ty = self.resolve_ty_shallow(from_ty); - let to_ty = self.resolve_ty_shallow(to_ty); - let (adjustments, ty) = self.table.coerce(&from_ty, &to_ty)?; - if let Some(expr) = expr { - self.write_expr_adj(expr, adjustments); - } - Ok(ty) - } -} - -impl<'a> InferenceTable<'a> { - /// Unify two types, but may coerce the first one to the second one - /// using "implicit coercion rules" if needed. - pub(crate) fn coerce( - &mut self, - from_ty: &Ty, - to_ty: &Ty, - ) -> Result<(Vec, Ty), TypeError> { - let from_ty = self.resolve_ty_shallow(from_ty); - let to_ty = self.resolve_ty_shallow(to_ty); - match self.coerce_inner(from_ty, &to_ty) { - Ok(InferOk { value: (adjustments, ty), goals }) => { - self.register_infer_ok(InferOk { value: (), goals }); - Ok((adjustments, ty)) - } - Err(e) => { - // FIXME deal with error - Err(e) - } - } - } - - fn coerce_inner(&mut self, from_ty: Ty, to_ty: &Ty) -> CoerceResult { - if from_ty.is_never() { - // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound - // type variable, we want `?T` to fallback to `!` if not - // otherwise constrained. An example where this arises: - // - // let _: Option = Some({ return; }); - // - // here, we would coerce from `!` to `?T`. - if let TyKind::InferenceVar(tv, TyVariableKind::General) = to_ty.kind(Interner) { - self.set_diverging(*tv, true); - } - return success(simple(Adjust::NeverToAny)(to_ty.clone()), to_ty.clone(), vec![]); - } - - // Consider coercing the subtype to a DST - if let Ok(ret) = self.try_coerce_unsized(&from_ty, to_ty) { - return Ok(ret); - } - - // Examine the supertype and consider auto-borrowing. - match to_ty.kind(Interner) { - TyKind::Raw(mt, _) => return self.coerce_ptr(from_ty, to_ty, *mt), - TyKind::Ref(mt, _, _) => return self.coerce_ref(from_ty, to_ty, *mt), - _ => {} - } - - match from_ty.kind(Interner) { - TyKind::FnDef(..) => { - // Function items are coercible to any closure - // type; function pointers are not (that would - // require double indirection). - // Additionally, we permit coercion of function - // items to drop the unsafe qualifier. - self.coerce_from_fn_item(from_ty, to_ty) - } - TyKind::Function(from_fn_ptr) => { - // We permit coercion of fn pointers to drop the - // unsafe qualifier. - self.coerce_from_fn_pointer(from_ty.clone(), from_fn_ptr, to_ty) - } - TyKind::Closure(_, from_substs) => { - // Non-capturing closures are coercible to - // function pointers or unsafe function pointers. - // It cannot convert closures that require unsafe. - self.coerce_closure_to_fn(from_ty.clone(), from_substs, to_ty) - } - _ => { - // Otherwise, just use unification rules. - self.unify_and(&from_ty, to_ty, identity) - } - } - } - - /// Unify two types (using sub or lub) and produce a specific coercion. - fn unify_and(&mut self, t1: &Ty, t2: &Ty, f: F) -> CoerceResult - where - F: FnOnce(Ty) -> Vec, - { - self.try_unify(t1, t2) - .and_then(|InferOk { goals, .. }| success(f(t1.clone()), t1.clone(), goals)) - } - - fn coerce_ptr(&mut self, from_ty: Ty, to_ty: &Ty, to_mt: Mutability) -> CoerceResult { - let (is_ref, from_mt, from_inner) = match from_ty.kind(Interner) { - TyKind::Ref(mt, _, ty) => (true, mt, ty), - TyKind::Raw(mt, ty) => (false, mt, ty), - _ => return self.unify_and(&from_ty, to_ty, identity), - }; - - coerce_mutabilities(*from_mt, to_mt)?; - - // Check that the types which they point at are compatible. - let from_raw = TyKind::Raw(to_mt, from_inner.clone()).intern(Interner); - - // Although references and unsafe ptrs have the same - // representation, we still register an Adjust::DerefRef so that - // regionck knows that the region for `a` must be valid here. - if is_ref { - self.unify_and(&from_raw, to_ty, |target| { - vec![ - Adjustment { kind: Adjust::Deref(None), target: from_inner.clone() }, - Adjustment { kind: Adjust::Borrow(AutoBorrow::RawPtr(to_mt)), target }, - ] - }) - } else if *from_mt != to_mt { - self.unify_and( - &from_raw, - to_ty, - simple(Adjust::Pointer(PointerCast::MutToConstPointer)), - ) - } else { - self.unify_and(&from_raw, to_ty, identity) - } - } - - /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`. - /// To match `A` with `B`, autoderef will be performed, - /// calling `deref`/`deref_mut` where necessary. - fn coerce_ref(&mut self, from_ty: Ty, to_ty: &Ty, to_mt: Mutability) -> CoerceResult { - let from_mt = match from_ty.kind(Interner) { - &TyKind::Ref(mt, _, _) => { - coerce_mutabilities(mt, to_mt)?; - mt - } - _ => return self.unify_and(&from_ty, to_ty, identity), - }; - - // NOTE: this code is mostly copied and adapted from rustc, and - // currently more complicated than necessary, carrying errors around - // etc.. This complication will become necessary when we actually track - // details of coercion errors though, so I think it's useful to leave - // the structure like it is. - - let snapshot = self.snapshot(); - - let mut autoderef = Autoderef::new(self, from_ty.clone()); - let mut first_error = None; - let mut found = None; - - while let Some((referent_ty, autoderefs)) = autoderef.next() { - if autoderefs == 0 { - // Don't let this pass, otherwise it would cause - // &T to autoref to &&T. - continue; - } - - // At this point, we have deref'd `a` to `referent_ty`. So - // imagine we are coercing from `&'a mut Vec` to `&'b mut [T]`. - // In the autoderef loop for `&'a mut Vec`, we would get - // three callbacks: - // - // - `&'a mut Vec` -- 0 derefs, just ignore it - // - `Vec` -- 1 deref - // - `[T]` -- 2 deref - // - // At each point after the first callback, we want to - // check to see whether this would match out target type - // (`&'b mut [T]`) if we autoref'd it. We can't just - // compare the referent types, though, because we still - // have to consider the mutability. E.g., in the case - // we've been considering, we have an `&mut` reference, so - // the `T` in `[T]` needs to be unified with equality. - // - // Therefore, we construct reference types reflecting what - // the types will be after we do the final auto-ref and - // compare those. Note that this means we use the target - // mutability [1], since it may be that we are coercing - // from `&mut T` to `&U`. - let lt = static_lifetime(); // FIXME: handle lifetimes correctly, see rustc - let derefd_from_ty = TyKind::Ref(to_mt, lt, referent_ty).intern(Interner); - match autoderef.table.try_unify(&derefd_from_ty, to_ty) { - Ok(result) => { - found = Some(result.map(|()| derefd_from_ty)); - break; - } - Err(err) => { - if first_error.is_none() { - first_error = Some(err); - } - } - } - } - - // Extract type or return an error. We return the first error - // we got, which should be from relating the "base" type - // (e.g., in example above, the failure from relating `Vec` - // to the target type), since that should be the least - // confusing. - let InferOk { value: ty, goals } = match found { - Some(d) => d, - None => { - self.rollback_to(snapshot); - let err = first_error.expect("coerce_borrowed_pointer had no error"); - return Err(err); - } - }; - if ty == from_ty && from_mt == Mutability::Not && autoderef.step_count() == 1 { - // As a special case, if we would produce `&'a *x`, that's - // a total no-op. We end up with the type `&'a T` just as - // we started with. In that case, just skip it - // altogether. This is just an optimization. - // - // Note that for `&mut`, we DO want to reborrow -- - // otherwise, this would be a move, which might be an - // error. For example `foo(self.x)` where `self` and - // `self.x` both have `&mut `type would be a move of - // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`, - // which is a borrow. - always!(to_mt == Mutability::Not); // can only coerce &T -> &U - return success(vec![], ty, goals); - } - - let mut adjustments = auto_deref_adjust_steps(&autoderef); - adjustments - .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(to_mt)), target: ty.clone() }); - - success(adjustments, ty, goals) - } - - /// Attempts to coerce from the type of a Rust function item into a function pointer. - fn coerce_from_fn_item(&mut self, from_ty: Ty, to_ty: &Ty) -> CoerceResult { - match to_ty.kind(Interner) { - TyKind::Function(_) => { - let from_sig = from_ty.callable_sig(self.db).expect("FnDef had no sig"); - - // FIXME check ABI: Intrinsics are not coercible to function pointers - // FIXME Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396) - - // FIXME rustc normalizes assoc types in the sig here, not sure if necessary - - let from_sig = from_sig.to_fn_ptr(); - let from_fn_pointer = TyKind::Function(from_sig.clone()).intern(Interner); - let ok = self.coerce_from_safe_fn( - from_fn_pointer.clone(), - &from_sig, - to_ty, - |unsafe_ty| { - vec![ - Adjustment { - kind: Adjust::Pointer(PointerCast::ReifyFnPointer), - target: from_fn_pointer, - }, - Adjustment { - kind: Adjust::Pointer(PointerCast::UnsafeFnPointer), - target: unsafe_ty, - }, - ] - }, - simple(Adjust::Pointer(PointerCast::ReifyFnPointer)), - )?; - - Ok(ok) - } - _ => self.unify_and(&from_ty, to_ty, identity), - } - } - - fn coerce_from_fn_pointer( - &mut self, - from_ty: Ty, - from_f: &FnPointer, - to_ty: &Ty, - ) -> CoerceResult { - self.coerce_from_safe_fn( - from_ty, - from_f, - to_ty, - simple(Adjust::Pointer(PointerCast::UnsafeFnPointer)), - identity, - ) - } - - fn coerce_from_safe_fn( - &mut self, - from_ty: Ty, - from_fn_ptr: &FnPointer, - to_ty: &Ty, - to_unsafe: F, - normal: G, - ) -> CoerceResult - where - F: FnOnce(Ty) -> Vec, - G: FnOnce(Ty) -> Vec, - { - if let TyKind::Function(to_fn_ptr) = to_ty.kind(Interner) { - if let (chalk_ir::Safety::Safe, chalk_ir::Safety::Unsafe) = - (from_fn_ptr.sig.safety, to_fn_ptr.sig.safety) - { - let from_unsafe = - TyKind::Function(safe_to_unsafe_fn_ty(from_fn_ptr.clone())).intern(Interner); - return self.unify_and(&from_unsafe, to_ty, to_unsafe); - } - } - self.unify_and(&from_ty, to_ty, normal) - } - - /// Attempts to coerce from the type of a non-capturing closure into a - /// function pointer. - fn coerce_closure_to_fn( - &mut self, - from_ty: Ty, - from_substs: &Substitution, - to_ty: &Ty, - ) -> CoerceResult { - match to_ty.kind(Interner) { - // if from_substs is non-capturing (FIXME) - TyKind::Function(fn_ty) => { - // We coerce the closure, which has fn type - // `extern "rust-call" fn((arg0,arg1,...)) -> _` - // to - // `fn(arg0,arg1,...) -> _` - // or - // `unsafe fn(arg0,arg1,...) -> _` - let safety = fn_ty.sig.safety; - let pointer_ty = coerce_closure_fn_ty(from_substs, safety); - self.unify_and( - &pointer_ty, - to_ty, - simple(Adjust::Pointer(PointerCast::ClosureFnPointer(safety))), - ) - } - _ => self.unify_and(&from_ty, to_ty, identity), - } - } - - /// Coerce a type using `from_ty: CoerceUnsized` - /// - /// See: - fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> CoerceResult { - // These 'if' statements require some explanation. - // The `CoerceUnsized` trait is special - it is only - // possible to write `impl CoerceUnsized for A` where - // A and B have 'matching' fields. This rules out the following - // two types of blanket impls: - // - // `impl CoerceUnsized for SomeType` - // `impl CoerceUnsized for T` - // - // Both of these trigger a special `CoerceUnsized`-related error (E0376) - // - // We can take advantage of this fact to avoid performing unnecessary work. - // If either `source` or `target` is a type variable, then any applicable impl - // would need to be generic over the self-type (`impl CoerceUnsized for T`) - // or generic over the `CoerceUnsized` type parameter (`impl CoerceUnsized for - // SomeType`). - // - // However, these are exactly the kinds of impls which are forbidden by - // the compiler! Therefore, we can be sure that coercion will always fail - // when either the source or target type is a type variable. This allows us - // to skip performing any trait selection, and immediately bail out. - if from_ty.is_ty_var() { - return Err(TypeError); - } - if to_ty.is_ty_var() { - return Err(TypeError); - } - - // Handle reborrows before trying to solve `Source: CoerceUnsized`. - let reborrow = match (from_ty.kind(Interner), to_ty.kind(Interner)) { - (TyKind::Ref(from_mt, _, from_inner), &TyKind::Ref(to_mt, _, _)) => { - coerce_mutabilities(*from_mt, to_mt)?; - - let lt = static_lifetime(); - Some(( - Adjustment { kind: Adjust::Deref(None), target: from_inner.clone() }, - Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(to_mt)), - target: TyKind::Ref(to_mt, lt, from_inner.clone()).intern(Interner), - }, - )) - } - (TyKind::Ref(from_mt, _, from_inner), &TyKind::Raw(to_mt, _)) => { - coerce_mutabilities(*from_mt, to_mt)?; - - Some(( - Adjustment { kind: Adjust::Deref(None), target: from_inner.clone() }, - Adjustment { - kind: Adjust::Borrow(AutoBorrow::RawPtr(to_mt)), - target: TyKind::Raw(to_mt, from_inner.clone()).intern(Interner), - }, - )) - } - _ => None, - }; - let coerce_from = - reborrow.as_ref().map_or_else(|| from_ty.clone(), |(_, adj)| adj.target.clone()); - - let krate = self.trait_env.krate; - let coerce_unsized_trait = - match self.db.lang_item(krate, SmolStr::new_inline("coerce_unsized")) { - Some(LangItemTarget::TraitId(trait_)) => trait_, - _ => return Err(TypeError), - }; - - let coerce_unsized_tref = { - let b = TyBuilder::trait_ref(self.db, coerce_unsized_trait); - if b.remaining() != 2 { - // The CoerceUnsized trait should have two generic params: Self and T. - return Err(TypeError); - } - b.push(coerce_from).push(to_ty.clone()).build() - }; - - let goal: InEnvironment = - InEnvironment::new(&self.trait_env.env, coerce_unsized_tref.cast(Interner)); - - let canonicalized = self.canonicalize(goal); - - // FIXME: rustc's coerce_unsized is more specialized -- it only tries to - // solve `CoerceUnsized` and `Unsize` goals at this point and leaves the - // rest for later. Also, there's some logic about sized type variables. - // Need to find out in what cases this is necessary - let solution = self - .db - .trait_solve(krate, canonicalized.value.clone().cast(Interner)) - .ok_or(TypeError)?; - - match solution { - Solution::Unique(v) => { - canonicalized.apply_solution( - self, - Canonical { - binders: v.binders, - // FIXME handle constraints - value: v.value.subst, - }, - ); - } - Solution::Ambig(Guidance::Definite(subst)) => { - // FIXME need to record an obligation here - canonicalized.apply_solution(self, subst) - } - // FIXME actually we maybe should also accept unknown guidance here - _ => return Err(TypeError), - }; - let unsize = - Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target: to_ty.clone() }; - let adjustments = match reborrow { - None => vec![unsize], - Some((deref, autoref)) => vec![deref, autoref, unsize], - }; - success(adjustments, to_ty.clone(), vec![]) - } -} - -fn coerce_closure_fn_ty(closure_substs: &Substitution, safety: chalk_ir::Safety) -> Ty { - let closure_sig = closure_substs.at(Interner, 0).assert_ty_ref(Interner).clone(); - match closure_sig.kind(Interner) { - TyKind::Function(fn_ty) => TyKind::Function(FnPointer { - num_binders: fn_ty.num_binders, - sig: FnSig { safety, ..fn_ty.sig }, - substitution: fn_ty.substitution.clone(), - }) - .intern(Interner), - _ => TyKind::Error.intern(Interner), - } -} - -fn safe_to_unsafe_fn_ty(fn_ty: FnPointer) -> FnPointer { - FnPointer { - num_binders: fn_ty.num_binders, - sig: FnSig { safety: chalk_ir::Safety::Unsafe, ..fn_ty.sig }, - substitution: fn_ty.substitution, - } -} - -fn coerce_mutabilities(from: Mutability, to: Mutability) -> Result<(), TypeError> { - match (from, to) { - (Mutability::Mut, Mutability::Mut | Mutability::Not) - | (Mutability::Not, Mutability::Not) => Ok(()), - (Mutability::Not, Mutability::Mut) => Err(TypeError), - } -} - -pub(super) fn auto_deref_adjust_steps(autoderef: &Autoderef<'_, '_>) -> Vec { - let steps = autoderef.steps(); - let targets = - steps.iter().skip(1).map(|(_, ty)| ty.clone()).chain(iter::once(autoderef.final_ty())); - steps - .iter() - .map(|(kind, _source)| match kind { - // We do not know what kind of deref we require at this point yet - AutoderefKind::Overloaded => Some(OverloadedDeref(Mutability::Not)), - AutoderefKind::Builtin => None, - }) - .zip(targets) - .map(|(autoderef, target)| Adjustment { kind: Adjust::Deref(autoderef), target }) - .collect() -} 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 deleted file mode 100644 index d164e64a8be07..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ /dev/null @@ -1,1527 +0,0 @@ -//! Type inference for expressions. - -use std::{ - collections::hash_map::Entry, - iter::{repeat, repeat_with}, - mem, -}; - -use chalk_ir::{ - cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind, -}; -use hir_def::{ - expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Ordering, Statement, UnaryOp}, - generics::TypeOrConstParamData, - path::{GenericArg, GenericArgs}, - resolver::resolver_for_expr, - ConstParamId, FieldId, FunctionId, ItemContainerId, Lookup, -}; -use hir_expand::name::{name, Name}; -use stdx::always; -use syntax::ast::RangeOp; - -use crate::{ - autoderef::{self, Autoderef}, - consteval, - infer::coerce::CoerceMany, - lower::{ - const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode, - }, - mapping::{from_chalk, ToChalk}, - method_resolution::{self, VisibleFromModule}, - primitive::{self, UintTy}, - static_lifetime, to_chalk_trait_id, - utils::{generics, Generics}, - AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar, - Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind, -}; - -use super::{ - coerce::auto_deref_adjust_steps, find_breakable, BindingMode, BreakableContext, Diverges, - Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch, -}; - -impl<'a> InferenceContext<'a> { - pub(crate) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { - let ty = self.infer_expr_inner(tgt_expr, expected); - if let Some(expected_ty) = expected.only_has_type(&mut self.table) { - let could_unify = self.unify(&ty, &expected_ty); - if !could_unify { - self.result.type_mismatches.insert( - tgt_expr.into(), - TypeMismatch { expected: expected_ty, actual: ty.clone() }, - ); - } - } - ty - } - - /// Infer type of expression with possibly implicit coerce to the expected type. - /// Return the type after possible coercion. - pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty { - let ty = self.infer_expr_inner(expr, expected); - if let Some(target) = expected.only_has_type(&mut self.table) { - match self.coerce(Some(expr), &ty, &target) { - Ok(res) => res, - Err(_) => { - self.result.type_mismatches.insert( - expr.into(), - TypeMismatch { expected: target.clone(), actual: ty.clone() }, - ); - target - } - } - } else { - ty - } - } - - fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { - self.db.unwind_if_cancelled(); - - let ty = match &self.body[tgt_expr] { - Expr::Missing => self.err_ty(), - &Expr::If { condition, then_branch, else_branch } => { - self.infer_expr( - condition, - &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)), - ); - - let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); - let mut both_arms_diverge = Diverges::Always; - - let result_ty = self.table.new_type_var(); - let then_ty = self.infer_expr_inner(then_branch, expected); - both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe); - let mut coerce = CoerceMany::new(result_ty); - coerce.coerce(self, Some(then_branch), &then_ty); - let else_ty = match else_branch { - Some(else_branch) => self.infer_expr_inner(else_branch, expected), - None => TyBuilder::unit(), - }; - both_arms_diverge &= self.diverges; - // FIXME: create a synthetic `else {}` so we have something to refer to here instead of None? - coerce.coerce(self, else_branch, &else_ty); - - self.diverges = condition_diverges | both_arms_diverge; - - coerce.complete() - } - &Expr::Let { pat, expr } => { - let input_ty = self.infer_expr(expr, &Expectation::none()); - self.infer_pat(pat, &input_ty, BindingMode::default()); - TyKind::Scalar(Scalar::Bool).intern(Interner) - } - Expr::Block { statements, tail, label, id: _ } => { - let old_resolver = mem::replace( - &mut self.resolver, - resolver_for_expr(self.db.upcast(), self.owner, tgt_expr), - ); - let ty = match label { - Some(_) => { - let break_ty = self.table.new_type_var(); - self.breakables.push(BreakableContext { - may_break: false, - coerce: CoerceMany::new(break_ty.clone()), - label: label.map(|label| self.body[label].name.clone()), - }); - let ty = self.infer_block( - tgt_expr, - statements, - *tail, - &Expectation::has_type(break_ty), - ); - let ctxt = self.breakables.pop().expect("breakable stack broken"); - if ctxt.may_break { - ctxt.coerce.complete() - } else { - ty - } - } - None => self.infer_block(tgt_expr, statements, *tail, expected), - }; - self.resolver = old_resolver; - ty - } - Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected), - Expr::TryBlock { body } => { - let _inner = self.infer_expr(*body, expected); - // FIXME should be std::result::Result<{inner}, _> - self.err_ty() - } - Expr::Async { body } => { - let ret_ty = self.table.new_type_var(); - let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); - let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); - - let inner_ty = self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); - - self.diverges = prev_diverges; - self.return_ty = prev_ret_ty; - - // Use the first type parameter as the output type of future. - // existential type AsyncBlockImplTrait: Future - let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body); - let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); - TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty)) - .intern(Interner) - } - Expr::Loop { body, label } => { - self.breakables.push(BreakableContext { - may_break: false, - coerce: CoerceMany::new(self.table.new_type_var()), - label: label.map(|label| self.body[label].name.clone()), - }); - self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit())); - - let ctxt = self.breakables.pop().expect("breakable stack broken"); - - if ctxt.may_break { - self.diverges = Diverges::Maybe; - ctxt.coerce.complete() - } else { - TyKind::Never.intern(Interner) - } - } - Expr::While { condition, body, label } => { - self.breakables.push(BreakableContext { - may_break: false, - coerce: CoerceMany::new(self.err_ty()), - label: label.map(|label| self.body[label].name.clone()), - }); - self.infer_expr( - *condition, - &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)), - ); - self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit())); - let _ctxt = self.breakables.pop().expect("breakable stack broken"); - // the body may not run, so it diverging doesn't mean we diverge - self.diverges = Diverges::Maybe; - TyBuilder::unit() - } - Expr::For { iterable, body, pat, label } => { - let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); - - self.breakables.push(BreakableContext { - may_break: false, - coerce: CoerceMany::new(self.err_ty()), - label: label.map(|label| self.body[label].name.clone()), - }); - let pat_ty = - self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); - - self.infer_pat(*pat, &pat_ty, BindingMode::default()); - - self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit())); - let _ctxt = self.breakables.pop().expect("breakable stack broken"); - // the body may not run, so it diverging doesn't mean we diverge - self.diverges = Diverges::Maybe; - TyBuilder::unit() - } - Expr::Closure { body, args, ret_type, arg_types } => { - assert_eq!(args.len(), arg_types.len()); - - let mut sig_tys = Vec::new(); - - // collect explicitly written argument types - for arg_type in arg_types.iter() { - let arg_ty = match arg_type { - Some(type_ref) => self.make_ty(type_ref), - None => self.table.new_type_var(), - }; - sig_tys.push(arg_ty); - } - - // add return type - let ret_ty = match ret_type { - Some(type_ref) => self.make_ty(type_ref), - None => self.table.new_type_var(), - }; - sig_tys.push(ret_ty.clone()); - let sig_ty = TyKind::Function(FnPointer { - num_binders: 0, - sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false }, - substitution: FnSubst( - Substitution::from_iter(Interner, sig_tys.clone()).shifted_in(Interner), - ), - }) - .intern(Interner); - let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into(); - let closure_ty = - TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone())) - .intern(Interner); - - // Eagerly try to relate the closure type with the expected - // type, otherwise we often won't have enough information to - // infer the body. - self.deduce_closure_type_from_expectations( - tgt_expr, - &closure_ty, - &sig_ty, - expected, - ); - - // Now go through the argument patterns - for (arg_pat, arg_ty) in args.iter().zip(sig_tys) { - self.infer_pat(*arg_pat, &arg_ty, BindingMode::default()); - } - - let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); - let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); - - self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); - - self.diverges = prev_diverges; - self.return_ty = prev_ret_ty; - - closure_ty - } - Expr::Call { callee, args, .. } => { - let callee_ty = self.infer_expr(*callee, &Expectation::none()); - let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone()); - let mut res = None; - let mut derefed_callee = callee_ty.clone(); - // manual loop to be able to access `derefs.table` - while let Some((callee_deref_ty, _)) = derefs.next() { - res = derefs.table.callable_sig(&callee_deref_ty, args.len()); - if res.is_some() { - derefed_callee = callee_deref_ty; - break; - } - } - // if the function is unresolved, we use is_varargs=true to - // suppress the arg count diagnostic here - let is_varargs = - derefed_callee.callable_sig(self.db).map_or(false, |sig| sig.is_varargs) - || res.is_none(); - let (param_tys, ret_ty) = match res { - Some(res) => { - let adjustments = auto_deref_adjust_steps(&derefs); - self.write_expr_adj(*callee, adjustments); - res - } - None => (Vec::new(), self.err_ty()), // FIXME diagnostic - }; - let indices_to_skip = self.check_legacy_const_generics(derefed_callee, args); - self.register_obligations_for_call(&callee_ty); - - let expected_inputs = self.expected_inputs_for_expected_output( - expected, - ret_ty.clone(), - param_tys.clone(), - ); - - self.check_call_arguments( - tgt_expr, - args, - &expected_inputs, - ¶m_tys, - &indices_to_skip, - is_varargs, - ); - self.normalize_associated_types_in(ret_ty) - } - Expr::MethodCall { receiver, args, method_name, generic_args } => self - .infer_method_call( - tgt_expr, - *receiver, - args, - method_name, - generic_args.as_deref(), - expected, - ), - Expr::Match { expr, arms } => { - let input_ty = self.infer_expr(*expr, &Expectation::none()); - - let expected = expected.adjust_for_branches(&mut self.table); - - let result_ty = if arms.is_empty() { - TyKind::Never.intern(Interner) - } else { - match &expected { - Expectation::HasType(ty) => ty.clone(), - _ => self.table.new_type_var(), - } - }; - let mut coerce = CoerceMany::new(result_ty); - - let matchee_diverges = self.diverges; - let mut all_arms_diverge = Diverges::Always; - - for arm in arms.iter() { - self.diverges = Diverges::Maybe; - let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default()); - if let Some(guard_expr) = arm.guard { - self.infer_expr( - guard_expr, - &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)), - ); - } - - let arm_ty = self.infer_expr_inner(arm.expr, &expected); - all_arms_diverge &= self.diverges; - coerce.coerce(self, Some(arm.expr), &arm_ty); - } - - self.diverges = matchee_diverges | all_arms_diverge; - - coerce.complete() - } - Expr::Path(p) => { - // FIXME this could be more efficient... - let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); - self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or_else(|| self.err_ty()) - } - Expr::Continue { .. } => TyKind::Never.intern(Interner), - Expr::Break { expr, label } => { - let mut coerce = match find_breakable(&mut self.breakables, label.as_ref()) { - Some(ctxt) => { - // avoiding the borrowck - mem::replace( - &mut ctxt.coerce, - CoerceMany::new(self.result.standard_types.unknown.clone()), - ) - } - None => CoerceMany::new(self.result.standard_types.unknown.clone()), - }; - - let val_ty = if let Some(expr) = *expr { - self.infer_expr(expr, &Expectation::none()) - } else { - TyBuilder::unit() - }; - - // FIXME: create a synthetic `()` during lowering so we have something to refer to here? - coerce.coerce(self, *expr, &val_ty); - - if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { - ctxt.coerce = coerce; - ctxt.may_break = true; - } else { - self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { - expr: tgt_expr, - }); - }; - - TyKind::Never.intern(Interner) - } - Expr::Return { expr } => { - if let Some(expr) = expr { - self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone())); - } else { - let unit = TyBuilder::unit(); - let _ = self.coerce(Some(tgt_expr), &unit, &self.return_ty.clone()); - } - TyKind::Never.intern(Interner) - } - Expr::Yield { expr } => { - // FIXME: track yield type for coercion - if let Some(expr) = expr { - self.infer_expr(*expr, &Expectation::none()); - } - TyKind::Never.intern(Interner) - } - Expr::RecordLit { path, fields, spread, .. } => { - let (ty, def_id) = self.resolve_variant(path.as_deref(), false); - if let Some(variant) = def_id { - self.write_variant_resolution(tgt_expr.into(), variant); - } - - if let Some(t) = expected.only_has_type(&mut self.table) { - self.unify(&ty, &t); - } - - let substs = ty - .as_adt() - .map(|(_, s)| s.clone()) - .unwrap_or_else(|| Substitution::empty(Interner)); - let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default(); - let variant_data = def_id.map(|it| it.variant_data(self.db.upcast())); - for field in fields.iter() { - let field_def = - variant_data.as_ref().and_then(|it| match it.field(&field.name) { - Some(local_id) => Some(FieldId { parent: def_id.unwrap(), local_id }), - None => { - self.push_diagnostic(InferenceDiagnostic::NoSuchField { - expr: field.expr, - }); - None - } - }); - let field_ty = field_def.map_or(self.err_ty(), |it| { - field_types[it.local_id].clone().substitute(Interner, &substs) - }); - self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty)); - } - if let Some(expr) = spread { - self.infer_expr(*expr, &Expectation::has_type(ty.clone())); - } - ty - } - Expr::Field { expr, name } => { - let receiver_ty = self.infer_expr_inner(*expr, &Expectation::none()); - - let mut autoderef = Autoderef::new(&mut self.table, receiver_ty); - let ty = autoderef.by_ref().find_map(|(derefed_ty, _)| { - let (field_id, parameters) = match derefed_ty.kind(Interner) { - TyKind::Tuple(_, substs) => { - return name.as_tuple_index().and_then(|idx| { - substs - .as_slice(Interner) - .get(idx) - .map(|a| a.assert_ty_ref(Interner)) - .cloned() - }); - } - TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => { - let local_id = self.db.struct_data(*s).variant_data.field(name)?; - let field = FieldId { parent: (*s).into(), local_id }; - (field, parameters.clone()) - } - TyKind::Adt(AdtId(hir_def::AdtId::UnionId(u)), parameters) => { - let local_id = self.db.union_data(*u).variant_data.field(name)?; - let field = FieldId { parent: (*u).into(), local_id }; - (field, parameters.clone()) - } - _ => return None, - }; - let is_visible = self.db.field_visibilities(field_id.parent)[field_id.local_id] - .is_visible_from(self.db.upcast(), self.resolver.module()); - if !is_visible { - // Write down the first field resolution even if it is not visible - // This aids IDE features for private fields like goto def and in - // case of autoderef finding an applicable field, this will be - // overwritten in a following cycle - if let Entry::Vacant(entry) = self.result.field_resolutions.entry(tgt_expr) - { - entry.insert(field_id); - } - return None; - } - // can't have `write_field_resolution` here because `self.table` is borrowed :( - self.result.field_resolutions.insert(tgt_expr, field_id); - let ty = self.db.field_types(field_id.parent)[field_id.local_id] - .clone() - .substitute(Interner, ¶meters); - Some(ty) - }); - let ty = match ty { - Some(ty) => { - let adjustments = auto_deref_adjust_steps(&autoderef); - self.write_expr_adj(*expr, adjustments); - let ty = self.insert_type_vars(ty); - let ty = self.normalize_associated_types_in(ty); - ty - } - _ => self.err_ty(), - }; - ty - } - Expr::Await { expr } => { - let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); - self.resolve_associated_type(inner_ty, self.resolve_future_future_output()) - } - Expr::Try { expr } => { - let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); - self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok()) - } - Expr::Cast { expr, type_ref } => { - // FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary) - let _inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); - let cast_ty = self.make_ty(type_ref); - // FIXME check the cast... - cast_ty - } - Expr::Ref { expr, rawness, mutability } => { - let mutability = lower_to_chalk_mutability(*mutability); - let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = expected - .only_has_type(&mut self.table) - .as_ref() - .and_then(|t| t.as_reference_or_ptr()) - { - if exp_mutability == Mutability::Mut && mutability == Mutability::Not { - // FIXME: record type error - expected mut reference but found shared ref, - // which cannot be coerced - } - if exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr { - // FIXME: record type error - expected reference but found ptr, - // which cannot be coerced - } - Expectation::rvalue_hint(&mut self.table, Ty::clone(exp_inner)) - } else { - Expectation::none() - }; - let inner_ty = self.infer_expr_inner(*expr, &expectation); - match rawness { - Rawness::RawPtr => TyKind::Raw(mutability, inner_ty), - Rawness::Ref => TyKind::Ref(mutability, static_lifetime(), inner_ty), - } - .intern(Interner) - } - &Expr::Box { expr } => self.infer_expr_box(expr, expected), - Expr::UnaryOp { expr, op } => { - let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); - let inner_ty = self.resolve_ty_shallow(&inner_ty); - match op { - UnaryOp::Deref => { - autoderef::deref(&mut self.table, inner_ty).unwrap_or_else(|| self.err_ty()) - } - UnaryOp::Neg => { - match inner_ty.kind(Interner) { - // Fast path for builtins - TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_)) - | TyKind::InferenceVar( - _, - TyVariableKind::Integer | TyVariableKind::Float, - ) => inner_ty, - // Otherwise we resolve via the std::ops::Neg trait - _ => self - .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()), - } - } - UnaryOp::Not => { - match inner_ty.kind(Interner) { - // Fast path for builtins - TyKind::Scalar(Scalar::Bool | Scalar::Int(_) | Scalar::Uint(_)) - | TyKind::InferenceVar(_, TyVariableKind::Integer) => inner_ty, - // Otherwise we resolve via the std::ops::Not trait - _ => self - .resolve_associated_type(inner_ty, self.resolve_ops_not_output()), - } - } - } - } - Expr::BinaryOp { lhs, rhs, op } => match op { - Some(BinaryOp::Assignment { op: None }) => { - let lhs = *lhs; - let is_ordinary = match &self.body[lhs] { - Expr::Array(_) - | Expr::RecordLit { .. } - | Expr::Tuple { .. } - | Expr::Underscore => false, - Expr::Call { callee, .. } => !matches!(&self.body[*callee], Expr::Path(_)), - _ => true, - }; - - // In ordinary (non-destructuring) assignments, the type of - // `lhs` must be inferred first so that the ADT fields - // instantiations in RHS can be coerced to it. Note that this - // cannot happen in destructuring assignments because of how - // they are desugared. - if is_ordinary { - let lhs_ty = self.infer_expr(lhs, &Expectation::none()); - self.infer_expr_coerce(*rhs, &Expectation::has_type(lhs_ty)); - } else { - let rhs_ty = self.infer_expr(*rhs, &Expectation::none()); - self.infer_assignee_expr(lhs, &rhs_ty); - } - self.result.standard_types.unit.clone() - } - Some(BinaryOp::LogicOp(_)) => { - let bool_ty = self.result.standard_types.bool_.clone(); - self.infer_expr_coerce(*lhs, &Expectation::HasType(bool_ty.clone())); - let lhs_diverges = self.diverges; - self.infer_expr_coerce(*rhs, &Expectation::HasType(bool_ty.clone())); - // Depending on the LHS' value, the RHS can never execute. - self.diverges = lhs_diverges; - bool_ty - } - Some(op) => self.infer_overloadable_binop(*lhs, *op, *rhs, tgt_expr), - _ => self.err_ty(), - }, - Expr::Range { lhs, rhs, range_type } => { - let lhs_ty = lhs.map(|e| self.infer_expr_inner(e, &Expectation::none())); - let rhs_expect = lhs_ty - .as_ref() - .map_or_else(Expectation::none, |ty| Expectation::has_type(ty.clone())); - let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect)); - match (range_type, lhs_ty, rhs_ty) { - (RangeOp::Exclusive, None, None) => match self.resolve_range_full() { - Some(adt) => TyBuilder::adt(self.db, adt).build(), - None => self.err_ty(), - }, - (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() { - Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(), - None => self.err_ty(), - }, - (RangeOp::Inclusive, None, Some(ty)) => { - match self.resolve_range_to_inclusive() { - Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(), - None => self.err_ty(), - } - } - (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() { - Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(), - None => self.err_ty(), - }, - (RangeOp::Inclusive, Some(_), Some(ty)) => { - match self.resolve_range_inclusive() { - Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(), - None => self.err_ty(), - } - } - (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() { - Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(), - None => self.err_ty(), - }, - (RangeOp::Inclusive, _, None) => self.err_ty(), - } - } - Expr::Index { base, index } => { - let base_ty = self.infer_expr_inner(*base, &Expectation::none()); - let index_ty = self.infer_expr(*index, &Expectation::none()); - - if let Some(index_trait) = self.resolve_ops_index() { - let canonicalized = self.canonicalize(base_ty.clone()); - let receiver_adjustments = method_resolution::resolve_indexing_op( - self.db, - self.trait_env.clone(), - canonicalized.value, - index_trait, - ); - let (self_ty, adj) = receiver_adjustments - .map_or((self.err_ty(), Vec::new()), |adj| { - adj.apply(&mut self.table, base_ty) - }); - self.write_expr_adj(*base, adj); - self.resolve_associated_type_with_params( - self_ty, - self.resolve_ops_index_output(), - &[GenericArgData::Ty(index_ty).intern(Interner)], - ) - } else { - self.err_ty() - } - } - Expr::Tuple { exprs, .. } => { - let mut tys = match expected - .only_has_type(&mut self.table) - .as_ref() - .map(|t| t.kind(Interner)) - { - Some(TyKind::Tuple(_, substs)) => substs - .iter(Interner) - .map(|a| a.assert_ty_ref(Interner).clone()) - .chain(repeat_with(|| self.table.new_type_var())) - .take(exprs.len()) - .collect::>(), - _ => (0..exprs.len()).map(|_| self.table.new_type_var()).collect(), - }; - - for (expr, ty) in exprs.iter().zip(tys.iter_mut()) { - self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone())); - } - - TyKind::Tuple(tys.len(), Substitution::from_iter(Interner, tys)).intern(Interner) - } - Expr::Array(array) => { - let elem_ty = - match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(Interner)) { - Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st.clone(), - _ => self.table.new_type_var(), - }; - let mut coerce = CoerceMany::new(elem_ty.clone()); - - let expected = Expectation::has_type(elem_ty.clone()); - let len = match array { - Array::ElementList { elements, .. } => { - for &expr in elements.iter() { - let cur_elem_ty = self.infer_expr_inner(expr, &expected); - coerce.coerce(self, Some(expr), &cur_elem_ty); - } - consteval::usize_const(Some(elements.len() as u128)) - } - &Array::Repeat { initializer, repeat } => { - self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty)); - self.infer_expr( - repeat, - &Expectation::has_type( - TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner), - ), - ); - - if let Some(g_def) = self.owner.as_generic_def_id() { - let generics = generics(self.db.upcast(), g_def); - consteval::eval_to_const( - repeat, - ParamLoweringMode::Placeholder, - self, - || generics, - DebruijnIndex::INNERMOST, - ) - } else { - consteval::usize_const(None) - } - } - }; - - TyKind::Array(coerce.complete(), len).intern(Interner) - } - Expr::Literal(lit) => match lit { - Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(Interner), - Literal::String(..) => { - TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(Interner)) - .intern(Interner) - } - Literal::ByteString(bs) => { - let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner); - - let len = consteval::usize_const(Some(bs.len() as u128)); - - let array_type = TyKind::Array(byte_type, len).intern(Interner); - TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(Interner) - } - Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(Interner), - Literal::Int(_v, ty) => match ty { - Some(int_ty) => { - TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(*int_ty))) - .intern(Interner) - } - None => self.table.new_integer_var(), - }, - Literal::Uint(_v, ty) => match ty { - Some(int_ty) => { - TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(*int_ty))) - .intern(Interner) - } - None => self.table.new_integer_var(), - }, - Literal::Float(_v, ty) => match ty { - Some(float_ty) => { - TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(*float_ty))) - .intern(Interner) - } - None => self.table.new_float_var(), - }, - }, - Expr::MacroStmts { tail, statements } => { - self.infer_block(tgt_expr, statements, *tail, expected) - } - Expr::Underscore => { - // Underscore expressions may only appear in assignee expressions, - // which are handled by `infer_assignee_expr()`, so any underscore - // expression reaching this branch is an error. - self.err_ty() - } - }; - // use a new type variable if we got unknown here - let ty = self.insert_type_vars_shallow(ty); - self.write_expr_ty(tgt_expr, ty.clone()); - if self.resolve_ty_shallow(&ty).is_never() { - // Any expression that produces a value of type `!` must have diverged - self.diverges = Diverges::Always; - } - ty - } - - fn infer_expr_box(&mut self, inner_expr: ExprId, expected: &Expectation) -> Ty { - if let Some(box_id) = self.resolve_boxed_box() { - let table = &mut self.table; - let inner_exp = expected - .to_option(table) - .as_ref() - .map(|e| e.as_adt()) - .flatten() - .filter(|(e_adt, _)| e_adt == &box_id) - .map(|(_, subts)| { - let g = subts.at(Interner, 0); - Expectation::rvalue_hint(table, Ty::clone(g.assert_ty_ref(Interner))) - }) - .unwrap_or_else(Expectation::none); - - let inner_ty = self.infer_expr_inner(inner_expr, &inner_exp); - TyBuilder::adt(self.db, box_id) - .push(inner_ty) - .fill_with_defaults(self.db, || self.table.new_type_var()) - .build() - } else { - self.err_ty() - } - } - - pub(super) fn infer_assignee_expr(&mut self, lhs: ExprId, rhs_ty: &Ty) -> Ty { - let is_rest_expr = |expr| { - matches!( - &self.body[expr], - Expr::Range { lhs: None, rhs: None, range_type: RangeOp::Exclusive }, - ) - }; - - let rhs_ty = self.resolve_ty_shallow(rhs_ty); - - let ty = match &self.body[lhs] { - Expr::Tuple { exprs, .. } => { - // We don't consider multiple ellipses. This is analogous to - // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`. - let ellipsis = exprs.iter().position(|e| is_rest_expr(*e)); - let exprs: Vec<_> = exprs.iter().filter(|e| !is_rest_expr(**e)).copied().collect(); - - self.infer_tuple_pat_like(&rhs_ty, (), ellipsis, &exprs) - } - Expr::Call { callee, args, .. } => { - // Tuple structs - let path = match &self.body[*callee] { - Expr::Path(path) => Some(path), - _ => None, - }; - - // We don't consider multiple ellipses. This is analogous to - // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`. - let ellipsis = args.iter().position(|e| is_rest_expr(*e)); - let args: Vec<_> = args.iter().filter(|e| !is_rest_expr(**e)).copied().collect(); - - self.infer_tuple_struct_pat_like(path, &rhs_ty, (), lhs, ellipsis, &args) - } - Expr::Array(Array::ElementList { elements, .. }) => { - let elem_ty = match rhs_ty.kind(Interner) { - TyKind::Array(st, _) => st.clone(), - _ => self.err_ty(), - }; - - // There's no need to handle `..` as it cannot be bound. - let sub_exprs = elements.iter().filter(|e| !is_rest_expr(**e)); - - for e in sub_exprs { - self.infer_assignee_expr(*e, &elem_ty); - } - - match rhs_ty.kind(Interner) { - TyKind::Array(_, _) => rhs_ty.clone(), - // Even when `rhs_ty` is not an array type, this assignee - // expression is inferred to be an array (of unknown element - // type and length). This should not be just an error type, - // because we are to compute the unifiability of this type and - // `rhs_ty` in the end of this function to issue type mismatches. - _ => TyKind::Array(self.err_ty(), crate::consteval::usize_const(None)) - .intern(Interner), - } - } - Expr::RecordLit { path, fields, .. } => { - let subs = fields.iter().map(|f| (f.name.clone(), f.expr)); - - self.infer_record_pat_like(path.as_deref(), &rhs_ty, (), lhs.into(), subs) - } - Expr::Underscore => rhs_ty.clone(), - _ => { - // `lhs` is a place expression, a unit struct, or an enum variant. - let lhs_ty = self.infer_expr(lhs, &Expectation::none()); - - // This is the only branch where this function may coerce any type. - // We are returning early to avoid the unifiability check below. - let lhs_ty = self.insert_type_vars_shallow(lhs_ty); - let ty = match self.coerce(None, &rhs_ty, &lhs_ty) { - Ok(ty) => ty, - Err(_) => { - self.result.type_mismatches.insert( - lhs.into(), - TypeMismatch { expected: rhs_ty.clone(), actual: lhs_ty.clone() }, - ); - // `rhs_ty` is returned so no further type mismatches are - // reported because of this mismatch. - rhs_ty - } - }; - self.write_expr_ty(lhs, ty.clone()); - return ty; - } - }; - - let ty = self.insert_type_vars_shallow(ty); - if !self.unify(&ty, &rhs_ty) { - self.result - .type_mismatches - .insert(lhs.into(), TypeMismatch { expected: rhs_ty.clone(), actual: ty.clone() }); - } - self.write_expr_ty(lhs, ty.clone()); - ty - } - - fn infer_overloadable_binop( - &mut self, - lhs: ExprId, - op: BinaryOp, - rhs: ExprId, - tgt_expr: ExprId, - ) -> Ty { - let lhs_expectation = Expectation::none(); - let lhs_ty = self.infer_expr(lhs, &lhs_expectation); - let rhs_ty = self.table.new_type_var(); - - let func = self.resolve_binop_method(op); - let func = match func { - Some(func) => func, - None => { - let rhs_ty = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone()); - let rhs_ty = self.infer_expr_coerce(rhs, &Expectation::from_option(rhs_ty)); - return self - .builtin_binary_op_return_ty(op, lhs_ty, rhs_ty) - .unwrap_or_else(|| self.err_ty()); - } - }; - - let subst = TyBuilder::subst_for_def(self.db, func) - .push(lhs_ty.clone()) - .push(rhs_ty.clone()) - .build(); - self.write_method_resolution(tgt_expr, func, subst.clone()); - - let method_ty = self.db.value_ty(func.into()).substitute(Interner, &subst); - self.register_obligations_for_call(&method_ty); - - self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty.clone())); - - let ret_ty = match method_ty.callable_sig(self.db) { - Some(sig) => sig.ret().clone(), - None => self.err_ty(), - }; - - let ret_ty = self.normalize_associated_types_in(ret_ty); - - // FIXME: record autoref adjustments - - // use knowledge of built-in binary ops, which can sometimes help inference - if let Some(builtin_rhs) = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone()) { - self.unify(&builtin_rhs, &rhs_ty); - } - if let Some(builtin_ret) = self.builtin_binary_op_return_ty(op, lhs_ty, rhs_ty) { - self.unify(&builtin_ret, &ret_ty); - } - - ret_ty - } - - fn infer_block( - &mut self, - expr: ExprId, - statements: &[Statement], - tail: Option, - expected: &Expectation, - ) -> Ty { - for stmt in statements { - match stmt { - Statement::Let { pat, type_ref, initializer, else_branch } => { - let decl_ty = type_ref - .as_ref() - .map(|tr| self.make_ty(tr)) - .unwrap_or_else(|| self.err_ty()); - - // Always use the declared type when specified - let mut ty = decl_ty.clone(); - - if let Some(expr) = initializer { - let actual_ty = - self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty.clone())); - if decl_ty.is_unknown() { - ty = actual_ty; - } - } - - if let Some(expr) = else_branch { - self.infer_expr_coerce( - *expr, - &Expectation::has_type(Ty::new(Interner, TyKind::Never)), - ); - } - - self.infer_pat(*pat, &ty, BindingMode::default()); - } - Statement::Expr { expr, .. } => { - self.infer_expr(*expr, &Expectation::none()); - } - } - } - - if let Some(expr) = tail { - self.infer_expr_coerce(expr, expected) - } else { - // Citing rustc: if there is no explicit tail expression, - // that is typically equivalent to a tail expression - // of `()` -- except if the block diverges. In that - // case, there is no value supplied from the tail - // expression (assuming there are no other breaks, - // this implies that the type of the block will be - // `!`). - if self.diverges.is_always() { - // we don't even make an attempt at coercion - self.table.new_maybe_never_var() - } else { - if let Some(t) = expected.only_has_type(&mut self.table) { - if self.coerce(Some(expr), &TyBuilder::unit(), &t).is_err() { - self.result.type_mismatches.insert( - expr.into(), - TypeMismatch { expected: t.clone(), actual: TyBuilder::unit() }, - ); - } - t - } else { - TyBuilder::unit() - } - } - } - } - - fn infer_method_call( - &mut self, - tgt_expr: ExprId, - receiver: ExprId, - args: &[ExprId], - method_name: &Name, - generic_args: Option<&GenericArgs>, - expected: &Expectation, - ) -> Ty { - let receiver_ty = self.infer_expr(receiver, &Expectation::none()); - let canonicalized_receiver = self.canonicalize(receiver_ty.clone()); - - let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast()); - - let resolved = method_resolution::lookup_method( - &canonicalized_receiver.value, - self.db, - self.trait_env.clone(), - &traits_in_scope, - VisibleFromModule::Filter(self.resolver.module()), - method_name, - ); - let (receiver_ty, method_ty, substs) = match resolved { - Some((adjust, func)) => { - let (ty, adjustments) = adjust.apply(&mut self.table, receiver_ty); - let generics = generics(self.db.upcast(), func.into()); - let substs = self.substs_for_method_call(generics, generic_args); - self.write_expr_adj(receiver, adjustments); - self.write_method_resolution(tgt_expr, func, substs.clone()); - (ty, self.db.value_ty(func.into()), substs) - } - None => ( - receiver_ty, - Binders::empty(Interner, self.err_ty()), - Substitution::empty(Interner), - ), - }; - let method_ty = method_ty.substitute(Interner, &substs); - self.register_obligations_for_call(&method_ty); - let (formal_receiver_ty, param_tys, ret_ty, is_varargs) = - match method_ty.callable_sig(self.db) { - Some(sig) => { - if !sig.params().is_empty() { - ( - sig.params()[0].clone(), - sig.params()[1..].to_vec(), - sig.ret().clone(), - sig.is_varargs, - ) - } else { - (self.err_ty(), Vec::new(), sig.ret().clone(), sig.is_varargs) - } - } - None => (self.err_ty(), Vec::new(), self.err_ty(), true), - }; - self.unify(&formal_receiver_ty, &receiver_ty); - - let expected_inputs = - self.expected_inputs_for_expected_output(expected, ret_ty.clone(), param_tys.clone()); - - self.check_call_arguments(tgt_expr, args, &expected_inputs, ¶m_tys, &[], is_varargs); - self.normalize_associated_types_in(ret_ty) - } - - fn expected_inputs_for_expected_output( - &mut self, - expected_output: &Expectation, - output: Ty, - inputs: Vec, - ) -> Vec { - if let Some(expected_ty) = expected_output.to_option(&mut self.table) { - self.table.fudge_inference(|table| { - if table.try_unify(&expected_ty, &output).is_ok() { - table.resolve_with_fallback(inputs, &|var, kind, _, _| match kind { - chalk_ir::VariableKind::Ty(tk) => var.to_ty(Interner, tk).cast(Interner), - chalk_ir::VariableKind::Lifetime => { - var.to_lifetime(Interner).cast(Interner) - } - chalk_ir::VariableKind::Const(ty) => { - var.to_const(Interner, ty).cast(Interner) - } - }) - } else { - Vec::new() - } - }) - } else { - Vec::new() - } - } - - fn check_call_arguments( - &mut self, - expr: ExprId, - args: &[ExprId], - expected_inputs: &[Ty], - param_tys: &[Ty], - skip_indices: &[u32], - is_varargs: bool, - ) { - if args.len() != param_tys.len() + skip_indices.len() && !is_varargs { - self.push_diagnostic(InferenceDiagnostic::MismatchedArgCount { - call_expr: expr, - expected: param_tys.len() + skip_indices.len(), - found: args.len(), - }); - } - - // Quoting https://github.com/rust-lang/rust/blob/6ef275e6c3cb1384ec78128eceeb4963ff788dca/src/librustc_typeck/check/mod.rs#L3325 -- - // We do this in a pretty awful way: first we type-check any arguments - // that are not closures, then we type-check the closures. This is so - // that we have more information about the types of arguments when we - // type-check the functions. This isn't really the right way to do this. - for &check_closures in &[false, true] { - let mut skip_indices = skip_indices.into_iter().copied().fuse().peekable(); - let param_iter = param_tys.iter().cloned().chain(repeat(self.err_ty())); - let expected_iter = expected_inputs - .iter() - .cloned() - .chain(param_iter.clone().skip(expected_inputs.len())); - for (idx, ((&arg, param_ty), expected_ty)) in - args.iter().zip(param_iter).zip(expected_iter).enumerate() - { - let is_closure = matches!(&self.body[arg], Expr::Closure { .. }); - if is_closure != check_closures { - continue; - } - - while skip_indices.peek().map_or(false, |i| *i < idx as u32) { - skip_indices.next(); - } - if skip_indices.peek().copied() == Some(idx as u32) { - continue; - } - - // the difference between param_ty and expected here is that - // expected is the parameter when the expected *return* type is - // taken into account. So in `let _: &[i32] = identity(&[1, 2])` - // the expected type is already `&[i32]`, whereas param_ty is - // still an unbound type variable. We don't always want to force - // the parameter to coerce to the expected type (for example in - // `coerce_unsize_expected_type_4`). - let param_ty = self.normalize_associated_types_in(param_ty); - let expected = Expectation::rvalue_hint(&mut self.table, expected_ty); - // infer with the expected type we have... - let ty = self.infer_expr_inner(arg, &expected); - - // then coerce to either the expected type or just the formal parameter type - let coercion_target = if let Some(ty) = expected.only_has_type(&mut self.table) { - // if we are coercing to the expectation, unify with the - // formal parameter type to connect everything - self.unify(&ty, ¶m_ty); - ty - } else { - param_ty - }; - if !coercion_target.is_unknown() { - if self.coerce(Some(arg), &ty, &coercion_target).is_err() { - self.result.type_mismatches.insert( - arg.into(), - TypeMismatch { expected: coercion_target, actual: ty.clone() }, - ); - } - } - } - } - } - - fn substs_for_method_call( - &mut self, - def_generics: Generics, - generic_args: Option<&GenericArgs>, - ) -> Substitution { - let (parent_params, self_params, type_params, const_params, impl_trait_params) = - def_generics.provenance_split(); - assert_eq!(self_params, 0); // method shouldn't have another Self param - let total_len = parent_params + type_params + const_params + impl_trait_params; - let mut substs = Vec::with_capacity(total_len); - // Parent arguments are unknown - for (id, param) in def_generics.iter_parent() { - match param { - TypeOrConstParamData::TypeParamData(_) => { - substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner)); - } - TypeOrConstParamData::ConstParamData(_) => { - let ty = self.db.const_param_ty(ConstParamId::from_unchecked(id)); - substs - .push(GenericArgData::Const(self.table.new_const_var(ty)).intern(Interner)); - } - } - } - // 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() - .filter(|arg| !matches!(arg, GenericArg::Lifetime(_))) - .take(type_params + const_params) - .zip(def_generics.iter_id().skip(parent_params)) - { - if let Some(g) = generic_arg_to_chalk( - self.db, - kind_id, - arg, - self, - |this, type_ref| this.make_ty(type_ref), - |this, c, ty| { - const_or_path_to_chalk( - this.db, - &this.resolver, - ty, - c, - ParamLoweringMode::Placeholder, - || generics(this.db.upcast(), (&this.resolver).generic_def().unwrap()), - DebruijnIndex::INNERMOST, - ) - }, - ) { - substs.push(g); - } - } - }; - for (id, data) in def_generics.iter().skip(substs.len()) { - match data { - TypeOrConstParamData::TypeParamData(_) => { - substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner)) - } - TypeOrConstParamData::ConstParamData(_) => { - substs.push( - GenericArgData::Const(self.table.new_const_var( - self.db.const_param_ty(ConstParamId::from_unchecked(id)), - )) - .intern(Interner), - ) - } - } - } - assert_eq!(substs.len(), total_len); - Substitution::from_iter(Interner, substs) - } - - fn register_obligations_for_call(&mut self, callable_ty: &Ty) { - let callable_ty = self.resolve_ty_shallow(callable_ty); - if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(Interner) { - let def: CallableDefId = from_chalk(self.db, *fn_def); - let generic_predicates = self.db.generic_predicates(def.into()); - for predicate in generic_predicates.iter() { - let (predicate, binders) = predicate - .clone() - .substitute(Interner, parameters) - .into_value_and_skipped_binders(); - always!(binders.len(Interner) == 0); // quantified where clauses not yet handled - self.push_obligation(predicate.cast(Interner)); - } - // add obligation for trait implementation, if this is a trait method - match def { - CallableDefId::FunctionId(f) => { - if let ItemContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container { - // construct a TraitRef - let substs = crate::subst_prefix( - &*parameters, - generics(self.db.upcast(), trait_.into()).len(), - ); - self.push_obligation( - TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs } - .cast(Interner), - ); - } - } - CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {} - } - } - } - - /// Returns the argument indices to skip. - fn check_legacy_const_generics(&mut self, callee: Ty, args: &[ExprId]) -> Box<[u32]> { - let (func, subst) = match callee.kind(Interner) { - TyKind::FnDef(fn_id, subst) => { - let callable = CallableDefId::from_chalk(self.db, *fn_id); - let func = match callable { - CallableDefId::FunctionId(f) => f, - _ => return Default::default(), - }; - (func, subst) - } - _ => return Default::default(), - }; - - let data = self.db.function_data(func); - if data.legacy_const_generics_indices.is_empty() { - return Default::default(); - } - - // only use legacy const generics if the param count matches with them - if data.params.len() + data.legacy_const_generics_indices.len() != args.len() { - if args.len() <= data.params.len() { - return Default::default(); - } else { - // there are more parameters than there should be without legacy - // const params; use them - let mut indices = data.legacy_const_generics_indices.clone(); - indices.sort(); - return indices; - } - } - - // check legacy const parameters - for (subst_idx, arg_idx) in data.legacy_const_generics_indices.iter().copied().enumerate() { - let arg = match subst.at(Interner, subst_idx).constant(Interner) { - Some(c) => c, - None => continue, // not a const parameter? - }; - if arg_idx >= args.len() as u32 { - continue; - } - let _ty = arg.data(Interner).ty.clone(); - let expected = Expectation::none(); // FIXME use actual const ty, when that is lowered correctly - self.infer_expr(args[arg_idx as usize], &expected); - // FIXME: evaluate and unify with the const - } - let mut indices = data.legacy_const_generics_indices.clone(); - indices.sort(); - indices - } - - fn builtin_binary_op_return_ty(&mut self, op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Option { - let lhs_ty = self.resolve_ty_shallow(&lhs_ty); - let rhs_ty = self.resolve_ty_shallow(&rhs_ty); - match op { - BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => { - Some(TyKind::Scalar(Scalar::Bool).intern(Interner)) - } - BinaryOp::Assignment { .. } => Some(TyBuilder::unit()), - BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => { - // all integer combinations are valid here - if matches!( - lhs_ty.kind(Interner), - TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)) - | TyKind::InferenceVar(_, TyVariableKind::Integer) - ) && matches!( - rhs_ty.kind(Interner), - TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)) - | TyKind::InferenceVar(_, TyVariableKind::Integer) - ) { - Some(lhs_ty) - } else { - None - } - } - BinaryOp::ArithOp(_) => match (lhs_ty.kind(Interner), rhs_ty.kind(Interner)) { - // (int, int) | (uint, uint) | (float, float) - (TyKind::Scalar(Scalar::Int(_)), TyKind::Scalar(Scalar::Int(_))) - | (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_))) - | (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::Float(_))) => { - Some(rhs_ty) - } - // ({int}, int) | ({int}, uint) - ( - TyKind::InferenceVar(_, TyVariableKind::Integer), - TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)), - ) => Some(rhs_ty), - // (int, {int}) | (uint, {int}) - ( - TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)), - TyKind::InferenceVar(_, TyVariableKind::Integer), - ) => Some(lhs_ty), - // ({float} | float) - ( - TyKind::InferenceVar(_, TyVariableKind::Float), - TyKind::Scalar(Scalar::Float(_)), - ) => Some(rhs_ty), - // (float, {float}) - ( - TyKind::Scalar(Scalar::Float(_)), - TyKind::InferenceVar(_, TyVariableKind::Float), - ) => Some(lhs_ty), - // ({int}, {int}) | ({float}, {float}) - ( - TyKind::InferenceVar(_, TyVariableKind::Integer), - TyKind::InferenceVar(_, TyVariableKind::Integer), - ) - | ( - TyKind::InferenceVar(_, TyVariableKind::Float), - TyKind::InferenceVar(_, TyVariableKind::Float), - ) => Some(rhs_ty), - _ => None, - }, - } - } - - fn builtin_binary_op_rhs_expectation(&mut self, op: BinaryOp, lhs_ty: Ty) -> Option { - Some(match op { - BinaryOp::LogicOp(..) => TyKind::Scalar(Scalar::Bool).intern(Interner), - BinaryOp::Assignment { op: None } => lhs_ty, - BinaryOp::CmpOp(CmpOp::Eq { .. }) => match self - .resolve_ty_shallow(&lhs_ty) - .kind(Interner) - { - TyKind::Scalar(_) | TyKind::Str => lhs_ty, - TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty, - _ => return None, - }, - BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => return None, - BinaryOp::CmpOp(CmpOp::Ord { .. }) - | BinaryOp::Assignment { op: Some(_) } - | BinaryOp::ArithOp(_) => match self.resolve_ty_shallow(&lhs_ty).kind(Interner) { - TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_)) => lhs_ty, - TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty, - _ => return None, - }, - }) - } - - fn resolve_binop_method(&self, op: BinaryOp) -> Option { - let (name, lang_item) = match op { - BinaryOp::LogicOp(_) => return None, - BinaryOp::ArithOp(aop) => match aop { - ArithOp::Add => (name!(add), name!(add)), - ArithOp::Mul => (name!(mul), name!(mul)), - ArithOp::Sub => (name!(sub), name!(sub)), - ArithOp::Div => (name!(div), name!(div)), - ArithOp::Rem => (name!(rem), name!(rem)), - ArithOp::Shl => (name!(shl), name!(shl)), - ArithOp::Shr => (name!(shr), name!(shr)), - ArithOp::BitXor => (name!(bitxor), name!(bitxor)), - ArithOp::BitOr => (name!(bitor), name!(bitor)), - ArithOp::BitAnd => (name!(bitand), name!(bitand)), - }, - BinaryOp::Assignment { op: Some(aop) } => match aop { - ArithOp::Add => (name!(add_assign), name!(add_assign)), - ArithOp::Mul => (name!(mul_assign), name!(mul_assign)), - ArithOp::Sub => (name!(sub_assign), name!(sub_assign)), - ArithOp::Div => (name!(div_assign), name!(div_assign)), - ArithOp::Rem => (name!(rem_assign), name!(rem_assign)), - ArithOp::Shl => (name!(shl_assign), name!(shl_assign)), - ArithOp::Shr => (name!(shr_assign), name!(shr_assign)), - ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)), - ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)), - ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)), - }, - BinaryOp::CmpOp(cop) => match cop { - CmpOp::Eq { negated: false } => (name!(eq), name!(eq)), - CmpOp::Eq { negated: true } => (name!(ne), name!(eq)), - CmpOp::Ord { ordering: Ordering::Less, strict: false } => { - (name!(le), name!(partial_ord)) - } - CmpOp::Ord { ordering: Ordering::Less, strict: true } => { - (name!(lt), name!(partial_ord)) - } - CmpOp::Ord { ordering: Ordering::Greater, strict: false } => { - (name!(ge), name!(partial_ord)) - } - CmpOp::Ord { ordering: Ordering::Greater, strict: true } => { - (name!(gt), name!(partial_ord)) - } - }, - BinaryOp::Assignment { op: None } => return None, - }; - - let trait_ = self.resolve_lang_item(lang_item)?.as_trait()?; - - self.db.trait_data(trait_).method_by_name(&name) - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs deleted file mode 100644 index 5e7320a5dd305..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ /dev/null @@ -1,354 +0,0 @@ -//! Type inference for patterns. - -use std::iter::repeat_with; - -use chalk_ir::Mutability; -use hir_def::{ - expr::{BindingAnnotation, Expr, Literal, Pat, PatId}, - path::Path, - type_ref::ConstScalar, -}; -use hir_expand::name::Name; - -use crate::{ - consteval::intern_const_scalar, - infer::{BindingMode, Expectation, InferenceContext, TypeMismatch}, - lower::lower_to_chalk_mutability, - static_lifetime, ConcreteConst, ConstValue, Interner, Substitution, Ty, TyBuilder, TyExt, - TyKind, -}; - -use super::PatLike; - -impl<'a> InferenceContext<'a> { - /// Infers type for tuple struct pattern or its corresponding assignee expression. - /// - /// Ellipses found in the original pattern or expression must be filtered out. - pub(super) fn infer_tuple_struct_pat_like( - &mut self, - path: Option<&Path>, - expected: &Ty, - default_bm: T::BindingMode, - id: T, - ellipsis: Option, - subs: &[T], - ) -> Ty { - let (ty, def) = self.resolve_variant(path, true); - let var_data = def.map(|it| it.variant_data(self.db.upcast())); - if let Some(variant) = def { - self.write_variant_resolution(id.into(), variant); - } - self.unify(&ty, expected); - - let substs = - ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(Interner)); - - let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); - let (pre, post) = match ellipsis { - Some(idx) => subs.split_at(idx), - None => (subs, &[][..]), - }; - let post_idx_offset = field_tys.iter().count().saturating_sub(post.len()); - - let pre_iter = pre.iter().enumerate(); - let post_iter = (post_idx_offset..).zip(post.iter()); - for (i, &subpat) in pre_iter.chain(post_iter) { - let expected_ty = var_data - .as_ref() - .and_then(|d| d.field(&Name::new_tuple_field(i))) - .map_or(self.err_ty(), |field| { - field_tys[field].clone().substitute(Interner, &substs) - }); - let expected_ty = self.normalize_associated_types_in(expected_ty); - T::infer(self, subpat, &expected_ty, default_bm); - } - - ty - } - - /// Infers type for record pattern or its corresponding assignee expression. - pub(super) fn infer_record_pat_like( - &mut self, - path: Option<&Path>, - expected: &Ty, - default_bm: T::BindingMode, - id: T, - subs: impl Iterator, - ) -> Ty { - let (ty, def) = self.resolve_variant(path, false); - if let Some(variant) = def { - self.write_variant_resolution(id.into(), variant); - } - - self.unify(&ty, expected); - - let substs = - ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(Interner)); - - let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); - let var_data = def.map(|it| it.variant_data(self.db.upcast())); - - for (name, inner) in subs { - let expected_ty = var_data - .as_ref() - .and_then(|it| it.field(&name)) - .map_or(self.err_ty(), |f| field_tys[f].clone().substitute(Interner, &substs)); - let expected_ty = self.normalize_associated_types_in(expected_ty); - - T::infer(self, inner, &expected_ty, default_bm); - } - - ty - } - - /// Infers type for tuple pattern or its corresponding assignee expression. - /// - /// Ellipses found in the original pattern or expression must be filtered out. - pub(super) fn infer_tuple_pat_like( - &mut self, - expected: &Ty, - default_bm: T::BindingMode, - ellipsis: Option, - subs: &[T], - ) -> Ty { - let expectations = match expected.as_tuple() { - Some(parameters) => &*parameters.as_slice(Interner), - _ => &[], - }; - - let ((pre, post), n_uncovered_patterns) = match ellipsis { - Some(idx) => (subs.split_at(idx), expectations.len().saturating_sub(subs.len())), - None => ((&subs[..], &[][..]), 0), - }; - let mut expectations_iter = expectations - .iter() - .cloned() - .map(|a| a.assert_ty_ref(Interner).clone()) - .chain(repeat_with(|| self.table.new_type_var())); - - let mut inner_tys = Vec::with_capacity(n_uncovered_patterns + subs.len()); - - inner_tys.extend(expectations_iter.by_ref().take(n_uncovered_patterns + subs.len())); - - // Process pre - for (ty, pat) in inner_tys.iter_mut().zip(pre) { - *ty = T::infer(self, *pat, ty, default_bm); - } - - // Process post - for (ty, pat) in inner_tys.iter_mut().skip(pre.len() + n_uncovered_patterns).zip(post) { - *ty = T::infer(self, *pat, ty, default_bm); - } - - TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys)) - .intern(Interner) - } - - pub(super) fn infer_pat( - &mut self, - pat: PatId, - expected: &Ty, - mut default_bm: BindingMode, - ) -> Ty { - let mut expected = self.resolve_ty_shallow(expected); - - if is_non_ref_pat(&self.body, pat) { - let mut pat_adjustments = Vec::new(); - while let Some((inner, _lifetime, mutability)) = expected.as_reference() { - pat_adjustments.push(expected.clone()); - expected = self.resolve_ty_shallow(inner); - default_bm = match default_bm { - BindingMode::Move => BindingMode::Ref(mutability), - BindingMode::Ref(Mutability::Not) => BindingMode::Ref(Mutability::Not), - BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(mutability), - } - } - - if !pat_adjustments.is_empty() { - pat_adjustments.shrink_to_fit(); - self.result.pat_adjustments.insert(pat, pat_adjustments); - } - } else if let Pat::Ref { .. } = &self.body[pat] { - cov_mark::hit!(match_ergonomics_ref); - // When you encounter a `&pat` pattern, reset to Move. - // This is so that `w` is by value: `let (_, &w) = &(1, &2);` - default_bm = BindingMode::Move; - } - - // Lose mutability. - let default_bm = default_bm; - let expected = expected; - - let ty = match &self.body[pat] { - Pat::Tuple { args, ellipsis } => { - self.infer_tuple_pat_like(&expected, default_bm, *ellipsis, args) - } - Pat::Or(pats) => { - if let Some((first_pat, rest)) = pats.split_first() { - let ty = self.infer_pat(*first_pat, &expected, default_bm); - for pat in rest { - self.infer_pat(*pat, &expected, default_bm); - } - ty - } else { - self.err_ty() - } - } - Pat::Ref { pat, mutability } => { - let mutability = lower_to_chalk_mutability(*mutability); - let expectation = match expected.as_reference() { - Some((inner_ty, _lifetime, exp_mut)) => { - if mutability != exp_mut { - // FIXME: emit type error? - } - inner_ty.clone() - } - _ => self.result.standard_types.unknown.clone(), - }; - let subty = self.infer_pat(*pat, &expectation, default_bm); - TyKind::Ref(mutability, static_lifetime(), subty).intern(Interner) - } - Pat::TupleStruct { path: p, args: subpats, ellipsis } => self - .infer_tuple_struct_pat_like( - p.as_deref(), - &expected, - default_bm, - pat, - *ellipsis, - subpats, - ), - Pat::Record { path: p, args: fields, ellipsis: _ } => { - let subs = fields.iter().map(|f| (f.name.clone(), f.pat)); - self.infer_record_pat_like(p.as_deref(), &expected, default_bm, pat.into(), subs) - } - Pat::Path(path) => { - // FIXME use correct resolver for the surrounding expression - let resolver = self.resolver.clone(); - self.infer_path(&resolver, path, pat.into()).unwrap_or_else(|| self.err_ty()) - } - Pat::Bind { mode, name: _, subpat } => { - let mode = if mode == &BindingAnnotation::Unannotated { - default_bm - } else { - BindingMode::convert(*mode) - }; - self.result.pat_binding_modes.insert(pat, mode); - - let inner_ty = match subpat { - Some(subpat) => self.infer_pat(*subpat, &expected, default_bm), - None => expected, - }; - let inner_ty = self.insert_type_vars_shallow(inner_ty); - - let bound_ty = match mode { - BindingMode::Ref(mutability) => { - TyKind::Ref(mutability, static_lifetime(), inner_ty.clone()) - .intern(Interner) - } - BindingMode::Move => inner_ty.clone(), - }; - self.write_pat_ty(pat, bound_ty); - return inner_ty; - } - Pat::Slice { prefix, slice, suffix } => { - let elem_ty = match expected.kind(Interner) { - TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(), - _ => self.err_ty(), - }; - - for &pat_id in prefix.iter().chain(suffix.iter()) { - self.infer_pat(pat_id, &elem_ty, default_bm); - } - - if let &Some(slice_pat_id) = slice { - let rest_pat_ty = match expected.kind(Interner) { - TyKind::Array(_, length) => { - let len = match length.data(Interner).value { - ConstValue::Concrete(ConcreteConst { - interned: ConstScalar::UInt(len), - }) => len.checked_sub((prefix.len() + suffix.len()) as u128), - _ => None, - }; - TyKind::Array( - elem_ty.clone(), - intern_const_scalar( - len.map_or(ConstScalar::Unknown, |len| ConstScalar::UInt(len)), - TyBuilder::usize(), - ), - ) - } - _ => TyKind::Slice(elem_ty.clone()), - } - .intern(Interner); - self.infer_pat(slice_pat_id, &rest_pat_ty, default_bm); - } - - match expected.kind(Interner) { - TyKind::Array(_, const_) => TyKind::Array(elem_ty, const_.clone()), - _ => TyKind::Slice(elem_ty), - } - .intern(Interner) - } - Pat::Wild => expected.clone(), - Pat::Range { start, end } => { - let start_ty = self.infer_expr(*start, &Expectation::has_type(expected.clone())); - self.infer_expr(*end, &Expectation::has_type(start_ty)) - } - Pat::Lit(expr) => self.infer_expr(*expr, &Expectation::has_type(expected.clone())), - Pat::Box { inner } => match self.resolve_boxed_box() { - Some(box_adt) => { - let (inner_ty, alloc_ty) = match expected.as_adt() { - Some((adt, subst)) if adt == box_adt => ( - subst.at(Interner, 0).assert_ty_ref(Interner).clone(), - subst.as_slice(Interner).get(1).and_then(|a| a.ty(Interner).cloned()), - ), - _ => (self.result.standard_types.unknown.clone(), None), - }; - - let inner_ty = self.infer_pat(*inner, &inner_ty, default_bm); - let mut b = TyBuilder::adt(self.db, box_adt).push(inner_ty); - - if let Some(alloc_ty) = alloc_ty { - b = b.push(alloc_ty); - } - b.fill_with_defaults(self.db, || self.table.new_type_var()).build() - } - None => self.err_ty(), - }, - Pat::ConstBlock(expr) => { - self.infer_expr(*expr, &Expectation::has_type(expected.clone())) - } - Pat::Missing => self.err_ty(), - }; - // use a new type variable if we got error type here - let ty = self.insert_type_vars_shallow(ty); - if !self.unify(&ty, &expected) { - self.result - .type_mismatches - .insert(pat.into(), TypeMismatch { expected, actual: ty.clone() }); - } - self.write_pat_ty(pat, ty.clone()); - ty - } -} - -fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { - match &body[pat] { - Pat::Tuple { .. } - | Pat::TupleStruct { .. } - | Pat::Record { .. } - | Pat::Range { .. } - | Pat::Slice { .. } => true, - Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)), - // FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented. - Pat::Path(..) => true, - Pat::ConstBlock(..) => true, - Pat::Lit(expr) => !matches!(body[*expr], Expr::Literal(Literal::String(..))), - Pat::Bind { - mode: BindingAnnotation::Mutable | BindingAnnotation::Unannotated, - subpat: Some(subpat), - .. - } => is_non_ref_pat(body, *subpat), - Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false, - } -} 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 deleted file mode 100644 index f580e09e91229..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ /dev/null @@ -1,295 +0,0 @@ -//! Path expression resolution. - -use chalk_ir::cast::Cast; -use hir_def::{ - path::{Path, PathSegment}, - resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, - AdtId, AssocItemId, EnumVariantId, ItemContainerId, Lookup, -}; -use hir_expand::name::Name; - -use crate::{ - builder::ParamKind, - consteval, - method_resolution::{self, VisibleFromModule}, - GenericArgData, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, - ValueTyDefId, -}; - -use super::{ExprOrPatId, InferenceContext, TraitRef}; - -impl<'a> InferenceContext<'a> { - pub(super) fn infer_path( - &mut self, - resolver: &Resolver, - path: &Path, - id: ExprOrPatId, - ) -> Option { - let ty = self.resolve_value_path(resolver, path, id)?; - let ty = self.insert_type_vars(ty); - let ty = self.normalize_associated_types_in(ty); - Some(ty) - } - - fn resolve_value_path( - &mut self, - resolver: &Resolver, - path: &Path, - id: ExprOrPatId, - ) -> Option { - let (value, self_subst) = if let Some(type_ref) = path.type_anchor() { - if path.segments().is_empty() { - // This can't actually happen syntax-wise - return None; - } - let ty = self.make_ty(type_ref); - let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); - let ctx = crate::lower::TyLoweringContext::new(self.db, resolver); - let (ty, _) = ctx.lower_ty_relative_path(ty, None, remaining_segments_for_ty); - self.resolve_ty_assoc_item( - ty, - path.segments().last().expect("path had at least one segment").name, - id, - )? - } else { - let value_or_partial = - resolver.resolve_path_in_value_ns(self.db.upcast(), path.mod_path())?; - - match value_or_partial { - ResolveValueResult::ValueNs(it) => (it, None), - ResolveValueResult::Partial(def, remaining_index) => { - self.resolve_assoc_item(def, path, remaining_index, id)? - } - } - }; - - let typable: ValueTyDefId = match value { - ValueNs::LocalBinding(pat) => { - let ty = self.result.type_of_pat.get(pat)?.clone(); - return Some(ty); - } - ValueNs::FunctionId(it) => it.into(), - ValueNs::ConstId(it) => it.into(), - ValueNs::StaticId(it) => it.into(), - ValueNs::StructId(it) => { - self.write_variant_resolution(id, it.into()); - - it.into() - } - ValueNs::EnumVariantId(it) => { - self.write_variant_resolution(id, it.into()); - - it.into() - } - ValueNs::ImplSelf(impl_id) => { - let generics = crate::utils::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() { - let ty = self.db.value_ty(struct_id.into()).substitute(Interner, &substs); - return Some(ty); - } else { - // FIXME: diagnostic, invalid Self reference - return None; - } - } - ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)), - }; - - let parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(Interner)); - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); - let substs = ctx.substs_from_path(path, typable, true); - let mut it = substs.as_slice(Interner)[parent_substs.len(Interner)..].iter().cloned(); - let ty = TyBuilder::value_ty(self.db, typable) - .use_parent_substs(&parent_substs) - .fill(|x| { - it.next().unwrap_or_else(|| match x { - ParamKind::Type => { - GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner) - } - ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()), - }) - }) - .build(); - Some(ty) - } - - fn resolve_assoc_item( - &mut self, - def: TypeNs, - path: &Path, - remaining_index: usize, - id: ExprOrPatId, - ) -> Option<(ValueNs, Option)> { - assert!(remaining_index < path.segments().len()); - // there may be more intermediate segments between the resolved one and - // the end. Only the last segment needs to be resolved to a value; from - // the segments before that, we need to get either a type or a trait ref. - - let resolved_segment = path.segments().get(remaining_index - 1).unwrap(); - let remaining_segments = path.segments().skip(remaining_index); - let is_before_last = remaining_segments.len() == 1; - - match (def, is_before_last) { - (TypeNs::TraitId(trait_), true) => { - let segment = - remaining_segments.last().expect("there should be at least one segment here"); - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); - let trait_ref = - ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None); - self.resolve_trait_assoc_item(trait_ref, segment, id) - } - (def, _) => { - // Either we already have a type (e.g. `Vec::new`), or we have a - // trait but it's not the last segment, so the next segment - // should resolve to an associated type of that trait (e.g. `::Item::default`) - let remaining_segments_for_ty = - remaining_segments.take(remaining_segments.len() - 1); - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); - let (ty, _) = ctx.lower_partly_resolved_path( - def, - resolved_segment, - remaining_segments_for_ty, - true, - ); - if let TyKind::Error = ty.kind(Interner) { - return None; - } - - let ty = self.insert_type_vars(ty); - let ty = self.normalize_associated_types_in(ty); - - let segment = - remaining_segments.last().expect("there should be at least one segment here"); - - self.resolve_ty_assoc_item(ty, segment.name, id) - } - } - } - - fn resolve_trait_assoc_item( - &mut self, - trait_ref: TraitRef, - segment: PathSegment<'_>, - id: ExprOrPatId, - ) -> Option<(ValueNs, Option)> { - let trait_ = trait_ref.hir_trait_id(); - let item = - self.db.trait_data(trait_).items.iter().map(|(_name, id)| (*id)).find_map(|item| { - match item { - AssocItemId::FunctionId(func) => { - if segment.name == &self.db.function_data(func).name { - Some(AssocItemId::FunctionId(func)) - } else { - None - } - } - - AssocItemId::ConstId(konst) => { - if self - .db - .const_data(konst) - .name - .as_ref() - .map_or(false, |n| n == segment.name) - { - Some(AssocItemId::ConstId(konst)) - } else { - None - } - } - AssocItemId::TypeAliasId(_) => None, - } - })?; - let def = match item { - AssocItemId::FunctionId(f) => ValueNs::FunctionId(f), - AssocItemId::ConstId(c) => ValueNs::ConstId(c), - AssocItemId::TypeAliasId(_) => unreachable!(), - }; - - self.write_assoc_resolution(id, item); - Some((def, Some(trait_ref.substitution))) - } - - fn resolve_ty_assoc_item( - &mut self, - ty: Ty, - name: &Name, - id: ExprOrPatId, - ) -> Option<(ValueNs, Option)> { - if let TyKind::Error = ty.kind(Interner) { - return None; - } - - if let Some(result) = self.resolve_enum_variant_on_ty(&ty, name, id) { - return Some(result); - } - - let canonical_ty = self.canonicalize(ty.clone()); - let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast()); - - method_resolution::iterate_method_candidates( - &canonical_ty.value, - self.db, - self.table.trait_env.clone(), - &traits_in_scope, - VisibleFromModule::Filter(self.resolver.module()), - Some(name), - method_resolution::LookupMode::Path, - move |_ty, item| { - let (def, container) = match item { - AssocItemId::FunctionId(f) => { - (ValueNs::FunctionId(f), f.lookup(self.db.upcast()).container) - } - AssocItemId::ConstId(c) => { - (ValueNs::ConstId(c), c.lookup(self.db.upcast()).container) - } - AssocItemId::TypeAliasId(_) => unreachable!(), - }; - let substs = match container { - ItemContainerId::ImplId(impl_id) => { - let impl_substs = TyBuilder::subst_for_def(self.db, impl_id) - .fill_with_inference_vars(&mut self.table) - .build(); - let impl_self_ty = - self.db.impl_self_ty(impl_id).substitute(Interner, &impl_substs); - self.unify(&impl_self_ty, &ty); - Some(impl_substs) - } - ItemContainerId::TraitId(trait_) => { - // we're picking this method - let trait_ref = TyBuilder::trait_ref(self.db, trait_) - .push(ty.clone()) - .fill_with_inference_vars(&mut self.table) - .build(); - self.push_obligation(trait_ref.clone().cast(Interner)); - Some(trait_ref.substitution) - } - ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None, - }; - - self.write_assoc_resolution(id, item); - Some((def, substs)) - }, - ) - } - - fn resolve_enum_variant_on_ty( - &mut self, - ty: &Ty, - name: &Name, - id: ExprOrPatId, - ) -> Option<(ValueNs, Option)> { - let ty = self.resolve_ty_shallow(ty); - let (enum_id, subst) = match ty.as_adt() { - Some((AdtId::EnumId(e), subst)) => (e, subst), - _ => return None, - }; - let enum_data = self.db.enum_data(enum_id); - let local_id = enum_data.variant(name)?; - let variant = EnumVariantId { parent: enum_id, local_id }; - self.write_variant_resolution(id, variant.into()); - Some((ValueNs::EnumVariantId(variant), Some(subst.clone()))) - } -} 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 deleted file mode 100644 index e77b55670b5e1..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ /dev/null @@ -1,738 +0,0 @@ -//! Unification and canonicalization logic. - -use std::{fmt, mem, sync::Arc}; - -use chalk_ir::{ - cast::Cast, fold::TypeFoldable, interner::HasInterner, zip::Zip, CanonicalVarKind, FloatTy, - IntTy, NoSolution, TyVariableKind, UniverseIndex, -}; -use chalk_solve::infer::ParameterEnaVariableExt; -use ena::unify::UnifyKey; -use hir_expand::name; -use stdx::never; - -use super::{InferOk, InferResult, InferenceContext, TypeError}; -use crate::{ - db::HirDatabase, fold_tys, static_lifetime, traits::FnTrait, AliasEq, AliasTy, BoundVar, - Canonical, Const, DebruijnIndex, GenericArg, GenericArgData, Goal, Guidance, InEnvironment, - InferenceVar, Interner, Lifetime, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution, - Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind, -}; - -impl<'a> InferenceContext<'a> { - pub(super) fn canonicalize + HasInterner>( - &mut self, - t: T, - ) -> Canonicalized - where - T: HasInterner, - { - self.table.canonicalize(t) - } -} - -#[derive(Debug, Clone)] -pub(crate) struct Canonicalized -where - T: HasInterner, -{ - pub(crate) value: Canonical, - free_vars: Vec, -} - -impl> Canonicalized { - pub(super) fn apply_solution( - &self, - ctx: &mut InferenceTable<'_>, - solution: Canonical, - ) { - // the solution may contain new variables, which we need to convert to new inference vars - let new_vars = Substitution::from_iter( - Interner, - solution.binders.iter(Interner).map(|k| match &k.kind { - VariableKind::Ty(TyVariableKind::General) => ctx.new_type_var().cast(Interner), - VariableKind::Ty(TyVariableKind::Integer) => ctx.new_integer_var().cast(Interner), - VariableKind::Ty(TyVariableKind::Float) => ctx.new_float_var().cast(Interner), - // Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere - VariableKind::Lifetime => static_lifetime().cast(Interner), - VariableKind::Const(ty) => ctx.new_const_var(ty.clone()).cast(Interner), - }), - ); - for (i, v) in solution.value.iter(Interner).enumerate() { - let var = self.free_vars[i].clone(); - if let Some(ty) = v.ty(Interner) { - // eagerly replace projections in the type; we may be getting types - // e.g. from where clauses where this hasn't happened yet - let ty = ctx.normalize_associated_types_in(new_vars.apply(ty.clone(), Interner)); - ctx.unify(var.assert_ty_ref(Interner), &ty); - } else { - let _ = ctx.try_unify(&var, &new_vars.apply(v.clone(), Interner)); - } - } - } -} - -pub fn could_unify( - db: &dyn HirDatabase, - env: Arc, - tys: &Canonical<(Ty, Ty)>, -) -> bool { - unify(db, env, tys).is_some() -} - -pub(crate) fn unify( - db: &dyn HirDatabase, - env: Arc, - tys: &Canonical<(Ty, Ty)>, -) -> Option { - let mut table = InferenceTable::new(db, env); - let vars = Substitution::from_iter( - Interner, - tys.binders.iter(Interner).map(|x| match &x.kind { - chalk_ir::VariableKind::Ty(_) => { - GenericArgData::Ty(table.new_type_var()).intern(Interner) - } - chalk_ir::VariableKind::Lifetime => { - GenericArgData::Ty(table.new_type_var()).intern(Interner) - } // FIXME: maybe wrong? - chalk_ir::VariableKind::Const(ty) => { - GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner) - } - }), - ); - let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner); - let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner); - if !table.unify(&ty1_with_vars, &ty2_with_vars) { - return None; - } - // default any type vars that weren't unified back to their original bound vars - // (kind of hacky) - let find_var = |iv| { - vars.iter(Interner).position(|v| match v.interned() { - chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(Interner), - chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(Interner), - chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner), - } == Some(iv)) - }; - let fallback = |iv, kind, default, binder| match kind { - chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv) - .map_or(default, |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner)), - chalk_ir::VariableKind::Lifetime => find_var(iv) - .map_or(default, |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner)), - chalk_ir::VariableKind::Const(ty) => find_var(iv) - .map_or(default, |i| BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner)), - }; - Some(Substitution::from_iter( - Interner, - vars.iter(Interner).map(|v| table.resolve_with_fallback(v.clone(), &fallback)), - )) -} - -#[derive(Copy, Clone, Debug)] -pub(crate) struct TypeVariableData { - diverging: bool, -} - -type ChalkInferenceTable = chalk_solve::infer::InferenceTable; - -#[derive(Clone)] -pub(crate) struct InferenceTable<'a> { - pub(crate) db: &'a dyn HirDatabase, - pub(crate) trait_env: Arc, - var_unification_table: ChalkInferenceTable, - type_variable_table: Vec, - pending_obligations: Vec>>, -} - -pub(crate) struct InferenceTableSnapshot { - var_table_snapshot: chalk_solve::infer::InferenceSnapshot, - pending_obligations: Vec>>, - type_variable_table_snapshot: Vec, -} - -impl<'a> InferenceTable<'a> { - pub(crate) fn new(db: &'a dyn HirDatabase, trait_env: Arc) -> Self { - InferenceTable { - db, - trait_env, - var_unification_table: ChalkInferenceTable::new(), - type_variable_table: Vec::new(), - pending_obligations: Vec::new(), - } - } - - /// Chalk doesn't know about the `diverging` flag, so when it unifies two - /// type variables of which one is diverging, the chosen root might not be - /// diverging and we have no way of marking it as such at that time. This - /// function goes through all type variables and make sure their root is - /// marked as diverging if necessary, so that resolving them gives the right - /// result. - pub(super) fn propagate_diverging_flag(&mut self) { - for i in 0..self.type_variable_table.len() { - if !self.type_variable_table[i].diverging { - continue; - } - let v = InferenceVar::from(i as u32); - let root = self.var_unification_table.inference_var_root(v); - if let Some(data) = self.type_variable_table.get_mut(root.index() as usize) { - data.diverging = true; - } - } - } - - pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) { - self.type_variable_table[iv.index() as usize].diverging = diverging; - } - - fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty { - match kind { - _ if self - .type_variable_table - .get(iv.index() as usize) - .map_or(false, |data| data.diverging) => - { - TyKind::Never - } - TyVariableKind::General => TyKind::Error, - TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)), - TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)), - } - .intern(Interner) - } - - pub(crate) fn canonicalize + HasInterner>( - &mut self, - t: T, - ) -> Canonicalized - where - T: HasInterner, - { - // try to resolve obligations before canonicalizing, since this might - // result in new knowledge about variables - self.resolve_obligations_as_possible(); - let result = self.var_unification_table.canonicalize(Interner, t); - let free_vars = result - .free_vars - .into_iter() - .map(|free_var| free_var.to_generic_arg(Interner)) - .collect(); - Canonicalized { value: result.quantified, free_vars } - } - - /// Recurses through the given type, normalizing associated types mentioned - /// in it by replacing them by type variables and registering obligations to - /// resolve later. This should be done once for every type we get from some - /// type annotation (e.g. from a let type annotation, field type or function - /// call). `make_ty` handles this already, but e.g. for field types we need - /// to do it as well. - pub(crate) fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { - fold_tys( - ty, - |ty, _| match ty.kind(Interner) { - TyKind::Alias(AliasTy::Projection(proj_ty)) => { - self.normalize_projection_ty(proj_ty.clone()) - } - _ => ty, - }, - DebruijnIndex::INNERMOST, - ) - } - - pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { - let var = self.new_type_var(); - let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() }; - let obligation = alias_eq.cast(Interner); - self.register_obligation(obligation); - var - } - - fn extend_type_variable_table(&mut self, to_index: usize) { - self.type_variable_table.extend( - (0..1 + to_index - self.type_variable_table.len()) - .map(|_| TypeVariableData { diverging: false }), - ); - } - - fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty { - let var = self.var_unification_table.new_variable(UniverseIndex::ROOT); - // Chalk might have created some type variables for its own purposes that we don't know about... - self.extend_type_variable_table(var.index() as usize); - assert_eq!(var.index() as usize, self.type_variable_table.len() - 1); - self.type_variable_table[var.index() as usize].diverging = diverging; - var.to_ty_with_kind(Interner, kind) - } - - pub(crate) fn new_type_var(&mut self) -> Ty { - self.new_var(TyVariableKind::General, false) - } - - pub(crate) fn new_integer_var(&mut self) -> Ty { - self.new_var(TyVariableKind::Integer, false) - } - - pub(crate) fn new_float_var(&mut self) -> Ty { - self.new_var(TyVariableKind::Float, false) - } - - pub(crate) fn new_maybe_never_var(&mut self) -> Ty { - self.new_var(TyVariableKind::General, true) - } - - pub(crate) fn new_const_var(&mut self, ty: Ty) -> Const { - let var = self.var_unification_table.new_variable(UniverseIndex::ROOT); - var.to_const(Interner, ty) - } - - pub(crate) fn new_lifetime_var(&mut self) -> Lifetime { - let var = self.var_unification_table.new_variable(UniverseIndex::ROOT); - var.to_lifetime(Interner) - } - - pub(crate) fn resolve_with_fallback( - &mut self, - t: T, - fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg, - ) -> T - where - T: HasInterner + TypeFoldable, - { - self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback) - } - - pub(crate) fn fresh_subst(&mut self, binders: &[CanonicalVarKind]) -> Substitution { - Substitution::from_iter( - Interner, - binders.iter().map(|kind| { - let param_infer_var = - kind.map_ref(|&ui| self.var_unification_table.new_variable(ui)); - param_infer_var.to_generic_arg(Interner) - }), - ) - } - - pub(crate) fn instantiate_canonical(&mut self, canonical: Canonical) -> T - where - T: HasInterner + TypeFoldable + std::fmt::Debug, - { - let subst = self.fresh_subst(canonical.binders.as_slice(Interner)); - subst.apply(canonical.value, Interner) - } - - fn resolve_with_fallback_inner( - &mut self, - var_stack: &mut Vec, - t: T, - fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg, - ) -> T - where - T: HasInterner + TypeFoldable, - { - t.fold_with( - &mut resolve::Resolver { table: self, var_stack, fallback }, - DebruijnIndex::INNERMOST, - ) - .expect("fold failed unexpectedly") - } - - pub(crate) fn resolve_completely(&mut self, t: T) -> T - where - T: HasInterner + TypeFoldable, - { - self.resolve_with_fallback(t, &|_, _, d, _| d) - } - - /// Unify two types and register new trait goals that arise from that. - pub(crate) fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { - let result = match self.try_unify(ty1, ty2) { - Ok(r) => r, - Err(_) => return false, - }; - self.register_infer_ok(result); - true - } - - /// Unify two types and return new trait goals arising from it, so the - /// caller needs to deal with them. - pub(crate) fn try_unify>(&mut self, t1: &T, t2: &T) -> InferResult<()> { - match self.var_unification_table.relate( - Interner, - &self.db, - &self.trait_env.env, - chalk_ir::Variance::Invariant, - t1, - t2, - ) { - Ok(result) => Ok(InferOk { goals: result.goals, value: () }), - Err(chalk_ir::NoSolution) => Err(TypeError), - } - } - - /// If `ty` is a type variable with known type, returns that type; - /// otherwise, return ty. - pub(crate) fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty { - self.resolve_obligations_as_possible(); - self.var_unification_table.normalize_ty_shallow(Interner, ty).unwrap_or_else(|| ty.clone()) - } - - pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot { - let var_table_snapshot = self.var_unification_table.snapshot(); - let type_variable_table_snapshot = self.type_variable_table.clone(); - let pending_obligations = self.pending_obligations.clone(); - InferenceTableSnapshot { - var_table_snapshot, - pending_obligations, - type_variable_table_snapshot, - } - } - - pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot) { - self.var_unification_table.rollback_to(snapshot.var_table_snapshot); - self.type_variable_table = snapshot.type_variable_table_snapshot; - self.pending_obligations = snapshot.pending_obligations; - } - - pub(crate) fn run_in_snapshot(&mut self, f: impl FnOnce(&mut InferenceTable<'_>) -> T) -> T { - let snapshot = self.snapshot(); - let result = f(self); - self.rollback_to(snapshot); - result - } - - /// Checks an obligation without registering it. Useful mostly to check - /// whether a trait *might* be implemented before deciding to 'lock in' the - /// choice (during e.g. method resolution or deref). - pub(crate) fn try_obligation(&mut self, goal: Goal) -> Option { - let in_env = InEnvironment::new(&self.trait_env.env, goal); - let canonicalized = self.canonicalize(in_env); - let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value); - solution - } - - pub(crate) fn register_obligation(&mut self, goal: Goal) { - let in_env = InEnvironment::new(&self.trait_env.env, goal); - self.register_obligation_in_env(in_env) - } - - fn register_obligation_in_env(&mut self, goal: InEnvironment) { - let canonicalized = self.canonicalize(goal); - if !self.try_resolve_obligation(&canonicalized) { - self.pending_obligations.push(canonicalized); - } - } - - pub(crate) fn register_infer_ok(&mut self, infer_ok: InferOk) { - infer_ok.goals.into_iter().for_each(|goal| self.register_obligation_in_env(goal)); - } - - pub(crate) fn resolve_obligations_as_possible(&mut self) { - let _span = profile::span("resolve_obligations_as_possible"); - let mut changed = true; - let mut obligations = Vec::new(); - while changed { - changed = false; - mem::swap(&mut self.pending_obligations, &mut obligations); - for canonicalized in obligations.drain(..) { - if !self.check_changed(&canonicalized) { - self.pending_obligations.push(canonicalized); - continue; - } - changed = true; - let uncanonical = chalk_ir::Substitute::apply( - &canonicalized.free_vars, - canonicalized.value.value, - Interner, - ); - self.register_obligation_in_env(uncanonical); - } - } - } - - pub(crate) fn fudge_inference>( - &mut self, - f: impl FnOnce(&mut Self) -> T, - ) -> T { - use chalk_ir::fold::TypeFolder; - struct VarFudger<'a, 'b> { - table: &'a mut InferenceTable<'b>, - highest_known_var: InferenceVar, - } - impl<'a, 'b> TypeFolder for VarFudger<'a, 'b> { - type Error = NoSolution; - - fn as_dyn(&mut self) -> &mut dyn TypeFolder { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn fold_inference_ty( - &mut self, - var: chalk_ir::InferenceVar, - kind: TyVariableKind, - _outer_binder: chalk_ir::DebruijnIndex, - ) -> chalk_ir::Fallible> { - Ok(if var < self.highest_known_var { - var.to_ty(Interner, kind) - } else { - self.table.new_type_var() - }) - } - - fn fold_inference_lifetime( - &mut self, - var: chalk_ir::InferenceVar, - _outer_binder: chalk_ir::DebruijnIndex, - ) -> chalk_ir::Fallible> { - Ok(if var < self.highest_known_var { - var.to_lifetime(Interner) - } else { - self.table.new_lifetime_var() - }) - } - - fn fold_inference_const( - &mut self, - ty: chalk_ir::Ty, - var: chalk_ir::InferenceVar, - _outer_binder: chalk_ir::DebruijnIndex, - ) -> chalk_ir::Fallible> { - Ok(if var < self.highest_known_var { - var.to_const(Interner, ty) - } else { - self.table.new_const_var(ty) - }) - } - } - - let snapshot = self.snapshot(); - let highest_known_var = self.new_type_var().inference_var(Interner).expect("inference_var"); - let result = f(self); - self.rollback_to(snapshot); - result - .fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST) - .expect("fold_with with VarFudger") - } - - /// This checks whether any of the free variables in the `canonicalized` - /// have changed (either been unified with another variable, or with a - /// value). If this is not the case, we don't need to try to solve the goal - /// again -- it'll give the same result as last time. - fn check_changed(&mut self, canonicalized: &Canonicalized>) -> bool { - canonicalized.free_vars.iter().any(|var| { - let iv = match var.data(Interner) { - chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(Interner), - chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(Interner), - chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner), - } - .expect("free var is not inference var"); - if self.var_unification_table.probe_var(iv).is_some() { - return true; - } - let root = self.var_unification_table.inference_var_root(iv); - iv != root - }) - } - - fn try_resolve_obligation( - &mut self, - canonicalized: &Canonicalized>, - ) -> bool { - let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value.clone()); - - match solution { - Some(Solution::Unique(canonical_subst)) => { - canonicalized.apply_solution( - self, - Canonical { - binders: canonical_subst.binders, - // FIXME: handle constraints - value: canonical_subst.value.subst, - }, - ); - true - } - Some(Solution::Ambig(Guidance::Definite(substs))) => { - canonicalized.apply_solution(self, substs); - false - } - Some(_) => { - // FIXME use this when trying to resolve everything at the end - false - } - None => { - // FIXME obligation cannot be fulfilled => diagnostic - true - } - } - } - - pub(crate) fn callable_sig(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec, Ty)> { - match ty.callable_sig(self.db) { - Some(sig) => Some((sig.params().to_vec(), sig.ret().clone())), - None => self.callable_sig_from_fn_trait(ty, num_args), - } - } - - fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec, Ty)> { - let krate = self.trait_env.krate; - let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; - let output_assoc_type = - self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; - - let mut arg_tys = vec![]; - let arg_ty = TyBuilder::tuple(num_args) - .fill(|x| { - let arg = match x { - ParamKind::Type => self.new_type_var(), - ParamKind::Const(ty) => { - never!("Tuple with const parameter"); - return GenericArgData::Const(self.new_const_var(ty.clone())) - .intern(Interner); - } - }; - arg_tys.push(arg.clone()); - GenericArgData::Ty(arg).intern(Interner) - }) - .build(); - - let projection = { - let b = TyBuilder::assoc_type_projection(self.db, output_assoc_type); - if b.remaining() != 2 { - return None; - } - b.push(ty.clone()).push(arg_ty).build() - }; - - let trait_env = self.trait_env.env.clone(); - let obligation = InEnvironment { - goal: projection.trait_ref(self.db).cast(Interner), - environment: trait_env, - }; - let canonical = self.canonicalize(obligation.clone()); - if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() { - self.register_obligation(obligation.goal); - let return_ty = self.normalize_projection_ty(projection); - Some((arg_tys, return_ty)) - } else { - None - } - } -} - -impl<'a> fmt::Debug for InferenceTable<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("InferenceTable").field("num_vars", &self.type_variable_table.len()).finish() - } -} - -mod resolve { - use super::InferenceTable; - use crate::{ - ConcreteConst, Const, ConstData, ConstValue, DebruijnIndex, GenericArg, InferenceVar, - Interner, Lifetime, Ty, TyVariableKind, VariableKind, - }; - use chalk_ir::{ - cast::Cast, - fold::{TypeFoldable, TypeFolder}, - Fallible, NoSolution, - }; - use hir_def::type_ref::ConstScalar; - - pub(super) struct Resolver<'a, 'b, F> { - pub(super) table: &'a mut InferenceTable<'b>, - pub(super) var_stack: &'a mut Vec, - pub(super) fallback: F, - } - impl<'a, 'b, 'i, F> TypeFolder for Resolver<'a, 'b, F> - where - F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg + 'i, - { - type Error = NoSolution; - - fn as_dyn(&mut self) -> &mut dyn TypeFolder { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn fold_inference_ty( - &mut self, - var: InferenceVar, - kind: TyVariableKind, - outer_binder: DebruijnIndex, - ) -> Fallible { - let var = self.table.var_unification_table.inference_var_root(var); - if self.var_stack.contains(&var) { - // recursive type - let default = self.table.fallback_value(var, kind).cast(Interner); - return Ok((self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) - .assert_ty_ref(Interner) - .clone()); - } - let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) { - // known_ty may contain other variables that are known by now - self.var_stack.push(var); - let result = - known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly"); - self.var_stack.pop(); - result.assert_ty_ref(Interner).clone() - } else { - let default = self.table.fallback_value(var, kind).cast(Interner); - (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) - .assert_ty_ref(Interner) - .clone() - }; - Ok(result) - } - - fn fold_inference_const( - &mut self, - ty: Ty, - var: InferenceVar, - outer_binder: DebruijnIndex, - ) -> Fallible { - let var = self.table.var_unification_table.inference_var_root(var); - let default = ConstData { - ty: ty.clone(), - value: ConstValue::Concrete(ConcreteConst { interned: ConstScalar::Unknown }), - } - .intern(Interner) - .cast(Interner); - if self.var_stack.contains(&var) { - // recursive - return Ok((self.fallback)(var, VariableKind::Const(ty), default, outer_binder) - .assert_const_ref(Interner) - .clone()); - } - let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) { - // known_ty may contain other variables that are known by now - self.var_stack.push(var); - let result = - known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly"); - self.var_stack.pop(); - result.assert_const_ref(Interner).clone() - } else { - (self.fallback)(var, VariableKind::Const(ty), default, outer_binder) - .assert_const_ref(Interner) - .clone() - }; - Ok(result) - } - - fn fold_inference_lifetime( - &mut self, - _var: InferenceVar, - _outer_binder: DebruijnIndex, - ) -> Fallible { - // fall back all lifetimes to 'static -- currently we don't deal - // with any lifetimes, but we can sometimes get some lifetime - // variables through Chalk's unification, and this at least makes - // sure we don't leak them outside of inference - Ok(crate::static_lifetime()) - } - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs deleted file mode 100644 index ca76e08fddb91..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs +++ /dev/null @@ -1,432 +0,0 @@ -//! Implementation of the Chalk `Interner` trait, which allows customizing the -//! representation of the various objects Chalk deals with (types, goals etc.). - -use crate::{chalk_db, tls, GenericArg}; -use base_db::salsa::InternId; -use chalk_ir::{Goal, GoalData}; -use hir_def::{ - intern::{impl_internable, InternStorage, Internable, Interned}, - type_ref::ConstScalar, - TypeAliasId, -}; -use smallvec::SmallVec; -use std::{fmt, sync::Arc}; - -#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] -pub struct Interner; - -#[derive(PartialEq, Eq, Hash)] -pub struct InternedWrapper(T); - -impl fmt::Debug for InternedWrapper { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.0, f) - } -} - -impl std::ops::Deref for InternedWrapper { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl_internable!( - InternedWrapper>>, - InternedWrapper>, - InternedWrapper>, - InternedWrapper>, - InternedWrapper>, - InternedWrapper, - InternedWrapper>>, - InternedWrapper>>, - InternedWrapper>>, - InternedWrapper>, -); - -impl chalk_ir::interner::Interner for Interner { - type InternedType = Interned>>; - type InternedLifetime = Interned>>; - type InternedConst = Interned>>; - type InternedConcreteConst = ConstScalar; - type InternedGenericArg = chalk_ir::GenericArgData; - type InternedGoal = Arc>; - type InternedGoals = Vec>; - type InternedSubstitution = Interned>>; - type InternedProgramClause = chalk_ir::ProgramClauseData; - type InternedProgramClauses = Interned>>>; - type InternedQuantifiedWhereClauses = - Interned>>>; - type InternedVariableKinds = Interned>>>; - type InternedCanonicalVarKinds = - Interned>>>; - type InternedConstraints = Vec>>; - type InternedVariances = Interned>>; - type DefId = InternId; - type InternedAdtId = hir_def::AdtId; - type Identifier = TypeAliasId; - type FnAbi = (); - - fn debug_adt_id( - type_kind_id: chalk_db::AdtId, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt))) - } - - fn debug_trait_id( - type_kind_id: chalk_db::TraitId, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt))) - } - - fn debug_assoc_type_id( - id: chalk_db::AssocTypeId, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt))) - } - - fn debug_alias( - alias: &chalk_ir::AliasTy, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - use std::fmt::Debug; - match alias { - chalk_ir::AliasTy::Projection(projection_ty) => { - Interner::debug_projection_ty(projection_ty, fmt) - } - chalk_ir::AliasTy::Opaque(opaque_ty) => Some(opaque_ty.fmt(fmt)), - } - } - - fn debug_projection_ty( - proj: &chalk_ir::ProjectionTy, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_projection_ty(proj, fmt))) - } - - fn debug_opaque_ty( - opaque_ty: &chalk_ir::OpaqueTy, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", opaque_ty.opaque_ty_id)) - } - - fn debug_opaque_ty_id( - opaque_ty_id: chalk_ir::OpaqueTyId, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "OpaqueTy#{}", opaque_ty_id.0)) - } - - fn debug_ty(ty: &chalk_ir::Ty, fmt: &mut fmt::Formatter<'_>) -> Option { - Some(write!(fmt, "{:?}", ty.data(Interner))) - } - - fn debug_lifetime( - lifetime: &chalk_ir::Lifetime, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", lifetime.data(Interner))) - } - - fn debug_generic_arg( - parameter: &GenericArg, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", parameter.data(Interner).inner_debug())) - } - - fn debug_goal(goal: &Goal, fmt: &mut fmt::Formatter<'_>) -> Option { - let goal_data = goal.data(Interner); - Some(write!(fmt, "{:?}", goal_data)) - } - - fn debug_goals( - goals: &chalk_ir::Goals, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", goals.debug(Interner))) - } - - fn debug_program_clause_implication( - pci: &chalk_ir::ProgramClauseImplication, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", pci.debug(Interner))) - } - - fn debug_substitution( - substitution: &chalk_ir::Substitution, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", substitution.debug(Interner))) - } - - fn debug_separator_trait_ref( - separator_trait_ref: &chalk_ir::SeparatorTraitRef<'_, Interner>, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", separator_trait_ref.debug(Interner))) - } - - fn debug_fn_def_id( - fn_def_id: chalk_ir::FnDefId, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_fn_def_id(fn_def_id, fmt))) - } - fn debug_const( - constant: &chalk_ir::Const, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", constant.data(Interner))) - } - fn debug_variable_kinds( - variable_kinds: &chalk_ir::VariableKinds, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", variable_kinds.as_slice(Interner))) - } - fn debug_variable_kinds_with_angles( - variable_kinds: &chalk_ir::VariableKinds, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", variable_kinds.inner_debug(Interner))) - } - fn debug_canonical_var_kinds( - canonical_var_kinds: &chalk_ir::CanonicalVarKinds, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", canonical_var_kinds.as_slice(Interner))) - } - fn debug_program_clause( - clause: &chalk_ir::ProgramClause, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", clause.data(Interner))) - } - fn debug_program_clauses( - clauses: &chalk_ir::ProgramClauses, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", clauses.as_slice(Interner))) - } - fn debug_quantified_where_clauses( - clauses: &chalk_ir::QuantifiedWhereClauses, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", clauses.as_slice(Interner))) - } - - fn intern_ty(self, kind: chalk_ir::TyKind) -> Self::InternedType { - let flags = kind.compute_flags(self); - Interned::new(InternedWrapper(chalk_ir::TyData { kind, flags })) - } - - fn ty_data<'a>(self, ty: &'a Self::InternedType) -> &'a chalk_ir::TyData { - &ty.0 - } - - fn intern_lifetime(self, lifetime: chalk_ir::LifetimeData) -> Self::InternedLifetime { - Interned::new(InternedWrapper(lifetime)) - } - - fn lifetime_data<'a>( - self, - lifetime: &'a Self::InternedLifetime, - ) -> &'a chalk_ir::LifetimeData { - &lifetime.0 - } - - fn intern_const(self, constant: chalk_ir::ConstData) -> Self::InternedConst { - Interned::new(InternedWrapper(constant)) - } - - fn const_data<'a>(self, constant: &'a Self::InternedConst) -> &'a chalk_ir::ConstData { - &constant.0 - } - - fn const_eq( - self, - _ty: &Self::InternedType, - c1: &Self::InternedConcreteConst, - c2: &Self::InternedConcreteConst, - ) -> bool { - (c1 == &ConstScalar::Unknown) || (c2 == &ConstScalar::Unknown) || (c1 == c2) - } - - fn intern_generic_arg( - self, - parameter: chalk_ir::GenericArgData, - ) -> Self::InternedGenericArg { - parameter - } - - fn generic_arg_data<'a>( - self, - parameter: &'a Self::InternedGenericArg, - ) -> &'a chalk_ir::GenericArgData { - parameter - } - - fn intern_goal(self, goal: GoalData) -> Self::InternedGoal { - Arc::new(goal) - } - - fn intern_goals( - self, - data: impl IntoIterator, E>>, - ) -> Result { - data.into_iter().collect() - } - - fn goal_data<'a>(self, goal: &'a Self::InternedGoal) -> &'a GoalData { - goal - } - - fn goals_data<'a>(self, goals: &'a Self::InternedGoals) -> &'a [Goal] { - goals - } - - fn intern_substitution( - self, - data: impl IntoIterator>, - ) -> Result { - Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) - } - - fn substitution_data<'a>( - self, - substitution: &'a Self::InternedSubstitution, - ) -> &'a [GenericArg] { - &substitution.as_ref().0 - } - - fn intern_program_clause( - self, - data: chalk_ir::ProgramClauseData, - ) -> Self::InternedProgramClause { - data - } - - fn program_clause_data<'a>( - self, - clause: &'a Self::InternedProgramClause, - ) -> &'a chalk_ir::ProgramClauseData { - clause - } - - fn intern_program_clauses( - self, - data: impl IntoIterator, E>>, - ) -> Result { - Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) - } - - fn program_clauses_data<'a>( - self, - clauses: &'a Self::InternedProgramClauses, - ) -> &'a [chalk_ir::ProgramClause] { - clauses - } - - fn intern_quantified_where_clauses( - self, - data: impl IntoIterator, E>>, - ) -> Result { - Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) - } - - fn quantified_where_clauses_data<'a>( - self, - clauses: &'a Self::InternedQuantifiedWhereClauses, - ) -> &'a [chalk_ir::QuantifiedWhereClause] { - clauses - } - - fn intern_generic_arg_kinds( - self, - data: impl IntoIterator, E>>, - ) -> Result { - Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) - } - - fn variable_kinds_data<'a>( - self, - parameter_kinds: &'a Self::InternedVariableKinds, - ) -> &'a [chalk_ir::VariableKind] { - ¶meter_kinds.as_ref().0 - } - - fn intern_canonical_var_kinds( - self, - data: impl IntoIterator, E>>, - ) -> Result { - Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) - } - - fn canonical_var_kinds_data<'a>( - self, - canonical_var_kinds: &'a Self::InternedCanonicalVarKinds, - ) -> &'a [chalk_ir::CanonicalVarKind] { - canonical_var_kinds - } - - fn intern_constraints( - self, - data: impl IntoIterator>, E>>, - ) -> Result { - data.into_iter().collect() - } - - fn constraints_data<'a>( - self, - constraints: &'a Self::InternedConstraints, - ) -> &'a [chalk_ir::InEnvironment>] { - constraints - } - fn debug_closure_id( - _fn_def_id: chalk_ir::ClosureId, - _fmt: &mut fmt::Formatter<'_>, - ) -> Option { - None - } - fn debug_constraints( - _clauses: &chalk_ir::Constraints, - _fmt: &mut fmt::Formatter<'_>, - ) -> Option { - None - } - - fn intern_variances( - self, - data: impl IntoIterator>, - ) -> Result { - Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) - } - - fn variances_data<'a>( - self, - variances: &'a Self::InternedVariances, - ) -> &'a [chalk_ir::Variance] { - variances - } -} - -impl chalk_ir::interner::HasInterner for Interner { - type Interner = Self; -} - -#[macro_export] -macro_rules! has_interner { - ($t:ty) => { - impl HasInterner for $t { - type Interner = crate::Interner; - } - }; -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs deleted file mode 100644 index 5a5d610e360ff..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ /dev/null @@ -1,525 +0,0 @@ -//! The type system. We currently use this to infer types for completion, hover -//! information and various assists. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -#[allow(unused)] -macro_rules! eprintln { - ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; -} - -mod autoderef; -mod builder; -mod chalk_db; -mod chalk_ext; -pub mod consteval; -mod infer; -mod interner; -mod lower; -mod mapping; -mod tls; -mod utils; -mod walk; -pub mod db; -pub mod diagnostics; -pub mod display; -pub mod method_resolution; -pub mod primitive; -pub mod traits; - -#[cfg(test)] -mod tests; -#[cfg(test)] -mod test_db; - -use std::sync::Arc; - -use chalk_ir::{ - fold::{Shift, TypeFoldable}, - interner::HasInterner, - NoSolution, -}; -use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId}; -use itertools::Either; -use utils::Generics; - -use crate::{consteval::unknown_const, db::HirDatabase, utils::generics}; - -pub use autoderef::autoderef; -pub use builder::{ParamKind, TyBuilder}; -pub use chalk_ext::*; -pub use infer::{ - could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic, - InferenceResult, -}; -pub use interner::Interner; -pub use lower::{ - associated_type_shorthand_candidates, CallableDefId, ImplTraitLoweringMode, TyDefId, - TyLoweringContext, ValueTyDefId, -}; -pub use mapping::{ - from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, - lt_from_placeholder_idx, to_assoc_type_id, to_chalk_trait_id, to_foreign_def_id, - to_placeholder_idx, -}; -pub use traits::TraitEnvironment; -pub use utils::{all_super_traits, is_fn_unsafe_to_call}; -pub use walk::TypeWalk; - -pub use chalk_ir::{ - cast::Cast, AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind, -}; - -pub type ForeignDefId = chalk_ir::ForeignDefId; -pub type AssocTypeId = chalk_ir::AssocTypeId; -pub type FnDefId = chalk_ir::FnDefId; -pub type ClosureId = chalk_ir::ClosureId; -pub type OpaqueTyId = chalk_ir::OpaqueTyId; -pub type PlaceholderIndex = chalk_ir::PlaceholderIndex; - -pub type VariableKind = chalk_ir::VariableKind; -pub type VariableKinds = chalk_ir::VariableKinds; -pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds; -pub type Binders = chalk_ir::Binders; -pub type Substitution = chalk_ir::Substitution; -pub type GenericArg = chalk_ir::GenericArg; -pub type GenericArgData = chalk_ir::GenericArgData; - -pub type Ty = chalk_ir::Ty; -pub type TyKind = chalk_ir::TyKind; -pub type DynTy = chalk_ir::DynTy; -pub type FnPointer = chalk_ir::FnPointer; -// pub type FnSubst = chalk_ir::FnSubst; -pub use chalk_ir::FnSubst; -pub type ProjectionTy = chalk_ir::ProjectionTy; -pub type AliasTy = chalk_ir::AliasTy; -pub type OpaqueTy = chalk_ir::OpaqueTy; -pub type InferenceVar = chalk_ir::InferenceVar; - -pub type Lifetime = chalk_ir::Lifetime; -pub type LifetimeData = chalk_ir::LifetimeData; -pub type LifetimeOutlives = chalk_ir::LifetimeOutlives; - -pub type Const = chalk_ir::Const; -pub type ConstData = chalk_ir::ConstData; -pub type ConstValue = chalk_ir::ConstValue; -pub type ConcreteConst = chalk_ir::ConcreteConst; - -pub type ChalkTraitId = chalk_ir::TraitId; -pub type TraitRef = chalk_ir::TraitRef; -pub type QuantifiedWhereClause = Binders; -pub type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses; -pub type Canonical = chalk_ir::Canonical; - -pub type FnSig = chalk_ir::FnSig; - -pub type InEnvironment = chalk_ir::InEnvironment; -pub type Environment = chalk_ir::Environment; -pub type DomainGoal = chalk_ir::DomainGoal; -pub type Goal = chalk_ir::Goal; -pub type AliasEq = chalk_ir::AliasEq; -pub type Solution = chalk_solve::Solution; -pub type ConstrainedSubst = chalk_ir::ConstrainedSubst; -pub type Guidance = chalk_solve::Guidance; -pub type WhereClause = chalk_ir::WhereClause; - -// FIXME: get rid of this -pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution { - Substitution::from_iter( - Interner, - s.as_slice(Interner)[..std::cmp::min(s.len(Interner), n)].iter().cloned(), - ) -} - -/// 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).param_idx(id) -} - -pub(crate) fn wrap_empty_binders(value: T) -> Binders -where - T: TypeFoldable + HasInterner, -{ - Binders::empty(Interner, value.shifted_in_from(Interner, DebruijnIndex::ONE)) -} - -pub(crate) fn make_type_and_const_binders>( - which_is_const: impl Iterator>, - value: T, -) -> Binders { - Binders::new( - VariableKinds::from_iter( - Interner, - which_is_const.map(|x| { - if let Some(ty) = x { - chalk_ir::VariableKind::Const(ty) - } else { - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) - } - }), - ), - value, - ) -} - -pub(crate) fn make_single_type_binders>( - value: T, -) -> Binders { - Binders::new( - VariableKinds::from_iter( - Interner, - std::iter::once(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)), - ), - value, - ) -} - -pub(crate) fn make_binders_with_count>( - db: &dyn HirDatabase, - count: usize, - generics: &Generics, - value: T, -) -> Binders { - let it = generics.iter_id().take(count).map(|id| match id { - Either::Left(_) => None, - Either::Right(id) => Some(db.const_param_ty(id)), - }); - crate::make_type_and_const_binders(it, value) -} - -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 -pub fn make_canonical>( - value: T, - kinds: impl IntoIterator, -) -> Canonical { - let kinds = kinds.into_iter().map(|tk| { - chalk_ir::CanonicalVarKind::new( - chalk_ir::VariableKind::Ty(tk), - chalk_ir::UniverseIndex::ROOT, - ) - }); - Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) } -} - -// 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. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct CallableSig { - params_and_return: Arc<[Ty]>, - is_varargs: bool, -} - -has_interner!(CallableSig); - -/// A polymorphic function signature. -pub type PolyFnSig = Binders; - -impl CallableSig { - pub fn from_params_and_return(mut params: Vec, ret: Ty, is_varargs: bool) -> CallableSig { - params.push(ret); - CallableSig { params_and_return: params.into(), is_varargs } - } - - pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig { - CallableSig { - // FIXME: what to do about lifetime params? -> return PolyFnSig - params_and_return: fn_ptr - .substitution - .clone() - .shifted_out_to(Interner, DebruijnIndex::ONE) - .expect("unexpected lifetime vars in fn ptr") - .0 - .as_slice(Interner) - .iter() - .map(|arg| arg.assert_ty_ref(Interner).clone()) - .collect(), - is_varargs: fn_ptr.sig.variadic, - } - } - - pub fn to_fn_ptr(&self) -> FnPointer { - FnPointer { - num_binders: 0, - sig: FnSig { abi: (), safety: Safety::Safe, variadic: self.is_varargs }, - substitution: FnSubst(Substitution::from_iter( - Interner, - self.params_and_return.iter().cloned(), - )), - } - } - - pub fn params(&self) -> &[Ty] { - &self.params_and_return[0..self.params_and_return.len() - 1] - } - - pub fn ret(&self) -> &Ty { - &self.params_and_return[self.params_and_return.len() - 1] - } -} - -impl TypeFoldable for CallableSig { - fn fold_with( - self, - folder: &mut dyn chalk_ir::fold::TypeFolder, - outer_binder: DebruijnIndex, - ) -> Result { - let vec = self.params_and_return.to_vec(); - let folded = vec.fold_with(folder, outer_binder)?; - Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs }) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] -pub enum ImplTraitId { - ReturnTypeImplTrait(hir_def::FunctionId, u16), - AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId), -} - -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct ReturnTypeImplTraits { - pub(crate) impl_traits: Vec, -} - -has_interner!(ReturnTypeImplTraits); - -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub(crate) struct ReturnTypeImplTrait { - pub(crate) bounds: Binders>, -} - -pub fn static_lifetime() -> Lifetime { - LifetimeData::Static.intern(Interner) -} - -pub(crate) fn fold_free_vars + TypeFoldable>( - t: T, - for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty, - for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const, -) -> T { - use chalk_ir::{fold::TypeFolder, Fallible}; - struct FreeVarFolder(F1, F2); - impl< - 'i, - F1: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i, - F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const + 'i, - > TypeFolder for FreeVarFolder - { - type Error = NoSolution; - - fn as_dyn(&mut self) -> &mut dyn TypeFolder { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn fold_free_var_ty( - &mut self, - bound_var: BoundVar, - outer_binder: DebruijnIndex, - ) -> Fallible { - Ok(self.0(bound_var, outer_binder)) - } - - fn fold_free_var_const( - &mut self, - ty: Ty, - bound_var: BoundVar, - outer_binder: DebruijnIndex, - ) -> Fallible { - Ok(self.1(ty, bound_var, outer_binder)) - } - } - t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST) - .expect("fold failed unexpectedly") -} - -pub(crate) fn fold_tys + TypeFoldable>( - t: T, - mut for_ty: impl FnMut(Ty, DebruijnIndex) -> Ty, - binders: DebruijnIndex, -) -> T { - fold_tys_and_consts( - t, - |x, d| match x { - Either::Left(x) => Either::Left(for_ty(x, d)), - Either::Right(x) => Either::Right(x), - }, - binders, - ) -} - -pub(crate) fn fold_tys_and_consts + TypeFoldable>( - t: T, - f: impl FnMut(Either, DebruijnIndex) -> Either, - binders: DebruijnIndex, -) -> T { - use chalk_ir::{ - fold::{TypeFolder, TypeSuperFoldable}, - Fallible, - }; - struct TyFolder(F); - impl<'i, F: FnMut(Either, DebruijnIndex) -> Either + 'i> - TypeFolder for TyFolder - { - type Error = NoSolution; - - fn as_dyn(&mut self) -> &mut dyn TypeFolder { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible { - let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?; - Ok(self.0(Either::Left(ty), outer_binder).left().unwrap()) - } - - fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Fallible { - Ok(self.0(Either::Right(c), outer_binder).right().unwrap()) - } - } - t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly") -} - -/// 'Canonicalizes' the `t` by replacing any errors with new variables. Also -/// ensures there are no unbound variables or inference variables anywhere in -/// the `t`. -pub fn replace_errors_with_variables(t: &T) -> Canonical -where - T: HasInterner + TypeFoldable + Clone, - T: HasInterner, -{ - use chalk_ir::{ - fold::{TypeFolder, TypeSuperFoldable}, - Fallible, - }; - struct ErrorReplacer { - vars: usize, - } - impl TypeFolder for ErrorReplacer { - type Error = NoSolution; - - fn as_dyn(&mut self) -> &mut dyn TypeFolder { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible { - if let TyKind::Error = ty.kind(Interner) { - let index = self.vars; - self.vars += 1; - Ok(TyKind::BoundVar(BoundVar::new(outer_binder, index)).intern(Interner)) - } else { - let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?; - Ok(ty) - } - } - - fn fold_inference_ty( - &mut self, - _var: InferenceVar, - _kind: TyVariableKind, - _outer_binder: DebruijnIndex, - ) -> Fallible { - if cfg!(debug_assertions) { - // we don't want to just panic here, because then the error message - // won't contain the whole thing, which would not be very helpful - Err(NoSolution) - } else { - Ok(TyKind::Error.intern(Interner)) - } - } - - fn fold_free_var_ty( - &mut self, - _bound_var: BoundVar, - _outer_binder: DebruijnIndex, - ) -> Fallible { - if cfg!(debug_assertions) { - // we don't want to just panic here, because then the error message - // won't contain the whole thing, which would not be very helpful - Err(NoSolution) - } else { - Ok(TyKind::Error.intern(Interner)) - } - } - - fn fold_inference_const( - &mut self, - ty: Ty, - _var: InferenceVar, - _outer_binder: DebruijnIndex, - ) -> Fallible { - if cfg!(debug_assertions) { - Err(NoSolution) - } else { - Ok(unknown_const(ty)) - } - } - - fn fold_free_var_const( - &mut self, - ty: Ty, - _bound_var: BoundVar, - _outer_binder: DebruijnIndex, - ) -> Fallible { - if cfg!(debug_assertions) { - Err(NoSolution) - } else { - Ok(unknown_const(ty)) - } - } - - fn fold_inference_lifetime( - &mut self, - _var: InferenceVar, - _outer_binder: DebruijnIndex, - ) -> Fallible { - if cfg!(debug_assertions) { - Err(NoSolution) - } else { - Ok(static_lifetime()) - } - } - - fn fold_free_var_lifetime( - &mut self, - _bound_var: BoundVar, - _outer_binder: DebruijnIndex, - ) -> Fallible { - if cfg!(debug_assertions) { - Err(NoSolution) - } else { - Ok(static_lifetime()) - } - } - } - let mut error_replacer = ErrorReplacer { vars: 0 }; - let value = match t.clone().fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) { - Ok(t) => t, - Err(_) => panic!("Encountered unbound or inference vars in {:?}", t), - }; - let kinds = (0..error_replacer.vars).map(|_| { - chalk_ir::CanonicalVarKind::new( - chalk_ir::VariableKind::Ty(TyVariableKind::General), - chalk_ir::UniverseIndex::ROOT, - ) - }); - Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs deleted file mode 100644 index 3ed9c941f4790..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ /dev/null @@ -1,1778 +0,0 @@ -//! Methods for lowering the HIR to types. There are two main cases here: -//! -//! - Lowering a type reference like `&usize` or `Option` to a -//! type: The entry point for this is `Ty::from_hir`. -//! - Building the type for an item: This happens through the `type_for_def` query. -//! -//! This usually involves resolving names, collecting generic arguments etc. -use std::{ - cell::{Cell, RefCell}, - iter, - sync::Arc, -}; - -use base_db::CrateId; -use chalk_ir::{ - cast::Cast, fold::Shift, fold::TypeFoldable, interner::HasInterner, Mutability, Safety, -}; - -use hir_def::{ - adt::StructKind, - body::{Expander, LowerCtx}, - builtin_type::BuiltinType, - generics::{ - TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, - }, - intern::Interned, - lang_item::lang_attr, - path::{GenericArg, ModPath, Path, PathKind, PathSegment, PathSegments}, - resolver::{HasResolver, Resolver, TypeNs}, - type_ref::{ - ConstScalarOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef, - }, - AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, - HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId, - TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId, -}; -use hir_expand::{name::Name, ExpandResult}; -use itertools::Either; -use la_arena::ArenaMap; -use rustc_hash::FxHashSet; -use smallvec::SmallVec; -use stdx::{impl_from, never}; -use syntax::{ast, SmolStr}; - -use crate::{ - all_super_traits, - consteval::{intern_const_scalar, path_to_const, unknown_const, unknown_const_as_generic}, - db::HirDatabase, - make_binders, - mapping::ToChalk, - static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, - utils::Generics, - utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics}, - AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DynTy, FnPointer, - FnSig, FnSubst, GenericArgData, ImplTraitId, Interner, ParamKind, PolyFnSig, ProjectionTy, - QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, - Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause, -}; - -#[derive(Debug)] -pub struct TyLoweringContext<'a> { - pub db: &'a dyn HirDatabase, - pub resolver: &'a Resolver, - in_binders: DebruijnIndex, - /// Note: Conceptually, it's thinkable that we could be in a location where - /// some type params should be represented as placeholders, and others - /// should be converted to variables. I think in practice, this isn't - /// possible currently, so this should be fine for now. - pub type_param_mode: ParamLoweringMode, - pub impl_trait_mode: ImplTraitLoweringMode, - impl_trait_counter: Cell, - /// When turning `impl Trait` into opaque types, we have to collect the - /// bounds at the same time to get the IDs correct (without becoming too - /// complicated). I don't like using interior mutability (as for the - /// counter), but I've tried and failed to make the lifetimes work for - /// passing around a `&mut TyLoweringContext`. The core problem is that - /// we're grouping the mutable data (the counter and this field) together - /// with the immutable context (the references to the DB and resolver). - /// Splitting this up would be a possible fix. - opaque_type_data: RefCell>, - expander: RefCell>, - /// Tracks types with explicit `?Sized` bounds. - pub(crate) unsized_types: RefCell>, -} - -impl<'a> TyLoweringContext<'a> { - pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self { - let impl_trait_counter = Cell::new(0); - let impl_trait_mode = ImplTraitLoweringMode::Disallowed; - let type_param_mode = ParamLoweringMode::Placeholder; - let in_binders = DebruijnIndex::INNERMOST; - let opaque_type_data = RefCell::new(Vec::new()); - Self { - db, - resolver, - in_binders, - impl_trait_mode, - impl_trait_counter, - type_param_mode, - opaque_type_data, - expander: RefCell::new(None), - unsized_types: RefCell::default(), - } - } - - pub fn with_debruijn( - &self, - debruijn: DebruijnIndex, - f: impl FnOnce(&TyLoweringContext<'_>) -> T, - ) -> T { - let opaque_ty_data_vec = self.opaque_type_data.take(); - let expander = self.expander.take(); - let unsized_types = self.unsized_types.take(); - let new_ctx = Self { - in_binders: debruijn, - impl_trait_counter: Cell::new(self.impl_trait_counter.get()), - opaque_type_data: RefCell::new(opaque_ty_data_vec), - expander: RefCell::new(expander), - unsized_types: RefCell::new(unsized_types), - ..*self - }; - let result = f(&new_ctx); - self.impl_trait_counter.set(new_ctx.impl_trait_counter.get()); - self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner()); - self.expander.replace(new_ctx.expander.into_inner()); - self.unsized_types.replace(new_ctx.unsized_types.into_inner()); - result - } - - pub fn with_shifted_in( - &self, - debruijn: DebruijnIndex, - f: impl FnOnce(&TyLoweringContext<'_>) -> T, - ) -> T { - self.with_debruijn(self.in_binders.shifted_in_from(debruijn), f) - } - - pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { - Self { impl_trait_mode, ..self } - } - - pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self { - Self { type_param_mode, ..self } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum ImplTraitLoweringMode { - /// `impl Trait` gets lowered into an opaque type that doesn't unify with - /// anything except itself. This is used in places where values flow 'out', - /// i.e. for arguments of the function we're currently checking, and return - /// types of functions we're calling. - Opaque, - /// `impl Trait` gets lowered into a type variable. Used for argument - /// position impl Trait when inside the respective function, since it allows - /// us to support that without Chalk. - Param, - /// `impl Trait` gets lowered into a variable that can unify with some - /// type. This is used in places where values flow 'in', i.e. for arguments - /// of functions we're calling, and the return type of the function we're - /// currently checking. - Variable, - /// `impl Trait` is disallowed and will be an error. - Disallowed, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum ParamLoweringMode { - Placeholder, - Variable, -} - -impl<'a> TyLoweringContext<'a> { - pub fn lower_ty(&self, type_ref: &TypeRef) -> Ty { - self.lower_ty_ext(type_ref).0 - } - - fn generics(&self) -> Generics { - generics( - self.db.upcast(), - self.resolver - .generic_def() - .expect("there should be generics if there's a generic param"), - ) - } - - pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option) { - let mut res = None; - let ty = match type_ref { - TypeRef::Never => TyKind::Never.intern(Interner), - TypeRef::Tuple(inner) => { - let inner_tys = inner.iter().map(|tr| self.lower_ty(tr)); - TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys)) - .intern(Interner) - } - TypeRef::Path(path) => { - let (ty, res_) = self.lower_path(path); - res = res_; - ty - } - TypeRef::RawPtr(inner, mutability) => { - let inner_ty = self.lower_ty(inner); - TyKind::Raw(lower_to_chalk_mutability(*mutability), inner_ty).intern(Interner) - } - TypeRef::Array(inner, len) => { - let inner_ty = self.lower_ty(inner); - let const_len = const_or_path_to_chalk( - self.db, - self.resolver, - TyBuilder::usize(), - len, - self.type_param_mode, - || self.generics(), - self.in_binders, - ); - - TyKind::Array(inner_ty, const_len).intern(Interner) - } - TypeRef::Slice(inner) => { - let inner_ty = self.lower_ty(inner); - TyKind::Slice(inner_ty).intern(Interner) - } - TypeRef::Reference(inner, _, mutability) => { - let inner_ty = self.lower_ty(inner); - let lifetime = static_lifetime(); - TyKind::Ref(lower_to_chalk_mutability(*mutability), lifetime, inner_ty) - .intern(Interner) - } - TypeRef::Placeholder => TyKind::Error.intern(Interner), - TypeRef::Fn(params, is_varargs) => { - let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { - Substitution::from_iter(Interner, params.iter().map(|(_, tr)| ctx.lower_ty(tr))) - }); - TyKind::Function(FnPointer { - num_binders: 0, // FIXME lower `for<'a> fn()` correctly - sig: FnSig { abi: (), safety: Safety::Safe, variadic: *is_varargs }, - substitution: FnSubst(substs), - }) - .intern(Interner) - } - TypeRef::DynTrait(bounds) => { - let self_ty = - TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner); - let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { - QuantifiedWhereClauses::from_iter( - Interner, - bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)), - ) - }); - let bounds = crate::make_single_type_binders(bounds); - TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner) - } - TypeRef::ImplTrait(bounds) => { - match self.impl_trait_mode { - ImplTraitLoweringMode::Opaque => { - let idx = self.impl_trait_counter.get(); - self.impl_trait_counter.set(idx + 1); - let func = match self.resolver.generic_def() { - Some(GenericDefId::FunctionId(f)) => f, - _ => panic!("opaque impl trait lowering in non-function"), - }; - - assert!(idx as usize == self.opaque_type_data.borrow().len()); - // this dance is to make sure the data is in the right - // place even if we encounter more opaque types while - // lowering the bounds - self.opaque_type_data.borrow_mut().push(ReturnTypeImplTrait { - bounds: crate::make_single_type_binders(Vec::new()), - }); - // We don't want to lower the bounds inside the binders - // we're currently in, because they don't end up inside - // those binders. E.g. when we have `impl Trait>`, the `impl OtherTrait` can't refer - // to the self parameter from `impl Trait`, and the - // bounds aren't actually stored nested within each - // other, but separately. So if the `T` refers to a type - // parameter of the outer function, it's just one binder - // away instead of two. - let actual_opaque_type_data = self - .with_debruijn(DebruijnIndex::INNERMOST, |ctx| { - ctx.lower_impl_trait(bounds, func) - }); - self.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data; - - let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx); - let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); - let generics = generics(self.db.upcast(), func.into()); - let parameters = generics.bound_vars_subst(self.db, self.in_binders); - TyKind::OpaqueType(opaque_ty_id, parameters).intern(Interner) - } - ImplTraitLoweringMode::Param => { - let idx = self.impl_trait_counter.get(); - // FIXME we're probably doing something wrong here - self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16); - if let Some(def) = self.resolver.generic_def() { - let generics = generics(self.db.upcast(), def); - let param = generics - .iter() - .filter(|(_, data)| { - matches!( - data, - TypeOrConstParamData::TypeParamData(data) - if data.provenance == TypeParamProvenance::ArgumentImplTrait - ) - }) - .nth(idx as usize) - .map_or(TyKind::Error, |(id, _)| { - TyKind::Placeholder(to_placeholder_idx(self.db, id)) - }); - param.intern(Interner) - } else { - TyKind::Error.intern(Interner) - } - } - ImplTraitLoweringMode::Variable => { - let idx = self.impl_trait_counter.get(); - // FIXME we're probably doing something wrong here - self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16); - let ( - parent_params, - self_params, - list_params, - const_params, - _impl_trait_params, - ) = if let Some(def) = self.resolver.generic_def() { - let generics = generics(self.db.upcast(), def); - generics.provenance_split() - } else { - (0, 0, 0, 0, 0) - }; - TyKind::BoundVar(BoundVar::new( - self.in_binders, - idx as usize + parent_params + self_params + list_params + const_params, - )) - .intern(Interner) - } - ImplTraitLoweringMode::Disallowed => { - // FIXME: report error - TyKind::Error.intern(Interner) - } - } - } - TypeRef::Macro(macro_call) => { - let (expander, recursion_start) = { - let mut expander = self.expander.borrow_mut(); - if expander.is_some() { - (Some(expander), false) - } else { - *expander = Some(Expander::new( - self.db.upcast(), - macro_call.file_id, - self.resolver.module(), - )); - (Some(expander), true) - } - }; - let ty = if let Some(mut expander) = expander { - let expander_mut = expander.as_mut().unwrap(); - let macro_call = macro_call.to_node(self.db.upcast()); - match expander_mut.enter_expand::(self.db.upcast(), macro_call) { - Ok(ExpandResult { value: Some((mark, expanded)), .. }) => { - let ctx = - LowerCtx::new(self.db.upcast(), expander_mut.current_file_id()); - let type_ref = TypeRef::from_ast(&ctx, expanded); - - drop(expander); - let ty = self.lower_ty(&type_ref); - - self.expander - .borrow_mut() - .as_mut() - .unwrap() - .exit(self.db.upcast(), mark); - Some(ty) - } - _ => None, - } - } else { - None - }; - if recursion_start { - *self.expander.borrow_mut() = None; - } - ty.unwrap_or_else(|| TyKind::Error.intern(Interner)) - } - TypeRef::Error => TyKind::Error.intern(Interner), - }; - (ty, res) - } - - /// This is only for `generic_predicates_for_param`, where we can't just - /// lower the self types of the predicates since that could lead to cycles. - /// So we just check here if the `type_ref` resolves to a generic param, and which. - fn lower_ty_only_param(&self, type_ref: &TypeRef) -> Option { - let path = match type_ref { - TypeRef::Path(path) => path, - _ => return None, - }; - if path.type_anchor().is_some() { - return None; - } - if path.segments().len() > 1 { - return None; - } - let resolution = - match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) { - Some((it, None)) => it, - _ => return None, - }; - match resolution { - TypeNs::GenericParam(param_id) => Some(param_id.into()), - _ => None, - } - } - - pub(crate) fn lower_ty_relative_path( - &self, - ty: Ty, - // We need the original resolution to lower `Self::AssocTy` correctly - res: Option, - remaining_segments: PathSegments<'_>, - ) -> (Ty, Option) { - match remaining_segments.len() { - 0 => (ty, res), - 1 => { - // resolve unselected assoc types - let segment = remaining_segments.first().unwrap(); - (self.select_associated_type(res, segment), None) - } - _ => { - // FIXME report error (ambiguous associated type) - (TyKind::Error.intern(Interner), None) - } - } - } - - pub(crate) fn lower_partly_resolved_path( - &self, - resolution: TypeNs, - resolved_segment: PathSegment<'_>, - remaining_segments: PathSegments<'_>, - infer_args: bool, - ) -> (Ty, Option) { - let ty = match resolution { - TypeNs::TraitId(trait_) => { - let ty = match remaining_segments.len() { - 1 => { - let trait_ref = - self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None); - let segment = remaining_segments.first().unwrap(); - let found = self - .db - .trait_data(trait_ref.hir_trait_id()) - .associated_type_by_name(segment.name); - match found { - Some(associated_ty) => { - // FIXME handle type parameters on the segment - TyKind::Alias(AliasTy::Projection(ProjectionTy { - associated_ty_id: to_assoc_type_id(associated_ty), - substitution: trait_ref.substitution, - })) - .intern(Interner) - } - None => { - // FIXME: report error (associated type not found) - TyKind::Error.intern(Interner) - } - } - } - 0 => { - let self_ty = Some( - TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)) - .intern(Interner), - ); - let trait_ref = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { - ctx.lower_trait_ref_from_resolved_path( - trait_, - resolved_segment, - self_ty, - ) - }); - let dyn_ty = DynTy { - bounds: crate::make_single_type_binders( - QuantifiedWhereClauses::from_iter( - Interner, - Some(crate::wrap_empty_binders(WhereClause::Implemented( - trait_ref, - ))), - ), - ), - lifetime: static_lifetime(), - }; - TyKind::Dyn(dyn_ty).intern(Interner) - } - _ => { - // FIXME report error (ambiguous associated type) - TyKind::Error.intern(Interner) - } - }; - return (ty, None); - } - TypeNs::GenericParam(param_id) => { - let generics = generics( - self.db.upcast(), - self.resolver.generic_def().expect("generics in scope"), - ); - match self.type_param_mode { - ParamLoweringMode::Placeholder => { - TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into())) - } - ParamLoweringMode::Variable => { - let idx = generics.param_idx(param_id.into()).expect("matching generics"); - TyKind::BoundVar(BoundVar::new(self.in_binders, idx)) - } - } - .intern(Interner) - } - TypeNs::SelfType(impl_id) => { - let generics = generics(self.db.upcast(), impl_id.into()); - let substs = match self.type_param_mode { - ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db), - ParamLoweringMode::Variable => { - generics.bound_vars_subst(self.db, self.in_binders) - } - }; - self.db.impl_self_ty(impl_id).substitute(Interner, &substs) - } - TypeNs::AdtSelfType(adt) => { - let generics = generics(self.db.upcast(), adt.into()); - let substs = match self.type_param_mode { - ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db), - ParamLoweringMode::Variable => { - generics.bound_vars_subst(self.db, self.in_binders) - } - }; - self.db.ty(adt.into()).substitute(Interner, &substs) - } - - TypeNs::AdtId(it) => self.lower_path_inner(resolved_segment, it.into(), infer_args), - TypeNs::BuiltinType(it) => { - self.lower_path_inner(resolved_segment, it.into(), infer_args) - } - TypeNs::TypeAliasId(it) => { - self.lower_path_inner(resolved_segment, it.into(), infer_args) - } - // FIXME: report error - TypeNs::EnumVariantId(_) => return (TyKind::Error.intern(Interner), None), - }; - self.lower_ty_relative_path(ty, Some(resolution), remaining_segments) - } - - pub(crate) fn lower_path(&self, path: &Path) -> (Ty, Option) { - // Resolve the path (in type namespace) - if let Some(type_ref) = path.type_anchor() { - let (ty, res) = self.lower_ty_ext(type_ref); - return self.lower_ty_relative_path(ty, res, path.segments()); - } - let (resolution, remaining_index) = - match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) { - Some(it) => it, - None => return (TyKind::Error.intern(Interner), None), - }; - let (resolved_segment, remaining_segments) = match remaining_index { - None => ( - path.segments().last().expect("resolved path has at least one element"), - PathSegments::EMPTY, - ), - Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)), - }; - self.lower_partly_resolved_path(resolution, resolved_segment, remaining_segments, false) - } - - fn select_associated_type(&self, res: Option, segment: PathSegment<'_>) -> Ty { - let (def, res) = match (self.resolver.generic_def(), res) { - (Some(def), Some(res)) => (def, res), - _ => return TyKind::Error.intern(Interner), - }; - let ty = named_associated_type_shorthand_candidates( - self.db, - def, - res, - Some(segment.name.clone()), - move |name, t, associated_ty| { - if name == segment.name { - let substs = match self.type_param_mode { - ParamLoweringMode::Placeholder => { - // if we're lowering to placeholders, we have to put - // them in now - let generics = generics( - self.db.upcast(), - self.resolver - .generic_def() - .expect("there should be generics if there's a generic param"), - ); - let s = generics.placeholder_subst(self.db); - s.apply(t.substitution.clone(), Interner) - } - ParamLoweringMode::Variable => t.substitution.clone(), - }; - // We need to shift in the bound vars, since - // associated_type_shorthand_candidates does not do that - let substs = substs.shifted_in_from(Interner, self.in_binders); - // FIXME handle type parameters on the segment - Some( - TyKind::Alias(AliasTy::Projection(ProjectionTy { - associated_ty_id: to_assoc_type_id(associated_ty), - substitution: substs, - })) - .intern(Interner), - ) - } else { - None - } - }, - ); - - ty.unwrap_or_else(|| TyKind::Error.intern(Interner)) - } - - fn lower_path_inner( - &self, - segment: PathSegment<'_>, - typeable: TyDefId, - infer_args: bool, - ) -> Ty { - let generic_def = match typeable { - TyDefId::BuiltinType(_) => None, - TyDefId::AdtId(it) => Some(it.into()), - TyDefId::TypeAliasId(it) => Some(it.into()), - }; - let substs = self.substs_from_path_segment(segment, generic_def, infer_args, None); - self.db.ty(typeable).substitute(Interner, &substs) - } - - /// Collect generic arguments from a path into a `Substs`. See also - /// `create_substs_for_ast_path` and `def_to_ty` in rustc. - pub(super) fn substs_from_path( - &self, - path: &Path, - // Note that we don't call `db.value_type(resolved)` here, - // `ValueTyDefId` is just a convenient way to pass generics and - // special-case enum variants - resolved: ValueTyDefId, - infer_args: bool, - ) -> Substitution { - let last = path.segments().last().expect("path should have at least one segment"); - let (segment, generic_def) = match resolved { - ValueTyDefId::FunctionId(it) => (last, Some(it.into())), - ValueTyDefId::StructId(it) => (last, Some(it.into())), - ValueTyDefId::UnionId(it) => (last, Some(it.into())), - ValueTyDefId::ConstId(it) => (last, Some(it.into())), - ValueTyDefId::StaticId(_) => (last, None), - ValueTyDefId::EnumVariantId(var) => { - // the generic args for an enum variant may be either specified - // on the segment referring to the enum, or on the segment - // referring to the variant. So `Option::::None` and - // `Option::None::` are both allowed (though the former is - // preferred). See also `def_ids_for_path_segments` in rustc. - let len = path.segments().len(); - let penultimate = len.checked_sub(2).and_then(|idx| path.segments().get(idx)); - let segment = match penultimate { - Some(segment) if segment.args_and_bindings.is_some() => segment, - _ => last, - }; - (segment, Some(var.parent.into())) - } - }; - self.substs_from_path_segment(segment, generic_def, infer_args, None) - } - - fn substs_from_path_segment( - &self, - segment: PathSegment<'_>, - def_generic: Option, - infer_args: bool, - explicit_self_ty: Option, - ) -> Substitution { - let mut substs = Vec::new(); - let def_generics = if let Some(def) = def_generic { - generics(self.db.upcast(), def) - } else { - return Substitution::empty(Interner); - }; - let (parent_params, self_params, type_params, const_params, impl_trait_params) = - def_generics.provenance_split(); - let total_len = - parent_params + self_params + type_params + const_params + impl_trait_params; - - let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner); - - let mut def_generic_iter = def_generics.iter_id(); - - for _ in 0..parent_params { - if let Some(eid) = def_generic_iter.next() { - match eid { - Either::Left(_) => substs.push(ty_error.clone()), - Either::Right(x) => { - substs.push(unknown_const_as_generic(self.db.const_param_ty(x))) - } - } - } - } - - let fill_self_params = || { - for x in explicit_self_ty - .into_iter() - .map(|x| GenericArgData::Ty(x).intern(Interner)) - .chain(iter::repeat(ty_error.clone())) - .take(self_params) - { - if let Some(id) = def_generic_iter.next() { - assert!(id.is_left()); - substs.push(x); - } - } - }; - let mut had_explicit_args = false; - - if let Some(generic_args) = &segment.args_and_bindings { - if !generic_args.has_self_type { - fill_self_params(); - } - let expected_num = if generic_args.has_self_type { - self_params + type_params + const_params - } else { - type_params + const_params - }; - let skip = if generic_args.has_self_type && self_params == 0 { 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 - .iter() - .filter(|arg| !matches!(arg, GenericArg::Lifetime(_))) - .skip(skip) - .take(expected_num) - { - if let Some(id) = def_generic_iter.next() { - if let Some(x) = generic_arg_to_chalk( - self.db, - id, - arg, - &mut (), - |_, type_ref| self.lower_ty(type_ref), - |_, c, ty| { - const_or_path_to_chalk( - self.db, - &self.resolver, - ty, - c, - self.type_param_mode, - || self.generics(), - self.in_binders, - ) - }, - ) { - had_explicit_args = true; - substs.push(x); - } else { - // we just filtered them out - never!("Unexpected lifetime argument"); - } - } - } - } else { - fill_self_params(); - } - - // handle defaults. In expression or pattern path segments without - // explicitly specified type arguments, missing type arguments are inferred - // (i.e. defaults aren't used). - if !infer_args || had_explicit_args { - if let Some(def_generic) = def_generic { - let defaults = self.db.generic_defaults(def_generic); - assert_eq!(total_len, defaults.len()); - - for default_ty in defaults.iter().skip(substs.len()) { - // each default can depend on the previous parameters - let substs_so_far = Substitution::from_iter(Interner, substs.clone()); - if let Some(_id) = def_generic_iter.next() { - substs.push(default_ty.clone().substitute(Interner, &substs_so_far)); - } - } - } - } - - // add placeholders for args that were not provided - // FIXME: emit diagnostics in contexts where this is not allowed - for eid in def_generic_iter { - match eid { - Either::Left(_) => substs.push(ty_error.clone()), - Either::Right(x) => { - substs.push(unknown_const_as_generic(self.db.const_param_ty(x))) - } - } - } - // If this assert fails, it means you pushed into subst but didn't call .next() of def_generic_iter - assert_eq!(substs.len(), total_len); - - Substitution::from_iter(Interner, substs) - } - - fn lower_trait_ref_from_path( - &self, - path: &Path, - explicit_self_ty: Option, - ) -> Option { - let resolved = - match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path.mod_path())? { - TypeNs::TraitId(tr) => tr, - _ => return None, - }; - let segment = path.segments().last().expect("path should have at least one segment"); - Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty)) - } - - pub(crate) fn lower_trait_ref_from_resolved_path( - &self, - resolved: TraitId, - segment: PathSegment<'_>, - explicit_self_ty: Option, - ) -> TraitRef { - let substs = self.trait_ref_substs_from_path(segment, resolved, explicit_self_ty); - TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs } - } - - fn lower_trait_ref( - &self, - trait_ref: &HirTraitRef, - explicit_self_ty: Option, - ) -> Option { - self.lower_trait_ref_from_path(&trait_ref.path, explicit_self_ty) - } - - fn trait_ref_substs_from_path( - &self, - segment: PathSegment<'_>, - resolved: TraitId, - explicit_self_ty: Option, - ) -> Substitution { - self.substs_from_path_segment(segment, Some(resolved.into()), false, explicit_self_ty) - } - - pub(crate) fn lower_where_predicate( - &'a self, - where_predicate: &'a WherePredicate, - ignore_bindings: bool, - ) -> impl Iterator + 'a { - match where_predicate { - WherePredicate::ForLifetime { target, bound, .. } - | WherePredicate::TypeBound { target, bound } => { - let self_ty = match target { - WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref), - WherePredicateTypeTarget::TypeOrConstParam(param_id) => { - let generic_def = self.resolver.generic_def().expect("generics in scope"); - let generics = generics(self.db.upcast(), generic_def); - let param_id = hir_def::TypeOrConstParamId { - parent: generic_def, - local_id: *param_id, - }; - let placeholder = to_placeholder_idx(self.db, param_id); - match self.type_param_mode { - ParamLoweringMode::Placeholder => TyKind::Placeholder(placeholder), - ParamLoweringMode::Variable => { - let idx = generics.param_idx(param_id).expect("matching generics"); - TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, idx)) - } - } - .intern(Interner) - } - }; - self.lower_type_bound(bound, self_ty, ignore_bindings) - .collect::>() - .into_iter() - } - WherePredicate::Lifetime { .. } => vec![].into_iter(), - } - } - - pub(crate) fn lower_type_bound( - &'a self, - bound: &'a TypeBound, - self_ty: Ty, - ignore_bindings: bool, - ) -> impl Iterator + 'a { - let mut bindings = None; - let trait_ref = match bound { - TypeBound::Path(path, TraitBoundModifier::None) => { - bindings = self.lower_trait_ref_from_path(path, Some(self_ty)); - bindings - .clone() - .filter(|tr| { - // ignore `T: Drop` or `T: Destruct` bounds. - // - `T: ~const Drop` has a special meaning in Rust 1.61 that we don't implement. - // (So ideally, we'd only ignore `~const Drop` here) - // - `Destruct` impls are built-in in 1.62 (current nightlies as of 08-04-2022), so until - // the builtin impls are supported by Chalk, we ignore them here. - if let Some(lang) = lang_attr(self.db.upcast(), tr.hir_trait_id()) { - if lang == "drop" || lang == "destruct" { - return false; - } - } - true - }) - .map(WhereClause::Implemented) - .map(crate::wrap_empty_binders) - } - TypeBound::Path(path, TraitBoundModifier::Maybe) => { - let sized_trait = self - .db - .lang_item(self.resolver.krate(), SmolStr::new_inline("sized")) - .and_then(|lang_item| lang_item.as_trait()); - // Don't lower associated type bindings as the only possible relaxed trait bound - // `?Sized` has no of them. - // If we got another trait here ignore the bound completely. - let trait_id = self - .lower_trait_ref_from_path(path, Some(self_ty.clone())) - .map(|trait_ref| trait_ref.hir_trait_id()); - if trait_id == sized_trait { - self.unsized_types.borrow_mut().insert(self_ty); - } - None - } - TypeBound::ForLifetime(_, path) => { - // FIXME Don't silently drop the hrtb lifetimes here - bindings = self.lower_trait_ref_from_path(path, Some(self_ty)); - bindings.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) - } - TypeBound::Lifetime(_) => None, - TypeBound::Error => None, - }; - trait_ref.into_iter().chain( - bindings - .into_iter() - .filter(move |_| !ignore_bindings) - .flat_map(move |tr| self.assoc_type_bindings_from_type_bound(bound, tr)), - ) - } - - fn assoc_type_bindings_from_type_bound( - &'a self, - bound: &'a TypeBound, - trait_ref: TraitRef, - ) -> impl Iterator + 'a { - let last_segment = match bound { - TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => { - path.segments().last() - } - TypeBound::Path(_, TraitBoundModifier::Maybe) - | TypeBound::Error - | TypeBound::Lifetime(_) => None, - }; - last_segment - .into_iter() - .filter_map(|segment| segment.args_and_bindings) - .flat_map(|args_and_bindings| &args_and_bindings.bindings) - .flat_map(move |binding| { - let found = associated_type_by_name_including_super_traits( - self.db, - trait_ref.clone(), - &binding.name, - ); - let (super_trait_ref, associated_ty) = match found { - None => return SmallVec::new(), - Some(t) => t, - }; - let projection_ty = ProjectionTy { - associated_ty_id: to_assoc_type_id(associated_ty), - substitution: super_trait_ref.substitution, - }; - let mut preds: SmallVec<[_; 1]> = SmallVec::with_capacity( - binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), - ); - if let Some(type_ref) = &binding.type_ref { - let ty = self.lower_ty(type_ref); - let alias_eq = - AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; - preds.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq))); - } - for bound in &binding.bounds { - preds.extend(self.lower_type_bound( - bound, - TyKind::Alias(AliasTy::Projection(projection_ty.clone())).intern(Interner), - false, - )); - } - preds - }) - } - - fn lower_impl_trait( - &self, - bounds: &[Interned], - func: FunctionId, - ) -> ReturnTypeImplTrait { - cov_mark::hit!(lower_rpit); - let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner); - let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { - let mut predicates: Vec<_> = bounds - .iter() - .flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)) - .collect(); - - if !ctx.unsized_types.borrow().contains(&self_ty) { - let krate = func.lookup(ctx.db.upcast()).module(ctx.db.upcast()).krate(); - let sized_trait = ctx - .db - .lang_item(krate, SmolStr::new_inline("sized")) - .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id)); - let sized_clause = sized_trait.map(|trait_id| { - let clause = WhereClause::Implemented(TraitRef { - trait_id, - substitution: Substitution::from1(Interner, self_ty.clone()), - }); - crate::wrap_empty_binders(clause) - }); - predicates.extend(sized_clause.into_iter()); - predicates.shrink_to_fit(); - } - predicates - }); - ReturnTypeImplTrait { bounds: crate::make_single_type_binders(predicates) } - } -} - -fn count_impl_traits(type_ref: &TypeRef) -> usize { - let mut count = 0; - type_ref.walk(&mut |type_ref| { - if matches!(type_ref, TypeRef::ImplTrait(_)) { - count += 1; - } - }); - count -} - -/// Build the signature of a callable item (function, struct or enum variant). -pub(crate) fn callable_item_sig(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig { - match def { - CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f), - CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s), - CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e), - } -} - -pub fn associated_type_shorthand_candidates( - db: &dyn HirDatabase, - def: GenericDefId, - res: TypeNs, - cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option, -) -> Option { - named_associated_type_shorthand_candidates(db, def, res, None, cb) -} - -fn named_associated_type_shorthand_candidates( - db: &dyn HirDatabase, - // If the type parameter is defined in an impl and we're in a method, there - // might be additional where clauses to consider - def: GenericDefId, - res: TypeNs, - assoc_name: Option, - mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option, -) -> Option { - let mut search = |t| { - for t in all_super_trait_refs(db, t) { - let data = db.trait_data(t.hir_trait_id()); - - for (name, assoc_id) in &data.items { - if let AssocItemId::TypeAliasId(alias) = assoc_id { - if let Some(result) = cb(name, &t, *alias) { - return Some(result); - } - } - } - } - None - }; - - match res { - TypeNs::SelfType(impl_id) => search( - // we're _in_ the impl -- the binders get added back later. Correct, - // but it would be nice to make this more explicit - db.impl_trait(impl_id)?.into_value_and_skipped_binders().0, - ), - TypeNs::GenericParam(param_id) => { - let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name); - let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() { - // FIXME: how to correctly handle higher-ranked bounds here? - WhereClause::Implemented(tr) => search( - tr.clone() - .shifted_out_to(Interner, DebruijnIndex::ONE) - .expect("FIXME unexpected higher-ranked trait bound"), - ), - _ => None, - }); - if let Some(_) = res { - return res; - } - // Handle `Self::Type` referring to own associated type in trait definitions - if let GenericDefId::TraitId(trait_id) = param_id.parent() { - let generics = generics(db.upcast(), trait_id.into()); - if generics.params.type_or_consts[param_id.local_id()].is_trait_self() { - let trait_ref = TyBuilder::trait_ref(db, trait_id) - .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0) - .build(); - return search(trait_ref); - } - } - None - } - _ => None, - } -} - -/// Build the type of all specific fields of a struct or enum variant. -pub(crate) fn field_types_query( - db: &dyn HirDatabase, - variant_id: VariantId, -) -> Arc>> { - let var_data = variant_id.variant_data(db.upcast()); - let (resolver, def): (_, GenericDefId) = match variant_id { - VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()), - VariantId::UnionId(it) => (it.resolver(db.upcast()), it.into()), - VariantId::EnumVariantId(it) => (it.parent.resolver(db.upcast()), it.parent.into()), - }; - let generics = generics(db.upcast(), def); - let mut res = ArenaMap::default(); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); - for (field_id, field_data) in var_data.fields().iter() { - res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref))) - } - Arc::new(res) -} - -/// This query exists only to be used when resolving short-hand associated types -/// like `T::Item`. -/// -/// See the analogous query in rustc and its comment: -/// -/// This is a query mostly to handle cycles somewhat gracefully; e.g. the -/// following bounds are disallowed: `T: Foo, U: Foo`, but -/// these are fine: `T: Foo, U: Foo<()>`. -pub(crate) fn generic_predicates_for_param_query( - db: &dyn HirDatabase, - def: GenericDefId, - param_id: TypeOrConstParamId, - assoc_name: Option, -) -> Arc<[Binders]> { - let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); - let generics = generics(db.upcast(), def); - let mut predicates: Vec<_> = resolver - .where_predicates_in_scope() - // we have to filter out all other predicates *first*, before attempting to lower them - .filter(|pred| match pred { - WherePredicate::ForLifetime { target, bound, .. } - | WherePredicate::TypeBound { target, bound, .. } => { - match target { - WherePredicateTypeTarget::TypeRef(type_ref) => { - if ctx.lower_ty_only_param(type_ref) != Some(param_id) { - return false; - } - } - &WherePredicateTypeTarget::TypeOrConstParam(local_id) => { - let target_id = TypeOrConstParamId { parent: def, local_id }; - if target_id != param_id { - return false; - } - } - }; - - match &**bound { - TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => { - // Only lower the bound if the trait could possibly define the associated - // type we're looking for. - - let assoc_name = match &assoc_name { - Some(it) => it, - None => return true, - }; - let tr = match resolver - .resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()) - { - Some(TypeNs::TraitId(tr)) => tr, - _ => return false, - }; - - all_super_traits(db.upcast(), tr).iter().any(|tr| { - db.trait_data(*tr).items.iter().any(|(name, item)| { - matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name - }) - }) - } - TypeBound::Lifetime(_) | TypeBound::Error => false, - } - } - WherePredicate::Lifetime { .. } => false, - }) - .flat_map(|pred| { - ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p)) - }) - .collect(); - - let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let explicitly_unsized_tys = ctx.unsized_types.into_inner(); - let implicitly_sized_predicates = - implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &subst, &resolver) - .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))); - predicates.extend(implicitly_sized_predicates); - predicates.into() -} - -pub(crate) fn generic_predicates_for_param_recover( - _db: &dyn HirDatabase, - _cycle: &[String], - _def: &GenericDefId, - _param_id: &TypeOrConstParamId, - _assoc_name: &Option, -) -> Arc<[Binders]> { - Arc::new([]) -} - -pub(crate) fn trait_environment_query( - db: &dyn HirDatabase, - def: GenericDefId, -) -> Arc { - let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Placeholder); - let mut traits_in_scope = Vec::new(); - let mut clauses = Vec::new(); - for pred in resolver.where_predicates_in_scope() { - for pred in ctx.lower_where_predicate(pred, false) { - if let WhereClause::Implemented(tr) = &pred.skip_binders() { - traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id())); - } - let program_clause: chalk_ir::ProgramClause = pred.cast(Interner); - clauses.push(program_clause.into_from_env_clause(Interner)); - } - } - - let container: Option = match def { - // FIXME: is there a function for this? - GenericDefId::FunctionId(f) => Some(f.lookup(db.upcast()).container), - GenericDefId::AdtId(_) => None, - GenericDefId::TraitId(_) => None, - GenericDefId::TypeAliasId(t) => Some(t.lookup(db.upcast()).container), - GenericDefId::ImplId(_) => None, - GenericDefId::EnumVariantId(_) => None, - GenericDefId::ConstId(c) => Some(c.lookup(db.upcast()).container), - }; - if let Some(ItemContainerId::TraitId(trait_id)) = container { - // add `Self: Trait` to the environment in trait - // function default implementations (and speculative code - // inside consts or type aliases) - cov_mark::hit!(trait_self_implements_self); - let substs = TyBuilder::placeholder_subst(db, trait_id); - let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs }; - let pred = WhereClause::Implemented(trait_ref); - let program_clause: chalk_ir::ProgramClause = pred.cast(Interner); - clauses.push(program_clause.into_from_env_clause(Interner)); - } - - let subst = generics(db.upcast(), def).placeholder_subst(db); - let explicitly_unsized_tys = ctx.unsized_types.into_inner(); - let implicitly_sized_clauses = - implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver).map(|pred| { - let program_clause: chalk_ir::ProgramClause = pred.cast(Interner); - program_clause.into_from_env_clause(Interner) - }); - clauses.extend(implicitly_sized_clauses); - - let krate = def.module(db.upcast()).krate(); - - let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses); - - Arc::new(TraitEnvironment { krate, traits_from_clauses: traits_in_scope, env }) -} - -/// Resolve the where clause(s) of an item with generics. -pub(crate) fn generic_predicates_query( - db: &dyn HirDatabase, - def: GenericDefId, -) -> Arc<[Binders]> { - let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); - let generics = generics(db.upcast(), def); - - let mut predicates = resolver - .where_predicates_in_scope() - .flat_map(|pred| { - ctx.lower_where_predicate(pred, false).map(|p| make_binders(db, &generics, p)) - }) - .collect::>(); - - let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let explicitly_unsized_tys = ctx.unsized_types.into_inner(); - let implicitly_sized_predicates = - implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) - .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))); - predicates.extend(implicitly_sized_predicates); - 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>( - db: &dyn HirDatabase, - def: GenericDefId, - explicitly_unsized_tys: &'a FxHashSet, - substitution: &'a Substitution, - resolver: &Resolver, -) -> impl Iterator + 'a { - let is_trait_def = matches!(def, GenericDefId::TraitId(..)); - let generic_args = &substitution.as_slice(Interner)[is_trait_def as usize..]; - let sized_trait = db - .lang_item(resolver.krate(), SmolStr::new_inline("sized")) - .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id)); - - sized_trait.into_iter().flat_map(move |sized_trait| { - let implicitly_sized_tys = generic_args - .iter() - .filter_map(|generic_arg| generic_arg.ty(Interner)) - .filter(move |&self_ty| !explicitly_unsized_tys.contains(self_ty)); - implicitly_sized_tys.map(move |self_ty| { - WhereClause::Implemented(TraitRef { - trait_id: sized_trait, - substitution: Substitution::from1(Interner, self_ty.clone()), - }) - }) - }) -} - -/// 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).with_type_param_mode(ParamLoweringMode::Variable); - let generic_params = generics(db.upcast(), def); - - let defaults = generic_params - .iter() - .enumerate() - .map(|(idx, (id, p))| { - let p = match p { - TypeOrConstParamData::TypeParamData(p) => p, - TypeOrConstParamData::ConstParamData(_) => { - // FIXME: implement const generic defaults - let val = unknown_const_as_generic( - db.const_param_ty(ConstParamId::from_unchecked(id)), - ); - return crate::make_binders_with_count(db, idx, &generic_params, val); - } - }; - 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. This is forbidden (FIXME: report - // diagnostic) - ty = fallback_bound_vars(ty, idx); - let val = GenericArgData::Ty(ty).intern(Interner); - crate::make_binders_with_count(db, idx, &generic_params, val) - }) - .collect(); - - defaults -} - -pub(crate) fn generic_defaults_recover( - db: &dyn HirDatabase, - _cycle: &[String], - def: &GenericDefId, -) -> Arc<[Binders]> { - let generic_params = generics(db.upcast(), *def); - // FIXME: this code is not covered in tests. - // we still need one default per parameter - let defaults = generic_params - .iter_id() - .enumerate() - .map(|(count, id)| { - let val = match id { - itertools::Either::Left(_) => { - GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner) - } - itertools::Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)), - }; - crate::make_binders_with_count(db, count, &generic_params, val) - }) - .collect(); - - defaults -} - -fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { - let data = db.function_data(def); - let resolver = def.resolver(db.upcast()); - let ctx_params = TyLoweringContext::new(db, &resolver) - .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 ctx_ret = TyLoweringContext::new(db, &resolver) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) - .with_type_param_mode(ParamLoweringMode::Variable); - let ret = ctx_ret.lower_ty(&data.ret_type); - let generics = generics(db.upcast(), def.into()); - let sig = CallableSig::from_params_and_return(params, ret, data.is_varargs()); - make_binders(db, &generics, sig) -} - -/// Build the declared type of a function. This should not need to look at the -/// function body. -fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders { - let generics = generics(db.upcast(), def.into()); - let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - make_binders( - db, - &generics, - TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(Interner), - ) -} - -/// Build the declared type of a const. -fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders { - let data = db.const_data(def); - let generics = generics(db.upcast(), def.into()); - let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); - - make_binders(db, &generics, ctx.lower_ty(&data.type_ref)) -} - -/// Build the declared type of a static. -fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders { - let data = db.static_data(def); - let resolver = def.resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver); - - Binders::empty(Interner, ctx.lower_ty(&data.type_ref)) -} - -fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig { - let struct_data = db.struct_data(def); - let fields = struct_data.variant_data.fields(); - let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); - let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::>(); - let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders(); - Binders::new(binders, CallableSig::from_params_and_return(params, ret, false)) -} - -/// Build the type of a tuple struct constructor. -fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders { - let struct_data = db.struct_data(def); - if let StructKind::Unit = struct_data.variant_data.kind() { - return type_for_adt(db, def.into()); - } - let generics = generics(db.upcast(), def.into()); - let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - make_binders( - db, - &generics, - TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(Interner), - ) -} - -fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> PolyFnSig { - let enum_data = db.enum_data(def.parent); - let var_data = &enum_data.variants[def.local_id]; - let fields = var_data.variant_data.fields(); - let resolver = def.parent.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); - let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::>(); - let (ret, binders) = type_for_adt(db, def.parent.into()).into_value_and_skipped_binders(); - Binders::new(binders, CallableSig::from_params_and_return(params, ret, false)) -} - -/// Build the type of a tuple enum variant constructor. -fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> Binders { - let enum_data = db.enum_data(def.parent); - let var_data = &enum_data.variants[def.local_id].variant_data; - if let StructKind::Unit = var_data.kind() { - return type_for_adt(db, def.parent.into()); - } - let generics = generics(db.upcast(), def.parent.into()); - let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - make_binders( - db, - &generics, - TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs).intern(Interner), - ) -} - -fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders { - let generics = generics(db.upcast(), adt.into()); - let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let ty = TyKind::Adt(crate::AdtId(adt), subst).intern(Interner); - make_binders(db, &generics, ty) -} - -fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders { - let generics = generics(db.upcast(), t.into()); - let resolver = t.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); - if db.type_alias_data(t).is_extern { - Binders::empty(Interner, TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner)) - } else { - let type_ref = &db.type_alias_data(t).type_ref; - let inner = ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error)); - make_binders(db, &generics, inner) - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum CallableDefId { - FunctionId(FunctionId), - StructId(StructId), - EnumVariantId(EnumVariantId), -} -impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId); - -impl CallableDefId { - pub fn krate(self, db: &dyn HirDatabase) -> CrateId { - let db = db.upcast(); - match self { - CallableDefId::FunctionId(f) => f.lookup(db).module(db), - CallableDefId::StructId(s) => s.lookup(db).container, - CallableDefId::EnumVariantId(e) => e.parent.lookup(db).container, - } - .krate() - } -} - -impl From for GenericDefId { - fn from(def: CallableDefId) -> GenericDefId { - match def { - CallableDefId::FunctionId(f) => f.into(), - CallableDefId::StructId(s) => s.into(), - CallableDefId::EnumVariantId(e) => e.into(), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum TyDefId { - BuiltinType(BuiltinType), - AdtId(AdtId), - TypeAliasId(TypeAliasId), -} -impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefId); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum ValueTyDefId { - FunctionId(FunctionId), - StructId(StructId), - UnionId(UnionId), - EnumVariantId(EnumVariantId), - ConstId(ConstId), - StaticId(StaticId), -} -impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId); - -/// Build the declared type of an item. This depends on the namespace; e.g. for -/// `struct Foo(usize)`, we have two types: The type of the struct itself, and -/// the constructor function `(usize) -> Foo` which lives in the values -/// namespace. -pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders { - match def { - TyDefId::BuiltinType(it) => Binders::empty(Interner, TyBuilder::builtin(it)), - TyDefId::AdtId(it) => type_for_adt(db, it), - TyDefId::TypeAliasId(it) => type_for_type_alias(db, it), - } -} - -pub(crate) fn ty_recover(db: &dyn HirDatabase, _cycle: &[String], def: &TyDefId) -> Binders { - let generics = match *def { - TyDefId::BuiltinType(_) => return Binders::empty(Interner, TyKind::Error.intern(Interner)), - TyDefId::AdtId(it) => generics(db.upcast(), it.into()), - TyDefId::TypeAliasId(it) => generics(db.upcast(), it.into()), - }; - make_binders(db, &generics, TyKind::Error.intern(Interner)) -} - -pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders { - match def { - ValueTyDefId::FunctionId(it) => type_for_fn(db, it), - ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), - ValueTyDefId::UnionId(it) => type_for_adt(db, it.into()), - ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), - ValueTyDefId::ConstId(it) => type_for_const(db, it), - ValueTyDefId::StaticId(it) => type_for_static(db, it), - } -} - -pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders { - let impl_loc = impl_id.lookup(db.upcast()); - let impl_data = db.impl_data(impl_id); - let resolver = impl_id.resolver(db.upcast()); - let _cx = stdx::panic_context::enter(format!( - "impl_self_ty_query({:?} -> {:?} -> {:?})", - impl_id, impl_loc, impl_data - )); - let generics = generics(db.upcast(), impl_id.into()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); - make_binders(db, &generics, ctx.lower_ty(&impl_data.self_ty)) -} - -// returns None if def is a type arg -pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { - let parent_data = db.generic_params(def.parent()); - let data = &parent_data.type_or_consts[def.local_id()]; - let resolver = def.parent().resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver); - match data { - TypeOrConstParamData::TypeParamData(_) => { - never!(); - Ty::new(Interner, TyKind::Error) - } - TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(&d.ty), - } -} - -pub(crate) fn impl_self_ty_recover( - db: &dyn HirDatabase, - _cycle: &[String], - impl_id: &ImplId, -) -> Binders { - let generics = generics(db.upcast(), (*impl_id).into()); - make_binders(db, &generics, TyKind::Error.intern(Interner)) -} - -pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option> { - let impl_loc = impl_id.lookup(db.upcast()); - let impl_data = db.impl_data(impl_id); - let resolver = impl_id.resolver(db.upcast()); - let _cx = stdx::panic_context::enter(format!( - "impl_trait_query({:?} -> {:?} -> {:?})", - impl_id, impl_loc, impl_data - )); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); - let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders(); - let target_trait = impl_data.target_trait.as_ref()?; - Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, Some(self_ty))?)) -} - -pub(crate) fn return_type_impl_traits( - db: &dyn HirDatabase, - def: hir_def::FunctionId, -) -> Option>> { - // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe - let data = db.function_data(def); - let resolver = def.resolver(db.upcast()); - let ctx_ret = TyLoweringContext::new(db, &resolver) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) - .with_type_param_mode(ParamLoweringMode::Variable); - let _ret = (&ctx_ret).lower_ty(&data.ret_type); - let generics = generics(db.upcast(), def.into()); - let return_type_impl_traits = - ReturnTypeImplTraits { impl_traits: ctx_ret.opaque_type_data.into_inner() }; - if return_type_impl_traits.impl_traits.is_empty() { - None - } else { - Some(Arc::new(make_binders(db, &generics, return_type_impl_traits))) - } -} - -pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mutability { - match m { - hir_def::type_ref::Mutability::Shared => Mutability::Not, - hir_def::type_ref::Mutability::Mut => 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: Either, - arg: &'a GenericArg, - this: &mut T, - for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a, - for_const: impl FnOnce(&mut T, &ConstScalarOrPath, Ty) -> Const + 'a, -) -> Option { - let kind = match kind_id { - Either::Left(_) => ParamKind::Type, - Either::Right(id) => { - let ty = db.const_param_ty(id); - ParamKind::Const(ty) - } - }; - Some(match (arg, kind) { - (GenericArg::Type(type_ref), ParamKind::Type) => { - let ty = for_type(this, type_ref); - GenericArgData::Ty(ty).intern(Interner) - } - (GenericArg::Const(c), ParamKind::Const(c_ty)) => { - GenericArgData::Const(for_const(this, c, c_ty)).intern(Interner) - } - (GenericArg::Const(_), ParamKind::Type) => { - GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner) - } - (GenericArg::Type(t), ParamKind::Const(c_ty)) => { - // We want to recover simple idents, which parser detects them - // 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 = ConstScalarOrPath::Path(n.clone()); - return Some( - GenericArgData::Const(for_const(this, &c, c_ty)).intern(Interner), - ); - } - } - } - unknown_const_as_generic(c_ty) - } - (GenericArg::Lifetime(_), _) => return None, - }) -} - -pub(crate) fn const_or_path_to_chalk( - db: &dyn HirDatabase, - resolver: &Resolver, - expected_ty: Ty, - value: &ConstScalarOrPath, - mode: ParamLoweringMode, - args: impl FnOnce() -> Generics, - debruijn: DebruijnIndex, -) -> Const { - match value { - ConstScalarOrPath::Scalar(s) => intern_const_scalar(s.clone(), expected_ty), - ConstScalarOrPath::Path(n) => { - let path = ModPath::from_segments(PathKind::Plain, Some(n.clone())); - path_to_const(db, resolver, &path, mode, args, debruijn) - .unwrap_or_else(|| unknown_const(expected_ty)) - } - } -} - -/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past -/// num_vars_to_keep) by `TyKind::Unknown`. -fn fallback_bound_vars + HasInterner>( - s: T, - num_vars_to_keep: usize, -) -> T { - crate::fold_free_vars( - s, - |bound, binders| { - if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST { - TyKind::Error.intern(Interner) - } else { - bound.shifted_in_from(binders).to_ty(Interner) - } - }, - |ty, bound, binders| { - if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST { - unknown_const(ty.clone()) - } else { - bound.shifted_in_from(binders).to_const(Interner, ty) - } - }, - ) -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs deleted file mode 100644 index d765fee0e1f4e..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs +++ /dev/null @@ -1,148 +0,0 @@ -//! This module contains the implementations of the `ToChalk` trait, which -//! handles conversion between our data types and their corresponding types in -//! Chalk (in both directions); plus some helper functions for more specialized -//! conversions. - -use chalk_solve::rust_ir; - -use base_db::salsa::{self, InternKey}; -use hir_def::{LifetimeParamId, TraitId, TypeAliasId, TypeOrConstParamId}; - -use crate::{ - chalk_db, db::HirDatabase, AssocTypeId, CallableDefId, ChalkTraitId, FnDefId, ForeignDefId, - Interner, OpaqueTyId, PlaceholderIndex, -}; - -pub(crate) trait ToChalk { - type Chalk; - fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk; - fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self; -} - -pub(crate) fn from_chalk(db: &dyn HirDatabase, chalk: ChalkT) -> T -where - T: ToChalk, -{ - T::from_chalk(db, chalk) -} - -impl ToChalk for hir_def::ImplId { - type Chalk = chalk_db::ImplId; - - fn to_chalk(self, _db: &dyn HirDatabase) -> chalk_db::ImplId { - chalk_ir::ImplId(self.as_intern_id()) - } - - fn from_chalk(_db: &dyn HirDatabase, impl_id: chalk_db::ImplId) -> hir_def::ImplId { - InternKey::from_intern_id(impl_id.0) - } -} - -impl ToChalk for CallableDefId { - type Chalk = FnDefId; - - fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId { - db.intern_callable_def(self).into() - } - - fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId { - db.lookup_intern_callable_def(fn_def_id.into()) - } -} - -pub(crate) struct TypeAliasAsValue(pub(crate) TypeAliasId); - -impl ToChalk for TypeAliasAsValue { - type Chalk = chalk_db::AssociatedTyValueId; - - fn to_chalk(self, _db: &dyn HirDatabase) -> chalk_db::AssociatedTyValueId { - rust_ir::AssociatedTyValueId(self.0.as_intern_id()) - } - - fn from_chalk( - _db: &dyn HirDatabase, - assoc_ty_value_id: chalk_db::AssociatedTyValueId, - ) -> TypeAliasAsValue { - TypeAliasAsValue(TypeAliasId::from_intern_id(assoc_ty_value_id.0)) - } -} - -impl From for crate::db::InternedCallableDefId { - fn from(fn_def_id: FnDefId) -> Self { - InternKey::from_intern_id(fn_def_id.0) - } -} - -impl From for FnDefId { - fn from(callable_def_id: crate::db::InternedCallableDefId) -> Self { - chalk_ir::FnDefId(callable_def_id.as_intern_id()) - } -} - -impl From for crate::db::InternedOpaqueTyId { - fn from(id: OpaqueTyId) -> Self { - InternKey::from_intern_id(id.0) - } -} - -impl From for OpaqueTyId { - fn from(id: crate::db::InternedOpaqueTyId) -> Self { - chalk_ir::OpaqueTyId(id.as_intern_id()) - } -} - -impl From> for crate::db::InternedClosureId { - fn from(id: chalk_ir::ClosureId) -> Self { - Self::from_intern_id(id.0) - } -} - -impl From for chalk_ir::ClosureId { - fn from(id: crate::db::InternedClosureId) -> Self { - chalk_ir::ClosureId(id.as_intern_id()) - } -} - -pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId { - chalk_ir::ForeignDefId(salsa::InternKey::as_intern_id(&id)) -} - -pub fn from_foreign_def_id(id: ForeignDefId) -> TypeAliasId { - salsa::InternKey::from_intern_id(id.0) -} - -pub fn to_assoc_type_id(id: TypeAliasId) -> AssocTypeId { - chalk_ir::AssocTypeId(salsa::InternKey::as_intern_id(&id)) -} - -pub fn from_assoc_type_id(id: AssocTypeId) -> TypeAliasId { - salsa::InternKey::from_intern_id(id.0) -} - -pub fn from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> TypeOrConstParamId { - assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT); - let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx)); - db.lookup_intern_type_or_const_param_id(interned_id) -} - -pub fn to_placeholder_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> PlaceholderIndex { - let interned_id = db.intern_type_or_const_param_id(id); - PlaceholderIndex { - ui: chalk_ir::UniverseIndex::ROOT, - idx: salsa::InternKey::as_intern_id(&interned_id).as_usize(), - } -} - -pub fn lt_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> LifetimeParamId { - assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT); - let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx)); - db.lookup_intern_lifetime_param_id(interned_id) -} - -pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId { - chalk_ir::TraitId(salsa::InternKey::as_intern_id(&id)) -} - -pub fn from_chalk_trait_id(id: ChalkTraitId) -> TraitId { - salsa::InternKey::from_intern_id(id.0) -} 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 deleted file mode 100644 index 15df7b3dd2b9b..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ /dev/null @@ -1,1186 +0,0 @@ -//! This module is concerned with finding methods that a given type provides. -//! For details about how this works in rustc, see the method lookup page in the -//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html) -//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs. -use std::{iter, ops::ControlFlow, sync::Arc}; - -use arrayvec::ArrayVec; -use base_db::{CrateId, Edition}; -use chalk_ir::{cast::Cast, Mutability, UniverseIndex}; -use hir_def::{ - data::ImplData, item_scope::ItemScope, nameres::DefMap, AssocItemId, BlockId, ConstId, - FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ModuleId, - TraitId, -}; -use hir_expand::name::Name; -use rustc_hash::{FxHashMap, FxHashSet}; -use stdx::never; - -use crate::{ - autoderef::{self, AutoderefKind}, - db::HirDatabase, - from_foreign_def_id, - infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast}, - primitive::{FloatTy, IntTy, UintTy}, - static_lifetime, - utils::all_super_traits, - AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner, - Scalar, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, -}; - -/// This is used as a key for indexing impls. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum TyFingerprint { - // These are lang item impls: - Str, - Slice, - Array, - Never, - RawPtr(Mutability), - Scalar(Scalar), - // These can have user-defined impls: - Adt(hir_def::AdtId), - Dyn(TraitId), - ForeignType(ForeignDefId), - // These only exist for trait impls - Unit, - Unnameable, - Function(u32), -} - -impl TyFingerprint { - /// Creates a TyFingerprint for looking up an inherent impl. Only certain - /// types can have inherent impls: if we have some `struct S`, we can have - /// an `impl S`, but not `impl &S`. Hence, this will return `None` for - /// reference types and such. - pub fn for_inherent_impl(ty: &Ty) -> Option { - let fp = match ty.kind(Interner) { - TyKind::Str => TyFingerprint::Str, - TyKind::Never => TyFingerprint::Never, - TyKind::Slice(..) => TyFingerprint::Slice, - TyKind::Array(..) => TyFingerprint::Array, - TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar), - TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt), - TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability), - TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id), - TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?, - _ => return None, - }; - Some(fp) - } - - /// Creates a TyFingerprint for looking up a trait impl. - pub fn for_trait_impl(ty: &Ty) -> Option { - let fp = match ty.kind(Interner) { - TyKind::Str => TyFingerprint::Str, - TyKind::Never => TyFingerprint::Never, - TyKind::Slice(..) => TyFingerprint::Slice, - TyKind::Array(..) => TyFingerprint::Array, - TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar), - TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt), - TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability), - TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id), - TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?, - TyKind::Ref(_, _, ty) => return TyFingerprint::for_trait_impl(ty), - TyKind::Tuple(_, subst) => { - let first_ty = subst.interned().get(0).map(|arg| arg.assert_ty_ref(Interner)); - match first_ty { - Some(ty) => return TyFingerprint::for_trait_impl(ty), - None => TyFingerprint::Unit, - } - } - TyKind::AssociatedType(_, _) - | TyKind::OpaqueType(_, _) - | TyKind::FnDef(_, _) - | TyKind::Closure(_, _) - | TyKind::Generator(..) - | TyKind::GeneratorWitness(..) => TyFingerprint::Unnameable, - TyKind::Function(fn_ptr) => { - TyFingerprint::Function(fn_ptr.substitution.0.len(Interner) as u32) - } - TyKind::Alias(_) - | TyKind::Placeholder(_) - | TyKind::BoundVar(_) - | TyKind::InferenceVar(_, _) - | TyKind::Error => return None, - }; - Some(fp) - } -} - -pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [ - TyFingerprint::Scalar(Scalar::Int(IntTy::I8)), - TyFingerprint::Scalar(Scalar::Int(IntTy::I16)), - TyFingerprint::Scalar(Scalar::Int(IntTy::I32)), - TyFingerprint::Scalar(Scalar::Int(IntTy::I64)), - TyFingerprint::Scalar(Scalar::Int(IntTy::I128)), - TyFingerprint::Scalar(Scalar::Int(IntTy::Isize)), - TyFingerprint::Scalar(Scalar::Uint(UintTy::U8)), - TyFingerprint::Scalar(Scalar::Uint(UintTy::U16)), - TyFingerprint::Scalar(Scalar::Uint(UintTy::U32)), - TyFingerprint::Scalar(Scalar::Uint(UintTy::U64)), - TyFingerprint::Scalar(Scalar::Uint(UintTy::U128)), - TyFingerprint::Scalar(Scalar::Uint(UintTy::Usize)), -]; - -pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [ - TyFingerprint::Scalar(Scalar::Float(FloatTy::F32)), - TyFingerprint::Scalar(Scalar::Float(FloatTy::F64)), -]; - -/// Trait impls defined or available in some crate. -#[derive(Debug, Eq, PartialEq)] -pub struct TraitImpls { - // If the `Option` is `None`, the impl may apply to any self type. - map: FxHashMap, Vec>>, -} - -impl TraitImpls { - pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc { - let _p = profile::span("trait_impls_in_crate_query").detail(|| format!("{krate:?}")); - let mut impls = Self { map: FxHashMap::default() }; - - let crate_def_map = db.crate_def_map(krate); - impls.collect_def_map(db, &crate_def_map); - impls.shrink_to_fit(); - - Arc::new(impls) - } - - pub(crate) fn trait_impls_in_block_query( - db: &dyn HirDatabase, - block: BlockId, - ) -> Option> { - let _p = profile::span("trait_impls_in_block_query"); - let mut impls = Self { map: FxHashMap::default() }; - - let block_def_map = db.block_def_map(block)?; - impls.collect_def_map(db, &block_def_map); - impls.shrink_to_fit(); - - Some(Arc::new(impls)) - } - - pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc { - let _p = profile::span("trait_impls_in_deps_query").detail(|| format!("{krate:?}")); - let crate_graph = db.crate_graph(); - let mut res = Self { map: FxHashMap::default() }; - - for krate in crate_graph.transitive_deps(krate) { - res.merge(&db.trait_impls_in_crate(krate)); - } - res.shrink_to_fit(); - - Arc::new(res) - } - - fn shrink_to_fit(&mut self) { - self.map.shrink_to_fit(); - self.map.values_mut().for_each(|map| { - map.shrink_to_fit(); - map.values_mut().for_each(Vec::shrink_to_fit); - }); - } - - fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) { - for (_module_id, module_data) in def_map.modules() { - for impl_id in module_data.scope.impls() { - let target_trait = match db.impl_trait(impl_id) { - Some(tr) => tr.skip_binders().hir_trait_id(), - None => continue, - }; - let self_ty = db.impl_self_ty(impl_id); - let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders()); - self.map - .entry(target_trait) - .or_default() - .entry(self_ty_fp) - .or_default() - .push(impl_id); - } - - // To better support custom derives, collect impls in all unnamed const items. - // const _: () = { ... }; - for konst in collect_unnamed_consts(db, &module_data.scope) { - let body = db.body(konst.into()); - for (_, block_def_map) in body.blocks(db.upcast()) { - self.collect_def_map(db, &block_def_map); - } - } - } - } - - fn merge(&mut self, other: &Self) { - for (trait_, other_map) in &other.map { - let map = self.map.entry(*trait_).or_default(); - for (fp, impls) in other_map { - map.entry(*fp).or_default().extend(impls); - } - } - } - - /// Queries all trait impls for the given type. - pub fn for_self_ty_without_blanket_impls( - &self, - fp: TyFingerprint, - ) -> impl Iterator + '_ { - self.map - .values() - .flat_map(move |impls| impls.get(&Some(fp)).into_iter()) - .flat_map(|it| it.iter().copied()) - } - - /// Queries all impls of the given trait. - pub fn for_trait(&self, trait_: TraitId) -> impl Iterator + '_ { - self.map - .get(&trait_) - .into_iter() - .flat_map(|map| map.values().flat_map(|v| v.iter().copied())) - } - - /// Queries all impls of `trait_` that may apply to `self_ty`. - pub fn for_trait_and_self_ty( - &self, - trait_: TraitId, - self_ty: TyFingerprint, - ) -> impl Iterator + '_ { - self.map - .get(&trait_) - .into_iter() - .flat_map(move |map| map.get(&Some(self_ty)).into_iter().chain(map.get(&None))) - .flat_map(|v| v.iter().copied()) - } - - pub fn all_impls(&self) -> impl Iterator + '_ { - self.map.values().flat_map(|map| map.values().flat_map(|v| v.iter().copied())) - } -} - -/// Inherent impls defined in some crate. -/// -/// Inherent impls can only be defined in the crate that also defines the self type of the impl -/// (note that some primitives are considered to be defined by both libcore and liballoc). -/// -/// This makes inherent impl lookup easier than trait impl lookup since we only have to consider a -/// single crate. -#[derive(Debug, Eq, PartialEq)] -pub struct InherentImpls { - map: FxHashMap>, -} - -impl InherentImpls { - pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc { - let mut impls = Self { map: FxHashMap::default() }; - - let crate_def_map = db.crate_def_map(krate); - impls.collect_def_map(db, &crate_def_map); - impls.shrink_to_fit(); - - Arc::new(impls) - } - - pub(crate) fn inherent_impls_in_block_query( - db: &dyn HirDatabase, - block: BlockId, - ) -> Option> { - let mut impls = Self { map: FxHashMap::default() }; - if let Some(block_def_map) = db.block_def_map(block) { - impls.collect_def_map(db, &block_def_map); - impls.shrink_to_fit(); - return Some(Arc::new(impls)); - } - None - } - - fn shrink_to_fit(&mut self) { - self.map.values_mut().for_each(Vec::shrink_to_fit); - self.map.shrink_to_fit(); - } - - fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) { - for (_module_id, module_data) in def_map.modules() { - for impl_id in module_data.scope.impls() { - let data = db.impl_data(impl_id); - if data.target_trait.is_some() { - continue; - } - - let self_ty = db.impl_self_ty(impl_id); - let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders()); - if let Some(fp) = fp { - self.map.entry(fp).or_default().push(impl_id); - } - // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution) - } - - // To better support custom derives, collect impls in all unnamed const items. - // const _: () = { ... }; - for konst in collect_unnamed_consts(db, &module_data.scope) { - let body = db.body(konst.into()); - for (_, block_def_map) in body.blocks(db.upcast()) { - self.collect_def_map(db, &block_def_map); - } - } - } - } - - pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] { - match TyFingerprint::for_inherent_impl(self_ty) { - Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]), - None => &[], - } - } - - pub fn all_impls(&self) -> impl Iterator + '_ { - self.map.values().flat_map(|v| v.iter().copied()) - } -} - -pub fn inherent_impl_crates_query( - db: &dyn HirDatabase, - krate: CrateId, - fp: TyFingerprint, -) -> ArrayVec { - let _p = profile::span("inherent_impl_crates_query"); - let mut res = ArrayVec::new(); - let crate_graph = db.crate_graph(); - - for krate in crate_graph.transitive_deps(krate) { - if res.is_full() { - // we don't currently look for or store more than two crates here, - // so don't needlessly look at more crates than necessary. - break; - } - let impls = db.inherent_impls_in_crate(krate); - if impls.map.get(&fp).map_or(false, |v| !v.is_empty()) { - res.push(krate); - } - } - - res -} - -fn collect_unnamed_consts<'a>( - db: &'a dyn HirDatabase, - scope: &'a ItemScope, -) -> impl Iterator + 'a { - let unnamed_consts = scope.unnamed_consts(); - - // FIXME: Also treat consts named `_DERIVE_*` as unnamed, since synstructure generates those. - // Should be removed once synstructure stops doing that. - let synstructure_hack_consts = scope.values().filter_map(|(item, _)| match item { - ModuleDefId::ConstId(id) => { - let loc = id.lookup(db.upcast()); - let item_tree = loc.id.item_tree(db.upcast()); - if item_tree[loc.id.value] - .name - .as_ref() - .map_or(false, |n| n.to_smol_str().starts_with("_DERIVE_")) - { - Some(id) - } else { - None - } - } - _ => None, - }); - - unnamed_consts.chain(synstructure_hack_consts) -} - -pub fn def_crates( - db: &dyn HirDatabase, - ty: &Ty, - cur_crate: CrateId, -) -> Option> { - let mod_to_crate_ids = |module: ModuleId| Some(iter::once(module.krate()).collect()); - - let fp = TyFingerprint::for_inherent_impl(ty); - - match ty.kind(Interner) { - TyKind::Adt(AdtId(def_id), _) => mod_to_crate_ids(def_id.module(db.upcast())), - TyKind::Foreign(id) => { - mod_to_crate_ids(from_foreign_def_id(*id).lookup(db.upcast()).module(db.upcast())) - } - TyKind::Dyn(_) => ty - .dyn_trait() - .and_then(|trait_| mod_to_crate_ids(GenericDefId::TraitId(trait_).module(db.upcast()))), - // for primitives, there may be impls in various places (core and alloc - // mostly). We just check the whole crate graph for crates with impls - // (cached behind a query). - TyKind::Scalar(_) - | TyKind::Str - | TyKind::Slice(_) - | TyKind::Array(..) - | TyKind::Raw(..) => { - Some(db.inherent_impl_crates(cur_crate, fp.expect("fingerprint for primitive"))) - } - _ => return None, - } -} - -/// Look up the method with the given name. -pub(crate) fn lookup_method( - ty: &Canonical, - db: &dyn HirDatabase, - env: Arc, - traits_in_scope: &FxHashSet, - visible_from_module: VisibleFromModule, - name: &Name, -) -> Option<(ReceiverAdjustments, FunctionId)> { - iterate_method_candidates( - ty, - db, - env, - traits_in_scope, - visible_from_module, - Some(name), - LookupMode::MethodCall, - |adjustments, f| match f { - AssocItemId::FunctionId(f) => Some((adjustments, f)), - _ => None, - }, - ) -} - -/// Whether we're looking up a dotted method call (like `v.len()`) or a path -/// (like `Vec::new`). -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum LookupMode { - /// Looking up a method call like `v.len()`: We only consider candidates - /// that have a `self` parameter, and do autoderef. - MethodCall, - /// Looking up a path like `Vec::new` or `Vec::default`: We consider all - /// candidates including associated constants, but don't do autoderef. - Path, -} - -#[derive(Clone, Copy)] -pub enum VisibleFromModule { - /// Filter for results that are visible from the given module - Filter(ModuleId), - /// Include impls from the given block. - IncludeBlock(BlockId), - /// Do nothing special in regards visibility - None, -} - -impl From> for VisibleFromModule { - fn from(module: Option) -> Self { - match module { - Some(module) => Self::Filter(module), - None => Self::None, - } - } -} - -impl From> for VisibleFromModule { - fn from(block: Option) -> Self { - match block { - Some(block) => Self::IncludeBlock(block), - None => Self::None, - } - } -} - -#[derive(Debug, Clone, Default)] -pub struct ReceiverAdjustments { - autoref: Option, - autoderefs: usize, - unsize_array: bool, -} - -impl ReceiverAdjustments { - pub(crate) fn apply(&self, table: &mut InferenceTable<'_>, ty: Ty) -> (Ty, Vec) { - let mut ty = ty; - let mut adjust = Vec::new(); - for _ in 0..self.autoderefs { - match autoderef::autoderef_step(table, ty.clone()) { - None => { - never!("autoderef not possible for {:?}", ty); - ty = TyKind::Error.intern(Interner); - break; - } - Some((kind, new_ty)) => { - ty = new_ty.clone(); - adjust.push(Adjustment { - kind: Adjust::Deref(match kind { - // FIXME should we know the mutability here? - AutoderefKind::Overloaded => Some(OverloadedDeref(Mutability::Not)), - AutoderefKind::Builtin => None, - }), - target: new_ty, - }); - } - } - } - if self.unsize_array { - ty = match ty.kind(Interner) { - TyKind::Array(inner, _) => TyKind::Slice(inner.clone()).intern(Interner), - _ => { - never!("unsize_array with non-array {:?}", ty); - ty - } - }; - // FIXME this is kind of wrong since the unsize needs to happen to a pointer/reference - adjust.push(Adjustment { - kind: Adjust::Pointer(PointerCast::Unsize), - target: ty.clone(), - }); - } - if let Some(m) = self.autoref { - ty = TyKind::Ref(m, static_lifetime(), ty).intern(Interner); - adjust - .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(m)), target: ty.clone() }); - } - (ty, adjust) - } - - fn with_autoref(&self, m: Mutability) -> ReceiverAdjustments { - Self { autoref: Some(m), ..*self } - } -} - -// This would be nicer if it just returned an iterator, but that runs into -// lifetime problems, because we need to borrow temp `CrateImplDefs`. -// FIXME add a context type here? -pub(crate) fn iterate_method_candidates( - ty: &Canonical, - db: &dyn HirDatabase, - env: Arc, - traits_in_scope: &FxHashSet, - visible_from_module: VisibleFromModule, - name: Option<&Name>, - mode: LookupMode, - mut callback: impl FnMut(ReceiverAdjustments, AssocItemId) -> Option, -) -> Option { - let mut slot = None; - iterate_method_candidates_dyn( - ty, - db, - env, - traits_in_scope, - visible_from_module, - name, - mode, - &mut |adj, item| { - assert!(slot.is_none()); - if let Some(it) = callback(adj, item) { - slot = Some(it); - return ControlFlow::Break(()); - } - ControlFlow::Continue(()) - }, - ); - slot -} - -pub fn lookup_impl_method( - self_ty: &Ty, - db: &dyn HirDatabase, - env: Arc, - trait_: TraitId, - name: &Name, -) -> Option { - let self_ty_fp = TyFingerprint::for_trait_impl(self_ty)?; - let trait_impls = db.trait_impls_in_deps(env.krate); - let impls = trait_impls.for_trait_and_self_ty(trait_, self_ty_fp); - let mut table = InferenceTable::new(db, env.clone()); - find_matching_impl(impls, &mut table, &self_ty).and_then(|data| { - data.items.iter().find_map(|it| match it { - AssocItemId::FunctionId(f) => (db.function_data(*f).name == *name).then(|| *f), - _ => None, - }) - }) -} - -fn find_matching_impl( - mut impls: impl Iterator, - table: &mut InferenceTable<'_>, - self_ty: &Ty, -) -> Option> { - let db = table.db; - loop { - let impl_ = impls.next()?; - let r = table.run_in_snapshot(|table| { - let impl_data = db.impl_data(impl_); - let substs = - TyBuilder::subst_for_def(db, impl_).fill_with_inference_vars(table).build(); - let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs); - - table - .unify(self_ty, &impl_ty) - .then(|| { - let wh_goals = - crate::chalk_db::convert_where_clauses(db, impl_.into(), &substs) - .into_iter() - .map(|b| b.cast(Interner)); - - let goal = crate::Goal::all(Interner, wh_goals); - - table.try_obligation(goal).map(|_| impl_data) - }) - .flatten() - }); - if r.is_some() { - break r; - } - } -} - -pub fn iterate_path_candidates( - ty: &Canonical, - db: &dyn HirDatabase, - env: Arc, - traits_in_scope: &FxHashSet, - visible_from_module: VisibleFromModule, - name: Option<&Name>, - callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>, -) -> ControlFlow<()> { - iterate_method_candidates_dyn( - ty, - db, - env, - traits_in_scope, - visible_from_module, - name, - LookupMode::Path, - // the adjustments are not relevant for path lookup - &mut |_, id| callback(id), - ) -} - -pub fn iterate_method_candidates_dyn( - ty: &Canonical, - db: &dyn HirDatabase, - env: Arc, - traits_in_scope: &FxHashSet, - visible_from_module: VisibleFromModule, - name: Option<&Name>, - mode: LookupMode, - callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>, -) -> ControlFlow<()> { - match mode { - LookupMode::MethodCall => { - // For method calls, rust first does any number of autoderef, and - // then one autoref (i.e. when the method takes &self or &mut self). - // Note that when we've got a receiver like &S, even if the method - // we find in the end takes &self, we still do the autoderef step - // (just as rustc does an autoderef and then autoref again). - - // We have to be careful about the order we're looking at candidates - // in here. Consider the case where we're resolving `x.clone()` - // where `x: &Vec<_>`. This resolves to the clone method with self - // type `Vec<_>`, *not* `&_`. I.e. we need to consider methods where - // the receiver type exactly matches before cases where we have to - // do autoref. But in the autoderef steps, the `&_` self type comes - // up *before* the `Vec<_>` self type. - // - // On the other hand, we don't want to just pick any by-value method - // before any by-autoref method; it's just that we need to consider - // the methods by autoderef order of *receiver types*, not *self - // types*. - - let mut table = InferenceTable::new(db, env.clone()); - let ty = table.instantiate_canonical(ty.clone()); - let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty); - - let result = deref_chain.into_iter().zip(adj).try_for_each(|(receiver_ty, adj)| { - iterate_method_candidates_with_autoref( - &receiver_ty, - adj, - db, - env.clone(), - traits_in_scope, - visible_from_module, - name, - callback, - ) - }); - result - } - LookupMode::Path => { - // No autoderef for path lookups - iterate_method_candidates_for_self_ty( - ty, - db, - env, - traits_in_scope, - visible_from_module, - name, - callback, - ) - } - } -} - -fn iterate_method_candidates_with_autoref( - receiver_ty: &Canonical, - first_adjustment: ReceiverAdjustments, - db: &dyn HirDatabase, - env: Arc, - traits_in_scope: &FxHashSet, - visible_from_module: VisibleFromModule, - name: Option<&Name>, - mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>, -) -> ControlFlow<()> { - if receiver_ty.value.is_general_var(Interner, &receiver_ty.binders) { - // don't try to resolve methods on unknown types - return ControlFlow::Continue(()); - } - - iterate_method_candidates_by_receiver( - receiver_ty, - first_adjustment.clone(), - db, - env.clone(), - traits_in_scope, - visible_from_module, - name, - &mut callback, - )?; - - let refed = Canonical { - value: TyKind::Ref(Mutability::Not, static_lifetime(), receiver_ty.value.clone()) - .intern(Interner), - binders: receiver_ty.binders.clone(), - }; - - iterate_method_candidates_by_receiver( - &refed, - first_adjustment.with_autoref(Mutability::Not), - db, - env.clone(), - traits_in_scope, - visible_from_module, - name, - &mut callback, - )?; - - let ref_muted = Canonical { - value: TyKind::Ref(Mutability::Mut, static_lifetime(), receiver_ty.value.clone()) - .intern(Interner), - binders: receiver_ty.binders.clone(), - }; - - iterate_method_candidates_by_receiver( - &ref_muted, - first_adjustment.with_autoref(Mutability::Mut), - db, - env, - traits_in_scope, - visible_from_module, - name, - &mut callback, - ) -} - -fn iterate_method_candidates_by_receiver( - receiver_ty: &Canonical, - receiver_adjustments: ReceiverAdjustments, - db: &dyn HirDatabase, - env: Arc, - traits_in_scope: &FxHashSet, - visible_from_module: VisibleFromModule, - name: Option<&Name>, - mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>, -) -> ControlFlow<()> { - let mut table = InferenceTable::new(db, env); - let receiver_ty = table.instantiate_canonical(receiver_ty.clone()); - let snapshot = table.snapshot(); - // We're looking for methods with *receiver* type receiver_ty. These could - // be found in any of the derefs of receiver_ty, so we have to go through - // that. - let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone()); - while let Some((self_ty, _)) = autoderef.next() { - iterate_inherent_methods( - &self_ty, - &mut autoderef.table, - name, - Some(&receiver_ty), - Some(receiver_adjustments.clone()), - visible_from_module, - &mut callback, - )? - } - - table.rollback_to(snapshot); - - let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone()); - while let Some((self_ty, _)) = autoderef.next() { - iterate_trait_method_candidates( - &self_ty, - &mut autoderef.table, - traits_in_scope, - name, - Some(&receiver_ty), - Some(receiver_adjustments.clone()), - &mut callback, - )? - } - - ControlFlow::Continue(()) -} - -fn iterate_method_candidates_for_self_ty( - self_ty: &Canonical, - db: &dyn HirDatabase, - env: Arc, - traits_in_scope: &FxHashSet, - visible_from_module: VisibleFromModule, - name: Option<&Name>, - mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>, -) -> ControlFlow<()> { - let mut table = InferenceTable::new(db, env); - let self_ty = table.instantiate_canonical(self_ty.clone()); - iterate_inherent_methods( - &self_ty, - &mut table, - name, - None, - None, - visible_from_module, - &mut callback, - )?; - iterate_trait_method_candidates( - &self_ty, - &mut table, - traits_in_scope, - name, - None, - None, - callback, - ) -} - -fn iterate_trait_method_candidates( - self_ty: &Ty, - table: &mut InferenceTable<'_>, - traits_in_scope: &FxHashSet, - name: Option<&Name>, - receiver_ty: Option<&Ty>, - receiver_adjustments: Option, - callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>, -) -> ControlFlow<()> { - let db = table.db; - let env = table.trait_env.clone(); - let self_is_array = matches!(self_ty.kind(Interner), chalk_ir::TyKind::Array(..)); - // if ty is `dyn Trait`, the trait doesn't need to be in scope - let inherent_trait = - self_ty.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t)); - let env_traits = matches!(self_ty.kind(Interner), TyKind::Placeholder(_)) - // if we have `T: Trait` in the param env, the trait doesn't need to be in scope - .then(|| { - env.traits_in_scope_from_clauses(self_ty.clone()) - .flat_map(|t| all_super_traits(db.upcast(), t)) - }) - .into_iter() - .flatten(); - let traits = inherent_trait.chain(env_traits).chain(traits_in_scope.iter().copied()); - - let canonical_self_ty = table.canonicalize(self_ty.clone()).value; - - 'traits: for t in traits { - let data = db.trait_data(t); - - // Traits annotated with `#[rustc_skip_array_during_method_dispatch]` are skipped during - // method resolution, if the receiver is an array, and we're compiling for editions before - // 2021. - // This is to make `[a].into_iter()` not break code with the new `IntoIterator` impl for - // arrays. - if data.skip_array_during_method_dispatch && self_is_array { - // FIXME: this should really be using the edition of the method name's span, in case it - // comes from a macro - if db.crate_graph()[env.krate].edition < Edition::Edition2021 { - continue; - } - } - - // we'll be lazy about checking whether the type implements the - // trait, but if we find out it doesn't, we'll skip the rest of the - // iteration - let mut known_implemented = false; - for &(_, item) in data.items.iter() { - // Don't pass a `visible_from_module` down to `is_valid_candidate`, - // since only inherent methods should be included into visibility checking. - if !is_valid_candidate(table, name, receiver_ty, item, self_ty, None) { - continue; - } - if !known_implemented { - let goal = generic_implements_goal(db, env.clone(), t, &canonical_self_ty); - if db.trait_solve(env.krate, goal.cast(Interner)).is_none() { - continue 'traits; - } - } - known_implemented = true; - callback(receiver_adjustments.clone().unwrap_or_default(), item)?; - } - } - ControlFlow::Continue(()) -} - -fn iterate_inherent_methods( - self_ty: &Ty, - table: &mut InferenceTable<'_>, - name: Option<&Name>, - receiver_ty: Option<&Ty>, - receiver_adjustments: Option, - visible_from_module: VisibleFromModule, - callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>, -) -> ControlFlow<()> { - let db = table.db; - let env = table.trait_env.clone(); - let def_crates = match def_crates(db, self_ty, env.krate) { - Some(k) => k, - None => return ControlFlow::Continue(()), - }; - - let (module, block) = match visible_from_module { - VisibleFromModule::Filter(module) => (Some(module), module.containing_block()), - VisibleFromModule::IncludeBlock(block) => (None, Some(block)), - VisibleFromModule::None => (None, None), - }; - - if let Some(block_id) = block { - if let Some(impls) = db.inherent_impls_in_block(block_id) { - impls_for_self_ty( - &impls, - self_ty, - table, - name, - receiver_ty, - receiver_adjustments.clone(), - module, - callback, - )?; - } - } - - for krate in def_crates { - let impls = db.inherent_impls_in_crate(krate); - impls_for_self_ty( - &impls, - self_ty, - table, - name, - receiver_ty, - receiver_adjustments.clone(), - module, - callback, - )?; - } - return ControlFlow::Continue(()); - - fn impls_for_self_ty( - impls: &InherentImpls, - self_ty: &Ty, - table: &mut InferenceTable<'_>, - name: Option<&Name>, - receiver_ty: Option<&Ty>, - receiver_adjustments: Option, - visible_from_module: Option, - callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>, - ) -> ControlFlow<()> { - let db = table.db; - let impls_for_self_ty = impls.for_self_ty(self_ty); - for &impl_def in impls_for_self_ty { - for &item in &db.impl_data(impl_def).items { - if !is_valid_candidate(table, name, receiver_ty, item, self_ty, visible_from_module) - { - continue; - } - callback(receiver_adjustments.clone().unwrap_or_default(), item)?; - } - } - ControlFlow::Continue(()) - } -} - -/// Returns the receiver type for the index trait call. -pub fn resolve_indexing_op( - db: &dyn HirDatabase, - env: Arc, - ty: Canonical, - index_trait: TraitId, -) -> Option { - let mut table = InferenceTable::new(db, env.clone()); - let ty = table.instantiate_canonical(ty); - let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty); - for (ty, adj) in deref_chain.into_iter().zip(adj) { - let goal = generic_implements_goal(db, env.clone(), index_trait, &ty); - if db.trait_solve(env.krate, goal.cast(Interner)).is_some() { - return Some(adj); - } - } - None -} - -fn is_valid_candidate( - table: &mut InferenceTable<'_>, - name: Option<&Name>, - receiver_ty: Option<&Ty>, - item: AssocItemId, - self_ty: &Ty, - visible_from_module: Option, -) -> bool { - macro_rules! check_that { - ($cond:expr) => { - if !$cond { - return false; - } - }; - } - - let db = table.db; - match item { - AssocItemId::FunctionId(m) => { - let data = db.function_data(m); - - check_that!(name.map_or(true, |n| n == &data.name)); - check_that!(visible_from_module.map_or(true, |from_module| { - let v = db.function_visibility(m).is_visible_from(db.upcast(), from_module); - if !v { - cov_mark::hit!(autoderef_candidate_not_visible); - } - v - })); - - table.run_in_snapshot(|table| { - let subst = TyBuilder::subst_for_def(db, m).fill_with_inference_vars(table).build(); - let expect_self_ty = match m.lookup(db.upcast()).container { - ItemContainerId::TraitId(_) => { - subst.at(Interner, 0).assert_ty_ref(Interner).clone() - } - ItemContainerId::ImplId(impl_id) => { - subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner) - } - // We should only get called for associated items (impl/trait) - ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => { - unreachable!() - } - }; - check_that!(table.unify(&expect_self_ty, self_ty)); - if let Some(receiver_ty) = receiver_ty { - check_that!(data.has_self_param()); - - let sig = db.callable_item_signature(m.into()); - let expected_receiver = - sig.map(|s| s.params()[0].clone()).substitute(Interner, &subst); - - check_that!(table.unify(&receiver_ty, &expected_receiver)); - } - true - }) - } - AssocItemId::ConstId(c) => { - let data = db.const_data(c); - check_that!(receiver_ty.is_none()); - - check_that!(name.map_or(true, |n| data.name.as_ref() == Some(n))); - check_that!(visible_from_module.map_or(true, |from_module| { - let v = db.const_visibility(c).is_visible_from(db.upcast(), from_module); - if !v { - cov_mark::hit!(const_candidate_not_visible); - } - v - })); - if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container { - let self_ty_matches = table.run_in_snapshot(|table| { - let subst = - TyBuilder::subst_for_def(db, c).fill_with_inference_vars(table).build(); - let expected_self_ty = - subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner); - table.unify(&expected_self_ty, &self_ty) - }); - if !self_ty_matches { - cov_mark::hit!(const_candidate_self_type_mismatch); - return false; - } - } - true - } - _ => false, - } -} - -pub fn implements_trait( - ty: &Canonical, - db: &dyn HirDatabase, - env: Arc, - trait_: TraitId, -) -> bool { - let goal = generic_implements_goal(db, env.clone(), trait_, ty); - let solution = db.trait_solve(env.krate, goal.cast(Interner)); - - solution.is_some() -} - -pub fn implements_trait_unique( - ty: &Canonical, - db: &dyn HirDatabase, - env: Arc, - trait_: TraitId, -) -> bool { - let goal = generic_implements_goal(db, env.clone(), trait_, ty); - let solution = db.trait_solve(env.krate, goal.cast(Interner)); - - matches!(solution, Some(crate::Solution::Unique(_))) -} - -/// This creates Substs for a trait with the given Self type and type variables -/// for all other parameters, to query Chalk with it. -fn generic_implements_goal( - db: &dyn HirDatabase, - env: Arc, - trait_: TraitId, - self_ty: &Canonical, -) -> Canonical> { - let mut kinds = self_ty.binders.interned().to_vec(); - let trait_ref = TyBuilder::trait_ref(db, trait_) - .push(self_ty.value.clone()) - .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len()) - .build(); - kinds.extend(trait_ref.substitution.iter(Interner).skip(1).map(|x| { - let vk = match x.data(Interner) { - chalk_ir::GenericArgData::Ty(_) => { - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) - } - chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime, - chalk_ir::GenericArgData::Const(c) => { - chalk_ir::VariableKind::Const(c.data(Interner).ty.clone()) - } - }; - chalk_ir::WithKind::new(vk, UniverseIndex::ROOT) - })); - let obligation = trait_ref.cast(Interner); - Canonical { - binders: CanonicalVarKinds::from_iter(Interner, kinds), - value: InEnvironment::new(&env.env, obligation), - } -} - -fn autoderef_method_receiver( - table: &mut InferenceTable<'_>, - ty: Ty, -) -> (Vec>, Vec) { - let (mut deref_chain, mut adjustments): (Vec<_>, Vec<_>) = (Vec::new(), Vec::new()); - let mut autoderef = autoderef::Autoderef::new(table, ty); - while let Some((ty, derefs)) = autoderef.next() { - deref_chain.push(autoderef.table.canonicalize(ty).value); - adjustments.push(ReceiverAdjustments { - autoref: None, - autoderefs: derefs, - unsize_array: false, - }); - } - // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!) - if let (Some((TyKind::Array(parameters, _), binders)), Some(adj)) = ( - deref_chain.last().map(|ty| (ty.value.kind(Interner), ty.binders.clone())), - adjustments.last().cloned(), - ) { - let unsized_ty = TyKind::Slice(parameters.clone()).intern(Interner); - deref_chain.push(Canonical { value: unsized_ty, binders }); - adjustments.push(ReceiverAdjustments { unsize_array: true, ..adj }); - } - (deref_chain, adjustments) -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/primitive.rs b/src/tools/rust-analyzer/crates/hir-ty/src/primitive.rs deleted file mode 100644 index d7f48c69a56ef..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/primitive.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! A few helper functions for dealing with primitives. - -pub use chalk_ir::{FloatTy, IntTy, UintTy}; -pub use hir_def::builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}; - -pub fn int_ty_to_string(ty: IntTy) -> &'static str { - match ty { - IntTy::Isize => "isize", - IntTy::I8 => "i8", - IntTy::I16 => "i16", - IntTy::I32 => "i32", - IntTy::I64 => "i64", - IntTy::I128 => "i128", - } -} - -pub fn uint_ty_to_string(ty: UintTy) -> &'static str { - match ty { - UintTy::Usize => "usize", - UintTy::U8 => "u8", - UintTy::U16 => "u16", - UintTy::U32 => "u32", - UintTy::U64 => "u64", - UintTy::U128 => "u128", - } -} - -pub fn float_ty_to_string(ty: FloatTy) -> &'static str { - match ty { - FloatTy::F32 => "f32", - FloatTy::F64 => "f64", - } -} - -pub(super) fn int_ty_from_builtin(t: BuiltinInt) -> IntTy { - match t { - BuiltinInt::Isize => IntTy::Isize, - BuiltinInt::I8 => IntTy::I8, - BuiltinInt::I16 => IntTy::I16, - BuiltinInt::I32 => IntTy::I32, - BuiltinInt::I64 => IntTy::I64, - BuiltinInt::I128 => IntTy::I128, - } -} - -pub(super) fn uint_ty_from_builtin(t: BuiltinUint) -> UintTy { - match t { - BuiltinUint::Usize => UintTy::Usize, - BuiltinUint::U8 => UintTy::U8, - BuiltinUint::U16 => UintTy::U16, - BuiltinUint::U32 => UintTy::U32, - BuiltinUint::U64 => UintTy::U64, - BuiltinUint::U128 => UintTy::U128, - } -} - -pub(super) fn float_ty_from_builtin(t: BuiltinFloat) -> FloatTy { - match t { - BuiltinFloat::F32 => FloatTy::F32, - BuiltinFloat::F64 => FloatTy::F64, - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs deleted file mode 100644 index dc7252f7072d8..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs +++ /dev/null @@ -1,150 +0,0 @@ -//! Database used for testing `hir`. - -use std::{ - fmt, panic, - sync::{Arc, Mutex}, -}; - -use base_db::{ - salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast, -}; -use hir_def::{db::DefDatabase, ModuleId}; -use hir_expand::db::AstDatabase; -use rustc_hash::{FxHashMap, FxHashSet}; -use syntax::TextRange; -use test_utils::extract_annotations; - -#[salsa::database( - base_db::SourceDatabaseExtStorage, - base_db::SourceDatabaseStorage, - hir_expand::db::AstDatabaseStorage, - hir_def::db::InternDatabaseStorage, - hir_def::db::DefDatabaseStorage, - crate::db::HirDatabaseStorage -)] -pub(crate) struct TestDB { - storage: salsa::Storage, - events: Mutex>>, -} - -impl Default for TestDB { - fn default() -> Self { - let mut this = Self { storage: Default::default(), events: Default::default() }; - this.set_enable_proc_attr_macros(true); - this - } -} - -impl fmt::Debug for TestDB { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TestDB").finish() - } -} - -impl Upcast for TestDB { - fn upcast(&self) -> &(dyn AstDatabase + 'static) { - &*self - } -} - -impl Upcast for TestDB { - fn upcast(&self) -> &(dyn DefDatabase + 'static) { - &*self - } -} - -impl salsa::Database for TestDB { - fn salsa_event(&self, event: salsa::Event) { - let mut events = self.events.lock().unwrap(); - if let Some(events) = &mut *events { - events.push(event); - } - } -} - -impl salsa::ParallelDatabase for TestDB { - fn snapshot(&self) -> salsa::Snapshot { - salsa::Snapshot::new(TestDB { - storage: self.storage.snapshot(), - events: Default::default(), - }) - } -} - -impl panic::RefUnwindSafe for TestDB {} - -impl FileLoader for TestDB { - fn file_text(&self, file_id: FileId) -> Arc { - FileLoaderDelegate(self).file_text(file_id) - } - fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { - FileLoaderDelegate(self).resolve_path(path) - } - fn relevant_crates(&self, file_id: FileId) -> Arc> { - FileLoaderDelegate(self).relevant_crates(file_id) - } -} - -impl TestDB { - pub(crate) fn module_for_file_opt(&self, file_id: FileId) -> Option { - for &krate in self.relevant_crates(file_id).iter() { - let crate_def_map = self.crate_def_map(krate); - for (local_id, data) in crate_def_map.modules() { - if data.origin.file_id() == Some(file_id) { - return Some(crate_def_map.module_id(local_id)); - } - } - } - None - } - - pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId { - self.module_for_file_opt(file_id).unwrap() - } - - pub(crate) fn extract_annotations(&self) -> FxHashMap> { - let mut files = Vec::new(); - let crate_graph = self.crate_graph(); - for krate in crate_graph.iter() { - let crate_def_map = self.crate_def_map(krate); - for (module_id, _) in crate_def_map.modules() { - let file_id = crate_def_map[module_id].origin.file_id(); - files.extend(file_id) - } - } - files - .into_iter() - .filter_map(|file_id| { - let text = self.file_text(file_id); - let annotations = extract_annotations(&text); - if annotations.is_empty() { - return None; - } - Some((file_id, annotations)) - }) - .collect() - } -} - -impl TestDB { - pub(crate) fn log(&self, f: impl FnOnce()) -> Vec { - *self.events.lock().unwrap() = Some(Vec::new()); - f(); - self.events.lock().unwrap().take().unwrap() - } - - pub(crate) fn log_executed(&self, f: impl FnOnce()) -> Vec { - let events = self.log(f); - events - .into_iter() - .filter_map(|e| match e.kind { - // This is pretty horrible, but `Debug` is the only way to inspect - // QueryDescriptor at the moment. - salsa::EventKind::WillExecute { database_key } => { - Some(format!("{:?}", database_key.debug(self))) - } - _ => None, - }) - .collect() - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs deleted file mode 100644 index d2f13e4351c73..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ /dev/null @@ -1,578 +0,0 @@ -mod never_type; -mod coercion; -mod regression; -mod simple; -mod patterns; -mod traits; -mod method_resolution; -mod macros; -mod display_source_code; -mod incremental; -mod diagnostics; - -use std::{collections::HashMap, env, sync::Arc}; - -use base_db::{fixture::WithFixture, FileRange, SourceDatabaseExt}; -use expect_test::Expect; -use hir_def::{ - body::{Body, BodySourceMap, SyntheticSyntax}, - db::DefDatabase, - expr::{ExprId, PatId}, - item_scope::ItemScope, - nameres::DefMap, - src::HasSource, - AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId, -}; -use hir_expand::{db::AstDatabase, InFile}; -use once_cell::race::OnceBool; -use stdx::format_to; -use syntax::{ - ast::{self, AstNode, HasName}, - SyntaxNode, -}; -use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; -use tracing_tree::HierarchicalLayer; - -use crate::{ - db::HirDatabase, - display::HirDisplay, - infer::{Adjustment, TypeMismatch}, - test_db::TestDB, - InferenceResult, Ty, -}; - -// These tests compare the inference results for all expressions in a file -// against snapshots of the expected results using expect. Use -// `env UPDATE_EXPECT=1 cargo test -p hir_ty` to update the snapshots. - -fn setup_tracing() -> Option { - static ENABLE: OnceBool = OnceBool::new(); - if !ENABLE.get_or_init(|| env::var("CHALK_DEBUG").is_ok()) { - return None; - } - - let filter = EnvFilter::from_env("CHALK_DEBUG"); - let layer = HierarchicalLayer::default() - .with_indent_lines(true) - .with_ansi(false) - .with_indent_amount(2) - .with_writer(std::io::stderr); - let subscriber = Registry::default().with(filter).with(layer); - Some(tracing::subscriber::set_default(subscriber)) -} - -fn check_types(ra_fixture: &str) { - check_impl(ra_fixture, false, true, false) -} - -fn check_types_source_code(ra_fixture: &str) { - check_impl(ra_fixture, false, true, true) -} - -fn check_no_mismatches(ra_fixture: &str) { - check_impl(ra_fixture, true, false, false) -} - -fn check(ra_fixture: &str) { - check_impl(ra_fixture, false, false, false) -} - -fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_source: bool) { - let _tracing = setup_tracing(); - let (db, files) = TestDB::with_many_files(ra_fixture); - - let mut had_annotations = false; - let mut mismatches = HashMap::new(); - let mut types = HashMap::new(); - let mut adjustments = HashMap::<_, Vec<_>>::new(); - for (file_id, annotations) in db.extract_annotations() { - for (range, expected) in annotations { - let file_range = FileRange { file_id, range }; - if only_types { - types.insert(file_range, expected); - } else if expected.starts_with("type: ") { - types.insert(file_range, expected.trim_start_matches("type: ").to_string()); - } else if expected.starts_with("expected") { - mismatches.insert(file_range, expected); - } else if expected.starts_with("adjustments: ") { - adjustments.insert( - file_range, - expected - .trim_start_matches("adjustments: ") - .split(',') - .map(|it| it.trim().to_string()) - .filter(|it| !it.is_empty()) - .collect(), - ); - } else { - panic!("unexpected annotation: {}", expected); - } - had_annotations = true; - } - } - assert!(had_annotations || allow_none, "no `//^` annotations found"); - - let mut defs: Vec = Vec::new(); - for file_id in files { - let module = db.module_for_file_opt(file_id); - let module = match module { - Some(m) => m, - None => continue, - }; - let def_map = module.def_map(&db); - visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it)); - } - defs.sort_by_key(|def| match def { - DefWithBodyId::FunctionId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.syntax().text_range().start() - } - DefWithBodyId::ConstId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.syntax().text_range().start() - } - DefWithBodyId::StaticId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.syntax().text_range().start() - } - }); - let mut unexpected_type_mismatches = String::new(); - for def in defs { - let (_body, body_source_map) = db.body_with_source_map(def); - let inference_result = db.infer(def); - - for (pat, ty) in inference_result.type_of_pat.iter() { - let node = match pat_node(&body_source_map, pat, &db) { - Some(value) => value, - None => continue, - }; - let range = node.as_ref().original_file_range(&db); - if let Some(expected) = types.remove(&range) { - let actual = if display_source { - ty.display_source_code(&db, def.module(&db)).unwrap() - } else { - ty.display_test(&db).to_string() - }; - assert_eq!(actual, expected); - } - } - - for (expr, ty) in inference_result.type_of_expr.iter() { - let node = match expr_node(&body_source_map, expr, &db) { - Some(value) => value, - None => continue, - }; - let range = node.as_ref().original_file_range(&db); - if let Some(expected) = types.remove(&range) { - let actual = if display_source { - ty.display_source_code(&db, def.module(&db)).unwrap() - } else { - ty.display_test(&db).to_string() - }; - assert_eq!(actual, expected); - } - if let Some(expected) = adjustments.remove(&range) { - if let Some(adjustments) = inference_result.expr_adjustments.get(&expr) { - assert_eq!( - expected, - adjustments - .iter() - .map(|Adjustment { kind, .. }| format!("{:?}", kind)) - .collect::>() - ); - } else { - panic!("expected {:?} adjustments, found none", expected); - } - } - } - - for (pat, mismatch) in inference_result.pat_type_mismatches() { - let node = match pat_node(&body_source_map, pat, &db) { - Some(value) => value, - None => continue, - }; - let range = node.as_ref().original_file_range(&db); - let actual = format!( - "expected {}, got {}", - mismatch.expected.display_test(&db), - mismatch.actual.display_test(&db) - ); - match mismatches.remove(&range) { - Some(annotation) => assert_eq!(actual, annotation), - None => format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual), - } - } - for (expr, mismatch) in inference_result.expr_type_mismatches() { - let node = match body_source_map.expr_syntax(expr) { - Ok(sp) => { - let root = db.parse_or_expand(sp.file_id).unwrap(); - sp.map(|ptr| ptr.to_node(&root).syntax().clone()) - } - Err(SyntheticSyntax) => continue, - }; - let range = node.as_ref().original_file_range(&db); - let actual = format!( - "expected {}, got {}", - mismatch.expected.display_test(&db), - mismatch.actual.display_test(&db) - ); - match mismatches.remove(&range) { - Some(annotation) => assert_eq!(actual, annotation), - None => format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual), - } - } - } - - let mut buf = String::new(); - if !unexpected_type_mismatches.is_empty() { - format_to!(buf, "Unexpected type mismatches:\n{}", unexpected_type_mismatches); - } - if !mismatches.is_empty() { - format_to!(buf, "Unchecked mismatch annotations:\n"); - for m in mismatches { - format_to!(buf, "{:?}: {}\n", m.0.range, m.1); - } - } - if !types.is_empty() { - format_to!(buf, "Unchecked type annotations:\n"); - for t in types { - format_to!(buf, "{:?}: type {}\n", t.0.range, t.1); - } - } - if !adjustments.is_empty() { - format_to!(buf, "Unchecked adjustments annotations:\n"); - for t in adjustments { - format_to!(buf, "{:?}: type {:?}\n", t.0.range, t.1); - } - } - assert!(buf.is_empty(), "{}", buf); -} - -fn expr_node( - body_source_map: &BodySourceMap, - expr: ExprId, - db: &TestDB, -) -> Option> { - Some(match body_source_map.expr_syntax(expr) { - Ok(sp) => { - let root = db.parse_or_expand(sp.file_id).unwrap(); - sp.map(|ptr| ptr.to_node(&root).syntax().clone()) - } - Err(SyntheticSyntax) => return None, - }) -} - -fn pat_node( - body_source_map: &BodySourceMap, - pat: PatId, - db: &TestDB, -) -> Option> { - Some(match body_source_map.pat_syntax(pat) { - Ok(sp) => { - let root = db.parse_or_expand(sp.file_id).unwrap(); - sp.map(|ptr| { - ptr.either( - |it| it.to_node(&root).syntax().clone(), - |it| it.to_node(&root).syntax().clone(), - ) - }) - } - Err(SyntheticSyntax) => return None, - }) -} - -fn infer(ra_fixture: &str) -> String { - infer_with_mismatches(ra_fixture, false) -} - -fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { - let _tracing = setup_tracing(); - let (db, file_id) = TestDB::with_single_file(content); - - let mut buf = String::new(); - - let mut infer_def = |inference_result: Arc, - body_source_map: Arc| { - let mut types: Vec<(InFile, &Ty)> = Vec::new(); - let mut mismatches: Vec<(InFile, &TypeMismatch)> = Vec::new(); - - for (pat, ty) in inference_result.type_of_pat.iter() { - let syntax_ptr = match body_source_map.pat_syntax(pat) { - Ok(sp) => { - let root = db.parse_or_expand(sp.file_id).unwrap(); - sp.map(|ptr| { - ptr.either( - |it| it.to_node(&root).syntax().clone(), - |it| it.to_node(&root).syntax().clone(), - ) - }) - } - Err(SyntheticSyntax) => continue, - }; - types.push((syntax_ptr.clone(), ty)); - if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat) { - mismatches.push((syntax_ptr, mismatch)); - } - } - - for (expr, ty) in inference_result.type_of_expr.iter() { - let node = match body_source_map.expr_syntax(expr) { - Ok(sp) => { - let root = db.parse_or_expand(sp.file_id).unwrap(); - sp.map(|ptr| ptr.to_node(&root).syntax().clone()) - } - Err(SyntheticSyntax) => continue, - }; - types.push((node.clone(), ty)); - if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) { - mismatches.push((node, mismatch)); - } - } - - // sort ranges for consistency - types.sort_by_key(|(node, _)| { - let range = node.value.text_range(); - (range.start(), range.end()) - }); - for (node, ty) in &types { - let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.value.clone()) { - (self_param.name().unwrap().syntax().text_range(), "self".to_string()) - } else { - (node.value.text_range(), node.value.text().to_string().replace('\n', " ")) - }; - let macro_prefix = if node.file_id != file_id.into() { "!" } else { "" }; - format_to!( - buf, - "{}{:?} '{}': {}\n", - macro_prefix, - range, - ellipsize(text, 15), - ty.display_test(&db) - ); - } - if include_mismatches { - mismatches.sort_by_key(|(node, _)| { - let range = node.value.text_range(); - (range.start(), range.end()) - }); - for (src_ptr, mismatch) in &mismatches { - let range = src_ptr.value.text_range(); - let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" }; - format_to!( - buf, - "{}{:?}: expected {}, got {}\n", - macro_prefix, - range, - mismatch.expected.display_test(&db), - mismatch.actual.display_test(&db), - ); - } - } - }; - - let module = db.module_for_file(file_id); - let def_map = module.def_map(&db); - - let mut defs: Vec = Vec::new(); - visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it)); - defs.sort_by_key(|def| match def { - DefWithBodyId::FunctionId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.syntax().text_range().start() - } - DefWithBodyId::ConstId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.syntax().text_range().start() - } - DefWithBodyId::StaticId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.syntax().text_range().start() - } - }); - for def in defs { - let (_body, source_map) = db.body_with_source_map(def); - let infer = db.infer(def); - infer_def(infer, source_map); - } - - buf.truncate(buf.trim_end().len()); - buf -} - -fn visit_module( - db: &TestDB, - crate_def_map: &DefMap, - module_id: LocalModuleId, - cb: &mut dyn FnMut(DefWithBodyId), -) { - visit_scope(db, crate_def_map, &crate_def_map[module_id].scope, cb); - for impl_id in crate_def_map[module_id].scope.impls() { - let impl_data = db.impl_data(impl_id); - for &item in impl_data.items.iter() { - match item { - AssocItemId::FunctionId(it) => { - let def = it.into(); - cb(def); - let body = db.body(def); - visit_body(db, &body, cb); - } - AssocItemId::ConstId(it) => { - let def = it.into(); - cb(def); - let body = db.body(def); - visit_body(db, &body, cb); - } - AssocItemId::TypeAliasId(_) => (), - } - } - } - - fn visit_scope( - db: &TestDB, - crate_def_map: &DefMap, - scope: &ItemScope, - cb: &mut dyn FnMut(DefWithBodyId), - ) { - for decl in scope.declarations() { - match decl { - ModuleDefId::FunctionId(it) => { - let def = it.into(); - cb(def); - let body = db.body(def); - visit_body(db, &body, cb); - } - ModuleDefId::ConstId(it) => { - let def = it.into(); - cb(def); - let body = db.body(def); - visit_body(db, &body, cb); - } - ModuleDefId::StaticId(it) => { - let def = it.into(); - cb(def); - let body = db.body(def); - visit_body(db, &body, cb); - } - ModuleDefId::TraitId(it) => { - let trait_data = db.trait_data(it); - for &(_, item) in trait_data.items.iter() { - match item { - AssocItemId::FunctionId(it) => cb(it.into()), - AssocItemId::ConstId(it) => cb(it.into()), - AssocItemId::TypeAliasId(_) => (), - } - } - } - ModuleDefId::ModuleId(it) => visit_module(db, crate_def_map, it.local_id, cb), - _ => (), - } - } - } - - fn visit_body(db: &TestDB, body: &Body, cb: &mut dyn FnMut(DefWithBodyId)) { - for (_, def_map) in body.blocks(db) { - for (mod_id, _) in def_map.modules() { - visit_module(db, &def_map, mod_id, cb); - } - } - } -} - -fn ellipsize(mut text: String, max_len: usize) -> String { - if text.len() <= max_len { - return text; - } - let ellipsis = "..."; - let e_len = ellipsis.len(); - let mut prefix_len = (max_len - e_len) / 2; - while !text.is_char_boundary(prefix_len) { - prefix_len += 1; - } - let mut suffix_len = max_len - e_len - prefix_len; - while !text.is_char_boundary(text.len() - suffix_len) { - suffix_len += 1; - } - text.replace_range(prefix_len..text.len() - suffix_len, ellipsis); - text -} - -fn check_infer(ra_fixture: &str, expect: Expect) { - let mut actual = infer(ra_fixture); - actual.push('\n'); - expect.assert_eq(&actual); -} - -fn check_infer_with_mismatches(ra_fixture: &str, expect: Expect) { - let mut actual = infer_with_mismatches(ra_fixture, true); - actual.push('\n'); - expect.assert_eq(&actual); -} - -#[test] -fn salsa_bug() { - let (mut db, pos) = TestDB::with_position( - " - //- /lib.rs - trait Index { - type Output; - } - - type Key = ::Key; - - pub trait UnificationStoreBase: Index> { - type Key; - - fn len(&self) -> usize; - } - - pub trait UnificationStoreMut: UnificationStoreBase { - fn push(&mut self, value: Self::Key); - } - - fn main() { - let x = 1; - x.push(1);$0 - } - ", - ); - - let module = db.module_for_file(pos.file_id); - let crate_def_map = module.def_map(&db); - visit_module(&db, &crate_def_map, module.local_id, &mut |def| { - db.infer(def); - }); - - let new_text = " - //- /lib.rs - trait Index { - type Output; - } - - type Key = ::Key; - - pub trait UnificationStoreBase: Index> { - type Key; - - fn len(&self) -> usize; - } - - pub trait UnificationStoreMut: UnificationStoreBase { - fn push(&mut self, value: Self::Key); - } - - fn main() { - - let x = 1; - x.push(1); - } - " - .to_string(); - - db.set_file_text(pos.file_id, Arc::new(new_text)); - - let module = db.module_for_file(pos.file_id); - let crate_def_map = module.def_map(&db); - visit_module(&db, &crate_def_map, module.local_id, &mut |def| { - db.infer(def); - }); -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs deleted file mode 100644 index bf59fadc2c336..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs +++ /dev/null @@ -1,755 +0,0 @@ -use super::{check, check_no_mismatches, check_types}; - -#[test] -fn block_expr_type_mismatch() { - check( - r" -fn test() { - let a: i32 = { 1i64 }; - // ^^^^ expected i32, got i64 -} - ", - ); -} - -#[test] -fn coerce_places() { - check_no_mismatches( - r#" -//- minicore: coerce_unsized -struct S { a: T } - -fn f(_: &[T]) -> T { loop {} } -fn g(_: S<&[T]>) -> T { loop {} } - -fn gen() -> *mut [T; 2] { loop {} } -fn test1() -> *mut [U] { - gen() -} - -fn test2() { - let arr: &[u8; 1] = &[1]; - - let a: &[_] = arr; - let b = f(arr); - let c: &[_] = { arr }; - let d = g(S { a: arr }); - let e: [&[_]; 1] = [arr]; - let f: [&[_]; 2] = [arr; 2]; - let g: (&[_], &[_]) = (arr, arr); -} -"#, - ); -} - -#[test] -fn let_stmt_coerce() { - check( - r" -//- minicore: coerce_unsized -fn test() { - let x: &[isize] = &[1]; - // ^^^^ adjustments: Deref(None), Borrow(Ref(Not)), Pointer(Unsize) - let x: *const [isize] = &[1]; - // ^^^^ adjustments: Deref(None), Borrow(RawPtr(Not)), Pointer(Unsize) -} -", - ); -} - -#[test] -fn custom_coerce_unsized() { - check( - r#" -//- minicore: coerce_unsized -use core::{marker::Unsize, ops::CoerceUnsized}; - -struct A(*const T); -struct B(*const T); -struct C { inner: *const T } - -impl, U: ?Sized> CoerceUnsized> for B {} -impl, U: ?Sized> CoerceUnsized> for C {} - -fn foo1(x: A<[T]>) -> A<[T]> { x } -fn foo2(x: B<[T]>) -> B<[T]> { x } -fn foo3(x: C<[T]>) -> C<[T]> { x } - -fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { - let d = foo1(a); - // ^ expected A<[{unknown}]>, got A<[u8; 2]> - let e = foo2(b); - // ^ type: B<[u8]> - let f = foo3(c); - // ^ type: C<[u8]> -} -"#, - ); -} - -#[test] -fn if_coerce() { - check_no_mismatches( - r#" -//- minicore: coerce_unsized -fn foo(x: &[T]) -> &[T] { x } -fn test() { - let x = if true { - foo(&[1]) - // ^^^^ adjustments: Deref(None), Borrow(Ref(Not)), Pointer(Unsize) - } else { - &[1] - }; -} -"#, - ); -} - -#[test] -fn if_else_coerce() { - check_no_mismatches( - r#" -//- minicore: coerce_unsized -fn foo(x: &[T]) -> &[T] { x } -fn test() { - let x = if true { - &[1] - } else { - foo(&[1]) - }; -} -"#, - ) -} - -#[test] -fn match_first_coerce() { - check_no_mismatches( - r#" -//- minicore: coerce_unsized -fn foo(x: &[T]) -> &[T] { x } -fn test(i: i32) { - let x = match i { - 2 => foo(&[2]), - // ^^^^ adjustments: Deref(None), Borrow(Ref(Not)), Pointer(Unsize) - 1 => &[1], - _ => &[3], - }; -} -"#, - ); -} - -#[test] -fn match_second_coerce() { - check_no_mismatches( - r#" -//- minicore: coerce_unsized -fn foo(x: &[T]) -> &[T] { loop {} } - // ^^^^^^^ adjustments: NeverToAny -fn test(i: i32) { - let x = match i { - 1 => &[1], - 2 => foo(&[2]), - _ => &[3], - }; -} -"#, - ); -} - -#[test] -fn coerce_merge_one_by_one1() { - cov_mark::check!(coerce_merge_fail_fallback); - - check( - r" -fn test() { - let t = &mut 1; - let x = match 1 { - 1 => t as *mut i32, - 2 => t as &i32, - //^^^^^^^^^ expected *mut i32, got &i32 - _ => t as *const i32, - // ^^^^^^^^^^^^^^^ adjustments: Pointer(MutToConstPointer) - - }; - x; - //^ type: *const i32 - -} - ", - ); -} - -#[test] -fn return_coerce_unknown() { - check_types( - r" -fn foo() -> u32 { - return unknown; - //^^^^^^^ u32 -} - ", - ); -} - -#[test] -fn coerce_autoderef() { - check_no_mismatches( - r" -struct Foo; -fn takes_ref_foo(x: &Foo) {} -fn test() { - takes_ref_foo(&Foo); - takes_ref_foo(&&Foo); - takes_ref_foo(&&&Foo); -}", - ); -} - -#[test] -fn coerce_autoderef_generic() { - check_no_mismatches( - r#" -struct Foo; -fn takes_ref(x: &T) -> T { *x } -fn test() { - takes_ref(&Foo); - takes_ref(&&Foo); - takes_ref(&&&Foo); -} -"#, - ); -} - -#[test] -fn coerce_autoderef_block() { - check_no_mismatches( - r#" -//- minicore: deref -struct String {} -impl core::ops::Deref for String { type Target = str; } -fn takes_ref_str(x: &str) {} -fn returns_string() -> String { loop {} } -fn test() { - takes_ref_str(&{ returns_string() }); - // ^^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(None), Deref(Some(OverloadedDeref(Not))), Borrow(Ref(Not)) -} -"#, - ); -} - -#[test] -fn coerce_autoderef_implication_1() { - check_no_mismatches( - r" -//- minicore: deref -struct Foo; -impl core::ops::Deref for Foo { type Target = (); } - -fn takes_ref_foo(x: &Foo) {} -fn test() { - let foo = Foo; - //^^^ type: Foo<{unknown}> - takes_ref_foo(&foo); - - let foo = Foo; - //^^^ type: Foo - let _: &() = &foo; -}", - ); -} - -#[test] -fn coerce_autoderef_implication_2() { - check( - r" -//- minicore: deref -struct Foo; -impl core::ops::Deref for Foo { type Target = (); } - -fn takes_ref_foo(x: &Foo) {} -fn test() { - let foo = Foo; - //^^^ type: Foo<{unknown}> - let _: &u32 = &Foo; - //^^^^ expected &u32, got &Foo<{unknown}> -}", - ); -} - -#[test] -fn closure_return_coerce() { - check_no_mismatches( - r" -fn foo() { - let x = || { - if true { - return &1u32; - } - &&1u32 - }; -}", - ); -} - -#[test] -fn assign_coerce() { - check_no_mismatches( - r" -//- minicore: deref -struct String; -impl core::ops::Deref for String { type Target = str; } -fn g(_text: &str) {} -fn f(text: &str) { - let mut text = text; - let tmp = String; - text = &tmp; - g(text); -} -", - ); -} - -#[test] -fn destructuring_assign_coerce() { - check_no_mismatches( - r" -//- minicore: deref -struct String; -impl core::ops::Deref for String { type Target = str; } -fn g(_text: &str) {} -fn f(text: &str) { - let mut text = text; - let tmp = String; - [text, _] = [&tmp, &tmp]; - g(text); -} -", - ); -} - -#[test] -fn coerce_fn_item_to_fn_ptr() { - check_no_mismatches( - r" -fn foo(x: u32) -> isize { 1 } -fn test() { - let f: fn(u32) -> isize = foo; - // ^^^ adjustments: Pointer(ReifyFnPointer) - let f: unsafe fn(u32) -> isize = foo; - // ^^^ adjustments: Pointer(ReifyFnPointer) -}", - ); -} - -#[test] -fn coerce_fn_items_in_match_arms() { - cov_mark::check!(coerce_fn_reification); - - check_types( - r" -fn foo1(x: u32) -> isize { 1 } -fn foo2(x: u32) -> isize { 2 } -fn foo3(x: u32) -> isize { 3 } -fn test() { - let x = match 1 { - 1 => foo1, - 2 => foo2, - _ => foo3, - }; - x; - //^ fn(u32) -> isize -}", - ); -} - -#[test] -fn coerce_closure_to_fn_ptr() { - check_no_mismatches( - r" -fn test() { - let f: fn(u32) -> isize = |x| { 1 }; -}", - ); -} - -#[test] -fn coerce_placeholder_ref() { - // placeholders should unify, even behind references - check_no_mismatches( - r" -struct S { t: T } -impl S { - fn get(&self) -> &TT { - &self.t - } -}", - ); -} - -#[test] -fn coerce_unsize_array() { - check_types( - r#" -//- minicore: coerce_unsized -fn test() { - let f: &[usize] = &[1, 2, 3]; - //^ usize -}"#, - ); -} - -#[test] -fn coerce_unsize_trait_object_simple() { - check_types( - r#" -//- minicore: coerce_unsized -trait Foo {} -trait Bar: Foo {} -trait Baz: Bar {} - -struct S; -impl Foo for S {} -impl Bar for S {} -impl Baz for S {} - -fn test() { - let obj: &dyn Baz = &S; - //^ S - let obj: &dyn Bar<_, i8, i16> = &S; - //^ S - let obj: &dyn Foo = &S; - //^ S -}"#, - ); -} - -#[test] -fn coerce_unsize_super_trait_cycle() { - check_no_mismatches( - r#" -//- minicore: coerce_unsized -trait A {} -trait B: C + A {} -trait C: B {} -trait D: C - -struct S; -impl A for S {} -impl B for S {} -impl C for S {} -impl D for S {} - -fn test() { - let obj: &dyn D = &S; - let obj: &dyn A = &S; -} -"#, - ); -} - -#[test] -fn coerce_unsize_generic() { - // FIXME: fix the type mismatches here - check( - r#" -//- minicore: coerce_unsized -struct Foo { t: T }; -struct Bar(Foo); - -fn test() { - let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; - //^^^^^^^^^ expected [usize], got [usize; 3] - let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); - //^^^^^^^^^ expected [usize], got [usize; 3] -} -"#, - ); -} - -#[test] -fn coerce_unsize_apit() { - check( - r#" -//- minicore: coerce_unsized -trait Foo {} - -fn test(f: impl Foo, g: &(impl Foo + ?Sized)) { - let _: &dyn Foo = &f; - let _: &dyn Foo = g; - //^ expected &dyn Foo, got &impl Foo + ?Sized -} - "#, - ); -} - -#[test] -fn two_closures_lub() { - check_types( - r#" -fn foo(c: i32) { - let add = |a: i32, b: i32| a + b; - let sub = |a, b| a - b; - //^^^^^^^^^^^^ |i32, i32| -> i32 - if c > 42 { add } else { sub }; - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fn(i32, i32) -> i32 -} - "#, - ) -} - -#[test] -fn match_diverging_branch_1() { - check_types( - r#" -enum Result { Ok(T), Err } -fn parse() -> T { loop {} } - -fn test() -> i32 { - let a = match parse() { - Ok(val) => val, - Err => return 0, - }; - a - //^ i32 -} - "#, - ) -} - -#[test] -fn match_diverging_branch_2() { - // same as 1 except for order of branches - check_types( - r#" -enum Result { Ok(T), Err } -fn parse() -> T { loop {} } - -fn test() -> i32 { - let a = match parse() { - Err => return 0, - Ok(val) => val, - }; - a - //^ i32 -} - "#, - ) -} - -#[test] -fn panic_macro() { - check_no_mismatches( - r#" -mod panic { - #[macro_export] - pub macro panic_2015 { - () => ( - $crate::panicking::panic() - ), - } -} - -mod panicking { - pub fn panic() -> ! { loop {} } -} - -#[rustc_builtin_macro = "core_panic"] -macro_rules! panic { - // Expands to either `$crate::panic::panic_2015` or `$crate::panic::panic_2021` - // depending on the edition of the caller. - ($($arg:tt)*) => { - /* compiler built-in */ - }; -} - -fn main() { - panic!() -} - "#, - ); -} - -#[test] -fn coerce_unsize_expected_type_1() { - check_no_mismatches( - r#" -//- minicore: coerce_unsized -fn main() { - let foo: &[u32] = &[1, 2]; - let foo: &[u32] = match true { - true => &[1, 2], - false => &[1, 2, 3], - }; - let foo: &[u32] = if true { - &[1, 2] - } else { - &[1, 2, 3] - }; -} - "#, - ); -} - -#[test] -fn coerce_unsize_expected_type_2() { - check_no_mismatches( - r#" -//- minicore: coerce_unsized -struct InFile; -impl InFile { - fn with_value(self, value: U) -> InFile { InFile } -} -struct RecordField; -trait AstNode {} -impl AstNode for RecordField {} - -fn takes_dyn(it: InFile<&dyn AstNode>) {} - -fn test() { - let x: InFile<()> = InFile; - let n = &RecordField; - takes_dyn(x.with_value(n)); -} - "#, - ); -} - -#[test] -fn coerce_unsize_expected_type_3() { - check_no_mismatches( - r#" -//- minicore: coerce_unsized -enum Option { Some(T), None } -struct RecordField; -trait AstNode {} -impl AstNode for RecordField {} - -fn takes_dyn(it: Option<&dyn AstNode>) {} - -fn test() { - let x: InFile<()> = InFile; - let n = &RecordField; - takes_dyn(Option::Some(n)); -} - "#, - ); -} - -#[test] -fn coerce_unsize_expected_type_4() { - check_no_mismatches( - r#" -//- minicore: coerce_unsized -use core::{marker::Unsize, ops::CoerceUnsized}; - -struct B(*const T); -impl B { - fn new(t: T) -> Self { B(&t) } -} - -impl, U: ?Sized> CoerceUnsized> for B {} - -fn test() { - let _: B<[isize]> = B::new({ [1, 2, 3] }); -} - "#, - ); -} - -#[test] -fn coerce_array_elems_lub() { - check_no_mismatches( - r#" -fn f() {} -fn g() {} - -fn test() { - [f, g]; -} - "#, - ); -} - -#[test] -fn coerce_type_var() { - check_types( - r#" -//- minicore: from, coerce_unsized -fn test() { - let x = (); - let _: &() = &x.into(); -} //^^^^^^^^ () -"#, - ) -} - -#[test] -fn coerce_overloaded_binary_op_rhs() { - check_types( - r#" -//- minicore: deref, add - -struct String {} -impl core::ops::Deref for String { type Target = str; } - -impl core::ops::Add<&str> for String { - type Output = String; -} - -fn test() { - let s1 = String {}; - let s2 = String {}; - s1 + &s2; - //^^^^^^^^ String -} - - "#, - ); -} - -#[test] -fn assign_coerce_struct_fields() { - check_no_mismatches( - r#" -//- minicore: coerce_unsized -struct S; -trait Tr {} -impl Tr for S {} -struct V { t: T } - -fn main() { - let a: V<&dyn Tr>; - a = V { t: &S }; - - let mut a: V<&dyn Tr> = V { t: &S }; - a = V { t: &S }; -} - "#, - ); -} - -#[test] -fn destructuring_assign_coerce_struct_fields() { - check( - r#" -//- minicore: coerce_unsized -struct S; -trait Tr {} -impl Tr for S {} -struct V { t: T } - -fn main() { - let a: V<&dyn Tr>; - (a,) = V { t: &S }; - //^^^^expected V<&S>, got (V<&dyn Tr>,) - - let mut a: V<&dyn Tr> = V { t: &S }; - (a,) = V { t: &S }; - //^^^^expected V<&S>, got (V<&dyn Tr>,) -} - "#, - ); -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs deleted file mode 100644 index f00fa97294877..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs +++ /dev/null @@ -1,75 +0,0 @@ -use super::check; - -#[test] -fn function_return_type_mismatch_1() { - check( - r#" -fn test() -> &'static str { - 5 - //^ expected &str, got i32 -} -"#, - ); -} - -#[test] -fn function_return_type_mismatch_2() { - check( - r#" -fn test(x: bool) -> &'static str { - if x { - return 1; - //^ expected &str, got i32 - } - "ok" -} -"#, - ); -} - -#[test] -fn function_return_type_mismatch_3() { - check( - r#" -fn test(x: bool) -> &'static str { - if x { - return "ok"; - } - 1 - //^ expected &str, got i32 -} -"#, - ); -} - -#[test] -fn function_return_type_mismatch_4() { - check( - r#" -fn test(x: bool) -> &'static str { - if x { - "ok" - } else { - 1 - //^ expected &str, got i32 - } -} -"#, - ); -} - -#[test] -fn function_return_type_mismatch_5() { - check( - r#" -fn test(x: bool) -> &'static str { - if x { - 1 - //^ expected &str, got i32 - } else { - "ok" - } -} -"#, - ); -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs deleted file mode 100644 index 240942e488d7d..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs +++ /dev/null @@ -1,176 +0,0 @@ -use super::check_types_source_code; - -#[test] -fn qualify_path_to_submodule() { - check_types_source_code( - r#" -mod foo { - pub struct Foo; -} - -fn bar() { - let foo: foo::Foo = foo::Foo; - foo; -} //^^^ foo::Foo - -"#, - ); -} - -#[test] -fn omit_default_type_parameters() { - check_types_source_code( - r#" -struct Foo { t: T } -fn main() { - let foo = Foo { t: 5u8 }; - foo; -} //^^^ Foo -"#, - ); - - check_types_source_code( - r#" -struct Foo { k: K, t: T } -fn main() { - let foo = Foo { k: 400, t: 5u8 }; - foo; -} //^^^ Foo -"#, - ); -} - -#[test] -fn render_raw_ptr_impl_ty() { - check_types_source_code( - r#" -//- minicore: sized -trait Unpin {} -fn foo() -> *const (impl Unpin + Sized) { loop {} } -fn main() { - let foo = foo(); - foo; -} //^^^ *const impl Unpin -"#, - ); -} - -#[test] -fn render_dyn_for_ty() { - // FIXME - check_types_source_code( - r#" -trait Foo<'a> {} - -fn foo(foo: &dyn for<'a> Foo<'a>) {} - // ^^^ &dyn Foo -"#, - ); -} - -#[test] -fn sized_bounds_apit() { - check_types_source_code( - r#" -//- minicore: sized -trait Foo {} -trait Bar {} -struct S; -fn test( - a: impl Foo, - b: impl Foo + Sized, - c: &(impl Foo + ?Sized), - d: S, - ref_any: &impl ?Sized, - empty: impl, -) { - a; - //^ impl Foo - b; - //^ impl Foo - c; - //^ &impl Foo + ?Sized - d; - //^ S - ref_any; - //^^^^^^^ &impl ?Sized - empty; -} //^^^^^ impl Sized -"#, - ); -} - -#[test] -fn sized_bounds_rpit() { - check_types_source_code( - r#" -//- minicore: sized -trait Foo {} -fn foo1() -> impl Foo { loop {} } -fn foo2() -> impl Foo + Sized { loop {} } -fn foo3() -> impl Foo + ?Sized { loop {} } -fn test() { - let foo = foo1(); - foo; - //^^^ impl Foo - let foo = foo2(); - foo; - //^^^ impl Foo - let foo = foo3(); - foo; -} //^^^ impl Foo + ?Sized -"#, - ); -} - -#[test] -fn parenthesize_ptr_rpit_sized_bounds() { - check_types_source_code( - r#" -//- minicore: sized -trait Foo {} -fn foo1() -> *const impl Foo { loop {} } -fn foo2() -> *const (impl Foo + Sized) { loop {} } -fn foo3() -> *const (impl Sized + Foo) { loop {} } -fn foo4() -> *const (impl Foo + ?Sized) { loop {} } -fn foo5() -> *const (impl ?Sized + Foo) { loop {} } -fn test() { - let foo = foo1(); - foo; - //^^^ *const impl Foo - let foo = foo2(); - foo; - //^^^ *const impl Foo - let foo = foo3(); - foo; - //^^^ *const impl Foo - let foo = foo4(); - foo; - //^^^ *const (impl Foo + ?Sized) - let foo = foo5(); - foo; -} //^^^ *const (impl Foo + ?Sized) -"#, - ); -} - -#[test] -fn sized_bounds_impl_traits_in_fn_signature() { - check_types_source_code( - r#" -//- minicore: sized -trait Foo {} -fn test( - a: fn(impl Foo) -> impl Foo, - b: fn(impl Foo + Sized) -> impl Foo + Sized, - c: fn(&(impl Foo + ?Sized)) -> &(impl Foo + ?Sized), -) { - a; - //^ fn(impl Foo) -> impl Foo - b; - //^ fn(impl Foo) -> impl Foo - c; -} //^ fn(&impl Foo + ?Sized) -> &impl Foo + ?Sized -"#, - ); -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs deleted file mode 100644 index 3e08e83e89a3e..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ /dev/null @@ -1,51 +0,0 @@ -use std::sync::Arc; - -use base_db::{fixture::WithFixture, SourceDatabaseExt}; - -use crate::{db::HirDatabase, test_db::TestDB}; - -use super::visit_module; - -#[test] -fn typing_whitespace_inside_a_function_should_not_invalidate_types() { - let (mut db, pos) = TestDB::with_position( - " - //- /lib.rs - fn foo() -> i32 { - $01 + 1 - } - ", - ); - { - let events = db.log_executed(|| { - let module = db.module_for_file(pos.file_id); - let crate_def_map = module.def_map(&db); - visit_module(&db, &crate_def_map, module.local_id, &mut |def| { - db.infer(def); - }); - }); - assert!(format!("{:?}", events).contains("infer")) - } - - let new_text = " - fn foo() -> i32 { - 1 - + - 1 - } - " - .to_string(); - - db.set_file_text(pos.file_id, Arc::new(new_text)); - - { - let events = db.log_executed(|| { - let module = db.module_for_file(pos.file_id); - let crate_def_map = module.def_map(&db); - visit_module(&db, &crate_def_map, module.local_id, &mut |def| { - db.infer(def); - }); - }); - assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events) - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs deleted file mode 100644 index a1ab6060e790c..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs +++ /dev/null @@ -1,1338 +0,0 @@ -use expect_test::expect; -use test_utils::{bench, bench_fixture, skip_slow_tests}; - -use crate::tests::check_infer_with_mismatches; - -use super::{check_infer, check_types}; - -#[test] -fn cfg_impl_def() { - check_types( - r#" -//- /main.rs crate:main deps:foo cfg:test -use foo::S as T; -struct S; - -#[cfg(test)] -impl S { - fn foo1(&self) -> i32 { 0 } -} - -#[cfg(not(test))] -impl S { - fn foo2(&self) -> i32 { 0 } -} - -fn test() { - let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4()); - t; -} //^ (i32, {unknown}, i32, {unknown}) - -//- /foo.rs crate:foo -pub struct S; - -#[cfg(not(test))] -impl S { - pub fn foo3(&self) -> i32 { 0 } -} - -#[cfg(test)] -impl S { - pub fn foo4(&self) -> i32 { 0 } -} -"#, - ); -} - -#[test] -fn infer_macros_expanded() { - check_infer( - r#" - struct Foo(Vec); - - macro_rules! foo { - ($($item:expr),*) => { - { - Foo(vec![$($item,)*]) - } - }; - } - - fn main() { - let x = foo!(1,2); - } - "#, - expect![[r#" - !0..17 '{Foo(v...,2,])}': Foo - !1..4 'Foo': Foo({unknown}) -> Foo - !1..16 'Foo(vec![1,2,])': Foo - !5..15 'vec![1,2,]': {unknown} - 155..181 '{ ...,2); }': () - 165..166 'x': Foo - "#]], - ); -} - -#[test] -fn infer_legacy_textual_scoped_macros_expanded() { - check_infer( - r#" - struct Foo(Vec); - - #[macro_use] - mod m { - macro_rules! foo { - ($($item:expr),*) => { - { - Foo(vec![$($item,)*]) - } - }; - } - } - - fn main() { - let x = foo!(1,2); - let y = crate::foo!(1,2); - } - "#, - expect![[r#" - !0..17 '{Foo(v...,2,])}': Foo - !1..4 'Foo': Foo({unknown}) -> Foo - !1..16 'Foo(vec![1,2,])': Foo - !5..15 'vec![1,2,]': {unknown} - 194..250 '{ ...,2); }': () - 204..205 'x': Foo - 227..228 'y': {unknown} - 231..247 'crate:...!(1,2)': {unknown} - "#]], - ); -} - -#[test] -fn infer_path_qualified_macros_expanded() { - check_infer( - r#" - #[macro_export] - macro_rules! foo { - () => { 42i32 } - } - - mod m { - pub use super::foo as bar; - } - - fn main() { - let x = crate::foo!(); - let y = m::bar!(); - } - "#, - expect![[r#" - !0..5 '42i32': i32 - !0..5 '42i32': i32 - 110..163 '{ ...!(); }': () - 120..121 'x': i32 - 147..148 'y': i32 - "#]], - ); -} - -#[test] -fn expr_macro_def_expanded_in_various_places() { - check_infer( - r#" - macro spam() { - 1isize - } - - fn spam() { - spam!(); - (spam!()); - spam!().spam(spam!()); - for _ in spam!() {} - || spam!(); - while spam!() {} - break spam!(); - return spam!(); - match spam!() { - _ if spam!() => spam!(), - } - spam!()(spam!()); - Spam { spam: spam!() }; - spam!()[spam!()]; - await spam!(); - spam!() as usize; - &spam!(); - -spam!(); - spam!()..spam!(); - spam!() + spam!(); - } - "#, - expect![[r#" - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - 39..442 '{ ...!(); }': () - 73..94 'spam!(...am!())': {unknown} - 100..119 'for _ ...!() {}': () - 104..105 '_': {unknown} - 117..119 '{}': () - 124..134 '|| spam!()': || -> isize - 140..156 'while ...!() {}': () - 154..156 '{}': () - 161..174 'break spam!()': ! - 180..194 'return spam!()': ! - 200..254 'match ... }': isize - 224..225 '_': isize - 259..275 'spam!(...am!())': {unknown} - 281..303 'Spam {...m!() }': {unknown} - 309..325 'spam!(...am!()]': {unknown} - 350..366 'spam!(... usize': usize - 372..380 '&spam!()': &isize - 386..394 '-spam!()': isize - 400..416 'spam!(...pam!()': {unknown} - 422..439 'spam!(...pam!()': isize - "#]], - ); -} - -#[test] -fn expr_macro_rules_expanded_in_various_places() { - check_infer( - r#" - macro_rules! spam { - () => (1isize); - } - - fn spam() { - spam!(); - (spam!()); - spam!().spam(spam!()); - for _ in spam!() {} - || spam!(); - while spam!() {} - break spam!(); - return spam!(); - match spam!() { - _ if spam!() => spam!(), - } - spam!()(spam!()); - Spam { spam: spam!() }; - spam!()[spam!()]; - await spam!(); - spam!() as usize; - &spam!(); - -spam!(); - spam!()..spam!(); - spam!() + spam!(); - } - "#, - expect![[r#" - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize - 53..456 '{ ...!(); }': () - 87..108 'spam!(...am!())': {unknown} - 114..133 'for _ ...!() {}': () - 118..119 '_': {unknown} - 131..133 '{}': () - 138..148 '|| spam!()': || -> isize - 154..170 'while ...!() {}': () - 168..170 '{}': () - 175..188 'break spam!()': ! - 194..208 'return spam!()': ! - 214..268 'match ... }': isize - 238..239 '_': isize - 273..289 'spam!(...am!())': {unknown} - 295..317 'Spam {...m!() }': {unknown} - 323..339 'spam!(...am!()]': {unknown} - 364..380 'spam!(... usize': usize - 386..394 '&spam!()': &isize - 400..408 '-spam!()': isize - 414..430 'spam!(...pam!()': {unknown} - 436..453 'spam!(...pam!()': isize - "#]], - ); -} - -#[test] -fn expr_macro_expanded_in_stmts() { - check_infer( - r#" - macro_rules! id { ($($es:tt)*) => { $($es)* } } - fn foo() { - id! { let a = (); } - } - "#, - expect![[r#" - !0..8 'leta=();': () - !3..4 'a': () - !5..7 '()': () - 57..84 '{ ...); } }': () - "#]], - ); -} - -#[test] -fn recurisve_macro_expanded_in_stmts() { - check_infer( - r#" - macro_rules! ng { - ([$($tts:tt)*]) => { - $($tts)*; - }; - ([$($tts:tt)*] $head:tt $($rest:tt)*) => { - ng! { - [$($tts)* $head] $($rest)* - } - }; - } - fn foo() { - ng!([] let a = 3); - let b = a; - } - "#, - expect![[r#" - !0..7 'leta=3;': () - !0..13 'ng!{[leta=3]}': () - !0..13 'ng!{[leta=]3}': () - !0..13 'ng!{[leta]=3}': () - !0..13 'ng!{[let]a=3}': () - !3..4 'a': i32 - !5..6 '3': i32 - 196..237 '{ ...= a; }': () - 229..230 'b': i32 - 233..234 'a': i32 - "#]], - ); -} - -#[test] -fn recursive_inner_item_macro_rules() { - check_infer( - r#" - macro_rules! mac { - () => { mac!($)}; - ($x:tt) => { macro_rules! blub { () => { 1 }; } }; - } - fn foo() { - mac!(); - let a = blub!(); - } - "#, - expect![[r#" - !0..1 '1': i32 - !0..7 'mac!($)': () - !0..26 'macro_...>{1};}': () - 107..143 '{ ...!(); }': () - 129..130 'a': i32 - "#]], - ); -} - -#[test] -fn infer_macro_defining_block_with_items() { - check_infer( - r#" - macro_rules! foo { - () => {{ - fn bar() -> usize { 0 } - bar() - }}; - } - fn main() { - let _a = foo!(); - } - "#, - expect![[r#" - !15..18 '{0}': usize - !16..17 '0': usize - !0..24 '{fnbar...bar()}': usize - !18..21 'bar': fn bar() -> usize - !18..23 'bar()': usize - 98..122 '{ ...!(); }': () - 108..110 '_a': usize - "#]], - ); -} - -#[test] -fn infer_type_value_macro_having_same_name() { - check_infer( - r#" - #[macro_export] - macro_rules! foo { - () => { - mod foo { - pub use super::foo; - } - }; - ($x:tt) => { - $x - }; - } - - foo!(); - - fn foo() { - let foo = foo::foo!(42i32); - } - "#, - expect![[r#" - !0..5 '42i32': i32 - 170..205 '{ ...32); }': () - 180..183 'foo': i32 - "#]], - ); -} - -#[test] -fn processes_impls_generated_by_macros() { - check_types( - r#" -macro_rules! m { - ($ident:ident) => (impl Trait for $ident {}) -} -trait Trait { fn foo(self) -> u128 { 0 } } -struct S; -m!(S); -fn test() { S.foo(); } - //^^^^^^^ u128 -"#, - ); -} - -#[test] -fn infer_assoc_items_generated_by_macros() { - check_types( - r#" -macro_rules! m { - () => (fn foo(&self) -> u128 {0}) -} -struct S; -impl S { - m!(); -} - -fn test() { S.foo(); } - //^^^^^^^ u128 -"#, - ); -} - -#[test] -fn infer_assoc_items_generated_by_macros_chain() { - check_types( - r#" -macro_rules! m_inner { - () => {fn foo(&self) -> u128 {0}} -} -macro_rules! m { - () => {m_inner!();} -} - -struct S; -impl S { - m!(); -} - -fn test() { S.foo(); } - //^^^^^^^ u128 -"#, - ); -} - -#[test] -fn infer_macro_with_dollar_crate_is_correct_in_expr() { - check_types( - r#" -//- /main.rs crate:main deps:foo -fn test() { - let x = (foo::foo!(1), foo::foo!(2)); - x; -} //^ (i32, usize) - -//- /lib.rs crate:foo -#[macro_export] -macro_rules! foo { - (1) => { $crate::bar!() }; - (2) => { 1 + $crate::baz() }; -} - -#[macro_export] -macro_rules! bar { - () => { 42 } -} - -pub fn baz() -> usize { 31usize } -"#, - ); -} - -#[test] -fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() { - check_types( - r#" -//- /main.rs crate:main deps:foo -use foo::Trait; - -fn test() { - let msg = foo::Message(foo::MessageRef); - let r = msg.deref(); - r; - //^ &MessageRef -} - -//- /lib.rs crate:foo -pub struct MessageRef; -pub struct Message(MessageRef); - -pub trait Trait { - type Target; - fn deref(&self) -> &Self::Target; -} - -#[macro_export] -macro_rules! expand { - () => { - impl Trait for Message { - type Target = $crate::MessageRef; - fn deref(&self) -> &Self::Target { - &self.0 - } - } - } -} - -expand!(); -"#, - ); -} - -#[test] -fn infer_macro_with_dollar_crate_in_def_site() { - check_types( - r#" -//- /main.rs crate:main deps:foo -use foo::expand; - -macro_rules! list { - ($($tt:tt)*) => { $($tt)* } -} - -fn test() { - let r = expand!(); - r; - //^ u128 -} - -//- /lib.rs crate:foo -#[macro_export] -macro_rules! expand { - () => { list!($crate::m!()) }; -} - -#[macro_export] -macro_rules! m { - () => { 0u128 }; -} -"#, - ); -} - -#[test] -fn infer_type_value_non_legacy_macro_use_as() { - check_infer( - r#" - mod m { - macro_rules! _foo { - ($x:ident) => { type $x = u64; } - } - pub(crate) use _foo as foo; - } - - m::foo!(foo); - use foo as bar; - fn f() -> bar { 0 } - fn main() { - let _a = f(); - } - "#, - expect![[r#" - 158..163 '{ 0 }': u64 - 160..161 '0': u64 - 174..196 '{ ...f(); }': () - 184..186 '_a': u64 - 190..191 'f': fn f() -> u64 - 190..193 'f()': u64 - "#]], - ); -} - -#[test] -fn infer_local_macro() { - check_infer( - r#" - fn main() { - macro_rules! foo { - () => { 1usize } - } - let _a = foo!(); - } - "#, - expect![[r#" - !0..6 '1usize': usize - 10..89 '{ ...!(); }': () - 74..76 '_a': usize - "#]], - ); -} - -#[test] -fn infer_local_inner_macros() { - check_types( - r#" -//- /main.rs crate:main deps:foo -fn test() { - let x = foo::foo!(1); - x; -} //^ i32 - -//- /lib.rs crate:foo -#[macro_export(local_inner_macros)] -macro_rules! foo { - (1) => { bar!() }; -} - -#[macro_export] -macro_rules! bar { - () => { 42 } -} - -"#, - ); -} - -#[test] -fn infer_builtin_macros_line() { - check_infer( - r#" - #[rustc_builtin_macro] - macro_rules! line {() => {}} - - fn main() { - let x = line!(); - } - "#, - expect![[r#" - !0..1 '0': i32 - 63..87 '{ ...!(); }': () - 73..74 'x': i32 - "#]], - ); -} - -#[test] -fn infer_builtin_macros_file() { - check_infer( - r#" - #[rustc_builtin_macro] - macro_rules! file {() => {}} - - fn main() { - let x = file!(); - } - "#, - expect![[r#" - !0..2 '""': &str - 63..87 '{ ...!(); }': () - 73..74 'x': &str - "#]], - ); -} - -#[test] -fn infer_builtin_macros_column() { - check_infer( - r#" - #[rustc_builtin_macro] - macro_rules! column {() => {}} - - fn main() { - let x = column!(); - } - "#, - expect![[r#" - !0..1 '0': i32 - 65..91 '{ ...!(); }': () - 75..76 'x': i32 - "#]], - ); -} - -#[test] -fn infer_builtin_macros_concat() { - check_infer( - r#" - #[rustc_builtin_macro] - macro_rules! concat {() => {}} - - fn main() { - let x = concat!("hello", concat!("world", "!")); - } - "#, - expect![[r#" - !0..13 '"helloworld!"': &str - 65..121 '{ ...")); }': () - 75..76 'x': &str - "#]], - ); -} - -#[test] -fn infer_builtin_macros_include() { - check_types( - r#" -//- /main.rs -#[rustc_builtin_macro] -macro_rules! include {() => {}} - -include!("foo.rs"); - -fn main() { - bar(); -} //^^^^^ u32 - -//- /foo.rs -fn bar() -> u32 {0} -"#, - ); -} - -#[test] -fn infer_builtin_macros_include_expression() { - check_types( - r#" -//- /main.rs -#[rustc_builtin_macro] -macro_rules! include {() => {}} -fn main() { - let i = include!("bla.rs"); - i; - //^ i32 -} -//- /bla.rs -0 - "#, - ) -} - -#[test] -fn infer_builtin_macros_include_child_mod() { - check_types( - r#" -//- /main.rs -#[rustc_builtin_macro] -macro_rules! include {() => {}} - -include!("f/foo.rs"); - -fn main() { - bar::bar(); -} //^^^^^^^^^^ u32 - -//- /f/foo.rs -pub mod bar; - -//- /f/bar.rs -pub fn bar() -> u32 {0} -"#, - ); -} - -#[test] -fn infer_builtin_macros_include_str() { - check_types( - r#" -//- /main.rs -#[rustc_builtin_macro] -macro_rules! include_str {() => {}} - -fn main() { - let a = include_str!("foo.rs"); - a; -} //^ &str - -//- /foo.rs -hello -"#, - ); -} - -#[test] -fn infer_builtin_macros_include_str_with_lazy_nested() { - check_types( - r#" -//- /main.rs -#[rustc_builtin_macro] -macro_rules! concat {() => {}} -#[rustc_builtin_macro] -macro_rules! include_str {() => {}} - -macro_rules! m { - ($x:expr) => { - concat!("foo", $x) - }; -} - -fn main() { - let a = include_str!(m!(".rs")); - a; -} //^ &str - -//- /foo.rs -hello -"#, - ); -} - -#[test] -fn benchmark_include_macro() { - if skip_slow_tests() { - return; - } - let data = bench_fixture::big_struct(); - let fixture = r#" -//- /main.rs -#[rustc_builtin_macro] -macro_rules! include {() => {}} - -include!("foo.rs"); - -fn main() { - RegisterBlock { }; - //^^^^^^^^^^^^^^^^^ RegisterBlock -} - "#; - let fixture = format!("{}\n//- /foo.rs\n{}", fixture, data); - - { - let _b = bench("include macro"); - check_types(&fixture); - } -} - -#[test] -fn infer_builtin_macros_include_concat() { - check_types( - r#" -//- /main.rs -#[rustc_builtin_macro] -macro_rules! include {() => {}} - -#[rustc_builtin_macro] -macro_rules! concat {() => {}} - -include!(concat!("f", "oo.rs")); - -fn main() { - bar(); -} //^^^^^ u32 - -//- /foo.rs -fn bar() -> u32 {0} -"#, - ); -} - -#[test] -fn infer_builtin_macros_include_concat_with_bad_env_should_failed() { - check_types( - r#" -//- /main.rs -#[rustc_builtin_macro] -macro_rules! include {() => {}} - -#[rustc_builtin_macro] -macro_rules! concat {() => {}} - -#[rustc_builtin_macro] -macro_rules! env {() => {}} - -include!(concat!(env!("OUT_DIR"), "/foo.rs")); - -fn main() { - bar(); -} //^^^^^ {unknown} - -//- /foo.rs -fn bar() -> u32 {0} -"#, - ); -} - -#[test] -fn infer_builtin_macros_include_itself_should_failed() { - check_types( - r#" -#[rustc_builtin_macro] -macro_rules! include {() => {}} - -include!("main.rs"); - -fn main() { - 0; -} //^ i32 -"#, - ); -} - -#[test] -fn infer_builtin_macros_concat_with_lazy() { - check_infer( - r#" - macro_rules! hello {() => {"hello"}} - - #[rustc_builtin_macro] - macro_rules! concat {() => {}} - - fn main() { - let x = concat!(hello!(), concat!("world", "!")); - } - "#, - expect![[r#" - !0..13 '"helloworld!"': &str - 103..160 '{ ...")); }': () - 113..114 'x': &str - "#]], - ); -} - -#[test] -fn infer_builtin_macros_env() { - check_infer( - r#" - //- /main.rs env:foo=bar - #[rustc_builtin_macro] - macro_rules! env {() => {}} - - fn main() { - let x = env!("foo"); - } - "#, - expect![[r#" - !0..22 '"__RA_...TED__"': &str - 62..90 '{ ...o"); }': () - 72..73 'x': &str - "#]], - ); -} - -#[test] -fn infer_derive_clone_simple() { - check_types( - r#" -//- minicore: derive, clone -#[derive(Clone)] -struct S; -fn test() { - S.clone(); -} //^^^^^^^^^ S -"#, - ); -} - -#[test] -fn infer_derive_clone_with_params() { - check_types( - r#" -//- minicore: clone, derive -#[derive(Clone)] -struct S; -#[derive(Clone)] -struct Wrapper(T); -struct NonClone; -fn test() { - let x = (Wrapper(S).clone(), Wrapper(NonClone).clone()); - x; - //^ (Wrapper, {unknown}) -} -"#, - ); -} - -#[test] -fn infer_custom_derive_simple() { - // FIXME: this test current now do nothing - check_types( - r#" -//- minicore: derive -use foo::Foo; - -#[derive(Foo)] -struct S{} - -fn test() { - S{}; -} //^^^ S -"#, - ); -} - -#[test] -fn macro_in_arm() { - check_infer( - r#" - macro_rules! unit { - () => { () }; - } - - fn main() { - let x = match () { - unit!() => 92u32, - }; - } - "#, - expect![[r#" - !0..2 '()': () - 51..110 '{ ... }; }': () - 61..62 'x': u32 - 65..107 'match ... }': u32 - 71..73 '()': () - 95..100 '92u32': u32 - "#]], - ); -} - -#[test] -fn macro_in_type_alias_position() { - check_infer( - r#" - macro_rules! U32 { - () => { u32 }; - } - - trait Foo { - type Ty; - } - - impl Foo for T { - type Ty = U32!(); - } - - type TayTo = U32!(); - - fn testy() { - let a: <() as Foo>::Ty; - let b: TayTo; - } - "#, - expect![[r#" - 147..196 '{ ...yTo; }': () - 157..158 'a': u32 - 185..186 'b': u32 - "#]], - ); -} - -#[test] -fn nested_macro_in_type_alias_position() { - check_infer( - r#" - macro_rules! U32Inner2 { - () => { u32 }; - } - - macro_rules! U32Inner1 { - () => { U32Inner2!() }; - } - - macro_rules! U32 { - () => { U32Inner1!() }; - } - - trait Foo { - type Ty; - } - - impl Foo for T { - type Ty = U32!(); - } - - type TayTo = U32!(); - - fn testy() { - let a: <() as Foo>::Ty; - let b: TayTo; - } - "#, - expect![[r#" - 259..308 '{ ...yTo; }': () - 269..270 'a': u32 - 297..298 'b': u32 - "#]], - ); -} - -#[test] -fn macros_in_type_alias_position_generics() { - check_infer( - r#" - struct Foo(A, B); - - macro_rules! U32 { - () => { u32 }; - } - - macro_rules! Bar { - () => { Foo }; - } - - trait Moo { - type Ty; - } - - impl Moo for T { - type Ty = Bar!(); - } - - type TayTo = Bar!(); - - fn main() { - let a: <() as Moo>::Ty; - let b: TayTo; - } - "#, - expect![[r#" - 228..277 '{ ...yTo; }': () - 238..239 'a': Foo - 266..267 'b': Foo - "#]], - ); -} - -#[test] -fn macros_in_type_position() { - check_infer( - r#" - struct Foo(A, B); - - macro_rules! U32 { - () => { u32 }; - } - - macro_rules! Bar { - () => { Foo }; - } - - fn main() { - let a: Bar!(); - } - "#, - expect![[r#" - 133..155 '{ ...!(); }': () - 143..144 'a': Foo - "#]], - ); -} - -#[test] -fn macros_in_type_generics() { - check_infer( - r#" - struct Foo(A, B); - - macro_rules! U32 { - () => { u32 }; - } - - macro_rules! Bar { - () => { Foo }; - } - - trait Moo { - type Ty; - } - - impl Moo for T { - type Ty = Foo; - } - - type TayTo = Foo; - - fn main() { - let a: <() as Moo>::Ty; - let b: TayTo; - } - "#, - expect![[r#" - 254..303 '{ ...yTo; }': () - 264..265 'a': Foo, Foo> - 292..293 'b': Foo, u32> - "#]], - ); -} - -#[test] -fn infinitely_recursive_macro_type() { - check_infer( - r#" - struct Bar(T, X); - - macro_rules! Foo { - () => { Foo!() } - } - - macro_rules! U32 { - () => { u32 } - } - - type A = Foo!(); - type B = Bar; - - fn main() { - let a: A; - let b: B; - } - "#, - expect![[r#" - 166..197 '{ ...: B; }': () - 176..177 'a': {unknown} - 190..191 'b': Bar<{unknown}, u32> - "#]], - ); -} - -#[test] -fn cfg_tails() { - check_infer_with_mismatches( - r#" -//- /lib.rs crate:foo cfg:feature=foo -struct S {} - -impl S { - fn new2(bar: u32) -> Self { - #[cfg(feature = "foo")] - { Self { } } - #[cfg(not(feature = "foo"))] - { Self { } } - } -} -"#, - expect![[r#" - 34..37 'bar': u32 - 52..170 '{ ... }': S - 62..106 '#[cfg(... { } }': S - 96..104 'Self { }': S - "#]], - ); -} - -#[test] -fn infer_in_unexpandable_attr_proc_macro_1() { - check_types( - r#" -//- /main.rs crate:main deps:mac -#[mac::attr_macro] -fn foo() { - let xxx = 1; - //^^^ i32 -} - -//- /mac.rs crate:mac -#![crate_type="proc-macro"] -#[proc_macro_attribute] -pub fn attr_macro() {} -"#, - ); -} - -#[test] -fn infer_in_unexpandable_attr_proc_macro_in_impl() { - check_types( - r#" -//- /main.rs crate:main deps:mac -struct Foo; -impl Foo { - #[mac::attr_macro] - fn foo() { - let xxx = 1; - //^^^ i32 - } -} - -//- /mac.rs crate:mac -#![crate_type="proc-macro"] -#[proc_macro_attribute] -pub fn attr_macro() {} -"#, - ); -} - -#[test] -fn infer_in_unexpandable_attr_proc_macro_in_trait() { - check_types( - r#" -//- /main.rs crate:main deps:mac -trait Foo { - #[mac::attr_macro] - fn foo() { - let xxx = 1; - //^^^ i32 - } -} - -//- /mac.rs crate:mac -#![crate_type="proc-macro"] -#[proc_macro_attribute] -pub fn attr_macro() {} -"#, - ); -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs deleted file mode 100644 index 68463dc068bcf..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs +++ /dev/null @@ -1,1792 +0,0 @@ -use expect_test::expect; - -use crate::tests::check; - -use super::{check_infer, check_no_mismatches, check_types}; - -#[test] -fn infer_slice_method() { - check_types( - r#" -impl [T] { - fn foo(&self) -> T { - loop {} - } -} - -fn test(x: &[u8]) { - <[_]>::foo(x); - //^^^^^^^^^^^^^ u8 -} - "#, - ); -} - -#[test] -fn cross_crate_primitive_method() { - check_types( - r#" -//- /main.rs crate:main deps:other_crate -fn test() { - let x = 1f32; - x.foo(); -} //^^^^^^^ f32 - -//- /lib.rs crate:other_crate -mod foo { - impl f32 { - pub fn foo(self) -> f32 { 0. } - } -} -"#, - ); -} - -#[test] -fn infer_array_inherent_impl() { - check_types( - r#" -impl [T; N] { - fn foo(&self) -> T { - loop {} - } -} -fn test(x: &[u8; 0]) { - <[_; 0]>::foo(x); - //^^^^^^^^^^^^^^^^ u8 -} - "#, - ); -} - -#[test] -fn infer_associated_method_struct() { - check_infer( - r#" - struct A { x: u32 } - - impl A { - fn new() -> A { - A { x: 0 } - } - } - fn test() { - let a = A::new(); - a.x; - } - "#, - expect![[r#" - 48..74 '{ ... }': A - 58..68 'A { x: 0 }': A - 65..66 '0': u32 - 87..121 '{ ...a.x; }': () - 97..98 'a': A - 101..107 'A::new': fn new() -> A - 101..109 'A::new()': A - 115..116 'a': A - 115..118 'a.x': u32 - "#]], - ); -} - -#[test] -fn infer_associated_method_struct_in_local_scope() { - check_infer( - r#" - fn mismatch() { - struct A; - - impl A { - fn from(_: i32, _: i32) -> Self { - A - } - } - - let _a = A::from(1, 2); - } - "#, - expect![[r#" - 14..146 '{ ... 2); }': () - 125..127 '_a': A - 130..137 'A::from': fn from(i32, i32) -> A - 130..143 'A::from(1, 2)': A - 138..139 '1': i32 - 141..142 '2': i32 - 60..61 '_': i32 - 68..69 '_': i32 - 84..109 '{ ... }': A - 98..99 'A': A - "#]], - ); -} - -#[test] -fn infer_associated_method_enum() { - check_infer( - r#" - enum A { B, C } - - impl A { - pub fn b() -> A { - A::B - } - pub fn c() -> A { - A::C - } - } - fn test() { - let a = A::b(); - a; - let c = A::c(); - c; - } - "#, - expect![[r#" - 46..66 '{ ... }': A - 56..60 'A::B': A - 87..107 '{ ... }': A - 97..101 'A::C': A - 120..177 '{ ... c; }': () - 130..131 'a': A - 134..138 'A::b': fn b() -> A - 134..140 'A::b()': A - 146..147 'a': A - 157..158 'c': A - 161..165 'A::c': fn c() -> A - 161..167 'A::c()': A - 173..174 'c': A - "#]], - ); -} - -#[test] -fn infer_associated_method_with_modules() { - check_infer( - r#" - mod a { - struct A; - impl A { pub fn thing() -> A { A {} }} - } - - mod b { - struct B; - impl B { pub fn thing() -> u32 { 99 }} - - mod c { - struct C; - impl C { pub fn thing() -> C { C {} }} - } - } - use b::c; - - fn test() { - let x = a::A::thing(); - let y = b::B::thing(); - let z = c::C::thing(); - } - "#, - expect![[r#" - 55..63 '{ A {} }': A - 57..61 'A {}': A - 125..131 '{ 99 }': u32 - 127..129 '99': u32 - 201..209 '{ C {} }': C - 203..207 'C {}': C - 240..324 '{ ...g(); }': () - 250..251 'x': A - 254..265 'a::A::thing': fn thing() -> A - 254..267 'a::A::thing()': A - 277..278 'y': u32 - 281..292 'b::B::thing': fn thing() -> u32 - 281..294 'b::B::thing()': u32 - 304..305 'z': C - 308..319 'c::C::thing': fn thing() -> C - 308..321 'c::C::thing()': C - "#]], - ); -} - -#[test] -fn infer_associated_method_generics() { - check_infer( - r#" - struct Gen { - val: T - } - - impl Gen { - pub fn make(val: T) -> Gen { - Gen { val } - } - } - - fn test() { - let a = Gen::make(0u32); - } - "#, - expect![[r#" - 63..66 'val': T - 81..108 '{ ... }': Gen - 91..102 'Gen { val }': Gen - 97..100 'val': T - 122..154 '{ ...32); }': () - 132..133 'a': Gen - 136..145 'Gen::make': fn make(u32) -> Gen - 136..151 'Gen::make(0u32)': Gen - 146..150 '0u32': u32 - "#]], - ); -} - -#[test] -fn infer_associated_method_generics_without_args() { - check_infer( - r#" - struct Gen { - val: T - } - - impl Gen { - pub fn make() -> Gen { - loop { } - } - } - - fn test() { - let a = Gen::::make(); - } - "#, - expect![[r#" - 75..99 '{ ... }': Gen - 85..93 'loop { }': ! - 90..93 '{ }': () - 113..148 '{ ...e(); }': () - 123..124 'a': Gen - 127..143 'Gen::<...::make': fn make() -> Gen - 127..145 'Gen::<...make()': Gen - "#]], - ); -} - -#[test] -fn infer_associated_method_generics_2_type_params_without_args() { - check_infer( - r#" - struct Gen { - val: T, - val2: U, - } - - impl Gen { - pub fn make() -> Gen { - loop { } - } - } - - fn test() { - let a = Gen::::make(); - } - "#, - expect![[r#" - 101..125 '{ ... }': Gen - 111..119 'loop { }': ! - 116..119 '{ }': () - 139..179 '{ ...e(); }': () - 149..150 'a': Gen - 153..174 'Gen::<...::make': fn make() -> Gen - 153..176 'Gen::<...make()': Gen - "#]], - ); -} - -#[test] -fn cross_crate_associated_method_call() { - check_types( - r#" -//- /main.rs crate:main deps:other_crate -fn test() { - let x = other_crate::foo::S::thing(); - x; -} //^ i128 - -//- /lib.rs crate:other_crate -pub mod foo { - pub struct S; - impl S { - pub fn thing() -> i128 { 0 } - } -} -"#, - ); -} - -#[test] -fn infer_trait_method_simple() { - // the trait implementation is intentionally incomplete -- it shouldn't matter - check_types( - r#" -trait Trait1 { - fn method(&self) -> u32; -} -struct S1; -impl Trait1 for S1 {} -trait Trait2 { - fn method(&self) -> i128; -} -struct S2; -impl Trait2 for S2 {} -fn test() { - S1.method(); - //^^^^^^^^^^^ u32 - S2.method(); // -> i128 - //^^^^^^^^^^^ i128 -} - "#, - ); -} - -#[test] -fn infer_trait_method_scoped() { - // the trait implementation is intentionally incomplete -- it shouldn't matter - check_types( - r#" -struct S; -mod foo { - pub trait Trait1 { - fn method(&self) -> u32; - } - impl Trait1 for super::S {} -} -mod bar { - pub trait Trait2 { - fn method(&self) -> i128; - } - impl Trait2 for super::S {} -} - -mod foo_test { - use super::S; - use super::foo::Trait1; - fn test() { - S.method(); - //^^^^^^^^^^ u32 - } -} - -mod bar_test { - use super::S; - use super::bar::Trait2; - fn test() { - S.method(); - //^^^^^^^^^^ i128 - } -} - "#, - ); -} - -#[test] -fn infer_trait_method_generic_1() { - // the trait implementation is intentionally incomplete -- it shouldn't matter - check_types( - r#" -trait Trait { - fn method(&self) -> T; -} -struct S; -impl Trait for S {} -fn test() { - S.method(); - //^^^^^^^^^^ u32 -} - "#, - ); -} - -#[test] -fn infer_trait_method_generic_more_params() { - // the trait implementation is intentionally incomplete -- it shouldn't matter - check_types( - r#" -trait Trait { - fn method1(&self) -> (T1, T2, T3); - fn method2(&self) -> (T3, T2, T1); -} -struct S1; -impl Trait for S1 {} -struct S2; -impl Trait for S2 {} -fn test() { - S1.method1(); - //^^^^^^^^^^^^ (u8, u16, u32) - S1.method2(); - //^^^^^^^^^^^^ (u32, u16, u8) - S2.method1(); - //^^^^^^^^^^^^ (i8, i16, {unknown}) - S2.method2(); - //^^^^^^^^^^^^ ({unknown}, i16, i8) -} - "#, - ); -} - -#[test] -fn infer_trait_method_generic_2() { - // the trait implementation is intentionally incomplete -- it shouldn't matter - check_types( - r#" -trait Trait { - fn method(&self) -> T; -} -struct S(T); -impl Trait for S {} -fn test() { - S(1u32).method(); - //^^^^^^^^^^^^^^^^ u32 -} - "#, - ); -} - -#[test] -fn infer_trait_assoc_method() { - check_infer( - r#" - trait Default { - fn default() -> Self; - } - struct S; - impl Default for S {} - fn test() { - let s1: S = Default::default(); - let s2 = S::default(); - let s3 = ::default(); - } - "#, - expect![[r#" - 86..192 '{ ...t(); }': () - 96..98 's1': S - 104..120 'Defaul...efault': fn default() -> S - 104..122 'Defaul...ault()': S - 132..134 's2': S - 137..147 'S::default': fn default() -> S - 137..149 'S::default()': S - 159..161 's3': S - 164..187 '() -> S - 164..189 ' { - fn make() -> T; - } - struct S; - impl Trait for S {} - struct G; - impl Trait for G {} - fn test() { - let a = S::make(); - let b = G::::make(); - let c: f64 = G::make(); - } - "#, - expect![[r#" - 126..210 '{ ...e(); }': () - 136..137 'a': u32 - 140..147 'S::make': fn make() -> u32 - 140..149 'S::make()': u32 - 159..160 'b': u64 - 163..177 'G::::make': fn make, u64>() -> u64 - 163..179 'G::, f64>() -> f64 - 198..207 'G::make()': f64 - "#]], - ); -} - -#[test] -fn infer_trait_assoc_method_generics_2() { - check_infer( - r#" - trait Trait { - fn make() -> (T, U); - } - struct S; - impl Trait for S {} - struct G; - impl Trait for G {} - fn test() { - let a = S::make::(); - let b: (_, i64) = S::make(); - let c = G::::make::(); - let d: (u32, _) = G::make::(); - let e: (u32, i64) = G::make(); - } - "#, - expect![[r#" - 134..312 '{ ...e(); }': () - 144..145 'a': (u32, i64) - 148..162 'S::make::': fn make() -> (u32, i64) - 148..164 'S::mak...i64>()': (u32, i64) - 174..175 'b': (u32, i64) - 188..195 'S::make': fn make() -> (u32, i64) - 188..197 'S::make()': (u32, i64) - 207..208 'c': (u32, i64) - 211..232 'G::': fn make, u32, i64>() -> (u32, i64) - 211..234 'G::()': (u32, i64) - 244..245 'd': (u32, i64) - 258..272 'G::make::': fn make, u32, i64>() -> (u32, i64) - 258..274 'G::mak...i64>()': (u32, i64) - 284..285 'e': (u32, i64) - 300..307 'G::make': fn make, u32, i64>() -> (u32, i64) - 300..309 'G::make()': (u32, i64) - "#]], - ); -} - -#[test] -fn infer_trait_assoc_method_generics_3() { - check_infer( - r#" - trait Trait { - fn make() -> (Self, T); - } - struct S; - impl Trait for S {} - fn test() { - let a = S::make(); - } - "#, - expect![[r#" - 100..126 '{ ...e(); }': () - 110..111 'a': (S, i64) - 114..121 'S::make': fn make, i64>() -> (S, i64) - 114..123 'S::make()': (S, i64) - "#]], - ); -} - -#[test] -fn infer_trait_assoc_method_generics_4() { - check_infer( - r#" - trait Trait { - fn make() -> (Self, T); - } - struct S; - impl Trait for S {} - impl Trait for S {} - fn test() { - let a: (S, _) = S::make(); - let b: (_, i32) = S::make(); - } - "#, - expect![[r#" - 130..202 '{ ...e(); }': () - 140..141 'a': (S, i64) - 157..164 'S::make': fn make, i64>() -> (S, i64) - 157..166 'S::make()': (S, i64) - 176..177 'b': (S, i32) - 190..197 'S::make': fn make, i32>() -> (S, i32) - 190..199 'S::make()': (S, i32) - "#]], - ); -} - -#[test] -fn infer_trait_assoc_method_generics_5() { - check_infer( - r#" - trait Trait { - fn make() -> (Self, T, U); - } - struct S; - impl Trait for S {} - fn test() { - let a = >::make::(); - let b: (S, _, _) = Trait::::make::(); - } - "#, - expect![[r#" - 106..210 '{ ...>(); }': () - 116..117 'a': (S, i64, u8) - 120..149 '': fn make, i64, u8>() -> (S, i64, u8) - 120..151 '()': (S, i64, u8) - 161..162 'b': (S, i64, u8) - 181..205 'Trait:...::': fn make, i64, u8>() -> (S, i64, u8) - 181..207 'Trait:...()': (S, i64, u8) - "#]], - ); -} - -#[test] -fn infer_call_trait_method_on_generic_param_1() { - check_infer( - r#" - trait Trait { - fn method(&self) -> u32; - } - fn test(t: T) { - t.method(); - } - "#, - expect![[r#" - 29..33 'self': &Self - 63..64 't': T - 69..88 '{ ...d(); }': () - 75..76 't': T - 75..85 't.method()': u32 - "#]], - ); -} - -#[test] -fn infer_call_trait_method_on_generic_param_2() { - check_infer( - r#" - trait Trait { - fn method(&self) -> T; - } - fn test>(t: T) { - t.method(); - } - "#, - expect![[r#" - 32..36 'self': &Self - 70..71 't': T - 76..95 '{ ...d(); }': () - 82..83 't': T - 82..92 't.method()': U - "#]], - ); -} - -#[test] -fn infer_with_multiple_trait_impls() { - check_infer( - r#" - trait Into { - fn into(self) -> T; - } - struct S; - impl Into for S {} - impl Into for S {} - fn test() { - let x: u32 = S.into(); - let y: u64 = S.into(); - let z = Into::::into(S); - } - "#, - expect![[r#" - 28..32 'self': Self - 110..201 '{ ...(S); }': () - 120..121 'x': u32 - 129..130 'S': S - 129..137 'S.into()': u32 - 147..148 'y': u64 - 156..157 'S': S - 156..164 'S.into()': u64 - 174..175 'z': u64 - 178..195 'Into::...::into': fn into(S) -> u64 - 178..198 'Into::...nto(S)': u64 - 196..197 'S': S - "#]], - ); -} - -#[test] -fn method_resolution_unify_impl_self_type() { - check_types( - r#" -struct S; -impl S { fn foo(&self) -> u8 { 0 } } -impl S { fn foo(&self) -> i8 { 0 } } -fn test() { (S::.foo(), S::.foo()); } - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (u8, i8) -"#, - ); -} - -#[test] -fn method_resolution_trait_before_autoref() { - check_types( - r#" -trait Trait { fn foo(self) -> u128; } -struct S; -impl S { fn foo(&self) -> i8 { 0 } } -impl Trait for S { fn foo(self) -> u128 { 0 } } -fn test() { S.foo(); } - //^^^^^^^ u128 -"#, - ); -} - -#[test] -fn method_resolution_by_value_before_autoref() { - check_types( - r#" -trait Clone { fn clone(&self) -> Self; } -struct S; -impl Clone for S {} -impl Clone for &S {} -fn test() { (S.clone(), (&S).clone(), (&&S).clone()); } - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (S, S, &S) -"#, - ); -} - -#[test] -fn method_resolution_trait_before_autoderef() { - check_types( - r#" -trait Trait { fn foo(self) -> u128; } -struct S; -impl S { fn foo(self) -> i8 { 0 } } -impl Trait for &S { fn foo(self) -> u128 { 0 } } -fn test() { (&S).foo(); } - //^^^^^^^^^^ u128 -"#, - ); -} - -#[test] -fn method_resolution_impl_before_trait() { - check_types( - r#" -trait Trait { fn foo(self) -> u128; } -struct S; -impl S { fn foo(self) -> i8 { 0 } } -impl Trait for S { fn foo(self) -> u128 { 0 } } -fn test() { S.foo(); } - //^^^^^^^ i8 -"#, - ); -} - -#[test] -fn method_resolution_impl_ref_before_trait() { - check_types( - r#" -trait Trait { fn foo(self) -> u128; } -struct S; -impl S { fn foo(&self) -> i8 { 0 } } -impl Trait for &S { fn foo(self) -> u128 { 0 } } -fn test() { S.foo(); } - //^^^^^^^ i8 -"#, - ); -} - -#[test] -fn method_resolution_trait_autoderef() { - check_types( - r#" -trait Trait { fn foo(self) -> u128; } -struct S; -impl Trait for S { fn foo(self) -> u128 { 0 } } -fn test() { (&S).foo(); } - //^^^^^^^^^^ u128 -"#, - ); -} - -#[test] -fn method_resolution_unsize_array() { - check_types( - r#" -//- minicore: slice -fn test() { - let a = [1, 2, 3]; - a.len(); -} //^^^^^^^ usize -"#, - ); -} - -#[test] -fn method_resolution_trait_from_prelude() { - check_types( - r#" -//- /main.rs crate:main deps:core -struct S; -impl Clone for S {} - -fn test() { - S.clone(); - //^^^^^^^^^ S -} - -//- /lib.rs crate:core -pub mod prelude { - pub mod rust_2018 { - pub trait Clone { - fn clone(&self) -> Self; - } - } -} -"#, - ); -} - -#[test] -fn method_resolution_where_clause_for_unknown_trait() { - // The blanket impl currently applies because we ignore the unresolved where clause - check_types( - r#" -trait Trait { fn foo(self) -> u128; } -struct S; -impl Trait for T where T: UnknownTrait {} -fn test() { (&S).foo(); } - //^^^^^^^^^^ u128 -"#, - ); -} - -#[test] -fn method_resolution_where_clause_not_met() { - // The blanket impl shouldn't apply because we can't prove S: Clone - // This is also to make sure that we don't resolve to the foo method just - // because that's the only method named foo we can find, which would make - // the below tests not work - check_types( - r#" -trait Clone {} -trait Trait { fn foo(self) -> u128; } -struct S; -impl Trait for T where T: Clone {} -fn test() { (&S).foo(); } - //^^^^^^^^^^ {unknown} -"#, - ); -} - -#[test] -fn method_resolution_where_clause_inline_not_met() { - // The blanket impl shouldn't apply because we can't prove S: Clone - check_types( - r#" -trait Clone {} -trait Trait { fn foo(self) -> u128; } -struct S; -impl Trait for T {} -fn test() { (&S).foo(); } - //^^^^^^^^^^ {unknown} -"#, - ); -} - -#[test] -fn method_resolution_where_clause_1() { - check_types( - r#" -trait Clone {} -trait Trait { fn foo(self) -> u128; } -struct S; -impl Clone for S {} -impl Trait for T where T: Clone {} -fn test() { S.foo(); } - //^^^^^^^ u128 -"#, - ); -} - -#[test] -fn method_resolution_where_clause_2() { - check_types( - r#" -trait Into { fn into(self) -> T; } -trait From { fn from(other: T) -> Self; } -struct S1; -struct S2; -impl From for S1 {} -impl Into for T where U: From {} -fn test() { S2.into(); } - //^^^^^^^^^ {unknown} -"#, - ); -} - -#[test] -fn method_resolution_where_clause_inline() { - check_types( - r#" -trait Into { fn into(self) -> T; } -trait From { fn from(other: T) -> Self; } -struct S1; -struct S2; -impl From for S1 {} -impl> Into for T {} -fn test() { S2.into(); } - //^^^^^^^^^ {unknown} -"#, - ); -} - -#[test] -fn method_resolution_overloaded_method() { - check_types( - r#" -struct Wrapper(T); -struct Foo(T); -struct Bar(T); - -impl Wrapper> { - pub fn new(foo_: T) -> Self { - Wrapper(Foo(foo_)) - } -} - -impl Wrapper> { - pub fn new(bar_: T) -> Self { - Wrapper(Bar(bar_)) - } -} - -fn main() { - let a = Wrapper::>::new(1.0); - let b = Wrapper::>::new(1.0); - (a, b); - //^^^^^^ (Wrapper>, Wrapper>) -} -"#, - ); -} - -#[test] -fn method_resolution_overloaded_const() { - cov_mark::check!(const_candidate_self_type_mismatch); - check_types( - r#" -struct Wrapper(T); -struct Foo(T); -struct Bar(T); - -impl Wrapper> { - pub const VALUE: Foo; -} - -impl Wrapper> { - pub const VALUE: Bar; -} - -fn main() { - let a = Wrapper::>::VALUE; - let b = Wrapper::>::VALUE; - (a, b); - //^^^^^^ (Foo, Bar) -} -"#, - ); -} - -#[test] -fn method_resolution_encountering_fn_type() { - check_types( - r#" -//- /main.rs -fn foo() {} -trait FnOnce { fn call(self); } -fn test() { foo.call(); } - //^^^^^^^^^^ {unknown} -"#, - ); -} - -#[test] -fn super_trait_impl_return_trait_method_resolution() { - check_infer( - r#" - //- minicore: sized - trait Base { - fn foo(self) -> usize; - } - - trait Super : Base {} - - fn base1() -> impl Base { loop {} } - fn super1() -> impl Super { loop {} } - - fn test(base2: impl Base, super2: impl Super) { - base1().foo(); - super1().foo(); - base2.foo(); - super2.foo(); - } - "#, - expect![[r#" - 24..28 'self': Self - 90..101 '{ loop {} }': ! - 92..99 'loop {}': ! - 97..99 '{}': () - 128..139 '{ loop {} }': ! - 130..137 'loop {}': ! - 135..137 '{}': () - 149..154 'base2': impl Base - 167..173 'super2': impl Super - 187..264 '{ ...o(); }': () - 193..198 'base1': fn base1() -> impl Base - 193..200 'base1()': impl Base - 193..206 'base1().foo()': usize - 212..218 'super1': fn super1() -> impl Super - 212..220 'super1()': impl Super - 212..226 'super1().foo()': usize - 232..237 'base2': impl Base - 232..243 'base2.foo()': usize - 249..255 'super2': impl Super - 249..261 'super2.foo()': usize - "#]], - ); -} - -#[test] -fn method_resolution_non_parameter_type() { - check_types( - r#" -mod a { - pub trait Foo { - fn foo(&self); - } -} - -struct Wrapper(T); -fn foo(t: Wrapper) -where - Wrapper: a::Foo, -{ - t.foo(); -} //^^^^^^^ {unknown} -"#, - ); -} - -#[test] -fn method_resolution_3373() { - check_types( - r#" -struct A(T); - -impl A { - fn from(v: i32) -> A { A(v) } -} - -fn main() { - A::from(3); -} //^^^^^^^^^^ A -"#, - ); -} - -#[test] -fn method_resolution_slow() { - // this can get quite slow if we set the solver size limit too high - check_types( - r#" -trait SendX {} - -struct S1; impl SendX for S1 {} -struct S2; impl SendX for S2 {} -struct U1; - -trait Trait { fn method(self); } - -struct X1 {} -impl SendX for X1 where A: SendX, B: SendX {} - -struct S {} - -trait FnX {} - -impl Trait for S where C: FnX, B: SendX {} - -fn test() { (S {}).method(); } - //^^^^^^^^^^^^^^^ () -"#, - ); -} - -#[test] -fn dyn_trait_super_trait_not_in_scope() { - check_infer( - r#" - mod m { - pub trait SuperTrait { - fn foo(&self) -> u32 { 0 } - } - } - trait Trait: m::SuperTrait {} - - struct S; - impl m::SuperTrait for S {} - impl Trait for S {} - - fn test(d: &dyn Trait) { - d.foo(); - } - "#, - expect![[r#" - 51..55 'self': &Self - 64..69 '{ 0 }': u32 - 66..67 '0': u32 - 176..177 'd': &dyn Trait - 191..207 '{ ...o(); }': () - 197..198 'd': &dyn Trait - 197..204 'd.foo()': u32 - "#]], - ); -} - -#[test] -fn method_resolution_foreign_opaque_type() { - check_infer( - r#" -extern "C" { - type S; - fn f() -> &'static S; -} - -impl S { - fn foo(&self) -> bool { - true - } -} - -fn test() { - let s = unsafe { f() }; - s.foo(); -} -"#, - expect![[r#" - 75..79 'self': &S - 89..109 '{ ... }': bool - 99..103 'true': bool - 123..167 '{ ...o(); }': () - 133..134 's': &S - 137..151 'unsafe { f() }': &S - 137..151 'unsafe { f() }': &S - 146..147 'f': fn f() -> &S - 146..149 'f()': &S - 157..158 's': &S - 157..164 's.foo()': bool - "#]], - ); -} - -#[test] -fn method_with_allocator_box_self_type() { - check_types( - r#" -struct Slice {} -struct Box {} - -impl Slice { - pub fn into_vec(self: Box) { } -} - -fn main() { - let foo: Slice; - foo.into_vec(); // we shouldn't crash on this at least -} //^^^^^^^^^^^^^^ {unknown} -"#, - ); -} - -#[test] -fn method_on_dyn_impl() { - check_types( - r#" -trait Foo {} - -impl Foo for u32 {} -impl dyn Foo + '_ { - pub fn dyn_foo(&self) -> u32 { - 0 - } -} - -fn main() { - let f = &42u32 as &dyn Foo; - f.dyn_foo(); - // ^^^^^^^^^^^ u32 -} -"#, - ); -} - -#[test] -fn autoderef_visibility_field() { - check( - r#" -//- minicore: deref -mod a { - pub struct Foo(pub char); - pub struct Bar(i32); - impl Bar { - pub fn new() -> Self { - Self(0) - } - } - impl core::ops::Deref for Bar { - type Target = Foo; - fn deref(&self) -> &Foo { - &Foo('z') - } - } -} -mod b { - fn foo() { - let x = super::a::Bar::new().0; - // ^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(Some(OverloadedDeref(Not))) - // ^^^^^^^^^^^^^^^^^^^^^^ type: char - } -} -"#, - ) -} - -#[test] -fn autoderef_visibility_method() { - cov_mark::check!(autoderef_candidate_not_visible); - check( - r#" -//- minicore: deref -mod a { - pub struct Foo(pub char); - impl Foo { - pub fn mango(&self) -> char { - self.0 - } - } - pub struct Bar(i32); - impl Bar { - pub fn new() -> Self { - Self(0) - } - fn mango(&self) -> i32 { - self.0 - } - } - impl core::ops::Deref for Bar { - type Target = Foo; - fn deref(&self) -> &Foo { - &Foo('z') - } - } -} -mod b { - fn foo() { - let x = super::a::Bar::new().mango(); - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: char - } -} -"#, - ) -} - -#[test] -fn trait_vs_private_inherent_const() { - cov_mark::check!(const_candidate_not_visible); - check( - r#" -mod a { - pub struct Foo; - impl Foo { - const VALUE: u32 = 2; - } - pub trait Trait { - const VALUE: usize; - } - impl Trait for Foo { - const VALUE: usize = 3; - } - - fn foo() { - let x = Foo::VALUE; - // ^^^^^^^^^^ type: u32 - } -} -use a::Trait; -fn foo() { - let x = a::Foo::VALUE; - // ^^^^^^^^^^^^^ type: usize -} -"#, - ) -} - -#[test] -fn trait_impl_in_unnamed_const() { - check_types( - r#" -struct S; - -trait Tr { - fn method(&self) -> u16; -} - -const _: () = { - impl Tr for S {} -}; - -fn f() { - S.method(); - //^^^^^^^^^^ u16 -} - "#, - ); -} - -#[test] -fn trait_impl_in_synstructure_const() { - check_types( - r#" -struct S; - -trait Tr { - fn method(&self) -> u16; -} - -const _DERIVE_Tr_: () = { - impl Tr for S {} -}; - -fn f() { - S.method(); - //^^^^^^^^^^ u16 -} - "#, - ); -} - -#[test] -fn inherent_impl_in_unnamed_const() { - check_types( - r#" -struct S; - -const _: () = { - impl S { - fn method(&self) -> u16 { 0 } - - pub(super) fn super_method(&self) -> u16 { 0 } - - pub(crate) fn crate_method(&self) -> u16 { 0 } - - pub fn pub_method(&self) -> u16 { 0 } - } -}; - -fn f() { - S.method(); - //^^^^^^^^^^ u16 - - S.super_method(); - //^^^^^^^^^^^^^^^^ u16 - - S.crate_method(); - //^^^^^^^^^^^^^^^^ u16 - - S.pub_method(); - //^^^^^^^^^^^^^^ u16 -} - "#, - ); -} - -#[test] -fn resolve_const_generic_array_methods() { - check_types( - r#" -#[lang = "array"] -impl [T; N] { - pub fn map(self, f: F) -> [U; N] - where - F: FnMut(T) -> U, - { loop {} } -} - -#[lang = "slice"] -impl [T] { - pub fn map(self, f: F) -> &[U] - where - F: FnMut(T) -> U, - { loop {} } -} - -fn f() { - let v = [1, 2].map::<_, usize>(|x| -> x * 2); - v; - //^ [usize; 2] -} - "#, - ); -} - -#[test] -fn resolve_const_generic_method() { - check_types( - r#" -struct Const; - -#[lang = "array"] -impl [T; N] { - pub fn my_map(self, f: F, c: Const) -> [U; X] - where - F: FnMut(T) -> U, - { loop {} } -} - -#[lang = "slice"] -impl [T] { - pub fn my_map(self, f: F, c: Const) -> &[U] - where - F: FnMut(T) -> U, - { loop {} } -} - -fn f() { - let v = [1, 2].my_map::<_, (), 12>(|x| -> x * 2, Const::<12>); - v; - //^ [(); 12] - let v = [1, 2].my_map::<_, P, C>(|x| -> x * 2, Const::); - v; - //^ [P; C] -} - "#, - ); -} - -#[test] -fn const_generic_type_alias() { - check_types( - r#" -struct Const; -type U2 = Const<2>; -type U5 = Const<5>; - -impl U2 { - fn f(self) -> Const<12> { - loop {} - } -} - -impl U5 { - fn f(self) -> Const<15> { - loop {} - } -} - -fn f(x: U2) { - let y = x.f(); - //^ Const<12> -} - "#, - ); -} - -#[test] -fn skip_array_during_method_dispatch() { - check_types( - r#" -//- /main2018.rs crate:main2018 deps:core -use core::IntoIterator; - -fn f() { - let v = [4].into_iter(); - v; - //^ &i32 - - let a = [0, 1].into_iter(); - a; - //^ &i32 -} - -//- /main2021.rs crate:main2021 deps:core edition:2021 -use core::IntoIterator; - -fn f() { - let v = [4].into_iter(); - v; - //^ i32 - - let a = [0, 1].into_iter(); - a; - //^ &i32 -} - -//- /core.rs crate:core -#[rustc_skip_array_during_method_dispatch] -pub trait IntoIterator { - type Out; - fn into_iter(self) -> Self::Out; -} - -impl IntoIterator for [T; 1] { - type Out = T; - fn into_iter(self) -> Self::Out { loop {} } -} -impl<'a, T> IntoIterator for &'a [T] { - type Out = &'a T; - fn into_iter(self) -> Self::Out { loop {} } -} - "#, - ); -} - -#[test] -fn sized_blanket_impl() { - check_infer( - r#" -//- minicore: sized -trait Foo { fn foo() -> u8; } -impl Foo for T {} -fn f() { - u32::foo; - S::foo; - T::foo; - U::foo; - <[u32]>::foo; -} -"#, - expect![[r#" - 89..160 '{ ...foo; }': () - 95..103 'u32::foo': fn foo() -> u8 - 109..115 'S::foo': fn foo() -> u8 - 121..127 'T::foo': fn foo() -> u8 - 133..139 'U::foo': {unknown} - 145..157 '<[u32]>::foo': {unknown} - "#]], - ); -} - -#[test] -fn local_impl() { - check_types( - r#" -fn main() { - struct SomeStruct(i32); - - impl SomeStruct { - fn is_even(&self) -> bool { - self.0 % 2 == 0 - } - } - - let o = SomeStruct(3); - let is_even = o.is_even(); - // ^^^^^^^ bool -} - "#, - ); -} - -#[test] -fn deref_fun_1() { - check_types( - r#" -//- minicore: deref - -struct A(T, U); -struct B(T); -struct C(T); - -impl core::ops::Deref for A, u32> { - type Target = B; - fn deref(&self) -> &B { &self.0 } -} -impl core::ops::Deref for B { - type Target = C; - fn deref(&self) -> &C { loop {} } -} - -impl C { - fn thing(&self) -> T { self.0 } -} - -fn make() -> T { loop {} } - -fn test() { - let a1 = A(make(), make()); - let _: usize = (*a1).0; - a1; - //^^ A, u32> - - let a2 = A(make(), make()); - a2.thing(); - //^^^^^^^^^^ isize - a2; - //^^ A, u32> -} -"#, - ); -} - -#[test] -fn deref_fun_2() { - check_types( - r#" -//- minicore: deref - -struct A(T, U); -struct B(T); -struct C(T); - -impl core::ops::Deref for A, u32> { - type Target = B; - fn deref(&self) -> &B { &self.0 } -} -impl core::ops::Deref for B { - type Target = C; - fn deref(&self) -> &C { loop {} } -} - -impl core::ops::Deref for A, i32> { - type Target = C; - fn deref(&self) -> &C { &self.0 } -} - -impl C { - fn thing(&self) -> T { self.0 } -} - -fn make() -> T { loop {} } - -fn test() { - let a1 = A(make(), 1u32); - a1.thing(); - a1; - //^^ A, u32> - - let a2 = A(make(), 1i32); - let _: &str = a2.thing(); - a2; - //^^ A, i32> -} -"#, - ); -} - -#[test] -fn receiver_adjustment_autoref() { - check( - r#" -struct Foo; -impl Foo { - fn foo(&self) {} -} -fn test() { - Foo.foo(); - //^^^ adjustments: Borrow(Ref(Not)) - (&Foo).foo(); - // ^^^^ adjustments: , -} -"#, - ); -} - -#[test] -fn receiver_adjustment_unsize_array() { - // FIXME not quite correct - check( - r#" -//- minicore: slice -fn test() { - let a = [1, 2, 3]; - a.len(); -} //^ adjustments: Pointer(Unsize), Borrow(Ref(Not)) -"#, - ); -} - -#[test] -fn bad_inferred_reference_1() { - check_no_mismatches( - r#" -//- minicore: sized -pub trait Into: Sized { - fn into(self) -> T; -} -impl Into for T { - fn into(self) -> T { self } -} - -trait ExactSizeIterator { - fn len(&self) -> usize; -} - -pub struct Foo; -impl Foo { - fn len(&self) -> usize { 0 } -} - -pub fn test(generic_args: impl Into) { - let generic_args = generic_args.into(); - generic_args.len(); - let _: Foo = generic_args; -} -"#, - ); -} - -#[test] -fn bad_inferred_reference_2() { - check_no_mismatches( - r#" -//- minicore: deref -trait ExactSizeIterator { - fn len(&self) -> usize; -} - -pub struct Foo; -impl Foo { - fn len(&self) -> usize { 0 } -} - -pub fn test() { - let generic_args; - generic_args.len(); - let _: Foo = generic_args; -} -"#, - ); -} - -#[test] -fn resolve_minicore_iterator() { - check_types( - r#" -//- minicore: iterators, sized -fn foo() { - let m = core::iter::repeat(()).filter_map(|()| Some(92)).next(); -} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Option -"#, - ); -} - -#[test] -fn primitive_assoc_fn_shadowed_by_use() { - check_types( - r#" -//- /lib.rs crate:lib deps:core -use core::u16; - -fn f() -> u16 { - let x = u16::from_le_bytes(); - x - //^ u16 -} - -//- /core.rs crate:core -pub mod u16 {} - -impl u16 { - pub fn from_le_bytes() -> Self { 0 } -} - "#, - ) -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs deleted file mode 100644 index fbdc8209f8f4b..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs +++ /dev/null @@ -1,485 +0,0 @@ -use expect_test::expect; - -use super::{check_infer_with_mismatches, check_no_mismatches, check_types}; - -#[test] -fn infer_never1() { - check_types( - r#" -fn test() { - let t = return; - t; -} //^ ! -"#, - ); -} - -#[test] -fn infer_never2() { - check_types( - r#" -fn gen() -> T { loop {} } - -fn test() { - let a = gen(); - if false { a } else { loop {} }; - a; -} //^ ! -"#, - ); -} - -#[test] -fn infer_never3() { - check_types( - r#" -fn gen() -> T { loop {} } - -fn test() { - let a = gen(); - if false { loop {} } else { a }; - a; - //^ ! -} -"#, - ); -} - -#[test] -fn never_type_in_generic_args() { - check_types( - r#" -enum Option { None, Some(T) } - -fn test() { - let a = if true { Option::None } else { Option::Some(return) }; - a; -} //^ Option -"#, - ); -} - -#[test] -fn never_type_can_be_reinferred1() { - check_types( - r#" -fn gen() -> T { loop {} } - -fn test() { - let a = gen(); - if false { loop {} } else { a }; - a; - //^ () - if false { a }; -} -"#, - ); -} - -#[test] -fn never_type_can_be_reinferred2() { - check_types( - r#" -enum Option { None, Some(T) } - -fn test() { - let a = if true { Option::None } else { Option::Some(return) }; - a; - //^ Option - match 42 { - 42 => a, - _ => Option::Some(42), - }; -} -"#, - ); -} - -#[test] -fn never_type_can_be_reinferred3() { - check_types( - r#" -enum Option { None, Some(T) } - -fn test() { - let a = if true { Option::None } else { Option::Some(return) }; - a; - //^ Option<&str> - match 42 { - 42 => a, - _ => Option::Some("str"), - }; -} -"#, - ); -} - -#[test] -fn match_no_arm() { - check_types( - r#" -enum Void {} - -fn test(a: Void) { - let t = match a {}; - t; -} //^ ! -"#, - ); -} - -#[test] -fn match_unknown_arm() { - check_types( - r#" -fn test(a: Option) { - let t = match 0 { - _ => unknown, - }; - t; -} //^ {unknown} -"#, - ); -} - -#[test] -fn if_never() { - check_types( - r#" -fn test() { - let i = if true { - loop {} - } else { - 3.0 - }; - i; -} //^ f64 -"#, - ); -} - -#[test] -fn if_else_never() { - check_types( - r#" -fn test(input: bool) { - let i = if input { - 2.0 - } else { - return - }; - i; -} //^ f64 -"#, - ); -} - -#[test] -fn match_first_arm_never() { - check_types( - r#" -fn test(a: i32) { - let i = match a { - 1 => return, - 2 => 2.0, - 3 => loop {}, - _ => 3.0, - }; - i; -} //^ f64 -"#, - ); -} - -#[test] -fn match_second_arm_never() { - check_types( - r#" -fn test(a: i32) { - let i = match a { - 1 => 3.0, - 2 => loop {}, - 3 => 3.0, - _ => return, - }; - i; -} //^ f64 -"#, - ); -} - -#[test] -fn match_all_arms_never() { - check_types( - r#" -fn test(a: i32) { - let i = match a { - 2 => return, - _ => loop {}, - }; - i; -} //^ ! -"#, - ); -} - -#[test] -fn match_no_never_arms() { - check_types( - r#" -fn test(a: i32) { - let i = match a { - 2 => 2.0, - _ => 3.0, - }; - i; -} //^ f64 -"#, - ); -} - -#[test] -fn diverging_expression_1() { - check_infer_with_mismatches( - r" - //- /main.rs - fn test1() { - let x: u32 = return; - } - fn test2() { - let x: u32 = { return; }; - } - fn test3() { - let x: u32 = loop {}; - } - fn test4() { - let x: u32 = { loop {} }; - } - fn test5() { - let x: u32 = { if true { loop {}; } else { loop {}; } }; - } - fn test6() { - let x: u32 = { let y: u32 = { loop {}; }; }; - } - ", - expect![[r" - 11..39 '{ ...urn; }': () - 21..22 'x': u32 - 30..36 'return': ! - 51..84 '{ ...; }; }': () - 61..62 'x': u32 - 70..81 '{ return; }': u32 - 72..78 'return': ! - 96..125 '{ ... {}; }': () - 106..107 'x': u32 - 115..122 'loop {}': ! - 120..122 '{}': () - 137..170 '{ ...} }; }': () - 147..148 'x': u32 - 156..167 '{ loop {} }': u32 - 158..165 'loop {}': ! - 163..165 '{}': () - 182..246 '{ ...} }; }': () - 192..193 'x': u32 - 201..243 '{ if t...}; } }': u32 - 203..241 'if tru... {}; }': u32 - 206..210 'true': bool - 211..223 '{ loop {}; }': u32 - 213..220 'loop {}': ! - 218..220 '{}': () - 229..241 '{ loop {}; }': u32 - 231..238 'loop {}': ! - 236..238 '{}': () - 258..310 '{ ...; }; }': () - 268..269 'x': u32 - 277..307 '{ let ...; }; }': u32 - 283..284 'y': u32 - 292..304 '{ loop {}; }': u32 - 294..301 'loop {}': ! - 299..301 '{}': () - "]], - ); -} - -#[test] -fn diverging_expression_2() { - check_infer_with_mismatches( - r#" - //- /main.rs - fn test1() { - // should give type mismatch - let x: u32 = { loop {}; "foo" }; - } - "#, - expect![[r#" - 11..84 '{ ..." }; }': () - 54..55 'x': u32 - 63..81 '{ loop...foo" }': u32 - 65..72 'loop {}': ! - 70..72 '{}': () - 74..79 '"foo"': &str - 74..79: expected u32, got &str - "#]], - ); -} - -#[test] -fn diverging_expression_3_break() { - check_infer_with_mismatches( - r" - //- /main.rs - fn test1() { - // should give type mismatch - let x: u32 = { loop { break; } }; - } - fn test2() { - // should give type mismatch - let x: u32 = { for a in b { break; }; }; - // should give type mismatch as well - let x: u32 = { for a in b {}; }; - // should give type mismatch as well - let x: u32 = { for a in b { return; }; }; - } - fn test3() { - // should give type mismatch - let x: u32 = { while true { break; }; }; - // should give type mismatch as well -- there's an implicit break, even if it's never hit - let x: u32 = { while true {}; }; - // should give type mismatch as well - let x: u32 = { while true { return; }; }; - } - ", - expect![[r#" - 11..85 '{ ...} }; }': () - 54..55 'x': u32 - 63..82 '{ loop...k; } }': u32 - 65..80 'loop { break; }': () - 70..80 '{ break; }': () - 72..77 'break': ! - 65..80: expected u32, got () - 97..343 '{ ...; }; }': () - 140..141 'x': u32 - 149..175 '{ for ...; }; }': u32 - 151..172 'for a ...eak; }': () - 155..156 'a': {unknown} - 160..161 'b': {unknown} - 162..172 '{ break; }': () - 164..169 'break': ! - 226..227 'x': u32 - 235..253 '{ for ... {}; }': u32 - 237..250 'for a in b {}': () - 241..242 'a': {unknown} - 246..247 'b': {unknown} - 248..250 '{}': () - 304..305 'x': u32 - 313..340 '{ for ...; }; }': u32 - 315..337 'for a ...urn; }': () - 319..320 'a': {unknown} - 324..325 'b': {unknown} - 326..337 '{ return; }': () - 328..334 'return': ! - 149..175: expected u32, got () - 235..253: expected u32, got () - 313..340: expected u32, got () - 355..654 '{ ...; }; }': () - 398..399 'x': u32 - 407..433 '{ whil...; }; }': u32 - 409..430 'while ...eak; }': () - 415..419 'true': bool - 420..430 '{ break; }': () - 422..427 'break': ! - 537..538 'x': u32 - 546..564 '{ whil... {}; }': u32 - 548..561 'while true {}': () - 554..558 'true': bool - 559..561 '{}': () - 615..616 'x': u32 - 624..651 '{ whil...; }; }': u32 - 626..648 'while ...urn; }': () - 632..636 'true': bool - 637..648 '{ return; }': () - 639..645 'return': ! - 407..433: expected u32, got () - 546..564: expected u32, got () - 624..651: expected u32, got () - "#]], - ); -} - -#[test] -fn let_else_must_diverge() { - check_infer_with_mismatches( - r#" - fn f() { - let 1 = 2 else { - return; - }; - } - "#, - expect![[r#" - 7..54 '{ ... }; }': () - 17..18 '1': i32 - 17..18 '1': i32 - 21..22 '2': i32 - 28..51 '{ ... }': ! - 38..44 'return': ! - "#]], - ); - check_infer_with_mismatches( - r#" - fn f() { - let 1 = 2 else {}; - } - "#, - expect![[r#" - 7..33 '{ ... {}; }': () - 17..18 '1': i32 - 17..18 '1': i32 - 21..22 '2': i32 - 28..30 '{}': ! - 28..30: expected !, got () - "#]], - ); -} - -#[test] -fn issue_11837() { - check_no_mismatches( - r#" -//- minicore: result -enum MyErr { - Err1, - Err2, -} - -fn example_ng() { - let value: Result = Ok(3); - - loop { - let ret = match value { - Ok(value) => value, - Err(ref err) => { - match err { - MyErr::Err1 => break, - MyErr::Err2 => continue, - }; - } - }; - } -} -"#, - ); -} - -#[test] -fn issue_11814() { - check_no_mismatches( - r#" -fn example() -> bool { - match 1 { - _ => return true, - }; -} -"#, - ); -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs deleted file mode 100644 index 399553356b041..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs +++ /dev/null @@ -1,991 +0,0 @@ -use expect_test::expect; - -use super::{check, check_infer, check_infer_with_mismatches, check_types}; - -#[test] -fn infer_pattern() { - check_infer( - r#" - fn test(x: &i32) { - let y = x; - let &z = x; - let a = z; - let (c, d) = (1, "hello"); - - for (e, f) in some_iter { - let g = e; - } - - if let [val] = opt { - let h = val; - } - - if let x @ true = &true {} - - let lambda = |a: u64, b, c: i32| { a + b; c }; - - let ref ref_to_x = x; - let mut mut_x = x; - let ref mut mut_ref_to_x = x; - let k = mut_ref_to_x; - } - "#, - expect![[r#" - 8..9 'x': &i32 - 17..400 '{ ...o_x; }': () - 27..28 'y': &i32 - 31..32 'x': &i32 - 42..44 '&z': &i32 - 43..44 'z': i32 - 47..48 'x': &i32 - 58..59 'a': i32 - 62..63 'z': i32 - 73..79 '(c, d)': (i32, &str) - 74..75 'c': i32 - 77..78 'd': &str - 82..94 '(1, "hello")': (i32, &str) - 83..84 '1': i32 - 86..93 '"hello"': &str - 101..151 'for (e... }': () - 105..111 '(e, f)': ({unknown}, {unknown}) - 106..107 'e': {unknown} - 109..110 'f': {unknown} - 115..124 'some_iter': {unknown} - 125..151 '{ ... }': () - 139..140 'g': {unknown} - 143..144 'e': {unknown} - 157..204 'if let... }': () - 160..175 'let [val] = opt': bool - 164..169 '[val]': [{unknown}] - 165..168 'val': {unknown} - 172..175 'opt': [{unknown}] - 176..204 '{ ... }': () - 190..191 'h': {unknown} - 194..197 'val': {unknown} - 210..236 'if let...rue {}': () - 213..233 'let x ... &true': bool - 217..225 'x @ true': &bool - 221..225 'true': bool - 221..225 'true': bool - 228..233 '&true': &bool - 229..233 'true': bool - 234..236 '{}': () - 246..252 'lambda': |u64, u64, i32| -> i32 - 255..287 '|a: u6...b; c }': |u64, u64, i32| -> i32 - 256..257 'a': u64 - 264..265 'b': u64 - 267..268 'c': i32 - 275..287 '{ a + b; c }': i32 - 277..278 'a': u64 - 277..282 'a + b': u64 - 281..282 'b': u64 - 284..285 'c': i32 - 298..310 'ref ref_to_x': &&i32 - 313..314 'x': &i32 - 324..333 'mut mut_x': &i32 - 336..337 'x': &i32 - 347..367 'ref mu...f_to_x': &mut &i32 - 370..371 'x': &i32 - 381..382 'k': &mut &i32 - 385..397 'mut_ref_to_x': &mut &i32 - "#]], - ); -} - -#[test] -fn infer_literal_pattern() { - check_infer_with_mismatches( - r#" - fn any() -> T { loop {} } - fn test(x: &i32) { - if let "foo" = any() {} - if let 1 = any() {} - if let 1u32 = any() {} - if let 1f32 = any() {} - if let 1.0 = any() {} - if let true = any() {} - } - "#, - expect![[r#" - 17..28 '{ loop {} }': T - 19..26 'loop {}': ! - 24..26 '{}': () - 37..38 'x': &i32 - 46..208 '{ ...) {} }': () - 52..75 'if let...y() {}': () - 55..72 'let "f... any()': bool - 59..64 '"foo"': &str - 59..64 '"foo"': &str - 67..70 'any': fn any<&str>() -> &str - 67..72 'any()': &str - 73..75 '{}': () - 80..99 'if let...y() {}': () - 83..96 'let 1 = any()': bool - 87..88 '1': i32 - 87..88 '1': i32 - 91..94 'any': fn any() -> i32 - 91..96 'any()': i32 - 97..99 '{}': () - 104..126 'if let...y() {}': () - 107..123 'let 1u... any()': bool - 111..115 '1u32': u32 - 111..115 '1u32': u32 - 118..121 'any': fn any() -> u32 - 118..123 'any()': u32 - 124..126 '{}': () - 131..153 'if let...y() {}': () - 134..150 'let 1f... any()': bool - 138..142 '1f32': f32 - 138..142 '1f32': f32 - 145..148 'any': fn any() -> f32 - 145..150 'any()': f32 - 151..153 '{}': () - 158..179 'if let...y() {}': () - 161..176 'let 1.0 = any()': bool - 165..168 '1.0': f64 - 165..168 '1.0': f64 - 171..174 'any': fn any() -> f64 - 171..176 'any()': f64 - 177..179 '{}': () - 184..206 'if let...y() {}': () - 187..203 'let tr... any()': bool - 191..195 'true': bool - 191..195 'true': bool - 198..201 'any': fn any() -> bool - 198..203 'any()': bool - 204..206 '{}': () - "#]], - ); -} - -#[test] -fn infer_range_pattern() { - check_infer_with_mismatches( - r#" - fn test(x: &i32) { - if let 1..76 = 2u32 {} - if let 1..=76 = 2u32 {} - } - "#, - expect![[r#" - 8..9 'x': &i32 - 17..75 '{ ...2 {} }': () - 23..45 'if let...u32 {}': () - 26..42 'let 1....= 2u32': bool - 30..35 '1..76': u32 - 38..42 '2u32': u32 - 43..45 '{}': () - 50..73 'if let...u32 {}': () - 53..70 'let 1....= 2u32': bool - 57..63 '1..=76': u32 - 66..70 '2u32': u32 - 71..73 '{}': () - "#]], - ); -} - -#[test] -fn infer_pattern_match_ergonomics() { - check_infer( - r#" - struct A(T); - - fn test() { - let A(n) = &A(1); - let A(n) = &mut A(1); - } - "#, - expect![[r#" - 27..78 '{ ...(1); }': () - 37..41 'A(n)': A - 39..40 'n': &i32 - 44..49 '&A(1)': &A - 45..46 'A': A(i32) -> A - 45..49 'A(1)': A - 47..48 '1': i32 - 59..63 'A(n)': A - 61..62 'n': &mut i32 - 66..75 '&mut A(1)': &mut A - 71..72 'A': A(i32) -> A - 71..75 'A(1)': A - 73..74 '1': i32 - "#]], - ); -} - -#[test] -fn infer_pattern_match_ergonomics_ref() { - cov_mark::check!(match_ergonomics_ref); - check_infer( - r#" - fn test() { - let v = &(1, &2); - let (_, &w) = v; - } - "#, - expect![[r#" - 10..56 '{ ...= v; }': () - 20..21 'v': &(i32, &i32) - 24..32 '&(1, &2)': &(i32, &i32) - 25..32 '(1, &2)': (i32, &i32) - 26..27 '1': i32 - 29..31 '&2': &i32 - 30..31 '2': i32 - 42..49 '(_, &w)': (i32, &i32) - 43..44 '_': i32 - 46..48 '&w': &i32 - 47..48 'w': i32 - 52..53 'v': &(i32, &i32) - "#]], - ); -} - -#[test] -fn infer_pattern_match_slice() { - check_infer( - r#" - fn test() { - let slice: &[f64] = &[0.0]; - match slice { - &[] => {}, - &[a] => { - a; - }, - &[b, c] => { - b; - c; - } - _ => {} - } - } - "#, - expect![[r#" - 10..209 '{ ... } }': () - 20..25 'slice': &[f64] - 36..42 '&[0.0]': &[f64; 1] - 37..42 '[0.0]': [f64; 1] - 38..41 '0.0': f64 - 48..207 'match ... }': () - 54..59 'slice': &[f64] - 70..73 '&[]': &[f64] - 71..73 '[]': [f64] - 77..79 '{}': () - 89..93 '&[a]': &[f64] - 90..93 '[a]': [f64] - 91..92 'a': f64 - 97..123 '{ ... }': () - 111..112 'a': f64 - 133..140 '&[b, c]': &[f64] - 134..140 '[b, c]': [f64] - 135..136 'b': f64 - 138..139 'c': f64 - 144..185 '{ ... }': () - 158..159 'b': f64 - 173..174 'c': f64 - 194..195 '_': &[f64] - 199..201 '{}': () - "#]], - ); -} - -#[test] -fn infer_pattern_match_string_literal() { - check_infer_with_mismatches( - r#" - fn test() { - let s: &str = "hello"; - match s { - "hello" => {} - _ => {} - } - } - "#, - expect![[r#" - 10..98 '{ ... } }': () - 20..21 's': &str - 30..37 '"hello"': &str - 43..96 'match ... }': () - 49..50 's': &str - 61..68 '"hello"': &str - 61..68 '"hello"': &str - 72..74 '{}': () - 83..84 '_': &str - 88..90 '{}': () - "#]], - ); -} - -#[test] -fn infer_pattern_match_or() { - check_infer_with_mismatches( - r#" - fn test() { - let s: &str = "hello"; - match s { - "hello" | "world" => {} - _ => {} - } - } - "#, - expect![[r#" - 10..108 '{ ... } }': () - 20..21 's': &str - 30..37 '"hello"': &str - 43..106 'match ... }': () - 49..50 's': &str - 61..68 '"hello"': &str - 61..68 '"hello"': &str - 61..78 '"hello...world"': &str - 71..78 '"world"': &str - 71..78 '"world"': &str - 82..84 '{}': () - 93..94 '_': &str - 98..100 '{}': () - "#]], - ); -} - -#[test] -fn infer_pattern_match_arr() { - check_infer( - r#" - fn test() { - let arr: [f64; 2] = [0.0, 1.0]; - match arr { - [1.0, a] => { - a; - }, - [b, c] => { - b; - c; - } - } - } - "#, - expect![[r#" - 10..179 '{ ... } }': () - 20..23 'arr': [f64; 2] - 36..46 '[0.0, 1.0]': [f64; 2] - 37..40 '0.0': f64 - 42..45 '1.0': f64 - 52..177 'match ... }': () - 58..61 'arr': [f64; 2] - 72..80 '[1.0, a]': [f64; 2] - 73..76 '1.0': f64 - 73..76 '1.0': f64 - 78..79 'a': f64 - 84..110 '{ ... }': () - 98..99 'a': f64 - 120..126 '[b, c]': [f64; 2] - 121..122 'b': f64 - 124..125 'c': f64 - 130..171 '{ ... }': () - 144..145 'b': f64 - 159..160 'c': f64 - "#]], - ); -} - -#[test] -fn infer_adt_pattern() { - check_infer( - r#" - enum E { - A { x: usize }, - B - } - - struct S(u32, E); - - fn test() { - let e = E::A { x: 3 }; - - let S(y, z) = foo; - let E::A { x: new_var } = e; - - match e { - E::A { x } => x, - E::B if foo => 1, - E::B => 10, - }; - - let ref d @ E::A { .. } = e; - d; - } - "#, - expect![[r#" - 67..288 '{ ... d; }': () - 77..78 'e': E - 81..94 'E::A { x: 3 }': E - 91..92 '3': usize - 105..112 'S(y, z)': S - 107..108 'y': u32 - 110..111 'z': E - 115..118 'foo': S - 128..147 'E::A {..._var }': E - 138..145 'new_var': usize - 150..151 'e': E - 158..244 'match ... }': usize - 164..165 'e': E - 176..186 'E::A { x }': E - 183..184 'x': usize - 190..191 'x': usize - 201..205 'E::B': E - 209..212 'foo': bool - 216..217 '1': usize - 227..231 'E::B': E - 235..237 '10': usize - 255..274 'ref d ...{ .. }': &E - 263..274 'E::A { .. }': E - 277..278 'e': E - 284..285 'd': &E - "#]], - ); -} - -#[test] -fn enum_variant_through_self_in_pattern() { - check_infer( - r#" - enum E { - A { x: usize }, - B(usize), - C - } - - impl E { - fn test() { - match (loop {}) { - Self::A { x } => { x; }, - Self::B(x) => { x; }, - Self::C => {}, - }; - } - } - "#, - expect![[r#" - 75..217 '{ ... }': () - 85..210 'match ... }': () - 92..99 'loop {}': ! - 97..99 '{}': () - 115..128 'Self::A { x }': E - 125..126 'x': usize - 132..138 '{ x; }': () - 134..135 'x': usize - 152..162 'Self::B(x)': E - 160..161 'x': usize - 166..172 '{ x; }': () - 168..169 'x': usize - 186..193 'Self::C': E - 197..199 '{}': () - "#]], - ); -} - -#[test] -fn infer_generics_in_patterns() { - check_infer( - r#" - struct A { - x: T, - } - - enum Option { - Some(T), - None, - } - - fn test(a1: A, o: Option) { - let A { x: x2 } = a1; - let A:: { x: x3 } = A { x: 1 }; - match o { - Option::Some(t) => t, - _ => 1, - }; - } - "#, - expect![[r#" - 78..80 'a1': A - 90..91 'o': Option - 106..243 '{ ... }; }': () - 116..127 'A { x: x2 }': A - 123..125 'x2': u32 - 130..132 'a1': A - 142..160 'A:: - 156..158 'x3': i64 - 163..173 'A { x: 1 }': A - 170..171 '1': i64 - 179..240 'match ... }': u64 - 185..186 'o': Option - 197..212 'Option::Some(t)': Option - 210..211 't': u64 - 216..217 't': u64 - 227..228 '_': Option - 232..233 '1': u64 - "#]], - ); -} - -#[test] -fn infer_const_pattern() { - check( - r#" -enum Option { None } -use Option::None; -struct Foo; -const Bar: usize = 1; - -fn test() { - let a: Option = None; - let b: Option = match a { - None => None, - }; - let _: () = match () { Foo => () }; - // ^^^ expected (), got Foo - let _: () = match () { Bar => () }; - // ^^^ expected (), got usize -} - "#, - ); -} - -#[test] -fn infer_guard() { - check_infer( - r#" -struct S; -impl S { fn foo(&self) -> bool { false } } - -fn main() { - match S { - s if s.foo() => (), - } -} - "#, - expect![[r#" - 27..31 'self': &S - 41..50 '{ false }': bool - 43..48 'false': bool - 64..115 '{ ... } }': () - 70..113 'match ... }': () - 76..77 'S': S - 88..89 's': S - 93..94 's': S - 93..100 's.foo()': bool - 104..106 '()': () - "#]], - ) -} - -#[test] -fn match_ergonomics_in_closure_params() { - check_infer( - r#" -//- minicore: fn -fn foo U>(t: T, f: F) -> U { loop {} } - -fn test() { - foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics - foo(&(1, "a"), |(x, y)| x); -} -"#, - expect![[r#" - 32..33 't': T - 38..39 'f': F - 49..60 '{ loop {} }': U - 51..58 'loop {}': ! - 56..58 '{}': () - 72..171 '{ ... x); }': () - 78..81 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32 - 78..105 'foo(&(...y)| x)': i32 - 82..91 '&(1, "a")': &(i32, &str) - 83..91 '(1, "a")': (i32, &str) - 84..85 '1': i32 - 87..90 '"a"': &str - 93..104 '|&(x, y)| x': |&(i32, &str)| -> i32 - 94..101 '&(x, y)': &(i32, &str) - 95..101 '(x, y)': (i32, &str) - 96..97 'x': i32 - 99..100 'y': &str - 103..104 'x': i32 - 142..145 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32 - 142..168 'foo(&(...y)| x)': &i32 - 146..155 '&(1, "a")': &(i32, &str) - 147..155 '(1, "a")': (i32, &str) - 148..149 '1': i32 - 151..154 '"a"': &str - 157..167 '|(x, y)| x': |&(i32, &str)| -> &i32 - 158..164 '(x, y)': (i32, &str) - 159..160 'x': &i32 - 162..163 'y': &&str - 166..167 'x': &i32 - "#]], - ); -} - -#[test] -fn slice_tail_pattern() { - check_infer( - r#" - fn foo(params: &[i32]) { - match params { - [head, tail @ ..] => { - } - } - } - "#, - expect![[r#" - 7..13 'params': &[i32] - 23..92 '{ ... } }': () - 29..90 'match ... }': () - 35..41 'params': &[i32] - 52..69 '[head,... @ ..]': [i32] - 53..57 'head': &i32 - 59..68 'tail @ ..': &[i32] - 66..68 '..': [i32] - 73..84 '{ }': () - "#]], - ); -} - -#[test] -fn box_pattern() { - check_infer( - r#" - pub struct Global; - #[lang = "owned_box"] - pub struct Box(T); - - fn foo(params: Box) { - match params { - box integer => {} - } - } - "#, - expect![[r#" - 83..89 'params': Box - 101..155 '{ ... } }': () - 107..153 'match ... }': () - 113..119 'params': Box - 130..141 'box integer': Box - 134..141 'integer': i32 - 145..147 '{}': () - "#]], - ); - check_infer( - r#" - #[lang = "owned_box"] - pub struct Box(T); - - fn foo(params: Box) { - match params { - box integer => {} - } - } - "#, - expect![[r#" - 52..58 'params': Box - 70..124 '{ ... } }': () - 76..122 'match ... }': () - 82..88 'params': Box - 99..110 'box integer': Box - 103..110 'integer': i32 - 114..116 '{}': () - "#]], - ); -} - -#[test] -fn tuple_ellipsis_pattern() { - check_infer_with_mismatches( - r#" -fn foo(tuple: (u8, i16, f32)) { - match tuple { - (.., b, c) => {}, - (a, .., c) => {}, - (a, b, ..) => {}, - (a, b) => {/*too short*/} - (a, b, c, d) => {/*too long*/} - _ => {} - } -}"#, - expect![[r#" - 7..12 'tuple': (u8, i16, f32) - 30..224 '{ ... } }': () - 36..222 'match ... }': () - 42..47 'tuple': (u8, i16, f32) - 58..68 '(.., b, c)': (u8, i16, f32) - 63..64 'b': i16 - 66..67 'c': f32 - 72..74 '{}': () - 84..94 '(a, .., c)': (u8, i16, f32) - 85..86 'a': u8 - 92..93 'c': f32 - 98..100 '{}': () - 110..120 '(a, b, ..)': (u8, i16, f32) - 111..112 'a': u8 - 114..115 'b': i16 - 124..126 '{}': () - 136..142 '(a, b)': (u8, i16) - 137..138 'a': u8 - 140..141 'b': i16 - 146..161 '{/*too short*/}': () - 170..182 '(a, b, c, d)': (u8, i16, f32, {unknown}) - 171..172 'a': u8 - 174..175 'b': i16 - 177..178 'c': f32 - 180..181 'd': {unknown} - 186..200 '{/*too long*/}': () - 209..210 '_': (u8, i16, f32) - 214..216 '{}': () - 136..142: expected (u8, i16, f32), got (u8, i16) - 170..182: expected (u8, i16, f32), got (u8, i16, f32, {unknown}) - "#]], - ); -} - -#[test] -fn tuple_struct_ellipsis_pattern() { - check_infer( - r#" -struct Tuple(u8, i16, f32); -fn foo(tuple: Tuple) { - match tuple { - Tuple(.., b, c) => {}, - Tuple(a, .., c) => {}, - Tuple(a, b, ..) => {}, - Tuple(a, b) => {/*too short*/} - Tuple(a, b, c, d) => {/*too long*/} - _ => {} - } -}"#, - expect![[r#" - 35..40 'tuple': Tuple - 49..268 '{ ... } }': () - 55..266 'match ... }': () - 61..66 'tuple': Tuple - 77..92 'Tuple(.., b, c)': Tuple - 87..88 'b': i16 - 90..91 'c': f32 - 96..98 '{}': () - 108..123 'Tuple(a, .., c)': Tuple - 114..115 'a': u8 - 121..122 'c': f32 - 127..129 '{}': () - 139..154 'Tuple(a, b, ..)': Tuple - 145..146 'a': u8 - 148..149 'b': i16 - 158..160 '{}': () - 170..181 'Tuple(a, b)': Tuple - 176..177 'a': u8 - 179..180 'b': i16 - 185..200 '{/*too short*/}': () - 209..226 'Tuple(... c, d)': Tuple - 215..216 'a': u8 - 218..219 'b': i16 - 221..222 'c': f32 - 224..225 'd': {unknown} - 230..244 '{/*too long*/}': () - 253..254 '_': Tuple - 258..260 '{}': () - "#]], - ); -} - -#[test] -fn const_block_pattern() { - check_infer( - r#" -struct Foo(usize); -fn foo(foo: Foo) { - match foo { - const { Foo(15 + 32) } => {}, - _ => {} - } -}"#, - expect![[r#" - 26..29 'foo': Foo - 36..115 '{ ... } }': () - 42..113 'match ... }': () - 48..51 'foo': Foo - 62..84 'const ... 32) }': Foo - 68..84 '{ Foo(... 32) }': Foo - 70..73 'Foo': Foo(usize) -> Foo - 70..82 'Foo(15 + 32)': Foo - 74..76 '15': usize - 74..81 '15 + 32': usize - 79..81 '32': usize - 88..90 '{}': () - 100..101 '_': Foo - 105..107 '{}': () - "#]], - ); -} - -#[test] -fn macro_pat() { - check_types( - r#" -macro_rules! pat { - ($name:ident) => { Enum::Variant1($name) } -} - -enum Enum { - Variant1(u8), - Variant2, -} - -fn f(e: Enum) { - match e { - pat!(bind) => { - bind; - //^^^^ u8 - } - Enum::Variant2 => {} - } -} - "#, - ) -} - -#[test] -fn type_mismatch_in_or_pattern() { - check_infer_with_mismatches( - r#" -fn main() { - match (false,) { - (true | (),) => {} - (() | true,) => {} - (_ | (),) => {} - (() | _,) => {} - } -} -"#, - expect![[r#" - 10..142 '{ ... } }': () - 16..140 'match ... }': () - 22..30 '(false,)': (bool,) - 23..28 'false': bool - 41..53 '(true | (),)': (bool,) - 42..46 'true': bool - 42..46 'true': bool - 42..51 'true | ()': bool - 49..51 '()': () - 57..59 '{}': () - 68..80 '(() | true,)': ((),) - 69..71 '()': () - 69..78 '() | true': () - 74..78 'true': bool - 74..78 'true': bool - 84..86 '{}': () - 95..104 '(_ | (),)': (bool,) - 96..97 '_': bool - 96..102 '_ | ()': bool - 100..102 '()': () - 108..110 '{}': () - 119..128 '(() | _,)': ((),) - 120..122 '()': () - 120..126 '() | _': () - 125..126 '_': bool - 132..134 '{}': () - 49..51: expected bool, got () - 68..80: expected (bool,), got ((),) - 69..71: expected bool, got () - 69..78: expected bool, got () - 100..102: expected bool, got () - 119..128: expected (bool,), got ((),) - 120..122: expected bool, got () - 120..126: expected bool, got () - "#]], - ); -} - -#[test] -fn slice_pattern_correctly_handles_array_length() { - check_infer( - r#" -fn main() { - let [head, middle @ .., tail, tail2] = [1, 2, 3, 4, 5]; -} - "#, - expect![[r#" - 10..73 '{ ... 5]; }': () - 20..52 '[head,...tail2]': [i32; 5] - 21..25 'head': i32 - 27..38 'middle @ ..': [i32; 2] - 36..38 '..': [i32; 2] - 40..44 'tail': i32 - 46..51 'tail2': i32 - 55..70 '[1, 2, 3, 4, 5]': [i32; 5] - 56..57 '1': i32 - 59..60 '2': i32 - 62..63 '3': i32 - 65..66 '4': i32 - 68..69 '5': i32 - "#]], - ); -} - -#[test] -fn pattern_lookup_in_value_ns() { - check_types( - r#" -use self::Constructor::*; -struct IntRange { - range: (), -} -enum Constructor { - IntRange(IntRange), -} -fn main() { - match Constructor::IntRange(IntRange { range: () }) { - IntRange(x) => { - x; - //^ IntRange - } - Constructor::IntRange(x) => { - x; - //^ IntRange - } - } -} - "#, - ); -} - -#[test] -fn if_let_guards() { - check_types( - r#" -fn main() { - match (0,) { - opt if let (x,) = opt => { - x; - //^ i32 - } - _ => {} - } -} - "#, - ); -} - -#[test] -fn tuple_wildcard() { - check_types( - r#" -fn main() { - enum Option {Some(T), None} - use Option::*; - - let mut x = None; - x; - //^ Option<(i32, i32)> - - if let Some((_, _a)) = x {} - - x = Some((1, 2)); -} - "#, - ); -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs deleted file mode 100644 index 93a88ab58ef82..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ /dev/null @@ -1,1650 +0,0 @@ -use expect_test::expect; - -use super::{check_infer, check_no_mismatches, check_types}; - -#[test] -fn bug_484() { - check_infer( - r#" - fn test() { - let x = if true {}; - } - "#, - expect![[r#" - 10..37 '{ ... {}; }': () - 20..21 'x': () - 24..34 'if true {}': () - 27..31 'true': bool - 32..34 '{}': () - "#]], - ); -} - -#[test] -fn no_panic_on_field_of_enum() { - check_infer( - r#" - enum X {} - - fn test(x: X) { - x.some_field; - } - "#, - expect![[r#" - 19..20 'x': X - 25..46 '{ ...eld; }': () - 31..32 'x': X - 31..43 'x.some_field': {unknown} - "#]], - ); -} - -#[test] -fn bug_585() { - check_infer( - r#" - fn test() { - X {}; - match x { - A::B {} => (), - A::Y() => (), - } - } - "#, - expect![[r#" - 10..88 '{ ... } }': () - 16..20 'X {}': {unknown} - 26..86 'match ... }': () - 32..33 'x': {unknown} - 44..51 'A::B {}': {unknown} - 55..57 '()': () - 67..73 'A::Y()': {unknown} - 77..79 '()': () - "#]], - ); -} - -#[test] -fn bug_651() { - check_infer( - r#" - fn quux() { - let y = 92; - 1 + y; - } - "#, - expect![[r#" - 10..40 '{ ...+ y; }': () - 20..21 'y': i32 - 24..26 '92': i32 - 32..33 '1': i32 - 32..37 '1 + y': i32 - 36..37 'y': i32 - "#]], - ); -} - -#[test] -fn recursive_vars() { - check_infer( - r#" - fn test() { - let y = unknown; - [y, &y]; - } - "#, - expect![[r#" - 10..47 '{ ...&y]; }': () - 20..21 'y': {unknown} - 24..31 'unknown': {unknown} - 37..44 '[y, &y]': [{unknown}; 2] - 38..39 'y': {unknown} - 41..43 '&y': &{unknown} - 42..43 'y': {unknown} - "#]], - ); -} - -#[test] -fn recursive_vars_2() { - check_infer( - r#" - fn test() { - let x = unknown; - let y = unknown; - [(x, y), (&y, &x)]; - } - "#, - expect![[r#" - 10..79 '{ ...x)]; }': () - 20..21 'x': &{unknown} - 24..31 'unknown': &{unknown} - 41..42 'y': {unknown} - 45..52 'unknown': {unknown} - 58..76 '[(x, y..., &x)]': [(&{unknown}, {unknown}); 2] - 59..65 '(x, y)': (&{unknown}, {unknown}) - 60..61 'x': &{unknown} - 63..64 'y': {unknown} - 67..75 '(&y, &x)': (&{unknown}, {unknown}) - 68..70 '&y': &{unknown} - 69..70 'y': {unknown} - 72..74 '&x': &&{unknown} - 73..74 'x': &{unknown} - "#]], - ); -} - -#[test] -fn array_elements_expected_type() { - check_no_mismatches( - r#" - fn test() { - let x: [[u32; 2]; 2] = [[1, 2], [3, 4]]; - } - "#, - ); -} - -#[test] -fn infer_std_crash_1() { - // caused stack overflow, taken from std - check_infer( - r#" - enum Maybe { - Real(T), - Fake, - } - - fn write() { - match something_unknown { - Maybe::Real(ref mut something) => (), - } - } - "#, - expect![[r#" - 53..138 '{ ... } }': () - 59..136 'match ... }': () - 65..82 'someth...nknown': Maybe<{unknown}> - 93..123 'Maybe:...thing)': Maybe<{unknown}> - 105..122 'ref mu...ething': &mut {unknown} - 127..129 '()': () - "#]], - ); -} - -#[test] -fn infer_std_crash_2() { - // caused "equating two type variables, ...", taken from std - check_infer( - r#" - fn test_line_buffer() { - &[0, b'\n', 1, b'\n']; - } - "#, - expect![[r#" - 22..52 '{ ...n']; }': () - 28..49 '&[0, b...b'\n']': &[u8; 4] - 29..49 '[0, b'...b'\n']': [u8; 4] - 30..31 '0': u8 - 33..38 'b'\n'': u8 - 40..41 '1': u8 - 43..48 'b'\n'': u8 - "#]], - ); -} - -#[test] -fn infer_std_crash_3() { - // taken from rustc - check_infer( - r#" - pub fn compute() { - match nope!() { - SizeSkeleton::Pointer { non_zero: true, tail } => {} - } - } - "#, - expect![[r#" - 17..107 '{ ... } }': () - 23..105 'match ... }': () - 29..36 'nope!()': {unknown} - 47..93 'SizeSk...tail }': {unknown} - 81..85 'true': bool - 81..85 'true': bool - 87..91 'tail': {unknown} - 97..99 '{}': () - "#]], - ); -} - -#[test] -fn infer_std_crash_4() { - // taken from rustc - check_infer( - r#" - pub fn primitive_type() { - match *self { - BorrowedRef { type_: Primitive(p), ..} => {}, - } - } - "#, - expect![[r#" - 24..105 '{ ... } }': () - 30..103 'match ... }': () - 36..41 '*self': {unknown} - 37..41 'self': {unknown} - 52..90 'Borrow...), ..}': {unknown} - 73..85 'Primitive(p)': {unknown} - 83..84 'p': {unknown} - 94..96 '{}': () - "#]], - ); -} - -#[test] -fn infer_std_crash_5() { - // taken from rustc - check_infer( - r#" - fn extra_compiler_flags() { - for content in doesnt_matter { - let name = if doesnt_matter { - first - } else { - &content - }; - - let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) { - name - } else { - content - }; - } - } - "#, - expect![[r#" - 26..322 '{ ... } }': () - 32..320 'for co... }': () - 36..43 'content': {unknown} - 47..60 'doesnt_matter': {unknown} - 61..320 '{ ... }': () - 75..79 'name': &{unknown} - 82..166 'if doe... }': &{unknown} - 85..98 'doesnt_matter': bool - 99..128 '{ ... }': &{unknown} - 113..118 'first': &{unknown} - 134..166 '{ ... }': &{unknown} - 148..156 '&content': &{unknown} - 149..156 'content': {unknown} - 181..188 'content': &{unknown} - 191..313 'if ICE... }': &{unknown} - 194..231 'ICE_RE..._VALUE': {unknown} - 194..247 'ICE_RE...&name)': bool - 241..246 '&name': &&{unknown} - 242..246 'name': &{unknown} - 248..276 '{ ... }': &{unknown} - 262..266 'name': &{unknown} - 282..313 '{ ... }': {unknown} - 296..303 'content': {unknown} - "#]], - ); -} - -#[test] -fn infer_nested_generics_crash() { - // another crash found typechecking rustc - check_infer( - r#" - struct Canonical { - value: V, - } - struct QueryResponse { - value: V, - } - fn test(query_response: Canonical>) { - &query_response.value; - } - "#, - expect![[r#" - 91..105 'query_response': Canonical> - 136..166 '{ ...lue; }': () - 142..163 '&query....value': &QueryResponse - 143..157 'query_response': Canonical> - 143..163 'query_....value': QueryResponse - "#]], - ); -} - -#[test] -fn infer_paren_macro_call() { - check_infer( - r#" - macro_rules! bar { () => {0u32} } - fn test() { - let a = (bar!()); - } - "#, - expect![[r#" - !0..4 '0u32': u32 - 44..69 '{ ...()); }': () - 54..55 'a': u32 - "#]], - ); -} - -#[test] -fn infer_array_macro_call() { - check_infer( - r#" - macro_rules! bar { () => {0u32} } - fn test() { - let a = [bar!()]; - } - "#, - expect![[r#" - !0..4 '0u32': u32 - 44..69 '{ ...()]; }': () - 54..55 'a': [u32; 1] - 58..66 '[bar!()]': [u32; 1] - "#]], - ); -} - -#[test] -fn bug_1030() { - check_infer( - r#" - struct HashSet; - struct FxHasher; - type FxHashSet = HashSet; - - impl HashSet { - fn default() -> HashSet {} - } - - pub fn main_loop() { - FxHashSet::default(); - } - "#, - expect![[r#" - 143..145 '{}': HashSet - 168..197 '{ ...t(); }': () - 174..192 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<{unknown}, FxHasher> - 174..194 'FxHash...ault()': HashSet<{unknown}, FxHasher> - "#]], - ); -} - -#[test] -fn issue_2669() { - check_infer( - r#" - trait A {} - trait Write {} - struct Response {} - - trait D { - fn foo(); - } - - impl D for Response { - fn foo() { - end(); - fn end() { - let _x: T = loop {}; - } - } - } - "#, - expect![[r#" - 119..214 '{ ... }': () - 129..132 'end': fn end<{unknown}>() - 129..134 'end()': () - 163..208 '{ ... }': () - 181..183 '_x': ! - 190..197 'loop {}': ! - 195..197 '{}': () - "#]], - ) -} - -#[test] -fn issue_2705() { - check_infer( - r#" - trait Trait {} - fn test() { - >::foo() - } - "#, - expect![[r#" - 25..52 '{ ...oo() }': () - 31..48 '::foo': {unknown} - 31..50 ' {} -impl<'a> Iterator for Chars<'a> { - type Item = char; - fn next(&mut self) -> Option { loop {} } -} - -fn test() { - let chars: Chars<'_>; - (chars.next(), chars.nth(1)); -} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (Option, Option) -"#, - ); -} - -#[test] -fn issue_3999_slice() { - check_infer( - r#" - fn foo(params: &[usize]) { - match params { - [ps @ .., _] => {} - } - } - "#, - expect![[r#" - 7..13 'params': &[usize] - 25..80 '{ ... } }': () - 31..78 'match ... }': () - 37..43 'params': &[usize] - 54..66 '[ps @ .., _]': [usize] - 55..62 'ps @ ..': &[usize] - 60..62 '..': [usize] - 64..65 '_': usize - 70..72 '{}': () - "#]], - ); -} - -#[test] -fn issue_3999_struct() { - // rust-analyzer should not panic on seeing this malformed - // record pattern. - check_infer( - r#" - struct Bar { - a: bool, - } - fn foo(b: Bar) { - match b { - Bar { a: .. } => {}, - } - } - "#, - expect![[r#" - 35..36 'b': Bar - 43..95 '{ ... } }': () - 49..93 'match ... }': () - 55..56 'b': Bar - 67..80 'Bar { a: .. }': Bar - 76..78 '..': bool - 84..86 '{}': () - "#]], - ); -} - -#[test] -fn issue_4235_name_conflicts() { - check_infer( - r#" - struct FOO {} - static FOO:FOO = FOO {}; - - impl FOO { - fn foo(&self) {} - } - - fn main() { - let a = &FOO; - a.foo(); - } - "#, - expect![[r#" - 31..37 'FOO {}': FOO - 63..67 'self': &FOO - 69..71 '{}': () - 85..119 '{ ...o(); }': () - 95..96 'a': &FOO - 99..103 '&FOO': &FOO - 100..103 'FOO': FOO - 109..110 'a': &FOO - 109..116 'a.foo()': () - "#]], - ); -} - -#[test] -fn issue_4465_dollar_crate_at_type() { - check_infer( - r#" - pub struct Foo {} - pub fn anything() -> T { - loop {} - } - macro_rules! foo { - () => {{ - let r: $crate::Foo = anything(); - r - }}; - } - fn main() { - let _a = foo!(); - } - "#, - expect![[r#" - 44..59 '{ loop {} }': T - 50..57 'loop {}': ! - 55..57 '{}': () - !0..31 '{letr:...g();r}': Foo - !4..5 'r': Foo - !18..26 'anything': fn anything() -> Foo - !18..28 'anything()': Foo - !29..30 'r': Foo - 163..187 '{ ...!(); }': () - 173..175 '_a': Foo - "#]], - ); -} - -#[test] -fn issue_6811() { - check_infer( - r#" - macro_rules! profile_function { - () => { - let _a = 1; - let _b = 1; - }; - } - fn main() { - profile_function!(); - } - "#, - expect![[r#" - !0..16 'let_a=...t_b=1;': () - !3..5 '_a': i32 - !6..7 '1': i32 - !11..13 '_b': i32 - !14..15 '1': i32 - 103..131 '{ ...!(); }': () - "#]], - ); -} - -#[test] -fn issue_4053_diesel_where_clauses() { - check_infer( - r#" - trait BoxedDsl { - type Output; - fn internal_into_boxed(self) -> Self::Output; - } - - struct SelectStatement { - order: Order, - } - - trait QueryFragment {} - - trait Into { fn into(self) -> T; } - - impl BoxedDsl - for SelectStatement - where - O: Into>, - { - type Output = XXX; - - fn internal_into_boxed(self) -> Self::Output { - self.order.into(); - } - } - "#, - expect![[r#" - 65..69 'self': Self - 267..271 'self': Self - 466..470 'self': SelectStatement - 488..522 '{ ... }': () - 498..502 'self': SelectStatement - 498..508 'self.order': O - 498..515 'self.o...into()': dyn QueryFragment - "#]], - ); -} - -#[test] -fn issue_4953() { - check_infer( - r#" - pub struct Foo(pub i64); - impl Foo { - fn test() -> Self { Self(0i64) } - } - "#, - expect![[r#" - 58..72 '{ Self(0i64) }': Foo - 60..64 'Self': Foo(i64) -> Foo - 60..70 'Self(0i64)': Foo - 65..69 '0i64': i64 - "#]], - ); - check_infer( - r#" - pub struct Foo(pub T); - impl Foo { - fn test() -> Self { Self(0i64) } - } - "#, - expect![[r#" - 64..78 '{ Self(0i64) }': Foo - 66..70 'Self': Foo(i64) -> Foo - 66..76 'Self(0i64)': Foo - 71..75 '0i64': i64 - "#]], - ); -} - -#[test] -fn issue_4931() { - check_infer( - r#" - trait Div { - type Output; - } - - trait CheckedDiv: Div<()> {} - - trait PrimInt: CheckedDiv { - fn pow(self); - } - - fn check(i: T) { - i.pow(); - } - "#, - expect![[r#" - 117..121 'self': Self - 148..149 'i': T - 154..170 '{ ...w(); }': () - 160..161 'i': T - 160..167 'i.pow()': () - "#]], - ); -} - -#[test] -fn issue_4885() { - check_infer( - r#" - //- minicore: coerce_unsized, future - use core::future::Future; - trait Foo { - type Bar; - } - fn foo(key: &K) -> impl Future - where - K: Foo, - { - bar(key) - } - fn bar(key: &K) -> impl Future - where - K: Foo, - { - } - "#, - expect![[r#" - 70..73 'key': &K - 132..148 '{ ...key) }': impl Future>::Bar> - 138..141 'bar': fn bar(&K) -> impl Future>::Bar> - 138..146 'bar(key)': impl Future>::Bar> - 142..145 'key': &K - 162..165 'key': &K - 224..227 '{ }': () - "#]], - ); -} - -#[test] -fn issue_4800() { - check_infer( - r#" - trait Debug {} - - struct Foo; - - type E1 = (T, T, T); - type E2 = E1>>; - - impl Debug for Foo> {} - - struct Request; - - pub trait Future { - type Output; - } - - pub struct PeerSet; - - impl Service for PeerSet - where - D: Discover, - D::Key: Debug, - { - type Error = (); - type Future = dyn Future; - - fn call(&mut self) -> Self::Future { - loop {} - } - } - - pub trait Discover { - type Key; - } - - pub trait Service { - type Error; - type Future: Future; - fn call(&mut self) -> Self::Future; - } - "#, - expect![[r#" - 379..383 'self': &mut PeerSet - 401..424 '{ ... }': dyn Future - 411..418 'loop {}': ! - 416..418 '{}': () - 575..579 'self': &mut Self - "#]], - ); -} - -#[test] -fn issue_4966() { - check_infer( - r#" - //- minicore: deref - pub trait IntoIterator { - type Item; - } - - struct Repeat { element: A } - - struct Map { f: F } - - struct Vec {} - - impl core::ops::Deref for Vec { - type Target = [T]; - } - - fn from_iter>(iter: T) -> Vec {} - - fn main() { - let inner = Map { f: |_: &f64| 0.0 }; - - let repeat = Repeat { element: inner }; - - let vec = from_iter(repeat); - - vec.foo_bar(); - } - "#, - expect![[r#" - 225..229 'iter': T - 244..246 '{}': Vec - 258..402 '{ ...r(); }': () - 268..273 'inner': Map<|&f64| -> f64> - 276..300 'Map { ... 0.0 }': Map<|&f64| -> f64> - 285..298 '|_: &f64| 0.0': |&f64| -> f64 - 286..287 '_': &f64 - 295..298 '0.0': f64 - 311..317 'repeat': Repeat f64>> - 320..345 'Repeat...nner }': Repeat f64>> - 338..343 'inner': Map<|&f64| -> f64> - 356..359 'vec': Vec f64>>>> - 362..371 'from_iter': fn from_iter f64>>>, Repeat f64>>>(Repeat f64>>) -> Vec f64>>>> - 362..379 'from_i...epeat)': Vec f64>>>> - 372..378 'repeat': Repeat f64>> - 386..389 'vec': Vec f64>>>> - 386..399 'vec.foo_bar()': {unknown} - "#]], - ); -} - -#[test] -fn issue_6628() { - check_infer( - r#" -//- minicore: fn -struct S(); -impl S { - fn f(&self, _t: T) {} - fn g(&self, _f: F) {} -} -fn main() { - let s = S(); - s.g(|_x| {}); - s.f(10); -} -"#, - expect![[r#" - 40..44 'self': &S - 46..48 '_t': T - 53..55 '{}': () - 81..85 'self': &S - 87..89 '_f': F - 94..96 '{}': () - 109..160 '{ ...10); }': () - 119..120 's': S - 123..124 'S': S() -> S - 123..126 'S()': S - 132..133 's': S - 132..144 's.g(|_x| {})': () - 136..143 '|_x| {}': |&i32| -> () - 137..139 '_x': &i32 - 141..143 '{}': () - 150..151 's': S - 150..157 's.f(10)': () - 154..156 '10': i32 - "#]], - ); -} - -#[test] -fn issue_6852() { - check_infer( - r#" -//- minicore: deref -use core::ops::Deref; - -struct BufWriter {} - -struct Mutex {} -struct MutexGuard<'a, T> {} -impl Mutex { - fn lock(&self) -> MutexGuard<'_, T> {} -} -impl<'a, T: 'a> Deref for MutexGuard<'a, T> { - type Target = T; -} -fn flush(&self) { - let w: &Mutex; - *(w.lock()); -} -"#, - expect![[r#" - 123..127 'self': &Mutex - 150..152 '{}': MutexGuard - 234..238 'self': &{unknown} - 240..290 '{ ...()); }': () - 250..251 'w': &Mutex - 276..287 '*(w.lock())': BufWriter - 278..279 'w': &Mutex - 278..286 'w.lock()': MutexGuard - "#]], - ); -} - -#[test] -fn param_overrides_fn() { - check_types( - r#" - fn example(example: i32) { - fn f() {} - example; - //^^^^^^^ i32 - } - "#, - ) -} - -#[test] -fn lifetime_from_chalk_during_deref() { - check_types( - r#" -//- minicore: deref -struct Box {} -impl core::ops::Deref for Box { - type Target = T; - - fn deref(&self) -> &Self::Target { - loop {} - } -} - -trait Iterator { - type Item; -} - -pub struct Iter<'a, T: 'a> { - inner: Box + 'a>, -} - -trait IterTrait<'a, T: 'a>: Iterator { - fn clone_box(&self); -} - -fn clone_iter(s: Iter) { - s.inner.clone_box(); - //^^^^^^^^^^^^^^^^^^^ () -} -"#, - ) -} - -#[test] -fn issue_8686() { - check_infer( - r#" -pub trait Try: FromResidual { - type Output; - type Residual; -} -pub trait FromResidual::Residual> { - fn from_residual(residual: R) -> Self; -} - -struct ControlFlow; -impl Try for ControlFlow { - type Output = C; - type Residual = ControlFlow; -} -impl FromResidual for ControlFlow { - fn from_residual(r: ControlFlow) -> Self { ControlFlow } -} - -fn test() { - ControlFlow::from_residual(ControlFlow::); -} - "#, - expect![[r#" - 144..152 'residual': R - 365..366 'r': ControlFlow - 395..410 '{ ControlFlow }': ControlFlow - 397..408 'ControlFlow': ControlFlow - 424..482 '{ ...!>); }': () - 430..456 'Contro...sidual': fn from_residual, ControlFlow>(ControlFlow) -> ControlFlow - 430..479 'Contro...2, !>)': ControlFlow - 457..478 'Contro...32, !>': ControlFlow - "#]], - ); -} - -#[test] -fn cfg_tail() { - // https://github.com/rust-lang/rust-analyzer/issues/8378 - check_infer( - r#" - fn fake_tail(){ - { "first" } - #[cfg(never)] 9 - } - fn multiple_fake(){ - { "fake" } - { "fake" } - { "second" } - #[cfg(never)] { 11 } - #[cfg(never)] 12; - #[cfg(never)] 13 - } - fn no_normal_tail(){ - { "third" } - #[cfg(never)] 14; - #[cfg(never)] 15; - } - fn no_actual_tail(){ - { "fourth" }; - #[cfg(never)] 14; - #[cfg(never)] 15 - } - "#, - expect![[r#" - 14..53 '{ ...)] 9 }': () - 20..31 '{ "first" }': () - 22..29 '"first"': &str - 72..190 '{ ...] 13 }': () - 78..88 '{ "fake" }': &str - 80..86 '"fake"': &str - 93..103 '{ "fake" }': &str - 95..101 '"fake"': &str - 108..120 '{ "second" }': () - 110..118 '"second"': &str - 210..273 '{ ... 15; }': () - 216..227 '{ "third" }': () - 218..225 '"third"': &str - 293..357 '{ ...] 15 }': () - 299..311 '{ "fourth" }': &str - 301..309 '"fourth"': &str - "#]], - ) -} - -#[test] -fn impl_trait_in_option_9530() { - check_types( - r#" -//- minicore: sized -struct Option; -impl Option { - fn unwrap(self) -> T { loop {} } -} -fn make() -> Option { Option } -trait Copy {} -fn test() { - let o = make(); - o.unwrap(); - //^^^^^^^^^^ impl Copy -} - "#, - ) -} - -#[test] -fn bare_dyn_trait_binders_9639() { - check_no_mismatches( - r#" -//- minicore: fn, coerce_unsized -fn infix_parse(_state: S, _level_code: &Fn(S)) -> T { - loop {} -} - -fn parse_arule() { - infix_parse((), &(|_recurse| ())) -} - "#, - ) -} - -#[test] -fn call_expected_type_closure() { - check_types( - r#" -//- minicore: fn, option - -fn map(o: Option, f: impl FnOnce(T) -> U) -> Option { loop {} } -struct S { - field: u32 -} - -fn test() { - let o = Some(S { field: 2 }); - let _: Option<()> = map(o, |s| { s.field; }); - // ^^^^^^^ u32 -} - "#, - ); -} - -#[test] -fn coerce_diesel_panic() { - check_no_mismatches( - r#" -//- minicore: option - -trait TypeMetadata { - type MetadataLookup; -} - -pub struct Output<'a, T, DB> -where - DB: TypeMetadata, - DB::MetadataLookup: 'a, -{ - out: T, - metadata_lookup: Option<&'a DB::MetadataLookup>, -} - -impl<'a, T, DB: TypeMetadata> Output<'a, T, DB> { - pub fn new(out: T, metadata_lookup: &'a DB::MetadataLookup) -> Self { - Output { - out, - metadata_lookup: Some(metadata_lookup), - } - } -} - "#, - ); -} - -#[test] -fn bitslice_panic() { - check_no_mismatches( - r#" -//- minicore: option, deref - -pub trait BitView { - type Store; -} - -pub struct Lsb0; - -pub struct BitArray { } - -pub struct BitSlice { } - -impl core::ops::Deref for BitArray { - type Target = BitSlice; -} - -impl BitSlice { - pub fn split_first(&self) -> Option<(T, &Self)> { loop {} } -} - -fn multiexp_inner() { - let exp: &BitArray; - exp.split_first(); -} - "#, - ); -} - -#[test] -fn macro_expands_to_impl_trait() { - check_no_mismatches( - r#" -trait Foo {} - -macro_rules! ty { - () => { - impl Foo - } -} - -fn foo(_: ty!()) {} - -fn bar() { - foo(()); -} - "#, - ) -} - -#[test] -fn nested_macro_in_fn_params() { - check_no_mismatches( - r#" -macro_rules! U32Inner { - () => { - u32 - }; -} - -macro_rules! U32 { - () => { - U32Inner!() - }; -} - -fn mamba(a: U32!(), p: u32) -> u32 { - a -} - "#, - ) -} - -#[test] -fn for_loop_block_expr_iterable() { - check_infer( - r#" -fn test() { - for _ in { let x = 0; } { - let y = 0; - } -} - "#, - expect![[r#" - 10..68 '{ ... } }': () - 16..66 'for _ ... }': () - 20..21 '_': {unknown} - 25..39 '{ let x = 0; }': () - 31..32 'x': i32 - 35..36 '0': i32 - 40..66 '{ ... }': () - 54..55 'y': i32 - 58..59 '0': i32 - "#]], - ); -} - -#[test] -fn while_loop_block_expr_iterable() { - check_infer( - r#" -fn test() { - while { true } { - let y = 0; - } -} - "#, - expect![[r#" - 10..59 '{ ... } }': () - 16..57 'while ... }': () - 22..30 '{ true }': bool - 24..28 'true': bool - 31..57 '{ ... }': () - 45..46 'y': i32 - 49..50 '0': i32 - "#]], - ); -} - -#[test] -fn bug_11242() { - // FIXME: wrong, should be u32 - check_types( - r#" -fn foo() -where - A: IntoIterator, - B: IntoIterator, -{ - let _x: ::Item; - // ^^ {unknown} -} - -pub trait Iterator { - type Item; -} - -pub trait IntoIterator { - type Item; - type IntoIter: Iterator; -} - -impl IntoIterator for I { - type Item = I::Item; - type IntoIter = I; -} -"#, - ); -} - -#[test] -fn bug_11659() { - check_no_mismatches( - r#" -struct LinkArray(LD); -fn f(x: LD) -> LinkArray { - let r = LinkArray::(x); - r -} - -fn test() { - let x = f::<2, i32>(5); - let y = LinkArray::<52, LinkArray<2, i32>>(x); -} - "#, - ); - check_no_mismatches( - r#" -struct LinkArray(LD); -fn f(x: LD) -> LinkArray { - let r = LinkArray::(x); - r -} - -fn test() { - let x = f::(5); - let y = LinkArray::, 52>(x); -} - "#, - ); -} - -#[test] -fn const_generic_error_tolerance() { - check_no_mismatches( - r#" -#[lang = "sized"] -pub trait Sized {} - -struct CT(T); -struct TC(T); -fn f(x: T) -> (CT, TC) { - let l = CT::(x); - let r = TC::(x); - (l, r) -} - -trait TR1; -trait TR2; - -impl TR1 for CT; -impl TR1<5> for TC; -impl TR2 for CT; - -trait TR3 { - fn tr3(&self) -> &Self; -} - -impl TR3<5> for TC { - fn tr3(&self) -> &Self { - self - } -} - -impl TR3 for TC {} -impl TR3 for TC {} - -fn impl_trait(inp: impl TR1) {} -fn dyn_trait(inp: &dyn TR2) {} -fn impl_trait_bad<'a, const N: usize>(inp: impl TR1) -> impl TR1<'a, i32> {} -fn impl_trait_very_bad(inp: impl TR1) -> impl TR1<'a, Item = i32, 5, Foo = N> {} - -fn test() { - f::<2, i32>(5); - f::<2, 2>(5); - f(5); - f::(5); - CT::<52, CT<2, i32>>(x); - CT::>(x); - impl_trait_bad(5); - impl_trait_bad(12); - TR3<5>::tr3(); - TR3<{ 2+3 }>::tr3(); - TC::(5).tr3(); - TC::(5).tr3(); - TC::(5).tr3(); - TC::(5).tr3(); -} - "#, - ); -} - -#[test] -fn const_generic_impl_trait() { - check_no_mismatches( - r#" - //- minicore: from - - struct Foo; - - trait Tr { - fn f(T) -> Self; - } - - impl Tr<[T; M]> for Foo { - fn f(_: [T; M]) -> Self { - Self - } - } - - fn test() { - Foo::f([1, 2, 7, 10]); - } - "#, - ); -} - -#[test] -fn nalgebra_factorial() { - check_no_mismatches( - r#" - const FACTORIAL: [u128; 4] = [1, 1, 2, 6]; - - fn factorial(n: usize) -> u128 { - match FACTORIAL.get(n) { - Some(f) => *f, - None => panic!("{}! is greater than u128::MAX", n), - } - } - "#, - ) -} - -#[test] -fn regression_11688_1() { - check_no_mismatches( - r#" - pub struct Buffer(T); - type Writer = Buffer; - impl Buffer { - fn extend_from_array(&mut self, xs: &[T; N]) { - loop {} - } - } - trait Encode { - fn encode(self, w: &mut Writer, s: &mut S); - } - impl Encode for u8 { - fn encode(self, w: &mut Writer, _: &mut S) { - w.extend_from_array(&self.to_le_bytes()); - } - } - "#, - ); -} - -#[test] -fn regression_11688_2() { - check_types( - r#" - union MaybeUninit { - uninit: (), - value: T, - } - - impl MaybeUninit { - fn uninit_array() -> [Self; LEN] { - loop {} - } - } - - fn main() { - let x = MaybeUninit::::uninit_array::<1>(); - //^ [MaybeUninit; 1] - } - "#, - ); -} - -#[test] -fn regression_11688_3() { - check_types( - r#" - //- minicore: iterator - struct Ar(T); - fn f( - num_zeros: usize, - ) -> dyn Iterator; LEN]> { - loop {} - } - fn dynamic_programming() { - for board in f::<9, u8, 7>(1) { - //^^^^^ [Ar; 9] - } - } - "#, - ); -} - -#[test] -fn regression_11688_4() { - check_types( - r#" - trait Bar { - fn baz(&self) -> [i32; C]; - } - - fn foo(x: &dyn Bar<2>) { - x.baz(); - //^^^^^^^ [i32; 2] - } - "#, - ) -} - -#[test] -fn gat_crash_1() { - cov_mark::check!(ignore_gats); - check_no_mismatches( - r#" -trait ATrait {} - -trait Crash { - type Member: ATrait; - fn new() -> Self::Member; -} - -fn test() { - T::new(); -} -"#, - ); -} - -#[test] -fn gat_crash_2() { - check_no_mismatches( - r#" -pub struct InlineStorage {} - -pub struct InlineStorageHandle {} - -pub unsafe trait Storage { - type Handle; - fn create() -> Self::Handle; -} - -unsafe impl Storage for InlineStorage { - type Handle = InlineStorageHandle; -} -"#, - ); -} - -#[test] -fn cfgd_out_self_param() { - cov_mark::check!(cfgd_out_self_param); - check_no_mismatches( - r#" -struct S; -impl S { - fn f(#[cfg(never)] &self) {} -} - -fn f(s: S) { - s.f(); -} -"#, - ); -} - -#[test] -fn rust_161_option_clone() { - check_types( - r#" -//- minicore: option, drop - -fn test(o: &Option) { - o.my_clone(); - //^^^^^^^^^^^^ Option -} - -pub trait MyClone: Sized { - fn my_clone(&self) -> Self; -} - -impl const MyClone for Option -where - T: ~const MyClone + ~const Drop + ~const Destruct, -{ - fn my_clone(&self) -> Self { - match self { - Some(x) => Some(x.my_clone()), - None => None, - } - } -} - -impl const MyClone for i32 { - fn my_clone(&self) -> Self { - *self - } -} - -pub trait Destruct {} - -impl const Destruct for T {} -"#, - ); -} - -#[test] -fn rust_162_option_clone() { - check_types( - r#" -//- minicore: option, drop - -fn test(o: &Option) { - o.my_clone(); - //^^^^^^^^^^^^ Option -} - -pub trait MyClone: Sized { - fn my_clone(&self) -> Self; -} - -impl const MyClone for Option -where - T: ~const MyClone + ~const Destruct, -{ - fn my_clone(&self) -> Self { - match self { - Some(x) => Some(x.my_clone()), - None => None, - } - } -} - -impl const MyClone for i32 { - fn my_clone(&self) -> Self { - *self - } -} - -#[lang = "destruct"] -pub trait Destruct {} -"#, - ); -} - -#[test] -fn tuple_struct_pattern_with_unmatched_args_crash() { - check_infer( - r#" -struct S(usize); -fn main() { - let S(.., a, b) = S(1); - let (.., a, b) = (1,); -} - "#, - expect![[r#" - 27..85 '{ ...1,); }': () - 37..48 'S(.., a, b)': S - 43..44 'a': usize - 46..47 'b': {unknown} - 51..52 'S': S(usize) -> S - 51..55 'S(1)': S - 53..54 '1': usize - 65..75 '(.., a, b)': (i32, {unknown}) - 70..71 'a': i32 - 73..74 'b': {unknown} - 78..82 '(1,)': (i32,) - 79..80 '1': i32 - "#]], - ); -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs deleted file mode 100644 index 5b08f552109ef..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ /dev/null @@ -1,3072 +0,0 @@ -use expect_test::expect; - -use super::{check, check_infer, check_no_mismatches, check_types}; - -#[test] -fn infer_box() { - check_types( - r#" -//- /main.rs crate:main deps:std -fn test() { - let x = box 1; - let t = (x, box x, box &1, box [1]); - t; -} //^ (Box, Box>, Box<&i32>, Box<[i32; 1]>) - -//- /std.rs crate:std -#[prelude_import] use prelude::*; -mod prelude {} - -mod boxed { - #[lang = "owned_box"] - pub struct Box { - inner: *mut T, - } -} -"#, - ); -} - -#[test] -fn infer_box_with_allocator() { - check_types( - r#" -//- /main.rs crate:main deps:std -fn test() { - let x = box 1; - let t = (x, box x, box &1, box [1]); - t; -} //^ (Box, Box, {unknown}>, Box<&i32, {unknown}>, Box<[i32; 1], {unknown}>) - -//- /std.rs crate:std -#[prelude_import] use prelude::*; -mod boxed { - #[lang = "owned_box"] - pub struct Box { - inner: *mut T, - allocator: A, - } -} -"#, - ); -} - -#[test] -fn infer_adt_self() { - check_types( - r#" -enum Nat { Succ(Self), Demo(Nat), Zero } - -fn test() { - let foo: Nat = Nat::Zero; - if let Nat::Succ(x) = foo { - x; - } //^ Nat -} -"#, - ); -} - -#[test] -fn self_in_struct_lit() { - check_infer( - r#" - //- /main.rs - struct S { x: T } - - impl S { - fn foo() { - Self { x: 1 }; - } - } - "#, - expect![[r#" - 49..79 '{ ... }': () - 59..72 'Self { x: 1 }': S - 69..70 '1': u32 - "#]], - ); -} - -#[test] -fn type_alias_in_struct_lit() { - check_infer( - r#" - //- /main.rs - struct S { x: T } - - type SS = S; - - fn foo() { - SS { x: 1 }; - } - "#, - expect![[r#" - 50..70 '{ ...1 }; }': () - 56..67 'SS { x: 1 }': S - 64..65 '1': u32 - "#]], - ); -} - -#[test] -fn infer_ranges() { - check_types( - r#" -//- minicore: range -fn test() { - let a = ..; - let b = 1..; - let c = ..2u32; - let d = 1..2usize; - let e = ..=10; - let f = 'a'..='z'; - - let t = (a, b, c, d, e, f); - t; -} //^ (RangeFull, RangeFrom, RangeTo, Range, RangeToInclusive, RangeInclusive) -"#, - ); -} - -#[test] -fn infer_while_let() { - check_types( - r#" -enum Option { Some(T), None } - -fn test() { - let foo: Option = None; - while let Option::Some(x) = foo { - x; - } //^ f32 -} -"#, - ); -} - -#[test] -fn infer_basics() { - check_infer( - r#" -fn test(a: u32, b: isize, c: !, d: &str) { - a; - b; - c; - d; - 1usize; - 1isize; - "test"; - 1.0f32; -} -"#, - expect![[r#" - 8..9 'a': u32 - 16..17 'b': isize - 26..27 'c': ! - 32..33 'd': &str - 41..120 '{ ...f32; }': () - 47..48 'a': u32 - 54..55 'b': isize - 61..62 'c': ! - 68..69 'd': &str - 75..81 '1usize': usize - 87..93 '1isize': isize - 99..105 '"test"': &str - 111..117 '1.0f32': f32 - "#]], - ); -} - -#[test] -fn infer_let() { - check_infer( - r#" -fn test() { - let a = 1isize; - let b: usize = 1; - let c = b; - let d: u32; - let e; - let f: i32 = e; -} -"#, - expect![[r#" - 10..117 '{ ...= e; }': () - 20..21 'a': isize - 24..30 '1isize': isize - 40..41 'b': usize - 51..52 '1': usize - 62..63 'c': usize - 66..67 'b': usize - 77..78 'd': u32 - 93..94 'e': i32 - 104..105 'f': i32 - 113..114 'e': i32 - "#]], - ); -} - -#[test] -fn infer_paths() { - check_infer( - r#" -fn a() -> u32 { 1 } - -mod b { - fn c() -> u32 { 1 } -} - -fn test() { - a(); - b::c(); -} -"#, - expect![[r#" - 14..19 '{ 1 }': u32 - 16..17 '1': u32 - 47..52 '{ 1 }': u32 - 49..50 '1': u32 - 66..90 '{ ...c(); }': () - 72..73 'a': fn a() -> u32 - 72..75 'a()': u32 - 81..85 'b::c': fn c() -> u32 - 81..87 'b::c()': u32 - "#]], - ); -} - -#[test] -fn infer_path_type() { - check_infer( - r#" -struct S; - -impl S { - fn foo() -> i32 { 1 } -} - -fn test() { - S::foo(); - ::foo(); -} -"#, - expect![[r#" - 40..45 '{ 1 }': i32 - 42..43 '1': i32 - 59..92 '{ ...o(); }': () - 65..71 'S::foo': fn foo() -> i32 - 65..73 'S::foo()': i32 - 79..87 '::foo': fn foo() -> i32 - 79..89 '::foo()': i32 - "#]], - ); -} - -#[test] -fn infer_struct() { - check_infer( - r#" -struct A { - b: B, - c: C, -} -struct B; -struct C(usize); - -fn test() { - let c = C(1); - B; - let a: A = A { b: B, c: C(1) }; - a.b; - a.c; -} -"#, - expect![[r#" - 71..153 '{ ...a.c; }': () - 81..82 'c': C - 85..86 'C': C(usize) -> C - 85..89 'C(1)': C - 87..88 '1': usize - 95..96 'B': B - 106..107 'a': A - 113..132 'A { b:...C(1) }': A - 120..121 'B': B - 126..127 'C': C(usize) -> C - 126..130 'C(1)': C - 128..129 '1': usize - 138..139 'a': A - 138..141 'a.b': B - 147..148 'a': A - 147..150 'a.c': C - "#]], - ); -} - -#[test] -fn infer_enum() { - check_infer( - r#" -enum E { - V1 { field: u32 }, - V2 -} -fn test() { - E::V1 { field: 1 }; - E::V2; -} -"#, - expect![[r#" - 51..89 '{ ...:V2; }': () - 57..75 'E::V1 ...d: 1 }': E - 72..73 '1': u32 - 81..86 'E::V2': E - "#]], - ); -} - -#[test] -fn infer_union() { - check_infer( - r#" -union MyUnion { - foo: u32, - bar: f32, -} - -fn test() { - let u = MyUnion { foo: 0 }; - unsafe { baz(u); } - let u = MyUnion { bar: 0.0 }; - unsafe { baz(u); } -} - -unsafe fn baz(u: MyUnion) { - let inner = u.foo; - let inner = u.bar; -} -"#, - expect![[r#" - 57..172 '{ ...); } }': () - 67..68 'u': MyUnion - 71..89 'MyUnio...o: 0 }': MyUnion - 86..87 '0': u32 - 95..113 'unsafe...(u); }': () - 95..113 'unsafe...(u); }': () - 104..107 'baz': fn baz(MyUnion) - 104..110 'baz(u)': () - 108..109 'u': MyUnion - 122..123 'u': MyUnion - 126..146 'MyUnio... 0.0 }': MyUnion - 141..144 '0.0': f32 - 152..170 'unsafe...(u); }': () - 152..170 'unsafe...(u); }': () - 161..164 'baz': fn baz(MyUnion) - 161..167 'baz(u)': () - 165..166 'u': MyUnion - 188..189 'u': MyUnion - 200..249 '{ ...bar; }': () - 210..215 'inner': u32 - 218..219 'u': MyUnion - 218..223 'u.foo': u32 - 233..238 'inner': f32 - 241..242 'u': MyUnion - 241..246 'u.bar': f32 - "#]], - ); -} - -#[test] -fn infer_refs() { - check_infer( - r#" -fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { - a; - *a; - &a; - &mut a; - b; - *b; - &b; - c; - *c; - d; - *d; -} - "#, - expect![[r#" - 8..9 'a': &u32 - 17..18 'b': &mut u32 - 30..31 'c': *const u32 - 45..46 'd': *mut u32 - 58..149 '{ ... *d; }': () - 64..65 'a': &u32 - 71..73 '*a': u32 - 72..73 'a': &u32 - 79..81 '&a': &&u32 - 80..81 'a': &u32 - 87..93 '&mut a': &mut &u32 - 92..93 'a': &u32 - 99..100 'b': &mut u32 - 106..108 '*b': u32 - 107..108 'b': &mut u32 - 114..116 '&b': &&mut u32 - 115..116 'b': &mut u32 - 122..123 'c': *const u32 - 129..131 '*c': u32 - 130..131 'c': *const u32 - 137..138 'd': *mut u32 - 144..146 '*d': u32 - 145..146 'd': *mut u32 - "#]], - ); -} - -#[test] -fn infer_raw_ref() { - check_infer( - r#" -fn test(a: i32) { - &raw mut a; - &raw const a; -} -"#, - expect![[r#" - 8..9 'a': i32 - 16..53 '{ ...t a; }': () - 22..32 '&raw mut a': *mut i32 - 31..32 'a': i32 - 38..50 '&raw const a': *const i32 - 49..50 'a': i32 - "#]], - ); -} - -#[test] -fn infer_literals() { - check_infer( - r##" - fn test() { - 5i32; - 5f32; - 5f64; - "hello"; - b"bytes"; - 'c'; - b'b'; - 3.14; - 5000; - false; - true; - r#" - //! doc - // non-doc - mod foo {} - "#; - br#"yolo"#; - let a = b"a\x20b\ - c"; - let b = br"g\ -h"; - let c = br#"x"\"yb"#; - } - "##, - expect![[r##" - 18..478 '{ ... }': () - 32..36 '5i32': i32 - 50..54 '5f32': f32 - 68..72 '5f64': f64 - 86..93 '"hello"': &str - 107..115 'b"bytes"': &[u8; 5] - 129..132 ''c'': char - 146..150 'b'b'': u8 - 164..168 '3.14': f64 - 182..186 '5000': i32 - 200..205 'false': bool - 219..223 'true': bool - 237..333 'r#" ... "#': &str - 347..357 'br#"yolo"#': &[u8; 4] - 375..376 'a': &[u8; 4] - 379..403 'b"a\x2... c"': &[u8; 4] - 421..422 'b': &[u8; 4] - 425..433 'br"g\ h"': &[u8; 4] - 451..452 'c': &[u8; 6] - 455..467 'br#"x"\"yb"#': &[u8; 6] - "##]], - ); -} - -#[test] -fn infer_unary_op() { - check_infer( - r#" -enum SomeType {} - -fn test(x: SomeType) { - let b = false; - let c = !b; - let a = 100; - let d: i128 = -a; - let e = -100; - let f = !!!true; - let g = !42; - let h = !10u32; - let j = !a; - -3.14; - !3; - -x; - !x; - -"hello"; - !"hello"; -} -"#, - expect![[r#" - 26..27 'x': SomeType - 39..271 '{ ...lo"; }': () - 49..50 'b': bool - 53..58 'false': bool - 68..69 'c': bool - 72..74 '!b': bool - 73..74 'b': bool - 84..85 'a': i128 - 88..91 '100': i128 - 101..102 'd': i128 - 111..113 '-a': i128 - 112..113 'a': i128 - 123..124 'e': i32 - 127..131 '-100': i32 - 128..131 '100': i32 - 141..142 'f': bool - 145..152 '!!!true': bool - 146..152 '!!true': bool - 147..152 '!true': bool - 148..152 'true': bool - 162..163 'g': i32 - 166..169 '!42': i32 - 167..169 '42': i32 - 179..180 'h': u32 - 183..189 '!10u32': u32 - 184..189 '10u32': u32 - 199..200 'j': i128 - 203..205 '!a': i128 - 204..205 'a': i128 - 211..216 '-3.14': f64 - 212..216 '3.14': f64 - 222..224 '!3': i32 - 223..224 '3': i32 - 230..232 '-x': {unknown} - 231..232 'x': SomeType - 238..240 '!x': {unknown} - 239..240 'x': SomeType - 246..254 '-"hello"': {unknown} - 247..254 '"hello"': &str - 260..268 '!"hello"': {unknown} - 261..268 '"hello"': &str - "#]], - ); -} - -#[test] -fn infer_backwards() { - check_infer( - r#" -fn takes_u32(x: u32) {} - -struct S { i32_field: i32 } - -fn test() -> &mut &f64 { - let a = unknown_function(); - takes_u32(a); - let b = unknown_function(); - S { i32_field: b }; - let c = unknown_function(); - &mut &c -} -"#, - expect![[r#" - 13..14 'x': u32 - 21..23 '{}': () - 77..230 '{ ...t &c }': &mut &f64 - 87..88 'a': u32 - 91..107 'unknow...nction': {unknown} - 91..109 'unknow...tion()': u32 - 115..124 'takes_u32': fn takes_u32(u32) - 115..127 'takes_u32(a)': () - 125..126 'a': u32 - 137..138 'b': i32 - 141..157 'unknow...nction': {unknown} - 141..159 'unknow...tion()': i32 - 165..183 'S { i3...d: b }': S - 180..181 'b': i32 - 193..194 'c': f64 - 197..213 'unknow...nction': {unknown} - 197..215 'unknow...tion()': f64 - 221..228 '&mut &c': &mut &f64 - 226..228 '&c': &f64 - 227..228 'c': f64 - "#]], - ); -} - -#[test] -fn infer_self() { - check_infer( - r#" -struct S; - -impl S { - fn test(&self) { - self; - } - fn test2(self: &Self) { - self; - } - fn test3() -> Self { - S {} - } - fn test4() -> Self { - Self {} - } -} -"#, - expect![[r#" - 33..37 'self': &S - 39..60 '{ ... }': () - 49..53 'self': &S - 74..78 'self': &S - 87..108 '{ ... }': () - 97..101 'self': &S - 132..152 '{ ... }': S - 142..146 'S {}': S - 176..199 '{ ... }': S - 186..193 'Self {}': S - "#]], - ); -} - -#[test] -fn infer_self_as_path() { - check_infer( - r#" -struct S1; -struct S2(isize); -enum E { - V1, - V2(u32), -} - -impl S1 { - fn test() { - Self; - } -} -impl S2 { - fn test() { - Self(1); - } -} -impl E { - fn test() { - Self::V1; - Self::V2(1); - } -} -"#, - expect![[r#" - 86..107 '{ ... }': () - 96..100 'Self': S1 - 134..158 '{ ... }': () - 144..148 'Self': S2(isize) -> S2 - 144..151 'Self(1)': S2 - 149..150 '1': isize - 184..230 '{ ... }': () - 194..202 'Self::V1': E - 212..220 'Self::V2': V2(u32) -> E - 212..223 'Self::V2(1)': E - 221..222 '1': u32 - "#]], - ); -} - -#[test] -fn infer_binary_op() { - check_infer( - r#" -fn f(x: bool) -> i32 { - 0i32 -} - -fn test() -> bool { - let x = a && b; - let y = true || false; - let z = x == y; - let t = x != y; - let minus_forty: isize = -40isize; - let h = minus_forty <= CONST_2; - let c = f(z || y) + 5; - let d = b; - let g = minus_forty ^= i; - let ten: usize = 10; - let ten_is_eleven = ten == some_num; - - ten < 3 -} -"#, - expect![[r#" - 5..6 'x': bool - 21..33 '{ 0i32 }': i32 - 27..31 '0i32': i32 - 53..369 '{ ... < 3 }': bool - 63..64 'x': bool - 67..68 'a': bool - 67..73 'a && b': bool - 72..73 'b': bool - 83..84 'y': bool - 87..91 'true': bool - 87..100 'true || false': bool - 95..100 'false': bool - 110..111 'z': bool - 114..115 'x': bool - 114..120 'x == y': bool - 119..120 'y': bool - 130..131 't': bool - 134..135 'x': bool - 134..140 'x != y': bool - 139..140 'y': bool - 150..161 'minus_forty': isize - 171..179 '-40isize': isize - 172..179 '40isize': isize - 189..190 'h': bool - 193..204 'minus_forty': isize - 193..215 'minus_...ONST_2': bool - 208..215 'CONST_2': isize - 225..226 'c': i32 - 229..230 'f': fn f(bool) -> i32 - 229..238 'f(z || y)': i32 - 229..242 'f(z || y) + 5': i32 - 231..232 'z': bool - 231..237 'z || y': bool - 236..237 'y': bool - 241..242 '5': i32 - 252..253 'd': {unknown} - 256..257 'b': {unknown} - 267..268 'g': () - 271..282 'minus_forty': isize - 271..287 'minus_...y ^= i': () - 286..287 'i': isize - 297..300 'ten': usize - 310..312 '10': usize - 322..335 'ten_is_eleven': bool - 338..341 'ten': usize - 338..353 'ten == some_num': bool - 345..353 'some_num': usize - 360..363 'ten': usize - 360..367 'ten < 3': bool - 366..367 '3': usize - "#]], - ); -} - -#[test] -fn infer_shift_op() { - check_infer( - r#" -fn test() { - 1u32 << 5u8; - 1u32 >> 5u8; -} -"#, - expect![[r#" - 10..47 '{ ...5u8; }': () - 16..20 '1u32': u32 - 16..27 '1u32 << 5u8': u32 - 24..27 '5u8': u8 - 33..37 '1u32': u32 - 33..44 '1u32 >> 5u8': u32 - 41..44 '5u8': u8 - "#]], - ); -} - -#[test] -fn infer_field_autoderef() { - check_infer( - r#" -struct A { - b: B, -} -struct B; - -fn test1(a: A) { - let a1 = a; - a1.b; - let a2 = &a; - a2.b; - let a3 = &mut a; - a3.b; - let a4 = &&&&&&&a; - a4.b; - let a5 = &mut &&mut &&mut a; - a5.b; -} - -fn test2(a1: *const A, a2: *mut A) { - a1.b; - a2.b; -} -"#, - expect![[r#" - 43..44 'a': A - 49..212 '{ ...5.b; }': () - 59..61 'a1': A - 64..65 'a': A - 71..73 'a1': A - 71..75 'a1.b': B - 85..87 'a2': &A - 90..92 '&a': &A - 91..92 'a': A - 98..100 'a2': &A - 98..102 'a2.b': B - 112..114 'a3': &mut A - 117..123 '&mut a': &mut A - 122..123 'a': A - 129..131 'a3': &mut A - 129..133 'a3.b': B - 143..145 'a4': &&&&&&&A - 148..156 '&&&&&&&a': &&&&&&&A - 149..156 '&&&&&&a': &&&&&&A - 150..156 '&&&&&a': &&&&&A - 151..156 '&&&&a': &&&&A - 152..156 '&&&a': &&&A - 153..156 '&&a': &&A - 154..156 '&a': &A - 155..156 'a': A - 162..164 'a4': &&&&&&&A - 162..166 'a4.b': B - 176..178 'a5': &mut &&mut &&mut A - 181..199 '&mut &...&mut a': &mut &&mut &&mut A - 186..199 '&&mut &&mut a': &&mut &&mut A - 187..199 '&mut &&mut a': &mut &&mut A - 192..199 '&&mut a': &&mut A - 193..199 '&mut a': &mut A - 198..199 'a': A - 205..207 'a5': &mut &&mut &&mut A - 205..209 'a5.b': B - 223..225 'a1': *const A - 237..239 'a2': *mut A - 249..272 '{ ...2.b; }': () - 255..257 'a1': *const A - 255..259 'a1.b': B - 265..267 'a2': *mut A - 265..269 'a2.b': B - "#]], - ); -} - -#[test] -fn infer_argument_autoderef() { - check_infer( - r#" -//- minicore: deref -use core::ops::Deref; -struct A(T); - -impl A { - fn foo(&self) -> &T { - &self.0 - } -} - -struct B(T); - -impl Deref for B { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -fn test() { - let t = A::foo(&&B(B(A(42)))); -} -"#, - expect![[r#" - 66..70 'self': &A - 78..101 '{ ... }': &T - 88..95 '&self.0': &T - 89..93 'self': &A - 89..95 'self.0': T - 182..186 'self': &B - 205..228 '{ ... }': &T - 215..222 '&self.0': &T - 216..220 'self': &B - 216..222 'self.0': T - 242..280 '{ ...))); }': () - 252..253 't': &i32 - 256..262 'A::foo': fn foo(&A) -> &i32 - 256..277 'A::foo...42))))': &i32 - 263..276 '&&B(B(A(42)))': &&B>> - 264..276 '&B(B(A(42)))': &B>> - 265..266 'B': B>>(B>) -> B>> - 265..276 'B(B(A(42)))': B>> - 267..268 'B': B>(A) -> B> - 267..275 'B(A(42))': B> - 269..270 'A': A(i32) -> A - 269..274 'A(42)': A - 271..273 '42': i32 - "#]], - ); -} - -#[test] -fn infer_method_argument_autoderef() { - check_infer( - r#" -//- minicore: deref -use core::ops::Deref; -struct A(*mut T); - -impl A { - fn foo(&self, x: &A) -> &T { - &*x.0 - } -} - -struct B(T); - -impl Deref for B { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -fn test(a: A) { - let t = A(0 as *mut _).foo(&&B(B(a))); -} -"#, - expect![[r#" - 71..75 'self': &A - 77..78 'x': &A - 93..114 '{ ... }': &T - 103..108 '&*x.0': &T - 104..108 '*x.0': T - 105..106 'x': &A - 105..108 'x.0': *mut T - 195..199 'self': &B - 218..241 '{ ... }': &T - 228..235 '&self.0': &T - 229..233 'self': &B - 229..235 'self.0': T - 253..254 'a': A - 264..310 '{ ...))); }': () - 274..275 't': &i32 - 278..279 'A': A(*mut i32) -> A - 278..292 'A(0 as *mut _)': A - 278..307 'A(0 as...B(a)))': &i32 - 280..281 '0': i32 - 280..291 '0 as *mut _': *mut i32 - 297..306 '&&B(B(a))': &&B>> - 298..306 '&B(B(a))': &B>> - 299..300 'B': B>>(B>) -> B>> - 299..306 'B(B(a))': B>> - 301..302 'B': B>(A) -> B> - 301..305 'B(a)': B> - 303..304 'a': A - "#]], - ); -} - -#[test] -fn infer_in_elseif() { - check_infer( - r#" -struct Foo { field: i32 } -fn main(foo: Foo) { - if true { - - } else if false { - foo.field - } -} -"#, - expect![[r#" - 34..37 'foo': Foo - 44..108 '{ ... } }': () - 50..106 'if tru... }': () - 53..57 'true': bool - 58..66 '{ }': () - 72..106 'if fal... }': () - 75..80 'false': bool - 81..106 '{ ... }': () - 91..94 'foo': Foo - 91..100 'foo.field': i32 - "#]], - ) -} - -#[test] -fn infer_if_match_with_return() { - check_infer( - r#" -fn foo() { - let _x1 = if true { - 1 - } else { - return; - }; - let _x2 = if true { - 2 - } else { - return - }; - let _x3 = match true { - true => 3, - _ => { - return; - } - }; - let _x4 = match true { - true => 4, - _ => return - }; -} -"#, - expect![[r#" - 9..322 '{ ... }; }': () - 19..22 '_x1': i32 - 25..79 'if tru... }': i32 - 28..32 'true': bool - 33..50 '{ ... }': i32 - 43..44 '1': i32 - 56..79 '{ ... }': i32 - 66..72 'return': ! - 89..92 '_x2': i32 - 95..148 'if tru... }': i32 - 98..102 'true': bool - 103..120 '{ ... }': i32 - 113..114 '2': i32 - 126..148 '{ ... }': ! - 136..142 'return': ! - 158..161 '_x3': i32 - 164..246 'match ... }': i32 - 170..174 'true': bool - 185..189 'true': bool - 185..189 'true': bool - 193..194 '3': i32 - 204..205 '_': bool - 209..240 '{ ... }': i32 - 223..229 'return': ! - 256..259 '_x4': i32 - 262..319 'match ... }': i32 - 268..272 'true': bool - 283..287 'true': bool - 283..287 'true': bool - 291..292 '4': i32 - 302..303 '_': bool - 307..313 'return': ! - "#]], - ) -} - -#[test] -fn infer_inherent_method() { - check_infer( - r#" - struct A; - - impl A { - fn foo(self, x: u32) -> i32 {} - } - - mod b { - impl super::A { - pub fn bar(&self, x: u64) -> i64 {} - } - } - - fn test(a: A) { - a.foo(1); - (&a).bar(1); - a.bar(1); - } - "#, - expect![[r#" - 31..35 'self': A - 37..38 'x': u32 - 52..54 '{}': i32 - 106..110 'self': &A - 112..113 'x': u64 - 127..129 '{}': i64 - 147..148 'a': A - 153..201 '{ ...(1); }': () - 159..160 'a': A - 159..167 'a.foo(1)': i32 - 165..166 '1': u32 - 173..184 '(&a).bar(1)': i64 - 174..176 '&a': &A - 175..176 'a': A - 182..183 '1': u64 - 190..191 'a': A - 190..198 'a.bar(1)': i64 - 196..197 '1': u64 - "#]], - ); -} - -#[test] -fn infer_inherent_method_str() { - check_infer( - r#" - #[lang = "str"] - impl str { - fn foo(&self) -> i32 {} - } - - fn test() { - "foo".foo(); - } - "#, - expect![[r#" - 39..43 'self': &str - 52..54 '{}': i32 - 68..88 '{ ...o(); }': () - 74..79 '"foo"': &str - 74..85 '"foo".foo()': i32 - "#]], - ); -} - -#[test] -fn infer_tuple() { - check_infer( - r#" - fn test(x: &str, y: isize) { - let a: (u32, &str) = (1, "a"); - let b = (a, x); - let c = (y, x); - let d = (c, x); - let e = (1, "e"); - let f = (e, "d"); - } - "#, - expect![[r#" - 8..9 'x': &str - 17..18 'y': isize - 27..169 '{ ...d"); }': () - 37..38 'a': (u32, &str) - 54..62 '(1, "a")': (u32, &str) - 55..56 '1': u32 - 58..61 '"a"': &str - 72..73 'b': ((u32, &str), &str) - 76..82 '(a, x)': ((u32, &str), &str) - 77..78 'a': (u32, &str) - 80..81 'x': &str - 92..93 'c': (isize, &str) - 96..102 '(y, x)': (isize, &str) - 97..98 'y': isize - 100..101 'x': &str - 112..113 'd': ((isize, &str), &str) - 116..122 '(c, x)': ((isize, &str), &str) - 117..118 'c': (isize, &str) - 120..121 'x': &str - 132..133 'e': (i32, &str) - 136..144 '(1, "e")': (i32, &str) - 137..138 '1': i32 - 140..143 '"e"': &str - 154..155 'f': ((i32, &str), &str) - 158..166 '(e, "d")': ((i32, &str), &str) - 159..160 'e': (i32, &str) - 162..165 '"d"': &str - "#]], - ); -} - -#[test] -fn infer_array() { - check_infer( - r#" - fn test(x: &str, y: isize) { - let a = [x]; - let b = [a, a]; - let c = [b, b]; - - let d = [y, 1, 2, 3]; - let d = [1, y, 2, 3]; - let e = [y]; - let f = [d, d]; - let g = [e, e]; - - let h = [1, 2]; - let i = ["a", "b"]; - - let b = [a, ["b"]]; - let x: [u8; 0] = []; - let y: [u8; 2+2] = [1,2,3,4]; - } - "#, - expect![[r#" - 8..9 'x': &str - 17..18 'y': isize - 27..326 '{ ...,4]; }': () - 37..38 'a': [&str; 1] - 41..44 '[x]': [&str; 1] - 42..43 'x': &str - 54..55 'b': [[&str; 1]; 2] - 58..64 '[a, a]': [[&str; 1]; 2] - 59..60 'a': [&str; 1] - 62..63 'a': [&str; 1] - 74..75 'c': [[[&str; 1]; 2]; 2] - 78..84 '[b, b]': [[[&str; 1]; 2]; 2] - 79..80 'b': [[&str; 1]; 2] - 82..83 'b': [[&str; 1]; 2] - 95..96 'd': [isize; 4] - 99..111 '[y, 1, 2, 3]': [isize; 4] - 100..101 'y': isize - 103..104 '1': isize - 106..107 '2': isize - 109..110 '3': isize - 121..122 'd': [isize; 4] - 125..137 '[1, y, 2, 3]': [isize; 4] - 126..127 '1': isize - 129..130 'y': isize - 132..133 '2': isize - 135..136 '3': isize - 147..148 'e': [isize; 1] - 151..154 '[y]': [isize; 1] - 152..153 'y': isize - 164..165 'f': [[isize; 4]; 2] - 168..174 '[d, d]': [[isize; 4]; 2] - 169..170 'd': [isize; 4] - 172..173 'd': [isize; 4] - 184..185 'g': [[isize; 1]; 2] - 188..194 '[e, e]': [[isize; 1]; 2] - 189..190 'e': [isize; 1] - 192..193 'e': [isize; 1] - 205..206 'h': [i32; 2] - 209..215 '[1, 2]': [i32; 2] - 210..211 '1': i32 - 213..214 '2': i32 - 225..226 'i': [&str; 2] - 229..239 '["a", "b"]': [&str; 2] - 230..233 '"a"': &str - 235..238 '"b"': &str - 250..251 'b': [[&str; 1]; 2] - 254..264 '[a, ["b"]]': [[&str; 1]; 2] - 255..256 'a': [&str; 1] - 258..263 '["b"]': [&str; 1] - 259..262 '"b"': &str - 274..275 'x': [u8; 0] - 287..289 '[]': [u8; 0] - 299..300 'y': [u8; 4] - 314..323 '[1,2,3,4]': [u8; 4] - 315..316 '1': u8 - 317..318 '2': u8 - 319..320 '3': u8 - 321..322 '4': u8 - "#]], - ); -} - -#[test] -fn infer_struct_generics() { - check_infer( - r#" - struct A { - x: T, - } - - fn test(a1: A, i: i32) { - a1.x; - let a2 = A { x: i }; - a2.x; - let a3 = A:: { x: 1 }; - a3.x; - } - "#, - expect![[r#" - 35..37 'a1': A - 47..48 'i': i32 - 55..146 '{ ...3.x; }': () - 61..63 'a1': A - 61..65 'a1.x': u32 - 75..77 'a2': A - 80..90 'A { x: i }': A - 87..88 'i': i32 - 96..98 'a2': A - 96..100 'a2.x': i32 - 110..112 'a3': A - 115..133 'A:: - 130..131 '1': i128 - 139..141 'a3': A - 139..143 'a3.x': i128 - "#]], - ); -} - -#[test] -fn infer_tuple_struct_generics() { - check_infer( - r#" - struct A(T); - enum Option { Some(T), None } - use Option::*; - - fn test() { - A(42); - A(42u128); - Some("x"); - Option::Some("x"); - None; - let x: Option = None; - } - "#, - expect![[r#" - 75..183 '{ ...one; }': () - 81..82 'A': A(i32) -> A - 81..86 'A(42)': A - 83..85 '42': i32 - 92..93 'A': A(u128) -> A - 92..101 'A(42u128)': A - 94..100 '42u128': u128 - 107..111 'Some': Some<&str>(&str) -> Option<&str> - 107..116 'Some("x")': Option<&str> - 112..115 '"x"': &str - 122..134 'Option::Some': Some<&str>(&str) -> Option<&str> - 122..139 'Option...e("x")': Option<&str> - 135..138 '"x"': &str - 145..149 'None': Option<{unknown}> - 159..160 'x': Option - 176..180 'None': Option - "#]], - ); -} - -#[test] -fn infer_function_generics() { - check_infer( - r#" - fn id(t: T) -> T { t } - - fn test() { - id(1u32); - id::(1); - let x: u64 = id(1); - } - "#, - expect![[r#" - 9..10 't': T - 20..25 '{ t }': T - 22..23 't': T - 37..97 '{ ...(1); }': () - 43..45 'id': fn id(u32) -> u32 - 43..51 'id(1u32)': u32 - 46..50 '1u32': u32 - 57..67 'id::': fn id(i128) -> i128 - 57..70 'id::(1)': i128 - 68..69 '1': i128 - 80..81 'x': u64 - 89..91 'id': fn id(u64) -> u64 - 89..94 'id(1)': u64 - 92..93 '1': u64 - "#]], - ); -} - -#[test] -fn infer_impl_generics_basic() { - check_infer( - r#" - struct A { - x: T1, - y: T2, - } - impl A { - fn x(self) -> X { - self.x - } - fn y(self) -> Y { - self.y - } - fn z(self, t: T) -> (X, Y, T) { - (self.x, self.y, t) - } - } - - fn test() -> i128 { - let a = A { x: 1u64, y: 1i64 }; - a.x(); - a.y(); - a.z(1i128); - a.z::(1); - } - "#, - expect![[r#" - 73..77 'self': A - 84..106 '{ ... }': X - 94..98 'self': A - 94..100 'self.x': X - 116..120 'self': A - 127..149 '{ ... }': Y - 137..141 'self': A - 137..143 'self.y': Y - 162..166 'self': A - 168..169 't': T - 187..222 '{ ... }': (X, Y, T) - 197..216 '(self.....y, t)': (X, Y, T) - 198..202 'self': A - 198..204 'self.x': X - 206..210 'self': A - 206..212 'self.y': Y - 214..215 't': T - 244..341 '{ ...(1); }': i128 - 254..255 'a': A - 258..280 'A { x:...1i64 }': A - 265..269 '1u64': u64 - 274..278 '1i64': i64 - 286..287 'a': A - 286..291 'a.x()': u64 - 297..298 'a': A - 297..302 'a.y()': i64 - 308..309 'a': A - 308..318 'a.z(1i128)': (u64, i64, i128) - 312..317 '1i128': i128 - 324..325 'a': A - 324..338 'a.z::(1)': (u64, i64, u128) - 336..337 '1': u128 - "#]], - ); -} - -#[test] -fn infer_impl_generics_with_autoderef() { - check_infer( - r#" - enum Option { - Some(T), - None, - } - impl Option { - fn as_ref(&self) -> Option<&T> {} - } - fn test(o: Option) { - (&o).as_ref(); - o.as_ref(); - } - "#, - expect![[r#" - 77..81 'self': &Option - 97..99 '{}': Option<&T> - 110..111 'o': Option - 126..164 '{ ...f(); }': () - 132..145 '(&o).as_ref()': Option<&u32> - 133..135 '&o': &Option - 134..135 'o': Option - 151..152 'o': Option - 151..161 'o.as_ref()': Option<&u32> - "#]], - ); -} - -#[test] -fn infer_generic_chain() { - check_infer( - r#" - struct A { - x: T, - } - impl A { - fn x(self) -> T2 { - self.x - } - } - fn id(t: T) -> T { t } - - fn test() -> i128 { - let x = 1; - let y = id(x); - let a = A { x: id(y) }; - let z = id(a.x); - let b = A { x: z }; - b.x() - } - "#, - expect![[r#" - 52..56 'self': A - 64..86 '{ ... }': T2 - 74..78 'self': A - 74..80 'self.x': T2 - 98..99 't': T - 109..114 '{ t }': T - 111..112 't': T - 134..254 '{ ....x() }': i128 - 144..145 'x': i128 - 148..149 '1': i128 - 159..160 'y': i128 - 163..165 'id': fn id(i128) -> i128 - 163..168 'id(x)': i128 - 166..167 'x': i128 - 178..179 'a': A - 182..196 'A { x: id(y) }': A - 189..191 'id': fn id(i128) -> i128 - 189..194 'id(y)': i128 - 192..193 'y': i128 - 206..207 'z': i128 - 210..212 'id': fn id(i128) -> i128 - 210..217 'id(a.x)': i128 - 213..214 'a': A - 213..216 'a.x': i128 - 227..228 'b': A - 231..241 'A { x: z }': A - 238..239 'z': i128 - 247..248 'b': A - 247..252 'b.x()': i128 - "#]], - ); -} - -#[test] -fn infer_associated_const() { - check_infer( - r#" - struct Struct; - - impl Struct { - const FOO: u32 = 1; - } - - enum Enum {} - - impl Enum { - const BAR: u32 = 2; - } - - trait Trait { - const ID: u32; - } - - struct TraitTest; - - impl Trait for TraitTest { - const ID: u32 = 5; - } - - fn test() { - let x = Struct::FOO; - let y = Enum::BAR; - let z = TraitTest::ID; - } - "#, - expect![[r#" - 51..52 '1': u32 - 104..105 '2': u32 - 212..213 '5': u32 - 228..306 '{ ...:ID; }': () - 238..239 'x': u32 - 242..253 'Struct::FOO': u32 - 263..264 'y': u32 - 267..276 'Enum::BAR': u32 - 286..287 'z': u32 - 290..303 'TraitTest::ID': u32 - "#]], - ); -} - -#[test] -fn infer_type_alias() { - check_infer( - r#" - struct A { x: X, y: Y } - type Foo = A; - type Bar = A; - type Baz = A; - fn test(x: Foo, y: Bar<&str>, z: Baz) { - x.x; - x.y; - y.x; - y.y; - z.x; - z.y; - } - mod m { - pub enum Enum { - Foo(u8), - } - pub type Alias = Enum; - } - fn f() { - let e = m::Alias::Foo(0); - let m::Alias::Foo(x) = &e; - } - "#, - expect![[r#" - 115..116 'x': A - 123..124 'y': A<&str, u128> - 137..138 'z': A - 153..210 '{ ...z.y; }': () - 159..160 'x': A - 159..162 'x.x': u32 - 168..169 'x': A - 168..171 'x.y': i128 - 177..178 'y': A<&str, u128> - 177..180 'y.x': &str - 186..187 'y': A<&str, u128> - 186..189 'y.y': u128 - 195..196 'z': A - 195..198 'z.x': u8 - 204..205 'z': A - 204..207 'z.y': i8 - 298..362 '{ ... &e; }': () - 308..309 'e': Enum - 312..325 'm::Alias::Foo': Foo(u8) -> Enum - 312..328 'm::Ali...Foo(0)': Enum - 326..327 '0': u8 - 338..354 'm::Ali...Foo(x)': Enum - 352..353 'x': &u8 - 357..359 '&e': &Enum - 358..359 'e': Enum - "#]], - ) -} - -#[test] -fn recursive_type_alias() { - check_infer( - r#" - struct A {} - type Foo = Foo; - type Bar = A; - fn test(x: Foo) {} - "#, - expect![[r#" - 58..59 'x': {unknown} - 66..68 '{}': () - "#]], - ) -} - -#[test] -fn infer_type_param() { - check_infer( - r#" - fn id(x: T) -> T { - x - } - - fn clone(x: &T) -> T { - *x - } - - fn test() { - let y = 10u32; - id(y); - let x: bool = clone(z); - id::(1); - } - "#, - expect![[r#" - 9..10 'x': T - 20..29 '{ x }': T - 26..27 'x': T - 43..44 'x': &T - 55..65 '{ *x }': T - 61..63 '*x': T - 62..63 'x': &T - 77..157 '{ ...(1); }': () - 87..88 'y': u32 - 91..96 '10u32': u32 - 102..104 'id': fn id(u32) -> u32 - 102..107 'id(y)': u32 - 105..106 'y': u32 - 117..118 'x': bool - 127..132 'clone': fn clone(&bool) -> bool - 127..135 'clone(z)': bool - 133..134 'z': &bool - 141..151 'id::': fn id(i128) -> i128 - 141..154 'id::(1)': i128 - 152..153 '1': i128 - "#]], - ); -} - -#[test] -fn infer_const() { - check_infer( - r#" - struct Foo; - impl Foo { const ASSOC_CONST: u32 = 0; } - const GLOBAL_CONST: u32 = 101; - fn test() { - const LOCAL_CONST: u32 = 99; - let x = LOCAL_CONST; - let z = GLOBAL_CONST; - let id = Foo::ASSOC_CONST; - } - "#, - expect![[r#" - 48..49 '0': u32 - 79..82 '101': u32 - 94..212 '{ ...NST; }': () - 137..138 'x': u32 - 141..152 'LOCAL_CONST': u32 - 162..163 'z': u32 - 166..178 'GLOBAL_CONST': u32 - 188..190 'id': u32 - 193..209 'Foo::A..._CONST': u32 - 125..127 '99': u32 - "#]], - ); -} - -#[test] -fn infer_static() { - check_infer( - r#" - static GLOBAL_STATIC: u32 = 101; - static mut GLOBAL_STATIC_MUT: u32 = 101; - fn test() { - static LOCAL_STATIC: u32 = 99; - static mut LOCAL_STATIC_MUT: u32 = 99; - let x = LOCAL_STATIC; - let y = LOCAL_STATIC_MUT; - let z = GLOBAL_STATIC; - let w = GLOBAL_STATIC_MUT; - } - "#, - expect![[r#" - 28..31 '101': u32 - 69..72 '101': u32 - 84..279 '{ ...MUT; }': () - 172..173 'x': u32 - 176..188 'LOCAL_STATIC': u32 - 198..199 'y': u32 - 202..218 'LOCAL_...IC_MUT': u32 - 228..229 'z': u32 - 232..245 'GLOBAL_STATIC': u32 - 255..256 'w': u32 - 259..276 'GLOBAL...IC_MUT': u32 - 117..119 '99': u32 - 160..162 '99': u32 - "#]], - ); -} - -#[test] -fn shadowing_primitive() { - check_types( - r#" -struct i32; -struct Foo; - -impl i32 { fn foo(&self) -> Foo { Foo } } - -fn main() { - let x: i32 = i32; - x.foo(); - //^^^^^^^ Foo -}"#, - ); -} - -#[test] -fn const_eval_array_repeat_expr() { - check_types( - r#" -fn main() { - const X: usize = 6 - 1; - let t = [(); X + 2]; - //^ [(); 7] -}"#, - ); -} - -#[test] -fn shadowing_primitive_with_inner_items() { - check_types( - r#" -struct i32; -struct Foo; - -impl i32 { fn foo(&self) -> Foo { Foo } } - -fn main() { - fn inner() {} - let x: i32 = i32; - x.foo(); - //^^^^^^^ Foo -}"#, - ); -} - -#[test] -fn not_shadowing_primitive_by_module() { - check_types( - r#" -//- /str.rs -fn foo() {} - -//- /main.rs -mod str; -fn foo() -> &'static str { "" } - -fn main() { - foo(); - //^^^^^ &str -}"#, - ); -} - -#[test] -fn not_shadowing_module_by_primitive() { - check_types( - r#" -//- /str.rs -fn foo() -> u32 {0} - -//- /main.rs -mod str; -fn foo() -> &'static str { "" } - -fn main() { - str::foo(); - //^^^^^^^^^^ u32 -}"#, - ); -} - -// This test is actually testing the shadowing behavior within hir_def. It -// lives here because the testing infrastructure in hir_def isn't currently -// capable of asserting the necessary conditions. -#[test] -fn should_be_shadowing_imports() { - check_types( - r#" -mod a { - pub fn foo() -> i8 {0} - pub struct foo { a: i8 } -} -mod b { pub fn foo () -> u8 {0} } -mod c { pub struct foo { a: u8 } } -mod d { - pub use super::a::*; - pub use super::c::foo; - pub use super::b::foo; -} - -fn main() { - d::foo(); - //^^^^^^^^ u8 - d::foo{a:0}; - //^^^^^^^^^^^ foo -}"#, - ); -} - -#[test] -fn closure_return() { - check_infer( - r#" - fn foo() -> u32 { - let x = || -> usize { return 1; }; - } - "#, - expect![[r#" - 16..58 '{ ...; }; }': u32 - 26..27 'x': || -> usize - 30..55 '|| -> ...n 1; }': || -> usize - 42..55 '{ return 1; }': usize - 44..52 'return 1': ! - 51..52 '1': usize - "#]], - ); -} - -#[test] -fn closure_return_unit() { - check_infer( - r#" - fn foo() -> u32 { - let x = || { return; }; - } - "#, - expect![[r#" - 16..47 '{ ...; }; }': u32 - 26..27 'x': || -> () - 30..44 '|| { return; }': || -> () - 33..44 '{ return; }': () - 35..41 'return': ! - "#]], - ); -} - -#[test] -fn closure_return_inferred() { - check_infer( - r#" - fn foo() -> u32 { - let x = || { "test" }; - } - "#, - expect![[r#" - 16..46 '{ ..." }; }': u32 - 26..27 'x': || -> &str - 30..43 '|| { "test" }': || -> &str - 33..43 '{ "test" }': &str - 35..41 '"test"': &str - "#]], - ); -} - -#[test] -fn fn_pointer_return() { - check_infer( - r#" - struct Vtable { - method: fn(), - } - - fn main() { - let vtable = Vtable { method: || {} }; - let m = vtable.method; - } - "#, - expect![[r#" - 47..120 '{ ...hod; }': () - 57..63 'vtable': Vtable - 66..90 'Vtable...| {} }': Vtable - 83..88 '|| {}': || -> () - 86..88 '{}': () - 100..101 'm': fn() - 104..110 'vtable': Vtable - 104..117 'vtable.method': fn() - "#]], - ); -} - -#[test] -fn block_modifiers_smoke_test() { - check_infer( - r#" -//- minicore: future -async fn main() { - let x = unsafe { 92 }; - let y = async { async { () }.await }; - let z = try { () }; - let w = const { 92 }; - let t = 'a: { 92 }; -} - "#, - expect![[r#" - 16..162 '{ ...2 }; }': () - 26..27 'x': i32 - 30..43 'unsafe { 92 }': i32 - 30..43 'unsafe { 92 }': i32 - 39..41 '92': i32 - 53..54 'y': impl Future - 57..85 'async ...wait }': () - 57..85 'async ...wait }': impl Future - 65..77 'async { () }': () - 65..77 'async { () }': impl Future - 65..83 'async ....await': () - 73..75 '()': () - 95..96 'z': {unknown} - 99..109 'try { () }': () - 99..109 'try { () }': {unknown} - 105..107 '()': () - 119..120 'w': i32 - 123..135 'const { 92 }': i32 - 123..135 'const { 92 }': i32 - 131..133 '92': i32 - 145..146 't': i32 - 149..159 ''a: { 92 }': i32 - 155..157 '92': i32 - "#]], - ) -} -#[test] -fn async_block_early_return() { - check_infer( - r#" -//- minicore: future, result, fn -fn test Fut, Fut: core::future::Future>>(f: F) {} - -fn main() { - async { - return Err(()); - Ok(()) - }; - test(|| async { - return Err(()); - Ok(()) - }); -} - "#, - expect![[r#" - 83..84 'f': F - 89..91 '{}': () - 103..231 '{ ... }); }': () - 109..161 'async ... }': Result<(), ()> - 109..161 'async ... }': impl Future> - 125..139 'return Err(())': ! - 132..135 'Err': Err<(), ()>(()) -> Result<(), ()> - 132..139 'Err(())': Result<(), ()> - 136..138 '()': () - 149..151 'Ok': Ok<(), ()>(()) -> Result<(), ()> - 149..155 'Ok(())': Result<(), ()> - 152..154 '()': () - 167..171 'test': fn test<(), (), || -> impl Future>, impl Future>>(|| -> impl Future>) - 167..228 'test(|... })': () - 172..227 '|| asy... }': || -> impl Future> - 175..227 'async ... }': Result<(), ()> - 175..227 'async ... }': impl Future> - 191..205 'return Err(())': ! - 198..201 'Err': Err<(), ()>(()) -> Result<(), ()> - 198..205 'Err(())': Result<(), ()> - 202..204 '()': () - 215..217 'Ok': Ok<(), ()>(()) -> Result<(), ()> - 215..221 'Ok(())': Result<(), ()> - 218..220 '()': () - "#]], - ) -} - -#[test] -fn infer_generic_from_later_assignment() { - check_infer( - r#" - enum Option { Some(T), None } - use Option::*; - - fn test() { - let mut end = None; - loop { - end = Some(true); - } - } - "#, - expect![[r#" - 59..129 '{ ... } }': () - 69..76 'mut end': Option - 79..83 'None': Option - 89..127 'loop {... }': ! - 94..127 '{ ... }': () - 104..107 'end': Option - 104..120 'end = ...(true)': () - 110..114 'Some': Some(bool) -> Option - 110..120 'Some(true)': Option - 115..119 'true': bool - "#]], - ); -} - -#[test] -fn infer_loop_break_with_val() { - check_infer( - r#" - enum Option { Some(T), None } - use Option::*; - - fn test() { - let x = loop { - if false { - break None; - } - - break Some(true); - }; - } - "#, - expect![[r#" - 59..168 '{ ... }; }': () - 69..70 'x': Option - 73..165 'loop {... }': Option - 78..165 '{ ... }': () - 88..132 'if fal... }': () - 91..96 'false': bool - 97..132 '{ ... }': () - 111..121 'break None': ! - 117..121 'None': Option - 142..158 'break ...(true)': ! - 148..152 'Some': Some(bool) -> Option - 148..158 'Some(true)': Option - 153..157 'true': bool - "#]], - ); -} - -#[test] -fn infer_loop_break_without_val() { - check_infer( - r#" - enum Option { Some(T), None } - use Option::*; - - fn test() { - let x = loop { - if false { - break; - } - }; - } - "#, - expect![[r#" - 59..136 '{ ... }; }': () - 69..70 'x': () - 73..133 'loop {... }': () - 78..133 '{ ... }': () - 88..127 'if fal... }': () - 91..96 'false': bool - 97..127 '{ ... }': () - 111..116 'break': ! - "#]], - ); -} - -#[test] -fn infer_labelled_break_with_val() { - check_infer( - r#" - fn foo() { - let _x = || 'outer: loop { - let inner = 'inner: loop { - let i = Default::default(); - if (break 'outer i) { - loop { break 'inner 5i8; }; - } else if true { - break 'inner 6; - } - break 7; - }; - break inner < 8; - }; - } - "#, - expect![[r#" - 9..335 '{ ... }; }': () - 19..21 '_x': || -> bool - 24..332 '|| 'ou... }': || -> bool - 27..332 ''outer... }': bool - 40..332 '{ ... }': () - 54..59 'inner': i8 - 62..300 ''inner... }': i8 - 75..300 '{ ... }': () - 93..94 'i': bool - 97..113 'Defaul...efault': {unknown} - 97..115 'Defaul...ault()': bool - 129..269 'if (br... }': () - 133..147 'break 'outer i': ! - 146..147 'i': bool - 149..208 '{ ... }': () - 167..193 'loop {...5i8; }': ! - 172..193 '{ brea...5i8; }': () - 174..190 'break ...er 5i8': ! - 187..190 '5i8': i8 - 214..269 'if tru... }': () - 217..221 'true': bool - 222..269 '{ ... }': () - 240..254 'break 'inner 6': ! - 253..254 '6': i8 - 282..289 'break 7': ! - 288..289 '7': i8 - 310..325 'break inner < 8': ! - 316..321 'inner': i8 - 316..325 'inner < 8': bool - 324..325 '8': i8 - "#]], - ); -} - -#[test] -fn infer_labelled_block_break_with_val() { - check_infer( - r#" -fn default() -> T { loop {} } -fn foo() { - let _x = 'outer: { - let inner = 'inner: { - let i = default(); - if (break 'outer i) { - break 'inner 5i8; - } else if true { - break 'inner 6; - } - break 'inner 'innermost: { 0 }; - 42 - }; - break 'outer inner < 8; - }; -} -"#, - expect![[r#" - 21..32 '{ loop {} }': T - 23..30 'loop {}': ! - 28..30 '{}': () - 42..381 '{ ... }; }': () - 52..54 '_x': bool - 57..378 ''outer... }': bool - 79..84 'inner': i8 - 87..339 ''inner... }': i8 - 113..114 'i': bool - 117..124 'default': fn default() -> bool - 117..126 'default()': bool - 140..270 'if (br... }': () - 144..158 'break 'outer i': ! - 157..158 'i': bool - 160..209 '{ ... }': () - 178..194 'break ...er 5i8': ! - 191..194 '5i8': i8 - 215..270 'if tru... }': () - 218..222 'true': bool - 223..270 '{ ... }': () - 241..255 'break 'inner 6': ! - 254..255 '6': i8 - 283..313 'break ... { 0 }': ! - 296..313 ''inner... { 0 }': i8 - 310..311 '0': i8 - 327..329 '42': i8 - 349..371 'break ...er < 8': ! - 362..367 'inner': i8 - 362..371 'inner < 8': bool - 370..371 '8': i8 - "#]], - ); -} - -#[test] -fn generic_default() { - check_infer( - r#" - struct Thing { t: T } - enum OtherThing { - One { t: T }, - Two(T), - } - - fn test(t1: Thing, t2: OtherThing, t3: Thing, t4: OtherThing) { - t1.t; - t3.t; - match t2 { - OtherThing::One { t } => { t; }, - OtherThing::Two(t) => { t; }, - } - match t4 { - OtherThing::One { t } => { t; }, - OtherThing::Two(t) => { t; }, - } - } - "#, - expect![[r#" - 97..99 't1': Thing<()> - 108..110 't2': OtherThing<()> - 124..126 't3': Thing - 140..142 't4': OtherThing - 161..384 '{ ... } }': () - 167..169 't1': Thing<()> - 167..171 't1.t': () - 177..179 't3': Thing - 177..181 't3.t': i32 - 187..282 'match ... }': () - 193..195 't2': OtherThing<()> - 206..227 'OtherT... { t }': OtherThing<()> - 224..225 't': () - 231..237 '{ t; }': () - 233..234 't': () - 247..265 'OtherT...Two(t)': OtherThing<()> - 263..264 't': () - 269..275 '{ t; }': () - 271..272 't': () - 287..382 'match ... }': () - 293..295 't4': OtherThing - 306..327 'OtherT... { t }': OtherThing - 324..325 't': i32 - 331..337 '{ t; }': () - 333..334 't': i32 - 347..365 'OtherT...Two(t)': OtherThing - 363..364 't': i32 - 369..375 '{ t; }': () - 371..372 't': i32 - "#]], - ); -} - -#[test] -fn generic_default_in_struct_literal() { - check_infer( - r#" - struct Thing { t: T } - enum OtherThing { - One { t: T }, - Two(T), - } - - fn test() { - let x = Thing { t: loop {} }; - let y = Thing { t: () }; - let z = Thing { t: 1i32 }; - if let Thing { t } = z { - t; - } - - let a = OtherThing::One { t: 1i32 }; - let b = OtherThing::Two(1i32); - } - "#, - expect![[r#" - 99..319 '{ ...32); }': () - 109..110 'x': Thing - 113..133 'Thing ...p {} }': Thing - 124..131 'loop {}': ! - 129..131 '{}': () - 143..144 'y': Thing<()> - 147..162 'Thing { t: () }': Thing<()> - 158..160 '()': () - 172..173 'z': Thing - 176..193 'Thing ...1i32 }': Thing - 187..191 '1i32': i32 - 199..240 'if let... }': () - 202..221 'let Th... } = z': bool - 206..217 'Thing { t }': Thing - 214..215 't': i32 - 220..221 'z': Thing - 222..240 '{ ... }': () - 232..233 't': i32 - 250..251 'a': OtherThing - 254..281 'OtherT...1i32 }': OtherThing - 275..279 '1i32': i32 - 291..292 'b': OtherThing - 295..310 'OtherThing::Two': Two(i32) -> OtherThing - 295..316 'OtherT...(1i32)': OtherThing - 311..315 '1i32': i32 - "#]], - ); -} - -#[test] -fn generic_default_depending_on_other_type_arg() { - // FIXME: the {unknown} is a bug - check_infer( - r#" - struct Thing T> { t: T } - - fn test(t1: Thing, t2: Thing) { - t1; - t2; - Thing::<_> { t: 1u32 }; - } - "#, - expect![[r#" - 56..58 't1': Thing u32> - 72..74 't2': Thing u128> - 83..130 '{ ...2 }; }': () - 89..91 't1': Thing u32> - 97..99 't2': Thing u128> - 105..127 'Thing:...1u32 }': Thing {unknown}> - 121..125 '1u32': u32 - "#]], - ); -} - -#[test] -fn generic_default_depending_on_other_type_arg_forward() { - // the {unknown} here is intentional, as defaults are not allowed to - // refer to type parameters coming later - check_infer( - r#" - struct Thing T, T = u128> { t: T } - - fn test(t1: Thing) { - t1; - } - "#, - expect![[r#" - 56..58 't1': Thing {unknown}, u128> - 67..78 '{ t1; }': () - 73..75 't1': Thing {unknown}, u128> - "#]], - ); -} - -#[test] -fn infer_operator_overload() { - check_types( - r#" -//- minicore: add -struct V2([f32; 2]); - -impl core::ops::Add for V2 { - type Output = V2; -} - -fn test() { - let va = V2([0.0, 1.0]); - let vb = V2([0.0, 1.0]); - - let r = va + vb; - // ^^^^^^^ V2 -} - - "#, - ); -} - -#[test] -fn infer_const_params() { - check_infer( - r#" - fn foo() { - let bar = FOO; - } - "#, - expect![[r#" - 27..49 '{ ...FOO; }': () - 37..40 'bar': usize - 43..46 'FOO': usize - "#]], - ); -} - -#[test] -fn infer_inner_type() { - check_infer( - r#" - fn foo() { - struct S { field: u32 } - let s = S { field: 0 }; - let f = s.field; - } - "#, - expect![[r#" - 9..89 '{ ...eld; }': () - 47..48 's': S - 51..65 'S { field: 0 }': S - 62..63 '0': u32 - 75..76 'f': u32 - 79..80 's': S - 79..86 's.field': u32 - "#]], - ); -} - -#[test] -fn infer_nested_inner_type() { - check_infer( - r#" - fn foo() { - { - let s = S { field: 0 }; - let f = s.field; - } - struct S { field: u32 } - } - "#, - expect![[r#" - 9..109 '{ ...32 } }': () - 15..79 '{ ... }': () - 29..30 's': S - 33..47 'S { field: 0 }': S - 44..45 '0': u32 - 61..62 'f': u32 - 65..66 's': S - 65..72 's.field': u32 - "#]], - ); -} - -#[test] -fn inner_use_enum_rename() { - check_infer( - r#" - enum Request { - Info - } - - fn f() { - use Request as R; - - let r = R::Info; - match r { - R::Info => {} - } - } - "#, - expect![[r#" - 34..123 '{ ... } }': () - 67..68 'r': Request - 71..78 'R::Info': Request - 84..121 'match ... }': () - 90..91 'r': Request - 102..109 'R::Info': Request - 113..115 '{}': () - "#]], - ) -} - -#[test] -fn box_into_vec() { - check_infer( - r#" -#[lang = "sized"] -pub trait Sized {} - -#[lang = "unsize"] -pub trait Unsize {} - -#[lang = "coerce_unsized"] -pub trait CoerceUnsized {} - -pub unsafe trait Allocator {} - -pub struct Global; -unsafe impl Allocator for Global {} - -#[lang = "owned_box"] -#[fundamental] -pub struct Box; - -impl, U: ?Sized, A: Allocator> CoerceUnsized> for Box {} - -pub struct Vec {} - -#[lang = "slice"] -impl [T] {} - -#[lang = "slice_alloc"] -impl [T] { - pub fn into_vec(self: Box) -> Vec { - unimplemented!() - } -} - -fn test() { - let vec = <[_]>::into_vec(box [1i32]); - let v: Vec> = <[_]> :: into_vec(box [box Astruct]); -} - -trait B{} -struct Astruct; -impl B for Astruct {} -"#, - expect![[r#" - 569..573 'self': Box<[T], A> - 602..634 '{ ... }': Vec - 612..628 'unimpl...ted!()': Vec - 648..761 '{ ...t]); }': () - 658..661 'vec': Vec - 664..679 '<[_]>::into_vec': fn into_vec(Box<[i32], Global>) -> Vec - 664..691 '<[_]>:...1i32])': Vec - 680..690 'box [1i32]': Box<[i32; 1], Global> - 684..690 '[1i32]': [i32; 1] - 685..689 '1i32': i32 - 701..702 'v': Vec, Global> - 722..739 '<[_]> ...to_vec': fn into_vec, Global>(Box<[Box], Global>) -> Vec, Global> - 722..758 '<[_]> ...ruct])': Vec, Global> - 740..757 'box [b...truct]': Box<[Box; 1], Global> - 744..757 '[box Astruct]': [Box; 1] - 745..756 'box Astruct': Box - 749..756 'Astruct': Astruct - "#]], - ) -} - -#[test] -fn cfgd_out_assoc_items() { - check_types( - r#" -struct S; - -impl S { - #[cfg(FALSE)] - const C: S = S; -} - -fn f() { - S::C; - //^^^^ {unknown} -} - "#, - ) -} - -#[test] -fn infer_missing_type() { - check_types( - r#" -struct S; - -fn f() { - let s: = S; - //^ S -} - "#, - ); -} - -#[test] -fn infer_type_alias_variant() { - check_infer( - r#" -type Qux = Foo; -enum Foo { - Bar(i32), - Baz { baz: f32 } -} - -fn f() { - match Foo::Bar(3) { - Qux::Bar(bar) => (), - Qux::Baz { baz } => (), - } -} - "#, - expect![[r#" - 72..166 '{ ... } }': () - 78..164 'match ... }': () - 84..92 'Foo::Bar': Bar(i32) -> Foo - 84..95 'Foo::Bar(3)': Foo - 93..94 '3': i32 - 106..119 'Qux::Bar(bar)': Foo - 115..118 'bar': i32 - 123..125 '()': () - 135..151 'Qux::B... baz }': Foo - 146..149 'baz': f32 - 155..157 '()': () - "#]], - ) -} - -#[test] -fn infer_boxed_self_receiver() { - check_infer( - r#" -//- minicore: deref -use core::ops::Deref; - -struct Box(T); - -impl Deref for Box { - type Target = T; - fn deref(&self) -> &Self::Target; -} - -struct Foo(T); - -impl Foo { - fn get_inner<'a>(self: &'a Box) -> &'a T {} - - fn get_self<'a>(self: &'a Box) -> &'a Self {} - - fn into_inner(self: Box) -> Self {} -} - -fn main() { - let boxed = Box(Foo(0_i32)); - - let bad1 = boxed.get_inner(); - let good1 = Foo::get_inner(&boxed); - - let bad2 = boxed.get_self(); - let good2 = Foo::get_self(&boxed); - - let inner = boxed.into_inner(); -} - "#, - expect![[r#" - 104..108 'self': &Box - 188..192 'self': &Box> - 218..220 '{}': &T - 242..246 'self': &Box> - 275..277 '{}': &Foo - 297..301 'self': Box> - 322..324 '{}': Foo - 338..559 '{ ...r(); }': () - 348..353 'boxed': Box> - 356..359 'Box': Box>(Foo) -> Box> - 356..371 'Box(Foo(0_i32))': Box> - 360..363 'Foo': Foo(i32) -> Foo - 360..370 'Foo(0_i32)': Foo - 364..369 '0_i32': i32 - 382..386 'bad1': &i32 - 389..394 'boxed': Box> - 389..406 'boxed....nner()': &i32 - 416..421 'good1': &i32 - 424..438 'Foo::get_inner': fn get_inner(&Box>) -> &i32 - 424..446 'Foo::g...boxed)': &i32 - 439..445 '&boxed': &Box> - 440..445 'boxed': Box> - 457..461 'bad2': &Foo - 464..469 'boxed': Box> - 464..480 'boxed....self()': &Foo - 490..495 'good2': &Foo - 498..511 'Foo::get_self': fn get_self(&Box>) -> &Foo - 498..519 'Foo::g...boxed)': &Foo - 512..518 '&boxed': &Box> - 513..518 'boxed': Box> - 530..535 'inner': Foo - 538..543 'boxed': Box> - 538..556 'boxed....nner()': Foo - "#]], - ); -} - -#[test] -fn prelude_2015() { - check_types( - r#" -//- /main.rs edition:2015 crate:main deps:core -fn f() { - Rust; - //^^^^ Rust -} - -//- /core.rs crate:core -pub mod prelude { - pub mod rust_2015 { - pub struct Rust; - } -} - "#, - ); -} - -#[test] -fn legacy_const_generics() { - check_no_mismatches( - r#" -#[rustc_legacy_const_generics(1, 3)] -fn mixed( - a: u8, - b: i8, -) {} - -fn f() { - mixed(0, "", -1, true); - mixed::<"", true>(0, -1); -} - "#, - ); -} - -#[test] -fn destructuring_assignment_slice() { - check_types( - r#" -fn main() { - let a; - //^usize - [a,] = [0usize]; - - let a; - //^usize - [a, ..] = [0usize; 5]; - - let a; - //^usize - [.., a] = [0usize; 5]; - - let a; - //^usize - [.., a, _] = [0usize; 5]; - - let a; - //^usize - [_, a, ..] = [0usize; 5]; - - let a: &mut i64 = &mut 0; - [*a, ..] = [1, 2, 3]; - - let a: usize; - let b; - //^usize - [a, _, b] = [3, 4, 5]; - //^usize - - let a; - //^i64 - let b; - //^i64 - [[a, ..], .., [.., b]] = [[1, 2], [3i64, 4], [5, 6], [7, 8]]; -} - "#, - ); -} - -#[test] -fn destructuring_assignment_tuple() { - check_types( - r#" -fn main() { - let a; - //^char - let b; - //^i64 - (a, b) = ('c', 0i64); - - let a; - //^char - (a, ..) = ('c', 0i64); - - let a; - //^i64 - (.., a) = ('c', 0i64); - - let a; - //^char - let b; - //^i64 - (a, .., b) = ('c', 0i64); - - let a; - //^char - let b; - //^bool - (a, .., b) = ('c', 0i64, true); - - let a; - //^i64 - let b; - //^bool - (_, a, .., b) = ('c', 0i64, true); - - let a; - //^i64 - let b; - //^usize - (_, a, .., b) = ('c', 0i64, true, 0usize); - - let mut a = 1; - //^^^^^i64 - let mut b: i64 = 0; - (a, b) = (b, a); -} - "#, - ); -} - -#[test] -fn destructuring_assignment_tuple_struct() { - check_types( - r#" -struct S2(char, i64); -struct S3(char, i64, bool); -struct S4(char, i64, bool usize); -fn main() { - let a; - //^char - let b; - //^i64 - S2(a, b) = S2('c', 0i64); - - let a; - //^char - let b; - //^i64 - S2(a, .., b) = S2('c', 0i64); - - let a; - //^char - let b; - //^bool - S3(a, .., b) = S3('c', 0i64, true); - - let a; - //^i64 - let b; - //^bool - S3(_, a, .., b) = S3('c', 0i64, true); - - let a; - //^i64 - let b; - //^usize - S4(_, a, .., b) = S4('c', 0i64, true, 0usize); - - struct Swap(i64, i64); - - let mut a = 1; - //^^^^^i64 - let mut b = 0; - //^^^^^i64 - Swap(a, b) = Swap(b, a); -} - "#, - ); -} - -#[test] -fn destructuring_assignment_struct() { - check_types( - r#" -struct S { - a: usize, - b: char, -} -struct T { - s: S, - t: i64, -} - -fn main() { - let a; - //^usize - let c; - //^char - S { a, b: c } = S { a: 3, b: 'b' }; - - let a; - //^char - S { b: a, .. } = S { a: 3, b: 'b' }; - - let a; - //^char - S { b: a, _ } = S { a: 3, b: 'b' }; - - let a; - //^usize - let c; - //^char - let t; - //^i64 - T { s: S { a, b: c }, t } = T { s: S { a: 3, b: 'b' }, t: 0 }; -} - "#, - ); -} - -#[test] -fn destructuring_assignment_nested() { - check_types( - r#" -struct S { - a: TS, - b: [char; 3], -} -struct TS(usize, i64); - -fn main() { - let a; - //^i32 - let b; - //^bool - ([.., a], .., b, _) = ([0, 1, 2], true, 'c'); - - let a; - //^i32 - let b; - //^i32 - [(.., a, _), .., (b, ..)] = [(1, 2); 5]; - - let a; - //^usize - let b; - //^char - S { a: TS(a, ..), b: [_, b, ..] } = S { a: TS(0, 0), b: ['a'; 3] }; -} - "#, - ); -} - -#[test] -fn destructuring_assignment_unit_struct() { - // taken from rustc; see https://github.com/rust-lang/rust/pull/95380 - check_no_mismatches( - r#" -struct S; -enum E { V, } -type A = E; - -fn main() { - let mut a; - - (S, a) = (S, ()); - - (E::V, a) = (E::V, ()); - - (::V, a) = (E::V, ()); - (A::V, a) = (E::V, ()); -} - -impl S { - fn check() { - let a; - (Self, a) = (S, ()); - } -} - -impl E { - fn check() { - let a; - (Self::V, a) = (E::V, ()); - } -} - "#, - ); -} - -#[test] -fn destructuring_assignment_no_default_binding_mode() { - check( - r#" -struct S { a: usize } -struct TS(usize); -fn main() { - let x; - [x,] = &[1,]; - //^^^^expected &[i32; 1], got [{unknown}; _] - - // FIXME we only want the outermost error, but this matches the current - // behavior of slice patterns - let x; - [(x,),] = &[(1,),]; - // ^^^^expected {unknown}, got ({unknown},) - //^^^^^^^expected &[(i32,); 1], got [{unknown}; _] - - let x; - ((x,),) = &((1,),); - //^^^^^^^expected &((i32,),), got (({unknown},),) - - let x; - (x,) = &(1,); - //^^^^expected &(i32,), got ({unknown},) - - let x; - (S { a: x },) = &(S { a: 42 },); - //^^^^^^^^^^^^^expected &(S,), got (S,) - - let x; - S { a: x } = &S { a: 42 }; - //^^^^^^^^^^expected &S, got S - - let x; - TS(x) = &TS(42); - //^^^^^expected &TS, got TS -} - "#, - ); -} - -#[test] -fn destructuring_assignment_type_mismatch_on_identifier() { - check( - r#" -struct S { v: i64 } -struct TS(i64); -fn main() { - let mut a: usize = 0; - (a,) = (0i64,); - //^expected i64, got usize - - let mut a: usize = 0; - [a,] = [0i64,]; - //^expected i64, got usize - - let mut a: usize = 0; - S { v: a } = S { v: 0 }; - //^expected i64, got usize - - let mut a: usize = 0; - TS(a) = TS(0); - //^expected i64, got usize -} - "#, - ); -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs deleted file mode 100644 index 75802a5eb4db8..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ /dev/null @@ -1,3782 +0,0 @@ -use cov_mark::check; -use expect_test::expect; - -use super::{check, check_infer, check_infer_with_mismatches, check_no_mismatches, check_types}; - -#[test] -fn infer_await() { - check_types( - r#" -//- minicore: future -struct IntFuture; - -impl core::future::Future for IntFuture { - type Output = u64; -} - -fn test() { - let r = IntFuture; - let v = r.await; - v; -} //^ u64 -"#, - ); -} - -#[test] -fn infer_async() { - check_types( - r#" -//- minicore: future -async fn foo() -> u64 { 128 } - -fn test() { - let r = foo(); - let v = r.await; - v; -} //^ u64 -"#, - ); -} - -#[test] -fn infer_desugar_async() { - check_types( - r#" -//- minicore: future, sized -async fn foo() -> u64 { 128 } - -fn test() { - let r = foo(); - r; -} //^ impl Future -"#, - ); -} - -#[test] -fn infer_async_block() { - check_types( - r#" -//- minicore: future, option -async fn test() { - let a = async { 42 }; - a; -// ^ impl Future - let x = a.await; - x; -// ^ i32 - let b = async {}.await; - b; -// ^ () - let c = async { - let y = None; - y - // ^ Option - }; - let _: Option = c.await; - c; -// ^ impl Future> -} -"#, - ); -} - -#[test] -fn auto_sized_async_block() { - check_no_mismatches( - r#" -//- minicore: future, sized - -use core::future::Future; -struct MyFut(Fut); - -impl Future for MyFut -where Fut: Future -{ - type Output = Fut::Output; -} -async fn reproduction() -> usize { - let f = async {999usize}; - MyFut(f).await -} - "#, - ); - check_no_mismatches( - r#" -//- minicore: future -//#11815 -#[lang = "sized"] -pub trait Sized {} - -#[lang = "unsize"] -pub trait Unsize {} - -#[lang = "coerce_unsized"] -pub trait CoerceUnsized {} - -pub unsafe trait Allocator {} - -pub struct Global; -unsafe impl Allocator for Global {} - -#[lang = "owned_box"] -#[fundamental] -pub struct Box; - -impl, U: ?Sized, A: Allocator> CoerceUnsized> for Box {} - -fn send() -> Box + Send + 'static>{ - box async move {} -} - -fn not_send() -> Box + 'static> { - box async move {} -} - "#, - ); -} - -#[test] -fn infer_try() { - check_types( - r#" -//- /main.rs crate:main deps:core -fn test() { - let r: Result = Result::Ok(1); - let v = r?; - v; -} //^ i32 - -//- /core.rs crate:core -pub mod ops { - pub trait Try { - type Ok; - type Error; - } -} - -pub mod result { - pub enum Result { - Ok(O), - Err(E) - } - - impl crate::ops::Try for Result { - type Ok = O; - type Error = E; - } -} - -pub mod prelude { - pub mod rust_2018 { - pub use crate::{result::*, ops::*}; - } -} -"#, - ); -} - -#[test] -fn infer_try_trait_v2() { - check_types( - r#" -//- /main.rs crate:main deps:core -fn test() { - let r: Result = Result::Ok(1); - let v = r?; - v; -} //^ i32 - -//- /core.rs crate:core -mod ops { - mod try_trait { - pub trait Try: FromResidual { - type Output; - type Residual; - } - pub trait FromResidual::Residual> {} - } - - pub use self::try_trait::FromResidual; - pub use self::try_trait::Try; -} - -mod convert { - pub trait From {} - impl From for T {} -} - -pub mod result { - use crate::convert::From; - use crate::ops::{Try, FromResidual}; - - pub enum Infallible {} - pub enum Result { - Ok(O), - Err(E) - } - - impl Try for Result { - type Output = O; - type Error = Result; - } - - impl> FromResidual> for Result {} -} - -pub mod prelude { - pub mod rust_2018 { - pub use crate::result::*; - } -} -"#, - ); -} - -#[test] -fn infer_for_loop() { - check_types( - r#" -//- /main.rs crate:main deps:core,alloc -#![no_std] -use alloc::collections::Vec; - -fn test() { - let v = Vec::new(); - v.push("foo"); - for x in v { - x; - } //^ &str -} - -//- /core.rs crate:core -pub mod iter { - pub trait IntoIterator { - type Item; - } -} -pub mod prelude { - pub mod rust_2018 { - pub use crate::iter::*; - } -} - -//- /alloc.rs crate:alloc deps:core -#![no_std] -pub mod collections { - pub struct Vec {} - impl Vec { - pub fn new() -> Self { Vec {} } - pub fn push(&mut self, t: T) { } - } - - impl IntoIterator for Vec { - type Item=T; - } -} -"#, - ); -} - -#[test] -fn infer_ops_neg() { - check_types( - r#" -//- /main.rs crate:main deps:std -struct Bar; -struct Foo; - -impl std::ops::Neg for Bar { - type Output = Foo; -} - -fn test() { - let a = Bar; - let b = -a; - b; -} //^ Foo - -//- /std.rs crate:std -#[prelude_import] use ops::*; -mod ops { - #[lang = "neg"] - pub trait Neg { - type Output; - } -} -"#, - ); -} - -#[test] -fn infer_ops_not() { - check_types( - r#" -//- /main.rs crate:main deps:std -struct Bar; -struct Foo; - -impl std::ops::Not for Bar { - type Output = Foo; -} - -fn test() { - let a = Bar; - let b = !a; - b; -} //^ Foo - -//- /std.rs crate:std -#[prelude_import] use ops::*; -mod ops { - #[lang = "not"] - pub trait Not { - type Output; - } -} -"#, - ); -} - -#[test] -fn infer_from_bound_1() { - check_types( - r#" -trait Trait {} -struct S(T); -impl Trait for S {} -fn foo>(t: T) {} -fn test() { - let s = S(unknown); - // ^^^^^^^ u32 - foo(s); -}"#, - ); -} - -#[test] -fn infer_from_bound_2() { - check_types( - r#" -trait Trait {} -struct S(T); -impl Trait for S {} -fn foo>(t: T) -> U { loop {} } -fn test() { - let s = S(unknown); - // ^^^^^^^ u32 - let x: u32 = foo(s); -}"#, - ); -} - -#[test] -fn trait_default_method_self_bound_implements_trait() { - cov_mark::check!(trait_self_implements_self); - check( - r#" -trait Trait { - fn foo(&self) -> i64; - fn bar(&self) -> () { - self.foo(); - // ^^^^^^^^^^ type: i64 - } -}"#, - ); -} - -#[test] -fn trait_default_method_self_bound_implements_super_trait() { - check( - r#" -trait SuperTrait { - fn foo(&self) -> i64; -} -trait Trait: SuperTrait { - fn bar(&self) -> () { - self.foo(); - // ^^^^^^^^^^ type: i64 - } -}"#, - ); -} - -#[test] -fn infer_project_associated_type() { - check_types( - r#" -trait Iterable { - type Item; -} -struct S; -impl Iterable for S { type Item = u32; } -fn test() { - let x: ::Item = 1; - // ^ u32 - let y: ::Item = u; - // ^ Iterable::Item - let z: T::Item = u; - // ^ Iterable::Item - let a: ::Item = u; - // ^ Iterable::Item -}"#, - ); -} - -#[test] -fn infer_return_associated_type() { - check_types( - r#" -trait Iterable { - type Item; -} -struct S; -impl Iterable for S { type Item = u32; } -fn foo1(t: T) -> T::Item { loop {} } -fn foo2(t: T) -> ::Item { loop {} } -fn foo3(t: T) -> ::Item { loop {} } -fn test() { - foo1(S); - // ^^^^^^^ u32 - foo2(S); - // ^^^^^^^ u32 - foo3(S); - // ^^^^^^^ u32 -}"#, - ); -} - -#[test] -fn associated_type_shorthand_from_method_bound() { - check_types( - r#" -trait Iterable { - type Item; -} -struct S; -impl S { - fn foo(self) -> T::Item where T: Iterable { loop {} } -} -fn test() { - let s: S; - s.foo(); - // ^^^^^^^ Iterable::Item -}"#, - ); -} - -#[test] -fn associated_type_shorthand_from_self_issue_12484() { - check_types( - r#" -trait Bar { - type A; -} -trait Foo { - type A; - fn test(a: Self::A, _: impl Bar) { - a; - //^ Foo::A - } -}"#, - ); -} - -#[test] -fn infer_associated_type_bound() { - check_types( - r#" -trait Iterable { - type Item; -} -fn test>() { - let y: T::Item = unknown; - // ^^^^^^^ u32 -}"#, - ); -} - -#[test] -fn infer_const_body() { - // FIXME make check_types work with other bodies - check_infer( - r#" -const A: u32 = 1 + 1; -static B: u64 = { let x = 1; x }; -"#, - expect![[r#" - 15..16 '1': u32 - 15..20 '1 + 1': u32 - 19..20 '1': u32 - 38..54 '{ let ...1; x }': u64 - 44..45 'x': u64 - 48..49 '1': u64 - 51..52 'x': u64 - "#]], - ); -} - -#[test] -fn tuple_struct_fields() { - check_infer( - r#" -struct S(i32, u64); -fn test() -> u64 { - let a = S(4, 6); - let b = a.0; - a.1 -}"#, - expect![[r#" - 37..86 '{ ... a.1 }': u64 - 47..48 'a': S - 51..52 'S': S(i32, u64) -> S - 51..58 'S(4, 6)': S - 53..54 '4': i32 - 56..57 '6': u64 - 68..69 'b': i32 - 72..73 'a': S - 72..75 'a.0': i32 - 81..82 'a': S - 81..84 'a.1': u64 - "#]], - ); -} - -#[test] -fn tuple_struct_with_fn() { - check_infer( - r#" -struct S(fn(u32) -> u64); -fn test() -> u64 { - let a = S(|i| 2*i); - let b = a.0(4); - a.0(2) -}"#, - expect![[r#" - 43..101 '{ ...0(2) }': u64 - 53..54 'a': S - 57..58 'S': S(fn(u32) -> u64) -> S - 57..67 'S(|i| 2*i)': S - 59..66 '|i| 2*i': |u32| -> u64 - 60..61 'i': u32 - 63..64 '2': u32 - 63..66 '2*i': u32 - 65..66 'i': u32 - 77..78 'b': u64 - 81..82 'a': S - 81..84 'a.0': fn(u32) -> u64 - 81..87 'a.0(4)': u64 - 85..86 '4': u32 - 93..94 'a': S - 93..96 'a.0': fn(u32) -> u64 - 93..99 'a.0(2)': u64 - 97..98 '2': u32 - "#]], - ); -} - -#[test] -fn indexing_arrays() { - check_infer( - "fn main() { &mut [9][2]; }", - expect![[r#" - 10..26 '{ &mut...[2]; }': () - 12..23 '&mut [9][2]': &mut {unknown} - 17..20 '[9]': [i32; 1] - 17..23 '[9][2]': {unknown} - 18..19 '9': i32 - 21..22 '2': i32 - "#]], - ) -} - -#[test] -fn infer_ops_index() { - check_types( - r#" -//- minicore: index -struct Bar; -struct Foo; - -impl core::ops::Index for Bar { - type Output = Foo; -} - -fn test() { - let a = Bar; - let b = a[1u32]; - b; -} //^ Foo -"#, - ); -} - -#[test] -fn infer_ops_index_field() { - check_types( - r#" -//- minicore: index -struct Bar; -struct Foo { - field: u32; -} - -impl core::ops::Index for Bar { - type Output = Foo; -} - -fn test() { - let a = Bar; - let b = a[1u32].field; - b; -} //^ u32 -"#, - ); -} - -#[test] -fn infer_ops_index_field_autoderef() { - check_types( - r#" -//- minicore: index -struct Bar; -struct Foo { - field: u32; -} - -impl core::ops::Index for Bar { - type Output = Foo; -} - -fn test() { - let a = Bar; - let b = (&a[1u32]).field; - b; -} //^ u32 -"#, - ); -} - -#[test] -fn infer_ops_index_int() { - check_types( - r#" -//- minicore: index -struct Bar; -struct Foo; - -impl core::ops::Index for Bar { - type Output = Foo; -} - -struct Range; -impl core::ops::Index for Bar { - type Output = Bar; -} - -fn test() { - let a = Bar; - let b = a[1]; - b; - //^ Foo -} -"#, - ); -} - -#[test] -fn infer_ops_index_autoderef() { - check_types( - r#" -//- minicore: index, slice -fn test() { - let a = &[1u32, 2, 3]; - let b = a[1]; - b; -} //^ u32 -"#, - ); -} - -#[test] -fn deref_trait() { - check_types( - r#" -//- minicore: deref -struct Arc; -impl core::ops::Deref for Arc { - type Target = T; -} - -struct S; -impl S { - fn foo(&self) -> u128 { 0 } -} - -fn test(s: Arc) { - (*s, s.foo()); -} //^^^^^^^^^^^^^ (S, u128) -"#, - ); -} - -#[test] -fn deref_trait_with_inference_var() { - check_types( - r#" -//- minicore: deref -struct Arc; -fn new_arc() -> Arc { Arc } -impl core::ops::Deref for Arc { - type Target = T; -} - -struct S; -fn foo(a: Arc) {} - -fn test() { - let a = new_arc(); - let b = *a; - //^^ S - foo(a); -} -"#, - ); -} - -#[test] -fn deref_trait_infinite_recursion() { - check_types( - r#" -//- minicore: deref -struct S; - -impl core::ops::Deref for S { - type Target = S; -} - -fn test(s: S) { - s.foo(); -} //^^^^^^^ {unknown} -"#, - ); -} - -#[test] -fn deref_trait_with_question_mark_size() { - check_types( - r#" -//- minicore: deref -struct Arc; -impl core::ops::Deref for Arc { - type Target = T; -} - -struct S; -impl S { - fn foo(&self) -> u128 { 0 } -} - -fn test(s: Arc) { - (*s, s.foo()); -} //^^^^^^^^^^^^^ (S, u128) -"#, - ); -} - -#[test] -fn deref_trait_with_implicit_sized_requirement_on_inference_var() { - check_types( - r#" -//- minicore: deref -struct Foo; -impl core::ops::Deref for Foo { - type Target = (); -} -fn test() { - let foo = Foo; - *foo; - //^^^^ () - let _: Foo = foo; -} -"#, - ) -} - -#[test] -fn obligation_from_function_clause() { - check_types( - r#" -struct S; - -trait Trait {} -impl Trait for S {} - -fn foo, U>(t: T) -> U { loop {} } - -fn test(s: S) { - foo(s); -} //^^^^^^ u32 -"#, - ); -} - -#[test] -fn obligation_from_method_clause() { - check_types( - r#" -//- /main.rs -struct S; - -trait Trait {} -impl Trait for S {} - -struct O; -impl O { - fn foo, U>(&self, t: T) -> U { loop {} } -} - -fn test() { - O.foo(S); -} //^^^^^^^^ isize -"#, - ); -} - -#[test] -fn obligation_from_self_method_clause() { - check_types( - r#" -struct S; - -trait Trait {} -impl Trait for S {} - -impl S { - fn foo(&self) -> U where Self: Trait { loop {} } -} - -fn test() { - S.foo(); -} //^^^^^^^ i64 -"#, - ); -} - -#[test] -fn obligation_from_impl_clause() { - check_types( - r#" -struct S; - -trait Trait {} -impl Trait<&str> for S {} - -struct O; -impl> O { - fn foo(&self) -> U { loop {} } -} - -fn test(o: O) { - o.foo(); -} //^^^^^^^ &str -"#, - ); -} - -#[test] -fn generic_param_env_1() { - check_types( - r#" -trait Clone {} -trait Trait { fn foo(self) -> u128; } -struct S; -impl Clone for S {} -impl Trait for T where T: Clone {} -fn test(t: T) { t.foo(); } - //^^^^^^^ u128 -"#, - ); -} - -#[test] -fn generic_param_env_1_not_met() { - check_types( - r#" -//- /main.rs -trait Clone {} -trait Trait { fn foo(self) -> u128; } -struct S; -impl Clone for S {} -impl Trait for T where T: Clone {} -fn test(t: T) { t.foo(); } - //^^^^^^^ {unknown} -"#, - ); -} - -#[test] -fn generic_param_env_2() { - check_types( - r#" -trait Trait { fn foo(self) -> u128; } -struct S; -impl Trait for S {} -fn test(t: T) { t.foo(); } - //^^^^^^^ u128 -"#, - ); -} - -#[test] -fn generic_param_env_2_not_met() { - check_types( - r#" -trait Trait { fn foo(self) -> u128; } -struct S; -impl Trait for S {} -fn test(t: T) { t.foo(); } - //^^^^^^^ {unknown} -"#, - ); -} - -#[test] -fn generic_param_env_deref() { - check_types( - r#" -//- minicore: deref -trait Trait {} -impl core::ops::Deref for T where T: Trait { - type Target = i128; -} -fn test(t: T) { *t; } - //^^ i128 -"#, - ); -} - -#[test] -fn associated_type_placeholder() { - // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types]. - check_types( - r#" -pub trait ApplyL { - type Out; -} - -pub struct RefMutL; - -impl ApplyL for RefMutL { - type Out = ::Out; -} - -fn test() { - let y: as ApplyL>::Out = no_matter; - y; -} //^ ApplyL::Out -"#, - ); -} - -#[test] -fn associated_type_placeholder_2() { - check_types( - r#" -pub trait ApplyL { - type Out; -} -fn foo(t: T) -> ::Out; - -fn test(t: T) { - let y = foo(t); - y; -} //^ ApplyL::Out -"#, - ); -} - -#[test] -fn argument_impl_trait() { - check_infer_with_mismatches( - r#" -//- minicore: sized -trait Trait { - fn foo(&self) -> T; - fn foo2(&self) -> i64; -} -fn bar(x: impl Trait) {} -struct S(T); -impl Trait for S {} - -fn test(x: impl Trait, y: &impl Trait) { - x; - y; - let z = S(1); - bar(z); - x.foo(); - y.foo(); - z.foo(); - x.foo2(); - y.foo2(); - z.foo2(); -}"#, - expect![[r#" - 29..33 'self': &Self - 54..58 'self': &Self - 77..78 'x': impl Trait - 97..99 '{}': () - 154..155 'x': impl Trait - 174..175 'y': &impl Trait - 195..323 '{ ...2(); }': () - 201..202 'x': impl Trait - 208..209 'y': &impl Trait - 219..220 'z': S - 223..224 'S': S(u16) -> S - 223..227 'S(1)': S - 225..226 '1': u16 - 233..236 'bar': fn bar(S) - 233..239 'bar(z)': () - 237..238 'z': S - 245..246 'x': impl Trait - 245..252 'x.foo()': u64 - 258..259 'y': &impl Trait - 258..265 'y.foo()': u32 - 271..272 'z': S - 271..278 'z.foo()': u16 - 284..285 'x': impl Trait - 284..292 'x.foo2()': i64 - 298..299 'y': &impl Trait - 298..306 'y.foo2()': i64 - 312..313 'z': S - 312..320 'z.foo2()': i64 - "#]], - ); -} - -#[test] -fn argument_impl_trait_type_args_1() { - check_infer_with_mismatches( - r#" -//- minicore: sized -trait Trait {} -trait Foo { - // this function has an implicit Self param, an explicit type param, - // and an implicit impl Trait param! - fn bar(x: impl Trait) -> T { loop {} } -} -fn foo(x: impl Trait) -> T { loop {} } -struct S; -impl Trait for S {} -struct F; -impl Foo for F {} - -fn test() { - Foo::bar(S); - ::bar(S); - F::bar(S); - Foo::bar::(S); - ::bar::(S); - - foo(S); - foo::(S); - foo::(S); // we should ignore the extraneous i32 -}"#, - expect![[r#" - 155..156 'x': impl Trait - 175..186 '{ loop {} }': T - 177..184 'loop {}': ! - 182..184 '{}': () - 199..200 'x': impl Trait - 219..230 '{ loop {} }': T - 221..228 'loop {}': ! - 226..228 '{}': () - 300..509 '{ ... i32 }': () - 306..314 'Foo::bar': fn bar<{unknown}, {unknown}>(S) -> {unknown} - 306..317 'Foo::bar(S)': {unknown} - 315..316 'S': S - 323..338 '::bar': fn bar(S) -> {unknown} - 323..341 '(S) -> {unknown} - 347..356 'F::bar(S)': {unknown} - 354..355 'S': S - 362..377 'Foo::bar::': fn bar<{unknown}, u32>(S) -> u32 - 362..380 'Foo::b...32>(S)': u32 - 378..379 'S': S - 386..408 '': fn bar(S) -> u32 - 386..411 '(S)': u32 - 409..410 'S': S - 418..421 'foo': fn foo<{unknown}>(S) -> {unknown} - 418..424 'foo(S)': {unknown} - 422..423 'S': S - 430..440 'foo::': fn foo(S) -> u32 - 430..443 'foo::(S)': u32 - 441..442 'S': S - 449..464 'foo::': fn foo(S) -> u32 - 449..467 'foo::<...32>(S)': u32 - 465..466 'S': S - "#]], - ); -} - -#[test] -fn argument_impl_trait_type_args_2() { - check_infer_with_mismatches( - r#" -//- minicore: sized -trait Trait {} -struct S; -impl Trait for S {} -struct F; -impl F { - fn foo(self, x: impl Trait) -> (T, U) { loop {} } -} - -fn test() { - F.foo(S); - F::.foo(S); - F::.foo::(S); - F::.foo::(S); // extraneous argument should be ignored -}"#, - expect![[r#" - 87..91 'self': F - 93..94 'x': impl Trait - 118..129 '{ loop {} }': (T, U) - 120..127 'loop {}': ! - 125..127 '{}': () - 143..283 '{ ...ored }': () - 149..150 'F': F<{unknown}> - 149..157 'F.foo(S)': ({unknown}, {unknown}) - 155..156 'S': S - 163..171 'F::': F - 163..178 'F::.foo(S)': (u32, {unknown}) - 176..177 'S': S - 184..192 'F::': F - 184..206 'F::(S)': (u32, i32) - 204..205 'S': S - 212..220 'F::': F - 212..239 'F::(S)': (u32, i32) - 237..238 'S': S - "#]], - ); -} - -#[test] -fn argument_impl_trait_to_fn_pointer() { - check_infer_with_mismatches( - r#" -//- minicore: sized -trait Trait {} -fn foo(x: impl Trait) { loop {} } -struct S; -impl Trait for S {} - -fn test() { - let f: fn(S) -> () = foo; -}"#, - expect![[r#" - 22..23 'x': impl Trait - 37..48 '{ loop {} }': () - 39..46 'loop {}': ! - 44..46 '{}': () - 90..123 '{ ...foo; }': () - 100..101 'f': fn(S) - 117..120 'foo': fn foo(S) - "#]], - ); -} - -#[test] -fn impl_trait() { - check_infer( - r#" -//- minicore: sized -trait Trait { - fn foo(&self) -> T; - fn foo2(&self) -> i64; -} -fn bar() -> impl Trait {} - -fn test(x: impl Trait, y: &impl Trait) { - x; - y; - let z = bar(); - x.foo(); - y.foo(); - z.foo(); - x.foo2(); - y.foo2(); - z.foo2(); -}"#, - expect![[r#" - 29..33 'self': &Self - 54..58 'self': &Self - 98..100 '{}': () - 110..111 'x': impl Trait - 130..131 'y': &impl Trait - 151..268 '{ ...2(); }': () - 157..158 'x': impl Trait - 164..165 'y': &impl Trait - 175..176 'z': impl Trait - 179..182 'bar': fn bar() -> impl Trait - 179..184 'bar()': impl Trait - 190..191 'x': impl Trait - 190..197 'x.foo()': u64 - 203..204 'y': &impl Trait - 203..210 'y.foo()': u64 - 216..217 'z': impl Trait - 216..223 'z.foo()': u64 - 229..230 'x': impl Trait - 229..237 'x.foo2()': i64 - 243..244 'y': &impl Trait - 243..251 'y.foo2()': i64 - 257..258 'z': impl Trait - 257..265 'z.foo2()': i64 - "#]], - ); -} - -#[test] -fn simple_return_pos_impl_trait() { - cov_mark::check!(lower_rpit); - check_infer( - r#" -//- minicore: sized -trait Trait { - fn foo(&self) -> T; -} -fn bar() -> impl Trait { loop {} } - -fn test() { - let a = bar(); - a.foo(); -}"#, - expect![[r#" - 29..33 'self': &Self - 71..82 '{ loop {} }': ! - 73..80 'loop {}': ! - 78..80 '{}': () - 94..129 '{ ...o(); }': () - 104..105 'a': impl Trait - 108..111 'bar': fn bar() -> impl Trait - 108..113 'bar()': impl Trait - 119..120 'a': impl Trait - 119..126 'a.foo()': u64 - "#]], - ); -} - -#[test] -fn more_return_pos_impl_trait() { - check_infer( - r#" -//- minicore: sized -trait Iterator { - type Item; - fn next(&mut self) -> Self::Item; -} -trait Trait { - fn foo(&self) -> T; -} -fn bar() -> (impl Iterator>, impl Trait) { loop {} } -fn baz(t: T) -> (impl Iterator>, impl Trait) { loop {} } - -fn test() { - let (a, b) = bar(); - a.next().foo(); - b.foo(); - let (c, d) = baz(1u128); - c.next().foo(); - d.foo(); -}"#, - expect![[r#" - 49..53 'self': &mut Self - 101..105 'self': &Self - 184..195 '{ loop {} }': ({unknown}, {unknown}) - 186..193 'loop {}': ! - 191..193 '{}': () - 206..207 't': T - 268..279 '{ loop {} }': ({unknown}, {unknown}) - 270..277 'loop {}': ! - 275..277 '{}': () - 291..413 '{ ...o(); }': () - 301..307 '(a, b)': (impl Iterator>, impl Trait) - 302..303 'a': impl Iterator> - 305..306 'b': impl Trait - 310..313 'bar': fn bar() -> (impl Iterator>, impl Trait) - 310..315 'bar()': (impl Iterator>, impl Trait) - 321..322 'a': impl Iterator> - 321..329 'a.next()': impl Trait - 321..335 'a.next().foo()': u32 - 341..342 'b': impl Trait - 341..348 'b.foo()': u64 - 358..364 '(c, d)': (impl Iterator>, impl Trait) - 359..360 'c': impl Iterator> - 362..363 'd': impl Trait - 367..370 'baz': fn baz(u128) -> (impl Iterator>, impl Trait) - 367..377 'baz(1u128)': (impl Iterator>, impl Trait) - 371..376 '1u128': u128 - 383..384 'c': impl Iterator> - 383..391 'c.next()': impl Trait - 383..397 'c.next().foo()': u128 - 403..404 'd': impl Trait - 403..410 'd.foo()': u128 - "#]], - ); -} - -#[test] -fn infer_from_return_pos_impl_trait() { - check_infer_with_mismatches( - r#" -//- minicore: fn, sized -trait Trait {} -struct Bar(T); -impl Trait for Bar {} -fn foo() -> (impl FnOnce(&str, T), impl Trait) { - (|input, t| {}, Bar(C)) -} -"#, - expect![[r#" - 134..165 '{ ...(C)) }': (|&str, T| -> (), Bar) - 140..163 '(|inpu...ar(C))': (|&str, T| -> (), Bar) - 141..154 '|input, t| {}': |&str, T| -> () - 142..147 'input': &str - 149..150 't': T - 152..154 '{}': () - 156..159 'Bar': Bar(u8) -> Bar - 156..162 'Bar(C)': Bar - 160..161 'C': u8 - "#]], - ); -} - -#[test] -fn dyn_trait() { - check_infer( - r#" -//- minicore: sized -trait Trait { - fn foo(&self) -> T; - fn foo2(&self) -> i64; -} -fn bar() -> dyn Trait {} - -fn test(x: dyn Trait, y: &dyn Trait) { - x; - y; - let z = bar(); - x.foo(); - y.foo(); - z.foo(); - x.foo2(); - y.foo2(); - z.foo2(); -}"#, - expect![[r#" - 29..33 'self': &Self - 54..58 'self': &Self - 97..99 '{}': dyn Trait - 109..110 'x': dyn Trait - 128..129 'y': &dyn Trait - 148..265 '{ ...2(); }': () - 154..155 'x': dyn Trait - 161..162 'y': &dyn Trait - 172..173 'z': dyn Trait - 176..179 'bar': fn bar() -> dyn Trait - 176..181 'bar()': dyn Trait - 187..188 'x': dyn Trait - 187..194 'x.foo()': u64 - 200..201 'y': &dyn Trait - 200..207 'y.foo()': u64 - 213..214 'z': dyn Trait - 213..220 'z.foo()': u64 - 226..227 'x': dyn Trait - 226..234 'x.foo2()': i64 - 240..241 'y': &dyn Trait - 240..248 'y.foo2()': i64 - 254..255 'z': dyn Trait - 254..262 'z.foo2()': i64 - "#]], - ); -} - -#[test] -fn dyn_trait_in_impl() { - check_infer( - r#" -//- minicore: sized -trait Trait { - fn foo(&self) -> (T, U); -} -struct S {} -impl S { - fn bar(&self) -> &dyn Trait { loop {} } -} -trait Trait2 { - fn baz(&self) -> (T, U); -} -impl Trait2 for dyn Trait { } - -fn test(s: S) { - s.bar().baz(); -}"#, - expect![[r#" - 32..36 'self': &Self - 102..106 'self': &S - 128..139 '{ loop {} }': &dyn Trait - 130..137 'loop {}': ! - 135..137 '{}': () - 175..179 'self': &Self - 251..252 's': S - 267..289 '{ ...z(); }': () - 273..274 's': S - 273..280 's.bar()': &dyn Trait - 273..286 's.bar().baz()': (u32, i32) - "#]], - ); -} - -#[test] -fn dyn_trait_bare() { - check_infer( - r#" -//- minicore: sized -trait Trait { - fn foo(&self) -> u64; -} -fn bar() -> Trait {} - -fn test(x: Trait, y: &Trait) -> u64 { - x; - y; - let z = bar(); - x.foo(); - y.foo(); - z.foo(); -}"#, - expect![[r#" - 26..30 'self': &Self - 60..62 '{}': dyn Trait - 72..73 'x': dyn Trait - 82..83 'y': &dyn Trait - 100..175 '{ ...o(); }': u64 - 106..107 'x': dyn Trait - 113..114 'y': &dyn Trait - 124..125 'z': dyn Trait - 128..131 'bar': fn bar() -> dyn Trait - 128..133 'bar()': dyn Trait - 139..140 'x': dyn Trait - 139..146 'x.foo()': u64 - 152..153 'y': &dyn Trait - 152..159 'y.foo()': u64 - 165..166 'z': dyn Trait - 165..172 'z.foo()': u64 - "#]], - ); -} - -#[test] -fn weird_bounds() { - check_infer( - r#" -//- minicore: sized -trait Trait {} -fn test( - a: impl Trait + 'lifetime, - b: impl 'lifetime, - c: impl (Trait), - d: impl ('lifetime), - e: impl ?Sized, - f: impl Trait + ?Sized -) {} -"#, - expect![[r#" - 28..29 'a': impl Trait - 59..60 'b': impl Sized - 82..83 'c': impl Trait - 103..104 'd': impl Sized - 128..129 'e': impl ?Sized - 148..149 'f': impl Trait + ?Sized - 173..175 '{}': () - "#]], - ); -} - -#[test] -fn error_bound_chalk() { - check_types( - r#" -trait Trait { - fn foo(&self) -> u32 { 0 } -} - -fn test(x: (impl Trait + UnknownTrait)) { - x.foo(); -} //^^^^^^^ u32 -"#, - ); -} - -#[test] -fn assoc_type_bindings() { - check_infer( - r#" -//- minicore: sized -trait Trait { - type Type; -} - -fn get(t: T) -> ::Type {} -fn get2>(t: T) -> U {} -fn set>(t: T) -> T {t} - -struct S; -impl Trait for S { type Type = T; } - -fn test>(x: T, y: impl Trait) { - get(x); - get2(x); - get(y); - get2(y); - get(set(S)); - get2(set(S)); - get2(S::); -}"#, - expect![[r#" - 49..50 't': T - 77..79 '{}': Trait::Type - 111..112 't': T - 122..124 '{}': U - 154..155 't': T - 165..168 '{t}': T - 166..167 't': T - 256..257 'x': T - 262..263 'y': impl Trait - 289..397 '{ ...r>); }': () - 295..298 'get': fn get(T) -> ::Type - 295..301 'get(x)': u32 - 299..300 'x': T - 307..311 'get2': fn get2(T) -> u32 - 307..314 'get2(x)': u32 - 312..313 'x': T - 320..323 'get': fn get>(impl Trait) -> as Trait>::Type - 320..326 'get(y)': i64 - 324..325 'y': impl Trait - 332..336 'get2': fn get2>(impl Trait) -> i64 - 332..339 'get2(y)': i64 - 337..338 'y': impl Trait - 345..348 'get': fn get>(S) -> as Trait>::Type - 345..356 'get(set(S))': u64 - 349..352 'set': fn set>(S) -> S - 349..355 'set(S)': S - 353..354 'S': S - 362..366 'get2': fn get2>(S) -> u64 - 362..374 'get2(set(S))': u64 - 367..370 'set': fn set>(S) -> S - 367..373 'set(S)': S - 371..372 'S': S - 380..384 'get2': fn get2>(S) -> str - 380..394 'get2(S::)': str - 385..393 'S::': S - "#]], - ); -} - -#[test] -fn impl_trait_assoc_binding_projection_bug() { - check_types( - r#" -//- minicore: iterator -pub trait Language { - type Kind; -} -pub enum RustLanguage {} -impl Language for RustLanguage { - type Kind = SyntaxKind; -} -struct SyntaxNode {} -fn foo() -> impl Iterator> {} - -trait Clone { - fn clone(&self) -> Self; -} - -fn api_walkthrough() { - for node in foo() { - node.clone(); - } //^^^^^^^^^^^^ {unknown} -} -"#, - ); -} - -#[test] -fn projection_eq_within_chalk() { - check_infer( - r#" -trait Trait1 { - type Type; -} -trait Trait2 { - fn foo(self) -> T; -} -impl Trait2 for U where U: Trait1 {} - -fn test>(x: T) { - x.foo(); -}"#, - expect![[r#" - 61..65 'self': Self - 163..164 'x': T - 169..185 '{ ...o(); }': () - 175..176 'x': T - 175..182 'x.foo()': u32 - "#]], - ); -} - -#[test] -fn where_clause_trait_in_scope_for_method_resolution() { - check_types( - r#" -mod foo { - trait Trait { - fn foo(&self) -> u32 { 0 } - } -} - -fn test(x: T) { - x.foo(); -} //^^^^^^^ u32 -"#, - ); -} - -#[test] -fn super_trait_method_resolution() { - check_infer( - r#" -mod foo { - trait SuperTrait { - fn foo(&self) -> u32 {} - } -} -trait Trait1: foo::SuperTrait {} -trait Trait2 where Self: foo::SuperTrait {} - -fn test(x: T, y: U) { - x.foo(); - y.foo(); -}"#, - expect![[r#" - 49..53 'self': &Self - 62..64 '{}': u32 - 181..182 'x': T - 187..188 'y': U - 193..222 '{ ...o(); }': () - 199..200 'x': T - 199..206 'x.foo()': u32 - 212..213 'y': U - 212..219 'y.foo()': u32 - "#]], - ); -} - -#[test] -fn super_trait_impl_trait_method_resolution() { - check_infer( - r#" -//- minicore: sized -mod foo { - trait SuperTrait { - fn foo(&self) -> u32 {} - } -} -trait Trait1: foo::SuperTrait {} - -fn test(x: &impl Trait1) { - x.foo(); -}"#, - expect![[r#" - 49..53 'self': &Self - 62..64 '{}': u32 - 115..116 'x': &impl Trait1 - 132..148 '{ ...o(); }': () - 138..139 'x': &impl Trait1 - 138..145 'x.foo()': u32 - "#]], - ); -} - -#[test] -fn super_trait_cycle() { - // This just needs to not crash - check_infer( - r#" - trait A: B {} - trait B: A {} - - fn test(x: T) { - x.foo(); - } - "#, - expect![[r#" - 43..44 'x': T - 49..65 '{ ...o(); }': () - 55..56 'x': T - 55..62 'x.foo()': {unknown} - "#]], - ); -} - -#[test] -fn super_trait_assoc_type_bounds() { - check_infer( - r#" -trait SuperTrait { type Type; } -trait Trait where Self: SuperTrait {} - -fn get2>(t: T) -> U {} -fn set>(t: T) -> T {t} - -struct S; -impl SuperTrait for S { type Type = T; } -impl Trait for S {} - -fn test() { - get2(set(S)); -}"#, - expect![[r#" - 102..103 't': T - 113..115 '{}': U - 145..146 't': T - 156..159 '{t}': T - 157..158 't': T - 258..279 '{ ...S)); }': () - 264..268 'get2': fn get2>(S) -> u64 - 264..276 'get2(set(S))': u64 - 269..272 'set': fn set>(S) -> S - 269..275 'set(S)': S - 273..274 'S': S - "#]], - ); -} - -#[test] -fn fn_trait() { - check_infer_with_mismatches( - r#" -trait FnOnce { - type Output; - - fn call_once(self, args: Args) -> >::Output; -} - -fn test u128>(f: F) { - f.call_once((1, 2)); -}"#, - expect![[r#" - 56..60 'self': Self - 62..66 'args': Args - 149..150 'f': F - 155..183 '{ ...2)); }': () - 161..162 'f': F - 161..180 'f.call...1, 2))': u128 - 173..179 '(1, 2)': (u32, u64) - 174..175 '1': u32 - 177..178 '2': u64 - "#]], - ); -} - -#[test] -fn fn_ptr_and_item() { - check_infer_with_mismatches( - r#" -#[lang="fn_once"] -trait FnOnce { - type Output; - - fn call_once(self, args: Args) -> Self::Output; -} - -trait Foo { - fn foo(&self) -> T; -} - -struct Bar(T); - -impl R> Foo<(A1, R)> for Bar { - fn foo(&self) -> (A1, R) { loop {} } -} - -enum Opt { None, Some(T) } -impl Opt { - fn map U>(self, f: F) -> Opt { loop {} } -} - -fn test() { - let bar: Bar u32>; - bar.foo(); - - let opt: Opt; - let f: fn(u8) -> u32; - opt.map(f); -}"#, - expect![[r#" - 74..78 'self': Self - 80..84 'args': Args - 139..143 'self': &Self - 243..247 'self': &Bar - 260..271 '{ loop {} }': (A1, R) - 262..269 'loop {}': ! - 267..269 '{}': () - 355..359 'self': Opt - 361..362 'f': F - 377..388 '{ loop {} }': Opt - 379..386 'loop {}': ! - 384..386 '{}': () - 402..518 '{ ...(f); }': () - 412..415 'bar': Bar u32> - 441..444 'bar': Bar u32> - 441..450 'bar.foo()': (u8, u32) - 461..464 'opt': Opt - 483..484 'f': fn(u8) -> u32 - 505..508 'opt': Opt - 505..515 'opt.map(f)': Opt - 513..514 'f': fn(u8) -> u32 - "#]], - ); -} - -#[test] -fn fn_trait_deref_with_ty_default() { - check_infer( - r#" -//- minicore: deref, fn -struct Foo; - -impl Foo { - fn foo(&self) -> usize {} -} - -struct Lazy T>(F); - -impl Lazy { - pub fn new(f: F) -> Lazy {} -} - -impl T> core::ops::Deref for Lazy { - type Target = T; -} - -fn test() { - let lazy1: Lazy = Lazy::new(|| Foo); - let r1 = lazy1.foo(); - - fn make_foo_fn() -> Foo {} - let make_foo_fn_ptr: fn() -> Foo = make_foo_fn; - let lazy2: Lazy = Lazy::new(make_foo_fn_ptr); - let r2 = lazy2.foo(); -}"#, - expect![[r#" - 36..40 'self': &Foo - 51..53 '{}': usize - 131..132 'f': F - 151..153 '{}': Lazy - 251..497 '{ ...o(); }': () - 261..266 'lazy1': Lazy Foo> - 283..292 'Lazy::new': fn new Foo>(|| -> Foo) -> Lazy Foo> - 283..300 'Lazy::...| Foo)': Lazy Foo> - 293..299 '|| Foo': || -> Foo - 296..299 'Foo': Foo - 310..312 'r1': usize - 315..320 'lazy1': Lazy Foo> - 315..326 'lazy1.foo()': usize - 368..383 'make_foo_fn_ptr': fn() -> Foo - 399..410 'make_foo_fn': fn make_foo_fn() -> Foo - 420..425 'lazy2': Lazy Foo> - 442..451 'Lazy::new': fn new Foo>(fn() -> Foo) -> Lazy Foo> - 442..468 'Lazy::...n_ptr)': Lazy Foo> - 452..467 'make_foo_fn_ptr': fn() -> Foo - 478..480 'r2': usize - 483..488 'lazy2': Lazy Foo> - 483..494 'lazy2.foo()': usize - 357..359 '{}': Foo - "#]], - ); -} - -#[test] -fn closure_1() { - check_infer_with_mismatches( - r#" -//- minicore: fn -enum Option { Some(T), None } -impl Option { - fn map U>(self, f: F) -> Option { loop {} } -} - -fn test() { - let x = Option::Some(1u32); - x.map(|v| v + 1); - x.map(|_v| 1u64); - let y: Option = x.map(|_v| 1); -}"#, - expect![[r#" - 86..90 'self': Option - 92..93 'f': F - 111..122 '{ loop {} }': Option - 113..120 'loop {}': ! - 118..120 '{}': () - 136..255 '{ ... 1); }': () - 146..147 'x': Option - 150..162 'Option::Some': Some(u32) -> Option - 150..168 'Option...(1u32)': Option - 163..167 '1u32': u32 - 174..175 'x': Option - 174..190 'x.map(...v + 1)': Option - 180..189 '|v| v + 1': |u32| -> u32 - 181..182 'v': u32 - 184..185 'v': u32 - 184..189 'v + 1': u32 - 188..189 '1': u32 - 196..197 'x': Option - 196..212 'x.map(... 1u64)': Option - 202..211 '|_v| 1u64': |u32| -> u64 - 203..205 '_v': u32 - 207..211 '1u64': u64 - 222..223 'y': Option - 239..240 'x': Option - 239..252 'x.map(|_v| 1)': Option - 245..251 '|_v| 1': |u32| -> i64 - 246..248 '_v': u32 - 250..251 '1': i64 - "#]], - ); -} - -#[test] -fn closure_2() { - check_types( - r#" -//- minicore: add, fn - -impl core::ops::Add for u64 { - type Output = Self; - fn add(self, rhs: u64) -> Self::Output {0} -} - -impl core::ops::Add for u128 { - type Output = Self; - fn add(self, rhs: u128) -> Self::Output {0} -} - -fn test u64>(f: F) { - f(1); - // ^ u32 - //^^^^ u64 - let g = |v| v + 1; - //^^^^^ u64 - //^^^^^^^^^ |u64| -> u64 - g(1u64); - //^^^^^^^ u64 - let h = |v| 1u128 + v; - //^^^^^^^^^^^^^ |u128| -> u128 -}"#, - ); -} - -#[test] -fn closure_as_argument_inference_order() { - check_infer_with_mismatches( - r#" -//- minicore: fn -fn foo1 U>(x: T, f: F) -> U { loop {} } -fn foo2 U>(f: F, x: T) -> U { loop {} } - -struct S; -impl S { - fn method(self) -> u64; - - fn foo1 U>(self, x: T, f: F) -> U { loop {} } - fn foo2 U>(self, f: F, x: T) -> U { loop {} } -} - -fn test() { - let x1 = foo1(S, |s| s.method()); - let x2 = foo2(|s| s.method(), S); - let x3 = S.foo1(S, |s| s.method()); - let x4 = S.foo2(|s| s.method(), S); -}"#, - expect![[r#" - 33..34 'x': T - 39..40 'f': F - 50..61 '{ loop {} }': U - 52..59 'loop {}': ! - 57..59 '{}': () - 95..96 'f': F - 101..102 'x': T - 112..123 '{ loop {} }': U - 114..121 'loop {}': ! - 119..121 '{}': () - 158..162 'self': S - 210..214 'self': S - 216..217 'x': T - 222..223 'f': F - 233..244 '{ loop {} }': U - 235..242 'loop {}': ! - 240..242 '{}': () - 282..286 'self': S - 288..289 'f': F - 294..295 'x': T - 305..316 '{ loop {} }': U - 307..314 'loop {}': ! - 312..314 '{}': () - 330..489 '{ ... S); }': () - 340..342 'x1': u64 - 345..349 'foo1': fn foo1 u64>(S, |S| -> u64) -> u64 - 345..368 'foo1(S...hod())': u64 - 350..351 'S': S - 353..367 '|s| s.method()': |S| -> u64 - 354..355 's': S - 357..358 's': S - 357..367 's.method()': u64 - 378..380 'x2': u64 - 383..387 'foo2': fn foo2 u64>(|S| -> u64, S) -> u64 - 383..406 'foo2(|...(), S)': u64 - 388..402 '|s| s.method()': |S| -> u64 - 389..390 's': S - 392..393 's': S - 392..402 's.method()': u64 - 404..405 'S': S - 416..418 'x3': u64 - 421..422 'S': S - 421..446 'S.foo1...hod())': u64 - 428..429 'S': S - 431..445 '|s| s.method()': |S| -> u64 - 432..433 's': S - 435..436 's': S - 435..445 's.method()': u64 - 456..458 'x4': u64 - 461..462 'S': S - 461..486 'S.foo2...(), S)': u64 - 468..482 '|s| s.method()': |S| -> u64 - 469..470 's': S - 472..473 's': S - 472..482 's.method()': u64 - 484..485 'S': S - "#]], - ); -} - -#[test] -fn fn_item_fn_trait() { - check_types( - r#" -//- minicore: fn -struct S; - -fn foo() -> S { S } - -fn takes_closure U>(f: F) -> U { f() } - -fn test() { - takes_closure(foo); -} //^^^^^^^^^^^^^^^^^^ S -"#, - ); -} - -#[test] -fn unselected_projection_in_trait_env_1() { - check_types( - r#" -//- /main.rs -trait Trait { - type Item; -} - -trait Trait2 { - fn foo(&self) -> u32; -} - -fn test() where T::Item: Trait2 { - let x: T::Item = no_matter; - x.foo(); -} //^^^^^^^ u32 -"#, - ); -} - -#[test] -fn unselected_projection_in_trait_env_2() { - check_types( - r#" -trait Trait { - type Item; -} - -trait Trait2 { - fn foo(&self) -> u32; -} - -fn test() where T::Item: Trait2, T: Trait, U: Trait<()> { - let x: T::Item = no_matter; - x.foo(); -} //^^^^^^^ u32 -"#, - ); -} - -#[test] -fn unselected_projection_on_impl_self() { - check_infer( - r#" -//- /main.rs -trait Trait { - type Item; - - fn f(&self, x: Self::Item); -} - -struct S; - -impl Trait for S { - type Item = u32; - fn f(&self, x: Self::Item) { let y = x; } -} - -struct S2; - -impl Trait for S2 { - type Item = i32; - fn f(&self, x: ::Item) { let y = x; } -}"#, - expect![[r#" - 40..44 'self': &Self - 46..47 'x': Trait::Item - 126..130 'self': &S - 132..133 'x': u32 - 147..161 '{ let y = x; }': () - 153..154 'y': u32 - 157..158 'x': u32 - 228..232 'self': &S2 - 234..235 'x': i32 - 251..265 '{ let y = x; }': () - 257..258 'y': i32 - 261..262 'x': i32 - "#]], - ); -} - -#[test] -fn unselected_projection_on_trait_self() { - check_types( - r#" -trait Trait { - type Item; - - fn f(&self) -> Self::Item { loop {} } -} - -struct S; -impl Trait for S { - type Item = u32; -} - -fn test() { - S.f(); -} //^^^^^ u32 -"#, - ); -} - -#[test] -fn unselected_projection_chalk_fold() { - check_types( - r#" -trait Interner {} -trait Fold { - type Result; -} - -struct Ty {} -impl Fold for Ty { - type Result = Ty; -} - -fn fold(interner: &I, t: T) -> T::Result -where - T: Fold, -{ - loop {} -} - -fn foo(interner: &I, t: Ty) { - fold(interner, t); -} //^^^^^^^^^^^^^^^^^ Ty -"#, - ); -} - -#[test] -fn trait_impl_self_ty() { - check_types( - r#" -trait Trait { - fn foo(&self); -} - -struct S; - -impl Trait for S {} - -fn test() { - S.foo(); -} //^^^^^^^ () -"#, - ); -} - -#[test] -fn trait_impl_self_ty_cycle() { - check_types( - r#" -trait Trait { - fn foo(&self); -} - -struct S; - -impl Trait for S {} - -fn test() { - S.foo(); -} //^^^^^^^ {unknown} -"#, - ); -} - -#[test] -fn unselected_projection_in_trait_env_cycle_1() { - // This is not a cycle, because the `T: Trait2` bound depends only on the `T: Trait` - // bound, not on itself (since only `Trait` can define `Item`). - check_types( - r#" -trait Trait { - type Item; -} - -trait Trait2 {} - -fn test() where T: Trait2 { - let x: T::Item = no_matter; -} //^^^^^^^^^ Trait::Item -"#, - ); -} - -#[test] -fn unselected_projection_in_trait_env_cycle_2() { - // this is a legitimate cycle - check_types( - r#" -//- /main.rs -trait Trait { - type Item; -} - -fn test() where T: Trait, U: Trait { - let x: T::Item = no_matter; -} //^^^^^^^^^ {unknown} -"#, - ); -} - -#[test] -fn unselected_projection_in_trait_env_cycle_3() { - // this is a cycle for rustc; we currently accept it - check_types( - r#" -//- /main.rs -trait Trait { - type Item; - type OtherItem; -} - -fn test() where T: Trait { - let x: T::Item = no_matter; -} //^^^^^^^^^ Trait::Item -"#, - ); -} - -#[test] -fn unselected_projection_in_trait_env_no_cycle() { - // this is not a cycle - check_types( - r#" -//- /main.rs -trait Index { - type Output; -} - -type Key = ::Key; - -pub trait UnificationStoreBase: Index> { - type Key; - - fn len(&self) -> usize; -} - -pub trait UnificationStoreMut: UnificationStoreBase { - fn push(&mut self, value: Self::Key); -} - -fn test(t: T) where T: UnificationStoreMut { - let x; - t.push(x); - let y: Key; - (x, y); -} //^^^^^^ (UnificationStoreBase::Key, UnificationStoreBase::Key) -"#, - ); -} - -#[test] -fn inline_assoc_type_bounds_1() { - check_types( - r#" -trait Iterator { - type Item; -} -trait OtherTrait { - fn foo(&self) -> T; -} - -// workaround for Chalk assoc type normalization problems -pub struct S; -impl Iterator for S { - type Item = ::Item; -} - -fn test>>() { - let x: as Iterator>::Item; - x.foo(); -} //^^^^^^^ u32 -"#, - ); -} - -#[test] -fn inline_assoc_type_bounds_2() { - check_types( - r#" -trait Iterator { - type Item; -} - -fn test>>() { - let x: <::Item as Iterator>::Item; - x; -} //^ u32 -"#, - ); -} - -#[test] -fn proc_macro_server_types() { - check_infer( - r#" -macro_rules! with_api { - ($S:ident, $self:ident, $m:ident) => { - $m! { - TokenStream { - fn new() -> $S::TokenStream; - }, - Group { - }, - } - }; -} -macro_rules! associated_item { - (type TokenStream) => - (type TokenStream: 'static;); - (type Group) => - (type Group: 'static;); - ($($item:tt)*) => ($($item)*;) -} -macro_rules! declare_server_traits { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - pub trait Types { - $(associated_item!(type $name);)* - } - - $(pub trait $name: Types { - $(associated_item!(fn $method($($arg: $arg_ty),*) $(-> $ret_ty)?);)* - })* - - pub trait Server: Types $(+ $name)* {} - impl Server for S {} - } -} - -with_api!(Self, self_, declare_server_traits); -struct G {} -struct T {} -struct RustAnalyzer; -impl Types for RustAnalyzer { - type TokenStream = T; - type Group = G; -} - -fn make() -> T { loop {} } -impl TokenStream for RustAnalyzer { - fn new() -> Self::TokenStream { - let group: Self::Group = make(); - make() - } -}"#, - expect![[r#" - 1075..1086 '{ loop {} }': T - 1077..1084 'loop {}': ! - 1082..1084 '{}': () - 1157..1220 '{ ... }': T - 1171..1176 'group': G - 1192..1196 'make': fn make() -> G - 1192..1198 'make()': G - 1208..1212 'make': fn make() -> T - 1208..1214 'make()': T - "#]], - ); -} - -#[test] -fn unify_impl_trait() { - check_infer_with_mismatches( - r#" -//- minicore: sized -trait Trait {} - -fn foo(x: impl Trait) { loop {} } -fn bar(x: impl Trait) -> T { loop {} } - -struct S(T); -impl Trait for S {} - -fn default() -> T { loop {} } - -fn test() -> impl Trait { - let s1 = S(default()); - foo(s1); - let x: i32 = bar(S(default())); - S(default()) -}"#, - expect![[r#" - 26..27 'x': impl Trait - 46..57 '{ loop {} }': () - 48..55 'loop {}': ! - 53..55 '{}': () - 68..69 'x': impl Trait - 91..102 '{ loop {} }': T - 93..100 'loop {}': ! - 98..100 '{}': () - 171..182 '{ loop {} }': T - 173..180 'loop {}': ! - 178..180 '{}': () - 213..309 '{ ...t()) }': S - 223..225 's1': S - 228..229 'S': S(u32) -> S - 228..240 'S(default())': S - 230..237 'default': fn default() -> u32 - 230..239 'default()': u32 - 246..249 'foo': fn foo(S) - 246..253 'foo(s1)': () - 250..252 's1': S - 263..264 'x': i32 - 272..275 'bar': fn bar(S) -> i32 - 272..289 'bar(S(...lt()))': i32 - 276..277 'S': S(i32) -> S - 276..288 'S(default())': S - 278..285 'default': fn default() -> i32 - 278..287 'default()': i32 - 295..296 'S': S(i32) -> S - 295..307 'S(default())': S - 297..304 'default': fn default() -> i32 - 297..306 'default()': i32 - "#]], - ); -} - -#[test] -fn assoc_types_from_bounds() { - check_infer( - r#" -//- minicore: fn -trait T { - type O; -} - -impl T for () { - type O = (); -} - -fn f(_v: F) -where - X: T, - F: FnOnce(&X::O), -{ } - -fn main() { - f::<(), _>(|z| { z; }); -}"#, - expect![[r#" - 72..74 '_v': F - 117..120 '{ }': () - 132..163 '{ ... }); }': () - 138..148 'f::<(), _>': fn f<(), |&()| -> ()>(|&()| -> ()) - 138..160 'f::<()... z; })': () - 149..159 '|z| { z; }': |&()| -> () - 150..151 'z': &() - 153..159 '{ z; }': () - 155..156 'z': &() - "#]], - ); -} - -#[test] -fn associated_type_bound() { - check_types( - r#" -pub trait Trait { - type Item: OtherTrait; -} -pub trait OtherTrait { - fn foo(&self) -> T; -} - -// this is just a workaround for chalk#234 -pub struct S; -impl Trait for S { - type Item = ::Item; -} - -fn test() { - let y: as Trait>::Item = no_matter; - y.foo(); -} //^^^^^^^ u32 -"#, - ); -} - -#[test] -fn dyn_trait_through_chalk() { - check_types( - r#" -//- minicore: deref -struct Box {} -impl core::ops::Deref for Box { - type Target = T; -} -trait Trait { - fn foo(&self); -} - -fn test(x: Box) { - x.foo(); -} //^^^^^^^ () -"#, - ); -} - -#[test] -fn string_to_owned() { - check_types( - r#" -struct String {} -pub trait ToOwned { - type Owned; - fn to_owned(&self) -> Self::Owned; -} -impl ToOwned for str { - type Owned = String; -} -fn test() { - "foo".to_owned(); -} //^^^^^^^^^^^^^^^^ String -"#, - ); -} - -#[test] -fn iterator_chain() { - check_infer_with_mismatches( - r#" -//- minicore: fn, option -pub trait Iterator { - type Item; - - fn filter_map(self, f: F) -> FilterMap - where - F: FnMut(Self::Item) -> Option, - { loop {} } - - fn for_each(self, f: F) - where - F: FnMut(Self::Item), - { loop {} } -} - -pub trait IntoIterator { - type Item; - type IntoIter: Iterator; - fn into_iter(self) -> Self::IntoIter; -} - -pub struct FilterMap { } -impl Iterator for FilterMap -where - F: FnMut(I::Item) -> Option, -{ - type Item = B; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for I { - type Item = I::Item; - type IntoIter = I; - - fn into_iter(self) -> I { - self - } -} - -struct Vec {} -impl Vec { - fn new() -> Self { loop {} } -} - -impl IntoIterator for Vec { - type Item = T; - type IntoIter = IntoIter; -} - -pub struct IntoIter { } -impl Iterator for IntoIter { - type Item = T; -} - -fn main() { - Vec::::new().into_iter() - .filter_map(|x| if x > 0 { Some(x as u32) } else { None }) - .for_each(|y| { y; }); -}"#, - expect![[r#" - 61..65 'self': Self - 67..68 'f': F - 152..163 '{ loop {} }': FilterMap - 154..161 'loop {}': ! - 159..161 '{}': () - 184..188 'self': Self - 190..191 'f': F - 240..251 '{ loop {} }': () - 242..249 'loop {}': ! - 247..249 '{}': () - 360..364 'self': Self - 689..693 'self': I - 700..720 '{ ... }': I - 710..714 'self': I - 779..790 '{ loop {} }': Vec - 781..788 'loop {}': ! - 786..788 '{}': () - 977..1104 '{ ... }); }': () - 983..998 'Vec::::new': fn new() -> Vec - 983..1000 'Vec::<...:new()': Vec - 983..1012 'Vec::<...iter()': IntoIter - 983..1075 'Vec::<...one })': FilterMap, |i32| -> Option> - 983..1101 'Vec::<... y; })': () - 1029..1074 '|x| if...None }': |i32| -> Option - 1030..1031 'x': i32 - 1033..1074 'if x >...None }': Option - 1036..1037 'x': i32 - 1036..1041 'x > 0': bool - 1040..1041 '0': i32 - 1042..1060 '{ Some...u32) }': Option - 1044..1048 'Some': Some(u32) -> Option - 1044..1058 'Some(x as u32)': Option - 1049..1050 'x': i32 - 1049..1057 'x as u32': u32 - 1066..1074 '{ None }': Option - 1068..1072 'None': Option - 1090..1100 '|y| { y; }': |u32| -> () - 1091..1092 'y': u32 - 1094..1100 '{ y; }': () - 1096..1097 'y': u32 - "#]], - ); -} - -#[test] -fn nested_assoc() { - check_types( - r#" -struct Bar; -struct Foo; - -trait A { - type OutputA; -} - -impl A for Bar { - type OutputA = Foo; -} - -trait B { - type Output; - fn foo() -> Self::Output; -} - -impl B for T { - type Output = T::OutputA; - fn foo() -> Self::Output { loop {} } -} - -fn main() { - Bar::foo(); -} //^^^^^^^^^^ Foo -"#, - ); -} - -#[test] -fn trait_object_no_coercion() { - check_infer_with_mismatches( - r#" -trait Foo {} - -fn foo(x: &dyn Foo) {} - -fn test(x: &dyn Foo) { - foo(x); -}"#, - expect![[r#" - 21..22 'x': &dyn Foo - 34..36 '{}': () - 46..47 'x': &dyn Foo - 59..74 '{ foo(x); }': () - 65..68 'foo': fn foo(&dyn Foo) - 65..71 'foo(x)': () - 69..70 'x': &dyn Foo - "#]], - ); -} - -#[test] -fn builtin_copy() { - check_infer_with_mismatches( - r#" -//- minicore: copy -struct IsCopy; -impl Copy for IsCopy {} -struct NotCopy; - -trait Test { fn test(&self) -> bool; } -impl Test for T {} - -fn test() { - IsCopy.test(); - NotCopy.test(); - (IsCopy, IsCopy).test(); - (IsCopy, NotCopy).test(); -}"#, - expect![[r#" - 78..82 'self': &Self - 134..235 '{ ...t(); }': () - 140..146 'IsCopy': IsCopy - 140..153 'IsCopy.test()': bool - 159..166 'NotCopy': NotCopy - 159..173 'NotCopy.test()': {unknown} - 179..195 '(IsCop...sCopy)': (IsCopy, IsCopy) - 179..202 '(IsCop...test()': bool - 180..186 'IsCopy': IsCopy - 188..194 'IsCopy': IsCopy - 208..225 '(IsCop...tCopy)': (IsCopy, NotCopy) - 208..232 '(IsCop...test()': {unknown} - 209..215 'IsCopy': IsCopy - 217..224 'NotCopy': NotCopy - "#]], - ); -} - -#[test] -fn builtin_fn_def_copy() { - check_infer_with_mismatches( - r#" -//- minicore: copy -fn foo() {} -fn bar(T) -> T {} -struct Struct(usize); -enum Enum { Variant(usize) } - -trait Test { fn test(&self) -> bool; } -impl Test for T {} - -fn test() { - foo.test(); - bar.test(); - Struct.test(); - Enum::Variant.test(); -}"#, - expect![[r#" - 9..11 '{}': () - 28..29 'T': {unknown} - 36..38 '{}': T - 36..38: expected T, got () - 113..117 'self': &Self - 169..249 '{ ...t(); }': () - 175..178 'foo': fn foo() - 175..185 'foo.test()': bool - 191..194 'bar': fn bar<{unknown}>({unknown}) -> {unknown} - 191..201 'bar.test()': bool - 207..213 'Struct': Struct(usize) -> Struct - 207..220 'Struct.test()': bool - 226..239 'Enum::Variant': Variant(usize) -> Enum - 226..246 'Enum::...test()': bool - "#]], - ); -} - -#[test] -fn builtin_fn_ptr_copy() { - check_infer_with_mismatches( - r#" -//- minicore: copy -trait Test { fn test(&self) -> bool; } -impl Test for T {} - -fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) { - f1.test(); - f2.test(); - f3.test(); -}"#, - expect![[r#" - 22..26 'self': &Self - 76..78 'f1': fn() - 86..88 'f2': fn(usize) -> u8 - 107..109 'f3': fn(u8, u8) -> &u8 - 130..178 '{ ...t(); }': () - 136..138 'f1': fn() - 136..145 'f1.test()': bool - 151..153 'f2': fn(usize) -> u8 - 151..160 'f2.test()': bool - 166..168 'f3': fn(u8, u8) -> &u8 - 166..175 'f3.test()': bool - "#]], - ); -} - -#[test] -fn builtin_sized() { - check_infer_with_mismatches( - r#" -//- minicore: sized -trait Test { fn test(&self) -> bool; } -impl Test for T {} - -fn test() { - 1u8.test(); - (*"foo").test(); // not Sized - (1u8, 1u8).test(); - (1u8, *"foo").test(); // not Sized -}"#, - expect![[r#" - 22..26 'self': &Self - 79..194 '{ ...ized }': () - 85..88 '1u8': u8 - 85..95 '1u8.test()': bool - 101..116 '(*"foo").test()': {unknown} - 102..108 '*"foo"': str - 103..108 '"foo"': &str - 135..145 '(1u8, 1u8)': (u8, u8) - 135..152 '(1u8, ...test()': bool - 136..139 '1u8': u8 - 141..144 '1u8': u8 - 158..171 '(1u8, *"foo")': (u8, str) - 158..178 '(1u8, ...test()': {unknown} - 159..162 '1u8': u8 - 164..170 '*"foo"': str - 165..170 '"foo"': &str - "#]], - ); -} - -#[test] -fn integer_range_iterate() { - check_types( - r#" -//- /main.rs crate:main deps:core -fn test() { - for x in 0..100 { x; } -} //^ i32 - -//- /core.rs crate:core -pub mod ops { - pub struct Range { - pub start: Idx, - pub end: Idx, - } -} - -pub mod iter { - pub trait Iterator { - type Item; - } - - pub trait IntoIterator { - type Item; - type IntoIter: Iterator; - } - - impl IntoIterator for T where T: Iterator { - type Item = ::Item; - type IntoIter = Self; - } -} - -trait Step {} -impl Step for i32 {} -impl Step for i64 {} - -impl iter::Iterator for ops::Range { - type Item = A; -} -"#, - ); -} - -#[test] -fn infer_closure_arg() { - check_infer( - r#" -//- /lib.rs - -enum Option { - None, - Some(T) -} - -fn foo() { - let s = Option::None; - let f = |x: Option| {}; - (&f)(s) -}"#, - expect![[r#" - 52..126 '{ ...)(s) }': () - 62..63 's': Option - 66..78 'Option::None': Option - 88..89 'f': |Option| -> () - 92..111 '|x: Op...2>| {}': |Option| -> () - 93..94 'x': Option - 109..111 '{}': () - 117..124 '(&f)(s)': () - 118..120 '&f': &|Option| -> () - 119..120 'f': |Option| -> () - 122..123 's': Option - "#]], - ); -} - -#[test] -fn dyn_fn_param_informs_call_site_closure_signature() { - cov_mark::check!(dyn_fn_param_informs_call_site_closure_signature); - check_types( - r#" -//- minicore: fn, coerce_unsized -struct S; -impl S { - fn inherent(&self) -> u8 { 0 } -} -fn take_dyn_fn(f: &dyn Fn(S)) {} - -fn f() { - take_dyn_fn(&|x| { x.inherent(); }); - //^^^^^^^^^^^^ u8 -} - "#, - ); -} - -#[test] -fn infer_fn_trait_arg() { - check_infer_with_mismatches( - r#" -//- minicore: fn, option -fn foo(f: F) -> T -where - F: Fn(Option) -> T, -{ - let s = None; - f(s) -} -"#, - expect![[r#" - 13..14 'f': F - 59..89 '{ ...f(s) }': T - 69..70 's': Option - 73..77 'None': Option - 83..84 'f': F - 83..87 'f(s)': T - 85..86 's': Option - "#]], - ); -} - -#[test] -fn infer_box_fn_arg() { - // The type mismatch is because we don't define Unsize and CoerceUnsized - check_infer_with_mismatches( - r#" -//- minicore: fn, deref, option -#[lang = "owned_box"] -pub struct Box { - inner: *mut T, -} - -impl core::ops::Deref for Box { - type Target = T; - - fn deref(&self) -> &T { - &self.inner - } -} - -fn foo() { - let s = None; - let f: Box)> = box (|ps| {}); - f(&s); -}"#, - expect![[r#" - 154..158 'self': &Box - 166..193 '{ ... }': &T - 176..187 '&self.inner': &*mut T - 177..181 'self': &Box - 177..187 'self.inner': *mut T - 206..296 '{ ...&s); }': () - 216..217 's': Option - 220..224 'None': Option - 234..235 'f': Box)> - 269..282 'box (|ps| {})': Box<|&Option| -> ()> - 274..281 '|ps| {}': |&Option| -> () - 275..277 'ps': &Option - 279..281 '{}': () - 288..289 'f': Box)> - 288..293 'f(&s)': () - 290..292 '&s': &Option - 291..292 's': Option - 269..282: expected Box)>, got Box<|&Option| -> ()> - "#]], - ); -} - -#[test] -fn infer_dyn_fn_output() { - check_types( - r#" -//- minicore: fn -fn foo() { - let f: &dyn Fn() -> i32; - f(); - //^^^ i32 -}"#, - ); -} - -#[test] -fn infer_dyn_fn_once_output() { - check_types( - r#" -//- minicore: fn -fn foo() { - let f: dyn FnOnce() -> i32; - f(); - //^^^ i32 -}"#, - ); -} - -#[test] -fn variable_kinds_1() { - check_types( - r#" -trait Trait { fn get(self, t: T) -> T; } -struct S; -impl Trait for S {} -impl Trait for S {} -fn test() { - S.get(1); - //^^^^^^^^ u128 - S.get(1.); - //^^^^^^^^^ f32 -} - "#, - ); -} - -#[test] -fn variable_kinds_2() { - check_types( - r#" -trait Trait { fn get(self) -> Self; } -impl Trait for u128 {} -impl Trait for f32 {} -fn test() { - 1.get(); - //^^^^^^^ u128 - (1.).get(); - //^^^^^^^^^^ f32 -} - "#, - ); -} - -#[test] -fn underscore_import() { - check_types( - r#" -mod tr { - pub trait Tr { - fn method(&self) -> u8 { 0 } - } -} - -struct Tr; -impl crate::tr::Tr for Tr {} - -use crate::tr::Tr as _; -fn test() { - Tr.method(); - //^^^^^^^^^^^ u8 -} - "#, - ); -} - -#[test] -fn inner_use() { - check_types( - r#" -mod m { - pub trait Tr { - fn method(&self) -> u8 { 0 } - } - - impl Tr for () {} -} - -fn f() { - use m::Tr; - - ().method(); - //^^^^^^^^^^^ u8 -} - "#, - ); -} - -#[test] -fn trait_in_scope_with_inner_item() { - check_infer( - r#" -mod m { - pub trait Tr { - fn method(&self) -> u8 { 0 } - } - - impl Tr for () {} -} - -use m::Tr; - -fn f() { - fn inner() { - ().method(); - //^^^^^^^^^^^ u8 - } -}"#, - expect![[r#" - 46..50 'self': &Self - 58..63 '{ 0 }': u8 - 60..61 '0': u8 - 115..185 '{ ... } }': () - 132..183 '{ ... }': () - 142..144 '()': () - 142..153 '().method()': u8 - "#]], - ); -} - -#[test] -fn inner_use_in_block() { - check_types( - r#" -mod m { - pub trait Tr { - fn method(&self) -> u8 { 0 } - } - - impl Tr for () {} -} - -fn f() { - { - use m::Tr; - - ().method(); - //^^^^^^^^^^^ u8 - } - - { - ().method(); - //^^^^^^^^^^^ {unknown} - } - - ().method(); - //^^^^^^^^^^^ {unknown} -} - "#, - ); -} - -#[test] -fn nested_inner_function_calling_self() { - check_infer( - r#" -struct S; -fn f() { - fn inner() -> S { - let s = inner(); - } -}"#, - expect![[r#" - 17..73 '{ ... } }': () - 39..71 '{ ... }': S - 53..54 's': S - 57..62 'inner': fn inner() -> S - 57..64 'inner()': S - "#]], - ) -} - -#[test] -fn infer_default_trait_type_parameter() { - check_infer( - r#" -struct A; - -trait Op { - type Output; - - fn do_op(self, rhs: RHS) -> Self::Output; -} - -impl Op for A { - type Output = bool; - - fn do_op(self, rhs: Self) -> Self::Output { - true - } -} - -fn test() { - let x = A; - let y = A; - let r = x.do_op(y); -}"#, - expect![[r#" - 63..67 'self': Self - 69..72 'rhs': RHS - 153..157 'self': A - 159..162 'rhs': A - 186..206 '{ ... }': bool - 196..200 'true': bool - 220..277 '{ ...(y); }': () - 230..231 'x': A - 234..235 'A': A - 245..246 'y': A - 249..250 'A': A - 260..261 'r': bool - 264..265 'x': A - 264..274 'x.do_op(y)': bool - 272..273 'y': A - "#]], - ) -} - -#[test] -fn qualified_path_as_qualified_trait() { - check_infer( - r#" -mod foo { - - pub trait Foo { - type Target; - } - pub trait Bar { - type Output; - fn boo() -> Self::Output { - loop {} - } - } -} - -struct F; -impl foo::Foo for F { - type Target = (); -} -impl foo::Bar for F { - type Output = ::Target; -} - -fn foo() { - use foo::Bar; - let x = ::boo(); -}"#, - expect![[r#" - 132..163 '{ ... }': Bar::Output - 146..153 'loop {}': ! - 151..153 '{}': () - 306..358 '{ ...o(); }': () - 334..335 'x': () - 338..353 '::boo': fn boo() -> ::Output - 338..355 ' u8 { 0 } - } -}; - -fn foo() { - Foo::deserialize(); - //^^^^^^^^^^^^^^^^^^ u8 -} - -//- /serde.rs crate:serde - -pub trait Deserialize { - fn deserialize() -> u8; -}"#, - ); -} - -#[test] -fn bin_op_with_rhs_is_self_for_assoc_bound() { - check_no_mismatches( - r#"//- minicore: eq - fn repro(t: T) -> bool -where - T: Request, - T::Output: Convertable, -{ - let a = execute(&t).convert(); - let b = execute(&t).convert(); - a.eq(&b); - let a = execute(&t).convert2(); - let b = execute(&t).convert2(); - a.eq(&b) -} -fn execute(t: &T) -> T::Output -where - T: Request, -{ - ::output() -} -trait Convertable { - type TraitSelf: PartialEq; - type AssocAsDefaultSelf: PartialEq; - fn convert(self) -> Self::AssocAsDefaultSelf; - fn convert2(self) -> Self::TraitSelf; -} -trait Request { - type Output; - fn output() -> Self::Output; -} - "#, - ); -} - -#[test] -fn bin_op_adt_with_rhs_primitive() { - check_infer_with_mismatches( - r#" -#[lang = "add"] -pub trait Add { - type Output; - fn add(self, rhs: Rhs) -> Self::Output; -} - -struct Wrapper(u32); -impl Add for Wrapper { - type Output = Self; - fn add(self, rhs: u32) -> Wrapper { - Wrapper(rhs) - } -} -fn main(){ - let wrapped = Wrapper(10); - let num: u32 = 2; - let res = wrapped + num; - -}"#, - expect![[r#" - 72..76 'self': Self - 78..81 'rhs': Rhs - 192..196 'self': Wrapper - 198..201 'rhs': u32 - 219..247 '{ ... }': Wrapper - 229..236 'Wrapper': Wrapper(u32) -> Wrapper - 229..241 'Wrapper(rhs)': Wrapper - 237..240 'rhs': u32 - 259..345 '{ ...um; }': () - 269..276 'wrapped': Wrapper - 279..286 'Wrapper': Wrapper(u32) -> Wrapper - 279..290 'Wrapper(10)': Wrapper - 287..289 '10': u32 - 300..303 'num': u32 - 311..312 '2': u32 - 322..325 'res': Wrapper - 328..335 'wrapped': Wrapper - 328..341 'wrapped + num': Wrapper - 338..341 'num': u32 - "#]], - ) -} - -#[test] -fn array_length() { - check_infer( - r#" -trait T { - type Output; - fn do_thing(&self) -> Self::Output; -} - -impl T for [u8; 4] { - type Output = usize; - fn do_thing(&self) -> Self::Output { - 2 - } -} - -impl T for [u8; 2] { - type Output = u8; - fn do_thing(&self) -> Self::Output { - 2 - } -} - -fn main() { - let v = [0u8; 2]; - let v2 = v.do_thing(); - let v3 = [0u8; 4]; - let v4 = v3.do_thing(); -} -"#, - expect![[r#" - 44..48 'self': &Self - 133..137 'self': &[u8; 4] - 155..172 '{ ... }': usize - 165..166 '2': usize - 236..240 'self': &[u8; 2] - 258..275 '{ ... }': u8 - 268..269 '2': u8 - 289..392 '{ ...g(); }': () - 299..300 'v': [u8; 2] - 303..311 '[0u8; 2]': [u8; 2] - 304..307 '0u8': u8 - 309..310 '2': usize - 321..323 'v2': u8 - 326..327 'v': [u8; 2] - 326..338 'v.do_thing()': u8 - 348..350 'v3': [u8; 4] - 353..361 '[0u8; 4]': [u8; 4] - 354..357 '0u8': u8 - 359..360 '4': usize - 371..373 'v4': usize - 376..378 'v3': [u8; 4] - 376..389 'v3.do_thing()': usize - "#]], - ) -} - -#[test] -fn const_generics() { - check_infer( - r#" -trait T { - type Output; - fn do_thing(&self) -> Self::Output; -} - -impl T for [u8; L] { - type Output = [u8; L]; - fn do_thing(&self) -> Self::Output { - *self - } -} - -fn main() { - let v = [0u8; 2]; - let v2 = v.do_thing(); -} -"#, - expect![[r#" - 44..48 'self': &Self - 151..155 'self': &[u8; L] - 173..194 '{ ... }': [u8; L] - 183..188 '*self': [u8; L] - 184..188 'self': &[u8; L] - 208..260 '{ ...g(); }': () - 218..219 'v': [u8; 2] - 222..230 '[0u8; 2]': [u8; 2] - 223..226 '0u8': u8 - 228..229 '2': usize - 240..242 'v2': [u8; 2] - 245..246 'v': [u8; 2] - 245..257 'v.do_thing()': [u8; 2] - "#]], - ) -} - -#[test] -fn fn_returning_unit() { - check_infer_with_mismatches( - r#" -//- minicore: fn -fn test(f: F) { - let _: () = f(); -}"#, - expect![[r#" - 21..22 'f': F - 27..51 '{ ...f(); }': () - 37..38 '_': () - 45..46 'f': F - 45..48 'f()': () - "#]], - ); -} - -#[test] -fn trait_in_scope_of_trait_impl() { - check_infer( - r#" -mod foo { - pub trait Foo { - fn foo(self); - fn bar(self) -> usize { 0 } - } -} -impl foo::Foo for u32 { - fn foo(self) { - let _x = self.bar(); - } -} - "#, - expect![[r#" - 45..49 'self': Self - 67..71 'self': Self - 82..87 '{ 0 }': usize - 84..85 '0': usize - 131..135 'self': u32 - 137..173 '{ ... }': () - 151..153 '_x': usize - 156..160 'self': u32 - 156..166 'self.bar()': usize - "#]], - ); -} - -#[test] -fn infer_async_ret_type() { - check_types( - r#" -//- minicore: future, result -struct Fooey; - -impl Fooey { - fn collect(self) -> B { - B::new() - } -} - -trait Convert { - fn new() -> Self; -} -impl Convert for u32 { - fn new() -> Self { 0 } -} - -async fn get_accounts() -> Result { - let ret = Fooey.collect(); - // ^^^^^^^^^^^^^^^ u32 - Ok(ret) -} -"#, - ); -} - -#[test] -fn local_impl_1() { - check!(block_local_impls); - check_types( - r#" -trait Trait { - fn foo(&self) -> T; -} - -fn test() { - struct S; - impl Trait for S { - fn foo(&self) -> u32 { 0 } - } - - S.foo(); - // ^^^^^^^ u32 -} -"#, - ); -} - -#[test] -fn local_impl_2() { - check!(block_local_impls); - check_types( - r#" -struct S; - -fn test() { - trait Trait { - fn foo(&self) -> T; - } - impl Trait for S { - fn foo(&self) -> u32 { 0 } - } - - S.foo(); - // ^^^^^^^ u32 -} -"#, - ); -} - -#[test] -fn local_impl_3() { - check!(block_local_impls); - check_types( - r#" -trait Trait { - fn foo(&self) -> T; -} - -fn test() { - struct S1; - { - struct S2; - - impl Trait for S2 { - fn foo(&self) -> S1 { S1 } - } - - S2.foo(); - // ^^^^^^^^ S1 - } -} -"#, - ); -} - -#[test] -fn associated_type_sized_bounds() { - check_infer( - r#" -//- minicore: sized -struct Yes; -trait IsSized { const IS_SIZED: Yes; } -impl IsSized for T { const IS_SIZED: Yes = Yes; } - -trait Foo { - type Explicit: Sized; - type Implicit; - type Relaxed: ?Sized; -} -fn f() { - F::Explicit::IS_SIZED; - F::Implicit::IS_SIZED; - F::Relaxed::IS_SIZED; -} -"#, - expect![[r#" - 104..107 'Yes': Yes - 212..295 '{ ...ZED; }': () - 218..239 'F::Exp..._SIZED': Yes - 245..266 'F::Imp..._SIZED': Yes - 272..292 'F::Rel..._SIZED': {unknown} - "#]], - ); -} - -#[test] -fn dyn_map() { - check_types( - r#" -pub struct Key {} - -pub trait Policy { - type K; - type V; -} - -impl Policy for (K, V) { - type K = K; - type V = V; -} - -pub struct KeyMap {} - -impl KeyMap> { - pub fn get(&self, key: &P::K) -> P::V { - loop {} - } -} - -struct Fn {} -struct FunctionId {} - -fn test() { - let key_map: &KeyMap> = loop {}; - let key; - let result = key_map.get(key); - //^^^^^^ FunctionId -} -"#, - ) -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs deleted file mode 100644 index 547850b021c3c..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs +++ /dev/null @@ -1,133 +0,0 @@ -//! Implementation of Chalk debug helper functions using TLS. -use std::fmt::{self, Display}; - -use itertools::Itertools; - -use crate::{ - chalk_db, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, mapping::from_chalk, - CallableDefId, Interner, -}; -use hir_def::{AdtId, ItemContainerId, Lookup, TypeAliasId}; - -pub(crate) use unsafe_tls::{set_current_program, with_current_program}; - -pub(crate) struct DebugContext<'a>(&'a dyn HirDatabase); - -impl DebugContext<'_> { - pub(crate) fn debug_struct_id( - &self, - id: chalk_db::AdtId, - f: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - let name = match id.0 { - AdtId::StructId(it) => self.0.struct_data(it).name.clone(), - AdtId::UnionId(it) => self.0.union_data(it).name.clone(), - AdtId::EnumId(it) => self.0.enum_data(it).name.clone(), - }; - name.fmt(f) - } - - pub(crate) fn debug_trait_id( - &self, - id: chalk_db::TraitId, - f: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - let trait_: hir_def::TraitId = from_chalk_trait_id(id); - let trait_data = self.0.trait_data(trait_); - trait_data.name.fmt(f) - } - - pub(crate) fn debug_assoc_type_id( - &self, - id: chalk_db::AssocTypeId, - fmt: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - let type_alias: TypeAliasId = from_assoc_type_id(id); - let type_alias_data = self.0.type_alias_data(type_alias); - let trait_ = match type_alias.lookup(self.0.upcast()).container { - ItemContainerId::TraitId(t) => t, - _ => panic!("associated type not in trait"), - }; - let trait_data = self.0.trait_data(trait_); - write!(fmt, "{}::{}", trait_data.name, type_alias_data.name) - } - - pub(crate) fn debug_projection_ty( - &self, - projection_ty: &chalk_ir::ProjectionTy, - fmt: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - let type_alias = from_assoc_type_id(projection_ty.associated_ty_id); - let type_alias_data = self.0.type_alias_data(type_alias); - let trait_ = match type_alias.lookup(self.0.upcast()).container { - ItemContainerId::TraitId(t) => t, - _ => panic!("associated type not in trait"), - }; - let trait_data = self.0.trait_data(trait_); - let params = projection_ty.substitution.as_slice(Interner); - write!(fmt, "<{:?} as {}", ¶ms[0], trait_data.name,)?; - if params.len() > 1 { - write!( - fmt, - "<{}>", - ¶ms[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))), - )?; - } - write!(fmt, ">::{}", type_alias_data.name) - } - - pub(crate) fn debug_fn_def_id( - &self, - fn_def_id: chalk_ir::FnDefId, - fmt: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - let def: CallableDefId = from_chalk(self.0, fn_def_id); - let name = match def { - CallableDefId::FunctionId(ff) => self.0.function_data(ff).name.clone(), - CallableDefId::StructId(s) => self.0.struct_data(s).name.clone(), - CallableDefId::EnumVariantId(e) => { - let enum_data = self.0.enum_data(e.parent); - enum_data.variants[e.local_id].name.clone() - } - }; - match def { - CallableDefId::FunctionId(_) => write!(fmt, "{{fn {}}}", name), - CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => { - write!(fmt, "{{ctor {}}}", name) - } - } - } -} - -mod unsafe_tls { - use super::DebugContext; - use crate::db::HirDatabase; - use scoped_tls::scoped_thread_local; - - scoped_thread_local!(static PROGRAM: DebugContext<'_>); - - pub(crate) fn with_current_program( - op: impl for<'a> FnOnce(Option<&'a DebugContext<'a>>) -> R, - ) -> R { - if PROGRAM.is_set() { - PROGRAM.with(|prog| op(Some(prog))) - } else { - op(None) - } - } - - pub(crate) fn set_current_program(p: &dyn HirDatabase, op: OP) -> R - where - OP: FnOnce() -> R, - { - let ctx = DebugContext(p); - // we're transmuting the lifetime in the DebugContext to static. This is - // fine because we only keep the reference for the lifetime of this - // function, *and* the only way to access the context is through - // `with_current_program`, which hides the lifetime through the `for` - // type. - let static_p: &DebugContext<'static> = - unsafe { std::mem::transmute::<&DebugContext<'_>, &DebugContext<'static>>(&ctx) }; - PROGRAM.set(static_p, op) - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs deleted file mode 100644 index 77afeb3217dd0..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ /dev/null @@ -1,187 +0,0 @@ -//! Trait solving using Chalk. - -use std::env::var; - -use chalk_ir::GoalData; -use chalk_recursive::Cache; -use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver}; - -use base_db::CrateId; -use hir_def::{lang_item::LangItemTarget, TraitId}; -use stdx::panic_context; -use syntax::SmolStr; - -use crate::{ - db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment, - Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause, -}; - -/// This controls how much 'time' we give the Chalk solver before giving up. -const CHALK_SOLVER_FUEL: i32 = 100; - -#[derive(Debug, Copy, Clone)] -pub(crate) struct ChalkContext<'a> { - pub(crate) db: &'a dyn HirDatabase, - pub(crate) krate: CrateId, -} - -fn create_chalk_solver() -> chalk_recursive::RecursiveSolver { - let overflow_depth = - var("CHALK_OVERFLOW_DEPTH").ok().and_then(|s| s.parse().ok()).unwrap_or(500); - let max_size = var("CHALK_SOLVER_MAX_SIZE").ok().and_then(|s| s.parse().ok()).unwrap_or(150); - chalk_recursive::RecursiveSolver::new(overflow_depth, max_size, Some(Cache::new())) -} - -/// A set of clauses that we assume to be true. E.g. if we are inside this function: -/// ```rust -/// fn foo(t: T) {} -/// ``` -/// we assume that `T: Default`. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct TraitEnvironment { - pub krate: CrateId, - // FIXME make this a BTreeMap - pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>, - pub env: chalk_ir::Environment, -} - -impl TraitEnvironment { - pub fn empty(krate: CrateId) -> Self { - TraitEnvironment { - krate, - traits_from_clauses: Vec::new(), - env: chalk_ir::Environment::new(Interner), - } - } - - pub fn traits_in_scope_from_clauses<'a>( - &'a self, - ty: Ty, - ) -> impl Iterator + 'a { - self.traits_from_clauses - .iter() - .filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then(|| *trait_id)) - } -} - -/// Solve a trait goal using Chalk. -pub(crate) fn trait_solve_query( - db: &dyn HirDatabase, - krate: CrateId, - goal: Canonical>, -) -> Option { - let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(Interner) { - GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => { - db.trait_data(it.hir_trait_id()).name.to_string() - } - GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_string(), - _ => "??".to_string(), - }); - tracing::info!("trait_solve_query({:?})", goal.value.goal); - - if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq { - alias: AliasTy::Projection(projection_ty), - .. - }))) = &goal.value.goal.data(Interner) - { - if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(Interner).kind(Interner) { - // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible - return Some(Solution::Ambig(Guidance::Unknown)); - } - } - - // We currently don't deal with universes (I think / hope they're not yet - // relevant for our use cases?) - let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 }; - solve(db, krate, &u_canonical) -} - -fn solve( - db: &dyn HirDatabase, - krate: CrateId, - goal: &chalk_ir::UCanonical>>, -) -> Option> { - let context = ChalkContext { db, krate }; - tracing::debug!("solve goal: {:?}", goal); - let mut solver = create_chalk_solver(); - - let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL); - - let should_continue = || { - db.unwind_if_cancelled(); - let remaining = fuel.get(); - fuel.set(remaining - 1); - if remaining == 0 { - tracing::debug!("fuel exhausted"); - } - remaining > 0 - }; - - let mut solve = || { - let _ctx = if is_chalk_debug() || is_chalk_print() { - Some(panic_context::enter(format!("solving {:?}", goal))) - } else { - None - }; - let solution = if is_chalk_print() { - let logging_db = - LoggingRustIrDatabaseLoggingOnDrop(LoggingRustIrDatabase::new(context)); - solver.solve_limited(&logging_db.0, goal, &should_continue) - } else { - solver.solve_limited(&context, goal, &should_continue) - }; - - tracing::debug!("solve({:?}) => {:?}", goal, solution); - - solution - }; - - // don't set the TLS for Chalk unless Chalk debugging is active, to make - // extra sure we only use it for debugging - if is_chalk_debug() { - crate::tls::set_current_program(db, solve) - } else { - solve() - } -} - -struct LoggingRustIrDatabaseLoggingOnDrop<'a>(LoggingRustIrDatabase>); - -impl<'a> Drop for LoggingRustIrDatabaseLoggingOnDrop<'a> { - fn drop(&mut self) { - eprintln!("chalk program:\n{}", self.0); - } -} - -fn is_chalk_debug() -> bool { - std::env::var("CHALK_DEBUG").is_ok() -} - -fn is_chalk_print() -> bool { - std::env::var("CHALK_PRINT").is_ok() -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum FnTrait { - FnOnce, - FnMut, - Fn, -} - -impl FnTrait { - const fn lang_item_name(self) -> &'static str { - match self { - FnTrait::FnOnce => "fn_once", - FnTrait::FnMut => "fn_mut", - FnTrait::Fn => "fn", - } - } - - pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option { - let target = db.lang_item(krate, SmolStr::new_inline(self.lang_item_name()))?; - match target { - LangItemTarget::TraitId(t) => Some(t), - _ => None, - } - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs deleted file mode 100644 index 83319755da73a..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ /dev/null @@ -1,408 +0,0 @@ -//! Helper functions for working with def, which don't need to be a separate -//! query, but can't be computed directly from `*Data` (ie, which need a `db`). - -use std::iter; - -use base_db::CrateId; -use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex}; -use hir_def::{ - db::DefDatabase, - generics::{ - GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate, - WherePredicateTypeTarget, - }, - intern::Interned, - resolver::{HasResolver, TypeNs}, - type_ref::{TraitBoundModifier, TypeRef}, - ConstParamId, FunctionId, GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, - TypeOrConstParamId, TypeParamId, -}; -use hir_expand::name::{known, Name}; -use itertools::Either; -use rustc_hash::FxHashSet; -use smallvec::{smallvec, SmallVec}; -use syntax::SmolStr; - -use crate::{ - db::HirDatabase, ChalkTraitId, ConstData, ConstValue, GenericArgData, Interner, Substitution, - TraitRef, TraitRefExt, TyKind, WhereClause, -}; - -pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator { - [ - db.lang_item(krate, SmolStr::new_inline("fn")), - db.lang_item(krate, SmolStr::new_inline("fn_mut")), - db.lang_item(krate, SmolStr::new_inline("fn_once")), - ] - .into_iter() - .flatten() - .flat_map(|it| it.as_trait()) -} - -fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> { - let resolver = trait_.resolver(db); - // returning the iterator directly doesn't easily work because of - // lifetime problems, but since there usually shouldn't be more than a - // few direct traits this should be fine (we could even use some kind of - // SmallVec if performance is a concern) - let generic_params = db.generic_params(trait_.into()); - let trait_self = generic_params.find_trait_self_param(); - generic_params - .where_predicates - .iter() - .filter_map(|pred| match pred { - WherePredicate::ForLifetime { target, bound, .. } - | WherePredicate::TypeBound { target, bound } => { - let is_trait = match target { - WherePredicateTypeTarget::TypeRef(type_ref) => match &**type_ref { - TypeRef::Path(p) => p.is_self_type(), - _ => false, - }, - WherePredicateTypeTarget::TypeOrConstParam(local_id) => { - Some(*local_id) == trait_self - } - }; - match is_trait { - true => bound.as_path(), - false => None, - } - } - WherePredicate::Lifetime { .. } => None, - }) - .filter(|(_, bound_modifier)| matches!(bound_modifier, TraitBoundModifier::None)) - .filter_map(|(path, _)| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { - Some(TypeNs::TraitId(t)) => Some(t), - _ => None, - }) - .collect() -} - -fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec { - // returning the iterator directly doesn't easily work because of - // lifetime problems, but since there usually shouldn't be more than a - // few direct traits this should be fine (we could even use some kind of - // SmallVec if performance is a concern) - let generic_params = db.generic_params(trait_ref.hir_trait_id().into()); - let trait_self = match generic_params.find_trait_self_param() { - Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p }, - None => return Vec::new(), - }; - db.generic_predicates_for_param(trait_self.parent, trait_self, None) - .iter() - .filter_map(|pred| { - pred.as_ref().filter_map(|pred| match pred.skip_binders() { - // FIXME: how to correctly handle higher-ranked bounds here? - WhereClause::Implemented(tr) => Some( - tr.clone() - .shifted_out_to(Interner, DebruijnIndex::ONE) - .expect("FIXME unexpected higher-ranked trait bound"), - ), - _ => None, - }) - }) - .map(|pred| pred.substitute(Interner, &trait_ref.substitution)) - .collect() -} - -/// Returns an iterator over the whole super trait hierarchy (including the -/// trait itself). -pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> { - // we need to take care a bit here to avoid infinite loops in case of cycles - // (i.e. if we have `trait A: B; trait B: A;`) - - let mut result = smallvec![trait_]; - let mut i = 0; - while let Some(&t) = result.get(i) { - // yeah this is quadratic, but trait hierarchies should be flat - // enough that this doesn't matter - for tt in direct_super_traits(db, t) { - if !result.contains(&tt) { - result.push(tt); - } - } - i += 1; - } - result -} - -/// Given a trait ref (`Self: Trait`), builds all the implied trait refs for -/// super traits. The original trait ref will be included. So the difference to -/// `all_super_traits` is that we keep track of type parameters; for example if -/// we have `Self: Trait` and `Trait: OtherTrait` we'll get -/// `Self: OtherTrait`. -pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) -> SuperTraits<'_> { - SuperTraits { db, seen: iter::once(trait_ref.trait_id).collect(), stack: vec![trait_ref] } -} - -pub(super) struct SuperTraits<'a> { - db: &'a dyn HirDatabase, - stack: Vec, - seen: FxHashSet, -} - -impl<'a> SuperTraits<'a> { - fn elaborate(&mut self, trait_ref: &TraitRef) { - let mut trait_refs = direct_super_trait_refs(self.db, trait_ref); - trait_refs.retain(|tr| !self.seen.contains(&tr.trait_id)); - self.stack.extend(trait_refs); - } -} - -impl<'a> Iterator for SuperTraits<'a> { - type Item = TraitRef; - - fn next(&mut self) -> Option { - if let Some(next) = self.stack.pop() { - self.elaborate(&next); - Some(next) - } else { - None - } - } -} - -pub(super) fn associated_type_by_name_including_super_traits( - db: &dyn HirDatabase, - trait_ref: TraitRef, - name: &Name, -) -> Option<(TraitRef, TypeAliasId)> { - all_super_trait_refs(db, trait_ref).find_map(|t| { - let assoc_type = db.trait_data(t.hir_trait_id()).associated_type_by_name(name)?; - Some((t, assoc_type)) - }) -} - -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))); - if parent_generics.is_some() && matches!(def, GenericDefId::TypeAliasId(_)) { - let params = db.generic_params(def); - let has_consts = - params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_))); - return if has_consts { - // XXX: treat const generic associated types as not existing to avoid crashes (#11769) - // - // Chalk expects the inner associated type's parameters to come - // *before*, not after the trait's generics as we've always done it. - // Adapting to this requires a larger refactoring - cov_mark::hit!(ignore_gats); - Generics { def, params: Interned::new(Default::default()), parent_generics } - } else { - Generics { def, params, parent_generics } - }; - } - Generics { def, params: db.generic_params(def), parent_generics } -} - -#[derive(Debug)] -pub(crate) struct Generics { - def: GenericDefId, - pub(crate) params: Interned, - parent_generics: Option>, -} - -impl Generics { - pub(crate) fn iter_id<'a>( - &'a self, - ) -> impl Iterator> + 'a { - self.iter().map(|(id, data)| match data { - TypeOrConstParamData::TypeParamData(_) => Either::Left(TypeParamId::from_unchecked(id)), - TypeOrConstParamData::ConstParamData(_) => { - Either::Right(ConstParamId::from_unchecked(id)) - } - }) - } - - /// Iterator over types and const params of parent, then self. - pub(crate) fn iter<'a>( - &'a self, - ) -> impl DoubleEndedIterator + 'a { - let to_toc_id = |it: &'a Generics| { - move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p) - }; - self.parent_generics() - .into_iter() - .flat_map(move |it| it.params.iter().map(to_toc_id(it))) - .chain(self.params.iter().map(to_toc_id(self))) - } - - /// Iterator over types and const params of parent. - pub(crate) fn iter_parent<'a>( - &'a self, - ) -> impl Iterator + 'a { - self.parent_generics().into_iter().flat_map(|it| { - let to_toc_id = - move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p); - it.params.iter().map(to_toc_id) - }) - } - - pub(crate) fn len(&self) -> usize { - let parent = self.parent_generics().map_or(0, Generics::len); - let child = self.params.type_or_consts.len(); - parent + child - } - - /// (parent total, self param, type param list, const param list, impl trait) - pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize) { - let ty_iter = || self.params.iter().filter_map(|x| x.1.type_param()); - - let self_params = - ty_iter().filter(|p| p.provenance == TypeParamProvenance::TraitSelf).count(); - let type_params = - ty_iter().filter(|p| p.provenance == TypeParamProvenance::TypeParamList).count(); - let impl_trait_params = - ty_iter().filter(|p| p.provenance == TypeParamProvenance::ArgumentImplTrait).count(); - let const_params = self.params.iter().filter_map(|x| x.1.const_param()).count(); - - let parent_len = self.parent_generics().map_or(0, Generics::len); - (parent_len, self_params, type_params, const_params, impl_trait_params) - } - - pub(crate) fn param_idx(&self, param: TypeOrConstParamId) -> Option { - Some(self.find_param(param)?.0) - } - - fn find_param(&self, param: TypeOrConstParamId) -> Option<(usize, &TypeOrConstParamData)> { - if param.parent == self.def { - let (idx, (_local_id, data)) = self - .params - .iter() - .enumerate() - .find(|(_, (idx, _))| *idx == param.local_id) - .unwrap(); - let parent_len = self.parent_generics().map_or(0, Generics::len); - Some((parent_len + idx, data)) - } else { - self.parent_generics().and_then(|g| g.find_param(param)) - } - } - - fn parent_generics(&self) -> Option<&Generics> { - self.parent_generics.as_ref().map(|it| &**it) - } - - /// 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 { - Either::Left(_) => GenericArgData::Ty( - TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner), - ) - .intern(Interner), - Either::Right(id) => GenericArgData::Const( - ConstData { - value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)), - ty: db.const_param_ty(id), - } - .intern(Interner), - ) - .intern(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 { - Either::Left(id) => GenericArgData::Ty( - TyKind::Placeholder(crate::to_placeholder_idx(db, id.into())).intern(Interner), - ) - .intern(Interner), - Either::Right(id) => GenericArgData::Const( - ConstData { - value: ConstValue::Placeholder(crate::to_placeholder_idx(db, id.into())), - ty: db.const_param_ty(id), - } - .intern(Interner), - ) - .intern(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.parent.into()), - GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) => 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() { - return true; - } - - match func.lookup(db.upcast()).container { - hir_def::ItemContainerId::ExternBlockId(block) => { - // Function in an `extern` block are always unsafe to call, except when it has - // `"rust-intrinsic"` ABI there are a few exceptions. - let id = block.lookup(db.upcast()).id; - !matches!( - id.item_tree(db.upcast())[id.value].abi.as_deref(), - Some("rust-intrinsic") if !is_intrinsic_fn_unsafe(&data.name) - ) - } - _ => false, - } -} - -/// Returns `true` if the given intrinsic is unsafe to call, or false otherwise. -fn is_intrinsic_fn_unsafe(name: &Name) -> bool { - // Should be kept in sync with https://github.com/rust-lang/rust/blob/532d2b14c05f9bc20b2d27cbb5f4550d28343a36/compiler/rustc_typeck/src/check/intrinsic.rs#L72-L106 - ![ - known::abort, - known::add_with_overflow, - known::bitreverse, - known::black_box, - known::bswap, - known::caller_location, - known::ctlz, - known::ctpop, - known::cttz, - known::discriminant_value, - known::forget, - known::likely, - known::maxnumf32, - known::maxnumf64, - known::min_align_of, - known::minnumf32, - known::minnumf64, - known::mul_with_overflow, - known::needs_drop, - known::ptr_guaranteed_eq, - known::ptr_guaranteed_ne, - known::rotate_left, - known::rotate_right, - known::rustc_peek, - known::saturating_add, - known::saturating_sub, - known::size_of, - known::sub_with_overflow, - known::type_id, - known::type_name, - known::unlikely, - known::variant_count, - known::wrapping_add, - known::wrapping_mul, - known::wrapping_sub, - ] - .contains(name) -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/walk.rs b/src/tools/rust-analyzer/crates/hir-ty/src/walk.rs deleted file mode 100644 index c476894552e6c..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/walk.rs +++ /dev/null @@ -1,147 +0,0 @@ -//! The `TypeWalk` trait (probably to be replaced by Chalk's `Fold` and -//! `Visit`). - -use chalk_ir::interner::HasInterner; - -use crate::{ - AliasEq, AliasTy, Binders, CallableSig, FnSubst, GenericArg, GenericArgData, Interner, - OpaqueTy, ProjectionTy, Substitution, TraitRef, Ty, TyKind, WhereClause, -}; - -/// This allows walking structures that contain types to do something with those -/// types, similar to Chalk's `Fold` trait. -pub trait TypeWalk { - fn walk(&self, f: &mut impl FnMut(&Ty)); -} - -impl TypeWalk for Ty { - fn walk(&self, f: &mut impl FnMut(&Ty)) { - match self.kind(Interner) { - TyKind::Alias(AliasTy::Projection(p_ty)) => { - for t in p_ty.substitution.iter(Interner) { - t.walk(f); - } - } - TyKind::Alias(AliasTy::Opaque(o_ty)) => { - for t in o_ty.substitution.iter(Interner) { - t.walk(f); - } - } - TyKind::Dyn(dyn_ty) => { - for p in dyn_ty.bounds.skip_binders().interned().iter() { - p.walk(f); - } - } - TyKind::Slice(ty) - | TyKind::Array(ty, _) - | TyKind::Ref(_, _, ty) - | TyKind::Raw(_, ty) => { - ty.walk(f); - } - TyKind::Function(fn_pointer) => { - fn_pointer.substitution.0.walk(f); - } - TyKind::Adt(_, substs) - | TyKind::FnDef(_, substs) - | TyKind::Tuple(_, substs) - | TyKind::OpaqueType(_, substs) - | TyKind::AssociatedType(_, substs) - | TyKind::Closure(.., substs) => { - substs.walk(f); - } - _ => {} - } - f(self); - } -} - -impl TypeWalk for Vec { - fn walk(&self, f: &mut impl FnMut(&Ty)) { - for t in self { - t.walk(f); - } - } -} - -impl TypeWalk for OpaqueTy { - fn walk(&self, f: &mut impl FnMut(&Ty)) { - self.substitution.walk(f); - } -} - -impl TypeWalk for ProjectionTy { - fn walk(&self, f: &mut impl FnMut(&Ty)) { - self.substitution.walk(f); - } -} - -impl TypeWalk for AliasTy { - fn walk(&self, f: &mut impl FnMut(&Ty)) { - match self { - AliasTy::Projection(it) => it.walk(f), - AliasTy::Opaque(it) => it.walk(f), - } - } -} - -impl TypeWalk for GenericArg { - fn walk(&self, f: &mut impl FnMut(&Ty)) { - if let GenericArgData::Ty(ty) = &self.interned() { - ty.walk(f); - } - } -} - -impl TypeWalk for Substitution { - fn walk(&self, f: &mut impl FnMut(&Ty)) { - for t in self.iter(Interner) { - t.walk(f); - } - } -} - -impl> TypeWalk for Binders { - fn walk(&self, f: &mut impl FnMut(&Ty)) { - self.skip_binders().walk(f); - } -} - -impl TypeWalk for TraitRef { - fn walk(&self, f: &mut impl FnMut(&Ty)) { - self.substitution.walk(f); - } -} - -impl TypeWalk for WhereClause { - fn walk(&self, f: &mut impl FnMut(&Ty)) { - match self { - WhereClause::Implemented(trait_ref) => trait_ref.walk(f), - WhereClause::AliasEq(alias_eq) => alias_eq.walk(f), - _ => {} - } - } -} - -impl TypeWalk for CallableSig { - fn walk(&self, f: &mut impl FnMut(&Ty)) { - for t in self.params_and_return.iter() { - t.walk(f); - } - } -} - -impl TypeWalk for AliasEq { - fn walk(&self, f: &mut impl FnMut(&Ty)) { - self.ty.walk(f); - match &self.alias { - AliasTy::Projection(projection_ty) => projection_ty.walk(f), - AliasTy::Opaque(opaque) => opaque.walk(f), - } - } -} - -impl TypeWalk for FnSubst { - fn walk(&self, f: &mut impl FnMut(&Ty)) { - self.0.walk(f) - } -} diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml deleted file mode 100644 index 8e6a2441b3311..0000000000000 --- a/src/tools/rust-analyzer/crates/hir/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "hir" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -rustc-hash = "1.1.0" -either = "1.7.0" -arrayvec = "0.7.2" -itertools = "0.10.3" -smallvec = "1.9.0" -once_cell = "1.12.0" - -stdx = { path = "../stdx", version = "0.0.0" } -syntax = { path = "../syntax", version = "0.0.0" } -base-db = { path = "../base-db", version = "0.0.0" } -profile = { path = "../profile", version = "0.0.0" } -hir-expand = { path = "../hir-expand", version = "0.0.0" } -hir-def = { path = "../hir-def", version = "0.0.0" } -hir-ty = { path = "../hir-ty", version = "0.0.0" } -tt = { path = "../tt", version = "0.0.0" } -cfg = { path = "../cfg", version = "0.0.0" } diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs deleted file mode 100644 index 0bd3793400109..0000000000000 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ /dev/null @@ -1,177 +0,0 @@ -//! Attributes & documentation for hir types. - -use hir_def::{ - attr::{AttrsWithOwner, Documentation}, - item_scope::ItemInNs, - path::ModPath, - per_ns::PerNs, - resolver::HasResolver, - AttrDefId, GenericParamId, ModuleDefId, -}; -use hir_expand::hygiene::Hygiene; -use hir_ty::db::HirDatabase; -use syntax::{ast, AstNode}; - -use crate::{ - Adt, AssocItem, Const, ConstParam, Enum, Field, Function, GenericParam, Impl, LifetimeParam, - Macro, Module, ModuleDef, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant, -}; - -pub trait HasAttrs { - fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner; - fn docs(self, db: &dyn HirDatabase) -> Option; - fn resolve_doc_path( - self, - db: &dyn HirDatabase, - link: &str, - ns: Option, - ) -> Option; -} - -#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] -pub enum Namespace { - Types, - Values, - Macros, -} - -macro_rules! impl_has_attrs { - ($(($def:ident, $def_id:ident),)*) => {$( - impl HasAttrs for $def { - fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner { - let def = AttrDefId::$def_id(self.into()); - db.attrs(def) - } - fn docs(self, db: &dyn HirDatabase) -> Option { - let def = AttrDefId::$def_id(self.into()); - db.attrs(def).docs() - } - fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option) -> Option { - let def = AttrDefId::$def_id(self.into()); - resolve_doc_path(db, def, link, ns).map(ModuleDef::from) - } - } - )*}; -} - -impl_has_attrs![ - (Field, FieldId), - (Variant, EnumVariantId), - (Static, StaticId), - (Const, ConstId), - (Trait, TraitId), - (TypeAlias, TypeAliasId), - (Macro, MacroId), - (Function, FunctionId), - (Adt, AdtId), - (Module, ModuleId), - (GenericParam, GenericParamId), - (Impl, ImplId), -]; - -macro_rules! impl_has_attrs_enum { - ($($variant:ident),* for $enum:ident) => {$( - impl HasAttrs for $variant { - fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner { - $enum::$variant(self).attrs(db) - } - fn docs(self, db: &dyn HirDatabase) -> Option { - $enum::$variant(self).docs(db) - } - fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option) -> Option { - $enum::$variant(self).resolve_doc_path(db, link, ns) - } - } - )*}; -} - -impl_has_attrs_enum![Struct, Union, Enum for Adt]; -impl_has_attrs_enum![TypeParam, ConstParam, LifetimeParam for GenericParam]; - -impl HasAttrs for AssocItem { - fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner { - match self { - AssocItem::Function(it) => it.attrs(db), - AssocItem::Const(it) => it.attrs(db), - AssocItem::TypeAlias(it) => it.attrs(db), - } - } - - fn docs(self, db: &dyn HirDatabase) -> Option { - match self { - AssocItem::Function(it) => it.docs(db), - AssocItem::Const(it) => it.docs(db), - AssocItem::TypeAlias(it) => it.docs(db), - } - } - - fn resolve_doc_path( - self, - db: &dyn HirDatabase, - link: &str, - ns: Option, - ) -> Option { - match self { - AssocItem::Function(it) => it.resolve_doc_path(db, link, ns), - AssocItem::Const(it) => it.resolve_doc_path(db, link, ns), - AssocItem::TypeAlias(it) => it.resolve_doc_path(db, link, ns), - } - } -} - -fn resolve_doc_path( - db: &dyn HirDatabase, - def: AttrDefId, - link: &str, - ns: Option, -) -> Option { - let resolver = match def { - AttrDefId::ModuleId(it) => it.resolver(db.upcast()), - AttrDefId::FieldId(it) => it.parent.resolver(db.upcast()), - AttrDefId::AdtId(it) => it.resolver(db.upcast()), - AttrDefId::FunctionId(it) => it.resolver(db.upcast()), - AttrDefId::EnumVariantId(it) => it.parent.resolver(db.upcast()), - AttrDefId::StaticId(it) => it.resolver(db.upcast()), - AttrDefId::ConstId(it) => it.resolver(db.upcast()), - AttrDefId::TraitId(it) => it.resolver(db.upcast()), - AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()), - AttrDefId::ImplId(it) => it.resolver(db.upcast()), - AttrDefId::ExternBlockId(it) => it.resolver(db.upcast()), - AttrDefId::MacroId(it) => it.resolver(db.upcast()), - AttrDefId::GenericParamId(it) => match it { - GenericParamId::TypeParamId(it) => it.parent(), - GenericParamId::ConstParamId(it) => it.parent(), - GenericParamId::LifetimeParamId(it) => it.parent, - } - .resolver(db.upcast()), - }; - - let modpath = { - // FIXME: this is not how we should get a mod path here - let ast_path = ast::SourceFile::parse(&format!("type T = {};", link)) - .syntax_node() - .descendants() - .find_map(ast::Path::cast)?; - if ast_path.to_string() != link { - return None; - } - ModPath::from_src(db.upcast(), ast_path, &Hygiene::new_unhygienic())? - }; - - let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); - let resolved = if resolved == PerNs::none() { - resolver.resolve_module_path_in_trait_assoc_items(db.upcast(), &modpath)? - } else { - resolved - }; - match ns { - Some(Namespace::Types) => resolved.take_types(), - Some(Namespace::Values) => resolved.take_values(), - Some(Namespace::Macros) => resolved.take_macros().map(ModuleDefId::MacroId), - None => resolved.iter_items().next().map(|it| match it { - ItemInNs::Types(it) => it, - ItemInNs::Values(it) => it, - ItemInNs::Macros(it) => ModuleDefId::MacroId(it), - }), - } -} diff --git a/src/tools/rust-analyzer/crates/hir/src/db.rs b/src/tools/rust-analyzer/crates/hir/src/db.rs deleted file mode 100644 index e25d867845824..0000000000000 --- a/src/tools/rust-analyzer/crates/hir/src/db.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Re-exports various subcrates databases so that the calling code can depend -//! only on `hir`. This breaks abstraction boundary a bit, it would be cool if -//! we didn't do that. -//! -//! But we need this for at least LRU caching at the query level. -pub use hir_def::db::*; -pub use hir_expand::db::{ - AstDatabase, AstDatabaseStorage, AstIdMapQuery, HygieneFrameQuery, InternMacroCallQuery, - MacroArgTextQuery, MacroDefQuery, MacroExpandQuery, ParseMacroExpansionQuery, -}; -pub use hir_ty::db::*; - -#[test] -fn hir_database_is_object_safe() { - fn _assert_object_safe(_: &dyn HirDatabase) {} -} diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs deleted file mode 100644 index 6c6c11ea4ebdc..0000000000000 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ /dev/null @@ -1,170 +0,0 @@ -//! Re-export diagnostics such that clients of `hir` don't have to depend on -//! low-level crates. -//! -//! This probably isn't the best way to do this -- ideally, diagnistics should -//! be expressed in terms of hir types themselves. -use base_db::CrateId; -use cfg::{CfgExpr, CfgOptions}; -use either::Either; -use hir_def::path::ModPath; -use hir_expand::{name::Name, HirFileId, InFile}; -use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; - -use crate::{MacroKind, Type}; - -macro_rules! diagnostics { - ($($diag:ident,)*) => { - pub enum AnyDiagnostic {$( - $diag(Box<$diag>), - )*} - - $( - impl From<$diag> for AnyDiagnostic { - fn from(d: $diag) -> AnyDiagnostic { - AnyDiagnostic::$diag(Box::new(d)) - } - } - )* - }; -} - -diagnostics![ - BreakOutsideOfLoop, - InactiveCode, - IncorrectCase, - InvalidDeriveTarget, - MacroError, - MalformedDerive, - MismatchedArgCount, - MissingFields, - MissingMatchArms, - MissingUnsafe, - NoSuchField, - ReplaceFilterMapNextWithFindMap, - TypeMismatch, - UnimplementedBuiltinMacro, - UnresolvedExternCrate, - UnresolvedImport, - UnresolvedMacroCall, - UnresolvedModule, - UnresolvedProcMacro, -]; - -#[derive(Debug)] -pub struct UnresolvedModule { - pub decl: InFile>, - pub candidates: Box<[String]>, -} - -#[derive(Debug)] -pub struct UnresolvedExternCrate { - pub decl: InFile>, -} - -#[derive(Debug)] -pub struct UnresolvedImport { - pub decl: InFile>, -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct UnresolvedMacroCall { - pub macro_call: InFile, - pub precise_location: Option, - pub path: ModPath, - pub is_bang: bool, -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct InactiveCode { - pub node: InFile, - pub cfg: CfgExpr, - pub opts: CfgOptions, -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct UnresolvedProcMacro { - pub node: InFile, - /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange` - /// to use instead. - pub precise_location: Option, - pub macro_name: Option, - pub kind: MacroKind, - /// The crate id of the proc-macro this macro belongs to, or `None` if the proc-macro can't be found. - pub krate: CrateId, -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct MacroError { - pub node: InFile, - pub precise_location: Option, - pub message: String, -} - -#[derive(Debug)] -pub struct UnimplementedBuiltinMacro { - pub node: InFile, -} - -#[derive(Debug)] -pub struct InvalidDeriveTarget { - pub node: InFile, -} - -#[derive(Debug)] -pub struct MalformedDerive { - pub node: InFile, -} - -#[derive(Debug)] -pub struct NoSuchField { - pub field: InFile>, -} - -#[derive(Debug)] -pub struct BreakOutsideOfLoop { - pub expr: InFile>, -} - -#[derive(Debug)] -pub struct MissingUnsafe { - pub expr: InFile>, -} - -#[derive(Debug)] -pub struct MissingFields { - pub file: HirFileId, - pub field_list_parent: Either, AstPtr>, - pub field_list_parent_path: Option>, - pub missed_fields: Vec, -} - -#[derive(Debug)] -pub struct ReplaceFilterMapNextWithFindMap { - pub file: HirFileId, - /// This expression is the whole method chain up to and including `.filter_map(..).next()`. - pub next_expr: AstPtr, -} - -#[derive(Debug)] -pub struct MismatchedArgCount { - pub call_expr: InFile>, - pub expected: usize, - pub found: usize, -} - -#[derive(Debug)] -pub struct MissingMatchArms { - pub file: HirFileId, - pub match_expr: AstPtr, - pub uncovered_patterns: String, -} - -#[derive(Debug)] -pub struct TypeMismatch { - // FIXME: add mismatches in patterns as well - pub expr: InFile>, - pub expected: Type, - pub actual: Type, -} - -pub use hir_ty::diagnostics::IncorrectCase; diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs deleted file mode 100644 index 0e29c52ade683..0000000000000 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ /dev/null @@ -1,530 +0,0 @@ -//! HirDisplay implementations for various hir types. -use hir_def::{ - adt::VariantData, - generics::{ - TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, - }, - type_ref::{TypeBound, TypeRef}, - AdtId, GenericDefId, -}; -use hir_ty::{ - display::{ - write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError, - HirFormatter, SizedByDefault, - }, - Interner, TraitRefExt, WhereClause, -}; -use syntax::SmolStr; - -use crate::{ - Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasCrate, HasVisibility, - LifetimeParam, Macro, Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias, - TypeOrConstParam, TypeParam, Union, Variant, -}; - -impl HirDisplay for Function { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - let data = f.db.function_data(self.id); - write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; - if data.has_default_kw() { - f.write_str("default ")?; - } - if data.has_const_kw() { - f.write_str("const ")?; - } - if data.has_async_kw() { - f.write_str("async ")?; - } - if self.is_unsafe_to_call(f.db) { - f.write_str("unsafe ")?; - } - if let Some(abi) = &data.abi { - // FIXME: String escape? - write!(f, "extern \"{}\" ", &**abi)?; - } - write!(f, "fn {}", data.name)?; - - write_generic_params(GenericDefId::FunctionId(self.id), f)?; - - f.write_char('(')?; - - let write_self_param = |ty: &TypeRef, f: &mut HirFormatter<'_>| match ty { - TypeRef::Path(p) if p.is_self_type() => f.write_str("self"), - TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner,TypeRef::Path(p) if p.is_self_type()) => - { - f.write_char('&')?; - if let Some(lifetime) = lifetime { - write!(f, "{} ", lifetime.name)?; - } - if let hir_def::type_ref::Mutability::Mut = mut_ { - f.write_str("mut ")?; - } - f.write_str("self") - } - _ => { - f.write_str("self: ")?; - ty.hir_fmt(f) - } - }; - - let mut first = true; - for (name, type_ref) in &data.params { - if !first { - f.write_str(", ")?; - } else { - first = false; - if data.has_self_param() { - write_self_param(type_ref, f)?; - continue; - } - } - match name { - Some(name) => write!(f, "{}: ", name)?, - None => f.write_str("_: ")?, - } - // FIXME: Use resolved `param.ty` or raw `type_ref`? - // The former will ignore lifetime arguments currently. - type_ref.hir_fmt(f)?; - } - - if data.is_varargs() { - f.write_str(", ...")?; - } - - f.write_char(')')?; - - // `FunctionData::ret_type` will be `::core::future::Future` for async fns. - // Use ugly pattern match to strip the Future trait. - // Better way? - let ret_type = if !data.has_async_kw() { - &data.ret_type - } else { - match &*data.ret_type { - TypeRef::ImplTrait(bounds) => match bounds[0].as_ref() { - TypeBound::Path(path, _) => { - path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings - [0] - .type_ref - .as_ref() - .unwrap() - } - _ => panic!("Async fn ret_type should be impl Future"), - }, - _ => panic!("Async fn ret_type should be impl Future"), - } - }; - - match ret_type { - TypeRef::Tuple(tup) if tup.is_empty() => {} - ty => { - f.write_str(" -> ")?; - ty.hir_fmt(f)?; - } - } - - write_where_clause(GenericDefId::FunctionId(self.id), f)?; - - Ok(()) - } -} - -impl HirDisplay for Adt { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match self { - Adt::Struct(it) => it.hir_fmt(f), - Adt::Union(it) => it.hir_fmt(f), - Adt::Enum(it) => it.hir_fmt(f), - } - } -} - -impl HirDisplay for Struct { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; - f.write_str("struct ")?; - write!(f, "{}", self.name(f.db))?; - let def_id = GenericDefId::AdtId(AdtId::StructId(self.id)); - write_generic_params(def_id, f)?; - write_where_clause(def_id, f)?; - Ok(()) - } -} - -impl HirDisplay for Enum { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; - f.write_str("enum ")?; - write!(f, "{}", self.name(f.db))?; - let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id)); - write_generic_params(def_id, f)?; - write_where_clause(def_id, f)?; - Ok(()) - } -} - -impl HirDisplay for Union { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; - f.write_str("union ")?; - write!(f, "{}", self.name(f.db))?; - let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id)); - write_generic_params(def_id, f)?; - write_where_clause(def_id, f)?; - Ok(()) - } -} - -impl HirDisplay for Field { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?; - write!(f, "{}: ", self.name(f.db))?; - self.ty(f.db).hir_fmt(f) - } -} - -impl HirDisplay for Variant { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "{}", self.name(f.db))?; - let data = self.variant_data(f.db); - match &*data { - VariantData::Unit => {} - VariantData::Tuple(fields) => { - f.write_char('(')?; - let mut first = true; - for (_, field) in fields.iter() { - if first { - first = false; - } else { - f.write_str(", ")?; - } - // Enum variant fields must be pub. - field.type_ref.hir_fmt(f)?; - } - f.write_char(')')?; - } - VariantData::Record(fields) => { - f.write_str(" {")?; - let mut first = true; - for (_, field) in fields.iter() { - if first { - first = false; - f.write_char(' ')?; - } else { - f.write_str(", ")?; - } - // Enum variant fields must be pub. - write!(f, "{}: ", field.name)?; - field.type_ref.hir_fmt(f)?; - } - f.write_str(" }")?; - } - } - Ok(()) - } -} - -impl HirDisplay for Type { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - self.ty.hir_fmt(f) - } -} - -impl HirDisplay for GenericParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match self { - GenericParam::TypeParam(it) => it.hir_fmt(f), - GenericParam::ConstParam(it) => it.hir_fmt(f), - GenericParam::LifetimeParam(it) => it.hir_fmt(f), - } - } -} - -impl HirDisplay for TypeOrConstParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match self.split(f.db) { - either::Either::Left(x) => x.hir_fmt(f), - either::Either::Right(x) => x.hir_fmt(f), - } - } -} - -impl HirDisplay for TypeParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "{}", self.name(f.db))?; - if f.omit_verbose_types() { - return Ok(()); - } - - let bounds = f.db.generic_predicates_for_param(self.id.parent(), self.id.into(), None); - let substs = TyBuilder::placeholder_subst(f.db, self.id.parent()); - let predicates: Vec<_> = - bounds.iter().cloned().map(|b| b.substitute(Interner, &substs)).collect(); - let krate = self.id.parent().krate(f.db).id; - let sized_trait = - f.db.lang_item(krate, SmolStr::new_inline("sized")) - .and_then(|lang_item| lang_item.as_trait()); - let has_only_sized_bound = predicates.iter().all(move |pred| match pred.skip_binders() { - WhereClause::Implemented(it) => Some(it.hir_trait_id()) == sized_trait, - _ => false, - }); - let has_only_not_sized_bound = predicates.is_empty(); - if !has_only_sized_bound || has_only_not_sized_bound { - let default_sized = SizedByDefault::Sized { anchor: krate }; - write_bounds_like_dyn_trait_with_prefix(":", &predicates, default_sized, f)?; - } - Ok(()) - } -} - -impl HirDisplay for LifetimeParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "{}", self.name(f.db)) - } -} - -impl HirDisplay for ConstParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "const {}: ", self.name(f.db))?; - self.ty(f.db).hir_fmt(f) - } -} - -fn write_generic_params( - def: GenericDefId, - f: &mut HirFormatter<'_>, -) -> Result<(), HirDisplayError> { - let params = f.db.generic_params(def); - if params.lifetimes.is_empty() - && params.type_or_consts.iter().all(|x| x.1.const_param().is_none()) - && params - .type_or_consts - .iter() - .filter_map(|x| x.1.type_param()) - .all(|param| !matches!(param.provenance, TypeParamProvenance::TypeParamList)) - { - return Ok(()); - } - f.write_char('<')?; - - let mut first = true; - let mut delim = |f: &mut HirFormatter<'_>| { - if first { - first = false; - Ok(()) - } else { - f.write_str(", ") - } - }; - for (_, lifetime) in params.lifetimes.iter() { - delim(f)?; - write!(f, "{}", lifetime.name)?; - } - for (_, ty) in params.type_or_consts.iter() { - if let Some(name) = &ty.name() { - match ty { - TypeOrConstParamData::TypeParamData(ty) => { - if ty.provenance != TypeParamProvenance::TypeParamList { - continue; - } - delim(f)?; - write!(f, "{}", name)?; - if let Some(default) = &ty.default { - f.write_str(" = ")?; - default.hir_fmt(f)?; - } - } - TypeOrConstParamData::ConstParamData(c) => { - delim(f)?; - write!(f, "const {}: ", name)?; - c.ty.hir_fmt(f)?; - } - } - } - } - - f.write_char('>')?; - Ok(()) -} - -fn write_where_clause(def: GenericDefId, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - 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 { - return Ok(()); - } - - 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), - 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)?; - } else { - new_predicate(f)?; - write!(f, "{}: {}", target.name, bound.name)?; - } - } - 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)?; - } - 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(',')?; - - Ok(()) -} - -impl HirDisplay for Const { - 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.const_data(self.id); - f.write_str("const ")?; - match &data.name { - Some(name) => write!(f, "{}: ", name)?, - None => f.write_str("_: ")?, - } - data.type_ref.hir_fmt(f)?; - Ok(()) - } -} - -impl HirDisplay for Static { - 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.static_data(self.id); - f.write_str("static ")?; - if data.mutable { - f.write_str("mut ")?; - } - write!(f, "{}: ", &data.name)?; - data.type_ref.hir_fmt(f)?; - Ok(()) - } -} - -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)?; - let def_id = GenericDefId::TraitId(self.id); - write_generic_params(def_id, f)?; - write_where_clause(def_id, f)?; - Ok(()) - } -} - -impl HirDisplay for TypeAlias { - 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.type_alias_data(self.id); - write!(f, "type {}", data.name)?; - if !data.bounds.is_empty() { - f.write_str(": ")?; - f.write_joined(&data.bounds, " + ")?; - } - if let Some(ty) = &data.type_ref { - f.write_str(" = ")?; - ty.hir_fmt(f)?; - } - Ok(()) - } -} - -impl HirDisplay for Module { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - // FIXME: Module doesn't have visibility saved in data. - match self.name(f.db) { - Some(name) => write!(f, "mod {}", name), - None if self.is_crate_root(f.db) => match self.krate(f.db).display_name(f.db) { - Some(name) => write!(f, "extern crate {}", name), - None => f.write_str("extern crate {unknown}"), - }, - None => f.write_str("mod {unnamed}"), - } - } -} - -impl HirDisplay for Macro { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match self.id { - hir_def::MacroId::Macro2Id(_) => f.write_str("macro"), - hir_def::MacroId::MacroRulesId(_) => f.write_str("macro_rules!"), - hir_def::MacroId::ProcMacroId(_) => f.write_str("proc_macro"), - }?; - write!(f, " {}", self.name(f.db)) - } -} diff --git a/src/tools/rust-analyzer/crates/hir/src/from_id.rs b/src/tools/rust-analyzer/crates/hir/src/from_id.rs deleted file mode 100644 index 9c7558d191877..0000000000000 --- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs +++ /dev/null @@ -1,293 +0,0 @@ -//! Utility module for converting between hir_def ids and code_model wrappers. -//! -//! It's unclear if we need this long-term, but it's definitely useful while we -//! are splitting the hir. - -use hir_def::{ - expr::{LabelId, PatId}, - AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, GenericParamId, - ModuleDefId, VariantId, -}; - -use crate::{ - Adt, AssocItem, BuiltinType, DefWithBody, Field, GenericDef, GenericParam, ItemInNs, Label, - Local, ModuleDef, Variant, VariantDef, -}; - -macro_rules! from_id { - ($(($id:path, $ty:path)),*) => {$( - impl From<$id> for $ty { - fn from(id: $id) -> $ty { - $ty { id } - } - } - impl From<$ty> for $id { - fn from(ty: $ty) -> $id { - ty.id - } - } - )*} -} - -from_id![ - (base_db::CrateId, crate::Crate), - (hir_def::ModuleId, crate::Module), - (hir_def::StructId, crate::Struct), - (hir_def::UnionId, crate::Union), - (hir_def::EnumId, crate::Enum), - (hir_def::TypeAliasId, crate::TypeAlias), - (hir_def::TraitId, crate::Trait), - (hir_def::StaticId, crate::Static), - (hir_def::ConstId, crate::Const), - (hir_def::FunctionId, crate::Function), - (hir_def::ImplId, crate::Impl), - (hir_def::TypeOrConstParamId, crate::TypeOrConstParam), - (hir_def::TypeParamId, crate::TypeParam), - (hir_def::ConstParamId, crate::ConstParam), - (hir_def::LifetimeParamId, crate::LifetimeParam), - (hir_def::MacroId, crate::Macro) -]; - -impl From for Adt { - fn from(id: AdtId) -> Self { - match id { - AdtId::StructId(it) => Adt::Struct(it.into()), - AdtId::UnionId(it) => Adt::Union(it.into()), - AdtId::EnumId(it) => Adt::Enum(it.into()), - } - } -} - -impl From for AdtId { - fn from(id: Adt) -> Self { - match id { - Adt::Struct(it) => AdtId::StructId(it.id), - Adt::Union(it) => AdtId::UnionId(it.id), - Adt::Enum(it) => AdtId::EnumId(it.id), - } - } -} - -impl From for GenericParam { - fn from(id: GenericParamId) -> Self { - match id { - GenericParamId::TypeParamId(it) => GenericParam::TypeParam(it.into()), - GenericParamId::ConstParamId(it) => GenericParam::ConstParam(it.into()), - GenericParamId::LifetimeParamId(it) => GenericParam::LifetimeParam(it.into()), - } - } -} - -impl From for GenericParamId { - fn from(id: GenericParam) -> Self { - match id { - GenericParam::LifetimeParam(it) => GenericParamId::LifetimeParamId(it.id), - GenericParam::ConstParam(it) => GenericParamId::ConstParamId(it.id), - GenericParam::TypeParam(it) => GenericParamId::TypeParamId(it.id), - } - } -} - -impl From for Variant { - fn from(id: EnumVariantId) -> Self { - Variant { parent: id.parent.into(), id: id.local_id } - } -} - -impl From for EnumVariantId { - fn from(def: Variant) -> Self { - EnumVariantId { parent: def.parent.id, local_id: def.id } - } -} - -impl From for ModuleDef { - fn from(id: ModuleDefId) -> Self { - match id { - ModuleDefId::ModuleId(it) => ModuleDef::Module(it.into()), - ModuleDefId::FunctionId(it) => ModuleDef::Function(it.into()), - ModuleDefId::AdtId(it) => ModuleDef::Adt(it.into()), - ModuleDefId::EnumVariantId(it) => ModuleDef::Variant(it.into()), - ModuleDefId::ConstId(it) => ModuleDef::Const(it.into()), - ModuleDefId::StaticId(it) => ModuleDef::Static(it.into()), - ModuleDefId::TraitId(it) => ModuleDef::Trait(it.into()), - ModuleDefId::TypeAliasId(it) => ModuleDef::TypeAlias(it.into()), - ModuleDefId::BuiltinType(it) => ModuleDef::BuiltinType(it.into()), - ModuleDefId::MacroId(it) => ModuleDef::Macro(it.into()), - } - } -} - -impl From for ModuleDefId { - fn from(id: ModuleDef) -> Self { - match id { - ModuleDef::Module(it) => ModuleDefId::ModuleId(it.into()), - ModuleDef::Function(it) => ModuleDefId::FunctionId(it.into()), - ModuleDef::Adt(it) => ModuleDefId::AdtId(it.into()), - ModuleDef::Variant(it) => ModuleDefId::EnumVariantId(it.into()), - ModuleDef::Const(it) => ModuleDefId::ConstId(it.into()), - ModuleDef::Static(it) => ModuleDefId::StaticId(it.into()), - ModuleDef::Trait(it) => ModuleDefId::TraitId(it.into()), - ModuleDef::TypeAlias(it) => ModuleDefId::TypeAliasId(it.into()), - ModuleDef::BuiltinType(it) => ModuleDefId::BuiltinType(it.into()), - ModuleDef::Macro(it) => ModuleDefId::MacroId(it.into()), - } - } -} - -impl From for DefWithBodyId { - fn from(def: DefWithBody) -> Self { - match def { - DefWithBody::Function(it) => DefWithBodyId::FunctionId(it.id), - DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id), - DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id), - } - } -} - -impl From for DefWithBody { - fn from(def: DefWithBodyId) -> Self { - match def { - DefWithBodyId::FunctionId(it) => DefWithBody::Function(it.into()), - DefWithBodyId::StaticId(it) => DefWithBody::Static(it.into()), - DefWithBodyId::ConstId(it) => DefWithBody::Const(it.into()), - } - } -} - -impl From for AssocItem { - fn from(def: AssocItemId) -> Self { - match def { - AssocItemId::FunctionId(it) => AssocItem::Function(it.into()), - AssocItemId::TypeAliasId(it) => AssocItem::TypeAlias(it.into()), - AssocItemId::ConstId(it) => AssocItem::Const(it.into()), - } - } -} - -impl From for GenericDefId { - fn from(def: GenericDef) -> Self { - match def { - GenericDef::Function(it) => GenericDefId::FunctionId(it.id), - GenericDef::Adt(it) => GenericDefId::AdtId(it.into()), - GenericDef::Trait(it) => GenericDefId::TraitId(it.id), - GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id), - GenericDef::Impl(it) => GenericDefId::ImplId(it.id), - GenericDef::Variant(it) => { - GenericDefId::EnumVariantId(EnumVariantId { parent: it.parent.id, local_id: it.id }) - } - GenericDef::Const(it) => GenericDefId::ConstId(it.id), - } - } -} - -impl From for GenericDef { - fn from(def: GenericDefId) -> Self { - match def { - GenericDefId::FunctionId(it) => GenericDef::Function(it.into()), - GenericDefId::AdtId(it) => GenericDef::Adt(it.into()), - GenericDefId::TraitId(it) => GenericDef::Trait(it.into()), - GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()), - GenericDefId::ImplId(it) => GenericDef::Impl(it.into()), - GenericDefId::EnumVariantId(it) => { - GenericDef::Variant(Variant { parent: it.parent.into(), id: it.local_id }) - } - GenericDefId::ConstId(it) => GenericDef::Const(it.into()), - } - } -} - -impl From for GenericDefId { - fn from(id: Adt) -> Self { - match id { - Adt::Struct(it) => it.id.into(), - Adt::Union(it) => it.id.into(), - Adt::Enum(it) => it.id.into(), - } - } -} - -impl From for VariantDef { - fn from(def: VariantId) -> Self { - match def { - VariantId::StructId(it) => VariantDef::Struct(it.into()), - VariantId::EnumVariantId(it) => VariantDef::Variant(it.into()), - VariantId::UnionId(it) => VariantDef::Union(it.into()), - } - } -} - -impl From for VariantId { - fn from(def: VariantDef) -> Self { - match def { - VariantDef::Struct(it) => VariantId::StructId(it.id), - VariantDef::Variant(it) => VariantId::EnumVariantId(it.into()), - VariantDef::Union(it) => VariantId::UnionId(it.id), - } - } -} - -impl From for FieldId { - fn from(def: Field) -> Self { - FieldId { parent: def.parent.into(), local_id: def.id } - } -} - -impl From for Field { - fn from(def: FieldId) -> Self { - Field { parent: def.parent.into(), id: def.local_id } - } -} - -impl From for GenericDefId { - fn from(item: AssocItem) -> Self { - match item { - AssocItem::Function(f) => f.id.into(), - AssocItem::Const(c) => c.id.into(), - AssocItem::TypeAlias(t) => t.id.into(), - } - } -} - -impl From<(DefWithBodyId, PatId)> for Local { - fn from((parent, pat_id): (DefWithBodyId, PatId)) -> Self { - Local { parent, pat_id } - } -} - -impl From<(DefWithBodyId, LabelId)> for Label { - fn from((parent, label_id): (DefWithBodyId, LabelId)) -> Self { - Label { parent, label_id } - } -} - -impl From for ItemInNs { - fn from(it: hir_def::item_scope::ItemInNs) -> Self { - match it { - hir_def::item_scope::ItemInNs::Types(it) => ItemInNs::Types(it.into()), - hir_def::item_scope::ItemInNs::Values(it) => ItemInNs::Values(it.into()), - hir_def::item_scope::ItemInNs::Macros(it) => ItemInNs::Macros(it.into()), - } - } -} - -impl From for hir_def::item_scope::ItemInNs { - fn from(it: ItemInNs) -> Self { - match it { - ItemInNs::Types(it) => Self::Types(it.into()), - ItemInNs::Values(it) => Self::Values(it.into()), - ItemInNs::Macros(it) => Self::Macros(it.into()), - } - } -} - -impl From for BuiltinType { - fn from(inner: hir_def::builtin_type::BuiltinType) -> Self { - Self { inner } - } -} - -impl From for hir_def::builtin_type::BuiltinType { - fn from(it: BuiltinType) -> Self { - it.inner - } -} diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs deleted file mode 100644 index f8b01db3e3288..0000000000000 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ /dev/null @@ -1,174 +0,0 @@ -//! Provides set of implementation for hir's objects that allows get back location in file. - -use either::Either; -use hir_def::{ - nameres::{ModuleOrigin, ModuleSource}, - src::{HasChildSource, HasSource as _}, - Lookup, MacroId, VariantId, -}; -use hir_expand::InFile; -use syntax::ast; - -use crate::{ - db::HirDatabase, Adt, Const, Enum, Field, FieldSource, Function, Impl, LifetimeParam, Macro, - Module, Static, Struct, Trait, TypeAlias, TypeOrConstParam, Union, Variant, -}; - -pub trait HasSource { - type Ast; - /// Fetches the definition's source node. - /// Using [`crate::Semantics::source`] is preferred when working with [`crate::Semantics`], - /// as that caches the parsed file in the semantics' cache. - fn source(self, db: &dyn HirDatabase) -> Option>; -} - -/// NB: Module is !HasSource, because it has two source nodes at the same time: -/// definition and declaration. -impl Module { - /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. - pub fn definition_source(self, db: &dyn HirDatabase) -> InFile { - let def_map = self.id.def_map(db.upcast()); - def_map[self.id.local_id].definition_source(db.upcast()) - } - - pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool { - let def_map = self.id.def_map(db.upcast()); - match def_map[self.id.local_id].origin { - ModuleOrigin::File { is_mod_rs, .. } => is_mod_rs, - _ => false, - } - } - - pub fn is_inline(self, db: &dyn HirDatabase) -> bool { - let def_map = self.id.def_map(db.upcast()); - def_map[self.id.local_id].origin.is_inline() - } - - /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. - /// `None` for the crate root. - pub fn declaration_source(self, db: &dyn HirDatabase) -> Option> { - let def_map = self.id.def_map(db.upcast()); - def_map[self.id.local_id].declaration_source(db.upcast()) - } -} - -impl HasSource for Field { - type Ast = FieldSource; - fn source(self, db: &dyn HirDatabase) -> Option> { - let var = VariantId::from(self.parent); - let src = var.child_source(db.upcast()); - let field_source = src.map(|it| match it[self.id].clone() { - Either::Left(it) => FieldSource::Pos(it), - Either::Right(it) => FieldSource::Named(it), - }); - Some(field_source) - } -} -impl HasSource for Adt { - type Ast = ast::Adt; - fn source(self, db: &dyn HirDatabase) -> Option> { - match self { - Adt::Struct(s) => Some(s.source(db)?.map(ast::Adt::Struct)), - Adt::Union(u) => Some(u.source(db)?.map(ast::Adt::Union)), - Adt::Enum(e) => Some(e.source(db)?.map(ast::Adt::Enum)), - } - } -} -impl HasSource for Struct { - type Ast = ast::Struct; - fn source(self, db: &dyn HirDatabase) -> Option> { - Some(self.id.lookup(db.upcast()).source(db.upcast())) - } -} -impl HasSource for Union { - type Ast = ast::Union; - fn source(self, db: &dyn HirDatabase) -> Option> { - Some(self.id.lookup(db.upcast()).source(db.upcast())) - } -} -impl HasSource for Enum { - type Ast = ast::Enum; - fn source(self, db: &dyn HirDatabase) -> Option> { - Some(self.id.lookup(db.upcast()).source(db.upcast())) - } -} -impl HasSource for Variant { - type Ast = ast::Variant; - fn source(self, db: &dyn HirDatabase) -> Option> { - Some(self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone())) - } -} -impl HasSource for Function { - type Ast = ast::Fn; - fn source(self, db: &dyn HirDatabase) -> Option> { - Some(self.id.lookup(db.upcast()).source(db.upcast())) - } -} -impl HasSource for Const { - type Ast = ast::Const; - fn source(self, db: &dyn HirDatabase) -> Option> { - Some(self.id.lookup(db.upcast()).source(db.upcast())) - } -} -impl HasSource for Static { - type Ast = ast::Static; - fn source(self, db: &dyn HirDatabase) -> Option> { - Some(self.id.lookup(db.upcast()).source(db.upcast())) - } -} -impl HasSource for Trait { - type Ast = ast::Trait; - fn source(self, db: &dyn HirDatabase) -> Option> { - Some(self.id.lookup(db.upcast()).source(db.upcast())) - } -} -impl HasSource for TypeAlias { - type Ast = ast::TypeAlias; - fn source(self, db: &dyn HirDatabase) -> Option> { - Some(self.id.lookup(db.upcast()).source(db.upcast())) - } -} -impl HasSource for Macro { - type Ast = Either; - fn source(self, db: &dyn HirDatabase) -> Option> { - match self.id { - MacroId::Macro2Id(it) => Some( - it.lookup(db.upcast()) - .source(db.upcast()) - .map(ast::Macro::MacroDef) - .map(Either::Left), - ), - MacroId::MacroRulesId(it) => Some( - it.lookup(db.upcast()) - .source(db.upcast()) - .map(ast::Macro::MacroRules) - .map(Either::Left), - ), - MacroId::ProcMacroId(it) => { - Some(it.lookup(db.upcast()).source(db.upcast()).map(Either::Right)) - } - } - } -} -impl HasSource for Impl { - type Ast = ast::Impl; - fn source(self, db: &dyn HirDatabase) -> Option> { - Some(self.id.lookup(db.upcast()).source(db.upcast())) - } -} - -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())) - } -} - -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())) - } -} diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs deleted file mode 100644 index d4925455d7bd2..0000000000000 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ /dev/null @@ -1,3635 +0,0 @@ -//! HIR (previously known as descriptors) provides a high-level object oriented -//! access to Rust code. -//! -//! The principal difference between HIR and syntax trees is that HIR is bound -//! to a particular crate instance. That is, it has cfg flags and features -//! applied. So, the relation between syntax and HIR is many-to-one. -//! -//! HIR is the public API of the all of the compiler logic above syntax trees. -//! It is written in "OO" style. Each type is self contained (as in, it knows it's -//! parents and full context). It should be "clean code". -//! -//! `hir_*` crates are the implementation of the compiler logic. -//! They are written in "ECS" style, with relatively little abstractions. -//! Many types are not self-contained, and explicitly use local indexes, arenas, etc. -//! -//! `hir` is what insulates the "we don't know how to actually write an incremental compiler" -//! from the ide with completions, hovers, etc. It is a (soft, internal) boundary: -//! . - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] -#![recursion_limit = "512"] - -mod semantics; -mod source_analyzer; - -mod from_id; -mod attrs; -mod has_source; - -pub mod diagnostics; -pub mod db; -pub mod symbols; - -mod display; - -use std::{iter, ops::ControlFlow, sync::Arc}; - -use arrayvec::ArrayVec; -use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind}; -use either::Either; -use hir_def::{ - adt::{ReprKind, VariantData}, - body::{BodyDiagnostic, SyntheticSyntax}, - expr::{BindingAnnotation, LabelId, Pat, PatId}, - generics::{TypeOrConstParamData, TypeParamProvenance}, - item_tree::ItemTreeNode, - lang_item::LangItemTarget, - nameres::{self, diagnostics::DefDiagnostic}, - per_ns::PerNs, - resolver::{HasResolver, Resolver}, - src::HasSource as _, - AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, - FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId, - LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, - TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, -}; -use hir_expand::{name::name, MacroCallKind}; -use hir_ty::{ - all_super_traits, autoderef, - consteval::{unknown_const_as_generic, ComputedExpr, ConstEvalError, ConstExt}, - diagnostics::BodyValidationDiagnostic, - method_resolution::{self, TyFingerprint}, - primitive::UintTy, - subst_prefix, - traits::FnTrait, - AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, - ClosureId, DebruijnIndex, GenericArgData, InEnvironment, Interner, ParamKind, - QuantifiedWhereClause, Scalar, Solution, Substitution, TraitEnvironment, TraitRefExt, Ty, - TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind, WhereClause, -}; -use itertools::Itertools; -use nameres::diagnostics::DefDiagnosticKind; -use once_cell::unsync::Lazy; -use rustc_hash::FxHashSet; -use stdx::{format_to, impl_from, never}; -use syntax::{ - ast::{self, HasAttrs as _, HasDocComments, HasName}, - AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T, -}; - -use crate::db::{DefDatabase, HirDatabase}; - -pub use crate::{ - attrs::{HasAttrs, Namespace}, - diagnostics::{ - AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, InvalidDeriveTarget, - MacroError, MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms, - MissingUnsafe, NoSuchField, ReplaceFilterMapNextWithFindMap, TypeMismatch, - UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, - UnresolvedModule, UnresolvedProcMacro, - }, - has_source::HasSource, - semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits}, -}; - -// Be careful with these re-exports. -// -// `hir` is the boundary between the compiler and the IDE. It should try hard to -// isolate the compiler from the ide, to allow the two to be refactored -// independently. Re-exporting something from the compiler is the sure way to -// breach the boundary. -// -// Generally, a refactoring which *removes* a name from this list is a good -// idea! -pub use { - cfg::{CfgAtom, CfgExpr, CfgOptions}, - hir_def::{ - adt::StructKind, - attr::{Attr, Attrs, AttrsWithOwner, Documentation}, - builtin_attr::AttributeTemplate, - find_path::PrefixKind, - import_map, - nameres::ModuleSource, - path::{ModPath, PathKind}, - type_ref::{Mutability, TypeRef}, - visibility::Visibility, - }, - hir_expand::{ - name::{known, Name}, - ExpandResult, HirFileId, InFile, MacroFile, Origin, - }, - hir_ty::display::HirDisplay, -}; - -// These are negative re-exports: pub using these names is forbidden, they -// should remain private to hir internals. -#[allow(unused)] -use { - hir_def::path::Path, - hir_expand::{hygiene::Hygiene, name::AsName}, -}; - -/// hir::Crate describes a single crate. It's the main interface with which -/// a crate's dependencies interact. Mostly, it should be just a proxy for the -/// root module. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Crate { - pub(crate) id: CrateId, -} - -#[derive(Debug)] -pub struct CrateDependency { - pub krate: Crate, - pub name: Name, -} - -impl Crate { - pub fn origin(self, db: &dyn HirDatabase) -> CrateOrigin { - db.crate_graph()[self.id].origin.clone() - } - - pub fn is_builtin(self, db: &dyn HirDatabase) -> bool { - matches!(self.origin(db), CrateOrigin::Lang(_)) - } - - pub fn dependencies(self, db: &dyn HirDatabase) -> Vec { - db.crate_graph()[self.id] - .dependencies - .iter() - .map(|dep| { - let krate = Crate { id: dep.crate_id }; - let name = dep.as_name(); - CrateDependency { krate, name } - }) - .collect() - } - - pub fn reverse_dependencies(self, db: &dyn HirDatabase) -> Vec { - let crate_graph = db.crate_graph(); - crate_graph - .iter() - .filter(|&krate| { - crate_graph[krate].dependencies.iter().any(|it| it.crate_id == self.id) - }) - .map(|id| Crate { id }) - .collect() - } - - pub fn transitive_reverse_dependencies( - self, - db: &dyn HirDatabase, - ) -> impl Iterator { - db.crate_graph().transitive_rev_deps(self.id).map(|id| Crate { id }) - } - - pub fn root_module(self, db: &dyn HirDatabase) -> Module { - let def_map = db.crate_def_map(self.id); - Module { id: def_map.module_id(def_map.root()) } - } - - pub fn modules(self, db: &dyn HirDatabase) -> Vec { - let def_map = db.crate_def_map(self.id); - def_map.modules().map(|(id, _)| def_map.module_id(id).into()).collect() - } - - pub fn root_file(self, db: &dyn HirDatabase) -> FileId { - db.crate_graph()[self.id].root_file_id - } - - pub fn edition(self, db: &dyn HirDatabase) -> Edition { - db.crate_graph()[self.id].edition - } - - pub fn version(self, db: &dyn HirDatabase) -> Option { - db.crate_graph()[self.id].version.clone() - } - - pub fn display_name(self, db: &dyn HirDatabase) -> Option { - db.crate_graph()[self.id].display_name.clone() - } - - pub fn query_external_importables( - self, - db: &dyn DefDatabase, - query: import_map::Query, - ) -> impl Iterator> { - let _p = profile::span("query_external_importables"); - 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), - ItemInNs::Macros(mac_id) => Either::Right(mac_id), - } - }) - } - - pub fn all(db: &dyn HirDatabase) -> Vec { - db.crate_graph().iter().map(|id| Crate { id }).collect() - } - - /// Try to get the root URL of the documentation of a crate. - pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option { - // Look for #![doc(html_root_url = "...")] - let attrs = db.attrs(AttrDefId::ModuleId(self.root_module(db).into())); - let doc_url = attrs.by_key("doc").find_string_value_in_tt("html_root_url"); - doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/") - } - - pub fn cfg(&self, db: &dyn HirDatabase) -> CfgOptions { - db.crate_graph()[self.id].cfg_options.clone() - } - - pub fn potential_cfg(&self, db: &dyn HirDatabase) -> CfgOptions { - db.crate_graph()[self.id].potential_cfg_options.clone() - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Module { - pub(crate) id: ModuleId, -} - -/// The defs which can be visible in the module. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum ModuleDef { - Module(Module), - Function(Function), - Adt(Adt), - // Can't be directly declared, but can be imported. - Variant(Variant), - Const(Const), - Static(Static), - Trait(Trait), - TypeAlias(TypeAlias), - BuiltinType(BuiltinType), - Macro(Macro), -} -impl_from!( - Module, - Function, - Adt(Struct, Enum, Union), - Variant, - Const, - Static, - Trait, - TypeAlias, - BuiltinType, - Macro - for ModuleDef -); - -impl From for ModuleDef { - fn from(var: VariantDef) -> Self { - match var { - VariantDef::Struct(t) => Adt::from(t).into(), - VariantDef::Union(t) => Adt::from(t).into(), - VariantDef::Variant(t) => t.into(), - } - } -} - -impl ModuleDef { - pub fn module(self, db: &dyn HirDatabase) -> Option { - match self { - ModuleDef::Module(it) => it.parent(db), - ModuleDef::Function(it) => Some(it.module(db)), - ModuleDef::Adt(it) => Some(it.module(db)), - ModuleDef::Variant(it) => Some(it.module(db)), - ModuleDef::Const(it) => Some(it.module(db)), - ModuleDef::Static(it) => Some(it.module(db)), - ModuleDef::Trait(it) => Some(it.module(db)), - ModuleDef::TypeAlias(it) => Some(it.module(db)), - ModuleDef::Macro(it) => Some(it.module(db)), - ModuleDef::BuiltinType(_) => None, - } - } - - pub fn canonical_path(&self, db: &dyn HirDatabase) -> Option { - let mut segments = vec![self.name(db)?]; - for m in self.module(db)?.path_to_root(db) { - segments.extend(m.name(db)) - } - segments.reverse(); - Some(segments.into_iter().join("::")) - } - - pub fn canonical_module_path( - &self, - db: &dyn HirDatabase, - ) -> Option> { - self.module(db).map(|it| it.path_to_root(db).into_iter().rev()) - } - - pub fn name(self, db: &dyn HirDatabase) -> Option { - let name = match self { - ModuleDef::Module(it) => it.name(db)?, - ModuleDef::Const(it) => it.name(db)?, - ModuleDef::Adt(it) => it.name(db), - ModuleDef::Trait(it) => it.name(db), - ModuleDef::Function(it) => it.name(db), - ModuleDef::Variant(it) => it.name(db), - ModuleDef::TypeAlias(it) => it.name(db), - ModuleDef::Static(it) => it.name(db), - ModuleDef::Macro(it) => it.name(db), - ModuleDef::BuiltinType(it) => it.name(), - }; - Some(name) - } - - pub fn diagnostics(self, db: &dyn HirDatabase) -> Vec { - let id = match self { - ModuleDef::Adt(it) => match it { - Adt::Struct(it) => it.id.into(), - Adt::Enum(it) => it.id.into(), - Adt::Union(it) => it.id.into(), - }, - ModuleDef::Trait(it) => it.id.into(), - ModuleDef::Function(it) => it.id.into(), - ModuleDef::TypeAlias(it) => it.id.into(), - ModuleDef::Module(it) => it.id.into(), - ModuleDef::Const(it) => it.id.into(), - ModuleDef::Static(it) => it.id.into(), - _ => return Vec::new(), - }; - - let module = match self.module(db) { - Some(it) => it, - None => return Vec::new(), - }; - - let mut acc = Vec::new(); - - match self.as_def_with_body() { - Some(def) => { - def.diagnostics(db, &mut acc); - } - None => { - for diag in hir_ty::diagnostics::incorrect_case(db, module.id.krate(), id) { - acc.push(diag.into()) - } - } - } - - acc - } - - pub fn as_def_with_body(self) -> Option { - match self { - ModuleDef::Function(it) => Some(it.into()), - ModuleDef::Const(it) => Some(it.into()), - ModuleDef::Static(it) => Some(it.into()), - - ModuleDef::Module(_) - | ModuleDef::Adt(_) - | ModuleDef::Variant(_) - | ModuleDef::Trait(_) - | ModuleDef::TypeAlias(_) - | ModuleDef::Macro(_) - | ModuleDef::BuiltinType(_) => None, - } - } - - pub fn attrs(&self, db: &dyn HirDatabase) -> Option { - Some(match self { - ModuleDef::Module(it) => it.attrs(db), - ModuleDef::Function(it) => it.attrs(db), - ModuleDef::Adt(it) => it.attrs(db), - ModuleDef::Variant(it) => it.attrs(db), - ModuleDef::Const(it) => it.attrs(db), - ModuleDef::Static(it) => it.attrs(db), - ModuleDef::Trait(it) => it.attrs(db), - ModuleDef::TypeAlias(it) => it.attrs(db), - ModuleDef::Macro(it) => it.attrs(db), - ModuleDef::BuiltinType(_) => return None, - }) - } -} - -impl HasVisibility for ModuleDef { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - match *self { - ModuleDef::Module(it) => it.visibility(db), - ModuleDef::Function(it) => it.visibility(db), - ModuleDef::Adt(it) => it.visibility(db), - ModuleDef::Const(it) => it.visibility(db), - ModuleDef::Static(it) => it.visibility(db), - ModuleDef::Trait(it) => it.visibility(db), - ModuleDef::TypeAlias(it) => it.visibility(db), - ModuleDef::Variant(it) => it.visibility(db), - ModuleDef::Macro(it) => it.visibility(db), - ModuleDef::BuiltinType(_) => Visibility::Public, - } - } -} - -impl Module { - /// Name of this module. - pub fn name(self, db: &dyn HirDatabase) -> Option { - let def_map = self.id.def_map(db.upcast()); - let parent = def_map[self.id.local_id].parent?; - def_map[parent].children.iter().find_map(|(name, module_id)| { - if *module_id == self.id.local_id { - Some(name.clone()) - } else { - None - } - }) - } - - /// Returns the crate this module is part of. - pub fn krate(self) -> Crate { - Crate { id: self.id.krate() } - } - - /// Topmost parent of this module. Every module has a `crate_root`, but some - /// might be missing `krate`. This can happen if a module's file is not included - /// in the module tree of any target in `Cargo.toml`. - pub fn crate_root(self, db: &dyn HirDatabase) -> Module { - let def_map = db.crate_def_map(self.id.krate()); - Module { id: def_map.module_id(def_map.root()) } - } - - pub fn is_crate_root(self, db: &dyn HirDatabase) -> bool { - let def_map = db.crate_def_map(self.id.krate()); - def_map.root() == self.id.local_id - } - - /// Iterates over all child modules. - pub fn children(self, db: &dyn HirDatabase) -> impl Iterator { - let def_map = self.id.def_map(db.upcast()); - let children = def_map[self.id.local_id] - .children - .iter() - .map(|(_, module_id)| Module { id: def_map.module_id(*module_id) }) - .collect::>(); - children.into_iter() - } - - /// Finds a parent module. - pub fn parent(self, db: &dyn HirDatabase) -> Option { - // FIXME: handle block expressions as modules (their parent is in a different DefMap) - let def_map = self.id.def_map(db.upcast()); - let parent_id = def_map[self.id.local_id].parent?; - Some(Module { id: def_map.module_id(parent_id) }) - } - - pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec { - let mut res = vec![self]; - let mut curr = self; - while let Some(next) = curr.parent(db) { - res.push(next); - curr = next - } - res - } - - /// Returns a `ModuleScope`: a set of items, visible in this module. - pub fn scope( - self, - db: &dyn HirDatabase, - visible_from: Option, - ) -> Vec<(Name, ScopeDef)> { - self.id.def_map(db.upcast())[self.id.local_id] - .scope - .entries() - .filter_map(|(name, def)| { - if let Some(m) = visible_from { - let filtered = - def.filter_visibility(|vis| vis.is_visible_from(db.upcast(), m.id)); - if filtered.is_none() && !def.is_none() { - None - } else { - Some((name, filtered)) - } - } else { - Some((name, def)) - } - }) - .flat_map(|(name, def)| { - ScopeDef::all_items(def).into_iter().map(move |item| (name.clone(), item)) - }) - .collect() - } - - pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec) { - let _p = profile::span("Module::diagnostics").detail(|| { - format!("{:?}", self.name(db).map_or("".into(), |name| name.to_string())) - }); - let def_map = self.id.def_map(db.upcast()); - for diag in def_map.diagnostics() { - if diag.in_module != self.id.local_id { - // FIXME: This is accidentally quadratic. - continue; - } - emit_def_diagnostic(db, acc, diag); - } - for decl in self.declarations(db) { - match decl { - ModuleDef::Module(m) => { - // Only add diagnostics from inline modules - if def_map[m.id.local_id].origin.is_inline() { - m.diagnostics(db, acc) - } - } - _ => acc.extend(decl.diagnostics(db)), - } - } - - for impl_def in self.impl_defs(db) { - for item in impl_def.items(db) { - let def: DefWithBody = match item { - AssocItem::Function(it) => it.into(), - AssocItem::Const(it) => it.into(), - AssocItem::TypeAlias(_) => continue, - }; - - def.diagnostics(db, acc); - } - } - } - - pub fn declarations(self, db: &dyn HirDatabase) -> Vec { - let def_map = self.id.def_map(db.upcast()); - let scope = &def_map[self.id.local_id].scope; - scope - .declarations() - .map(ModuleDef::from) - .chain(scope.unnamed_consts().map(|id| ModuleDef::Const(Const::from(id)))) - .collect() - } - - pub fn legacy_macros(self, db: &dyn HirDatabase) -> Vec { - let def_map = self.id.def_map(db.upcast()); - let scope = &def_map[self.id.local_id].scope; - scope.legacy_macros().flat_map(|(_, it)| it).map(|&it| MacroId::from(it).into()).collect() - } - - pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec { - let def_map = self.id.def_map(db.upcast()); - def_map[self.id.local_id].scope.impls().map(Impl::from).collect() - } - - /// Finds a path that can be used to refer to the given item from within - /// this module, if possible. - pub fn find_use_path(self, db: &dyn DefDatabase, item: impl Into) -> Option { - hir_def::find_path::find_path(db, item.into().into(), self.into()) - } - - /// Finds a path that can be used to refer to the given item from within - /// this module, if possible. This is used for returning import paths for use-statements. - pub fn find_use_path_prefixed( - self, - db: &dyn DefDatabase, - item: impl Into, - prefix_kind: PrefixKind, - ) -> Option { - hir_def::find_path::find_path_prefixed(db, item.into().into(), self.into(), prefix_kind) - } -} - -fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec, diag: &DefDiagnostic) { - match &diag.kind { - DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => { - let decl = declaration.to_node(db.upcast()); - acc.push( - UnresolvedModule { - decl: InFile::new(declaration.file_id, AstPtr::new(&decl)), - candidates: candidates.clone(), - } - .into(), - ) - } - DefDiagnosticKind::UnresolvedExternCrate { ast } => { - let item = ast.to_node(db.upcast()); - acc.push( - UnresolvedExternCrate { decl: InFile::new(ast.file_id, AstPtr::new(&item)) }.into(), - ); - } - - DefDiagnosticKind::UnresolvedImport { id, index } => { - let file_id = id.file_id(); - let item_tree = id.item_tree(db.upcast()); - let import = &item_tree[id.value]; - - let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index); - acc.push( - UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }.into(), - ); - } - - DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => { - let item = ast.to_node(db.upcast()); - acc.push( - InactiveCode { - node: ast.with_value(AstPtr::new(&item).into()), - cfg: cfg.clone(), - opts: opts.clone(), - } - .into(), - ); - } - - DefDiagnosticKind::UnresolvedProcMacro { ast, krate } => { - let (node, precise_location, macro_name, kind) = precise_macro_call_location(ast, db); - acc.push( - UnresolvedProcMacro { node, precise_location, macro_name, kind, krate: *krate } - .into(), - ); - } - - DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { - let (node, precise_location, _, _) = precise_macro_call_location(ast, db); - acc.push( - UnresolvedMacroCall { - macro_call: node, - precise_location, - path: path.clone(), - is_bang: matches!(ast, MacroCallKind::FnLike { .. }), - } - .into(), - ); - } - - DefDiagnosticKind::MacroError { ast, message } => { - let (node, precise_location, _, _) = precise_macro_call_location(ast, db); - acc.push(MacroError { node, precise_location, message: message.clone() }.into()); - } - - DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { - let node = ast.to_node(db.upcast()); - // Must have a name, otherwise we wouldn't emit it. - let name = node.name().expect("unimplemented builtin macro with no name"); - acc.push( - UnimplementedBuiltinMacro { - node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&name))), - } - .into(), - ); - } - DefDiagnosticKind::InvalidDeriveTarget { ast, id } => { - let node = ast.to_node(db.upcast()); - let derive = node.attrs().nth(*id as usize); - match derive { - Some(derive) => { - acc.push( - InvalidDeriveTarget { - node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))), - } - .into(), - ); - } - None => stdx::never!("derive diagnostic on item without derive attribute"), - } - } - DefDiagnosticKind::MalformedDerive { ast, id } => { - let node = ast.to_node(db.upcast()); - let derive = node.attrs().nth(*id as usize); - match derive { - Some(derive) => { - acc.push( - MalformedDerive { - node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))), - } - .into(), - ); - } - None => stdx::never!("derive diagnostic on item without derive attribute"), - } - } - } -} - -fn precise_macro_call_location( - ast: &MacroCallKind, - db: &dyn HirDatabase, -) -> (InFile, Option, Option, MacroKind) { - // FIXME: maaybe we actually want slightly different ranges for the different macro diagnostics - // - e.g. the full attribute for macro errors, but only the name for name resolution - match ast { - MacroCallKind::FnLike { ast_id, .. } => { - let node = ast_id.to_node(db.upcast()); - ( - ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), - node.path() - .and_then(|it| it.segment()) - .and_then(|it| it.name_ref()) - .map(|it| it.syntax().text_range()), - node.path().and_then(|it| it.segment()).map(|it| it.to_string()), - MacroKind::ProcMacro, - ) - } - MacroCallKind::Derive { ast_id, derive_attr_index, derive_index } => { - let node = ast_id.to_node(db.upcast()); - // Compute the precise location of the macro name's token in the derive - // list. - let token = (|| { - let derive_attr = node - .doc_comments_and_attrs() - .nth(*derive_attr_index as usize) - .and_then(Either::left)?; - let token_tree = derive_attr.meta()?.token_tree()?; - let group_by = token_tree - .syntax() - .children_with_tokens() - .filter_map(|elem| match elem { - syntax::NodeOrToken::Token(tok) => Some(tok), - _ => None, - }) - .group_by(|t| t.kind() == T![,]); - let (_, mut group) = group_by - .into_iter() - .filter(|&(comma, _)| !comma) - .nth(*derive_index as usize)?; - group.find(|t| t.kind() == T![ident]) - })(); - ( - ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), - token.as_ref().map(|tok| tok.text_range()), - token.as_ref().map(ToString::to_string), - MacroKind::Derive, - ) - } - MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => { - let node = ast_id.to_node(db.upcast()); - let attr = node - .doc_comments_and_attrs() - .nth((*invoc_attr_index) as usize) - .and_then(Either::left) - .unwrap_or_else(|| panic!("cannot find attribute #{}", invoc_attr_index)); - - ( - ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))), - Some(attr.syntax().text_range()), - attr.path() - .and_then(|path| path.segment()) - .and_then(|seg| seg.name_ref()) - .as_ref() - .map(ToString::to_string), - MacroKind::Attr, - ) - } - } -} - -impl HasVisibility for Module { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - let def_map = self.id.def_map(db.upcast()); - let module_data = &def_map[self.id.local_id]; - module_data.visibility - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Field { - pub(crate) parent: VariantDef, - pub(crate) id: LocalFieldId, -} - -#[derive(Debug, PartialEq, Eq)] -pub enum FieldSource { - Named(ast::RecordField), - Pos(ast::TupleField), -} - -impl Field { - pub fn name(&self, db: &dyn HirDatabase) -> Name { - self.parent.variant_data(db).fields()[self.id].name.clone() - } - - /// Returns the type as in the signature of the struct (i.e., with - /// placeholder types for type parameters). Only use this in the context of - /// the field definition. - pub fn ty(&self, db: &dyn HirDatabase) -> Type { - let var_id = self.parent.into(); - let generic_def_id: GenericDefId = match self.parent { - VariantDef::Struct(it) => it.id.into(), - VariantDef::Union(it) => it.id.into(), - VariantDef::Variant(it) => it.parent.id.into(), - }; - let substs = TyBuilder::placeholder_subst(db, generic_def_id); - let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs); - Type::new(db, var_id, ty) - } - - pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef { - self.parent - } -} - -impl HasVisibility for Field { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - let variant_data = self.parent.variant_data(db); - let visibility = &variant_data.fields()[self.id].visibility; - let parent_id: hir_def::VariantId = self.parent.into(); - visibility.resolve(db.upcast(), &parent_id.resolver(db.upcast())) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Struct { - pub(crate) id: StructId, -} - -impl Struct { - pub fn module(self, db: &dyn HirDatabase) -> Module { - Module { id: self.id.lookup(db.upcast()).container } - } - - pub fn name(self, db: &dyn HirDatabase) -> Name { - db.struct_data(self.id).name.clone() - } - - pub fn fields(self, db: &dyn HirDatabase) -> Vec { - db.struct_data(self.id) - .variant_data - .fields() - .iter() - .map(|(id, _)| Field { parent: self.into(), id }) - .collect() - } - - pub fn ty(self, db: &dyn HirDatabase) -> Type { - Type::from_def(db, self.id) - } - - pub fn repr(self, db: &dyn HirDatabase) -> Option { - db.struct_data(self.id).repr.clone() - } - - pub fn kind(self, db: &dyn HirDatabase) -> StructKind { - self.variant_data(db).kind() - } - - fn variant_data(self, db: &dyn HirDatabase) -> Arc { - db.struct_data(self.id).variant_data.clone() - } -} - -impl HasVisibility for Struct { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - db.struct_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Union { - pub(crate) id: UnionId, -} - -impl Union { - pub fn name(self, db: &dyn HirDatabase) -> Name { - db.union_data(self.id).name.clone() - } - - pub fn module(self, db: &dyn HirDatabase) -> Module { - Module { id: self.id.lookup(db.upcast()).container } - } - - pub fn ty(self, db: &dyn HirDatabase) -> Type { - Type::from_def(db, self.id) - } - - pub fn fields(self, db: &dyn HirDatabase) -> Vec { - db.union_data(self.id) - .variant_data - .fields() - .iter() - .map(|(id, _)| Field { parent: self.into(), id }) - .collect() - } - - fn variant_data(self, db: &dyn HirDatabase) -> Arc { - db.union_data(self.id).variant_data.clone() - } -} - -impl HasVisibility for Union { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - db.union_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Enum { - pub(crate) id: EnumId, -} - -impl Enum { - pub fn module(self, db: &dyn HirDatabase) -> Module { - Module { id: self.id.lookup(db.upcast()).container } - } - - pub fn name(self, db: &dyn HirDatabase) -> Name { - db.enum_data(self.id).name.clone() - } - - pub fn variants(self, db: &dyn HirDatabase) -> Vec { - db.enum_data(self.id).variants.iter().map(|(id, _)| Variant { parent: self, id }).collect() - } - - pub fn ty(self, db: &dyn HirDatabase) -> Type { - Type::from_def(db, self.id) - } -} - -impl HasVisibility for Enum { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - db.enum_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Variant { - pub(crate) parent: Enum, - pub(crate) id: LocalEnumVariantId, -} - -impl Variant { - pub fn module(self, db: &dyn HirDatabase) -> Module { - self.parent.module(db) - } - - pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum { - self.parent - } - - pub fn name(self, db: &dyn HirDatabase) -> Name { - db.enum_data(self.parent.id).variants[self.id].name.clone() - } - - pub fn fields(self, db: &dyn HirDatabase) -> Vec { - self.variant_data(db) - .fields() - .iter() - .map(|(id, _)| Field { parent: self.into(), id }) - .collect() - } - - pub fn kind(self, db: &dyn HirDatabase) -> StructKind { - self.variant_data(db).kind() - } - - pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc { - db.enum_data(self.parent.id).variants[self.id].variant_data.clone() - } -} - -/// Variants inherit visibility from the parent enum. -impl HasVisibility for Variant { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - self.parent_enum(db).visibility(db) - } -} - -/// A Data Type -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum Adt { - Struct(Struct), - Union(Union), - Enum(Enum), -} -impl_from!(Struct, Union, Enum for Adt); - -impl Adt { - pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { - let subst = db.generic_defaults(self.into()); - subst.iter().any(|ty| match ty.skip_binders().data(Interner) { - GenericArgData::Ty(x) => x.is_unknown(), - _ => false, - }) - } - - /// Turns this ADT into a type. Any type parameters of the ADT will be - /// turned into unknown types, which is good for e.g. finding the most - /// general set of completions, but will not look very nice when printed. - pub fn ty(self, db: &dyn HirDatabase) -> Type { - let id = AdtId::from(self); - Type::from_def(db, id) - } - - /// Turns this ADT into a type with the given type parameters. This isn't - /// the greatest API, FIXME find a better one. - pub fn ty_with_args(self, db: &dyn HirDatabase, args: &[Type]) -> Type { - let id = AdtId::from(self); - let mut it = args.iter().map(|t| t.ty.clone()); - let ty = TyBuilder::def_ty(db, id.into()) - .fill(|x| { - let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner)); - match x { - ParamKind::Type => GenericArgData::Ty(r).intern(Interner), - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), - } - }) - .build(); - Type::new(db, id, ty) - } - - pub fn module(self, db: &dyn HirDatabase) -> Module { - match self { - Adt::Struct(s) => s.module(db), - Adt::Union(s) => s.module(db), - Adt::Enum(e) => e.module(db), - } - } - - pub fn name(self, db: &dyn HirDatabase) -> Name { - match self { - Adt::Struct(s) => s.name(db), - Adt::Union(u) => u.name(db), - Adt::Enum(e) => e.name(db), - } - } - - pub fn as_enum(&self) -> Option { - if let Self::Enum(v) = self { - Some(*v) - } else { - None - } - } -} - -impl HasVisibility for Adt { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - match self { - Adt::Struct(it) => it.visibility(db), - Adt::Union(it) => it.visibility(db), - Adt::Enum(it) => it.visibility(db), - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum VariantDef { - Struct(Struct), - Union(Union), - Variant(Variant), -} -impl_from!(Struct, Union, Variant for VariantDef); - -impl VariantDef { - pub fn fields(self, db: &dyn HirDatabase) -> Vec { - match self { - VariantDef::Struct(it) => it.fields(db), - VariantDef::Union(it) => it.fields(db), - VariantDef::Variant(it) => it.fields(db), - } - } - - pub fn module(self, db: &dyn HirDatabase) -> Module { - match self { - VariantDef::Struct(it) => it.module(db), - VariantDef::Union(it) => it.module(db), - VariantDef::Variant(it) => it.module(db), - } - } - - pub fn name(&self, db: &dyn HirDatabase) -> Name { - match self { - VariantDef::Struct(s) => s.name(db), - VariantDef::Union(u) => u.name(db), - VariantDef::Variant(e) => e.name(db), - } - } - - pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc { - match self { - VariantDef::Struct(it) => it.variant_data(db), - VariantDef::Union(it) => it.variant_data(db), - VariantDef::Variant(it) => it.variant_data(db), - } - } -} - -/// The defs which have a body. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum DefWithBody { - Function(Function), - Static(Static), - Const(Const), -} -impl_from!(Function, Const, Static for DefWithBody); - -impl DefWithBody { - pub fn module(self, db: &dyn HirDatabase) -> Module { - match self { - DefWithBody::Const(c) => c.module(db), - DefWithBody::Function(f) => f.module(db), - DefWithBody::Static(s) => s.module(db), - } - } - - pub fn name(self, db: &dyn HirDatabase) -> Option { - match self { - DefWithBody::Function(f) => Some(f.name(db)), - DefWithBody::Static(s) => Some(s.name(db)), - DefWithBody::Const(c) => c.name(db), - } - } - - /// Returns the type this def's body has to evaluate to. - pub fn body_type(self, db: &dyn HirDatabase) -> Type { - match self { - DefWithBody::Function(it) => it.ret_type(db), - DefWithBody::Static(it) => it.ty(db), - DefWithBody::Const(it) => it.ty(db), - } - } - - pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec) { - let krate = self.module(db).id.krate(); - - let (body, source_map) = db.body_with_source_map(self.into()); - - for (_, def_map) in body.blocks(db.upcast()) { - for diag in def_map.diagnostics() { - emit_def_diagnostic(db, acc, diag); - } - } - - for diag in source_map.diagnostics() { - match diag { - BodyDiagnostic::InactiveCode { node, cfg, opts } => acc.push( - InactiveCode { node: node.clone(), cfg: cfg.clone(), opts: opts.clone() } - .into(), - ), - BodyDiagnostic::MacroError { node, message } => acc.push( - MacroError { - node: node.clone().map(|it| it.into()), - precise_location: None, - message: message.to_string(), - } - .into(), - ), - BodyDiagnostic::UnresolvedProcMacro { node, krate } => acc.push( - UnresolvedProcMacro { - node: node.clone().map(|it| it.into()), - precise_location: None, - macro_name: None, - kind: MacroKind::ProcMacro, - krate: *krate, - } - .into(), - ), - BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push( - UnresolvedMacroCall { - macro_call: node.clone().map(|ast_ptr| ast_ptr.into()), - precise_location: None, - path: path.clone(), - is_bang: true, - } - .into(), - ), - } - } - - let infer = db.infer(self.into()); - let source_map = Lazy::new(|| db.body_with_source_map(self.into()).1); - for d in &infer.diagnostics { - match d { - hir_ty::InferenceDiagnostic::NoSuchField { expr } => { - let field = source_map.field_syntax(*expr); - acc.push(NoSuchField { field }.into()) - } - hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => { - let expr = source_map - .expr_syntax(*expr) - .expect("break outside of loop in synthetic syntax"); - acc.push(BreakOutsideOfLoop { expr }.into()) - } - hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => { - match source_map.expr_syntax(*call_expr) { - Ok(source_ptr) => acc.push( - MismatchedArgCount { - call_expr: source_ptr, - expected: *expected, - found: *found, - } - .into(), - ), - Err(SyntheticSyntax) => (), - } - } - } - } - for (expr, mismatch) in infer.expr_type_mismatches() { - let expr = match source_map.expr_syntax(expr) { - Ok(expr) => expr, - Err(SyntheticSyntax) => continue, - }; - acc.push( - TypeMismatch { - expr, - expected: Type::new(db, DefWithBodyId::from(self), mismatch.expected.clone()), - actual: Type::new(db, DefWithBodyId::from(self), mismatch.actual.clone()), - } - .into(), - ); - } - - for expr in hir_ty::diagnostics::missing_unsafe(db, self.into()) { - match source_map.expr_syntax(expr) { - Ok(expr) => acc.push(MissingUnsafe { expr }.into()), - Err(SyntheticSyntax) => { - // FIXME: Here and eslwhere in this file, the `expr` was - // desugared, report or assert that this doesn't happen. - } - } - } - - for diagnostic in BodyValidationDiagnostic::collect(db, self.into()) { - match diagnostic { - BodyValidationDiagnostic::RecordMissingFields { - record, - variant, - missed_fields, - } => { - let variant_data = variant.variant_data(db.upcast()); - let missed_fields = missed_fields - .into_iter() - .map(|idx| variant_data.fields()[idx].name.clone()) - .collect(); - - match record { - Either::Left(record_expr) => match source_map.expr_syntax(record_expr) { - Ok(source_ptr) => { - let root = source_ptr.file_syntax(db.upcast()); - if let ast::Expr::RecordExpr(record_expr) = - &source_ptr.value.to_node(&root) - { - if record_expr.record_expr_field_list().is_some() { - acc.push( - MissingFields { - file: source_ptr.file_id, - field_list_parent: Either::Left(AstPtr::new( - record_expr, - )), - field_list_parent_path: record_expr - .path() - .map(|path| AstPtr::new(&path)), - missed_fields, - } - .into(), - ) - } - } - } - Err(SyntheticSyntax) => (), - }, - Either::Right(record_pat) => match source_map.pat_syntax(record_pat) { - Ok(source_ptr) => { - if let Some(expr) = source_ptr.value.as_ref().left() { - let root = source_ptr.file_syntax(db.upcast()); - if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { - if record_pat.record_pat_field_list().is_some() { - acc.push( - MissingFields { - file: source_ptr.file_id, - field_list_parent: Either::Right(AstPtr::new( - &record_pat, - )), - field_list_parent_path: record_pat - .path() - .map(|path| AstPtr::new(&path)), - missed_fields, - } - .into(), - ) - } - } - } - } - Err(SyntheticSyntax) => (), - }, - } - } - BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => { - if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) { - acc.push( - ReplaceFilterMapNextWithFindMap { - file: next_source_ptr.file_id, - next_expr: next_source_ptr.value, - } - .into(), - ); - } - } - BodyValidationDiagnostic::MissingMatchArms { match_expr, uncovered_patterns } => { - match source_map.expr_syntax(match_expr) { - Ok(source_ptr) => { - let root = source_ptr.file_syntax(db.upcast()); - if let ast::Expr::MatchExpr(match_expr) = - &source_ptr.value.to_node(&root) - { - if let Some(match_expr) = match_expr.expr() { - acc.push( - MissingMatchArms { - file: source_ptr.file_id, - match_expr: AstPtr::new(&match_expr), - uncovered_patterns, - } - .into(), - ); - } - } - } - Err(SyntheticSyntax) => (), - } - } - } - } - - let def: ModuleDef = match self { - DefWithBody::Function(it) => it.into(), - DefWithBody::Static(it) => it.into(), - DefWithBody::Const(it) => it.into(), - }; - for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) { - acc.push(diag.into()) - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Function { - pub(crate) id: FunctionId, -} - -impl Function { - pub fn module(self, db: &dyn HirDatabase) -> Module { - self.id.lookup(db.upcast()).module(db.upcast()).into() - } - - pub fn name(self, db: &dyn HirDatabase) -> Name { - db.function_data(self.id).name.clone() - } - - /// Get this function's return type - pub fn ret_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 = callable_sig.ret().clone(); - Type::new_with_resolver_inner(db, &resolver, ty) - } - - pub fn async_ret_type(self, db: &dyn HirDatabase) -> Option { - if !self.is_async(db) { - return None; - } - 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 ret_ty = callable_sig.ret().clone(); - for pred in ret_ty.impl_trait_bounds(db).into_iter().flatten() { - if let WhereClause::AliasEq(output_eq) = pred.into_value_and_skipped_binders().0 { - return Type::new_with_resolver_inner(db, &resolver, output_eq.ty).into(); - } - } - never!("Async fn ret_type should be impl Future"); - None - } - - pub fn has_self_param(self, db: &dyn HirDatabase) -> bool { - db.function_data(self.id).has_self_param() - } - - pub fn self_param(self, db: &dyn HirDatabase) -> Option { - self.has_self_param(db).then(|| SelfParam { func: self.id }) - } - - pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec { - let environment = db.trait_environment(self.id.into()); - let substs = TyBuilder::placeholder_subst(db, self.id); - let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); - callable_sig - .params() - .iter() - .enumerate() - .map(|(idx, ty)| { - let ty = Type { env: environment.clone(), ty: ty.clone() }; - Param { func: self, ty, idx } - }) - .collect() - } - - pub fn method_params(self, db: &dyn HirDatabase) -> Option> { - if self.self_param(db).is_none() { - return None; - } - Some(self.params_without_self(db)) - } - - pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec { - let environment = db.trait_environment(self.id.into()); - let substs = TyBuilder::placeholder_subst(db, self.id); - let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); - let skip = if db.function_data(self.id).has_self_param() { 1 } else { 0 }; - callable_sig - .params() - .iter() - .enumerate() - .skip(skip) - .map(|(idx, ty)| { - let ty = Type { env: environment.clone(), ty: ty.clone() }; - Param { func: self, ty, idx } - }) - .collect() - } - - pub fn is_const(self, db: &dyn HirDatabase) -> bool { - db.function_data(self.id).has_const_kw() - } - - pub fn is_async(self, db: &dyn HirDatabase) -> bool { - db.function_data(self.id).has_async_kw() - } - - pub fn is_unsafe_to_call(self, db: &dyn HirDatabase) -> bool { - hir_ty::is_fn_unsafe_to_call(db, self.id) - } - - /// Whether this function declaration has a definition. - /// - /// This is false in the case of required (not provided) trait methods. - pub fn has_body(self, db: &dyn HirDatabase) -> bool { - db.function_data(self.id).has_body() - } - - pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option { - let function_data = db.function_data(self.id); - let attrs = &function_data.attrs; - // FIXME: Store this in FunctionData flags? - if !(attrs.is_proc_macro() - || attrs.is_proc_macro_attribute() - || attrs.is_proc_macro_derive()) - { - return None; - } - let loc = self.id.lookup(db.upcast()); - let def_map = db.crate_def_map(loc.krate(db).into()); - def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() }) - } - - /// A textual representation of the HIR of this function for debugging purposes. - pub fn debug_hir(self, db: &dyn HirDatabase) -> String { - let body = db.body(self.id.into()); - - let mut result = String::new(); - format_to!(result, "HIR expressions in the body of `{}`:\n", self.name(db)); - for (id, expr) in body.exprs.iter() { - format_to!(result, "{:?}: {:?}\n", id, expr); - } - - result - } -} - -// Note: logically, this belongs to `hir_ty`, but we are not using it there yet. -#[derive(Clone, Copy, PartialEq, Eq)] -pub enum Access { - Shared, - Exclusive, - Owned, -} - -impl From for Access { - fn from(mutability: hir_ty::Mutability) -> Access { - match mutability { - hir_ty::Mutability::Not => Access::Shared, - hir_ty::Mutability::Mut => Access::Exclusive, - } - } -} - -#[derive(Clone, Debug)] -pub struct Param { - func: Function, - /// The index in parameter list, including self parameter. - idx: usize, - ty: Type, -} - -impl Param { - pub fn ty(&self) -> &Type { - &self.ty - } - - pub fn name(&self, db: &dyn HirDatabase) -> Option { - db.function_data(self.func.id).params[self.idx].0.clone() - } - - pub fn as_local(&self, db: &dyn HirDatabase) -> Option { - let parent = DefWithBodyId::FunctionId(self.func.into()); - let body = db.body(parent); - let pat_id = body.params[self.idx]; - if let Pat::Bind { .. } = &body[pat_id] { - Some(Local { parent, pat_id: body.params[self.idx] }) - } else { - None - } - } - - pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option { - self.source(db).and_then(|p| p.value.pat()) - } - - pub fn source(&self, db: &dyn HirDatabase) -> Option> { - let InFile { file_id, value } = self.func.source(db)?; - let params = value.param_list()?; - if params.self_param().is_some() { - params.params().nth(self.idx.checked_sub(1)?) - } else { - params.params().nth(self.idx) - } - .map(|value| InFile { file_id, value }) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct SelfParam { - func: FunctionId, -} - -impl SelfParam { - pub fn access(self, db: &dyn HirDatabase) -> Access { - let func_data = db.function_data(self.func); - func_data - .params - .first() - .map(|(_, param)| match &**param { - TypeRef::Reference(.., mutability) => match mutability { - hir_def::type_ref::Mutability::Shared => Access::Shared, - hir_def::type_ref::Mutability::Mut => Access::Exclusive, - }, - _ => Access::Owned, - }) - .unwrap_or(Access::Owned) - } - - pub fn display(self, db: &dyn HirDatabase) -> &'static str { - match self.access(db) { - Access::Shared => "&self", - Access::Exclusive => "&mut self", - Access::Owned => "self", - } - } - - 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 ty(&self, db: &dyn HirDatabase) -> Type { - let substs = TyBuilder::placeholder_subst(db, self.func); - let callable_sig = - db.callable_item_signature(self.func.into()).substitute(Interner, &substs); - let environment = db.trait_environment(self.func.into()); - let ty = callable_sig.params()[0].clone(); - Type { env: environment, ty } - } -} - -impl HasVisibility for Function { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - db.function_visibility(self.id) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Const { - pub(crate) id: ConstId, -} - -impl Const { - pub fn module(self, db: &dyn HirDatabase) -> Module { - Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } - } - - pub fn name(self, db: &dyn HirDatabase) -> Option { - db.const_data(self.id).name.clone() - } - - pub fn value(self, db: &dyn HirDatabase) -> Option { - self.source(db)?.value.body() - } - - pub fn ty(self, db: &dyn HirDatabase) -> Type { - let data = db.const_data(self.id); - let resolver = self.id.resolver(db.upcast()); - let ctx = hir_ty::TyLoweringContext::new(db, &resolver); - let ty = ctx.lower_ty(&data.type_ref); - Type::new_with_resolver_inner(db, &resolver, ty) - } - - pub fn eval(self, db: &dyn HirDatabase) -> Result { - db.const_eval(self.id) - } -} - -impl HasVisibility for Const { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - db.const_visibility(self.id) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Static { - pub(crate) id: StaticId, -} - -impl Static { - pub fn module(self, db: &dyn HirDatabase) -> Module { - Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } - } - - pub fn name(self, db: &dyn HirDatabase) -> Name { - db.static_data(self.id).name.clone() - } - - pub fn is_mut(self, db: &dyn HirDatabase) -> bool { - db.static_data(self.id).mutable - } - - pub fn value(self, db: &dyn HirDatabase) -> Option { - self.source(db)?.value.body() - } - - pub fn ty(self, db: &dyn HirDatabase) -> Type { - let data = db.static_data(self.id); - let resolver = self.id.resolver(db.upcast()); - let ctx = hir_ty::TyLoweringContext::new(db, &resolver); - let ty = ctx.lower_ty(&data.type_ref); - Type::new_with_resolver_inner(db, &resolver, ty) - } -} - -impl HasVisibility for Static { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - db.static_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Trait { - pub(crate) id: TraitId, -} - -impl Trait { - pub fn lang(db: &dyn HirDatabase, krate: Crate, name: &Name) -> Option { - db.lang_item(krate.into(), name.to_smol_str()) - .and_then(LangItemTarget::as_trait) - .map(Into::into) - } - - pub fn module(self, db: &dyn HirDatabase) -> Module { - Module { id: self.id.lookup(db.upcast()).container } - } - - pub fn name(self, db: &dyn HirDatabase) -> Name { - db.trait_data(self.id).name.clone() - } - - pub fn items(self, db: &dyn HirDatabase) -> Vec { - db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect() - } - - pub fn items_with_supertraits(self, db: &dyn HirDatabase) -> Vec { - let traits = all_super_traits(db.upcast(), self.into()); - traits.iter().flat_map(|tr| Trait::from(*tr).items(db)).collect() - } - - pub fn is_auto(self, db: &dyn HirDatabase) -> bool { - db.trait_data(self.id).is_auto - } - - pub fn is_unsafe(&self, db: &dyn HirDatabase) -> bool { - db.trait_data(self.id).is_unsafe - } - - pub fn type_or_const_param_count( - &self, - db: &dyn HirDatabase, - count_required_only: bool, - ) -> usize { - db.generic_params(GenericDefId::from(self.id)) - .type_or_consts - .iter() - .filter(|(_, ty)| match ty { - TypeOrConstParamData::TypeParamData(ty) - if ty.provenance != TypeParamProvenance::TypeParamList => - { - false - } - _ => true, - }) - .filter(|(_, ty)| !count_required_only || !ty.has_default()) - .count() - } -} - -impl HasVisibility for Trait { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - db.trait_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct TypeAlias { - pub(crate) id: TypeAliasId, -} - -impl TypeAlias { - pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { - let subst = db.generic_defaults(self.id.into()); - subst.iter().any(|ty| match ty.skip_binders().data(Interner) { - GenericArgData::Ty(x) => x.is_unknown(), - _ => false, - }) - } - - pub fn module(self, db: &dyn HirDatabase) -> Module { - Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } - } - - pub fn type_ref(self, db: &dyn HirDatabase) -> Option { - db.type_alias_data(self.id).type_ref.as_deref().cloned() - } - - pub fn ty(self, db: &dyn HirDatabase) -> Type { - Type::from_def(db, self.id) - } - - pub fn name(self, db: &dyn HirDatabase) -> Name { - db.type_alias_data(self.id).name.clone() - } -} - -impl HasVisibility for TypeAlias { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - let function_data = db.type_alias_data(self.id); - let visibility = &function_data.visibility; - visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct BuiltinType { - pub(crate) inner: hir_def::builtin_type::BuiltinType, -} - -impl BuiltinType { - pub fn str() -> BuiltinType { - BuiltinType { inner: hir_def::builtin_type::BuiltinType::Str } - } - - pub fn ty(self, db: &dyn HirDatabase) -> Type { - Type::new_for_crate(db.crate_graph().iter().next().unwrap(), TyBuilder::builtin(self.inner)) - } - - pub fn name(self) -> Name { - self.inner.as_name() - } - - pub fn is_int(&self) -> bool { - matches!(self.inner, hir_def::builtin_type::BuiltinType::Int(_)) - } - - pub fn is_uint(&self) -> bool { - matches!(self.inner, hir_def::builtin_type::BuiltinType::Uint(_)) - } - - pub fn is_float(&self) -> bool { - matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_)) - } - - pub fn is_char(&self) -> bool { - matches!(self.inner, hir_def::builtin_type::BuiltinType::Char) - } - - pub fn is_bool(&self) -> bool { - matches!(self.inner, hir_def::builtin_type::BuiltinType::Bool) - } - - pub fn is_str(&self) -> bool { - matches!(self.inner, hir_def::builtin_type::BuiltinType::Str) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum MacroKind { - /// `macro_rules!` or Macros 2.0 macro. - Declarative, - /// A built-in or custom derive. - Derive, - /// A built-in function-like macro. - BuiltIn, - /// A procedural attribute macro. - Attr, - /// A function-like procedural macro. - ProcMacro, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Macro { - pub(crate) id: MacroId, -} - -impl Macro { - pub fn module(self, db: &dyn HirDatabase) -> Module { - Module { id: self.id.module(db.upcast()) } - } - - pub fn name(self, db: &dyn HirDatabase) -> Name { - match self.id { - MacroId::Macro2Id(id) => db.macro2_data(id).name.clone(), - MacroId::MacroRulesId(id) => db.macro_rules_data(id).name.clone(), - MacroId::ProcMacroId(id) => db.proc_macro_data(id).name.clone(), - } - } - - pub fn is_macro_export(self, db: &dyn HirDatabase) -> bool { - matches!(self.id, MacroId::MacroRulesId(id) if db.macro_rules_data(id).macro_export) - } - - pub fn kind(&self, db: &dyn HirDatabase) -> MacroKind { - match self.id { - MacroId::Macro2Id(it) => match it.lookup(db.upcast()).expander { - MacroExpander::Declarative => MacroKind::Declarative, - MacroExpander::BuiltIn(_) | MacroExpander::BuiltInEager(_) => MacroKind::BuiltIn, - MacroExpander::BuiltInAttr(_) => MacroKind::Attr, - MacroExpander::BuiltInDerive(_) => MacroKind::Derive, - }, - MacroId::MacroRulesId(it) => match it.lookup(db.upcast()).expander { - MacroExpander::Declarative => MacroKind::Declarative, - MacroExpander::BuiltIn(_) | MacroExpander::BuiltInEager(_) => MacroKind::BuiltIn, - MacroExpander::BuiltInAttr(_) => MacroKind::Attr, - MacroExpander::BuiltInDerive(_) => MacroKind::Derive, - }, - MacroId::ProcMacroId(it) => match it.lookup(db.upcast()).kind { - ProcMacroKind::CustomDerive => MacroKind::Derive, - ProcMacroKind::FuncLike => MacroKind::ProcMacro, - ProcMacroKind::Attr => MacroKind::Attr, - }, - } - } - - pub fn is_fn_like(&self, db: &dyn HirDatabase) -> bool { - match self.kind(db) { - MacroKind::Declarative | MacroKind::BuiltIn | MacroKind::ProcMacro => true, - MacroKind::Attr | MacroKind::Derive => false, - } - } - - pub fn is_builtin_derive(&self, db: &dyn HirDatabase) -> bool { - match self.id { - MacroId::Macro2Id(it) => { - matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInDerive(_)) - } - MacroId::MacroRulesId(it) => { - matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInDerive(_)) - } - MacroId::ProcMacroId(_) => false, - } - } - - pub fn is_attr(&self, db: &dyn HirDatabase) -> bool { - matches!(self.kind(db), MacroKind::Attr) - } - - pub fn is_derive(&self, db: &dyn HirDatabase) -> bool { - matches!(self.kind(db), MacroKind::Derive) - } -} - -impl HasVisibility for Macro { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - match self.id { - MacroId::Macro2Id(id) => { - let data = db.macro2_data(id); - let visibility = &data.visibility; - visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) - } - MacroId::MacroRulesId(_) => Visibility::Public, - MacroId::ProcMacroId(_) => Visibility::Public, - } - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] -pub enum ItemInNs { - Types(ModuleDef), - Values(ModuleDef), - Macros(Macro), -} - -impl From for ItemInNs { - fn from(it: Macro) -> Self { - Self::Macros(it) - } -} - -impl From for ItemInNs { - fn from(module_def: ModuleDef) -> Self { - match module_def { - ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => { - ItemInNs::Values(module_def) - } - _ => ItemInNs::Types(module_def), - } - } -} - -impl ItemInNs { - pub fn as_module_def(self) -> Option { - match self { - ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id), - ItemInNs::Macros(_) => None, - } - } - - /// Returns the crate defining this item (or `None` if `self` is built-in). - pub fn krate(&self, db: &dyn HirDatabase) -> Option { - match self { - ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate()), - ItemInNs::Macros(id) => Some(id.module(db).krate()), - } - } - - pub fn attrs(&self, db: &dyn HirDatabase) -> Option { - match self { - ItemInNs::Types(it) | ItemInNs::Values(it) => it.attrs(db), - ItemInNs::Macros(it) => Some(it.attrs(db)), - } - } -} - -/// Invariant: `inner.as_assoc_item(db).is_some()` -/// We do not actively enforce this invariant. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum AssocItem { - Function(Function), - Const(Const), - TypeAlias(TypeAlias), -} -#[derive(Debug)] -pub enum AssocItemContainer { - Trait(Trait), - Impl(Impl), -} -pub trait AsAssocItem { - fn as_assoc_item(self, db: &dyn HirDatabase) -> Option; -} - -impl AsAssocItem for Function { - fn as_assoc_item(self, db: &dyn HirDatabase) -> Option { - as_assoc_item(db, AssocItem::Function, self.id) - } -} -impl AsAssocItem for Const { - fn as_assoc_item(self, db: &dyn HirDatabase) -> Option { - as_assoc_item(db, AssocItem::Const, self.id) - } -} -impl AsAssocItem for TypeAlias { - fn as_assoc_item(self, db: &dyn HirDatabase) -> Option { - as_assoc_item(db, AssocItem::TypeAlias, self.id) - } -} -impl AsAssocItem for ModuleDef { - fn as_assoc_item(self, db: &dyn HirDatabase) -> Option { - match self { - ModuleDef::Function(it) => it.as_assoc_item(db), - ModuleDef::Const(it) => it.as_assoc_item(db), - ModuleDef::TypeAlias(it) => it.as_assoc_item(db), - _ => None, - } - } -} -fn as_assoc_item(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option -where - ID: Lookup>, - DEF: From, - CTOR: FnOnce(DEF) -> AssocItem, - AST: ItemTreeNode, -{ - match id.lookup(db.upcast()).container { - ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))), - ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None, - } -} - -impl AssocItem { - pub fn name(self, db: &dyn HirDatabase) -> Option { - match self { - AssocItem::Function(it) => Some(it.name(db)), - AssocItem::Const(it) => it.name(db), - AssocItem::TypeAlias(it) => Some(it.name(db)), - } - } - pub fn module(self, db: &dyn HirDatabase) -> Module { - match self { - AssocItem::Function(f) => f.module(db), - AssocItem::Const(c) => c.module(db), - AssocItem::TypeAlias(t) => t.module(db), - } - } - pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer { - let container = match self { - AssocItem::Function(it) => it.id.lookup(db.upcast()).container, - AssocItem::Const(it) => it.id.lookup(db.upcast()).container, - AssocItem::TypeAlias(it) => it.id.lookup(db.upcast()).container, - }; - match container { - ItemContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()), - ItemContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()), - ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => { - panic!("invalid AssocItem") - } - } - } - - pub fn containing_trait(self, db: &dyn HirDatabase) -> Option { - match self.container(db) { - AssocItemContainer::Trait(t) => Some(t), - _ => None, - } - } - - pub fn containing_trait_impl(self, db: &dyn HirDatabase) -> Option { - match self.container(db) { - AssocItemContainer::Impl(i) => i.trait_(db), - _ => None, - } - } - - pub fn containing_trait_or_trait_impl(self, db: &dyn HirDatabase) -> Option { - match self.container(db) { - AssocItemContainer::Trait(t) => Some(t), - AssocItemContainer::Impl(i) => i.trait_(db), - } - } -} - -impl HasVisibility for AssocItem { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - match self { - AssocItem::Function(f) => f.visibility(db), - AssocItem::Const(c) => c.visibility(db), - AssocItem::TypeAlias(t) => t.visibility(db), - } - } -} - -impl From for ModuleDef { - fn from(assoc: AssocItem) -> Self { - match assoc { - AssocItem::Function(it) => ModuleDef::Function(it), - AssocItem::Const(it) => ModuleDef::Const(it), - AssocItem::TypeAlias(it) => ModuleDef::TypeAlias(it), - } - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] -pub enum GenericDef { - Function(Function), - Adt(Adt), - Trait(Trait), - TypeAlias(TypeAlias), - Impl(Impl), - // enum variants cannot have generics themselves, but their parent enums - // can, and this makes some code easier to write - Variant(Variant), - // consts can have type parameters from their parents (i.e. associated consts of traits) - Const(Const), -} -impl_from!( - Function, - Adt(Struct, Enum, Union), - Trait, - TypeAlias, - Impl, - Variant, - Const - for GenericDef -); - -impl GenericDef { - pub fn params(self, db: &dyn HirDatabase) -> Vec { - let generics = db.generic_params(self.into()); - let ty_params = generics.type_or_consts.iter().map(|(local_id, _)| { - let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } }; - match toc.split(db) { - Either::Left(x) => GenericParam::ConstParam(x), - Either::Right(x) => GenericParam::TypeParam(x), - } - }); - let lt_params = generics - .lifetimes - .iter() - .map(|(local_id, _)| LifetimeParam { - id: LifetimeParamId { parent: self.into(), local_id }, - }) - .map(GenericParam::LifetimeParam); - lt_params.chain(ty_params).collect() - } - - pub fn type_params(self, db: &dyn HirDatabase) -> Vec { - let generics = db.generic_params(self.into()); - generics - .type_or_consts - .iter() - .map(|(local_id, _)| TypeOrConstParam { - id: TypeOrConstParamId { parent: self.into(), local_id }, - }) - .collect() - } -} - -/// A single local definition. -/// -/// If the definition of this is part of a "MultiLocal", that is a local that has multiple declarations due to or-patterns -/// then this only references a single one of those. -/// To retrieve the other locals you should use [`Local::associated_locals`] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct Local { - pub(crate) parent: DefWithBodyId, - pub(crate) pat_id: PatId, -} - -impl Local { - pub fn is_param(self, db: &dyn HirDatabase) -> bool { - let src = self.source(db); - match src.value { - Either::Left(pat) => pat - .syntax() - .ancestors() - .map(|it| it.kind()) - .take_while(|&kind| ast::Pat::can_cast(kind) || ast::Param::can_cast(kind)) - .any(ast::Param::can_cast), - Either::Right(_) => true, - } - } - - pub fn as_self_param(self, db: &dyn HirDatabase) -> Option { - match self.parent { - DefWithBodyId::FunctionId(func) if self.is_self(db) => Some(SelfParam { func }), - _ => None, - } - } - - pub fn name(self, db: &dyn HirDatabase) -> Name { - let body = db.body(self.parent); - match &body[self.pat_id] { - Pat::Bind { name, .. } => name.clone(), - _ => { - stdx::never!("hir::Local is missing a name!"); - Name::missing() - } - } - } - - pub fn is_self(self, db: &dyn HirDatabase) -> bool { - self.name(db) == name![self] - } - - pub fn is_mut(self, db: &dyn HirDatabase) -> bool { - let body = db.body(self.parent); - matches!(&body[self.pat_id], Pat::Bind { mode: BindingAnnotation::Mutable, .. }) - } - - pub fn is_ref(self, db: &dyn HirDatabase) -> bool { - let body = db.body(self.parent); - matches!( - &body[self.pat_id], - Pat::Bind { mode: BindingAnnotation::Ref | BindingAnnotation::RefMut, .. } - ) - } - - pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { - self.parent.into() - } - - pub fn module(self, db: &dyn HirDatabase) -> Module { - self.parent(db).module(db) - } - - pub fn ty(self, db: &dyn HirDatabase) -> Type { - let def = self.parent; - let infer = db.infer(def); - let ty = infer[self.pat_id].clone(); - Type::new(db, def, ty) - } - - pub fn associated_locals(self, db: &dyn HirDatabase) -> Box<[Local]> { - let body = db.body(self.parent); - body.ident_patterns_for(&self.pat_id) - .iter() - .map(|&pat_id| Local { parent: self.parent, pat_id }) - .collect() - } - - /// If this local is part of a multi-local, retrieve the representative local. - /// That is the local that references are being resolved to. - pub fn representative(self, db: &dyn HirDatabase) -> Local { - let body = db.body(self.parent); - Local { pat_id: body.pattern_representative(self.pat_id), ..self } - } - - pub fn source(self, db: &dyn HirDatabase) -> InFile> { - let (_body, source_map) = db.body_with_source_map(self.parent); - let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm... - let root = src.file_syntax(db.upcast()); - src.map(|ast| match ast { - // Suspicious unwrap - Either::Left(it) => Either::Left(it.cast().unwrap().to_node(&root)), - Either::Right(it) => Either::Right(it.to_node(&root)), - }) - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DeriveHelper { - pub(crate) derive: MacroId, - pub(crate) idx: usize, -} - -impl DeriveHelper { - pub fn derive(&self) -> Macro { - Macro { id: self.derive.into() } - } - - pub fn name(&self, db: &dyn HirDatabase) -> Name { - match self.derive { - MacroId::Macro2Id(_) => None, - MacroId::MacroRulesId(_) => None, - MacroId::ProcMacroId(proc_macro) => db - .proc_macro_data(proc_macro) - .helpers - .as_ref() - .and_then(|it| it.get(self.idx)) - .cloned(), - } - .unwrap_or_else(|| Name::missing()) - } -} - -// FIXME: Wrong name? This is could also be a registered attribute -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BuiltinAttr { - krate: Option, - idx: usize, -} - -impl BuiltinAttr { - // FIXME: consider crates\hir_def\src\nameres\attr_resolution.rs? - pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option { - if let builtin @ Some(_) = Self::builtin(name) { - return builtin; - } - let idx = db.crate_def_map(krate.id).registered_attrs().iter().position(|it| it == name)?; - Some(BuiltinAttr { krate: Some(krate.id), idx }) - } - - fn builtin(name: &str) -> Option { - hir_def::builtin_attr::INERT_ATTRIBUTES - .iter() - .position(|tool| tool.name == name) - .map(|idx| BuiltinAttr { krate: None, idx }) - } - - pub fn name(&self, db: &dyn HirDatabase) -> SmolStr { - // FIXME: Return a `Name` here - match self.krate { - Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx].clone(), - None => SmolStr::new(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].name), - } - } - - pub fn template(&self, _: &dyn HirDatabase) -> Option { - match self.krate { - Some(_) => None, - None => Some(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].template), - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct ToolModule { - krate: Option, - idx: usize, -} - -impl ToolModule { - // FIXME: consider crates\hir_def\src\nameres\attr_resolution.rs? - pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option { - if let builtin @ Some(_) = Self::builtin(name) { - return builtin; - } - let idx = db.crate_def_map(krate.id).registered_tools().iter().position(|it| it == name)?; - Some(ToolModule { krate: Some(krate.id), idx }) - } - - fn builtin(name: &str) -> Option { - hir_def::builtin_attr::TOOL_MODULES - .iter() - .position(|&tool| tool == name) - .map(|idx| ToolModule { krate: None, idx }) - } - - pub fn name(&self, db: &dyn HirDatabase) -> SmolStr { - // FIXME: Return a `Name` here - match self.krate { - Some(krate) => db.crate_def_map(krate).registered_tools()[self.idx].clone(), - None => SmolStr::new(hir_def::builtin_attr::TOOL_MODULES[self.idx]), - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct Label { - pub(crate) parent: DefWithBodyId, - pub(crate) label_id: LabelId, -} - -impl Label { - pub fn module(self, db: &dyn HirDatabase) -> Module { - self.parent(db).module(db) - } - - pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { - self.parent.into() - } - - pub fn name(self, db: &dyn HirDatabase) -> Name { - 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)] -pub enum GenericParam { - TypeParam(TypeParam), - ConstParam(ConstParam), - LifetimeParam(LifetimeParam), -} -impl_from!(TypeParam, ConstParam, LifetimeParam for GenericParam); - -impl GenericParam { - pub fn module(self, db: &dyn HirDatabase) -> Module { - match self { - GenericParam::TypeParam(it) => it.module(db), - GenericParam::ConstParam(it) => it.module(db), - GenericParam::LifetimeParam(it) => it.module(db), - } - } - - pub fn name(self, db: &dyn HirDatabase) -> Name { - match self { - GenericParam::TypeParam(it) => it.name(db), - GenericParam::ConstParam(it) => it.name(db), - GenericParam::LifetimeParam(it) => it.name(db), - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct TypeParam { - pub(crate) id: TypeParamId, -} - -impl TypeParam { - pub fn merge(self) -> TypeOrConstParam { - TypeOrConstParam { id: self.id.into() } - } - - pub fn name(self, db: &dyn HirDatabase) -> Name { - self.merge().name(db) - } - - pub fn module(self, db: &dyn HirDatabase) -> Module { - self.id.parent().module(db.upcast()).into() - } - - /// Is this type parameter implicitly introduced (eg. `Self` in a trait or an `impl Trait` - /// argument)? - pub fn is_implicit(self, db: &dyn HirDatabase) -> bool { - let params = db.generic_params(self.id.parent()); - let data = ¶ms.type_or_consts[self.id.local_id()]; - match data.type_param().unwrap().provenance { - hir_def::generics::TypeParamProvenance::TypeParamList => false, - hir_def::generics::TypeParamProvenance::TraitSelf - | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => true, - } - } - - pub fn ty(self, db: &dyn HirDatabase) -> Type { - let resolver = self.id.parent().resolver(db.upcast()); - let ty = - TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id.into())).intern(Interner); - Type::new_with_resolver_inner(db, &resolver, ty) - } - - /// FIXME: this only lists trait bounds from the item defining the type - /// parameter, not additional bounds that might be added e.g. by a method if - /// the parameter comes from an impl! - pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec { - db.generic_predicates_for_param(self.id.parent(), self.id.into(), None) - .iter() - .filter_map(|pred| match &pred.skip_binders().skip_binders() { - hir_ty::WhereClause::Implemented(trait_ref) => { - Some(Trait::from(trait_ref.hir_trait_id())) - } - _ => None, - }) - .collect() - } - - pub fn default(self, db: &dyn HirDatabase) -> Option { - let params = db.generic_defaults(self.id.parent()); - let local_idx = hir_ty::param_idx(db, self.id.into())?; - let resolver = self.id.parent().resolver(db.upcast()); - let ty = params.get(local_idx)?.clone(); - let subst = TyBuilder::placeholder_subst(db, self.id.parent()); - let ty = ty.substitute(Interner, &subst_prefix(&subst, local_idx)); - match ty.data(Interner) { - GenericArgData::Ty(x) => Some(Type::new_with_resolver_inner(db, &resolver, x.clone())), - _ => None, - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LifetimeParam { - pub(crate) id: LifetimeParamId, -} - -impl LifetimeParam { - pub fn name(self, db: &dyn HirDatabase) -> Name { - let params = db.generic_params(self.id.parent); - params.lifetimes[self.id.local_id].name.clone() - } - - pub fn module(self, db: &dyn HirDatabase) -> Module { - self.id.parent.module(db.upcast()).into() - } - - pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { - self.id.parent.into() - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct ConstParam { - pub(crate) id: ConstParamId, -} - -impl ConstParam { - pub fn merge(self) -> TypeOrConstParam { - TypeOrConstParam { id: self.id.into() } - } - - pub fn name(self, db: &dyn HirDatabase) -> Name { - let params = db.generic_params(self.id.parent()); - match params.type_or_consts[self.id.local_id()].name() { - Some(x) => x.clone(), - None => { - never!(); - Name::missing() - } - } - } - - pub fn module(self, db: &dyn HirDatabase) -> Module { - self.id.parent().module(db.upcast()).into() - } - - pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { - self.id.parent().into() - } - - pub fn ty(self, db: &dyn HirDatabase) -> Type { - Type::new(db, self.id.parent(), db.const_param_ty(self.id)) - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct TypeOrConstParam { - pub(crate) id: TypeOrConstParamId, -} - -impl TypeOrConstParam { - pub fn name(self, db: &dyn HirDatabase) -> Name { - let params = db.generic_params(self.id.parent); - match params.type_or_consts[self.id.local_id].name() { - Some(n) => n.clone(), - _ => Name::missing(), - } - } - - pub fn module(self, db: &dyn HirDatabase) -> Module { - self.id.parent.module(db.upcast()).into() - } - - pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { - self.id.parent.into() - } - - pub fn split(self, db: &dyn HirDatabase) -> Either { - let params = db.generic_params(self.id.parent); - match ¶ms.type_or_consts[self.id.local_id] { - hir_def::generics::TypeOrConstParamData::TypeParamData(_) => { - Either::Right(TypeParam { id: TypeParamId::from_unchecked(self.id) }) - } - hir_def::generics::TypeOrConstParamData::ConstParamData(_) => { - Either::Left(ConstParam { id: ConstParamId::from_unchecked(self.id) }) - } - } - } - - pub fn ty(self, db: &dyn HirDatabase) -> Type { - match self.split(db) { - Either::Left(x) => x.ty(db), - Either::Right(x) => x.ty(db), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Impl { - pub(crate) id: ImplId, -} - -impl Impl { - pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec { - let inherent = db.inherent_impls_in_crate(krate.id); - let trait_ = db.trait_impls_in_crate(krate.id); - - inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect() - } - - pub fn all_for_type(db: &dyn HirDatabase, Type { ty, env }: Type) -> Vec { - let def_crates = match method_resolution::def_crates(db, &ty, env.krate) { - Some(def_crates) => def_crates, - None => return Vec::new(), - }; - - let filter = |impl_def: &Impl| { - let self_ty = impl_def.self_ty(db); - let rref = self_ty.remove_ref(); - ty.equals_ctor(rref.as_ref().map_or(&self_ty.ty, |it| &it.ty)) - }; - - let fp = TyFingerprint::for_inherent_impl(&ty); - let fp = match fp { - Some(fp) => fp, - None => return Vec::new(), - }; - - let mut all = Vec::new(); - def_crates.iter().for_each(|&id| { - all.extend( - db.inherent_impls_in_crate(id) - .for_self_ty(&ty) - .iter() - .cloned() - .map(Self::from) - .filter(filter), - ) - }); - for id in def_crates - .iter() - .flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db)) - .map(|Crate { id }| id) - .chain(def_crates.iter().copied()) - .unique() - { - all.extend( - db.trait_impls_in_crate(id) - .for_self_ty_without_blanket_impls(fp) - .map(Self::from) - .filter(filter), - ); - } - all - } - - pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec { - let krate = trait_.module(db).krate(); - let mut all = Vec::new(); - for Crate { id } in krate.transitive_reverse_dependencies(db).into_iter() { - let impls = db.trait_impls_in_crate(id); - all.extend(impls.for_trait(trait_.id).map(Self::from)) - } - all - } - - // FIXME: the return type is wrong. This should be a hir version of - // `TraitRef` (to account for parameters and qualifiers) - pub fn trait_(self, db: &dyn HirDatabase) -> Option { - let trait_ref = db.impl_trait(self.id)?.skip_binders().clone(); - let id = hir_ty::from_chalk_trait_id(trait_ref.trait_id); - Some(Trait { id }) - } - - pub fn self_ty(self, db: &dyn HirDatabase) -> Type { - let resolver = self.id.resolver(db.upcast()); - let substs = TyBuilder::placeholder_subst(db, self.id); - let ty = db.impl_self_ty(self.id).substitute(Interner, &substs); - Type::new_with_resolver_inner(db, &resolver, ty) - } - - pub fn items(self, db: &dyn HirDatabase) -> Vec { - db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect() - } - - pub fn is_negative(self, db: &dyn HirDatabase) -> bool { - db.impl_data(self.id).is_negative - } - - pub fn module(self, db: &dyn HirDatabase) -> Module { - self.id.lookup(db.upcast()).container.into() - } - - pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option> { - let src = self.source(db)?; - src.file_id.is_builtin_derive(db.upcast()) - } -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct Type { - env: Arc, - ty: Ty, -} - -impl Type { - pub(crate) fn new_with_resolver(db: &dyn HirDatabase, resolver: &Resolver, ty: Ty) -> Type { - Type::new_with_resolver_inner(db, resolver, ty) - } - - pub(crate) fn new_with_resolver_inner( - db: &dyn HirDatabase, - resolver: &Resolver, - ty: Ty, - ) -> Type { - let environment = resolver.generic_def().map_or_else( - || Arc::new(TraitEnvironment::empty(resolver.krate())), - |d| db.trait_environment(d), - ); - Type { env: environment, ty } - } - - pub(crate) fn new_for_crate(krate: CrateId, ty: Ty) -> Type { - Type { env: Arc::new(TraitEnvironment::empty(krate)), ty } - } - - pub fn reference(inner: &Type, m: Mutability) -> Type { - inner.derived( - TyKind::Ref( - if m.is_mut() { hir_ty::Mutability::Mut } else { hir_ty::Mutability::Not }, - hir_ty::static_lifetime(), - inner.ty.clone(), - ) - .intern(Interner), - ) - } - - fn new(db: &dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty) -> Type { - let resolver = lexical_env.resolver(db.upcast()); - let environment = resolver.generic_def().map_or_else( - || Arc::new(TraitEnvironment::empty(resolver.krate())), - |d| db.trait_environment(d), - ); - Type { env: environment, ty } - } - - fn from_def(db: &dyn HirDatabase, def: impl HasResolver + Into) -> Type { - let ty = TyBuilder::def_ty(db, def.into()).fill_with_unknown().build(); - Type::new(db, def, ty) - } - - pub fn new_slice(ty: Type) -> Type { - Type { env: ty.env, ty: TyBuilder::slice(ty.ty) } - } - - pub fn is_unit(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Tuple(0, ..)) - } - - pub fn is_bool(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Bool)) - } - - pub fn is_never(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Never) - } - - pub fn is_mutable_reference(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..)) - } - - pub fn is_reference(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Ref(..)) - } - - pub fn as_reference(&self) -> Option<(Type, Mutability)> { - let (ty, _lt, m) = self.ty.as_reference()?; - let m = Mutability::from_mutable(matches!(m, hir_ty::Mutability::Mut)); - Some((self.derived(ty.clone()), m)) - } - - pub fn is_slice(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Slice(..)) - } - - pub fn is_usize(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize))) - } - - pub fn remove_ref(&self) -> Option { - match &self.ty.kind(Interner) { - TyKind::Ref(.., ty) => Some(self.derived(ty.clone())), - _ => None, - } - } - - pub fn strip_references(&self) -> Type { - self.derived(self.ty.strip_references().clone()) - } - - pub fn is_unknown(&self) -> bool { - self.ty.is_unknown() - } - - /// Checks that particular type `ty` implements `std::future::Future`. - /// This function is used in `.await` syntax completion. - pub fn impls_future(&self, db: &dyn HirDatabase) -> bool { - let std_future_trait = db - .lang_item(self.env.krate, SmolStr::new_inline("future_trait")) - .and_then(|it| it.as_trait()); - let std_future_trait = match std_future_trait { - Some(it) => it, - None => return false, - }; - - let canonical_ty = - Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; - method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), std_future_trait) - } - - /// Checks that particular type `ty` implements `std::ops::FnOnce`. - /// - /// This function can be used to check if a particular type is callable, since FnOnce is a - /// supertrait of Fn and FnMut, so all callable types implements at least FnOnce. - pub fn impls_fnonce(&self, db: &dyn HirDatabase) -> bool { - let fnonce_trait = match FnTrait::FnOnce.get_id(db, self.env.krate) { - Some(it) => it, - None => return false, - }; - - let canonical_ty = - Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; - method_resolution::implements_trait_unique( - &canonical_ty, - db, - self.env.clone(), - fnonce_trait, - ) - } - - pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool { - let mut it = args.iter().map(|t| t.ty.clone()); - let trait_ref = TyBuilder::trait_ref(db, trait_.id) - .push(self.ty.clone()) - .fill(|x| { - let r = it.next().unwrap(); - match x { - ParamKind::Type => GenericArgData::Ty(r).intern(Interner), - ParamKind::Const(ty) => { - // FIXME: this code is not covered in tests. - unknown_const_as_generic(ty.clone()) - } - } - }) - .build(); - - let goal = Canonical { - value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(Interner)), - binders: CanonicalVarKinds::empty(Interner), - }; - - db.trait_solve(self.env.krate, goal).is_some() - } - - pub fn normalize_trait_assoc_type( - &self, - db: &dyn HirDatabase, - args: &[Type], - alias: TypeAlias, - ) -> Option { - let mut args = args.iter(); - let projection = TyBuilder::assoc_type_projection(db, alias.id) - .push(self.ty.clone()) - .fill(|x| { - // FIXME: this code is not covered in tests. - match x { - ParamKind::Type => { - GenericArgData::Ty(args.next().unwrap().ty.clone()).intern(Interner) - } - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), - } - }) - .build(); - let goal = hir_ty::make_canonical( - InEnvironment::new( - &self.env.env, - AliasEq { - alias: AliasTy::Projection(projection), - ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)) - .intern(Interner), - } - .cast(Interner), - ), - [TyVariableKind::General].into_iter(), - ); - - match db.trait_solve(self.env.krate, goal)? { - Solution::Unique(s) => s - .value - .subst - .as_slice(Interner) - .first() - .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone())), - Solution::Ambig(_) => None, - } - } - - pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { - let lang_item = db.lang_item(self.env.krate, SmolStr::new_inline("copy")); - let copy_trait = match lang_item { - Some(LangItemTarget::TraitId(it)) => it, - _ => return false, - }; - self.impls_trait(db, copy_trait.into(), &[]) - } - - pub fn as_callable(&self, db: &dyn HirDatabase) -> Option { - let callee = match self.ty.kind(Interner) { - TyKind::Closure(id, _) => Callee::Closure(*id), - TyKind::Function(_) => Callee::FnPtr, - _ => Callee::Def(self.ty.callable_def(db)?), - }; - - let sig = self.ty.callable_sig(db)?; - Some(Callable { ty: self.clone(), sig, callee, is_bound_method: false }) - } - - pub fn is_closure(&self) -> bool { - matches!(&self.ty.kind(Interner), TyKind::Closure { .. }) - } - - pub fn is_fn(&self) -> bool { - matches!(&self.ty.kind(Interner), TyKind::FnDef(..) | TyKind::Function { .. }) - } - - pub fn is_array(&self) -> bool { - matches!(&self.ty.kind(Interner), TyKind::Array(..)) - } - - pub fn is_packed(&self, db: &dyn HirDatabase) -> bool { - let adt_id = match *self.ty.kind(Interner) { - TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id, - _ => return false, - }; - - let adt = adt_id.into(); - match adt { - Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)), - _ => false, - } - } - - pub fn is_raw_ptr(&self) -> bool { - matches!(&self.ty.kind(Interner), TyKind::Raw(..)) - } - - pub fn contains_unknown(&self) -> bool { - return go(&self.ty); - - fn go(ty: &Ty) -> bool { - match ty.kind(Interner) { - TyKind::Error => true, - - TyKind::Adt(_, substs) - | TyKind::AssociatedType(_, substs) - | TyKind::Tuple(_, substs) - | TyKind::OpaqueType(_, substs) - | TyKind::FnDef(_, substs) - | TyKind::Closure(_, substs) => { - substs.iter(Interner).filter_map(|a| a.ty(Interner)).any(go) - } - - TyKind::Array(_ty, len) if len.is_unknown() => true, - TyKind::Array(ty, _) - | TyKind::Slice(ty) - | TyKind::Raw(_, ty) - | TyKind::Ref(_, _, ty) => go(ty), - - TyKind::Scalar(_) - | TyKind::Str - | TyKind::Never - | TyKind::Placeholder(_) - | TyKind::BoundVar(_) - | TyKind::InferenceVar(_, _) - | TyKind::Dyn(_) - | TyKind::Function(_) - | TyKind::Alias(_) - | TyKind::Foreign(_) - | TyKind::Generator(..) - | TyKind::GeneratorWitness(..) => false, - } - } - } - - pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> { - let (variant_id, substs) = match self.ty.kind(Interner) { - TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), substs) => ((*s).into(), substs), - TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), substs) => ((*u).into(), substs), - _ => return Vec::new(), - }; - - db.field_types(variant_id) - .iter() - .map(|(local_id, ty)| { - let def = Field { parent: variant_id.into(), id: local_id }; - let ty = ty.clone().substitute(Interner, substs); - (def, self.derived(ty)) - }) - .collect() - } - - pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec { - if let TyKind::Tuple(_, substs) = &self.ty.kind(Interner) { - substs - .iter(Interner) - .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone())) - .collect() - } else { - Vec::new() - } - } - - pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator + 'a { - self.autoderef_(db).map(move |ty| self.derived(ty)) - } - - fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator + 'a { - // There should be no inference vars in types passed here - let canonical = hir_ty::replace_errors_with_variables(&self.ty); - let environment = self.env.clone(); - autoderef(db, environment, canonical).map(|canonical| canonical.value) - } - - // This would be nicer if it just returned an iterator, but that runs into - // lifetime problems, because we need to borrow temp `CrateImplDefs`. - pub fn iterate_assoc_items( - &self, - db: &dyn HirDatabase, - krate: Crate, - mut callback: impl FnMut(AssocItem) -> Option, - ) -> Option { - let mut slot = None; - self.iterate_assoc_items_dyn(db, krate, &mut |assoc_item_id| { - slot = callback(assoc_item_id.into()); - slot.is_some() - }); - slot - } - - fn iterate_assoc_items_dyn( - &self, - db: &dyn HirDatabase, - krate: Crate, - callback: &mut dyn FnMut(AssocItemId) -> bool, - ) { - let def_crates = match method_resolution::def_crates(db, &self.ty, krate.id) { - Some(it) => it, - None => return, - }; - for krate in def_crates { - let impls = db.inherent_impls_in_crate(krate); - - for impl_def in impls.for_self_ty(&self.ty) { - for &item in db.impl_data(*impl_def).items.iter() { - if callback(item) { - return; - } - } - } - } - } - - pub fn type_arguments(&self) -> impl Iterator + '_ { - self.ty - .strip_references() - .as_adt() - .into_iter() - .flat_map(|(_, substs)| substs.iter(Interner)) - .filter_map(|arg| arg.ty(Interner).cloned()) - .map(move |ty| self.derived(ty)) - } - - pub fn iterate_method_candidates( - &self, - db: &dyn HirDatabase, - scope: &SemanticsScope<'_>, - // FIXME this can be retrieved from `scope`, except autoimport uses this - // to specify a different set, so the method needs to be split - traits_in_scope: &FxHashSet, - with_local_impls: Option, - name: Option<&Name>, - mut callback: impl FnMut(Function) -> Option, - ) -> Option { - let _p = profile::span("iterate_method_candidates"); - let mut slot = None; - - self.iterate_method_candidates_dyn( - db, - scope, - traits_in_scope, - with_local_impls, - name, - &mut |assoc_item_id| { - if let AssocItemId::FunctionId(func) = assoc_item_id { - if let Some(res) = callback(func.into()) { - slot = Some(res); - return ControlFlow::Break(()); - } - } - ControlFlow::Continue(()) - }, - ); - slot - } - - fn iterate_method_candidates_dyn( - &self, - db: &dyn HirDatabase, - scope: &SemanticsScope<'_>, - traits_in_scope: &FxHashSet, - with_local_impls: Option, - name: Option<&Name>, - callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>, - ) { - // There should be no inference vars in types passed here - let canonical = hir_ty::replace_errors_with_variables(&self.ty); - - let krate = scope.krate(); - let environment = scope.resolver().generic_def().map_or_else( - || Arc::new(TraitEnvironment::empty(krate.id)), - |d| db.trait_environment(d), - ); - - method_resolution::iterate_method_candidates_dyn( - &canonical, - db, - environment, - traits_in_scope, - with_local_impls.and_then(|b| b.id.containing_block()).into(), - name, - method_resolution::LookupMode::MethodCall, - &mut |_adj, id| callback(id), - ); - } - - pub fn iterate_path_candidates( - &self, - db: &dyn HirDatabase, - scope: &SemanticsScope<'_>, - traits_in_scope: &FxHashSet, - with_local_impls: Option, - name: Option<&Name>, - mut callback: impl FnMut(AssocItem) -> Option, - ) -> Option { - let _p = profile::span("iterate_path_candidates"); - let mut slot = None; - self.iterate_path_candidates_dyn( - db, - scope, - traits_in_scope, - with_local_impls, - name, - &mut |assoc_item_id| { - if let Some(res) = callback(assoc_item_id.into()) { - slot = Some(res); - return ControlFlow::Break(()); - } - ControlFlow::Continue(()) - }, - ); - slot - } - - fn iterate_path_candidates_dyn( - &self, - db: &dyn HirDatabase, - scope: &SemanticsScope<'_>, - traits_in_scope: &FxHashSet, - with_local_impls: Option, - name: Option<&Name>, - callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>, - ) { - let canonical = hir_ty::replace_errors_with_variables(&self.ty); - - let krate = scope.krate(); - let environment = scope.resolver().generic_def().map_or_else( - || Arc::new(TraitEnvironment::empty(krate.id)), - |d| db.trait_environment(d), - ); - - method_resolution::iterate_path_candidates( - &canonical, - db, - environment, - traits_in_scope, - with_local_impls.and_then(|b| b.id.containing_block()).into(), - name, - &mut |id| callback(id), - ); - } - - pub fn as_adt(&self) -> Option { - let (adt, _subst) = self.ty.as_adt()?; - Some(adt.into()) - } - - pub fn as_builtin(&self) -> Option { - self.ty.as_builtin().map(|inner| BuiltinType { inner }) - } - - pub fn as_dyn_trait(&self) -> Option { - self.ty.dyn_trait().map(Into::into) - } - - /// If a type can be represented as `dyn Trait`, returns all traits accessible via this type, - /// or an empty iterator otherwise. - pub fn applicable_inherent_traits<'a>( - &'a self, - db: &'a dyn HirDatabase, - ) -> impl Iterator + 'a { - let _p = profile::span("applicable_inherent_traits"); - 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)) - .map(Trait::from) - } - - pub fn env_traits<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator + 'a { - let _p = profile::span("env_traits"); - self.autoderef_(db) - .filter(|ty| matches!(ty.kind(Interner), TyKind::Placeholder(_))) - .flat_map(|ty| { - self.env - .traits_in_scope_from_clauses(ty) - .flat_map(|t| hir_ty::all_super_traits(db.upcast(), t)) - }) - .map(Trait::from) - } - - pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option> { - self.ty.impl_trait_bounds(db).map(|it| { - it.into_iter().filter_map(|pred| match pred.skip_binders() { - hir_ty::WhereClause::Implemented(trait_ref) => { - Some(Trait::from(trait_ref.hir_trait_id())) - } - _ => None, - }) - }) - } - - pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option { - self.ty.associated_type_parent_trait(db).map(Into::into) - } - - fn derived(&self, ty: Ty) -> Type { - Type { env: self.env.clone(), ty } - } - - pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) { - // TypeWalk::walk for a Ty at first visits parameters and only after that the Ty itself. - // We need a different order here. - - fn walk_substs( - db: &dyn HirDatabase, - type_: &Type, - substs: &Substitution, - cb: &mut impl FnMut(Type), - ) { - for ty in substs.iter(Interner).filter_map(|a| a.ty(Interner)) { - walk_type(db, &type_.derived(ty.clone()), cb); - } - } - - fn walk_bounds( - db: &dyn HirDatabase, - type_: &Type, - bounds: &[QuantifiedWhereClause], - cb: &mut impl FnMut(Type), - ) { - for pred in bounds { - if let WhereClause::Implemented(trait_ref) = pred.skip_binders() { - cb(type_.clone()); - // skip the self type. it's likely the type we just got the bounds from - for ty in - trait_ref.substitution.iter(Interner).skip(1).filter_map(|a| a.ty(Interner)) - { - walk_type(db, &type_.derived(ty.clone()), cb); - } - } - } - } - - fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) { - let ty = type_.ty.strip_references(); - match ty.kind(Interner) { - TyKind::Adt(_, substs) => { - cb(type_.derived(ty.clone())); - walk_substs(db, type_, substs, cb); - } - TyKind::AssociatedType(_, substs) => { - if ty.associated_type_parent_trait(db).is_some() { - cb(type_.derived(ty.clone())); - } - walk_substs(db, type_, substs, cb); - } - TyKind::OpaqueType(_, subst) => { - if let Some(bounds) = ty.impl_trait_bounds(db) { - walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); - } - - walk_substs(db, type_, subst, cb); - } - TyKind::Alias(AliasTy::Opaque(opaque_ty)) => { - if let Some(bounds) = ty.impl_trait_bounds(db) { - walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); - } - - walk_substs(db, type_, &opaque_ty.substitution, cb); - } - TyKind::Placeholder(_) => { - if let Some(bounds) = ty.impl_trait_bounds(db) { - walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); - } - } - TyKind::Dyn(bounds) => { - walk_bounds( - db, - &type_.derived(ty.clone()), - bounds.bounds.skip_binders().interned(), - cb, - ); - } - - TyKind::Ref(_, _, ty) - | TyKind::Raw(_, ty) - | TyKind::Array(ty, _) - | TyKind::Slice(ty) => { - walk_type(db, &type_.derived(ty.clone()), cb); - } - - TyKind::FnDef(_, substs) - | TyKind::Tuple(_, substs) - | TyKind::Closure(.., substs) => { - walk_substs(db, type_, substs, cb); - } - TyKind::Function(hir_ty::FnPointer { substitution, .. }) => { - walk_substs(db, type_, &substitution.0, cb); - } - - _ => {} - } - } - - walk_type(db, self, &mut cb); - } - - pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool { - let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone())); - hir_ty::could_unify(db, self.env.clone(), &tys) - } - - pub fn could_coerce_to(&self, db: &dyn HirDatabase, to: &Type) -> bool { - let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), to.ty.clone())); - hir_ty::could_coerce(db, self.env.clone(), &tys) - } - - pub fn as_type_param(&self, db: &dyn HirDatabase) -> Option { - match self.ty.kind(Interner) { - TyKind::Placeholder(p) => Some(TypeParam { - id: TypeParamId::from_unchecked(hir_ty::from_placeholder_idx(db, *p)), - }), - _ => None, - } - } -} - -#[derive(Debug)] -pub struct Callable { - ty: Type, - sig: CallableSig, - callee: Callee, - pub(crate) is_bound_method: bool, -} - -#[derive(Debug)] -enum Callee { - Def(CallableDefId), - Closure(ClosureId), - FnPtr, -} - -pub enum CallableKind { - Function(Function), - TupleStruct(Struct), - TupleEnumVariant(Variant), - Closure, - FnPtr, -} - -impl Callable { - pub fn kind(&self) -> CallableKind { - use Callee::*; - match self.callee { - Def(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()), - Def(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()), - Def(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()), - Closure(_) => CallableKind::Closure, - FnPtr => CallableKind::FnPtr, - } - } - pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option { - let func = match self.callee { - Callee::Def(CallableDefId::FunctionId(it)) if self.is_bound_method => it, - _ => return None, - }; - let src = func.lookup(db.upcast()).source(db.upcast()); - let param_list = src.value.param_list()?; - param_list.self_param() - } - pub fn n_params(&self) -> usize { - self.sig.params().len() - if self.is_bound_method { 1 } else { 0 } - } - pub fn params( - &self, - db: &dyn HirDatabase, - ) -> Vec<(Option>, Type)> { - let types = self - .sig - .params() - .iter() - .skip(if self.is_bound_method { 1 } else { 0 }) - .map(|ty| self.ty.derived(ty.clone())); - let map_param = |it: ast::Param| it.pat().map(Either::Right); - let patterns = match self.callee { - Callee::Def(CallableDefId::FunctionId(func)) => { - let src = func.lookup(db.upcast()).source(db.upcast()); - src.value.param_list().map(|param_list| { - param_list - .self_param() - .map(|it| Some(Either::Left(it))) - .filter(|_| !self.is_bound_method) - .into_iter() - .chain(param_list.params().map(map_param)) - }) - } - Callee::Closure(closure_id) => match closure_source(db, closure_id) { - Some(src) => src.param_list().map(|param_list| { - param_list - .self_param() - .map(|it| Some(Either::Left(it))) - .filter(|_| !self.is_bound_method) - .into_iter() - .chain(param_list.params().map(map_param)) - }), - None => None, - }, - _ => None, - }; - patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect() - } - pub fn return_type(&self) -> Type { - self.ty.derived(self.sig.ret().clone()) - } -} - -fn closure_source(db: &dyn HirDatabase, closure: ClosureId) -> Option { - let (owner, expr_id) = db.lookup_intern_closure(closure.into()); - let (_, source_map) = db.body_with_source_map(owner); - let ast = source_map.expr_syntax(expr_id).ok()?; - let root = ast.file_syntax(db.upcast()); - let expr = ast.value.to_node(&root); - match expr { - ast::Expr::ClosureExpr(it) => Some(it), - _ => None, - } -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum BindingMode { - Move, - Ref(Mutability), -} - -/// For IDE only -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum ScopeDef { - ModuleDef(ModuleDef), - GenericParam(GenericParam), - ImplSelfType(Impl), - AdtSelfType(Adt), - Local(Local), - Label(Label), - Unknown, -} - -impl ScopeDef { - pub fn all_items(def: PerNs) -> ArrayVec { - let mut items = ArrayVec::new(); - - match (def.take_types(), def.take_values()) { - (Some(m1), None) => items.push(ScopeDef::ModuleDef(m1.into())), - (None, Some(m2)) => items.push(ScopeDef::ModuleDef(m2.into())), - (Some(m1), Some(m2)) => { - // Some items, like unit structs and enum variants, are - // returned as both a type and a value. Here we want - // to de-duplicate them. - if m1 != m2 { - items.push(ScopeDef::ModuleDef(m1.into())); - items.push(ScopeDef::ModuleDef(m2.into())); - } else { - items.push(ScopeDef::ModuleDef(m1.into())); - } - } - (None, None) => {} - }; - - if let Some(macro_def_id) = def.take_macros() { - items.push(ScopeDef::ModuleDef(ModuleDef::Macro(macro_def_id.into()))); - } - - if items.is_empty() { - items.push(ScopeDef::Unknown); - } - - items - } - - pub fn attrs(&self, db: &dyn HirDatabase) -> Option { - match self { - ScopeDef::ModuleDef(it) => it.attrs(db), - ScopeDef::GenericParam(it) => Some(it.attrs(db)), - ScopeDef::ImplSelfType(_) - | ScopeDef::AdtSelfType(_) - | ScopeDef::Local(_) - | ScopeDef::Label(_) - | ScopeDef::Unknown => None, - } - } - - pub fn krate(&self, db: &dyn HirDatabase) -> Option { - match self { - ScopeDef::ModuleDef(it) => it.module(db).map(|m| m.krate()), - ScopeDef::GenericParam(it) => Some(it.module(db).krate()), - ScopeDef::ImplSelfType(_) => None, - ScopeDef::AdtSelfType(it) => Some(it.module(db).krate()), - ScopeDef::Local(it) => Some(it.module(db).krate()), - ScopeDef::Label(it) => Some(it.module(db).krate()), - ScopeDef::Unknown => None, - } - } -} - -impl From for ScopeDef { - fn from(item: ItemInNs) -> Self { - match item { - ItemInNs::Types(id) => ScopeDef::ModuleDef(id), - ItemInNs::Values(id) => ScopeDef::ModuleDef(id), - ItemInNs::Macros(id) => ScopeDef::ModuleDef(ModuleDef::Macro(id)), - } - } -} - -pub trait HasVisibility { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility; - fn is_visible_from(&self, db: &dyn HirDatabase, module: Module) -> bool { - let vis = self.visibility(db); - vis.is_visible_from(db.upcast(), module.id) - } -} - -/// Trait for obtaining the defining crate of an item. -pub trait HasCrate { - fn krate(&self, db: &dyn HirDatabase) -> Crate; -} - -impl HasCrate for T { - fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db.upcast()).krate().into() - } -} - -impl HasCrate for AssocItem { - fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() - } -} - -impl HasCrate for Struct { - fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() - } -} - -impl HasCrate for Union { - fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() - } -} - -impl HasCrate for Field { - fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.parent_def(db).module(db).krate() - } -} - -impl HasCrate for Variant { - fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() - } -} - -impl HasCrate for Function { - fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() - } -} - -impl HasCrate for Const { - fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() - } -} - -impl HasCrate for TypeAlias { - fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() - } -} - -impl HasCrate for Type { - fn krate(&self, _db: &dyn HirDatabase) -> Crate { - self.env.krate.into() - } -} - -impl HasCrate for Macro { - fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() - } -} - -impl HasCrate for Trait { - fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() - } -} - -impl HasCrate for Static { - fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() - } -} - -impl HasCrate for Adt { - fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() - } -} - -impl HasCrate for Module { - fn krate(&self, _: &dyn HirDatabase) -> Crate { - Module::krate(*self) - } -} diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs deleted file mode 100644 index fc8f23f19ab91..0000000000000 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ /dev/null @@ -1,1517 +0,0 @@ -//! See `Semantics`. - -mod source_to_def; - -use std::{cell::RefCell, fmt, iter, ops}; - -use base_db::{FileId, FileRange}; -use hir_def::{ - body, macro_id_to_def_id, - resolver::{self, HasResolver, Resolver, TypeNs}, - type_ref::Mutability, - AsMacroCall, FunctionId, MacroId, TraitId, VariantId, -}; -use hir_expand::{ - db::AstDatabase, - name::{known, AsName}, - ExpansionInfo, MacroCallId, -}; -use itertools::Itertools; -use rustc_hash::{FxHashMap, FxHashSet}; -use smallvec::{smallvec, SmallVec}; -use syntax::{ - algo::skip_trivia_token, - ast::{self, HasAttrs as _, HasGenericParams, HasLoopBody}, - match_ast, AstNode, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextSize, -}; - -use crate::{ - db::HirDatabase, - semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, - source_analyzer::{resolve_hir_path, SourceAnalyzer}, - Access, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, DeriveHelper, Field, Function, - HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef, - Name, Path, ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum PathResolution { - /// An item - Def(ModuleDef), - /// A local binding (only value namespace) - Local(Local), - /// A type parameter - TypeParam(TypeParam), - /// A const parameter - ConstParam(ConstParam), - SelfType(Impl), - BuiltinAttr(BuiltinAttr), - ToolModule(ToolModule), - DeriveHelper(DeriveHelper), -} - -impl PathResolution { - pub(crate) fn in_type_ns(&self) -> Option { - match self { - PathResolution::Def(ModuleDef::Adt(adt)) => Some(TypeNs::AdtId((*adt).into())), - PathResolution::Def(ModuleDef::BuiltinType(builtin)) => { - Some(TypeNs::BuiltinType((*builtin).into())) - } - PathResolution::Def( - ModuleDef::Const(_) - | ModuleDef::Variant(_) - | ModuleDef::Macro(_) - | ModuleDef::Function(_) - | ModuleDef::Module(_) - | ModuleDef::Static(_) - | ModuleDef::Trait(_), - ) => None, - PathResolution::Def(ModuleDef::TypeAlias(alias)) => { - Some(TypeNs::TypeAliasId((*alias).into())) - } - PathResolution::BuiltinAttr(_) - | PathResolution::ToolModule(_) - | PathResolution::Local(_) - | PathResolution::DeriveHelper(_) - | PathResolution::ConstParam(_) => None, - PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())), - PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())), - } - } -} - -#[derive(Debug)] -pub struct TypeInfo { - /// The original type of the expression or pattern. - pub original: Type, - /// The adjusted type, if an adjustment happened. - pub adjusted: Option, -} - -impl TypeInfo { - pub fn original(self) -> Type { - self.original - } - - pub fn has_adjustment(&self) -> bool { - self.adjusted.is_some() - } - - /// The adjusted type, or the original in case no adjustments occurred. - pub fn adjusted(self) -> Type { - self.adjusted.unwrap_or(self.original) - } -} - -/// Primary API to get semantic information, like types, from syntax trees. -pub struct Semantics<'db, DB> { - pub db: &'db DB, - imp: SemanticsImpl<'db>, -} - -pub struct SemanticsImpl<'db> { - pub db: &'db dyn HirDatabase, - s2d_cache: RefCell, - expansion_info_cache: RefCell>>, - // Rootnode to HirFileId cache - cache: RefCell>, - // MacroCall to its expansion's HirFileId cache - macro_call_cache: RefCell, HirFileId>>, -} - -impl fmt::Debug for Semantics<'_, DB> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Semantics {{ ... }}") - } -} - -impl<'db, DB: HirDatabase> Semantics<'db, DB> { - pub fn new(db: &DB) -> Semantics<'_, DB> { - let impl_ = SemanticsImpl::new(db); - Semantics { db, imp: impl_ } - } - - pub fn parse(&self, file_id: FileId) -> ast::SourceFile { - self.imp.parse(file_id) - } - - pub fn parse_or_expand(&self, file_id: HirFileId) -> Option { - self.imp.parse_or_expand(file_id) - } - - pub fn expand(&self, macro_call: &ast::MacroCall) -> Option { - self.imp.expand(macro_call) - } - - /// If `item` has an attribute macro attached to it, expands it. - pub fn expand_attr_macro(&self, item: &ast::Item) -> Option { - self.imp.expand_attr_macro(item) - } - - pub fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option { - self.imp.expand_derive_as_pseudo_attr_macro(attr) - } - - pub fn resolve_derive_macro(&self, derive: &ast::Attr) -> Option>> { - self.imp.resolve_derive_macro(derive) - } - - pub fn expand_derive_macro(&self, derive: &ast::Attr) -> Option> { - self.imp.expand_derive_macro(derive) - } - - pub fn is_attr_macro_call(&self, item: &ast::Item) -> bool { - self.imp.is_attr_macro_call(item) - } - - pub fn is_derive_annotated(&self, item: &ast::Adt) -> bool { - self.imp.is_derive_annotated(item) - } - - pub fn speculative_expand( - &self, - actual_macro_call: &ast::MacroCall, - speculative_args: &ast::TokenTree, - token_to_map: SyntaxToken, - ) -> Option<(SyntaxNode, SyntaxToken)> { - self.imp.speculative_expand(actual_macro_call, speculative_args, token_to_map) - } - - pub fn speculative_expand_attr_macro( - &self, - actual_macro_call: &ast::Item, - speculative_args: &ast::Item, - token_to_map: SyntaxToken, - ) -> Option<(SyntaxNode, SyntaxToken)> { - self.imp.speculative_expand_attr(actual_macro_call, speculative_args, token_to_map) - } - - pub fn speculative_expand_derive_as_pseudo_attr_macro( - &self, - actual_macro_call: &ast::Attr, - speculative_args: &ast::Attr, - token_to_map: SyntaxToken, - ) -> Option<(SyntaxNode, SyntaxToken)> { - self.imp.speculative_expand_derive_as_pseudo_attr_macro( - actual_macro_call, - speculative_args, - token_to_map, - ) - } - - /// Descend the token into macrocalls to its first mapped counterpart. - pub fn descend_into_macros_single(&self, token: SyntaxToken) -> SyntaxToken { - self.imp.descend_into_macros_single(token) - } - - /// Descend the token into macrocalls to all its mapped counterparts. - pub fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> { - self.imp.descend_into_macros(token) - } - - /// Descend the token into macrocalls to all its mapped counterparts that have the same text as the input token. - /// - /// Returns the original non descended token if none of the mapped counterparts have the same text. - pub fn descend_into_macros_with_same_text( - &self, - token: SyntaxToken, - ) -> SmallVec<[SyntaxToken; 1]> { - self.imp.descend_into_macros_with_same_text(token) - } - - pub fn descend_into_macros_with_kind_preference(&self, token: SyntaxToken) -> SyntaxToken { - self.imp.descend_into_macros_with_kind_preference(token) - } - - /// Maps a node down by mapping its first and last token down. - pub fn descend_node_into_attributes(&self, node: N) -> SmallVec<[N; 1]> { - self.imp.descend_node_into_attributes(node) - } - - /// Search for a definition's source and cache its syntax tree - pub fn source(&self, def: Def) -> Option> - where - Def::Ast: AstNode, - { - self.imp.source(def) - } - - pub fn hir_file_for(&self, syntax_node: &SyntaxNode) -> HirFileId { - self.imp.find_file(syntax_node).file_id - } - - /// Attempts to map the node out of macro expanded files returning the original file range. - /// If upmapping is not possible, this will fall back to the range of the macro call of the - /// macro file the node resides in. - pub fn original_range(&self, node: &SyntaxNode) -> FileRange { - self.imp.original_range(node) - } - - /// Attempts to map the node out of macro expanded files returning the original file range. - pub fn original_range_opt(&self, node: &SyntaxNode) -> Option { - self.imp.original_range_opt(node) - } - - /// Attempts to map the node out of macro expanded files. - /// This only work for attribute expansions, as other ones do not have nodes as input. - pub fn original_ast_node(&self, node: N) -> Option { - self.imp.original_ast_node(node) - } - - pub fn diagnostics_display_range(&self, diagnostics: InFile) -> FileRange { - self.imp.diagnostics_display_range(diagnostics) - } - - pub fn token_ancestors_with_macros( - &self, - token: SyntaxToken, - ) -> impl Iterator + '_ { - token.parent().into_iter().flat_map(move |it| self.ancestors_with_macros(it)) - } - - /// Iterates the ancestors of the given node, climbing up macro expansions while doing so. - pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator + '_ { - self.imp.ancestors_with_macros(node) - } - - pub fn ancestors_at_offset_with_macros( - &self, - node: &SyntaxNode, - offset: TextSize, - ) -> impl Iterator + '_ { - self.imp.ancestors_at_offset_with_macros(node, offset) - } - - /// Find an AstNode by offset inside SyntaxNode, if it is inside *Macrofile*, - /// search up until it is of the target AstNode type - pub fn find_node_at_offset_with_macros( - &self, - node: &SyntaxNode, - offset: TextSize, - ) -> Option { - self.imp.ancestors_at_offset_with_macros(node, offset).find_map(N::cast) - } - - /// Find an AstNode by offset inside SyntaxNode, if it is inside *MacroCall*, - /// descend it and find again - pub fn find_node_at_offset_with_descend( - &self, - node: &SyntaxNode, - offset: TextSize, - ) -> Option { - self.imp.descend_node_at_offset(node, offset).flatten().find_map(N::cast) - } - - /// Find an AstNode by offset inside SyntaxNode, if it is inside *MacroCall*, - /// descend it and find again - pub fn find_nodes_at_offset_with_descend<'slf, N: AstNode + 'slf>( - &'slf self, - node: &SyntaxNode, - offset: TextSize, - ) -> impl Iterator + 'slf { - self.imp.descend_node_at_offset(node, offset).filter_map(|mut it| it.find_map(N::cast)) - } - - pub fn resolve_lifetime_param(&self, lifetime: &ast::Lifetime) -> Option { - self.imp.resolve_lifetime_param(lifetime) - } - - pub fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option
, -} - -impl Assist { - fn collect() -> Vec { - let handlers_dir = project_root().join("crates/ide-assists/src/handlers"); - - let mut res = Vec::new(); - for path in sourcegen::list_rust_files(&handlers_dir) { - collect_file(&mut res, path.as_path()); - } - res.sort_by(|lhs, rhs| lhs.id.cmp(&rhs.id)); - return res; - - fn collect_file(acc: &mut Vec, path: &Path) { - let text = fs::read_to_string(path).unwrap(); - let comment_blocks = sourcegen::CommentBlock::extract("Assist", &text); - - for block in comment_blocks { - // FIXME: doesn't support blank lines yet, need to tweak - // `extract_comment_blocks` for that. - let id = block.id; - assert!( - id.chars().all(|it| it.is_ascii_lowercase() || it == '_'), - "invalid assist id: {:?}", - id - ); - let mut lines = block.contents.iter().peekable(); - let location = sourcegen::Location { file: path.to_path_buf(), line: block.line }; - let mut assist = Assist { id, location, sections: Vec::new() }; - - while lines.peek().is_some() { - let doc = take_until(lines.by_ref(), "```").trim().to_string(); - assert!( - (doc.chars().next().unwrap().is_ascii_uppercase() && doc.ends_with('.')) - || assist.sections.len() > 0, - "\n\n{}: assist docs should be proper sentences, with capitalization and a full stop at the end.\n\n{}\n\n", - &assist.id, - doc, - ); - - let before = take_until(lines.by_ref(), "```"); - - assert_eq!(lines.next().unwrap().as_str(), "->"); - assert_eq!(lines.next().unwrap().as_str(), "```"); - let after = take_until(lines.by_ref(), "```"); - - assist.sections.push(Section { doc, before, after }); - } - - acc.push(assist) - } - } - - fn take_until<'a>(lines: impl Iterator, marker: &str) -> String { - let mut buf = Vec::new(); - for line in lines { - if line == marker { - break; - } - buf.push(line.clone()); - } - buf.join("\n") - } - } -} - -impl fmt::Display for Assist { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let _ = writeln!( - f, - "[discrete]\n=== `{}` -**Source:** {}", - self.id, self.location, - ); - - for section in &self.sections { - let before = section.before.replace("$0", "┃"); // Unicode pseudo-graphics bar - let after = section.after.replace("$0", "┃"); - let _ = writeln!( - f, - " -{} - -.Before -```rust -{}``` - -.After -```rust -{}```", - section.doc, - hide_hash_comments(&before), - hide_hash_comments(&after) - ); - } - - Ok(()) - } -} - -fn hide_hash_comments(text: &str) -> String { - text.split('\n') // want final newline - .filter(|&it| !(it.starts_with("# ") || it == "#")) - .map(|it| format!("{}\n", it)) - .collect() -} - -fn reveal_hash_comments(text: &str) -> String { - text.split('\n') // want final newline - .map(|it| { - if let Some(stripped) = it.strip_prefix("# ") { - stripped - } else if it == "#" { - "" - } else { - it - } - }) - .map(|it| format!("{}\n", it)) - .collect() -} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs deleted file mode 100644 index 3e61d0741d3fe..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ /dev/null @@ -1,703 +0,0 @@ -//! Assorted functions shared by several assists. - -use std::ops; - -use itertools::Itertools; - -pub(crate) use gen_trait_fn_body::gen_trait_fn_body; -use hir::{db::HirDatabase, HirDisplay, Semantics}; -use ide_db::{famous_defs::FamousDefs, path_transform::PathTransform, RootDatabase, SnippetCap}; -use stdx::format_to; -use syntax::{ - ast::{ - self, - edit::{self, AstNodeEdit}, - edit_in_place::AttrsOwnerEdit, - make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace, - }, - ted, AstNode, AstToken, Direction, SmolStr, SourceFile, - SyntaxKind::*, - SyntaxNode, TextRange, TextSize, T, -}; - -use crate::assist_context::{AssistBuilder, AssistContext}; - -pub(crate) mod suggest_name; -mod gen_trait_fn_body; - -pub(crate) fn unwrap_trivial_block(block_expr: ast::BlockExpr) -> ast::Expr { - extract_trivial_expression(&block_expr) - .filter(|expr| !expr.syntax().text().contains_char('\n')) - .unwrap_or_else(|| block_expr.into()) -} - -pub fn extract_trivial_expression(block_expr: &ast::BlockExpr) -> Option { - if block_expr.modifier().is_some() { - return None; - } - let stmt_list = block_expr.stmt_list()?; - let has_anything_else = |thing: &SyntaxNode| -> bool { - let mut non_trivial_children = - stmt_list.syntax().children_with_tokens().filter(|it| match it.kind() { - WHITESPACE | T!['{'] | T!['}'] => false, - _ => it.as_node() != Some(thing), - }); - non_trivial_children.next().is_some() - }; - - if let Some(expr) = stmt_list.tail_expr() { - if has_anything_else(expr.syntax()) { - return None; - } - return Some(expr); - } - // Unwrap `{ continue; }` - let stmt = stmt_list.statements().next()?; - if let ast::Stmt::ExprStmt(expr_stmt) = stmt { - if has_anything_else(expr_stmt.syntax()) { - return None; - } - let expr = expr_stmt.expr()?; - if matches!(expr.syntax().kind(), CONTINUE_EXPR | BREAK_EXPR | RETURN_EXPR) { - return Some(expr); - } - } - None -} - -/// This is a method with a heuristics to support test methods annotated with custom test annotations, such as -/// `#[test_case(...)]`, `#[tokio::test]` and similar. -/// Also a regular `#[test]` annotation is supported. -/// -/// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test, -/// but it's better than not to have the runnables for the tests at all. -pub fn test_related_attribute(fn_def: &ast::Fn) -> Option { - fn_def.attrs().find_map(|attr| { - let path = attr.path()?; - let text = path.syntax().text().to_string(); - if text.starts_with("test") || text.ends_with("test") { - Some(attr) - } else { - None - } - }) -} - -#[derive(Copy, Clone, PartialEq)] -pub enum DefaultMethods { - Only, - No, -} - -pub fn filter_assoc_items( - sema: &Semantics<'_, RootDatabase>, - items: &[hir::AssocItem], - default_methods: DefaultMethods, -) -> Vec { - fn has_def_name(item: &ast::AssocItem) -> bool { - match item { - ast::AssocItem::Fn(def) => def.name(), - ast::AssocItem::TypeAlias(def) => def.name(), - ast::AssocItem::Const(def) => def.name(), - ast::AssocItem::MacroCall(_) => None, - } - .is_some() - } - - items - .iter() - // Note: This throws away items with no source. - .filter_map(|&i| { - let item = match i { - hir::AssocItem::Function(i) => ast::AssocItem::Fn(sema.source(i)?.value), - hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(sema.source(i)?.value), - hir::AssocItem::Const(i) => ast::AssocItem::Const(sema.source(i)?.value), - }; - Some(item) - }) - .filter(has_def_name) - .filter(|it| match it { - ast::AssocItem::Fn(def) => matches!( - (default_methods, def.body()), - (DefaultMethods::Only, Some(_)) | (DefaultMethods::No, None) - ), - _ => default_methods == DefaultMethods::No, - }) - .collect::>() -} - -pub fn add_trait_assoc_items_to_impl( - sema: &Semantics<'_, RootDatabase>, - items: Vec, - trait_: hir::Trait, - impl_: ast::Impl, - target_scope: hir::SemanticsScope<'_>, -) -> (ast::Impl, ast::AssocItem) { - let source_scope = sema.scope_for_def(trait_); - - let transform = PathTransform::trait_impl(&target_scope, &source_scope, trait_, impl_.clone()); - - let items = items.into_iter().map(|assoc_item| { - transform.apply(assoc_item.syntax()); - assoc_item.remove_attrs_and_docs(); - assoc_item - }); - - let res = impl_.clone_for_update(); - - let assoc_item_list = res.get_or_create_assoc_item_list(); - let mut first_item = None; - for item in items { - first_item.get_or_insert_with(|| item.clone()); - match &item { - ast::AssocItem::Fn(fn_) if fn_.body().is_none() => { - let body = make::block_expr(None, Some(make::ext::expr_todo())) - .indent(edit::IndentLevel(1)); - ted::replace(fn_.get_or_create_body().syntax(), body.clone_for_update().syntax()) - } - ast::AssocItem::TypeAlias(type_alias) => { - if let Some(type_bound_list) = type_alias.type_bound_list() { - type_bound_list.remove() - } - } - _ => {} - } - - assoc_item_list.add_item(item) - } - - (res, first_item.unwrap()) -} - -#[derive(Clone, Copy, Debug)] -pub(crate) enum Cursor<'a> { - Replace(&'a SyntaxNode), - Before(&'a SyntaxNode), -} - -impl<'a> Cursor<'a> { - fn node(self) -> &'a SyntaxNode { - match self { - Cursor::Replace(node) | Cursor::Before(node) => node, - } - } -} - -pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor<'_>) -> String { - assert!(cursor.node().ancestors().any(|it| it == *node)); - let range = cursor.node().text_range() - node.text_range().start(); - let range: ops::Range = range.into(); - - let mut placeholder = cursor.node().to_string(); - escape(&mut placeholder); - let tab_stop = match cursor { - Cursor::Replace(placeholder) => format!("${{0:{}}}", placeholder), - Cursor::Before(placeholder) => format!("$0{}", placeholder), - }; - - let mut buf = node.to_string(); - buf.replace_range(range, &tab_stop); - return buf; - - fn escape(buf: &mut String) { - stdx::replace(buf, '{', r"\{"); - stdx::replace(buf, '}', r"\}"); - stdx::replace(buf, '$', r"\$"); - } -} - -pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize { - node.children_with_tokens() - .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR)) - .map(|it| it.text_range().start()) - .unwrap_or_else(|| node.text_range().start()) -} - -pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr { - invert_special_case(&expr).unwrap_or_else(|| make::expr_prefix(T![!], expr)) -} - -fn invert_special_case(expr: &ast::Expr) -> Option { - match expr { - ast::Expr::BinExpr(bin) => { - let bin = bin.clone_for_update(); - let op_token = bin.op_token()?; - let rev_token = match op_token.kind() { - T![==] => T![!=], - T![!=] => T![==], - T![<] => T![>=], - T![<=] => T![>], - T![>] => T![<=], - T![>=] => T![<], - // Parenthesize other expressions before prefixing `!` - _ => return Some(make::expr_prefix(T![!], make::expr_paren(expr.clone()))), - }; - ted::replace(op_token, make::token(rev_token)); - Some(bin.into()) - } - ast::Expr::MethodCallExpr(mce) => { - let receiver = mce.receiver()?; - let method = mce.name_ref()?; - let arg_list = mce.arg_list()?; - - let method = match method.text().as_str() { - "is_some" => "is_none", - "is_none" => "is_some", - "is_ok" => "is_err", - "is_err" => "is_ok", - _ => return None, - }; - Some(make::expr_method_call(receiver, make::name_ref(method), arg_list)) - } - ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::UnaryOp::Not => match pe.expr()? { - ast::Expr::ParenExpr(parexpr) => parexpr.expr(), - _ => pe.expr(), - }, - ast::Expr::Literal(lit) => match lit.kind() { - ast::LiteralKind::Bool(b) => match b { - true => Some(ast::Expr::Literal(make::expr_literal("false"))), - false => Some(ast::Expr::Literal(make::expr_literal("true"))), - }, - _ => None, - }, - _ => None, - } -} - -pub(crate) fn next_prev() -> impl Iterator { - [Direction::Next, Direction::Prev].into_iter() -} - -pub(crate) fn does_pat_match_variant(pat: &ast::Pat, var: &ast::Pat) -> bool { - let first_node_text = |pat: &ast::Pat| pat.syntax().first_child().map(|node| node.text()); - - let pat_head = match pat { - ast::Pat::IdentPat(bind_pat) => match bind_pat.pat() { - Some(p) => first_node_text(&p), - None => return pat.syntax().text() == var.syntax().text(), - }, - pat => first_node_text(pat), - }; - - let var_head = first_node_text(var); - - pat_head == var_head -} - -pub(crate) fn does_nested_pattern(pat: &ast::Pat) -> bool { - let depth = calc_depth(pat, 0); - - if 1 < depth { - return true; - } - false -} - -fn calc_depth(pat: &ast::Pat, depth: usize) -> usize { - match pat { - ast::Pat::IdentPat(_) - | ast::Pat::BoxPat(_) - | ast::Pat::RestPat(_) - | ast::Pat::LiteralPat(_) - | ast::Pat::MacroPat(_) - | ast::Pat::OrPat(_) - | ast::Pat::ParenPat(_) - | ast::Pat::PathPat(_) - | ast::Pat::WildcardPat(_) - | ast::Pat::RangePat(_) - | ast::Pat::RecordPat(_) - | ast::Pat::RefPat(_) - | ast::Pat::SlicePat(_) - | ast::Pat::TuplePat(_) - | ast::Pat::ConstBlockPat(_) => depth, - - // FIXME: Other patterns may also be nested. Currently it simply supports only `TupleStructPat` - ast::Pat::TupleStructPat(pat) => { - let mut max_depth = depth; - for p in pat.fields() { - let d = calc_depth(&p, depth + 1); - if d > max_depth { - max_depth = d - } - } - max_depth - } - } -} - -// Uses a syntax-driven approach to find any impl blocks for the struct that -// exist within the module/file -// -// Returns `None` if we've found an existing fn -// -// FIXME: change the new fn checking to a more semantic approach when that's more -// viable (e.g. we process proc macros, etc) -// FIXME: this partially overlaps with `find_impl_block_*` -pub(crate) fn find_struct_impl( - ctx: &AssistContext<'_>, - adt: &ast::Adt, - name: &str, -) -> Option> { - let db = ctx.db(); - let module = adt.syntax().parent()?; - - let struct_def = ctx.sema.to_def(adt)?; - - let block = module.descendants().filter_map(ast::Impl::cast).find_map(|impl_blk| { - let blk = ctx.sema.to_def(&impl_blk)?; - - // FIXME: handle e.g. `struct S; impl S {}` - // (we currently use the wrong type parameter) - // also we wouldn't want to use e.g. `impl S` - - let same_ty = match blk.self_ty(db).as_adt() { - Some(def) => def == struct_def, - None => false, - }; - let not_trait_impl = blk.trait_(db).is_none(); - - if !(same_ty && not_trait_impl) { - None - } else { - Some(impl_blk) - } - }); - - if let Some(ref impl_blk) = block { - if has_fn(impl_blk, name) { - return None; - } - } - - Some(block) -} - -fn has_fn(imp: &ast::Impl, rhs_name: &str) -> bool { - if let Some(il) = imp.assoc_item_list() { - for item in il.assoc_items() { - if let ast::AssocItem::Fn(f) = item { - if let Some(name) = f.name() { - if name.text().eq_ignore_ascii_case(rhs_name) { - return true; - } - } - } - } - } - - false -} - -/// Find the start of the `impl` block for the given `ast::Impl`. -// -// FIXME: this partially overlaps with `find_struct_impl` -pub(crate) fn find_impl_block_start(impl_def: ast::Impl, buf: &mut String) -> Option { - buf.push('\n'); - let start = impl_def.assoc_item_list().and_then(|it| it.l_curly_token())?.text_range().end(); - Some(start) -} - -/// Find the end of the `impl` block for the given `ast::Impl`. -// -// FIXME: this partially overlaps with `find_struct_impl` -pub(crate) fn find_impl_block_end(impl_def: ast::Impl, buf: &mut String) -> Option { - buf.push('\n'); - let end = impl_def - .assoc_item_list() - .and_then(|it| it.r_curly_token())? - .prev_sibling_or_token()? - .text_range() - .end(); - Some(end) -} - -// Generates the surrounding `impl Type { }` including type and lifetime -// parameters -pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String { - generate_impl_text_inner(adt, None, code) -} - -// Generates the surrounding `impl for Type { }` including type -// and lifetime parameters -pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &str) -> String { - generate_impl_text_inner(adt, Some(trait_text), code) -} - -fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str) -> String { - let generic_params = adt.generic_param_list(); - let mut buf = String::with_capacity(code.len()); - buf.push_str("\n\n"); - adt.attrs() - .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false)) - .for_each(|attr| buf.push_str(format!("{}\n", attr).as_str())); - buf.push_str("impl"); - if let Some(generic_params) = &generic_params { - let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax())); - let toc_params = generic_params.type_or_const_params().map(|toc_param| { - let type_param = match toc_param { - ast::TypeOrConstParam::Type(x) => x, - ast::TypeOrConstParam::Const(x) => return x.syntax().to_string(), - }; - let mut buf = String::new(); - if let Some(it) = type_param.name() { - format_to!(buf, "{}", it.syntax()); - } - if let Some(it) = type_param.colon_token() { - format_to!(buf, "{} ", it); - } - if let Some(it) = type_param.type_bound_list() { - format_to!(buf, "{}", it.syntax()); - } - buf - }); - let generics = lifetimes.chain(toc_params).format(", "); - format_to!(buf, "<{}>", generics); - } - buf.push(' '); - if let Some(trait_text) = trait_text { - buf.push_str(trait_text); - buf.push_str(" for "); - } - buf.push_str(&adt.name().unwrap().text()); - if let Some(generic_params) = generic_params { - let lifetime_params = generic_params - .lifetime_params() - .filter_map(|it| it.lifetime()) - .map(|it| SmolStr::from(it.text())); - let toc_params = generic_params - .type_or_const_params() - .filter_map(|it| it.name()) - .map(|it| SmolStr::from(it.text())); - format_to!(buf, "<{}>", lifetime_params.chain(toc_params).format(", ")) - } - - match adt.where_clause() { - Some(where_clause) => { - format_to!(buf, "\n{}\n{{\n{}\n}}", where_clause, code); - } - None => { - format_to!(buf, " {{\n{}\n}}", code); - } - } - - buf -} - -pub(crate) fn add_method_to_adt( - builder: &mut AssistBuilder, - adt: &ast::Adt, - impl_def: Option, - method: &str, -) { - let mut buf = String::with_capacity(method.len() + 2); - if impl_def.is_some() { - buf.push('\n'); - } - buf.push_str(method); - - let start_offset = impl_def - .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf)) - .unwrap_or_else(|| { - buf = generate_impl_text(adt, &buf); - adt.syntax().text_range().end() - }); - - builder.insert(start_offset, buf); -} - -#[derive(Debug)] -pub(crate) struct ReferenceConversion { - conversion: ReferenceConversionType, - ty: hir::Type, -} - -#[derive(Debug)] -enum ReferenceConversionType { - // reference can be stripped if the type is Copy - Copy, - // &String -> &str - AsRefStr, - // &Vec -> &[T] - AsRefSlice, - // &Box -> &T - Dereferenced, - // &Option -> Option<&T> - Option, - // &Result -> Result<&T, &E> - Result, -} - -impl ReferenceConversion { - pub(crate) fn convert_type(&self, db: &dyn HirDatabase) -> String { - match self.conversion { - ReferenceConversionType::Copy => self.ty.display(db).to_string(), - ReferenceConversionType::AsRefStr => "&str".to_string(), - ReferenceConversionType::AsRefSlice => { - let type_argument_name = - self.ty.type_arguments().next().unwrap().display(db).to_string(); - format!("&[{}]", type_argument_name) - } - ReferenceConversionType::Dereferenced => { - let type_argument_name = - self.ty.type_arguments().next().unwrap().display(db).to_string(); - format!("&{}", type_argument_name) - } - ReferenceConversionType::Option => { - let type_argument_name = - self.ty.type_arguments().next().unwrap().display(db).to_string(); - format!("Option<&{}>", type_argument_name) - } - ReferenceConversionType::Result => { - let mut type_arguments = self.ty.type_arguments(); - let first_type_argument_name = - type_arguments.next().unwrap().display(db).to_string(); - let second_type_argument_name = - type_arguments.next().unwrap().display(db).to_string(); - format!("Result<&{}, &{}>", first_type_argument_name, second_type_argument_name) - } - } - } - - pub(crate) fn getter(&self, field_name: String) -> String { - match self.conversion { - ReferenceConversionType::Copy => format!("self.{}", field_name), - ReferenceConversionType::AsRefStr - | ReferenceConversionType::AsRefSlice - | ReferenceConversionType::Dereferenced - | ReferenceConversionType::Option - | ReferenceConversionType::Result => format!("self.{}.as_ref()", field_name), - } - } -} - -// FIXME: It should return a new hir::Type, but currently constructing new types is too cumbersome -// and all users of this function operate on string type names, so they can do the conversion -// itself themselves. -pub(crate) fn convert_reference_type( - ty: hir::Type, - db: &RootDatabase, - famous_defs: &FamousDefs<'_, '_>, -) -> Option { - handle_copy(&ty, db) - .or_else(|| handle_as_ref_str(&ty, db, famous_defs)) - .or_else(|| handle_as_ref_slice(&ty, db, famous_defs)) - .or_else(|| handle_dereferenced(&ty, db, famous_defs)) - .or_else(|| handle_option_as_ref(&ty, db, famous_defs)) - .or_else(|| handle_result_as_ref(&ty, db, famous_defs)) - .map(|conversion| ReferenceConversion { ty, conversion }) -} - -fn handle_copy(ty: &hir::Type, db: &dyn HirDatabase) -> Option { - ty.is_copy(db).then(|| ReferenceConversionType::Copy) -} - -fn handle_as_ref_str( - ty: &hir::Type, - db: &dyn HirDatabase, - famous_defs: &FamousDefs<'_, '_>, -) -> Option { - let str_type = hir::BuiltinType::str().ty(db); - - ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[str_type]) - .then(|| ReferenceConversionType::AsRefStr) -} - -fn handle_as_ref_slice( - ty: &hir::Type, - db: &dyn HirDatabase, - famous_defs: &FamousDefs<'_, '_>, -) -> Option { - let type_argument = ty.type_arguments().next()?; - let slice_type = hir::Type::new_slice(type_argument); - - ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[slice_type]) - .then(|| ReferenceConversionType::AsRefSlice) -} - -fn handle_dereferenced( - ty: &hir::Type, - db: &dyn HirDatabase, - famous_defs: &FamousDefs<'_, '_>, -) -> Option { - let type_argument = ty.type_arguments().next()?; - - ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[type_argument]) - .then(|| ReferenceConversionType::Dereferenced) -} - -fn handle_option_as_ref( - ty: &hir::Type, - db: &dyn HirDatabase, - famous_defs: &FamousDefs<'_, '_>, -) -> Option { - if ty.as_adt() == famous_defs.core_option_Option()?.ty(db).as_adt() { - Some(ReferenceConversionType::Option) - } else { - None - } -} - -fn handle_result_as_ref( - ty: &hir::Type, - db: &dyn HirDatabase, - famous_defs: &FamousDefs<'_, '_>, -) -> Option { - if ty.as_adt() == famous_defs.core_result_Result()?.ty(db).as_adt() { - Some(ReferenceConversionType::Result) - } else { - None - } -} - -pub(crate) fn get_methods(items: &ast::AssocItemList) -> Vec { - items - .assoc_items() - .flat_map(|i| match i { - ast::AssocItem::Fn(f) => Some(f), - _ => None, - }) - .filter(|f| f.name().is_some()) - .collect() -} - -/// Trim(remove leading and trailing whitespace) `initial_range` in `source_file`, return the trimmed range. -pub(crate) fn trimmed_text_range(source_file: &SourceFile, initial_range: TextRange) -> TextRange { - let mut trimmed_range = initial_range; - while source_file - .syntax() - .token_at_offset(trimmed_range.start()) - .find_map(Whitespace::cast) - .is_some() - && trimmed_range.start() < trimmed_range.end() - { - let start = trimmed_range.start() + TextSize::from(1); - trimmed_range = TextRange::new(start, trimmed_range.end()); - } - while source_file - .syntax() - .token_at_offset(trimmed_range.end()) - .find_map(Whitespace::cast) - .is_some() - && trimmed_range.start() < trimmed_range.end() - { - let end = trimmed_range.end() - TextSize::from(1); - trimmed_range = TextRange::new(trimmed_range.start(), end); - } - trimmed_range -} - -/// Convert a list of function params to a list of arguments that can be passed -/// into a function call. -pub(crate) fn convert_param_list_to_arg_list(list: ast::ParamList) -> ast::ArgList { - let mut args = vec![]; - for param in list.params() { - if let Some(ast::Pat::IdentPat(pat)) = param.pat() { - if let Some(name) = pat.name() { - let name = name.to_string(); - let expr = make::expr_path(make::ext::ident_path(&name)); - args.push(expr); - } - } - } - make::arg_list(args) -} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs deleted file mode 100644 index 7a0c912959a12..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs +++ /dev/null @@ -1,661 +0,0 @@ -//! This module contains functions to generate default trait impl function bodies where possible. - -use syntax::{ - ast::{self, edit::AstNodeEdit, make, AstNode, BinaryOp, CmpOp, HasName, LogicOp}, - ted, -}; - -/// Generate custom trait bodies without default implementation where possible. -/// -/// Returns `Option` so that we can use `?` rather than `if let Some`. Returning -/// `None` means that generating a custom trait body failed, and the body will remain -/// as `todo!` instead. -pub(crate) fn gen_trait_fn_body( - func: &ast::Fn, - trait_path: &ast::Path, - adt: &ast::Adt, -) -> Option<()> { - match trait_path.segment()?.name_ref()?.text().as_str() { - "Clone" => gen_clone_impl(adt, func), - "Debug" => gen_debug_impl(adt, func), - "Default" => gen_default_impl(adt, func), - "Hash" => gen_hash_impl(adt, func), - "PartialEq" => gen_partial_eq(adt, func), - "PartialOrd" => gen_partial_ord(adt, func), - _ => None, - } -} - -/// Generate a `Clone` impl based on the fields and members of the target type. -fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { - stdx::always!(func.name().map_or(false, |name| name.text() == "clone")); - fn gen_clone_call(target: ast::Expr) -> ast::Expr { - let method = make::name_ref("clone"); - make::expr_method_call(target, method, make::arg_list(None)) - } - let expr = match adt { - // `Clone` cannot be derived for unions, so no default impl can be provided. - ast::Adt::Union(_) => return None, - ast::Adt::Enum(enum_) => { - let list = enum_.variant_list()?; - let mut arms = vec![]; - for variant in list.variants() { - let name = variant.name()?; - let variant_name = make::ext::path_from_idents(["Self", &format!("{}", name)])?; - - match variant.field_list() { - // => match self { Self::Name { x } => Self::Name { x: x.clone() } } - Some(ast::FieldList::RecordFieldList(list)) => { - let mut pats = vec![]; - let mut fields = vec![]; - for field in list.fields() { - let field_name = field.name()?; - let pat = make::ident_pat(false, false, field_name.clone()); - pats.push(pat.into()); - - let path = make::ext::ident_path(&field_name.to_string()); - let method_call = gen_clone_call(make::expr_path(path)); - let name_ref = make::name_ref(&field_name.to_string()); - let field = make::record_expr_field(name_ref, Some(method_call)); - fields.push(field); - } - let pat = make::record_pat(variant_name.clone(), pats.into_iter()); - let fields = make::record_expr_field_list(fields); - let record_expr = make::record_expr(variant_name, fields).into(); - arms.push(make::match_arm(Some(pat.into()), None, record_expr)); - } - - // => match self { Self::Name(arg1) => Self::Name(arg1.clone()) } - Some(ast::FieldList::TupleFieldList(list)) => { - let mut pats = vec![]; - let mut fields = vec![]; - for (i, _) in list.fields().enumerate() { - let field_name = format!("arg{}", i); - let pat = make::ident_pat(false, false, make::name(&field_name)); - pats.push(pat.into()); - - let f_path = make::expr_path(make::ext::ident_path(&field_name)); - fields.push(gen_clone_call(f_path)); - } - let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter()); - let struct_name = make::expr_path(variant_name); - let tuple_expr = make::expr_call(struct_name, make::arg_list(fields)); - arms.push(make::match_arm(Some(pat.into()), None, tuple_expr)); - } - - // => match self { Self::Name => Self::Name } - None => { - let pattern = make::path_pat(variant_name.clone()); - let variant_expr = make::expr_path(variant_name); - arms.push(make::match_arm(Some(pattern), None, variant_expr)); - } - } - } - - let match_target = make::expr_path(make::ext::ident_path("self")); - let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1)); - make::expr_match(match_target, list) - } - ast::Adt::Struct(strukt) => { - match strukt.field_list() { - // => Self { name: self.name.clone() } - Some(ast::FieldList::RecordFieldList(field_list)) => { - let mut fields = vec![]; - for field in field_list.fields() { - let base = make::expr_path(make::ext::ident_path("self")); - let target = make::expr_field(base, &field.name()?.to_string()); - let method_call = gen_clone_call(target); - let name_ref = make::name_ref(&field.name()?.to_string()); - let field = make::record_expr_field(name_ref, Some(method_call)); - fields.push(field); - } - let struct_name = make::ext::ident_path("Self"); - let fields = make::record_expr_field_list(fields); - make::record_expr(struct_name, fields).into() - } - // => Self(self.0.clone(), self.1.clone()) - Some(ast::FieldList::TupleFieldList(field_list)) => { - let mut fields = vec![]; - for (i, _) in field_list.fields().enumerate() { - let f_path = make::expr_path(make::ext::ident_path("self")); - let target = make::expr_field(f_path, &format!("{}", i)); - fields.push(gen_clone_call(target)); - } - let struct_name = make::expr_path(make::ext::ident_path("Self")); - make::expr_call(struct_name, make::arg_list(fields)) - } - // => Self { } - None => { - let struct_name = make::ext::ident_path("Self"); - let fields = make::record_expr_field_list(None); - make::record_expr(struct_name, fields).into() - } - } - } - }; - let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1)); - ted::replace(func.body()?.syntax(), body.clone_for_update().syntax()); - Some(()) -} - -/// Generate a `Debug` impl based on the fields and members of the target type. -fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { - let annotated_name = adt.name()?; - match adt { - // `Debug` cannot be derived for unions, so no default impl can be provided. - ast::Adt::Union(_) => None, - - // => match self { Self::Variant => write!(f, "Variant") } - ast::Adt::Enum(enum_) => { - let list = enum_.variant_list()?; - let mut arms = vec![]; - for variant in list.variants() { - let name = variant.name()?; - let variant_name = make::ext::path_from_idents(["Self", &format!("{}", name)])?; - let target = make::expr_path(make::ext::ident_path("f")); - - match variant.field_list() { - Some(ast::FieldList::RecordFieldList(list)) => { - // => f.debug_struct(name) - let target = make::expr_path(make::ext::ident_path("f")); - let method = make::name_ref("debug_struct"); - let struct_name = format!("\"{}\"", name); - let args = make::arg_list(Some(make::expr_literal(&struct_name).into())); - let mut expr = make::expr_method_call(target, method, args); - - let mut pats = vec![]; - for field in list.fields() { - let field_name = field.name()?; - - // create a field pattern for use in `MyStruct { fields.. }` - let pat = make::ident_pat(false, false, field_name.clone()); - pats.push(pat.into()); - - // => .field("field_name", field) - let method_name = make::name_ref("field"); - let name = make::expr_literal(&(format!("\"{}\"", field_name))).into(); - let path = &format!("{}", field_name); - let path = make::expr_path(make::ext::ident_path(path)); - let args = make::arg_list(vec![name, path]); - expr = make::expr_method_call(expr, method_name, args); - } - - // => .finish() - let method = make::name_ref("finish"); - let expr = make::expr_method_call(expr, method, make::arg_list(None)); - - // => MyStruct { fields.. } => f.debug_struct("MyStruct")...finish(), - let pat = make::record_pat(variant_name.clone(), pats.into_iter()); - arms.push(make::match_arm(Some(pat.into()), None, expr)); - } - Some(ast::FieldList::TupleFieldList(list)) => { - // => f.debug_tuple(name) - let target = make::expr_path(make::ext::ident_path("f")); - let method = make::name_ref("debug_tuple"); - let struct_name = format!("\"{}\"", name); - let args = make::arg_list(Some(make::expr_literal(&struct_name).into())); - let mut expr = make::expr_method_call(target, method, args); - - let mut pats = vec![]; - for (i, _) in list.fields().enumerate() { - let name = format!("arg{}", i); - - // create a field pattern for use in `MyStruct(fields..)` - let field_name = make::name(&name); - let pat = make::ident_pat(false, false, field_name.clone()); - pats.push(pat.into()); - - // => .field(field) - let method_name = make::name_ref("field"); - let field_path = &name.to_string(); - let field_path = make::expr_path(make::ext::ident_path(field_path)); - let args = make::arg_list(vec![field_path]); - expr = make::expr_method_call(expr, method_name, args); - } - - // => .finish() - let method = make::name_ref("finish"); - let expr = make::expr_method_call(expr, method, make::arg_list(None)); - - // => MyStruct (fields..) => f.debug_tuple("MyStruct")...finish(), - let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter()); - arms.push(make::match_arm(Some(pat.into()), None, expr)); - } - None => { - let fmt_string = make::expr_literal(&(format!("\"{}\"", name))).into(); - let args = make::arg_list([target, fmt_string]); - let macro_name = make::expr_path(make::ext::ident_path("write")); - let macro_call = make::expr_macro_call(macro_name, args); - - let variant_name = make::path_pat(variant_name); - arms.push(make::match_arm(Some(variant_name), None, macro_call)); - } - } - } - - let match_target = make::expr_path(make::ext::ident_path("self")); - let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1)); - let match_expr = make::expr_match(match_target, list); - - let body = make::block_expr(None, Some(match_expr)); - let body = body.indent(ast::edit::IndentLevel(1)); - ted::replace(func.body()?.syntax(), body.clone_for_update().syntax()); - Some(()) - } - - ast::Adt::Struct(strukt) => { - let name = format!("\"{}\"", annotated_name); - let args = make::arg_list(Some(make::expr_literal(&name).into())); - let target = make::expr_path(make::ext::ident_path("f")); - - let expr = match strukt.field_list() { - // => f.debug_struct("Name").finish() - None => make::expr_method_call(target, make::name_ref("debug_struct"), args), - - // => f.debug_struct("Name").field("foo", &self.foo).finish() - Some(ast::FieldList::RecordFieldList(field_list)) => { - let method = make::name_ref("debug_struct"); - let mut expr = make::expr_method_call(target, method, args); - for field in field_list.fields() { - let name = field.name()?; - let f_name = make::expr_literal(&(format!("\"{}\"", name))).into(); - let f_path = make::expr_path(make::ext::ident_path("self")); - let f_path = make::expr_ref(f_path, false); - let f_path = make::expr_field(f_path, &format!("{}", name)); - let args = make::arg_list([f_name, f_path]); - expr = make::expr_method_call(expr, make::name_ref("field"), args); - } - expr - } - - // => f.debug_tuple("Name").field(self.0).finish() - Some(ast::FieldList::TupleFieldList(field_list)) => { - let method = make::name_ref("debug_tuple"); - let mut expr = make::expr_method_call(target, method, args); - for (i, _) in field_list.fields().enumerate() { - let f_path = make::expr_path(make::ext::ident_path("self")); - let f_path = make::expr_ref(f_path, false); - let f_path = make::expr_field(f_path, &format!("{}", i)); - let method = make::name_ref("field"); - expr = make::expr_method_call(expr, method, make::arg_list(Some(f_path))); - } - expr - } - }; - - let method = make::name_ref("finish"); - let expr = make::expr_method_call(expr, method, make::arg_list(None)); - let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1)); - ted::replace(func.body()?.syntax(), body.clone_for_update().syntax()); - Some(()) - } - } -} - -/// Generate a `Debug` impl based on the fields and members of the target type. -fn gen_default_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { - fn gen_default_call() -> Option { - let fn_name = make::ext::path_from_idents(["Default", "default"])?; - Some(make::expr_call(make::expr_path(fn_name), make::arg_list(None))) - } - match adt { - // `Debug` cannot be derived for unions, so no default impl can be provided. - ast::Adt::Union(_) => None, - // Deriving `Debug` for enums is not stable yet. - ast::Adt::Enum(_) => None, - ast::Adt::Struct(strukt) => { - let expr = match strukt.field_list() { - Some(ast::FieldList::RecordFieldList(field_list)) => { - let mut fields = vec![]; - for field in field_list.fields() { - let method_call = gen_default_call()?; - let name_ref = make::name_ref(&field.name()?.to_string()); - let field = make::record_expr_field(name_ref, Some(method_call)); - fields.push(field); - } - let struct_name = make::ext::ident_path("Self"); - let fields = make::record_expr_field_list(fields); - make::record_expr(struct_name, fields).into() - } - Some(ast::FieldList::TupleFieldList(field_list)) => { - let struct_name = make::expr_path(make::ext::ident_path("Self")); - let fields = field_list - .fields() - .map(|_| gen_default_call()) - .collect::>>()?; - make::expr_call(struct_name, make::arg_list(fields)) - } - None => { - let struct_name = make::ext::ident_path("Self"); - let fields = make::record_expr_field_list(None); - make::record_expr(struct_name, fields).into() - } - }; - let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1)); - ted::replace(func.body()?.syntax(), body.clone_for_update().syntax()); - Some(()) - } - } -} - -/// Generate a `Hash` impl based on the fields and members of the target type. -fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { - stdx::always!(func.name().map_or(false, |name| name.text() == "hash")); - fn gen_hash_call(target: ast::Expr) -> ast::Stmt { - let method = make::name_ref("hash"); - let arg = make::expr_path(make::ext::ident_path("state")); - let expr = make::expr_method_call(target, method, make::arg_list(Some(arg))); - make::expr_stmt(expr).into() - } - - let body = match adt { - // `Hash` cannot be derived for unions, so no default impl can be provided. - ast::Adt::Union(_) => return None, - - // => std::mem::discriminant(self).hash(state); - ast::Adt::Enum(_) => { - let fn_name = make_discriminant()?; - - let arg = make::expr_path(make::ext::ident_path("self")); - let fn_call = make::expr_call(fn_name, make::arg_list(Some(arg))); - let stmt = gen_hash_call(fn_call); - - make::block_expr(Some(stmt), None).indent(ast::edit::IndentLevel(1)) - } - ast::Adt::Struct(strukt) => match strukt.field_list() { - // => self..hash(state); - Some(ast::FieldList::RecordFieldList(field_list)) => { - let mut stmts = vec![]; - for field in field_list.fields() { - let base = make::expr_path(make::ext::ident_path("self")); - let target = make::expr_field(base, &field.name()?.to_string()); - stmts.push(gen_hash_call(target)); - } - make::block_expr(stmts, None).indent(ast::edit::IndentLevel(1)) - } - - // => self..hash(state); - Some(ast::FieldList::TupleFieldList(field_list)) => { - let mut stmts = vec![]; - for (i, _) in field_list.fields().enumerate() { - let base = make::expr_path(make::ext::ident_path("self")); - let target = make::expr_field(base, &format!("{}", i)); - stmts.push(gen_hash_call(target)); - } - make::block_expr(stmts, None).indent(ast::edit::IndentLevel(1)) - } - - // No fields in the body means there's nothing to hash. - None => return None, - }, - }; - - ted::replace(func.body()?.syntax(), body.clone_for_update().syntax()); - Some(()) -} - -/// Generate a `PartialEq` impl based on the fields and members of the target type. -fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { - stdx::always!(func.name().map_or(false, |name| name.text() == "eq")); - fn gen_eq_chain(expr: Option, cmp: ast::Expr) -> Option { - match expr { - Some(expr) => Some(make::expr_bin_op(expr, BinaryOp::LogicOp(LogicOp::And), cmp)), - None => Some(cmp), - } - } - - fn gen_record_pat_field(field_name: &str, pat_name: &str) -> ast::RecordPatField { - let pat = make::ext::simple_ident_pat(make::name(pat_name)); - let name_ref = make::name_ref(field_name); - make::record_pat_field(name_ref, pat.into()) - } - - fn gen_record_pat(record_name: ast::Path, fields: Vec) -> ast::RecordPat { - let list = make::record_pat_field_list(fields); - make::record_pat_with_fields(record_name, list) - } - - fn gen_variant_path(variant: &ast::Variant) -> Option { - make::ext::path_from_idents(["Self", &variant.name()?.to_string()]) - } - - fn gen_tuple_field(field_name: &String) -> ast::Pat { - ast::Pat::IdentPat(make::ident_pat(false, false, make::name(field_name))) - } - - // FIXME: return `None` if the trait carries a generic type; we can only - // generate this code `Self` for the time being. - - let body = match adt { - // `PartialEq` cannot be derived for unions, so no default impl can be provided. - ast::Adt::Union(_) => return None, - - ast::Adt::Enum(enum_) => { - // => std::mem::discriminant(self) == std::mem::discriminant(other) - let lhs_name = make::expr_path(make::ext::ident_path("self")); - let lhs = make::expr_call(make_discriminant()?, make::arg_list(Some(lhs_name.clone()))); - let rhs_name = make::expr_path(make::ext::ident_path("other")); - let rhs = make::expr_call(make_discriminant()?, make::arg_list(Some(rhs_name.clone()))); - let eq_check = - make::expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs); - - let mut n_cases = 0; - let mut arms = vec![]; - for variant in enum_.variant_list()?.variants() { - n_cases += 1; - match variant.field_list() { - // => (Self::Bar { bin: l_bin }, Self::Bar { bin: r_bin }) => l_bin == r_bin, - Some(ast::FieldList::RecordFieldList(list)) => { - let mut expr = None; - let mut l_fields = vec![]; - let mut r_fields = vec![]; - - for field in list.fields() { - let field_name = field.name()?.to_string(); - - let l_name = &format!("l_{}", field_name); - l_fields.push(gen_record_pat_field(&field_name, l_name)); - - let r_name = &format!("r_{}", field_name); - r_fields.push(gen_record_pat_field(&field_name, r_name)); - - let lhs = make::expr_path(make::ext::ident_path(l_name)); - let rhs = make::expr_path(make::ext::ident_path(r_name)); - let cmp = make::expr_bin_op( - lhs, - BinaryOp::CmpOp(CmpOp::Eq { negated: false }), - rhs, - ); - expr = gen_eq_chain(expr, cmp); - } - - let left = gen_record_pat(gen_variant_path(&variant)?, l_fields); - let right = gen_record_pat(gen_variant_path(&variant)?, r_fields); - let tuple = make::tuple_pat(vec![left.into(), right.into()]); - - if let Some(expr) = expr { - arms.push(make::match_arm(Some(tuple.into()), None, expr)); - } - } - - Some(ast::FieldList::TupleFieldList(list)) => { - let mut expr = None; - let mut l_fields = vec![]; - let mut r_fields = vec![]; - - for (i, _) in list.fields().enumerate() { - let field_name = format!("{}", i); - - let l_name = format!("l{}", field_name); - l_fields.push(gen_tuple_field(&l_name)); - - let r_name = format!("r{}", field_name); - r_fields.push(gen_tuple_field(&r_name)); - - let lhs = make::expr_path(make::ext::ident_path(&l_name)); - let rhs = make::expr_path(make::ext::ident_path(&r_name)); - let cmp = make::expr_bin_op( - lhs, - BinaryOp::CmpOp(CmpOp::Eq { negated: false }), - rhs, - ); - expr = gen_eq_chain(expr, cmp); - } - - let left = make::tuple_struct_pat(gen_variant_path(&variant)?, l_fields); - let right = make::tuple_struct_pat(gen_variant_path(&variant)?, r_fields); - let tuple = make::tuple_pat(vec![left.into(), right.into()]); - - if let Some(expr) = expr { - arms.push(make::match_arm(Some(tuple.into()), None, expr)); - } - } - None => continue, - } - } - - let expr = match arms.len() { - 0 => eq_check, - _ => { - if n_cases > arms.len() { - let lhs = make::wildcard_pat().into(); - arms.push(make::match_arm(Some(lhs), None, eq_check)); - } - - let match_target = make::expr_tuple(vec![lhs_name, rhs_name]); - let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1)); - make::expr_match(match_target, list) - } - }; - - make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1)) - } - ast::Adt::Struct(strukt) => match strukt.field_list() { - Some(ast::FieldList::RecordFieldList(field_list)) => { - let mut expr = None; - for field in field_list.fields() { - let lhs = make::expr_path(make::ext::ident_path("self")); - let lhs = make::expr_field(lhs, &field.name()?.to_string()); - let rhs = make::expr_path(make::ext::ident_path("other")); - let rhs = make::expr_field(rhs, &field.name()?.to_string()); - let cmp = - make::expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs); - expr = gen_eq_chain(expr, cmp); - } - make::block_expr(None, expr).indent(ast::edit::IndentLevel(1)) - } - - Some(ast::FieldList::TupleFieldList(field_list)) => { - let mut expr = None; - for (i, _) in field_list.fields().enumerate() { - let idx = format!("{}", i); - let lhs = make::expr_path(make::ext::ident_path("self")); - let lhs = make::expr_field(lhs, &idx); - let rhs = make::expr_path(make::ext::ident_path("other")); - let rhs = make::expr_field(rhs, &idx); - let cmp = - make::expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs); - expr = gen_eq_chain(expr, cmp); - } - make::block_expr(None, expr).indent(ast::edit::IndentLevel(1)) - } - - // No fields in the body means there's nothing to hash. - None => { - let expr = make::expr_literal("true").into(); - make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1)) - } - }, - }; - - ted::replace(func.body()?.syntax(), body.clone_for_update().syntax()); - Some(()) -} - -fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { - stdx::always!(func.name().map_or(false, |name| name.text() == "partial_cmp")); - fn gen_partial_eq_match(match_target: ast::Expr) -> Option { - let mut arms = vec![]; - - let variant_name = - make::path_pat(make::ext::path_from_idents(["core", "cmp", "Ordering", "Equal"])?); - let lhs = make::tuple_struct_pat(make::ext::path_from_idents(["Some"])?, [variant_name]); - arms.push(make::match_arm(Some(lhs.into()), None, make::expr_empty_block())); - - arms.push(make::match_arm( - [make::ident_pat(false, false, make::name("ord")).into()], - None, - make::expr_return(Some(make::expr_path(make::ext::ident_path("ord")))), - )); - let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1)); - Some(make::expr_stmt(make::expr_match(match_target, list)).into()) - } - - fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr { - let rhs = make::expr_ref(rhs, false); - let method = make::name_ref("partial_cmp"); - make::expr_method_call(lhs, method, make::arg_list(Some(rhs))) - } - - // FIXME: return `None` if the trait carries a generic type; we can only - // generate this code `Self` for the time being. - - let body = match adt { - // `PartialOrd` cannot be derived for unions, so no default impl can be provided. - ast::Adt::Union(_) => return None, - // `core::mem::Discriminant` does not implement `PartialOrd` in stable Rust today. - ast::Adt::Enum(_) => return None, - ast::Adt::Struct(strukt) => match strukt.field_list() { - Some(ast::FieldList::RecordFieldList(field_list)) => { - let mut exprs = vec![]; - for field in field_list.fields() { - let lhs = make::expr_path(make::ext::ident_path("self")); - let lhs = make::expr_field(lhs, &field.name()?.to_string()); - let rhs = make::expr_path(make::ext::ident_path("other")); - let rhs = make::expr_field(rhs, &field.name()?.to_string()); - let ord = gen_partial_cmp_call(lhs, rhs); - exprs.push(ord); - } - - let tail = exprs.pop(); - let stmts = exprs - .into_iter() - .map(gen_partial_eq_match) - .collect::>>()?; - make::block_expr(stmts.into_iter(), tail).indent(ast::edit::IndentLevel(1)) - } - - Some(ast::FieldList::TupleFieldList(field_list)) => { - let mut exprs = vec![]; - for (i, _) in field_list.fields().enumerate() { - let idx = format!("{}", i); - let lhs = make::expr_path(make::ext::ident_path("self")); - let lhs = make::expr_field(lhs, &idx); - let rhs = make::expr_path(make::ext::ident_path("other")); - let rhs = make::expr_field(rhs, &idx); - let ord = gen_partial_cmp_call(lhs, rhs); - exprs.push(ord); - } - let tail = exprs.pop(); - let stmts = exprs - .into_iter() - .map(gen_partial_eq_match) - .collect::>>()?; - make::block_expr(stmts.into_iter(), tail).indent(ast::edit::IndentLevel(1)) - } - - // No fields in the body means there's nothing to compare. - None => { - let expr = make::expr_literal("true").into(); - make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1)) - } - }, - }; - - ted::replace(func.body()?.syntax(), body.clone_for_update().syntax()); - Some(()) -} - -fn make_discriminant() -> Option { - Some(make::expr_path(make::ext::path_from_idents(["core", "mem", "discriminant"])?)) -} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs deleted file mode 100644 index 779cdbc93c54a..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs +++ /dev/null @@ -1,775 +0,0 @@ -//! This module contains functions to suggest names for expressions, functions and other items - -use hir::Semantics; -use ide_db::RootDatabase; -use itertools::Itertools; -use stdx::to_lower_snake_case; -use syntax::{ - ast::{self, HasName}, - match_ast, AstNode, SmolStr, -}; - -/// Trait names, that will be ignored when in `impl Trait` and `dyn Trait` -const USELESS_TRAITS: &[&str] = &["Send", "Sync", "Copy", "Clone", "Eq", "PartialEq"]; - -/// Identifier names that won't be suggested, ever -/// -/// **NOTE**: they all must be snake lower case -const USELESS_NAMES: &[&str] = - &["new", "default", "option", "some", "none", "ok", "err", "str", "string"]; - -/// Generic types replaced by their first argument -/// -/// # Examples -/// `Option` -> `Name` -/// `Result` -> `User` -const WRAPPER_TYPES: &[&str] = &["Box", "Option", "Result"]; - -/// Prefixes to strip from methods names -/// -/// # Examples -/// `vec.as_slice()` -> `slice` -/// `args.into_config()` -> `config` -/// `bytes.to_vec()` -> `vec` -const USELESS_METHOD_PREFIXES: &[&str] = &["into_", "as_", "to_"]; - -/// Useless methods that are stripped from expression -/// -/// # Examples -/// `var.name().to_string()` -> `var.name()` -const USELESS_METHODS: &[&str] = &[ - "to_string", - "as_str", - "to_owned", - "as_ref", - "clone", - "cloned", - "expect", - "expect_none", - "unwrap", - "unwrap_none", - "unwrap_or", - "unwrap_or_default", - "unwrap_or_else", - "unwrap_unchecked", - "iter", - "into_iter", - "iter_mut", -]; - -pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr { - let c = ty - .type_bound_list() - .and_then(|bounds| bounds.syntax().text().char_at(0.into())) - .unwrap_or('T'); - c.encode_utf8(&mut [0; 4]).into() -} - -/// Suggest name of variable for given expression -/// -/// **NOTE**: it is caller's responsibility to guarantee uniqueness of the name. -/// I.e. it doesn't look for names in scope. -/// -/// # Current implementation -/// -/// In current implementation, the function tries to get the name from -/// the following sources: -/// -/// * if expr is an argument to function/method, use paramter name -/// * if expr is a function/method call, use function name -/// * expression type name if it exists (E.g. `()`, `fn() -> ()` or `!` do not have names) -/// * fallback: `var_name` -/// -/// It also applies heuristics to filter out less informative names -/// -/// Currently it sticks to the first name found. -// FIXME: Microoptimize and return a `SmolStr` here. -pub(crate) fn for_variable(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> String { - // `from_param` does not benifit from stripping - // it need the largest context possible - // so we check firstmost - if let Some(name) = from_param(expr, sema) { - return name; - } - - let mut next_expr = Some(expr.clone()); - while let Some(expr) = next_expr { - let name = - from_call(&expr).or_else(|| from_type(&expr, sema)).or_else(|| from_field_name(&expr)); - if let Some(name) = name { - return name; - } - - match expr { - ast::Expr::RefExpr(inner) => next_expr = inner.expr(), - ast::Expr::BoxExpr(inner) => next_expr = inner.expr(), - ast::Expr::AwaitExpr(inner) => next_expr = inner.expr(), - // ast::Expr::BlockExpr(block) => expr = block.tail_expr(), - ast::Expr::CastExpr(inner) => next_expr = inner.expr(), - ast::Expr::MethodCallExpr(method) if is_useless_method(&method) => { - next_expr = method.receiver(); - } - ast::Expr::ParenExpr(inner) => next_expr = inner.expr(), - ast::Expr::TryExpr(inner) => next_expr = inner.expr(), - ast::Expr::PrefixExpr(prefix) if prefix.op_kind() == Some(ast::UnaryOp::Deref) => { - next_expr = prefix.expr() - } - _ => break, - } - } - - "var_name".to_string() -} - -fn normalize(name: &str) -> Option { - let name = to_lower_snake_case(name); - - if USELESS_NAMES.contains(&name.as_str()) { - return None; - } - - if !is_valid_name(&name) { - return None; - } - - Some(name) -} - -fn is_valid_name(name: &str) -> bool { - match ide_db::syntax_helpers::LexedStr::single_token(name) { - Some((syntax::SyntaxKind::IDENT, _error)) => true, - _ => false, - } -} - -fn is_useless_method(method: &ast::MethodCallExpr) -> bool { - let ident = method.name_ref().and_then(|it| it.ident_token()); - - match ident { - Some(ident) => USELESS_METHODS.contains(&ident.text()), - None => false, - } -} - -fn from_call(expr: &ast::Expr) -> Option { - from_func_call(expr).or_else(|| from_method_call(expr)) -} - -fn from_func_call(expr: &ast::Expr) -> Option { - let call = match expr { - ast::Expr::CallExpr(call) => call, - _ => return None, - }; - let func = match call.expr()? { - ast::Expr::PathExpr(path) => path, - _ => return None, - }; - let ident = func.path()?.segment()?.name_ref()?.ident_token()?; - normalize(ident.text()) -} - -fn from_method_call(expr: &ast::Expr) -> Option { - let method = match expr { - ast::Expr::MethodCallExpr(call) => call, - _ => return None, - }; - let ident = method.name_ref()?.ident_token()?; - let mut name = ident.text(); - - if USELESS_METHODS.contains(&name) { - return None; - } - - for prefix in USELESS_METHOD_PREFIXES { - if let Some(suffix) = name.strip_prefix(prefix) { - name = suffix; - break; - } - } - - normalize(name) -} - -fn from_param(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option { - let arg_list = expr.syntax().parent().and_then(ast::ArgList::cast)?; - let args_parent = arg_list.syntax().parent()?; - let func = match_ast! { - match args_parent { - ast::CallExpr(call) => { - let func = call.expr()?; - let func_ty = sema.type_of_expr(&func)?.adjusted(); - func_ty.as_callable(sema.db)? - }, - ast::MethodCallExpr(method) => sema.resolve_method_call_as_callable(&method)?, - _ => return None, - } - }; - - let (idx, _) = arg_list.args().find_position(|it| it == expr).unwrap(); - let (pat, _) = func.params(sema.db).into_iter().nth(idx)?; - let pat = match pat? { - either::Either::Right(pat) => pat, - _ => return None, - }; - let name = var_name_from_pat(&pat)?; - normalize(&name.to_string()) -} - -fn var_name_from_pat(pat: &ast::Pat) -> Option { - match pat { - ast::Pat::IdentPat(var) => var.name(), - ast::Pat::RefPat(ref_pat) => var_name_from_pat(&ref_pat.pat()?), - ast::Pat::BoxPat(box_pat) => var_name_from_pat(&box_pat.pat()?), - _ => None, - } -} - -fn from_type(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option { - let ty = sema.type_of_expr(expr)?.adjusted(); - let ty = ty.remove_ref().unwrap_or(ty); - - name_of_type(&ty, sema.db) -} - -fn name_of_type(ty: &hir::Type, db: &RootDatabase) -> Option { - let name = if let Some(adt) = ty.as_adt() { - let name = adt.name(db).to_string(); - - if WRAPPER_TYPES.contains(&name.as_str()) { - let inner_ty = ty.type_arguments().next()?; - return name_of_type(&inner_ty, db); - } - - name - } else if let Some(trait_) = ty.as_dyn_trait() { - trait_name(&trait_, db)? - } else if let Some(traits) = ty.as_impl_traits(db) { - let mut iter = traits.filter_map(|t| trait_name(&t, db)); - let name = iter.next()?; - if iter.next().is_some() { - return None; - } - name - } else { - return None; - }; - normalize(&name) -} - -fn trait_name(trait_: &hir::Trait, db: &RootDatabase) -> Option { - let name = trait_.name(db).to_string(); - if USELESS_TRAITS.contains(&name.as_str()) { - return None; - } - Some(name) -} - -fn from_field_name(expr: &ast::Expr) -> Option { - let field = match expr { - ast::Expr::FieldExpr(field) => field, - _ => return None, - }; - let ident = field.name_ref()?.ident_token()?; - normalize(ident.text()) -} - -#[cfg(test)] -mod tests { - use ide_db::base_db::{fixture::WithFixture, FileRange}; - - use super::*; - - #[track_caller] - fn check(ra_fixture: &str, expected: &str) { - let (db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture); - let frange = FileRange { file_id, range: range_or_offset.into() }; - - let sema = Semantics::new(&db); - let source_file = sema.parse(frange.file_id); - let element = source_file.syntax().covering_element(frange.range); - let expr = - element.ancestors().find_map(ast::Expr::cast).expect("selection is not an expression"); - assert_eq!( - expr.syntax().text_range(), - frange.range, - "selection is not an expression(yet contained in one)" - ); - let name = for_variable(&expr, &sema); - assert_eq!(&name, expected); - } - - #[test] - fn no_args() { - check(r#"fn foo() { $0bar()$0 }"#, "bar"); - check(r#"fn foo() { $0bar.frobnicate()$0 }"#, "frobnicate"); - } - - #[test] - fn single_arg() { - check(r#"fn foo() { $0bar(1)$0 }"#, "bar"); - } - - #[test] - fn many_args() { - check(r#"fn foo() { $0bar(1, 2, 3)$0 }"#, "bar"); - } - - #[test] - fn path() { - check(r#"fn foo() { $0i32::bar(1, 2, 3)$0 }"#, "bar"); - } - - #[test] - fn generic_params() { - check(r#"fn foo() { $0bar::(1, 2, 3)$0 }"#, "bar"); - check(r#"fn foo() { $0bar.frobnicate::()$0 }"#, "frobnicate"); - } - - #[test] - fn to_name() { - check( - r#" -struct Args; -struct Config; -impl Args { - fn to_config(&self) -> Config {} -} -fn foo() { - $0Args.to_config()$0; -} -"#, - "config", - ); - } - - #[test] - fn plain_func() { - check( - r#" -fn bar(n: i32, m: u32); -fn foo() { bar($01$0, 2) } -"#, - "n", - ); - } - - #[test] - fn mut_param() { - check( - r#" -fn bar(mut n: i32, m: u32); -fn foo() { bar($01$0, 2) } -"#, - "n", - ); - } - - #[test] - fn func_does_not_exist() { - check(r#"fn foo() { bar($01$0, 2) }"#, "var_name"); - } - - #[test] - fn unnamed_param() { - check( - r#" -fn bar(_: i32, m: u32); -fn foo() { bar($01$0, 2) } -"#, - "var_name", - ); - } - - #[test] - fn tuple_pat() { - check( - r#" -fn bar((n, k): (i32, i32), m: u32); -fn foo() { - bar($0(1, 2)$0, 3) -} -"#, - "var_name", - ); - } - - #[test] - fn ref_pat() { - check( - r#" -fn bar(&n: &i32, m: u32); -fn foo() { bar($0&1$0, 3) } -"#, - "n", - ); - } - - #[test] - fn box_pat() { - check( - r#" -fn bar(box n: &i32, m: u32); -fn foo() { bar($01$0, 3) } -"#, - "n", - ); - } - - #[test] - fn param_out_of_index() { - check( - r#" -fn bar(n: i32, m: u32); -fn foo() { bar(1, 2, $03$0) } -"#, - "var_name", - ); - } - - #[test] - fn generic_param_resolved() { - check( - r#" -fn bar(n: T, m: u32); -fn foo() { bar($01$0, 2) } -"#, - "n", - ); - } - - #[test] - fn generic_param_unresolved() { - check( - r#" -fn bar(n: T, m: u32); -fn foo(x: T) { bar($0x$0, 2) } -"#, - "n", - ); - } - - #[test] - fn method() { - check( - r#" -struct S; -impl S { fn bar(&self, n: i32, m: u32); } -fn foo() { S.bar($01$0, 2) } -"#, - "n", - ); - } - - #[test] - fn method_on_impl_trait() { - check( - r#" -struct S; -trait T { - fn bar(&self, n: i32, m: u32); -} -impl T for S { fn bar(&self, n: i32, m: u32); } -fn foo() { S.bar($01$0, 2) } -"#, - "n", - ); - } - - #[test] - fn method_ufcs() { - check( - r#" -struct S; -impl S { fn bar(&self, n: i32, m: u32); } -fn foo() { S::bar(&S, $01$0, 2) } -"#, - "n", - ); - } - - #[test] - fn method_self() { - check( - r#" -struct S; -impl S { fn bar(&self, n: i32, m: u32); } -fn foo() { S::bar($0&S$0, 1, 2) } -"#, - "s", - ); - } - - #[test] - fn method_self_named() { - check( - r#" -struct S; -impl S { fn bar(strukt: &Self, n: i32, m: u32); } -fn foo() { S::bar($0&S$0, 1, 2) } -"#, - "strukt", - ); - } - - #[test] - fn i32() { - check(r#"fn foo() { let _: i32 = $01$0; }"#, "var_name"); - } - - #[test] - fn u64() { - check(r#"fn foo() { let _: u64 = $01$0; }"#, "var_name"); - } - - #[test] - fn bool() { - check(r#"fn foo() { let _: bool = $0true$0; }"#, "var_name"); - } - - #[test] - fn struct_unit() { - check( - r#" -struct Seed; -fn foo() { let _ = $0Seed$0; } -"#, - "seed", - ); - } - - #[test] - fn struct_unit_to_snake() { - check( - r#" -struct SeedState; -fn foo() { let _ = $0SeedState$0; } -"#, - "seed_state", - ); - } - - #[test] - fn struct_single_arg() { - check( - r#" -struct Seed(u32); -fn foo() { let _ = $0Seed(0)$0; } -"#, - "seed", - ); - } - - #[test] - fn struct_with_fields() { - check( - r#" -struct Seed { value: u32 } -fn foo() { let _ = $0Seed { value: 0 }$0; } -"#, - "seed", - ); - } - - #[test] - fn enum_() { - check( - r#" -enum Kind { A, B } -fn foo() { let _ = $0Kind::A$0; } -"#, - "kind", - ); - } - - #[test] - fn enum_generic_resolved() { - check( - r#" -enum Kind { A { x: T }, B } -fn foo() { let _ = $0Kind::A { x:1 }$0; } -"#, - "kind", - ); - } - - #[test] - fn enum_generic_unresolved() { - check( - r#" -enum Kind { A { x: T }, B } -fn foo(x: T) { let _ = $0Kind::A { x }$0; } -"#, - "kind", - ); - } - - #[test] - fn dyn_trait() { - check( - r#" -trait DynHandler {} -fn bar() -> dyn DynHandler {} -fn foo() { $0(bar())$0; } -"#, - "dyn_handler", - ); - } - - #[test] - fn impl_trait() { - check( - r#" -trait StaticHandler {} -fn bar() -> impl StaticHandler {} -fn foo() { $0(bar())$0; } -"#, - "static_handler", - ); - } - - #[test] - fn impl_trait_plus_clone() { - check( - r#" -trait StaticHandler {} -trait Clone {} -fn bar() -> impl StaticHandler + Clone {} -fn foo() { $0(bar())$0; } -"#, - "static_handler", - ); - } - - #[test] - fn impl_trait_plus_lifetime() { - check( - r#" -trait StaticHandler {} -trait Clone {} -fn bar<'a>(&'a i32) -> impl StaticHandler + 'a {} -fn foo() { $0(bar(&1))$0; } -"#, - "static_handler", - ); - } - - #[test] - fn impl_trait_plus_trait() { - check( - r#" -trait Handler {} -trait StaticHandler {} -fn bar() -> impl StaticHandler + Handler {} -fn foo() { $0(bar())$0; } -"#, - "bar", - ); - } - - #[test] - fn ref_value() { - check( - r#" -struct Seed; -fn bar() -> &Seed {} -fn foo() { $0(bar())$0; } -"#, - "seed", - ); - } - - #[test] - fn box_value() { - check( - r#" -struct Box(*const T); -struct Seed; -fn bar() -> Box {} -fn foo() { $0(bar())$0; } -"#, - "seed", - ); - } - - #[test] - fn box_generic() { - check( - r#" -struct Box(*const T); -fn bar() -> Box {} -fn foo() { $0(bar::())$0; } -"#, - "bar", - ); - } - - #[test] - fn option_value() { - check( - r#" -enum Option { Some(T) } -struct Seed; -fn bar() -> Option {} -fn foo() { $0(bar())$0; } -"#, - "seed", - ); - } - - #[test] - fn result_value() { - check( - r#" -enum Result { Ok(T), Err(E) } -struct Seed; -struct Error; -fn bar() -> Result {} -fn foo() { $0(bar())$0; } -"#, - "seed", - ); - } - - #[test] - fn ref_call() { - check( - r#" -fn foo() { $0&bar(1, 3)$0 } -"#, - "bar", - ); - } - - #[test] - fn name_to_string() { - check( - r#" -fn foo() { $0function.name().to_string()$0 } -"#, - "name", - ); - } - - #[test] - fn nested_useless_method() { - check( - r#" -fn foo() { $0function.name().as_ref().unwrap().to_string()$0 } -"#, - "name", - ); - } - - #[test] - fn struct_field_name() { - check( - r#" -struct S { - some_field: T; -} -fn foo(some_struct: S) { $0some_struct.some_field$0 } -"#, - "some_field", - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml deleted file mode 100644 index 8c9d6b228648e..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "ide-completion" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -cov-mark = "2.0.0-pre.1" -itertools = "0.10.3" - -once_cell = "1.12.0" -smallvec = "1.9.0" - -stdx = { path = "../stdx", version = "0.0.0" } -syntax = { path = "../syntax", version = "0.0.0" } -text-edit = { path = "../text-edit", version = "0.0.0" } -base-db = { path = "../base-db", version = "0.0.0" } -ide-db = { path = "../ide-db", version = "0.0.0" } -profile = { path = "../profile", version = "0.0.0" } - -# completions crate should depend only on the top-level `hir` package. if you need -# something from some `hir-xxx` subpackage, reexport the API via `hir`. -hir = { path = "../hir", version = "0.0.0" } - -[dev-dependencies] -expect-test = "1.4.0" - -test-utils = { path = "../test-utils" } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs deleted file mode 100644 index 149afcac9d478..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ /dev/null @@ -1,682 +0,0 @@ -//! This module defines an accumulator for completions which are going to be presented to user. - -pub(crate) mod attribute; -pub(crate) mod dot; -pub(crate) mod expr; -pub(crate) mod extern_abi; -pub(crate) mod field; -pub(crate) mod flyimport; -pub(crate) mod fn_param; -pub(crate) mod format_string; -pub(crate) mod item_list; -pub(crate) mod keyword; -pub(crate) mod lifetime; -pub(crate) mod mod_; -pub(crate) mod pattern; -pub(crate) mod postfix; -pub(crate) mod record; -pub(crate) mod snippet; -pub(crate) mod r#type; -pub(crate) mod use_; -pub(crate) mod vis; - -use std::iter; - -use hir::{known, ScopeDef}; -use ide_db::{imports::import_assets::LocatedImport, SymbolKind}; -use syntax::ast; - -use crate::{ - context::{ - DotAccess, ItemListKind, NameContext, NameKind, NameRefContext, NameRefKind, - PathCompletionCtx, PathKind, PatternContext, TypeLocation, Visible, - }, - item::Builder, - render::{ - const_::render_const, - function::{render_fn, render_method}, - literal::{render_struct_literal, render_variant_lit}, - macro_::render_macro, - pattern::{render_struct_pat, render_variant_pat}, - render_field, render_path_resolution, render_pattern_resolution, render_tuple_field, - type_alias::{render_type_alias, render_type_alias_with_eq}, - union_literal::render_union_literal, - RenderContext, - }, - CompletionContext, CompletionItem, CompletionItemKind, -}; - -/// Represents an in-progress set of completions being built. -#[derive(Debug, Default)] -pub struct Completions { - buf: Vec, -} - -impl From for Vec { - fn from(val: Completions) -> Self { - val.buf - } -} - -impl Builder { - /// Convenience method, which allows to add a freshly created completion into accumulator - /// without binding it to the variable. - pub(crate) fn add_to(self, acc: &mut Completions) { - acc.add(self.build()) - } -} - -impl Completions { - fn add(&mut self, item: CompletionItem) { - self.buf.push(item) - } - - fn add_opt(&mut self, item: Option) { - if let Some(item) = item { - self.buf.push(item) - } - } - - pub(crate) fn add_all(&mut self, items: I) - where - I: IntoIterator, - I::Item: Into, - { - items.into_iter().for_each(|item| self.add(item.into())) - } - - pub(crate) fn add_keyword(&mut self, ctx: &CompletionContext<'_>, keyword: &'static str) { - let item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), keyword); - item.add_to(self); - } - - pub(crate) fn add_nameref_keywords_with_colon(&mut self, ctx: &CompletionContext<'_>) { - ["self::", "crate::"].into_iter().for_each(|kw| self.add_keyword(ctx, kw)); - - if ctx.depth_from_crate_root > 0 { - self.add_keyword(ctx, "super::"); - } - } - - pub(crate) fn add_nameref_keywords(&mut self, ctx: &CompletionContext<'_>) { - ["self", "crate"].into_iter().for_each(|kw| self.add_keyword(ctx, kw)); - - if ctx.depth_from_crate_root > 0 { - self.add_keyword(ctx, "super"); - } - } - - pub(crate) fn add_super_keyword( - &mut self, - ctx: &CompletionContext<'_>, - super_chain_len: Option, - ) { - if let Some(len) = super_chain_len { - if len > 0 && len < ctx.depth_from_crate_root { - self.add_keyword(ctx, "super::"); - } - } - } - - pub(crate) fn add_keyword_snippet_expr( - &mut self, - ctx: &CompletionContext<'_>, - incomplete_let: bool, - kw: &str, - snippet: &str, - ) { - let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw); - - match ctx.config.snippet_cap { - Some(cap) => { - if incomplete_let && snippet.ends_with('}') { - // complete block expression snippets with a trailing semicolon, if inside an incomplete let - cov_mark::hit!(let_semi); - item.insert_snippet(cap, format!("{};", snippet)); - } else { - item.insert_snippet(cap, snippet); - } - } - None => { - item.insert_text(if snippet.contains('$') { kw } else { snippet }); - } - }; - item.add_to(self); - } - - pub(crate) fn add_keyword_snippet( - &mut self, - ctx: &CompletionContext<'_>, - kw: &str, - snippet: &str, - ) { - let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw); - - match ctx.config.snippet_cap { - Some(cap) => item.insert_snippet(cap, snippet), - None => item.insert_text(if snippet.contains('$') { kw } else { snippet }), - }; - item.add_to(self); - } - - pub(crate) fn add_crate_roots( - &mut self, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - ) { - ctx.process_all_names(&mut |name, res| match res { - ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => { - self.add_module(ctx, path_ctx, m, name); - } - _ => (), - }); - } - - pub(crate) fn add_path_resolution( - &mut self, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - local_name: hir::Name, - resolution: hir::ScopeDef, - ) { - let is_private_editable = match ctx.def_is_visible(&resolution) { - Visible::Yes => false, - Visible::Editable => true, - Visible::No => return, - }; - self.add( - render_path_resolution( - RenderContext::new(ctx).private_editable(is_private_editable), - path_ctx, - local_name, - resolution, - ) - .build(), - ); - } - - pub(crate) fn add_pattern_resolution( - &mut self, - ctx: &CompletionContext<'_>, - pattern_ctx: &PatternContext, - local_name: hir::Name, - resolution: hir::ScopeDef, - ) { - let is_private_editable = match ctx.def_is_visible(&resolution) { - Visible::Yes => false, - Visible::Editable => true, - Visible::No => return, - }; - self.add( - render_pattern_resolution( - RenderContext::new(ctx).private_editable(is_private_editable), - pattern_ctx, - local_name, - resolution, - ) - .build(), - ); - } - - pub(crate) fn add_enum_variants( - &mut self, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - e: hir::Enum, - ) { - e.variants(ctx.db) - .into_iter() - .for_each(|variant| self.add_enum_variant(ctx, path_ctx, variant, None)); - } - - pub(crate) fn add_module( - &mut self, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - module: hir::Module, - local_name: hir::Name, - ) { - self.add_path_resolution( - ctx, - path_ctx, - local_name, - hir::ScopeDef::ModuleDef(module.into()), - ); - } - - pub(crate) fn add_macro( - &mut self, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - mac: hir::Macro, - local_name: hir::Name, - ) { - let is_private_editable = match ctx.is_visible(&mac) { - Visible::Yes => false, - Visible::Editable => true, - Visible::No => return, - }; - self.add( - render_macro( - RenderContext::new(ctx).private_editable(is_private_editable), - path_ctx, - local_name, - mac, - ) - .build(), - ); - } - - pub(crate) fn add_function( - &mut self, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - func: hir::Function, - local_name: Option, - ) { - let is_private_editable = match ctx.is_visible(&func) { - Visible::Yes => false, - Visible::Editable => true, - Visible::No => return, - }; - self.add( - render_fn( - RenderContext::new(ctx).private_editable(is_private_editable), - path_ctx, - local_name, - func, - ) - .build(), - ); - } - - pub(crate) fn add_method( - &mut self, - ctx: &CompletionContext<'_>, - dot_access: &DotAccess, - func: hir::Function, - receiver: Option, - local_name: Option, - ) { - let is_private_editable = match ctx.is_visible(&func) { - Visible::Yes => false, - Visible::Editable => true, - Visible::No => return, - }; - self.add( - render_method( - RenderContext::new(ctx).private_editable(is_private_editable), - dot_access, - receiver, - local_name, - func, - ) - .build(), - ); - } - - pub(crate) fn add_method_with_import( - &mut self, - ctx: &CompletionContext<'_>, - dot_access: &DotAccess, - func: hir::Function, - import: LocatedImport, - ) { - let is_private_editable = match ctx.is_visible(&func) { - Visible::Yes => false, - Visible::Editable => true, - Visible::No => return, - }; - self.add( - render_method( - RenderContext::new(ctx) - .private_editable(is_private_editable) - .import_to_add(Some(import)), - dot_access, - None, - None, - func, - ) - .build(), - ); - } - - pub(crate) fn add_const(&mut self, ctx: &CompletionContext<'_>, konst: hir::Const) { - let is_private_editable = match ctx.is_visible(&konst) { - Visible::Yes => false, - Visible::Editable => true, - Visible::No => return, - }; - self.add_opt(render_const( - RenderContext::new(ctx).private_editable(is_private_editable), - konst, - )); - } - - pub(crate) fn add_type_alias( - &mut self, - ctx: &CompletionContext<'_>, - type_alias: hir::TypeAlias, - ) { - let is_private_editable = match ctx.is_visible(&type_alias) { - Visible::Yes => false, - Visible::Editable => true, - Visible::No => return, - }; - self.add_opt(render_type_alias( - RenderContext::new(ctx).private_editable(is_private_editable), - type_alias, - )); - } - - pub(crate) fn add_type_alias_with_eq( - &mut self, - ctx: &CompletionContext<'_>, - type_alias: hir::TypeAlias, - ) { - self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias)); - } - - pub(crate) fn add_qualified_enum_variant( - &mut self, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - variant: hir::Variant, - path: hir::ModPath, - ) { - if let Some(builder) = - render_variant_lit(RenderContext::new(ctx), path_ctx, None, variant, Some(path)) - { - self.add(builder.build()); - } - } - - pub(crate) fn add_enum_variant( - &mut self, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - variant: hir::Variant, - local_name: Option, - ) { - if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx { - cov_mark::hit!(enum_variant_pattern_path); - self.add_variant_pat(ctx, pat_ctx, variant, local_name); - return; - } - - if let Some(builder) = - render_variant_lit(RenderContext::new(ctx), path_ctx, local_name, variant, None) - { - self.add(builder.build()); - } - } - - pub(crate) fn add_field( - &mut self, - ctx: &CompletionContext<'_>, - dot_access: &DotAccess, - receiver: Option, - field: hir::Field, - ty: &hir::Type, - ) { - let is_private_editable = match ctx.is_visible(&field) { - Visible::Yes => false, - Visible::Editable => true, - Visible::No => return, - }; - let item = render_field( - RenderContext::new(ctx).private_editable(is_private_editable), - dot_access, - receiver, - field, - ty, - ); - self.add(item); - } - - pub(crate) fn add_struct_literal( - &mut self, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - strukt: hir::Struct, - path: Option, - local_name: Option, - ) { - if let Some(builder) = - render_struct_literal(RenderContext::new(ctx), path_ctx, strukt, path, local_name) - { - self.add(builder.build()); - } - } - - pub(crate) fn add_union_literal( - &mut self, - ctx: &CompletionContext<'_>, - un: hir::Union, - path: Option, - local_name: Option, - ) { - let item = render_union_literal(RenderContext::new(ctx), un, path, local_name); - self.add_opt(item); - } - - pub(crate) fn add_tuple_field( - &mut self, - ctx: &CompletionContext<'_>, - receiver: Option, - field: usize, - ty: &hir::Type, - ) { - let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty); - self.add(item); - } - - pub(crate) fn add_lifetime(&mut self, ctx: &CompletionContext<'_>, name: hir::Name) { - CompletionItem::new(SymbolKind::LifetimeParam, ctx.source_range(), name.to_smol_str()) - .add_to(self) - } - - pub(crate) fn add_label(&mut self, ctx: &CompletionContext<'_>, name: hir::Name) { - CompletionItem::new(SymbolKind::Label, ctx.source_range(), name.to_smol_str()).add_to(self) - } - - pub(crate) fn add_variant_pat( - &mut self, - ctx: &CompletionContext<'_>, - pattern_ctx: &PatternContext, - variant: hir::Variant, - local_name: Option, - ) { - self.add_opt(render_variant_pat( - RenderContext::new(ctx), - pattern_ctx, - variant, - local_name.clone(), - None, - )); - } - - pub(crate) fn add_qualified_variant_pat( - &mut self, - ctx: &CompletionContext<'_>, - pattern_ctx: &PatternContext, - variant: hir::Variant, - path: hir::ModPath, - ) { - let path = Some(&path); - self.add_opt(render_variant_pat(RenderContext::new(ctx), pattern_ctx, variant, None, path)); - } - - pub(crate) fn add_struct_pat( - &mut self, - ctx: &CompletionContext<'_>, - pattern_ctx: &PatternContext, - strukt: hir::Struct, - local_name: Option, - ) { - self.add_opt(render_struct_pat(RenderContext::new(ctx), pattern_ctx, strukt, local_name)); - } -} - -/// Calls the callback for each variant of the provided enum with the path to the variant. -/// Skips variants that are visible with single segment paths. -fn enum_variants_with_paths( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - enum_: hir::Enum, - impl_: &Option, - cb: impl Fn(&mut Completions, &CompletionContext<'_>, hir::Variant, hir::ModPath), -) { - let variants = enum_.variants(ctx.db); - - if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { - if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) { - for &variant in &variants { - let self_path = hir::ModPath::from_segments( - hir::PathKind::Plain, - iter::once(known::SELF_TYPE).chain(iter::once(variant.name(ctx.db))), - ); - cb(acc, ctx, variant, self_path); - } - } - } - - for variant in variants { - if let Some(path) = ctx.module.find_use_path(ctx.db, hir::ModuleDef::from(variant)) { - // Variants with trivial paths are already added by the existing completion logic, - // so we should avoid adding these twice - if path.segments().len() > 1 { - cb(acc, ctx, variant, path); - } - } - } -} - -pub(super) fn complete_name( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - NameContext { name, kind }: &NameContext, -) { - match kind { - NameKind::Const => { - item_list::trait_impl::complete_trait_impl_const(acc, ctx, name); - } - NameKind::Function => { - item_list::trait_impl::complete_trait_impl_fn(acc, ctx, name); - } - NameKind::IdentPat(pattern_ctx) => { - if ctx.token.kind() != syntax::T![_] { - complete_patterns(acc, ctx, pattern_ctx) - } - } - NameKind::Module(mod_under_caret) => { - mod_::complete_mod(acc, ctx, mod_under_caret); - } - NameKind::TypeAlias => { - item_list::trait_impl::complete_trait_impl_type_alias(acc, ctx, name); - } - NameKind::RecordField => { - field::complete_field_list_record_variant(acc, ctx); - } - NameKind::ConstParam - | NameKind::Enum - | NameKind::MacroDef - | NameKind::MacroRules - | NameKind::Rename - | NameKind::SelfParam - | NameKind::Static - | NameKind::Struct - | NameKind::Trait - | NameKind::TypeParam - | NameKind::Union - | NameKind::Variant => (), - } -} - -pub(super) fn complete_name_ref( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - NameRefContext { nameref, kind }: &NameRefContext, -) { - match kind { - NameRefKind::Path(path_ctx) => { - flyimport::import_on_the_fly_path(acc, ctx, path_ctx); - - match &path_ctx.kind { - PathKind::Expr { expr_ctx } => { - expr::complete_expr_path(acc, ctx, path_ctx, expr_ctx); - - dot::complete_undotted_self(acc, ctx, path_ctx, expr_ctx); - item_list::complete_item_list_in_expr(acc, ctx, path_ctx, expr_ctx); - record::complete_record_expr_func_update(acc, ctx, path_ctx, expr_ctx); - snippet::complete_expr_snippet(acc, ctx, path_ctx, expr_ctx); - } - PathKind::Type { location } => { - r#type::complete_type_path(acc, ctx, path_ctx, location); - - match location { - TypeLocation::TupleField => { - field::complete_field_list_tuple_variant(acc, ctx, path_ctx); - } - TypeLocation::TypeAscription(ascription) => { - r#type::complete_ascribed_type(acc, ctx, path_ctx, ascription); - } - TypeLocation::GenericArgList(_) - | TypeLocation::TypeBound - | TypeLocation::ImplTarget - | TypeLocation::ImplTrait - | TypeLocation::Other => (), - } - } - PathKind::Attr { attr_ctx } => { - attribute::complete_attribute_path(acc, ctx, path_ctx, attr_ctx); - } - PathKind::Derive { existing_derives } => { - attribute::complete_derive_path(acc, ctx, path_ctx, existing_derives); - } - PathKind::Item { kind } => { - item_list::complete_item_list(acc, ctx, path_ctx, kind); - - snippet::complete_item_snippet(acc, ctx, path_ctx, kind); - if let ItemListKind::TraitImpl(impl_) = kind { - item_list::trait_impl::complete_trait_impl_item_by_name( - acc, ctx, path_ctx, nameref, impl_, - ); - } - } - PathKind::Pat { .. } => { - pattern::complete_pattern_path(acc, ctx, path_ctx); - } - PathKind::Vis { has_in_token } => { - vis::complete_vis_path(acc, ctx, path_ctx, has_in_token); - } - PathKind::Use => { - use_::complete_use_path(acc, ctx, path_ctx, nameref); - } - } - } - NameRefKind::DotAccess(dot_access) => { - flyimport::import_on_the_fly_dot(acc, ctx, dot_access); - dot::complete_dot(acc, ctx, dot_access); - postfix::complete_postfix(acc, ctx, dot_access); - } - NameRefKind::Keyword(item) => { - keyword::complete_for_and_where(acc, ctx, item); - } - NameRefKind::RecordExpr { dot_prefix, expr } => { - record::complete_record_expr_fields(acc, ctx, expr, dot_prefix); - } - NameRefKind::Pattern(pattern_ctx) => complete_patterns(acc, ctx, pattern_ctx), - } -} - -fn complete_patterns( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - pattern_ctx: &PatternContext, -) { - flyimport::import_on_the_fly_pat(acc, ctx, pattern_ctx); - fn_param::complete_fn_param(acc, ctx, pattern_ctx); - pattern::complete_pattern(acc, ctx, pattern_ctx); - record::complete_record_pattern_fields(acc, ctx, pattern_ctx); -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs deleted file mode 100644 index 1d8a8c5f20db3..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs +++ /dev/null @@ -1,380 +0,0 @@ -//! Completion for (built-in) attributes, derives and lints. -//! -//! This module uses a bit of static metadata to provide completions for builtin-in attributes and lints. - -use ide_db::{ - generated::lints::{ - Lint, CLIPPY_LINTS, CLIPPY_LINT_GROUPS, DEFAULT_LINTS, FEATURES, RUSTDOC_LINTS, - }, - syntax_helpers::node_ext::parse_tt_as_comma_sep_paths, - FxHashMap, SymbolKind, -}; -use itertools::Itertools; -use once_cell::sync::Lazy; -use syntax::{ - ast::{self, AttrKind}, - AstNode, SyntaxKind, T, -}; - -use crate::{ - context::{AttrCtx, CompletionContext, PathCompletionCtx, Qualified}, - item::CompletionItem, - Completions, -}; - -mod cfg; -mod derive; -mod lint; -mod repr; - -pub(crate) use self::derive::complete_derive_path; - -/// Complete inputs to known builtin attributes as well as derive attributes -pub(crate) fn complete_known_attribute_input( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - &colon_prefix: &bool, - fake_attribute_under_caret: &ast::Attr, -) -> Option<()> { - let attribute = fake_attribute_under_caret; - let name_ref = match attribute.path() { - Some(p) => Some(p.as_single_name_ref()?), - None => None, - }; - let (path, tt) = name_ref.zip(attribute.token_tree())?; - if tt.l_paren_token().is_none() { - return None; - } - - match path.text().as_str() { - "repr" => repr::complete_repr(acc, ctx, tt), - "feature" => { - lint::complete_lint(acc, ctx, colon_prefix, &parse_tt_as_comma_sep_paths(tt)?, FEATURES) - } - "allow" | "warn" | "deny" | "forbid" => { - let existing_lints = parse_tt_as_comma_sep_paths(tt)?; - - let lints: Vec = CLIPPY_LINT_GROUPS - .iter() - .map(|g| &g.lint) - .chain(DEFAULT_LINTS) - .chain(CLIPPY_LINTS) - .chain(RUSTDOC_LINTS) - .cloned() - .collect(); - - lint::complete_lint(acc, ctx, colon_prefix, &existing_lints, &lints); - } - "cfg" => cfg::complete_cfg(acc, ctx), - _ => (), - } - Some(()) -} - -pub(crate) fn complete_attribute_path( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, - &AttrCtx { kind, annotated_item_kind }: &AttrCtx, -) { - let is_inner = kind == AttrKind::Inner; - - match qualified { - Qualified::With { - resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))), - super_chain_len, - .. - } => { - acc.add_super_keyword(ctx, *super_chain_len); - - for (name, def) in module.scope(ctx.db, Some(ctx.module)) { - match def { - hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_attr(ctx.db) => { - acc.add_macro(ctx, path_ctx, m, name) - } - hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => { - acc.add_module(ctx, path_ctx, m, name) - } - _ => (), - } - } - return; - } - // fresh use tree with leading colon2, only show crate roots - Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx), - // only show modules in a fresh UseTree - Qualified::No => { - ctx.process_all_names(&mut |name, def| match def { - hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_attr(ctx.db) => { - acc.add_macro(ctx, path_ctx, m, name) - } - hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => { - acc.add_module(ctx, path_ctx, m, name) - } - _ => (), - }); - acc.add_nameref_keywords_with_colon(ctx); - } - Qualified::Infer | Qualified::With { .. } => {} - } - - let attributes = annotated_item_kind.and_then(|kind| { - if ast::Expr::can_cast(kind) { - Some(EXPR_ATTRIBUTES) - } else { - KIND_TO_ATTRIBUTES.get(&kind).copied() - } - }); - - let add_completion = |attr_completion: &AttrCompletion| { - let mut item = - CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), attr_completion.label); - - if let Some(lookup) = attr_completion.lookup { - item.lookup_by(lookup); - } - - if let Some((snippet, cap)) = attr_completion.snippet.zip(ctx.config.snippet_cap) { - item.insert_snippet(cap, snippet); - } - - if is_inner || !attr_completion.prefer_inner { - item.add_to(acc); - } - }; - - match attributes { - Some(applicable) => applicable - .iter() - .flat_map(|name| ATTRIBUTES.binary_search_by(|attr| attr.key().cmp(name)).ok()) - .flat_map(|idx| ATTRIBUTES.get(idx)) - .for_each(add_completion), - None if is_inner => ATTRIBUTES.iter().for_each(add_completion), - None => ATTRIBUTES.iter().filter(|compl| !compl.prefer_inner).for_each(add_completion), - } -} - -struct AttrCompletion { - label: &'static str, - lookup: Option<&'static str>, - snippet: Option<&'static str>, - prefer_inner: bool, -} - -impl AttrCompletion { - fn key(&self) -> &'static str { - self.lookup.unwrap_or(self.label) - } - - const fn prefer_inner(self) -> AttrCompletion { - AttrCompletion { prefer_inner: true, ..self } - } -} - -const fn attr( - label: &'static str, - lookup: Option<&'static str>, - snippet: Option<&'static str>, -) -> AttrCompletion { - AttrCompletion { label, lookup, snippet, prefer_inner: false } -} - -macro_rules! attrs { - // attributes applicable to all items - [@ { item $($tt:tt)* } {$($acc:tt)*}] => { - attrs!(@ { $($tt)* } { $($acc)*, "deprecated", "doc", "dochidden", "docalias", "must_use", "no_mangle" }) - }; - // attributes applicable to all adts - [@ { adt $($tt:tt)* } {$($acc:tt)*}] => { - attrs!(@ { $($tt)* } { $($acc)*, "derive", "repr" }) - }; - // attributes applicable to all linkable things aka functions/statics - [@ { linkable $($tt:tt)* } {$($acc:tt)*}] => { - attrs!(@ { $($tt)* } { $($acc)*, "export_name", "link_name", "link_section" }) - }; - // error fallback for nicer error message - [@ { $ty:ident $($tt:tt)* } {$($acc:tt)*}] => { - compile_error!(concat!("unknown attr subtype ", stringify!($ty))) - }; - // general push down accumulation - [@ { $lit:literal $($tt:tt)*} {$($acc:tt)*}] => { - attrs!(@ { $($tt)* } { $($acc)*, $lit }) - }; - [@ {$($tt:tt)+} {$($tt2:tt)*}] => { - compile_error!(concat!("Unexpected input ", stringify!($($tt)+))) - }; - // final output construction - [@ {} {$($tt:tt)*}] => { &[$($tt)*] as _ }; - // starting matcher - [$($tt:tt),*] => { - attrs!(@ { $($tt)* } { "allow", "cfg", "cfg_attr", "deny", "forbid", "warn" }) - }; -} - -#[rustfmt::skip] -static KIND_TO_ATTRIBUTES: Lazy> = Lazy::new(|| { - use SyntaxKind::*; - [ - ( - SOURCE_FILE, - attrs!( - item, - "crate_name", "feature", "no_implicit_prelude", "no_main", "no_std", - "recursion_limit", "type_length_limit", "windows_subsystem" - ), - ), - (MODULE, attrs!(item, "macro_use", "no_implicit_prelude", "path")), - (ITEM_LIST, attrs!(item, "no_implicit_prelude")), - (MACRO_RULES, attrs!(item, "macro_export", "macro_use")), - (MACRO_DEF, attrs!(item)), - (EXTERN_CRATE, attrs!(item, "macro_use", "no_link")), - (USE, attrs!(item)), - (TYPE_ALIAS, attrs!(item)), - (STRUCT, attrs!(item, adt, "non_exhaustive")), - (ENUM, attrs!(item, adt, "non_exhaustive")), - (UNION, attrs!(item, adt)), - (CONST, attrs!(item)), - ( - FN, - attrs!( - item, linkable, - "cold", "ignore", "inline", "must_use", "panic_handler", "proc_macro", - "proc_macro_derive", "proc_macro_attribute", "should_panic", "target_feature", - "test", "track_caller" - ), - ), - (STATIC, attrs!(item, linkable, "global_allocator", "used")), - (TRAIT, attrs!(item, "must_use")), - (IMPL, attrs!(item, "automatically_derived")), - (ASSOC_ITEM_LIST, attrs!(item)), - (EXTERN_BLOCK, attrs!(item, "link")), - (EXTERN_ITEM_LIST, attrs!(item, "link")), - (MACRO_CALL, attrs!()), - (SELF_PARAM, attrs!()), - (PARAM, attrs!()), - (RECORD_FIELD, attrs!()), - (VARIANT, attrs!("non_exhaustive")), - (TYPE_PARAM, attrs!()), - (CONST_PARAM, attrs!()), - (LIFETIME_PARAM, attrs!()), - (LET_STMT, attrs!()), - (EXPR_STMT, attrs!()), - (LITERAL, attrs!()), - (RECORD_EXPR_FIELD_LIST, attrs!()), - (RECORD_EXPR_FIELD, attrs!()), - (MATCH_ARM_LIST, attrs!()), - (MATCH_ARM, attrs!()), - (IDENT_PAT, attrs!()), - (RECORD_PAT_FIELD, attrs!()), - ] - .into_iter() - .collect() -}); -const EXPR_ATTRIBUTES: &[&str] = attrs!(); - -/// -// Keep these sorted for the binary search! -const ATTRIBUTES: &[AttrCompletion] = &[ - attr("allow(…)", Some("allow"), Some("allow(${0:lint})")), - attr("automatically_derived", None, None), - attr("cfg(…)", Some("cfg"), Some("cfg(${0:predicate})")), - attr("cfg_attr(…)", Some("cfg_attr"), Some("cfg_attr(${1:predicate}, ${0:attr})")), - attr("cold", None, None), - attr(r#"crate_name = """#, Some("crate_name"), Some(r#"crate_name = "${0:crate_name}""#)) - .prefer_inner(), - attr("deny(…)", Some("deny"), Some("deny(${0:lint})")), - attr(r#"deprecated"#, Some("deprecated"), Some(r#"deprecated"#)), - attr("derive(…)", Some("derive"), Some(r#"derive(${0:Debug})"#)), - attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)), - attr(r#"doc(alias = "…")"#, Some("docalias"), Some(r#"doc(alias = "${0:docs}")"#)), - attr(r#"doc(hidden)"#, Some("dochidden"), Some(r#"doc(hidden)"#)), - attr( - r#"export_name = "…""#, - Some("export_name"), - Some(r#"export_name = "${0:exported_symbol_name}""#), - ), - attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(), - attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")), - attr("global_allocator", None, None), - attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)), - attr("inline", Some("inline"), Some("inline")), - attr("link", None, None), - attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)), - attr( - r#"link_section = "…""#, - Some("link_section"), - Some(r#"link_section = "${0:section_name}""#), - ), - attr("macro_export", None, None), - attr("macro_use", None, None), - attr(r#"must_use"#, Some("must_use"), Some(r#"must_use"#)), - attr("no_implicit_prelude", None, None).prefer_inner(), - attr("no_link", None, None).prefer_inner(), - attr("no_main", None, None).prefer_inner(), - attr("no_mangle", None, None), - attr("no_std", None, None).prefer_inner(), - attr("non_exhaustive", None, None), - attr("panic_handler", None, None), - attr(r#"path = "…""#, Some("path"), Some(r#"path ="${0:path}""#)), - attr("proc_macro", None, None), - attr("proc_macro_attribute", None, None), - attr("proc_macro_derive(…)", Some("proc_macro_derive"), Some("proc_macro_derive(${0:Trait})")), - attr( - r#"recursion_limit = "…""#, - Some("recursion_limit"), - Some(r#"recursion_limit = "${0:128}""#), - ) - .prefer_inner(), - attr("repr(…)", Some("repr"), Some("repr(${0:C})")), - attr("should_panic", Some("should_panic"), Some(r#"should_panic"#)), - attr( - r#"target_feature(enable = "…")"#, - Some("target_feature"), - Some(r#"target_feature(enable = "${0:feature}")"#), - ), - attr("test", None, None), - attr("track_caller", None, None), - attr("type_length_limit = …", Some("type_length_limit"), Some("type_length_limit = ${0:128}")) - .prefer_inner(), - attr("used", None, None), - attr("warn(…)", Some("warn"), Some("warn(${0:lint})")), - attr( - r#"windows_subsystem = "…""#, - Some("windows_subsystem"), - Some(r#"windows_subsystem = "${0:subsystem}""#), - ) - .prefer_inner(), -]; - -fn parse_comma_sep_expr(input: ast::TokenTree) -> Option> { - let r_paren = input.r_paren_token()?; - let tokens = input - .syntax() - .children_with_tokens() - .skip(1) - .take_while(|it| it.as_token() != Some(&r_paren)); - let input_expressions = tokens.group_by(|tok| tok.kind() == T![,]); - Some( - input_expressions - .into_iter() - .filter_map(|(is_sep, group)| (!is_sep).then(|| group)) - .filter_map(|mut tokens| syntax::hacks::parse_expr_from_str(&tokens.join(""))) - .collect::>(), - ) -} - -#[test] -fn attributes_are_sorted() { - let mut attrs = ATTRIBUTES.iter().map(|attr| attr.key()); - let mut prev = attrs.next().unwrap(); - - attrs.for_each(|next| { - assert!( - prev < next, - r#"ATTRIBUTES array is not sorted, "{}" should come after "{}""#, - prev, - next - ); - prev = next; - }); -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs deleted file mode 100644 index 311060143b06a..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! Completion for cfg - -use std::iter; - -use ide_db::SymbolKind; -use itertools::Itertools; -use syntax::SyntaxKind; - -use crate::{completions::Completions, context::CompletionContext, CompletionItem}; - -pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) { - let add_completion = |item: &str| { - let mut completion = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), item); - completion.insert_text(format!(r#""{}""#, item)); - acc.add(completion.build()); - }; - - let previous = iter::successors(ctx.original_token.prev_token(), |t| { - (matches!(t.kind(), SyntaxKind::EQ) || t.kind().is_trivia()) - .then(|| t.prev_token()) - .flatten() - }) - .find(|t| matches!(t.kind(), SyntaxKind::IDENT)); - - match previous.as_ref().map(|p| p.text()) { - Some("target_arch") => KNOWN_ARCH.iter().copied().for_each(add_completion), - Some("target_env") => KNOWN_ENV.iter().copied().for_each(add_completion), - Some("target_os") => KNOWN_OS.iter().copied().for_each(add_completion), - Some("target_vendor") => KNOWN_VENDOR.iter().copied().for_each(add_completion), - Some("target_endian") => ["little", "big"].into_iter().for_each(add_completion), - Some(name) => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| { - let insert_text = format!(r#""{}""#, s); - let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s); - item.insert_text(insert_text); - - acc.add(item.build()); - }), - None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().unique().for_each(|s| { - let item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s); - acc.add(item.build()); - }), - }; -} - -const KNOWN_ARCH: [&str; 19] = [ - "aarch64", - "arm", - "avr", - "hexagon", - "mips", - "mips64", - "msp430", - "nvptx64", - "powerpc", - "powerpc64", - "riscv32", - "riscv64", - "s390x", - "sparc", - "sparc64", - "wasm32", - "wasm64", - "x86", - "x86_64", -]; - -const KNOWN_ENV: [&str; 7] = ["eabihf", "gnu", "gnueabihf", "msvc", "relibc", "sgx", "uclibc"]; - -const KNOWN_OS: [&str; 20] = [ - "cuda", - "dragonfly", - "emscripten", - "freebsd", - "fuchsia", - "haiku", - "hermit", - "illumos", - "l4re", - "linux", - "netbsd", - "none", - "openbsd", - "psp", - "redox", - "solaris", - "uefi", - "unknown", - "vxworks", - "windows", -]; - -const KNOWN_VENDOR: [&str; 8] = - ["apple", "fortanix", "nvidia", "pc", "sony", "unknown", "wrs", "uwp"]; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs deleted file mode 100644 index 14538fef6072c..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs +++ /dev/null @@ -1,116 +0,0 @@ -//! Completion for derives -use hir::{HasAttrs, ScopeDef}; -use ide_db::SymbolKind; -use itertools::Itertools; -use syntax::SmolStr; - -use crate::{ - context::{CompletionContext, ExistingDerives, PathCompletionCtx, Qualified}, - item::CompletionItem, - Completions, -}; - -pub(crate) fn complete_derive_path( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, - existing_derives: &ExistingDerives, -) { - let core = ctx.famous_defs().core(); - - match qualified { - Qualified::With { - resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))), - super_chain_len, - .. - } => { - acc.add_super_keyword(ctx, *super_chain_len); - - for (name, def) in module.scope(ctx.db, Some(ctx.module)) { - match def { - ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) - if !existing_derives.contains(&mac) && mac.is_derive(ctx.db) => - { - acc.add_macro(ctx, path_ctx, mac, name) - } - ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => { - acc.add_module(ctx, path_ctx, m, name) - } - _ => (), - } - } - } - Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx), - // only show modules in a fresh UseTree - Qualified::No => { - ctx.process_all_names(&mut |name, def| { - let mac = match def { - ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) - if !existing_derives.contains(&mac) && mac.is_derive(ctx.db) => - { - mac - } - ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => { - return acc.add_module(ctx, path_ctx, m, name); - } - _ => return, - }; - - match (core, mac.module(ctx.db).krate()) { - // show derive dependencies for `core`/`std` derives - (Some(core), mac_krate) if core == mac_krate => {} - _ => return acc.add_macro(ctx, path_ctx, mac, name), - }; - - let name_ = name.to_smol_str(); - let find = DEFAULT_DERIVE_DEPENDENCIES - .iter() - .find(|derive_completion| derive_completion.label == name_); - - match find { - Some(derive_completion) => { - let mut components = vec![derive_completion.label]; - components.extend(derive_completion.dependencies.iter().filter( - |&&dependency| { - !existing_derives - .iter() - .map(|it| it.name(ctx.db)) - .any(|it| it.to_smol_str() == dependency) - }, - )); - let lookup = components.join(", "); - let label = Itertools::intersperse(components.into_iter().rev(), ", "); - - let mut item = CompletionItem::new( - SymbolKind::Derive, - ctx.source_range(), - SmolStr::from_iter(label), - ); - if let Some(docs) = mac.docs(ctx.db) { - item.documentation(docs); - } - item.lookup_by(lookup); - item.add_to(acc); - } - None => acc.add_macro(ctx, path_ctx, mac, name), - } - }); - acc.add_nameref_keywords_with_colon(ctx); - } - Qualified::Infer | Qualified::With { .. } => {} - } -} - -struct DeriveDependencies { - label: &'static str, - dependencies: &'static [&'static str], -} - -/// Standard Rust derives that have dependencies -/// (the dependencies are needed so that the main derive don't break the compilation when added) -const DEFAULT_DERIVE_DEPENDENCIES: &[DeriveDependencies] = &[ - DeriveDependencies { label: "Copy", dependencies: &["Clone"] }, - DeriveDependencies { label: "Eq", dependencies: &["PartialEq"] }, - DeriveDependencies { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] }, - DeriveDependencies { label: "PartialOrd", dependencies: &["PartialEq"] }, -]; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs deleted file mode 100644 index 967f6ddd9a83b..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Completion for lints -use ide_db::{generated::lints::Lint, SymbolKind}; -use syntax::ast; - -use crate::{context::CompletionContext, item::CompletionItem, Completions}; - -pub(super) fn complete_lint( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - is_qualified: bool, - existing_lints: &[ast::Path], - lints_completions: &[Lint], -) { - for &Lint { label, description } in lints_completions { - let (qual, name) = { - // FIXME: change `Lint`'s label to not store a path in it but split the prefix off instead? - let mut parts = label.split("::"); - let ns_or_label = match parts.next() { - Some(it) => it, - None => continue, - }; - let label = parts.next(); - match label { - Some(label) => (Some(ns_or_label), label), - None => (None, ns_or_label), - } - }; - if qual.is_none() && is_qualified { - // qualified completion requested, but this lint is unqualified - continue; - } - let lint_already_annotated = existing_lints - .iter() - .filter_map(|path| { - let q = path.qualifier(); - if q.as_ref().and_then(|it| it.qualifier()).is_some() { - return None; - } - Some((q.and_then(|it| it.as_single_name_ref()), path.segment()?.name_ref()?)) - }) - .any(|(q, name_ref)| { - let qualifier_matches = match (q, qual) { - (None, None) => true, - (None, Some(_)) => false, - (Some(_), None) => false, - (Some(q), Some(ns)) => q.text() == ns, - }; - qualifier_matches && name_ref.text() == name - }); - if lint_already_annotated { - continue; - } - let label = match qual { - Some(qual) if !is_qualified => format!("{}::{}", qual, name), - _ => name.to_owned(), - }; - let mut item = CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), label); - item.documentation(hir::Documentation::new(description.to_owned())); - item.add_to(acc) - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/repr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/repr.rs deleted file mode 100644 index a29417133e68b..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/repr.rs +++ /dev/null @@ -1,74 +0,0 @@ -//! Completion for representations. - -use ide_db::SymbolKind; -use syntax::ast; - -use crate::{context::CompletionContext, item::CompletionItem, Completions}; - -pub(super) fn complete_repr( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - input: ast::TokenTree, -) { - if let Some(existing_reprs) = super::parse_comma_sep_expr(input) { - for &ReprCompletion { label, snippet, lookup, collides } in REPR_COMPLETIONS { - let repr_already_annotated = existing_reprs - .iter() - .filter_map(|expr| match expr { - ast::Expr::PathExpr(path) => path.path()?.as_single_name_ref(), - ast::Expr::CallExpr(call) => match call.expr()? { - ast::Expr::PathExpr(path) => path.path()?.as_single_name_ref(), - _ => None, - }, - _ => None, - }) - .any(|it| { - let text = it.text(); - lookup.unwrap_or(label) == text || collides.contains(&text.as_str()) - }); - if repr_already_annotated { - continue; - } - - let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), label); - if let Some(lookup) = lookup { - item.lookup_by(lookup); - } - if let Some((snippet, cap)) = snippet.zip(ctx.config.snippet_cap) { - item.insert_snippet(cap, snippet); - } - item.add_to(acc); - } - } -} - -struct ReprCompletion { - label: &'static str, - snippet: Option<&'static str>, - lookup: Option<&'static str>, - collides: &'static [&'static str], -} - -const fn attr(label: &'static str, collides: &'static [&'static str]) -> ReprCompletion { - ReprCompletion { label, snippet: None, lookup: None, collides } -} - -#[rustfmt::skip] -const REPR_COMPLETIONS: &[ReprCompletion] = &[ - ReprCompletion { label: "align($0)", snippet: Some("align($0)"), lookup: Some("align"), collides: &["transparent", "packed"] }, - attr("packed", &["transparent", "align"]), - attr("transparent", &["C", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), - attr("C", &["transparent"]), - attr("u8", &["transparent", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), - attr("u16", &["transparent", "u8", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), - attr("u32", &["transparent", "u8", "u16", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), - attr("u64", &["transparent", "u8", "u16", "u32", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), - attr("u128", &["transparent", "u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), - attr("usize", &["transparent", "u8", "u16", "u32", "u64", "u128", "i8", "i16", "i32", "i64", "i128", "isize"]), - attr("i8", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i16", "i32", "i64", "i128", "isize"]), - attr("i16", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i32", "i64", "i128", "isize"]), - attr("i32", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i64", "i128", "isize"]), - attr("i64", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i128", "isize"]), - attr("i28", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "isize"]), - attr("isize", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128"]), -]; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs deleted file mode 100644 index cf40ca489c009..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ /dev/null @@ -1,947 +0,0 @@ -//! Completes references after dot (fields and method calls). - -use ide_db::FxHashSet; - -use crate::{ - context::{CompletionContext, DotAccess, DotAccessKind, ExprCtx, PathCompletionCtx, Qualified}, - CompletionItem, CompletionItemKind, Completions, -}; - -/// Complete dot accesses, i.e. fields or methods. -pub(crate) fn complete_dot( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - dot_access: &DotAccess, -) { - let receiver_ty = match dot_access { - DotAccess { receiver_ty: Some(receiver_ty), .. } => &receiver_ty.original, - _ => return, - }; - - // Suggest .await syntax for types that implement Future trait - if receiver_ty.impls_future(ctx.db) { - let mut item = - CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), "await"); - item.detail("expr.await"); - item.add_to(acc); - } - - if let DotAccessKind::Method { .. } = dot_access.kind { - cov_mark::hit!(test_no_struct_field_completion_for_method_call); - } else { - complete_fields( - acc, - ctx, - &receiver_ty, - |acc, field, ty| acc.add_field(ctx, dot_access, None, field, &ty), - |acc, field, ty| acc.add_tuple_field(ctx, None, field, &ty), - ); - } - complete_methods(ctx, &receiver_ty, |func| acc.add_method(ctx, dot_access, func, None, None)); -} - -pub(crate) fn complete_undotted_self( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - expr_ctx: &ExprCtx, -) { - if !ctx.config.enable_self_on_the_fly { - return; - } - if !path_ctx.is_trivial_path() { - return; - } - if !ctx.qualifier_ctx.none() { - return; - } - if !matches!(path_ctx.qualified, Qualified::No) { - return; - } - let self_param = match expr_ctx { - ExprCtx { self_param: Some(self_param), .. } => self_param, - _ => return, - }; - - let ty = self_param.ty(ctx.db); - complete_fields( - acc, - ctx, - &ty, - |acc, field, ty| { - acc.add_field( - ctx, - &DotAccess { - receiver: None, - receiver_ty: None, - kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }, - }, - Some(hir::known::SELF_PARAM), - field, - &ty, - ) - }, - |acc, field, ty| acc.add_tuple_field(ctx, Some(hir::known::SELF_PARAM), field, &ty), - ); - complete_methods(ctx, &ty, |func| { - acc.add_method( - ctx, - &DotAccess { - receiver: None, - receiver_ty: None, - kind: DotAccessKind::Method { has_parens: false }, - }, - func, - Some(hir::known::SELF_PARAM), - None, - ) - }); -} - -fn complete_fields( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - receiver: &hir::Type, - mut named_field: impl FnMut(&mut Completions, hir::Field, hir::Type), - mut tuple_index: impl FnMut(&mut Completions, usize, hir::Type), -) { - for receiver in receiver.autoderef(ctx.db) { - for (field, ty) in receiver.fields(ctx.db) { - named_field(acc, field, ty); - } - for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() { - // Tuple fields are always public (tuple struct fields are handled above). - tuple_index(acc, i, ty); - } - } -} - -fn complete_methods( - ctx: &CompletionContext<'_>, - receiver: &hir::Type, - mut f: impl FnMut(hir::Function), -) { - let mut seen_methods = FxHashSet::default(); - receiver.iterate_method_candidates( - ctx.db, - &ctx.scope, - &ctx.traits_in_scope(), - Some(ctx.module), - None, - |func| { - if func.self_param(ctx.db).is_some() && seen_methods.insert(func.name(ctx.db)) { - f(func); - } - None::<()> - }, - ); -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use crate::tests::{ - check_edit, completion_list_no_kw, completion_list_no_kw_with_private_editable, - }; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw(ra_fixture); - expect.assert_eq(&actual); - } - - fn check_with_private_editable(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw_with_private_editable(ra_fixture); - expect.assert_eq(&actual); - } - - #[test] - fn test_struct_field_and_method_completion() { - check( - r#" -struct S { foo: u32 } -impl S { - fn bar(&self) {} -} -fn foo(s: S) { s.$0 } -"#, - expect![[r#" - fd foo u32 - me bar() fn(&self) - "#]], - ); - } - - #[test] - fn test_struct_field_completion_self() { - check( - r#" -struct S { the_field: (u32,) } -impl S { - fn foo(self) { self.$0 } -} -"#, - expect![[r#" - fd the_field (u32,) - me foo() fn(self) - "#]], - ) - } - - #[test] - fn test_struct_field_completion_autoderef() { - check( - r#" -struct A { the_field: (u32, i32) } -impl A { - fn foo(&self) { self.$0 } -} -"#, - expect![[r#" - fd the_field (u32, i32) - me foo() fn(&self) - "#]], - ) - } - - #[test] - fn test_no_struct_field_completion_for_method_call() { - cov_mark::check!(test_no_struct_field_completion_for_method_call); - check( - r#" -struct A { the_field: u32 } -fn foo(a: A) { a.$0() } -"#, - expect![[r#""#]], - ); - } - - #[test] - fn test_visibility_filtering() { - check( - r#" -//- /lib.rs crate:lib new_source_root:local -pub mod m { - pub struct A { - private_field: u32, - pub pub_field: u32, - pub(crate) crate_field: u32, - pub(super) super_field: u32, - } -} -//- /main.rs crate:main deps:lib new_source_root:local -fn foo(a: lib::m::A) { a.$0 } -"#, - expect![[r#" - fd pub_field u32 - "#]], - ); - - check( - r#" -//- /lib.rs crate:lib new_source_root:library -pub mod m { - pub struct A { - private_field: u32, - pub pub_field: u32, - pub(crate) crate_field: u32, - pub(super) super_field: u32, - } -} -//- /main.rs crate:main deps:lib new_source_root:local -fn foo(a: lib::m::A) { a.$0 } -"#, - expect![[r#" - fd pub_field u32 - "#]], - ); - - check( - r#" -//- /lib.rs crate:lib new_source_root:library -pub mod m { - pub struct A( - i32, - pub f64, - ); -} -//- /main.rs crate:main deps:lib new_source_root:local -fn foo(a: lib::m::A) { a.$0 } -"#, - expect![[r#" - fd 1 f64 - "#]], - ); - - check( - r#" -//- /lib.rs crate:lib new_source_root:local -pub struct A {} -mod m { - impl super::A { - fn private_method(&self) {} - pub(crate) fn crate_method(&self) {} - pub fn pub_method(&self) {} - } -} -//- /main.rs crate:main deps:lib new_source_root:local -fn foo(a: lib::A) { a.$0 } -"#, - expect![[r#" - me pub_method() fn(&self) - "#]], - ); - check( - r#" -//- /lib.rs crate:lib new_source_root:library -pub struct A {} -mod m { - impl super::A { - fn private_method(&self) {} - pub(crate) fn crate_method(&self) {} - pub fn pub_method(&self) {} - } -} -//- /main.rs crate:main deps:lib new_source_root:local -fn foo(a: lib::A) { a.$0 } -"#, - expect![[r#" - me pub_method() fn(&self) - "#]], - ); - } - - #[test] - fn test_visibility_filtering_with_private_editable_enabled() { - check_with_private_editable( - r#" -//- /lib.rs crate:lib new_source_root:local -pub mod m { - pub struct A { - private_field: u32, - pub pub_field: u32, - pub(crate) crate_field: u32, - pub(super) super_field: u32, - } -} -//- /main.rs crate:main deps:lib new_source_root:local -fn foo(a: lib::m::A) { a.$0 } -"#, - expect![[r#" - fd crate_field u32 - fd private_field u32 - fd pub_field u32 - fd super_field u32 - "#]], - ); - - check_with_private_editable( - r#" -//- /lib.rs crate:lib new_source_root:library -pub mod m { - pub struct A { - private_field: u32, - pub pub_field: u32, - pub(crate) crate_field: u32, - pub(super) super_field: u32, - } -} -//- /main.rs crate:main deps:lib new_source_root:local -fn foo(a: lib::m::A) { a.$0 } -"#, - expect![[r#" - fd pub_field u32 - "#]], - ); - - check_with_private_editable( - r#" -//- /lib.rs crate:lib new_source_root:library -pub mod m { - pub struct A( - i32, - pub f64, - ); -} -//- /main.rs crate:main deps:lib new_source_root:local -fn foo(a: lib::m::A) { a.$0 } -"#, - expect![[r#" - fd 1 f64 - "#]], - ); - - check_with_private_editable( - r#" -//- /lib.rs crate:lib new_source_root:local -pub struct A {} -mod m { - impl super::A { - fn private_method(&self) {} - pub(crate) fn crate_method(&self) {} - pub fn pub_method(&self) {} - } -} -//- /main.rs crate:main deps:lib new_source_root:local -fn foo(a: lib::A) { a.$0 } -"#, - expect![[r#" - me crate_method() fn(&self) - me private_method() fn(&self) - me pub_method() fn(&self) - "#]], - ); - check_with_private_editable( - r#" -//- /lib.rs crate:lib new_source_root:library -pub struct A {} -mod m { - impl super::A { - fn private_method(&self) {} - pub(crate) fn crate_method(&self) {} - pub fn pub_method(&self) {} - } -} -//- /main.rs crate:main deps:lib new_source_root:local -fn foo(a: lib::A) { a.$0 } -"#, - expect![[r#" - me pub_method() fn(&self) - "#]], - ); - } - - #[test] - fn test_local_impls() { - check( - r#" -//- /lib.rs crate:lib -pub struct A {} -mod m { - impl super::A { - pub fn pub_module_method(&self) {} - } - fn f() { - impl super::A { - pub fn pub_foreign_local_method(&self) {} - } - } -} -//- /main.rs crate:main deps:lib -fn foo(a: lib::A) { - impl lib::A { - fn local_method(&self) {} - } - a.$0 -} -"#, - expect![[r#" - me local_method() fn(&self) - me pub_module_method() fn(&self) - "#]], - ); - } - - #[test] - fn test_doc_hidden_filtering() { - check( - r#" -//- /lib.rs crate:lib deps:dep -fn foo(a: dep::A) { a.$0 } -//- /dep.rs crate:dep -pub struct A { - #[doc(hidden)] - pub hidden_field: u32, - pub pub_field: u32, -} - -impl A { - pub fn pub_method(&self) {} - - #[doc(hidden)] - pub fn hidden_method(&self) {} -} - "#, - expect![[r#" - fd pub_field u32 - me pub_method() fn(&self) - "#]], - ) - } - - #[test] - fn test_union_field_completion() { - check( - r#" -union U { field: u8, other: u16 } -fn foo(u: U) { u.$0 } -"#, - expect![[r#" - fd field u8 - fd other u16 - "#]], - ); - } - - #[test] - fn test_method_completion_only_fitting_impls() { - check( - r#" -struct A {} -impl A { - fn the_method(&self) {} -} -impl A { - fn the_other_method(&self) {} -} -fn foo(a: A) { a.$0 } -"#, - expect![[r#" - me the_method() fn(&self) - "#]], - ) - } - - #[test] - fn test_trait_method_completion() { - check( - r#" -struct A {} -trait Trait { fn the_method(&self); } -impl Trait for A {} -fn foo(a: A) { a.$0 } -"#, - expect![[r#" - me the_method() (as Trait) fn(&self) - "#]], - ); - check_edit( - "the_method", - r#" -struct A {} -trait Trait { fn the_method(&self); } -impl Trait for A {} -fn foo(a: A) { a.$0 } -"#, - r#" -struct A {} -trait Trait { fn the_method(&self); } -impl Trait for A {} -fn foo(a: A) { a.the_method()$0 } -"#, - ); - } - - #[test] - fn test_trait_method_completion_deduplicated() { - check( - r" -struct A {} -trait Trait { fn the_method(&self); } -impl Trait for T {} -fn foo(a: &A) { a.$0 } -", - expect![[r#" - me the_method() (as Trait) fn(&self) - "#]], - ); - } - - #[test] - fn completes_trait_method_from_other_module() { - check( - r" -struct A {} -mod m { - pub trait Trait { fn the_method(&self); } -} -use m::Trait; -impl Trait for A {} -fn foo(a: A) { a.$0 } -", - expect![[r#" - me the_method() (as Trait) fn(&self) - "#]], - ); - } - - #[test] - fn test_no_non_self_method() { - check( - r#" -struct A {} -impl A { - fn the_method() {} -} -fn foo(a: A) { - a.$0 -} -"#, - expect![[r#""#]], - ); - } - - #[test] - fn test_tuple_field_completion() { - check( - r#" -fn foo() { - let b = (0, 3.14); - b.$0 -} -"#, - expect![[r#" - fd 0 i32 - fd 1 f64 - "#]], - ); - } - - #[test] - fn test_tuple_struct_field_completion() { - check( - r#" -struct S(i32, f64); -fn foo() { - let b = S(0, 3.14); - b.$0 -} -"#, - expect![[r#" - fd 0 i32 - fd 1 f64 - "#]], - ); - } - - #[test] - fn test_tuple_field_inference() { - check( - r#" -pub struct S; -impl S { pub fn blah(&self) {} } - -struct T(S); - -impl T { - fn foo(&self) { - // FIXME: This doesn't work without the trailing `a` as `0.` is a float - self.0.a$0 - } -} -"#, - expect![[r#" - me blah() fn(&self) - "#]], - ); - } - - #[test] - fn test_completion_works_in_consts() { - check( - r#" -struct A { the_field: u32 } -const X: u32 = { - A { the_field: 92 }.$0 -}; -"#, - expect![[r#" - fd the_field u32 - "#]], - ); - } - - #[test] - fn works_in_simple_macro_1() { - check( - r#" -macro_rules! m { ($e:expr) => { $e } } -struct A { the_field: u32 } -fn foo(a: A) { - m!(a.x$0) -} -"#, - expect![[r#" - fd the_field u32 - "#]], - ); - } - - #[test] - fn works_in_simple_macro_2() { - // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery - check( - r#" -macro_rules! m { ($e:expr) => { $e } } -struct A { the_field: u32 } -fn foo(a: A) { - m!(a.$0) -} -"#, - expect![[r#" - fd the_field u32 - "#]], - ); - } - - #[test] - fn works_in_simple_macro_recursive_1() { - check( - r#" -macro_rules! m { ($e:expr) => { $e } } -struct A { the_field: u32 } -fn foo(a: A) { - m!(m!(m!(a.x$0))) -} -"#, - expect![[r#" - fd the_field u32 - "#]], - ); - } - - #[test] - fn macro_expansion_resilient() { - check( - r#" -macro_rules! d { - () => {}; - ($val:expr) => { - match $val { tmp => { tmp } } - }; - // Trailing comma with single argument is ignored - ($val:expr,) => { $crate::d!($val) }; - ($($val:expr),+ $(,)?) => { - ($($crate::d!($val)),+,) - }; -} -struct A { the_field: u32 } -fn foo(a: A) { - d!(a.$0) -} -"#, - expect![[r#" - fd the_field u32 - "#]], - ); - } - - #[test] - fn test_method_completion_issue_3547() { - check( - r#" -struct HashSet {} -impl HashSet { - pub fn the_method(&self) {} -} -fn foo() { - let s: HashSet<_>; - s.$0 -} -"#, - expect![[r#" - me the_method() fn(&self) - "#]], - ); - } - - #[test] - fn completes_method_call_when_receiver_is_a_macro_call() { - check( - r#" -struct S; -impl S { fn foo(&self) {} } -macro_rules! make_s { () => { S }; } -fn main() { make_s!().f$0; } -"#, - expect![[r#" - me foo() fn(&self) - "#]], - ) - } - - #[test] - fn completes_after_macro_call_in_submodule() { - check( - r#" -macro_rules! empty { - () => {}; -} - -mod foo { - #[derive(Debug, Default)] - struct Template2 {} - - impl Template2 { - fn private(&self) {} - } - fn baz() { - let goo: Template2 = Template2 {}; - empty!(); - goo.$0 - } -} - "#, - expect![[r#" - me private() fn(&self) - "#]], - ); - } - - #[test] - fn issue_8931() { - check( - r#" -//- minicore: fn -struct S; - -struct Foo; -impl Foo { - fn foo(&self) -> &[u8] { loop {} } -} - -impl S { - fn indented(&mut self, f: impl FnOnce(&mut Self)) { - } - - fn f(&mut self, v: Foo) { - self.indented(|this| v.$0) - } -} - "#, - expect![[r#" - me foo() fn(&self) -> &[u8] - "#]], - ); - } - - #[test] - fn completes_bare_fields_and_methods_in_methods() { - check( - r#" -struct Foo { field: i32 } - -impl Foo { fn foo(&self) { $0 } }"#, - expect![[r#" - fd self.field i32 - lc self &Foo - sp Self - st Foo - bt u32 - me self.foo() fn(&self) - "#]], - ); - check( - r#" -struct Foo(i32); - -impl Foo { fn foo(&mut self) { $0 } }"#, - expect![[r#" - fd self.0 i32 - lc self &mut Foo - sp Self - st Foo - bt u32 - me self.foo() fn(&mut self) - "#]], - ); - } - - #[test] - fn macro_completion_after_dot() { - check( - r#" -macro_rules! m { - ($e:expr) => { $e }; -} - -struct Completable; - -impl Completable { - fn method(&self) {} -} - -fn f() { - let c = Completable; - m!(c.$0); -} - "#, - expect![[r#" - me method() fn(&self) - "#]], - ); - } - - #[test] - fn completes_method_call_when_receiver_type_has_errors_issue_10297() { - check( - r#" -//- minicore: iterator, sized -struct Vec; -impl IntoIterator for Vec { - type Item = (); - type IntoIter = (); - fn into_iter(self); -} -fn main() { - let x: Vec<_>; - x.$0; -} -"#, - expect![[r#" - me into_iter() (as IntoIterator) fn(self) -> ::IntoIter - "#]], - ) - } - - #[test] - fn postfix_drop_completion() { - cov_mark::check!(postfix_drop_completion); - check_edit( - "drop", - r#" -//- minicore: drop -struct Vec(T); -impl Drop for Vec { - fn drop(&mut self) {} -} -fn main() { - let x = Vec(0u32) - x.$0; -} -"#, - r" -struct Vec(T); -impl Drop for Vec { - fn drop(&mut self) {} -} -fn main() { - let x = Vec(0u32) - drop($0x); -} -", - ) - } - - #[test] - fn issue_12484() { - check( - r#" -//- minicore: sized -trait SizeUser { - type Size; -} -trait Closure: SizeUser {} -trait Encrypt: SizeUser { - fn encrypt(self, _: impl Closure); -} -fn test(thing: impl Encrypt) { - thing.$0; -} - "#, - expect![[r#" - me encrypt(…) (as Encrypt) fn(self, impl Closure::Size>) - "#]], - ) - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs deleted file mode 100644 index bdf6e64f09696..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ /dev/null @@ -1,246 +0,0 @@ -//! Completion of names from the current scope in expression position. - -use hir::ScopeDef; - -use crate::{ - context::{ExprCtx, PathCompletionCtx, Qualified}, - CompletionContext, Completions, -}; - -pub(crate) fn complete_expr_path( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, - &ExprCtx { - in_block_expr, - in_loop_body, - after_if_expr, - in_condition, - incomplete_let, - ref ref_expr_parent, - ref is_func_update, - ref innermost_ret_ty, - ref impl_, - in_match_guard, - .. - }: &ExprCtx, -) { - let _p = profile::span("complete_expr_path"); - if !ctx.qualifier_ctx.none() { - return; - } - - let wants_mut_token = - ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false); - - let scope_def_applicable = |def| match def { - ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => false, - ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db), - _ => true, - }; - - let add_assoc_item = |acc: &mut Completions, item| match item { - hir::AssocItem::Function(func) => acc.add_function(ctx, path_ctx, func, None), - hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), - hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), - }; - - match qualified { - Qualified::Infer => ctx - .traits_in_scope() - .iter() - .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db)) - .for_each(|item| add_assoc_item(acc, item)), - Qualified::With { resolution: None, .. } => {} - Qualified::With { resolution: Some(resolution), .. } => { - // Add associated types on type parameters and `Self`. - ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| { - acc.add_type_alias(ctx, alias); - None::<()> - }); - match resolution { - hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { - let module_scope = module.scope(ctx.db, Some(ctx.module)); - for (name, def) in module_scope { - if scope_def_applicable(def) { - acc.add_path_resolution(ctx, path_ctx, name, def); - } - } - } - hir::PathResolution::Def( - def @ (hir::ModuleDef::Adt(_) - | hir::ModuleDef::TypeAlias(_) - | hir::ModuleDef::BuiltinType(_)), - ) => { - let ty = match def { - hir::ModuleDef::Adt(adt) => adt.ty(ctx.db), - hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db), - hir::ModuleDef::BuiltinType(builtin) => { - cov_mark::hit!(completes_primitive_assoc_const); - builtin.ty(ctx.db) - } - _ => return, - }; - - if let Some(hir::Adt::Enum(e)) = ty.as_adt() { - cov_mark::hit!(completes_variant_through_alias); - acc.add_enum_variants(ctx, path_ctx, e); - } - - // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType. - // (where AssocType is defined on a trait, not an inherent impl) - - ctx.iterate_path_candidates(&ty, |item| { - add_assoc_item(acc, item); - }); - - // Iterate assoc types separately - ty.iterate_assoc_items(ctx.db, ctx.krate, |item| { - if let hir::AssocItem::TypeAlias(ty) = item { - acc.add_type_alias(ctx, ty) - } - None::<()> - }); - } - hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => { - // Handles `Trait::assoc` as well as `::assoc`. - for item in t.items(ctx.db) { - add_assoc_item(acc, item); - } - } - hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => { - let ty = match resolution { - hir::PathResolution::TypeParam(param) => param.ty(ctx.db), - hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db), - _ => return, - }; - - if let Some(hir::Adt::Enum(e)) = ty.as_adt() { - cov_mark::hit!(completes_variant_through_self); - acc.add_enum_variants(ctx, path_ctx, e); - } - - ctx.iterate_path_candidates(&ty, |item| { - add_assoc_item(acc, item); - }); - } - _ => (), - } - } - Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx), - Qualified::No => { - acc.add_nameref_keywords_with_colon(ctx); - if let Some(adt) = - ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) - { - let self_ty = (|| ctx.sema.to_def(impl_.as_ref()?)?.self_ty(ctx.db).as_adt())(); - let complete_self = self_ty == Some(adt); - - match adt { - hir::Adt::Struct(strukt) => { - let path = ctx - .module - .find_use_path(ctx.db, hir::ModuleDef::from(strukt)) - .filter(|it| it.len() > 1); - - acc.add_struct_literal(ctx, path_ctx, strukt, path, None); - - if complete_self { - acc.add_struct_literal( - ctx, - path_ctx, - strukt, - None, - Some(hir::known::SELF_TYPE), - ); - } - } - hir::Adt::Union(un) => { - let path = ctx - .module - .find_use_path(ctx.db, hir::ModuleDef::from(un)) - .filter(|it| it.len() > 1); - - acc.add_union_literal(ctx, un, path, None); - if complete_self { - acc.add_union_literal(ctx, un, None, Some(hir::known::SELF_TYPE)); - } - } - hir::Adt::Enum(e) => { - super::enum_variants_with_paths( - acc, - ctx, - e, - impl_, - |acc, ctx, variant, path| { - acc.add_qualified_enum_variant(ctx, path_ctx, variant, path) - }, - ); - } - } - } - ctx.process_all_names(&mut |name, def| { - if scope_def_applicable(def) { - acc.add_path_resolution(ctx, path_ctx, name, def); - } - }); - - if is_func_update.is_none() { - let mut add_keyword = - |kw, snippet| acc.add_keyword_snippet_expr(ctx, incomplete_let, kw, snippet); - - if !in_block_expr { - add_keyword("unsafe", "unsafe {\n $0\n}"); - } - add_keyword("match", "match $1 {\n $0\n}"); - add_keyword("while", "while $1 {\n $0\n}"); - add_keyword("while let", "while let $1 = $2 {\n $0\n}"); - add_keyword("loop", "loop {\n $0\n}"); - if in_match_guard { - add_keyword("if", "if $0"); - } else { - add_keyword("if", "if $1 {\n $0\n}"); - } - add_keyword("if let", "if let $1 = $2 {\n $0\n}"); - add_keyword("for", "for $1 in $2 {\n $0\n}"); - add_keyword("true", "true"); - add_keyword("false", "false"); - - if in_condition || in_block_expr { - add_keyword("let", "let"); - } - - if after_if_expr { - add_keyword("else", "else {\n $0\n}"); - add_keyword("else if", "else if $1 {\n $0\n}"); - } - - if wants_mut_token { - add_keyword("mut", "mut "); - } - - if in_loop_body { - if in_block_expr { - add_keyword("continue", "continue;"); - add_keyword("break", "break;"); - } else { - add_keyword("continue", "continue"); - add_keyword("break", "break"); - } - } - - if let Some(ty) = innermost_ret_ty { - add_keyword( - "return", - match (in_block_expr, ty.is_unit()) { - (true, true) => "return ;", - (true, false) => "return;", - (false, true) => "return $0", - (false, false) => "return", - }, - ); - } - } - } - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs deleted file mode 100644 index 4e89ef6960821..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! Completes function abi strings. -use syntax::{ - ast::{self, IsString}, - AstNode, AstToken, -}; - -use crate::{ - completions::Completions, context::CompletionContext, CompletionItem, CompletionItemKind, -}; - -// Most of these are feature gated, we should filter/add feature gate completions once we have them. -const SUPPORTED_CALLING_CONVENTIONS: &[&str] = &[ - "Rust", - "C", - "C-unwind", - "cdecl", - "stdcall", - "stdcall-unwind", - "fastcall", - "vectorcall", - "thiscall", - "thiscall-unwind", - "aapcs", - "win64", - "sysv64", - "ptx-kernel", - "msp430-interrupt", - "x86-interrupt", - "amdgpu-kernel", - "efiapi", - "avr-interrupt", - "avr-non-blocking-interrupt", - "C-cmse-nonsecure-call", - "wasm", - "system", - "system-unwind", - "rust-intrinsic", - "rust-call", - "platform-intrinsic", - "unadjusted", -]; - -pub(crate) fn complete_extern_abi( - acc: &mut Completions, - _ctx: &CompletionContext<'_>, - expanded: &ast::String, -) -> Option<()> { - if !expanded.syntax().parent().map_or(false, |it| ast::Abi::can_cast(it.kind())) { - return None; - } - let abi_str = expanded; - let source_range = abi_str.text_range_between_quotes()?; - for &abi in SUPPORTED_CALLING_CONVENTIONS { - CompletionItem::new(CompletionItemKind::Keyword, source_range, abi).add_to(acc); - } - Some(()) -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use crate::tests::{check_edit, completion_list_no_kw}; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw(ra_fixture); - expect.assert_eq(&actual); - } - - #[test] - fn only_completes_in_string_literals() { - check( - r#" -$0 fn foo {} -"#, - expect![[]], - ); - } - - #[test] - fn requires_extern_prefix() { - check( - r#" -"$0" fn foo {} -"#, - expect![[]], - ); - } - - #[test] - fn works() { - check( - r#" -extern "$0" fn foo {} -"#, - expect![[]], - ); - check_edit( - "Rust", - r#" -extern "$0" fn foo {} -"#, - r#" -extern "Rust" fn foo {} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs deleted file mode 100644 index 870df63b7bf2a..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Completion of field list position. - -use crate::{ - context::{PathCompletionCtx, Qualified}, - CompletionContext, Completions, -}; - -pub(crate) fn complete_field_list_tuple_variant( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, -) { - if ctx.qualifier_ctx.vis_node.is_some() { - return; - } - match path_ctx { - PathCompletionCtx { - has_macro_bang: false, - qualified: Qualified::No, - parent: None, - has_type_args: false, - .. - } => { - let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet); - add_keyword("pub(crate)", "pub(crate)"); - add_keyword("pub(super)", "pub(super)"); - add_keyword("pub", "pub"); - } - _ => (), - } -} - -pub(crate) fn complete_field_list_record_variant( - acc: &mut Completions, - ctx: &CompletionContext<'_>, -) { - if ctx.qualifier_ctx.vis_node.is_none() { - let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet); - add_keyword("pub(crate)", "pub(crate)"); - add_keyword("pub(super)", "pub(super)"); - add_keyword("pub", "pub"); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs deleted file mode 100644 index f04cc15d7fabd..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs +++ /dev/null @@ -1,407 +0,0 @@ -//! See [`import_on_the_fly`]. -use hir::{ItemInNs, ModuleDef}; -use ide_db::imports::{ - import_assets::{ImportAssets, LocatedImport}, - insert_use::ImportScope, -}; -use itertools::Itertools; -use syntax::{ - ast::{self}, - AstNode, SyntaxNode, T, -}; - -use crate::{ - context::{ - CompletionContext, DotAccess, PathCompletionCtx, PathKind, PatternContext, Qualified, - TypeLocation, - }, - render::{render_resolution_with_import, render_resolution_with_import_pat, RenderContext}, -}; - -use super::Completions; - -// Feature: Completion With Autoimport -// -// When completing names in the current scope, proposes additional imports from other modules or crates, -// if they can be qualified in the scope, and their name contains all symbols from the completion input. -// -// To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent. -// If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the containing is checked case-insensitively. -// -// ``` -// fn main() { -// pda$0 -// } -// # pub mod std { pub mod marker { pub struct PhantomData { } } } -// ``` -// -> -// ``` -// use std::marker::PhantomData; -// -// fn main() { -// PhantomData -// } -// # pub mod std { pub mod marker { pub struct PhantomData { } } } -// ``` -// -// Also completes associated items, that require trait imports. -// If any unresolved and/or partially-qualified path precedes the input, it will be taken into account. -// Currently, only the imports with their import path ending with the whole qualifier will be proposed -// (no fuzzy matching for qualifier). -// -// ``` -// mod foo { -// pub mod bar { -// pub struct Item; -// -// impl Item { -// pub const TEST_ASSOC: usize = 3; -// } -// } -// } -// -// fn main() { -// bar::Item::TEST_A$0 -// } -// ``` -// -> -// ``` -// use foo::bar; -// -// mod foo { -// pub mod bar { -// pub struct Item; -// -// impl Item { -// pub const TEST_ASSOC: usize = 3; -// } -// } -// } -// -// fn main() { -// bar::Item::TEST_ASSOC -// } -// ``` -// -// NOTE: currently, if an assoc item comes from a trait that's not currently imported, and it also has an unresolved and/or partially-qualified path, -// no imports will be proposed. -// -// .Fuzzy search details -// -// To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only -// (i.e. in `HashMap` in the `std::collections::HashMap` path). -// For the same reasons, avoids searching for any path imports for inputs with their length less than 2 symbols -// (but shows all associated items for any input length). -// -// .Import configuration -// -// It is possible to configure how use-trees are merged with the `imports.granularity.group` setting. -// Mimics the corresponding behavior of the `Auto Import` feature. -// -// .LSP and performance implications -// -// The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits` -// (case-sensitive) resolve client capability in its client capabilities. -// This way the server is able to defer the costly computations, doing them for a selected completion item only. -// For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones, -// which might be slow ergo the feature is automatically disabled. -// -// .Feature toggle -// -// The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.autoimport.enable` flag. -// Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corresponding -// capability enabled. -pub(crate) fn import_on_the_fly_path( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, -) -> Option<()> { - if !ctx.config.enable_imports_on_the_fly { - return None; - } - let qualified = match path_ctx { - PathCompletionCtx { - kind: - PathKind::Expr { .. } - | PathKind::Type { .. } - | PathKind::Attr { .. } - | PathKind::Derive { .. } - | PathKind::Item { .. } - | PathKind::Pat { .. }, - qualified, - .. - } => qualified, - _ => return None, - }; - let potential_import_name = import_name(ctx); - let qualifier = match qualified { - Qualified::With { path, .. } => Some(path.clone()), - _ => None, - }; - let import_assets = import_assets_for_path(ctx, &potential_import_name, qualifier.clone())?; - - import_on_the_fly( - acc, - ctx, - path_ctx, - import_assets, - qualifier.map(|it| it.syntax().clone()).or_else(|| ctx.original_token.parent())?, - potential_import_name, - ) -} - -pub(crate) fn import_on_the_fly_pat( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - pattern_ctx: &PatternContext, -) -> Option<()> { - if !ctx.config.enable_imports_on_the_fly { - return None; - } - if let PatternContext { record_pat: Some(_), .. } = pattern_ctx { - return None; - } - - let potential_import_name = import_name(ctx); - let import_assets = import_assets_for_path(ctx, &potential_import_name, None)?; - - import_on_the_fly_pat_( - acc, - ctx, - pattern_ctx, - import_assets, - ctx.original_token.parent()?, - potential_import_name, - ) -} - -pub(crate) fn import_on_the_fly_dot( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - dot_access: &DotAccess, -) -> Option<()> { - if !ctx.config.enable_imports_on_the_fly { - return None; - } - let receiver = dot_access.receiver.as_ref()?; - let ty = dot_access.receiver_ty.as_ref()?; - let potential_import_name = import_name(ctx); - let import_assets = ImportAssets::for_fuzzy_method_call( - ctx.module, - ty.original.clone(), - potential_import_name.clone(), - receiver.syntax().clone(), - )?; - - import_on_the_fly_method( - acc, - ctx, - dot_access, - import_assets, - receiver.syntax().clone(), - potential_import_name, - ) -} - -fn import_on_the_fly( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { kind, .. }: &PathCompletionCtx, - import_assets: ImportAssets, - position: SyntaxNode, - potential_import_name: String, -) -> Option<()> { - let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.clone()); - - if ImportScope::find_insert_use_container(&position, &ctx.sema).is_none() { - return None; - } - - let ns_filter = |import: &LocatedImport| { - match (kind, import.original_item) { - // Aren't handled in flyimport - (PathKind::Vis { .. } | PathKind::Use, _) => false, - // modules are always fair game - (_, ItemInNs::Types(hir::ModuleDef::Module(_))) => true, - // and so are macros(except for attributes) - ( - PathKind::Expr { .. } - | PathKind::Type { .. } - | PathKind::Item { .. } - | PathKind::Pat { .. }, - ItemInNs::Macros(mac), - ) => mac.is_fn_like(ctx.db), - (PathKind::Item { .. }, ..) => false, - - (PathKind::Expr { .. }, ItemInNs::Types(_) | ItemInNs::Values(_)) => true, - - (PathKind::Pat { .. }, ItemInNs::Types(_)) => true, - (PathKind::Pat { .. }, ItemInNs::Values(def)) => { - matches!(def, hir::ModuleDef::Const(_)) - } - - (PathKind::Type { location }, ItemInNs::Types(ty)) => { - if matches!(location, TypeLocation::TypeBound) { - matches!(ty, ModuleDef::Trait(_)) - } else { - true - } - } - (PathKind::Type { .. }, ItemInNs::Values(_)) => false, - - (PathKind::Attr { .. }, ItemInNs::Macros(mac)) => mac.is_attr(ctx.db), - (PathKind::Attr { .. }, _) => false, - - (PathKind::Derive { existing_derives }, ItemInNs::Macros(mac)) => { - mac.is_derive(ctx.db) && !existing_derives.contains(&mac) - } - (PathKind::Derive { .. }, _) => false, - } - }; - let user_input_lowercased = potential_import_name.to_lowercase(); - - acc.add_all( - import_assets - .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind) - .into_iter() - .filter(ns_filter) - .filter(|import| { - !ctx.is_item_hidden(&import.item_to_import) - && !ctx.is_item_hidden(&import.original_item) - }) - .sorted_by_key(|located_import| { - compute_fuzzy_completion_order_key( - &located_import.import_path, - &user_input_lowercased, - ) - }) - .filter_map(|import| { - render_resolution_with_import(RenderContext::new(ctx), path_ctx, import) - }) - .map(|builder| builder.build()), - ); - Some(()) -} - -fn import_on_the_fly_pat_( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - pattern_ctx: &PatternContext, - import_assets: ImportAssets, - position: SyntaxNode, - potential_import_name: String, -) -> Option<()> { - let _p = profile::span("import_on_the_fly_pat").detail(|| potential_import_name.clone()); - - if ImportScope::find_insert_use_container(&position, &ctx.sema).is_none() { - return None; - } - - let ns_filter = |import: &LocatedImport| match import.original_item { - ItemInNs::Macros(mac) => mac.is_fn_like(ctx.db), - ItemInNs::Types(_) => true, - ItemInNs::Values(def) => matches!(def, hir::ModuleDef::Const(_)), - }; - let user_input_lowercased = potential_import_name.to_lowercase(); - - acc.add_all( - import_assets - .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind) - .into_iter() - .filter(ns_filter) - .filter(|import| { - !ctx.is_item_hidden(&import.item_to_import) - && !ctx.is_item_hidden(&import.original_item) - }) - .sorted_by_key(|located_import| { - compute_fuzzy_completion_order_key( - &located_import.import_path, - &user_input_lowercased, - ) - }) - .filter_map(|import| { - render_resolution_with_import_pat(RenderContext::new(ctx), pattern_ctx, import) - }) - .map(|builder| builder.build()), - ); - Some(()) -} - -fn import_on_the_fly_method( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - dot_access: &DotAccess, - import_assets: ImportAssets, - position: SyntaxNode, - potential_import_name: String, -) -> Option<()> { - let _p = profile::span("import_on_the_fly_method").detail(|| potential_import_name.clone()); - - if ImportScope::find_insert_use_container(&position, &ctx.sema).is_none() { - return None; - } - - let user_input_lowercased = potential_import_name.to_lowercase(); - - import_assets - .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind) - .into_iter() - .filter(|import| { - !ctx.is_item_hidden(&import.item_to_import) - && !ctx.is_item_hidden(&import.original_item) - }) - .sorted_by_key(|located_import| { - compute_fuzzy_completion_order_key(&located_import.import_path, &user_input_lowercased) - }) - .for_each(|import| match import.original_item { - ItemInNs::Values(hir::ModuleDef::Function(f)) => { - acc.add_method_with_import(ctx, dot_access, f, import); - } - _ => (), - }); - Some(()) -} - -fn import_name(ctx: &CompletionContext<'_>) -> String { - let token_kind = ctx.token.kind(); - if matches!(token_kind, T![.] | T![::]) { - String::new() - } else { - ctx.token.to_string() - } -} - -fn import_assets_for_path( - ctx: &CompletionContext<'_>, - potential_import_name: &str, - qualifier: Option, -) -> Option { - let fuzzy_name_length = potential_import_name.len(); - let mut assets_for_path = ImportAssets::for_fuzzy_path( - ctx.module, - qualifier, - potential_import_name.to_owned(), - &ctx.sema, - ctx.token.parent()?, - )?; - if fuzzy_name_length < 3 { - cov_mark::hit!(flyimport_exact_on_short_path); - assets_for_path.path_fuzzy_name_to_exact(false); - } - Some(assets_for_path) -} - -fn compute_fuzzy_completion_order_key( - proposed_mod_path: &hir::ModPath, - user_input_lowercased: &str, -) -> usize { - cov_mark::hit!(certain_fuzzy_order_test); - let import_name = match proposed_mod_path.segments().last() { - Some(name) => name.to_smol_str().to_lowercase(), - None => return usize::MAX, - }; - match import_name.match_indices(user_input_lowercased).next() { - Some((first_matching_index, _)) => first_matching_index, - None => usize::MAX, - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs deleted file mode 100644 index f0ecc595af33e..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs +++ /dev/null @@ -1,196 +0,0 @@ -//! See [`complete_fn_param`]. - -use hir::HirDisplay; -use ide_db::FxHashMap; -use syntax::{ - algo, - ast::{self, HasModuleItem}, - match_ast, AstNode, Direction, SyntaxKind, TextRange, TextSize, -}; - -use crate::{ - context::{ParamContext, ParamKind, PatternContext}, - CompletionContext, CompletionItem, CompletionItemKind, Completions, -}; - -// FIXME: Make this a submodule of [`pattern`] -/// Complete repeated parameters, both name and type. For example, if all -/// functions in a file have a `spam: &mut Spam` parameter, a completion with -/// `spam: &mut Spam` insert text/label will be suggested. -/// -/// Also complete parameters for closure or local functions from the surrounding defined locals. -pub(crate) fn complete_fn_param( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - pattern_ctx: &PatternContext, -) -> Option<()> { - let (ParamContext { param_list, kind, .. }, impl_) = match pattern_ctx { - PatternContext { param_ctx: Some(kind), impl_, .. } => (kind, impl_), - _ => return None, - }; - - let comma_wrapper = comma_wrapper(ctx); - let mut add_new_item_to_acc = |label: &str| { - let mk_item = |label: &str, range: TextRange| { - CompletionItem::new(CompletionItemKind::Binding, range, label) - }; - let item = match &comma_wrapper { - Some((fmt, range)) => mk_item(&fmt(label), *range), - None => mk_item(label, ctx.source_range()), - }; - // Completion lookup is omitted intentionally here. - // See the full discussion: https://github.com/rust-lang/rust-analyzer/issues/12073 - item.add_to(acc) - }; - - match kind { - ParamKind::Function(function) => { - fill_fn_params(ctx, function, param_list, impl_, add_new_item_to_acc); - } - ParamKind::Closure(closure) => { - let stmt_list = closure.syntax().ancestors().find_map(ast::StmtList::cast)?; - params_from_stmt_list_scope(ctx, stmt_list, |name, ty| { - add_new_item_to_acc(&format!("{name}: {ty}")); - }); - } - } - - Some(()) -} - -fn fill_fn_params( - ctx: &CompletionContext<'_>, - function: &ast::Fn, - param_list: &ast::ParamList, - impl_: &Option, - mut add_new_item_to_acc: impl FnMut(&str), -) { - let mut file_params = FxHashMap::default(); - - let mut extract_params = |f: ast::Fn| { - f.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| { - if let Some(pat) = param.pat() { - // FIXME: We should be able to turn these into SmolStr without having to allocate a String - let whole_param = param.syntax().text().to_string(); - let binding = pat.syntax().text().to_string(); - file_params.entry(whole_param).or_insert(binding); - } - }); - }; - - for node in ctx.token.parent_ancestors() { - match_ast! { - match node { - ast::SourceFile(it) => it.items().filter_map(|item| match item { - ast::Item::Fn(it) => Some(it), - _ => None, - }).for_each(&mut extract_params), - ast::ItemList(it) => it.items().filter_map(|item| match item { - ast::Item::Fn(it) => Some(it), - _ => None, - }).for_each(&mut extract_params), - ast::AssocItemList(it) => it.assoc_items().filter_map(|item| match item { - ast::AssocItem::Fn(it) => Some(it), - _ => None, - }).for_each(&mut extract_params), - _ => continue, - } - }; - } - - if let Some(stmt_list) = function.syntax().parent().and_then(ast::StmtList::cast) { - params_from_stmt_list_scope(ctx, stmt_list, |name, ty| { - file_params.entry(format!("{name}: {ty}")).or_insert(name.to_string()); - }); - } - remove_duplicated(&mut file_params, param_list.params()); - let self_completion_items = ["self", "&self", "mut self", "&mut self"]; - if should_add_self_completions(ctx.token.text_range().start(), param_list, impl_) { - self_completion_items.into_iter().for_each(|self_item| add_new_item_to_acc(self_item)); - } - - file_params.keys().for_each(|whole_param| add_new_item_to_acc(whole_param)); -} - -fn params_from_stmt_list_scope( - ctx: &CompletionContext<'_>, - stmt_list: ast::StmtList, - mut cb: impl FnMut(hir::Name, String), -) { - let syntax_node = match stmt_list.syntax().last_child() { - Some(it) => it, - None => return, - }; - if let Some(scope) = - ctx.sema.scope_at_offset(stmt_list.syntax(), syntax_node.text_range().end()) - { - let module = scope.module().into(); - scope.process_all_names(&mut |name, def| { - if let hir::ScopeDef::Local(local) = def { - if let Ok(ty) = local.ty(ctx.db).display_source_code(ctx.db, module) { - cb(name, ty); - } - } - }); - } -} - -fn remove_duplicated( - file_params: &mut FxHashMap, - fn_params: ast::AstChildren, -) { - fn_params.for_each(|param| { - let whole_param = param.syntax().text().to_string(); - file_params.remove(&whole_param); - - match param.pat() { - // remove suggestions for patterns that already exist - // if the type is missing we are checking the current param to be completed - // in which case this would find itself removing the suggestions due to itself - Some(pattern) if param.ty().is_some() => { - let binding = pattern.syntax().text().to_string(); - file_params.retain(|_, v| v != &binding); - } - _ => (), - } - }) -} - -fn should_add_self_completions( - cursor: TextSize, - param_list: &ast::ParamList, - impl_: &Option, -) -> bool { - if impl_.is_none() || param_list.self_param().is_some() { - return false; - } - match param_list.params().next() { - Some(first) => first.pat().map_or(false, |pat| pat.syntax().text_range().contains(cursor)), - None => true, - } -} - -fn comma_wrapper(ctx: &CompletionContext<'_>) -> Option<(impl Fn(&str) -> String, TextRange)> { - let param = ctx.token.parent_ancestors().find(|node| node.kind() == SyntaxKind::PARAM)?; - - let next_token_kind = { - let t = param.last_token()?.next_token()?; - let t = algo::skip_whitespace_token(t, Direction::Next)?; - t.kind() - }; - let prev_token_kind = { - let t = param.first_token()?.prev_token()?; - let t = algo::skip_whitespace_token(t, Direction::Prev)?; - t.kind() - }; - - let has_trailing_comma = - matches!(next_token_kind, SyntaxKind::COMMA | SyntaxKind::R_PAREN | SyntaxKind::PIPE); - let trailing = if has_trailing_comma { "" } else { "," }; - - let has_leading_comma = - matches!(prev_token_kind, SyntaxKind::COMMA | SyntaxKind::L_PAREN | SyntaxKind::PIPE); - let leading = if has_leading_comma { "" } else { ", " }; - - Some((move |label: &_| (format!("{}{}{}", leading, label, trailing)), param.text_range())) -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs deleted file mode 100644 index 038bdb4279e07..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! Completes identifiers in format string literals. - -use ide_db::syntax_helpers::format_string::is_format_string; -use itertools::Itertools; -use syntax::{ast, AstToken, TextRange, TextSize}; - -use crate::{context::CompletionContext, CompletionItem, CompletionItemKind, Completions}; - -/// Complete identifiers in format strings. -pub(crate) fn format_string( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - original: &ast::String, - expanded: &ast::String, -) { - if !is_format_string(&expanded) { - return; - } - let cursor = ctx.position.offset; - let lit_start = ctx.original_token.text_range().start(); - let cursor_in_lit = cursor - lit_start; - - let prefix = &original.text()[..cursor_in_lit.into()]; - let braces = prefix.char_indices().rev().skip_while(|&(_, c)| c.is_alphanumeric()).next_tuple(); - let brace_offset = match braces { - // escaped brace - Some(((_, '{'), (_, '{'))) => return, - Some(((idx, '{'), _)) => lit_start + TextSize::from(idx as u32 + 1), - _ => return, - }; - - let source_range = TextRange::new(brace_offset, cursor); - ctx.locals.iter().for_each(|(name, _)| { - CompletionItem::new(CompletionItemKind::Binding, source_range, name.to_smol_str()) - .add_to(acc); - }) -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use crate::tests::{check_edit, completion_list_no_kw}; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw(ra_fixture); - expect.assert_eq(&actual); - } - - #[test] - fn works_when_wrapped() { - check( - r#" -macro_rules! format_args { - ($lit:literal $(tt:tt)*) => { 0 }, -} -macro_rules! print { - ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*))); -} -fn main() { - let foobar = 1; - print!("f$0"); -} -"#, - expect![[]], - ); - } - - #[test] - fn no_completion_without_brace() { - check( - r#" -macro_rules! format_args { - ($lit:literal $(tt:tt)*) => { 0 }, -} -fn main() { - let foobar = 1; - format_args!("f$0"); -} -"#, - expect![[]], - ); - } - - #[test] - fn completes_locals() { - check_edit( - "foobar", - r#" -macro_rules! format_args { - ($lit:literal $(tt:tt)*) => { 0 }, -} -fn main() { - let foobar = 1; - format_args!("{f$0"); -} -"#, - r#" -macro_rules! format_args { - ($lit:literal $(tt:tt)*) => { 0 }, -} -fn main() { - let foobar = 1; - format_args!("{foobar"); -} -"#, - ); - check_edit( - "foobar", - r#" -macro_rules! format_args { - ($lit:literal $(tt:tt)*) => { 0 }, -} -fn main() { - let foobar = 1; - format_args!("{$0"); -} -"#, - r#" -macro_rules! format_args { - ($lit:literal $(tt:tt)*) => { 0 }, -} -fn main() { - let foobar = 1; - format_args!("{foobar"); -} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs deleted file mode 100644 index 4e4c9fba6cc57..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs +++ /dev/null @@ -1,133 +0,0 @@ -//! Completion of paths and keywords at item list position. - -use crate::{ - context::{ExprCtx, ItemListKind, PathCompletionCtx, Qualified}, - CompletionContext, Completions, -}; - -pub(crate) mod trait_impl; - -pub(crate) fn complete_item_list_in_expr( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - expr_ctx: &ExprCtx, -) { - if !expr_ctx.in_block_expr { - return; - } - if !path_ctx.is_trivial_path() { - return; - } - add_keywords(acc, ctx, None); -} - -pub(crate) fn complete_item_list( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, - kind: &ItemListKind, -) { - let _p = profile::span("complete_item_list"); - if path_ctx.is_trivial_path() { - add_keywords(acc, ctx, Some(kind)); - } - - match qualified { - Qualified::With { - resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))), - super_chain_len, - .. - } => { - for (name, def) in module.scope(ctx.db, Some(ctx.module)) { - match def { - hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_fn_like(ctx.db) => { - acc.add_macro(ctx, path_ctx, m, name) - } - hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => { - acc.add_module(ctx, path_ctx, m, name) - } - _ => (), - } - } - - acc.add_super_keyword(ctx, *super_chain_len); - } - Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx), - Qualified::No if ctx.qualifier_ctx.none() => { - ctx.process_all_names(&mut |name, def| match def { - hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_fn_like(ctx.db) => { - acc.add_macro(ctx, path_ctx, m, name) - } - hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => { - acc.add_module(ctx, path_ctx, m, name) - } - _ => (), - }); - acc.add_nameref_keywords_with_colon(ctx); - } - Qualified::Infer | Qualified::No | Qualified::With { .. } => {} - } -} - -fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option<&ItemListKind>) { - let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet); - - let in_item_list = matches!(kind, Some(ItemListKind::SourceFile | ItemListKind::Module) | None); - let in_assoc_non_trait_impl = matches!(kind, Some(ItemListKind::Impl | ItemListKind::Trait)); - let in_extern_block = matches!(kind, Some(ItemListKind::ExternBlock)); - let in_trait = matches!(kind, Some(ItemListKind::Trait)); - let in_trait_impl = matches!(kind, Some(ItemListKind::TraitImpl(_))); - let in_inherent_impl = matches!(kind, Some(ItemListKind::Impl)); - let no_qualifiers = ctx.qualifier_ctx.vis_node.is_none(); - let in_block = matches!(kind, None); - - if !in_trait_impl { - if ctx.qualifier_ctx.unsafe_tok.is_some() { - if in_item_list || in_assoc_non_trait_impl { - add_keyword("fn", "fn $1($2) {\n $0\n}"); - } - if in_item_list { - add_keyword("trait", "trait $1 {\n $0\n}"); - if no_qualifiers { - add_keyword("impl", "impl $1 {\n $0\n}"); - } - } - return; - } - - if in_item_list { - add_keyword("enum", "enum $1 {\n $0\n}"); - add_keyword("mod", "mod $0"); - add_keyword("static", "static $0"); - add_keyword("struct", "struct $0"); - add_keyword("trait", "trait $1 {\n $0\n}"); - add_keyword("union", "union $1 {\n $0\n}"); - add_keyword("use", "use $0"); - if no_qualifiers { - add_keyword("impl", "impl $1 {\n $0\n}"); - } - } - - if !in_trait && !in_block && no_qualifiers { - add_keyword("pub(crate)", "pub(crate)"); - add_keyword("pub(super)", "pub(super)"); - add_keyword("pub", "pub"); - } - - if in_extern_block { - add_keyword("fn", "fn $1($2);"); - } else { - if !in_inherent_impl { - if !in_trait { - add_keyword("extern", "extern $0"); - } - add_keyword("type", "type $0"); - } - - add_keyword("fn", "fn $1($2) {\n $0\n}"); - add_keyword("unsafe", "unsafe"); - add_keyword("const", "const $0"); - } - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs deleted file mode 100644 index e9256803cc4f7..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ /dev/null @@ -1,1160 +0,0 @@ -//! Completion for associated items in a trait implementation. -//! -//! This module adds the completion items related to implementing associated -//! items within an `impl Trait for Struct` block. The current context node -//! must be within either a `FN`, `TYPE_ALIAS`, or `CONST` node -//! and an direct child of an `IMPL`. -//! -//! # Examples -//! -//! Considering the following trait `impl`: -//! -//! ```ignore -//! trait SomeTrait { -//! fn foo(); -//! } -//! -//! impl SomeTrait for () { -//! fn f$0 -//! } -//! ``` -//! -//! may result in the completion of the following method: -//! -//! ```ignore -//! # trait SomeTrait { -//! # fn foo(); -//! # } -//! -//! impl SomeTrait for () { -//! fn foo() {}$0 -//! } -//! ``` - -use hir::{self, HasAttrs}; -use ide_db::{ - path_transform::PathTransform, syntax_helpers::insert_whitespace_into_node, - traits::get_missing_assoc_items, SymbolKind, -}; -use syntax::{ - ast::{self, edit_in_place::AttrsOwnerEdit}, - AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, T, -}; -use text_edit::TextEdit; - -use crate::{ - context::PathCompletionCtx, CompletionContext, CompletionItem, CompletionItemKind, - CompletionRelevance, Completions, -}; - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -enum ImplCompletionKind { - All, - Fn, - TypeAlias, - Const, -} - -pub(crate) fn complete_trait_impl_const( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - name: &Option, -) -> Option<()> { - complete_trait_impl_name(acc, ctx, name, ImplCompletionKind::Const) -} - -pub(crate) fn complete_trait_impl_type_alias( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - name: &Option, -) -> Option<()> { - complete_trait_impl_name(acc, ctx, name, ImplCompletionKind::TypeAlias) -} - -pub(crate) fn complete_trait_impl_fn( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - name: &Option, -) -> Option<()> { - complete_trait_impl_name(acc, ctx, name, ImplCompletionKind::Fn) -} - -fn complete_trait_impl_name( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - name: &Option, - kind: ImplCompletionKind, -) -> Option<()> { - let token = ctx.token.clone(); - let item = match name { - Some(name) => name.syntax().parent(), - None => if token.kind() == SyntaxKind::WHITESPACE { token.prev_token()? } else { token } - .parent(), - }?; - complete_trait_impl( - acc, - ctx, - kind, - replacement_range(ctx, &item), - // item -> ASSOC_ITEM_LIST -> IMPL - &ast::Impl::cast(item.parent()?.parent()?)?, - ); - Some(()) -} - -pub(crate) fn complete_trait_impl_item_by_name( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - name_ref: &Option, - impl_: &Option, -) { - if !path_ctx.is_trivial_path() { - return; - } - if let Some(impl_) = impl_ { - complete_trait_impl( - acc, - ctx, - ImplCompletionKind::All, - match name_ref { - Some(name) => name.syntax().text_range(), - None => ctx.source_range(), - }, - impl_, - ); - } -} - -fn complete_trait_impl( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - kind: ImplCompletionKind, - replacement_range: TextRange, - impl_def: &ast::Impl, -) { - if let Some(hir_impl) = ctx.sema.to_def(impl_def) { - get_missing_assoc_items(&ctx.sema, impl_def).into_iter().for_each(|item| { - use self::ImplCompletionKind::*; - match (item, kind) { - (hir::AssocItem::Function(func), All | Fn) => { - add_function_impl(acc, ctx, replacement_range, func, hir_impl) - } - (hir::AssocItem::TypeAlias(type_alias), All | TypeAlias) => { - add_type_alias_impl(acc, ctx, replacement_range, type_alias) - } - (hir::AssocItem::Const(const_), All | Const) => { - add_const_impl(acc, ctx, replacement_range, const_, hir_impl) - } - _ => {} - } - }); - } -} - -fn add_function_impl( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - replacement_range: TextRange, - func: hir::Function, - impl_def: hir::Impl, -) { - let fn_name = func.name(ctx.db); - - let label = format!( - "fn {}({})", - fn_name, - if func.assoc_fn_params(ctx.db).is_empty() { "" } else { ".." } - ); - - let completion_kind = if func.has_self_param(ctx.db) { - CompletionItemKind::Method - } else { - CompletionItemKind::SymbolKind(SymbolKind::Function) - }; - - let mut item = CompletionItem::new(completion_kind, replacement_range, label); - item.lookup_by(format!("fn {}", fn_name)) - .set_documentation(func.docs(ctx.db)) - .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() }); - - if let Some(source) = ctx.sema.source(func) { - let assoc_item = ast::AssocItem::Fn(source.value); - if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { - let transformed_fn = match transformed_item { - ast::AssocItem::Fn(func) => func, - _ => unreachable!(), - }; - - let function_decl = function_declaration(&transformed_fn, source.file_id.is_macro()); - match ctx.config.snippet_cap { - Some(cap) => { - let snippet = format!("{} {{\n $0\n}}", function_decl); - item.snippet_edit(cap, TextEdit::replace(replacement_range, snippet)); - } - None => { - let header = format!("{} {{", function_decl); - item.text_edit(TextEdit::replace(replacement_range, header)); - } - }; - item.add_to(acc); - } - } -} - -/// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc. -fn get_transformed_assoc_item( - ctx: &CompletionContext<'_>, - assoc_item: ast::AssocItem, - impl_def: hir::Impl, -) -> Option { - let assoc_item = assoc_item.clone_for_update(); - let trait_ = impl_def.trait_(ctx.db)?; - let source_scope = &ctx.sema.scope_for_def(trait_); - let target_scope = &ctx.sema.scope(ctx.sema.source(impl_def)?.syntax().value)?; - let transform = PathTransform::trait_impl( - target_scope, - source_scope, - trait_, - ctx.sema.source(impl_def)?.value, - ); - - transform.apply(assoc_item.syntax()); - if let ast::AssocItem::Fn(func) = &assoc_item { - func.remove_attrs_and_docs(); - } - Some(assoc_item) -} - -fn add_type_alias_impl( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - replacement_range: TextRange, - type_alias: hir::TypeAlias, -) { - let alias_name = type_alias.name(ctx.db); - let (alias_name, escaped_name) = (alias_name.to_smol_str(), alias_name.escaped().to_smol_str()); - - let label = format!("type {} =", alias_name); - let replacement = format!("type {} = ", escaped_name); - - let mut item = CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label); - item.lookup_by(format!("type {}", alias_name)) - .set_documentation(type_alias.docs(ctx.db)) - .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() }); - match ctx.config.snippet_cap { - Some(cap) => item - .snippet_edit(cap, TextEdit::replace(replacement_range, format!("{}$0;", replacement))), - None => item.text_edit(TextEdit::replace(replacement_range, replacement)), - }; - item.add_to(acc); -} - -fn add_const_impl( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - replacement_range: TextRange, - const_: hir::Const, - impl_def: hir::Impl, -) { - let const_name = const_.name(ctx.db).map(|n| n.to_smol_str()); - - if let Some(const_name) = const_name { - if let Some(source) = ctx.sema.source(const_) { - let assoc_item = ast::AssocItem::Const(source.value); - if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { - let transformed_const = match transformed_item { - ast::AssocItem::Const(const_) => const_, - _ => unreachable!(), - }; - - let label = make_const_compl_syntax(&transformed_const, source.file_id.is_macro()); - let replacement = format!("{} ", label); - - let mut item = CompletionItem::new(SymbolKind::Const, replacement_range, label); - item.lookup_by(format!("const {}", const_name)) - .set_documentation(const_.docs(ctx.db)) - .set_relevance(CompletionRelevance { - is_item_from_trait: true, - ..Default::default() - }); - match ctx.config.snippet_cap { - Some(cap) => item.snippet_edit( - cap, - TextEdit::replace(replacement_range, format!("{}$0;", replacement)), - ), - None => item.text_edit(TextEdit::replace(replacement_range, replacement)), - }; - item.add_to(acc); - } - } - } -} - -fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> String { - const_.remove_attrs_and_docs(); - let const_ = if needs_whitespace { - insert_whitespace_into_node::insert_ws_into(const_.syntax().clone()) - } else { - const_.syntax().clone() - }; - - let start = const_.text_range().start(); - let const_end = const_.text_range().end(); - - let end = const_ - .children_with_tokens() - .find(|s| s.kind() == T![;] || s.kind() == T![=]) - .map_or(const_end, |f| f.text_range().start()); - - let len = end - start; - let range = TextRange::new(0.into(), len); - - let syntax = const_.text().slice(range).to_string(); - - format!("{} =", syntax.trim_end()) -} - -fn function_declaration(node: &ast::Fn, needs_whitespace: bool) -> String { - node.remove_attrs_and_docs(); - - let node = if needs_whitespace { - insert_whitespace_into_node::insert_ws_into(node.syntax().clone()) - } else { - node.syntax().clone() - }; - - let start = node.text_range().start(); - let end = node.text_range().end(); - - let end = node - .last_child_or_token() - .filter(|s| s.kind() == T![;] || s.kind() == SyntaxKind::BLOCK_EXPR) - .map_or(end, |f| f.text_range().start()); - - let len = end - start; - let range = TextRange::new(0.into(), len); - - let syntax = node.text().slice(range).to_string(); - - syntax.trim_end().to_owned() -} - -fn replacement_range(ctx: &CompletionContext<'_>, item: &SyntaxNode) -> TextRange { - let first_child = item - .children_with_tokens() - .find(|child| { - !matches!(child.kind(), SyntaxKind::COMMENT | SyntaxKind::WHITESPACE | SyntaxKind::ATTR) - }) - .unwrap_or_else(|| SyntaxElement::Node(item.clone())); - - TextRange::new(first_child.text_range().start(), ctx.source_range().end()) -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use crate::tests::{check_edit, completion_list_no_kw}; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw(ra_fixture); - expect.assert_eq(&actual) - } - - #[test] - fn no_completion_inside_fn() { - check( - r" -trait Test { fn test(); fn test2(); } -struct T; - -impl Test for T { - fn test() { - t$0 - } -} -", - expect![[r#" - sp Self - st T - tt Test - bt u32 - "#]], - ); - - check( - r" -trait Test { fn test(); fn test2(); } -struct T; - -impl Test for T { - fn test() { - fn t$0 - } -} -", - expect![[""]], - ); - - check( - r" -trait Test { fn test(); fn test2(); } -struct T; - -impl Test for T { - fn test() { - fn $0 - } -} -", - expect![[""]], - ); - - // https://github.com/rust-lang/rust-analyzer/pull/5976#issuecomment-692332191 - check( - r" -trait Test { fn test(); fn test2(); } -struct T; - -impl Test for T { - fn test() { - foo.$0 - } -} -", - expect![[r#""#]], - ); - - check( - r" -trait Test { fn test(_: i32); fn test2(); } -struct T; - -impl Test for T { - fn test(t$0) -} -", - expect![[r#" - sp Self - st T - bn &mut self - bn &self - bn mut self - bn self - "#]], - ); - - check( - r" -trait Test { fn test(_: fn()); fn test2(); } -struct T; - -impl Test for T { - fn test(f: fn $0) -} -", - expect![[r#" - sp Self - st T - "#]], - ); - } - - #[test] - fn no_completion_inside_const() { - check( - r" -trait Test { const TEST: fn(); const TEST2: u32; type Test; fn test(); } -struct T; - -impl Test for T { - const TEST: fn $0 -} -", - expect![[r#""#]], - ); - - check( - r" -trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } -struct T; - -impl Test for T { - const TEST: T$0 -} -", - expect![[r#" - sp Self - st T - tt Test - bt u32 - "#]], - ); - - check( - r" -trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } -struct T; - -impl Test for T { - const TEST: u32 = f$0 -} -", - expect![[r#" - sp Self - st T - tt Test - bt u32 - "#]], - ); - - check( - r" -trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } -struct T; - -impl Test for T { - const TEST: u32 = { - t$0 - }; -} -", - expect![[r#" - sp Self - st T - tt Test - bt u32 - "#]], - ); - - check( - r" -trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } -struct T; - -impl Test for T { - const TEST: u32 = { - fn $0 - }; -} -", - expect![[""]], - ); - - check( - r" -trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } -struct T; - -impl Test for T { - const TEST: u32 = { - fn t$0 - }; -} -", - expect![[""]], - ); - } - - #[test] - fn no_completion_inside_type() { - check( - r" -trait Test { type Test; type Test2; fn test(); } -struct T; - -impl Test for T { - type Test = T$0; -} -", - expect![[r#" - sp Self - st T - tt Test - bt u32 - "#]], - ); - - check( - r" -trait Test { type Test; type Test2; fn test(); } -struct T; - -impl Test for T { - type Test = fn $0; -} -", - expect![[r#""#]], - ); - } - - #[test] - fn name_ref_single_function() { - check_edit( - "fn test", - r#" -trait Test { - fn test(); -} -struct T; - -impl Test for T { - t$0 -} -"#, - r#" -trait Test { - fn test(); -} -struct T; - -impl Test for T { - fn test() { - $0 -} -} -"#, - ); - } - - #[test] - fn single_function() { - check_edit( - "fn test", - r#" -trait Test { - fn test(); -} -struct T; - -impl Test for T { - fn t$0 -} -"#, - r#" -trait Test { - fn test(); -} -struct T; - -impl Test for T { - fn test() { - $0 -} -} -"#, - ); - } - - #[test] - fn generic_fn() { - check_edit( - "fn foo", - r#" -trait Test { - fn foo(); -} -struct T; - -impl Test for T { - fn f$0 -} -"#, - r#" -trait Test { - fn foo(); -} -struct T; - -impl Test for T { - fn foo() { - $0 -} -} -"#, - ); - check_edit( - "fn foo", - r#" -trait Test { - fn foo() where T: Into; -} -struct T; - -impl Test for T { - fn f$0 -} -"#, - r#" -trait Test { - fn foo() where T: Into; -} -struct T; - -impl Test for T { - fn foo() where T: Into { - $0 -} -} -"#, - ); - } - - #[test] - fn associated_type() { - check_edit( - "type SomeType", - r#" -trait Test { - type SomeType; -} - -impl Test for () { - type S$0 -} -"#, - " -trait Test { - type SomeType; -} - -impl Test for () { - type SomeType = $0;\n\ -} -", - ); - check_edit( - "type SomeType", - r#" -trait Test { - type SomeType; -} - -impl Test for () { - type$0 -} -"#, - " -trait Test { - type SomeType; -} - -impl Test for () { - type SomeType = $0;\n\ -} -", - ); - } - - #[test] - fn associated_const() { - check_edit( - "const SOME_CONST", - r#" -trait Test { - const SOME_CONST: u16; -} - -impl Test for () { - const S$0 -} -"#, - " -trait Test { - const SOME_CONST: u16; -} - -impl Test for () { - const SOME_CONST: u16 = $0;\n\ -} -", - ); - - check_edit( - "const SOME_CONST", - r#" -trait Test { - const SOME_CONST: u16 = 92; -} - -impl Test for () { - const S$0 -} -"#, - " -trait Test { - const SOME_CONST: u16 = 92; -} - -impl Test for () { - const SOME_CONST: u16 = $0;\n\ -} -", - ); - } - - #[test] - fn complete_without_name() { - let test = |completion: &str, hint: &str, completed: &str, next_sibling: &str| { - check_edit( - completion, - &format!( - r#" -trait Test {{ - type Foo; - const CONST: u16; - fn bar(); -}} -struct T; - -impl Test for T {{ - {} - {} -}} -"#, - hint, next_sibling - ), - &format!( - r#" -trait Test {{ - type Foo; - const CONST: u16; - fn bar(); -}} -struct T; - -impl Test for T {{ - {} - {} -}} -"#, - completed, next_sibling - ), - ) - }; - - // Enumerate some possible next siblings. - for next_sibling in &[ - "", - "fn other_fn() {}", // `const $0 fn` -> `const fn` - "type OtherType = i32;", - "const OTHER_CONST: i32 = 0;", - "async fn other_fn() {}", - "unsafe fn other_fn() {}", - "default fn other_fn() {}", - "default type OtherType = i32;", - "default const OTHER_CONST: i32 = 0;", - ] { - test("fn bar", "fn $0", "fn bar() {\n $0\n}", next_sibling); - test("type Foo", "type $0", "type Foo = $0;", next_sibling); - test("const CONST", "const $0", "const CONST: u16 = $0;", next_sibling); - } - } - - #[test] - fn snippet_does_not_overwrite_comment_or_attr() { - let test = |completion: &str, hint: &str, completed: &str| { - check_edit( - completion, - &format!( - r#" -trait Foo {{ - type Type; - fn function(); - const CONST: i32 = 0; -}} -struct T; - -impl Foo for T {{ - // Comment - #[bar] - {} -}} -"#, - hint - ), - &format!( - r#" -trait Foo {{ - type Type; - fn function(); - const CONST: i32 = 0; -}} -struct T; - -impl Foo for T {{ - // Comment - #[bar] - {} -}} -"#, - completed - ), - ) - }; - test("fn function", "fn f$0", "fn function() {\n $0\n}"); - test("type Type", "type T$0", "type Type = $0;"); - test("const CONST", "const C$0", "const CONST: i32 = $0;"); - } - - #[test] - fn generics_are_inlined_in_return_type() { - check_edit( - "fn function", - r#" -trait Foo { - fn function() -> T; -} -struct Bar; - -impl Foo for Bar { - fn f$0 -} -"#, - r#" -trait Foo { - fn function() -> T; -} -struct Bar; - -impl Foo for Bar { - fn function() -> u32 { - $0 -} -} -"#, - ) - } - - #[test] - fn generics_are_inlined_in_parameter() { - check_edit( - "fn function", - r#" -trait Foo { - fn function(bar: T); -} -struct Bar; - -impl Foo for Bar { - fn f$0 -} -"#, - r#" -trait Foo { - fn function(bar: T); -} -struct Bar; - -impl Foo for Bar { - fn function(bar: u32) { - $0 -} -} -"#, - ) - } - - #[test] - fn generics_are_inlined_when_part_of_other_types() { - check_edit( - "fn function", - r#" -trait Foo { - fn function(bar: Vec); -} -struct Bar; - -impl Foo for Bar { - fn f$0 -} -"#, - r#" -trait Foo { - fn function(bar: Vec); -} -struct Bar; - -impl Foo for Bar { - fn function(bar: Vec) { - $0 -} -} -"#, - ) - } - - #[test] - fn generics_are_inlined_complex() { - check_edit( - "fn function", - r#" -trait Foo { - fn function(bar: Vec, baz: U) -> Arc>; -} -struct Bar; - -impl Foo, u8> for Bar { - fn f$0 -} -"#, - r#" -trait Foo { - fn function(bar: Vec, baz: U) -> Arc>; -} -struct Bar; - -impl Foo, u8> for Bar { - fn function(bar: Vec, baz: Vec) -> Arc> { - $0 -} -} -"#, - ) - } - - #[test] - fn generics_are_inlined_in_associated_const() { - check_edit( - "const BAR", - r#" -trait Foo { - const BAR: T; -} -struct Bar; - -impl Foo for Bar { - const B$0 -} -"#, - r#" -trait Foo { - const BAR: T; -} -struct Bar; - -impl Foo for Bar { - const BAR: u32 = $0; -} -"#, - ) - } - - #[test] - fn generics_are_inlined_in_where_clause() { - check_edit( - "fn function", - r#" -trait SomeTrait {} - -trait Foo { - fn function() - where Self: SomeTrait; -} -struct Bar; - -impl Foo for Bar { - fn f$0 -} -"#, - r#" -trait SomeTrait {} - -trait Foo { - fn function() - where Self: SomeTrait; -} -struct Bar; - -impl Foo for Bar { - fn function() - where Self: SomeTrait { - $0 -} -} -"#, - ) - } - - #[test] - fn works_directly_in_impl() { - check( - r#" -trait Tr { - fn required(); -} - -impl Tr for () { - $0 -} -"#, - expect![[r#" - fn fn required() - "#]], - ); - check( - r#" -trait Tr { - fn provided() {} - fn required(); -} - -impl Tr for () { - fn provided() {} - $0 -} -"#, - expect![[r#" - fn fn required() - "#]], - ); - } - - #[test] - fn fixes_up_macro_generated() { - check_edit( - "fn foo", - r#" -macro_rules! noop { - ($($item: item)*) => { - $($item)* - } -} - -noop! { - trait Foo { - fn foo(&mut self, bar: i64, baz: &mut u32) -> Result<(), u32>; - } -} - -struct Test; - -impl Foo for Test { - $0 -} -"#, - r#" -macro_rules! noop { - ($($item: item)*) => { - $($item)* - } -} - -noop! { - trait Foo { - fn foo(&mut self, bar: i64, baz: &mut u32) -> Result<(), u32>; - } -} - -struct Test; - -impl Foo for Test { - fn foo(&mut self,bar:i64,baz: &mut u32) -> Result<(),u32> { - $0 -} -} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs deleted file mode 100644 index 3989a451bde42..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs +++ /dev/null @@ -1,237 +0,0 @@ -//! Completes `where` and `for` keywords. - -use syntax::ast::{self, Item}; - -use crate::{CompletionContext, Completions}; - -pub(crate) fn complete_for_and_where( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - keyword_item: &ast::Item, -) { - let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet); - - match keyword_item { - Item::Impl(it) => { - if it.for_token().is_none() && it.trait_().is_none() && it.self_ty().is_some() { - add_keyword("for", "for"); - } - add_keyword("where", "where"); - } - Item::Enum(_) - | Item::Fn(_) - | Item::Struct(_) - | Item::Trait(_) - | Item::TypeAlias(_) - | Item::Union(_) => { - add_keyword("where", "where"); - } - _ => (), - } -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use crate::tests::{check_edit, completion_list}; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) - } - - #[test] - fn test_else_edit_after_if() { - check_edit( - "else", - r#"fn quux() { if true { () } $0 }"#, - r#"fn quux() { if true { () } else { - $0 -} }"#, - ); - } - - #[test] - fn test_keywords_after_unsafe_in_block_expr() { - check( - r"fn my_fn() { unsafe $0 }", - expect![[r#" - kw fn - kw impl - kw trait - "#]], - ); - } - - #[test] - fn test_completion_await_impls_future() { - check( - r#" -//- minicore: future -use core::future::*; -struct A {} -impl Future for A {} -fn foo(a: A) { a.$0 } -"#, - expect![[r#" - kw await expr.await - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr - "#]], - ); - - check( - r#" -//- minicore: future -use std::future::*; -fn foo() { - let a = async {}; - a.$0 -} -"#, - expect![[r#" - kw await expr.await - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr - "#]], - ) - } - - #[test] - fn let_semi() { - cov_mark::check!(let_semi); - check_edit( - "match", - r#" -fn main() { let x = $0 } -"#, - r#" -fn main() { let x = match $1 { - $0 -}; } -"#, - ); - - check_edit( - "if", - r#" -fn main() { - let x = $0 - let y = 92; -} -"#, - r#" -fn main() { - let x = if $1 { - $0 -}; - let y = 92; -} -"#, - ); - - check_edit( - "loop", - r#" -fn main() { - let x = $0 - bar(); -} -"#, - r#" -fn main() { - let x = loop { - $0 -}; - bar(); -} -"#, - ); - } - - #[test] - fn if_completion_in_match_guard() { - check_edit( - "if", - r" -fn main() { - match () { - () $0 - } -} -", - r" -fn main() { - match () { - () if $0 - } -} -", - ) - } - - #[test] - fn if_completion_in_match_arm_expr() { - check_edit( - "if", - r" -fn main() { - match () { - () => $0 - } -} -", - r" -fn main() { - match () { - () => if $1 { - $0 -} - } -} -", - ) - } - - #[test] - fn if_completion_in_match_arm_expr_block() { - check_edit( - "if", - r" -fn main() { - match () { - () => { - $0 - } - } -} -", - r" -fn main() { - match () { - () => { - if $1 { - $0 -} - } - } -} -", - ) - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs deleted file mode 100644 index 3b79def639df4..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs +++ /dev/null @@ -1,341 +0,0 @@ -//! Completes lifetimes and labels. -//! -//! These completions work a bit differently in that they are only shown when what the user types -//! has a `'` preceding it, as our fake syntax tree is invalid otherwise (due to us not inserting -//! a lifetime but an ident for obvious reasons). -//! Due to this all the tests for lifetimes and labels live in this module for the time being as -//! there is no value in lifting these out into the outline module test since they will either not -//! show up for normal completions, or they won't show completions other than lifetimes depending -//! on the fixture input. -use hir::{known, ScopeDef}; -use syntax::{ast, TokenText}; - -use crate::{ - completions::Completions, - context::{CompletionContext, LifetimeContext, LifetimeKind}, -}; - -/// Completes lifetimes. -pub(crate) fn complete_lifetime( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - lifetime_ctx: &LifetimeContext, -) { - let (lp, lifetime) = match lifetime_ctx { - LifetimeContext { kind: LifetimeKind::Lifetime, lifetime } => (None, lifetime), - LifetimeContext { - kind: LifetimeKind::LifetimeParam { is_decl: false, param }, - lifetime, - } => (Some(param), lifetime), - _ => return, - }; - let param_lifetime = match (lifetime, lp.and_then(|lp| lp.lifetime())) { - (Some(lt), Some(lp)) if lp == lt.clone() => return, - (Some(_), Some(lp)) => Some(lp), - _ => None, - }; - let param_lifetime = param_lifetime.as_ref().map(ast::Lifetime::text); - let param_lifetime = param_lifetime.as_ref().map(TokenText::as_str); - - ctx.process_all_names_raw(&mut |name, res| { - if matches!( - res, - ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) - if param_lifetime != Some(&*name.to_smol_str()) - ) { - acc.add_lifetime(ctx, name); - } - }); - if param_lifetime.is_none() { - acc.add_lifetime(ctx, known::STATIC_LIFETIME); - } -} - -/// Completes labels. -pub(crate) fn complete_label( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - lifetime_ctx: &LifetimeContext, -) { - if !matches!(lifetime_ctx, LifetimeContext { kind: LifetimeKind::LabelRef, .. }) { - return; - } - ctx.process_all_names_raw(&mut |name, res| { - if let ScopeDef::Label(_) = res { - acc.add_label(ctx, name); - } - }); -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use crate::tests::{check_edit, completion_list}; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); - } - - #[test] - fn check_lifetime_edit() { - check_edit( - "'lifetime", - r#" -fn func<'lifetime>(foo: &'li$0) {} -"#, - r#" -fn func<'lifetime>(foo: &'lifetime) {} -"#, - ); - cov_mark::check!(completes_if_lifetime_without_idents); - check_edit( - "'lifetime", - r#" -fn func<'lifetime>(foo: &'$0) {} -"#, - r#" -fn func<'lifetime>(foo: &'lifetime) {} -"#, - ); - } - - #[test] - fn complete_lifetime_in_ref() { - check( - r#" -fn foo<'lifetime>(foo: &'a$0 usize) {} -"#, - expect![[r#" - lt 'lifetime - lt 'static - "#]], - ); - } - - #[test] - fn complete_lifetime_in_ref_missing_ty() { - check( - r#" -fn foo<'lifetime>(foo: &'a$0) {} -"#, - expect![[r#" - lt 'lifetime - lt 'static - "#]], - ); - } - #[test] - fn complete_lifetime_in_self_ref() { - check( - r#" -struct Foo; -impl<'impl> Foo { - fn foo<'func>(&'a$0 self) {} -} -"#, - expect![[r#" - lt 'func - lt 'impl - lt 'static - "#]], - ); - } - - #[test] - fn complete_lifetime_in_arg_list() { - check( - r#" -struct Foo<'lt>; -fn foo<'lifetime>(_: Foo<'a$0>) {} -"#, - expect![[r#" - lt 'lifetime - lt 'static - "#]], - ); - } - - #[test] - fn complete_lifetime_in_where_pred() { - check( - r#" -fn foo2<'lifetime, T>() where 'a$0 {} -"#, - expect![[r#" - lt 'lifetime - lt 'static - "#]], - ); - } - - #[test] - fn complete_lifetime_in_ty_bound() { - check( - r#" -fn foo2<'lifetime, T>() where T: 'a$0 {} -"#, - expect![[r#" - lt 'lifetime - lt 'static - "#]], - ); - check( - r#" -fn foo2<'lifetime, T>() where T: Trait<'a$0> {} -"#, - expect![[r#" - lt 'lifetime - lt 'static - "#]], - ); - } - - #[test] - fn dont_complete_lifetime_in_assoc_ty_bound() { - check( - r#" -fn foo2<'lifetime, T>() where T: Trait {} -"#, - expect![[r#""#]], - ); - } - - #[test] - fn complete_lifetime_in_param_list() { - check( - r#" -fn foo<'$0>() {} -"#, - expect![[r#""#]], - ); - check( - r#" -fn foo<'a$0>() {} -"#, - expect![[r#""#]], - ); - check( - r#" -fn foo<'footime, 'lifetime: 'a$0>() {} -"#, - expect![[r#" - lt 'footime - "#]], - ); - } - - #[test] - fn check_label_edit() { - check_edit( - "'label", - r#" -fn foo() { - 'label: loop { - break '$0 - } -} -"#, - r#" -fn foo() { - 'label: loop { - break 'label - } -} -"#, - ); - } - - #[test] - fn complete_label_in_loop() { - check( - r#" -fn foo() { - 'foop: loop { - break '$0 - } -} -"#, - expect![[r#" - lb 'foop - "#]], - ); - check( - r#" -fn foo() { - 'foop: loop { - continue '$0 - } -} -"#, - expect![[r#" - lb 'foop - "#]], - ); - } - - #[test] - fn complete_label_in_block_nested() { - check( - r#" -fn foo() { - 'foop: { - 'baap: { - break '$0 - } - } -} -"#, - expect![[r#" - lb 'baap - lb 'foop - "#]], - ); - } - - #[test] - fn complete_label_in_loop_with_value() { - check( - r#" -fn foo() { - 'foop: loop { - break '$0 i32; - } -} -"#, - expect![[r#" - lb 'foop - "#]], - ); - } - - #[test] - fn complete_label_in_while_cond() { - check( - r#" -fn foo() { - 'outer: while { 'inner: loop { break '$0 } } {} -} -"#, - expect![[r#" - lb 'inner - lb 'outer - "#]], - ); - } - - #[test] - fn complete_label_in_for_iterable() { - check( - r#" -fn foo() { - 'outer: for _ in [{ 'inner: loop { break '$0 } }] {} -} -"#, - expect![[r#" - lb 'inner - "#]], - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs deleted file mode 100644 index 9c975b9295337..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs +++ /dev/null @@ -1,354 +0,0 @@ -//! Completes mod declarations. - -use std::iter; - -use hir::{Module, ModuleSource}; -use ide_db::{ - base_db::{SourceDatabaseExt, VfsPath}, - FxHashSet, RootDatabase, SymbolKind, -}; -use syntax::{ast, AstNode, SyntaxKind}; - -use crate::{context::CompletionContext, CompletionItem, Completions}; - -/// Complete mod declaration, i.e. `mod $0;` -pub(crate) fn complete_mod( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - mod_under_caret: &ast::Module, -) -> Option<()> { - if mod_under_caret.item_list().is_some() { - return None; - } - - let _p = profile::span("completion::complete_mod"); - - let mut current_module = ctx.module; - // For `mod $0`, `ctx.module` is its parent, but for `mod f$0`, it's `mod f` itself, but we're - // interested in its parent. - if ctx.original_token.kind() == SyntaxKind::IDENT { - if let Some(module) = - ctx.original_token.parent_ancestors().nth(1).and_then(ast::Module::cast) - { - match ctx.sema.to_def(&module) { - Some(module) if module == current_module => { - if let Some(parent) = current_module.parent(ctx.db) { - current_module = parent; - } - } - _ => {} - } - } - } - - let module_definition_file = - current_module.definition_source(ctx.db).file_id.original_file(ctx.db); - let source_root = ctx.db.source_root(ctx.db.file_source_root(module_definition_file)); - let directory_to_look_for_submodules = directory_to_look_for_submodules( - current_module, - ctx.db, - source_root.path_for_file(&module_definition_file)?, - )?; - - let existing_mod_declarations = current_module - .children(ctx.db) - .filter_map(|module| Some(module.name(ctx.db)?.to_string())) - .collect::>(); - - let module_declaration_file = - current_module.declaration_source(ctx.db).map(|module_declaration_source_file| { - module_declaration_source_file.file_id.original_file(ctx.db) - }); - - source_root - .iter() - .filter(|submodule_candidate_file| submodule_candidate_file != &module_definition_file) - .filter(|submodule_candidate_file| { - Some(submodule_candidate_file) != module_declaration_file.as_ref() - }) - .filter_map(|submodule_file| { - let submodule_path = source_root.path_for_file(&submodule_file)?; - let directory_with_submodule = submodule_path.parent()?; - let (name, ext) = submodule_path.name_and_extension()?; - if ext != Some("rs") { - return None; - } - match name { - "lib" | "main" => None, - "mod" => { - if directory_with_submodule.parent()? == directory_to_look_for_submodules { - match directory_with_submodule.name_and_extension()? { - (directory_name, None) => Some(directory_name.to_owned()), - _ => None, - } - } else { - None - } - } - file_name if directory_with_submodule == directory_to_look_for_submodules => { - Some(file_name.to_owned()) - } - _ => None, - } - }) - .filter(|name| !existing_mod_declarations.contains(name)) - .for_each(|submodule_name| { - let mut label = submodule_name; - if mod_under_caret.semicolon_token().is_none() { - label.push(';'); - } - let item = CompletionItem::new(SymbolKind::Module, ctx.source_range(), &label); - item.add_to(acc) - }); - - Some(()) -} - -fn directory_to_look_for_submodules( - module: Module, - db: &RootDatabase, - module_file_path: &VfsPath, -) -> Option { - let directory_with_module_path = module_file_path.parent()?; - let (name, ext) = module_file_path.name_and_extension()?; - if ext != Some("rs") { - return None; - } - let base_directory = match name { - "mod" | "lib" | "main" => Some(directory_with_module_path), - regular_rust_file_name => { - if matches!( - ( - directory_with_module_path - .parent() - .as_ref() - .and_then(|path| path.name_and_extension()), - directory_with_module_path.name_and_extension(), - ), - (Some(("src", None)), Some(("bin", None))) - ) { - // files in /src/bin/ can import each other directly - Some(directory_with_module_path) - } else { - directory_with_module_path.join(regular_rust_file_name) - } - } - }?; - - module_chain_to_containing_module_file(module, db) - .into_iter() - .filter_map(|module| module.name(db)) - .try_fold(base_directory, |path, name| path.join(&name.to_smol_str())) -} - -fn module_chain_to_containing_module_file( - current_module: Module, - db: &RootDatabase, -) -> Vec { - let mut path = - iter::successors(Some(current_module), |current_module| current_module.parent(db)) - .take_while(|current_module| { - matches!(current_module.definition_source(db).value, ModuleSource::Module(_)) - }) - .collect::>(); - path.reverse(); - path -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use crate::tests::completion_list; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); - } - - #[test] - fn lib_module_completion() { - check( - r#" -//- /lib.rs -mod $0 -//- /foo.rs -fn foo() {} -//- /foo/ignored_foo.rs -fn ignored_foo() {} -//- /bar/mod.rs -fn bar() {} -//- /bar/ignored_bar.rs -fn ignored_bar() {} -"#, - expect![[r#" - md bar; - md foo; - "#]], - ); - } - - #[test] - fn no_module_completion_with_module_body() { - check( - r#" -//- /lib.rs -mod $0 { - -} -//- /foo.rs -fn foo() {} -"#, - expect![[r#""#]], - ); - } - - #[test] - fn main_module_completion() { - check( - r#" -//- /main.rs -mod $0 -//- /foo.rs -fn foo() {} -//- /foo/ignored_foo.rs -fn ignored_foo() {} -//- /bar/mod.rs -fn bar() {} -//- /bar/ignored_bar.rs -fn ignored_bar() {} -"#, - expect![[r#" - md bar; - md foo; - "#]], - ); - } - - #[test] - fn main_test_module_completion() { - check( - r#" -//- /main.rs -mod tests { - mod $0; -} -//- /tests/foo.rs -fn foo() {} -"#, - expect![[r#" - md foo - "#]], - ); - } - - #[test] - fn directly_nested_module_completion() { - check( - r#" -//- /lib.rs -mod foo; -//- /foo.rs -mod $0; -//- /foo/bar.rs -fn bar() {} -//- /foo/bar/ignored_bar.rs -fn ignored_bar() {} -//- /foo/baz/mod.rs -fn baz() {} -//- /foo/moar/ignored_moar.rs -fn ignored_moar() {} -"#, - expect![[r#" - md bar - md baz - "#]], - ); - } - - #[test] - fn nested_in_source_module_completion() { - check( - r#" -//- /lib.rs -mod foo; -//- /foo.rs -mod bar { - mod $0 -} -//- /foo/bar/baz.rs -fn baz() {} -"#, - expect![[r#" - md baz; - "#]], - ); - } - - // FIXME binary modules are not supported in tests properly - // Binary modules are a bit special, they allow importing the modules from `/src/bin` - // and that's why are good to test two things: - // * no cycles are allowed in mod declarations - // * no modules from the parent directory are proposed - // Unfortunately, binary modules support is in cargo not rustc, - // hence the test does not work now - // - // #[test] - // fn regular_bin_module_completion() { - // check( - // r#" - // //- /src/bin.rs - // fn main() {} - // //- /src/bin/foo.rs - // mod $0 - // //- /src/bin/bar.rs - // fn bar() {} - // //- /src/bin/bar/bar_ignored.rs - // fn bar_ignored() {} - // "#, - // expect![[r#" - // md bar; - // "#]],foo - // ); - // } - - #[test] - fn already_declared_bin_module_completion_omitted() { - check( - r#" -//- /src/bin.rs crate:main -fn main() {} -//- /src/bin/foo.rs -mod $0 -//- /src/bin/bar.rs -mod foo; -fn bar() {} -//- /src/bin/bar/bar_ignored.rs -fn bar_ignored() {} -"#, - expect![[r#""#]], - ); - } - - #[test] - fn name_partially_typed() { - check( - r#" -//- /lib.rs -mod f$0 -//- /foo.rs -fn foo() {} -//- /foo/ignored_foo.rs -fn ignored_foo() {} -//- /bar/mod.rs -fn bar() {} -//- /bar/ignored_bar.rs -fn ignored_bar() {} -"#, - expect![[r#" - md bar; - md foo; - "#]], - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs deleted file mode 100644 index 17dfe432b3529..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs +++ /dev/null @@ -1,185 +0,0 @@ -//! Completes constants and paths in unqualified patterns. - -use hir::{db::DefDatabase, AssocItem, ScopeDef}; -use syntax::ast::Pat; - -use crate::{ - context::{PathCompletionCtx, PatternContext, PatternRefutability, Qualified}, - CompletionContext, Completions, -}; - -/// Completes constants and paths in unqualified patterns. -pub(crate) fn complete_pattern( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - pattern_ctx: &PatternContext, -) { - match pattern_ctx.parent_pat.as_ref() { - Some(Pat::RangePat(_) | Pat::BoxPat(_)) => (), - Some(Pat::RefPat(r)) => { - if r.mut_token().is_none() { - acc.add_keyword(ctx, "mut"); - } - } - _ => { - let tok = ctx.token.text_range().start(); - match (pattern_ctx.ref_token.as_ref(), pattern_ctx.mut_token.as_ref()) { - (None, None) => { - acc.add_keyword(ctx, "ref"); - acc.add_keyword(ctx, "mut"); - } - (None, Some(m)) if tok < m.text_range().start() => { - acc.add_keyword(ctx, "ref"); - } - (Some(r), None) if tok > r.text_range().end() => { - acc.add_keyword(ctx, "mut"); - } - _ => (), - } - } - } - - if pattern_ctx.record_pat.is_some() { - return; - } - - let refutable = pattern_ctx.refutability == PatternRefutability::Refutable; - let single_variant_enum = |enum_: hir::Enum| ctx.db.enum_data(enum_.into()).variants.len() == 1; - - if let Some(hir::Adt::Enum(e)) = - ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) - { - if refutable || single_variant_enum(e) { - super::enum_variants_with_paths( - acc, - ctx, - e, - &pattern_ctx.impl_, - |acc, ctx, variant, path| { - acc.add_qualified_variant_pat(ctx, pattern_ctx, variant, path); - }, - ); - } - } - - // FIXME: ideally, we should look at the type we are matching against and - // suggest variants + auto-imports - ctx.process_all_names(&mut |name, res| { - let add_simple_path = match res { - hir::ScopeDef::ModuleDef(def) => match def { - hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => { - acc.add_struct_pat(ctx, pattern_ctx, strukt, Some(name.clone())); - true - } - hir::ModuleDef::Variant(variant) - if refutable || single_variant_enum(variant.parent_enum(ctx.db)) => - { - acc.add_variant_pat(ctx, pattern_ctx, variant, Some(name.clone())); - true - } - hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e), - hir::ModuleDef::Const(..) => refutable, - hir::ModuleDef::Module(..) => true, - hir::ModuleDef::Macro(mac) => mac.is_fn_like(ctx.db), - _ => false, - }, - hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() { - Some(hir::Adt::Struct(strukt)) => { - acc.add_struct_pat(ctx, pattern_ctx, strukt, Some(name.clone())); - true - } - Some(hir::Adt::Enum(e)) => refutable || single_variant_enum(e), - Some(hir::Adt::Union(_)) => true, - _ => false, - }, - ScopeDef::GenericParam(hir::GenericParam::ConstParam(_)) => true, - ScopeDef::GenericParam(_) - | ScopeDef::AdtSelfType(_) - | ScopeDef::Local(_) - | ScopeDef::Label(_) - | ScopeDef::Unknown => false, - }; - if add_simple_path { - acc.add_pattern_resolution(ctx, pattern_ctx, name, res); - } - }); -} - -pub(crate) fn complete_pattern_path( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, -) { - match qualified { - Qualified::With { resolution: Some(resolution), super_chain_len, .. } => { - acc.add_super_keyword(ctx, *super_chain_len); - - match resolution { - hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { - let module_scope = module.scope(ctx.db, Some(ctx.module)); - for (name, def) in module_scope { - let add_resolution = match def { - ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => { - mac.is_fn_like(ctx.db) - } - ScopeDef::ModuleDef(_) => true, - _ => false, - }; - - if add_resolution { - acc.add_path_resolution(ctx, path_ctx, name, def); - } - } - } - res => { - let ty = match res { - hir::PathResolution::TypeParam(param) => param.ty(ctx.db), - hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db), - hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Struct(s))) => { - s.ty(ctx.db) - } - hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => { - e.ty(ctx.db) - } - hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Union(u))) => { - u.ty(ctx.db) - } - hir::PathResolution::Def(hir::ModuleDef::BuiltinType(ty)) => ty.ty(ctx.db), - _ => return, - }; - - if let Some(hir::Adt::Enum(e)) = ty.as_adt() { - acc.add_enum_variants(ctx, path_ctx, e); - } - - ctx.iterate_path_candidates(&ty, |item| match item { - AssocItem::TypeAlias(ta) => acc.add_type_alias(ctx, ta), - AssocItem::Const(c) => acc.add_const(ctx, c), - _ => {} - }); - } - } - } - Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx), - Qualified::No => { - // this will only be hit if there are brackets or braces, otherwise this will be parsed as an ident pattern - ctx.process_all_names(&mut |name, res| { - // FIXME: we should check what kind of pattern we are in and filter accordingly - let add_completion = match res { - ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db), - ScopeDef::ModuleDef(hir::ModuleDef::Adt(_)) => true, - ScopeDef::ModuleDef(hir::ModuleDef::Variant(_)) => true, - ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true, - ScopeDef::ImplSelfType(_) => true, - _ => false, - }; - if add_completion { - acc.add_path_resolution(ctx, path_ctx, name, res); - } - }); - - acc.add_nameref_keywords_with_colon(ctx); - } - Qualified::Infer | Qualified::With { .. } => {} - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs deleted file mode 100644 index 9a891cea2d458..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ /dev/null @@ -1,616 +0,0 @@ -//! Postfix completions, like `Ok(10).ifl$0` => `if let Ok() = Ok(10) { $0 }`. - -mod format_like; - -use hir::{Documentation, HasAttrs}; -use ide_db::{imports::insert_use::ImportScope, ty_filter::TryEnum, SnippetCap}; -use syntax::{ - ast::{self, AstNode, AstToken}, - SyntaxKind::{EXPR_STMT, STMT_LIST}, - TextRange, TextSize, -}; -use text_edit::TextEdit; - -use crate::{ - completions::postfix::format_like::add_format_like_completions, - context::{CompletionContext, DotAccess, DotAccessKind}, - item::{Builder, CompletionRelevancePostfixMatch}, - CompletionItem, CompletionItemKind, CompletionRelevance, Completions, SnippetScope, -}; - -pub(crate) fn complete_postfix( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - dot_access: &DotAccess, -) { - if !ctx.config.enable_postfix_completions { - return; - } - - let (dot_receiver, receiver_ty, receiver_is_ambiguous_float_literal) = match dot_access { - DotAccess { receiver_ty: Some(ty), receiver: Some(it), kind, .. } => ( - it, - &ty.original, - match *kind { - DotAccessKind::Field { receiver_is_ambiguous_float_literal } => { - receiver_is_ambiguous_float_literal - } - DotAccessKind::Method { .. } => false, - }, - ), - _ => return, - }; - - let receiver_text = get_receiver_text(dot_receiver, receiver_is_ambiguous_float_literal); - - let cap = match ctx.config.snippet_cap { - Some(it) => it, - None => return, - }; - - let postfix_snippet = match build_postfix_snippet_builder(ctx, cap, dot_receiver) { - Some(it) => it, - None => return, - }; - - if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() { - if receiver_ty.impls_trait(ctx.db, drop_trait, &[]) { - if let &[hir::AssocItem::Function(drop_fn)] = &*drop_trait.items(ctx.db) { - cov_mark::hit!(postfix_drop_completion); - // FIXME: check that `drop` is in scope, use fully qualified path if it isn't/if shadowed - let mut item = postfix_snippet( - "drop", - "fn drop(&mut self)", - &format!("drop($0{})", receiver_text), - ); - item.set_documentation(drop_fn.docs(ctx.db)); - item.add_to(acc); - } - } - } - - if !ctx.config.snippets.is_empty() { - add_custom_postfix_completions(acc, ctx, &postfix_snippet, &receiver_text); - } - - let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty.strip_references()); - if let Some(try_enum) = &try_enum { - match try_enum { - TryEnum::Result => { - postfix_snippet( - "ifl", - "if let Ok {}", - &format!("if let Ok($1) = {} {{\n $0\n}}", receiver_text), - ) - .add_to(acc); - - postfix_snippet( - "while", - "while let Ok {}", - &format!("while let Ok($1) = {} {{\n $0\n}}", receiver_text), - ) - .add_to(acc); - } - TryEnum::Option => { - postfix_snippet( - "ifl", - "if let Some {}", - &format!("if let Some($1) = {} {{\n $0\n}}", receiver_text), - ) - .add_to(acc); - - postfix_snippet( - "while", - "while let Some {}", - &format!("while let Some($1) = {} {{\n $0\n}}", receiver_text), - ) - .add_to(acc); - } - } - } else if receiver_ty.is_bool() || receiver_ty.is_unknown() { - postfix_snippet("if", "if expr {}", &format!("if {} {{\n $0\n}}", receiver_text)) - .add_to(acc); - postfix_snippet( - "while", - "while expr {}", - &format!("while {} {{\n $0\n}}", receiver_text), - ) - .add_to(acc); - postfix_snippet("not", "!expr", &format!("!{}", receiver_text)).add_to(acc); - } else if let Some(trait_) = ctx.famous_defs().core_iter_IntoIterator() { - if receiver_ty.impls_trait(ctx.db, trait_, &[]) { - postfix_snippet( - "for", - "for ele in expr {}", - &format!("for ele in {} {{\n $0\n}}", receiver_text), - ) - .add_to(acc); - } - } - - postfix_snippet("ref", "&expr", &format!("&{}", receiver_text)).add_to(acc); - postfix_snippet("refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc); - - // The rest of the postfix completions create an expression that moves an argument, - // so it's better to consider references now to avoid breaking the compilation - let dot_receiver = include_references(dot_receiver); - let receiver_text = get_receiver_text(&dot_receiver, receiver_is_ambiguous_float_literal); - let postfix_snippet = match build_postfix_snippet_builder(ctx, cap, &dot_receiver) { - Some(it) => it, - None => return, - }; - - match try_enum { - Some(try_enum) => match try_enum { - TryEnum::Result => { - postfix_snippet( - "match", - "match expr {}", - &format!("match {} {{\n Ok(${{1:_}}) => {{$2}},\n Err(${{3:_}}) => {{$0}},\n}}", receiver_text), - ) - .add_to(acc); - } - TryEnum::Option => { - postfix_snippet( - "match", - "match expr {}", - &format!( - "match {} {{\n Some(${{1:_}}) => {{$2}},\n None => {{$0}},\n}}", - receiver_text - ), - ) - .add_to(acc); - } - }, - None => { - postfix_snippet( - "match", - "match expr {}", - &format!("match {} {{\n ${{1:_}} => {{$0}},\n}}", receiver_text), - ) - .add_to(acc); - } - } - - postfix_snippet("box", "Box::new(expr)", &format!("Box::new({})", receiver_text)).add_to(acc); - postfix_snippet("dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc); // fixme - postfix_snippet("dbgr", "dbg!(&expr)", &format!("dbg!(&{})", receiver_text)).add_to(acc); - postfix_snippet("call", "function(expr)", &format!("${{1}}({})", receiver_text)).add_to(acc); - - if let Some(parent) = dot_receiver.syntax().parent().and_then(|p| p.parent()) { - if matches!(parent.kind(), STMT_LIST | EXPR_STMT) { - postfix_snippet("let", "let", &format!("let $0 = {};", receiver_text)).add_to(acc); - postfix_snippet("letm", "let mut", &format!("let mut $0 = {};", receiver_text)) - .add_to(acc); - } - } - - if let ast::Expr::Literal(literal) = dot_receiver.clone() { - if let Some(literal_text) = ast::String::cast(literal.token()) { - add_format_like_completions(acc, ctx, &dot_receiver, cap, &literal_text); - } - } -} - -fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String { - let text = if receiver_is_ambiguous_float_literal { - let text = receiver.syntax().text(); - let without_dot = ..text.len() - TextSize::of('.'); - text.slice(without_dot).to_string() - } else { - receiver.to_string() - }; - - // The receiver texts should be interpreted as-is, as they are expected to be - // normal Rust expressions. We escape '\' and '$' so they don't get treated as - // snippet-specific constructs. - // - // Note that we don't need to escape the other characters that can be escaped, - // because they wouldn't be treated as snippet-specific constructs without '$'. - text.replace('\\', "\\\\").replace('$', "\\$") -} - -fn include_references(initial_element: &ast::Expr) -> ast::Expr { - let mut resulting_element = initial_element.clone(); - while let Some(parent_ref_element) = - resulting_element.syntax().parent().and_then(ast::RefExpr::cast) - { - resulting_element = ast::Expr::from(parent_ref_element); - } - resulting_element -} - -fn build_postfix_snippet_builder<'ctx>( - ctx: &'ctx CompletionContext<'_>, - cap: SnippetCap, - receiver: &'ctx ast::Expr, -) -> Option Builder + 'ctx> { - let receiver_syntax = receiver.syntax(); - let receiver_range = ctx.sema.original_range_opt(receiver_syntax)?.range; - if ctx.source_range().end() < receiver_range.start() { - // This shouldn't happen, yet it does. I assume this might be due to an incorrect token mapping. - return None; - } - let delete_range = TextRange::new(receiver_range.start(), ctx.source_range().end()); - - // Wrapping impl Fn in an option ruins lifetime inference for the parameters in a way that - // can't be annotated for the closure, hence fix it by constructing it without the Option first - fn build<'ctx>( - ctx: &'ctx CompletionContext<'_>, - cap: SnippetCap, - delete_range: TextRange, - ) -> impl Fn(&str, &str, &str) -> Builder + 'ctx { - move |label, detail, snippet| { - let edit = TextEdit::replace(delete_range, snippet.to_string()); - let mut item = - CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label); - item.detail(detail).snippet_edit(cap, edit); - let postfix_match = if ctx.original_token.text() == label { - cov_mark::hit!(postfix_exact_match_is_high_priority); - Some(CompletionRelevancePostfixMatch::Exact) - } else { - cov_mark::hit!(postfix_inexact_match_is_low_priority); - Some(CompletionRelevancePostfixMatch::NonExact) - }; - let relevance = CompletionRelevance { postfix_match, ..Default::default() }; - item.set_relevance(relevance); - item - } - } - Some(build(ctx, cap, delete_range)) -} - -fn add_custom_postfix_completions( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - postfix_snippet: impl Fn(&str, &str, &str) -> Builder, - receiver_text: &str, -) -> Option<()> { - if ImportScope::find_insert_use_container(&ctx.token.parent()?, &ctx.sema).is_none() { - return None; - } - ctx.config.postfix_snippets().filter(|(_, snip)| snip.scope == SnippetScope::Expr).for_each( - |(trigger, snippet)| { - let imports = match snippet.imports(ctx) { - Some(imports) => imports, - None => return, - }; - let body = snippet.postfix_snippet(receiver_text); - let mut builder = - postfix_snippet(trigger, snippet.description.as_deref().unwrap_or_default(), &body); - builder.documentation(Documentation::new(format!("```rust\n{}\n```", body))); - for import in imports.into_iter() { - builder.add_import(import); - } - builder.add_to(acc); - }, - ); - None -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use crate::{ - tests::{check_edit, check_edit_with_config, completion_list, TEST_CONFIG}, - CompletionConfig, Snippet, - }; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) - } - - #[test] - fn postfix_completion_works_for_trivial_path_expression() { - check( - r#" -fn main() { - let bar = true; - bar.$0 -} -"#, - expect![[r#" - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn if if expr {} - sn let let - sn letm let mut - sn match match expr {} - sn not !expr - sn ref &expr - sn refm &mut expr - sn while while expr {} - "#]], - ); - } - - #[test] - fn postfix_completion_works_for_function_calln() { - check( - r#" -fn foo(elt: bool) -> bool { - !elt -} - -fn main() { - let bar = true; - foo(bar.$0) -} -"#, - expect![[r#" - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn if if expr {} - sn match match expr {} - sn not !expr - sn ref &expr - sn refm &mut expr - sn while while expr {} - "#]], - ); - } - - #[test] - fn postfix_type_filtering() { - check( - r#" -fn main() { - let bar: u8 = 12; - bar.$0 -} -"#, - expect![[r#" - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr - "#]], - ) - } - - #[test] - fn let_middle_block() { - check( - r#" -fn main() { - baz.l$0 - res -} -"#, - expect![[r#" - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn if if expr {} - sn let let - sn letm let mut - sn match match expr {} - sn not !expr - sn ref &expr - sn refm &mut expr - sn while while expr {} - "#]], - ); - } - - #[test] - fn option_iflet() { - check_edit( - "ifl", - r#" -//- minicore: option -fn main() { - let bar = Some(true); - bar.$0 -} -"#, - r#" -fn main() { - let bar = Some(true); - if let Some($1) = bar { - $0 -} -} -"#, - ); - } - - #[test] - fn result_match() { - check_edit( - "match", - r#" -//- minicore: result -fn main() { - let bar = Ok(true); - bar.$0 -} -"#, - r#" -fn main() { - let bar = Ok(true); - match bar { - Ok(${1:_}) => {$2}, - Err(${3:_}) => {$0}, -} -} -"#, - ); - } - - #[test] - fn postfix_completion_works_for_ambiguous_float_literal() { - check_edit("refm", r#"fn main() { 42.$0 }"#, r#"fn main() { &mut 42 }"#) - } - - #[test] - fn works_in_simple_macro() { - check_edit( - "dbg", - r#" -macro_rules! m { ($e:expr) => { $e } } -fn main() { - let bar: u8 = 12; - m!(bar.d$0) -} -"#, - r#" -macro_rules! m { ($e:expr) => { $e } } -fn main() { - let bar: u8 = 12; - m!(dbg!(bar)) -} -"#, - ); - } - - #[test] - fn postfix_completion_for_references() { - check_edit("dbg", r#"fn main() { &&42.$0 }"#, r#"fn main() { dbg!(&&42) }"#); - check_edit("refm", r#"fn main() { &&42.$0 }"#, r#"fn main() { &&&mut 42 }"#); - check_edit( - "ifl", - r#" -//- minicore: option -fn main() { - let bar = &Some(true); - bar.$0 -} -"#, - r#" -fn main() { - let bar = &Some(true); - if let Some($1) = bar { - $0 -} -} -"#, - ) - } - - #[test] - fn custom_postfix_completion() { - let config = CompletionConfig { - snippets: vec![Snippet::new( - &[], - &["break".into()], - &["ControlFlow::Break(${receiver})".into()], - "", - &["core::ops::ControlFlow".into()], - crate::SnippetScope::Expr, - ) - .unwrap()], - ..TEST_CONFIG - }; - - check_edit_with_config( - config.clone(), - "break", - r#" -//- minicore: try -fn main() { 42.$0 } -"#, - r#" -use core::ops::ControlFlow; - -fn main() { ControlFlow::Break(42) } -"#, - ); - - // The receiver texts should be escaped, see comments in `get_receiver_text()` - // for detail. - // - // Note that the last argument is what *lsp clients would see* rather than - // what users would see. Unescaping happens thereafter. - check_edit_with_config( - config.clone(), - "break", - r#" -//- minicore: try -fn main() { '\\'.$0 } -"#, - r#" -use core::ops::ControlFlow; - -fn main() { ControlFlow::Break('\\\\') } -"#, - ); - - check_edit_with_config( - config.clone(), - "break", - r#" -//- minicore: try -fn main() { - match true { - true => "${1:placeholder}", - false => "\$", - }.$0 -} -"#, - r#" -use core::ops::ControlFlow; - -fn main() { - ControlFlow::Break(match true { - true => "\${1:placeholder}", - false => "\\\$", - }) -} -"#, - ); - } - - #[test] - fn postfix_completion_for_format_like_strings() { - check_edit( - "format", - r#"fn main() { "{some_var:?}".$0 }"#, - r#"fn main() { format!("{:?}", some_var) }"#, - ); - check_edit( - "panic", - r#"fn main() { "Panic with {a}".$0 }"#, - r#"fn main() { panic!("Panic with {}", a) }"#, - ); - check_edit( - "println", - r#"fn main() { "{ 2+2 } { SomeStruct { val: 1, other: 32 } :?}".$0 }"#, - r#"fn main() { println!("{} {:?}", 2+2, SomeStruct { val: 1, other: 32 }) }"#, - ); - check_edit( - "loge", - r#"fn main() { "{2+2}".$0 }"#, - r#"fn main() { log::error!("{}", 2+2) }"#, - ); - check_edit( - "logt", - r#"fn main() { "{2+2}".$0 }"#, - r#"fn main() { log::trace!("{}", 2+2) }"#, - ); - check_edit( - "logd", - r#"fn main() { "{2+2}".$0 }"#, - r#"fn main() { log::debug!("{}", 2+2) }"#, - ); - check_edit("logi", r#"fn main() { "{2+2}".$0 }"#, r#"fn main() { log::info!("{}", 2+2) }"#); - check_edit("logw", r#"fn main() { "{2+2}".$0 }"#, r#"fn main() { log::warn!("{}", 2+2) }"#); - check_edit( - "loge", - r#"fn main() { "{2+2}".$0 }"#, - r#"fn main() { log::error!("{}", 2+2) }"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs deleted file mode 100644 index 6b94347e0ad05..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs +++ /dev/null @@ -1,311 +0,0 @@ -// Feature: Format String Completion -// -// `"Result {result} is {2 + 2}"` is expanded to the `"Result {} is {}", result, 2 + 2`. -// -// The following postfix snippets are available: -// -// * `format` -> `format!(...)` -// * `panic` -> `panic!(...)` -// * `println` -> `println!(...)` -// * `log`: -// ** `logd` -> `log::debug!(...)` -// ** `logt` -> `log::trace!(...)` -// ** `logi` -> `log::info!(...)` -// ** `logw` -> `log::warn!(...)` -// ** `loge` -> `log::error!(...)` -// -// image::https://user-images.githubusercontent.com/48062697/113020656-b560f500-917a-11eb-87de-02991f61beb8.gif[] - -use ide_db::SnippetCap; -use syntax::ast::{self, AstToken}; - -use crate::{ - completions::postfix::build_postfix_snippet_builder, context::CompletionContext, Completions, -}; - -/// Mapping ("postfix completion item" => "macro to use") -static KINDS: &[(&str, &str)] = &[ - ("format", "format!"), - ("panic", "panic!"), - ("println", "println!"), - ("eprintln", "eprintln!"), - ("logd", "log::debug!"), - ("logt", "log::trace!"), - ("logi", "log::info!"), - ("logw", "log::warn!"), - ("loge", "log::error!"), -]; - -pub(crate) fn add_format_like_completions( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - dot_receiver: &ast::Expr, - cap: SnippetCap, - receiver_text: &ast::String, -) { - let input = match string_literal_contents(receiver_text) { - // It's not a string literal, do not parse input. - Some(input) => input, - None => return, - }; - - let postfix_snippet = match build_postfix_snippet_builder(ctx, cap, dot_receiver) { - Some(it) => it, - None => return, - }; - let mut parser = FormatStrParser::new(input); - - if parser.parse().is_ok() { - for (label, macro_name) in KINDS { - let snippet = parser.to_suggestion(macro_name); - - postfix_snippet(label, macro_name, &snippet).add_to(acc); - } - } -} - -/// Checks whether provided item is a string literal. -fn string_literal_contents(item: &ast::String) -> Option { - let item = item.text(); - if item.len() >= 2 && item.starts_with('\"') && item.ends_with('\"') { - return Some(item[1..item.len() - 1].to_owned()); - } - - None -} - -/// Parser for a format-like string. It is more allowing in terms of string contents, -/// as we expect variable placeholders to be filled with expressions. -#[derive(Debug)] -pub(crate) struct FormatStrParser { - input: String, - output: String, - extracted_expressions: Vec, - state: State, - parsed: bool, -} - -#[derive(Debug, Clone, Copy, PartialEq)] -enum State { - NotExpr, - MaybeExpr, - Expr, - MaybeIncorrect, - FormatOpts, -} - -impl FormatStrParser { - pub(crate) fn new(input: String) -> Self { - Self { - input, - output: String::new(), - extracted_expressions: Vec::new(), - state: State::NotExpr, - parsed: false, - } - } - - pub(crate) fn parse(&mut self) -> Result<(), ()> { - let mut current_expr = String::new(); - - let mut placeholder_id = 1; - - // Count of open braces inside of an expression. - // We assume that user knows what they're doing, thus we treat it like a correct pattern, e.g. - // "{MyStruct { val_a: 0, val_b: 1 }}". - let mut inexpr_open_count = 0; - - // We need to escape '\' and '$'. See the comments on `get_receiver_text()` for detail. - let mut chars = self.input.chars().peekable(); - while let Some(chr) = chars.next() { - match (self.state, chr) { - (State::NotExpr, '{') => { - self.output.push(chr); - self.state = State::MaybeExpr; - } - (State::NotExpr, '}') => { - self.output.push(chr); - self.state = State::MaybeIncorrect; - } - (State::NotExpr, _) => { - if matches!(chr, '\\' | '$') { - self.output.push('\\'); - } - self.output.push(chr); - } - (State::MaybeIncorrect, '}') => { - // It's okay, we met "}}". - self.output.push(chr); - self.state = State::NotExpr; - } - (State::MaybeIncorrect, _) => { - // Error in the string. - return Err(()); - } - (State::MaybeExpr, '{') => { - self.output.push(chr); - self.state = State::NotExpr; - } - (State::MaybeExpr, '}') => { - // This is an empty sequence '{}'. Replace it with placeholder. - self.output.push(chr); - self.extracted_expressions.push(format!("${}", placeholder_id)); - placeholder_id += 1; - self.state = State::NotExpr; - } - (State::MaybeExpr, _) => { - if matches!(chr, '\\' | '$') { - current_expr.push('\\'); - } - current_expr.push(chr); - self.state = State::Expr; - } - (State::Expr, '}') => { - if inexpr_open_count == 0 { - self.output.push(chr); - self.extracted_expressions.push(current_expr.trim().into()); - current_expr = String::new(); - self.state = State::NotExpr; - } else { - // We're closing one brace met before inside of the expression. - current_expr.push(chr); - inexpr_open_count -= 1; - } - } - (State::Expr, ':') if chars.peek().copied() == Some(':') => { - // path seperator - current_expr.push_str("::"); - chars.next(); - } - (State::Expr, ':') => { - if inexpr_open_count == 0 { - // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}" - self.output.push(chr); - self.extracted_expressions.push(current_expr.trim().into()); - current_expr = String::new(); - self.state = State::FormatOpts; - } else { - // We're inside of braced expression, assume that it's a struct field name/value delimeter. - current_expr.push(chr); - } - } - (State::Expr, '{') => { - current_expr.push(chr); - inexpr_open_count += 1; - } - (State::Expr, _) => { - if matches!(chr, '\\' | '$') { - current_expr.push('\\'); - } - current_expr.push(chr); - } - (State::FormatOpts, '}') => { - self.output.push(chr); - self.state = State::NotExpr; - } - (State::FormatOpts, _) => { - if matches!(chr, '\\' | '$') { - self.output.push('\\'); - } - self.output.push(chr); - } - } - } - - if self.state != State::NotExpr { - return Err(()); - } - - self.parsed = true; - Ok(()) - } - - pub(crate) fn to_suggestion(&self, macro_name: &str) -> String { - assert!(self.parsed, "Attempt to get a suggestion from not parsed expression"); - - let expressions_as_string = self.extracted_expressions.join(", "); - format!(r#"{}("{}", {})"#, macro_name, self.output, expressions_as_string) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use expect_test::{expect, Expect}; - - fn check(input: &str, expect: &Expect) { - let mut parser = FormatStrParser::new((*input).to_owned()); - let outcome_repr = if parser.parse().is_ok() { - // Parsing should be OK, expected repr is "string; expr_1, expr_2". - if parser.extracted_expressions.is_empty() { - parser.output - } else { - format!("{}; {}", parser.output, parser.extracted_expressions.join(", ")) - } - } else { - // Parsing should fail, expected repr is "-". - "-".to_owned() - }; - - expect.assert_eq(&outcome_repr); - } - - #[test] - fn format_str_parser() { - let test_vector = &[ - ("no expressions", expect![["no expressions"]]), - (r"no expressions with \$0$1", expect![r"no expressions with \\\$0\$1"]), - ("{expr} is {2 + 2}", expect![["{} is {}; expr, 2 + 2"]]), - ("{expr:?}", expect![["{:?}; expr"]]), - ("{expr:1$}", expect![[r"{:1\$}; expr"]]), - ("{$0}", expect![[r"{}; \$0"]]), - ("{malformed", expect![["-"]]), - ("malformed}", expect![["-"]]), - ("{{correct", expect![["{{correct"]]), - ("correct}}", expect![["correct}}"]]), - ("{correct}}}", expect![["{}}}; correct"]]), - ("{correct}}}}}", expect![["{}}}}}; correct"]]), - ("{incorrect}}", expect![["-"]]), - ("placeholders {} {}", expect![["placeholders {} {}; $1, $2"]]), - ("mixed {} {2 + 2} {}", expect![["mixed {} {} {}; $1, 2 + 2, $2"]]), - ( - "{SomeStruct { val_a: 0, val_b: 1 }}", - expect![["{}; SomeStruct { val_a: 0, val_b: 1 }"]], - ), - ("{expr:?} is {2.32f64:.5}", expect![["{:?} is {:.5}; expr, 2.32f64"]]), - ( - "{SomeStruct { val_a: 0, val_b: 1 }:?}", - expect![["{:?}; SomeStruct { val_a: 0, val_b: 1 }"]], - ), - ("{ 2 + 2 }", expect![["{}; 2 + 2"]]), - ("{strsim::jaro_winkle(a)}", expect![["{}; strsim::jaro_winkle(a)"]]), - ("{foo::bar::baz()}", expect![["{}; foo::bar::baz()"]]), - ("{foo::bar():?}", expect![["{:?}; foo::bar()"]]), - ]; - - for (input, output) in test_vector { - check(input, output) - } - } - - #[test] - fn test_into_suggestion() { - let test_vector = &[ - ("println!", "{}", r#"println!("{}", $1)"#), - ("eprintln!", "{}", r#"eprintln!("{}", $1)"#), - ( - "log::info!", - "{} {expr} {} {2 + 2}", - r#"log::info!("{} {} {} {}", $1, expr, $2, 2 + 2)"#, - ), - ("format!", "{expr:?}", r#"format!("{:?}", expr)"#), - ]; - - for (kind, input, output) in test_vector { - let mut parser = FormatStrParser::new((*input).to_owned()); - parser.parse().expect("Parsing must succeed"); - - assert_eq!(&parser.to_suggestion(*kind), output); - } - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs deleted file mode 100644 index 1c9042390d3b2..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs +++ /dev/null @@ -1,369 +0,0 @@ -//! Complete fields in record literals and patterns. -use ide_db::SymbolKind; -use syntax::ast::{self, Expr}; - -use crate::{ - context::{DotAccess, DotAccessKind, ExprCtx, PathCompletionCtx, PatternContext, Qualified}, - CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance, - CompletionRelevancePostfixMatch, Completions, -}; - -pub(crate) fn complete_record_pattern_fields( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - pattern_ctx: &PatternContext, -) { - if let PatternContext { record_pat: Some(record_pat), .. } = pattern_ctx { - complete_fields(acc, ctx, ctx.sema.record_pattern_missing_fields(record_pat)); - } -} - -pub(crate) fn complete_record_expr_fields( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - record_expr: &ast::RecordExpr, - &dot_prefix: &bool, -) { - let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone())); - - let missing_fields = match ty.as_ref().and_then(|t| t.original.as_adt()) { - Some(hir::Adt::Union(un)) => { - // ctx.sema.record_literal_missing_fields will always return - // an empty Vec on a union literal. This is normally - // reasonable, but here we'd like to present the full list - // of fields if the literal is empty. - let were_fields_specified = - record_expr.record_expr_field_list().and_then(|fl| fl.fields().next()).is_some(); - - match were_fields_specified { - false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(), - true => return, - } - } - _ => { - let missing_fields = ctx.sema.record_literal_missing_fields(record_expr); - add_default_update(acc, ctx, ty, &missing_fields); - if dot_prefix { - let mut item = - CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), ".."); - item.insert_text("."); - item.add_to(acc); - return; - } - missing_fields - } - }; - complete_fields(acc, ctx, missing_fields); -} - -// FIXME: This should probably be part of complete_path_expr -pub(crate) fn complete_record_expr_func_update( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - expr_ctx: &ExprCtx, -) { - if !matches!(path_ctx.qualified, Qualified::No) { - return; - } - if let ExprCtx { is_func_update: Some(record_expr), .. } = expr_ctx { - let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone())); - - match ty.as_ref().and_then(|t| t.original.as_adt()) { - Some(hir::Adt::Union(_)) => (), - _ => { - let missing_fields = ctx.sema.record_literal_missing_fields(record_expr); - add_default_update(acc, ctx, ty, &missing_fields); - } - }; - } -} - -fn add_default_update( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - ty: Option, - missing_fields: &[(hir::Field, hir::Type)], -) { - let default_trait = ctx.famous_defs().core_default_Default(); - let impl_default_trait = default_trait - .zip(ty.as_ref()) - .map_or(false, |(default_trait, ty)| ty.original.impls_trait(ctx.db, default_trait, &[])); - if impl_default_trait && !missing_fields.is_empty() { - // FIXME: This should make use of scope_def like completions so we get all the other goodies - let completion_text = "..Default::default()"; - let mut item = CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text); - let completion_text = - completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text); - item.insert_text(completion_text).set_relevance(CompletionRelevance { - postfix_match: Some(CompletionRelevancePostfixMatch::Exact), - ..Default::default() - }); - item.add_to(acc); - } -} - -fn complete_fields( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - missing_fields: Vec<(hir::Field, hir::Type)>, -) { - for (field, ty) in missing_fields { - acc.add_field( - ctx, - &DotAccess { - receiver: None, - receiver_ty: None, - kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }, - }, - None, - field, - &ty, - ); - } -} - -#[cfg(test)] -mod tests { - use crate::tests::check_edit; - - #[test] - fn literal_struct_completion_edit() { - check_edit( - "FooDesc {…}", - r#" -struct FooDesc { pub bar: bool } - -fn create_foo(foo_desc: &FooDesc) -> () { () } - -fn baz() { - let foo = create_foo(&$0); -} - "#, - r#" -struct FooDesc { pub bar: bool } - -fn create_foo(foo_desc: &FooDesc) -> () { () } - -fn baz() { - let foo = create_foo(&FooDesc { bar: ${1:()} }$0); -} - "#, - ) - } - - #[test] - fn literal_struct_impl_self_completion() { - check_edit( - "Self {…}", - r#" -struct Foo { - bar: u64, -} - -impl Foo { - fn new() -> Foo { - Self$0 - } -} - "#, - r#" -struct Foo { - bar: u64, -} - -impl Foo { - fn new() -> Foo { - Self { bar: ${1:()} }$0 - } -} - "#, - ); - - check_edit( - "Self(…)", - r#" -mod submod { - pub struct Foo(pub u64); -} - -impl submod::Foo { - fn new() -> submod::Foo { - Self$0 - } -} - "#, - r#" -mod submod { - pub struct Foo(pub u64); -} - -impl submod::Foo { - fn new() -> submod::Foo { - Self(${1:()})$0 - } -} - "#, - ) - } - - #[test] - fn literal_struct_completion_from_sub_modules() { - check_edit( - "submod::Struct {…}", - r#" -mod submod { - pub struct Struct { - pub a: u64, - } -} - -fn f() -> submod::Struct { - Stru$0 -} - "#, - r#" -mod submod { - pub struct Struct { - pub a: u64, - } -} - -fn f() -> submod::Struct { - submod::Struct { a: ${1:()} }$0 -} - "#, - ) - } - - #[test] - fn literal_struct_complexion_module() { - check_edit( - "FooDesc {…}", - r#" -mod _69latrick { - pub struct FooDesc { pub six: bool, pub neuf: Vec, pub bar: bool } - pub fn create_foo(foo_desc: &FooDesc) -> () { () } -} - -fn baz() { - use _69latrick::*; - - let foo = create_foo(&$0); -} - "#, - r#" -mod _69latrick { - pub struct FooDesc { pub six: bool, pub neuf: Vec, pub bar: bool } - pub fn create_foo(foo_desc: &FooDesc) -> () { () } -} - -fn baz() { - use _69latrick::*; - - let foo = create_foo(&FooDesc { six: ${1:()}, neuf: ${2:()}, bar: ${3:()} }$0); -} - "#, - ); - } - - #[test] - fn default_completion_edit() { - check_edit( - "..Default::default()", - r#" -//- minicore: default -struct Struct { foo: u32, bar: usize } - -impl Default for Struct { - fn default() -> Self {} -} - -fn foo() { - let other = Struct { - foo: 5, - .$0 - }; -} -"#, - r#" -struct Struct { foo: u32, bar: usize } - -impl Default for Struct { - fn default() -> Self {} -} - -fn foo() { - let other = Struct { - foo: 5, - ..Default::default() - }; -} -"#, - ); - check_edit( - "..Default::default()", - r#" -//- minicore: default -struct Struct { foo: u32, bar: usize } - -impl Default for Struct { - fn default() -> Self {} -} - -fn foo() { - let other = Struct { - foo: 5, - $0 - }; -} -"#, - r#" -struct Struct { foo: u32, bar: usize } - -impl Default for Struct { - fn default() -> Self {} -} - -fn foo() { - let other = Struct { - foo: 5, - ..Default::default() - }; -} -"#, - ); - check_edit( - "..Default::default()", - r#" -//- minicore: default -struct Struct { foo: u32, bar: usize } - -impl Default for Struct { - fn default() -> Self {} -} - -fn foo() { - let other = Struct { - foo: 5, - ..$0 - }; -} -"#, - r#" -struct Struct { foo: u32, bar: usize } - -impl Default for Struct { - fn default() -> Self {} -} - -fn foo() { - let other = Struct { - foo: 5, - ..Default::default() - }; -} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs deleted file mode 100644 index 66adb4286373a..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs +++ /dev/null @@ -1,189 +0,0 @@ -//! This file provides snippet completions, like `pd` => `eprintln!(...)`. - -use hir::Documentation; -use ide_db::{imports::insert_use::ImportScope, SnippetCap}; - -use crate::{ - context::{ExprCtx, ItemListKind, PathCompletionCtx, Qualified}, - item::Builder, - CompletionContext, CompletionItem, CompletionItemKind, Completions, SnippetScope, -}; - -pub(crate) fn complete_expr_snippet( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - &ExprCtx { in_block_expr, .. }: &ExprCtx, -) { - if !matches!(path_ctx.qualified, Qualified::No) { - return; - } - if !ctx.qualifier_ctx.none() { - return; - } - - let cap = match ctx.config.snippet_cap { - Some(it) => it, - None => return, - }; - - if !ctx.config.snippets.is_empty() { - add_custom_completions(acc, ctx, cap, SnippetScope::Expr); - } - - if in_block_expr { - snippet(ctx, cap, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc); - snippet(ctx, cap, "ppd", "eprintln!(\"$0 = {:#?}\", $0);").add_to(acc); - let item = snippet( - ctx, - cap, - "macro_rules", - "\ -macro_rules! $1 { - ($2) => { - $0 - }; -}", - ); - item.add_to(acc); - } -} - -pub(crate) fn complete_item_snippet( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - kind: &ItemListKind, -) { - if !matches!(path_ctx.qualified, Qualified::No) { - return; - } - if !ctx.qualifier_ctx.none() { - return; - } - let cap = match ctx.config.snippet_cap { - Some(it) => it, - None => return, - }; - - if !ctx.config.snippets.is_empty() { - add_custom_completions(acc, ctx, cap, SnippetScope::Item); - } - - // Test-related snippets shouldn't be shown in blocks. - if let ItemListKind::SourceFile | ItemListKind::Module = kind { - let mut item = snippet( - ctx, - cap, - "tmod (Test module)", - "\ -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn ${1:test_name}() { - $0 - } -}", - ); - item.lookup_by("tmod"); - item.add_to(acc); - - let mut item = snippet( - ctx, - cap, - "tfn (Test function)", - "\ -#[test] -fn ${1:feature}() { - $0 -}", - ); - item.lookup_by("tfn"); - item.add_to(acc); - - let item = snippet( - ctx, - cap, - "macro_rules", - "\ -macro_rules! $1 { - ($2) => { - $0 - }; -}", - ); - item.add_to(acc); - } -} - -fn snippet(ctx: &CompletionContext<'_>, cap: SnippetCap, label: &str, snippet: &str) -> Builder { - let mut item = CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label); - item.insert_snippet(cap, snippet); - item -} - -fn add_custom_completions( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - cap: SnippetCap, - scope: SnippetScope, -) -> Option<()> { - if ImportScope::find_insert_use_container(&ctx.token.parent()?, &ctx.sema).is_none() { - return None; - } - ctx.config.prefix_snippets().filter(|(_, snip)| snip.scope == scope).for_each( - |(trigger, snip)| { - let imports = match snip.imports(ctx) { - Some(imports) => imports, - None => return, - }; - let body = snip.snippet(); - let mut builder = snippet(ctx, cap, trigger, &body); - builder.documentation(Documentation::new(format!("```rust\n{}\n```", body))); - for import in imports.into_iter() { - builder.add_import(import); - } - builder.set_detail(snip.description.clone()); - builder.add_to(acc); - }, - ); - None -} - -#[cfg(test)] -mod tests { - use crate::{ - tests::{check_edit_with_config, TEST_CONFIG}, - CompletionConfig, Snippet, - }; - - #[test] - fn custom_snippet_completion() { - check_edit_with_config( - CompletionConfig { - snippets: vec![Snippet::new( - &["break".into()], - &[], - &["ControlFlow::Break(())".into()], - "", - &["core::ops::ControlFlow".into()], - crate::SnippetScope::Expr, - ) - .unwrap()], - ..TEST_CONFIG - }, - "break", - r#" -//- minicore: try -fn main() { $0 } -"#, - r#" -use core::ops::ControlFlow; - -fn main() { ControlFlow::Break(()) } -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs deleted file mode 100644 index 87a998dfcce6b..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs +++ /dev/null @@ -1,230 +0,0 @@ -//! Completion of names from the current scope in type position. - -use hir::{HirDisplay, ScopeDef}; -use syntax::{ast, AstNode, SyntaxKind}; - -use crate::{ - context::{PathCompletionCtx, Qualified, TypeAscriptionTarget, TypeLocation}, - render::render_type_inference, - CompletionContext, Completions, -}; - -pub(crate) fn complete_type_path( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, - location: &TypeLocation, -) { - let _p = profile::span("complete_type_path"); - - let scope_def_applicable = |def| { - use hir::{GenericParam::*, ModuleDef::*}; - match def { - ScopeDef::GenericParam(LifetimeParam(_)) | ScopeDef::Label(_) => false, - // no values in type places - ScopeDef::ModuleDef(Function(_) | Variant(_) | Static(_)) | ScopeDef::Local(_) => false, - // unless its a constant in a generic arg list position - ScopeDef::ModuleDef(Const(_)) | ScopeDef::GenericParam(ConstParam(_)) => { - matches!(location, TypeLocation::GenericArgList(_)) - } - ScopeDef::ImplSelfType(_) => { - !matches!(location, TypeLocation::ImplTarget | TypeLocation::ImplTrait) - } - // Don't suggest attribute macros and derives. - ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db), - // Type things are fine - ScopeDef::ModuleDef(BuiltinType(_) | Adt(_) | Module(_) | Trait(_) | TypeAlias(_)) - | ScopeDef::AdtSelfType(_) - | ScopeDef::Unknown - | ScopeDef::GenericParam(TypeParam(_)) => true, - } - }; - - let add_assoc_item = |acc: &mut Completions, item| match item { - hir::AssocItem::Const(ct) if matches!(location, TypeLocation::GenericArgList(_)) => { - acc.add_const(ctx, ct) - } - hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => (), - hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), - }; - - match qualified { - Qualified::Infer => ctx - .traits_in_scope() - .iter() - .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db)) - .for_each(|item| add_assoc_item(acc, item)), - Qualified::With { resolution: None, .. } => {} - Qualified::With { resolution: Some(resolution), .. } => { - // Add associated types on type parameters and `Self`. - ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| { - acc.add_type_alias(ctx, alias); - None::<()> - }); - - match resolution { - hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { - let module_scope = module.scope(ctx.db, Some(ctx.module)); - for (name, def) in module_scope { - if scope_def_applicable(def) { - acc.add_path_resolution(ctx, path_ctx, name, def); - } - } - } - hir::PathResolution::Def( - def @ (hir::ModuleDef::Adt(_) - | hir::ModuleDef::TypeAlias(_) - | hir::ModuleDef::BuiltinType(_)), - ) => { - let ty = match def { - hir::ModuleDef::Adt(adt) => adt.ty(ctx.db), - hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db), - hir::ModuleDef::BuiltinType(builtin) => builtin.ty(ctx.db), - _ => return, - }; - - // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType. - // (where AssocType is defined on a trait, not an inherent impl) - - ctx.iterate_path_candidates(&ty, |item| { - add_assoc_item(acc, item); - }); - - // Iterate assoc types separately - ty.iterate_assoc_items(ctx.db, ctx.krate, |item| { - if let hir::AssocItem::TypeAlias(ty) = item { - acc.add_type_alias(ctx, ty) - } - None::<()> - }); - } - hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => { - // Handles `Trait::assoc` as well as `::assoc`. - for item in t.items(ctx.db) { - add_assoc_item(acc, item); - } - } - hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => { - let ty = match resolution { - hir::PathResolution::TypeParam(param) => param.ty(ctx.db), - hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db), - _ => return, - }; - - ctx.iterate_path_candidates(&ty, |item| { - add_assoc_item(acc, item); - }); - } - _ => (), - } - } - Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx), - Qualified::No => { - match location { - TypeLocation::TypeBound => { - acc.add_nameref_keywords_with_colon(ctx); - ctx.process_all_names(&mut |name, res| { - let add_resolution = match res { - ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => { - mac.is_fn_like(ctx.db) - } - ScopeDef::ModuleDef( - hir::ModuleDef::Trait(_) | hir::ModuleDef::Module(_), - ) => true, - _ => false, - }; - if add_resolution { - acc.add_path_resolution(ctx, path_ctx, name, res); - } - }); - return; - } - TypeLocation::GenericArgList(Some(arg_list)) => { - let in_assoc_type_arg = ctx - .original_token - .parent_ancestors() - .any(|node| node.kind() == SyntaxKind::ASSOC_TYPE_ARG); - - if !in_assoc_type_arg { - if let Some(path_seg) = - arg_list.syntax().parent().and_then(ast::PathSegment::cast) - { - if path_seg - .syntax() - .ancestors() - .find_map(ast::TypeBound::cast) - .is_some() - { - if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait( - trait_, - ))) = ctx.sema.resolve_path(&path_seg.parent_path()) - { - let arg_idx = arg_list - .generic_args() - .filter(|arg| { - arg.syntax().text_range().end() - < ctx.original_token.text_range().start() - }) - .count(); - - let n_required_params = - trait_.type_or_const_param_count(ctx.sema.db, true); - if arg_idx >= n_required_params { - trait_ - .items_with_supertraits(ctx.sema.db) - .into_iter() - .for_each(|it| { - if let hir::AssocItem::TypeAlias(alias) = it { - cov_mark::hit!( - complete_assoc_type_in_generics_list - ); - acc.add_type_alias_with_eq(ctx, alias); - } - }); - - let n_params = - trait_.type_or_const_param_count(ctx.sema.db, false); - if arg_idx >= n_params { - return; // only show assoc types - } - } - } - } - } - } - } - _ => {} - }; - - acc.add_nameref_keywords_with_colon(ctx); - ctx.process_all_names(&mut |name, def| { - if scope_def_applicable(def) { - acc.add_path_resolution(ctx, path_ctx, name, def); - } - }); - } - } -} - -pub(crate) fn complete_ascribed_type( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - ascription: &TypeAscriptionTarget, -) -> Option<()> { - if !path_ctx.is_trivial_path() { - return None; - } - let x = match ascription { - TypeAscriptionTarget::Let(pat) | TypeAscriptionTarget::FnParam(pat) => { - ctx.sema.type_of_pat(pat.as_ref()?) - } - TypeAscriptionTarget::Const(exp) | TypeAscriptionTarget::RetType(exp) => { - ctx.sema.type_of_expr(exp.as_ref()?) - } - }? - .adjusted(); - let ty_string = x.display_source_code(ctx.db, ctx.module.into()).ok()?; - acc.add(render_type_inference(ty_string, ctx)); - None -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs deleted file mode 100644 index bb2ecc9fdde76..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs +++ /dev/null @@ -1,120 +0,0 @@ -//! Completion for use trees - -use hir::ScopeDef; -use ide_db::{FxHashSet, SymbolKind}; -use syntax::{ast, AstNode}; - -use crate::{ - context::{CompletionContext, PathCompletionCtx, Qualified}, - item::Builder, - CompletionItem, CompletionItemKind, CompletionRelevance, Completions, -}; - -pub(crate) fn complete_use_path( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { qualified, use_tree_parent, .. }: &PathCompletionCtx, - name_ref: &Option, -) { - match qualified { - Qualified::With { path, resolution: Some(resolution), super_chain_len } => { - acc.add_super_keyword(ctx, *super_chain_len); - - // only show `self` in a new use-tree when the qualifier doesn't end in self - let not_preceded_by_self = *use_tree_parent - && !matches!( - path.segment().and_then(|it| it.kind()), - Some(ast::PathSegmentKind::SelfKw) - ); - if not_preceded_by_self { - acc.add_keyword(ctx, "self"); - } - - let mut already_imported_names = FxHashSet::default(); - if let Some(list) = ctx.token.parent_ancestors().find_map(ast::UseTreeList::cast) { - let use_tree = list.parent_use_tree(); - if use_tree.path().as_ref() == Some(path) { - for tree in list.use_trees().filter(|tree| tree.is_simple_path()) { - if let Some(name) = tree.path().and_then(|path| path.as_single_name_ref()) { - already_imported_names.insert(name.to_string()); - } - } - } - } - - match resolution { - hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { - let module_scope = module.scope(ctx.db, Some(ctx.module)); - let unknown_is_current = |name: &hir::Name| { - matches!( - name_ref, - Some(name_ref) if name_ref.syntax().text() == name.to_smol_str().as_str() - ) - }; - for (name, def) in module_scope { - let is_name_already_imported = name - .as_text() - .map_or(false, |text| already_imported_names.contains(text.as_str())); - - let add_resolution = match def { - ScopeDef::Unknown if unknown_is_current(&name) => { - // for `use self::foo$0`, don't suggest `foo` as a completion - cov_mark::hit!(dont_complete_current_use); - continue; - } - ScopeDef::ModuleDef(_) | ScopeDef::Unknown => true, - _ => false, - }; - - if add_resolution { - let mut builder = Builder::from_resolution(ctx, path_ctx, name, def); - builder.set_relevance(CompletionRelevance { - is_name_already_imported, - ..Default::default() - }); - acc.add(builder.build()); - } - } - } - hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => { - cov_mark::hit!(enum_plain_qualified_use_tree); - acc.add_enum_variants(ctx, path_ctx, *e); - } - _ => {} - } - } - // fresh use tree with leading colon2, only show crate roots - Qualified::Absolute => { - cov_mark::hit!(use_tree_crate_roots_only); - acc.add_crate_roots(ctx, path_ctx); - } - // only show modules and non-std enum in a fresh UseTree - Qualified::No => { - cov_mark::hit!(unqualified_path_selected_only); - ctx.process_all_names(&mut |name, res| { - match res { - ScopeDef::ModuleDef(hir::ModuleDef::Module(module)) => { - acc.add_module(ctx, path_ctx, module, name); - } - ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => { - // exclude prelude enum - let is_builtin = - res.krate(ctx.db).map_or(false, |krate| krate.is_builtin(ctx.db)); - - if !is_builtin { - let item = CompletionItem::new( - CompletionItemKind::SymbolKind(SymbolKind::Enum), - ctx.source_range(), - format!("{}::", e.name(ctx.db)), - ); - acc.add(item.build()); - } - } - _ => {} - }; - }); - acc.add_nameref_keywords_with_colon(ctx); - } - Qualified::Infer | Qualified::With { resolution: None, .. } => {} - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs deleted file mode 100644 index ca8303906a800..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs +++ /dev/null @@ -1,41 +0,0 @@ -//! Completion for visibility specifiers. - -use crate::{ - context::{CompletionContext, PathCompletionCtx, Qualified}, - Completions, -}; - -pub(crate) fn complete_vis_path( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, - &has_in_token: &bool, -) { - match qualified { - Qualified::With { - resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))), - super_chain_len, - .. - } => { - // Try completing next child module of the path that is still a parent of the current module - let next_towards_current = - ctx.module.path_to_root(ctx.db).into_iter().take_while(|it| it != module).last(); - if let Some(next) = next_towards_current { - if let Some(name) = next.name(ctx.db) { - cov_mark::hit!(visibility_qualified); - acc.add_module(ctx, path_ctx, next, name); - } - } - - acc.add_super_keyword(ctx, *super_chain_len); - } - Qualified::Absolute | Qualified::Infer | Qualified::With { .. } => {} - Qualified::No => { - if !has_in_token { - cov_mark::hit!(kw_completion_in); - acc.add_keyword(ctx, "in"); - } - acc.add_nameref_keywords(ctx); - } - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs deleted file mode 100644 index 80d6af28168f5..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs +++ /dev/null @@ -1,41 +0,0 @@ -//! Settings for tweaking completion. -//! -//! The fun thing here is `SnippetCap` -- this type can only be created in this -//! module, and we use to statically check that we only produce snippet -//! completions if we are allowed to. - -use ide_db::{imports::insert_use::InsertUseConfig, SnippetCap}; - -use crate::snippet::Snippet; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CompletionConfig { - pub enable_postfix_completions: bool, - pub enable_imports_on_the_fly: bool, - pub enable_self_on_the_fly: bool, - pub enable_private_editable: bool, - pub callable: Option, - pub snippet_cap: Option, - pub insert_use: InsertUseConfig, - pub snippets: Vec, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum CallableSnippets { - FillArguments, - AddParentheses, -} - -impl CompletionConfig { - pub fn postfix_snippets(&self) -> impl Iterator { - self.snippets - .iter() - .flat_map(|snip| snip.postfix_triggers.iter().map(move |trigger| (&**trigger, snip))) - } - - pub fn prefix_snippets(&self) -> impl Iterator { - self.snippets - .iter() - .flat_map(|snip| snip.prefix_triggers.iter().map(move |trigger| (&**trigger, snip))) - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs deleted file mode 100644 index 93b6ad5d145df..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ /dev/null @@ -1,636 +0,0 @@ -//! See `CompletionContext` structure. - -mod analysis; -#[cfg(test)] -mod tests; - -use std::iter; - -use base_db::SourceDatabaseExt; -use hir::{ - HasAttrs, Local, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, Type, TypeInfo, -}; -use ide_db::{ - base_db::{FilePosition, SourceDatabase}, - famous_defs::FamousDefs, - FxHashMap, FxHashSet, RootDatabase, -}; -use syntax::{ - ast::{self, AttrKind, NameOrNameRef}, - AstNode, - SyntaxKind::{self, *}, - SyntaxToken, TextRange, TextSize, -}; -use text_edit::Indel; - -use crate::CompletionConfig; - -const COMPLETION_MARKER: &str = "intellijRulezz"; - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub(crate) enum PatternRefutability { - Refutable, - Irrefutable, -} - -#[derive(Debug)] -pub(crate) enum Visible { - Yes, - Editable, - No, -} - -/// Existing qualifiers for the thing we are currently completing. -#[derive(Debug, Default)] -pub(super) struct QualifierCtx { - pub(super) unsafe_tok: Option, - pub(super) vis_node: Option, -} - -impl QualifierCtx { - pub(super) fn none(&self) -> bool { - self.unsafe_tok.is_none() && self.vis_node.is_none() - } -} - -/// The state of the path we are currently completing. -#[derive(Debug)] -pub(crate) struct PathCompletionCtx { - /// If this is a call with () already there (or {} in case of record patterns) - pub(super) has_call_parens: bool, - /// If this has a macro call bang ! - pub(super) has_macro_bang: bool, - /// The qualifier of the current path. - pub(super) qualified: Qualified, - /// The parent of the path we are completing. - pub(super) parent: Option, - /// The path of which we are completing the segment - pub(super) path: ast::Path, - pub(super) kind: PathKind, - /// Whether the path segment has type args or not. - pub(super) has_type_args: bool, - /// Whether the qualifier comes from a use tree parent or not - pub(crate) use_tree_parent: bool, -} - -impl PathCompletionCtx { - pub(super) fn is_trivial_path(&self) -> bool { - matches!( - self, - PathCompletionCtx { - has_call_parens: false, - has_macro_bang: false, - qualified: Qualified::No, - parent: None, - has_type_args: false, - .. - } - ) - } -} - -/// The kind of path we are completing right now. -#[derive(Debug, PartialEq, Eq)] -pub(super) enum PathKind { - Expr { - expr_ctx: ExprCtx, - }, - Type { - location: TypeLocation, - }, - Attr { - attr_ctx: AttrCtx, - }, - Derive { - existing_derives: ExistingDerives, - }, - /// Path in item position, that is inside an (Assoc)ItemList - Item { - kind: ItemListKind, - }, - Pat { - pat_ctx: PatternContext, - }, - Vis { - has_in_token: bool, - }, - Use, -} - -pub(crate) type ExistingDerives = FxHashSet; - -#[derive(Debug, PartialEq, Eq)] -pub(crate) struct AttrCtx { - pub(crate) kind: AttrKind, - pub(crate) annotated_item_kind: Option, -} - -#[derive(Debug, PartialEq, Eq)] -pub(crate) struct ExprCtx { - pub(crate) in_block_expr: bool, - pub(crate) in_loop_body: bool, - pub(crate) after_if_expr: bool, - /// Whether this expression is the direct condition of an if or while expression - pub(crate) in_condition: bool, - pub(crate) incomplete_let: bool, - pub(crate) ref_expr_parent: Option, - pub(crate) is_func_update: Option, - pub(crate) self_param: Option, - pub(crate) innermost_ret_ty: Option, - pub(crate) impl_: Option, - /// Whether this expression occurs in match arm guard position: before the - /// fat arrow token - pub(crate) in_match_guard: bool, -} - -/// Original file ast nodes -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) enum TypeLocation { - TupleField, - TypeAscription(TypeAscriptionTarget), - GenericArgList(Option), - TypeBound, - ImplTarget, - ImplTrait, - Other, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) enum TypeAscriptionTarget { - Let(Option), - FnParam(Option), - RetType(Option), - Const(Option), -} - -/// The kind of item list a [`PathKind::Item`] belongs to. -#[derive(Debug, PartialEq, Eq)] -pub(super) enum ItemListKind { - SourceFile, - Module, - Impl, - TraitImpl(Option), - Trait, - ExternBlock, -} - -#[derive(Debug)] -pub(super) enum Qualified { - No, - With { - path: ast::Path, - resolution: Option, - /// How many `super` segments are present in the path - /// - /// This would be None, if path is not solely made of - /// `super` segments, e.g. - /// - /// ```rust - /// use super::foo; - /// ``` - /// - /// Otherwise it should be Some(count of `super`) - super_chain_len: Option, - }, - /// <_>:: - Infer, - /// Whether the path is an absolute path - Absolute, -} - -/// The state of the pattern we are completing. -#[derive(Debug, Clone, PartialEq, Eq)] -pub(super) struct PatternContext { - pub(super) refutability: PatternRefutability, - pub(super) param_ctx: Option, - pub(super) has_type_ascription: bool, - pub(super) parent_pat: Option, - pub(super) ref_token: Option, - pub(super) mut_token: Option, - /// The record pattern this name or ref is a field of - pub(super) record_pat: Option, - pub(super) impl_: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub(super) struct ParamContext { - pub(super) param_list: ast::ParamList, - pub(super) param: ast::Param, - pub(super) kind: ParamKind, -} - -/// The state of the lifetime we are completing. -#[derive(Debug)] -pub(super) struct LifetimeContext { - pub(super) lifetime: Option, - pub(super) kind: LifetimeKind, -} - -/// The kind of lifetime we are completing. -#[derive(Debug)] -pub(super) enum LifetimeKind { - LifetimeParam { is_decl: bool, param: ast::LifetimeParam }, - Lifetime, - LabelRef, - LabelDef, -} - -/// The state of the name we are completing. -#[derive(Debug)] -pub(super) struct NameContext { - #[allow(dead_code)] - pub(super) name: Option, - pub(super) kind: NameKind, -} - -/// The kind of the name we are completing. -#[derive(Debug)] -#[allow(dead_code)] -pub(super) enum NameKind { - Const, - ConstParam, - Enum, - Function, - IdentPat(PatternContext), - MacroDef, - MacroRules, - /// Fake node - Module(ast::Module), - RecordField, - Rename, - SelfParam, - Static, - Struct, - Trait, - TypeAlias, - TypeParam, - Union, - Variant, -} - -/// The state of the NameRef we are completing. -#[derive(Debug)] -pub(super) struct NameRefContext { - /// NameRef syntax in the original file - pub(super) nameref: Option, - pub(super) kind: NameRefKind, -} - -/// The kind of the NameRef we are completing. -#[derive(Debug)] -pub(super) enum NameRefKind { - Path(PathCompletionCtx), - DotAccess(DotAccess), - /// Position where we are only interested in keyword completions - Keyword(ast::Item), - /// The record expression this nameref is a field of and whether a dot precedes the completion identifier. - RecordExpr { - dot_prefix: bool, - expr: ast::RecordExpr, - }, - Pattern(PatternContext), -} - -/// The identifier we are currently completing. -#[derive(Debug)] -pub(super) enum CompletionAnalysis { - Name(NameContext), - NameRef(NameRefContext), - Lifetime(LifetimeContext), - /// The string the cursor is currently inside - String { - /// original token - original: ast::String, - /// fake token - expanded: Option, - }, - /// Set if we are currently completing in an unexpanded attribute, this usually implies a builtin attribute like `allow($0)` - UnexpandedAttrTT { - colon_prefix: bool, - fake_attribute_under_caret: Option, - }, -} - -/// Information about the field or method access we are completing. -#[derive(Debug)] -pub(super) struct DotAccess { - pub(super) receiver: Option, - pub(super) receiver_ty: Option, - pub(super) kind: DotAccessKind, -} - -#[derive(Debug)] -pub(super) enum DotAccessKind { - Field { - /// True if the receiver is an integer and there is no ident in the original file after it yet - /// like `0.$0` - receiver_is_ambiguous_float_literal: bool, - }, - Method { - has_parens: bool, - }, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) enum ParamKind { - Function(ast::Fn), - Closure(ast::ClosureExpr), -} - -/// `CompletionContext` is created early during completion to figure out, where -/// exactly is the cursor, syntax-wise. -#[derive(Debug)] -pub(crate) struct CompletionContext<'a> { - pub(super) sema: Semantics<'a, RootDatabase>, - pub(super) scope: SemanticsScope<'a>, - pub(super) db: &'a RootDatabase, - pub(super) config: &'a CompletionConfig, - pub(super) position: FilePosition, - - /// The token before the cursor, in the original file. - pub(super) original_token: SyntaxToken, - /// The token before the cursor, in the macro-expanded file. - pub(super) token: SyntaxToken, - /// The crate of the current file. - pub(super) krate: hir::Crate, - /// The module of the `scope`. - pub(super) module: hir::Module, - - /// The expected name of what we are completing. - /// This is usually the parameter name of the function argument we are completing. - pub(super) expected_name: Option, - /// The expected type of what we are completing. - pub(super) expected_type: Option, - - pub(super) qualifier_ctx: QualifierCtx, - - pub(super) locals: FxHashMap, - - /// The module depth of the current module of the cursor position. - /// - crate-root - /// - mod foo - /// - mod bar - /// Here depth will be 2 - pub(super) depth_from_crate_root: usize, -} - -impl<'a> CompletionContext<'a> { - /// The range of the identifier that is being completed. - pub(crate) fn source_range(&self) -> TextRange { - // check kind of macro-expanded token, but use range of original token - let kind = self.token.kind(); - match kind { - CHAR => { - // assume we are completing a lifetime but the user has only typed the ' - cov_mark::hit!(completes_if_lifetime_without_idents); - TextRange::at(self.original_token.text_range().start(), TextSize::from(1)) - } - IDENT | LIFETIME_IDENT | UNDERSCORE => self.original_token.text_range(), - _ if kind.is_keyword() => self.original_token.text_range(), - _ => TextRange::empty(self.position.offset), - } - } - - pub(crate) fn famous_defs(&self) -> FamousDefs<'_, '_> { - FamousDefs(&self.sema, self.krate) - } - - /// Checks if an item is visible and not `doc(hidden)` at the completion site. - pub(crate) fn def_is_visible(&self, item: &ScopeDef) -> Visible { - match item { - ScopeDef::ModuleDef(def) => match def { - hir::ModuleDef::Module(it) => self.is_visible(it), - hir::ModuleDef::Function(it) => self.is_visible(it), - hir::ModuleDef::Adt(it) => self.is_visible(it), - hir::ModuleDef::Variant(it) => self.is_visible(it), - hir::ModuleDef::Const(it) => self.is_visible(it), - hir::ModuleDef::Static(it) => self.is_visible(it), - hir::ModuleDef::Trait(it) => self.is_visible(it), - hir::ModuleDef::TypeAlias(it) => self.is_visible(it), - hir::ModuleDef::Macro(it) => self.is_visible(it), - hir::ModuleDef::BuiltinType(_) => Visible::Yes, - }, - ScopeDef::GenericParam(_) - | ScopeDef::ImplSelfType(_) - | ScopeDef::AdtSelfType(_) - | ScopeDef::Local(_) - | ScopeDef::Label(_) - | ScopeDef::Unknown => Visible::Yes, - } - } - - /// Checks if an item is visible and not `doc(hidden)` at the completion site. - pub(crate) fn is_visible(&self, item: &I) -> Visible - where - I: hir::HasVisibility + hir::HasAttrs + hir::HasCrate + Copy, - { - let vis = item.visibility(self.db); - let attrs = item.attrs(self.db); - self.is_visible_impl(&vis, &attrs, item.krate(self.db)) - } - - /// Check if an item is `#[doc(hidden)]`. - pub(crate) fn is_item_hidden(&self, item: &hir::ItemInNs) -> bool { - let attrs = item.attrs(self.db); - let krate = item.krate(self.db); - match (attrs, krate) { - (Some(attrs), Some(krate)) => self.is_doc_hidden(&attrs, krate), - _ => false, - } - } - - /// Whether the given trait is an operator trait or not. - pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool { - match trait_.attrs(self.db).lang() { - Some(lang) => OP_TRAIT_LANG_NAMES.contains(&lang.as_str()), - None => false, - } - } - - /// Returns the traits in scope, with the [`Drop`] trait removed. - pub(crate) fn traits_in_scope(&self) -> hir::VisibleTraits { - let mut traits_in_scope = self.scope.visible_traits(); - if let Some(drop) = self.famous_defs().core_ops_Drop() { - traits_in_scope.0.remove(&drop.into()); - } - traits_in_scope - } - - pub(crate) fn iterate_path_candidates( - &self, - ty: &hir::Type, - mut cb: impl FnMut(hir::AssocItem), - ) { - let mut seen = FxHashSet::default(); - ty.iterate_path_candidates( - self.db, - &self.scope, - &self.traits_in_scope(), - Some(self.module), - None, - |item| { - // We might iterate candidates of a trait multiple times here, so deduplicate - // them. - if seen.insert(item) { - cb(item) - } - None::<()> - }, - ); - } - - /// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items. - pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) { - let _p = profile::span("CompletionContext::process_all_names"); - self.scope.process_all_names(&mut |name, def| { - if self.is_scope_def_hidden(def) { - return; - } - - f(name, def); - }); - } - - pub(crate) fn process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef)) { - let _p = profile::span("CompletionContext::process_all_names_raw"); - self.scope.process_all_names(&mut |name, def| f(name, def)); - } - - fn is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool { - if let (Some(attrs), Some(krate)) = (scope_def.attrs(self.db), scope_def.krate(self.db)) { - return self.is_doc_hidden(&attrs, krate); - } - - false - } - - fn is_visible_impl( - &self, - vis: &hir::Visibility, - attrs: &hir::Attrs, - defining_crate: hir::Crate, - ) -> Visible { - if !vis.is_visible_from(self.db, self.module.into()) { - if !self.config.enable_private_editable { - return Visible::No; - } - // If the definition location is editable, also show private items - let root_file = defining_crate.root_file(self.db); - let source_root_id = self.db.file_source_root(root_file); - let is_editable = !self.db.source_root(source_root_id).is_library; - return if is_editable { Visible::Editable } else { Visible::No }; - } - - if self.is_doc_hidden(attrs, defining_crate) { - Visible::No - } else { - Visible::Yes - } - } - - fn is_doc_hidden(&self, attrs: &hir::Attrs, defining_crate: hir::Crate) -> bool { - // `doc(hidden)` items are only completed within the defining crate. - self.krate != defining_crate && attrs.has_doc_hidden() - } -} - -// CompletionContext construction -impl<'a> CompletionContext<'a> { - pub(super) fn new( - db: &'a RootDatabase, - position @ FilePosition { file_id, offset }: FilePosition, - config: &'a CompletionConfig, - ) -> Option<(CompletionContext<'a>, CompletionAnalysis)> { - let _p = profile::span("CompletionContext::new"); - let sema = Semantics::new(db); - - let original_file = sema.parse(file_id); - - // Insert a fake ident to get a valid parse tree. We will use this file - // to determine context, though the original_file will be used for - // actual completion. - let file_with_fake_ident = { - let parse = db.parse(file_id); - let edit = Indel::insert(offset, COMPLETION_MARKER.to_string()); - parse.reparse(&edit).tree() - }; - let fake_ident_token = - file_with_fake_ident.syntax().token_at_offset(offset).right_biased()?; - - let original_token = original_file.syntax().token_at_offset(offset).left_biased()?; - let token = sema.descend_into_macros_single(original_token.clone()); - - // adjust for macro input, this still fails if there is no token written yet - let scope_offset = if original_token == token { offset } else { token.text_range().end() }; - let scope = sema.scope_at_offset(&token.parent()?, scope_offset)?; - - let krate = scope.krate(); - let module = scope.module(); - - let mut locals = FxHashMap::default(); - scope.process_all_names(&mut |name, scope| { - if let ScopeDef::Local(local) = scope { - locals.insert(name, local); - } - }); - - let depth_from_crate_root = iter::successors(module.parent(db), |m| m.parent(db)).count(); - - let mut ctx = CompletionContext { - sema, - scope, - db, - config, - position, - original_token, - token, - krate, - module, - expected_name: None, - expected_type: None, - qualifier_ctx: Default::default(), - locals, - depth_from_crate_root, - }; - let ident_ctx = ctx.expand_and_analyze( - original_file.syntax().clone(), - file_with_fake_ident.syntax().clone(), - offset, - fake_ident_token, - )?; - Some((ctx, ident_ctx)) - } -} - -const OP_TRAIT_LANG_NAMES: &[&str] = &[ - "add_assign", - "add", - "bitand_assign", - "bitand", - "bitor_assign", - "bitor", - "bitxor_assign", - "bitxor", - "deref_mut", - "deref", - "div_assign", - "div", - "eq", - "fn_mut", - "fn_once", - "fn", - "index_mut", - "index", - "mul_assign", - "mul", - "neg", - "not", - "partial_ord", - "rem_assign", - "rem", - "shl_assign", - "shl", - "shr_assign", - "shr", - "sub", -]; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs deleted file mode 100644 index c71ffa0ed86fd..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ /dev/null @@ -1,1233 +0,0 @@ -//! Module responsible for analyzing the code surrounding the cursor for completion. -use std::iter; - -use hir::{Semantics, Type, TypeInfo}; -use ide_db::{active_parameter::ActiveParameter, RootDatabase}; -use syntax::{ - algo::{find_node_at_offset, non_trivia_sibling}, - ast::{self, AttrKind, HasArgList, HasLoopBody, HasName, NameOrNameRef}, - match_ast, AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, - SyntaxToken, TextRange, TextSize, T, -}; - -use crate::context::{ - AttrCtx, CompletionAnalysis, CompletionContext, DotAccess, DotAccessKind, ExprCtx, - ItemListKind, LifetimeContext, LifetimeKind, NameContext, NameKind, NameRefContext, - NameRefKind, ParamContext, ParamKind, PathCompletionCtx, PathKind, PatternContext, - PatternRefutability, Qualified, QualifierCtx, TypeAscriptionTarget, TypeLocation, - COMPLETION_MARKER, -}; - -impl<'a> CompletionContext<'a> { - /// Expand attributes and macro calls at the current cursor position for both the original file - /// and fake file repeatedly. As soon as one of the two expansions fail we stop so the original - /// and speculative states stay in sync. - pub(super) fn expand_and_analyze( - &mut self, - mut original_file: SyntaxNode, - mut speculative_file: SyntaxNode, - mut offset: TextSize, - mut fake_ident_token: SyntaxToken, - ) -> Option { - let _p = profile::span("CompletionContext::expand_and_fill"); - let mut derive_ctx = None; - - 'expansion: loop { - let parent_item = - |item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast); - let ancestor_items = iter::successors( - Option::zip( - find_node_at_offset::(&original_file, offset), - find_node_at_offset::(&speculative_file, offset), - ), - |(a, b)| parent_item(a).zip(parent_item(b)), - ); - - // first try to expand attributes as these are always the outermost macro calls - 'ancestors: for (actual_item, item_with_fake_ident) in ancestor_items { - match ( - self.sema.expand_attr_macro(&actual_item), - self.sema.speculative_expand_attr_macro( - &actual_item, - &item_with_fake_ident, - fake_ident_token.clone(), - ), - ) { - // maybe parent items have attributes, so continue walking the ancestors - (None, None) => continue 'ancestors, - // successful expansions - (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => { - let new_offset = fake_mapped_token.text_range().start(); - if new_offset > actual_expansion.text_range().end() { - // offset outside of bounds from the original expansion, - // stop here to prevent problems from happening - break 'expansion; - } - original_file = actual_expansion; - speculative_file = fake_expansion; - fake_ident_token = fake_mapped_token; - offset = new_offset; - continue 'expansion; - } - // exactly one expansion failed, inconsistent state so stop expanding completely - _ => break 'expansion, - } - } - - // No attributes have been expanded, so look for macro_call! token trees or derive token trees - let orig_tt = match find_node_at_offset::(&original_file, offset) { - Some(it) => it, - None => break 'expansion, - }; - let spec_tt = match find_node_at_offset::(&speculative_file, offset) { - Some(it) => it, - None => break 'expansion, - }; - - // Expand pseudo-derive expansion - if let (Some(orig_attr), Some(spec_attr)) = ( - orig_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()), - spec_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()), - ) { - if let (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) = ( - self.sema.expand_derive_as_pseudo_attr_macro(&orig_attr), - self.sema.speculative_expand_derive_as_pseudo_attr_macro( - &orig_attr, - &spec_attr, - fake_ident_token.clone(), - ), - ) { - derive_ctx = Some(( - actual_expansion, - fake_expansion, - fake_mapped_token.text_range().start(), - orig_attr, - )); - } - // at this point we won't have any more successful expansions, so stop - break 'expansion; - } - - // Expand fn-like macro calls - if let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = ( - orig_tt.syntax().ancestors().find_map(ast::MacroCall::cast), - spec_tt.syntax().ancestors().find_map(ast::MacroCall::cast), - ) { - let mac_call_path0 = actual_macro_call.path().as_ref().map(|s| s.syntax().text()); - let mac_call_path1 = - macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text()); - - // inconsistent state, stop expanding - if mac_call_path0 != mac_call_path1 { - break 'expansion; - } - let speculative_args = match macro_call_with_fake_ident.token_tree() { - Some(tt) => tt, - None => break 'expansion, - }; - - match ( - self.sema.expand(&actual_macro_call), - self.sema.speculative_expand( - &actual_macro_call, - &speculative_args, - fake_ident_token.clone(), - ), - ) { - // successful expansions - (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => { - let new_offset = fake_mapped_token.text_range().start(); - if new_offset > actual_expansion.text_range().end() { - // offset outside of bounds from the original expansion, - // stop here to prevent problems from happening - break 'expansion; - } - original_file = actual_expansion; - speculative_file = fake_expansion; - fake_ident_token = fake_mapped_token; - offset = new_offset; - continue 'expansion; - } - // at least on expansion failed, we won't have anything to expand from this point - // onwards so break out - _ => break 'expansion, - } - } - - // none of our states have changed so stop the loop - break 'expansion; - } - - self.analyze(&original_file, speculative_file, offset, derive_ctx) - } - - /// Calculate the expected type and name of the cursor position. - fn expected_type_and_name(&self) -> (Option, Option) { - let mut node = match self.token.parent() { - Some(it) => it, - None => return (None, None), - }; - loop { - break match_ast! { - match node { - ast::LetStmt(it) => { - cov_mark::hit!(expected_type_let_with_leading_char); - cov_mark::hit!(expected_type_let_without_leading_char); - let ty = it.pat() - .and_then(|pat| self.sema.type_of_pat(&pat)) - .or_else(|| it.initializer().and_then(|it| self.sema.type_of_expr(&it))) - .map(TypeInfo::original); - let name = match it.pat() { - Some(ast::Pat::IdentPat(ident)) => ident.name().map(NameOrNameRef::Name), - Some(_) | None => None, - }; - - (ty, name) - }, - ast::LetExpr(it) => { - cov_mark::hit!(expected_type_if_let_without_leading_char); - let ty = it.pat() - .and_then(|pat| self.sema.type_of_pat(&pat)) - .or_else(|| it.expr().and_then(|it| self.sema.type_of_expr(&it))) - .map(TypeInfo::original); - (ty, None) - }, - ast::ArgList(_) => { - cov_mark::hit!(expected_type_fn_param); - ActiveParameter::at_token( - &self.sema, - self.token.clone(), - ).map(|ap| { - let name = ap.ident().map(NameOrNameRef::Name); - let ty = if has_ref(&self.token) { - cov_mark::hit!(expected_type_fn_param_ref); - ap.ty.remove_ref() - } else { - Some(ap.ty) - }; - (ty, name) - }) - .unwrap_or((None, None)) - }, - ast::RecordExprFieldList(it) => { - // wouldn't try {} be nice... - (|| { - if self.token.kind() == T![..] - || self.token.prev_token().map(|t| t.kind()) == Some(T![..]) - { - cov_mark::hit!(expected_type_struct_func_update); - let record_expr = it.syntax().parent().and_then(ast::RecordExpr::cast)?; - let ty = self.sema.type_of_expr(&record_expr.into())?; - Some(( - Some(ty.original), - None - )) - } else { - cov_mark::hit!(expected_type_struct_field_without_leading_char); - let expr_field = self.token.prev_sibling_or_token()? - .into_node() - .and_then(ast::RecordExprField::cast)?; - let (_, _, ty) = self.sema.resolve_record_field(&expr_field)?; - Some(( - Some(ty), - expr_field.field_name().map(NameOrNameRef::NameRef), - )) - } - })().unwrap_or((None, None)) - }, - ast::RecordExprField(it) => { - if let Some(expr) = it.expr() { - cov_mark::hit!(expected_type_struct_field_with_leading_char); - ( - self.sema.type_of_expr(&expr).map(TypeInfo::original), - it.field_name().map(NameOrNameRef::NameRef), - ) - } else { - cov_mark::hit!(expected_type_struct_field_followed_by_comma); - let ty = self.sema.resolve_record_field(&it) - .map(|(_, _, ty)| ty); - ( - ty, - it.field_name().map(NameOrNameRef::NameRef), - ) - } - }, - // match foo { $0 } - // match foo { ..., pat => $0 } - ast::MatchExpr(it) => { - let on_arrow = previous_non_trivia_token(self.token.clone()).map_or(false, |it| T![=>] == it.kind()); - - let ty = if on_arrow { - // match foo { ..., pat => $0 } - cov_mark::hit!(expected_type_match_arm_body_without_leading_char); - cov_mark::hit!(expected_type_match_arm_body_with_leading_char); - self.sema.type_of_expr(&it.into()) - } else { - // match foo { $0 } - cov_mark::hit!(expected_type_match_arm_without_leading_char); - it.expr().and_then(|e| self.sema.type_of_expr(&e)) - }.map(TypeInfo::original); - (ty, None) - }, - ast::IfExpr(it) => { - let ty = it.condition() - .and_then(|e| self.sema.type_of_expr(&e)) - .map(TypeInfo::original); - (ty, None) - }, - ast::IdentPat(it) => { - cov_mark::hit!(expected_type_if_let_with_leading_char); - cov_mark::hit!(expected_type_match_arm_with_leading_char); - let ty = self.sema.type_of_pat(&ast::Pat::from(it)).map(TypeInfo::original); - (ty, None) - }, - ast::Fn(it) => { - cov_mark::hit!(expected_type_fn_ret_with_leading_char); - cov_mark::hit!(expected_type_fn_ret_without_leading_char); - let def = self.sema.to_def(&it); - (def.map(|def| def.ret_type(self.db)), None) - }, - ast::ClosureExpr(it) => { - let ty = self.sema.type_of_expr(&it.into()); - ty.and_then(|ty| ty.original.as_callable(self.db)) - .map(|c| (Some(c.return_type()), None)) - .unwrap_or((None, None)) - }, - ast::ParamList(_) => (None, None), - ast::Stmt(_) => (None, None), - ast::Item(_) => (None, None), - _ => { - match node.parent() { - Some(n) => { - node = n; - continue; - }, - None => (None, None), - } - }, - } - }; - } - } - - /// Fill the completion context, this is what does semantic reasoning about the surrounding context - /// of the completion location. - fn analyze( - &mut self, - original_file: &SyntaxNode, - file_with_fake_ident: SyntaxNode, - offset: TextSize, - derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize, ast::Attr)>, - ) -> Option { - let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased()?; - let syntax_element = NodeOrToken::Token(fake_ident_token); - if is_in_token_of_for_loop(syntax_element.clone()) { - // for pat $0 - // there is nothing to complete here except `in` keyword - // don't bother populating the context - // FIXME: the completion calculations should end up good enough - // such that this special case becomes unnecessary - return None; - } - - (self.expected_type, self.expected_name) = self.expected_type_and_name(); - - // Overwrite the path kind for derives - if let Some((original_file, file_with_fake_ident, offset, origin_attr)) = derive_ctx { - if let Some(ast::NameLike::NameRef(name_ref)) = - find_node_at_offset(&file_with_fake_ident, offset) - { - let parent = name_ref.syntax().parent()?; - let (mut nameref_ctx, _) = - Self::classify_name_ref(&self.sema, &original_file, name_ref, parent)?; - if let NameRefKind::Path(path_ctx) = &mut nameref_ctx.kind { - path_ctx.kind = PathKind::Derive { - existing_derives: self - .sema - .resolve_derive_macro(&origin_attr) - .into_iter() - .flatten() - .flatten() - .collect(), - }; - } - return Some(CompletionAnalysis::NameRef(nameref_ctx)); - } - return None; - } - - let name_like = match find_node_at_offset(&file_with_fake_ident, offset) { - Some(it) => it, - None => { - let analysis = - if let Some(original) = ast::String::cast(self.original_token.clone()) { - CompletionAnalysis::String { - original, - expanded: ast::String::cast(self.token.clone()), - } - } else { - // Fix up trailing whitespace problem - // #[attr(foo = $0 - let token = - syntax::algo::skip_trivia_token(self.token.clone(), Direction::Prev)?; - let p = token.parent()?; - if p.kind() == SyntaxKind::TOKEN_TREE - && p.ancestors().any(|it| it.kind() == SyntaxKind::META) - { - let colon_prefix = previous_non_trivia_token(self.token.clone()) - .map_or(false, |it| T![:] == it.kind()); - CompletionAnalysis::UnexpandedAttrTT { - fake_attribute_under_caret: syntax_element - .ancestors() - .find_map(ast::Attr::cast), - colon_prefix, - } - } else { - return None; - } - }; - return Some(analysis); - } - }; - let analysis = match name_like { - ast::NameLike::Lifetime(lifetime) => CompletionAnalysis::Lifetime( - Self::classify_lifetime(&self.sema, original_file, lifetime)?, - ), - ast::NameLike::NameRef(name_ref) => { - let parent = name_ref.syntax().parent()?; - let (nameref_ctx, qualifier_ctx) = - Self::classify_name_ref(&self.sema, &original_file, name_ref, parent.clone())?; - - self.qualifier_ctx = qualifier_ctx; - CompletionAnalysis::NameRef(nameref_ctx) - } - ast::NameLike::Name(name) => { - let name_ctx = Self::classify_name(&self.sema, original_file, name)?; - CompletionAnalysis::Name(name_ctx) - } - }; - Some(analysis) - } - - fn classify_lifetime( - _sema: &Semantics<'_, RootDatabase>, - original_file: &SyntaxNode, - lifetime: ast::Lifetime, - ) -> Option { - let parent = lifetime.syntax().parent()?; - if parent.kind() == SyntaxKind::ERROR { - return None; - } - - let kind = match_ast! { - match parent { - ast::LifetimeParam(param) => LifetimeKind::LifetimeParam { - is_decl: param.lifetime().as_ref() == Some(&lifetime), - param - }, - ast::BreakExpr(_) => LifetimeKind::LabelRef, - ast::ContinueExpr(_) => LifetimeKind::LabelRef, - ast::Label(_) => LifetimeKind::LabelDef, - _ => LifetimeKind::Lifetime, - } - }; - let lifetime = find_node_at_offset(&original_file, lifetime.syntax().text_range().start()); - - Some(LifetimeContext { lifetime, kind }) - } - - fn classify_name( - sema: &Semantics<'_, RootDatabase>, - original_file: &SyntaxNode, - name: ast::Name, - ) -> Option { - let parent = name.syntax().parent()?; - let kind = match_ast! { - match parent { - ast::Const(_) => NameKind::Const, - ast::ConstParam(_) => NameKind::ConstParam, - ast::Enum(_) => NameKind::Enum, - ast::Fn(_) => NameKind::Function, - ast::IdentPat(bind_pat) => { - let mut pat_ctx = pattern_context_for(sema, original_file, bind_pat.into()); - if let Some(record_field) = ast::RecordPatField::for_field_name(&name) { - pat_ctx.record_pat = find_node_in_file_compensated(sema, original_file, &record_field.parent_record_pat()); - } - - NameKind::IdentPat(pat_ctx) - }, - ast::MacroDef(_) => NameKind::MacroDef, - ast::MacroRules(_) => NameKind::MacroRules, - ast::Module(module) => NameKind::Module(module), - ast::RecordField(_) => NameKind::RecordField, - ast::Rename(_) => NameKind::Rename, - ast::SelfParam(_) => NameKind::SelfParam, - ast::Static(_) => NameKind::Static, - ast::Struct(_) => NameKind::Struct, - ast::Trait(_) => NameKind::Trait, - ast::TypeAlias(_) => NameKind::TypeAlias, - ast::TypeParam(_) => NameKind::TypeParam, - ast::Union(_) => NameKind::Union, - ast::Variant(_) => NameKind::Variant, - _ => return None, - } - }; - let name = find_node_at_offset(&original_file, name.syntax().text_range().start()); - Some(NameContext { name, kind }) - } - - fn classify_name_ref( - sema: &Semantics<'_, RootDatabase>, - original_file: &SyntaxNode, - name_ref: ast::NameRef, - parent: SyntaxNode, - ) -> Option<(NameRefContext, QualifierCtx)> { - let nameref = find_node_at_offset(&original_file, name_ref.syntax().text_range().start()); - - let make_res = - |kind| (NameRefContext { nameref: nameref.clone(), kind }, Default::default()); - - if let Some(record_field) = ast::RecordExprField::for_field_name(&name_ref) { - let dot_prefix = previous_non_trivia_token(name_ref.syntax().clone()) - .map_or(false, |it| T![.] == it.kind()); - - return find_node_in_file_compensated( - sema, - original_file, - &record_field.parent_record_lit(), - ) - .map(|expr| NameRefKind::RecordExpr { expr, dot_prefix }) - .map(make_res); - } - if let Some(record_field) = ast::RecordPatField::for_field_name_ref(&name_ref) { - let kind = NameRefKind::Pattern(PatternContext { - param_ctx: None, - has_type_ascription: false, - ref_token: None, - mut_token: None, - record_pat: find_node_in_file_compensated( - sema, - original_file, - &record_field.parent_record_pat(), - ), - ..pattern_context_for( - sema, - original_file, - record_field.parent_record_pat().clone().into(), - ) - }); - return Some(make_res(kind)); - } - - let segment = match_ast! { - match parent { - ast::PathSegment(segment) => segment, - ast::FieldExpr(field) => { - let receiver = find_opt_node_in_file(original_file, field.expr()); - let receiver_is_ambiguous_float_literal = match &receiver { - Some(ast::Expr::Literal(l)) => matches! { - l.kind(), - ast::LiteralKind::FloatNumber { .. } if l.syntax().last_token().map_or(false, |it| it.text().ends_with('.')) - }, - _ => false, - }; - let kind = NameRefKind::DotAccess(DotAccess { - receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)), - kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal }, - receiver - }); - return Some(make_res(kind)); - }, - ast::MethodCallExpr(method) => { - let receiver = find_opt_node_in_file(original_file, method.receiver()); - let kind = NameRefKind::DotAccess(DotAccess { - receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)), - kind: DotAccessKind::Method { has_parens: method.arg_list().map_or(false, |it| it.l_paren_token().is_some()) }, - receiver - }); - return Some(make_res(kind)); - }, - _ => return None, - } - }; - - let path = segment.parent_path(); - let mut path_ctx = PathCompletionCtx { - has_call_parens: false, - has_macro_bang: false, - qualified: Qualified::No, - parent: path.parent_path(), - path: path.clone(), - kind: PathKind::Item { kind: ItemListKind::SourceFile }, - has_type_args: false, - use_tree_parent: false, - }; - - let is_in_block = |it: &SyntaxNode| { - it.parent() - .map(|node| { - ast::ExprStmt::can_cast(node.kind()) || ast::StmtList::can_cast(node.kind()) - }) - .unwrap_or(false) - }; - let func_update_record = |syn: &SyntaxNode| { - if let Some(record_expr) = syn.ancestors().nth(2).and_then(ast::RecordExpr::cast) { - find_node_in_file_compensated(sema, original_file, &record_expr) - } else { - None - } - }; - let after_if_expr = |node: SyntaxNode| { - let prev_expr = (|| { - let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?; - ast::ExprStmt::cast(prev_sibling)?.expr() - })(); - matches!(prev_expr, Some(ast::Expr::IfExpr(_))) - }; - - // We do not want to generate path completions when we are sandwiched between an item decl signature and its body. - // ex. trait Foo $0 {} - // in these cases parser recovery usually kicks in for our inserted identifier, causing it - // to either be parsed as an ExprStmt or a MacroCall, depending on whether it is in a block - // expression or an item list. - // The following code checks if the body is missing, if it is we either cut off the body - // from the item or it was missing in the first place - let inbetween_body_and_decl_check = |node: SyntaxNode| { - if let Some(NodeOrToken::Node(n)) = - syntax::algo::non_trivia_sibling(node.into(), syntax::Direction::Prev) - { - if let Some(item) = ast::Item::cast(n) { - let is_inbetween = match &item { - ast::Item::Const(it) => it.body().is_none(), - ast::Item::Enum(it) => it.variant_list().is_none(), - ast::Item::ExternBlock(it) => it.extern_item_list().is_none(), - ast::Item::Fn(it) => it.body().is_none(), - ast::Item::Impl(it) => it.assoc_item_list().is_none(), - ast::Item::Module(it) => it.item_list().is_none(), - ast::Item::Static(it) => it.body().is_none(), - ast::Item::Struct(it) => it.field_list().is_none(), - ast::Item::Trait(it) => it.assoc_item_list().is_none(), - ast::Item::TypeAlias(it) => it.ty().is_none(), - ast::Item::Union(it) => it.record_field_list().is_none(), - _ => false, - }; - if is_inbetween { - return Some(item); - } - } - } - None - }; - - let type_location = |node: &SyntaxNode| { - let parent = node.parent()?; - let res = match_ast! { - match parent { - ast::Const(it) => { - let name = find_opt_node_in_file(original_file, it.name())?; - let original = ast::Const::cast(name.syntax().parent()?)?; - TypeLocation::TypeAscription(TypeAscriptionTarget::Const(original.body())) - }, - ast::RetType(it) => { - if it.thin_arrow_token().is_none() { - return None; - } - let parent = match ast::Fn::cast(parent.parent()?) { - Some(x) => x.param_list(), - None => ast::ClosureExpr::cast(parent.parent()?)?.param_list(), - }; - - let parent = find_opt_node_in_file(original_file, parent)?.syntax().parent()?; - TypeLocation::TypeAscription(TypeAscriptionTarget::RetType(match_ast! { - match parent { - ast::ClosureExpr(it) => { - it.body() - }, - ast::Fn(it) => { - it.body().map(ast::Expr::BlockExpr) - }, - _ => return None, - } - })) - }, - ast::Param(it) => { - if it.colon_token().is_none() { - return None; - } - TypeLocation::TypeAscription(TypeAscriptionTarget::FnParam(find_opt_node_in_file(original_file, it.pat()))) - }, - ast::LetStmt(it) => { - if it.colon_token().is_none() { - return None; - } - TypeLocation::TypeAscription(TypeAscriptionTarget::Let(find_opt_node_in_file(original_file, it.pat()))) - }, - ast::Impl(it) => { - match it.trait_() { - Some(t) if t.syntax() == node => TypeLocation::ImplTrait, - _ => match it.self_ty() { - Some(t) if t.syntax() == node => TypeLocation::ImplTarget, - _ => return None, - }, - } - }, - ast::TypeBound(_) => TypeLocation::TypeBound, - // is this case needed? - ast::TypeBoundList(_) => TypeLocation::TypeBound, - ast::GenericArg(it) => TypeLocation::GenericArgList(find_opt_node_in_file_compensated(sema, original_file, it.syntax().parent().and_then(ast::GenericArgList::cast))), - // is this case needed? - ast::GenericArgList(it) => TypeLocation::GenericArgList(find_opt_node_in_file_compensated(sema, original_file, Some(it))), - ast::TupleField(_) => TypeLocation::TupleField, - _ => return None, - } - }; - Some(res) - }; - - let is_in_condition = |it: &ast::Expr| { - (|| { - let parent = it.syntax().parent()?; - if let Some(expr) = ast::WhileExpr::cast(parent.clone()) { - Some(expr.condition()? == *it) - } else if let Some(expr) = ast::IfExpr::cast(parent) { - Some(expr.condition()? == *it) - } else { - None - } - })() - .unwrap_or(false) - }; - - let make_path_kind_expr = |expr: ast::Expr| { - let it = expr.syntax(); - let in_block_expr = is_in_block(it); - let in_loop_body = is_in_loop_body(it); - let after_if_expr = after_if_expr(it.clone()); - let ref_expr_parent = - path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast); - let (innermost_ret_ty, self_param) = { - let find_ret_ty = |it: SyntaxNode| { - if let Some(item) = ast::Item::cast(it.clone()) { - match item { - ast::Item::Fn(f) => { - Some(sema.to_def(&f).map(|it| it.ret_type(sema.db))) - } - ast::Item::MacroCall(_) => None, - _ => Some(None), - } - } else { - let expr = ast::Expr::cast(it)?; - let callable = match expr { - // FIXME - // ast::Expr::BlockExpr(b) if b.async_token().is_some() || b.try_token().is_some() => sema.type_of_expr(b), - ast::Expr::ClosureExpr(_) => sema.type_of_expr(&expr), - _ => return None, - }; - Some( - callable - .and_then(|c| c.adjusted().as_callable(sema.db)) - .map(|it| it.return_type()), - ) - } - }; - let find_fn_self_param = |it| match it { - ast::Item::Fn(fn_) => { - Some(sema.to_def(&fn_).and_then(|it| it.self_param(sema.db))) - } - ast::Item::MacroCall(_) => None, - _ => Some(None), - }; - - match find_node_in_file_compensated(sema, original_file, &expr) { - Some(it) => { - let innermost_ret_ty = sema - .ancestors_with_macros(it.syntax().clone()) - .find_map(find_ret_ty) - .flatten(); - - let self_param = sema - .ancestors_with_macros(it.syntax().clone()) - .filter_map(ast::Item::cast) - .find_map(find_fn_self_param) - .flatten(); - (innermost_ret_ty, self_param) - } - None => (None, None), - } - }; - let is_func_update = func_update_record(it); - let in_condition = is_in_condition(&expr); - let incomplete_let = it - .parent() - .and_then(ast::LetStmt::cast) - .map_or(false, |it| it.semicolon_token().is_none()); - let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax()); - - let in_match_guard = match it.parent().and_then(ast::MatchArm::cast) { - Some(arm) => arm - .fat_arrow_token() - .map_or(true, |arrow| it.text_range().start() < arrow.text_range().start()), - None => false, - }; - - PathKind::Expr { - expr_ctx: ExprCtx { - in_block_expr, - in_loop_body, - after_if_expr, - in_condition, - ref_expr_parent, - is_func_update, - innermost_ret_ty, - self_param, - incomplete_let, - impl_, - in_match_guard, - }, - } - }; - let make_path_kind_type = |ty: ast::Type| { - let location = type_location(ty.syntax()); - PathKind::Type { location: location.unwrap_or(TypeLocation::Other) } - }; - - // Infer the path kind - let parent = path.syntax().parent()?; - let kind = match_ast! { - match parent { - ast::PathType(it) => make_path_kind_type(it.into()), - ast::PathExpr(it) => { - if let Some(p) = it.syntax().parent() { - if ast::ExprStmt::can_cast(p.kind()) { - if let Some(kind) = inbetween_body_and_decl_check(p) { - return Some(make_res(NameRefKind::Keyword(kind))); - } - } - } - - path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind())); - - make_path_kind_expr(it.into()) - }, - ast::TupleStructPat(it) => { - path_ctx.has_call_parens = true; - PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())} - }, - ast::RecordPat(it) => { - path_ctx.has_call_parens = true; - PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())} - }, - ast::PathPat(it) => { - PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())} - }, - ast::MacroCall(it) => { - // A macro call in this position is usually a result of parsing recovery, so check that - if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) { - return Some(make_res(NameRefKind::Keyword(kind))); - } - - path_ctx.has_macro_bang = it.excl_token().is_some(); - let parent = it.syntax().parent()?; - // Any path in an item list will be treated as a macro call by the parser - match_ast! { - match parent { - ast::MacroExpr(expr) => make_path_kind_expr(expr.into()), - ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}, - ast::MacroType(ty) => make_path_kind_type(ty.into()), - ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module }, - ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() { - Some(it) => match_ast! { - match it { - ast::Trait(_) => ItemListKind::Trait, - ast::Impl(it) => if it.trait_().is_some() { - ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it)) - } else { - ItemListKind::Impl - }, - _ => return None - } - }, - None => return None, - } }, - ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock }, - ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile }, - _ => return None, - } - } - }, - ast::Meta(meta) => { - let attr = meta.parent_attr()?; - let kind = attr.kind(); - let attached = attr.syntax().parent()?; - let is_trailing_outer_attr = kind != AttrKind::Inner - && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none(); - let annotated_item_kind = if is_trailing_outer_attr { - None - } else { - Some(attached.kind()) - }; - PathKind::Attr { - attr_ctx: AttrCtx { - kind, - annotated_item_kind, - } - } - }, - ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() }, - ast::UseTree(_) => PathKind::Use, - _ => return None, - - } - }; - - path_ctx.kind = kind; - path_ctx.has_type_args = segment.generic_arg_list().is_some(); - - // calculate the qualifier context - if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) { - path_ctx.use_tree_parent = use_tree_parent; - if !use_tree_parent && segment.coloncolon_token().is_some() { - path_ctx.qualified = Qualified::Absolute; - } else { - let path = path - .segment() - .and_then(|it| find_node_in_file(original_file, &it)) - .map(|it| it.parent_path()); - if let Some(path) = path { - // `<_>::$0` - let is_infer_qualifier = path.qualifier().is_none() - && matches!( - path.segment().and_then(|it| it.kind()), - Some(ast::PathSegmentKind::Type { - type_ref: Some(ast::Type::InferType(_)), - trait_ref: None, - }) - ); - - path_ctx.qualified = if is_infer_qualifier { - Qualified::Infer - } else { - let res = sema.resolve_path(&path); - - // For understanding how and why super_chain_len is calculated the way it - // is check the documentation at it's definition - let mut segment_count = 0; - let super_count = iter::successors(Some(path.clone()), |p| p.qualifier()) - .take_while(|p| { - p.segment() - .and_then(|s| { - segment_count += 1; - s.super_token() - }) - .is_some() - }) - .count(); - - let super_chain_len = - if segment_count > super_count { None } else { Some(super_count) }; - - Qualified::With { path, resolution: res, super_chain_len } - } - }; - } - } else if let Some(segment) = path.segment() { - if segment.coloncolon_token().is_some() { - path_ctx.qualified = Qualified::Absolute; - } - } - - let mut qualifier_ctx = QualifierCtx::default(); - if path_ctx.is_trivial_path() { - // fetch the full expression that may have qualifiers attached to it - let top_node = match path_ctx.kind { - PathKind::Expr { expr_ctx: ExprCtx { in_block_expr: true, .. } } => { - parent.ancestors().find(|it| ast::PathExpr::can_cast(it.kind())).and_then(|p| { - let parent = p.parent()?; - if ast::StmtList::can_cast(parent.kind()) { - Some(p) - } else if ast::ExprStmt::can_cast(parent.kind()) { - Some(parent) - } else { - None - } - }) - } - PathKind::Item { .. } => { - parent.ancestors().find(|it| ast::MacroCall::can_cast(it.kind())) - } - _ => None, - }; - if let Some(top) = top_node { - if let Some(NodeOrToken::Node(error_node)) = - syntax::algo::non_trivia_sibling(top.clone().into(), syntax::Direction::Prev) - { - if error_node.kind() == SyntaxKind::ERROR { - qualifier_ctx.unsafe_tok = error_node - .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .find(|it| it.kind() == T![unsafe]); - qualifier_ctx.vis_node = - error_node.children().find_map(ast::Visibility::cast); - } - } - - if let PathKind::Item { .. } = path_ctx.kind { - if qualifier_ctx.none() { - if let Some(t) = top.first_token() { - if let Some(prev) = t - .prev_token() - .and_then(|t| syntax::algo::skip_trivia_token(t, Direction::Prev)) - { - if ![T![;], T!['}'], T!['{']].contains(&prev.kind()) { - // This was inferred to be an item position path, but it seems - // to be part of some other broken node which leaked into an item - // list - return None; - } - } - } - } - } - } - } - Some((NameRefContext { nameref, kind: NameRefKind::Path(path_ctx) }, qualifier_ctx)) - } -} - -fn pattern_context_for( - sema: &Semantics<'_, RootDatabase>, - original_file: &SyntaxNode, - pat: ast::Pat, -) -> PatternContext { - let mut param_ctx = None; - let (refutability, has_type_ascription) = - pat - .syntax() - .ancestors() - .skip_while(|it| ast::Pat::can_cast(it.kind())) - .next() - .map_or((PatternRefutability::Irrefutable, false), |node| { - let refutability = match_ast! { - match node { - ast::LetStmt(let_) => return (PatternRefutability::Irrefutable, let_.ty().is_some()), - ast::Param(param) => { - let has_type_ascription = param.ty().is_some(); - param_ctx = (|| { - let fake_param_list = param.syntax().parent().and_then(ast::ParamList::cast)?; - let param_list = find_node_in_file_compensated(sema, original_file, &fake_param_list)?; - let param_list_owner = param_list.syntax().parent()?; - let kind = match_ast! { - match param_list_owner { - ast::ClosureExpr(closure) => ParamKind::Closure(closure), - ast::Fn(fn_) => ParamKind::Function(fn_), - _ => return None, - } - }; - Some(ParamContext { - param_list, param, kind - }) - })(); - return (PatternRefutability::Irrefutable, has_type_ascription) - }, - ast::MatchArm(_) => PatternRefutability::Refutable, - ast::LetExpr(_) => PatternRefutability::Refutable, - ast::ForExpr(_) => PatternRefutability::Irrefutable, - _ => PatternRefutability::Irrefutable, - } - }; - (refutability, false) - }); - let (ref_token, mut_token) = match &pat { - ast::Pat::IdentPat(it) => (it.ref_token(), it.mut_token()), - _ => (None, None), - }; - - PatternContext { - refutability, - param_ctx, - has_type_ascription, - parent_pat: pat.syntax().parent().and_then(ast::Pat::cast), - mut_token, - ref_token, - record_pat: None, - impl_: fetch_immediate_impl(sema, original_file, pat.syntax()), - } -} - -fn fetch_immediate_impl( - sema: &Semantics<'_, RootDatabase>, - original_file: &SyntaxNode, - node: &SyntaxNode, -) -> Option { - let mut ancestors = ancestors_in_file_compensated(sema, original_file, node)? - .filter_map(ast::Item::cast) - .filter(|it| !matches!(it, ast::Item::MacroCall(_))); - - match ancestors.next()? { - ast::Item::Const(_) | ast::Item::Fn(_) | ast::Item::TypeAlias(_) => (), - ast::Item::Impl(it) => return Some(it), - _ => return None, - } - match ancestors.next()? { - ast::Item::Impl(it) => Some(it), - _ => None, - } -} - -/// Attempts to find `node` inside `syntax` via `node`'s text range. -/// If the fake identifier has been inserted after this node or inside of this node use the `_compensated` version instead. -fn find_opt_node_in_file(syntax: &SyntaxNode, node: Option) -> Option { - find_node_in_file(syntax, &node?) -} - -/// Attempts to find `node` inside `syntax` via `node`'s text range. -/// If the fake identifier has been inserted after this node or inside of this node use the `_compensated` version instead. -fn find_node_in_file(syntax: &SyntaxNode, node: &N) -> Option { - let syntax_range = syntax.text_range(); - let range = node.syntax().text_range(); - let intersection = range.intersect(syntax_range)?; - syntax.covering_element(intersection).ancestors().find_map(N::cast) -} - -/// Attempts to find `node` inside `syntax` via `node`'s text range while compensating -/// for the offset introduced by the fake ident. -/// This is wrong if `node` comes before the insertion point! Use `find_node_in_file` instead. -fn find_node_in_file_compensated( - sema: &Semantics<'_, RootDatabase>, - in_file: &SyntaxNode, - node: &N, -) -> Option { - ancestors_in_file_compensated(sema, in_file, node.syntax())?.find_map(N::cast) -} - -fn ancestors_in_file_compensated<'sema>( - sema: &'sema Semantics<'_, RootDatabase>, - in_file: &SyntaxNode, - node: &SyntaxNode, -) -> Option + 'sema> { - let syntax_range = in_file.text_range(); - let range = node.text_range(); - let end = range.end().checked_sub(TextSize::try_from(COMPLETION_MARKER.len()).ok()?)?; - if end < range.start() { - return None; - } - let range = TextRange::new(range.start(), end); - // our inserted ident could cause `range` to go outside of the original syntax, so cap it - let intersection = range.intersect(syntax_range)?; - let node = match in_file.covering_element(intersection) { - NodeOrToken::Node(node) => node, - NodeOrToken::Token(tok) => tok.parent()?, - }; - Some(sema.ancestors_with_macros(node)) -} - -/// Attempts to find `node` inside `syntax` via `node`'s text range while compensating -/// for the offset introduced by the fake ident.. -/// This is wrong if `node` comes before the insertion point! Use `find_node_in_file` instead. -fn find_opt_node_in_file_compensated( - sema: &Semantics<'_, RootDatabase>, - syntax: &SyntaxNode, - node: Option, -) -> Option { - find_node_in_file_compensated(sema, syntax, &node?) -} - -fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> { - if let Some(qual) = path.qualifier() { - return Some((qual, false)); - } - let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; - let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?; - Some((use_tree.path()?, true)) -} - -fn has_ref(token: &SyntaxToken) -> bool { - let mut token = token.clone(); - for skip in [SyntaxKind::IDENT, SyntaxKind::WHITESPACE, T![mut]] { - if token.kind() == skip { - token = match token.prev_token() { - Some(it) => it, - None => return false, - } - } - } - token.kind() == T![&] -} - -pub(crate) fn is_in_token_of_for_loop(element: SyntaxElement) -> bool { - // oh my ... - (|| { - let syntax_token = element.into_token()?; - let range = syntax_token.text_range(); - let for_expr = syntax_token.parent_ancestors().find_map(ast::ForExpr::cast)?; - - // check if the current token is the `in` token of a for loop - if let Some(token) = for_expr.in_token() { - return Some(syntax_token == token); - } - let pat = for_expr.pat()?; - if range.end() < pat.syntax().text_range().end() { - // if we are inside or before the pattern we can't be at the `in` token position - return None; - } - let next_sibl = next_non_trivia_sibling(pat.syntax().clone().into())?; - Some(match next_sibl { - // the loop body is some node, if our token is at the start we are at the `in` position, - // otherwise we could be in a recovered expression, we don't wanna ruin completions there - syntax::NodeOrToken::Node(n) => n.text_range().start() == range.start(), - // the loop body consists of a single token, if we are this we are certainly at the `in` token position - syntax::NodeOrToken::Token(t) => t == syntax_token, - }) - })() - .unwrap_or(false) -} - -#[test] -fn test_for_is_prev2() { - crate::tests::check_pattern_is_applicable(r"fn __() { for i i$0 }", is_in_token_of_for_loop); -} - -pub(crate) fn is_in_loop_body(node: &SyntaxNode) -> bool { - node.ancestors() - .take_while(|it| it.kind() != SyntaxKind::FN && it.kind() != SyntaxKind::CLOSURE_EXPR) - .find_map(|it| { - let loop_body = match_ast! { - match it { - ast::ForExpr(it) => it.loop_body(), - ast::WhileExpr(it) => it.loop_body(), - ast::LoopExpr(it) => it.loop_body(), - _ => None, - } - }; - loop_body.filter(|it| it.syntax().text_range().contains_range(node.text_range())) - }) - .is_some() -} - -fn previous_non_trivia_token(e: impl Into) -> Option { - let mut token = match e.into() { - SyntaxElement::Node(n) => n.first_token()?, - SyntaxElement::Token(t) => t, - } - .prev_token(); - while let Some(inner) = token { - if !inner.kind().is_trivia() { - return Some(inner); - } else { - token = inner.prev_token(); - } - } - None -} - -fn next_non_trivia_sibling(ele: SyntaxElement) -> Option { - let mut e = ele.next_sibling_or_token(); - while let Some(inner) = e { - if !inner.kind().is_trivia() { - return Some(inner); - } else { - e = inner.next_sibling_or_token(); - } - } - None -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs deleted file mode 100644 index c5557bdafb339..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs +++ /dev/null @@ -1,393 +0,0 @@ -use expect_test::{expect, Expect}; -use hir::HirDisplay; - -use crate::{ - context::CompletionContext, - tests::{position, TEST_CONFIG}, -}; - -fn check_expected_type_and_name(ra_fixture: &str, expect: Expect) { - let (db, pos) = position(ra_fixture); - let config = TEST_CONFIG; - let (completion_context, _analysis) = CompletionContext::new(&db, pos, &config).unwrap(); - - let ty = completion_context - .expected_type - .map(|t| t.display_test(&db).to_string()) - .unwrap_or("?".to_owned()); - - let name = - completion_context.expected_name.map_or_else(|| "?".to_owned(), |name| name.to_string()); - - expect.assert_eq(&format!("ty: {}, name: {}", ty, name)); -} - -#[test] -fn expected_type_let_without_leading_char() { - cov_mark::check!(expected_type_let_without_leading_char); - check_expected_type_and_name( - r#" -fn foo() { - let x: u32 = $0; -} -"#, - expect![[r#"ty: u32, name: x"#]], - ); -} - -#[test] -fn expected_type_let_with_leading_char() { - cov_mark::check!(expected_type_let_with_leading_char); - check_expected_type_and_name( - r#" -fn foo() { - let x: u32 = c$0; -} -"#, - expect![[r#"ty: u32, name: x"#]], - ); -} - -#[test] -fn expected_type_let_pat() { - check_expected_type_and_name( - r#" -fn foo() { - let x$0 = 0u32; -} -"#, - expect![[r#"ty: u32, name: ?"#]], - ); - check_expected_type_and_name( - r#" -fn foo() { - let $0 = 0u32; -} -"#, - expect![[r#"ty: u32, name: ?"#]], - ); -} - -#[test] -fn expected_type_fn_param() { - cov_mark::check!(expected_type_fn_param); - check_expected_type_and_name( - r#" -fn foo() { bar($0); } -fn bar(x: u32) {} -"#, - expect![[r#"ty: u32, name: x"#]], - ); - check_expected_type_and_name( - r#" -fn foo() { bar(c$0); } -fn bar(x: u32) {} -"#, - expect![[r#"ty: u32, name: x"#]], - ); -} - -#[test] -fn expected_type_fn_param_ref() { - cov_mark::check!(expected_type_fn_param_ref); - check_expected_type_and_name( - r#" -fn foo() { bar(&$0); } -fn bar(x: &u32) {} -"#, - expect![[r#"ty: u32, name: x"#]], - ); - check_expected_type_and_name( - r#" -fn foo() { bar(&mut $0); } -fn bar(x: &mut u32) {} -"#, - expect![[r#"ty: u32, name: x"#]], - ); - check_expected_type_and_name( - r#" -fn foo() { bar(& c$0); } -fn bar(x: &u32) {} - "#, - expect![[r#"ty: u32, name: x"#]], - ); - check_expected_type_and_name( - r#" -fn foo() { bar(&mut c$0); } -fn bar(x: &mut u32) {} -"#, - expect![[r#"ty: u32, name: x"#]], - ); - check_expected_type_and_name( - r#" -fn foo() { bar(&c$0); } -fn bar(x: &u32) {} - "#, - expect![[r#"ty: u32, name: x"#]], - ); -} - -#[test] -fn expected_type_struct_field_without_leading_char() { - cov_mark::check!(expected_type_struct_field_without_leading_char); - check_expected_type_and_name( - r#" -struct Foo { a: u32 } -fn foo() { - Foo { a: $0 }; -} -"#, - expect![[r#"ty: u32, name: a"#]], - ) -} - -#[test] -fn expected_type_struct_field_followed_by_comma() { - cov_mark::check!(expected_type_struct_field_followed_by_comma); - check_expected_type_and_name( - r#" -struct Foo { a: u32 } -fn foo() { - Foo { a: $0, }; -} -"#, - expect![[r#"ty: u32, name: a"#]], - ) -} - -#[test] -fn expected_type_generic_struct_field() { - check_expected_type_and_name( - r#" -struct Foo { a: T } -fn foo() -> Foo { - Foo { a: $0 } -} -"#, - expect![[r#"ty: u32, name: a"#]], - ) -} - -#[test] -fn expected_type_struct_field_with_leading_char() { - cov_mark::check!(expected_type_struct_field_with_leading_char); - check_expected_type_and_name( - r#" -struct Foo { a: u32 } -fn foo() { - Foo { a: c$0 }; -} -"#, - expect![[r#"ty: u32, name: a"#]], - ); -} - -#[test] -fn expected_type_match_arm_without_leading_char() { - cov_mark::check!(expected_type_match_arm_without_leading_char); - check_expected_type_and_name( - r#" -enum E { X } -fn foo() { - match E::X { $0 } -} -"#, - expect![[r#"ty: E, name: ?"#]], - ); -} - -#[test] -fn expected_type_match_arm_with_leading_char() { - cov_mark::check!(expected_type_match_arm_with_leading_char); - check_expected_type_and_name( - r#" -enum E { X } -fn foo() { - match E::X { c$0 } -} -"#, - expect![[r#"ty: E, name: ?"#]], - ); -} - -#[test] -fn expected_type_match_arm_body_without_leading_char() { - cov_mark::check!(expected_type_match_arm_body_without_leading_char); - check_expected_type_and_name( - r#" -struct Foo; -enum E { X } -fn foo() -> Foo { - match E::X { E::X => $0 } -} -"#, - expect![[r#"ty: Foo, name: ?"#]], - ); -} - -#[test] -fn expected_type_match_body_arm_with_leading_char() { - cov_mark::check!(expected_type_match_arm_body_with_leading_char); - check_expected_type_and_name( - r#" -struct Foo; -enum E { X } -fn foo() -> Foo { - match E::X { E::X => c$0 } -} -"#, - expect![[r#"ty: Foo, name: ?"#]], - ); -} - -#[test] -fn expected_type_if_let_without_leading_char() { - cov_mark::check!(expected_type_if_let_without_leading_char); - check_expected_type_and_name( - r#" -enum Foo { Bar, Baz, Quux } - -fn foo() { - let f = Foo::Quux; - if let $0 = f { } -} -"#, - expect![[r#"ty: Foo, name: ?"#]], - ) -} - -#[test] -fn expected_type_if_let_with_leading_char() { - cov_mark::check!(expected_type_if_let_with_leading_char); - check_expected_type_and_name( - r#" -enum Foo { Bar, Baz, Quux } - -fn foo() { - let f = Foo::Quux; - if let c$0 = f { } -} -"#, - expect![[r#"ty: Foo, name: ?"#]], - ) -} - -#[test] -fn expected_type_fn_ret_without_leading_char() { - cov_mark::check!(expected_type_fn_ret_without_leading_char); - check_expected_type_and_name( - r#" -fn foo() -> u32 { - $0 -} -"#, - expect![[r#"ty: u32, name: ?"#]], - ) -} - -#[test] -fn expected_type_fn_ret_with_leading_char() { - cov_mark::check!(expected_type_fn_ret_with_leading_char); - check_expected_type_and_name( - r#" -fn foo() -> u32 { - c$0 -} -"#, - expect![[r#"ty: u32, name: ?"#]], - ) -} - -#[test] -fn expected_type_fn_ret_fn_ref_fully_typed() { - check_expected_type_and_name( - r#" -fn foo() -> u32 { - foo$0 -} -"#, - expect![[r#"ty: u32, name: ?"#]], - ) -} - -#[test] -fn expected_type_closure_param_return() { - // FIXME: make this work with `|| $0` - check_expected_type_and_name( - r#" -//- minicore: fn -fn foo() { - bar(|| a$0); -} - -fn bar(f: impl FnOnce() -> u32) {} -"#, - expect![[r#"ty: u32, name: ?"#]], - ); -} - -#[test] -fn expected_type_generic_function() { - check_expected_type_and_name( - r#" -fn foo() { - bar::($0); -} - -fn bar(t: T) {} -"#, - expect![[r#"ty: u32, name: t"#]], - ); -} - -#[test] -fn expected_type_generic_method() { - check_expected_type_and_name( - r#" -fn foo() { - S(1u32).bar($0); -} - -struct S(T); -impl S { - fn bar(self, t: T) {} -} -"#, - expect![[r#"ty: u32, name: t"#]], - ); -} - -#[test] -fn expected_type_functional_update() { - cov_mark::check!(expected_type_struct_func_update); - check_expected_type_and_name( - r#" -struct Foo { field: u32 } -fn foo() { - Foo { - ..$0 - } -} -"#, - expect![[r#"ty: Foo, name: ?"#]], - ); -} - -#[test] -fn expected_type_param_pat() { - check_expected_type_and_name( - r#" -struct Foo { field: u32 } -fn foo(a$0: Foo) {} -"#, - expect![[r#"ty: Foo, name: ?"#]], - ); - check_expected_type_and_name( - r#" -struct Foo { field: u32 } -fn foo($0: Foo) {} -"#, - // FIXME make this work, currently fails due to pattern recovery eating the `:` - expect![[r#"ty: ?, name: ?"#]], - ); -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs deleted file mode 100644 index 27c3ccb35a1ea..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ /dev/null @@ -1,637 +0,0 @@ -//! See `CompletionItem` structure. - -use std::fmt; - -use hir::{Documentation, Mutability}; -use ide_db::{imports::import_assets::LocatedImport, SnippetCap, SymbolKind}; -use smallvec::SmallVec; -use stdx::{impl_from, never}; -use syntax::{SmolStr, TextRange, TextSize}; -use text_edit::TextEdit; - -use crate::{ - context::{CompletionContext, PathCompletionCtx}, - render::{render_path_resolution, RenderContext}, -}; - -/// `CompletionItem` describes a single completion variant in the editor pop-up. -/// It is basically a POD with various properties. To construct a -/// `CompletionItem`, use `new` method and the `Builder` struct. -#[derive(Clone)] -pub struct CompletionItem { - /// Label in the completion pop up which identifies completion. - label: SmolStr, - /// Range of identifier that is being completed. - /// - /// It should be used primarily for UI, but we also use this to convert - /// generic TextEdit into LSP's completion edit (see conv.rs). - /// - /// `source_range` must contain the completion offset. `text_edit` should - /// start with what `source_range` points to, or VSCode will filter out the - /// completion silently. - source_range: TextRange, - /// What happens when user selects this item. - /// - /// Typically, replaces `source_range` with new identifier. - text_edit: TextEdit, - is_snippet: bool, - - /// What item (struct, function, etc) are we completing. - kind: CompletionItemKind, - - /// Lookup is used to check if completion item indeed can complete current - /// ident. - /// - /// That is, in `foo.bar$0` lookup of `abracadabra` will be accepted (it - /// contains `bar` sub sequence), and `quux` will rejected. - lookup: Option, - - /// Additional info to show in the UI pop up. - detail: Option, - documentation: Option, - - /// Whether this item is marked as deprecated - deprecated: bool, - - /// If completing a function call, ask the editor to show parameter popup - /// after completion. - trigger_call_info: bool, - - /// We use this to sort completion. Relevance records facts like "do the - /// types align precisely?". We can't sort by relevances directly, they are - /// only partially ordered. - /// - /// Note that Relevance ignores fuzzy match score. We compute Relevance for - /// all possible items, and then separately build an ordered completion list - /// based on relevance and fuzzy matching with the already typed identifier. - relevance: CompletionRelevance, - - /// Indicates that a reference or mutable reference to this variable is a - /// possible match. - ref_match: Option<(Mutability, TextSize)>, - - /// The import data to add to completion's edits. - import_to_add: SmallVec<[LocatedImport; 1]>, -} - -// We use custom debug for CompletionItem to make snapshot tests more readable. -impl fmt::Debug for CompletionItem { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut s = f.debug_struct("CompletionItem"); - s.field("label", &self.label()).field("source_range", &self.source_range()); - if self.text_edit().len() == 1 { - let atom = &self.text_edit().iter().next().unwrap(); - s.field("delete", &atom.delete); - s.field("insert", &atom.insert); - } else { - s.field("text_edit", &self.text_edit); - } - s.field("kind", &self.kind()); - if self.lookup() != self.label() { - s.field("lookup", &self.lookup()); - } - if let Some(detail) = self.detail() { - s.field("detail", &detail); - } - if let Some(documentation) = self.documentation() { - s.field("documentation", &documentation); - } - if self.deprecated { - s.field("deprecated", &true); - } - - if self.relevance != CompletionRelevance::default() { - s.field("relevance", &self.relevance); - } - - if let Some((mutability, offset)) = &self.ref_match { - s.field("ref_match", &format!("&{}@{offset:?}", mutability.as_keyword_for_ref())); - } - if self.trigger_call_info { - s.field("trigger_call_info", &true); - } - s.finish() - } -} - -#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] -pub struct CompletionRelevance { - /// This is set in cases like these: - /// - /// ``` - /// fn f(spam: String) {} - /// fn main { - /// let spam = 92; - /// f($0) // name of local matches the name of param - /// } - /// ``` - pub exact_name_match: bool, - /// See CompletionRelevanceTypeMatch doc comments for cases where this is set. - pub type_match: Option, - /// This is set in cases like these: - /// - /// ``` - /// fn foo(a: u32) { - /// let b = 0; - /// $0 // `a` and `b` are local - /// } - /// ``` - pub is_local: bool, - /// This is set when trait items are completed in an impl of that trait. - pub is_item_from_trait: bool, - /// This is set when an import is suggested whose name is already imported. - pub is_name_already_imported: bool, - /// This is set for completions that will insert a `use` item. - pub requires_import: bool, - /// Set for method completions of the `core::ops` and `core::cmp` family. - pub is_op_method: bool, - /// Set for item completions that are private but in the workspace. - pub is_private_editable: bool, - /// Set for postfix snippet item completions - pub postfix_match: Option, - /// This is set for type inference results - pub is_definite: bool, -} - -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub enum CompletionRelevanceTypeMatch { - /// This is set in cases like these: - /// - /// ``` - /// enum Option { Some(T), None } - /// fn f(a: Option) {} - /// fn main { - /// f(Option::N$0) // type `Option` could unify with `Option` - /// } - /// ``` - CouldUnify, - /// This is set in cases like these: - /// - /// ``` - /// fn f(spam: String) {} - /// fn main { - /// let foo = String::new(); - /// f($0) // type of local matches the type of param - /// } - /// ``` - Exact, -} - -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub enum CompletionRelevancePostfixMatch { - /// Set in cases when item is postfix, but not exact - NonExact, - /// This is set in cases like these: - /// - /// ``` - /// (a > b).not$0 - /// ``` - /// - /// Basically, we want to guarantee that postfix snippets always takes - /// precedence over everything else. - Exact, -} - -impl CompletionRelevance { - /// Provides a relevance score. Higher values are more relevant. - /// - /// The absolute value of the relevance score is not meaningful, for - /// example a value of 0 doesn't mean "not relevant", rather - /// it means "least relevant". The score value should only be used - /// for relative ordering. - /// - /// See is_relevant if you need to make some judgement about score - /// in an absolute sense. - pub fn score(self) -> u32 { - let mut score = 0; - let CompletionRelevance { - exact_name_match, - type_match, - is_local, - is_item_from_trait, - is_name_already_imported, - requires_import, - is_op_method, - is_private_editable, - postfix_match, - is_definite, - } = self; - - // lower rank private things - if !is_private_editable { - score += 1; - } - // lower rank trait op methods - if !is_op_method { - score += 10; - } - // lower rank for conflicting import names - if !is_name_already_imported { - score += 1; - } - // lower rank for items that don't need an import - if !requires_import { - score += 1; - } - if exact_name_match { - score += 10; - } - score += match postfix_match { - Some(CompletionRelevancePostfixMatch::Exact) => 100, - Some(CompletionRelevancePostfixMatch::NonExact) => 0, - None => 3, - }; - score += match type_match { - Some(CompletionRelevanceTypeMatch::Exact) => 8, - Some(CompletionRelevanceTypeMatch::CouldUnify) => 3, - None => 0, - }; - // slightly prefer locals - if is_local { - score += 1; - } - if is_item_from_trait { - score += 1; - } - if is_definite { - score += 10; - } - score - } - - /// Returns true when the score for this threshold is above - /// some threshold such that we think it is especially likely - /// to be relevant. - pub fn is_relevant(&self) -> bool { - self.score() > 0 - } -} - -/// The type of the completion item. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum CompletionItemKind { - SymbolKind(SymbolKind), - Binding, - BuiltinType, - InferredType, - Keyword, - Method, - Snippet, - UnresolvedReference, -} - -impl_from!(SymbolKind for CompletionItemKind); - -impl CompletionItemKind { - #[cfg(test)] - pub(crate) fn tag(&self) -> &'static str { - match self { - CompletionItemKind::SymbolKind(kind) => match kind { - SymbolKind::Attribute => "at", - SymbolKind::BuiltinAttr => "ba", - SymbolKind::Const => "ct", - SymbolKind::ConstParam => "cp", - SymbolKind::Derive => "de", - SymbolKind::DeriveHelper => "dh", - SymbolKind::Enum => "en", - SymbolKind::Field => "fd", - SymbolKind::Function => "fn", - SymbolKind::Impl => "im", - SymbolKind::Label => "lb", - SymbolKind::LifetimeParam => "lt", - SymbolKind::Local => "lc", - SymbolKind::Macro => "ma", - SymbolKind::Module => "md", - SymbolKind::SelfParam => "sp", - SymbolKind::SelfType => "sy", - SymbolKind::Static => "sc", - SymbolKind::Struct => "st", - SymbolKind::ToolModule => "tm", - SymbolKind::Trait => "tt", - SymbolKind::TypeAlias => "ta", - SymbolKind::TypeParam => "tp", - SymbolKind::Union => "un", - SymbolKind::ValueParam => "vp", - SymbolKind::Variant => "ev", - }, - CompletionItemKind::Binding => "bn", - CompletionItemKind::BuiltinType => "bt", - CompletionItemKind::InferredType => "it", - CompletionItemKind::Keyword => "kw", - CompletionItemKind::Method => "me", - CompletionItemKind::Snippet => "sn", - CompletionItemKind::UnresolvedReference => "??", - } - } -} - -impl CompletionItem { - pub(crate) fn new( - kind: impl Into, - source_range: TextRange, - label: impl Into, - ) -> Builder { - let label = label.into(); - Builder { - source_range, - label, - insert_text: None, - is_snippet: false, - trait_name: None, - detail: None, - documentation: None, - lookup: None, - kind: kind.into(), - text_edit: None, - deprecated: false, - trigger_call_info: false, - relevance: CompletionRelevance::default(), - ref_match: None, - imports_to_add: Default::default(), - } - } - - /// What user sees in pop-up in the UI. - pub fn label(&self) -> &str { - &self.label - } - pub fn source_range(&self) -> TextRange { - self.source_range - } - - pub fn text_edit(&self) -> &TextEdit { - &self.text_edit - } - /// Whether `text_edit` is a snippet (contains `$0` markers). - pub fn is_snippet(&self) -> bool { - self.is_snippet - } - - /// Short one-line additional information, like a type - pub fn detail(&self) -> Option<&str> { - self.detail.as_deref() - } - /// A doc-comment - pub fn documentation(&self) -> Option { - self.documentation.clone() - } - /// What string is used for filtering. - pub fn lookup(&self) -> &str { - self.lookup.as_deref().unwrap_or(&self.label) - } - - pub fn kind(&self) -> CompletionItemKind { - self.kind - } - - pub fn deprecated(&self) -> bool { - self.deprecated - } - - pub fn relevance(&self) -> CompletionRelevance { - self.relevance - } - - pub fn trigger_call_info(&self) -> bool { - self.trigger_call_info - } - - pub fn ref_match(&self) -> Option<(Mutability, TextSize, CompletionRelevance)> { - // Relevance of the ref match should be the same as the original - // match, but with exact type match set because self.ref_match - // is only set if there is an exact type match. - let mut relevance = self.relevance; - relevance.type_match = Some(CompletionRelevanceTypeMatch::Exact); - - self.ref_match.map(|(mutability, offset)| (mutability, offset, relevance)) - } - - pub fn imports_to_add(&self) -> &[LocatedImport] { - &self.import_to_add - } -} - -/// A helper to make `CompletionItem`s. -#[must_use] -#[derive(Clone)] -pub(crate) struct Builder { - source_range: TextRange, - imports_to_add: SmallVec<[LocatedImport; 1]>, - trait_name: Option, - label: SmolStr, - insert_text: Option, - is_snippet: bool, - detail: Option, - documentation: Option, - lookup: Option, - kind: CompletionItemKind, - text_edit: Option, - deprecated: bool, - trigger_call_info: bool, - relevance: CompletionRelevance, - ref_match: Option<(Mutability, TextSize)>, -} - -impl Builder { - pub(crate) fn from_resolution( - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - local_name: hir::Name, - resolution: hir::ScopeDef, - ) -> Self { - render_path_resolution(RenderContext::new(ctx), path_ctx, local_name, resolution) - } - - pub(crate) fn build(self) -> CompletionItem { - let _p = profile::span("item::Builder::build"); - - let mut label = self.label; - let mut lookup = self.lookup; - let insert_text = self.insert_text.unwrap_or_else(|| label.to_string()); - - if let [import_edit] = &*self.imports_to_add { - // snippets can have multiple imports, but normal completions only have up to one - if let Some(original_path) = import_edit.original_path.as_ref() { - lookup = lookup.or_else(|| Some(label.clone())); - label = SmolStr::from(format!("{} (use {})", label, original_path)); - } - } else if let Some(trait_name) = self.trait_name { - label = SmolStr::from(format!("{} (as {})", label, trait_name)); - } - - let text_edit = match self.text_edit { - Some(it) => it, - None => TextEdit::replace(self.source_range, insert_text), - }; - - CompletionItem { - source_range: self.source_range, - label, - text_edit, - is_snippet: self.is_snippet, - detail: self.detail, - documentation: self.documentation, - lookup, - kind: self.kind, - deprecated: self.deprecated, - trigger_call_info: self.trigger_call_info, - relevance: self.relevance, - ref_match: self.ref_match, - import_to_add: self.imports_to_add, - } - } - pub(crate) fn lookup_by(&mut self, lookup: impl Into) -> &mut Builder { - self.lookup = Some(lookup.into()); - self - } - pub(crate) fn label(&mut self, label: impl Into) -> &mut Builder { - self.label = label.into(); - self - } - pub(crate) fn trait_name(&mut self, trait_name: SmolStr) -> &mut Builder { - self.trait_name = Some(trait_name); - self - } - pub(crate) fn insert_text(&mut self, insert_text: impl Into) -> &mut Builder { - self.insert_text = Some(insert_text.into()); - self - } - pub(crate) fn insert_snippet( - &mut self, - cap: SnippetCap, - snippet: impl Into, - ) -> &mut Builder { - let _ = cap; - self.is_snippet = true; - self.insert_text(snippet) - } - pub(crate) fn text_edit(&mut self, edit: TextEdit) -> &mut Builder { - self.text_edit = Some(edit); - self - } - pub(crate) fn snippet_edit(&mut self, _cap: SnippetCap, edit: TextEdit) -> &mut Builder { - self.is_snippet = true; - self.text_edit(edit) - } - pub(crate) fn detail(&mut self, detail: impl Into) -> &mut Builder { - self.set_detail(Some(detail)) - } - pub(crate) fn set_detail(&mut self, detail: Option>) -> &mut Builder { - self.detail = detail.map(Into::into); - if let Some(detail) = &self.detail { - if never!(detail.contains('\n'), "multiline detail:\n{}", detail) { - self.detail = Some(detail.splitn(2, '\n').next().unwrap().to_string()); - } - } - self - } - #[allow(unused)] - pub(crate) fn documentation(&mut self, docs: Documentation) -> &mut Builder { - self.set_documentation(Some(docs)) - } - pub(crate) fn set_documentation(&mut self, docs: Option) -> &mut Builder { - self.documentation = docs.map(Into::into); - self - } - pub(crate) fn set_deprecated(&mut self, deprecated: bool) -> &mut Builder { - self.deprecated = deprecated; - self - } - pub(crate) fn set_relevance(&mut self, relevance: CompletionRelevance) -> &mut Builder { - self.relevance = relevance; - self - } - pub(crate) fn trigger_call_info(&mut self) -> &mut Builder { - self.trigger_call_info = true; - self - } - pub(crate) fn add_import(&mut self, import_to_add: LocatedImport) -> &mut Builder { - self.imports_to_add.push(import_to_add); - self - } - pub(crate) fn ref_match(&mut self, mutability: Mutability, offset: TextSize) -> &mut Builder { - self.ref_match = Some((mutability, offset)); - self - } -} - -#[cfg(test)] -mod tests { - use itertools::Itertools; - use test_utils::assert_eq_text; - - use super::{ - CompletionRelevance, CompletionRelevancePostfixMatch, CompletionRelevanceTypeMatch, - }; - - /// Check that these are CompletionRelevance are sorted in ascending order - /// by their relevance score. - /// - /// We want to avoid making assertions about the absolute score of any - /// item, but we do want to assert whether each is >, <, or == to the - /// others. - /// - /// If provided vec![vec![a], vec![b, c], vec![d]], then this will assert: - /// a.score < b.score == c.score < d.score - fn check_relevance_score_ordered(expected_relevance_order: Vec>) { - let expected = format!("{:#?}", &expected_relevance_order); - - let actual_relevance_order = expected_relevance_order - .into_iter() - .flatten() - .map(|r| (r.score(), r)) - .sorted_by_key(|(score, _r)| *score) - .fold( - (u32::MIN, vec![vec![]]), - |(mut currently_collecting_score, mut out), (score, r)| { - if currently_collecting_score == score { - out.last_mut().unwrap().push(r); - } else { - currently_collecting_score = score; - out.push(vec![r]); - } - (currently_collecting_score, out) - }, - ) - .1; - - let actual = format!("{:#?}", &actual_relevance_order); - - assert_eq_text!(&expected, &actual); - } - - #[test] - fn relevance_score() { - use CompletionRelevance as Cr; - let default = Cr::default(); - // This test asserts that the relevance score for these items is ascending, and - // that any items in the same vec have the same score. - let expected_relevance_order = vec![ - vec![], - vec![Cr { is_op_method: true, is_private_editable: true, ..default }], - vec![Cr { is_op_method: true, ..default }], - vec![Cr { postfix_match: Some(CompletionRelevancePostfixMatch::NonExact), ..default }], - vec![Cr { is_private_editable: true, ..default }], - vec![default], - vec![Cr { is_local: true, ..default }], - vec![Cr { type_match: Some(CompletionRelevanceTypeMatch::CouldUnify), ..default }], - vec![Cr { type_match: Some(CompletionRelevanceTypeMatch::Exact), ..default }], - vec![Cr { exact_name_match: true, ..default }], - vec![Cr { exact_name_match: true, is_local: true, ..default }], - vec![Cr { - exact_name_match: true, - type_match: Some(CompletionRelevanceTypeMatch::Exact), - ..default - }], - vec![Cr { - exact_name_match: true, - type_match: Some(CompletionRelevanceTypeMatch::Exact), - is_local: true, - ..default - }], - vec![Cr { postfix_match: Some(CompletionRelevancePostfixMatch::Exact), ..default }], - ]; - - check_relevance_score_ordered(expected_relevance_order); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs deleted file mode 100644 index ae1a440d06da7..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ /dev/null @@ -1,247 +0,0 @@ -//! `completions` crate provides utilities for generating completions of user input. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -mod completions; -mod config; -mod context; -mod item; -mod render; - -#[cfg(test)] -mod tests; -mod snippet; - -use ide_db::{ - base_db::FilePosition, - helpers::mod_path_to_ast, - imports::{ - import_assets::NameToImport, - insert_use::{self, ImportScope}, - }, - items_locator, RootDatabase, -}; -use syntax::algo; -use text_edit::TextEdit; - -use crate::{ - completions::Completions, - context::{ - CompletionAnalysis, CompletionContext, NameRefContext, NameRefKind, PathCompletionCtx, - PathKind, - }, -}; - -pub use crate::{ - config::{CallableSnippets, CompletionConfig}, - item::{ - CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch, - }, - snippet::{Snippet, SnippetScope}, -}; - -//FIXME: split the following feature into fine-grained features. - -// Feature: Magic Completions -// -// In addition to usual reference completion, rust-analyzer provides some ✨magic✨ -// completions as well: -// -// Keywords like `if`, `else` `while`, `loop` are completed with braces, and cursor -// is placed at the appropriate position. Even though `if` is easy to type, you -// still want to complete it, to get ` { }` for free! `return` is inserted with a -// space or `;` depending on the return type of the function. -// -// When completing a function call, `()` are automatically inserted. If a function -// takes arguments, the cursor is positioned inside the parenthesis. -// -// There are postfix completions, which can be triggered by typing something like -// `foo().if`. The word after `.` determines postfix completion. Possible variants are: -// -// - `expr.if` -> `if expr {}` or `if let ... {}` for `Option` or `Result` -// - `expr.match` -> `match expr {}` -// - `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result` -// - `expr.ref` -> `&expr` -// - `expr.refm` -> `&mut expr` -// - `expr.let` -> `let $0 = expr;` -// - `expr.letm` -> `let mut $0 = expr;` -// - `expr.not` -> `!expr` -// - `expr.dbg` -> `dbg!(expr)` -// - `expr.dbgr` -> `dbg!(&expr)` -// - `expr.call` -> `(expr)` -// -// There also snippet completions: -// -// .Expressions -// - `pd` -> `eprintln!(" = {:?}", );` -// - `ppd` -> `eprintln!(" = {:#?}", );` -// -// .Items -// - `tfn` -> `#[test] fn feature(){}` -// - `tmod` -> -// ```rust -// #[cfg(test)] -// mod tests { -// use super::*; -// -// #[test] -// fn test_name() {} -// } -// ``` -// -// And the auto import completions, enabled with the `rust-analyzer.completion.autoimport.enable` setting and the corresponding LSP client capabilities. -// Those are the additional completion options with automatic `use` import and options from all project importable items, -// fuzzy matched against the completion input. -// -// image::https://user-images.githubusercontent.com/48062697/113020667-b72ab880-917a-11eb-8778-716cf26a0eb3.gif[] - -/// Main entry point for completion. We run completion as a two-phase process. -/// -/// First, we look at the position and collect a so-called `CompletionContext. -/// This is a somewhat messy process, because, during completion, syntax tree is -/// incomplete and can look really weird. -/// -/// Once the context is collected, we run a series of completion routines which -/// look at the context and produce completion items. One subtlety about this -/// phase is that completion engine should not filter by the substring which is -/// already present, it should give all possible variants for the identifier at -/// the caret. In other words, for -/// -/// ```no_run -/// fn f() { -/// let foo = 92; -/// let _ = bar$0 -/// } -/// ``` -/// -/// `foo` *should* be present among the completion variants. Filtering by -/// identifier prefix/fuzzy match should be done higher in the stack, together -/// with ordering of completions (currently this is done by the client). -/// -/// # Speculative Completion Problem -/// -/// There's a curious unsolved problem in the current implementation. Often, you -/// want to compute completions on a *slightly different* text document. -/// -/// In the simplest case, when the code looks like `let x = `, you want to -/// insert a fake identifier to get a better syntax tree: `let x = complete_me`. -/// -/// We do this in `CompletionContext`, and it works OK-enough for *syntax* -/// analysis. However, we might want to, eg, ask for the type of `complete_me` -/// variable, and that's where our current infrastructure breaks down. salsa -/// doesn't allow such "phantom" inputs. -/// -/// Another case where this would be instrumental is macro expansion. We want to -/// insert a fake ident and re-expand code. There's `expand_speculative` as a -/// work-around for this. -/// -/// A different use-case is completion of injection (examples and links in doc -/// comments). When computing completion for a path in a doc-comment, you want -/// to inject a fake path expression into the item being documented and complete -/// that. -/// -/// IntelliJ has CodeFragment/Context infrastructure for that. You can create a -/// temporary PSI node, and say that the context ("parent") of this node is some -/// existing node. Asking for, eg, type of this `CodeFragment` node works -/// correctly, as the underlying infrastructure makes use of contexts to do -/// analysis. -pub fn completions( - db: &RootDatabase, - config: &CompletionConfig, - position: FilePosition, - trigger_character: Option, -) -> Option> { - let (ctx, analysis) = &CompletionContext::new(db, position, config)?; - let mut completions = Completions::default(); - - // prevent `(` from triggering unwanted completion noise - if trigger_character == Some('(') { - if let CompletionAnalysis::NameRef(NameRefContext { kind, .. }) = &analysis { - if let NameRefKind::Path( - path_ctx @ PathCompletionCtx { kind: PathKind::Vis { has_in_token }, .. }, - ) = kind - { - completions::vis::complete_vis_path(&mut completions, ctx, path_ctx, has_in_token); - } - } - // prevent `(` from triggering unwanted completion noise - return Some(completions.into()); - } - - { - let acc = &mut completions; - - match &analysis { - CompletionAnalysis::Name(name_ctx) => completions::complete_name(acc, ctx, name_ctx), - CompletionAnalysis::NameRef(name_ref_ctx) => { - completions::complete_name_ref(acc, ctx, name_ref_ctx) - } - CompletionAnalysis::Lifetime(lifetime_ctx) => { - completions::lifetime::complete_label(acc, ctx, lifetime_ctx); - completions::lifetime::complete_lifetime(acc, ctx, lifetime_ctx); - } - CompletionAnalysis::String { original, expanded: Some(expanded) } => { - completions::extern_abi::complete_extern_abi(acc, ctx, expanded); - completions::format_string::format_string(acc, ctx, original, expanded); - } - CompletionAnalysis::UnexpandedAttrTT { - colon_prefix, - fake_attribute_under_caret: Some(attr), - } => { - completions::attribute::complete_known_attribute_input( - acc, - ctx, - colon_prefix, - attr, - ); - } - CompletionAnalysis::UnexpandedAttrTT { .. } | CompletionAnalysis::String { .. } => (), - } - } - - Some(completions.into()) -} - -/// Resolves additional completion data at the position given. -/// This is used for import insertion done via completions like flyimport and custom user snippets. -pub fn resolve_completion_edits( - db: &RootDatabase, - config: &CompletionConfig, - FilePosition { file_id, offset }: FilePosition, - imports: impl IntoIterator, -) -> Option> { - let _p = profile::span("resolve_completion_edits"); - let sema = hir::Semantics::new(db); - - let original_file = sema.parse(file_id); - let original_token = - syntax::AstNode::syntax(&original_file).token_at_offset(offset).left_biased()?; - let position_for_import = &original_token.parent()?; - let scope = ImportScope::find_insert_use_container(position_for_import, &sema)?; - - let current_module = sema.scope(position_for_import)?.module(); - let current_crate = current_module.krate(); - let new_ast = scope.clone_for_update(); - let mut import_insert = TextEdit::builder(); - - imports.into_iter().for_each(|(full_import_path, imported_name)| { - let items_with_name = items_locator::items_with_name( - &sema, - current_crate, - NameToImport::exact_case_sensitive(imported_name), - items_locator::AssocItemSearch::Include, - Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()), - ); - let import = items_with_name - .filter_map(|candidate| { - current_module.find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind) - }) - .find(|mod_path| mod_path.to_string() == full_import_path); - if let Some(import_path) = import { - insert_use::insert_use(&new_ast, mod_path_to_ast(&import_path), &config.insert_use); - } - }); - - algo::diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert); - Some(vec![import_insert.finish()]) -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs deleted file mode 100644 index 9b25964a6086e..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ /dev/null @@ -1,1913 +0,0 @@ -//! `render` module provides utilities for rendering completion suggestions -//! into code pieces that will be presented to user. - -pub(crate) mod macro_; -pub(crate) mod function; -pub(crate) mod const_; -pub(crate) mod pattern; -pub(crate) mod type_alias; -pub(crate) mod variant; -pub(crate) mod union_literal; -pub(crate) mod literal; - -use hir::{AsAssocItem, HasAttrs, HirDisplay, ScopeDef}; -use ide_db::{ - helpers::item_name, imports::import_assets::LocatedImport, RootDatabase, SnippetCap, SymbolKind, -}; -use syntax::{AstNode, SmolStr, SyntaxKind, TextRange}; - -use crate::{ - context::{DotAccess, PathCompletionCtx, PathKind, PatternContext}, - item::{Builder, CompletionRelevanceTypeMatch}, - render::{ - function::render_fn, - literal::render_variant_lit, - macro_::{render_macro, render_macro_pat}, - }, - CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance, -}; -/// Interface for data and methods required for items rendering. -#[derive(Debug, Clone)] -pub(crate) struct RenderContext<'a> { - completion: &'a CompletionContext<'a>, - is_private_editable: bool, - import_to_add: Option, -} - -impl<'a> RenderContext<'a> { - pub(crate) fn new(completion: &'a CompletionContext<'a>) -> RenderContext<'a> { - RenderContext { completion, is_private_editable: false, import_to_add: None } - } - - pub(crate) fn private_editable(mut self, private_editable: bool) -> Self { - self.is_private_editable = private_editable; - self - } - - pub(crate) fn import_to_add(mut self, import_to_add: Option) -> Self { - self.import_to_add = import_to_add; - self - } - - fn snippet_cap(&self) -> Option { - self.completion.config.snippet_cap - } - - fn db(&self) -> &'a RootDatabase { - self.completion.db - } - - fn source_range(&self) -> TextRange { - self.completion.source_range() - } - - fn completion_relevance(&self) -> CompletionRelevance { - CompletionRelevance { - is_private_editable: self.is_private_editable, - requires_import: self.import_to_add.is_some(), - ..Default::default() - } - } - - fn is_immediately_after_macro_bang(&self) -> bool { - self.completion.token.kind() == SyntaxKind::BANG - && self - .completion - .token - .parent() - .map_or(false, |it| it.kind() == SyntaxKind::MACRO_CALL) - } - - fn is_deprecated(&self, def: impl HasAttrs) -> bool { - let attrs = def.attrs(self.db()); - attrs.by_key("deprecated").exists() - } - - fn is_deprecated_assoc_item(&self, as_assoc_item: impl AsAssocItem) -> bool { - let db = self.db(); - let assoc = match as_assoc_item.as_assoc_item(db) { - Some(assoc) => assoc, - None => return false, - }; - - let is_assoc_deprecated = match assoc { - hir::AssocItem::Function(it) => self.is_deprecated(it), - hir::AssocItem::Const(it) => self.is_deprecated(it), - hir::AssocItem::TypeAlias(it) => self.is_deprecated(it), - }; - is_assoc_deprecated - || assoc - .containing_trait_or_trait_impl(db) - .map(|trait_| self.is_deprecated(trait_)) - .unwrap_or(false) - } - - // FIXME: remove this - fn docs(&self, def: impl HasAttrs) -> Option { - def.docs(self.db()) - } -} - -pub(crate) fn render_field( - ctx: RenderContext<'_>, - dot_access: &DotAccess, - receiver: Option, - field: hir::Field, - ty: &hir::Type, -) -> CompletionItem { - let is_deprecated = ctx.is_deprecated(field); - let name = field.name(ctx.db()); - let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str()); - let mut item = CompletionItem::new( - SymbolKind::Field, - ctx.source_range(), - field_with_receiver(receiver.as_ref(), &name), - ); - item.set_relevance(CompletionRelevance { - type_match: compute_type_match(ctx.completion, ty), - exact_name_match: compute_exact_name_match(ctx.completion, name.as_str()), - ..CompletionRelevance::default() - }); - item.detail(ty.display(ctx.db()).to_string()) - .set_documentation(field.docs(ctx.db())) - .set_deprecated(is_deprecated) - .lookup_by(name.clone()); - item.insert_text(field_with_receiver(receiver.as_ref(), &escaped_name)); - if let Some(receiver) = &dot_access.receiver { - if let Some(original) = ctx.completion.sema.original_ast_node(receiver.clone()) { - if let Some(ref_match) = compute_ref_match(ctx.completion, ty) { - item.ref_match(ref_match, original.syntax().text_range().start()); - } - } - } - item.build() -} - -fn field_with_receiver(receiver: Option<&hir::Name>, field_name: &str) -> SmolStr { - receiver - .map_or_else(|| field_name.into(), |receiver| format!("{}.{}", receiver, field_name).into()) -} - -pub(crate) fn render_tuple_field( - ctx: RenderContext<'_>, - receiver: Option, - field: usize, - ty: &hir::Type, -) -> CompletionItem { - let mut item = CompletionItem::new( - SymbolKind::Field, - ctx.source_range(), - field_with_receiver(receiver.as_ref(), &field.to_string()), - ); - item.detail(ty.display(ctx.db()).to_string()).lookup_by(field.to_string()); - item.build() -} - -pub(crate) fn render_type_inference( - ty_string: String, - ctx: &CompletionContext<'_>, -) -> CompletionItem { - let mut builder = - CompletionItem::new(CompletionItemKind::InferredType, ctx.source_range(), ty_string); - builder.set_relevance(CompletionRelevance { is_definite: true, ..Default::default() }); - builder.build() -} - -pub(crate) fn render_path_resolution( - ctx: RenderContext<'_>, - path_ctx: &PathCompletionCtx, - local_name: hir::Name, - resolution: ScopeDef, -) -> Builder { - render_resolution_path(ctx, path_ctx, local_name, None, resolution) -} - -pub(crate) fn render_pattern_resolution( - ctx: RenderContext<'_>, - pattern_ctx: &PatternContext, - local_name: hir::Name, - resolution: ScopeDef, -) -> Builder { - render_resolution_pat(ctx, pattern_ctx, local_name, None, resolution) -} - -pub(crate) fn render_resolution_with_import( - ctx: RenderContext<'_>, - path_ctx: &PathCompletionCtx, - import_edit: LocatedImport, -) -> Option { - let resolution = ScopeDef::from(import_edit.original_item); - let local_name = scope_def_to_name(resolution, &ctx, &import_edit)?; - - Some(render_resolution_path(ctx, path_ctx, local_name, Some(import_edit), resolution)) -} - -pub(crate) fn render_resolution_with_import_pat( - ctx: RenderContext<'_>, - pattern_ctx: &PatternContext, - import_edit: LocatedImport, -) -> Option { - let resolution = ScopeDef::from(import_edit.original_item); - let local_name = scope_def_to_name(resolution, &ctx, &import_edit)?; - Some(render_resolution_pat(ctx, pattern_ctx, local_name, Some(import_edit), resolution)) -} - -fn scope_def_to_name( - resolution: ScopeDef, - ctx: &RenderContext<'_>, - import_edit: &LocatedImport, -) -> Option { - Some(match resolution { - ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db), - ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?, - ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db), - _ => item_name(ctx.db(), import_edit.original_item)?, - }) -} - -fn render_resolution_pat( - ctx: RenderContext<'_>, - pattern_ctx: &PatternContext, - local_name: hir::Name, - import_to_add: Option, - resolution: ScopeDef, -) -> Builder { - let _p = profile::span("render_resolution"); - use hir::ModuleDef::*; - - match resolution { - ScopeDef::ModuleDef(Macro(mac)) => { - let ctx = ctx.import_to_add(import_to_add); - return render_macro_pat(ctx, pattern_ctx, local_name, mac); - } - _ => (), - } - - render_resolution_simple_(ctx, &local_name, import_to_add, resolution) -} - -fn render_resolution_path( - ctx: RenderContext<'_>, - path_ctx: &PathCompletionCtx, - local_name: hir::Name, - import_to_add: Option, - resolution: ScopeDef, -) -> Builder { - let _p = profile::span("render_resolution"); - use hir::ModuleDef::*; - - match resolution { - ScopeDef::ModuleDef(Macro(mac)) => { - let ctx = ctx.import_to_add(import_to_add); - return render_macro(ctx, path_ctx, local_name, mac); - } - ScopeDef::ModuleDef(Function(func)) => { - let ctx = ctx.import_to_add(import_to_add); - return render_fn(ctx, path_ctx, Some(local_name), func); - } - ScopeDef::ModuleDef(Variant(var)) => { - let ctx = ctx.clone().import_to_add(import_to_add.clone()); - if let Some(item) = - render_variant_lit(ctx, path_ctx, Some(local_name.clone()), var, None) - { - return item; - } - } - _ => (), - } - - let completion = ctx.completion; - let cap = ctx.snippet_cap(); - let db = completion.db; - let config = completion.config; - - let name = local_name.to_smol_str(); - let mut item = render_resolution_simple_(ctx, &local_name, import_to_add, resolution); - if local_name.escaped().is_escaped() { - item.insert_text(local_name.escaped().to_smol_str()); - } - // Add `<>` for generic types - let type_path_no_ty_args = matches!( - path_ctx, - PathCompletionCtx { kind: PathKind::Type { .. }, has_type_args: false, .. } - ) && config.callable.is_some(); - if type_path_no_ty_args { - if let Some(cap) = cap { - let has_non_default_type_params = match resolution { - ScopeDef::ModuleDef(hir::ModuleDef::Adt(it)) => it.has_non_default_type_params(db), - ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(it)) => { - it.has_non_default_type_params(db) - } - _ => false, - }; - - if has_non_default_type_params { - cov_mark::hit!(inserts_angle_brackets_for_generics); - item.lookup_by(name.clone()) - .label(SmolStr::from_iter([&name, "<…>"])) - .trigger_call_info() - .insert_snippet(cap, format!("{}<$0>", local_name.escaped())); - } - } - } - if let ScopeDef::Local(local) = resolution { - let ty = local.ty(db); - if !ty.is_unknown() { - item.detail(ty.display(db).to_string()); - } - - item.set_relevance(CompletionRelevance { - type_match: compute_type_match(completion, &ty), - exact_name_match: compute_exact_name_match(completion, &name), - is_local: true, - ..CompletionRelevance::default() - }); - - if let Some(ref_match) = compute_ref_match(completion, &ty) { - item.ref_match(ref_match, path_ctx.path.syntax().text_range().start()); - } - }; - item -} - -fn render_resolution_simple_( - ctx: RenderContext<'_>, - local_name: &hir::Name, - import_to_add: Option, - resolution: ScopeDef, -) -> Builder { - let _p = profile::span("render_resolution"); - - let db = ctx.db(); - let ctx = ctx.import_to_add(import_to_add); - let kind = res_to_kind(resolution); - - let mut item = CompletionItem::new(kind, ctx.source_range(), local_name.to_smol_str()); - item.set_relevance(ctx.completion_relevance()) - .set_documentation(scope_def_docs(db, resolution)) - .set_deprecated(scope_def_is_deprecated(&ctx, resolution)); - - if let Some(import_to_add) = ctx.import_to_add { - item.add_import(import_to_add); - } - item -} - -fn res_to_kind(resolution: ScopeDef) -> CompletionItemKind { - use hir::ModuleDef::*; - match resolution { - ScopeDef::Unknown => CompletionItemKind::UnresolvedReference, - ScopeDef::ModuleDef(Function(_)) => CompletionItemKind::SymbolKind(SymbolKind::Function), - ScopeDef::ModuleDef(Variant(_)) => CompletionItemKind::SymbolKind(SymbolKind::Variant), - ScopeDef::ModuleDef(Macro(_)) => CompletionItemKind::SymbolKind(SymbolKind::Macro), - ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module), - ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt { - hir::Adt::Struct(_) => SymbolKind::Struct, - hir::Adt::Union(_) => SymbolKind::Union, - hir::Adt::Enum(_) => SymbolKind::Enum, - }), - ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const), - ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static), - ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait), - ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::SymbolKind(SymbolKind::TypeAlias), - ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, - ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param { - hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam, - hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam, - hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam, - }), - ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local), - ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label), - ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => { - CompletionItemKind::SymbolKind(SymbolKind::SelfParam) - } - } -} - -fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option { - use hir::ModuleDef::*; - match resolution { - ScopeDef::ModuleDef(Module(it)) => it.docs(db), - ScopeDef::ModuleDef(Adt(it)) => it.docs(db), - ScopeDef::ModuleDef(Variant(it)) => it.docs(db), - ScopeDef::ModuleDef(Const(it)) => it.docs(db), - ScopeDef::ModuleDef(Static(it)) => it.docs(db), - ScopeDef::ModuleDef(Trait(it)) => it.docs(db), - ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(db), - _ => None, - } -} - -fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: ScopeDef) -> bool { - match resolution { - ScopeDef::ModuleDef(it) => ctx.is_deprecated_assoc_item(it), - ScopeDef::GenericParam(it) => ctx.is_deprecated(it), - ScopeDef::AdtSelfType(it) => ctx.is_deprecated(it), - _ => false, - } -} - -fn compute_type_match( - ctx: &CompletionContext<'_>, - completion_ty: &hir::Type, -) -> Option { - let expected_type = ctx.expected_type.as_ref()?; - - // We don't ever consider unit type to be an exact type match, since - // nearly always this is not meaningful to the user. - if expected_type.is_unit() { - return None; - } - - if completion_ty == expected_type { - Some(CompletionRelevanceTypeMatch::Exact) - } else if expected_type.could_unify_with(ctx.db, completion_ty) { - Some(CompletionRelevanceTypeMatch::CouldUnify) - } else { - None - } -} - -fn compute_exact_name_match(ctx: &CompletionContext<'_>, completion_name: &str) -> bool { - ctx.expected_name.as_ref().map_or(false, |name| name.text() == completion_name) -} - -fn compute_ref_match( - ctx: &CompletionContext<'_>, - completion_ty: &hir::Type, -) -> Option { - let expected_type = ctx.expected_type.as_ref()?; - if completion_ty != expected_type { - let expected_type_without_ref = expected_type.remove_ref()?; - if completion_ty.autoderef(ctx.db).any(|deref_ty| deref_ty == expected_type_without_ref) { - cov_mark::hit!(suggest_ref); - let mutability = if expected_type.is_mutable_reference() { - hir::Mutability::Mut - } else { - hir::Mutability::Shared - }; - return Some(mutability); - }; - } - None -} - -#[cfg(test)] -mod tests { - use std::cmp; - - use expect_test::{expect, Expect}; - use ide_db::SymbolKind; - use itertools::Itertools; - - use crate::{ - item::CompletionRelevanceTypeMatch, - tests::{check_edit, do_completion, get_all_items, TEST_CONFIG}, - CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch, - }; - - #[track_caller] - fn check(ra_fixture: &str, kind: impl Into, expect: Expect) { - let actual = do_completion(ra_fixture, kind.into()); - expect.assert_debug_eq(&actual); - } - - #[track_caller] - fn check_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) { - let actual: Vec<_> = - kinds.iter().flat_map(|&kind| do_completion(ra_fixture, kind)).collect(); - expect.assert_debug_eq(&actual); - } - - #[track_caller] - fn check_relevance_for_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) { - let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None); - actual.retain(|it| kinds.contains(&it.kind())); - actual.sort_by_key(|it| cmp::Reverse(it.relevance().score())); - check_relevance_(actual, expect); - } - - #[track_caller] - fn check_relevance(ra_fixture: &str, expect: Expect) { - let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None); - actual.retain(|it| it.kind() != CompletionItemKind::Snippet); - actual.retain(|it| it.kind() != CompletionItemKind::Keyword); - actual.retain(|it| it.kind() != CompletionItemKind::BuiltinType); - actual.sort_by_key(|it| cmp::Reverse(it.relevance().score())); - check_relevance_(actual, expect); - } - - #[track_caller] - fn check_relevance_(actual: Vec, expect: Expect) { - let actual = actual - .into_iter() - .flat_map(|it| { - let mut items = vec![]; - - let tag = it.kind().tag(); - let relevance = display_relevance(it.relevance()); - items.push(format!("{} {} {}\n", tag, it.label(), relevance)); - - if let Some((mutability, _offset, relevance)) = it.ref_match() { - let label = format!("&{}{}", mutability.as_keyword_for_ref(), it.label()); - let relevance = display_relevance(relevance); - - items.push(format!("{} {} {}\n", tag, label, relevance)); - } - - items - }) - .collect::(); - - expect.assert_eq(&actual); - - fn display_relevance(relevance: CompletionRelevance) -> String { - let relevance_factors = vec![ - (relevance.type_match == Some(CompletionRelevanceTypeMatch::Exact), "type"), - ( - relevance.type_match == Some(CompletionRelevanceTypeMatch::CouldUnify), - "type_could_unify", - ), - (relevance.exact_name_match, "name"), - (relevance.is_local, "local"), - ( - relevance.postfix_match == Some(CompletionRelevancePostfixMatch::Exact), - "snippet", - ), - (relevance.is_op_method, "op_method"), - (relevance.requires_import, "requires_import"), - ] - .into_iter() - .filter_map(|(cond, desc)| if cond { Some(desc) } else { None }) - .join("+"); - - format!("[{}]", relevance_factors) - } - } - - #[test] - fn enum_detail_includes_record_fields() { - check( - r#" -enum Foo { Foo { x: i32, y: i32 } } - -fn main() { Foo::Fo$0 } -"#, - SymbolKind::Variant, - expect![[r#" - [ - CompletionItem { - label: "Foo {…}", - source_range: 54..56, - delete: 54..56, - insert: "Foo { x: ${1:()}, y: ${2:()} }$0", - kind: SymbolKind( - Variant, - ), - detail: "Foo { x: i32, y: i32 }", - }, - ] - "#]], - ); - } - - #[test] - fn enum_detail_includes_tuple_fields() { - check( - r#" -enum Foo { Foo (i32, i32) } - -fn main() { Foo::Fo$0 } -"#, - SymbolKind::Variant, - expect![[r#" - [ - CompletionItem { - label: "Foo(…)", - source_range: 46..48, - delete: 46..48, - insert: "Foo(${1:()}, ${2:()})$0", - kind: SymbolKind( - Variant, - ), - detail: "Foo(i32, i32)", - }, - ] - "#]], - ); - } - - #[test] - fn fn_detail_includes_args_and_return_type() { - check( - r#" -fn foo(a: u32, b: u32, t: T) -> (u32, T) { (a, t) } - -fn main() { fo$0 } -"#, - SymbolKind::Function, - expect![[r#" - [ - CompletionItem { - label: "foo(…)", - source_range: 68..70, - delete: 68..70, - insert: "foo(${1:a}, ${2:b}, ${3:t})$0", - kind: SymbolKind( - Function, - ), - lookup: "foo", - detail: "fn(u32, u32, T) -> (u32, T)", - trigger_call_info: true, - }, - CompletionItem { - label: "main()", - source_range: 68..70, - delete: 68..70, - insert: "main()$0", - kind: SymbolKind( - Function, - ), - lookup: "main", - detail: "fn()", - }, - ] - "#]], - ); - } - - #[test] - fn enum_detail_just_name_for_unit() { - check( - r#" -enum Foo { Foo } - -fn main() { Foo::Fo$0 } -"#, - SymbolKind::Variant, - expect![[r#" - [ - CompletionItem { - label: "Foo", - source_range: 35..37, - delete: 35..37, - insert: "Foo$0", - kind: SymbolKind( - Variant, - ), - detail: "Foo", - }, - ] - "#]], - ); - } - - #[test] - fn lookup_enums_by_two_qualifiers() { - check_kinds( - r#" -mod m { - pub enum Spam { Foo, Bar(i32) } -} -fn main() { let _: m::Spam = S$0 } -"#, - &[ - CompletionItemKind::SymbolKind(SymbolKind::Function), - CompletionItemKind::SymbolKind(SymbolKind::Module), - CompletionItemKind::SymbolKind(SymbolKind::Variant), - ], - expect![[r#" - [ - CompletionItem { - label: "main()", - source_range: 75..76, - delete: 75..76, - insert: "main()$0", - kind: SymbolKind( - Function, - ), - lookup: "main", - detail: "fn()", - }, - CompletionItem { - label: "m", - source_range: 75..76, - delete: 75..76, - insert: "m", - kind: SymbolKind( - Module, - ), - }, - CompletionItem { - label: "m::Spam::Bar(…)", - source_range: 75..76, - delete: 75..76, - insert: "m::Spam::Bar(${1:()})$0", - kind: SymbolKind( - Variant, - ), - lookup: "Spam::Bar(…)", - detail: "m::Spam::Bar(i32)", - relevance: CompletionRelevance { - exact_name_match: false, - type_match: Some( - Exact, - ), - is_local: false, - is_item_from_trait: false, - is_name_already_imported: false, - requires_import: false, - is_op_method: false, - is_private_editable: false, - postfix_match: None, - is_definite: false, - }, - }, - CompletionItem { - label: "m::Spam::Foo", - source_range: 75..76, - delete: 75..76, - insert: "m::Spam::Foo$0", - kind: SymbolKind( - Variant, - ), - lookup: "Spam::Foo", - detail: "m::Spam::Foo", - relevance: CompletionRelevance { - exact_name_match: false, - type_match: Some( - Exact, - ), - is_local: false, - is_item_from_trait: false, - is_name_already_imported: false, - requires_import: false, - is_op_method: false, - is_private_editable: false, - postfix_match: None, - is_definite: false, - }, - }, - ] - "#]], - ) - } - - #[test] - fn sets_deprecated_flag_in_items() { - check( - r#" -#[deprecated] -fn something_deprecated() {} - -fn main() { som$0 } -"#, - SymbolKind::Function, - expect![[r#" - [ - CompletionItem { - label: "main()", - source_range: 56..59, - delete: 56..59, - insert: "main()$0", - kind: SymbolKind( - Function, - ), - lookup: "main", - detail: "fn()", - }, - CompletionItem { - label: "something_deprecated()", - source_range: 56..59, - delete: 56..59, - insert: "something_deprecated()$0", - kind: SymbolKind( - Function, - ), - lookup: "something_deprecated", - detail: "fn()", - deprecated: true, - }, - ] - "#]], - ); - - check( - r#" -struct A { #[deprecated] the_field: u32 } -fn foo() { A { the$0 } } -"#, - SymbolKind::Field, - expect![[r#" - [ - CompletionItem { - label: "the_field", - source_range: 57..60, - delete: 57..60, - insert: "the_field", - kind: SymbolKind( - Field, - ), - detail: "u32", - deprecated: true, - relevance: CompletionRelevance { - exact_name_match: false, - type_match: Some( - CouldUnify, - ), - is_local: false, - is_item_from_trait: false, - is_name_already_imported: false, - requires_import: false, - is_op_method: false, - is_private_editable: false, - postfix_match: None, - is_definite: false, - }, - }, - ] - "#]], - ); - } - - #[test] - fn renders_docs() { - check_kinds( - r#" -struct S { - /// Field docs - foo: -} -impl S { - /// Method docs - fn bar(self) { self.$0 } -}"#, - &[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)], - expect![[r#" - [ - CompletionItem { - label: "bar()", - source_range: 94..94, - delete: 94..94, - insert: "bar()$0", - kind: Method, - lookup: "bar", - detail: "fn(self)", - documentation: Documentation( - "Method docs", - ), - }, - CompletionItem { - label: "foo", - source_range: 94..94, - delete: 94..94, - insert: "foo", - kind: SymbolKind( - Field, - ), - detail: "{unknown}", - documentation: Documentation( - "Field docs", - ), - }, - ] - "#]], - ); - - check_kinds( - r#" -use self::my$0; - -/// mod docs -mod my { } - -/// enum docs -enum E { - /// variant docs - V -} -use self::E::*; -"#, - &[ - CompletionItemKind::SymbolKind(SymbolKind::Module), - CompletionItemKind::SymbolKind(SymbolKind::Variant), - CompletionItemKind::SymbolKind(SymbolKind::Enum), - ], - expect![[r#" - [ - CompletionItem { - label: "my", - source_range: 10..12, - delete: 10..12, - insert: "my", - kind: SymbolKind( - Module, - ), - documentation: Documentation( - "mod docs", - ), - }, - CompletionItem { - label: "V", - source_range: 10..12, - delete: 10..12, - insert: "V$0", - kind: SymbolKind( - Variant, - ), - detail: "V", - documentation: Documentation( - "variant docs", - ), - }, - CompletionItem { - label: "E", - source_range: 10..12, - delete: 10..12, - insert: "E", - kind: SymbolKind( - Enum, - ), - documentation: Documentation( - "enum docs", - ), - }, - ] - "#]], - ) - } - - #[test] - fn dont_render_attrs() { - check( - r#" -struct S; -impl S { - #[inline] - fn the_method(&self) { } -} -fn foo(s: S) { s.$0 } -"#, - CompletionItemKind::Method, - expect![[r#" - [ - CompletionItem { - label: "the_method()", - source_range: 81..81, - delete: 81..81, - insert: "the_method()$0", - kind: Method, - lookup: "the_method", - detail: "fn(&self)", - }, - ] - "#]], - ) - } - - #[test] - fn no_call_parens_if_fn_ptr_needed() { - cov_mark::check!(no_call_parens_if_fn_ptr_needed); - check_edit( - "foo", - r#" -fn foo(foo: u8, bar: u8) {} -struct ManualVtable { f: fn(u8, u8) } - -fn main() -> ManualVtable { - ManualVtable { f: f$0 } -} -"#, - r#" -fn foo(foo: u8, bar: u8) {} -struct ManualVtable { f: fn(u8, u8) } - -fn main() -> ManualVtable { - ManualVtable { f: foo } -} -"#, - ); - check_edit( - "type", - r#" -struct RawIdentTable { r#type: u32 } - -fn main() -> RawIdentTable { - RawIdentTable { t$0: 42 } -} -"#, - r#" -struct RawIdentTable { r#type: u32 } - -fn main() -> RawIdentTable { - RawIdentTable { r#type: 42 } -} -"#, - ); - } - - #[test] - fn no_parens_in_use_item() { - check_edit( - "foo", - r#" -mod m { pub fn foo() {} } -use crate::m::f$0; -"#, - r#" -mod m { pub fn foo() {} } -use crate::m::foo; -"#, - ); - } - - #[test] - fn no_parens_in_call() { - check_edit( - "foo", - r#" -fn foo(x: i32) {} -fn main() { f$0(); } -"#, - r#" -fn foo(x: i32) {} -fn main() { foo(); } -"#, - ); - check_edit( - "foo", - r#" -struct Foo; -impl Foo { fn foo(&self){} } -fn f(foo: &Foo) { foo.f$0(); } -"#, - r#" -struct Foo; -impl Foo { fn foo(&self){} } -fn f(foo: &Foo) { foo.foo(); } -"#, - ); - } - - #[test] - fn inserts_angle_brackets_for_generics() { - cov_mark::check!(inserts_angle_brackets_for_generics); - check_edit( - "Vec", - r#" -struct Vec {} -fn foo(xs: Ve$0) -"#, - r#" -struct Vec {} -fn foo(xs: Vec<$0>) -"#, - ); - check_edit( - "Vec", - r#" -type Vec = (T,); -fn foo(xs: Ve$0) -"#, - r#" -type Vec = (T,); -fn foo(xs: Vec<$0>) -"#, - ); - check_edit( - "Vec", - r#" -struct Vec {} -fn foo(xs: Ve$0) -"#, - r#" -struct Vec {} -fn foo(xs: Vec) -"#, - ); - check_edit( - "Vec", - r#" -struct Vec {} -fn foo(xs: Ve$0) -"#, - r#" -struct Vec {} -fn foo(xs: Vec) -"#, - ); - } - - #[test] - fn active_param_relevance() { - check_relevance( - r#" -struct S { foo: i64, bar: u32, baz: u32 } -fn test(bar: u32) { } -fn foo(s: S) { test(s.$0) } -"#, - expect![[r#" - fd bar [type+name] - fd baz [type] - fd foo [] - "#]], - ); - } - - #[test] - fn record_field_relevances() { - check_relevance( - r#" -struct A { foo: i64, bar: u32, baz: u32 } -struct B { x: (), y: f32, bar: u32 } -fn foo(a: A) { B { bar: a.$0 }; } -"#, - expect![[r#" - fd bar [type+name] - fd baz [type] - fd foo [] - "#]], - ) - } - - #[test] - fn record_field_and_call_relevances() { - check_relevance( - r#" -struct A { foo: i64, bar: u32, baz: u32 } -struct B { x: (), y: f32, bar: u32 } -fn f(foo: i64) { } -fn foo(a: A) { B { bar: f(a.$0) }; } -"#, - expect![[r#" - fd foo [type+name] - fd bar [] - fd baz [] - "#]], - ); - check_relevance( - r#" -struct A { foo: i64, bar: u32, baz: u32 } -struct B { x: (), y: f32, bar: u32 } -fn f(foo: i64) { } -fn foo(a: A) { f(B { bar: a.$0 }); } -"#, - expect![[r#" - fd bar [type+name] - fd baz [type] - fd foo [] - "#]], - ); - } - - #[test] - fn prioritize_exact_ref_match() { - check_relevance( - r#" -struct WorldSnapshot { _f: () }; -fn go(world: &WorldSnapshot) { go(w$0) } -"#, - expect![[r#" - lc world [type+name+local] - st WorldSnapshot {…} [] - st &WorldSnapshot {…} [type] - st WorldSnapshot [] - fn go(…) [] - "#]], - ); - } - - #[test] - fn too_many_arguments() { - cov_mark::check!(too_many_arguments); - check_relevance( - r#" -struct Foo; -fn f(foo: &Foo) { f(foo, w$0) } -"#, - expect![[r#" - lc foo [local] - st Foo [] - fn f(…) [] - "#]], - ); - } - - #[test] - fn score_fn_type_and_name_match() { - check_relevance( - r#" -struct A { bar: u8 } -fn baz() -> u8 { 0 } -fn bar() -> u8 { 0 } -fn f() { A { bar: b$0 }; } -"#, - expect![[r#" - fn bar() [type+name] - fn baz() [type] - st A [] - fn f() [] - "#]], - ); - } - - #[test] - fn score_method_type_and_name_match() { - check_relevance( - r#" -fn baz(aaa: u32){} -struct Foo; -impl Foo { -fn aaa(&self) -> u32 { 0 } -fn bbb(&self) -> u32 { 0 } -fn ccc(&self) -> u64 { 0 } -} -fn f() { - baz(Foo.$0 -} -"#, - expect![[r#" - me aaa() [type+name] - me bbb() [type] - me ccc() [] - "#]], - ); - } - - #[test] - fn score_method_name_match_only() { - check_relevance( - r#" -fn baz(aaa: u32){} -struct Foo; -impl Foo { -fn aaa(&self) -> u64 { 0 } -} -fn f() { - baz(Foo.$0 -} -"#, - expect![[r#" - me aaa() [name] - "#]], - ); - } - - #[test] - fn suggest_ref_mut() { - cov_mark::check!(suggest_ref); - check_relevance( - r#" -struct S; -fn foo(s: &mut S) {} -fn main() { - let mut s = S; - foo($0); -} - "#, - expect![[r#" - lc s [name+local] - lc &mut s [type+name+local] - st S [] - st &mut S [type] - st S [] - fn main() [] - fn foo(…) [] - "#]], - ); - check_relevance( - r#" -struct S; -fn foo(s: &mut S) {} -fn main() { - let mut s = S; - foo(&mut $0); -} - "#, - expect![[r#" - lc s [type+name+local] - st S [type] - st S [] - fn main() [] - fn foo(…) [] - "#]], - ); - check_relevance( - r#" -struct S; -fn foo(s: &mut S) {} -fn main() { - let mut ssss = S; - foo(&mut s$0); -} - "#, - expect![[r#" - lc ssss [type+local] - st S [type] - st S [] - fn main() [] - fn foo(…) [] - "#]], - ); - } - - #[test] - fn suggest_deref() { - check_relevance( - r#" -//- minicore: deref -struct S; -struct T(S); - -impl core::ops::Deref for T { - type Target = S; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -fn foo(s: &S) {} - -fn main() { - let t = T(S); - let m = 123; - - foo($0); -} - "#, - expect![[r#" - lc m [local] - lc t [local] - lc &t [type+local] - st S [] - st &S [type] - st T [] - st S [] - fn main() [] - fn foo(…) [] - md core [] - tt Sized [] - "#]], - ) - } - - #[test] - fn suggest_deref_mut() { - check_relevance( - r#" -//- minicore: deref_mut -struct S; -struct T(S); - -impl core::ops::Deref for T { - type Target = S; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl core::ops::DerefMut for T { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -fn foo(s: &mut S) {} - -fn main() { - let t = T(S); - let m = 123; - - foo($0); -} - "#, - expect![[r#" - lc m [local] - lc t [local] - lc &mut t [type+local] - st S [] - st &mut S [type] - st T [] - st S [] - fn main() [] - fn foo(…) [] - md core [] - tt Sized [] - "#]], - ) - } - - #[test] - fn locals() { - check_relevance( - r#" -fn foo(bar: u32) { - let baz = 0; - - f$0 -} -"#, - expect![[r#" - lc baz [local] - lc bar [local] - fn foo(…) [] - "#]], - ); - } - - #[test] - fn enum_owned() { - check_relevance( - r#" -enum Foo { A, B } -fn foo() { - bar($0); -} -fn bar(t: Foo) {} -"#, - expect![[r#" - ev Foo::A [type] - ev Foo::B [type] - en Foo [] - fn bar(…) [] - fn foo() [] - "#]], - ); - } - - #[test] - fn enum_ref() { - check_relevance( - r#" -enum Foo { A, B } -fn foo() { - bar($0); -} -fn bar(t: &Foo) {} -"#, - expect![[r#" - ev Foo::A [] - ev &Foo::A [type] - ev Foo::B [] - ev &Foo::B [type] - en Foo [] - fn bar(…) [] - fn foo() [] - "#]], - ); - } - - #[test] - fn suggest_deref_fn_ret() { - check_relevance( - r#" -//- minicore: deref -struct S; -struct T(S); - -impl core::ops::Deref for T { - type Target = S; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -fn foo(s: &S) {} -fn bar() -> T {} - -fn main() { - foo($0); -} -"#, - expect![[r#" - st S [] - st &S [type] - st T [] - st S [] - fn main() [] - fn bar() [] - fn &bar() [type] - fn foo(…) [] - md core [] - tt Sized [] - "#]], - ) - } - - #[test] - fn op_function_relevances() { - check_relevance( - r#" -#[lang = "sub"] -trait Sub { - fn sub(self, other: Self) -> Self { self } -} -impl Sub for u32 {} -fn foo(a: u32) { a.$0 } -"#, - expect![[r#" - me sub(…) (as Sub) [op_method] - "#]], - ); - check_relevance( - r#" -struct Foo; -impl Foo { - fn new() -> Self {} -} -#[lang = "eq"] -pub trait PartialEq { - fn eq(&self, other: &Rhs) -> bool; - fn ne(&self, other: &Rhs) -> bool; -} - -impl PartialEq for Foo {} -fn main() { - Foo::$0 -} -"#, - expect![[r#" - fn new() [] - me eq(…) (as PartialEq) [op_method] - me ne(…) (as PartialEq) [op_method] - "#]], - ); - } - - #[test] - fn struct_field_method_ref() { - check_kinds( - r#" -struct Foo { bar: u32 } -impl Foo { fn baz(&self) -> u32 { 0 } } - -fn foo(f: Foo) { let _: &u32 = f.b$0 } -"#, - &[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)], - expect![[r#" - [ - CompletionItem { - label: "baz()", - source_range: 98..99, - delete: 98..99, - insert: "baz()$0", - kind: Method, - lookup: "baz", - detail: "fn(&self) -> u32", - ref_match: "&@96", - }, - CompletionItem { - label: "bar", - source_range: 98..99, - delete: 98..99, - insert: "bar", - kind: SymbolKind( - Field, - ), - detail: "u32", - ref_match: "&@96", - }, - ] - "#]], - ); - } - - #[test] - fn qualified_path_ref() { - check_kinds( - r#" -struct S; - -struct T; -impl T { - fn foo() -> S {} -} - -fn bar(s: &S) {} - -fn main() { - bar(T::$0); -} -"#, - &[CompletionItemKind::SymbolKind(SymbolKind::Function)], - expect![[r#" - [ - CompletionItem { - label: "foo()", - source_range: 95..95, - delete: 95..95, - insert: "foo()$0", - kind: SymbolKind( - Function, - ), - lookup: "foo", - detail: "fn() -> S", - ref_match: "&@92", - }, - ] - "#]], - ); - } - - #[test] - fn generic_enum() { - check_relevance( - r#" -enum Foo { A(T), B } -// bar() should not be an exact type match -// because the generic parameters are different -fn bar() -> Foo { Foo::B } -// FIXME baz() should be an exact type match -// because the types could unify, but it currently -// is not. This is due to the T here being -// TyKind::Placeholder rather than TyKind::Missing. -fn baz() -> Foo { Foo::B } -fn foo() { - let foo: Foo = Foo::B; - let _: Foo = f$0; -} -"#, - expect![[r#" - lc foo [type+local] - ev Foo::A(…) [type_could_unify] - ev Foo::B [type_could_unify] - fn foo() [] - en Foo [] - fn baz() [] - fn bar() [] - "#]], - ); - } - - #[test] - fn postfix_exact_match_is_high_priority() { - cov_mark::check!(postfix_exact_match_is_high_priority); - check_relevance_for_kinds( - r#" -mod ops { - pub trait Not { - type Output; - fn not(self) -> Self::Output; - } - - impl Not for bool { - type Output = bool; - fn not(self) -> bool { if self { false } else { true }} - } -} - -fn main() { - let _: bool = (9 > 2).not$0; -} - "#, - &[CompletionItemKind::Snippet, CompletionItemKind::Method], - expect![[r#" - sn not [snippet] - me not() (use ops::Not) [type_could_unify+requires_import] - sn if [] - sn while [] - sn ref [] - sn refm [] - sn match [] - sn box [] - sn dbg [] - sn dbgr [] - sn call [] - "#]], - ); - } - - #[test] - fn postfix_inexact_match_is_low_priority() { - cov_mark::check!(postfix_inexact_match_is_low_priority); - check_relevance_for_kinds( - r#" -struct S; -impl S { - fn f(&self) {} -} -fn main() { - S.$0 -} - "#, - &[CompletionItemKind::Snippet, CompletionItemKind::Method], - expect![[r#" - me f() [] - sn ref [] - sn refm [] - sn match [] - sn box [] - sn dbg [] - sn dbgr [] - sn call [] - sn let [] - sn letm [] - "#]], - ); - } - - #[test] - fn flyimport_reduced_relevance() { - check_relevance( - r#" -mod std { - pub mod io { - pub trait BufRead {} - pub struct BufReader; - pub struct BufWriter; - } -} -struct Buffer; - -fn f() { - Buf$0 -} -"#, - expect![[r#" - md std [] - st Buffer [] - fn f() [] - tt BufRead (use std::io::BufRead) [requires_import] - st BufReader (use std::io::BufReader) [requires_import] - st BufWriter (use std::io::BufWriter) [requires_import] - "#]], - ); - } - - #[test] - fn completes_struct_with_raw_identifier() { - check_edit( - "type", - r#" -mod m { pub struct r#type {} } -fn main() { - let r#type = m::t$0; -} -"#, - r#" -mod m { pub struct r#type {} } -fn main() { - let r#type = m::r#type; -} -"#, - ) - } - - #[test] - fn completes_fn_with_raw_identifier() { - check_edit( - "type", - r#" -mod m { pub fn r#type {} } -fn main() { - m::t$0 -} -"#, - r#" -mod m { pub fn r#type {} } -fn main() { - m::r#type()$0 -} -"#, - ) - } - - #[test] - fn completes_macro_with_raw_identifier() { - check_edit( - "let!", - r#" -macro_rules! r#let { () => {} } -fn main() { - $0 -} -"#, - r#" -macro_rules! r#let { () => {} } -fn main() { - r#let!($0) -} -"#, - ) - } - - #[test] - fn completes_variant_with_raw_identifier() { - check_edit( - "type", - r#" -enum A { r#type } -fn main() { - let a = A::t$0 -} -"#, - r#" -enum A { r#type } -fn main() { - let a = A::r#type$0 -} -"#, - ) - } - - #[test] - fn completes_field_with_raw_identifier() { - check_edit( - "fn", - r#" -mod r#type { - pub struct r#struct { - pub r#fn: u32 - } -} - -fn main() { - let a = r#type::r#struct {}; - a.$0 -} -"#, - r#" -mod r#type { - pub struct r#struct { - pub r#fn: u32 - } -} - -fn main() { - let a = r#type::r#struct {}; - a.r#fn -} -"#, - ) - } - - #[test] - fn completes_const_with_raw_identifier() { - check_edit( - "type", - r#" -struct r#struct {} -impl r#struct { pub const r#type: u8 = 1; } -fn main() { - r#struct::t$0 -} -"#, - r#" -struct r#struct {} -impl r#struct { pub const r#type: u8 = 1; } -fn main() { - r#struct::r#type -} -"#, - ) - } - - #[test] - fn completes_type_alias_with_raw_identifier() { - check_edit( - "type type", - r#" -struct r#struct {} -trait r#trait { type r#type; } -impl r#trait for r#struct { type t$0 } -"#, - r#" -struct r#struct {} -trait r#trait { type r#type; } -impl r#trait for r#struct { type r#type = $0; } -"#, - ) - } - - #[test] - fn field_access_includes_self() { - check_edit( - "length", - r#" -struct S { - length: i32 -} - -impl S { - fn some_fn(&self) { - let l = len$0 - } -} -"#, - r#" -struct S { - length: i32 -} - -impl S { - fn some_fn(&self) { - let l = self.length - } -} -"#, - ) - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs deleted file mode 100644 index a810eef18dd1f..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! Renderer for `const` fields. - -use hir::{AsAssocItem, HirDisplay}; -use ide_db::SymbolKind; - -use crate::{item::CompletionItem, render::RenderContext}; - -pub(crate) fn render_const(ctx: RenderContext<'_>, const_: hir::Const) -> Option { - let _p = profile::span("render_const"); - render(ctx, const_) -} - -fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option { - let db = ctx.db(); - let name = const_.name(db)?; - let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str()); - let detail = const_.display(db).to_string(); - - let mut item = CompletionItem::new(SymbolKind::Const, ctx.source_range(), name.clone()); - item.set_documentation(ctx.docs(const_)) - .set_deprecated(ctx.is_deprecated(const_) || ctx.is_deprecated_assoc_item(const_)) - .detail(detail) - .set_relevance(ctx.completion_relevance()); - - if let Some(actm) = const_.as_assoc_item(db) { - if let Some(trt) = actm.containing_trait_or_trait_impl(db) { - item.trait_name(trt.name(db).to_smol_str()); - } - } - item.insert_text(escaped_name); - - Some(item.build()) -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs deleted file mode 100644 index 241de0a1834a0..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs +++ /dev/null @@ -1,669 +0,0 @@ -//! Renderer for function calls. - -use hir::{db::HirDatabase, AsAssocItem, HirDisplay}; -use ide_db::{SnippetCap, SymbolKind}; -use itertools::Itertools; -use stdx::{format_to, to_lower_snake_case}; -use syntax::{AstNode, SmolStr}; - -use crate::{ - context::{CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind}, - item::{Builder, CompletionItem, CompletionItemKind, CompletionRelevance}, - render::{compute_exact_name_match, compute_ref_match, compute_type_match, RenderContext}, - CallableSnippets, -}; - -#[derive(Debug)] -enum FuncKind<'ctx> { - Function(&'ctx PathCompletionCtx), - Method(&'ctx DotAccess, Option), -} - -pub(crate) fn render_fn( - ctx: RenderContext<'_>, - path_ctx: &PathCompletionCtx, - local_name: Option, - func: hir::Function, -) -> Builder { - let _p = profile::span("render_fn"); - render(ctx, local_name, func, FuncKind::Function(path_ctx)) -} - -pub(crate) fn render_method( - ctx: RenderContext<'_>, - dot_access: &DotAccess, - receiver: Option, - local_name: Option, - func: hir::Function, -) -> Builder { - let _p = profile::span("render_method"); - render(ctx, local_name, func, FuncKind::Method(dot_access, receiver)) -} - -fn render( - ctx @ RenderContext { completion, .. }: RenderContext<'_>, - local_name: Option, - func: hir::Function, - func_kind: FuncKind<'_>, -) -> Builder { - let db = completion.db; - - let name = local_name.unwrap_or_else(|| func.name(db)); - - let (call, escaped_call) = match &func_kind { - FuncKind::Method(_, Some(receiver)) => ( - format!("{}.{}", receiver, &name).into(), - format!("{}.{}", receiver.escaped(), name.escaped()).into(), - ), - _ => (name.to_smol_str(), name.escaped().to_smol_str()), - }; - let mut item = CompletionItem::new( - if func.self_param(db).is_some() { - CompletionItemKind::Method - } else { - CompletionItemKind::SymbolKind(SymbolKind::Function) - }, - ctx.source_range(), - call.clone(), - ); - - let ret_type = func.ret_type(db); - let is_op_method = func - .as_assoc_item(ctx.db()) - .and_then(|trait_| trait_.containing_trait_or_trait_impl(ctx.db())) - .map_or(false, |trait_| completion.is_ops_trait(trait_)); - item.set_relevance(CompletionRelevance { - type_match: compute_type_match(completion, &ret_type), - exact_name_match: compute_exact_name_match(completion, &call), - is_op_method, - ..ctx.completion_relevance() - }); - - if let Some(ref_match) = compute_ref_match(completion, &ret_type) { - match func_kind { - FuncKind::Function(path_ctx) => { - item.ref_match(ref_match, path_ctx.path.syntax().text_range().start()); - } - FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => { - item.ref_match(ref_match, receiver.syntax().text_range().start()); - } - _ => (), - } - } - - item.set_documentation(ctx.docs(func)) - .set_deprecated(ctx.is_deprecated(func) || ctx.is_deprecated_assoc_item(func)) - .detail(detail(db, func)) - .lookup_by(name.to_smol_str()); - - match ctx.completion.config.snippet_cap { - Some(cap) => { - let complete_params = match func_kind { - FuncKind::Function(PathCompletionCtx { - kind: PathKind::Expr { .. }, - has_call_parens: false, - .. - }) => Some(false), - FuncKind::Method( - DotAccess { - kind: - DotAccessKind::Method { has_parens: false } | DotAccessKind::Field { .. }, - .. - }, - _, - ) => Some(true), - _ => None, - }; - if let Some(has_dot_receiver) = complete_params { - if let Some((self_param, params)) = - params(ctx.completion, func, &func_kind, has_dot_receiver) - { - add_call_parens( - &mut item, - completion, - cap, - call, - escaped_call, - self_param, - params, - ); - } - } - } - _ => (), - }; - - match ctx.import_to_add { - Some(import_to_add) => { - item.add_import(import_to_add); - } - None => { - if let Some(actm) = func.as_assoc_item(db) { - if let Some(trt) = actm.containing_trait_or_trait_impl(db) { - item.trait_name(trt.name(db).to_smol_str()); - } - } - } - } - item -} - -pub(super) fn add_call_parens<'b>( - builder: &'b mut Builder, - ctx: &CompletionContext<'_>, - cap: SnippetCap, - name: SmolStr, - escaped_name: SmolStr, - self_param: Option, - params: Vec, -) -> &'b mut Builder { - cov_mark::hit!(inserts_parens_for_function_calls); - - let (snippet, label_suffix) = if self_param.is_none() && params.is_empty() { - (format!("{}()$0", escaped_name), "()") - } else { - builder.trigger_call_info(); - let snippet = if let Some(CallableSnippets::FillArguments) = ctx.config.callable { - let offset = if self_param.is_some() { 2 } else { 1 }; - let function_params_snippet = - params.iter().enumerate().format_with(", ", |(index, param), f| { - match param.name(ctx.db) { - Some(n) => { - let smol_str = n.to_smol_str(); - let text = smol_str.as_str().trim_start_matches('_'); - let ref_ = ref_of_param(ctx, text, param.ty()); - f(&format_args!("${{{}:{}{}}}", index + offset, ref_, text)) - } - None => { - let name = match param.ty().as_adt() { - None => "_".to_string(), - Some(adt) => adt - .name(ctx.db) - .as_text() - .map(|s| to_lower_snake_case(s.as_str())) - .unwrap_or_else(|| "_".to_string()), - }; - f(&format_args!("${{{}:{}}}", index + offset, name)) - } - } - }); - match self_param { - Some(self_param) => { - format!( - "{}(${{1:{}}}{}{})$0", - escaped_name, - self_param.display(ctx.db), - if params.is_empty() { "" } else { ", " }, - function_params_snippet - ) - } - None => { - format!("{}({})$0", escaped_name, function_params_snippet) - } - } - } else { - cov_mark::hit!(suppress_arg_snippets); - format!("{}($0)", escaped_name) - }; - - (snippet, "(…)") - }; - builder.label(SmolStr::from_iter([&name, label_suffix])).insert_snippet(cap, snippet) -} - -fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type) -> &'static str { - if let Some(derefed_ty) = ty.remove_ref() { - for (name, local) in ctx.locals.iter() { - if name.as_text().as_deref() == Some(arg) { - return if local.ty(ctx.db) == derefed_ty { - if ty.is_mutable_reference() { - "&mut " - } else { - "&" - } - } else { - "" - }; - } - } - } - "" -} - -fn detail(db: &dyn HirDatabase, func: hir::Function) -> String { - let mut ret_ty = func.ret_type(db); - let mut detail = String::new(); - - if func.is_const(db) { - format_to!(detail, "const "); - } - if func.is_async(db) { - format_to!(detail, "async "); - if let Some(async_ret) = func.async_ret_type(db) { - ret_ty = async_ret; - } - } - if func.is_unsafe_to_call(db) { - format_to!(detail, "unsafe "); - } - - format_to!(detail, "fn({})", params_display(db, func)); - if !ret_ty.is_unit() { - format_to!(detail, " -> {}", ret_ty.display(db)); - } - detail -} - -fn params_display(db: &dyn HirDatabase, func: hir::Function) -> String { - if let Some(self_param) = func.self_param(db) { - let assoc_fn_params = func.assoc_fn_params(db); - let params = assoc_fn_params - .iter() - .skip(1) // skip the self param because we are manually handling that - .map(|p| p.ty().display(db)); - format!( - "{}{}", - self_param.display(db), - params.format_with("", |display, f| { - f(&", ")?; - f(&display) - }) - ) - } else { - let assoc_fn_params = func.assoc_fn_params(db); - assoc_fn_params.iter().map(|p| p.ty().display(db)).join(", ") - } -} - -fn params( - ctx: &CompletionContext<'_>, - func: hir::Function, - func_kind: &FuncKind<'_>, - has_dot_receiver: bool, -) -> Option<(Option, Vec)> { - if ctx.config.callable.is_none() { - return None; - } - - // Don't add parentheses if the expected type is some function reference. - if let Some(ty) = &ctx.expected_type { - // FIXME: check signature matches? - if ty.is_fn() { - cov_mark::hit!(no_call_parens_if_fn_ptr_needed); - return None; - } - } - - let self_param = if has_dot_receiver || matches!(func_kind, FuncKind::Method(_, Some(_))) { - None - } else { - func.self_param(ctx.db) - }; - Some((self_param, func.params_without_self(ctx.db))) -} - -#[cfg(test)] -mod tests { - use crate::{ - tests::{check_edit, check_edit_with_config, TEST_CONFIG}, - CallableSnippets, CompletionConfig, - }; - - #[test] - fn inserts_parens_for_function_calls() { - cov_mark::check!(inserts_parens_for_function_calls); - check_edit( - "no_args", - r#" -fn no_args() {} -fn main() { no_$0 } -"#, - r#" -fn no_args() {} -fn main() { no_args()$0 } -"#, - ); - - check_edit( - "with_args", - r#" -fn with_args(x: i32, y: String) {} -fn main() { with_$0 } -"#, - r#" -fn with_args(x: i32, y: String) {} -fn main() { with_args(${1:x}, ${2:y})$0 } -"#, - ); - - check_edit( - "foo", - r#" -struct S; -impl S { - fn foo(&self) {} -} -fn bar(s: &S) { s.f$0 } -"#, - r#" -struct S; -impl S { - fn foo(&self) {} -} -fn bar(s: &S) { s.foo()$0 } -"#, - ); - - check_edit( - "foo", - r#" -struct S {} -impl S { - fn foo(&self, x: i32) {} -} -fn bar(s: &S) { - s.f$0 -} -"#, - r#" -struct S {} -impl S { - fn foo(&self, x: i32) {} -} -fn bar(s: &S) { - s.foo(${1:x})$0 -} -"#, - ); - - check_edit( - "foo", - r#" -struct S {} -impl S { - fn foo(&self, x: i32) { - $0 - } -} -"#, - r#" -struct S {} -impl S { - fn foo(&self, x: i32) { - self.foo(${1:x})$0 - } -} -"#, - ); - } - - #[test] - fn parens_for_method_call_as_assoc_fn() { - check_edit( - "foo", - r#" -struct S; -impl S { - fn foo(&self) {} -} -fn main() { S::f$0 } -"#, - r#" -struct S; -impl S { - fn foo(&self) {} -} -fn main() { S::foo(${1:&self})$0 } -"#, - ); - } - - #[test] - fn suppress_arg_snippets() { - cov_mark::check!(suppress_arg_snippets); - check_edit_with_config( - CompletionConfig { callable: Some(CallableSnippets::AddParentheses), ..TEST_CONFIG }, - "with_args", - r#" -fn with_args(x: i32, y: String) {} -fn main() { with_$0 } -"#, - r#" -fn with_args(x: i32, y: String) {} -fn main() { with_args($0) } -"#, - ); - } - - #[test] - fn strips_underscores_from_args() { - check_edit( - "foo", - r#" -fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} -fn main() { f$0 } -"#, - r#" -fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} -fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 } -"#, - ); - } - - #[test] - fn insert_ref_when_matching_local_in_scope() { - check_edit( - "ref_arg", - r#" -struct Foo {} -fn ref_arg(x: &Foo) {} -fn main() { - let x = Foo {}; - ref_ar$0 -} -"#, - r#" -struct Foo {} -fn ref_arg(x: &Foo) {} -fn main() { - let x = Foo {}; - ref_arg(${1:&x})$0 -} -"#, - ); - } - - #[test] - fn insert_mut_ref_when_matching_local_in_scope() { - check_edit( - "ref_arg", - r#" -struct Foo {} -fn ref_arg(x: &mut Foo) {} -fn main() { - let x = Foo {}; - ref_ar$0 -} -"#, - r#" -struct Foo {} -fn ref_arg(x: &mut Foo) {} -fn main() { - let x = Foo {}; - ref_arg(${1:&mut x})$0 -} -"#, - ); - } - - #[test] - fn insert_ref_when_matching_local_in_scope_for_method() { - check_edit( - "apply_foo", - r#" -struct Foo {} -struct Bar {} -impl Bar { - fn apply_foo(&self, x: &Foo) {} -} - -fn main() { - let x = Foo {}; - let y = Bar {}; - y.$0 -} -"#, - r#" -struct Foo {} -struct Bar {} -impl Bar { - fn apply_foo(&self, x: &Foo) {} -} - -fn main() { - let x = Foo {}; - let y = Bar {}; - y.apply_foo(${1:&x})$0 -} -"#, - ); - } - - #[test] - fn trim_mut_keyword_in_func_completion() { - check_edit( - "take_mutably", - r#" -fn take_mutably(mut x: &i32) {} - -fn main() { - take_m$0 -} -"#, - r#" -fn take_mutably(mut x: &i32) {} - -fn main() { - take_mutably(${1:x})$0 -} -"#, - ); - } - - #[test] - fn complete_pattern_args_with_type_name_if_adt() { - check_edit( - "qux", - r#" -struct Foo { - bar: i32 -} - -fn qux(Foo { bar }: Foo) { - println!("{}", bar); -} - -fn main() { - qu$0 -} -"#, - r#" -struct Foo { - bar: i32 -} - -fn qux(Foo { bar }: Foo) { - println!("{}", bar); -} - -fn main() { - qux(${1:foo})$0 -} -"#, - ); - } - - #[test] - fn complete_fn_param() { - // has mut kw - check_edit( - "mut bar: u32", - r#" -fn f(foo: (), mut bar: u32) {} -fn g(foo: (), mut ba$0) -"#, - r#" -fn f(foo: (), mut bar: u32) {} -fn g(foo: (), mut bar: u32) -"#, - ); - - // has type param - check_edit( - "mut bar: u32", - r#" -fn g(foo: (), mut ba$0: u32) -fn f(foo: (), mut bar: u32) {} -"#, - r#" -fn g(foo: (), mut bar: u32) -fn f(foo: (), mut bar: u32) {} -"#, - ); - } - - #[test] - fn complete_fn_mut_param_add_comma() { - // add leading and trailing comma - check_edit( - ", mut bar: u32,", - r#" -fn f(foo: (), mut bar: u32) {} -fn g(foo: ()mut ba$0 baz: ()) -"#, - r#" -fn f(foo: (), mut bar: u32) {} -fn g(foo: (), mut bar: u32, baz: ()) -"#, - ); - } - - #[test] - fn complete_fn_mut_param_has_attribute() { - check_edit( - r#"#[baz = "qux"] mut bar: u32"#, - r#" -fn f(foo: (), #[baz = "qux"] mut bar: u32) {} -fn g(foo: (), mut ba$0) -"#, - r#" -fn f(foo: (), #[baz = "qux"] mut bar: u32) {} -fn g(foo: (), #[baz = "qux"] mut bar: u32) -"#, - ); - - check_edit( - r#"#[baz = "qux"] mut bar: u32"#, - r#" -fn f(foo: (), #[baz = "qux"] mut bar: u32) {} -fn g(foo: (), #[baz = "qux"] mut ba$0) -"#, - r#" -fn f(foo: (), #[baz = "qux"] mut bar: u32) {} -fn g(foo: (), #[baz = "qux"] mut bar: u32) -"#, - ); - - check_edit( - r#", #[baz = "qux"] mut bar: u32"#, - r#" -fn f(foo: (), #[baz = "qux"] mut bar: u32) {} -fn g(foo: ()#[baz = "qux"] mut ba$0) -"#, - r#" -fn f(foo: (), #[baz = "qux"] mut bar: u32) {} -fn g(foo: (), #[baz = "qux"] mut bar: u32) -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs deleted file mode 100644 index 91a253f8fc8c1..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs +++ /dev/null @@ -1,191 +0,0 @@ -//! Renderer for `enum` variants. - -use hir::{db::HirDatabase, Documentation, HasAttrs, StructKind}; -use ide_db::SymbolKind; -use syntax::AstNode; - -use crate::{ - context::{CompletionContext, PathCompletionCtx, PathKind}, - item::{Builder, CompletionItem}, - render::{ - compute_ref_match, compute_type_match, - variant::{ - format_literal_label, render_record_lit, render_tuple_lit, visible_fields, - RenderedLiteral, - }, - RenderContext, - }, - CompletionItemKind, CompletionRelevance, -}; - -pub(crate) fn render_variant_lit( - ctx: RenderContext<'_>, - path_ctx: &PathCompletionCtx, - local_name: Option, - variant: hir::Variant, - path: Option, -) -> Option { - let _p = profile::span("render_enum_variant"); - let db = ctx.db(); - - let name = local_name.unwrap_or_else(|| variant.name(db)); - render(ctx, path_ctx, Variant::EnumVariant(variant), name, path) -} - -pub(crate) fn render_struct_literal( - ctx: RenderContext<'_>, - path_ctx: &PathCompletionCtx, - strukt: hir::Struct, - path: Option, - local_name: Option, -) -> Option { - let _p = profile::span("render_struct_literal"); - let db = ctx.db(); - - let name = local_name.unwrap_or_else(|| strukt.name(db)); - render(ctx, path_ctx, Variant::Struct(strukt), name, path) -} - -fn render( - ctx @ RenderContext { completion, .. }: RenderContext<'_>, - path_ctx: &PathCompletionCtx, - thing: Variant, - name: hir::Name, - path: Option, -) -> Option { - let db = completion.db; - let mut kind = thing.kind(db); - let should_add_parens = match &path_ctx { - PathCompletionCtx { has_call_parens: true, .. } => false, - PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. } => false, - _ => true, - }; - - let fields = thing.fields(completion)?; - let (qualified_name, short_qualified_name, qualified) = match path { - Some(path) => { - let short = hir::ModPath::from_segments( - hir::PathKind::Plain, - path.segments().iter().skip(path.segments().len().saturating_sub(2)).cloned(), - ); - (path, short, true) - } - None => (name.clone().into(), name.into(), false), - }; - let (qualified_name, escaped_qualified_name) = - (qualified_name.to_string(), qualified_name.escaped().to_string()); - let snippet_cap = ctx.snippet_cap(); - - let mut rendered = match kind { - StructKind::Tuple if should_add_parens => { - render_tuple_lit(db, snippet_cap, &fields, &escaped_qualified_name) - } - StructKind::Record if should_add_parens => { - render_record_lit(db, snippet_cap, &fields, &escaped_qualified_name) - } - _ => RenderedLiteral { - literal: escaped_qualified_name.clone(), - detail: escaped_qualified_name.clone(), - }, - }; - - if snippet_cap.is_some() { - rendered.literal.push_str("$0"); - } - - // only show name in label if not adding parens - if !should_add_parens { - kind = StructKind::Unit; - } - - let mut item = CompletionItem::new( - CompletionItemKind::SymbolKind(thing.symbol_kind()), - ctx.source_range(), - format_literal_label(&qualified_name, kind), - ); - - item.detail(rendered.detail); - - match snippet_cap { - Some(snippet_cap) => item.insert_snippet(snippet_cap, rendered.literal), - None => item.insert_text(rendered.literal), - }; - - if qualified { - item.lookup_by(format_literal_label(&short_qualified_name.to_string(), kind)); - } - item.set_documentation(thing.docs(db)).set_deprecated(thing.is_deprecated(&ctx)); - - let ty = thing.ty(db); - item.set_relevance(CompletionRelevance { - type_match: compute_type_match(ctx.completion, &ty), - ..ctx.completion_relevance() - }); - if let Some(ref_match) = compute_ref_match(completion, &ty) { - item.ref_match(ref_match, path_ctx.path.syntax().text_range().start()); - } - - if let Some(import_to_add) = ctx.import_to_add { - item.add_import(import_to_add); - } - Some(item) -} - -#[derive(Clone, Copy)] -enum Variant { - Struct(hir::Struct), - EnumVariant(hir::Variant), -} - -impl Variant { - fn fields(self, ctx: &CompletionContext<'_>) -> Option> { - let fields = match self { - Variant::Struct(it) => it.fields(ctx.db), - Variant::EnumVariant(it) => it.fields(ctx.db), - }; - let (visible_fields, fields_omitted) = match self { - Variant::Struct(it) => visible_fields(ctx, &fields, it)?, - Variant::EnumVariant(it) => visible_fields(ctx, &fields, it)?, - }; - if !fields_omitted { - Some(visible_fields) - } else { - None - } - } - - fn kind(self, db: &dyn HirDatabase) -> StructKind { - match self { - Variant::Struct(it) => it.kind(db), - Variant::EnumVariant(it) => it.kind(db), - } - } - - fn symbol_kind(self) -> SymbolKind { - match self { - Variant::Struct(_) => SymbolKind::Struct, - Variant::EnumVariant(_) => SymbolKind::Variant, - } - } - - fn docs(self, db: &dyn HirDatabase) -> Option { - match self { - Variant::Struct(it) => it.docs(db), - Variant::EnumVariant(it) => it.docs(db), - } - } - - fn is_deprecated(self, ctx: &RenderContext<'_>) -> bool { - match self { - Variant::Struct(it) => ctx.is_deprecated(it), - Variant::EnumVariant(it) => ctx.is_deprecated(it), - } - } - - fn ty(self, db: &dyn HirDatabase) -> hir::Type { - match self { - Variant::Struct(it) => it.ty(db), - Variant::EnumVariant(it) => it.parent_enum(db).ty(db), - } - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs deleted file mode 100644 index ca2269f1398f0..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs +++ /dev/null @@ -1,270 +0,0 @@ -//! Renderer for macro invocations. - -use hir::{Documentation, HirDisplay}; -use ide_db::SymbolKind; -use syntax::SmolStr; - -use crate::{ - context::{PathCompletionCtx, PathKind, PatternContext}, - item::{Builder, CompletionItem}, - render::RenderContext, -}; - -pub(crate) fn render_macro( - ctx: RenderContext<'_>, - PathCompletionCtx { kind, has_macro_bang, has_call_parens, .. }: &PathCompletionCtx, - - name: hir::Name, - macro_: hir::Macro, -) -> Builder { - let _p = profile::span("render_macro"); - render(ctx, *kind == PathKind::Use, *has_macro_bang, *has_call_parens, name, macro_) -} - -pub(crate) fn render_macro_pat( - ctx: RenderContext<'_>, - _pattern_ctx: &PatternContext, - name: hir::Name, - macro_: hir::Macro, -) -> Builder { - let _p = profile::span("render_macro"); - render(ctx, false, false, false, name, macro_) -} - -fn render( - ctx @ RenderContext { completion, .. }: RenderContext<'_>, - is_use_path: bool, - has_macro_bang: bool, - has_call_parens: bool, - name: hir::Name, - macro_: hir::Macro, -) -> Builder { - let source_range = if ctx.is_immediately_after_macro_bang() { - cov_mark::hit!(completes_macro_call_if_cursor_at_bang_token); - completion.token.parent().map_or_else(|| ctx.source_range(), |it| it.text_range()) - } else { - ctx.source_range() - }; - - let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str()); - let docs = ctx.docs(macro_); - let docs_str = docs.as_ref().map(Documentation::as_str).unwrap_or_default(); - let is_fn_like = macro_.is_fn_like(completion.db); - let (bra, ket) = if is_fn_like { guess_macro_braces(&name, docs_str) } else { ("", "") }; - - let needs_bang = is_fn_like && !is_use_path && !has_macro_bang; - - let mut item = CompletionItem::new( - SymbolKind::from(macro_.kind(completion.db)), - source_range, - label(&ctx, needs_bang, bra, ket, &name), - ); - item.set_deprecated(ctx.is_deprecated(macro_)) - .detail(macro_.display(completion.db).to_string()) - .set_documentation(docs) - .set_relevance(ctx.completion_relevance()); - - match ctx.snippet_cap() { - Some(cap) if needs_bang && !has_call_parens => { - let snippet = format!("{}!{}$0{}", escaped_name, bra, ket); - let lookup = banged_name(&name); - item.insert_snippet(cap, snippet).lookup_by(lookup); - } - _ if needs_bang => { - item.insert_text(banged_name(&escaped_name)).lookup_by(banged_name(&name)); - } - _ => { - cov_mark::hit!(dont_insert_macro_call_parens_unncessary); - item.insert_text(escaped_name); - } - }; - if let Some(import_to_add) = ctx.import_to_add { - item.add_import(import_to_add); - } - - item -} - -fn label( - ctx: &RenderContext<'_>, - needs_bang: bool, - bra: &str, - ket: &str, - name: &SmolStr, -) -> SmolStr { - if needs_bang { - if ctx.snippet_cap().is_some() { - SmolStr::from_iter([&*name, "!", bra, "…", ket]) - } else { - banged_name(name) - } - } else { - name.clone() - } -} - -fn banged_name(name: &str) -> SmolStr { - SmolStr::from_iter([name, "!"]) -} - -fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static str) { - let mut votes = [0, 0, 0]; - for (idx, s) in docs.match_indices(¯o_name) { - let (before, after) = (&docs[..idx], &docs[idx + s.len()..]); - // Ensure to match the full word - if after.starts_with('!') - && !before.ends_with(|c: char| c == '_' || c.is_ascii_alphanumeric()) - { - // It may have spaces before the braces like `foo! {}` - match after[1..].chars().find(|&c| !c.is_whitespace()) { - Some('{') => votes[0] += 1, - Some('[') => votes[1] += 1, - Some('(') => votes[2] += 1, - _ => {} - } - } - } - - // Insert a space before `{}`. - // We prefer the last one when some votes equal. - let (_vote, (bra, ket)) = votes - .iter() - .zip(&[(" {", "}"), ("[", "]"), ("(", ")")]) - .max_by_key(|&(&vote, _)| vote) - .unwrap(); - (*bra, *ket) -} - -#[cfg(test)] -mod tests { - use crate::tests::check_edit; - - #[test] - fn dont_insert_macro_call_parens_unncessary() { - cov_mark::check!(dont_insert_macro_call_parens_unncessary); - check_edit( - "frobnicate", - r#" -//- /main.rs crate:main deps:foo -use foo::$0; -//- /foo/lib.rs crate:foo -#[macro_export] -macro_rules! frobnicate { () => () } -"#, - r#" -use foo::frobnicate; -"#, - ); - - check_edit( - "frobnicate", - r#" -macro_rules! frobnicate { () => () } -fn main() { frob$0!(); } -"#, - r#" -macro_rules! frobnicate { () => () } -fn main() { frobnicate!(); } -"#, - ); - } - - #[test] - fn add_bang_to_parens() { - check_edit( - "frobnicate!", - r#" -macro_rules! frobnicate { () => () } -fn main() { - frob$0() -} -"#, - r#" -macro_rules! frobnicate { () => () } -fn main() { - frobnicate!() -} -"#, - ); - } - - #[test] - fn guesses_macro_braces() { - check_edit( - "vec!", - r#" -/// Creates a [`Vec`] containing the arguments. -/// -/// ``` -/// let v = vec![1, 2, 3]; -/// assert_eq!(v[0], 1); -/// assert_eq!(v[1], 2); -/// assert_eq!(v[2], 3); -/// ``` -macro_rules! vec { () => {} } - -fn main() { v$0 } -"#, - r#" -/// Creates a [`Vec`] containing the arguments. -/// -/// ``` -/// let v = vec![1, 2, 3]; -/// assert_eq!(v[0], 1); -/// assert_eq!(v[1], 2); -/// assert_eq!(v[2], 3); -/// ``` -macro_rules! vec { () => {} } - -fn main() { vec![$0] } -"#, - ); - - check_edit( - "foo!", - r#" -/// Foo -/// -/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`, -/// call as `let _=foo! { hello world };` -macro_rules! foo { () => {} } -fn main() { $0 } -"#, - r#" -/// Foo -/// -/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`, -/// call as `let _=foo! { hello world };` -macro_rules! foo { () => {} } -fn main() { foo! {$0} } -"#, - ) - } - - #[test] - fn completes_macro_call_if_cursor_at_bang_token() { - // Regression test for https://github.com/rust-lang/rust-analyzer/issues/9904 - cov_mark::check!(completes_macro_call_if_cursor_at_bang_token); - check_edit( - "foo!", - r#" -macro_rules! foo { - () => {} -} - -fn main() { - foo!$0 -} -"#, - r#" -macro_rules! foo { - () => {} -} - -fn main() { - foo!($0) -} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs deleted file mode 100644 index 03db08a911e92..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs +++ /dev/null @@ -1,178 +0,0 @@ -//! Renderer for patterns. - -use hir::{db::HirDatabase, HasAttrs, Name, StructKind}; -use ide_db::SnippetCap; -use itertools::Itertools; -use syntax::SmolStr; - -use crate::{ - context::{ParamContext, ParamKind, PatternContext}, - render::{ - variant::{format_literal_label, visible_fields}, - RenderContext, - }, - CompletionItem, CompletionItemKind, -}; - -pub(crate) fn render_struct_pat( - ctx: RenderContext<'_>, - pattern_ctx: &PatternContext, - strukt: hir::Struct, - local_name: Option, -) -> Option { - let _p = profile::span("render_struct_pat"); - - let fields = strukt.fields(ctx.db()); - let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, strukt)?; - - if visible_fields.is_empty() { - // Matching a struct without matching its fields is pointless, unlike matching a Variant without its fields - return None; - } - - let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())); - let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str()); - let kind = strukt.kind(ctx.db()); - let label = format_literal_label(name.as_str(), kind); - let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?; - - Some(build_completion(ctx, label, pat, strukt)) -} - -pub(crate) fn render_variant_pat( - ctx: RenderContext<'_>, - pattern_ctx: &PatternContext, - variant: hir::Variant, - local_name: Option, - path: Option<&hir::ModPath>, -) -> Option { - let _p = profile::span("render_variant_pat"); - - let fields = variant.fields(ctx.db()); - let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, variant)?; - - let (name, escaped_name) = match path { - Some(path) => (path.to_string().into(), path.escaped().to_string().into()), - None => { - let name = local_name.unwrap_or_else(|| variant.name(ctx.db())); - (name.to_smol_str(), name.escaped().to_smol_str()) - } - }; - let kind = variant.kind(ctx.db()); - let label = format_literal_label(name.as_str(), kind); - let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?; - - Some(build_completion(ctx, label, pat, variant)) -} - -fn build_completion( - ctx: RenderContext<'_>, - label: SmolStr, - pat: String, - def: impl HasAttrs + Copy, -) -> CompletionItem { - let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), label); - item.set_documentation(ctx.docs(def)) - .set_deprecated(ctx.is_deprecated(def)) - .detail(&pat) - .set_relevance(ctx.completion_relevance()); - match ctx.snippet_cap() { - Some(snippet_cap) => item.insert_snippet(snippet_cap, pat), - None => item.insert_text(pat), - }; - item.build() -} - -fn render_pat( - ctx: &RenderContext<'_>, - pattern_ctx: &PatternContext, - name: &str, - kind: StructKind, - fields: &[hir::Field], - fields_omitted: bool, -) -> Option { - let mut pat = match kind { - StructKind::Tuple => render_tuple_as_pat(ctx.snippet_cap(), fields, name, fields_omitted), - StructKind::Record => { - render_record_as_pat(ctx.db(), ctx.snippet_cap(), fields, name, fields_omitted) - } - StructKind::Unit => name.to_string(), - }; - - let needs_ascription = matches!( - pattern_ctx, - PatternContext { - param_ctx: Some(ParamContext { kind: ParamKind::Function(_), .. }), - has_type_ascription: false, - .. - } - ); - if needs_ascription { - pat.push(':'); - pat.push(' '); - pat.push_str(name); - } - if ctx.snippet_cap().is_some() { - pat.push_str("$0"); - } - Some(pat) -} - -fn render_record_as_pat( - db: &dyn HirDatabase, - snippet_cap: Option, - fields: &[hir::Field], - name: &str, - fields_omitted: bool, -) -> String { - let fields = fields.iter(); - match snippet_cap { - Some(_) => { - format!( - "{name} {{ {}{} }}", - fields.enumerate().format_with(", ", |(idx, field), f| { - f(&format_args!("{}${}", field.name(db).escaped(), idx + 1)) - }), - if fields_omitted { ", .." } else { "" }, - name = name - ) - } - None => { - format!( - "{name} {{ {}{} }}", - fields.map(|field| field.name(db).escaped().to_smol_str()).format(", "), - if fields_omitted { ", .." } else { "" }, - name = name - ) - } - } -} - -fn render_tuple_as_pat( - snippet_cap: Option, - fields: &[hir::Field], - name: &str, - fields_omitted: bool, -) -> String { - let fields = fields.iter(); - match snippet_cap { - Some(_) => { - format!( - "{name}({}{})", - fields - .enumerate() - .format_with(", ", |(idx, _), f| { f(&format_args!("${}", idx + 1)) }), - if fields_omitted { ", .." } else { "" }, - name = name - ) - } - None => { - format!( - "{name}({}{})", - fields.enumerate().map(|(idx, _)| idx).format(", "), - if fields_omitted { ", .." } else { "" }, - name = name - ) - } - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs deleted file mode 100644 index f1b23c76e7b43..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! Renderer for type aliases. - -use hir::{AsAssocItem, HirDisplay}; -use ide_db::SymbolKind; -use syntax::SmolStr; - -use crate::{item::CompletionItem, render::RenderContext}; - -pub(crate) fn render_type_alias( - ctx: RenderContext<'_>, - type_alias: hir::TypeAlias, -) -> Option { - let _p = profile::span("render_type_alias"); - render(ctx, type_alias, false) -} - -pub(crate) fn render_type_alias_with_eq( - ctx: RenderContext<'_>, - type_alias: hir::TypeAlias, -) -> Option { - let _p = profile::span("render_type_alias_with_eq"); - render(ctx, type_alias, true) -} - -fn render( - ctx: RenderContext<'_>, - type_alias: hir::TypeAlias, - with_eq: bool, -) -> Option { - let db = ctx.db(); - - let name = type_alias.name(db); - let (name, escaped_name) = if with_eq { - ( - SmolStr::from_iter([&name.to_smol_str(), " = "]), - SmolStr::from_iter([&name.escaped().to_smol_str(), " = "]), - ) - } else { - (name.to_smol_str(), name.escaped().to_smol_str()) - }; - let detail = type_alias.display(db).to_string(); - - let mut item = CompletionItem::new(SymbolKind::TypeAlias, ctx.source_range(), name.clone()); - item.set_documentation(ctx.docs(type_alias)) - .set_deprecated(ctx.is_deprecated(type_alias) || ctx.is_deprecated_assoc_item(type_alias)) - .detail(detail) - .set_relevance(ctx.completion_relevance()); - - if let Some(actm) = type_alias.as_assoc_item(db) { - if let Some(trt) = actm.containing_trait_or_trait_impl(db) { - item.trait_name(trt.name(db).to_smol_str()); - } - } - item.insert_text(escaped_name); - - Some(item.build()) -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs deleted file mode 100644 index 9c9540a9bd963..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! Renderer for `union` literals. - -use hir::{HirDisplay, Name, StructKind}; -use ide_db::SymbolKind; -use itertools::Itertools; - -use crate::{ - render::{ - variant::{format_literal_label, visible_fields}, - RenderContext, - }, - CompletionItem, CompletionItemKind, -}; - -pub(crate) fn render_union_literal( - ctx: RenderContext<'_>, - un: hir::Union, - path: Option, - local_name: Option, -) -> Option { - let name = local_name.unwrap_or_else(|| un.name(ctx.db())); - - let (qualified_name, escaped_qualified_name) = match path { - Some(p) => (p.to_string(), p.escaped().to_string()), - None => (name.to_string(), name.escaped().to_string()), - }; - - let mut item = CompletionItem::new( - CompletionItemKind::SymbolKind(SymbolKind::Union), - ctx.source_range(), - format_literal_label(&name.to_smol_str(), StructKind::Record), - ); - - let fields = un.fields(ctx.db()); - let (fields, fields_omitted) = visible_fields(ctx.completion, &fields, un)?; - - if fields.is_empty() { - return None; - } - - let literal = if ctx.snippet_cap().is_some() { - format!( - "{} {{ ${{1|{}|}}: ${{2:()}} }}$0", - escaped_qualified_name, - fields.iter().map(|field| field.name(ctx.db()).escaped().to_smol_str()).format(",") - ) - } else { - format!( - "{} {{ {} }}", - escaped_qualified_name, - fields.iter().format_with(", ", |field, f| { - f(&format_args!("{}: ()", field.name(ctx.db()).escaped())) - }) - ) - }; - - let detail = format!( - "{} {{ {}{} }}", - qualified_name, - fields.iter().format_with(", ", |field, f| { - f(&format_args!("{}: {}", field.name(ctx.db()), field.ty(ctx.db()).display(ctx.db()))) - }), - if fields_omitted { ", .." } else { "" } - ); - - item.set_documentation(ctx.docs(un)) - .set_deprecated(ctx.is_deprecated(un)) - .detail(&detail) - .set_relevance(ctx.completion_relevance()); - - match ctx.snippet_cap() { - Some(snippet_cap) => item.insert_snippet(snippet_cap, literal), - None => item.insert_text(literal), - }; - - Some(item.build()) -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs deleted file mode 100644 index 003a0c11ed2f8..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs +++ /dev/null @@ -1,96 +0,0 @@ -//! Code common to structs, unions, and enum variants. - -use crate::context::CompletionContext; -use hir::{db::HirDatabase, HasAttrs, HasCrate, HasVisibility, HirDisplay, StructKind}; -use ide_db::SnippetCap; -use itertools::Itertools; -use syntax::SmolStr; - -/// A rendered struct, union, or enum variant, split into fields for actual -/// auto-completion (`literal`, using `field: ()`) and display in the -/// completions menu (`detail`, using `field: type`). -pub(crate) struct RenderedLiteral { - pub(crate) literal: String, - pub(crate) detail: String, -} - -/// Render a record type (or sub-type) to a `RenderedCompound`. Use `None` for -/// the `name` argument for an anonymous type. -pub(crate) fn render_record_lit( - db: &dyn HirDatabase, - snippet_cap: Option, - fields: &[hir::Field], - path: &str, -) -> RenderedLiteral { - let completions = fields.iter().enumerate().format_with(", ", |(idx, field), f| { - if snippet_cap.is_some() { - f(&format_args!("{}: ${{{}:()}}", field.name(db).escaped(), idx + 1)) - } else { - f(&format_args!("{}: ()", field.name(db).escaped())) - } - }); - - let types = fields.iter().format_with(", ", |field, f| { - f(&format_args!("{}: {}", field.name(db), field.ty(db).display(db))) - }); - - RenderedLiteral { - literal: format!("{} {{ {} }}", path, completions), - detail: format!("{} {{ {} }}", path, types), - } -} - -/// Render a tuple type (or sub-type) to a `RenderedCompound`. Use `None` for -/// the `name` argument for an anonymous type. -pub(crate) fn render_tuple_lit( - db: &dyn HirDatabase, - snippet_cap: Option, - fields: &[hir::Field], - path: &str, -) -> RenderedLiteral { - let completions = fields.iter().enumerate().format_with(", ", |(idx, _), f| { - if snippet_cap.is_some() { - f(&format_args!("${{{}:()}}", idx + 1)) - } else { - f(&format_args!("()")) - } - }); - - let types = fields.iter().format_with(", ", |field, f| f(&field.ty(db).display(db))); - - RenderedLiteral { - literal: format!("{}({})", path, completions), - detail: format!("{}({})", path, types), - } -} - -/// Find all the visible fields in a given list. Returns the list of visible -/// fields, plus a boolean for whether the list is comprehensive (contains no -/// private fields and its item is not marked `#[non_exhaustive]`). -pub(crate) fn visible_fields( - ctx: &CompletionContext<'_>, - fields: &[hir::Field], - item: impl HasAttrs + HasCrate + Copy, -) -> Option<(Vec, bool)> { - let module = ctx.module; - let n_fields = fields.len(); - let fields = fields - .iter() - .filter(|field| field.is_visible_from(ctx.db, module)) - .copied() - .collect::>(); - let has_invisible_field = n_fields - fields.len() > 0; - let is_foreign_non_exhaustive = item.attrs(ctx.db).by_key("non_exhaustive").exists() - && item.krate(ctx.db) != module.krate(); - let fields_omitted = has_invisible_field || is_foreign_non_exhaustive; - Some((fields, fields_omitted)) -} - -/// Format a struct, etc. literal option for display in the completions menu. -pub(crate) fn format_literal_label(name: &str, kind: StructKind) -> SmolStr { - match kind { - StructKind::Tuple => SmolStr::from_iter([name, "(…)"]), - StructKind::Record => SmolStr::from_iter([name, " {…}"]), - StructKind::Unit => name.into(), - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs deleted file mode 100644 index dc1039fa623e8..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs +++ /dev/null @@ -1,214 +0,0 @@ -//! User (postfix)-snippet definitions. -//! -//! Actual logic is implemented in [`crate::completions::postfix`] and [`crate::completions::snippet`] respectively. - -// Feature: User Snippet Completions -// -// rust-analyzer allows the user to define custom (postfix)-snippets that may depend on items to be accessible for the current scope to be applicable. -// -// A custom snippet can be defined by adding it to the `rust-analyzer.completion.snippets.custom` object respectively. -// -// [source,json] -// ---- -// { -// "rust-analyzer.completion.snippets.custom": { -// "thread spawn": { -// "prefix": ["spawn", "tspawn"], -// "body": [ -// "thread::spawn(move || {", -// "\t$0", -// "});", -// ], -// "description": "Insert a thread::spawn call", -// "requires": "std::thread", -// "scope": "expr", -// } -// } -// } -// ---- -// -// In the example above: -// -// * `"thread spawn"` is the name of the snippet. -// -// * `prefix` defines one or more trigger words that will trigger the snippets completion. -// Using `postfix` will instead create a postfix snippet. -// -// * `body` is one or more lines of content joined via newlines for the final output. -// -// * `description` is an optional description of the snippet, if unset the snippet name will be used. -// -// * `requires` is an optional list of item paths that have to be resolvable in the current crate where the completion is rendered. -// On failure of resolution the snippet won't be applicable, otherwise the snippet will insert an import for the items on insertion if -// the items aren't yet in scope. -// -// * `scope` is an optional filter for when the snippet should be applicable. Possible values are: -// ** for Snippet-Scopes: `expr`, `item` (default: `item`) -// ** for Postfix-Snippet-Scopes: `expr`, `type` (default: `expr`) -// -// The `body` field also has access to placeholders as visible in the example as `$0`. -// These placeholders take the form of `$number` or `${number:placeholder_text}` which can be traversed as tabstop in ascending order starting from 1, -// with `$0` being a special case that always comes last. -// -// There is also a special placeholder, `${receiver}`, which will be replaced by the receiver expression for postfix snippets, or a `$0` tabstop in case of normal snippets. -// This replacement for normal snippets allows you to reuse a snippet for both post- and prefix in a single definition. -// -// For the VSCode editor, rust-analyzer also ships with a small set of defaults which can be removed -// by overwriting the settings object mentioned above, the defaults are: -// [source,json] -// ---- -// { -// "Arc::new": { -// "postfix": "arc", -// "body": "Arc::new(${receiver})", -// "requires": "std::sync::Arc", -// "description": "Put the expression into an `Arc`", -// "scope": "expr" -// }, -// "Rc::new": { -// "postfix": "rc", -// "body": "Rc::new(${receiver})", -// "requires": "std::rc::Rc", -// "description": "Put the expression into an `Rc`", -// "scope": "expr" -// }, -// "Box::pin": { -// "postfix": "pinbox", -// "body": "Box::pin(${receiver})", -// "requires": "std::boxed::Box", -// "description": "Put the expression into a pinned `Box`", -// "scope": "expr" -// }, -// "Ok": { -// "postfix": "ok", -// "body": "Ok(${receiver})", -// "description": "Wrap the expression in a `Result::Ok`", -// "scope": "expr" -// }, -// "Err": { -// "postfix": "err", -// "body": "Err(${receiver})", -// "description": "Wrap the expression in a `Result::Err`", -// "scope": "expr" -// }, -// "Some": { -// "postfix": "some", -// "body": "Some(${receiver})", -// "description": "Wrap the expression in an `Option::Some`", -// "scope": "expr" -// } -// } -// ---- - -use ide_db::imports::import_assets::LocatedImport; -use itertools::Itertools; -use syntax::{ast, AstNode, GreenNode, SyntaxNode}; - -use crate::context::CompletionContext; - -/// A snippet scope describing where a snippet may apply to. -/// These may differ slightly in meaning depending on the snippet trigger. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum SnippetScope { - Item, - Expr, - Type, -} - -/// A user supplied snippet. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Snippet { - pub postfix_triggers: Box<[Box]>, - pub prefix_triggers: Box<[Box]>, - pub scope: SnippetScope, - pub description: Option>, - snippet: String, - // These are `ast::Path`'s but due to SyntaxNodes not being Send we store these - // and reconstruct them on demand instead. This is cheaper than reparsing them - // from strings - requires: Box<[GreenNode]>, -} - -impl Snippet { - pub fn new( - prefix_triggers: &[String], - postfix_triggers: &[String], - snippet: &[String], - description: &str, - requires: &[String], - scope: SnippetScope, - ) -> Option { - if prefix_triggers.is_empty() && postfix_triggers.is_empty() { - return None; - } - let (requires, snippet, description) = validate_snippet(snippet, description, requires)?; - Some(Snippet { - // Box::into doesn't work as that has a Copy bound 😒 - postfix_triggers: postfix_triggers.iter().map(String::as_str).map(Into::into).collect(), - prefix_triggers: prefix_triggers.iter().map(String::as_str).map(Into::into).collect(), - scope, - snippet, - description, - requires, - }) - } - - /// Returns [`None`] if the required items do not resolve. - pub(crate) fn imports(&self, ctx: &CompletionContext<'_>) -> Option> { - import_edits(ctx, &self.requires) - } - - pub fn snippet(&self) -> String { - self.snippet.replace("${receiver}", "$0") - } - - pub fn postfix_snippet(&self, receiver: &str) -> String { - self.snippet.replace("${receiver}", receiver) - } -} - -fn import_edits(ctx: &CompletionContext<'_>, requires: &[GreenNode]) -> Option> { - let resolve = |import: &GreenNode| { - let path = ast::Path::cast(SyntaxNode::new_root(import.clone()))?; - let item = match ctx.scope.speculative_resolve(&path)? { - hir::PathResolution::Def(def) => def.into(), - _ => return None, - }; - let path = - ctx.module.find_use_path_prefixed(ctx.db, item, ctx.config.insert_use.prefix_kind)?; - Some((path.len() > 1).then(|| LocatedImport::new(path.clone(), item, item, None))) - }; - let mut res = Vec::with_capacity(requires.len()); - for import in requires { - match resolve(import) { - Some(first) => res.extend(first), - None => return None, - } - } - Some(res) -} - -fn validate_snippet( - snippet: &[String], - description: &str, - requires: &[String], -) -> Option<(Box<[GreenNode]>, String, Option>)> { - let mut imports = Vec::with_capacity(requires.len()); - for path in requires.iter() { - let use_path = ast::SourceFile::parse(&format!("use {};", path)) - .syntax_node() - .descendants() - .find_map(ast::Path::cast)?; - if use_path.syntax().text() != path.as_str() { - return None; - } - let green = use_path.syntax().green().into_owned(); - imports.push(green); - } - let snippet = snippet.iter().join("\n"); - let description = (!description.is_empty()) - .then(|| description.split_once('\n').map_or(description, |(it, _)| it)) - .map(ToOwned::to_owned) - .map(Into::into); - Some((imports.into_boxed_slice(), snippet, description)) -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs deleted file mode 100644 index 4be6acbe8461e..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs +++ /dev/null @@ -1,310 +0,0 @@ -//! Tests and test utilities for completions. -//! -//! Most tests live in this module or its submodules. The tests in these submodules are "location" -//! oriented, that is they try to check completions for something like type position, param position -//! etc. -//! Tests that are more orientated towards specific completion types like visibility checks of path -//! completions or `check_edit` tests usually live in their respective completion modules instead. -//! This gives this test module and its submodules here the main purpose of giving the developer an -//! overview of whats being completed where, not how. - -mod attribute; -mod expression; -mod flyimport; -mod fn_param; -mod item_list; -mod item; -mod pattern; -mod predicate; -mod proc_macros; -mod record; -mod special; -mod type_pos; -mod use_tree; -mod visibility; - -use std::mem; - -use hir::{db::DefDatabase, PrefixKind, Semantics}; -use ide_db::{ - base_db::{fixture::ChangeFixture, FileLoader, FilePosition}, - imports::insert_use::{ImportGranularity, InsertUseConfig}, - RootDatabase, SnippetCap, -}; -use itertools::Itertools; -use stdx::{format_to, trim_indent}; -use syntax::{AstNode, NodeOrToken, SyntaxElement}; -use test_utils::assert_eq_text; - -use crate::{ - resolve_completion_edits, CallableSnippets, CompletionConfig, CompletionItem, - CompletionItemKind, -}; - -/// Lots of basic item definitions -const BASE_ITEMS_FIXTURE: &str = r#" -enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV } -use self::Enum::TupleV; -mod module {} - -trait Trait {} -static STATIC: Unit = Unit; -const CONST: Unit = Unit; -struct Record { field: u32 } -struct Tuple(u32); -struct Unit; -#[macro_export] -macro_rules! makro {} -#[rustc_builtin_macro] -pub macro Clone {} -fn function() {} -union Union { field: i32 } -"#; - -pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { - enable_postfix_completions: true, - enable_imports_on_the_fly: true, - enable_self_on_the_fly: true, - enable_private_editable: false, - callable: Some(CallableSnippets::FillArguments), - snippet_cap: SnippetCap::new(true), - insert_use: InsertUseConfig { - granularity: ImportGranularity::Crate, - prefix_kind: PrefixKind::Plain, - enforce_granularity: true, - group: true, - skip_glob_imports: true, - }, - snippets: Vec::new(), -}; - -pub(crate) fn completion_list(ra_fixture: &str) -> String { - completion_list_with_config(TEST_CONFIG, ra_fixture, true, None) -} - -pub(crate) fn completion_list_no_kw(ra_fixture: &str) -> String { - completion_list_with_config(TEST_CONFIG, ra_fixture, false, None) -} - -pub(crate) fn completion_list_no_kw_with_private_editable(ra_fixture: &str) -> String { - let mut config = TEST_CONFIG.clone(); - config.enable_private_editable = true; - completion_list_with_config(config, ra_fixture, false, None) -} - -pub(crate) fn completion_list_with_trigger_character( - ra_fixture: &str, - trigger_character: Option, -) -> String { - completion_list_with_config(TEST_CONFIG, ra_fixture, true, trigger_character) -} - -fn completion_list_with_config( - config: CompletionConfig, - ra_fixture: &str, - include_keywords: bool, - trigger_character: Option, -) -> String { - // filter out all but one builtintype completion for smaller test outputs - let items = get_all_items(config, ra_fixture, trigger_character); - let mut bt_seen = false; - let items = items - .into_iter() - .filter(|it| { - it.kind() != CompletionItemKind::BuiltinType || !mem::replace(&mut bt_seen, true) - }) - .filter(|it| include_keywords || it.kind() != CompletionItemKind::Keyword) - .filter(|it| include_keywords || it.kind() != CompletionItemKind::Snippet) - .sorted_by_key(|it| (it.kind(), it.label().to_owned(), it.detail().map(ToOwned::to_owned))) - .collect(); - render_completion_list(items) -} - -/// Creates analysis from a multi-file fixture, returns positions marked with $0. -pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { - let change_fixture = ChangeFixture::parse(ra_fixture); - let mut database = RootDatabase::default(); - database.set_enable_proc_attr_macros(true); - database.apply_change(change_fixture.change); - let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); - let offset = range_or_offset.expect_offset(); - (database, FilePosition { file_id, offset }) -} - -pub(crate) fn do_completion(code: &str, kind: CompletionItemKind) -> Vec { - do_completion_with_config(TEST_CONFIG, code, kind) -} - -pub(crate) fn do_completion_with_config( - config: CompletionConfig, - code: &str, - kind: CompletionItemKind, -) -> Vec { - get_all_items(config, code, None) - .into_iter() - .filter(|c| c.kind() == kind) - .sorted_by(|l, r| l.label().cmp(r.label())) - .collect() -} - -fn render_completion_list(completions: Vec) -> String { - fn monospace_width(s: &str) -> usize { - s.chars().count() - } - let label_width = - completions.iter().map(|it| monospace_width(it.label())).max().unwrap_or_default().min(22); - completions - .into_iter() - .map(|it| { - let tag = it.kind().tag(); - let var_name = format!("{} {}", tag, it.label()); - let mut buf = var_name; - if let Some(detail) = it.detail() { - let width = label_width.saturating_sub(monospace_width(it.label())); - format_to!(buf, "{:width$} {}", "", detail, width = width); - } - if it.deprecated() { - format_to!(buf, " DEPRECATED"); - } - format_to!(buf, "\n"); - buf - }) - .collect() -} - -#[track_caller] -pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { - check_edit_with_config(TEST_CONFIG, what, ra_fixture_before, ra_fixture_after) -} - -#[track_caller] -pub(crate) fn check_edit_with_config( - config: CompletionConfig, - what: &str, - ra_fixture_before: &str, - ra_fixture_after: &str, -) { - let ra_fixture_after = trim_indent(ra_fixture_after); - let (db, position) = position(ra_fixture_before); - let completions: Vec = - crate::completions(&db, &config, position, None).unwrap().into(); - let (completion,) = completions - .iter() - .filter(|it| it.lookup() == what) - .collect_tuple() - .unwrap_or_else(|| panic!("can't find {:?} completion in {:#?}", what, completions)); - let mut actual = db.file_text(position.file_id).to_string(); - - let mut combined_edit = completion.text_edit().to_owned(); - - resolve_completion_edits( - &db, - &config, - position, - completion.imports_to_add().iter().filter_map(|import_edit| { - let import_path = &import_edit.import_path; - let import_name = import_path.segments().last()?; - Some((import_path.to_string(), import_name.to_string())) - }), - ) - .into_iter() - .flatten() - .for_each(|text_edit| { - combined_edit.union(text_edit).expect( - "Failed to apply completion resolve changes: change ranges overlap, but should not", - ) - }); - - combined_edit.apply(&mut actual); - assert_eq_text!(&ra_fixture_after, &actual) -} - -pub(crate) fn check_pattern_is_applicable(code: &str, check: impl FnOnce(SyntaxElement) -> bool) { - let (db, pos) = position(code); - - let sema = Semantics::new(&db); - let original_file = sema.parse(pos.file_id); - let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap(); - assert!(check(NodeOrToken::Token(token))); -} - -pub(crate) fn get_all_items( - config: CompletionConfig, - code: &str, - trigger_character: Option, -) -> Vec { - let (db, position) = position(code); - let res = crate::completions(&db, &config, position, trigger_character) - .map_or_else(Vec::default, Into::into); - // validate - res.iter().for_each(|it| { - let sr = it.source_range(); - assert!( - sr.contains_inclusive(position.offset), - "source range {sr:?} does not contain the offset {:?} of the completion request: {it:?}", - position.offset - ); - }); - res -} - -#[test] -fn test_no_completions_required() { - assert_eq!(completion_list(r#"fn foo() { for i i$0 }"#), String::new()); -} - -#[test] -fn regression_10042() { - completion_list( - r#" -macro_rules! preset { - ($($x:ident)&&*) => { - { - let mut v = Vec::new(); - $( - v.push($x.into()); - )* - v - } - }; -} - -fn foo() { - preset!(foo$0); -} -"#, - ); -} - -#[test] -fn no_completions_in_comments() { - assert_eq!( - completion_list( - r#" -fn test() { -let x = 2; // A comment$0 -} -"#, - ), - String::new(), - ); - assert_eq!( - completion_list( - r#" -/* -Some multi-line comment$0 -*/ -"#, - ), - String::new(), - ); - assert_eq!( - completion_list( - r#" -/// Some doc comment -/// let test$0 = 1 -"#, - ), - String::new(), - ); -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs deleted file mode 100644 index 1578ba2c37712..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs +++ /dev/null @@ -1,1016 +0,0 @@ -//! Completion tests for attributes. -use expect_test::{expect, Expect}; - -use crate::tests::{check_edit, completion_list}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); -} - -#[test] -fn proc_macros() { - check( - r#" -//- proc_macros: identity -#[$0] -struct Foo; -"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at derive(…) - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at forbid(…) - at must_use - at no_mangle - at non_exhaustive - at repr(…) - at warn(…) - md proc_macros - kw crate:: - kw self:: - "#]], - ) -} - -#[test] -fn proc_macros_on_comment() { - check( - r#" -//- proc_macros: identity -/// $0 -#[proc_macros::identity] -struct Foo; -"#, - expect![[r#""#]], - ) -} - -#[test] -fn proc_macros_qualified() { - check( - r#" -//- proc_macros: identity -#[proc_macros::$0] -struct Foo; -"#, - expect![[r#" - at identity proc_macro identity - "#]], - ) -} - -#[test] -fn inside_nested_attr() { - check(r#"#[cfg($0)]"#, expect![[]]) -} - -#[test] -fn with_existing_attr() { - check( - r#"#[no_mangle] #[$0] mcall!();"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at forbid(…) - at warn(…) - kw crate:: - kw self:: - "#]], - ) -} - -#[test] -fn attr_on_source_file() { - check( - r#"#![$0]"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at crate_name = "" - at deny(…) - at deprecated - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at feature(…) - at forbid(…) - at must_use - at no_implicit_prelude - at no_main - at no_mangle - at no_std - at recursion_limit = "…" - at type_length_limit = … - at warn(…) - at windows_subsystem = "…" - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn attr_on_module() { - check( - r#"#[$0] mod foo;"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at forbid(…) - at macro_use - at must_use - at no_mangle - at path = "…" - at warn(…) - kw crate:: - kw self:: - kw super:: - "#]], - ); - check( - r#"mod foo {#![$0]}"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at forbid(…) - at must_use - at no_implicit_prelude - at no_mangle - at warn(…) - kw crate:: - kw self:: - kw super:: - "#]], - ); -} - -#[test] -fn attr_on_macro_rules() { - check( - r#"#[$0] macro_rules! foo {}"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at forbid(…) - at macro_export - at macro_use - at must_use - at no_mangle - at warn(…) - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn attr_on_macro_def() { - check( - r#"#[$0] macro foo {}"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at forbid(…) - at must_use - at no_mangle - at warn(…) - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn attr_on_extern_crate() { - check( - r#"#[$0] extern crate foo;"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at forbid(…) - at macro_use - at must_use - at no_mangle - at warn(…) - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn attr_on_use() { - check( - r#"#[$0] use foo;"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at forbid(…) - at must_use - at no_mangle - at warn(…) - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn attr_on_type_alias() { - check( - r#"#[$0] type foo = ();"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at forbid(…) - at must_use - at no_mangle - at warn(…) - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn attr_on_struct() { - check( - r#" -//- minicore:derive -#[$0] -struct Foo; -"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at derive macro derive - at derive(…) - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at forbid(…) - at must_use - at no_mangle - at non_exhaustive - at repr(…) - at warn(…) - md core - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn attr_on_enum() { - check( - r#"#[$0] enum Foo {}"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at derive(…) - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at forbid(…) - at must_use - at no_mangle - at non_exhaustive - at repr(…) - at warn(…) - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn attr_on_const() { - check( - r#"#[$0] const FOO: () = ();"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at forbid(…) - at must_use - at no_mangle - at warn(…) - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn attr_on_static() { - check( - r#"#[$0] static FOO: () = ()"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at export_name = "…" - at forbid(…) - at global_allocator - at link_name = "…" - at link_section = "…" - at must_use - at no_mangle - at used - at warn(…) - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn attr_on_trait() { - check( - r#"#[$0] trait Foo {}"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at forbid(…) - at must_use - at must_use - at no_mangle - at warn(…) - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn attr_on_impl() { - check( - r#"#[$0] impl () {}"#, - expect![[r#" - at allow(…) - at automatically_derived - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at forbid(…) - at must_use - at no_mangle - at warn(…) - kw crate:: - kw self:: - "#]], - ); - check( - r#"impl () {#![$0]}"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at forbid(…) - at must_use - at no_mangle - at warn(…) - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn attr_on_extern_block() { - check( - r#"#[$0] extern {}"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at forbid(…) - at link - at must_use - at no_mangle - at warn(…) - kw crate:: - kw self:: - "#]], - ); - check( - r#"extern {#![$0]}"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at deprecated - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at forbid(…) - at link - at must_use - at no_mangle - at warn(…) - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn attr_on_variant() { - check( - r#"enum Foo { #[$0] Bar }"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at deny(…) - at forbid(…) - at non_exhaustive - at warn(…) - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn attr_on_fn() { - check( - r#"#[$0] fn main() {}"#, - expect![[r#" - at allow(…) - at cfg(…) - at cfg_attr(…) - at cold - at deny(…) - at deprecated - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at export_name = "…" - at forbid(…) - at ignore = "…" - at inline - at link_name = "…" - at link_section = "…" - at must_use - at must_use - at no_mangle - at panic_handler - at proc_macro - at proc_macro_attribute - at proc_macro_derive(…) - at should_panic - at target_feature(enable = "…") - at test - at track_caller - at warn(…) - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn attr_in_source_file_end() { - check( - r#"#[$0]"#, - expect![[r#" - at allow(…) - at automatically_derived - at cfg(…) - at cfg_attr(…) - at cold - at deny(…) - at deprecated - at derive(…) - at doc = "…" - at doc(alias = "…") - at doc(hidden) - at export_name = "…" - at forbid(…) - at global_allocator - at ignore = "…" - at inline - at link - at link_name = "…" - at link_section = "…" - at macro_export - at macro_use - at must_use - at no_mangle - at non_exhaustive - at panic_handler - at path = "…" - at proc_macro - at proc_macro_attribute - at proc_macro_derive(…) - at repr(…) - at should_panic - at target_feature(enable = "…") - at test - at track_caller - at used - at warn(…) - kw crate:: - kw self:: - "#]], - ); -} - -mod cfg { - use super::*; - - #[test] - fn cfg_target_endian() { - check( - r#"#[cfg(target_endian = $0"#, - expect![[r#" - ba big - ba little - "#]], - ); - } -} - -mod derive { - use super::*; - - fn check_derive(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); - } - - #[test] - fn no_completion_for_incorrect_derive() { - check_derive( - r#" -//- minicore: derive, copy, clone, ord, eq, default, fmt -#[derive{$0)] struct Test; -"#, - expect![[]], - ) - } - - #[test] - fn empty_derive() { - check_derive( - r#" -//- minicore: derive, copy, clone, ord, eq, default, fmt -#[derive($0)] struct Test; -"#, - expect![[r#" - de Clone macro Clone - de Clone, Copy - de Default macro Default - de PartialEq macro PartialEq - de PartialEq, Eq - de PartialEq, Eq, PartialOrd, Ord - de PartialEq, PartialOrd - md core - kw crate:: - kw self:: - "#]], - ); - } - - #[test] - fn derive_with_input_before() { - check_derive( - r#" -//- minicore: derive, copy, clone, ord, eq, default, fmt -#[derive(serde::Serialize, PartialEq, $0)] struct Test; -"#, - expect![[r#" - de Clone macro Clone - de Clone, Copy - de Default macro Default - de Eq - de Eq, PartialOrd, Ord - de PartialOrd - md core - kw crate:: - kw self:: - "#]], - ) - } - - #[test] - fn derive_with_input_after() { - check_derive( - r#" -//- minicore: derive, copy, clone, ord, eq, default, fmt -#[derive($0 serde::Serialize, PartialEq)] struct Test; -"#, - expect![[r#" - de Clone macro Clone - de Clone, Copy - de Default macro Default - de Eq - de Eq, PartialOrd, Ord - de PartialOrd - md core - kw crate:: - kw self:: - "#]], - ); - } - - #[test] - fn derive_with_existing_derives() { - check_derive( - r#" -//- minicore: derive, copy, clone, ord, eq, default, fmt -#[derive(PartialEq, Eq, Or$0)] struct Test; -"#, - expect![[r#" - de Clone macro Clone - de Clone, Copy - de Default macro Default - de PartialOrd - de PartialOrd, Ord - md core - kw crate:: - kw self:: - "#]], - ); - } - - #[test] - fn derive_flyimport() { - check_derive( - r#" -//- proc_macros: derive_identity -//- minicore: derive -#[derive(der$0)] struct Test; -"#, - expect![[r#" - de DeriveIdentity (use proc_macros::DeriveIdentity) proc_macro DeriveIdentity - md core - md proc_macros - kw crate:: - kw self:: - "#]], - ); - check_derive( - r#" -//- proc_macros: derive_identity -//- minicore: derive -use proc_macros::DeriveIdentity; -#[derive(der$0)] struct Test; -"#, - expect![[r#" - de DeriveIdentity proc_macro DeriveIdentity - md core - md proc_macros - kw crate:: - kw self:: - "#]], - ); - } - - #[test] - fn derive_flyimport_edit() { - check_edit( - "DeriveIdentity", - r#" -//- proc_macros: derive_identity -//- minicore: derive -#[derive(der$0)] struct Test; -"#, - r#" -use proc_macros::DeriveIdentity; - -#[derive(DeriveIdentity)] struct Test; -"#, - ); - } - - #[test] - fn qualified() { - check_derive( - r#" -//- proc_macros: derive_identity -//- minicore: derive, copy, clone -#[derive(proc_macros::$0)] struct Test; -"#, - expect![[r#" - de DeriveIdentity proc_macro DeriveIdentity - "#]], - ); - check_derive( - r#" -//- proc_macros: derive_identity -//- minicore: derive, copy, clone -#[derive(proc_macros::C$0)] struct Test; -"#, - expect![[r#" - de DeriveIdentity proc_macro DeriveIdentity - "#]], - ); - } -} - -mod lint { - use super::*; - - #[test] - fn lint_empty() { - check_edit( - "deprecated", - r#"#[allow($0)] struct Test;"#, - r#"#[allow(deprecated)] struct Test;"#, - ) - } - - #[test] - fn lint_with_existing() { - check_edit( - "deprecated", - r#"#[allow(keyword_idents, $0)] struct Test;"#, - r#"#[allow(keyword_idents, deprecated)] struct Test;"#, - ) - } - - #[test] - fn lint_qualified() { - check_edit( - "deprecated", - r#"#[allow(keyword_idents, $0)] struct Test;"#, - r#"#[allow(keyword_idents, deprecated)] struct Test;"#, - ) - } - - #[test] - fn lint_feature() { - check_edit( - "box_syntax", - r#"#[feature(box_$0)] struct Test;"#, - r#"#[feature(box_syntax)] struct Test;"#, - ) - } - - #[test] - fn lint_clippy_unqualified() { - check_edit( - "clippy::as_conversions", - r#"#[allow($0)] struct Test;"#, - r#"#[allow(clippy::as_conversions)] struct Test;"#, - ); - } - - #[test] - fn lint_clippy_qualified() { - check_edit( - "as_conversions", - r#"#[allow(clippy::$0)] struct Test;"#, - r#"#[allow(clippy::as_conversions)] struct Test;"#, - ); - } - - #[test] - fn lint_rustdoc_unqualified() { - check_edit( - "rustdoc::bare_urls", - r#"#[allow($0)] struct Test;"#, - r#"#[allow(rustdoc::bare_urls)] struct Test;"#, - ); - } - - #[test] - fn lint_rustdoc_qualified() { - check_edit( - "bare_urls", - r#"#[allow(rustdoc::$0)] struct Test;"#, - r#"#[allow(rustdoc::bare_urls)] struct Test;"#, - ); - } - - #[test] - fn lint_unclosed() { - check_edit( - "deprecated", - r#"#[allow(dep$0 struct Test;"#, - r#"#[allow(deprecated struct Test;"#, - ); - check_edit( - "bare_urls", - r#"#[allow(rustdoc::$0 struct Test;"#, - r#"#[allow(rustdoc::bare_urls struct Test;"#, - ); - } -} - -mod repr { - use super::*; - - fn check_repr(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); - } - - #[test] - fn no_completion_for_incorrect_repr() { - check_repr(r#"#[repr{$0)] struct Test;"#, expect![[]]) - } - - #[test] - fn empty() { - check_repr( - r#"#[repr($0)] struct Test;"#, - expect![[r#" - ba C - ba align($0) - ba i16 - ba i28 - ba i32 - ba i64 - ba i8 - ba isize - ba packed - ba transparent - ba u128 - ba u16 - ba u32 - ba u64 - ba u8 - ba usize - "#]], - ); - } - - #[test] - fn transparent() { - check_repr(r#"#[repr(transparent, $0)] struct Test;"#, expect![[r#""#]]); - } - - #[test] - fn align() { - check_repr( - r#"#[repr(align(1), $0)] struct Test;"#, - expect![[r#" - ba C - ba i16 - ba i28 - ba i32 - ba i64 - ba i8 - ba isize - ba transparent - ba u128 - ba u16 - ba u32 - ba u64 - ba u8 - ba usize - "#]], - ); - } - - #[test] - fn packed() { - check_repr( - r#"#[repr(packed, $0)] struct Test;"#, - expect![[r#" - ba C - ba i16 - ba i28 - ba i32 - ba i64 - ba i8 - ba isize - ba transparent - ba u128 - ba u16 - ba u32 - ba u64 - ba u8 - ba usize - "#]], - ); - } - - #[test] - fn c() { - check_repr( - r#"#[repr(C, $0)] struct Test;"#, - expect![[r#" - ba align($0) - ba i16 - ba i28 - ba i32 - ba i64 - ba i8 - ba isize - ba packed - ba u128 - ba u16 - ba u32 - ba u64 - ba u8 - ba usize - "#]], - ); - } - - #[test] - fn prim() { - check_repr( - r#"#[repr(usize, $0)] struct Test;"#, - expect![[r#" - ba C - ba align($0) - ba packed - "#]], - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs deleted file mode 100644 index ce9d01d337bae..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ /dev/null @@ -1,655 +0,0 @@ -//! Completion tests for expressions. -use expect_test::{expect, Expect}; - -use crate::tests::{completion_list, BASE_ITEMS_FIXTURE}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{}{}", BASE_ITEMS_FIXTURE, ra_fixture)); - expect.assert_eq(&actual) -} - -fn check_empty(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); -} - -#[test] -fn complete_literal_struct_with_a_private_field() { - // `FooDesc.bar` is private, the completion should not be triggered. - check( - r#" -mod _69latrick { - pub struct FooDesc { pub six: bool, pub neuf: Vec, bar: bool } - pub fn create_foo(foo_desc: &FooDesc) -> () { () } -} - -fn baz() { - use _69latrick::*; - - let foo = create_foo(&$0); -} - "#, - // This should not contain `FooDesc {…}`. - expect![[r#" - ct CONST - en Enum - fn baz() fn() - fn create_foo(…) fn(&FooDesc) - fn function() fn() - ma makro!(…) macro_rules! makro - md _69latrick - md module - sc STATIC - st FooDesc - st Record - st Tuple - st Unit - tt Trait - un Union - ev TupleV(…) TupleV(u32) - bt u32 - kw crate:: - kw false - kw for - kw if - kw if let - kw loop - kw match - kw mut - kw return - kw self:: - kw true - kw unsafe - kw while - kw while let - "#]], - ) -} - -#[test] -fn completes_various_bindings() { - check_empty( - r#" -fn func(param0 @ (param1, param2): (i32, i32)) { - let letlocal = 92; - if let ifletlocal = 100 { - match 0 { - matcharm => 1 + $0, - otherwise => (), - } - } - let letlocal2 = 44; -} -"#, - expect![[r#" - fn func(…) fn((i32, i32)) - lc ifletlocal i32 - lc letlocal i32 - lc matcharm i32 - lc param0 (i32, i32) - lc param1 i32 - lc param2 i32 - bt u32 - kw crate:: - kw false - kw for - kw if - kw if let - kw loop - kw match - kw return - kw self:: - kw true - kw unsafe - kw while - kw while let - "#]], - ); -} - -#[test] -fn completes_all_the_things_in_fn_body() { - check( - r#" -use non_existant::Unresolved; -mod qualified { pub enum Enum { Variant } } - -impl Unit { - fn foo<'lifetime, TypeParam, const CONST_PARAM: usize>(self) { - fn local_func() {} - $0 - } -} -"#, - // `self` is in here twice, once as the module, once as the local - expect![[r#" - ct CONST - cp CONST_PARAM - en Enum - fn function() fn() - fn local_func() fn() - lc self Unit - ma makro!(…) macro_rules! makro - md module - md qualified - sp Self - sc STATIC - st Record - st Tuple - st Unit - tt Trait - tp TypeParam - un Union - ev TupleV(…) TupleV(u32) - bt u32 - kw const - kw crate:: - kw enum - kw extern - kw false - kw fn - kw for - kw if - kw if let - kw impl - kw let - kw loop - kw match - kw mod - kw return - kw self:: - kw static - kw struct - kw trait - kw true - kw type - kw union - kw unsafe - kw use - kw while - kw while let - me self.foo() fn(self) - sn macro_rules - sn pd - sn ppd - ?? Unresolved - "#]], - ); - check( - r#" -use non_existant::Unresolved; -mod qualified { pub enum Enum { Variant } } - -impl Unit { - fn foo<'lifetime, TypeParam, const CONST_PARAM: usize>(self) { - fn local_func() {} - self::$0 - } -} -"#, - expect![[r#" - ct CONST - en Enum - fn function() fn() - ma makro!(…) macro_rules! makro - md module - md qualified - sc STATIC - st Record - st Tuple - st Unit - tt Trait - un Union - ev TupleV(…) TupleV(u32) - ?? Unresolved - "#]], - ); -} - -#[test] -fn complete_in_block() { - check_empty( - r#" - fn foo() { - if true { - $0 - } - } -"#, - expect![[r#" - fn foo() fn() - bt u32 - kw const - kw crate:: - kw enum - kw extern - kw false - kw fn - kw for - kw if - kw if let - kw impl - kw let - kw loop - kw match - kw mod - kw return - kw self:: - kw static - kw struct - kw trait - kw true - kw type - kw union - kw unsafe - kw use - kw while - kw while let - sn macro_rules - sn pd - sn ppd - "#]], - ) -} - -#[test] -fn complete_after_if_expr() { - check_empty( - r#" - fn foo() { - if true {} - $0 - } -"#, - expect![[r#" - fn foo() fn() - bt u32 - kw const - kw crate:: - kw else - kw else if - kw enum - kw extern - kw false - kw fn - kw for - kw if - kw if let - kw impl - kw let - kw loop - kw match - kw mod - kw return - kw self:: - kw static - kw struct - kw trait - kw true - kw type - kw union - kw unsafe - kw use - kw while - kw while let - sn macro_rules - sn pd - sn ppd - "#]], - ) -} - -#[test] -fn complete_in_match_arm() { - check_empty( - r#" - fn foo() { - match () { - () => $0 - } - } -"#, - expect![[r#" - fn foo() fn() - bt u32 - kw crate:: - kw false - kw for - kw if - kw if let - kw loop - kw match - kw return - kw self:: - kw true - kw unsafe - kw while - kw while let - "#]], - ) -} - -#[test] -fn completes_in_loop_ctx() { - check_empty( - r"fn my() { loop { $0 } }", - expect![[r#" - fn my() fn() - bt u32 - kw break - kw const - kw continue - kw crate:: - kw enum - kw extern - kw false - kw fn - kw for - kw if - kw if let - kw impl - kw let - kw loop - kw match - kw mod - kw return - kw self:: - kw static - kw struct - kw trait - kw true - kw type - kw union - kw unsafe - kw use - kw while - kw while let - sn macro_rules - sn pd - sn ppd - "#]], - ); -} - -#[test] -fn completes_in_let_initializer() { - check_empty( - r#"fn main() { let _ = $0 }"#, - expect![[r#" - fn main() fn() - bt u32 - kw crate:: - kw false - kw for - kw if - kw if let - kw loop - kw match - kw return - kw self:: - kw true - kw unsafe - kw while - kw while let - "#]], - ) -} - -#[test] -fn struct_initializer_field_expr() { - check_empty( - r#" -struct Foo { - pub f: i32, -} -fn foo() { - Foo { - f: $0 - } -} -"#, - expect![[r#" - fn foo() fn() - st Foo - bt u32 - kw crate:: - kw false - kw for - kw if - kw if let - kw loop - kw match - kw return - kw self:: - kw true - kw unsafe - kw while - kw while let - "#]], - ); -} - -#[test] -fn shadowing_shows_single_completion() { - cov_mark::check!(shadowing_shows_single_completion); - - check_empty( - r#" -fn foo() { - let bar = 92; - { - let bar = 62; - drop($0) - } -} -"#, - expect![[r#" - fn foo() fn() - lc bar i32 - bt u32 - kw crate:: - kw false - kw for - kw if - kw if let - kw loop - kw match - kw return - kw self:: - kw true - kw unsafe - kw while - kw while let - "#]], - ); -} - -#[test] -fn in_macro_expr_frag() { - check_empty( - r#" -macro_rules! m { ($e:expr) => { $e } } -fn quux(x: i32) { - m!($0); -} -"#, - expect![[r#" - fn quux(…) fn(i32) - lc x i32 - ma m!(…) macro_rules! m - bt u32 - kw crate:: - kw false - kw for - kw if - kw if let - kw loop - kw match - kw return - kw self:: - kw true - kw unsafe - kw while - kw while let - "#]], - ); - check_empty( - r" -macro_rules! m { ($e:expr) => { $e } } -fn quux(x: i32) { - m!(x$0); -} -", - expect![[r#" - fn quux(…) fn(i32) - lc x i32 - ma m!(…) macro_rules! m - bt u32 - kw crate:: - kw false - kw for - kw if - kw if let - kw loop - kw match - kw return - kw self:: - kw true - kw unsafe - kw while - kw while let - "#]], - ); - check_empty( - r#" -macro_rules! m { ($e:expr) => { $e } } -fn quux(x: i32) { - let y = 92; - m!(x$0 -} -"#, - expect![[r#""#]], - ); -} - -#[test] -fn enum_qualified() { - check( - r#" -impl Enum { - type AssocType = (); - const ASSOC_CONST: () = (); - fn assoc_fn() {} -} -fn func() { - Enum::$0 -} -"#, - expect![[r#" - ct ASSOC_CONST const ASSOC_CONST: () - fn assoc_fn() fn() - ta AssocType type AssocType = () - ev RecordV {…} RecordV { field: u32 } - ev TupleV(…) TupleV(u32) - ev UnitV UnitV - "#]], - ); -} - -#[test] -fn ty_qualified_no_drop() { - check_empty( - r#" -//- minicore: drop -struct Foo; -impl Drop for Foo { - fn drop(&mut self) {} -} -fn func() { - Foo::$0 -} -"#, - expect![[r#""#]], - ); -} - -#[test] -fn with_parens() { - check_empty( - r#" -enum Enum { - Variant() -} -impl Enum { - fn variant() -> Self { Enum::Variant() } -} -fn func() { - Enum::$0() -} -"#, - expect![[r#" - fn variant fn() -> Enum - ev Variant Variant - "#]], - ); -} - -#[test] -fn detail_impl_trait_in_return_position() { - check_empty( - r" -//- minicore: sized -trait Trait {} -fn foo() -> impl Trait {} -fn main() { - self::$0 -} -", - expect![[r#" - fn foo() fn() -> impl Trait - fn main() fn() - tt Trait - "#]], - ); -} - -#[test] -fn detail_async_fn() { - check_empty( - r#" -//- minicore: future, sized -trait Trait {} -async fn foo() -> u8 {} -async fn bar() -> impl Trait {} -fn main() { - self::$0 -} -"#, - expect![[r#" - fn bar() async fn() -> impl Trait - fn foo() async fn() -> u8 - fn main() fn() - tt Trait - "#]], - ); -} - -#[test] -fn detail_impl_trait_in_argument_position() { - check_empty( - r" -//- minicore: sized -trait Trait {} -struct Foo; -impl Foo { - fn bar(_: impl Trait) {} -} -fn main() { - Foo::$0 -} -", - expect![[r" - fn bar(…) fn(impl Trait) - "]], - ); -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs deleted file mode 100644 index 0bba7f2459caf..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs +++ /dev/null @@ -1,1232 +0,0 @@ -use expect_test::{expect, Expect}; - -use crate::{ - context::{CompletionAnalysis, NameContext, NameKind, NameRefKind}, - tests::{check_edit, check_edit_with_config, TEST_CONFIG}, -}; - -fn check(ra_fixture: &str, expect: Expect) { - let config = TEST_CONFIG; - let (db, position) = crate::tests::position(ra_fixture); - let (ctx, analysis) = crate::context::CompletionContext::new(&db, position, &config).unwrap(); - - let mut acc = crate::completions::Completions::default(); - if let CompletionAnalysis::Name(NameContext { kind: NameKind::IdentPat(pat_ctx), .. }) = - &analysis - { - crate::completions::flyimport::import_on_the_fly_pat(&mut acc, &ctx, pat_ctx); - } - if let CompletionAnalysis::NameRef(name_ref_ctx) = &analysis { - match &name_ref_ctx.kind { - NameRefKind::Path(path) => { - crate::completions::flyimport::import_on_the_fly_path(&mut acc, &ctx, path); - } - NameRefKind::DotAccess(dot_access) => { - crate::completions::flyimport::import_on_the_fly_dot(&mut acc, &ctx, dot_access); - } - NameRefKind::Pattern(pattern) => { - crate::completions::flyimport::import_on_the_fly_pat(&mut acc, &ctx, pattern); - } - _ => (), - } - } - - expect.assert_eq(&super::render_completion_list(Vec::from(acc))); -} - -#[test] -fn function_fuzzy_completion() { - check_edit( - "stdin", - r#" -//- /lib.rs crate:dep -pub mod io { - pub fn stdin() {} -}; - -//- /main.rs crate:main deps:dep -fn main() { - stdi$0 -} -"#, - r#" -use dep::io::stdin; - -fn main() { - stdin()$0 -} -"#, - ); -} - -#[test] -fn macro_fuzzy_completion() { - check_edit( - "macro_with_curlies!", - r#" -//- /lib.rs crate:dep -/// Please call me as macro_with_curlies! {} -#[macro_export] -macro_rules! macro_with_curlies { - () => {} -} - -//- /main.rs crate:main deps:dep -fn main() { - curli$0 -} -"#, - r#" -use dep::macro_with_curlies; - -fn main() { - macro_with_curlies! {$0} -} -"#, - ); -} - -#[test] -fn struct_fuzzy_completion() { - check_edit( - "ThirdStruct", - r#" -//- /lib.rs crate:dep -pub struct FirstStruct; -pub mod some_module { - pub struct SecondStruct; - pub struct ThirdStruct; -} - -//- /main.rs crate:main deps:dep -use dep::{FirstStruct, some_module::SecondStruct}; - -fn main() { - this$0 -} -"#, - r#" -use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; - -fn main() { - ThirdStruct -} -"#, - ); -} - -#[test] -fn short_paths_are_ignored() { - cov_mark::check!(flyimport_exact_on_short_path); - - check( - r#" -//- /lib.rs crate:dep -pub struct Bar; -pub struct Rcar; -pub struct Rc; -pub mod some_module { - pub struct Bar; - pub struct Rcar; - pub struct Rc; -} - -//- /main.rs crate:main deps:dep -fn main() { - rc$0 -} -"#, - expect![[r#" - st Rc (use dep::Rc) - st Rc (use dep::some_module::Rc) - "#]], - ); -} - -#[test] -fn fuzzy_completions_come_in_specific_order() { - cov_mark::check!(certain_fuzzy_order_test); - check( - r#" -//- /lib.rs crate:dep -pub struct FirstStruct; -pub mod some_module { - // already imported, omitted - pub struct SecondStruct; - // does not contain all letters from the query, omitted - pub struct UnrelatedOne; - // contains all letters from the query, but not in sequence, displayed last - pub struct ThiiiiiirdStruct; - // contains all letters from the query, but not in the beginning, displayed second - pub struct AfterThirdStruct; - // contains all letters from the query in the begginning, displayed first - pub struct ThirdStruct; -} - -//- /main.rs crate:main deps:dep -use dep::{FirstStruct, some_module::SecondStruct}; - -fn main() { - hir$0 -} -"#, - expect![[r#" - st ThirdStruct (use dep::some_module::ThirdStruct) - st AfterThirdStruct (use dep::some_module::AfterThirdStruct) - st ThiiiiiirdStruct (use dep::some_module::ThiiiiiirdStruct) - "#]], - ); -} - -#[test] -fn trait_function_fuzzy_completion() { - let fixture = r#" - //- /lib.rs crate:dep - pub mod test_mod { - pub trait TestTrait { - const SPECIAL_CONST: u8; - type HumbleType; - fn weird_function(); - fn random_method(&self); - } - pub struct TestStruct {} - impl TestTrait for TestStruct { - const SPECIAL_CONST: u8 = 42; - type HumbleType = (); - fn weird_function() {} - fn random_method(&self) {} - } - } - - //- /main.rs crate:main deps:dep - fn main() { - dep::test_mod::TestStruct::wei$0 - } - "#; - - check( - fixture, - expect![[r#" - fn weird_function() (use dep::test_mod::TestTrait) fn() - "#]], - ); - - check_edit( - "weird_function", - fixture, - r#" -use dep::test_mod::TestTrait; - -fn main() { - dep::test_mod::TestStruct::weird_function()$0 -} -"#, - ); -} - -#[test] -fn trait_const_fuzzy_completion() { - let fixture = r#" - //- /lib.rs crate:dep - pub mod test_mod { - pub trait TestTrait { - const SPECIAL_CONST: u8; - type HumbleType; - fn weird_function(); - fn random_method(&self); - } - pub struct TestStruct {} - impl TestTrait for TestStruct { - const SPECIAL_CONST: u8 = 42; - type HumbleType = (); - fn weird_function() {} - fn random_method(&self) {} - } - } - - //- /main.rs crate:main deps:dep - fn main() { - dep::test_mod::TestStruct::spe$0 - } - "#; - - check( - fixture, - expect![[r#" - ct SPECIAL_CONST (use dep::test_mod::TestTrait) - "#]], - ); - - check_edit( - "SPECIAL_CONST", - fixture, - r#" -use dep::test_mod::TestTrait; - -fn main() { - dep::test_mod::TestStruct::SPECIAL_CONST -} -"#, - ); -} - -#[test] -fn trait_method_fuzzy_completion() { - let fixture = r#" - //- /lib.rs crate:dep - pub mod test_mod { - pub trait TestTrait { - const SPECIAL_CONST: u8; - type HumbleType; - fn weird_function(); - fn random_method(&self); - } - pub struct TestStruct {} - impl TestTrait for TestStruct { - const SPECIAL_CONST: u8 = 42; - type HumbleType = (); - fn weird_function() {} - fn random_method(&self) {} - } - } - - //- /main.rs crate:main deps:dep - fn main() { - let test_struct = dep::test_mod::TestStruct {}; - test_struct.ran$0 - } - "#; - - check( - fixture, - expect![[r#" - me random_method() (use dep::test_mod::TestTrait) fn(&self) - "#]], - ); - - check_edit( - "random_method", - fixture, - r#" -use dep::test_mod::TestTrait; - -fn main() { - let test_struct = dep::test_mod::TestStruct {}; - test_struct.random_method()$0 -} -"#, - ); -} - -#[test] -fn trait_method_from_alias() { - let fixture = r#" -//- /lib.rs crate:dep -pub mod test_mod { - pub trait TestTrait { - fn random_method(); - } - pub struct TestStruct {} - impl TestTrait for TestStruct { - fn random_method() {} - } - pub type TestAlias = TestStruct; -} - -//- /main.rs crate:main deps:dep -fn main() { - dep::test_mod::TestAlias::ran$0 -} -"#; - - check( - fixture, - expect![[r#" - fn random_method() (use dep::test_mod::TestTrait) fn() - "#]], - ); - - check_edit( - "random_method", - fixture, - r#" -use dep::test_mod::TestTrait; - -fn main() { - dep::test_mod::TestAlias::random_method()$0 -} -"#, - ); -} - -#[test] -fn no_trait_type_fuzzy_completion() { - check( - r#" -//- /lib.rs crate:dep -pub mod test_mod { - pub trait TestTrait { - const SPECIAL_CONST: u8; - type HumbleType; - fn weird_function(); - fn random_method(&self); - } - pub struct TestStruct {} - impl TestTrait for TestStruct { - const SPECIAL_CONST: u8 = 42; - type HumbleType = (); - fn weird_function() {} - fn random_method(&self) {} - } -} - -//- /main.rs crate:main deps:dep -fn main() { - dep::test_mod::TestStruct::hum$0 -} -"#, - expect![[r#""#]], - ); -} - -#[test] -fn does_not_propose_names_in_scope() { - check( - r#" -//- /lib.rs crate:dep -pub mod test_mod { - pub trait TestTrait { - const SPECIAL_CONST: u8; - type HumbleType; - fn weird_function(); - fn random_method(&self); - } - pub struct TestStruct {} - impl TestTrait for TestStruct { - const SPECIAL_CONST: u8 = 42; - type HumbleType = (); - fn weird_function() {} - fn random_method(&self) {} - } -} - -//- /main.rs crate:main deps:dep -use dep::test_mod::TestStruct; -fn main() { - TestSt$0 -} -"#, - expect![[r#""#]], - ); -} - -#[test] -fn does_not_propose_traits_in_scope() { - check( - r#" -//- /lib.rs crate:dep -pub mod test_mod { - pub trait TestTrait { - const SPECIAL_CONST: u8; - type HumbleType; - fn weird_function(); - fn random_method(&self); - } - pub struct TestStruct {} - impl TestTrait for TestStruct { - const SPECIAL_CONST: u8 = 42; - type HumbleType = (); - fn weird_function() {} - fn random_method(&self) {} - } -} - -//- /main.rs crate:main deps:dep -use dep::test_mod::{TestStruct, TestTrait}; -fn main() { - dep::test_mod::TestStruct::hum$0 -} -"#, - expect![[r#""#]], - ); -} - -#[test] -fn blanket_trait_impl_import() { - check_edit( - "another_function", - r#" -//- /lib.rs crate:dep -pub mod test_mod { - pub struct TestStruct {} - pub trait TestTrait { - fn another_function(); - } - impl TestTrait for T { - fn another_function() {} - } -} - -//- /main.rs crate:main deps:dep -fn main() { - dep::test_mod::TestStruct::ano$0 -} -"#, - r#" -use dep::test_mod::TestTrait; - -fn main() { - dep::test_mod::TestStruct::another_function()$0 -} -"#, - ); -} - -#[test] -fn zero_input_deprecated_assoc_item_completion() { - check( - r#" -//- /lib.rs crate:dep -pub mod test_mod { - #[deprecated] - pub trait TestTrait { - const SPECIAL_CONST: u8; - type HumbleType; - fn weird_function(); - fn random_method(&self); - } - pub struct TestStruct {} - impl TestTrait for TestStruct { - const SPECIAL_CONST: u8 = 42; - type HumbleType = (); - fn weird_function() {} - fn random_method(&self) {} - } -} - -//- /main.rs crate:main deps:dep -fn main() { - let test_struct = dep::test_mod::TestStruct {}; - test_struct.$0 -} - "#, - expect![[r#" - me random_method() (use dep::test_mod::TestTrait) fn(&self) DEPRECATED - "#]], - ); - - check( - r#" -//- /lib.rs crate:dep -pub mod test_mod { - #[deprecated] - pub trait TestTrait { - const SPECIAL_CONST: u8; - type HumbleType; - fn weird_function(); - fn random_method(&self); - } - pub struct TestStruct {} - impl TestTrait for TestStruct { - const SPECIAL_CONST: u8 = 42; - type HumbleType = (); - fn weird_function() {} - fn random_method(&self) {} - } -} - -//- /main.rs crate:main deps:dep -fn main() { - dep::test_mod::TestStruct::$0 -} -"#, - expect![[r#" - fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED - ct SPECIAL_CONST (use dep::test_mod::TestTrait) DEPRECATED - "#]], - ); -} - -#[test] -fn no_completions_in_use_statements() { - check( - r#" -//- /lib.rs crate:dep -pub mod io { - pub fn stdin() {} -}; - -//- /main.rs crate:main deps:dep -use stdi$0 - -fn main() {} -"#, - expect![[]], - ); -} - -#[test] -fn prefix_config_usage() { - let fixture = r#" -mod foo { - pub mod bar { - pub struct Item; - } -} - -use crate::foo::bar; - -fn main() { - Ite$0 -}"#; - let mut config = TEST_CONFIG; - - config.insert_use.prefix_kind = hir::PrefixKind::ByCrate; - check_edit_with_config( - config.clone(), - "Item", - fixture, - r#" -mod foo { - pub mod bar { - pub struct Item; - } -} - -use crate::foo::bar::{self, Item}; - -fn main() { - Item -}"#, - ); - - config.insert_use.prefix_kind = hir::PrefixKind::BySelf; - check_edit_with_config( - config.clone(), - "Item", - fixture, - r#" -mod foo { - pub mod bar { - pub struct Item; - } -} - -use crate::foo::bar; - -use self::foo::bar::Item; - -fn main() { - Item -}"#, - ); - - config.insert_use.prefix_kind = hir::PrefixKind::Plain; - check_edit_with_config( - config, - "Item", - fixture, - r#" -mod foo { - pub mod bar { - pub struct Item; - } -} - -use foo::bar::Item; - -use crate::foo::bar; - -fn main() { - Item -}"#, - ); -} - -#[test] -fn unresolved_qualifier() { - let fixture = r#" -mod foo { - pub mod bar { - pub mod baz { - pub struct Item; - } - } -} - -fn main() { - bar::baz::Ite$0 -}"#; - - check( - fixture, - expect![[r#" - st Item (use foo::bar::baz::Item) - "#]], - ); - - check_edit( - "Item", - fixture, - r#" - use foo::bar; - - mod foo { - pub mod bar { - pub mod baz { - pub struct Item; - } - } - } - - fn main() { - bar::baz::Item - }"#, - ); -} - -#[test] -fn unresolved_assoc_item_container() { - let fixture = r#" -mod foo { - pub struct Item; - - impl Item { - pub const TEST_ASSOC: usize = 3; - } -} - -fn main() { - Item::TEST_A$0 -}"#; - - check( - fixture, - expect![[r#" - ct TEST_ASSOC (use foo::Item) - "#]], - ); - - check_edit( - "TEST_ASSOC", - fixture, - r#" -use foo::Item; - -mod foo { - pub struct Item; - - impl Item { - pub const TEST_ASSOC: usize = 3; - } -} - -fn main() { - Item::TEST_ASSOC -}"#, - ); -} - -#[test] -fn unresolved_assoc_item_container_with_path() { - let fixture = r#" -mod foo { - pub mod bar { - pub struct Item; - - impl Item { - pub const TEST_ASSOC: usize = 3; - } - } -} - -fn main() { - bar::Item::TEST_A$0 -}"#; - - check( - fixture, - expect![[r#" - ct TEST_ASSOC (use foo::bar::Item) - "#]], - ); - - check_edit( - "TEST_ASSOC", - fixture, - r#" -use foo::bar; - -mod foo { - pub mod bar { - pub struct Item; - - impl Item { - pub const TEST_ASSOC: usize = 3; - } - } -} - -fn main() { - bar::Item::TEST_ASSOC -}"#, - ); -} - -#[test] -fn fuzzy_unresolved_path() { - check( - r#" -mod foo { - pub mod bar { - pub struct Item; - - impl Item { - pub const TEST_ASSOC: usize = 3; - } - } -} - -fn main() { - bar::ASS$0 -}"#, - expect![[]], - ) -} - -#[test] -fn unqualified_assoc_items_are_omitted() { - check( - r#" -mod something { - pub trait BaseTrait { - fn test_function() -> i32; - } - - pub struct Item1; - pub struct Item2; - - impl BaseTrait for Item1 { - fn test_function() -> i32 { - 1 - } - } - - impl BaseTrait for Item2 { - fn test_function() -> i32 { - 2 - } - } -} - -fn main() { - test_f$0 -}"#, - expect![[]], - ) -} - -#[test] -fn case_matters() { - check( - r#" -mod foo { - pub const TEST_CONST: usize = 3; - pub fn test_function() -> i32 { - 4 - } -} - -fn main() { - TES$0 -}"#, - expect![[r#" - ct TEST_CONST (use foo::TEST_CONST) - "#]], - ); - - check( - r#" -mod foo { - pub const TEST_CONST: usize = 3; - pub fn test_function() -> i32 { - 4 - } -} - -fn main() { - tes$0 -}"#, - expect![[r#" - ct TEST_CONST (use foo::TEST_CONST) - fn test_function() (use foo::test_function) fn() -> i32 - "#]], - ); - - check( - r#" -mod foo { - pub const TEST_CONST: usize = 3; - pub fn test_function() -> i32 { - 4 - } -} - -fn main() { - Te$0 -}"#, - expect![[]], - ); -} - -#[test] -fn no_fuzzy_during_fields_of_record_lit_syntax() { - check( - r#" -mod m { - pub fn some_fn() -> i32 { - 42 - } -} -struct Foo { - some_field: i32, -} -fn main() { - let _ = Foo { so$0 }; -} -"#, - expect![[]], - ); -} - -#[test] -fn fuzzy_after_fields_of_record_lit_syntax() { - check( - r#" -mod m { - pub fn some_fn() -> i32 { - 42 - } -} -struct Foo { - some_field: i32, -} -fn main() { - let _ = Foo { some_field: som$0 }; -} -"#, - expect![[r#" - fn some_fn() (use m::some_fn) fn() -> i32 - "#]], - ); -} - -#[test] -fn no_flyimports_in_traits_and_impl_declarations() { - check( - r#" -mod m { - pub fn some_fn() -> i32 { - 42 - } -} -trait Foo { - som$0 -} -"#, - expect![[r#""#]], - ); - - check( - r#" -mod m { - pub fn some_fn() -> i32 { - 42 - } -} -struct Foo; -impl Foo { - som$0 -} -"#, - expect![[r#""#]], - ); - - check( - r#" -mod m { - pub fn some_fn() -> i32 { - 42 - } -} -struct Foo; -trait Bar {} -impl Bar for Foo { - som$0 -} -"#, - expect![[r#""#]], - ); -} - -#[test] -fn no_inherent_candidates_proposed() { - check( - r#" -mod baz { - pub trait DefDatabase { - fn method1(&self); - } - pub trait HirDatabase: DefDatabase { - fn method2(&self); - } -} - -mod bar { - fn test(db: &dyn crate::baz::HirDatabase) { - db.metho$0 - } -} - "#, - expect![[r#""#]], - ); - check( - r#" -mod baz { - pub trait DefDatabase { - fn method1(&self); - } - pub trait HirDatabase: DefDatabase { - fn method2(&self); - } -} - -mod bar { - fn test(db: &impl crate::baz::HirDatabase) { - db.metho$0 - } -} -"#, - expect![[r#""#]], - ); - check( - r#" -mod baz { - pub trait DefDatabase { - fn method1(&self); - } - pub trait HirDatabase: DefDatabase { - fn method2(&self); - } -} - -mod bar { - fn test(db: T) { - db.metho$0 - } -} -"#, - expect![[r#""#]], - ); -} - -#[test] -fn respects_doc_hidden() { - check( - r#" -//- /lib.rs crate:lib deps:dep -fn f() { - ().fro$0 -} - -//- /dep.rs crate:dep -#[doc(hidden)] -pub trait Private { - fn frob(&self) {} -} - -impl Private for T {} - "#, - expect![[r#""#]], - ); - check( - r#" -//- /lib.rs crate:lib deps:dep -fn f() { - ().fro$0 -} - -//- /dep.rs crate:dep -pub trait Private { - #[doc(hidden)] - fn frob(&self) {} -} - -impl Private for T {} - "#, - expect![[r#""#]], - ); -} - -#[test] -fn regression_9760() { - check( - r#" -struct Struct; -fn main() {} - -mod mud { - fn func() { - let struct_instance = Stru$0 - } -} -"#, - expect![[r#" - st Struct (use crate::Struct) - "#]], - ); -} - -#[test] -fn flyimport_pattern() { - check( - r#" -mod module { - pub struct FooStruct {} - pub const FooConst: () = (); - pub fn foo_fun() {} -} -fn function() { - let foo$0 -} -"#, - expect![[r#" - ct FooConst (use module::FooConst) - st FooStruct (use module::FooStruct) - "#]], - ); -} - -#[test] -fn flyimport_item_name() { - check( - r#" -mod module { - pub struct Struct; -} -struct Str$0 - "#, - expect![[r#""#]], - ); -} - -#[test] -fn flyimport_rename() { - check( - r#" -mod module { - pub struct Struct; -} -use self as Str$0; - "#, - expect![[r#""#]], - ); -} - -#[test] -fn flyimport_enum_variant() { - check( - r#" -mod foo { - pub struct Barbara; -} - -enum Foo { - Barba$0() -} -}"#, - expect![[r#""#]], - ); - - check( - r#" -mod foo { - pub struct Barbara; -} - -enum Foo { - Barba(Barba$0) -} -}"#, - expect![[r#" - st Barbara (use foo::Barbara) - "#]], - ) -} - -#[test] -fn flyimport_attribute() { - check( - r#" -//- proc_macros:identity -#[ide$0] -struct Foo; -"#, - expect![[r#" - at identity (use proc_macros::identity) proc_macro identity - "#]], - ); - check_edit( - "identity", - r#" -//- proc_macros:identity -#[ide$0] -struct Foo; -"#, - r#" -use proc_macros::identity; - -#[identity] -struct Foo; -"#, - ); -} - -#[test] -fn flyimport_in_type_bound_omits_types() { - check( - r#" -mod module { - pub struct CompletemeStruct; - pub type CompletemeType = (); - pub enum CompletemeEnum {} - pub trait CompletemeTrait {} -} - -fn f() where T: Comp$0 -"#, - expect![[r#" - tt CompletemeTrait (use module::CompletemeTrait) - "#]], - ); -} - -#[test] -fn flyimport_source_file() { - check( - r#" -//- /main.rs crate:main deps:dep -def$0 -//- /lib.rs crate:dep -#[macro_export] -macro_rules! define_struct { - () => { - pub struct Foo; - }; -} -"#, - expect![[r#" - ma define_struct!(…) (use dep::define_struct) macro_rules! define_struct - "#]], - ); -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs deleted file mode 100644 index cce74604c2d0e..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs +++ /dev/null @@ -1,274 +0,0 @@ -use expect_test::{expect, Expect}; - -use crate::tests::{completion_list, completion_list_with_trigger_character}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); -} - -fn check_with_trigger_character(ra_fixture: &str, trigger_character: char, expect: Expect) { - let actual = completion_list_with_trigger_character(ra_fixture, Some(trigger_character)); - expect.assert_eq(&actual) -} - -#[test] -fn only_param() { - check( - r#" -fn foo(file_id: usize) {} -fn bar(file_id: usize) {} -fn baz(file$0) {} -"#, - expect![[r#" - bn file_id: usize - kw mut - kw ref - "#]], - ); -} - -#[test] -fn last_param() { - check( - r#" -fn foo(file_id: usize) {} -fn bar(file_id: usize) {} -fn baz(foo: (), file$0) {} -"#, - expect![[r#" - bn file_id: usize - kw mut - kw ref - "#]], - ); -} - -#[test] -fn first_param() { - check( - r#" -fn foo(file_id: usize) {} -fn bar(file_id: usize) {} -fn baz(file$0 id: u32) {} -"#, - expect![[r#" - bn file_id: usize, - kw mut - kw ref - "#]], - ); -} - -#[test] -fn repeated_param_name() { - check( - r#" -fn foo(file_id: usize) {} -fn bar(file_id: u32, $0) {} -"#, - expect![[r#" - kw mut - kw ref - "#]], - ); - - check( - r#" -fn f(#[foo = "bar"] baz: u32,) {} -fn g(baz: (), ba$0) -"#, - expect![[r#" - kw mut - kw ref - "#]], - ) -} - -#[test] -fn trait_param() { - check( - r#" -pub(crate) trait SourceRoot { - pub fn contains(file_id: usize) -> bool; - pub fn syntax(file$0) -} -"#, - expect![[r#" - bn file_id: usize - kw mut - kw ref - "#]], - ); -} - -#[test] -fn in_inner_function() { - check( - r#" -fn outer(text: &str) { - fn inner($0) -} -"#, - expect![[r#" - bn text: &str - kw mut - kw ref - "#]], - ) -} - -#[test] -fn trigger_by_l_paren() { - check_with_trigger_character( - r#" -fn foo($0) -"#, - '(', - expect![[]], - ) -} - -#[test] -fn shows_non_ident_pat_param() { - check( - r#" -struct Bar { bar: u32 } -fn foo(Bar { bar }: Bar) {} -fn foo2($0) {} -"#, - expect![[r#" - st Bar - bn Bar { bar }: Bar - bn Bar {…} Bar { bar$1 }: Bar$0 - kw mut - kw ref - "#]], - ) -} - -#[test] -fn in_impl_only_param() { - check( - r#" -struct A {} - -impl A { - fn foo(file_id: usize) {} - fn new($0) {} -} -"#, - expect![[r#" - sp Self - st A - bn &mut self - bn &self - bn file_id: usize - bn mut self - bn self - kw mut - kw ref - "#]], - ) -} - -#[test] -fn in_impl_after_self() { - check( - r#" -struct A {} - -impl A { - fn foo(file_id: usize) {} - fn new(self, $0) {} -} -"#, - expect![[r#" - sp Self - st A - bn file_id: usize - kw mut - kw ref - "#]], - ) -} - -// doesn't complete qux due to there being no expression after -// see source_analyzer::adjust comment -#[test] -fn local_fn_shows_locals_for_params() { - check( - r#" -fn outer() { - let foo = 3; - { - let bar = 3; - fn inner($0) {} - let baz = 3; - let qux = 3; - } - let fez = 3; -} -"#, - expect![[r#" - bn bar: i32 - bn baz: i32 - bn foo: i32 - kw mut - kw ref - "#]], - ) -} - -#[test] -fn closure_shows_locals_for_params() { - check( - r#" -fn outer() { - let foo = 3; - { - let bar = 3; - |$0| {}; - let baz = 3; - let qux = 3; - } - let fez = 3; -} -"#, - expect![[r#" - bn bar: i32 - bn baz: i32 - bn foo: i32 - kw mut - kw ref - "#]], - ) -} - -#[test] -fn completes_fully_equal() { - check( - r#" -fn foo(bar: u32) {} -fn bar(bar$0) {} -"#, - expect![[r#" - bn bar: u32 - kw mut - kw ref - "#]], - ) -} - -#[test] -fn completes_for_params_with_attributes() { - check( - r#" -fn f(foo: (), #[baz = "qux"] mut bar: u32) {} -fn g(foo: (), #[baz = "qux"] mut ba$0) -"#, - expect![[r##" - bn #[baz = "qux"] mut bar: u32 - "##]], - ) -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs deleted file mode 100644 index 409413c1dcdb1..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs +++ /dev/null @@ -1,154 +0,0 @@ -//! Completion tests for item specifics overall. -//! -//! Except for use items which are tested in [super::use_tree] and mod declarations with are tested -//! in [crate::completions::mod_]. -use expect_test::{expect, Expect}; - -use crate::tests::{completion_list, BASE_ITEMS_FIXTURE}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{}{}", BASE_ITEMS_FIXTURE, ra_fixture)); - expect.assert_eq(&actual) -} - -#[test] -fn target_type_or_trait_in_impl_block() { - check( - r#" -impl Tra$0 -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - st Record - st Tuple - st Unit - tt Trait - un Union - bt u32 - kw crate:: - kw self:: - "#]], - ) -} - -#[test] -fn target_type_in_trait_impl_block() { - check( - r#" -impl Trait for Str$0 -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - st Record - st Tuple - st Unit - tt Trait - un Union - bt u32 - kw crate:: - kw self:: - "#]], - ) -} - -#[test] -fn after_trait_name_in_trait_def() { - check( - r"trait A $0", - expect![[r#" - kw where - "#]], - ); -} - -#[test] -fn after_target_name_in_impl() { - check( - r"impl Trait $0", - expect![[r#" - kw for - kw where - "#]], - ); - check( - r"impl Trait f$0", - expect![[r#" - kw for - kw where - "#]], - ); - check( - r"impl Trait for Type $0", - expect![[r#" - kw where - "#]], - ); -} - -#[test] -fn completes_where() { - check( - r"struct Struct $0", - expect![[r#" - kw where - "#]], - ); - check( - r"struct Struct $0 {}", - expect![[r#" - kw where - "#]], - ); - // FIXME: This shouldn't be completed here - check( - r"struct Struct $0 ()", - expect![[r#" - kw where - "#]], - ); - check( - r"fn func() $0", - expect![[r#" - kw where - "#]], - ); - check( - r"enum Enum $0", - expect![[r#" - kw where - "#]], - ); - check( - r"enum Enum $0 {}", - expect![[r#" - kw where - "#]], - ); - check( - r"trait Trait $0 {}", - expect![[r#" - kw where - "#]], - ); -} - -#[test] -fn before_record_field() { - check( - r#" -struct Foo { - $0 - pub f: i32, -} -"#, - expect![[r#" - kw pub - kw pub(crate) - kw pub(super) - "#]], - ) -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs deleted file mode 100644 index 5076c6e86caee..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs +++ /dev/null @@ -1,247 +0,0 @@ -//! Completion tests for item list position. -use expect_test::{expect, Expect}; - -use crate::tests::{completion_list, BASE_ITEMS_FIXTURE}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{}{}", BASE_ITEMS_FIXTURE, ra_fixture)); - expect.assert_eq(&actual) -} - -#[test] -fn in_mod_item_list() { - check( - r#"mod tests { $0 }"#, - expect![[r#" - ma makro!(…) macro_rules! makro - kw const - kw crate:: - kw enum - kw extern - kw fn - kw impl - kw mod - kw pub - kw pub(crate) - kw pub(super) - kw self:: - kw static - kw struct - kw super:: - kw trait - kw type - kw union - kw unsafe - kw use - sn macro_rules - sn tfn (Test function) - sn tmod (Test module) - "#]], - ) -} - -#[test] -fn in_source_file_item_list() { - check( - r#"$0"#, - expect![[r#" - ma makro!(…) macro_rules! makro - md module - kw const - kw crate:: - kw enum - kw extern - kw fn - kw impl - kw mod - kw pub - kw pub(crate) - kw pub(super) - kw self:: - kw static - kw struct - kw trait - kw type - kw union - kw unsafe - kw use - sn macro_rules - sn tfn (Test function) - sn tmod (Test module) - "#]], - ) -} - -#[test] -fn in_item_list_after_attr() { - check( - r#"#[attr] $0"#, - expect![[r#" - ma makro!(…) macro_rules! makro - md module - kw const - kw crate:: - kw enum - kw extern - kw fn - kw impl - kw mod - kw pub - kw pub(crate) - kw pub(super) - kw self:: - kw static - kw struct - kw trait - kw type - kw union - kw unsafe - kw use - sn macro_rules - sn tfn (Test function) - sn tmod (Test module) - "#]], - ) -} - -#[test] -fn in_qualified_path() { - check( - r#"crate::$0"#, - expect![[r#" - ma makro!(…) macro_rules! makro - md module - "#]], - ) -} - -#[test] -fn after_unsafe_token() { - check( - r#"unsafe $0"#, - expect![[r#" - kw fn - kw impl - kw trait - "#]], - ); -} - -#[test] -fn after_visibility() { - check( - r#"pub $0"#, - expect![[r#" - kw const - kw enum - kw extern - kw fn - kw mod - kw static - kw struct - kw trait - kw type - kw union - kw unsafe - kw use - "#]], - ); -} - -#[test] -fn after_visibility_unsafe() { - check( - r#"pub unsafe $0"#, - expect![[r#" - kw fn - kw trait - "#]], - ); -} - -#[test] -fn in_impl_assoc_item_list() { - check( - r#"impl Struct { $0 }"#, - expect![[r#" - ma makro!(…) macro_rules! makro - md module - kw const - kw crate:: - kw fn - kw pub - kw pub(crate) - kw pub(super) - kw self:: - kw unsafe - "#]], - ) -} - -#[test] -fn in_impl_assoc_item_list_after_attr() { - check( - r#"impl Struct { #[attr] $0 }"#, - expect![[r#" - ma makro!(…) macro_rules! makro - md module - kw const - kw crate:: - kw fn - kw pub - kw pub(crate) - kw pub(super) - kw self:: - kw unsafe - "#]], - ) -} - -#[test] -fn in_trait_assoc_item_list() { - check( - r"trait Foo { $0 }", - expect![[r#" - ma makro!(…) macro_rules! makro - md module - kw const - kw crate:: - kw fn - kw self:: - kw type - kw unsafe - "#]], - ); -} - -#[test] -fn in_trait_impl_assoc_item_list() { - check( - r#" -trait Test { - type Type0; - type Type1; - const CONST0: (); - const CONST1: (); - fn function0(); - fn function1(); -} - -impl Test for () { - type Type0 = (); - const CONST0: () = (); - fn function0() {} - $0 -} -"#, - expect![[r#" - ct const CONST1: () = - fn fn function1() - ma makro!(…) macro_rules! makro - md module - ta type Type1 = - kw crate:: - kw self:: - "#]], - ); -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs deleted file mode 100644 index 877b5f2164331..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs +++ /dev/null @@ -1,716 +0,0 @@ -//! Completion tests for pattern position. -use expect_test::{expect, Expect}; - -use crate::tests::{check_edit, completion_list, BASE_ITEMS_FIXTURE}; - -fn check_empty(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) -} - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{}\n{}", BASE_ITEMS_FIXTURE, ra_fixture)); - expect.assert_eq(&actual) -} - -#[test] -fn wildcard() { - check( - r#" -fn quux() { - let _$0 -} -"#, - expect![""], - ); -} - -#[test] -fn ident_rebind_pat() { - check_empty( - r#" -fn quux() { - let en$0 @ x -} -"#, - expect![[r#" - kw mut - kw ref - "#]], - ); -} - -#[test] -fn ident_ref_pat() { - check_empty( - r#" -fn quux() { - let ref en$0 -} -"#, - expect![[r#" - kw mut - "#]], - ); - check_empty( - r#" -fn quux() { - let ref en$0 @ x -} -"#, - expect![[r#" - kw mut - "#]], - ); -} - -#[test] -fn ident_ref_mut_pat() { - check_empty( - r#" -fn quux() { - let ref mut en$0 -} -"#, - expect![[r#""#]], - ); - check_empty( - r#" -fn quux() { - let ref mut en$0 @ x -} -"#, - expect![[r#""#]], - ); -} - -#[test] -fn ref_pat() { - check_empty( - r#" -fn quux() { - let &en$0 -} -"#, - expect![[r#" - kw mut - "#]], - ); - check_empty( - r#" -fn quux() { - let &mut en$0 -} -"#, - expect![[r#""#]], - ); - check_empty( - r#" -fn foo() { - for &$0 in () {} -} -"#, - expect![[r#" - kw mut - "#]], - ); -} - -#[test] -fn refutable() { - check( - r#" -fn foo() { - if let a$0 -} -"#, - expect![[r#" - ct CONST - en Enum - ma makro!(…) macro_rules! makro - md module - st Record - st Tuple - st Unit - ev TupleV - bn Record {…} Record { field$1 }$0 - bn Tuple(…) Tuple($1)$0 - bn TupleV(…) TupleV($1)$0 - kw mut - kw ref - "#]], - ); -} - -#[test] -fn irrefutable() { - check( - r#" -enum SingleVariantEnum { - Variant -} -use SingleVariantEnum::Variant; -fn foo() { - let a$0 -} -"#, - expect![[r#" - en SingleVariantEnum - ma makro!(…) macro_rules! makro - md module - st Record - st Tuple - st Unit - ev Variant - bn Record {…} Record { field$1 }$0 - bn Tuple(…) Tuple($1)$0 - bn Variant Variant$0 - kw mut - kw ref - "#]], - ); -} - -#[test] -fn in_param() { - check( - r#" -fn foo(a$0) { -} -"#, - expect![[r#" - ma makro!(…) macro_rules! makro - md module - st Record - st Tuple - st Unit - bn Record {…} Record { field$1 }: Record$0 - bn Tuple(…) Tuple($1): Tuple$0 - kw mut - kw ref - "#]], - ); - check( - r#" -fn foo(a$0: Tuple) { -} -"#, - expect![[r#" - ma makro!(…) macro_rules! makro - md module - st Record - st Tuple - st Unit - bn Record {…} Record { field$1 }$0 - bn Tuple(…) Tuple($1)$0 - kw mut - kw ref - "#]], - ); -} - -#[test] -fn only_fn_like_macros() { - check_empty( - r#" -macro_rules! m { ($e:expr) => { $e } } - -#[rustc_builtin_macro] -macro Clone {} - -fn foo() { - let x$0 -} -"#, - expect![[r#" - ma m!(…) macro_rules! m - kw mut - kw ref - "#]], - ); -} - -#[test] -fn in_simple_macro_call() { - check_empty( - r#" -macro_rules! m { ($e:expr) => { $e } } -enum E { X } - -fn foo() { - m!(match E::X { a$0 }) -} -"#, - expect![[r#" - en E - ma m!(…) macro_rules! m - bn E::X E::X$0 - kw mut - kw ref - "#]], - ); -} - -#[test] -fn omits_private_fields_pat() { - check_empty( - r#" -mod foo { - pub struct Record { pub field: i32, _field: i32 } - pub struct Tuple(pub u32, u32); - pub struct Invisible(u32, u32); -} -use foo::*; - -fn outer() { - if let a$0 -} -"#, - expect![[r#" - md foo - st Invisible - st Record - st Tuple - bn Record {…} Record { field$1, .. }$0 - bn Tuple(…) Tuple($1, ..)$0 - kw mut - kw ref - "#]], - ) -} - -#[test] -fn completes_self_pats() { - check_empty( - r#" -struct Foo(i32); -impl Foo { - fn foo() { - match Foo(0) { - a$0 - } - } -} - "#, - expect![[r#" - sp Self - st Foo - bn Foo(…) Foo($1)$0 - bn Self(…) Self($1)$0 - kw mut - kw ref - "#]], - ) -} - -#[test] -fn enum_qualified() { - check( - r#" -impl Enum { - type AssocType = (); - const ASSOC_CONST: () = (); - fn assoc_fn() {} -} -fn func() { - if let Enum::$0 = unknown {} -} -"#, - expect![[r#" - ct ASSOC_CONST const ASSOC_CONST: () - bn RecordV {…} RecordV { field$1 }$0 - bn TupleV(…) TupleV($1)$0 - bn UnitV UnitV$0 - "#]], - ); -} - -#[test] -fn completes_in_record_field_pat() { - check_empty( - r#" -struct Foo { bar: Bar } -struct Bar(u32); -fn outer(Foo { bar: $0 }: Foo) {} -"#, - expect![[r#" - st Bar - st Foo - bn Bar(…) Bar($1)$0 - bn Foo {…} Foo { bar$1 }$0 - kw mut - kw ref - "#]], - ) -} - -#[test] -fn skips_in_record_field_pat_name() { - check_empty( - r#" -struct Foo { bar: Bar } -struct Bar(u32); -fn outer(Foo { bar$0 }: Foo) {} -"#, - expect![[r#" - kw mut - kw ref - "#]], - ) -} - -#[test] -fn completes_in_fn_param() { - check_empty( - r#" -struct Foo { bar: Bar } -struct Bar(u32); -fn foo($0) {} -"#, - expect![[r#" - st Bar - st Foo - bn Bar(…) Bar($1): Bar$0 - bn Foo {…} Foo { bar$1 }: Foo$0 - kw mut - kw ref - "#]], - ) -} - -#[test] -fn completes_in_closure_param() { - check_empty( - r#" -struct Foo { bar: Bar } -struct Bar(u32); -fn foo() { - |$0| {}; -} -"#, - expect![[r#" - st Bar - st Foo - bn Bar(…) Bar($1)$0 - bn Foo {…} Foo { bar$1 }$0 - kw mut - kw ref - "#]], - ) -} - -#[test] -fn completes_no_delims_if_existing() { - check_empty( - r#" -struct Bar(u32); -fn foo() { - match Bar(0) { - B$0(b) => {} - } -} -"#, - expect![[r#" - st Bar - kw crate:: - kw self:: - "#]], - ); - check_empty( - r#" -struct Foo { bar: u32 } -fn foo() { - match (Foo { bar: 0 }) { - F$0 { bar } => {} - } -} -"#, - expect![[r#" - st Foo - kw crate:: - kw self:: - "#]], - ); - check_empty( - r#" -enum Enum { - TupleVariant(u32) -} -fn foo() { - match Enum::TupleVariant(0) { - Enum::T$0(b) => {} - } -} -"#, - expect![[r#" - bn TupleVariant(…) TupleVariant($1)$0 - "#]], - ); - check_empty( - r#" -enum Enum { - RecordVariant { field: u32 } -} -fn foo() { - match (Enum::RecordVariant { field: 0 }) { - Enum::RecordV$0 { field } => {} - } -} -"#, - expect![[r#" - bn RecordVariant {…} RecordVariant { field$1 }$0 - "#]], - ); -} - -#[test] -fn completes_enum_variant_pat() { - cov_mark::check!(enum_variant_pattern_path); - check_edit( - "RecordVariant {…}", - r#" -enum Enum { - RecordVariant { field: u32 } -} -fn foo() { - match (Enum::RecordVariant { field: 0 }) { - Enum::RecordV$0 - } -} -"#, - r#" -enum Enum { - RecordVariant { field: u32 } -} -fn foo() { - match (Enum::RecordVariant { field: 0 }) { - Enum::RecordVariant { field$1 }$0 - } -} -"#, - ); -} - -#[test] -fn completes_enum_variant_pat_escape() { - cov_mark::check!(enum_variant_pattern_path); - check_empty( - r#" -enum Enum { - A, - B { r#type: i32 }, - r#type, - r#struct { r#type: i32 }, -} -fn foo() { - match (Enum::A) { - $0 - } -} -"#, - expect![[r#" - en Enum - bn Enum::A Enum::A$0 - bn Enum::B {…} Enum::B { r#type$1 }$0 - bn Enum::struct {…} Enum::r#struct { r#type$1 }$0 - bn Enum::type Enum::r#type$0 - kw mut - kw ref - "#]], - ); - - check_empty( - r#" -enum Enum { - A, - B { r#type: i32 }, - r#type, - r#struct { r#type: i32 }, -} -fn foo() { - match (Enum::A) { - Enum::$0 - } -} -"#, - expect![[r#" - bn A A$0 - bn B {…} B { r#type$1 }$0 - bn struct {…} r#struct { r#type$1 }$0 - bn type r#type$0 - "#]], - ); -} - -#[test] -fn completes_associated_const() { - check_empty( - r#" -#[derive(PartialEq, Eq)] -struct Ty(u8); - -impl Ty { - const ABC: Self = Self(0); -} - -fn f(t: Ty) { - match t { - Ty::$0 => {} - _ => {} - } -} -"#, - expect![[r#" - ct ABC const ABC: Self - "#]], - ); - - check_empty( - r#" -enum MyEnum {} - -impl MyEnum { - pub const A: i32 = 123; - pub const B: i32 = 456; -} - -fn f(e: MyEnum) { - match e { - MyEnum::$0 => {} - _ => {} - } -} -"#, - expect![[r#" - ct A pub const A: i32 - ct B pub const B: i32 - "#]], - ); - - check_empty( - r#" -union U { - i: i32, - f: f32, -} - -impl U { - pub const C: i32 = 123; - pub const D: i32 = 456; -} - -fn f(u: U) { - match u { - U::$0 => {} - _ => {} - } -} -"#, - expect![[r#" - ct C pub const C: i32 - ct D pub const D: i32 - "#]], - ); - - check_empty( - r#" -#[lang = "u32"] -impl u32 { - pub const MIN: Self = 0; -} - -fn f(v: u32) { - match v { - u32::$0 - } -} - "#, - expect![[r#" - ct MIN pub const MIN: Self - "#]], - ); -} - -#[test] -fn in_method_param() { - check_empty( - r#" -struct Ty(u8); - -impl Ty { - fn foo($0) -} -"#, - expect![[r#" - sp Self - st Ty - bn &mut self - bn &self - bn Self(…) Self($1): Self$0 - bn Ty(…) Ty($1): Ty$0 - bn mut self - bn self - kw mut - kw ref - "#]], - ); - check_empty( - r#" -struct Ty(u8); - -impl Ty { - fn foo(s$0) -} -"#, - expect![[r#" - sp Self - st Ty - bn &mut self - bn &self - bn Self(…) Self($1): Self$0 - bn Ty(…) Ty($1): Ty$0 - bn mut self - bn self - kw mut - kw ref - "#]], - ); - check_empty( - r#" -struct Ty(u8); - -impl Ty { - fn foo(s$0, foo: u8) -} -"#, - expect![[r#" - sp Self - st Ty - bn &mut self - bn &self - bn Self(…) Self($1): Self$0 - bn Ty(…) Ty($1): Ty$0 - bn mut self - bn self - kw mut - kw ref - "#]], - ); - check_empty( - r#" -struct Ty(u8); - -impl Ty { - fn foo(foo: u8, b$0) -} -"#, - expect![[r#" - sp Self - st Ty - bn Self(…) Self($1): Self$0 - bn Ty(…) Ty($1): Ty$0 - kw mut - kw ref - "#]], - ); -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs deleted file mode 100644 index a8676e2f24787..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs +++ /dev/null @@ -1,131 +0,0 @@ -//! Completion tests for predicates and bounds. -use expect_test::{expect, Expect}; - -use crate::tests::{completion_list, BASE_ITEMS_FIXTURE}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{}\n{}", BASE_ITEMS_FIXTURE, ra_fixture)); - expect.assert_eq(&actual) -} - -#[test] -fn predicate_start() { - // FIXME: `for` kw - check( - r#" -struct Foo<'lt, T, const C: usize> where $0 {} -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - st Foo<…> - st Record - st Tuple - st Unit - tt Trait - un Union - bt u32 - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn bound_for_type_pred() { - check( - r#" -struct Foo<'lt, T, const C: usize> where T: $0 {} -"#, - expect![[r#" - ma makro!(…) macro_rules! makro - md module - tt Trait - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn bound_for_lifetime_pred() { - // FIXME: should only show lifetimes here, that is we shouldn't get any completions here when not typing - // a `'` - check( - r#" -struct Foo<'lt, T, const C: usize> where 'lt: $0 {} -"#, - expect![[r#" - ma makro!(…) macro_rules! makro - md module - tt Trait - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn bound_for_for_pred() { - check( - r#" -struct Foo<'lt, T, const C: usize> where for<'a> T: $0 {} -"#, - expect![[r#" - ma makro!(…) macro_rules! makro - md module - tt Trait - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn param_list_for_for_pred() { - check( - r#" -struct Foo<'lt, T, const C: usize> where for<'a> $0 {} -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - st Foo<…> - st Record - st Tuple - st Unit - tt Trait - un Union - bt u32 - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn pred_on_fn_in_impl() { - check( - r#" -impl Record { - fn method(self) where $0 {} -} -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - sp Self - st Record - st Tuple - st Unit - tt Trait - un Union - bt u32 - kw crate:: - kw self:: - "#]], - ); -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs deleted file mode 100644 index 9eae6f84954b1..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs +++ /dev/null @@ -1,133 +0,0 @@ -//! Completion tests for expressions. -use expect_test::{expect, Expect}; - -use crate::tests::completion_list; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) -} - -#[test] -fn complete_dot_in_attr() { - check( - r#" -//- proc_macros: identity -pub struct Foo; -impl Foo { - fn foo(&self) {} -} - -#[proc_macros::identity] -fn main() { - Foo.$0 -} -"#, - expect![[r#" - me foo() fn(&self) - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr - "#]], - ) -} - -#[test] -fn complete_dot_in_attr2() { - check( - r#" -//- proc_macros: identity -pub struct Foo; -impl Foo { - fn foo(&self) {} -} - -#[proc_macros::identity] -fn main() { - Foo.f$0 -} -"#, - expect![[r#" - me foo() fn(&self) - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr - "#]], - ) -} - -#[test] -fn complete_dot_in_attr_input() { - check( - r#" -//- proc_macros: input_replace -pub struct Foo; -impl Foo { - fn foo(&self) {} -} - -#[proc_macros::input_replace( - fn suprise() { - Foo.$0 - } -)] -fn main() {} -"#, - expect![[r#" - me foo() fn(&self) - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr - "#]], - ) -} - -#[test] -fn complete_dot_in_attr_input2() { - check( - r#" -//- proc_macros: input_replace -pub struct Foo; -impl Foo { - fn foo(&self) {} -} - -#[proc_macros::input_replace( - fn suprise() { - Foo.f$0 - } -)] -fn main() {} -"#, - expect![[r#" - me foo() fn(&self) - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr - "#]], - ) -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs deleted file mode 100644 index ec32602fa3c2f..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs +++ /dev/null @@ -1,230 +0,0 @@ -use expect_test::{expect, Expect}; - -use crate::tests::completion_list; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); -} - -#[test] -fn without_default_impl() { - check( - r#" -struct Struct { foo: u32, bar: usize } - -fn foo() { - let other = Struct { - foo: 5, - $0 - }; -} -"#, - expect![[r#" - fd bar usize - "#]], - ); -} - -#[test] -fn record_pattern_field() { - check( - r#" -struct Struct { foo: u32, bar: u32 } - -fn foo(s: Struct) { - match s { - Struct { foo, $0: 92 } => (), - } -} -"#, - expect![[r#" - fd bar u32 - kw mut - kw ref - "#]], - ); -} - -#[test] -fn pattern_enum_variant() { - check( - r#" -enum Enum { Variant { foo: u32, bar: u32 } } -fn foo(e: Enum) { - match e { - Enum::Variant { foo, $0 } => (), - } -} -"#, - expect![[r#" - fd bar u32 - kw mut - kw ref - "#]], - ); -} - -#[test] -fn record_literal_field_in_macro() { - check( - r#" -macro_rules! m { ($e:expr) => { $e } } -struct Struct { field: u32 } -fn foo() { - m!(Struct { fie$0 }) -} -"#, - expect![[r#" - fd field u32 - "#]], - ); -} - -#[test] -fn record_pattern_field_in_macro() { - check( - r" -macro_rules! m { ($e:expr) => { $e } } -struct Struct { field: u32 } - -fn foo(f: Struct) { - m!(match f { - Struct { f$0: 92 } => (), - }) -} -", - expect![[r#" - fd field u32 - kw mut - kw ref - "#]], - ); -} - -#[test] -fn functional_update() { - // FIXME: This should filter out all completions that do not have the type `Foo` - check( - r#" -//- minicore:default -struct Foo { foo1: u32, foo2: u32 } -impl Default for Foo { - fn default() -> Self { loop {} } -} - -fn main() { - let thing = 1; - let foo = Foo { foo1: 0, foo2: 0 }; - let foo2 = Foo { thing, $0 } -} -"#, - expect![[r#" - fd ..Default::default() - fd foo1 u32 - fd foo2 u32 - "#]], - ); - check( - r#" -//- minicore:default -struct Foo { foo1: u32, foo2: u32 } -impl Default for Foo { - fn default() -> Self { loop {} } -} - -fn main() { - let thing = 1; - let foo = Foo { foo1: 0, foo2: 0 }; - let foo2 = Foo { thing, .$0 } -} -"#, - expect![[r#" - fd ..Default::default() - sn .. - "#]], - ); - check( - r#" -//- minicore:default -struct Foo { foo1: u32, foo2: u32 } -impl Default for Foo { - fn default() -> Self { loop {} } -} - -fn main() { - let thing = 1; - let foo = Foo { foo1: 0, foo2: 0 }; - let foo2 = Foo { thing, ..$0 } -} -"#, - expect![[r#" - fd ..Default::default() - fn main() fn() - lc foo Foo - lc thing i32 - md core - st Foo - st Foo {…} Foo { foo1: u32, foo2: u32 } - tt Default - tt Sized - bt u32 - kw crate:: - kw self:: - "#]], - ); - check( - r#" -//- minicore:default -struct Foo { foo1: u32, foo2: u32 } -impl Default for Foo { - fn default() -> Self { loop {} } -} - -fn main() { - let thing = 1; - let foo = Foo { foo1: 0, foo2: 0 }; - let foo2 = Foo { thing, ..Default::$0 } -} -"#, - expect![[r#" - fn default() (as Default) fn() -> Self - "#]], - ); -} - -#[test] -fn empty_union_literal() { - check( - r#" -union Union { foo: u32, bar: f32 } - -fn foo() { - let other = Union { - $0 - }; -} - "#, - expect![[r#" - fd bar f32 - fd foo u32 - "#]], - ) -} - -#[test] -fn dont_suggest_additional_union_fields() { - check( - r#" -union Union { foo: u32, bar: f32 } - -fn foo() { - let other = Union { - foo: 1, - $0 - }; -} - "#, - expect![[r#""#]], - ) -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs deleted file mode 100644 index ca779c2fc713e..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs +++ /dev/null @@ -1,842 +0,0 @@ -//! Tests that don't fit into a specific category. - -use expect_test::{expect, Expect}; - -use crate::tests::{check_edit, completion_list_no_kw}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw(ra_fixture); - expect.assert_eq(&actual) -} - -#[test] -fn completes_if_prefix_is_keyword() { - check_edit( - "wherewolf", - r#" -fn main() { - let wherewolf = 92; - drop(where$0) -} -"#, - r#" -fn main() { - let wherewolf = 92; - drop(wherewolf) -} -"#, - ) -} - -/// Regression test for issue #6091. -#[test] -fn correctly_completes_module_items_prefixed_with_underscore() { - check_edit( - "_alpha", - r#" -fn main() { - _$0 -} -fn _alpha() {} -"#, - r#" -fn main() { - _alpha()$0 -} -fn _alpha() {} -"#, - ) -} - -#[test] -fn completes_prelude() { - check( - r#" -//- /main.rs crate:main deps:std -fn foo() { let x: $0 } - -//- /std/lib.rs crate:std -pub mod prelude { - pub mod rust_2018 { - pub struct Option; - } -} -"#, - expect![[r#" - md std - st Option - bt u32 - "#]], - ); -} - -#[test] -fn completes_prelude_macros() { - check( - r#" -//- /main.rs crate:main deps:std -fn f() {$0} - -//- /std/lib.rs crate:std -pub mod prelude { - pub mod rust_2018 { - pub use crate::concat; - } -} - -mod macros { - #[rustc_builtin_macro] - #[macro_export] - macro_rules! concat { } -} -"#, - expect![[r#" - fn f() fn() - ma concat!(…) macro_rules! concat - md std - bt u32 - "#]], - ); -} - -#[test] -fn completes_std_prelude_if_core_is_defined() { - check( - r#" -//- /main.rs crate:main deps:core,std -fn foo() { let x: $0 } - -//- /core/lib.rs crate:core -pub mod prelude { - pub mod rust_2018 { - pub struct Option; - } -} - -//- /std/lib.rs crate:std deps:core -pub mod prelude { - pub mod rust_2018 { - pub struct String; - } -} -"#, - expect![[r#" - md core - md std - st String - bt u32 - "#]], - ); -} - -#[test] -fn respects_doc_hidden() { - check( - r#" -//- /lib.rs crate:lib deps:std -fn f() { - format_$0 -} - -//- /std.rs crate:std -#[doc(hidden)] -#[macro_export] -macro_rules! format_args_nl { - () => {} -} - -pub mod prelude { - pub mod rust_2018 {} -} - "#, - expect![[r#" - fn f() fn() - md std - bt u32 - "#]], - ); -} - -#[test] -fn respects_doc_hidden_in_assoc_item_list() { - check( - r#" -//- /lib.rs crate:lib deps:std -struct S; -impl S { - format_$0 -} - -//- /std.rs crate:std -#[doc(hidden)] -#[macro_export] -macro_rules! format_args_nl { - () => {} -} - -pub mod prelude { - pub mod rust_2018 {} -} - "#, - expect![[r#" - md std - "#]], - ); -} - -#[test] -fn associated_item_visibility() { - check( - r#" -//- /lib.rs crate:lib new_source_root:library -pub struct S; - -impl S { - pub fn public_method() { } - fn private_method() { } - pub type PublicType = u32; - type PrivateType = u32; - pub const PUBLIC_CONST: u32 = 1; - const PRIVATE_CONST: u32 = 1; -} - -//- /main.rs crate:main deps:lib new_source_root:local -fn foo() { let _ = lib::S::$0 } -"#, - expect![[r#" - ct PUBLIC_CONST pub const PUBLIC_CONST: u32 - fn public_method() fn() - ta PublicType pub type PublicType = u32 - "#]], - ); -} - -#[test] -fn completes_union_associated_method() { - check( - r#" -union U {}; -impl U { fn m() { } } - -fn foo() { let _ = U::$0 } -"#, - expect![[r#" - fn m() fn() - "#]], - ); -} - -#[test] -fn completes_trait_associated_method_1() { - check( - r#" -trait Trait { fn m(); } - -fn foo() { let _ = Trait::$0 } -"#, - expect![[r#" - fn m() (as Trait) fn() - "#]], - ); -} - -#[test] -fn completes_trait_associated_method_2() { - check( - r#" -trait Trait { fn m(); } - -struct S; -impl Trait for S {} - -fn foo() { let _ = S::$0 } -"#, - expect![[r#" - fn m() (as Trait) fn() - "#]], - ); -} - -#[test] -fn completes_trait_associated_method_3() { - check( - r#" -trait Trait { fn m(); } - -struct S; -impl Trait for S {} - -fn foo() { let _ = ::$0 } -"#, - expect![[r#" - fn m() (as Trait) fn() - "#]], - ); -} - -#[test] -fn completes_ty_param_assoc_ty() { - check( - r#" -trait Super { - type Ty; - const CONST: u8; - fn func() {} - fn method(&self) {} -} - -trait Sub: Super { - type SubTy; - const C2: (); - fn subfunc() {} - fn submethod(&self) {} -} - -fn foo() { T::$0 } -"#, - expect![[r#" - ct C2 (as Sub) const C2: () - ct CONST (as Super) const CONST: u8 - fn func() (as Super) fn() - fn subfunc() (as Sub) fn() - ta SubTy (as Sub) type SubTy - ta Ty (as Super) type Ty - me method(…) (as Super) fn(&self) - me submethod(…) (as Sub) fn(&self) - "#]], - ); -} - -#[test] -fn completes_self_param_assoc_ty() { - check( - r#" -trait Super { - type Ty; - const CONST: u8 = 0; - fn func() {} - fn method(&self) {} -} - -trait Sub: Super { - type SubTy; - const C2: () = (); - fn subfunc() {} - fn submethod(&self) {} -} - -struct Wrap(T); -impl Super for Wrap {} -impl Sub for Wrap { - fn subfunc() { - // Should be able to assume `Self: Sub + Super` - Self::$0 - } -} -"#, - expect![[r#" - ct C2 (as Sub) const C2: () - ct CONST (as Super) const CONST: u8 - fn func() (as Super) fn() - fn subfunc() (as Sub) fn() - ta SubTy (as Sub) type SubTy - ta Ty (as Super) type Ty - me method(…) (as Super) fn(&self) - me submethod(…) (as Sub) fn(&self) - "#]], - ); -} - -#[test] -fn completes_type_alias() { - check( - r#" -struct S; -impl S { fn foo() {} } -type T = S; -impl T { fn bar() {} } - -fn main() { T::$0; } -"#, - expect![[r#" - fn bar() fn() - fn foo() fn() - "#]], - ); -} - -#[test] -fn completes_qualified_macros() { - check( - r#" -#[macro_export] -macro_rules! foo { () => {} } - -fn main() { let _ = crate::$0 } -"#, - expect![[r#" - fn main() fn() - ma foo!(…) macro_rules! foo - "#]], - ); -} - -#[test] -fn does_not_complete_non_fn_macros() { - check( - r#" -mod m { - #[rustc_builtin_macro] - pub macro Clone {} -} - -fn f() {m::$0} -"#, - expect![[r#""#]], - ); - check( - r#" -mod m { - #[rustc_builtin_macro] - pub macro bench {} -} - -fn f() {m::$0} -"#, - expect![[r#""#]], - ); -} - -#[test] -fn completes_reexported_items_under_correct_name() { - check( - r#" -fn foo() { self::m::$0 } - -mod m { - pub use super::p::wrong_fn as right_fn; - pub use super::p::WRONG_CONST as RIGHT_CONST; - pub use super::p::WrongType as RightType; -} -mod p { - pub fn wrong_fn() {} - pub const WRONG_CONST: u32 = 1; - pub struct WrongType {}; -} -"#, - expect![[r#" - ct RIGHT_CONST - fn right_fn() fn() - st RightType - "#]], - ); - - check_edit( - "RightType", - r#" -fn foo() { self::m::$0 } - -mod m { - pub use super::p::wrong_fn as right_fn; - pub use super::p::WRONG_CONST as RIGHT_CONST; - pub use super::p::WrongType as RightType; -} -mod p { - pub fn wrong_fn() {} - pub const WRONG_CONST: u32 = 1; - pub struct WrongType {}; -} -"#, - r#" -fn foo() { self::m::RightType } - -mod m { - pub use super::p::wrong_fn as right_fn; - pub use super::p::WRONG_CONST as RIGHT_CONST; - pub use super::p::WrongType as RightType; -} -mod p { - pub fn wrong_fn() {} - pub const WRONG_CONST: u32 = 1; - pub struct WrongType {}; -} -"#, - ); -} - -#[test] -fn completes_in_simple_macro_call() { - check( - r#" -macro_rules! m { ($e:expr) => { $e } } -fn main() { m!(self::f$0); } -fn foo() {} -"#, - expect![[r#" - fn foo() fn() - fn main() fn() - "#]], - ); -} - -#[test] -fn function_mod_share_name() { - check( - r#" -fn foo() { self::m::$0 } - -mod m { - pub mod z {} - pub fn z() {} -} -"#, - expect![[r#" - fn z() fn() - md z - "#]], - ); -} - -#[test] -fn completes_hashmap_new() { - check( - r#" -struct RandomState; -struct HashMap {} - -impl HashMap { - pub fn new() -> HashMap { } -} -fn foo() { - HashMap::$0 -} -"#, - expect![[r#" - fn new() fn() -> HashMap - "#]], - ); -} - -#[test] -fn completes_variant_through_self() { - cov_mark::check!(completes_variant_through_self); - check( - r#" -enum Foo { - Bar, - Baz, -} - -impl Foo { - fn foo(self) { - Self::$0 - } -} -"#, - expect![[r#" - ev Bar Bar - ev Baz Baz - me foo(…) fn(self) - "#]], - ); -} - -#[test] -fn completes_non_exhaustive_variant_within_the_defining_crate() { - check( - r#" -enum Foo { - #[non_exhaustive] - Bar, - Baz, -} - -fn foo(self) { - Foo::$0 -} -"#, - expect![[r#" - ev Bar Bar - ev Baz Baz - "#]], - ); - - check( - r#" -//- /main.rs crate:main deps:e -fn foo(self) { - e::Foo::$0 -} - -//- /e.rs crate:e -enum Foo { - #[non_exhaustive] - Bar, - Baz, -} -"#, - expect![[r#" - ev Baz Baz - "#]], - ); -} - -#[test] -fn completes_primitive_assoc_const() { - cov_mark::check!(completes_primitive_assoc_const); - check( - r#" -//- /lib.rs crate:lib deps:core -fn f() { - u8::$0 -} - -//- /core.rs crate:core -#[lang = "u8"] -impl u8 { - pub const MAX: Self = 255; - - pub fn func(self) {} -} -"#, - expect![[r#" - ct MAX pub const MAX: Self - me func(…) fn(self) - "#]], - ); -} - -#[test] -fn completes_variant_through_alias() { - cov_mark::check!(completes_variant_through_alias); - check( - r#" -enum Foo { - Bar -} -type Foo2 = Foo; -fn main() { - Foo2::$0 -} -"#, - expect![[r#" - ev Bar Bar - "#]], - ); -} - -#[test] -fn respects_doc_hidden2() { - check( - r#" -//- /lib.rs crate:lib deps:dep -fn f() { - dep::$0 -} - -//- /dep.rs crate:dep -#[doc(hidden)] -#[macro_export] -macro_rules! m { - () => {} -} - -#[doc(hidden)] -pub fn f() {} - -#[doc(hidden)] -pub struct S; - -#[doc(hidden)] -pub mod m {} - "#, - expect![[r#""#]], - ) -} - -#[test] -fn type_anchor_empty() { - check( - r#" -trait Foo { - fn foo() -> Self; -} -struct Bar; -impl Foo for Bar { - fn foo() -> { - Bar - } -} -fn bar() -> Bar { - <_>::$0 -} -"#, - expect![[r#" - fn foo() (as Foo) fn() -> Self - "#]], - ) -} - -#[test] -fn completes_fn_in_pub_trait_generated_by_macro() { - check( - r#" -mod other_mod { - macro_rules! make_method { - ($name:ident) => { - fn $name(&self) {} - }; - } - - pub trait MyTrait { - make_method! { by_macro } - fn not_by_macro(&self) {} - } - - pub struct Foo {} - - impl MyTrait for Foo {} -} - -fn main() { - use other_mod::{Foo, MyTrait}; - let f = Foo {}; - f.$0 -} -"#, - expect![[r#" - me by_macro() (as MyTrait) fn(&self) - me not_by_macro() (as MyTrait) fn(&self) - "#]], - ) -} - -#[test] -fn completes_fn_in_pub_trait_generated_by_recursive_macro() { - check( - r#" -mod other_mod { - macro_rules! make_method { - ($name:ident) => { - fn $name(&self) {} - }; - } - - macro_rules! make_trait { - () => { - pub trait MyTrait { - make_method! { by_macro } - fn not_by_macro(&self) {} - } - } - } - - make_trait!(); - - pub struct Foo {} - - impl MyTrait for Foo {} -} - -fn main() { - use other_mod::{Foo, MyTrait}; - let f = Foo {}; - f.$0 -} -"#, - expect![[r#" - me by_macro() (as MyTrait) fn(&self) - me not_by_macro() (as MyTrait) fn(&self) - "#]], - ) -} - -#[test] -fn completes_const_in_pub_trait_generated_by_macro() { - check( - r#" -mod other_mod { - macro_rules! make_const { - ($name:ident) => { - const $name: u8 = 1; - }; - } - - pub trait MyTrait { - make_const! { by_macro } - } - - pub struct Foo {} - - impl MyTrait for Foo {} -} - -fn main() { - use other_mod::{Foo, MyTrait}; - let f = Foo {}; - Foo::$0 -} -"#, - expect![[r#" - ct by_macro (as MyTrait) pub const by_macro: u8 - "#]], - ) -} - -#[test] -fn completes_locals_from_macros() { - check( - r#" - -macro_rules! x { - ($x:ident, $expr:expr) => { - let $x = 0; - $expr - }; -} -fn main() { - x! { - foobar, { - f$0 - } - }; -} -"#, - expect![[r#" - fn main() fn() - lc foobar i32 - ma x!(…) macro_rules! x - bt u32 - "#]], - ) -} - -#[test] -fn regression_12644() { - check( - r#" -macro_rules! __rust_force_expr { - ($e:expr) => { - $e - }; -} -macro_rules! vec { - ($elem:expr) => { - __rust_force_expr!($elem) - }; -} - -struct Struct; -impl Struct { - fn foo(self) {} -} - -fn f() { - vec![Struct].$0; -} -"#, - expect![[r#" - me foo() fn(self) - "#]], - ); -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs deleted file mode 100644 index f0b7726c51d9b..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs +++ /dev/null @@ -1,671 +0,0 @@ -//! Completion tests for type position. -use expect_test::{expect, Expect}; - -use crate::tests::{completion_list, BASE_ITEMS_FIXTURE}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{}\n{}", BASE_ITEMS_FIXTURE, ra_fixture)); - expect.assert_eq(&actual) -} - -#[test] -fn record_field_ty() { - check( - r#" -struct Foo<'lt, T, const C: usize> { - f: $0 -} -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - sp Self - st Foo<…> - st Record - st Tuple - st Unit - tt Trait - tp T - un Union - bt u32 - kw crate:: - kw self:: - "#]], - ) -} - -#[test] -fn tuple_struct_field() { - check( - r#" -struct Foo<'lt, T, const C: usize>(f$0); -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - sp Self - st Foo<…> - st Record - st Tuple - st Unit - tt Trait - tp T - un Union - bt u32 - kw crate:: - kw pub - kw pub(crate) - kw pub(super) - kw self:: - "#]], - ) -} - -#[test] -fn fn_return_type() { - check( - r#" -fn x<'lt, T, const C: usize>() -> $0 -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - st Record - st Tuple - st Unit - tt Trait - tp T - un Union - bt u32 - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn fn_return_type_no_local_items() { - check( - r#" -fn foo() -> B$0 { - struct Bar; - enum Baz {} - union Bax { - i: i32, - f: f32 - } -} -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - st Record - st Tuple - st Unit - tt Trait - un Union - bt u32 - it () - kw crate:: - kw self:: - "#]], - ) -} - -#[test] -fn inferred_type_const() { - check( - r#" -struct Foo(T); -const FOO: $0 = Foo(2); -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - st Foo<…> - st Record - st Tuple - st Unit - tt Trait - un Union - bt u32 - it Foo - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn inferred_type_closure_param() { - check( - r#" -fn f1(f: fn(i32) -> i32) {} -fn f2() { - f1(|x: $0); -} -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - st Record - st Tuple - st Unit - tt Trait - un Union - bt u32 - it i32 - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn inferred_type_closure_return() { - check( - r#" -fn f1(f: fn(u64) -> u64) {} -fn f2() { - f1(|x| -> $0 { - x + 5 - }); -} -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - st Record - st Tuple - st Unit - tt Trait - un Union - bt u32 - it u64 - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn inferred_type_fn_return() { - check( - r#" -fn f2(x: u64) -> $0 { - x + 5 -} -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - st Record - st Tuple - st Unit - tt Trait - un Union - bt u32 - it u64 - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn inferred_type_fn_param() { - check( - r#" -fn f1(x: i32) {} -fn f2(x: $0) { - f1(x); -} -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - st Record - st Tuple - st Unit - tt Trait - un Union - bt u32 - it i32 - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn inferred_type_not_in_the_scope() { - check( - r#" -mod a { - pub struct Foo(T); - pub fn x() -> Foo> { - Foo(Foo(2)) - } -} -fn foo<'lt, T, const C: usize>() { - let local = (); - let foo: $0 = a::x(); -} -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md a - md module - st Record - st Tuple - st Unit - tt Trait - tp T - un Union - bt u32 - it a::Foo> - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn inferred_type_let() { - check( - r#" -struct Foo(T); -fn foo<'lt, T, const C: usize>() { - let local = (); - let foo: $0 = Foo(2); -} -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - st Foo<…> - st Record - st Tuple - st Unit - tt Trait - tp T - un Union - bt u32 - it Foo - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn body_type_pos() { - check( - r#" -fn foo<'lt, T, const C: usize>() { - let local = (); - let _: $0; -} -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - st Record - st Tuple - st Unit - tt Trait - tp T - un Union - bt u32 - kw crate:: - kw self:: - "#]], - ); - check( - r#" -fn foo<'lt, T, const C: usize>() { - let local = (); - let _: self::$0; -} -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - st Record - st Tuple - st Unit - tt Trait - un Union - "#]], - ); -} - -#[test] -fn completes_types_and_const_in_arg_list() { - cov_mark::check!(complete_assoc_type_in_generics_list); - check( - r#" -trait Trait1 { - type Super; -} -trait Trait2: Trait1 { - type Foo; -} - -fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {} -"#, - expect![[r#" - ta Foo = (as Trait2) type Foo - ta Super = (as Trait1) type Super - "#]], - ); - check( - r#" -trait Trait1 { - type Super; -} -trait Trait2: Trait1 { - type Foo; -} - -fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {} -"#, - expect![[r#" - ct CONST - cp CONST_PARAM - en Enum - ma makro!(…) macro_rules! makro - md module - st Record - st Tuple - st Unit - tt Trait - tt Trait1 - tt Trait2 - tp T - un Union - bt u32 - kw crate:: - kw self:: - "#]], - ); - check( - r#" -trait Trait2 { - type Foo; -} - -fn foo<'lt, T: Trait2, const CONST_PARAM: usize>(_: T) {} - "#, - expect![[r#" - ct CONST - en Enum - ma makro!(…) macro_rules! makro - md module - st Record - st Tuple - st Unit - tt Trait - tt Trait2 - un Union - "#]], - ); -} - -#[test] -fn no_assoc_completion_outside_type_bounds() { - check( - r#" -struct S; -trait Tr { - type Ty; -} - -impl Tr<$0 - "#, - expect![[r#" - ct CONST - en Enum - ma makro!(…) macro_rules! makro - md module - sp Self - st Record - st S - st Tuple - st Unit - tt Tr - tt Trait - un Union - bt u32 - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn enum_qualified() { - check( - r#" -impl Enum { - type AssocType = (); - const ASSOC_CONST: () = (); - fn assoc_fn() {} -} -fn func(_: Enum::$0) {} -"#, - expect![[r#" - ta AssocType type AssocType = () - "#]], - ); -} - -#[test] -fn completes_type_parameter_or_associated_type() { - check( - r#" -trait MyTrait { - type Item1; - type Item2; -}; - -fn f(t: impl MyTrait { - type Item1; - type Item2; -}; - -fn f(t: impl MyTrait { - type Item1; - type Item2; -}; - -fn f(t: impl MyTrait { - type Item1; - type Item2; -}; - -fn f(t: impl MyTrait { - type Item1; - type Item2; -}; - -fn f(t: impl MyTrait { - type Item1; - type Item2; -}; - -fn f(t: impl MyTrait {} } - pub use foo_ as foo; -} -struct Bar; -"#, - expect![[r#" - ma foo macro_rules! foo_ - st Foo - "#]], - ); -} - -#[test] -fn enum_plain_qualified_use_tree() { - cov_mark::check!(enum_plain_qualified_use_tree); - check( - r#" -use Foo::$0 - -enum Foo { - UnitVariant, - TupleVariant(), - RecordVariant {}, -} -impl Foo { - const CONST: () = () - fn func() {} -} -"#, - expect![[r#" - ev RecordVariant RecordVariant - ev TupleVariant TupleVariant - ev UnitVariant UnitVariant - "#]], - ); -} - -#[test] -fn self_qualified_use_tree() { - check( - r#" -use self::$0 - -mod foo {} -struct Bar; -"#, - expect![[r#" - md foo - st Bar - "#]], - ); -} - -#[test] -fn super_qualified_use_tree() { - check( - r#" -mod bar { - use super::$0 -} - -mod foo {} -struct Bar; -"#, - expect![[r#" - md bar - md foo - st Bar - "#]], - ); -} - -#[test] -fn super_super_qualified_use_tree() { - check( - r#" -mod a { - const A: usize = 0; - mod b { - const B: usize = 0; - mod c { use super::super::$0 } - } -} -"#, - expect![[r#" - ct A - md b - kw super:: - "#]], - ); -} - -#[test] -fn crate_qualified_use_tree() { - check( - r#" -use crate::$0 - -mod foo {} -struct Bar; -"#, - expect![[r#" - md foo - st Bar - "#]], - ); -} - -#[test] -fn extern_crate_qualified_use_tree() { - check( - r#" -//- /lib.rs crate:main deps:other_crate -use other_crate::$0 -//- /other_crate/lib.rs crate:other_crate -pub struct Foo; -pub mod foo {} -"#, - expect![[r#" - md foo - st Foo - "#]], - ); -} - -#[test] -fn pub_use_tree() { - check( - r#" -pub struct X; -pub mod bar {} -pub use $0; -"#, - expect![[r#" - md bar - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn pub_suggest_use_tree_super_acc_to_depth_in_tree() { - // https://github.com/rust-lang/rust-analyzer/issues/12439 - // Check discussion in https://github.com/rust-lang/rust-analyzer/pull/12447 - - check( - r#" -mod foo { - mod bar { - pub use super::$0; - } -} -"#, - expect![[r#" - md bar - kw super:: - "#]], - ); - - // Not suggest super when at crate root - check( - r#" -mod foo { - mod bar { - pub use super::super::$0; - } -} -"#, - expect![[r#" - md foo - "#]], - ); - - check( - r#" -mod foo { - use $0; -} -"#, - expect![[r#" - kw crate:: - kw self:: - kw super:: - "#]], - ); - - // Not suggest super after another kw in path ( here it is foo1 ) - check( - r#" -mod foo { - mod bar { - use super::super::foo1::$0; - } -} - -mod foo1 { - pub mod bar1 {} -} -"#, - expect![[r#" - md bar1 - "#]], - ); -} - -#[test] -fn use_tree_braces_at_start() { - check( - r#" -struct X; -mod bar {} -use {$0}; -"#, - expect![[r#" - md bar - kw crate:: - kw self:: - "#]], - ); -} - -#[test] -fn impl_prefix_does_not_add_fn_snippet() { - // regression test for 7222 - check( - r#" -mod foo { - pub fn bar(x: u32) {} -} -use self::foo::impl$0 -"#, - expect![[r#" - fn bar fn(u32) - "#]], - ); -} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs deleted file mode 100644 index c18d6e66dd602..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs +++ /dev/null @@ -1,90 +0,0 @@ -//! Completion tests for visibility modifiers. -use expect_test::{expect, Expect}; - -use crate::tests::{completion_list, completion_list_with_trigger_character}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) -} - -fn check_with_trigger_character(ra_fixture: &str, trigger_character: char, expect: Expect) { - let actual = completion_list_with_trigger_character(ra_fixture, Some(trigger_character)); - expect.assert_eq(&actual) -} - -#[test] -fn empty_pub() { - cov_mark::check!(kw_completion_in); - check_with_trigger_character( - r#" -pub($0) -"#, - '(', - expect![[r#" - kw crate - kw in - kw self - "#]], - ); -} - -#[test] -fn after_in_kw() { - check( - r#" -pub(in $0) -"#, - expect![[r#" - kw crate - kw self - "#]], - ); -} - -#[test] -fn qualified() { - cov_mark::check!(visibility_qualified); - check( - r#" -mod foo { - pub(in crate::$0) -} - -mod bar {} -"#, - expect![[r#" - md foo - "#]], - ); - check( - r#" -mod qux { - mod foo { - pub(in crate::$0) - } - mod baz {} -} - -mod bar {} -"#, - expect![[r#" - md qux - "#]], - ); - check( - r#" -mod qux { - mod foo { - pub(in crate::qux::$0) - } - mod baz {} -} - -mod bar {} -"#, - expect![[r#" - md foo - "#]], - ); -} diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml deleted file mode 100644 index a1b0bd6cb3044..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -name = "ide-db" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -cov-mark = "2.0.0-pre.1" -tracing = "0.1.35" -rayon = "1.5.3" -fst = { version = "0.4.7", default-features = false } -rustc-hash = "1.1.0" -once_cell = "1.12.0" -either = "1.7.0" -itertools = "0.10.3" -arrayvec = "0.7.2" -indexmap = "1.9.1" - -stdx = { path = "../stdx", version = "0.0.0" } -parser = { path = "../parser", version = "0.0.0" } -syntax = { path = "../syntax", version = "0.0.0" } -text-edit = { path = "../text-edit", version = "0.0.0" } -base-db = { path = "../base-db", version = "0.0.0" } -profile = { path = "../profile", version = "0.0.0" } -# ide should depend only on the top-level `hir` package. if you need -# something from some `hir-xxx` subpackage, reexport the API via `hir`. -hir = { path = "../hir", version = "0.0.0" } -limit = { path = "../limit", version = "0.0.0" } - -[dev-dependencies] -test-utils = { path = "../test-utils" } -sourcegen = { path = "../sourcegen" } -xshell = "0.2.2" -expect-test = "1.4.0" diff --git a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs deleted file mode 100644 index 7303ef8b7bb58..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! This module provides functionality for querying callable information about a token. - -use either::Either; -use hir::{Semantics, Type}; -use syntax::{ - ast::{self, HasArgList, HasName}, - AstNode, SyntaxToken, -}; - -use crate::RootDatabase; - -#[derive(Debug)] -pub struct ActiveParameter { - pub ty: Type, - pub pat: Either, -} - -impl ActiveParameter { - /// Returns information about the call argument this token is part of. - pub fn at_token(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option { - let (signature, active_parameter) = callable_for_token(sema, token)?; - - let idx = active_parameter?; - let mut params = signature.params(sema.db); - if !(idx < params.len()) { - cov_mark::hit!(too_many_arguments); - return None; - } - let (pat, ty) = params.swap_remove(idx); - pat.map(|pat| ActiveParameter { ty, pat }) - } - - pub fn ident(&self) -> Option { - self.pat.as_ref().right().and_then(|param| match param { - ast::Pat::IdentPat(ident) => ident.name(), - _ => None, - }) - } -} - -/// Returns a [`hir::Callable`] this token is a part of and its argument index of said callable. -pub fn callable_for_token( - sema: &Semantics<'_, RootDatabase>, - token: SyntaxToken, -) -> Option<(hir::Callable, Option)> { - // Find the calling expression and its NameRef - let parent = token.parent()?; - let calling_node = parent.ancestors().filter_map(ast::CallableExpr::cast).find(|it| { - it.arg_list() - .map_or(false, |it| it.syntax().text_range().contains(token.text_range().start())) - })?; - - callable_for_node(sema, &calling_node, &token) -} - -pub fn callable_for_node( - sema: &Semantics<'_, RootDatabase>, - calling_node: &ast::CallableExpr, - token: &SyntaxToken, -) -> Option<(hir::Callable, Option)> { - let callable = match &calling_node { - ast::CallableExpr::Call(call) => { - let expr = call.expr()?; - sema.type_of_expr(&expr)?.adjusted().as_callable(sema.db) - } - ast::CallableExpr::MethodCall(call) => sema.resolve_method_call_as_callable(call), - }?; - let active_param = if let Some(arg_list) = calling_node.arg_list() { - let param = arg_list - .args() - .take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start()) - .count(); - Some(param) - } else { - None - }; - Some((callable, active_param)) -} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs deleted file mode 100644 index 98b0e9c947a74..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs +++ /dev/null @@ -1,163 +0,0 @@ -//! Applies changes to the IDE state transactionally. - -use std::sync::Arc; - -use base_db::{ - salsa::{Database, Durability}, - Change, SourceRootId, -}; -use profile::{memory_usage, Bytes}; -use rustc_hash::FxHashSet; - -use crate::{symbol_index::SymbolsDatabase, RootDatabase}; - -impl RootDatabase { - pub fn request_cancellation(&mut self) { - let _p = profile::span("RootDatabase::request_cancellation"); - self.salsa_runtime_mut().synthetic_write(Durability::LOW); - } - - pub fn apply_change(&mut self, change: Change) { - let _p = profile::span("RootDatabase::apply_change"); - self.request_cancellation(); - tracing::info!("apply_change {:?}", change); - if let Some(roots) = &change.roots { - let mut local_roots = FxHashSet::default(); - let mut library_roots = FxHashSet::default(); - for (idx, root) in roots.iter().enumerate() { - let root_id = SourceRootId(idx as u32); - if root.is_library { - library_roots.insert(root_id); - } else { - local_roots.insert(root_id); - } - } - self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH); - self.set_library_roots_with_durability(Arc::new(library_roots), Durability::HIGH); - } - change.apply(self); - } - - // Feature: Memory Usage - // - // Clears rust-analyzer's internal database and prints memory usage statistics. - // - // |=== - // | Editor | Action Name - // - // | VS Code | **Rust Analyzer: Memory Usage (Clears Database)** - // |=== - // image::https://user-images.githubusercontent.com/48062697/113065592-08559f00-91b1-11eb-8c96-64b88068ec02.gif[] - pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> { - let mut acc: Vec<(String, Bytes)> = vec![]; - macro_rules! purge_each_query { - ($($q:path)*) => {$( - let before = memory_usage().allocated; - $q.in_db(self).purge(); - let after = memory_usage().allocated; - let q: $q = Default::default(); - let name = format!("{:?}", q); - acc.push((name, before - after)); - )*} - } - purge_each_query![ - // SourceDatabase - base_db::ParseQuery - base_db::CrateGraphQuery - - // SourceDatabaseExt - base_db::FileTextQuery - base_db::FileSourceRootQuery - base_db::SourceRootQuery - base_db::SourceRootCratesQuery - - // AstDatabase - hir::db::AstIdMapQuery - hir::db::MacroArgTextQuery - hir::db::MacroDefQuery - hir::db::ParseMacroExpansionQuery - hir::db::MacroExpandQuery - hir::db::HygieneFrameQuery - hir::db::InternMacroCallQuery - - // DefDatabase - hir::db::FileItemTreeQuery - hir::db::BlockDefMapQuery - hir::db::CrateDefMapQueryQuery - hir::db::FieldsAttrsQuery - hir::db::VariantsAttrsQuery - hir::db::FieldsAttrsSourceMapQuery - hir::db::VariantsAttrsSourceMapQuery - hir::db::StructDataQuery - hir::db::UnionDataQuery - hir::db::EnumDataQuery - hir::db::ImplDataQuery - hir::db::TraitDataQuery - hir::db::TypeAliasDataQuery - hir::db::FunctionDataQuery - hir::db::ConstDataQuery - hir::db::StaticDataQuery - hir::db::BodyWithSourceMapQuery - hir::db::BodyQuery - hir::db::ExprScopesQuery - hir::db::GenericParamsQuery - hir::db::AttrsQuery - hir::db::CrateLangItemsQuery - hir::db::LangItemQuery - hir::db::ImportMapQuery - - // HirDatabase - hir::db::InferQueryQuery - hir::db::TyQuery - hir::db::ValueTyQuery - hir::db::ImplSelfTyQuery - hir::db::ImplTraitQuery - hir::db::FieldTypesQuery - hir::db::CallableItemSignatureQuery - hir::db::GenericPredicatesForParamQuery - hir::db::GenericPredicatesQuery - hir::db::GenericDefaultsQuery - hir::db::InherentImplsInCrateQuery - hir::db::TraitEnvironmentQuery - hir::db::TraitImplsInCrateQuery - hir::db::TraitImplsInDepsQuery - hir::db::AssociatedTyDataQuery - hir::db::AssociatedTyDataQuery - hir::db::TraitDatumQuery - hir::db::StructDatumQuery - hir::db::ImplDatumQuery - hir::db::FnDefDatumQuery - hir::db::ReturnTypeImplTraitsQuery - hir::db::InternCallableDefQuery - hir::db::InternTypeOrConstParamIdQuery - hir::db::InternImplTraitIdQuery - hir::db::InternClosureQuery - hir::db::AssociatedTyValueQuery - hir::db::TraitSolveQueryQuery - hir::db::InternTypeOrConstParamIdQuery - - // SymbolsDatabase - crate::symbol_index::ModuleSymbolsQuery - crate::symbol_index::LibrarySymbolsQuery - crate::symbol_index::LocalRootsQuery - crate::symbol_index::LibraryRootsQuery - - // LineIndexDatabase - crate::LineIndexQuery - - // InternDatabase - hir::db::InternFunctionQuery - hir::db::InternStructQuery - hir::db::InternUnionQuery - hir::db::InternEnumQuery - hir::db::InternConstQuery - hir::db::InternStaticQuery - hir::db::InternTraitQuery - hir::db::InternTypeAliasQuery - hir::db::InternImplQuery - ]; - - acc.sort_by_key(|it| std::cmp::Reverse(it.1)); - acc - } -} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/assists.rs b/src/tools/rust-analyzer/crates/ide-db/src/assists.rs deleted file mode 100644 index da23763dc2924..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-db/src/assists.rs +++ /dev/null @@ -1,137 +0,0 @@ -//! This module defines the `Assist` data structure. The actual assist live in -//! the `ide_assists` downstream crate. We want to define the data structures in -//! this low-level crate though, because `ide_diagnostics` also need them -//! (fixits for diagnostics and assists are the same thing under the hood). We -//! want to compile `ide_assists` and `ide_diagnostics` in parallel though, so -//! we pull the common definitions upstream, to this crate. - -use std::str::FromStr; - -use syntax::TextRange; - -use crate::{label::Label, source_change::SourceChange}; - -#[derive(Debug, Clone)] -pub struct Assist { - pub id: AssistId, - /// Short description of the assist, as shown in the UI. - pub label: Label, - pub group: Option, - /// Target ranges are used to sort assists: the smaller the target range, - /// the more specific assist is, and so it should be sorted first. - pub target: TextRange, - /// Computing source change sometimes is much more costly then computing the - /// other fields. Additionally, the actual change is not required to show - /// the lightbulb UI, it only is needed when the user tries to apply an - /// assist. So, we compute it lazily: the API allow requesting assists with - /// or without source change. We could (and in fact, used to) distinguish - /// between resolved and unresolved assists at the type level, but this is - /// cumbersome, especially if you want to embed an assist into another data - /// structure, such as a diagnostic. - pub source_change: Option, - pub trigger_signature_help: bool, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum AssistKind { - // FIXME: does the None variant make sense? Probably not. - None, - - QuickFix, - Generate, - Refactor, - RefactorExtract, - RefactorInline, - RefactorRewrite, -} - -impl AssistKind { - pub fn contains(self, other: AssistKind) -> bool { - if self == other { - return true; - } - - match self { - AssistKind::None | AssistKind::Generate => true, - AssistKind::Refactor => matches!( - other, - AssistKind::RefactorExtract - | AssistKind::RefactorInline - | AssistKind::RefactorRewrite - ), - _ => false, - } - } - - pub fn name(&self) -> &str { - match self { - AssistKind::None => "None", - AssistKind::QuickFix => "QuickFix", - AssistKind::Generate => "Generate", - AssistKind::Refactor => "Refactor", - AssistKind::RefactorExtract => "RefactorExtract", - AssistKind::RefactorInline => "RefactorInline", - AssistKind::RefactorRewrite => "RefactorRewrite", - } - } -} - -impl FromStr for AssistKind { - type Err = String; - - fn from_str(s: &str) -> Result { - match s { - "None" => Ok(AssistKind::None), - "QuickFix" => Ok(AssistKind::QuickFix), - "Generate" => Ok(AssistKind::Generate), - "Refactor" => Ok(AssistKind::Refactor), - "RefactorExtract" => Ok(AssistKind::RefactorExtract), - "RefactorInline" => Ok(AssistKind::RefactorInline), - "RefactorRewrite" => Ok(AssistKind::RefactorRewrite), - unknown => Err(format!("Unknown AssistKind: '{}'", unknown)), - } - } -} - -/// Unique identifier of the assist, should not be shown to the user -/// directly. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct AssistId(pub &'static str, pub AssistKind); - -/// A way to control how many asssist to resolve during the assist resolution. -/// When an assist is resolved, its edits are calculated that might be costly to always do by default. -#[derive(Debug)] -pub enum AssistResolveStrategy { - /// No assists should be resolved. - None, - /// All assists should be resolved. - All, - /// Only a certain assist should be resolved. - Single(SingleResolve), -} - -/// Hold the [`AssistId`] data of a certain assist to resolve. -/// The original id object cannot be used due to a `'static` lifetime -/// and the requirement to construct this struct dynamically during the resolve handling. -#[derive(Debug)] -pub struct SingleResolve { - /// The id of the assist. - pub assist_id: String, - // The kind of the assist. - pub assist_kind: AssistKind, -} - -impl AssistResolveStrategy { - pub fn should_resolve(&self, id: &AssistId) -> bool { - match self { - AssistResolveStrategy::None => false, - AssistResolveStrategy::All => true, - AssistResolveStrategy::Single(single_resolve) => { - single_resolve.assist_id == id.0 && single_resolve.assist_kind == id.1 - } - } - } -} - -#[derive(Clone, Debug)] -pub struct GroupLabel(pub String); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs deleted file mode 100644 index aeaca00ec65cc..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ /dev/null @@ -1,545 +0,0 @@ -//! `NameDefinition` keeps information about the element we want to search references for. -//! The element is represented by `NameKind`. It's located inside some `container` and -//! has a `visibility`, which defines a search scope. -//! Note that the reference search is possible for not all of the classified items. - -// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). - -use arrayvec::ArrayVec; -use hir::{ - Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, DeriveHelper, Field, - Function, GenericParam, HasVisibility, Impl, ItemInNs, Label, Local, Macro, Module, ModuleDef, - Name, PathResolution, Semantics, Static, ToolModule, Trait, TypeAlias, Variant, Visibility, -}; -use stdx::impl_from; -use syntax::{ - ast::{self, AstNode}, - match_ast, SyntaxKind, SyntaxNode, SyntaxToken, -}; - -use crate::RootDatabase; - -// FIXME: a more precise name would probably be `Symbol`? -#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum Definition { - Macro(Macro), - Field(Field), - Module(Module), - Function(Function), - Adt(Adt), - Variant(Variant), - Const(Const), - Static(Static), - Trait(Trait), - TypeAlias(TypeAlias), - BuiltinType(BuiltinType), - SelfType(Impl), - Local(Local), - GenericParam(GenericParam), - Label(Label), - DeriveHelper(DeriveHelper), - BuiltinAttr(BuiltinAttr), - ToolModule(ToolModule), -} - -impl Definition { - pub fn canonical_module_path(&self, db: &RootDatabase) -> Option> { - self.module(db).map(|it| it.path_to_root(db).into_iter().rev()) - } - - pub fn krate(&self, db: &RootDatabase) -> Option { - Some(match self { - Definition::Module(m) => m.krate(), - _ => self.module(db)?.krate(), - }) - } - - pub fn module(&self, db: &RootDatabase) -> Option { - let module = match self { - Definition::Macro(it) => it.module(db), - Definition::Module(it) => it.parent(db)?, - Definition::Field(it) => it.parent_def(db).module(db), - Definition::Function(it) => it.module(db), - Definition::Adt(it) => it.module(db), - Definition::Const(it) => it.module(db), - Definition::Static(it) => it.module(db), - Definition::Trait(it) => it.module(db), - Definition::TypeAlias(it) => it.module(db), - Definition::Variant(it) => it.module(db), - Definition::SelfType(it) => it.module(db), - Definition::Local(it) => it.module(db), - Definition::GenericParam(it) => it.module(db), - Definition::Label(it) => it.module(db), - Definition::DeriveHelper(it) => it.derive().module(db), - Definition::BuiltinAttr(_) | Definition::BuiltinType(_) | Definition::ToolModule(_) => { - return None - } - }; - Some(module) - } - - pub fn visibility(&self, db: &RootDatabase) -> Option { - let vis = match self { - Definition::Field(sf) => sf.visibility(db), - Definition::Module(it) => it.visibility(db), - Definition::Function(it) => it.visibility(db), - Definition::Adt(it) => it.visibility(db), - Definition::Const(it) => it.visibility(db), - Definition::Static(it) => it.visibility(db), - Definition::Trait(it) => it.visibility(db), - Definition::TypeAlias(it) => it.visibility(db), - Definition::Variant(it) => it.visibility(db), - Definition::BuiltinType(_) => Visibility::Public, - Definition::Macro(_) => return None, - Definition::BuiltinAttr(_) - | Definition::ToolModule(_) - | Definition::SelfType(_) - | Definition::Local(_) - | Definition::GenericParam(_) - | Definition::Label(_) - | Definition::DeriveHelper(_) => return None, - }; - Some(vis) - } - - pub fn name(&self, db: &RootDatabase) -> Option { - let name = match self { - Definition::Macro(it) => it.name(db), - Definition::Field(it) => it.name(db), - Definition::Module(it) => it.name(db)?, - Definition::Function(it) => it.name(db), - Definition::Adt(it) => it.name(db), - Definition::Variant(it) => it.name(db), - Definition::Const(it) => it.name(db)?, - Definition::Static(it) => it.name(db), - Definition::Trait(it) => it.name(db), - Definition::TypeAlias(it) => it.name(db), - Definition::BuiltinType(it) => it.name(), - Definition::SelfType(_) => return None, - Definition::Local(it) => it.name(db), - Definition::GenericParam(it) => it.name(db), - Definition::Label(it) => it.name(db), - Definition::BuiltinAttr(_) => return None, // FIXME - Definition::ToolModule(_) => return None, // FIXME - Definition::DeriveHelper(it) => it.name(db), - }; - Some(name) - } -} - -#[derive(Debug)] -pub enum IdentClass { - NameClass(NameClass), - NameRefClass(NameRefClass), -} - -impl IdentClass { - pub fn classify_node( - sema: &Semantics<'_, RootDatabase>, - node: &SyntaxNode, - ) -> Option { - match_ast! { - match node { - ast::Name(name) => NameClass::classify(sema, &name).map(IdentClass::NameClass), - ast::NameRef(name_ref) => NameRefClass::classify(sema, &name_ref).map(IdentClass::NameRefClass), - ast::Lifetime(lifetime) => { - NameClass::classify_lifetime(sema, &lifetime) - .map(IdentClass::NameClass) - .or_else(|| NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass)) - }, - _ => None, - } - } - } - - pub fn classify_token( - sema: &Semantics<'_, RootDatabase>, - token: &SyntaxToken, - ) -> Option { - let parent = token.parent()?; - Self::classify_node(sema, &parent) - } - - pub fn classify_lifetime( - sema: &Semantics<'_, RootDatabase>, - lifetime: &ast::Lifetime, - ) -> Option { - NameRefClass::classify_lifetime(sema, lifetime) - .map(IdentClass::NameRefClass) - .or_else(|| NameClass::classify_lifetime(sema, lifetime).map(IdentClass::NameClass)) - } - - pub fn definitions(self) -> ArrayVec { - let mut res = ArrayVec::new(); - match self { - IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => { - res.push(it) - } - IdentClass::NameClass(NameClass::PatFieldShorthand { local_def, field_ref }) => { - res.push(Definition::Local(local_def)); - res.push(Definition::Field(field_ref)); - } - IdentClass::NameRefClass(NameRefClass::Definition(it)) => res.push(it), - IdentClass::NameRefClass(NameRefClass::FieldShorthand { local_ref, field_ref }) => { - res.push(Definition::Local(local_ref)); - res.push(Definition::Field(field_ref)); - } - } - res - } -} - -/// On a first blush, a single `ast::Name` defines a single definition at some -/// scope. That is, that, by just looking at the syntactical category, we can -/// unambiguously define the semantic category. -/// -/// Sadly, that's not 100% true, there are special cases. To make sure that -/// callers handle all the special cases correctly via exhaustive matching, we -/// add a [`NameClass`] enum which lists all of them! -/// -/// A model special case is `None` constant in pattern. -#[derive(Debug)] -pub enum NameClass { - Definition(Definition), - /// `None` in `if let None = Some(82) {}`. - /// Syntactically, it is a name, but semantically it is a reference. - ConstReference(Definition), - /// `field` in `if let Foo { field } = foo`. Here, `ast::Name` both introduces - /// a definition into a local scope, and refers to an existing definition. - PatFieldShorthand { - local_def: Local, - field_ref: Field, - }, -} - -impl NameClass { - /// `Definition` defined by this name. - pub fn defined(self) -> Option { - let res = match self { - NameClass::Definition(it) => it, - NameClass::ConstReference(_) => return None, - NameClass::PatFieldShorthand { local_def, field_ref: _ } => { - Definition::Local(local_def) - } - }; - Some(res) - } - - pub fn classify(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option { - let _p = profile::span("classify_name"); - - let parent = name.syntax().parent()?; - - let definition = match_ast! { - match parent { - ast::Item(it) => classify_item(sema, it)?, - ast::IdentPat(it) => return classify_ident_pat(sema, it), - ast::Rename(it) => classify_rename(sema, it)?, - ast::SelfParam(it) => Definition::Local(sema.to_def(&it)?), - ast::RecordField(it) => Definition::Field(sema.to_def(&it)?), - ast::Variant(it) => Definition::Variant(sema.to_def(&it)?), - ast::TypeParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()), - ast::ConstParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()), - _ => return None, - } - }; - return Some(NameClass::Definition(definition)); - - fn classify_item( - sema: &Semantics<'_, RootDatabase>, - item: ast::Item, - ) -> Option { - let definition = match item { - ast::Item::MacroRules(it) => { - Definition::Macro(sema.to_def(&ast::Macro::MacroRules(it))?) - } - ast::Item::MacroDef(it) => { - Definition::Macro(sema.to_def(&ast::Macro::MacroDef(it))?) - } - ast::Item::Const(it) => Definition::Const(sema.to_def(&it)?), - ast::Item::Fn(it) => { - let def = sema.to_def(&it)?; - def.as_proc_macro(sema.db) - .map(Definition::Macro) - .unwrap_or(Definition::Function(def)) - } - ast::Item::Module(it) => Definition::Module(sema.to_def(&it)?), - ast::Item::Static(it) => Definition::Static(sema.to_def(&it)?), - ast::Item::Trait(it) => Definition::Trait(sema.to_def(&it)?), - ast::Item::TypeAlias(it) => Definition::TypeAlias(sema.to_def(&it)?), - ast::Item::Enum(it) => Definition::Adt(hir::Adt::Enum(sema.to_def(&it)?)), - ast::Item::Struct(it) => Definition::Adt(hir::Adt::Struct(sema.to_def(&it)?)), - ast::Item::Union(it) => Definition::Adt(hir::Adt::Union(sema.to_def(&it)?)), - _ => return None, - }; - Some(definition) - } - - fn classify_ident_pat( - sema: &Semantics<'_, RootDatabase>, - ident_pat: ast::IdentPat, - ) -> Option { - if let Some(def) = sema.resolve_bind_pat_to_const(&ident_pat) { - return Some(NameClass::ConstReference(Definition::from(def))); - } - - let local = sema.to_def(&ident_pat)?; - let pat_parent = ident_pat.syntax().parent(); - if let Some(record_pat_field) = pat_parent.and_then(ast::RecordPatField::cast) { - if record_pat_field.name_ref().is_none() { - if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) { - return Some(NameClass::PatFieldShorthand { - local_def: local, - field_ref: field, - }); - } - } - } - Some(NameClass::Definition(Definition::Local(local))) - } - - fn classify_rename( - sema: &Semantics<'_, RootDatabase>, - rename: ast::Rename, - ) -> Option { - if let Some(use_tree) = rename.syntax().parent().and_then(ast::UseTree::cast) { - let path = use_tree.path()?; - sema.resolve_path(&path).map(Definition::from) - } else { - let extern_crate = rename.syntax().parent().and_then(ast::ExternCrate::cast)?; - let krate = sema.resolve_extern_crate(&extern_crate)?; - let root_module = krate.root_module(sema.db); - Some(Definition::Module(root_module)) - } - } - } - - pub fn classify_lifetime( - sema: &Semantics<'_, RootDatabase>, - lifetime: &ast::Lifetime, - ) -> Option { - let _p = profile::span("classify_lifetime").detail(|| lifetime.to_string()); - let parent = lifetime.syntax().parent()?; - - if let Some(it) = ast::LifetimeParam::cast(parent.clone()) { - sema.to_def(&it).map(Into::into).map(Definition::GenericParam) - } else if let Some(it) = ast::Label::cast(parent) { - sema.to_def(&it).map(Definition::Label) - } else { - None - } - .map(NameClass::Definition) - } -} - -/// This is similar to [`NameClass`], but works for [`ast::NameRef`] rather than -/// for [`ast::Name`]. Similarly, what looks like a reference in syntax is a -/// reference most of the time, but there are a couple of annoying exceptions. -/// -/// A model special case is field shorthand syntax, which uses a single -/// reference to point to two different defs. -#[derive(Debug)] -pub enum NameRefClass { - Definition(Definition), - FieldShorthand { local_ref: Local, field_ref: Field }, -} - -impl NameRefClass { - // Note: we don't have unit-tests for this rather important function. - // It is primarily exercised via goto definition tests in `ide`. - pub fn classify( - sema: &Semantics<'_, RootDatabase>, - name_ref: &ast::NameRef, - ) -> Option { - let _p = profile::span("classify_name_ref").detail(|| name_ref.to_string()); - - let parent = name_ref.syntax().parent()?; - - if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) { - if let Some((field, local, _)) = sema.resolve_record_field(&record_field) { - let res = match local { - None => NameRefClass::Definition(Definition::Field(field)), - Some(local) => { - NameRefClass::FieldShorthand { field_ref: field, local_ref: local } - } - }; - return Some(res); - } - } - - if let Some(path) = ast::PathSegment::cast(parent.clone()).map(|it| it.parent_path()) { - if path.parent_path().is_none() { - if let Some(macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { - // Only use this to resolve to macro calls for last segments as qualifiers resolve - // to modules below. - if let Some(macro_def) = sema.resolve_macro_call(¯o_call) { - return Some(NameRefClass::Definition(Definition::Macro(macro_def))); - } - } - } - return sema.resolve_path(&path).map(Into::into).map(NameRefClass::Definition); - } - - match_ast! { - match parent { - ast::MethodCallExpr(method_call) => { - sema.resolve_method_call(&method_call) - .map(Definition::Function) - .map(NameRefClass::Definition) - }, - ast::FieldExpr(field_expr) => { - sema.resolve_field(&field_expr) - .map(Definition::Field) - .map(NameRefClass::Definition) - }, - ast::RecordPatField(record_pat_field) => { - sema.resolve_record_pat_field(&record_pat_field) - .map(Definition::Field) - .map(NameRefClass::Definition) - }, - ast::AssocTypeArg(_) => { - // `Trait` - // ^^^^^ - let containing_path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; - let resolved = sema.resolve_path(&containing_path)?; - if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved { - if let Some(ty) = tr - .items_with_supertraits(sema.db) - .iter() - .filter_map(|&assoc| match assoc { - hir::AssocItem::TypeAlias(it) => Some(it), - _ => None, - }) - .find(|alias| alias.name(sema.db).to_smol_str() == name_ref.text().as_str()) - { - return Some(NameRefClass::Definition(Definition::TypeAlias(ty))); - } - } - None - }, - ast::ExternCrate(extern_crate) => { - let krate = sema.resolve_extern_crate(&extern_crate)?; - let root_module = krate.root_module(sema.db); - Some(NameRefClass::Definition(Definition::Module(root_module))) - }, - _ => None - } - } - } - - pub fn classify_lifetime( - sema: &Semantics<'_, RootDatabase>, - lifetime: &ast::Lifetime, - ) -> Option { - let _p = profile::span("classify_lifetime_ref").detail(|| lifetime.to_string()); - let parent = lifetime.syntax().parent()?; - match parent.kind() { - SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => { - sema.resolve_label(lifetime).map(Definition::Label).map(NameRefClass::Definition) - } - SyntaxKind::LIFETIME_ARG - | SyntaxKind::SELF_PARAM - | SyntaxKind::TYPE_BOUND - | SyntaxKind::WHERE_PRED - | SyntaxKind::REF_TYPE => sema - .resolve_lifetime_param(lifetime) - .map(GenericParam::LifetimeParam) - .map(Definition::GenericParam) - .map(NameRefClass::Definition), - // lifetime bounds, as in the 'b in 'a: 'b aren't wrapped in TypeBound nodes so we gotta check - // if our lifetime is in a LifetimeParam without being the constrained lifetime - _ if ast::LifetimeParam::cast(parent).and_then(|param| param.lifetime()).as_ref() - != Some(lifetime) => - { - sema.resolve_lifetime_param(lifetime) - .map(GenericParam::LifetimeParam) - .map(Definition::GenericParam) - .map(NameRefClass::Definition) - } - _ => None, - } - } -} - -impl_from!( - Field, Module, Function, Adt, Variant, Const, Static, Trait, TypeAlias, BuiltinType, Local, - GenericParam, Label, Macro - for Definition -); - -impl From for Definition { - fn from(impl_: Impl) -> Self { - Definition::SelfType(impl_) - } -} - -impl AsAssocItem for Definition { - fn as_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option { - match self { - Definition::Function(it) => it.as_assoc_item(db), - Definition::Const(it) => it.as_assoc_item(db), - Definition::TypeAlias(it) => it.as_assoc_item(db), - _ => None, - } - } -} - -impl From for Definition { - fn from(assoc_item: AssocItem) -> Self { - match assoc_item { - AssocItem::Function(it) => Definition::Function(it), - AssocItem::Const(it) => Definition::Const(it), - AssocItem::TypeAlias(it) => Definition::TypeAlias(it), - } - } -} - -impl From for Definition { - fn from(path_resolution: PathResolution) -> Self { - match path_resolution { - PathResolution::Def(def) => def.into(), - PathResolution::Local(local) => Definition::Local(local), - PathResolution::TypeParam(par) => Definition::GenericParam(par.into()), - PathResolution::ConstParam(par) => Definition::GenericParam(par.into()), - PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def), - PathResolution::BuiltinAttr(attr) => Definition::BuiltinAttr(attr), - PathResolution::ToolModule(tool) => Definition::ToolModule(tool), - PathResolution::DeriveHelper(helper) => Definition::DeriveHelper(helper), - } - } -} - -impl From for Definition { - fn from(def: ModuleDef) -> Self { - match def { - ModuleDef::Module(it) => Definition::Module(it), - ModuleDef::Function(it) => Definition::Function(it), - ModuleDef::Adt(it) => Definition::Adt(it), - ModuleDef::Variant(it) => Definition::Variant(it), - ModuleDef::Const(it) => Definition::Const(it), - ModuleDef::Static(it) => Definition::Static(it), - ModuleDef::Trait(it) => Definition::Trait(it), - ModuleDef::TypeAlias(it) => Definition::TypeAlias(it), - ModuleDef::Macro(it) => Definition::Macro(it), - ModuleDef::BuiltinType(it) => Definition::BuiltinType(it), - } - } -} - -impl From for Option { - fn from(def: Definition) -> Self { - let item = match def { - Definition::Module(it) => ModuleDef::Module(it), - Definition::Function(it) => ModuleDef::Function(it), - Definition::Adt(it) => ModuleDef::Adt(it), - Definition::Variant(it) => ModuleDef::Variant(it), - Definition::Const(it) => ModuleDef::Const(it), - Definition::Static(it) => ModuleDef::Static(it), - Definition::Trait(it) => ModuleDef::Trait(it), - Definition::TypeAlias(it) => ModuleDef::TypeAlias(it), - Definition::BuiltinType(it) => ModuleDef::BuiltinType(it), - _ => return None, - }; - Some(ItemInNs::from(item)) - } -} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs deleted file mode 100644 index c8341fed1c72c..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs +++ /dev/null @@ -1,185 +0,0 @@ -//! See [`FamousDefs`]. - -use base_db::{CrateOrigin, LangCrateOrigin, SourceDatabase}; -use hir::{Crate, Enum, Macro, Module, ScopeDef, Semantics, Trait}; - -use crate::RootDatabase; - -/// Helps with finding well-know things inside the standard library. This is -/// somewhat similar to the known paths infra inside hir, but it different; We -/// want to make sure that IDE specific paths don't become interesting inside -/// the compiler itself as well. -/// -/// Note that, by default, rust-analyzer tests **do not** include core or std -/// libraries. If you are writing tests for functionality using [`FamousDefs`], -/// you'd want to include minicore (see `test_utils::MiniCore`) declaration at -/// the start of your tests: -/// -/// ``` -/// //- minicore: iterator, ord, derive -/// ``` -pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Crate); - -#[allow(non_snake_case)] -impl FamousDefs<'_, '_> { - pub fn std(&self) -> Option { - self.find_lang_crate(LangCrateOrigin::Std) - } - - pub fn core(&self) -> Option { - self.find_lang_crate(LangCrateOrigin::Core) - } - - pub fn alloc(&self) -> Option { - self.find_lang_crate(LangCrateOrigin::Alloc) - } - - pub fn test(&self) -> Option { - self.find_lang_crate(LangCrateOrigin::Test) - } - - pub fn proc_macro(&self) -> Option { - self.find_lang_crate(LangCrateOrigin::ProcMacro) - } - - pub fn core_cmp_Ord(&self) -> Option { - self.find_trait("core:cmp:Ord") - } - - pub fn core_convert_From(&self) -> Option { - self.find_trait("core:convert:From") - } - - pub fn core_convert_Into(&self) -> Option { - self.find_trait("core:convert:Into") - } - - pub fn core_option_Option(&self) -> Option { - self.find_enum("core:option:Option") - } - - pub fn core_result_Result(&self) -> Option { - self.find_enum("core:result:Result") - } - - pub fn core_default_Default(&self) -> Option { - self.find_trait("core:default:Default") - } - - pub fn core_iter_Iterator(&self) -> Option { - self.find_trait("core:iter:traits:iterator:Iterator") - } - - pub fn core_iter_IntoIterator(&self) -> Option { - self.find_trait("core:iter:traits:collect:IntoIterator") - } - - pub fn core_iter(&self) -> Option { - self.find_module("core:iter") - } - - pub fn core_ops_Deref(&self) -> Option { - self.find_trait("core:ops:Deref") - } - - pub fn core_ops_DerefMut(&self) -> Option { - self.find_trait("core:ops:DerefMut") - } - - pub fn core_convert_AsRef(&self) -> Option { - self.find_trait("core:convert:AsRef") - } - - pub fn core_ops_ControlFlow(&self) -> Option { - self.find_enum("core:ops:ControlFlow") - } - - pub fn core_ops_Drop(&self) -> Option { - self.find_trait("core:ops:Drop") - } - - pub fn core_marker_Copy(&self) -> Option { - self.find_trait("core:marker:Copy") - } - - pub fn core_macros_builtin_derive(&self) -> Option { - self.find_macro("core:macros:builtin:derive") - } - - pub fn builtin_crates(&self) -> impl Iterator { - IntoIterator::into_iter([ - self.std(), - self.core(), - self.alloc(), - self.test(), - self.proc_macro(), - ]) - .flatten() - } - - fn find_trait(&self, path: &str) -> Option { - match self.find_def(path)? { - hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), - _ => None, - } - } - - fn find_macro(&self, path: &str) -> Option { - match self.find_def(path)? { - hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(it)) => Some(it), - _ => None, - } - } - - fn find_enum(&self, path: &str) -> Option { - match self.find_def(path)? { - hir::ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(it))) => Some(it), - _ => None, - } - } - - fn find_module(&self, path: &str) -> Option { - match self.find_def(path)? { - hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(it)) => Some(it), - _ => None, - } - } - - fn find_lang_crate(&self, origin: LangCrateOrigin) -> Option { - let krate = self.1; - let db = self.0.db; - let crate_graph = self.0.db.crate_graph(); - let res = krate - .dependencies(db) - .into_iter() - .find(|dep| crate_graph[dep.krate.into()].origin == CrateOrigin::Lang(origin))? - .krate; - Some(res) - } - - fn find_def(&self, path: &str) -> Option { - let db = self.0.db; - let mut path = path.split(':'); - let trait_ = path.next_back()?; - let lang_crate = path.next()?; - let lang_crate = match LangCrateOrigin::from(lang_crate) { - LangCrateOrigin::Other => return None, - lang_crate => lang_crate, - }; - let std_crate = self.find_lang_crate(lang_crate)?; - let mut module = std_crate.root_module(db); - for segment in path { - module = module.children(db).find_map(|child| { - let name = child.name(db)?; - if name.to_smol_str() == segment { - Some(child) - } else { - None - } - })?; - } - let def = - module.scope(db, None).into_iter().find(|(name, _def)| name.to_smol_str() == trait_)?.1; - Some(def) - } -} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs deleted file mode 100644 index 64dd2bb5f2d14..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ /dev/null @@ -1,7682 +0,0 @@ -//! Generated by `sourcegen_lints`, do not edit by hand. - -#[derive(Clone)] -pub struct Lint { - pub label: &'static str, - pub description: &'static str, -} -pub struct LintGroup { - pub lint: Lint, - pub children: &'static [&'static str], -} -pub const DEFAULT_LINTS: &[Lint] = &[ - Lint { - label: "absolute_paths_not_starting_with_crate", - description: r##"fully qualified paths that start with a module name instead of `crate`, `self`, or an extern crate name"##, - }, - Lint { label: "ambiguous_associated_items", description: r##"ambiguous associated items"## }, - Lint { label: "anonymous_parameters", description: r##"detects anonymous parameters"## }, - Lint { label: "arithmetic_overflow", description: r##"arithmetic operation overflows"## }, - Lint { - label: "array_into_iter", - description: r##"detects calling `into_iter` on arrays in Rust 2015 and 2018"##, - }, - Lint { - label: "asm_sub_register", - description: r##"using only a subset of a register for inline asm inputs"##, - }, - Lint { label: "bad_asm_style", description: r##"incorrect use of inline assembly"## }, - Lint { - label: "bare_trait_objects", - description: r##"suggest using `dyn Trait` for trait objects"##, - }, - Lint { - label: "bindings_with_variant_name", - description: r##"detects pattern bindings with the same name as one of the matched variants"##, - }, - Lint { label: "box_pointers", description: r##"use of owned (Box type) heap memory"## }, - Lint { - label: "break_with_label_and_loop", - description: r##"`break` expression with label and unlabeled loop as value expression"##, - }, - Lint { - label: "cenum_impl_drop_cast", - description: r##"a C-like enum implementing Drop is cast"##, - }, - Lint { - label: "clashing_extern_declarations", - description: r##"detects when an extern fn has been declared with the same name but different types"##, - }, - Lint { - label: "coherence_leak_check", - description: r##"distinct impls distinguished only by the leak-check code"##, - }, - Lint { - label: "conflicting_repr_hints", - description: r##"conflicts between `#[repr(..)]` hints that were previously accepted and used in practice"##, - }, - Lint { - label: "confusable_idents", - description: r##"detects visually confusable pairs between identifiers"##, - }, - Lint { - label: "const_err", - description: r##"constant evaluation encountered erroneous expression"##, - }, - Lint { - label: "const_evaluatable_unchecked", - description: r##"detects a generic constant is used in a type without a emitting a warning"##, - }, - Lint { - label: "const_item_mutation", - description: r##"detects attempts to mutate a `const` item"##, - }, - Lint { label: "dead_code", description: r##"detect unused, unexported items"## }, - Lint { label: "deprecated", description: r##"detects use of deprecated items"## }, - Lint { - label: "deprecated_in_future", - description: r##"detects use of items that will be deprecated in a future version"##, - }, - Lint { - label: "deref_into_dyn_supertrait", - description: r##"`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future"##, - }, - Lint { - label: "deref_nullptr", - description: r##"detects when an null pointer is dereferenced"##, - }, - Lint { - label: "drop_bounds", - description: r##"bounds of the form `T: Drop` are most likely incorrect"##, - }, - Lint { - label: "dyn_drop", - description: r##"trait objects of the form `dyn Drop` are useless"##, - }, - Lint { - label: "elided_lifetimes_in_paths", - description: r##"hidden lifetime parameters in types are deprecated"##, - }, - Lint { - label: "ellipsis_inclusive_range_patterns", - description: r##"`...` range patterns are deprecated"##, - }, - Lint { - label: "enum_intrinsics_non_enums", - description: r##"detects calls to `core::mem::discriminant` and `core::mem::variant_count` with non-enum types"##, - }, - Lint { - label: "explicit_outlives_requirements", - description: r##"outlives requirements can be inferred"##, - }, - Lint { - label: "exported_private_dependencies", - description: r##"public interface leaks type from a private dependency"##, - }, - Lint { label: "forbidden_lint_groups", description: r##"applying forbid to lint-groups"## }, - Lint { - label: "function_item_references", - description: r##"suggest casting to a function pointer when attempting to take references to function items"##, - }, - Lint { - label: "future_incompatible", - description: r##"lint group for: forbidden-lint-groups, illegal-floating-point-literal-pattern, private-in-public, pub-use-of-private-extern-crate, invalid-type-param-default, const-err, unaligned-references, patterns-in-fns-without-body, missing-fragment-specifier, late-bound-lifetime-arguments, order-dependent-trait-objects, coherence-leak-check, unstable-name-collisions, where-clauses-object-safety, proc-macro-derive-resolution-fallback, macro-expanded-macro-exports-accessed-by-absolute-paths, ill-formed-attribute-input, conflicting-repr-hints, ambiguous-associated-items, mutable-borrow-reservation-conflict, indirect-structural-match, pointer-structural-match, nontrivial-structural-match, soft-unstable, cenum-impl-drop-cast, const-evaluatable-unchecked, uninhabited-static, unsupported-naked-functions, invalid-doc-attributes, semicolon-in-expressions-from-macros, legacy-derive-helpers, proc-macro-back-compat, unsupported-calling-conventions, deref-into-dyn-supertrait"##, - }, - Lint { - label: "ill_formed_attribute_input", - description: r##"ill-formed attribute inputs that were previously accepted and used in practice"##, - }, - Lint { - label: "illegal_floating_point_literal_pattern", - description: r##"floating-point literals cannot be used in patterns"##, - }, - Lint { - label: "improper_ctypes", - description: r##"proper use of libc types in foreign modules"##, - }, - Lint { - label: "improper_ctypes_definitions", - description: r##"proper use of libc types in foreign item definitions"##, - }, - Lint { - label: "incomplete_features", - description: r##"incomplete features that may function improperly in some or all cases"##, - }, - Lint { label: "incomplete_include", description: r##"trailing content in included file"## }, - Lint { - label: "indirect_structural_match", - description: r##"constant used in pattern contains value of non-structural-match type in a field or a variant"##, - }, - Lint { - label: "ineffective_unstable_trait_impl", - description: r##"detects `#[unstable]` on stable trait implementations for stable types"##, - }, - Lint { - label: "inline_no_sanitize", - description: r##"detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`"##, - }, - Lint { - label: "invalid_atomic_ordering", - description: r##"usage of invalid atomic ordering in atomic operations and memory fences"##, - }, - Lint { - label: "invalid_doc_attributes", - description: r##"detects invalid `#[doc(...)]` attributes"##, - }, - Lint { - label: "invalid_type_param_default", - description: r##"type parameter default erroneously allowed in invalid location"##, - }, - Lint { - label: "invalid_value", - description: r##"an invalid value is being created (such as a null reference)"##, - }, - Lint { - label: "irrefutable_let_patterns", - description: r##"detects irrefutable patterns in `if let` and `while let` statements"##, - }, - Lint { - label: "keyword_idents", - description: r##"detects edition keywords being used as an identifier"##, - }, - Lint { label: "large_assignments", description: r##"detects large moves or copies"## }, - Lint { - label: "late_bound_lifetime_arguments", - description: r##"detects generic lifetime arguments in path segments with late bound lifetime parameters"##, - }, - Lint { - label: "legacy_derive_helpers", - description: r##"detects derive helper attributes that are used before they are introduced"##, - }, - Lint { - label: "macro_expanded_macro_exports_accessed_by_absolute_paths", - description: r##"macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths"##, - }, - Lint { - label: "macro_use_extern_crate", - description: r##"the `#[macro_use]` attribute is now deprecated in favor of using macros via the module system"##, - }, - Lint { - label: "meta_variable_misuse", - description: r##"possible meta-variable misuse at macro definition"##, - }, - Lint { label: "missing_abi", description: r##"No declared ABI for extern declaration"## }, - Lint { - label: "missing_copy_implementations", - description: r##"detects potentially-forgotten implementations of `Copy`"##, - }, - Lint { - label: "missing_debug_implementations", - description: r##"detects missing implementations of Debug"##, - }, - Lint { - label: "missing_docs", - description: r##"detects missing documentation for public members"##, - }, - Lint { - label: "missing_fragment_specifier", - description: r##"detects missing fragment specifiers in unused `macro_rules!` patterns"##, - }, - Lint { - label: "mixed_script_confusables", - description: r##"detects Unicode scripts whose mixed script confusables codepoints are solely used"##, - }, - Lint { - label: "must_not_suspend", - description: r##"use of a `#[must_not_suspend]` value across a yield point"##, - }, - Lint { - label: "mutable_borrow_reservation_conflict", - description: r##"reservation of a two-phased borrow conflicts with other shared borrows"##, - }, - Lint { - label: "mutable_transmutes", - description: r##"mutating transmuted &mut T from &T may cause undefined behavior"##, - }, - Lint { label: "named_asm_labels", description: r##"named labels in inline assembly"## }, - Lint { - label: "no_mangle_const_items", - description: r##"const items will not have their symbols exported"##, - }, - Lint { label: "no_mangle_generic_items", description: r##"generic items must be mangled"## }, - Lint { label: "non_ascii_idents", description: r##"detects non-ASCII identifiers"## }, - Lint { - label: "non_camel_case_types", - description: r##"types, variants, traits and type parameters should have camel case names"##, - }, - Lint { - label: "non_exhaustive_omitted_patterns", - description: r##"detect when patterns of types marked `non_exhaustive` are missed"##, - }, - Lint { - label: "non_fmt_panics", - description: r##"detect single-argument panic!() invocations in which the argument is not a format string"##, - }, - Lint { - label: "non_shorthand_field_patterns", - description: r##"using `Struct { x: x }` instead of `Struct { x }` in a pattern"##, - }, - Lint { - label: "non_snake_case", - description: r##"variables, methods, functions, lifetime parameters and modules should have snake case names"##, - }, - Lint { - label: "non_upper_case_globals", - description: r##"static constants should have uppercase identifiers"##, - }, - Lint { - label: "nonstandard_style", - description: r##"lint group for: non-camel-case-types, non-snake-case, non-upper-case-globals"##, - }, - Lint { - label: "nontrivial_structural_match", - description: r##"constant used in pattern of non-structural-match type and the constant's initializer expression contains values of non-structural-match types"##, - }, - Lint { - label: "noop_method_call", - description: r##"detects the use of well-known noop methods"##, - }, - Lint { - label: "order_dependent_trait_objects", - description: r##"trait-object types were treated as different depending on marker-trait order"##, - }, - Lint { label: "overflowing_literals", description: r##"literal out of range for its type"## }, - Lint { - label: "overlapping_range_endpoints", - description: r##"detects range patterns with overlapping endpoints"##, - }, - Lint { label: "path_statements", description: r##"path statements with no effect"## }, - Lint { - label: "patterns_in_fns_without_body", - description: r##"patterns in functions without body were erroneously allowed"##, - }, - Lint { - label: "pointer_structural_match", - description: r##"pointers are not structural-match"##, - }, - Lint { - label: "private_in_public", - description: r##"detect private items in public interfaces not caught by the old implementation"##, - }, - Lint { - label: "proc_macro_back_compat", - description: r##"detects usage of old versions of certain proc-macro crates"##, - }, - Lint { - label: "proc_macro_derive_resolution_fallback", - description: r##"detects proc macro derives using inaccessible names from parent modules"##, - }, - Lint { - label: "pub_use_of_private_extern_crate", - description: r##"detect public re-exports of private extern crates"##, - }, - Lint { - label: "redundant_semicolons", - description: r##"detects unnecessary trailing semicolons"##, - }, - Lint { - label: "renamed_and_removed_lints", - description: r##"lints that have been renamed or removed"##, - }, - Lint { - label: "rust_2018_compatibility", - description: r##"lint group for: keyword-idents, anonymous-parameters, tyvar-behind-raw-pointer, absolute-paths-not-starting-with-crate"##, - }, - Lint { - label: "rust_2018_idioms", - description: r##"lint group for: bare-trait-objects, unused-extern-crates, ellipsis-inclusive-range-patterns, elided-lifetimes-in-paths, explicit-outlives-requirements"##, - }, - Lint { - label: "rust_2021_compatibility", - description: r##"lint group for: ellipsis-inclusive-range-patterns, bare-trait-objects, rust-2021-incompatible-closure-captures, rust-2021-incompatible-or-patterns, rust-2021-prelude-collisions, rust-2021-prefixes-incompatible-syntax, array-into-iter, non-fmt-panics"##, - }, - Lint { - label: "rust_2021_incompatible_closure_captures", - description: r##"detects closures affected by Rust 2021 changes"##, - }, - Lint { - label: "rust_2021_incompatible_or_patterns", - description: r##"detects usage of old versions of or-patterns"##, - }, - Lint { - label: "rust_2021_prefixes_incompatible_syntax", - description: r##"identifiers that will be parsed as a prefix in Rust 2021"##, - }, - Lint { - label: "rust_2021_prelude_collisions", - description: r##"detects the usage of trait methods which are ambiguous with traits added to the prelude in future editions"##, - }, - Lint { - label: "semicolon_in_expressions_from_macros", - description: r##"trailing semicolon in macro body used as expression"##, - }, - Lint { - label: "single_use_lifetimes", - description: r##"detects lifetime parameters that are only used once"##, - }, - Lint { - label: "soft_unstable", - description: r##"a feature gate that doesn't break dependent crates"##, - }, - Lint { - label: "stable_features", - description: r##"stable features found in `#[feature]` directive"##, - }, - Lint { - label: "temporary_cstring_as_ptr", - description: r##"detects getting the inner pointer of a temporary `CString`"##, - }, - Lint { - label: "text_direction_codepoint_in_comment", - description: r##"invisible directionality-changing codepoints in comment"##, - }, - Lint { - label: "text_direction_codepoint_in_literal", - description: r##"detect special Unicode codepoints that affect the visual representation of text on screen, changing the direction in which text flows"##, - }, - Lint { - label: "trivial_bounds", - description: r##"these bounds don't depend on an type parameters"##, - }, - Lint { - label: "trivial_casts", - description: r##"detects trivial casts which could be removed"##, - }, - Lint { - label: "trivial_numeric_casts", - description: r##"detects trivial casts of numeric types which could be removed"##, - }, - Lint { - label: "type_alias_bounds", - description: r##"bounds in type aliases are not enforced"##, - }, - Lint { - label: "tyvar_behind_raw_pointer", - description: r##"raw pointer to an inference variable"##, - }, - Lint { - label: "unaligned_references", - description: r##"detects unaligned references to fields of packed structs"##, - }, - Lint { - label: "uncommon_codepoints", - description: r##"detects uncommon Unicode codepoints in identifiers"##, - }, - Lint { - label: "unconditional_panic", - description: r##"operation will cause a panic at runtime"##, - }, - Lint { - label: "unconditional_recursion", - description: r##"functions that cannot return without calling themselves"##, - }, - Lint { label: "uninhabited_static", description: r##"uninhabited static"## }, - Lint { - label: "unknown_crate_types", - description: r##"unknown crate type found in `#[crate_type]` directive"##, - }, - Lint { label: "unknown_lints", description: r##"unrecognized lint attribute"## }, - Lint { - label: "unnameable_test_items", - description: r##"detects an item that cannot be named being marked as `#[test_case]`"##, - }, - Lint { label: "unreachable_code", description: r##"detects unreachable code paths"## }, - Lint { label: "unreachable_patterns", description: r##"detects unreachable patterns"## }, - Lint { - label: "unreachable_pub", - description: r##"`pub` items not reachable from crate root"##, - }, - Lint { label: "unsafe_code", description: r##"usage of `unsafe` code"## }, - Lint { - label: "unsafe_op_in_unsafe_fn", - description: r##"unsafe operations in unsafe functions without an explicit unsafe block are deprecated"##, - }, - Lint { - label: "unstable_features", - description: r##"enabling unstable features (deprecated. do not use)"##, - }, - Lint { - label: "unstable_name_collisions", - description: r##"detects name collision with an existing but unstable method"##, - }, - Lint { - label: "unsupported_calling_conventions", - description: r##"use of unsupported calling convention"##, - }, - Lint { - label: "unsupported_naked_functions", - description: r##"unsupported naked function definitions"##, - }, - Lint { - label: "unused", - description: r##"lint group for: unused-imports, unused-variables, unused-assignments, dead-code, unused-mut, unreachable-code, unreachable-patterns, unused-must-use, unused-unsafe, path-statements, unused-attributes, unused-macros, unused-allocation, unused-doc-comments, unused-extern-crates, unused-features, unused-labels, unused-parens, unused-braces, redundant-semicolons"##, - }, - Lint { - label: "unused_allocation", - description: r##"detects unnecessary allocations that can be eliminated"##, - }, - Lint { - label: "unused_assignments", - description: r##"detect assignments that will never be read"##, - }, - Lint { - label: "unused_attributes", - description: r##"detects attributes that were not used by the compiler"##, - }, - Lint { label: "unused_braces", description: r##"unnecessary braces around an expression"## }, - Lint { - label: "unused_comparisons", - description: r##"comparisons made useless by limits of the types involved"##, - }, - Lint { - label: "unused_crate_dependencies", - description: r##"crate dependencies that are never used"##, - }, - Lint { - label: "unused_doc_comments", - description: r##"detects doc comments that aren't used by rustdoc"##, - }, - Lint { label: "unused_extern_crates", description: r##"extern crates that are never used"## }, - Lint { - label: "unused_features", - description: r##"unused features found in crate-level `#[feature]` directives"##, - }, - Lint { - label: "unused_import_braces", - description: r##"unnecessary braces around an imported item"##, - }, - Lint { label: "unused_imports", description: r##"imports that are never used"## }, - Lint { label: "unused_labels", description: r##"detects labels that are never used"## }, - Lint { - label: "unused_lifetimes", - description: r##"detects lifetime parameters that are never used"##, - }, - Lint { label: "unused_macros", description: r##"detects macros that were not used"## }, - Lint { - label: "unused_must_use", - description: r##"unused result of a type flagged as `#[must_use]`"##, - }, - Lint { - label: "unused_mut", - description: r##"detect mut variables which don't need to be mutable"##, - }, - Lint { - label: "unused_parens", - description: r##"`if`, `match`, `while` and `return` do not need parentheses"##, - }, - Lint { - label: "unused_qualifications", - description: r##"detects unnecessarily qualified names"##, - }, - Lint { - label: "unused_results", - description: r##"unused result of an expression in a statement"##, - }, - Lint { label: "unused_unsafe", description: r##"unnecessary use of an `unsafe` block"## }, - Lint { - label: "unused_variables", - description: r##"detect variables which are not used in any way"##, - }, - Lint { - label: "useless_deprecated", - description: r##"detects deprecation attributes with no effect"##, - }, - Lint { - label: "variant_size_differences", - description: r##"detects enums with widely varying variant sizes"##, - }, - Lint { - label: "warnings", - description: r##"mass-change the level for lints which produce warnings"##, - }, - Lint { - label: "warnings", - description: r##"lint group for: all lints that are set to issue warnings"##, - }, - Lint { - label: "where_clauses_object_safety", - description: r##"checks the object safety of where clauses"##, - }, - Lint { - label: "while_true", - description: r##"suggest using `loop { }` instead of `while true { }`"##, - }, -]; -pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ - LintGroup { - lint: Lint { - label: "future_incompatible", - description: r##"lint group for: forbidden-lint-groups, illegal-floating-point-literal-pattern, private-in-public, pub-use-of-private-extern-crate, invalid-type-param-default, const-err, unaligned-references, patterns-in-fns-without-body, missing-fragment-specifier, late-bound-lifetime-arguments, order-dependent-trait-objects, coherence-leak-check, unstable-name-collisions, where-clauses-object-safety, proc-macro-derive-resolution-fallback, macro-expanded-macro-exports-accessed-by-absolute-paths, ill-formed-attribute-input, conflicting-repr-hints, ambiguous-associated-items, mutable-borrow-reservation-conflict, indirect-structural-match, pointer-structural-match, nontrivial-structural-match, soft-unstable, cenum-impl-drop-cast, const-evaluatable-unchecked, uninhabited-static, unsupported-naked-functions, invalid-doc-attributes, semicolon-in-expressions-from-macros, legacy-derive-helpers, proc-macro-back-compat, unsupported-calling-conventions, deref-into-dyn-supertrait"##, - }, - children: &[ - "forbidden_lint_groups", - "illegal_floating_point_literal_pattern", - "private_in_public", - "pub_use_of_private_extern_crate", - "invalid_type_param_default", - "const_err", - "unaligned_references", - "patterns_in_fns_without_body", - "missing_fragment_specifier", - "late_bound_lifetime_arguments", - "order_dependent_trait_objects", - "coherence_leak_check", - "unstable_name_collisions", - "where_clauses_object_safety", - "proc_macro_derive_resolution_fallback", - "macro_expanded_macro_exports_accessed_by_absolute_paths", - "ill_formed_attribute_input", - "conflicting_repr_hints", - "ambiguous_associated_items", - "mutable_borrow_reservation_conflict", - "indirect_structural_match", - "pointer_structural_match", - "nontrivial_structural_match", - "soft_unstable", - "cenum_impl_drop_cast", - "const_evaluatable_unchecked", - "uninhabited_static", - "unsupported_naked_functions", - "invalid_doc_attributes", - "semicolon_in_expressions_from_macros", - "legacy_derive_helpers", - "proc_macro_back_compat", - "unsupported_calling_conventions", - "deref_into_dyn_supertrait", - ], - }, - LintGroup { - lint: Lint { - label: "nonstandard_style", - description: r##"lint group for: non-camel-case-types, non-snake-case, non-upper-case-globals"##, - }, - children: &["non_camel_case_types", "non_snake_case", "non_upper_case_globals"], - }, - LintGroup { - lint: Lint { - label: "rust_2018_compatibility", - description: r##"lint group for: keyword-idents, anonymous-parameters, tyvar-behind-raw-pointer, absolute-paths-not-starting-with-crate"##, - }, - children: &[ - "keyword_idents", - "anonymous_parameters", - "tyvar_behind_raw_pointer", - "absolute_paths_not_starting_with_crate", - ], - }, - LintGroup { - lint: Lint { - label: "rust_2018_idioms", - description: r##"lint group for: bare-trait-objects, unused-extern-crates, ellipsis-inclusive-range-patterns, elided-lifetimes-in-paths, explicit-outlives-requirements"##, - }, - children: &[ - "bare_trait_objects", - "unused_extern_crates", - "ellipsis_inclusive_range_patterns", - "elided_lifetimes_in_paths", - "explicit_outlives_requirements", - ], - }, - LintGroup { - lint: Lint { - label: "rust_2021_compatibility", - description: r##"lint group for: ellipsis-inclusive-range-patterns, bare-trait-objects, rust-2021-incompatible-closure-captures, rust-2021-incompatible-or-patterns, rust-2021-prelude-collisions, rust-2021-prefixes-incompatible-syntax, array-into-iter, non-fmt-panics"##, - }, - children: &[ - "ellipsis_inclusive_range_patterns", - "bare_trait_objects", - "rust_2021_incompatible_closure_captures", - "rust_2021_incompatible_or_patterns", - "rust_2021_prelude_collisions", - "rust_2021_prefixes_incompatible_syntax", - "array_into_iter", - "non_fmt_panics", - ], - }, - LintGroup { - lint: Lint { - label: "unused", - description: r##"lint group for: unused-imports, unused-variables, unused-assignments, dead-code, unused-mut, unreachable-code, unreachable-patterns, unused-must-use, unused-unsafe, path-statements, unused-attributes, unused-macros, unused-allocation, unused-doc-comments, unused-extern-crates, unused-features, unused-labels, unused-parens, unused-braces, redundant-semicolons"##, - }, - children: &[ - "unused_imports", - "unused_variables", - "unused_assignments", - "dead_code", - "unused_mut", - "unreachable_code", - "unreachable_patterns", - "unused_must_use", - "unused_unsafe", - "path_statements", - "unused_attributes", - "unused_macros", - "unused_allocation", - "unused_doc_comments", - "unused_extern_crates", - "unused_features", - "unused_labels", - "unused_parens", - "unused_braces", - "redundant_semicolons", - ], - }, - LintGroup { - lint: Lint { - label: "warnings", - description: r##"lint group for: all lints that are set to issue warnings"##, - }, - children: &[], - }, -]; - -pub const RUSTDOC_LINTS: &[Lint] = &[ - Lint { - label: "rustdoc::all", - description: r##"lint group for: rustdoc::broken-intra-doc-links, rustdoc::private-intra-doc-links, rustdoc::missing-doc-code-examples, rustdoc::private-doc-tests, rustdoc::invalid-codeblock-attributes, rustdoc::invalid-rust-codeblocks, rustdoc::invalid-html-tags, rustdoc::bare-urls, rustdoc::missing-crate-level-docs"##, - }, - Lint { label: "rustdoc::bare_urls", description: r##"detects URLs that are not hyperlinks"## }, - Lint { - label: "rustdoc::broken_intra_doc_links", - description: r##"failures in resolving intra-doc link targets"##, - }, - Lint { - label: "rustdoc::invalid_codeblock_attributes", - description: r##"codeblock attribute looks a lot like a known one"##, - }, - Lint { - label: "rustdoc::invalid_html_tags", - description: r##"detects invalid HTML tags in doc comments"##, - }, - Lint { - label: "rustdoc::invalid_rust_codeblocks", - description: r##"codeblock could not be parsed as valid Rust or is empty"##, - }, - Lint { - label: "rustdoc::missing_crate_level_docs", - description: r##"detects crates with no crate-level documentation"##, - }, - Lint { - label: "rustdoc::missing_doc_code_examples", - description: r##"detects publicly-exported items without code samples in their documentation"##, - }, - Lint { - label: "rustdoc::private_doc_tests", - description: r##"detects code samples in docs of private items not documented by rustdoc"##, - }, - Lint { - label: "rustdoc::private_intra_doc_links", - description: r##"linking from a public item to a private one"##, - }, -]; -pub const RUSTDOC_LINT_GROUPS: &[LintGroup] = &[LintGroup { - lint: Lint { - label: "rustdoc::all", - description: r##"lint group for: rustdoc::broken-intra-doc-links, rustdoc::private-intra-doc-links, rustdoc::missing-doc-code-examples, rustdoc::private-doc-tests, rustdoc::invalid-codeblock-attributes, rustdoc::invalid-rust-codeblocks, rustdoc::invalid-html-tags, rustdoc::bare-urls, rustdoc::missing-crate-level-docs"##, - }, - children: &[ - "rustdoc::broken_intra_doc_links", - "rustdoc::private_intra_doc_links", - "rustdoc::missing_doc_code_examples", - "rustdoc::private_doc_tests", - "rustdoc::invalid_codeblock_attributes", - "rustdoc::invalid_rust_codeblocks", - "rustdoc::invalid_html_tags", - "rustdoc::bare_urls", - "rustdoc::missing_crate_level_docs", - ], -}]; - -pub const FEATURES: &[Lint] = &[ - Lint { - label: "abi_c_cmse_nonsecure_call", - description: r##"# `abi_c_cmse_nonsecure_call` - -The tracking issue for this feature is: [#81391] - -[#81391]: https://github.com/rust-lang/rust/issues/81391 - ------------------------- - -The [TrustZone-M -feature](https://developer.arm.com/documentation/100690/latest/) is available -for targets with the Armv8-M architecture profile (`thumbv8m` in their target -name). -LLVM, the Rust compiler and the linker are providing -[support](https://developer.arm.com/documentation/ecm0359818/latest/) for the -TrustZone-M feature. - -One of the things provided, with this unstable feature, is the -`C-cmse-nonsecure-call` function ABI. This ABI is used on function pointers to -non-secure code to mark a non-secure function call (see [section -5.5](https://developer.arm.com/documentation/ecm0359818/latest/) for details). - -With this ABI, the compiler will do the following to perform the call: -* save registers needed after the call to Secure memory -* clear all registers that might contain confidential information -* clear the Least Significant Bit of the function address -* branches using the BLXNS instruction - -To avoid using the non-secure stack, the compiler will constrain the number and -type of parameters/return value. - -The `extern "C-cmse-nonsecure-call"` ABI is otherwise equivalent to the -`extern "C"` ABI. - - - -``` rust,ignore -#![no_std] -#![feature(abi_c_cmse_nonsecure_call)] - -#[no_mangle] -pub fn call_nonsecure_function(addr: usize) -> u32 { - let non_secure_function = - unsafe { core::mem::transmute:: u32>(addr) }; - non_secure_function() -} -``` - -``` text -$ rustc --emit asm --crate-type lib --target thumbv8m.main-none-eabi function.rs - -call_nonsecure_function: - .fnstart - .save {r7, lr} - push {r7, lr} - .setfp r7, sp - mov r7, sp - .pad #16 - sub sp, #16 - str r0, [sp, #12] - ldr r0, [sp, #12] - str r0, [sp, #8] - b .LBB0_1 -.LBB0_1: - ldr r0, [sp, #8] - push.w {r4, r5, r6, r7, r8, r9, r10, r11} - bic r0, r0, #1 - mov r1, r0 - mov r2, r0 - mov r3, r0 - mov r4, r0 - mov r5, r0 - mov r6, r0 - mov r7, r0 - mov r8, r0 - mov r9, r0 - mov r10, r0 - mov r11, r0 - mov r12, r0 - msr apsr_nzcvq, r0 - blxns r0 - pop.w {r4, r5, r6, r7, r8, r9, r10, r11} - str r0, [sp, #4] - b .LBB0_2 -.LBB0_2: - ldr r0, [sp, #4] - add sp, #16 - pop {r7, pc} -``` -"##, - }, - Lint { - label: "abi_msp430_interrupt", - description: r##"# `abi_msp430_interrupt` - -The tracking issue for this feature is: [#38487] - -[#38487]: https://github.com/rust-lang/rust/issues/38487 - ------------------------- - -In the MSP430 architecture, interrupt handlers have a special calling -convention. You can use the `"msp430-interrupt"` ABI to make the compiler apply -the right calling convention to the interrupt handlers you define. - - - -``` rust,ignore -#![feature(abi_msp430_interrupt)] -#![no_std] - -// Place the interrupt handler at the appropriate memory address -// (Alternatively, you can use `#[used]` and remove `pub` and `#[no_mangle]`) -#[link_section = "__interrupt_vector_10"] -#[no_mangle] -pub static TIM0_VECTOR: extern "msp430-interrupt" fn() = tim0; - -// The interrupt handler -extern "msp430-interrupt" fn tim0() { - // .. -} -``` - -``` text -$ msp430-elf-objdump -CD ./target/msp430/release/app -Disassembly of section __interrupt_vector_10: - -0000fff2 : - fff2: 00 c0 interrupt service routine at 0xc000 - -Disassembly of section .text: - -0000c000 : - c000: 00 13 reti -``` -"##, - }, - Lint { - label: "abi_ptx", - description: r##"# `abi_ptx` - -The tracking issue for this feature is: [#38788] - -[#38788]: https://github.com/rust-lang/rust/issues/38788 - ------------------------- - -When emitting PTX code, all vanilla Rust functions (`fn`) get translated to -"device" functions. These functions are *not* callable from the host via the -CUDA API so a crate with only device functions is not too useful! - -OTOH, "global" functions *can* be called by the host; you can think of them -as the real public API of your crate. To produce a global function use the -`"ptx-kernel"` ABI. - - - -``` rust,ignore -#![feature(abi_ptx)] -#![no_std] - -pub unsafe extern "ptx-kernel" fn global_function() { - device_function(); -} - -pub fn device_function() { - // .. -} -``` - -``` text -$ xargo rustc --target nvptx64-nvidia-cuda --release -- --emit=asm - -$ cat $(find -name '*.s') -// -// Generated by LLVM NVPTX Back-End -// - -.version 3.2 -.target sm_20 -.address_size 64 - - // .globl _ZN6kernel15global_function17h46111ebe6516b382E - -.visible .entry _ZN6kernel15global_function17h46111ebe6516b382E() -{ - - - ret; -} - - // .globl _ZN6kernel15device_function17hd6a0e4993bbf3f78E -.visible .func _ZN6kernel15device_function17hd6a0e4993bbf3f78E() -{ - - - ret; -} -``` -"##, - }, - Lint { - label: "abi_thiscall", - description: r##"# `abi_thiscall` - -The tracking issue for this feature is: [#42202] - -[#42202]: https://github.com/rust-lang/rust/issues/42202 - ------------------------- - -The MSVC ABI on x86 Windows uses the `thiscall` calling convention for C++ -instance methods by default; it is identical to the usual (C) calling -convention on x86 Windows except that the first parameter of the method, -the `this` pointer, is passed in the ECX register. -"##, - }, - Lint { - label: "allocator_api", - description: r##"# `allocator_api` - -The tracking issue for this feature is [#32838] - -[#32838]: https://github.com/rust-lang/rust/issues/32838 - ------------------------- - -Sometimes you want the memory for one collection to use a different -allocator than the memory for another collection. In this case, -replacing the global allocator is not a workable option. Instead, -you need to pass in an instance of an `AllocRef` to each collection -for which you want a custom allocator. - -TBD -"##, - }, - Lint { - label: "allocator_internals", - description: r##"# `allocator_internals` - -This feature does not have a tracking issue, it is an unstable implementation -detail of the `global_allocator` feature not intended for use outside the -compiler. - ------------------------- -"##, - }, - Lint { - label: "arbitrary_enum_discriminant", - description: r##"# `arbitrary_enum_discriminant` - -The tracking issue for this feature is: [#60553] - -[#60553]: https://github.com/rust-lang/rust/issues/60553 - ------------------------- - -The `arbitrary_enum_discriminant` feature permits tuple-like and -struct-like enum variants with `#[repr()]` to have explicit discriminants. - -## Examples - -```rust -#![feature(arbitrary_enum_discriminant)] - -#[allow(dead_code)] -#[repr(u8)] -enum Enum { - Unit = 3, - Tuple(u16) = 2, - Struct { - a: u8, - b: u16, - } = 1, -} - -impl Enum { - fn tag(&self) -> u8 { - unsafe { *(self as *const Self as *const u8) } - } -} - -assert_eq!(3, Enum::Unit.tag()); -assert_eq!(2, Enum::Tuple(5).tag()); -assert_eq!(1, Enum::Struct{a: 7, b: 11}.tag()); -``` -"##, - }, - Lint { - label: "asm_const", - description: r##"# `asm_const` - -The tracking issue for this feature is: [#72016] - -[#72016]: https://github.com/rust-lang/rust/issues/72016 - ------------------------- - -This feature adds a `const ` operand type to `asm!` and `global_asm!`. -- `` must be an integer constant expression. -- The value of the expression is formatted as a string and substituted directly into the asm template string. -"##, - }, - Lint { - label: "asm_experimental_arch", - description: r##"# `asm_experimental_arch` - -The tracking issue for this feature is: [#72016] - -[#72016]: https://github.com/rust-lang/rust/issues/72016 - ------------------------- - -This feature tracks `asm!` and `global_asm!` support for the following architectures: -- NVPTX -- PowerPC -- Hexagon -- MIPS32r2 and MIPS64r2 -- wasm32 -- BPF -- SPIR-V -- AVR - -## Register classes - -| Architecture | Register class | Registers | LLVM constraint code | -| ------------ | -------------- | ---------------------------------- | -------------------- | -| MIPS | `reg` | `$[2-25]` | `r` | -| MIPS | `freg` | `$f[0-31]` | `f` | -| NVPTX | `reg16` | None\* | `h` | -| NVPTX | `reg32` | None\* | `r` | -| NVPTX | `reg64` | None\* | `l` | -| Hexagon | `reg` | `r[0-28]` | `r` | -| PowerPC | `reg` | `r[0-31]` | `r` | -| PowerPC | `reg_nonzero` | `r[1-31]` | `b` | -| PowerPC | `freg` | `f[0-31]` | `f` | -| PowerPC | `cr` | `cr[0-7]`, `cr` | Only clobbers | -| PowerPC | `xer` | `xer` | Only clobbers | -| wasm32 | `local` | None\* | `r` | -| BPF | `reg` | `r[0-10]` | `r` | -| BPF | `wreg` | `w[0-10]` | `w` | -| AVR | `reg` | `r[2-25]`, `XH`, `XL`, `ZH`, `ZL` | `r` | -| AVR | `reg_upper` | `r[16-25]`, `XH`, `XL`, `ZH`, `ZL` | `d` | -| AVR | `reg_pair` | `r3r2` .. `r25r24`, `X`, `Z` | `r` | -| AVR | `reg_iw` | `r25r24`, `X`, `Z` | `w` | -| AVR | `reg_ptr` | `X`, `Z` | `e` | - -> **Notes**: -> - NVPTX doesn't have a fixed register set, so named registers are not supported. -> -> - WebAssembly doesn't have registers, so named registers are not supported. - -# Register class supported types - -| Architecture | Register class | Target feature | Allowed types | -| ------------ | ------------------------------- | -------------- | --------------------------------------- | -| MIPS32 | `reg` | None | `i8`, `i16`, `i32`, `f32` | -| MIPS32 | `freg` | None | `f32`, `f64` | -| MIPS64 | `reg` | None | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` | -| MIPS64 | `freg` | None | `f32`, `f64` | -| NVPTX | `reg16` | None | `i8`, `i16` | -| NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` | -| NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | -| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` | -| PowerPC | `reg` | None | `i8`, `i16`, `i32` | -| PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` | -| PowerPC | `freg` | None | `f32`, `f64` | -| PowerPC | `cr` | N/A | Only clobbers | -| PowerPC | `xer` | N/A | Only clobbers | -| wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` | -| BPF | `reg` | None | `i8` `i16` `i32` `i64` | -| BPF | `wreg` | `alu32` | `i8` `i16` `i32` | -| AVR | `reg`, `reg_upper` | None | `i8` | -| AVR | `reg_pair`, `reg_iw`, `reg_ptr` | None | `i16` | - -## Register aliases - -| Architecture | Base register | Aliases | -| ------------ | ------------- | --------- | -| Hexagon | `r29` | `sp` | -| Hexagon | `r30` | `fr` | -| Hexagon | `r31` | `lr` | -| BPF | `r[0-10]` | `w[0-10]` | -| AVR | `XH` | `r27` | -| AVR | `XL` | `r26` | -| AVR | `ZH` | `r31` | -| AVR | `ZL` | `r30` | - -## Unsupported registers - -| Architecture | Unsupported register | Reason | -| ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR) | The frame pointer cannot be used as an input or output. | -| All | `r19` (Hexagon) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | -| MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | -| MIPS | `$1` or `$at` | Reserved for assembler. | -| MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. | -| MIPS | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. | -| MIPS | `$ra` | Return address cannot be used as inputs or outputs. | -| Hexagon | `lr` | This is the link register which cannot be used as an input or output. | -| AVR | `r0`, `r1`, `r1r0` | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs. If modified, they must be restored to their original values before the end of the block. | - -## Template modifiers - -| Architecture | Register class | Modifier | Example output | LLVM modifier | -| ------------ | -------------- | -------- | -------------- | ------------- | -| MIPS | `reg` | None | `$2` | None | -| MIPS | `freg` | None | `$f0` | None | -| NVPTX | `reg16` | None | `rs0` | None | -| NVPTX | `reg32` | None | `r0` | None | -| NVPTX | `reg64` | None | `rd0` | None | -| Hexagon | `reg` | None | `r0` | None | -| PowerPC | `reg` | None | `0` | None | -| PowerPC | `reg_nonzero` | None | `3` | `b` | -| PowerPC | `freg` | None | `0` | None | - -# Flags covered by `preserves_flags` - -These flags registers must be restored upon exiting the asm block if the `preserves_flags` option is set: -- AVR - - The status register `SREG`. -"##, - }, - Lint { - label: "asm_sym", - description: r##"# `asm_sym` - -The tracking issue for this feature is: [#72016] - -[#72016]: https://github.com/rust-lang/rust/issues/72016 - ------------------------- - -This feature adds a `sym ` operand type to `asm!` and `global_asm!`. -- `` must refer to a `fn` or `static`. -- A mangled symbol name referring to the item is substituted into the asm template string. -- The substituted string does not include any modifiers (e.g. GOT, PLT, relocations, etc). -- `` is allowed to point to a `#[thread_local]` static, in which case the asm code can combine the symbol with relocations (e.g. `@plt`, `@TPOFF`) to read from thread-local data. -"##, - }, - Lint { - label: "asm_unwind", - description: r##"# `asm_unwind` - -The tracking issue for this feature is: [#72016] - -[#72016]: https://github.com/rust-lang/rust/issues/72016 - ------------------------- - -This feature adds a `may_unwind` option to `asm!` which allows an `asm` block to unwind stack and be part of the stack unwinding process. This option is only supported by the LLVM backend right now. -"##, - }, - Lint { - label: "auto_traits", - description: r##"# `auto_traits` - -The tracking issue for this feature is [#13231] - -[#13231]: https://github.com/rust-lang/rust/issues/13231 - ----- - -The `auto_traits` feature gate allows you to define auto traits. - -Auto traits, like [`Send`] or [`Sync`] in the standard library, are marker traits -that are automatically implemented for every type, unless the type, or a type it contains, -has explicitly opted out via a negative impl. (Negative impls are separately controlled -by the `negative_impls` feature.) - -[`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html -[`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html - -```rust,ignore (partial-example) -impl !Trait for Type {} -``` - -Example: - -```rust -#![feature(negative_impls)] -#![feature(auto_traits)] - -auto trait Valid {} - -struct True; -struct False; - -impl !Valid for False {} - -struct MaybeValid(T); - -fn must_be_valid(_t: T) { } - -fn main() { - // works - must_be_valid( MaybeValid(True) ); - - // compiler error - trait bound not satisfied - // must_be_valid( MaybeValid(False) ); -} -``` - -## Automatic trait implementations - -When a type is declared as an `auto trait`, we will automatically -create impls for every struct/enum/union, unless an explicit impl is -provided. These automatic impls contain a where clause for each field -of the form `T: AutoTrait`, where `T` is the type of the field and -`AutoTrait` is the auto trait in question. As an example, consider the -struct `List` and the auto trait `Send`: - -```rust -struct List { - data: T, - next: Option>>, -} -``` - -Presuming that there is no explicit impl of `Send` for `List`, the -compiler will supply an automatic impl of the form: - -```rust -struct List { - data: T, - next: Option>>, -} - -unsafe impl Send for List -where - T: Send, // from the field `data` - Option>>: Send, // from the field `next` -{ } -``` - -Explicit impls may be either positive or negative. They take the form: - -```rust,ignore (partial-example) -impl<...> AutoTrait for StructName<..> { } -impl<...> !AutoTrait for StructName<..> { } -``` - -## Coinduction: Auto traits permit cyclic matching - -Unlike ordinary trait matching, auto traits are **coinductive**. This -means, in short, that cycles which occur in trait matching are -considered ok. As an example, consider the recursive struct `List` -introduced in the previous section. In attempting to determine whether -`List: Send`, we would wind up in a cycle: to apply the impl, we must -show that `Option>: Send`, which will in turn require -`Box: Send` and then finally `List: Send` again. Under ordinary -trait matching, this cycle would be an error, but for an auto trait it -is considered a successful match. - -## Items - -Auto traits cannot have any trait items, such as methods or associated types. This ensures that we can generate default implementations. - -## Supertraits - -Auto traits cannot have supertraits. This is for soundness reasons, as the interaction of coinduction with implied bounds is difficult to reconcile. -"##, - }, - Lint { - label: "box_patterns", - description: r##"# `box_patterns` - -The tracking issue for this feature is: [#29641] - -[#29641]: https://github.com/rust-lang/rust/issues/29641 - -See also [`box_syntax`](box-syntax.md) - ------------------------- - -Box patterns let you match on `Box`s: - - -```rust -#![feature(box_patterns)] - -fn main() { - let b = Some(Box::new(5)); - match b { - Some(box n) if n < 0 => { - println!("Box contains negative number {}", n); - }, - Some(box n) if n >= 0 => { - println!("Box contains non-negative number {}", n); - }, - None => { - println!("No box"); - }, - _ => unreachable!() - } -} -``` -"##, - }, - Lint { - label: "box_syntax", - description: r##"# `box_syntax` - -The tracking issue for this feature is: [#49733] - -[#49733]: https://github.com/rust-lang/rust/issues/49733 - -See also [`box_patterns`](box-patterns.md) - ------------------------- - -Currently the only stable way to create a `Box` is via the `Box::new` method. -Also it is not possible in stable Rust to destructure a `Box` in a match -pattern. The unstable `box` keyword can be used to create a `Box`. An example -usage would be: - -```rust -#![feature(box_syntax)] - -fn main() { - let b = box 5; -} -``` -"##, - }, - Lint { - label: "c_unwind", - description: r##"# `c_unwind` - -The tracking issue for this feature is: [#74990] - -[#74990]: https://github.com/rust-lang/rust/issues/74990 - ------------------------- - -Introduces four new ABI strings: "C-unwind", "stdcall-unwind", -"thiscall-unwind", and "system-unwind". These enable unwinding from other -languages (such as C++) into Rust frames and from Rust into other languages. - -See [RFC 2945] for more information. - -[RFC 2945]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md -"##, - }, - Lint { - label: "c_variadic", - description: r##"# `c_variadic` - -The tracking issue for this feature is: [#44930] - -[#44930]: https://github.com/rust-lang/rust/issues/44930 - ------------------------- - -The `c_variadic` language feature enables C-variadic functions to be -defined in Rust. The may be called both from within Rust and via FFI. - -## Examples - -```rust -#![feature(c_variadic)] - -pub unsafe extern "C" fn add(n: usize, mut args: ...) -> usize { - let mut sum = 0; - for _ in 0..n { - sum += args.arg::(); - } - sum -} -``` -"##, - }, - Lint { - label: "c_variadic", - description: r##"# `c_variadic` - -The tracking issue for this feature is: [#44930] - -[#44930]: https://github.com/rust-lang/rust/issues/44930 - ------------------------- - -The `c_variadic` library feature exposes the `VaList` structure, -Rust's analogue of C's `va_list` type. - -## Examples - -```rust -#![feature(c_variadic)] - -use std::ffi::VaList; - -pub unsafe extern "C" fn vadd(n: usize, mut args: VaList) -> usize { - let mut sum = 0; - for _ in 0..n { - sum += args.arg::(); - } - sum -} -``` -"##, - }, - Lint { - label: "c_void_variant", - description: r##"# `c_void_variant` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "cfg_panic", - description: r##"# `cfg_panic` - -The tracking issue for this feature is: [#77443] - -[#77443]: https://github.com/rust-lang/rust/issues/77443 - ------------------------- - -The `cfg_panic` feature makes it possible to execute different code -depending on the panic strategy. - -Possible values at the moment are `"unwind"` or `"abort"`, although -it is possible that new panic strategies may be added to Rust in the -future. - -## Examples - -```rust -#![feature(cfg_panic)] - -#[cfg(panic = "unwind")] -fn a() { - // ... -} - -#[cfg(not(panic = "unwind"))] -fn a() { - // ... -} - -fn b() { - if cfg!(panic = "abort") { - // ... - } else { - // ... - } -} -``` -"##, - }, - Lint { - label: "cfg_sanitize", - description: r##"# `cfg_sanitize` - -The tracking issue for this feature is: [#39699] - -[#39699]: https://github.com/rust-lang/rust/issues/39699 - ------------------------- - -The `cfg_sanitize` feature makes it possible to execute different code -depending on whether a particular sanitizer is enabled or not. - -## Examples - -```rust -#![feature(cfg_sanitize)] - -#[cfg(sanitize = "thread")] -fn a() { - // ... -} - -#[cfg(not(sanitize = "thread"))] -fn a() { - // ... -} - -fn b() { - if cfg!(sanitize = "leak") { - // ... - } else { - // ... - } -} -``` -"##, - }, - Lint { - label: "cfg_version", - description: r##"# `cfg_version` - -The tracking issue for this feature is: [#64796] - -[#64796]: https://github.com/rust-lang/rust/issues/64796 - ------------------------- - -The `cfg_version` feature makes it possible to execute different code -depending on the compiler version. It will return true if the compiler -version is greater than or equal to the specified version. - -## Examples - -```rust -#![feature(cfg_version)] - -#[cfg(version("1.42"))] // 1.42 and above -fn a() { - // ... -} - -#[cfg(not(version("1.42")))] // 1.41 and below -fn a() { - // ... -} - -fn b() { - if cfg!(version("1.42")) { - // ... - } else { - // ... - } -} -``` -"##, - }, - Lint { - label: "char_error_internals", - description: r##"# `char_error_internals` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "closure_track_caller", - description: r##"# `closure_track_caller` - -The tracking issue for this feature is: [#87417] - -[#87417]: https://github.com/rust-lang/rust/issues/87417 - ------------------------- - -Allows using the `#[track_caller]` attribute on closures and generators. -Calls made to the closure or generator will have caller information -available through `std::panic::Location::caller()`, just like using -`#[track_caller]` on a function. -"##, - }, - Lint { - label: "cmse_nonsecure_entry", - description: r##"# `cmse_nonsecure_entry` - -The tracking issue for this feature is: [#75835] - -[#75835]: https://github.com/rust-lang/rust/issues/75835 - ------------------------- - -The [TrustZone-M -feature](https://developer.arm.com/documentation/100690/latest/) is available -for targets with the Armv8-M architecture profile (`thumbv8m` in their target -name). -LLVM, the Rust compiler and the linker are providing -[support](https://developer.arm.com/documentation/ecm0359818/latest/) for the -TrustZone-M feature. - -One of the things provided, with this unstable feature, is the -`cmse_nonsecure_entry` attribute. This attribute marks a Secure function as an -entry function (see [section -5.4](https://developer.arm.com/documentation/ecm0359818/latest/) for details). -With this attribute, the compiler will do the following: -* add a special symbol on the function which is the `__acle_se_` prefix and the - standard function name -* constrain the number of parameters to avoid using the Non-Secure stack -* before returning from the function, clear registers that might contain Secure - information -* use the `BXNS` instruction to return - -Because the stack can not be used to pass parameters, there will be compilation -errors if: -* the total size of all parameters is too big (for example more than four 32 - bits integers) -* the entry function is not using a C ABI - -The special symbol `__acle_se_` will be used by the linker to generate a secure -gateway veneer. - - - -``` rust,ignore -#![feature(cmse_nonsecure_entry)] - -#[no_mangle] -#[cmse_nonsecure_entry] -pub extern "C" fn entry_function(input: u32) -> u32 { - input + 6 -} -``` - -``` text -$ rustc --emit obj --crate-type lib --target thumbv8m.main-none-eabi function.rs -$ arm-none-eabi-objdump -D function.o - -00000000 : - 0: b580 push {r7, lr} - 2: 466f mov r7, sp - 4: b082 sub sp, #8 - 6: 9001 str r0, [sp, #4] - 8: 1d81 adds r1, r0, #6 - a: 460a mov r2, r1 - c: 4281 cmp r1, r0 - e: 9200 str r2, [sp, #0] - 10: d30b bcc.n 2a - 12: e7ff b.n 14 - 14: 9800 ldr r0, [sp, #0] - 16: b002 add sp, #8 - 18: e8bd 4080 ldmia.w sp!, {r7, lr} - 1c: 4671 mov r1, lr - 1e: 4672 mov r2, lr - 20: 4673 mov r3, lr - 22: 46f4 mov ip, lr - 24: f38e 8800 msr CPSR_f, lr - 28: 4774 bxns lr - 2a: f240 0000 movw r0, #0 - 2e: f2c0 0000 movt r0, #0 - 32: f240 0200 movw r2, #0 - 36: f2c0 0200 movt r2, #0 - 3a: 211c movs r1, #28 - 3c: f7ff fffe bl 0 <_ZN4core9panicking5panic17h5c028258ca2fb3f5E> - 40: defe udf #254 ; 0xfe -``` -"##, - }, - Lint { - label: "compiler_builtins", - description: r##"# `compiler_builtins` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "concat_idents", - description: r##"# `concat_idents` - -The tracking issue for this feature is: [#29599] - -[#29599]: https://github.com/rust-lang/rust/issues/29599 - ------------------------- - -The `concat_idents` feature adds a macro for concatenating multiple identifiers -into one identifier. - -## Examples - -```rust -#![feature(concat_idents)] - -fn main() { - fn foobar() -> u32 { 23 } - let f = concat_idents!(foo, bar); - assert_eq!(f(), 23); -} -``` -"##, - }, - Lint { - label: "const_eval_limit", - description: r##"# `const_eval_limit` - -The tracking issue for this feature is: [#67217] - -[#67217]: https://github.com/rust-lang/rust/issues/67217 - -The `const_eval_limit` allows someone to limit the evaluation steps the CTFE undertakes to evaluate a `const fn`. -"##, - }, - Lint { - label: "core_intrinsics", - description: r##"# `core_intrinsics` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "core_panic", - description: r##"# `core_panic` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "core_private_bignum", - description: r##"# `core_private_bignum` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "core_private_diy_float", - description: r##"# `core_private_diy_float` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "crate_visibility_modifier", - description: r##"# `crate_visibility_modifier` - -The tracking issue for this feature is: [#53120] - -[#53120]: https://github.com/rust-lang/rust/issues/53120 - ------ - -The `crate_visibility_modifier` feature allows the `crate` keyword to be used -as a visibility modifier synonymous to `pub(crate)`, indicating that a type -(function, _&c._) is to be visible to the entire enclosing crate, but not to -other crates. - -```rust -#![feature(crate_visibility_modifier)] - -crate struct Foo { - bar: usize, -} -``` -"##, - }, - Lint { - label: "custom_test_frameworks", - description: r##"# `custom_test_frameworks` - -The tracking issue for this feature is: [#50297] - -[#50297]: https://github.com/rust-lang/rust/issues/50297 - ------------------------- - -The `custom_test_frameworks` feature allows the use of `#[test_case]` and `#![test_runner]`. -Any function, const, or static can be annotated with `#[test_case]` causing it to be aggregated (like `#[test]`) -and be passed to the test runner determined by the `#![test_runner]` crate attribute. - -```rust -#![feature(custom_test_frameworks)] -#![test_runner(my_runner)] - -fn my_runner(tests: &[&i32]) { - for t in tests { - if **t == 0 { - println!("PASSED"); - } else { - println!("FAILED"); - } - } -} - -#[test_case] -const WILL_PASS: i32 = 0; - -#[test_case] -const WILL_FAIL: i32 = 4; -``` -"##, - }, - Lint { - label: "dec2flt", - description: r##"# `dec2flt` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "default_free_fn", - description: r##"# `default_free_fn` - -The tracking issue for this feature is: [#73014] - -[#73014]: https://github.com/rust-lang/rust/issues/73014 - ------------------------- - -Adds a free `default()` function to the `std::default` module. This function -just forwards to [`Default::default()`], but may remove repetition of the word -"default" from the call site. - -[`Default::default()`]: https://doc.rust-lang.org/nightly/std/default/trait.Default.html#tymethod.default - -Here is an example: - -```rust -#![feature(default_free_fn)] -use std::default::default; - -#[derive(Default)] -struct AppConfig { - foo: FooConfig, - bar: BarConfig, -} - -#[derive(Default)] -struct FooConfig { - foo: i32, -} - -#[derive(Default)] -struct BarConfig { - bar: f32, - baz: u8, -} - -fn main() { - let options = AppConfig { - foo: default(), - bar: BarConfig { - bar: 10.1, - ..default() - }, - }; -} -``` -"##, - }, - Lint { - label: "derive_clone_copy", - description: r##"# `derive_clone_copy` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "derive_eq", - description: r##"# `derive_eq` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "doc_cfg", - description: r##"# `doc_cfg` - -The tracking issue for this feature is: [#43781] - ------- - -The `doc_cfg` feature allows an API be documented as only available in some specific platforms. -This attribute has two effects: - -1. In the annotated item's documentation, there will be a message saying "This is supported on - (platform) only". - -2. The item's doc-tests will only run on the specific platform. - -In addition to allowing the use of the `#[doc(cfg)]` attribute, this feature enables the use of a -special conditional compilation flag, `#[cfg(doc)]`, set whenever building documentation on your -crate. - -This feature was introduced as part of PR [#43348] to allow the platform-specific parts of the -standard library be documented. - -```rust -#![feature(doc_cfg)] - -#[cfg(any(windows, doc))] -#[doc(cfg(windows))] -/// The application's icon in the notification area (a.k.a. system tray). -/// -/// # Examples -/// -/// ```no_run -/// extern crate my_awesome_ui_library; -/// use my_awesome_ui_library::current_app; -/// use my_awesome_ui_library::windows::notification; -/// -/// let icon = current_app().get::(); -/// icon.show(); -/// icon.show_message("Hello"); -/// ``` -pub struct Icon { - // ... -} -``` - -[#43781]: https://github.com/rust-lang/rust/issues/43781 -[#43348]: https://github.com/rust-lang/rust/issues/43348 -"##, - }, - Lint { - label: "doc_masked", - description: r##"# `doc_masked` - -The tracking issue for this feature is: [#44027] - ------ - -The `doc_masked` feature allows a crate to exclude types from a given crate from appearing in lists -of trait implementations. The specifics of the feature are as follows: - -1. When rustdoc encounters an `extern crate` statement annotated with a `#[doc(masked)]` attribute, - it marks the crate as being masked. - -2. When listing traits a given type implements, rustdoc ensures that traits from masked crates are - not emitted into the documentation. - -3. When listing types that implement a given trait, rustdoc ensures that types from masked crates - are not emitted into the documentation. - -This feature was introduced in PR [#44026] to ensure that compiler-internal and -implementation-specific types and traits were not included in the standard library's documentation. -Such types would introduce broken links into the documentation. - -[#44026]: https://github.com/rust-lang/rust/pull/44026 -[#44027]: https://github.com/rust-lang/rust/pull/44027 -"##, - }, - Lint { - label: "doc_notable_trait", - description: r##"# `doc_notable_trait` - -The tracking issue for this feature is: [#45040] - -The `doc_notable_trait` feature allows the use of the `#[doc(notable_trait)]` -attribute, which will display the trait in a "Notable traits" dialog for -functions returning types that implement the trait. For example, this attribute -is applied to the `Iterator`, `Future`, `io::Read`, and `io::Write` traits in -the standard library. - -You can do this on your own traits like so: - -``` -#![feature(doc_notable_trait)] - -#[doc(notable_trait)] -pub trait MyTrait {} - -pub struct MyStruct; -impl MyTrait for MyStruct {} - -/// The docs for this function will have a button that displays a dialog about -/// `MyStruct` implementing `MyTrait`. -pub fn my_fn() -> MyStruct { MyStruct } -``` - -This feature was originally implemented in PR [#45039]. - -See also its documentation in [the rustdoc book][rustdoc-book-notable_trait]. - -[#45040]: https://github.com/rust-lang/rust/issues/45040 -[#45039]: https://github.com/rust-lang/rust/pull/45039 -[rustdoc-book-notable_trait]: ../../rustdoc/unstable-features.html#adding-your-trait-to-the-notable-traits-dialog -"##, - }, - Lint { - label: "exclusive_range_pattern", - description: r##"# `exclusive_range_pattern` - -The tracking issue for this feature is: [#37854]. - - -[#67264]: https://github.com/rust-lang/rust/issues/67264 -[#37854]: https://github.com/rust-lang/rust/issues/37854 ------ - -The `exclusive_range_pattern` feature allows non-inclusive range -patterns (`0..10`) to be used in appropriate pattern matching -contexts. It also can be combined with `#![feature(half_open_range_patterns]` -to be able to use RangeTo patterns (`..10`). - -It also enabled RangeFrom patterns but that has since been -stabilized. - -```rust -#![feature(exclusive_range_pattern)] - let x = 5; - match x { - 0..10 => println!("single digit"), - 10 => println!("ten isn't part of the above range"), - _ => println!("nor is everything else.") - } -``` -"##, - }, - Lint { - label: "explicit_generic_args_with_impl_trait", - description: r##"# `explicit_generic_args_with_impl_trait` - -The tracking issue for this feature is: [#83701] - -[#83701]: https://github.com/rust-lang/rust/issues/83701 - ------------------------- - -The `explicit_generic_args_with_impl_trait` feature gate lets you specify generic arguments even -when `impl Trait` is used in argument position. - -A simple example is: - -```rust -#![feature(explicit_generic_args_with_impl_trait)] - -fn foo(_f: impl AsRef) {} - -fn main() { - foo::("".to_string()); -} -``` - -This is currently rejected: - -```text -error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position - --> src/main.rs:6:11 - | -6 | foo::("".to_string()); - | ^^^ explicit generic argument not allowed - -``` - -However it would compile if `explicit_generic_args_with_impl_trait` is enabled. - -Note that the synthetic type parameters from `impl Trait` are still implicit and you -cannot explicitly specify these: - -```rust,compile_fail -#![feature(explicit_generic_args_with_impl_trait)] - -fn foo(_f: impl AsRef) {} -fn bar>(_f: F) {} - -fn main() { - bar::("".to_string()); // Okay - bar::("".to_string()); // Okay - - foo::("".to_string()); // Okay - foo::("".to_string()); // Error, you cannot specify `impl Trait` explicitly -} -``` -"##, - }, - Lint { - label: "fd", - description: r##"# `fd` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "fd_read", - description: r##"# `fd_read` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "ffi_const", - description: r##"# `ffi_const` - -The tracking issue for this feature is: [#58328] - ------- - -The `#[ffi_const]` attribute applies clang's `const` attribute to foreign -functions declarations. - -That is, `#[ffi_const]` functions shall have no effects except for its return -value, which can only depend on the values of the function parameters, and is -not affected by changes to the observable state of the program. - -Applying the `#[ffi_const]` attribute to a function that violates these -requirements is undefined behaviour. - -This attribute enables Rust to perform common optimizations, like sub-expression -elimination, and it can avoid emitting some calls in repeated invocations of the -function with the same argument values regardless of other operations being -performed in between these functions calls (as opposed to `#[ffi_pure]` -functions). - -## Pitfalls - -A `#[ffi_const]` function can only read global memory that would not affect -its return value for the whole execution of the program (e.g. immutable global -memory). `#[ffi_const]` functions are referentially-transparent and therefore -more strict than `#[ffi_pure]` functions. - -A common pitfall involves applying the `#[ffi_const]` attribute to a -function that reads memory through pointer arguments which do not necessarily -point to immutable global memory. - -A `#[ffi_const]` function that returns unit has no effect on the abstract -machine's state, and a `#[ffi_const]` function cannot be `#[ffi_pure]`. - -A `#[ffi_const]` function must not diverge, neither via a side effect (e.g. a -call to `abort`) nor by infinite loops. - -When translating C headers to Rust FFI, it is worth verifying for which targets -the `const` attribute is enabled in those headers, and using the appropriate -`cfg` macros in the Rust side to match those definitions. While the semantics of -`const` are implemented identically by many C and C++ compilers, e.g., clang, -[GCC], [ARM C/C++ compiler], [IBM ILE C/C++], etc. they are not necessarily -implemented in this way on all of them. It is therefore also worth verifying -that the semantics of the C toolchain used to compile the binary being linked -against are compatible with those of the `#[ffi_const]`. - -[#58328]: https://github.com/rust-lang/rust/issues/58328 -[ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacgigch.html -[GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-const-function-attribute -[IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_const.htm -"##, - }, - Lint { - label: "ffi_pure", - description: r##"# `ffi_pure` - -The tracking issue for this feature is: [#58329] - ------- - -The `#[ffi_pure]` attribute applies clang's `pure` attribute to foreign -functions declarations. - -That is, `#[ffi_pure]` functions shall have no effects except for its return -value, which shall not change across two consecutive function calls with -the same parameters. - -Applying the `#[ffi_pure]` attribute to a function that violates these -requirements is undefined behavior. - -This attribute enables Rust to perform common optimizations, like sub-expression -elimination and loop optimizations. Some common examples of pure functions are -`strlen` or `memcmp`. - -These optimizations are only applicable when the compiler can prove that no -program state observable by the `#[ffi_pure]` function has changed between calls -of the function, which could alter the result. See also the `#[ffi_const]` -attribute, which provides stronger guarantees regarding the allowable behavior -of a function, enabling further optimization. - -## Pitfalls - -A `#[ffi_pure]` function can read global memory through the function -parameters (e.g. pointers), globals, etc. `#[ffi_pure]` functions are not -referentially-transparent, and are therefore more relaxed than `#[ffi_const]` -functions. - -However, accessing global memory through volatile or atomic reads can violate the -requirement that two consecutive function calls shall return the same value. - -A `pure` function that returns unit has no effect on the abstract machine's -state. - -A `#[ffi_pure]` function must not diverge, neither via a side effect (e.g. a -call to `abort`) nor by infinite loops. - -When translating C headers to Rust FFI, it is worth verifying for which targets -the `pure` attribute is enabled in those headers, and using the appropriate -`cfg` macros in the Rust side to match those definitions. While the semantics of -`pure` are implemented identically by many C and C++ compilers, e.g., clang, -[GCC], [ARM C/C++ compiler], [IBM ILE C/C++], etc. they are not necessarily -implemented in this way on all of them. It is therefore also worth verifying -that the semantics of the C toolchain used to compile the binary being linked -against are compatible with those of the `#[ffi_pure]`. - - -[#58329]: https://github.com/rust-lang/rust/issues/58329 -[ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacigdac.html -[GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-pure-function-attribute -[IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_pure.htm -"##, - }, - Lint { - label: "flt2dec", - description: r##"# `flt2dec` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "fmt_internals", - description: r##"# `fmt_internals` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "fn_traits", - description: r##"# `fn_traits` - -The tracking issue for this feature is [#29625] - -See Also: [`unboxed_closures`](../language-features/unboxed-closures.md) - -[#29625]: https://github.com/rust-lang/rust/issues/29625 - ----- - -The `fn_traits` feature allows for implementation of the [`Fn*`] traits -for creating custom closure-like types. - -[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html - -```rust -#![feature(unboxed_closures)] -#![feature(fn_traits)] - -struct Adder { - a: u32 -} - -impl FnOnce<(u32, )> for Adder { - type Output = u32; - extern "rust-call" fn call_once(self, b: (u32, )) -> Self::Output { - self.a + b.0 - } -} - -fn main() { - let adder = Adder { a: 3 }; - assert_eq!(adder(2), 5); -} -``` -"##, - }, - Lint { - label: "generators", - description: r##"# `generators` - -The tracking issue for this feature is: [#43122] - -[#43122]: https://github.com/rust-lang/rust/issues/43122 - ------------------------- - -The `generators` feature gate in Rust allows you to define generator or -coroutine literals. A generator is a "resumable function" that syntactically -resembles a closure but compiles to much different semantics in the compiler -itself. The primary feature of a generator is that it can be suspended during -execution to be resumed at a later date. Generators use the `yield` keyword to -"return", and then the caller can `resume` a generator to resume execution just -after the `yield` keyword. - -Generators are an extra-unstable feature in the compiler right now. Added in -[RFC 2033] they're mostly intended right now as a information/constraint -gathering phase. The intent is that experimentation can happen on the nightly -compiler before actual stabilization. A further RFC will be required to -stabilize generators/coroutines and will likely contain at least a few small -tweaks to the overall design. - -[RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033 - -A syntactical example of a generator is: - -```rust -#![feature(generators, generator_trait)] - -use std::ops::{Generator, GeneratorState}; -use std::pin::Pin; - -fn main() { - let mut generator = || { - yield 1; - return "foo" - }; - - match Pin::new(&mut generator).resume(()) { - GeneratorState::Yielded(1) => {} - _ => panic!("unexpected value from resume"), - } - match Pin::new(&mut generator).resume(()) { - GeneratorState::Complete("foo") => {} - _ => panic!("unexpected value from resume"), - } -} -``` - -Generators are closure-like literals which can contain a `yield` statement. The -`yield` statement takes an optional expression of a value to yield out of the -generator. All generator literals implement the `Generator` trait in the -`std::ops` module. The `Generator` trait has one main method, `resume`, which -resumes execution of the generator at the previous suspension point. - -An example of the control flow of generators is that the following example -prints all numbers in order: - -```rust -#![feature(generators, generator_trait)] - -use std::ops::Generator; -use std::pin::Pin; - -fn main() { - let mut generator = || { - println!("2"); - yield; - println!("4"); - }; - - println!("1"); - Pin::new(&mut generator).resume(()); - println!("3"); - Pin::new(&mut generator).resume(()); - println!("5"); -} -``` - -At this time the main intended use case of generators is an implementation -primitive for async/await syntax, but generators will likely be extended to -ergonomic implementations of iterators and other primitives in the future. -Feedback on the design and usage is always appreciated! - -### The `Generator` trait - -The `Generator` trait in `std::ops` currently looks like: - -```rust -# #![feature(arbitrary_self_types, generator_trait)] -# use std::ops::GeneratorState; -# use std::pin::Pin; - -pub trait Generator { - type Yield; - type Return; - fn resume(self: Pin<&mut Self>, resume: R) -> GeneratorState; -} -``` - -The `Generator::Yield` type is the type of values that can be yielded with the -`yield` statement. The `Generator::Return` type is the returned type of the -generator. This is typically the last expression in a generator's definition or -any value passed to `return` in a generator. The `resume` function is the entry -point for executing the `Generator` itself. - -The return value of `resume`, `GeneratorState`, looks like: - -```rust -pub enum GeneratorState { - Yielded(Y), - Complete(R), -} -``` - -The `Yielded` variant indicates that the generator can later be resumed. This -corresponds to a `yield` point in a generator. The `Complete` variant indicates -that the generator is complete and cannot be resumed again. Calling `resume` -after a generator has returned `Complete` will likely result in a panic of the -program. - -### Closure-like semantics - -The closure-like syntax for generators alludes to the fact that they also have -closure-like semantics. Namely: - -* When created, a generator executes no code. A closure literal does not - actually execute any of the closure's code on construction, and similarly a - generator literal does not execute any code inside the generator when - constructed. - -* Generators can capture outer variables by reference or by move, and this can - be tweaked with the `move` keyword at the beginning of the closure. Like - closures all generators will have an implicit environment which is inferred by - the compiler. Outer variables can be moved into a generator for use as the - generator progresses. - -* Generator literals produce a value with a unique type which implements the - `std::ops::Generator` trait. This allows actual execution of the generator - through the `Generator::resume` method as well as also naming it in return - types and such. - -* Traits like `Send` and `Sync` are automatically implemented for a `Generator` - depending on the captured variables of the environment. Unlike closures, - generators also depend on variables live across suspension points. This means - that although the ambient environment may be `Send` or `Sync`, the generator - itself may not be due to internal variables live across `yield` points being - not-`Send` or not-`Sync`. Note that generators do - not implement traits like `Copy` or `Clone` automatically. - -* Whenever a generator is dropped it will drop all captured environment - variables. - -### Generators as state machines - -In the compiler, generators are currently compiled as state machines. Each -`yield` expression will correspond to a different state that stores all live -variables over that suspension point. Resumption of a generator will dispatch on -the current state and then execute internally until a `yield` is reached, at -which point all state is saved off in the generator and a value is returned. - -Let's take a look at an example to see what's going on here: - -```rust -#![feature(generators, generator_trait)] - -use std::ops::Generator; -use std::pin::Pin; - -fn main() { - let ret = "foo"; - let mut generator = move || { - yield 1; - return ret - }; - - Pin::new(&mut generator).resume(()); - Pin::new(&mut generator).resume(()); -} -``` - -This generator literal will compile down to something similar to: - -```rust -#![feature(arbitrary_self_types, generators, generator_trait)] - -use std::ops::{Generator, GeneratorState}; -use std::pin::Pin; - -fn main() { - let ret = "foo"; - let mut generator = { - enum __Generator { - Start(&'static str), - Yield1(&'static str), - Done, - } - - impl Generator for __Generator { - type Yield = i32; - type Return = &'static str; - - fn resume(mut self: Pin<&mut Self>, resume: ()) -> GeneratorState { - use std::mem; - match mem::replace(&mut *self, __Generator::Done) { - __Generator::Start(s) => { - *self = __Generator::Yield1(s); - GeneratorState::Yielded(1) - } - - __Generator::Yield1(s) => { - *self = __Generator::Done; - GeneratorState::Complete(s) - } - - __Generator::Done => { - panic!("generator resumed after completion") - } - } - } - } - - __Generator::Start(ret) - }; - - Pin::new(&mut generator).resume(()); - Pin::new(&mut generator).resume(()); -} -``` - -Notably here we can see that the compiler is generating a fresh type, -`__Generator` in this case. This type has a number of states (represented here -as an `enum`) corresponding to each of the conceptual states of the generator. -At the beginning we're closing over our outer variable `foo` and then that -variable is also live over the `yield` point, so it's stored in both states. - -When the generator starts it'll immediately yield 1, but it saves off its state -just before it does so indicating that it has reached the yield point. Upon -resuming again we'll execute the `return ret` which returns the `Complete` -state. - -Here we can also note that the `Done` state, if resumed, panics immediately as -it's invalid to resume a completed generator. It's also worth noting that this -is just a rough desugaring, not a normative specification for what the compiler -does. -"##, - }, - Lint { - label: "half_open_range_patterns", - description: r##"# `half_open_range_patterns` - -The tracking issue for this feature is: [#67264] -It is part of the `#![exclusive_range_pattern]` feature, -tracked at [#37854]. - -[#67264]: https://github.com/rust-lang/rust/issues/67264 -[#37854]: https://github.com/rust-lang/rust/issues/37854 ------ - -The `half_open_range_patterns` feature allows RangeTo patterns -(`..10`) to be used in appropriate pattern matching contexts. -This requires also enabling the `exclusive_range_pattern` feature. - -It also enabled RangeFrom patterns but that has since been -stabilized. - -```rust -#![feature(half_open_range_patterns)] -#![feature(exclusive_range_pattern)] - let x = 5; - match x { - ..0 => println!("negative!"), // "RangeTo" pattern. Unstable. - 0 => println!("zero!"), - 1.. => println!("positive!"), // "RangeFrom" pattern. Stable. - } -``` -"##, - }, - Lint { - label: "infer_static_outlives_requirements", - description: r##"# `infer_static_outlives_requirements` - -The tracking issue for this feature is: [#54185] - -[#54185]: https://github.com/rust-lang/rust/issues/54185 - ------------------------- -The `infer_static_outlives_requirements` feature indicates that certain -`'static` outlives requirements can be inferred by the compiler rather than -stating them explicitly. - -Note: It is an accompanying feature to `infer_outlives_requirements`, -which must be enabled to infer outlives requirements. - -For example, currently generic struct definitions that contain -references, require where-clauses of the form T: 'static. By using -this feature the outlives predicates will be inferred, although -they may still be written explicitly. - -```rust,ignore (pseudo-Rust) -struct Foo where U: 'static { // <-- currently required - bar: Bar -} -struct Bar { - x: T, -} -``` - - -## Examples: - -```rust,ignore (pseudo-Rust) -#![feature(infer_outlives_requirements)] -#![feature(infer_static_outlives_requirements)] - -#[rustc_outlives] -// Implicitly infer U: 'static -struct Foo { - bar: Bar -} -struct Bar { - x: T, -} -``` -"##, - }, - Lint { - label: "inline_const", - description: r##"# `inline_const` - -The tracking issue for this feature is: [#76001] - -See also [`inline_const_pat`](inline-const-pat.md) - ------- - -This feature allows you to use inline constant expressions. For example, you can -turn this code: - -```rust -# fn add_one(x: i32) -> i32 { x + 1 } -const MY_COMPUTATION: i32 = 1 + 2 * 3 / 4; - -fn main() { - let x = add_one(MY_COMPUTATION); -} -``` - -into this code: - -```rust -#![feature(inline_const)] - -# fn add_one(x: i32) -> i32 { x + 1 } -fn main() { - let x = add_one(const { 1 + 2 * 3 / 4 }); -} -``` - -[#76001]: https://github.com/rust-lang/rust/issues/76001 -"##, - }, - Lint { - label: "inline_const_pat", - description: r##"# `inline_const_pat` - -The tracking issue for this feature is: [#76001] - -See also [`inline_const`](inline-const.md) - ------- - -This feature allows you to use inline constant expressions in pattern position: - -```rust -#![feature(inline_const_pat)] - -const fn one() -> i32 { 1 } - -let some_int = 3; -match some_int { - const { 1 + 2 } => println!("Matched 1 + 2"), - const { one() } => println!("Matched const fn returning 1"), - _ => println!("Didn't match anything :("), -} -``` - -[#76001]: https://github.com/rust-lang/rust/issues/76001 -"##, - }, - Lint { - label: "int_error_internals", - description: r##"# `int_error_internals` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "internal_output_capture", - description: r##"# `internal_output_capture` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "intra_doc_pointers", - description: r##"# `intra-doc-pointers` - -The tracking issue for this feature is: [#80896] - -[#80896]: https://github.com/rust-lang/rust/issues/80896 - ------------------------- - -Rustdoc does not currently allow disambiguating between `*const` and `*mut`, and -raw pointers in intra-doc links are unstable until it does. - -```rust -#![feature(intra_doc_pointers)] -//! [pointer::add] -``` -"##, - }, - Lint { - label: "intrinsics", - description: r##"# `intrinsics` - -The tracking issue for this feature is: None. - -Intrinsics are never intended to be stable directly, but intrinsics are often -exported in some sort of stable manner. Prefer using the stable interfaces to -the intrinsic directly when you can. - ------------------------- - - -These are imported as if they were FFI functions, with the special -`rust-intrinsic` ABI. For example, if one was in a freestanding -context, but wished to be able to `transmute` between types, and -perform efficient pointer arithmetic, one would import those functions -via a declaration like - -```rust -#![feature(intrinsics)] -# fn main() {} - -extern "rust-intrinsic" { - fn transmute(x: T) -> U; - - fn offset(dst: *const T, offset: isize) -> *const T; -} -``` - -As with any other FFI functions, these are always `unsafe` to call. -"##, - }, - Lint { - label: "is_sorted", - description: r##"# `is_sorted` - -The tracking issue for this feature is: [#53485] - -[#53485]: https://github.com/rust-lang/rust/issues/53485 - ------------------------- - -Add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to `[T]`; -add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to -`Iterator`. -"##, - }, - Lint { - label: "lang_items", - description: r##"# `lang_items` - -The tracking issue for this feature is: None. - ------------------------- - -The `rustc` compiler has certain pluggable operations, that is, -functionality that isn't hard-coded into the language, but is -implemented in libraries, with a special marker to tell the compiler -it exists. The marker is the attribute `#[lang = "..."]` and there are -various different values of `...`, i.e. various different 'lang -items'. - -For example, `Box` pointers require two lang items, one for allocation -and one for deallocation. A freestanding program that uses the `Box` -sugar for dynamic allocations via `malloc` and `free`: - -```rust,ignore (libc-is-finicky) -#![feature(lang_items, box_syntax, start, libc, core_intrinsics, rustc_private)] -#![no_std] -use core::intrinsics; -use core::panic::PanicInfo; - -extern crate libc; - -#[lang = "owned_box"] -pub struct Box(*mut T); - -#[lang = "exchange_malloc"] -unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { - let p = libc::malloc(size as libc::size_t) as *mut u8; - - // Check if `malloc` failed: - if p as usize == 0 { - intrinsics::abort(); - } - - p -} - -#[lang = "box_free"] -unsafe fn box_free(ptr: *mut T) { - libc::free(ptr as *mut libc::c_void) -} - -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { - let _x = box 1; - - 0 -} - -#[lang = "eh_personality"] extern fn rust_eh_personality() {} -#[lang = "panic_impl"] extern fn rust_begin_panic(info: &PanicInfo) -> ! { unsafe { intrinsics::abort() } } -#[no_mangle] pub extern fn rust_eh_register_frames () {} -#[no_mangle] pub extern fn rust_eh_unregister_frames () {} -``` - -Note the use of `abort`: the `exchange_malloc` lang item is assumed to -return a valid pointer, and so needs to do the check internally. - -Other features provided by lang items include: - -- overloadable operators via traits: the traits corresponding to the - `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all - marked with lang items; those specific four are `eq`, `ord`, - `deref`, and `add` respectively. -- stack unwinding and general failure; the `eh_personality`, - `panic` and `panic_bounds_check` lang items. -- the traits in `std::marker` used to indicate types of - various kinds; lang items `send`, `sync` and `copy`. -- the marker types and variance indicators found in - `std::marker`; lang items `covariant_type`, - `contravariant_lifetime`, etc. - -Lang items are loaded lazily by the compiler; e.g. if one never uses -`Box` then there is no need to define functions for `exchange_malloc` -and `box_free`. `rustc` will emit an error when an item is needed -but not found in the current crate or any that it depends on. - -Most lang items are defined by `libcore`, but if you're trying to build -an executable without the standard library, you'll run into the need -for lang items. The rest of this page focuses on this use-case, even though -lang items are a bit broader than that. - -### Using libc - -In order to build a `#[no_std]` executable we will need libc as a dependency. -We can specify this using our `Cargo.toml` file: - -```toml -[dependencies] -libc = { version = "0.2.14", default-features = false } -``` - -Note that the default features have been disabled. This is a critical step - -**the default features of libc include the standard library and so must be -disabled.** - -### Writing an executable without stdlib - -Controlling the entry point is possible in two ways: the `#[start]` attribute, -or overriding the default shim for the C `main` function with your own. - -The function marked `#[start]` is passed the command line parameters -in the same format as C: - -```rust,ignore (libc-is-finicky) -#![feature(lang_items, core_intrinsics, rustc_private)] -#![feature(start)] -#![no_std] -use core::intrinsics; -use core::panic::PanicInfo; - -// Pull in the system libc library for what crt0.o likely requires. -extern crate libc; - -// Entry point for this program. -#[start] -fn start(_argc: isize, _argv: *const *const u8) -> isize { - 0 -} - -// These functions are used by the compiler, but not -// for a bare-bones hello world. These are normally -// provided by libstd. -#[lang = "eh_personality"] -#[no_mangle] -pub extern fn rust_eh_personality() { -} - -#[lang = "panic_impl"] -#[no_mangle] -pub extern fn rust_begin_panic(info: &PanicInfo) -> ! { - unsafe { intrinsics::abort() } -} -``` - -To override the compiler-inserted `main` shim, one has to disable it -with `#![no_main]` and then create the appropriate symbol with the -correct ABI and the correct name, which requires overriding the -compiler's name mangling too: - -```rust,ignore (libc-is-finicky) -#![feature(lang_items, core_intrinsics, rustc_private)] -#![feature(start)] -#![no_std] -#![no_main] -use core::intrinsics; -use core::panic::PanicInfo; - -// Pull in the system libc library for what crt0.o likely requires. -extern crate libc; - -// Entry point for this program. -#[no_mangle] // ensure that this symbol is called `main` in the output -pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 { - 0 -} - -// These functions are used by the compiler, but not -// for a bare-bones hello world. These are normally -// provided by libstd. -#[lang = "eh_personality"] -#[no_mangle] -pub extern fn rust_eh_personality() { -} - -#[lang = "panic_impl"] -#[no_mangle] -pub extern fn rust_begin_panic(info: &PanicInfo) -> ! { - unsafe { intrinsics::abort() } -} -``` - -In many cases, you may need to manually link to the `compiler_builtins` crate -when building a `no_std` binary. You may observe this via linker error messages -such as "```undefined reference to `__rust_probestack'```". - -## More about the language items - -The compiler currently makes a few assumptions about symbols which are -available in the executable to call. Normally these functions are provided by -the standard library, but without it you must define your own. These symbols -are called "language items", and they each have an internal name, and then a -signature that an implementation must conform to. - -The first of these functions, `rust_eh_personality`, is used by the failure -mechanisms of the compiler. This is often mapped to GCC's personality function -(see the [libstd implementation][unwind] for more information), but crates -which do not trigger a panic can be assured that this function is never -called. The language item's name is `eh_personality`. - -[unwind]: https://github.com/rust-lang/rust/blob/master/library/panic_unwind/src/gcc.rs - -The second function, `rust_begin_panic`, is also used by the failure mechanisms of the -compiler. When a panic happens, this controls the message that's displayed on -the screen. While the language item's name is `panic_impl`, the symbol name is -`rust_begin_panic`. - -Finally, a `eh_catch_typeinfo` static is needed for certain targets which -implement Rust panics on top of C++ exceptions. - -## List of all language items - -This is a list of all language items in Rust along with where they are located in -the source code. - -- Primitives - - `i8`: `libcore/num/mod.rs` - - `i16`: `libcore/num/mod.rs` - - `i32`: `libcore/num/mod.rs` - - `i64`: `libcore/num/mod.rs` - - `i128`: `libcore/num/mod.rs` - - `isize`: `libcore/num/mod.rs` - - `u8`: `libcore/num/mod.rs` - - `u16`: `libcore/num/mod.rs` - - `u32`: `libcore/num/mod.rs` - - `u64`: `libcore/num/mod.rs` - - `u128`: `libcore/num/mod.rs` - - `usize`: `libcore/num/mod.rs` - - `f32`: `libstd/f32.rs` - - `f64`: `libstd/f64.rs` - - `char`: `libcore/char.rs` - - `slice`: `liballoc/slice.rs` - - `str`: `liballoc/str.rs` - - `const_ptr`: `libcore/ptr.rs` - - `mut_ptr`: `libcore/ptr.rs` - - `unsafe_cell`: `libcore/cell.rs` -- Runtime - - `start`: `libstd/rt.rs` - - `eh_personality`: `libpanic_unwind/emcc.rs` (EMCC) - - `eh_personality`: `libpanic_unwind/gcc.rs` (GNU) - - `eh_personality`: `libpanic_unwind/seh.rs` (SEH) - - `eh_catch_typeinfo`: `libpanic_unwind/emcc.rs` (EMCC) - - `panic`: `libcore/panicking.rs` - - `panic_bounds_check`: `libcore/panicking.rs` - - `panic_impl`: `libcore/panicking.rs` - - `panic_impl`: `libstd/panicking.rs` -- Allocations - - `owned_box`: `liballoc/boxed.rs` - - `exchange_malloc`: `liballoc/heap.rs` - - `box_free`: `liballoc/heap.rs` -- Operands - - `not`: `libcore/ops/bit.rs` - - `bitand`: `libcore/ops/bit.rs` - - `bitor`: `libcore/ops/bit.rs` - - `bitxor`: `libcore/ops/bit.rs` - - `shl`: `libcore/ops/bit.rs` - - `shr`: `libcore/ops/bit.rs` - - `bitand_assign`: `libcore/ops/bit.rs` - - `bitor_assign`: `libcore/ops/bit.rs` - - `bitxor_assign`: `libcore/ops/bit.rs` - - `shl_assign`: `libcore/ops/bit.rs` - - `shr_assign`: `libcore/ops/bit.rs` - - `deref`: `libcore/ops/deref.rs` - - `deref_mut`: `libcore/ops/deref.rs` - - `index`: `libcore/ops/index.rs` - - `index_mut`: `libcore/ops/index.rs` - - `add`: `libcore/ops/arith.rs` - - `sub`: `libcore/ops/arith.rs` - - `mul`: `libcore/ops/arith.rs` - - `div`: `libcore/ops/arith.rs` - - `rem`: `libcore/ops/arith.rs` - - `neg`: `libcore/ops/arith.rs` - - `add_assign`: `libcore/ops/arith.rs` - - `sub_assign`: `libcore/ops/arith.rs` - - `mul_assign`: `libcore/ops/arith.rs` - - `div_assign`: `libcore/ops/arith.rs` - - `rem_assign`: `libcore/ops/arith.rs` - - `eq`: `libcore/cmp.rs` - - `ord`: `libcore/cmp.rs` -- Functions - - `fn`: `libcore/ops/function.rs` - - `fn_mut`: `libcore/ops/function.rs` - - `fn_once`: `libcore/ops/function.rs` - - `generator_state`: `libcore/ops/generator.rs` - - `generator`: `libcore/ops/generator.rs` -- Other - - `coerce_unsized`: `libcore/ops/unsize.rs` - - `drop`: `libcore/ops/drop.rs` - - `drop_in_place`: `libcore/ptr.rs` - - `clone`: `libcore/clone.rs` - - `copy`: `libcore/marker.rs` - - `send`: `libcore/marker.rs` - - `sized`: `libcore/marker.rs` - - `unsize`: `libcore/marker.rs` - - `sync`: `libcore/marker.rs` - - `phantom_data`: `libcore/marker.rs` - - `discriminant_kind`: `libcore/marker.rs` - - `freeze`: `libcore/marker.rs` - - `debug_trait`: `libcore/fmt/mod.rs` - - `non_zero`: `libcore/nonzero.rs` - - `arc`: `liballoc/sync.rs` - - `rc`: `liballoc/rc.rs` -"##, - }, - Lint { - label: "libstd_sys_internals", - description: r##"# `libstd_sys_internals` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "libstd_thread_internals", - description: r##"# `libstd_thread_internals` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "link_cfg", - description: r##"# `link_cfg` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "llvm_asm", - description: r##"# `llvm_asm` - -The tracking issue for this feature is: [#70173] - -[#70173]: https://github.com/rust-lang/rust/issues/70173 - ------------------------- - -For extremely low-level manipulations and performance reasons, one -might wish to control the CPU directly. Rust supports using inline -assembly to do this via the `llvm_asm!` macro. - -```rust,ignore (pseudo-code) -llvm_asm!(assembly template - : output operands - : input operands - : clobbers - : options - ); -``` - -Any use of `llvm_asm` is feature gated (requires `#![feature(llvm_asm)]` on the -crate to allow) and of course requires an `unsafe` block. - -> **Note**: the examples here are given in x86/x86-64 assembly, but -> all platforms are supported. - -## Assembly template - -The `assembly template` is the only required parameter and must be a -literal string (i.e. `""`) - -```rust -#![feature(llvm_asm)] - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn foo() { - unsafe { - llvm_asm!("NOP"); - } -} - -// Other platforms: -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -fn foo() { /* ... */ } - -fn main() { - // ... - foo(); - // ... -} -``` - -(The `feature(llvm_asm)` and `#[cfg]`s are omitted from now on.) - -Output operands, input operands, clobbers and options are all optional -but you must add the right number of `:` if you skip them: - -```rust -# #![feature(llvm_asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -# fn main() { unsafe { -llvm_asm!("xor %eax, %eax" - : - : - : "eax" - ); -# } } -# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -# fn main() {} -``` - -Whitespace also doesn't matter: - -```rust -# #![feature(llvm_asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -# fn main() { unsafe { -llvm_asm!("xor %eax, %eax" ::: "eax"); -# } } -# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -# fn main() {} -``` - -## Operands - -Input and output operands follow the same format: `: -"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand -expressions must be mutable place, or not yet assigned: - -```rust -# #![feature(llvm_asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn add(a: i32, b: i32) -> i32 { - let c: i32; - unsafe { - llvm_asm!("add $2, $0" - : "=r"(c) - : "0"(a), "r"(b) - ); - } - c -} -# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -# fn add(a: i32, b: i32) -> i32 { a + b } - -fn main() { - assert_eq!(add(3, 14159), 14162) -} -``` - -If you would like to use real operands in this position, however, -you are required to put curly braces `{}` around the register that -you want, and you are required to put the specific size of the -operand. This is useful for very low level programming, where -which register you use is important: - -```rust -# #![feature(llvm_asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -# unsafe fn read_byte_in(port: u16) -> u8 { -let result: u8; -llvm_asm!("in %dx, %al" : "={al}"(result) : "{dx}"(port)); -result -# } -``` - -## Clobbers - -Some instructions modify registers which might otherwise have held -different values so we use the clobbers list to indicate to the -compiler not to assume any values loaded into those registers will -stay valid. - -```rust -# #![feature(llvm_asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -# fn main() { unsafe { -// Put the value 0x200 in eax: -llvm_asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax"); -# } } -# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -# fn main() {} -``` - -Input and output registers need not be listed since that information -is already communicated by the given constraints. Otherwise, any other -registers used either implicitly or explicitly should be listed. - -If the assembly changes the condition code register `cc` should be -specified as one of the clobbers. Similarly, if the assembly modifies -memory, `memory` should also be specified. - -## Options - -The last section, `options` is specific to Rust. The format is comma -separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to -specify some extra info about the inline assembly: - -Current valid options are: - -1. `volatile` - specifying this is analogous to - `__asm__ __volatile__ (...)` in gcc/clang. -2. `alignstack` - certain instructions expect the stack to be - aligned a certain way (i.e. SSE) and specifying this indicates to - the compiler to insert its usual stack alignment code -3. `intel` - use intel syntax instead of the default AT&T. - -```rust -# #![feature(llvm_asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -# fn main() { -let result: i32; -unsafe { - llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel") -} -println!("eax is currently {}", result); -# } -# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -# fn main() {} -``` - -## More Information - -The current implementation of the `llvm_asm!` macro is a direct binding to [LLVM's -inline assembler expressions][llvm-docs], so be sure to check out [their -documentation as well][llvm-docs] for more information about clobbers, -constraints, etc. - -[llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions -"##, - }, - Lint { - label: "marker_trait_attr", - description: r##"# `marker_trait_attr` - -The tracking issue for this feature is: [#29864] - -[#29864]: https://github.com/rust-lang/rust/issues/29864 - ------------------------- - -Normally, Rust keeps you from adding trait implementations that could -overlap with each other, as it would be ambiguous which to use. This -feature, however, carves out an exception to that rule: a trait can -opt-in to having overlapping implementations, at the cost that those -implementations are not allowed to override anything (and thus the -trait itself cannot have any associated items, as they're pointless -when they'd need to do the same thing for every type anyway). - -```rust -#![feature(marker_trait_attr)] - -#[marker] trait CheapToClone: Clone {} - -impl CheapToClone for T {} - -// These could potentially overlap with the blanket implementation above, -// so are only allowed because CheapToClone is a marker trait. -impl CheapToClone for (T, U) {} -impl CheapToClone for std::ops::Range {} - -fn cheap_clone(t: T) -> T { - t.clone() -} -``` - -This is expected to replace the unstable `overlapping_marker_traits` -feature, which applied to all empty traits (without needing an opt-in). -"##, - }, - Lint { - label: "more_qualified_paths", - description: r##"# `more_qualified_paths` - -The `more_qualified_paths` feature can be used in order to enable the -use of qualified paths in patterns. - -## Example - -```rust -#![feature(more_qualified_paths)] - -fn main() { - // destructure through a qualified path - let ::Assoc { br } = StructStruct { br: 2 }; -} - -struct StructStruct { - br: i8, -} - -struct Foo; - -trait A { - type Assoc; -} - -impl A for Foo { - type Assoc = StructStruct; -} -``` -"##, - }, - Lint { - label: "native_link_modifiers", - description: r##"# `native_link_modifiers` - -The tracking issue for this feature is: [#81490] - -[#81490]: https://github.com/rust-lang/rust/issues/81490 - ------------------------- - -The `native_link_modifiers` feature allows you to use the `modifiers` syntax with the `#[link(..)]` attribute. - -Modifiers are specified as a comma-delimited string with each modifier prefixed with either a `+` or `-` to indicate that the modifier is enabled or disabled, respectively. The last boolean value specified for a given modifier wins. -"##, - }, - Lint { - label: "native_link_modifiers_as_needed", - description: r##"# `native_link_modifiers_as_needed` - -The tracking issue for this feature is: [#81490] - -[#81490]: https://github.com/rust-lang/rust/issues/81490 - ------------------------- - -The `native_link_modifiers_as_needed` feature allows you to use the `as-needed` modifier. - -`as-needed` is only compatible with the `dynamic` and `framework` linking kinds. Using any other kind will result in a compiler error. - -`+as-needed` means that the library will be actually linked only if it satisfies some undefined symbols at the point at which it is specified on the command line, making it similar to static libraries in this regard. - -This modifier translates to `--as-needed` for ld-like linkers, and to `-dead_strip_dylibs` / `-needed_library` / `-needed_framework` for ld64. -The modifier does nothing for linkers that don't support it (e.g. `link.exe`). - -The default for this modifier is unclear, some targets currently specify it as `+as-needed`, some do not. We may want to try making `+as-needed` a default for all targets. -"##, - }, - Lint { - label: "native_link_modifiers_bundle", - description: r##"# `native_link_modifiers_bundle` - -The tracking issue for this feature is: [#81490] - -[#81490]: https://github.com/rust-lang/rust/issues/81490 - ------------------------- - -The `native_link_modifiers_bundle` feature allows you to use the `bundle` modifier. - -Only compatible with the `static` linking kind. Using any other kind will result in a compiler error. - -`+bundle` means objects from the static library are bundled into the produced crate (a rlib, for example) and are used from this crate later during linking of the final binary. - -`-bundle` means the static library is included into the produced rlib "by name" and object files from it are included only during linking of the final binary, the file search by that name is also performed during final linking. - -This modifier is supposed to supersede the `static-nobundle` linking kind defined by [RFC 1717](https://github.com/rust-lang/rfcs/pull/1717). - -The default for this modifier is currently `+bundle`, but it could be changed later on some future edition boundary. -"##, - }, - Lint { - label: "native_link_modifiers_verbatim", - description: r##"# `native_link_modifiers_verbatim` - -The tracking issue for this feature is: [#81490] - -[#81490]: https://github.com/rust-lang/rust/issues/81490 - ------------------------- - -The `native_link_modifiers_verbatim` feature allows you to use the `verbatim` modifier. - -`+verbatim` means that rustc itself won't add any target-specified library prefixes or suffixes (like `lib` or `.a`) to the library name, and will try its best to ask for the same thing from the linker. - -For `ld`-like linkers rustc will use the `-l:filename` syntax (note the colon) when passing the library, so the linker won't add any prefixes or suffixes as well. -See [`-l namespec`](https://sourceware.org/binutils/docs/ld/Options.html) in ld documentation for more details. -For linkers not supporting any verbatim modifiers (e.g. `link.exe` or `ld64`) the library name will be passed as is. - -The default for this modifier is `-verbatim`. - -This RFC changes the behavior of `raw-dylib` linking kind specified by [RFC 2627](https://github.com/rust-lang/rfcs/pull/2627). The `.dll` suffix (or other target-specified suffixes for other targets) is now added automatically. -If your DLL doesn't have the `.dll` suffix, it can be specified with `+verbatim`. -"##, - }, - Lint { - label: "native_link_modifiers_whole_archive", - description: r##"# `native_link_modifiers_whole_archive` - -The tracking issue for this feature is: [#81490] - -[#81490]: https://github.com/rust-lang/rust/issues/81490 - ------------------------- - -The `native_link_modifiers_whole_archive` feature allows you to use the `whole-archive` modifier. - -Only compatible with the `static` linking kind. Using any other kind will result in a compiler error. - -`+whole-archive` means that the static library is linked as a whole archive without throwing any object files away. - -This modifier translates to `--whole-archive` for `ld`-like linkers, to `/WHOLEARCHIVE` for `link.exe`, and to `-force_load` for `ld64`. -The modifier does nothing for linkers that don't support it. - -The default for this modifier is `-whole-archive`. -"##, - }, - Lint { - label: "negative_impls", - description: r##"# `negative_impls` - -The tracking issue for this feature is [#68318]. - -[#68318]: https://github.com/rust-lang/rust/issues/68318 - ----- - -With the feature gate `negative_impls`, you can write negative impls as well as positive ones: - -```rust -#![feature(negative_impls)] -trait DerefMut { } -impl !DerefMut for &T { } -``` - -Negative impls indicate a semver guarantee that the given trait will not be implemented for the given types. Negative impls play an additional purpose for auto traits, described below. - -Negative impls have the following characteristics: - -* They do not have any items. -* They must obey the orphan rules as if they were a positive impl. -* They cannot "overlap" with any positive impls. - -## Semver interaction - -It is a breaking change to remove a negative impl. Negative impls are a commitment not to implement the given trait for the named types. - -## Orphan and overlap rules - -Negative impls must obey the same orphan rules as a positive impl. This implies you cannot add a negative impl for types defined in upstream crates and so forth. - -Similarly, negative impls cannot overlap with positive impls, again using the same "overlap" check that we ordinarily use to determine if two impls overlap. (Note that positive impls typically cannot overlap with one another either, except as permitted by specialization.) - -## Interaction with auto traits - -Declaring a negative impl `impl !SomeAutoTrait for SomeType` for an -auto-trait serves two purposes: - -* as with any trait, it declares that `SomeType` will never implement `SomeAutoTrait`; -* it disables the automatic `SomeType: SomeAutoTrait` impl that would otherwise have been generated. - -Note that, at present, there is no way to indicate that a given type -does not implement an auto trait *but that it may do so in the -future*. For ordinary types, this is done by simply not declaring any -impl at all, but that is not an option for auto traits. A workaround -is that one could embed a marker type as one of the fields, where the -marker type is `!AutoTrait`. - -## Immediate uses - -Negative impls are used to declare that `&T: !DerefMut` and `&mut T: !Clone`, as required to fix the soundness of `Pin` described in [#66544](https://github.com/rust-lang/rust/issues/66544). - -This serves two purposes: - -* For proving the correctness of unsafe code, we can use that impl as evidence that no `DerefMut` or `Clone` impl exists. -* It prevents downstream crates from creating such impls. -"##, - }, - Lint { - label: "no_coverage", - description: r##"# `no_coverage` - -The tracking issue for this feature is: [#84605] - -[#84605]: https://github.com/rust-lang/rust/issues/84605 - ---- - -The `no_coverage` attribute can be used to selectively disable coverage -instrumentation in an annotated function. This might be useful to: - -- Avoid instrumentation overhead in a performance critical function -- Avoid generating coverage for a function that is not meant to be executed, - but still target 100% coverage for the rest of the program. - -## Example - -```rust -#![feature(no_coverage)] - -// `foo()` will get coverage instrumentation (by default) -fn foo() { - // ... -} - -#[no_coverage] -fn bar() { - // ... -} -``` -"##, - }, - Lint { - label: "no_sanitize", - description: r##"# `no_sanitize` - -The tracking issue for this feature is: [#39699] - -[#39699]: https://github.com/rust-lang/rust/issues/39699 - ------------------------- - -The `no_sanitize` attribute can be used to selectively disable sanitizer -instrumentation in an annotated function. This might be useful to: avoid -instrumentation overhead in a performance critical function, or avoid -instrumenting code that contains constructs unsupported by given sanitizer. - -The precise effect of this annotation depends on particular sanitizer in use. -For example, with `no_sanitize(thread)`, the thread sanitizer will no longer -instrument non-atomic store / load operations, but it will instrument atomic -operations to avoid reporting false positives and provide meaning full stack -traces. - -## Examples - -``` rust -#![feature(no_sanitize)] - -#[no_sanitize(address)] -fn foo() { - // ... -} -``` -"##, - }, - Lint { - label: "plugin", - description: r##"# `plugin` - -The tracking issue for this feature is: [#29597] - -[#29597]: https://github.com/rust-lang/rust/issues/29597 - - -This feature is part of "compiler plugins." It will often be used with the -`rustc_private` feature. - ------------------------- - -`rustc` can load compiler plugins, which are user-provided libraries that -extend the compiler's behavior with new lint checks, etc. - -A plugin is a dynamic library crate with a designated *registrar* function that -registers extensions with `rustc`. Other crates can load these extensions using -the crate attribute `#![plugin(...)]`. See the -`rustc_driver::plugin` documentation for more about the -mechanics of defining and loading a plugin. - -In the vast majority of cases, a plugin should *only* be used through -`#![plugin]` and not through an `extern crate` item. Linking a plugin would -pull in all of librustc_ast and librustc as dependencies of your crate. This is -generally unwanted unless you are building another plugin. - -The usual practice is to put compiler plugins in their own crate, separate from -any `macro_rules!` macros or ordinary Rust code meant to be used by consumers -of a library. - -# Lint plugins - -Plugins can extend [Rust's lint -infrastructure](../../reference/attributes/diagnostics.md#lint-check-attributes) with -additional checks for code style, safety, etc. Now let's write a plugin -[`lint-plugin-test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs) -that warns about any item named `lintme`. - -```rust,ignore (requires-stage-2) -#![feature(box_syntax, rustc_private)] - -extern crate rustc_ast; - -// Load rustc as a plugin to get macros -extern crate rustc_driver; -#[macro_use] -extern crate rustc_lint; -#[macro_use] -extern crate rustc_session; - -use rustc_driver::plugin::Registry; -use rustc_lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; -use rustc_ast::ast; -declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); - -declare_lint_pass!(Pass => [TEST_LINT]); - -impl EarlyLintPass for Pass { - fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { - if it.ident.name.as_str() == "lintme" { - cx.lint(TEST_LINT, |lint| { - lint.build("item is named 'lintme'").set_span(it.span).emit() - }); - } - } -} - -#[no_mangle] -fn __rustc_plugin_registrar(reg: &mut Registry) { - reg.lint_store.register_lints(&[&TEST_LINT]); - reg.lint_store.register_early_pass(|| box Pass); -} -``` - -Then code like - -```rust,ignore (requires-plugin) -#![feature(plugin)] -#![plugin(lint_plugin_test)] - -fn lintme() { } -``` - -will produce a compiler warning: - -```txt -foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default -foo.rs:4 fn lintme() { } - ^~~~~~~~~~~~~~~ -``` - -The components of a lint plugin are: - -* one or more `declare_lint!` invocations, which define static `Lint` structs; - -* a struct holding any state needed by the lint pass (here, none); - -* a `LintPass` - implementation defining how to check each syntax element. A single - `LintPass` may call `span_lint` for several different `Lint`s, but should - register them all through the `get_lints` method. - -Lint passes are syntax traversals, but they run at a late stage of compilation -where type information is available. `rustc`'s [built-in -lints](https://github.com/rust-lang/rust/blob/master/src/librustc_session/lint/builtin.rs) -mostly use the same infrastructure as lint plugins, and provide examples of how -to access type information. - -Lints defined by plugins are controlled by the usual [attributes and compiler -flags](../../reference/attributes/diagnostics.md#lint-check-attributes), e.g. -`#[allow(test_lint)]` or `-A test-lint`. These identifiers are derived from the -first argument to `declare_lint!`, with appropriate case and punctuation -conversion. - -You can run `rustc -W help foo.rs` to see a list of lints known to `rustc`, -including those provided by plugins loaded by `foo.rs`. -"##, - }, - Lint { - label: "print_internals", - description: r##"# `print_internals` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "profiler_runtime", - description: r##"# `profiler_runtime` - -The tracking issue for this feature is: [#42524](https://github.com/rust-lang/rust/issues/42524). - ------------------------- -"##, - }, - Lint { - label: "profiler_runtime_lib", - description: r##"# `profiler_runtime_lib` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "raw_dylib", - description: r##"# `raw_dylib` - -The tracking issue for this feature is: [#58713] - -[#58713]: https://github.com/rust-lang/rust/issues/58713 - ------------------------- - -The `raw_dylib` feature allows you to link against the implementations of functions in an `extern` -block without, on Windows, linking against an import library. - -```rust,ignore (partial-example) -#![feature(raw_dylib)] - -#[link(name="library", kind="raw-dylib")] -extern { - fn extern_function(x: i32); -} - -fn main() { - unsafe { - extern_function(14); - } -} -``` - -## Limitations - -Currently, this feature is only supported on `-windows-msvc` targets. Non-Windows platforms don't have import -libraries, and an incompatibility between LLVM and the BFD linker means that it is not currently supported on -`-windows-gnu` targets. - -On the `i686-pc-windows-msvc` target, this feature supports only the `cdecl`, `stdcall`, `system`, and `fastcall` -calling conventions. -"##, - }, - Lint { - label: "repr128", - description: r##"# `repr128` - -The tracking issue for this feature is: [#56071] - -[#56071]: https://github.com/rust-lang/rust/issues/56071 - ------------------------- - -The `repr128` feature adds support for `#[repr(u128)]` on `enum`s. - -```rust -#![feature(repr128)] - -#[repr(u128)] -enum Foo { - Bar(u64), -} -``` -"##, - }, - Lint { - label: "rt", - description: r##"# `rt` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "rustc_attrs", - description: r##"# `rustc_attrs` - -This feature has no tracking issue, and is therefore internal to -the compiler, not being intended for general use. - -Note: `rustc_attrs` enables many rustc-internal attributes and this page -only discuss a few of them. - ------------------------- - -The `rustc_attrs` feature allows debugging rustc type layouts by using -`#[rustc_layout(...)]` to debug layout at compile time (it even works -with `cargo check`) as an alternative to `rustc -Z print-type-sizes` -that is way more verbose. - -Options provided by `#[rustc_layout(...)]` are `debug`, `size`, `align`, -`abi`. Note that it only works on sized types without generics. - -## Examples - -```rust,compile_fail -#![feature(rustc_attrs)] - -#[rustc_layout(abi, size)] -pub enum X { - Y(u8, u8, u8), - Z(isize), -} -``` - -When that is compiled, the compiler will error with something like - -```text -error: abi: Aggregate { sized: true } - --> src/lib.rs:4:1 - | -4 | / pub enum T { -5 | | Y(u8, u8, u8), -6 | | Z(isize), -7 | | } - | |_^ - -error: size: Size { raw: 16 } - --> src/lib.rs:4:1 - | -4 | / pub enum T { -5 | | Y(u8, u8, u8), -6 | | Z(isize), -7 | | } - | |_^ - -error: aborting due to 2 previous errors -``` -"##, - }, - Lint { - label: "sort_internals", - description: r##"# `sort_internals` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "str_internals", - description: r##"# `str_internals` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "test", - description: r##"# `test` - -The tracking issue for this feature is: None. - ------------------------- - -The internals of the `test` crate are unstable, behind the `test` flag. The -most widely used part of the `test` crate are benchmark tests, which can test -the performance of your code. Let's make our `src/lib.rs` look like this -(comments elided): - -```rust,no_run -#![feature(test)] - -extern crate test; - -pub fn add_two(a: i32) -> i32 { - a + 2 -} - -#[cfg(test)] -mod tests { - use super::*; - use test::Bencher; - - #[test] - fn it_works() { - assert_eq!(4, add_two(2)); - } - - #[bench] - fn bench_add_two(b: &mut Bencher) { - b.iter(|| add_two(2)); - } -} -``` - -Note the `test` feature gate, which enables this unstable feature. - -We've imported the `test` crate, which contains our benchmarking support. -We have a new function as well, with the `bench` attribute. Unlike regular -tests, which take no arguments, benchmark tests take a `&mut Bencher`. This -`Bencher` provides an `iter` method, which takes a closure. This closure -contains the code we'd like to benchmark. - -We can run benchmark tests with `cargo bench`: - -```bash -$ cargo bench - Compiling adder v0.0.1 (file:///home/steve/tmp/adder) - Running target/release/adder-91b3e234d4ed382a - -running 2 tests -test tests::it_works ... ignored -test tests::bench_add_two ... bench: 1 ns/iter (+/- 0) - -test result: ok. 0 passed; 0 failed; 1 ignored; 1 measured -``` - -Our non-benchmark test was ignored. You may have noticed that `cargo bench` -takes a bit longer than `cargo test`. This is because Rust runs our benchmark -a number of times, and then takes the average. Because we're doing so little -work in this example, we have a `1 ns/iter (+/- 0)`, but this would show -the variance if there was one. - -Advice on writing benchmarks: - - -* Move setup code outside the `iter` loop; only put the part you want to measure inside -* Make the code do "the same thing" on each iteration; do not accumulate or change state -* Make the outer function idempotent too; the benchmark runner is likely to run - it many times -* Make the inner `iter` loop short and fast so benchmark runs are fast and the - calibrator can adjust the run-length at fine resolution -* Make the code in the `iter` loop do something simple, to assist in pinpointing - performance improvements (or regressions) - -## Gotcha: optimizations - -There's another tricky part to writing benchmarks: benchmarks compiled with -optimizations activated can be dramatically changed by the optimizer so that -the benchmark is no longer benchmarking what one expects. For example, the -compiler might recognize that some calculation has no external effects and -remove it entirely. - -```rust,no_run -#![feature(test)] - -extern crate test; -use test::Bencher; - -#[bench] -fn bench_xor_1000_ints(b: &mut Bencher) { - b.iter(|| { - (0..1000).fold(0, |old, new| old ^ new); - }); -} -``` - -gives the following results - -```text -running 1 test -test bench_xor_1000_ints ... bench: 0 ns/iter (+/- 0) - -test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured -``` - -The benchmarking runner offers two ways to avoid this. Either, the closure that -the `iter` method receives can return an arbitrary value which forces the -optimizer to consider the result used and ensures it cannot remove the -computation entirely. This could be done for the example above by adjusting the -`b.iter` call to - -```rust -# struct X; -# impl X { fn iter(&self, _: F) where F: FnMut() -> T {} } let b = X; -b.iter(|| { - // Note lack of `;` (could also use an explicit `return`). - (0..1000).fold(0, |old, new| old ^ new) -}); -``` - -Or, the other option is to call the generic `test::black_box` function, which -is an opaque "black box" to the optimizer and so forces it to consider any -argument as used. - -```rust -#![feature(test)] - -extern crate test; - -# fn main() { -# struct X; -# impl X { fn iter(&self, _: F) where F: FnMut() -> T {} } let b = X; -b.iter(|| { - let n = test::black_box(1000); - - (0..n).fold(0, |a, b| a ^ b) -}) -# } -``` - -Neither of these read or modify the value, and are very cheap for small values. -Larger values can be passed indirectly to reduce overhead (e.g. -`black_box(&huge_struct)`). - -Performing either of the above changes gives the following benchmarking results - -```text -running 1 test -test bench_xor_1000_ints ... bench: 131 ns/iter (+/- 3) - -test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured -``` - -However, the optimizer can still modify a testcase in an undesirable manner -even when using either of the above. -"##, - }, - Lint { - label: "thread_local_internals", - description: r##"# `thread_local_internals` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "trace_macros", - description: r##"# `trace_macros` - -The tracking issue for this feature is [#29598]. - -[#29598]: https://github.com/rust-lang/rust/issues/29598 - ------------------------- - -With `trace_macros` you can trace the expansion of macros in your code. - -## Examples - -```rust -#![feature(trace_macros)] - -fn main() { - trace_macros!(true); - println!("Hello, Rust!"); - trace_macros!(false); -} -``` - -The `cargo build` output: - -```txt -note: trace_macro - --> src/main.rs:5:5 - | -5 | println!("Hello, Rust!"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: expanding `println! { "Hello, Rust!" }` - = note: to `print ! ( concat ! ( "Hello, Rust!" , "\n" ) )` - = note: expanding `print! { concat ! ( "Hello, Rust!" , "\n" ) }` - = note: to `$crate :: io :: _print ( format_args ! ( concat ! ( "Hello, Rust!" , "\n" ) ) - )` - - Finished dev [unoptimized + debuginfo] target(s) in 0.60 secs -``` -"##, - }, - Lint { - label: "trait_alias", - description: r##"# `trait_alias` - -The tracking issue for this feature is: [#41517] - -[#41517]: https://github.com/rust-lang/rust/issues/41517 - ------------------------- - -The `trait_alias` feature adds support for trait aliases. These allow aliases -to be created for one or more traits (currently just a single regular trait plus -any number of auto-traits), and used wherever traits would normally be used as -either bounds or trait objects. - -```rust -#![feature(trait_alias)] - -trait Foo = std::fmt::Debug + Send; -trait Bar = Foo + Sync; - -// Use trait alias as bound on type parameter. -fn foo(v: &T) { - println!("{:?}", v); -} - -pub fn main() { - foo(&1); - - // Use trait alias for trait objects. - let a: &Bar = &123; - println!("{:?}", a); - let b = Box::new(456) as Box; - println!("{:?}", b); -} -``` -"##, - }, - Lint { - label: "trait_upcasting", - description: r##"# `trait_upcasting` - -The tracking issue for this feature is: [#65991] - -[#65991]: https://github.com/rust-lang/rust/issues/65991 - ------------------------- - -The `trait_upcasting` feature adds support for trait upcasting coercion. This allows a -trait object of type `dyn Bar` to be cast to a trait object of type `dyn Foo` -so long as `Bar: Foo`. - -```rust,edition2018 -#![feature(trait_upcasting)] -#![allow(incomplete_features)] - -trait Foo {} - -trait Bar: Foo {} - -impl Foo for i32 {} - -impl Bar for T {} - -let bar: &dyn Bar = &123; -let foo: &dyn Foo = bar; -``` -"##, - }, - Lint { - label: "transparent_unions", - description: r##"# `transparent_unions` - -The tracking issue for this feature is [#60405] - -[#60405]: https://github.com/rust-lang/rust/issues/60405 - ----- - -The `transparent_unions` feature allows you mark `union`s as -`#[repr(transparent)]`. A `union` may be `#[repr(transparent)]` in exactly the -same conditions in which a `struct` may be `#[repr(transparent)]` (generally, -this means the `union` must have exactly one non-zero-sized field). Some -concrete illustrations follow. - -```rust -#![feature(transparent_unions)] - -// This union has the same representation as `f32`. -#[repr(transparent)] -union SingleFieldUnion { - field: f32, -} - -// This union has the same representation as `usize`. -#[repr(transparent)] -union MultiFieldUnion { - field: usize, - nothing: (), -} -``` - -For consistency with transparent `struct`s, `union`s must have exactly one -non-zero-sized field. If all fields are zero-sized, the `union` must not be -`#[repr(transparent)]`: - -```rust -#![feature(transparent_unions)] - -// This (non-transparent) union is already valid in stable Rust: -pub union GoodUnion { - pub nothing: (), -} - -// Error: transparent union needs exactly one non-zero-sized field, but has 0 -// #[repr(transparent)] -// pub union BadUnion { -// pub nothing: (), -// } -``` - -The one exception is if the `union` is generic over `T` and has a field of type -`T`, it may be `#[repr(transparent)]` even if `T` is a zero-sized type: - -```rust -#![feature(transparent_unions)] - -// This union has the same representation as `T`. -#[repr(transparent)] -pub union GenericUnion { // Unions with non-`Copy` fields are unstable. - pub field: T, - pub nothing: (), -} - -// This is okay even though `()` is a zero-sized type. -pub const THIS_IS_OKAY: GenericUnion<()> = GenericUnion { field: () }; -``` - -Like transarent `struct`s, a transparent `union` of type `U` has the same -layout, size, and ABI as its single non-ZST field. If it is generic over a type -`T`, and all its fields are ZSTs except for exactly one field of type `T`, then -it has the same layout and ABI as `T` (even if `T` is a ZST when monomorphized). - -Like transparent `struct`s, transparent `union`s are FFI-safe if and only if -their underlying representation type is also FFI-safe. - -A `union` may not be eligible for the same nonnull-style optimizations that a -`struct` or `enum` (with the same fields) are eligible for. Adding -`#[repr(transparent)]` to `union` does not change this. To give a more concrete -example, it is unspecified whether `size_of::()` is equal to -`size_of::>()`, where `T` is a `union` (regardless of whether or not -it is transparent). The Rust compiler is free to perform this optimization if -possible, but is not required to, and different compiler versions may differ in -their application of these optimizations. -"##, - }, - Lint { - label: "try_blocks", - description: r##"# `try_blocks` - -The tracking issue for this feature is: [#31436] - -[#31436]: https://github.com/rust-lang/rust/issues/31436 - ------------------------- - -The `try_blocks` feature adds support for `try` blocks. A `try` -block creates a new scope one can use the `?` operator in. - -```rust,edition2018 -#![feature(try_blocks)] - -use std::num::ParseIntError; - -let result: Result = try { - "1".parse::()? - + "2".parse::()? - + "3".parse::()? -}; -assert_eq!(result, Ok(6)); - -let result: Result = try { - "1".parse::()? - + "foo".parse::()? - + "3".parse::()? -}; -assert!(result.is_err()); -``` -"##, - }, - Lint { - label: "type_changing_struct_update", - description: r##"# `type_changing_struct_update` - -The tracking issue for this feature is: [#86555] - -[#86555]: https://github.com/rust-lang/rust/issues/86555 - ------------------------- - -This implements [RFC2528]. When turned on, you can create instances of the same struct -that have different generic type or lifetime parameters. - -[RFC2528]: https://github.com/rust-lang/rfcs/blob/master/text/2528-type-changing-struct-update-syntax.md - -```rust -#![allow(unused_variables, dead_code)] -#![feature(type_changing_struct_update)] - -fn main () { - struct Foo { - field1: T, - field2: U, - } - - let base: Foo = Foo { - field1: String::from("hello"), - field2: 1234, - }; - let updated: Foo = Foo { - field1: 3.14, - ..base - }; -} -``` -"##, - }, - Lint { - label: "unboxed_closures", - description: r##"# `unboxed_closures` - -The tracking issue for this feature is [#29625] - -See Also: [`fn_traits`](../library-features/fn-traits.md) - -[#29625]: https://github.com/rust-lang/rust/issues/29625 - ----- - -The `unboxed_closures` feature allows you to write functions using the `"rust-call"` ABI, -required for implementing the [`Fn*`] family of traits. `"rust-call"` functions must have -exactly one (non self) argument, a tuple representing the argument list. - -[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html - -```rust -#![feature(unboxed_closures)] - -extern "rust-call" fn add_args(args: (u32, u32)) -> u32 { - args.0 + args.1 -} - -fn main() {} -``` -"##, - }, - Lint { - label: "unsized_locals", - description: r##"# `unsized_locals` - -The tracking issue for this feature is: [#48055] - -[#48055]: https://github.com/rust-lang/rust/issues/48055 - ------------------------- - -This implements [RFC1909]. When turned on, you can have unsized arguments and locals: - -[RFC1909]: https://github.com/rust-lang/rfcs/blob/master/text/1909-unsized-rvalues.md - -```rust -#![allow(incomplete_features)] -#![feature(unsized_locals, unsized_fn_params)] - -use std::any::Any; - -fn main() { - let x: Box = Box::new(42); - let x: dyn Any = *x; - // ^ unsized local variable - // ^^ unsized temporary - foo(x); -} - -fn foo(_: dyn Any) {} -// ^^^^^^ unsized argument -``` - -The RFC still forbids the following unsized expressions: - -```rust,compile_fail -#![feature(unsized_locals)] - -use std::any::Any; - -struct MyStruct { - content: T, -} - -struct MyTupleStruct(T); - -fn answer() -> Box { - Box::new(42) -} - -fn main() { - // You CANNOT have unsized statics. - static X: dyn Any = *answer(); // ERROR - const Y: dyn Any = *answer(); // ERROR - - // You CANNOT have struct initialized unsized. - MyStruct { content: *answer() }; // ERROR - MyTupleStruct(*answer()); // ERROR - (42, *answer()); // ERROR - - // You CANNOT have unsized return types. - fn my_function() -> dyn Any { *answer() } // ERROR - - // You CAN have unsized local variables... - let mut x: dyn Any = *answer(); // OK - // ...but you CANNOT reassign to them. - x = *answer(); // ERROR - - // You CANNOT even initialize them separately. - let y: dyn Any; // OK - y = *answer(); // ERROR - - // Not mentioned in the RFC, but by-move captured variables are also Sized. - let x: dyn Any = *answer(); - (move || { // ERROR - let y = x; - })(); - - // You CAN create a closure with unsized arguments, - // but you CANNOT call it. - // This is an implementation detail and may be changed in the future. - let f = |x: dyn Any| {}; - f(*answer()); // ERROR -} -``` - -## By-value trait objects - -With this feature, you can have by-value `self` arguments without `Self: Sized` bounds. - -```rust -#![feature(unsized_fn_params)] - -trait Foo { - fn foo(self) {} -} - -impl Foo for T {} - -fn main() { - let slice: Box<[i32]> = Box::new([1, 2, 3]); - <[i32] as Foo>::foo(*slice); -} -``` - -And `Foo` will also be object-safe. - -```rust -#![feature(unsized_fn_params)] - -trait Foo { - fn foo(self) {} -} - -impl Foo for T {} - -fn main () { - let slice: Box = Box::new([1, 2, 3]); - // doesn't compile yet - ::foo(*slice); -} -``` - -One of the objectives of this feature is to allow `Box`. - -## Variable length arrays - -The RFC also describes an extension to the array literal syntax: `[e; dyn n]`. In the syntax, `n` isn't necessarily a constant expression. The array is dynamically allocated on the stack and has the type of `[T]`, instead of `[T; n]`. - -```rust,ignore (not-yet-implemented) -#![feature(unsized_locals)] - -fn mergesort(a: &mut [T]) { - let mut tmp = [T; dyn a.len()]; - // ... -} - -fn main() { - let mut a = [3, 1, 5, 6]; - mergesort(&mut a); - assert_eq!(a, [1, 3, 5, 6]); -} -``` - -VLAs are not implemented yet. The syntax isn't final, either. We may need an alternative syntax for Rust 2015 because, in Rust 2015, expressions like `[e; dyn(1)]` would be ambiguous. One possible alternative proposed in the RFC is `[e; n]`: if `n` captures one or more local variables, then it is considered as `[e; dyn n]`. - -## Advisory on stack usage - -It's advised not to casually use the `#![feature(unsized_locals)]` feature. Typical use-cases are: - -- When you need a by-value trait objects. -- When you really need a fast allocation of small temporary arrays. - -Another pitfall is repetitive allocation and temporaries. Currently the compiler simply extends the stack frame every time it encounters an unsized assignment. So for example, the code - -```rust -#![feature(unsized_locals)] - -fn main() { - let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]); - let _x = {{{{{{{{{{*x}}}}}}}}}}; -} -``` - -and the code - -```rust -#![feature(unsized_locals)] - -fn main() { - for _ in 0..10 { - let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]); - let _x = *x; - } -} -``` - -will unnecessarily extend the stack frame. -"##, - }, - Lint { - label: "unsized_tuple_coercion", - description: r##"# `unsized_tuple_coercion` - -The tracking issue for this feature is: [#42877] - -[#42877]: https://github.com/rust-lang/rust/issues/42877 - ------------------------- - -This is a part of [RFC0401]. According to the RFC, there should be an implementation like this: - -```rust,ignore (partial-example) -impl<..., T, U: ?Sized> Unsized<(..., U)> for (..., T) where T: Unsized {} -``` - -This implementation is currently gated behind `#[feature(unsized_tuple_coercion)]` to avoid insta-stability. Therefore you can use it like this: - -```rust -#![feature(unsized_tuple_coercion)] - -fn main() { - let x : ([i32; 3], [i32; 3]) = ([1, 2, 3], [4, 5, 6]); - let y : &([i32; 3], [i32]) = &x; - assert_eq!(y.1[0], 4); -} -``` - -[RFC0401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md -"##, - }, - Lint { - label: "update_panic_count", - description: r##"# `update_panic_count` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "windows_c", - description: r##"# `windows_c` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "windows_handle", - description: r##"# `windows_handle` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "windows_net", - description: r##"# `windows_net` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "windows_stdio", - description: r##"# `windows_stdio` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, -]; - -pub const CLIPPY_LINTS: &[Lint] = &[ - Lint { - label: "clippy::absurd_extreme_comparisons", - description: r##"Checks for comparisons where one side of the relation is -either the minimum or maximum value for its type and warns if it involves a -case that is always true or always false. Only integer and boolean types are -checked."##, - }, - Lint { - label: "clippy::almost_swapped", - description: r##"Checks for `foo = bar; bar = foo` sequences."##, - }, - Lint { - label: "clippy::approx_constant", - description: r##"Checks for floating point literals that approximate -constants which are defined in -[`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants) -or -[`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants), -respectively, suggesting to use the predefined constant."##, - }, - Lint { - label: "clippy::as_conversions", - description: r##"Checks for usage of `as` conversions. - -Note that this lint is specialized in linting *every single* use of `as` -regardless of whether good alternatives exist or not. -If you want more precise lints for `as`, please consider using these separate lints: -`unnecessary_cast`, `cast_lossless/possible_truncation/possible_wrap/precision_loss/sign_loss`, -`fn_to_numeric_cast(_with_truncation)`, `char_lit_as_u8`, `ref_to_mut` and `ptr_as_ptr`. -There is a good explanation the reason why this lint should work in this way and how it is useful -[in this issue](https://github.com/rust-lang/rust-clippy/issues/5122)."##, - }, - Lint { - label: "clippy::assertions_on_constants", - description: r##"Checks for `assert!(true)` and `assert!(false)` calls."##, - }, - Lint { - label: "clippy::assign_op_pattern", - description: r##"Checks for `a = a op b` or `a = b commutative_op a` -patterns."##, - }, - Lint { - label: "clippy::assign_ops", - description: r##"Nothing. This lint has been deprecated."##, - }, - Lint { - label: "clippy::async_yields_async", - description: r##"Checks for async blocks that yield values of types -that can themselves be awaited."##, - }, - Lint { - label: "clippy::await_holding_lock", - description: r##"Checks for calls to await while holding a -non-async-aware MutexGuard."##, - }, - Lint { - label: "clippy::await_holding_refcell_ref", - description: r##"Checks for calls to await while holding a -`RefCell` `Ref` or `RefMut`."##, - }, - Lint { - label: "clippy::bad_bit_mask", - description: r##"Checks for incompatible bit masks in comparisons. - -The formula for detecting if an expression of the type `_ m - c` (where `` is one of {`&`, `|`} and `` is one of -{`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following -table: - -|Comparison |Bit Op|Example |is always|Formula | -|------------|------|------------|---------|----------------------| -|`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | -|`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | -|`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | -|`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | -|`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | -|`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` |"##, - }, - Lint { - label: "clippy::bind_instead_of_map", - description: r##"Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or -`_.or_else(|x| Err(y))`."##, - }, - Lint { - label: "clippy::blacklisted_name", - description: r##"Checks for usage of blacklisted names for variables, such -as `foo`."##, - }, - Lint { - label: "clippy::blanket_clippy_restriction_lints", - description: r##"Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category."##, - }, - Lint { - label: "clippy::blocks_in_if_conditions", - description: r##"Checks for `if` conditions that use blocks containing an -expression, statements or conditions that use closures with blocks."##, - }, - Lint { - label: "clippy::bool_assert_comparison", - description: r##"This lint warns about boolean comparisons in assert-like macros."##, - }, - Lint { - label: "clippy::bool_comparison", - description: r##"Checks for expressions of the form `x == true`, -`x != true` and order comparisons such as `x < true` (or vice versa) and -suggest using the variable directly."##, - }, - Lint { - label: "clippy::borrow_interior_mutable_const", - description: r##"Checks if `const` items which is interior mutable (e.g., -contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly."##, - }, - Lint { - label: "clippy::borrowed_box", - description: r##"Checks for use of `&Box` anywhere in the code. -Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information."##, - }, - Lint { - label: "clippy::box_collection", - description: r##"Checks for use of `Box` where T is a collection such as Vec anywhere in the code. -Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information."##, - }, - Lint { - label: "clippy::boxed_local", - description: r##"Checks for usage of `Box` where an unboxed `T` would -work fine."##, - }, - Lint { - label: "clippy::branches_sharing_code", - description: r##"Checks if the `if` and `else` block contain shared code that can be -moved out of the blocks."##, - }, - Lint { - label: "clippy::builtin_type_shadow", - description: r##"Warns if a generic shadows a built-in type."##, - }, - Lint { - label: "clippy::bytes_nth", - description: r##"Checks for the use of `.bytes().nth()`."##, - }, - Lint { - label: "clippy::cargo_common_metadata", - description: r##"Checks to see if all common metadata is defined in -`Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata"##, - }, - Lint { - label: "clippy::case_sensitive_file_extension_comparisons", - description: r##"Checks for calls to `ends_with` with possible file extensions -and suggests to use a case-insensitive approach instead."##, - }, - Lint { - label: "clippy::cast_lossless", - description: r##"Checks for casts between numerical types that may -be replaced by safe conversion functions."##, - }, - Lint { - label: "clippy::cast_possible_truncation", - description: r##"Checks for casts between numerical types that may -truncate large values. This is expected behavior, so the cast is `Allow` by -default."##, - }, - Lint { - label: "clippy::cast_possible_wrap", - description: r##"Checks for casts from an unsigned type to a signed type of -the same size. Performing such a cast is a 'no-op' for the compiler, -i.e., nothing is changed at the bit level, and the binary representation of -the value is reinterpreted. This can cause wrapping if the value is too big -for the target signed type. However, the cast works as defined, so this lint -is `Allow` by default."##, - }, - Lint { - label: "clippy::cast_precision_loss", - description: r##"Checks for casts from any numerical to a float type where -the receiving type cannot store all values from the original type without -rounding errors. This possible rounding is to be expected, so this lint is -`Allow` by default. - -Basically, this warns on casting any integer with 32 or more bits to `f32` -or any 64-bit integer to `f64`."##, - }, - Lint { - label: "clippy::cast_ptr_alignment", - description: r##"Checks for casts, using `as` or `pointer::cast`, -from a less-strictly-aligned pointer to a more-strictly-aligned pointer"##, - }, - Lint { - label: "clippy::cast_ref_to_mut", - description: r##"Checks for casts of `&T` to `&mut T` anywhere in the code."##, - }, - Lint { - label: "clippy::cast_sign_loss", - description: r##"Checks for casts from a signed to an unsigned numerical -type. In this case, negative values wrap around to large positive values, -which can be quite surprising in practice. However, as the cast works as -defined, this lint is `Allow` by default."##, - }, - Lint { - label: "clippy::char_lit_as_u8", - description: r##"Checks for expressions where a character literal is cast -to `u8` and suggests using a byte literal instead."##, - }, - Lint { - label: "clippy::chars_last_cmp", - description: r##"Checks for usage of `_.chars().last()` or -`_.chars().next_back()` on a `str` to check if it ends with a given char."##, - }, - Lint { - label: "clippy::chars_next_cmp", - description: r##"Checks for usage of `.chars().next()` on a `str` to check -if it starts with a given char."##, - }, - Lint { - label: "clippy::checked_conversions", - description: r##"Checks for explicit bounds checking when casting."##, - }, - Lint { - label: "clippy::clone_double_ref", - description: r##"Checks for usage of `.clone()` on an `&&T`."##, - }, - Lint { - label: "clippy::clone_on_copy", - description: r##"Checks for usage of `.clone()` on a `Copy` type."##, - }, - Lint { - label: "clippy::clone_on_ref_ptr", - description: r##"Checks for usage of `.clone()` on a ref-counted pointer, -(`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified -function syntax instead (e.g., `Rc::clone(foo)`)."##, - }, - Lint { - label: "clippy::cloned_instead_of_copied", - description: r##"Checks for usages of `cloned()` on an `Iterator` or `Option` where -`copied()` could be used instead."##, - }, - Lint { label: "clippy::cmp_nan", description: r##"Checks for comparisons to NaN."## }, - Lint { - label: "clippy::cmp_null", - description: r##"This lint checks for equality comparisons with `ptr::null`"##, - }, - Lint { - label: "clippy::cmp_owned", - description: r##"Checks for conversions to owned values just for the sake -of a comparison."##, - }, - Lint { - label: "clippy::cognitive_complexity", - description: r##"Checks for methods with high cognitive complexity."##, - }, - Lint { - label: "clippy::collapsible_else_if", - description: r##"Checks for collapsible `else { if ... }` expressions -that can be collapsed to `else if ...`."##, - }, - Lint { - label: "clippy::collapsible_if", - description: r##"Checks for nested `if` statements which can be collapsed -by `&&`-combining their conditions."##, - }, - Lint { - label: "clippy::collapsible_match", - description: r##"Finds nested `match` or `if let` expressions where the patterns may be collapsed together -without adding any branches. - -Note that this lint is not intended to find _all_ cases where nested match patterns can be merged, but only -cases where merging would most likely make the code more readable."##, - }, - Lint { - label: "clippy::comparison_chain", - description: r##"Checks comparison chains written with `if` that can be -rewritten with `match` and `cmp`."##, - }, - Lint { - label: "clippy::comparison_to_empty", - description: r##"Checks for comparing to an empty slice such as `` or `[]`, -and suggests using `.is_empty()` where applicable."##, - }, - Lint { - label: "clippy::copy_iterator", - description: r##"Checks for types that implement `Copy` as well as -`Iterator`."##, - }, - Lint { - label: "clippy::create_dir", - description: r##"Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead."##, - }, - Lint { - label: "clippy::crosspointer_transmute", - description: r##"Checks for transmutes between a type `T` and `*T`."##, - }, - Lint { label: "clippy::dbg_macro", description: r##"Checks for usage of dbg!() macro."## }, - Lint { - label: "clippy::debug_assert_with_mut_call", - description: r##"Checks for function/method calls with a mutable -parameter in `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` macros."##, - }, - Lint { - label: "clippy::decimal_literal_representation", - description: r##"Warns if there is a better representation for a numeric literal."##, - }, - Lint { - label: "clippy::declare_interior_mutable_const", - description: r##"Checks for declaration of `const` items which is interior -mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.)."##, - }, - Lint { - label: "clippy::default_numeric_fallback", - description: r##"Checks for usage of unconstrained numeric literals which may cause default numeric fallback in type -inference. - -Default numeric fallback means that if numeric types have not yet been bound to concrete -types at the end of type inference, then integer type is bound to `i32`, and similarly -floating type is bound to `f64`. - -See [RFC0212](https://github.com/rust-lang/rfcs/blob/master/text/0212-restore-int-fallback.md) for more information about the fallback."##, - }, - Lint { - label: "clippy::default_trait_access", - description: r##"Checks for literal calls to `Default::default()`."##, - }, - Lint { - label: "clippy::deprecated_cfg_attr", - description: r##"Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it -with `#[rustfmt::skip]`."##, - }, - Lint { - label: "clippy::deprecated_semver", - description: r##"Checks for `#[deprecated]` annotations with a `since` -field that is not a valid semantic version."##, - }, - Lint { - label: "clippy::deref_addrof", - description: r##"Checks for usage of `*&` and `*&mut` in expressions."##, - }, - Lint { - label: "clippy::derivable_impls", - description: r##"Detects manual `std::default::Default` implementations that are identical to a derived implementation."##, - }, - Lint { - label: "clippy::derive_hash_xor_eq", - description: r##"Checks for deriving `Hash` but implementing `PartialEq` -explicitly or vice versa."##, - }, - Lint { - label: "clippy::derive_ord_xor_partial_ord", - description: r##"Checks for deriving `Ord` but implementing `PartialOrd` -explicitly or vice versa."##, - }, - Lint { - label: "clippy::disallowed_methods", - description: r##"Denies the configured methods and functions in clippy.toml"##, - }, - Lint { - label: "clippy::disallowed_script_idents", - description: r##"Checks for usage of unicode scripts other than those explicitly allowed -by the lint config. - -This lint doesn't take into account non-text scripts such as `Unknown` and `Linear_A`. -It also ignores the `Common` script type. -While configuring, be sure to use official script name [aliases] from -[the list of supported scripts][supported_scripts]. - -See also: [`non_ascii_idents`]. - -[aliases]: http://www.unicode.org/reports/tr24/tr24-31.html#Script_Value_Aliases -[supported_scripts]: https://www.unicode.org/iso15924/iso15924-codes.html"##, - }, - Lint { - label: "clippy::disallowed_types", - description: r##"Denies the configured types in clippy.toml."##, - }, - Lint { - label: "clippy::diverging_sub_expression", - description: r##"Checks for diverging calls that are not match arms or -statements."##, - }, - Lint { - label: "clippy::doc_markdown", - description: r##"Checks for the presence of `_`, `::` or camel-case words -outside ticks in documentation."##, - }, - Lint { - label: "clippy::double_comparisons", - description: r##"Checks for double comparisons that could be simplified to a single expression."##, - }, - Lint { - label: "clippy::double_must_use", - description: r##"Checks for a `#[must_use]` attribute without -further information on functions and methods that return a type already -marked as `#[must_use]`."##, - }, - Lint { - label: "clippy::double_neg", - description: r##"Detects expressions of the form `--x`."##, - }, - Lint { - label: "clippy::double_parens", - description: r##"Checks for unnecessary double parentheses."##, - }, - Lint { - label: "clippy::drop_copy", - description: r##"Checks for calls to `std::mem::drop` with a value -that derives the Copy trait"##, - }, - Lint { - label: "clippy::drop_ref", - description: r##"Checks for calls to `std::mem::drop` with a reference -instead of an owned value."##, - }, - Lint { - label: "clippy::duplicate_underscore_argument", - description: r##"Checks for function arguments having the similar names -differing by an underscore."##, - }, - Lint { - label: "clippy::duration_subsec", - description: r##"Checks for calculation of subsecond microseconds or milliseconds -from other `Duration` methods."##, - }, - Lint { - label: "clippy::else_if_without_else", - description: r##"Checks for usage of if expressions with an `else if` branch, -but without a final `else` branch."##, - }, - Lint { - label: "clippy::empty_enum", - description: r##"Checks for `enum`s with no variants. - -As of this writing, the `never_type` is still a -nightly-only experimental API. Therefore, this lint is only triggered -if the `never_type` is enabled."##, - }, - Lint { - label: "clippy::empty_line_after_outer_attr", - description: r##"Checks for empty lines after outer attributes"##, - }, - Lint { label: "clippy::empty_loop", description: r##"Checks for empty `loop` expressions."## }, - Lint { - label: "clippy::enum_clike_unportable_variant", - description: r##"Checks for C-like enumerations that are -`repr(isize/usize)` and have values that don't fit into an `i32`."##, - }, - Lint { label: "clippy::enum_glob_use", description: r##"Checks for `use Enum::*`."## }, - Lint { - label: "clippy::enum_variant_names", - description: r##"Detects enumeration variants that are prefixed or suffixed -by the same characters."##, - }, - Lint { - label: "clippy::eq_op", - description: r##"Checks for equal operands to comparison, logical and -bitwise, difference and division binary operators (`==`, `>`, etc., `&&`, -`||`, `&`, `|`, `^`, `-` and `/`)."##, - }, - Lint { - label: "clippy::equatable_if_let", - description: r##"Checks for pattern matchings that can be expressed using equality."##, - }, - Lint { - label: "clippy::erasing_op", - description: r##"Checks for erasing operations, e.g., `x * 0`."##, - }, - Lint { - label: "clippy::eval_order_dependence", - description: r##"Checks for a read and a write to the same variable where -whether the read occurs before or after the write depends on the evaluation -order of sub-expressions."##, - }, - Lint { - label: "clippy::excessive_precision", - description: r##"Checks for float literals with a precision greater -than that supported by the underlying type."##, - }, - Lint { - label: "clippy::exhaustive_enums", - description: r##"Warns on any exported `enum`s that are not tagged `#[non_exhaustive]`"##, - }, - Lint { - label: "clippy::exhaustive_structs", - description: r##"Warns on any exported `structs`s that are not tagged `#[non_exhaustive]`"##, - }, - Lint { - label: "clippy::exit", - description: r##"`exit()` terminates the program and doesn't provide a -stack trace."##, - }, - Lint { - label: "clippy::expect_fun_call", - description: r##"Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`, -etc., and suggests to use `unwrap_or_else` instead"##, - }, - Lint { - label: "clippy::expect_used", - description: r##"Checks for `.expect()` calls on `Option`s and `Result`s."##, - }, - Lint { - label: "clippy::expl_impl_clone_on_copy", - description: r##"Checks for explicit `Clone` implementations for `Copy` -types."##, - }, - Lint { - label: "clippy::explicit_counter_loop", - description: r##"Checks `for` loops over slices with an explicit counter -and suggests the use of `.enumerate()`."##, - }, - Lint { - label: "clippy::explicit_deref_methods", - description: r##"Checks for explicit `deref()` or `deref_mut()` method calls."##, - }, - Lint { - label: "clippy::explicit_into_iter_loop", - description: r##"Checks for loops on `y.into_iter()` where `y` will do, and -suggests the latter."##, - }, - Lint { - label: "clippy::explicit_iter_loop", - description: r##"Checks for loops on `x.iter()` where `&x` will do, and -suggests the latter."##, - }, - Lint { - label: "clippy::explicit_write", - description: r##"Checks for usage of `write!()` / `writeln()!` which can be -replaced with `(e)print!()` / `(e)println!()`"##, - }, - Lint { - label: "clippy::extend_from_slice", - description: r##"Nothing. This lint has been deprecated."##, - }, - Lint { - label: "clippy::extend_with_drain", - description: r##"Checks for occurrences where one vector gets extended instead of append"##, - }, - Lint { - label: "clippy::extra_unused_lifetimes", - description: r##"Checks for lifetimes in generics that are never used -anywhere else."##, - }, - Lint { - label: "clippy::fallible_impl_from", - description: r##"Checks for impls of `From<..>` that contain `panic!()` or `unwrap()`"##, - }, - Lint { - label: "clippy::field_reassign_with_default", - description: r##"Checks for immediate reassignment of fields initialized -with Default::default()."##, - }, - Lint { - label: "clippy::filetype_is_file", - description: r##"Checks for `FileType::is_file()`."##, - }, - Lint { - label: "clippy::filter_map", - description: r##"Nothing. This lint has been deprecated."##, - }, - Lint { - label: "clippy::filter_map_identity", - description: r##"Checks for usage of `filter_map(|x| x)`."##, - }, - Lint { - label: "clippy::filter_map_next", - description: r##"Checks for usage of `_.filter_map(_).next()`."##, - }, - Lint { - label: "clippy::filter_next", - description: r##"Checks for usage of `_.filter(_).next()`."##, - }, - Lint { label: "clippy::find_map", description: r##"Nothing. This lint has been deprecated."## }, - Lint { - label: "clippy::flat_map_identity", - description: r##"Checks for usage of `flat_map(|x| x)`."##, - }, - Lint { - label: "clippy::flat_map_option", - description: r##"Checks for usages of `Iterator::flat_map()` where `filter_map()` could be -used instead."##, - }, - Lint { label: "clippy::float_arithmetic", description: r##"Checks for float arithmetic."## }, - Lint { - label: "clippy::float_cmp", - description: r##"Checks for (in-)equality comparisons on floating-point -values (apart from zero), except in functions called `*eq*` (which probably -implement equality for a type involving floats)."##, - }, - Lint { - label: "clippy::float_cmp_const", - description: r##"Checks for (in-)equality comparisons on floating-point -value and constant, except in functions called `*eq*` (which probably -implement equality for a type involving floats)."##, - }, - Lint { - label: "clippy::float_equality_without_abs", - description: r##"Checks for statements of the form `(a - b) < f32::EPSILON` or -`(a - b) < f64::EPSILON`. Notes the missing `.abs()`."##, - }, - Lint { - label: "clippy::fn_address_comparisons", - description: r##"Checks for comparisons with an address of a function item."##, - }, - Lint { - label: "clippy::fn_params_excessive_bools", - description: r##"Checks for excessive use of -bools in function definitions."##, - }, - Lint { - label: "clippy::fn_to_numeric_cast", - description: r##"Checks for casts of function pointers to something other than usize"##, - }, - Lint { - label: "clippy::fn_to_numeric_cast_any", - description: r##"Checks for casts of a function pointer to any integer type."##, - }, - Lint { - label: "clippy::fn_to_numeric_cast_with_truncation", - description: r##"Checks for casts of a function pointer to a numeric type not wide enough to -store address."##, - }, - Lint { - label: "clippy::for_kv_map", - description: r##"Checks for iterating a map (`HashMap` or `BTreeMap`) and -ignoring either the keys or values."##, - }, - Lint { - label: "clippy::for_loops_over_fallibles", - description: r##"Checks for `for` loops over `Option` or `Result` values."##, - }, - Lint { - label: "clippy::forget_copy", - description: r##"Checks for calls to `std::mem::forget` with a value that -derives the Copy trait"##, - }, - Lint { - label: "clippy::forget_ref", - description: r##"Checks for calls to `std::mem::forget` with a reference -instead of an owned value."##, - }, - Lint { - label: "clippy::format_in_format_args", - description: r##"Detects `format!` within the arguments of another macro that does -formatting such as `format!` itself, `write!` or `println!`. Suggests -inlining the `format!` call."##, - }, - Lint { - label: "clippy::from_iter_instead_of_collect", - description: r##"Checks for `from_iter()` function calls on types that implement the `FromIterator` -trait."##, - }, - Lint { - label: "clippy::from_over_into", - description: r##"Searches for implementations of the `Into<..>` trait and suggests to implement `From<..>` instead."##, - }, - Lint { - label: "clippy::from_str_radix_10", - description: r##"Checks for function invocations of the form `primitive::from_str_radix(s, 10)`"##, - }, - Lint { - label: "clippy::future_not_send", - description: r##"This lint requires Future implementations returned from -functions and methods to implement the `Send` marker trait. It is mostly -used by library authors (public and internal) that target an audience where -multithreaded executors are likely to be used for running these Futures."##, - }, - Lint { - label: "clippy::get_last_with_len", - description: r##"Checks for using `x.get(x.len() - 1)` instead of -`x.last()`."##, - }, - Lint { - label: "clippy::get_unwrap", - description: r##"Checks for use of `.get().unwrap()` (or -`.get_mut().unwrap`) on a standard library type which implements `Index`"##, - }, - Lint { - label: "clippy::identity_op", - description: r##"Checks for identity operations, e.g., `x + 0`."##, - }, - Lint { - label: "clippy::if_let_mutex", - description: r##"Checks for `Mutex::lock` calls in `if let` expression -with lock calls in any of the else blocks."##, - }, - Lint { - label: "clippy::if_let_redundant_pattern_matching", - description: r##"Nothing. This lint has been deprecated."##, - }, - Lint { - label: "clippy::if_not_else", - description: r##"Checks for usage of `!` or `!=` in an if condition with an -else branch."##, - }, - Lint { - label: "clippy::if_same_then_else", - description: r##"Checks for `if/else` with the same body as the *then* part -and the *else* part."##, - }, - Lint { - label: "clippy::if_then_some_else_none", - description: r##"Checks for if-else that could be written to `bool::then`."##, - }, - Lint { - label: "clippy::ifs_same_cond", - description: r##"Checks for consecutive `if`s with the same condition."##, - }, - Lint { - label: "clippy::implicit_clone", - description: r##"Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer."##, - }, - Lint { - label: "clippy::implicit_hasher", - description: r##"Checks for public `impl` or `fn` missing generalization -over different hashers and implicitly defaulting to the default hashing -algorithm (`SipHash`)."##, - }, - Lint { - label: "clippy::implicit_return", - description: r##"Checks for missing return statements at the end of a block."##, - }, - Lint { - label: "clippy::implicit_saturating_sub", - description: r##"Checks for implicit saturating subtraction."##, - }, - Lint { - label: "clippy::imprecise_flops", - description: r##"Looks for floating-point expressions that -can be expressed using built-in methods to improve accuracy -at the cost of performance."##, - }, - Lint { - label: "clippy::inconsistent_digit_grouping", - description: r##"Warns if an integral or floating-point constant is -grouped inconsistently with underscores."##, - }, - Lint { - label: "clippy::inconsistent_struct_constructor", - description: r##"Checks for struct constructors where all fields are shorthand and -the order of the field init shorthand in the constructor is inconsistent -with the order in the struct definition."##, - }, - Lint { - label: "clippy::index_refutable_slice", - description: r##"The lint checks for slice bindings in patterns that are only used to -access individual slice values."##, - }, - Lint { - label: "clippy::indexing_slicing", - description: r##"Checks for usage of indexing or slicing. Arrays are special cases, this lint -does report on arrays if we can tell that slicing operations are in bounds and does not -lint on constant `usize` indexing on arrays because that is handled by rustc's `const_err` lint."##, - }, - Lint { - label: "clippy::ineffective_bit_mask", - description: r##"Checks for bit masks in comparisons which can be removed -without changing the outcome. The basic structure can be seen in the -following table: - -|Comparison| Bit Op |Example |equals | -|----------|---------|-----------|-------| -|`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`| -|`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|"##, - }, - Lint { - label: "clippy::inefficient_to_string", - description: r##"Checks for usage of `.to_string()` on an `&&T` where -`T` implements `ToString` directly (like `&&str` or `&&String`)."##, - }, - Lint { - label: "clippy::infallible_destructuring_match", - description: r##"Checks for matches being used to destructure a single-variant enum -or tuple struct where a `let` will suffice."##, - }, - Lint { - label: "clippy::infinite_iter", - description: r##"Checks for iteration that is guaranteed to be infinite."##, - }, - Lint { - label: "clippy::inherent_to_string", - description: r##"Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`."##, - }, - Lint { - label: "clippy::inherent_to_string_shadow_display", - description: r##"Checks for the definition of inherent methods with a signature of `to_string(&self) -> String` and if the type implementing this method also implements the `Display` trait."##, - }, - Lint { - label: "clippy::inline_always", - description: r##"Checks for items annotated with `#[inline(always)]`, -unless the annotated function is empty or simply panics."##, - }, - Lint { - label: "clippy::inline_asm_x86_att_syntax", - description: r##"Checks for usage of AT&T x86 assembly syntax."##, - }, - Lint { - label: "clippy::inline_asm_x86_intel_syntax", - description: r##"Checks for usage of Intel x86 assembly syntax."##, - }, - Lint { - label: "clippy::inline_fn_without_body", - description: r##"Checks for `#[inline]` on trait methods without bodies"##, - }, - Lint { - label: "clippy::inspect_for_each", - description: r##"Checks for usage of `inspect().for_each()`."##, - }, - Lint { - label: "clippy::int_plus_one", - description: r##"Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block"##, - }, - Lint { - label: "clippy::integer_arithmetic", - description: r##"Checks for integer arithmetic operations which could overflow or panic. - -Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable -of overflowing according to the [Rust -Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), -or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is -attempted."##, - }, - Lint { label: "clippy::integer_division", description: r##"Checks for division of integers"## }, - Lint { - label: "clippy::into_iter_on_ref", - description: r##"Checks for `into_iter` calls on references which should be replaced by `iter` -or `iter_mut`."##, - }, - Lint { - label: "clippy::invalid_null_ptr_usage", - description: r##"This lint checks for invalid usages of `ptr::null`."##, - }, - Lint { - label: "clippy::invalid_regex", - description: r##"Checks [regex](https://crates.io/crates/regex) creation -(with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`) for correct -regex syntax."##, - }, - Lint { - label: "clippy::invalid_upcast_comparisons", - description: r##"Checks for comparisons where the relation is always either -true or false, but where one side has been upcast so that the comparison is -necessary. Only integer types are checked."##, - }, - Lint { - label: "clippy::invisible_characters", - description: r##"Checks for invisible Unicode characters in the code."##, - }, - Lint { - label: "clippy::items_after_statements", - description: r##"Checks for items declared after some statement in a block."##, - }, - Lint { - label: "clippy::iter_cloned_collect", - description: r##"Checks for the use of `.cloned().collect()` on slice to -create a `Vec`."##, - }, - Lint { - label: "clippy::iter_count", - description: r##"Checks for the use of `.iter().count()`."##, - }, - Lint { label: "clippy::iter_next_loop", description: r##"Checks for loops on `x.next()`."## }, - Lint { - label: "clippy::iter_next_slice", - description: r##"Checks for usage of `iter().next()` on a Slice or an Array"##, - }, - Lint { - label: "clippy::iter_not_returning_iterator", - description: r##"Detects methods named `iter` or `iter_mut` that do not have a return type that implements `Iterator`."##, - }, - Lint { - label: "clippy::iter_nth", - description: r##"Checks for use of `.iter().nth()` (and the related -`.iter_mut().nth()`) on standard library types with *O*(1) element access."##, - }, - Lint { - label: "clippy::iter_nth_zero", - description: r##"Checks for the use of `iter.nth(0)`."##, - }, - Lint { - label: "clippy::iter_skip_next", - description: r##"Checks for use of `.skip(x).next()` on iterators."##, - }, - Lint { - label: "clippy::iterator_step_by_zero", - description: r##"Checks for calling `.step_by(0)` on iterators which panics."##, - }, - Lint { - label: "clippy::just_underscores_and_digits", - description: r##"Checks if you have variables whose name consists of just -underscores and digits."##, - }, - Lint { - label: "clippy::large_const_arrays", - description: r##"Checks for large `const` arrays that should -be defined as `static` instead."##, - }, - Lint { - label: "clippy::large_digit_groups", - description: r##"Warns if the digits of an integral or floating-point -constant are grouped into groups that -are too large."##, - }, - Lint { - label: "clippy::large_enum_variant", - description: r##"Checks for large size differences between variants on -`enum`s."##, - }, - Lint { - label: "clippy::large_stack_arrays", - description: r##"Checks for local arrays that may be too large."##, - }, - Lint { - label: "clippy::large_types_passed_by_value", - description: r##"Checks for functions taking arguments by value, where -the argument type is `Copy` and large enough to be worth considering -passing by reference. Does not trigger if the function is being exported, -because that might induce API breakage, if the parameter is declared as mutable, -or if the argument is a `self`."##, - }, - Lint { - label: "clippy::len_without_is_empty", - description: r##"Checks for items that implement `.len()` but not -`.is_empty()`."##, - }, - Lint { - label: "clippy::len_zero", - description: r##"Checks for getting the length of something via `.len()` -just to compare to zero, and suggests using `.is_empty()` where applicable."##, - }, - Lint { - label: "clippy::let_and_return", - description: r##"Checks for `let`-bindings, which are subsequently -returned."##, - }, - Lint { - label: "clippy::let_underscore_drop", - description: r##"Checks for `let _ = ` -where expr has a type that implements `Drop`"##, - }, - Lint { - label: "clippy::let_underscore_lock", - description: r##"Checks for `let _ = sync_lock`. -This supports `mutex` and `rwlock` in `std::sync` and `parking_lot`."##, - }, - Lint { - label: "clippy::let_underscore_must_use", - description: r##"Checks for `let _ = ` where expr is `#[must_use]`"##, - }, - Lint { label: "clippy::let_unit_value", description: r##"Checks for binding a unit value."## }, - Lint { - label: "clippy::linkedlist", - description: r##"Checks for usage of any `LinkedList`, suggesting to use a -`Vec` or a `VecDeque` (formerly called `RingBuf`)."##, - }, - Lint { - label: "clippy::logic_bug", - description: r##"Checks for boolean expressions that contain terminals that -can be eliminated."##, - }, - Lint { - label: "clippy::lossy_float_literal", - description: r##"Checks for whole number float literals that -cannot be represented as the underlying type without loss."##, - }, - Lint { - label: "clippy::macro_use_imports", - description: r##"Checks for `#[macro_use] use...`."##, - }, - Lint { - label: "clippy::main_recursion", - description: r##"Checks for recursion using the entrypoint."##, - }, - Lint { - label: "clippy::manual_assert", - description: r##"Detects `if`-then-`panic!` that can be replaced with `assert!`."##, - }, - Lint { - label: "clippy::manual_async_fn", - description: r##"It checks for manual implementations of `async` functions."##, - }, - Lint { - label: "clippy::manual_filter_map", - description: r##"Checks for usage of `_.filter(_).map(_)` that can be written more simply -as `filter_map(_)`."##, - }, - Lint { - label: "clippy::manual_find_map", - description: r##"Checks for usage of `_.find(_).map(_)` that can be written more simply -as `find_map(_)`."##, - }, - Lint { - label: "clippy::manual_flatten", - description: r##"Check for unnecessary `if let` usage in a for loop -where only the `Some` or `Ok` variant of the iterator element is used."##, - }, - Lint { - label: "clippy::manual_map", - description: r##"Checks for usages of `match` which could be implemented using `map`"##, - }, - Lint { - label: "clippy::manual_memcpy", - description: r##"Checks for for-loops that manually copy items between -slices that could be optimized by having a memcpy."##, - }, - Lint { - label: "clippy::manual_non_exhaustive", - description: r##"Checks for manual implementations of the non-exhaustive pattern."##, - }, - Lint { - label: "clippy::manual_ok_or", - description: r##"Finds patterns that reimplement `Option::ok_or`."##, - }, - Lint { - label: "clippy::manual_range_contains", - description: r##"Checks for expressions like `x >= 3 && x < 8` that could -be more readably expressed as `(3..8).contains(x)`."##, - }, - Lint { - label: "clippy::manual_saturating_arithmetic", - description: r##"Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`."##, - }, - Lint { - label: "clippy::manual_split_once", - description: r##"Checks for usages of `str::splitn(2, _)`"##, - }, - Lint { - label: "clippy::manual_str_repeat", - description: r##"Checks for manual implementations of `str::repeat`"##, - }, - Lint { - label: "clippy::manual_strip", - description: r##"Suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing using -the pattern's length."##, - }, - Lint { label: "clippy::manual_swap", description: r##"Checks for manual swapping."## }, - Lint { - label: "clippy::manual_unwrap_or", - description: r##"Finds patterns that reimplement `Option::unwrap_or` or `Result::unwrap_or`."##, - }, - Lint { - label: "clippy::many_single_char_names", - description: r##"Checks for too many variables whose name consists of a -single character."##, - }, - Lint { - label: "clippy::map_clone", - description: r##"Checks for usage of `map(|x| x.clone())` or -dereferencing closures for `Copy` types, on `Iterator` or `Option`, -and suggests `cloned()` or `copied()` instead"##, - }, - Lint { - label: "clippy::map_collect_result_unit", - description: r##"Checks for usage of `_.map(_).collect::()`."##, - }, - Lint { - label: "clippy::map_entry", - description: r##"Checks for uses of `contains_key` + `insert` on `HashMap` -or `BTreeMap`."##, - }, - Lint { - label: "clippy::map_err_ignore", - description: r##"Checks for instances of `map_err(|_| Some::Enum)`"##, - }, - Lint { - label: "clippy::map_flatten", - description: r##"Checks for usage of `_.map(_).flatten(_)` on `Iterator` and `Option`"##, - }, - Lint { - label: "clippy::map_identity", - description: r##"Checks for instances of `map(f)` where `f` is the identity function."##, - }, - Lint { - label: "clippy::map_unwrap_or", - description: r##"Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or -`result.map(_).unwrap_or_else(_)`."##, - }, - Lint { - label: "clippy::match_as_ref", - description: r##"Checks for match which is used to add a reference to an -`Option` value."##, - }, - Lint { - label: "clippy::match_bool", - description: r##"Checks for matches where match expression is a `bool`. It -suggests to replace the expression with an `if...else` block."##, - }, - Lint { - label: "clippy::match_like_matches_macro", - description: r##"Checks for `match` or `if let` expressions producing a -`bool` that could be written using `matches!`"##, - }, - Lint { - label: "clippy::match_on_vec_items", - description: r##"Checks for `match vec[idx]` or `match vec[n..m]`."##, - }, - Lint { - label: "clippy::match_overlapping_arm", - description: r##"Checks for overlapping match arms."##, - }, - Lint { - label: "clippy::match_ref_pats", - description: r##"Checks for matches where all arms match a reference, -suggesting to remove the reference and deref the matched expression -instead. It also checks for `if let &foo = bar` blocks."##, - }, - Lint { - label: "clippy::match_result_ok", - description: r##"Checks for unnecessary `ok()` in `while let`."##, - }, - Lint { - label: "clippy::match_same_arms", - description: r##"Checks for `match` with identical arm bodies."##, - }, - Lint { - label: "clippy::match_single_binding", - description: r##"Checks for useless match that binds to only one value."##, - }, - Lint { - label: "clippy::match_str_case_mismatch", - description: r##"Checks for `match` expressions modifying the case of a string with non-compliant arms"##, - }, - Lint { - label: "clippy::match_wild_err_arm", - description: r##"Checks for arm which matches all errors with `Err(_)` -and take drastic actions like `panic!`."##, - }, - Lint { - label: "clippy::match_wildcard_for_single_variants", - description: r##"Checks for wildcard enum matches for a single variant."##, - }, - Lint { - label: "clippy::maybe_infinite_iter", - description: r##"Checks for iteration that may be infinite."##, - }, - Lint { - label: "clippy::mem_forget", - description: r##"Checks for usage of `std::mem::forget(t)` where `t` is -`Drop`."##, - }, - Lint { - label: "clippy::mem_replace_option_with_none", - description: r##"Checks for `mem::replace()` on an `Option` with -`None`."##, - }, - Lint { - label: "clippy::mem_replace_with_default", - description: r##"Checks for `std::mem::replace` on a value of type -`T` with `T::default()`."##, - }, - Lint { - label: "clippy::mem_replace_with_uninit", - description: r##"Checks for `mem::replace(&mut _, mem::uninitialized())` -and `mem::replace(&mut _, mem::zeroed())`."##, - }, - Lint { - label: "clippy::min_max", - description: r##"Checks for expressions where `std::cmp::min` and `max` are -used to clamp values, but switched so that the result is constant."##, - }, - Lint { - label: "clippy::misaligned_transmute", - description: r##"Nothing. This lint has been deprecated."##, - }, - Lint { - label: "clippy::mismatched_target_os", - description: r##"Checks for cfg attributes having operating systems used in target family position."##, - }, - Lint { - label: "clippy::misrefactored_assign_op", - description: r##"Checks for `a op= a op b` or `a op= b op a` patterns."##, - }, - Lint { - label: "clippy::missing_const_for_fn", - description: r##"Suggests the use of `const` in functions and methods where possible."##, - }, - Lint { - label: "clippy::missing_docs_in_private_items", - description: r##"Warns if there is missing doc for any documentable item -(public or private)."##, - }, - Lint { - label: "clippy::missing_enforced_import_renames", - description: r##"Checks for imports that do not rename the item as specified -in the `enforce-import-renames` config option."##, - }, - Lint { - label: "clippy::missing_errors_doc", - description: r##"Checks the doc comments of publicly visible functions that -return a `Result` type and warns if there is no `# Errors` section."##, - }, - Lint { - label: "clippy::missing_inline_in_public_items", - description: r##"It lints if an exported function, method, trait method with default impl, -or trait method impl is not `#[inline]`."##, - }, - Lint { - label: "clippy::missing_panics_doc", - description: r##"Checks the doc comments of publicly visible functions that -may panic and warns if there is no `# Panics` section."##, - }, - Lint { - label: "clippy::missing_safety_doc", - description: r##"Checks for the doc comments of publicly visible -unsafe functions and warns if there is no `# Safety` section."##, - }, - Lint { - label: "clippy::mistyped_literal_suffixes", - description: r##"Warns for mistyped suffix in literals"##, - }, - Lint { - label: "clippy::mixed_case_hex_literals", - description: r##"Warns on hexadecimal literals with mixed-case letter -digits."##, - }, - Lint { - label: "clippy::mod_module_files", - description: r##"Checks that module layout uses only self named module files, bans mod.rs files."##, - }, - Lint { - label: "clippy::module_inception", - description: r##"Checks for modules that have the same name as their -parent module"##, - }, - Lint { - label: "clippy::module_name_repetitions", - description: r##"Detects type names that are prefixed or suffixed by the -containing module's name."##, - }, - Lint { label: "clippy::modulo_arithmetic", description: r##"Checks for modulo arithmetic."## }, - Lint { - label: "clippy::modulo_one", - description: r##"Checks for getting the remainder of a division by one or minus -one."##, - }, - Lint { - label: "clippy::multiple_crate_versions", - description: r##"Checks to see if multiple versions of a crate are being -used."##, - }, - Lint { - label: "clippy::multiple_inherent_impl", - description: r##"Checks for multiple inherent implementations of a struct"##, - }, - Lint { - label: "clippy::must_use_candidate", - description: r##"Checks for public functions that have no -`#[must_use]` attribute, but return something not already marked -must-use, have no mutable arg and mutate no statics."##, - }, - Lint { - label: "clippy::must_use_unit", - description: r##"Checks for a `#[must_use]` attribute on -unit-returning functions and methods."##, - }, - Lint { - label: "clippy::mut_from_ref", - description: r##"This lint checks for functions that take immutable -references and return mutable ones."##, - }, - Lint { - label: "clippy::mut_mut", - description: r##"Checks for instances of `mut mut` references."##, - }, - Lint { - label: "clippy::mut_mutex_lock", - description: r##"Checks for `&mut Mutex::lock` calls"##, - }, - Lint { - label: "clippy::mut_range_bound", - description: r##"Checks for loops which have a range bound that is a mutable variable"##, - }, - Lint { - label: "clippy::mutable_key_type", - description: r##"Checks for sets/maps with mutable key types."##, - }, - Lint { - label: "clippy::mutex_atomic", - description: r##"Checks for usages of `Mutex` where an atomic will do."##, - }, - Lint { - label: "clippy::mutex_integer", - description: r##"Checks for usages of `Mutex` where `X` is an integral -type."##, - }, - Lint { label: "clippy::naive_bytecount", description: r##"Checks for naive byte counts"## }, - Lint { - label: "clippy::needless_arbitrary_self_type", - description: r##"The lint checks for `self` in fn parameters that -specify the `Self`-type explicitly"##, - }, - Lint { - label: "clippy::needless_bitwise_bool", - description: r##"Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using -a lazy and."##, - }, - Lint { - label: "clippy::needless_bool", - description: r##"Checks for expressions of the form `if c { true } else { -false }` (or vice versa) and suggests using the condition directly."##, - }, - Lint { - label: "clippy::needless_borrow", - description: r##"Checks for address of operations (`&`) that are going to -be dereferenced immediately by the compiler."##, - }, - Lint { - label: "clippy::needless_borrowed_reference", - description: r##"Checks for bindings that destructure a reference and borrow the inner -value with `&ref`."##, - }, - Lint { - label: "clippy::needless_collect", - description: r##"Checks for functions collecting an iterator when collect -is not needed."##, - }, - Lint { - label: "clippy::needless_continue", - description: r##"The lint checks for `if`-statements appearing in loops -that contain a `continue` statement in either their main blocks or their -`else`-blocks, when omitting the `else`-block possibly with some -rearrangement of code can make the code easier to understand."##, - }, - Lint { - label: "clippy::needless_doctest_main", - description: r##"Checks for `fn main() { .. }` in doctests"##, - }, - Lint { - label: "clippy::needless_for_each", - description: r##"Checks for usage of `for_each` that would be more simply written as a -`for` loop."##, - }, - Lint { - label: "clippy::needless_late_init", - description: r##"Checks for late initializations that can be replaced by a `let` statement -with an initializer."##, - }, - Lint { - label: "clippy::needless_lifetimes", - description: r##"Checks for lifetime annotations which can be removed by -relying on lifetime elision."##, - }, - Lint { - label: "clippy::needless_option_as_deref", - description: r##"Checks for no-op uses of Option::{as_deref,as_deref_mut}, -for example, `Option<&T>::as_deref()` returns the same type."##, - }, - Lint { - label: "clippy::needless_pass_by_value", - description: r##"Checks for functions taking arguments by value, but not -consuming them in its -body."##, - }, - Lint { - label: "clippy::needless_question_mark", - description: r##"Suggests alternatives for useless applications of `?` in terminating expressions"##, - }, - Lint { - label: "clippy::needless_range_loop", - description: r##"Checks for looping over the range of `0..len` of some -collection just to get the values by index."##, - }, - Lint { - label: "clippy::needless_return", - description: r##"Checks for return statements at the end of a block."##, - }, - Lint { - label: "clippy::needless_splitn", - description: r##"Checks for usages of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same."##, - }, - Lint { - label: "clippy::needless_update", - description: r##"Checks for needlessly including a base struct on update -when all fields are changed anyway. - -This lint is not applied to structs marked with -[non_exhaustive](https://doc.rust-lang.org/reference/attributes/type_system.html)."##, - }, - Lint { - label: "clippy::neg_cmp_op_on_partial_ord", - description: r##"Checks for the usage of negated comparison operators on types which only implement -`PartialOrd` (e.g., `f64`)."##, - }, - Lint { - label: "clippy::neg_multiply", - description: r##"Checks for multiplication by -1 as a form of negation."##, - }, - Lint { - label: "clippy::negative_feature_names", - description: r##"Checks for negative feature names with prefix `no-` or `not-`"##, - }, - Lint { - label: "clippy::never_loop", - description: r##"Checks for loops that will always `break`, `return` or -`continue` an outer loop."##, - }, - Lint { - label: "clippy::new_ret_no_self", - description: r##"Checks for `new` not returning a type that contains `Self`."##, - }, - Lint { - label: "clippy::new_without_default", - description: r##"Checks for types with a `fn new() -> Self` method and no -implementation of -[`Default`](https://doc.rust-lang.org/std/default/trait.Default.html)."##, - }, - Lint { - label: "clippy::no_effect", - description: r##"Checks for statements which have no effect."##, - }, - Lint { - label: "clippy::no_effect_underscore_binding", - description: r##"Checks for binding to underscore prefixed variable without side-effects."##, - }, - Lint { - label: "clippy::non_ascii_literal", - description: r##"Checks for non-ASCII characters in string and char literals."##, - }, - Lint { - label: "clippy::non_octal_unix_permissions", - description: r##"Checks for non-octal values used to set Unix file permissions."##, - }, - Lint { - label: "clippy::non_send_fields_in_send_ty", - description: r##"This lint warns about a `Send` implementation for a type that -contains fields that are not safe to be sent across threads. -It tries to detect fields that can cause a soundness issue -when sent to another thread (e.g., `Rc`) while allowing `!Send` fields -that are expected to exist in a `Send` type, such as raw pointers."##, - }, - Lint { - label: "clippy::nonminimal_bool", - description: r##"Checks for boolean expressions that can be written more -concisely."##, - }, - Lint { - label: "clippy::nonsensical_open_options", - description: r##"Checks for duplicate open options as well as combinations -that make no sense."##, - }, - Lint { - label: "clippy::nonstandard_macro_braces", - description: r##"Checks that common macros are used with consistent bracing."##, - }, - Lint { - label: "clippy::not_unsafe_ptr_arg_deref", - description: r##"Checks for public functions that dereference raw pointer -arguments but are not marked `unsafe`."##, - }, - Lint { - label: "clippy::octal_escapes", - description: r##"Checks for `\\0` escapes in string and byte literals that look like octal -character escapes in C."##, - }, - Lint { label: "clippy::ok_expect", description: r##"Checks for usage of `ok().expect(..)`."## }, - Lint { - label: "clippy::op_ref", - description: r##"Checks for arguments to `==` which have their address -taken to satisfy a bound -and suggests to dereference the other argument instead"##, - }, - Lint { - label: "clippy::option_as_ref_deref", - description: r##"Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str)."##, - }, - Lint { - label: "clippy::option_env_unwrap", - description: r##"Checks for usage of `option_env!(...).unwrap()` and -suggests usage of the `env!` macro."##, - }, - Lint { - label: "clippy::option_filter_map", - description: r##"Checks for indirect collection of populated `Option`"##, - }, - Lint { - label: "clippy::option_if_let_else", - description: r##"Lints usage of `if let Some(v) = ... { y } else { x }` which is more -idiomatically done with `Option::map_or` (if the else bit is a pure -expression) or `Option::map_or_else` (if the else bit is an impure -expression)."##, - }, - Lint { - label: "clippy::option_map_or_none", - description: r##"Checks for usage of `_.map_or(None, _)`."##, - }, - Lint { - label: "clippy::option_map_unit_fn", - description: r##"Checks for usage of `option.map(f)` where f is a function -or closure that returns the unit type `()`."##, - }, - Lint { - label: "clippy::option_option", - description: r##"Checks for use of `Option>` in function signatures and type -definitions"##, - }, - Lint { - label: "clippy::or_fun_call", - description: r##"Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, -etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or -`unwrap_or_default` instead."##, - }, - Lint { - label: "clippy::out_of_bounds_indexing", - description: r##"Checks for out of bounds array indexing with a constant -index."##, - }, - Lint { - label: "clippy::overflow_check_conditional", - description: r##"Detects classic underflow/overflow checks."##, - }, - Lint { label: "clippy::panic", description: r##"Checks for usage of `panic!`."## }, - Lint { - label: "clippy::panic_in_result_fn", - description: r##"Checks for usage of `panic!`, `unimplemented!`, `todo!`, `unreachable!` or assertions in a function of type result."##, - }, - Lint { - label: "clippy::panicking_unwrap", - description: r##"Checks for calls of `unwrap[_err]()` that will always fail."##, - }, - Lint { - label: "clippy::partialeq_ne_impl", - description: r##"Checks for manual re-implementations of `PartialEq::ne`."##, - }, - Lint { - label: "clippy::path_buf_push_overwrite", - description: r##"* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push) -calls on `PathBuf` that can cause overwrites."##, - }, - Lint { - label: "clippy::pattern_type_mismatch", - description: r##"Checks for patterns that aren't exact representations of the types -they are applied to. - -To satisfy this lint, you will have to adjust either the expression that is matched -against or the pattern itself, as well as the bindings that are introduced by the -adjusted patterns. For matching you will have to either dereference the expression -with the `*` operator, or amend the patterns to explicitly match against `&` -or `&mut ` depending on the reference mutability. For the bindings you need -to use the inverse. You can leave them as plain bindings if you wish for the value -to be copied, but you must use `ref mut ` or `ref ` to construct -a reference into the matched structure. - -If you are looking for a way to learn about ownership semantics in more detail, it -is recommended to look at IDE options available to you to highlight types, lifetimes -and reference semantics in your code. The available tooling would expose these things -in a general way even outside of the various pattern matching mechanics. Of course -this lint can still be used to highlight areas of interest and ensure a good understanding -of ownership semantics."##, - }, - Lint { - label: "clippy::possible_missing_comma", - description: r##"Checks for possible missing comma in an array. It lints if -an array element is a binary operator expression and it lies on two lines."##, - }, - Lint { - label: "clippy::precedence", - description: r##"Checks for operations where precedence may be unclear -and suggests to add parentheses. Currently it catches the following: -* mixed usage of arithmetic and bit shifting/combining operators without -parentheses -* a negative numeric literal (which is really a unary `-` followed by a -numeric literal) - followed by a method call"##, - }, - Lint { - label: "clippy::print_literal", - description: r##"This lint warns about the use of literals as `print!`/`println!` args."##, - }, - Lint { - label: "clippy::print_stderr", - description: r##"Checks for printing on *stderr*. The purpose of this lint -is to catch debugging remnants."##, - }, - Lint { - label: "clippy::print_stdout", - description: r##"Checks for printing on *stdout*. The purpose of this lint -is to catch debugging remnants."##, - }, - Lint { - label: "clippy::print_with_newline", - description: r##"This lint warns when you use `print!()` with a format -string that ends in a newline."##, - }, - Lint { - label: "clippy::println_empty_string", - description: r##"This lint warns when you use `println!()` to -print a newline."##, - }, - Lint { - label: "clippy::ptr_arg", - description: r##"This lint checks for function arguments of type `&String` -or `&Vec` unless the references are mutable. It will also suggest you -replace `.clone()` calls with the appropriate `.to_owned()`/`to_string()` -calls."##, - }, - Lint { - label: "clippy::ptr_as_ptr", - description: r##"Checks for `as` casts between raw pointers without changing its mutability, -namely `*const T` to `*const U` and `*mut T` to `*mut U`."##, - }, - Lint { label: "clippy::ptr_eq", description: r##"Use `std::ptr::eq` when applicable"## }, - Lint { - label: "clippy::ptr_offset_with_cast", - description: r##"Checks for usage of the `offset` pointer method with a `usize` casted to an -`isize`."##, - }, - Lint { - label: "clippy::pub_enum_variant_names", - description: r##"Nothing. This lint has been deprecated."##, - }, - Lint { - label: "clippy::question_mark", - description: r##"Checks for expressions that could be replaced by the question mark operator."##, - }, - Lint { - label: "clippy::range_minus_one", - description: r##"Checks for inclusive ranges where 1 is subtracted from -the upper bound, e.g., `x..=(y-1)`."##, - }, - Lint { - label: "clippy::range_plus_one", - description: r##"Checks for exclusive ranges where 1 is added to the -upper bound, e.g., `x..(y+1)`."##, - }, - Lint { - label: "clippy::range_step_by_zero", - description: r##"Nothing. This lint has been deprecated."##, - }, - Lint { - label: "clippy::range_zip_with_len", - description: r##"Checks for zipping a collection with the range of -`0.._.len()`."##, - }, - Lint { - label: "clippy::rc_buffer", - description: r##"Checks for `Rc` and `Arc` when `T` is a mutable buffer type such as `String` or `Vec`."##, - }, - Lint { label: "clippy::rc_mutex", description: r##"Checks for `Rc>`."## }, - Lint { - label: "clippy::redundant_allocation", - description: r##"Checks for use of redundant allocations anywhere in the code."##, - }, - Lint { - label: "clippy::redundant_clone", - description: r##"Checks for a redundant `clone()` (and its relatives) which clones an owned -value that is going to be dropped without further use."##, - }, - Lint { - label: "clippy::redundant_closure", - description: r##"Checks for closures which just call another function where -the function can be called directly. `unsafe` functions or calls where types -get adjusted are ignored."##, - }, - Lint { - label: "clippy::redundant_closure_call", - description: r##"Detects closures called in the same expression where they -are defined."##, - }, - Lint { - label: "clippy::redundant_closure_for_method_calls", - description: r##"Checks for closures which only invoke a method on the closure -argument and can be replaced by referencing the method directly."##, - }, - Lint { - label: "clippy::redundant_else", - description: r##"Checks for `else` blocks that can be removed without changing semantics."##, - }, - Lint { - label: "clippy::redundant_feature_names", - description: r##"Checks for feature names with prefix `use-`, `with-` or suffix `-support`"##, - }, - Lint { - label: "clippy::redundant_field_names", - description: r##"Checks for fields in struct literals where shorthands -could be used."##, - }, - Lint { - label: "clippy::redundant_pattern", - description: r##"Checks for patterns in the form `name @ _`."##, - }, - Lint { - label: "clippy::redundant_pattern_matching", - description: r##"Lint for redundant pattern matching over `Result`, `Option`, -`std::task::Poll` or `std::net::IpAddr`"##, - }, - Lint { - label: "clippy::redundant_pub_crate", - description: r##"Checks for items declared `pub(crate)` that are not crate visible because they -are inside a private module."##, - }, - Lint { - label: "clippy::redundant_slicing", - description: r##"Checks for redundant slicing expressions which use the full range, and -do not change the type."##, - }, - Lint { - label: "clippy::redundant_static_lifetimes", - description: r##"Checks for constants and statics with an explicit `'static` lifetime."##, - }, - Lint { - label: "clippy::ref_binding_to_reference", - description: r##"Checks for `ref` bindings which create a reference to a reference."##, - }, - Lint { - label: "clippy::ref_in_deref", - description: r##"Checks for references in expressions that use -auto dereference."##, - }, - Lint { - label: "clippy::ref_option_ref", - description: r##"Checks for usage of `&Option<&T>`."##, - }, - Lint { - label: "clippy::regex_macro", - description: r##"Nothing. This lint has been deprecated."##, - }, - Lint { - label: "clippy::repeat_once", - description: r##"Checks for usage of `.repeat(1)` and suggest the following method for each types. -- `.to_string()` for `str` -- `.clone()` for `String` -- `.to_vec()` for `slice` - -The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if -they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306))"##, - }, - Lint { - label: "clippy::replace_consts", - description: r##"Nothing. This lint has been deprecated."##, - }, - Lint { - label: "clippy::rest_pat_in_fully_bound_structs", - description: r##"Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched."##, - }, - Lint { - label: "clippy::result_map_or_into_option", - description: r##"Checks for usage of `_.map_or(None, Some)`."##, - }, - Lint { - label: "clippy::result_map_unit_fn", - description: r##"Checks for usage of `result.map(f)` where f is a function -or closure that returns the unit type `()`."##, - }, - Lint { - label: "clippy::result_unit_err", - description: r##"Checks for public functions that return a `Result` -with an `Err` type of `()`. It suggests using a custom type that -implements `std::error::Error`."##, - }, - Lint { - label: "clippy::return_self_not_must_use", - description: r##"This lint warns when a method returning `Self` doesn't have the `#[must_use]` attribute."##, - }, - Lint { - label: "clippy::reversed_empty_ranges", - description: r##"Checks for range expressions `x..y` where both `x` and `y` -are constant and `x` is greater or equal to `y`."##, - }, - Lint { - label: "clippy::same_functions_in_if_condition", - description: r##"Checks for consecutive `if`s with the same function call."##, - }, - Lint { - label: "clippy::same_item_push", - description: r##"Checks whether a for loop is being used to push a constant -value into a Vec."##, - }, - Lint { - label: "clippy::same_name_method", - description: r##"It lints if a struct has two methods with the same name: -one from a trait, another not from trait."##, - }, - Lint { - label: "clippy::search_is_some", - description: r##"Checks for an iterator or string search (such as `find()`, -`position()`, or `rposition()`) followed by a call to `is_some()` or `is_none()`."##, - }, - Lint { - label: "clippy::self_assignment", - description: r##"Checks for explicit self-assignments."##, - }, - Lint { - label: "clippy::self_named_constructors", - description: r##"Warns when constructors have the same name as their types."##, - }, - Lint { - label: "clippy::self_named_module_files", - description: r##"Checks that module layout uses only mod.rs files."##, - }, - Lint { - label: "clippy::semicolon_if_nothing_returned", - description: r##"Looks for blocks of expressions and fires if the last expression returns -`()` but is not followed by a semicolon."##, - }, - Lint { - label: "clippy::separated_literal_suffix", - description: r##"Warns if literal suffixes are separated by an underscore. -To enforce separated literal suffix style, -see the `unseparated_literal_suffix` lint."##, - }, - Lint { - label: "clippy::serde_api_misuse", - description: r##"Checks for mis-uses of the serde API."##, - }, - Lint { - label: "clippy::shadow_reuse", - description: r##"Checks for bindings that shadow other bindings already in -scope, while reusing the original value."##, - }, - Lint { - label: "clippy::shadow_same", - description: r##"Checks for bindings that shadow other bindings already in -scope, while just changing reference level or mutability."##, - }, - Lint { - label: "clippy::shadow_unrelated", - description: r##"Checks for bindings that shadow other bindings already in -scope, either without an initialization or with one that does not even use -the original value."##, - }, - Lint { - label: "clippy::short_circuit_statement", - description: r##"Checks for the use of short circuit boolean conditions as -a -statement."##, - }, - Lint { - label: "clippy::should_assert_eq", - description: r##"Nothing. This lint has been deprecated."##, - }, - Lint { - label: "clippy::should_implement_trait", - description: r##"Checks for methods that should live in a trait -implementation of a `std` trait (see [llogiq's blog -post](http://llogiq.github.io/2015/07/30/traits.html) for further -information) instead of an inherent implementation."##, - }, - Lint { - label: "clippy::similar_names", - description: r##"Checks for names that are very similar and thus confusing."##, - }, - Lint { - label: "clippy::single_char_add_str", - description: r##"Warns when using `push_str`/`insert_str` with a single-character string literal -where `push`/`insert` with a `char` would work fine."##, - }, - Lint { - label: "clippy::single_char_pattern", - description: r##"Checks for string methods that receive a single-character -`str` as an argument, e.g., `_.split(x)`."##, - }, - Lint { - label: "clippy::single_component_path_imports", - description: r##"Checking for imports with single component use path."##, - }, - Lint { - label: "clippy::single_element_loop", - description: r##"Checks whether a for loop has a single element."##, - }, - Lint { - label: "clippy::single_match", - description: r##"Checks for matches with a single arm where an `if let` -will usually suffice."##, - }, - Lint { - label: "clippy::single_match_else", - description: r##"Checks for matches with two arms where an `if let else` will -usually suffice."##, - }, - Lint { - label: "clippy::size_of_in_element_count", - description: r##"Detects expressions where -`size_of::` or `size_of_val::` is used as a -count of elements of type `T`"##, - }, - Lint { - label: "clippy::skip_while_next", - description: r##"Checks for usage of `_.skip_while(condition).next()`."##, - }, - Lint { - label: "clippy::slow_vector_initialization", - description: r##"Checks slow zero-filled vector initialization"##, - }, - Lint { - label: "clippy::stable_sort_primitive", - description: r##"When sorting primitive values (integers, bools, chars, as well -as arrays, slices, and tuples of such items), it is better to -use an unstable sort than a stable sort."##, - }, - Lint { - label: "clippy::str_to_string", - description: r##"This lint checks for `.to_string()` method calls on values of type `&str`."##, - }, - Lint { - label: "clippy::string_add", - description: r##"Checks for all instances of `x + _` where `x` is of type -`String`, but only if [`string_add_assign`](#string_add_assign) does *not* -match."##, - }, - Lint { - label: "clippy::string_add_assign", - description: r##"Checks for string appends of the form `x = x + y` (without -`let`!)."##, - }, - Lint { - label: "clippy::string_extend_chars", - description: r##"Checks for the use of `.extend(s.chars())` where s is a -`&str` or `String`."##, - }, - Lint { - label: "clippy::string_from_utf8_as_bytes", - description: r##"Check if the string is transformed to byte array and casted back to string."##, - }, - Lint { - label: "clippy::string_lit_as_bytes", - description: r##"Checks for the `as_bytes` method called on string literals -that contain only ASCII characters."##, - }, - Lint { - label: "clippy::string_slice", - description: r##"Checks for slice operations on strings"##, - }, - Lint { - label: "clippy::string_to_string", - description: r##"This lint checks for `.to_string()` method calls on values of type `String`."##, - }, - Lint { - label: "clippy::strlen_on_c_strings", - description: r##"Checks for usage of `libc::strlen` on a `CString` or `CStr` value, -and suggest calling `as_bytes().len()` or `to_bytes().len()` respectively instead."##, - }, - Lint { - label: "clippy::struct_excessive_bools", - description: r##"Checks for excessive -use of bools in structs."##, - }, - Lint { - label: "clippy::suboptimal_flops", - description: r##"Looks for floating-point expressions that -can be expressed using built-in methods to improve both -accuracy and performance."##, - }, - Lint { - label: "clippy::suspicious_arithmetic_impl", - description: r##"Lints for suspicious operations in impls of arithmetic operators, e.g. -subtracting elements in an Add impl."##, - }, - Lint { - label: "clippy::suspicious_assignment_formatting", - description: r##"Checks for use of the non-existent `=*`, `=!` and `=-` -operators."##, - }, - Lint { - label: "clippy::suspicious_else_formatting", - description: r##"Checks for formatting of `else`. It lints if the `else` -is followed immediately by a newline or the `else` seems to be missing."##, - }, - Lint { - label: "clippy::suspicious_map", - description: r##"Checks for calls to `map` followed by a `count`."##, - }, - Lint { - label: "clippy::suspicious_op_assign_impl", - description: r##"Lints for suspicious operations in impls of OpAssign, e.g. -subtracting elements in an AddAssign impl."##, - }, - Lint { - label: "clippy::suspicious_operation_groupings", - description: r##"Checks for unlikely usages of binary operators that are almost -certainly typos and/or copy/paste errors, given the other usages -of binary operators nearby."##, - }, - Lint { - label: "clippy::suspicious_splitn", - description: r##"Checks for calls to [`splitn`] -(https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and -related functions with either zero or one splits."##, - }, - Lint { - label: "clippy::suspicious_unary_op_formatting", - description: r##"Checks the formatting of a unary operator on the right hand side -of a binary operator. It lints if there is no space between the binary and unary operators, -but there is a space between the unary and its operand."##, - }, - Lint { - label: "clippy::tabs_in_doc_comments", - description: r##"Checks doc comments for usage of tab characters."##, - }, - Lint { - label: "clippy::temporary_assignment", - description: r##"Checks for construction of a structure or tuple just to -assign a value in it."##, - }, - Lint { - label: "clippy::to_digit_is_some", - description: r##"Checks for `.to_digit(..).is_some()` on `char`s."##, - }, - Lint { - label: "clippy::to_string_in_display", - description: r##"Checks for uses of `to_string()` in `Display` traits."##, - }, - Lint { - label: "clippy::to_string_in_format_args", - description: r##"Checks for [`ToString::to_string`](https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string) -applied to a type that implements [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html) -in a macro that does formatting."##, - }, - Lint { label: "clippy::todo", description: r##"Checks for usage of `todo!`."## }, - Lint { - label: "clippy::too_many_arguments", - description: r##"Checks for functions with too many parameters."##, - }, - Lint { - label: "clippy::too_many_lines", - description: r##"Checks for functions with a large amount of lines."##, - }, - Lint { - label: "clippy::toplevel_ref_arg", - description: r##"Checks for function arguments and let bindings denoted as -`ref`."##, - }, - Lint { - label: "clippy::trailing_empty_array", - description: r##"Displays a warning when a struct with a trailing zero-sized array is declared without a `repr` attribute."##, - }, - Lint { - label: "clippy::trait_duplication_in_bounds", - description: r##"Checks for cases where generics are being used and multiple -syntax specifications for trait bounds are used simultaneously."##, - }, - Lint { - label: "clippy::transmute_bytes_to_str", - description: r##"Checks for transmutes from a `&[u8]` to a `&str`."##, - }, - Lint { - label: "clippy::transmute_float_to_int", - description: r##"Checks for transmutes from a float to an integer."##, - }, - Lint { - label: "clippy::transmute_int_to_bool", - description: r##"Checks for transmutes from an integer to a `bool`."##, - }, - Lint { - label: "clippy::transmute_int_to_char", - description: r##"Checks for transmutes from an integer to a `char`."##, - }, - Lint { - label: "clippy::transmute_int_to_float", - description: r##"Checks for transmutes from an integer to a float."##, - }, - Lint { - label: "clippy::transmute_num_to_bytes", - description: r##"Checks for transmutes from a number to an array of `u8`"##, - }, - Lint { - label: "clippy::transmute_ptr_to_ptr", - description: r##"Checks for transmutes from a pointer to a pointer, or -from a reference to a reference."##, - }, - Lint { - label: "clippy::transmute_ptr_to_ref", - description: r##"Checks for transmutes from a pointer to a reference."##, - }, - Lint { - label: "clippy::transmutes_expressible_as_ptr_casts", - description: r##"Checks for transmutes that could be a pointer cast."##, - }, - Lint { - label: "clippy::transmuting_null", - description: r##"Checks for transmute calls which would receive a null pointer."##, - }, - Lint { - label: "clippy::trivial_regex", - description: r##"Checks for trivial [regex](https://crates.io/crates/regex) -creation (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`)."##, - }, - Lint { - label: "clippy::trivially_copy_pass_by_ref", - description: r##"Checks for functions taking arguments by reference, where -the argument type is `Copy` and small enough to be more efficient to always -pass by value."##, - }, - Lint { label: "clippy::try_err", description: r##"Checks for usages of `Err(x)?`."## }, - Lint { - label: "clippy::type_complexity", - description: r##"Checks for types used in structs, parameters and `let` -declarations above a certain complexity threshold."##, - }, - Lint { - label: "clippy::type_repetition_in_bounds", - description: r##"This lint warns about unnecessary type repetitions in trait bounds"##, - }, - Lint { - label: "clippy::undocumented_unsafe_blocks", - description: r##"Checks for `unsafe` blocks without a `// Safety: ` comment -explaining why the unsafe operations performed inside -the block are safe."##, - }, - Lint { - label: "clippy::undropped_manually_drops", - description: r##"Prevents the safe `std::mem::drop` function from being called on `std::mem::ManuallyDrop`."##, - }, - Lint { - label: "clippy::unicode_not_nfc", - description: r##"Checks for string literals that contain Unicode in a form -that is not equal to its -[NFC-recomposition](http://www.unicode.org/reports/tr15/#Norm_Forms)."##, - }, - Lint { - label: "clippy::unimplemented", - description: r##"Checks for usage of `unimplemented!`."##, - }, - Lint { - label: "clippy::uninit_assumed_init", - description: r##"Checks for `MaybeUninit::uninit().assume_init()`."##, - }, - Lint { - label: "clippy::uninit_vec", - description: r##"Checks for `set_len()` call that creates `Vec` with uninitialized elements. -This is commonly caused by calling `set_len()` right after allocating or -reserving a buffer with `new()`, `default()`, `with_capacity()`, or `reserve()`."##, - }, - Lint { - label: "clippy::unit_arg", - description: r##"Checks for passing a unit value as an argument to a function without using a -unit literal (`()`)."##, - }, - Lint { - label: "clippy::unit_cmp", - description: r##"Checks for comparisons to unit. This includes all binary -comparisons (like `==` and `<`) and asserts."##, - }, - Lint { label: "clippy::unit_hash", description: r##"Detects `().hash(_)`."## }, - Lint { - label: "clippy::unit_return_expecting_ord", - description: r##"Checks for functions that expect closures of type -Fn(...) -> Ord where the implemented closure returns the unit type. -The lint also suggests to remove the semi-colon at the end of the statement if present."##, - }, - Lint { - label: "clippy::unnecessary_cast", - description: r##"Checks for casts to the same type, casts of int literals to integer types -and casts of float literals to float types."##, - }, - Lint { - label: "clippy::unnecessary_filter_map", - description: r##"Checks for `filter_map` calls which could be replaced by `filter` or `map`. -More specifically it checks if the closure provided is only performing one of the -filter or map operations and suggests the appropriate option."##, - }, - Lint { - label: "clippy::unnecessary_fold", - description: r##"Checks for using `fold` when a more succinct alternative exists. -Specifically, this checks for `fold`s which could be replaced by `any`, `all`, -`sum` or `product`."##, - }, - Lint { - label: "clippy::unnecessary_lazy_evaluations", - description: r##"As the counterpart to `or_fun_call`, this lint looks for unnecessary -lazily evaluated closures on `Option` and `Result`. - -This lint suggests changing the following functions, when eager evaluation results in -simpler code: - - `unwrap_or_else` to `unwrap_or` - - `and_then` to `and` - - `or_else` to `or` - - `get_or_insert_with` to `get_or_insert` - - `ok_or_else` to `ok_or`"##, - }, - Lint { - label: "clippy::unnecessary_mut_passed", - description: r##"Detects passing a mutable reference to a function that only -requires an immutable reference."##, - }, - Lint { - label: "clippy::unnecessary_operation", - description: r##"Checks for expression statements that can be reduced to a -sub-expression."##, - }, - Lint { - label: "clippy::unnecessary_self_imports", - description: r##"Checks for imports ending in `::{self}`."##, - }, - Lint { - label: "clippy::unnecessary_sort_by", - description: r##"Detects uses of `Vec::sort_by` passing in a closure -which compares the two arguments, either directly or indirectly."##, - }, - Lint { - label: "clippy::unnecessary_to_owned", - description: r##"Checks for unnecessary calls to [`ToOwned::to_owned`](https://doc.rust-lang.org/std/borrow/trait.ToOwned.html#tymethod.to_owned) -and other `to_owned`-like functions."##, - }, - Lint { - label: "clippy::unnecessary_unwrap", - description: r##"Checks for calls of `unwrap[_err]()` that cannot fail."##, - }, - Lint { - label: "clippy::unnecessary_wraps", - description: r##"Checks for private functions that only return `Ok` or `Some`."##, - }, - Lint { - label: "clippy::unneeded_field_pattern", - description: r##"Checks for structure field patterns bound to wildcards."##, - }, - Lint { - label: "clippy::unneeded_wildcard_pattern", - description: r##"Checks for tuple patterns with a wildcard -pattern (`_`) is next to a rest pattern (`..`). - -_NOTE_: While `_, ..` means there is at least one element left, `..` -means there are 0 or more elements left. This can make a difference -when refactoring, but shouldn't result in errors in the refactored code, -since the wildcard pattern isn't used anyway."##, - }, - Lint { - label: "clippy::unnested_or_patterns", - description: r##"Checks for unnested or-patterns, e.g., `Some(0) | Some(2)` and -suggests replacing the pattern with a nested one, `Some(0 | 2)`. - -Another way to think of this is that it rewrites patterns in -*disjunctive normal form (DNF)* into *conjunctive normal form (CNF)*."##, - }, - Lint { label: "clippy::unreachable", description: r##"Checks for usage of `unreachable!`."## }, - Lint { - label: "clippy::unreadable_literal", - description: r##"Warns if a long integral or floating-point constant does -not contain underscores."##, - }, - Lint { - label: "clippy::unsafe_derive_deserialize", - description: r##"Checks for deriving `serde::Deserialize` on a type that -has methods using `unsafe`."##, - }, - Lint { - label: "clippy::unsafe_removed_from_name", - description: r##"Checks for imports that remove unsafe from an item's -name."##, - }, - Lint { - label: "clippy::unsafe_vector_initialization", - description: r##"Nothing. This lint has been deprecated."##, - }, - Lint { - label: "clippy::unseparated_literal_suffix", - description: r##"Warns if literal suffixes are not separated by an -underscore. -To enforce unseparated literal suffix style, -see the `separated_literal_suffix` lint."##, - }, - Lint { - label: "clippy::unsound_collection_transmute", - description: r##"Checks for transmutes between collections whose -types have different ABI, size or alignment."##, - }, - Lint { - label: "clippy::unstable_as_mut_slice", - description: r##"Nothing. This lint has been deprecated."##, - }, - Lint { - label: "clippy::unstable_as_slice", - description: r##"Nothing. This lint has been deprecated."##, - }, - Lint { - label: "clippy::unused_async", - description: r##"Checks for functions that are declared `async` but have no `.await`s inside of them."##, - }, - Lint { - label: "clippy::unused_collect", - description: r##"Nothing. This lint has been deprecated."##, - }, - Lint { - label: "clippy::unused_io_amount", - description: r##"Checks for unused written/read amount."##, - }, - Lint { - label: "clippy::unused_self", - description: r##"Checks methods that contain a `self` argument but don't use it"##, - }, - Lint { - label: "clippy::unused_unit", - description: r##"Checks for unit (`()`) expressions that can be removed."##, - }, - Lint { - label: "clippy::unusual_byte_groupings", - description: r##"Warns if hexadecimal or binary literals are not grouped -by nibble or byte."##, - }, - Lint { - label: "clippy::unwrap_in_result", - description: r##"Checks for functions of type `Result` that contain `expect()` or `unwrap()`"##, - }, - Lint { - label: "clippy::unwrap_or_else_default", - description: r##"Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and -`Result` values."##, - }, - Lint { - label: "clippy::unwrap_used", - description: r##"Checks for `.unwrap()` calls on `Option`s and on `Result`s."##, - }, - Lint { - label: "clippy::upper_case_acronyms", - description: r##"Checks for fully capitalized names and optionally names containing a capitalized acronym."##, - }, - Lint { - label: "clippy::use_debug", - description: r##"Checks for use of `Debug` formatting. The purpose of this -lint is to catch debugging remnants."##, - }, - Lint { - label: "clippy::use_self", - description: r##"Checks for unnecessary repetition of structure name when a -replacement with `Self` is applicable."##, - }, - Lint { - label: "clippy::used_underscore_binding", - description: r##"Checks for the use of bindings with a single leading -underscore."##, - }, - Lint { - label: "clippy::useless_asref", - description: r##"Checks for usage of `.as_ref()` or `.as_mut()` where the -types before and after the call are the same."##, - }, - Lint { - label: "clippy::useless_attribute", - description: r##"Checks for `extern crate` and `use` items annotated with -lint attributes. - -This lint permits `#[allow(unused_imports)]`, `#[allow(deprecated)]`, -`#[allow(unreachable_pub)]`, `#[allow(clippy::wildcard_imports)]` and -`#[allow(clippy::enum_glob_use)]` on `use` items and `#[allow(unused_imports)]` on -`extern crate` items with a `#[macro_use]` attribute."##, - }, - Lint { - label: "clippy::useless_conversion", - description: r##"Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls -which uselessly convert to the same type."##, - }, - Lint { - label: "clippy::useless_format", - description: r##"Checks for the use of `format!(string literal with no -argument)` and `format!({}, foo)` where `foo` is a string."##, - }, - Lint { - label: "clippy::useless_let_if_seq", - description: r##"Checks for variable declarations immediately followed by a -conditional affectation."##, - }, - Lint { - label: "clippy::useless_transmute", - description: r##"Checks for transmutes to the original type of the object -and transmutes that could be a cast."##, - }, - Lint { - label: "clippy::useless_vec", - description: r##"Checks for usage of `&vec![..]` when using `&[..]` would -be possible."##, - }, - Lint { - label: "clippy::vec_box", - description: r##"Checks for use of `Vec>` where T: Sized anywhere in the code. -Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information."##, - }, - Lint { - label: "clippy::vec_init_then_push", - description: r##"Checks for calls to `push` immediately after creating a new `Vec`."##, - }, - Lint { - label: "clippy::vec_resize_to_zero", - description: r##"Finds occurrences of `Vec::resize(0, an_int)`"##, - }, - Lint { - label: "clippy::verbose_bit_mask", - description: r##"Checks for bit masks that can be replaced by a call -to `trailing_zeros`"##, - }, - Lint { - label: "clippy::verbose_file_reads", - description: r##"Checks for use of File::read_to_end and File::read_to_string."##, - }, - Lint { - label: "clippy::vtable_address_comparisons", - description: r##"Checks for comparisons with an address of a trait vtable."##, - }, - Lint { - label: "clippy::while_immutable_condition", - description: r##"Checks whether variables used within while loop condition -can be (and are) mutated in the body."##, - }, - Lint { - label: "clippy::while_let_loop", - description: r##"Detects `loop + match` combinations that are easier -written as a `while let` loop."##, - }, - Lint { - label: "clippy::while_let_on_iterator", - description: r##"Checks for `while let` expressions on iterators."##, - }, - Lint { - label: "clippy::wildcard_dependencies", - description: r##"Checks for wildcard dependencies in the `Cargo.toml`."##, - }, - Lint { - label: "clippy::wildcard_enum_match_arm", - description: r##"Checks for wildcard enum matches using `_`."##, - }, - Lint { - label: "clippy::wildcard_imports", - description: r##"Checks for wildcard imports `use _::*`."##, - }, - Lint { - label: "clippy::wildcard_in_or_patterns", - description: r##"Checks for wildcard pattern used with others patterns in same match arm."##, - }, - Lint { - label: "clippy::write_literal", - description: r##"This lint warns about the use of literals as `write!`/`writeln!` args."##, - }, - Lint { - label: "clippy::write_with_newline", - description: r##"This lint warns when you use `write!()` with a format -string that -ends in a newline."##, - }, - Lint { - label: "clippy::writeln_empty_string", - description: r##"This lint warns when you use `writeln!(buf, )` to -print a newline."##, - }, - Lint { - label: "clippy::wrong_pub_self_convention", - description: r##"Nothing. This lint has been deprecated."##, - }, - Lint { - label: "clippy::wrong_self_convention", - description: r##"Checks for methods with certain name prefixes and which -doesn't match how self is taken. The actual rules are: - -|Prefix |Postfix |`self` taken | `self` type | -|-------|------------|-----------------------|--------------| -|`as_` | none |`&self` or `&mut self` | any | -|`from_`| none | none | any | -|`into_`| none |`self` | any | -|`is_` | none |`&self` or none | any | -|`to_` | `_mut` |`&mut self` | any | -|`to_` | not `_mut` |`self` | `Copy` | -|`to_` | not `_mut` |`&self` | not `Copy` | - -Note: Clippy doesn't trigger methods with `to_` prefix in: -- Traits definition. -Clippy can not tell if a type that implements a trait is `Copy` or not. -- Traits implementation, when `&self` is taken. -The method signature is controlled by the trait and often `&self` is required for all types that implement the trait -(see e.g. the `std::string::ToString` trait). - -Clippy allows `Pin<&Self>` and `Pin<&mut Self>` if `&self` and `&mut self` is required. - -Please find more info here: -https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv"##, - }, - Lint { - label: "clippy::wrong_transmute", - description: r##"Checks for transmutes that can't ever be correct on any -architecture."##, - }, - Lint { label: "clippy::zero_divided_by_zero", description: r##"Checks for `0.0 / 0.0`."## }, - Lint { - label: "clippy::zero_prefixed_literal", - description: r##"Warns if an integral constant literal starts with `0`."##, - }, - Lint { - label: "clippy::zero_ptr", - description: r##"Catch casts from `0` to some pointer type"##, - }, - Lint { - label: "clippy::zero_sized_map_values", - description: r##"Checks for maps with zero-sized value types anywhere in the code."##, - }, - Lint { - label: "clippy::zst_offset", - description: r##"Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to -zero-sized types"##, - }, -]; -pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ - LintGroup { - lint: Lint { - label: "clippy::cargo", - description: r##"lint group for: clippy::cargo_common_metadata, clippy::multiple_crate_versions, clippy::negative_feature_names, clippy::redundant_feature_names, clippy::wildcard_dependencies"##, - }, - children: &[ - "clippy::cargo_common_metadata", - "clippy::multiple_crate_versions", - "clippy::negative_feature_names", - "clippy::redundant_feature_names", - "clippy::wildcard_dependencies", - ], - }, - LintGroup { - lint: Lint { - label: "clippy::complexity", - description: r##"lint group for: clippy::bind_instead_of_map, clippy::bool_comparison, clippy::borrowed_box, clippy::char_lit_as_u8, clippy::clone_on_copy, clippy::crosspointer_transmute, clippy::deprecated_cfg_attr, clippy::deref_addrof, clippy::derivable_impls, clippy::diverging_sub_expression, clippy::double_comparisons, clippy::double_parens, clippy::duration_subsec, clippy::explicit_counter_loop, clippy::explicit_write, clippy::extra_unused_lifetimes, clippy::filter_map_identity, clippy::filter_next, clippy::flat_map_identity, clippy::get_last_with_len, clippy::identity_op, clippy::inspect_for_each, clippy::int_plus_one, clippy::iter_count, clippy::manual_filter_map, clippy::manual_find_map, clippy::manual_flatten, clippy::manual_split_once, clippy::manual_strip, clippy::manual_swap, clippy::manual_unwrap_or, clippy::map_flatten, clippy::map_identity, clippy::match_as_ref, clippy::match_single_binding, clippy::needless_arbitrary_self_type, clippy::needless_bool, clippy::needless_borrowed_reference, clippy::needless_lifetimes, clippy::needless_option_as_deref, clippy::needless_question_mark, clippy::needless_splitn, clippy::needless_update, clippy::neg_cmp_op_on_partial_ord, clippy::no_effect, clippy::nonminimal_bool, clippy::option_as_ref_deref, clippy::option_filter_map, clippy::option_map_unit_fn, clippy::overflow_check_conditional, clippy::partialeq_ne_impl, clippy::precedence, clippy::ptr_offset_with_cast, clippy::range_zip_with_len, clippy::redundant_closure_call, clippy::redundant_slicing, clippy::ref_in_deref, clippy::repeat_once, clippy::result_map_unit_fn, clippy::search_is_some, clippy::short_circuit_statement, clippy::single_element_loop, clippy::skip_while_next, clippy::string_from_utf8_as_bytes, clippy::strlen_on_c_strings, clippy::temporary_assignment, clippy::too_many_arguments, clippy::transmute_bytes_to_str, clippy::transmute_float_to_int, clippy::transmute_int_to_bool, clippy::transmute_int_to_char, clippy::transmute_int_to_float, clippy::transmute_num_to_bytes, clippy::transmute_ptr_to_ref, clippy::transmutes_expressible_as_ptr_casts, clippy::type_complexity, clippy::unit_arg, clippy::unnecessary_cast, clippy::unnecessary_filter_map, clippy::unnecessary_operation, clippy::unnecessary_sort_by, clippy::unnecessary_unwrap, clippy::unneeded_wildcard_pattern, clippy::useless_asref, clippy::useless_conversion, clippy::useless_format, clippy::vec_box, clippy::while_let_loop, clippy::wildcard_in_or_patterns, clippy::zero_divided_by_zero, clippy::zero_prefixed_literal"##, - }, - children: &[ - "clippy::bind_instead_of_map", - "clippy::bool_comparison", - "clippy::borrowed_box", - "clippy::char_lit_as_u8", - "clippy::clone_on_copy", - "clippy::crosspointer_transmute", - "clippy::deprecated_cfg_attr", - "clippy::deref_addrof", - "clippy::derivable_impls", - "clippy::diverging_sub_expression", - "clippy::double_comparisons", - "clippy::double_parens", - "clippy::duration_subsec", - "clippy::explicit_counter_loop", - "clippy::explicit_write", - "clippy::extra_unused_lifetimes", - "clippy::filter_map_identity", - "clippy::filter_next", - "clippy::flat_map_identity", - "clippy::get_last_with_len", - "clippy::identity_op", - "clippy::inspect_for_each", - "clippy::int_plus_one", - "clippy::iter_count", - "clippy::manual_filter_map", - "clippy::manual_find_map", - "clippy::manual_flatten", - "clippy::manual_split_once", - "clippy::manual_strip", - "clippy::manual_swap", - "clippy::manual_unwrap_or", - "clippy::map_flatten", - "clippy::map_identity", - "clippy::match_as_ref", - "clippy::match_single_binding", - "clippy::needless_arbitrary_self_type", - "clippy::needless_bool", - "clippy::needless_borrowed_reference", - "clippy::needless_lifetimes", - "clippy::needless_option_as_deref", - "clippy::needless_question_mark", - "clippy::needless_splitn", - "clippy::needless_update", - "clippy::neg_cmp_op_on_partial_ord", - "clippy::no_effect", - "clippy::nonminimal_bool", - "clippy::option_as_ref_deref", - "clippy::option_filter_map", - "clippy::option_map_unit_fn", - "clippy::overflow_check_conditional", - "clippy::partialeq_ne_impl", - "clippy::precedence", - "clippy::ptr_offset_with_cast", - "clippy::range_zip_with_len", - "clippy::redundant_closure_call", - "clippy::redundant_slicing", - "clippy::ref_in_deref", - "clippy::repeat_once", - "clippy::result_map_unit_fn", - "clippy::search_is_some", - "clippy::short_circuit_statement", - "clippy::single_element_loop", - "clippy::skip_while_next", - "clippy::string_from_utf8_as_bytes", - "clippy::strlen_on_c_strings", - "clippy::temporary_assignment", - "clippy::too_many_arguments", - "clippy::transmute_bytes_to_str", - "clippy::transmute_float_to_int", - "clippy::transmute_int_to_bool", - "clippy::transmute_int_to_char", - "clippy::transmute_int_to_float", - "clippy::transmute_num_to_bytes", - "clippy::transmute_ptr_to_ref", - "clippy::transmutes_expressible_as_ptr_casts", - "clippy::type_complexity", - "clippy::unit_arg", - "clippy::unnecessary_cast", - "clippy::unnecessary_filter_map", - "clippy::unnecessary_operation", - "clippy::unnecessary_sort_by", - "clippy::unnecessary_unwrap", - "clippy::unneeded_wildcard_pattern", - "clippy::useless_asref", - "clippy::useless_conversion", - "clippy::useless_format", - "clippy::vec_box", - "clippy::while_let_loop", - "clippy::wildcard_in_or_patterns", - "clippy::zero_divided_by_zero", - "clippy::zero_prefixed_literal", - ], - }, - LintGroup { - lint: Lint { - label: "clippy::correctness", - description: r##"lint group for: clippy::absurd_extreme_comparisons, clippy::almost_swapped, clippy::approx_constant, clippy::async_yields_async, clippy::bad_bit_mask, clippy::cast_ref_to_mut, clippy::clone_double_ref, clippy::cmp_nan, clippy::deprecated_semver, clippy::derive_hash_xor_eq, clippy::derive_ord_xor_partial_ord, clippy::drop_copy, clippy::drop_ref, clippy::enum_clike_unportable_variant, clippy::eq_op, clippy::erasing_op, clippy::fn_address_comparisons, clippy::forget_copy, clippy::forget_ref, clippy::if_let_mutex, clippy::if_same_then_else, clippy::ifs_same_cond, clippy::ineffective_bit_mask, clippy::infinite_iter, clippy::inherent_to_string_shadow_display, clippy::inline_fn_without_body, clippy::invalid_null_ptr_usage, clippy::invalid_regex, clippy::invisible_characters, clippy::iter_next_loop, clippy::iterator_step_by_zero, clippy::let_underscore_lock, clippy::logic_bug, clippy::match_str_case_mismatch, clippy::mem_replace_with_uninit, clippy::min_max, clippy::mismatched_target_os, clippy::mistyped_literal_suffixes, clippy::modulo_one, clippy::mut_from_ref, clippy::never_loop, clippy::non_octal_unix_permissions, clippy::nonsensical_open_options, clippy::not_unsafe_ptr_arg_deref, clippy::option_env_unwrap, clippy::out_of_bounds_indexing, clippy::panicking_unwrap, clippy::possible_missing_comma, clippy::reversed_empty_ranges, clippy::self_assignment, clippy::serde_api_misuse, clippy::size_of_in_element_count, clippy::suspicious_splitn, clippy::to_string_in_display, clippy::transmuting_null, clippy::undropped_manually_drops, clippy::uninit_assumed_init, clippy::uninit_vec, clippy::unit_cmp, clippy::unit_hash, clippy::unit_return_expecting_ord, clippy::unsound_collection_transmute, clippy::unused_io_amount, clippy::useless_attribute, clippy::vec_resize_to_zero, clippy::vtable_address_comparisons, clippy::while_immutable_condition, clippy::wrong_transmute, clippy::zst_offset"##, - }, - children: &[ - "clippy::absurd_extreme_comparisons", - "clippy::almost_swapped", - "clippy::approx_constant", - "clippy::async_yields_async", - "clippy::bad_bit_mask", - "clippy::cast_ref_to_mut", - "clippy::clone_double_ref", - "clippy::cmp_nan", - "clippy::deprecated_semver", - "clippy::derive_hash_xor_eq", - "clippy::derive_ord_xor_partial_ord", - "clippy::drop_copy", - "clippy::drop_ref", - "clippy::enum_clike_unportable_variant", - "clippy::eq_op", - "clippy::erasing_op", - "clippy::fn_address_comparisons", - "clippy::forget_copy", - "clippy::forget_ref", - "clippy::if_let_mutex", - "clippy::if_same_then_else", - "clippy::ifs_same_cond", - "clippy::ineffective_bit_mask", - "clippy::infinite_iter", - "clippy::inherent_to_string_shadow_display", - "clippy::inline_fn_without_body", - "clippy::invalid_null_ptr_usage", - "clippy::invalid_regex", - "clippy::invisible_characters", - "clippy::iter_next_loop", - "clippy::iterator_step_by_zero", - "clippy::let_underscore_lock", - "clippy::logic_bug", - "clippy::match_str_case_mismatch", - "clippy::mem_replace_with_uninit", - "clippy::min_max", - "clippy::mismatched_target_os", - "clippy::mistyped_literal_suffixes", - "clippy::modulo_one", - "clippy::mut_from_ref", - "clippy::never_loop", - "clippy::non_octal_unix_permissions", - "clippy::nonsensical_open_options", - "clippy::not_unsafe_ptr_arg_deref", - "clippy::option_env_unwrap", - "clippy::out_of_bounds_indexing", - "clippy::panicking_unwrap", - "clippy::possible_missing_comma", - "clippy::reversed_empty_ranges", - "clippy::self_assignment", - "clippy::serde_api_misuse", - "clippy::size_of_in_element_count", - "clippy::suspicious_splitn", - "clippy::to_string_in_display", - "clippy::transmuting_null", - "clippy::undropped_manually_drops", - "clippy::uninit_assumed_init", - "clippy::uninit_vec", - "clippy::unit_cmp", - "clippy::unit_hash", - "clippy::unit_return_expecting_ord", - "clippy::unsound_collection_transmute", - "clippy::unused_io_amount", - "clippy::useless_attribute", - "clippy::vec_resize_to_zero", - "clippy::vtable_address_comparisons", - "clippy::while_immutable_condition", - "clippy::wrong_transmute", - "clippy::zst_offset", - ], - }, - LintGroup { - lint: Lint { - label: "clippy::deprecated", - description: r##"lint group for: clippy::assign_ops, clippy::extend_from_slice, clippy::filter_map, clippy::find_map, clippy::if_let_redundant_pattern_matching, clippy::misaligned_transmute, clippy::pub_enum_variant_names, clippy::range_step_by_zero, clippy::regex_macro, clippy::replace_consts, clippy::should_assert_eq, clippy::unsafe_vector_initialization, clippy::unstable_as_mut_slice, clippy::unstable_as_slice, clippy::unused_collect, clippy::wrong_pub_self_convention"##, - }, - children: &[ - "clippy::assign_ops", - "clippy::extend_from_slice", - "clippy::filter_map", - "clippy::find_map", - "clippy::if_let_redundant_pattern_matching", - "clippy::misaligned_transmute", - "clippy::pub_enum_variant_names", - "clippy::range_step_by_zero", - "clippy::regex_macro", - "clippy::replace_consts", - "clippy::should_assert_eq", - "clippy::unsafe_vector_initialization", - "clippy::unstable_as_mut_slice", - "clippy::unstable_as_slice", - "clippy::unused_collect", - "clippy::wrong_pub_self_convention", - ], - }, - LintGroup { - lint: Lint { - label: "clippy::nursery", - description: r##"lint group for: clippy::branches_sharing_code, clippy::cognitive_complexity, clippy::debug_assert_with_mut_call, clippy::disallowed_methods, clippy::disallowed_types, clippy::empty_line_after_outer_attr, clippy::equatable_if_let, clippy::fallible_impl_from, clippy::future_not_send, clippy::imprecise_flops, clippy::index_refutable_slice, clippy::missing_const_for_fn, clippy::mutex_integer, clippy::non_send_fields_in_send_ty, clippy::nonstandard_macro_braces, clippy::option_if_let_else, clippy::path_buf_push_overwrite, clippy::redundant_pub_crate, clippy::string_lit_as_bytes, clippy::suboptimal_flops, clippy::suspicious_operation_groupings, clippy::trailing_empty_array, clippy::trivial_regex, clippy::use_self, clippy::useless_let_if_seq, clippy::useless_transmute"##, - }, - children: &[ - "clippy::branches_sharing_code", - "clippy::cognitive_complexity", - "clippy::debug_assert_with_mut_call", - "clippy::disallowed_methods", - "clippy::disallowed_types", - "clippy::empty_line_after_outer_attr", - "clippy::equatable_if_let", - "clippy::fallible_impl_from", - "clippy::future_not_send", - "clippy::imprecise_flops", - "clippy::index_refutable_slice", - "clippy::missing_const_for_fn", - "clippy::mutex_integer", - "clippy::non_send_fields_in_send_ty", - "clippy::nonstandard_macro_braces", - "clippy::option_if_let_else", - "clippy::path_buf_push_overwrite", - "clippy::redundant_pub_crate", - "clippy::string_lit_as_bytes", - "clippy::suboptimal_flops", - "clippy::suspicious_operation_groupings", - "clippy::trailing_empty_array", - "clippy::trivial_regex", - "clippy::use_self", - "clippy::useless_let_if_seq", - "clippy::useless_transmute", - ], - }, - LintGroup { - lint: Lint { - label: "clippy::pedantic", - description: r##"lint group for: clippy::await_holding_lock, clippy::await_holding_refcell_ref, clippy::case_sensitive_file_extension_comparisons, clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_ptr_alignment, clippy::cast_sign_loss, clippy::checked_conversions, clippy::cloned_instead_of_copied, clippy::copy_iterator, clippy::default_trait_access, clippy::doc_markdown, clippy::empty_enum, clippy::enum_glob_use, clippy::expl_impl_clone_on_copy, clippy::explicit_deref_methods, clippy::explicit_into_iter_loop, clippy::explicit_iter_loop, clippy::filter_map_next, clippy::flat_map_option, clippy::float_cmp, clippy::fn_params_excessive_bools, clippy::from_iter_instead_of_collect, clippy::if_not_else, clippy::implicit_clone, clippy::implicit_hasher, clippy::implicit_saturating_sub, clippy::inconsistent_struct_constructor, clippy::inefficient_to_string, clippy::inline_always, clippy::invalid_upcast_comparisons, clippy::items_after_statements, clippy::iter_not_returning_iterator, clippy::large_digit_groups, clippy::large_stack_arrays, clippy::large_types_passed_by_value, clippy::let_underscore_drop, clippy::let_unit_value, clippy::linkedlist, clippy::macro_use_imports, clippy::manual_assert, clippy::manual_ok_or, clippy::many_single_char_names, clippy::map_unwrap_or, clippy::match_bool, clippy::match_on_vec_items, clippy::match_same_arms, clippy::match_wild_err_arm, clippy::match_wildcard_for_single_variants, clippy::maybe_infinite_iter, clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::mut_mut, clippy::naive_bytecount, clippy::needless_bitwise_bool, clippy::needless_continue, clippy::needless_for_each, clippy::needless_pass_by_value, clippy::no_effect_underscore_binding, clippy::option_option, clippy::ptr_as_ptr, clippy::range_minus_one, clippy::range_plus_one, clippy::redundant_closure_for_method_calls, clippy::redundant_else, clippy::ref_binding_to_reference, clippy::ref_option_ref, clippy::same_functions_in_if_condition, clippy::semicolon_if_nothing_returned, clippy::similar_names, clippy::single_match_else, clippy::string_add_assign, clippy::struct_excessive_bools, clippy::too_many_lines, clippy::trait_duplication_in_bounds, clippy::transmute_ptr_to_ptr, clippy::trivially_copy_pass_by_ref, clippy::type_repetition_in_bounds, clippy::unicode_not_nfc, clippy::unnecessary_wraps, clippy::unnested_or_patterns, clippy::unreadable_literal, clippy::unsafe_derive_deserialize, clippy::unused_async, clippy::unused_self, clippy::used_underscore_binding, clippy::verbose_bit_mask, clippy::wildcard_imports, clippy::zero_sized_map_values"##, - }, - children: &[ - "clippy::await_holding_lock", - "clippy::await_holding_refcell_ref", - "clippy::case_sensitive_file_extension_comparisons", - "clippy::cast_lossless", - "clippy::cast_possible_truncation", - "clippy::cast_possible_wrap", - "clippy::cast_precision_loss", - "clippy::cast_ptr_alignment", - "clippy::cast_sign_loss", - "clippy::checked_conversions", - "clippy::cloned_instead_of_copied", - "clippy::copy_iterator", - "clippy::default_trait_access", - "clippy::doc_markdown", - "clippy::empty_enum", - "clippy::enum_glob_use", - "clippy::expl_impl_clone_on_copy", - "clippy::explicit_deref_methods", - "clippy::explicit_into_iter_loop", - "clippy::explicit_iter_loop", - "clippy::filter_map_next", - "clippy::flat_map_option", - "clippy::float_cmp", - "clippy::fn_params_excessive_bools", - "clippy::from_iter_instead_of_collect", - "clippy::if_not_else", - "clippy::implicit_clone", - "clippy::implicit_hasher", - "clippy::implicit_saturating_sub", - "clippy::inconsistent_struct_constructor", - "clippy::inefficient_to_string", - "clippy::inline_always", - "clippy::invalid_upcast_comparisons", - "clippy::items_after_statements", - "clippy::iter_not_returning_iterator", - "clippy::large_digit_groups", - "clippy::large_stack_arrays", - "clippy::large_types_passed_by_value", - "clippy::let_underscore_drop", - "clippy::let_unit_value", - "clippy::linkedlist", - "clippy::macro_use_imports", - "clippy::manual_assert", - "clippy::manual_ok_or", - "clippy::many_single_char_names", - "clippy::map_unwrap_or", - "clippy::match_bool", - "clippy::match_on_vec_items", - "clippy::match_same_arms", - "clippy::match_wild_err_arm", - "clippy::match_wildcard_for_single_variants", - "clippy::maybe_infinite_iter", - "clippy::missing_errors_doc", - "clippy::missing_panics_doc", - "clippy::module_name_repetitions", - "clippy::must_use_candidate", - "clippy::mut_mut", - "clippy::naive_bytecount", - "clippy::needless_bitwise_bool", - "clippy::needless_continue", - "clippy::needless_for_each", - "clippy::needless_pass_by_value", - "clippy::no_effect_underscore_binding", - "clippy::option_option", - "clippy::ptr_as_ptr", - "clippy::range_minus_one", - "clippy::range_plus_one", - "clippy::redundant_closure_for_method_calls", - "clippy::redundant_else", - "clippy::ref_binding_to_reference", - "clippy::ref_option_ref", - "clippy::same_functions_in_if_condition", - "clippy::semicolon_if_nothing_returned", - "clippy::similar_names", - "clippy::single_match_else", - "clippy::string_add_assign", - "clippy::struct_excessive_bools", - "clippy::too_many_lines", - "clippy::trait_duplication_in_bounds", - "clippy::transmute_ptr_to_ptr", - "clippy::trivially_copy_pass_by_ref", - "clippy::type_repetition_in_bounds", - "clippy::unicode_not_nfc", - "clippy::unnecessary_wraps", - "clippy::unnested_or_patterns", - "clippy::unreadable_literal", - "clippy::unsafe_derive_deserialize", - "clippy::unused_async", - "clippy::unused_self", - "clippy::used_underscore_binding", - "clippy::verbose_bit_mask", - "clippy::wildcard_imports", - "clippy::zero_sized_map_values", - ], - }, - LintGroup { - lint: Lint { - label: "clippy::perf", - description: r##"lint group for: clippy::box_collection, clippy::boxed_local, clippy::cmp_owned, clippy::expect_fun_call, clippy::extend_with_drain, clippy::format_in_format_args, clippy::iter_nth, clippy::large_const_arrays, clippy::large_enum_variant, clippy::manual_memcpy, clippy::manual_str_repeat, clippy::map_entry, clippy::mutex_atomic, clippy::needless_collect, clippy::or_fun_call, clippy::redundant_allocation, clippy::redundant_clone, clippy::single_char_pattern, clippy::slow_vector_initialization, clippy::stable_sort_primitive, clippy::to_string_in_format_args, clippy::unnecessary_to_owned, clippy::useless_vec, clippy::vec_init_then_push"##, - }, - children: &[ - "clippy::box_collection", - "clippy::boxed_local", - "clippy::cmp_owned", - "clippy::expect_fun_call", - "clippy::extend_with_drain", - "clippy::format_in_format_args", - "clippy::iter_nth", - "clippy::large_const_arrays", - "clippy::large_enum_variant", - "clippy::manual_memcpy", - "clippy::manual_str_repeat", - "clippy::map_entry", - "clippy::mutex_atomic", - "clippy::needless_collect", - "clippy::or_fun_call", - "clippy::redundant_allocation", - "clippy::redundant_clone", - "clippy::single_char_pattern", - "clippy::slow_vector_initialization", - "clippy::stable_sort_primitive", - "clippy::to_string_in_format_args", - "clippy::unnecessary_to_owned", - "clippy::useless_vec", - "clippy::vec_init_then_push", - ], - }, - LintGroup { - lint: Lint { - label: "clippy::restriction", - description: r##"lint group for: clippy::as_conversions, clippy::clone_on_ref_ptr, clippy::create_dir, clippy::dbg_macro, clippy::decimal_literal_representation, clippy::default_numeric_fallback, clippy::disallowed_script_idents, clippy::else_if_without_else, clippy::exhaustive_enums, clippy::exhaustive_structs, clippy::exit, clippy::expect_used, clippy::filetype_is_file, clippy::float_arithmetic, clippy::float_cmp_const, clippy::fn_to_numeric_cast_any, clippy::get_unwrap, clippy::if_then_some_else_none, clippy::implicit_return, clippy::indexing_slicing, clippy::inline_asm_x86_att_syntax, clippy::inline_asm_x86_intel_syntax, clippy::integer_arithmetic, clippy::integer_division, clippy::let_underscore_must_use, clippy::lossy_float_literal, clippy::map_err_ignore, clippy::mem_forget, clippy::missing_docs_in_private_items, clippy::missing_enforced_import_renames, clippy::missing_inline_in_public_items, clippy::mod_module_files, clippy::modulo_arithmetic, clippy::multiple_inherent_impl, clippy::non_ascii_literal, clippy::panic, clippy::panic_in_result_fn, clippy::pattern_type_mismatch, clippy::print_stderr, clippy::print_stdout, clippy::rc_buffer, clippy::rc_mutex, clippy::rest_pat_in_fully_bound_structs, clippy::same_name_method, clippy::self_named_module_files, clippy::separated_literal_suffix, clippy::shadow_reuse, clippy::shadow_same, clippy::shadow_unrelated, clippy::str_to_string, clippy::string_add, clippy::string_slice, clippy::string_to_string, clippy::todo, clippy::undocumented_unsafe_blocks, clippy::unimplemented, clippy::unnecessary_self_imports, clippy::unneeded_field_pattern, clippy::unreachable, clippy::unseparated_literal_suffix, clippy::unwrap_in_result, clippy::unwrap_used, clippy::use_debug, clippy::verbose_file_reads, clippy::wildcard_enum_match_arm"##, - }, - children: &[ - "clippy::as_conversions", - "clippy::clone_on_ref_ptr", - "clippy::create_dir", - "clippy::dbg_macro", - "clippy::decimal_literal_representation", - "clippy::default_numeric_fallback", - "clippy::disallowed_script_idents", - "clippy::else_if_without_else", - "clippy::exhaustive_enums", - "clippy::exhaustive_structs", - "clippy::exit", - "clippy::expect_used", - "clippy::filetype_is_file", - "clippy::float_arithmetic", - "clippy::float_cmp_const", - "clippy::fn_to_numeric_cast_any", - "clippy::get_unwrap", - "clippy::if_then_some_else_none", - "clippy::implicit_return", - "clippy::indexing_slicing", - "clippy::inline_asm_x86_att_syntax", - "clippy::inline_asm_x86_intel_syntax", - "clippy::integer_arithmetic", - "clippy::integer_division", - "clippy::let_underscore_must_use", - "clippy::lossy_float_literal", - "clippy::map_err_ignore", - "clippy::mem_forget", - "clippy::missing_docs_in_private_items", - "clippy::missing_enforced_import_renames", - "clippy::missing_inline_in_public_items", - "clippy::mod_module_files", - "clippy::modulo_arithmetic", - "clippy::multiple_inherent_impl", - "clippy::non_ascii_literal", - "clippy::panic", - "clippy::panic_in_result_fn", - "clippy::pattern_type_mismatch", - "clippy::print_stderr", - "clippy::print_stdout", - "clippy::rc_buffer", - "clippy::rc_mutex", - "clippy::rest_pat_in_fully_bound_structs", - "clippy::same_name_method", - "clippy::self_named_module_files", - "clippy::separated_literal_suffix", - "clippy::shadow_reuse", - "clippy::shadow_same", - "clippy::shadow_unrelated", - "clippy::str_to_string", - "clippy::string_add", - "clippy::string_slice", - "clippy::string_to_string", - "clippy::todo", - "clippy::undocumented_unsafe_blocks", - "clippy::unimplemented", - "clippy::unnecessary_self_imports", - "clippy::unneeded_field_pattern", - "clippy::unreachable", - "clippy::unseparated_literal_suffix", - "clippy::unwrap_in_result", - "clippy::unwrap_used", - "clippy::use_debug", - "clippy::verbose_file_reads", - "clippy::wildcard_enum_match_arm", - ], - }, - LintGroup { - lint: Lint { - label: "clippy::style", - description: r##"lint group for: clippy::assertions_on_constants, clippy::assign_op_pattern, clippy::blacklisted_name, clippy::blocks_in_if_conditions, clippy::bool_assert_comparison, clippy::borrow_interior_mutable_const, clippy::builtin_type_shadow, clippy::bytes_nth, clippy::chars_last_cmp, clippy::chars_next_cmp, clippy::cmp_null, clippy::collapsible_else_if, clippy::collapsible_if, clippy::collapsible_match, clippy::comparison_chain, clippy::comparison_to_empty, clippy::declare_interior_mutable_const, clippy::double_must_use, clippy::double_neg, clippy::duplicate_underscore_argument, clippy::enum_variant_names, clippy::excessive_precision, clippy::field_reassign_with_default, clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation, clippy::for_kv_map, clippy::from_over_into, clippy::from_str_radix_10, clippy::inconsistent_digit_grouping, clippy::infallible_destructuring_match, clippy::inherent_to_string, clippy::into_iter_on_ref, clippy::iter_cloned_collect, clippy::iter_next_slice, clippy::iter_nth_zero, clippy::iter_skip_next, clippy::just_underscores_and_digits, clippy::len_without_is_empty, clippy::len_zero, clippy::let_and_return, clippy::main_recursion, clippy::manual_async_fn, clippy::manual_map, clippy::manual_non_exhaustive, clippy::manual_range_contains, clippy::manual_saturating_arithmetic, clippy::map_clone, clippy::map_collect_result_unit, clippy::match_like_matches_macro, clippy::match_overlapping_arm, clippy::match_ref_pats, clippy::match_result_ok, clippy::mem_replace_option_with_none, clippy::mem_replace_with_default, clippy::missing_safety_doc, clippy::mixed_case_hex_literals, clippy::module_inception, clippy::must_use_unit, clippy::mut_mutex_lock, clippy::needless_borrow, clippy::needless_doctest_main, clippy::needless_late_init, clippy::needless_range_loop, clippy::needless_return, clippy::neg_multiply, clippy::new_ret_no_self, clippy::new_without_default, clippy::ok_expect, clippy::op_ref, clippy::option_map_or_none, clippy::print_literal, clippy::print_with_newline, clippy::println_empty_string, clippy::ptr_arg, clippy::ptr_eq, clippy::question_mark, clippy::redundant_closure, clippy::redundant_field_names, clippy::redundant_pattern, clippy::redundant_pattern_matching, clippy::redundant_static_lifetimes, clippy::result_map_or_into_option, clippy::result_unit_err, clippy::same_item_push, clippy::self_named_constructors, clippy::should_implement_trait, clippy::single_char_add_str, clippy::single_component_path_imports, clippy::single_match, clippy::string_extend_chars, clippy::tabs_in_doc_comments, clippy::to_digit_is_some, clippy::toplevel_ref_arg, clippy::try_err, clippy::unnecessary_fold, clippy::unnecessary_lazy_evaluations, clippy::unnecessary_mut_passed, clippy::unsafe_removed_from_name, clippy::unused_unit, clippy::unusual_byte_groupings, clippy::unwrap_or_else_default, clippy::upper_case_acronyms, clippy::while_let_on_iterator, clippy::write_literal, clippy::write_with_newline, clippy::writeln_empty_string, clippy::wrong_self_convention, clippy::zero_ptr"##, - }, - children: &[ - "clippy::assertions_on_constants", - "clippy::assign_op_pattern", - "clippy::blacklisted_name", - "clippy::blocks_in_if_conditions", - "clippy::bool_assert_comparison", - "clippy::borrow_interior_mutable_const", - "clippy::builtin_type_shadow", - "clippy::bytes_nth", - "clippy::chars_last_cmp", - "clippy::chars_next_cmp", - "clippy::cmp_null", - "clippy::collapsible_else_if", - "clippy::collapsible_if", - "clippy::collapsible_match", - "clippy::comparison_chain", - "clippy::comparison_to_empty", - "clippy::declare_interior_mutable_const", - "clippy::double_must_use", - "clippy::double_neg", - "clippy::duplicate_underscore_argument", - "clippy::enum_variant_names", - "clippy::excessive_precision", - "clippy::field_reassign_with_default", - "clippy::fn_to_numeric_cast", - "clippy::fn_to_numeric_cast_with_truncation", - "clippy::for_kv_map", - "clippy::from_over_into", - "clippy::from_str_radix_10", - "clippy::inconsistent_digit_grouping", - "clippy::infallible_destructuring_match", - "clippy::inherent_to_string", - "clippy::into_iter_on_ref", - "clippy::iter_cloned_collect", - "clippy::iter_next_slice", - "clippy::iter_nth_zero", - "clippy::iter_skip_next", - "clippy::just_underscores_and_digits", - "clippy::len_without_is_empty", - "clippy::len_zero", - "clippy::let_and_return", - "clippy::main_recursion", - "clippy::manual_async_fn", - "clippy::manual_map", - "clippy::manual_non_exhaustive", - "clippy::manual_range_contains", - "clippy::manual_saturating_arithmetic", - "clippy::map_clone", - "clippy::map_collect_result_unit", - "clippy::match_like_matches_macro", - "clippy::match_overlapping_arm", - "clippy::match_ref_pats", - "clippy::match_result_ok", - "clippy::mem_replace_option_with_none", - "clippy::mem_replace_with_default", - "clippy::missing_safety_doc", - "clippy::mixed_case_hex_literals", - "clippy::module_inception", - "clippy::must_use_unit", - "clippy::mut_mutex_lock", - "clippy::needless_borrow", - "clippy::needless_doctest_main", - "clippy::needless_late_init", - "clippy::needless_range_loop", - "clippy::needless_return", - "clippy::neg_multiply", - "clippy::new_ret_no_self", - "clippy::new_without_default", - "clippy::ok_expect", - "clippy::op_ref", - "clippy::option_map_or_none", - "clippy::print_literal", - "clippy::print_with_newline", - "clippy::println_empty_string", - "clippy::ptr_arg", - "clippy::ptr_eq", - "clippy::question_mark", - "clippy::redundant_closure", - "clippy::redundant_field_names", - "clippy::redundant_pattern", - "clippy::redundant_pattern_matching", - "clippy::redundant_static_lifetimes", - "clippy::result_map_or_into_option", - "clippy::result_unit_err", - "clippy::same_item_push", - "clippy::self_named_constructors", - "clippy::should_implement_trait", - "clippy::single_char_add_str", - "clippy::single_component_path_imports", - "clippy::single_match", - "clippy::string_extend_chars", - "clippy::tabs_in_doc_comments", - "clippy::to_digit_is_some", - "clippy::toplevel_ref_arg", - "clippy::try_err", - "clippy::unnecessary_fold", - "clippy::unnecessary_lazy_evaluations", - "clippy::unnecessary_mut_passed", - "clippy::unsafe_removed_from_name", - "clippy::unused_unit", - "clippy::unusual_byte_groupings", - "clippy::unwrap_or_else_default", - "clippy::upper_case_acronyms", - "clippy::while_let_on_iterator", - "clippy::write_literal", - "clippy::write_with_newline", - "clippy::writeln_empty_string", - "clippy::wrong_self_convention", - "clippy::zero_ptr", - ], - }, - LintGroup { - lint: Lint { - label: "clippy::suspicious", - description: r##"lint group for: clippy::blanket_clippy_restriction_lints, clippy::empty_loop, clippy::eval_order_dependence, clippy::float_equality_without_abs, clippy::for_loops_over_fallibles, clippy::misrefactored_assign_op, clippy::mut_range_bound, clippy::mutable_key_type, clippy::octal_escapes, clippy::return_self_not_must_use, clippy::suspicious_arithmetic_impl, clippy::suspicious_assignment_formatting, clippy::suspicious_else_formatting, clippy::suspicious_map, clippy::suspicious_op_assign_impl, clippy::suspicious_unary_op_formatting"##, - }, - children: &[ - "clippy::blanket_clippy_restriction_lints", - "clippy::empty_loop", - "clippy::eval_order_dependence", - "clippy::float_equality_without_abs", - "clippy::for_loops_over_fallibles", - "clippy::misrefactored_assign_op", - "clippy::mut_range_bound", - "clippy::mutable_key_type", - "clippy::octal_escapes", - "clippy::return_self_not_must_use", - "clippy::suspicious_arithmetic_impl", - "clippy::suspicious_assignment_formatting", - "clippy::suspicious_else_formatting", - "clippy::suspicious_map", - "clippy::suspicious_op_assign_impl", - "clippy::suspicious_unary_op_formatting", - ], - }, -]; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs deleted file mode 100644 index 6e56efe344d72..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! Random assortment of ide helpers for high-level ide features that don't fit in any other module. - -use std::collections::VecDeque; - -use base_db::FileId; -use hir::{ItemInNs, ModuleDef, Name, Semantics}; -use syntax::{ - ast::{self, make}, - AstToken, SyntaxKind, SyntaxToken, TokenAtOffset, -}; - -use crate::{defs::Definition, generated, RootDatabase}; - -pub fn item_name(db: &RootDatabase, item: ItemInNs) -> Option { - match item { - ItemInNs::Types(module_def_id) => module_def_id.name(db), - ItemInNs::Values(module_def_id) => module_def_id.name(db), - ItemInNs::Macros(macro_def_id) => Some(macro_def_id.name(db)), - } -} - -/// Picks the token with the highest rank returned by the passed in function. -pub fn pick_best_token( - tokens: TokenAtOffset, - f: impl Fn(SyntaxKind) -> usize, -) -> Option { - tokens.max_by_key(move |t| f(t.kind())) -} -pub fn pick_token(mut tokens: TokenAtOffset) -> Option { - tokens.find_map(T::cast) -} - -/// Converts the mod path struct into its ast representation. -pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path { - let _p = profile::span("mod_path_to_ast"); - - let mut segments = Vec::new(); - let mut is_abs = false; - match path.kind { - hir::PathKind::Plain => {} - hir::PathKind::Super(0) => segments.push(make::path_segment_self()), - hir::PathKind::Super(n) => segments.extend((0..n).map(|_| make::path_segment_super())), - hir::PathKind::DollarCrate(_) | hir::PathKind::Crate => { - segments.push(make::path_segment_crate()) - } - hir::PathKind::Abs => is_abs = true, - } - - segments.extend( - path.segments() - .iter() - .map(|segment| make::path_segment(make::name_ref(&segment.to_smol_str()))), - ); - make::path_from_segments(segments, is_abs) -} - -/// Iterates all `ModuleDef`s and `Impl` blocks of the given file. -pub fn visit_file_defs( - sema: &Semantics<'_, RootDatabase>, - file_id: FileId, - cb: &mut dyn FnMut(Definition), -) { - let db = sema.db; - let module = match sema.to_module_def(file_id) { - Some(it) => it, - None => return, - }; - let mut defs: VecDeque<_> = module.declarations(db).into(); - while let Some(def) = defs.pop_front() { - if let ModuleDef::Module(submodule) = def { - if let hir::ModuleSource::Module(_) = submodule.definition_source(db).value { - defs.extend(submodule.declarations(db)); - submodule.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into())); - } - } - cb(def.into()); - } - module.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into())); - - let is_root = module.is_crate_root(db); - module - .legacy_macros(db) - .into_iter() - // don't show legacy macros declared in the crate-root that were already covered in declarations earlier - .filter(|it| !(is_root && it.is_macro_export(db))) - .for_each(|mac| cb(mac.into())); -} - -/// Checks if the given lint is equal or is contained by the other lint which may or may not be a group. -pub fn lint_eq_or_in_group(lint: &str, lint_is: &str) -> bool { - if lint == lint_is { - return true; - } - - if let Some(group) = generated::lints::DEFAULT_LINT_GROUPS - .iter() - .chain(generated::lints::CLIPPY_LINT_GROUPS.iter()) - .chain(generated::lints::RUSTDOC_LINT_GROUPS.iter()) - .find(|&check| check.lint.label == lint_is) - { - group.children.contains(&lint) - } else { - false - } -} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs deleted file mode 100644 index 26ef86155e534..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs +++ /dev/null @@ -1,674 +0,0 @@ -//! Look up accessible paths for items. -use hir::{ - AsAssocItem, AssocItem, AssocItemContainer, Crate, ItemInNs, ModPath, Module, ModuleDef, - PathResolution, PrefixKind, ScopeDef, Semantics, SemanticsScope, Type, -}; -use itertools::Itertools; -use rustc_hash::FxHashSet; -use syntax::{ - ast::{self, HasName}, - utils::path_to_string_stripping_turbo_fish, - AstNode, SyntaxNode, -}; - -use crate::{ - helpers::item_name, - items_locator::{self, AssocItemSearch, DEFAULT_QUERY_SEARCH_LIMIT}, - RootDatabase, -}; - -/// A candidate for import, derived during various IDE activities: -/// * completion with imports on the fly proposals -/// * completion edit resolve requests -/// * assists -/// * etc. -#[derive(Debug)] -pub enum ImportCandidate { - /// A path, qualified (`std::collections::HashMap`) or not (`HashMap`). - Path(PathImportCandidate), - /// A trait associated function (with no self parameter) or an associated constant. - /// For 'test_mod::TestEnum::test_function', `ty` is the `test_mod::TestEnum` expression type - /// and `name` is the `test_function` - TraitAssocItem(TraitImportCandidate), - /// A trait method with self parameter. - /// For 'test_enum.test_method()', `ty` is the `test_enum` expression type - /// and `name` is the `test_method` - TraitMethod(TraitImportCandidate), -} - -/// A trait import needed for a given associated item access. -/// For `some::path::SomeStruct::ASSOC_`, contains the -/// type of `some::path::SomeStruct` and `ASSOC_` as the item name. -#[derive(Debug)] -pub struct TraitImportCandidate { - /// A type of the item that has the associated item accessed at. - pub receiver_ty: Type, - /// The associated item name that the trait to import should contain. - pub assoc_item_name: NameToImport, -} - -/// Path import for a given name, qualified or not. -#[derive(Debug)] -pub struct PathImportCandidate { - /// Optional qualifier before name. - pub qualifier: Option, - /// The name the item (struct, trait, enum, etc.) should have. - pub name: NameToImport, -} - -/// A qualifier that has a first segment and it's unresolved. -#[derive(Debug)] -pub struct FirstSegmentUnresolved { - fist_segment: ast::NameRef, - full_qualifier: ast::Path, -} - -/// A name that will be used during item lookups. -#[derive(Debug, Clone)] -pub enum NameToImport { - /// Requires items with names that exactly match the given string, bool indicates case-sensitivity. - Exact(String, bool), - /// Requires items with names that case-insensitively contain all letters from the string, - /// in the same order, but not necessary adjacent. - Fuzzy(String), -} - -impl NameToImport { - pub fn exact_case_sensitive(s: String) -> NameToImport { - NameToImport::Exact(s, true) - } -} - -impl NameToImport { - pub fn text(&self) -> &str { - match self { - NameToImport::Exact(text, _) => text.as_str(), - NameToImport::Fuzzy(text) => text.as_str(), - } - } -} - -/// A struct to find imports in the project, given a certain name (or its part) and the context. -#[derive(Debug)] -pub struct ImportAssets { - import_candidate: ImportCandidate, - candidate_node: SyntaxNode, - module_with_candidate: Module, -} - -impl ImportAssets { - pub fn for_method_call( - method_call: &ast::MethodCallExpr, - sema: &Semantics<'_, RootDatabase>, - ) -> Option { - let candidate_node = method_call.syntax().clone(); - Some(Self { - import_candidate: ImportCandidate::for_method_call(sema, method_call)?, - module_with_candidate: sema.scope(&candidate_node)?.module(), - candidate_node, - }) - } - - pub fn for_exact_path( - fully_qualified_path: &ast::Path, - sema: &Semantics<'_, RootDatabase>, - ) -> Option { - let candidate_node = fully_qualified_path.syntax().clone(); - if let Some(use_tree) = candidate_node.ancestors().find_map(ast::UseTree::cast) { - // Path is inside a use tree, then only continue if it is the first segment of a use statement. - if use_tree.syntax().parent().and_then(ast::Use::cast).is_none() - || fully_qualified_path.qualifier().is_some() - { - return None; - } - } - Some(Self { - import_candidate: ImportCandidate::for_regular_path(sema, fully_qualified_path)?, - module_with_candidate: sema.scope(&candidate_node)?.module(), - candidate_node, - }) - } - - pub fn for_ident_pat(sema: &Semantics<'_, RootDatabase>, pat: &ast::IdentPat) -> Option { - if !pat.is_simple_ident() { - return None; - } - let name = pat.name()?; - let candidate_node = pat.syntax().clone(); - Some(Self { - import_candidate: ImportCandidate::for_name(sema, &name)?, - module_with_candidate: sema.scope(&candidate_node)?.module(), - candidate_node, - }) - } - - pub fn for_fuzzy_path( - module_with_candidate: Module, - qualifier: Option, - fuzzy_name: String, - sema: &Semantics<'_, RootDatabase>, - candidate_node: SyntaxNode, - ) -> Option { - Some(Self { - import_candidate: ImportCandidate::for_fuzzy_path(qualifier, fuzzy_name, sema)?, - module_with_candidate, - candidate_node, - }) - } - - pub fn for_fuzzy_method_call( - module_with_method_call: Module, - receiver_ty: Type, - fuzzy_method_name: String, - candidate_node: SyntaxNode, - ) -> Option { - Some(Self { - import_candidate: ImportCandidate::TraitMethod(TraitImportCandidate { - receiver_ty, - assoc_item_name: NameToImport::Fuzzy(fuzzy_method_name), - }), - module_with_candidate: module_with_method_call, - candidate_node, - }) - } -} - -/// An import (not necessary the only one) that corresponds a certain given [`PathImportCandidate`]. -/// (the structure is not entirely correct, since there can be situations requiring two imports, see FIXME below for the details) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct LocatedImport { - /// The path to use in the `use` statement for a given candidate to be imported. - pub import_path: ModPath, - /// An item that will be imported with the import path given. - pub item_to_import: ItemInNs, - /// The path import candidate, resolved. - /// - /// Not necessary matches the import: - /// For any associated constant from the trait, we try to access as `some::path::SomeStruct::ASSOC_` - /// the original item is the associated constant, but the import has to be a trait that - /// defines this constant. - pub original_item: ItemInNs, - /// A path of the original item. - pub original_path: Option, -} - -impl LocatedImport { - pub fn new( - import_path: ModPath, - item_to_import: ItemInNs, - original_item: ItemInNs, - original_path: Option, - ) -> Self { - Self { import_path, item_to_import, original_item, original_path } - } -} - -impl ImportAssets { - pub fn import_candidate(&self) -> &ImportCandidate { - &self.import_candidate - } - - pub fn search_for_imports( - &self, - sema: &Semantics<'_, RootDatabase>, - prefix_kind: PrefixKind, - ) -> Vec { - let _p = profile::span("import_assets::search_for_imports"); - self.search_for(sema, Some(prefix_kind)) - } - - /// This may return non-absolute paths if a part of the returned path is already imported into scope. - pub fn search_for_relative_paths( - &self, - sema: &Semantics<'_, RootDatabase>, - ) -> Vec { - let _p = profile::span("import_assets::search_for_relative_paths"); - self.search_for(sema, None) - } - - pub fn path_fuzzy_name_to_exact(&mut self, case_sensitive: bool) { - if let ImportCandidate::Path(PathImportCandidate { name: to_import, .. }) = - &mut self.import_candidate - { - let name = match to_import { - NameToImport::Fuzzy(name) => std::mem::take(name), - _ => return, - }; - *to_import = NameToImport::Exact(name, case_sensitive); - } - } - - fn search_for( - &self, - sema: &Semantics<'_, RootDatabase>, - prefixed: Option, - ) -> Vec { - let _p = profile::span("import_assets::search_for"); - - let scope_definitions = self.scope_definitions(sema); - let mod_path = |item| { - get_mod_path( - sema.db, - item_for_path_search(sema.db, item)?, - &self.module_with_candidate, - prefixed, - ) - }; - - let krate = self.module_with_candidate.krate(); - let scope = match sema.scope(&self.candidate_node) { - Some(it) => it, - None => return Vec::new(), - }; - - match &self.import_candidate { - ImportCandidate::Path(path_candidate) => { - path_applicable_imports(sema, krate, path_candidate, mod_path) - } - ImportCandidate::TraitAssocItem(trait_candidate) => { - trait_applicable_items(sema, krate, &scope, trait_candidate, true, mod_path) - } - ImportCandidate::TraitMethod(trait_candidate) => { - trait_applicable_items(sema, krate, &scope, trait_candidate, false, mod_path) - } - } - .into_iter() - .filter(|import| import.import_path.len() > 1) - .filter(|import| !scope_definitions.contains(&ScopeDef::from(import.item_to_import))) - .sorted_by(|a, b| a.import_path.cmp(&b.import_path)) - .collect() - } - - fn scope_definitions(&self, sema: &Semantics<'_, RootDatabase>) -> FxHashSet { - let _p = profile::span("import_assets::scope_definitions"); - let mut scope_definitions = FxHashSet::default(); - if let Some(scope) = sema.scope(&self.candidate_node) { - scope.process_all_names(&mut |_, scope_def| { - scope_definitions.insert(scope_def); - }); - } - scope_definitions - } -} - -fn path_applicable_imports( - sema: &Semantics<'_, RootDatabase>, - current_crate: Crate, - path_candidate: &PathImportCandidate, - mod_path: impl Fn(ItemInNs) -> Option + Copy, -) -> FxHashSet { - let _p = profile::span("import_assets::path_applicable_imports"); - - match &path_candidate.qualifier { - None => { - items_locator::items_with_name( - sema, - current_crate, - path_candidate.name.clone(), - // FIXME: we could look up assoc items by the input and propose those in completion, - // but that requires more preparation first: - // * store non-trait assoc items in import_map to fully enable this lookup - // * ensure that does not degrade the performance (benchmark it) - // * write more logic to check for corresponding trait presence requirement (we're unable to flyimport multiple item right now) - // * improve the associated completion item matching and/or scoring to ensure no noisy completions appear - // - // see also an ignored test under FIXME comment in the qualify_path.rs module - AssocItemSearch::Exclude, - Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()), - ) - .filter_map(|item| { - let mod_path = mod_path(item)?; - Some(LocatedImport::new(mod_path.clone(), item, item, Some(mod_path))) - }) - .collect() - } - Some(first_segment_unresolved) => { - let unresolved_qualifier = - path_to_string_stripping_turbo_fish(&first_segment_unresolved.full_qualifier); - let unresolved_first_segment = first_segment_unresolved.fist_segment.text(); - items_locator::items_with_name( - sema, - current_crate, - path_candidate.name.clone(), - AssocItemSearch::Include, - Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()), - ) - .filter_map(|item| { - import_for_item( - sema.db, - mod_path, - &unresolved_first_segment, - &unresolved_qualifier, - item, - ) - }) - .collect() - } - } -} - -fn import_for_item( - db: &RootDatabase, - mod_path: impl Fn(ItemInNs) -> Option, - unresolved_first_segment: &str, - unresolved_qualifier: &str, - original_item: ItemInNs, -) -> Option { - let _p = profile::span("import_assets::import_for_item"); - - let original_item_candidate = item_for_path_search(db, original_item)?; - let import_path_candidate = mod_path(original_item_candidate)?; - let import_path_string = import_path_candidate.to_string(); - - let expected_import_end = if item_as_assoc(db, original_item).is_some() { - unresolved_qualifier.to_string() - } else { - format!("{}::{}", unresolved_qualifier, item_name(db, original_item)?) - }; - if !import_path_string.contains(unresolved_first_segment) - || !import_path_string.ends_with(&expected_import_end) - { - return None; - } - - let segment_import = - find_import_for_segment(db, original_item_candidate, unresolved_first_segment)?; - let trait_item_to_import = item_as_assoc(db, original_item) - .and_then(|assoc| assoc.containing_trait(db)) - .map(|trait_| ItemInNs::from(ModuleDef::from(trait_))); - Some(match (segment_import == original_item_candidate, trait_item_to_import) { - (true, Some(_)) => { - // FIXME we should be able to import both the trait and the segment, - // but it's unclear what to do with overlapping edits (merge imports?) - // especially in case of lazy completion edit resolutions. - return None; - } - (false, Some(trait_to_import)) => LocatedImport::new( - mod_path(trait_to_import)?, - trait_to_import, - original_item, - mod_path(original_item), - ), - (true, None) => LocatedImport::new( - import_path_candidate, - original_item_candidate, - original_item, - mod_path(original_item), - ), - (false, None) => LocatedImport::new( - mod_path(segment_import)?, - segment_import, - original_item, - mod_path(original_item), - ), - }) -} - -pub fn item_for_path_search(db: &RootDatabase, item: ItemInNs) -> Option { - Some(match item { - ItemInNs::Types(_) | ItemInNs::Values(_) => match item_as_assoc(db, item) { - Some(assoc_item) => match assoc_item.container(db) { - AssocItemContainer::Trait(trait_) => ItemInNs::from(ModuleDef::from(trait_)), - AssocItemContainer::Impl(impl_) => { - ItemInNs::from(ModuleDef::from(impl_.self_ty(db).as_adt()?)) - } - }, - None => item, - }, - ItemInNs::Macros(_) => item, - }) -} - -fn find_import_for_segment( - db: &RootDatabase, - original_item: ItemInNs, - unresolved_first_segment: &str, -) -> Option { - let segment_is_name = item_name(db, original_item) - .map(|name| name.to_smol_str() == unresolved_first_segment) - .unwrap_or(false); - - Some(if segment_is_name { - original_item - } else { - let matching_module = - module_with_segment_name(db, unresolved_first_segment, original_item)?; - ItemInNs::from(ModuleDef::from(matching_module)) - }) -} - -fn module_with_segment_name( - db: &RootDatabase, - segment_name: &str, - candidate: ItemInNs, -) -> Option { - let mut current_module = match candidate { - ItemInNs::Types(module_def_id) => module_def_id.module(db), - ItemInNs::Values(module_def_id) => module_def_id.module(db), - ItemInNs::Macros(macro_def_id) => ModuleDef::from(macro_def_id).module(db), - }; - while let Some(module) = current_module { - if let Some(module_name) = module.name(db) { - if module_name.to_smol_str() == segment_name { - return Some(module); - } - } - current_module = module.parent(db); - } - None -} - -fn trait_applicable_items( - sema: &Semantics<'_, RootDatabase>, - current_crate: Crate, - scope: &SemanticsScope<'_>, - trait_candidate: &TraitImportCandidate, - trait_assoc_item: bool, - mod_path: impl Fn(ItemInNs) -> Option, -) -> FxHashSet { - let _p = profile::span("import_assets::trait_applicable_items"); - - let db = sema.db; - - let inherent_traits = trait_candidate.receiver_ty.applicable_inherent_traits(db); - let env_traits = trait_candidate.receiver_ty.env_traits(db); - let related_traits = inherent_traits.chain(env_traits).collect::>(); - - let mut required_assoc_items = FxHashSet::default(); - let trait_candidates = items_locator::items_with_name( - sema, - current_crate, - trait_candidate.assoc_item_name.clone(), - AssocItemSearch::AssocItemsOnly, - Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()), - ) - .filter_map(|input| item_as_assoc(db, input)) - .filter_map(|assoc| { - let assoc_item_trait = assoc.containing_trait(db)?; - if related_traits.contains(&assoc_item_trait) { - None - } else { - required_assoc_items.insert(assoc); - Some(assoc_item_trait.into()) - } - }) - .collect(); - - let mut located_imports = FxHashSet::default(); - - if trait_assoc_item { - trait_candidate.receiver_ty.iterate_path_candidates( - db, - scope, - &trait_candidates, - None, - None, - |assoc| { - if required_assoc_items.contains(&assoc) { - if let AssocItem::Function(f) = assoc { - if f.self_param(db).is_some() { - return None; - } - } - let located_trait = assoc.containing_trait(db)?; - let trait_item = ItemInNs::from(ModuleDef::from(located_trait)); - let original_item = assoc_to_item(assoc); - located_imports.insert(LocatedImport::new( - mod_path(trait_item)?, - trait_item, - original_item, - mod_path(original_item), - )); - } - None::<()> - }, - ) - } else { - trait_candidate.receiver_ty.iterate_method_candidates( - db, - scope, - &trait_candidates, - None, - None, - |function| { - let assoc = function.as_assoc_item(db)?; - if required_assoc_items.contains(&assoc) { - let located_trait = assoc.containing_trait(db)?; - let trait_item = ItemInNs::from(ModuleDef::from(located_trait)); - let original_item = assoc_to_item(assoc); - located_imports.insert(LocatedImport::new( - mod_path(trait_item)?, - trait_item, - original_item, - mod_path(original_item), - )); - } - None::<()> - }, - ) - }; - - located_imports -} - -fn assoc_to_item(assoc: AssocItem) -> ItemInNs { - match assoc { - AssocItem::Function(f) => ItemInNs::from(ModuleDef::from(f)), - AssocItem::Const(c) => ItemInNs::from(ModuleDef::from(c)), - AssocItem::TypeAlias(t) => ItemInNs::from(ModuleDef::from(t)), - } -} - -fn get_mod_path( - db: &RootDatabase, - item_to_search: ItemInNs, - module_with_candidate: &Module, - prefixed: Option, -) -> Option { - if let Some(prefix_kind) = prefixed { - module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind) - } else { - module_with_candidate.find_use_path(db, item_to_search) - } -} - -impl ImportCandidate { - fn for_method_call( - sema: &Semantics<'_, RootDatabase>, - method_call: &ast::MethodCallExpr, - ) -> Option { - match sema.resolve_method_call(method_call) { - Some(_) => None, - None => Some(Self::TraitMethod(TraitImportCandidate { - receiver_ty: sema.type_of_expr(&method_call.receiver()?)?.adjusted(), - assoc_item_name: NameToImport::exact_case_sensitive( - method_call.name_ref()?.to_string(), - ), - })), - } - } - - fn for_regular_path(sema: &Semantics<'_, RootDatabase>, path: &ast::Path) -> Option { - if sema.resolve_path(path).is_some() { - return None; - } - path_import_candidate( - sema, - path.qualifier(), - NameToImport::exact_case_sensitive(path.segment()?.name_ref()?.to_string()), - ) - } - - fn for_name(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option { - if sema - .scope(name.syntax())? - .speculative_resolve(&ast::make::ext::ident_path(&name.text())) - .is_some() - { - return None; - } - Some(ImportCandidate::Path(PathImportCandidate { - qualifier: None, - name: NameToImport::exact_case_sensitive(name.to_string()), - })) - } - - fn for_fuzzy_path( - qualifier: Option, - fuzzy_name: String, - sema: &Semantics<'_, RootDatabase>, - ) -> Option { - path_import_candidate(sema, qualifier, NameToImport::Fuzzy(fuzzy_name)) - } -} - -fn path_import_candidate( - sema: &Semantics<'_, RootDatabase>, - qualifier: Option, - name: NameToImport, -) -> Option { - Some(match qualifier { - Some(qualifier) => match sema.resolve_path(&qualifier) { - None => { - let qualifier_start = - qualifier.syntax().descendants().find_map(ast::NameRef::cast)?; - let qualifier_start_path = - qualifier_start.syntax().ancestors().find_map(ast::Path::cast)?; - if sema.resolve_path(&qualifier_start_path).is_none() { - ImportCandidate::Path(PathImportCandidate { - qualifier: Some(FirstSegmentUnresolved { - fist_segment: qualifier_start, - full_qualifier: qualifier, - }), - name, - }) - } else { - return None; - } - } - Some(PathResolution::Def(ModuleDef::Adt(assoc_item_path))) => { - ImportCandidate::TraitAssocItem(TraitImportCandidate { - receiver_ty: assoc_item_path.ty(sema.db), - assoc_item_name: name, - }) - } - Some(PathResolution::Def(ModuleDef::TypeAlias(alias))) => { - let ty = alias.ty(sema.db); - if ty.as_adt().is_some() { - ImportCandidate::TraitAssocItem(TraitImportCandidate { - receiver_ty: ty, - assoc_item_name: name, - }) - } else { - return None; - } - } - Some(_) => return None, - }, - None => ImportCandidate::Path(PathImportCandidate { qualifier: None, name }), - }) -} - -fn item_as_assoc(db: &RootDatabase, item: ItemInNs) -> Option { - item.as_module_def().and_then(|module_def| module_def.as_assoc_item(db)) -} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs deleted file mode 100644 index c14182279d05e..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs +++ /dev/null @@ -1,446 +0,0 @@ -//! Handle syntactic aspects of inserting a new `use` item. -#[cfg(test)] -mod tests; - -use std::cmp::Ordering; - -use hir::Semantics; -use syntax::{ - algo, - ast::{self, make, AstNode, HasAttrs, HasModuleItem, HasVisibility, PathSegmentKind}, - ted, Direction, NodeOrToken, SyntaxKind, SyntaxNode, -}; - -use crate::{ - imports::merge_imports::{ - common_prefix, eq_attrs, eq_visibility, try_merge_imports, use_tree_path_cmp, MergeBehavior, - }, - RootDatabase, -}; - -pub use hir::PrefixKind; - -/// How imports should be grouped into use statements. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum ImportGranularity { - /// Do not change the granularity of any imports and preserve the original structure written by the developer. - Preserve, - /// Merge imports from the same crate into a single use statement. - Crate, - /// Merge imports from the same module into a single use statement. - Module, - /// Flatten imports so that each has its own use statement. - Item, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct InsertUseConfig { - pub granularity: ImportGranularity, - pub enforce_granularity: bool, - pub prefix_kind: PrefixKind, - pub group: bool, - pub skip_glob_imports: bool, -} - -#[derive(Debug, Clone)] -pub enum ImportScope { - File(ast::SourceFile), - Module(ast::ItemList), - Block(ast::StmtList), -} - -impl ImportScope { - // FIXME: Remove this? - #[cfg(test)] - fn from(syntax: SyntaxNode) -> Option { - use syntax::match_ast; - fn contains_cfg_attr(attrs: &dyn HasAttrs) -> bool { - attrs - .attrs() - .any(|attr| attr.as_simple_call().map_or(false, |(ident, _)| ident == "cfg")) - } - match_ast! { - match syntax { - ast::Module(module) => module.item_list().map(ImportScope::Module), - ast::SourceFile(file) => Some(ImportScope::File(file)), - ast::Fn(func) => contains_cfg_attr(&func).then(|| func.body().and_then(|it| it.stmt_list().map(ImportScope::Block))).flatten(), - ast::Const(konst) => contains_cfg_attr(&konst).then(|| match konst.body()? { - ast::Expr::BlockExpr(block) => Some(block), - _ => None, - }).flatten().and_then(|it| it.stmt_list().map(ImportScope::Block)), - ast::Static(statik) => contains_cfg_attr(&statik).then(|| match statik.body()? { - ast::Expr::BlockExpr(block) => Some(block), - _ => None, - }).flatten().and_then(|it| it.stmt_list().map(ImportScope::Block)), - _ => None, - - } - } - } - - /// Determines the containing syntax node in which to insert a `use` statement affecting `position`. - /// Returns the original source node inside attributes. - pub fn find_insert_use_container( - position: &SyntaxNode, - sema: &Semantics<'_, RootDatabase>, - ) -> Option { - fn contains_cfg_attr(attrs: &dyn HasAttrs) -> bool { - attrs - .attrs() - .any(|attr| attr.as_simple_call().map_or(false, |(ident, _)| ident == "cfg")) - } - - // Walk up the ancestor tree searching for a suitable node to do insertions on - // with special handling on cfg-gated items, in which case we want to insert imports locally - // or FIXME: annotate inserted imports with the same cfg - for syntax in sema.ancestors_with_macros(position.clone()) { - if let Some(file) = ast::SourceFile::cast(syntax.clone()) { - return Some(ImportScope::File(file)); - } else if let Some(item) = ast::Item::cast(syntax) { - return match item { - ast::Item::Const(konst) if contains_cfg_attr(&konst) => { - // FIXME: Instead of bailing out with None, we should note down that - // this import needs an attribute added - match sema.original_ast_node(konst)?.body()? { - ast::Expr::BlockExpr(block) => block, - _ => return None, - } - .stmt_list() - .map(ImportScope::Block) - } - ast::Item::Fn(func) if contains_cfg_attr(&func) => { - // FIXME: Instead of bailing out with None, we should note down that - // this import needs an attribute added - sema.original_ast_node(func)?.body()?.stmt_list().map(ImportScope::Block) - } - ast::Item::Static(statik) if contains_cfg_attr(&statik) => { - // FIXME: Instead of bailing out with None, we should note down that - // this import needs an attribute added - match sema.original_ast_node(statik)?.body()? { - ast::Expr::BlockExpr(block) => block, - _ => return None, - } - .stmt_list() - .map(ImportScope::Block) - } - ast::Item::Module(module) => { - // early return is important here, if we can't find the original module - // in the input there is no way for us to insert an import anywhere. - sema.original_ast_node(module)?.item_list().map(ImportScope::Module) - } - _ => continue, - }; - } - } - None - } - - pub fn as_syntax_node(&self) -> &SyntaxNode { - match self { - ImportScope::File(file) => file.syntax(), - ImportScope::Module(item_list) => item_list.syntax(), - ImportScope::Block(block) => block.syntax(), - } - } - - pub fn clone_for_update(&self) -> Self { - match self { - ImportScope::File(file) => ImportScope::File(file.clone_for_update()), - ImportScope::Module(item_list) => ImportScope::Module(item_list.clone_for_update()), - ImportScope::Block(block) => ImportScope::Block(block.clone_for_update()), - } - } -} - -/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. -pub fn insert_use(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) { - let _p = profile::span("insert_use"); - let mut mb = match cfg.granularity { - ImportGranularity::Crate => Some(MergeBehavior::Crate), - ImportGranularity::Module => Some(MergeBehavior::Module), - ImportGranularity::Item | ImportGranularity::Preserve => None, - }; - if !cfg.enforce_granularity { - let file_granularity = guess_granularity_from_scope(scope); - mb = match file_granularity { - ImportGranularityGuess::Unknown => mb, - ImportGranularityGuess::Item => None, - ImportGranularityGuess::Module => Some(MergeBehavior::Module), - ImportGranularityGuess::ModuleOrItem => mb.and(Some(MergeBehavior::Module)), - ImportGranularityGuess::Crate => Some(MergeBehavior::Crate), - ImportGranularityGuess::CrateOrModule => mb.or(Some(MergeBehavior::Crate)), - }; - } - - let use_item = - make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update(); - // merge into existing imports if possible - if let Some(mb) = mb { - let filter = |it: &_| !(cfg.skip_glob_imports && ast::Use::is_simple_glob(it)); - for existing_use in - scope.as_syntax_node().children().filter_map(ast::Use::cast).filter(filter) - { - if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) { - ted::replace(existing_use.syntax(), merged.syntax()); - return; - } - } - } - - // either we weren't allowed to merge or there is no import that fits the merge conditions - // so look for the place we have to insert to - insert_use_(scope, &path, cfg.group, use_item); -} - -pub fn remove_path_if_in_use_stmt(path: &ast::Path) { - // FIXME: improve this - if path.parent_path().is_some() { - return; - } - if let Some(use_tree) = path.syntax().parent().and_then(ast::UseTree::cast) { - if use_tree.use_tree_list().is_some() || use_tree.star_token().is_some() { - return; - } - if let Some(use_) = use_tree.syntax().parent().and_then(ast::Use::cast) { - use_.remove(); - return; - } - use_tree.remove(); - } -} - -#[derive(Eq, PartialEq, PartialOrd, Ord)] -enum ImportGroup { - // the order here defines the order of new group inserts - Std, - ExternCrate, - ThisCrate, - ThisModule, - SuperModule, -} - -impl ImportGroup { - fn new(path: &ast::Path) -> ImportGroup { - let default = ImportGroup::ExternCrate; - - let first_segment = match path.first_segment() { - Some(it) => it, - None => return default, - }; - - let kind = first_segment.kind().unwrap_or(PathSegmentKind::SelfKw); - match kind { - PathSegmentKind::SelfKw => ImportGroup::ThisModule, - PathSegmentKind::SuperKw => ImportGroup::SuperModule, - PathSegmentKind::CrateKw => ImportGroup::ThisCrate, - PathSegmentKind::Name(name) => match name.text().as_str() { - "std" => ImportGroup::Std, - "core" => ImportGroup::Std, - _ => ImportGroup::ExternCrate, - }, - // these aren't valid use paths, so fall back to something random - PathSegmentKind::SelfTypeKw => ImportGroup::ExternCrate, - PathSegmentKind::Type { .. } => ImportGroup::ExternCrate, - } - } -} - -#[derive(PartialEq, PartialOrd, Debug, Clone, Copy)] -enum ImportGranularityGuess { - Unknown, - Item, - Module, - ModuleOrItem, - Crate, - CrateOrModule, -} - -fn guess_granularity_from_scope(scope: &ImportScope) -> ImportGranularityGuess { - // The idea is simple, just check each import as well as the import and its precedent together for - // whether they fulfill a granularity criteria. - let use_stmt = |item| match item { - ast::Item::Use(use_) => { - let use_tree = use_.use_tree()?; - Some((use_tree, use_.visibility(), use_.attrs())) - } - _ => None, - }; - let mut use_stmts = match scope { - ImportScope::File(f) => f.items(), - ImportScope::Module(m) => m.items(), - ImportScope::Block(b) => b.items(), - } - .filter_map(use_stmt); - let mut res = ImportGranularityGuess::Unknown; - let (mut prev, mut prev_vis, mut prev_attrs) = match use_stmts.next() { - Some(it) => it, - None => return res, - }; - loop { - if let Some(use_tree_list) = prev.use_tree_list() { - if use_tree_list.use_trees().any(|tree| tree.use_tree_list().is_some()) { - // Nested tree lists can only occur in crate style, or with no proper style being enforced in the file. - break ImportGranularityGuess::Crate; - } else { - // Could still be crate-style so continue looking. - res = ImportGranularityGuess::CrateOrModule; - } - } - - let (curr, curr_vis, curr_attrs) = match use_stmts.next() { - Some(it) => it, - None => break res, - }; - if eq_visibility(prev_vis, curr_vis.clone()) && eq_attrs(prev_attrs, curr_attrs.clone()) { - if let Some((prev_path, curr_path)) = prev.path().zip(curr.path()) { - if let Some((prev_prefix, _)) = common_prefix(&prev_path, &curr_path) { - if prev.use_tree_list().is_none() && curr.use_tree_list().is_none() { - let prefix_c = prev_prefix.qualifiers().count(); - let curr_c = curr_path.qualifiers().count() - prefix_c; - let prev_c = prev_path.qualifiers().count() - prefix_c; - if curr_c == 1 && prev_c == 1 { - // Same prefix, only differing in the last segment and no use tree lists so this has to be of item style. - break ImportGranularityGuess::Item; - } else { - // Same prefix and no use tree list but differs in more than one segment at the end. This might be module style still. - res = ImportGranularityGuess::ModuleOrItem; - } - } else { - // Same prefix with item tree lists, has to be module style as it - // can't be crate style since the trees wouldn't share a prefix then. - break ImportGranularityGuess::Module; - } - } - } - } - prev = curr; - prev_vis = curr_vis; - prev_attrs = curr_attrs; - } -} - -fn insert_use_( - scope: &ImportScope, - insert_path: &ast::Path, - group_imports: bool, - use_item: ast::Use, -) { - let scope_syntax = scope.as_syntax_node(); - let group = ImportGroup::new(insert_path); - let path_node_iter = scope_syntax - .children() - .filter_map(|node| ast::Use::cast(node.clone()).zip(Some(node))) - .flat_map(|(use_, node)| { - let tree = use_.use_tree()?; - let path = tree.path()?; - let has_tl = tree.use_tree_list().is_some(); - Some((path, has_tl, node)) - }); - - if group_imports { - // Iterator that discards anything thats not in the required grouping - // This implementation allows the user to rearrange their import groups as this only takes the first group that fits - let group_iter = path_node_iter - .clone() - .skip_while(|(path, ..)| ImportGroup::new(path) != group) - .take_while(|(path, ..)| ImportGroup::new(path) == group); - - // track the last element we iterated over, if this is still None after the iteration then that means we never iterated in the first place - let mut last = None; - // find the element that would come directly after our new import - let post_insert: Option<(_, _, SyntaxNode)> = group_iter - .inspect(|(.., node)| last = Some(node.clone())) - .find(|&(ref path, has_tl, _)| { - use_tree_path_cmp(insert_path, false, path, has_tl) != Ordering::Greater - }); - - if let Some((.., node)) = post_insert { - cov_mark::hit!(insert_group); - // insert our import before that element - return ted::insert(ted::Position::before(node), use_item.syntax()); - } - if let Some(node) = last { - cov_mark::hit!(insert_group_last); - // there is no element after our new import, so append it to the end of the group - return ted::insert(ted::Position::after(node), use_item.syntax()); - } - - // the group we were looking for actually doesn't exist, so insert - - let mut last = None; - // find the group that comes after where we want to insert - let post_group = path_node_iter - .inspect(|(.., node)| last = Some(node.clone())) - .find(|(p, ..)| ImportGroup::new(p) > group); - if let Some((.., node)) = post_group { - cov_mark::hit!(insert_group_new_group); - ted::insert(ted::Position::before(&node), use_item.syntax()); - if let Some(node) = algo::non_trivia_sibling(node.into(), Direction::Prev) { - ted::insert(ted::Position::after(node), make::tokens::single_newline()); - } - return; - } - // there is no such group, so append after the last one - if let Some(node) = last { - cov_mark::hit!(insert_group_no_group); - ted::insert(ted::Position::after(&node), use_item.syntax()); - ted::insert(ted::Position::after(node), make::tokens::single_newline()); - return; - } - } else { - // There exists a group, so append to the end of it - if let Some((_, _, node)) = path_node_iter.last() { - cov_mark::hit!(insert_no_grouping_last); - ted::insert(ted::Position::after(node), use_item.syntax()); - return; - } - } - - let l_curly = match scope { - ImportScope::File(_) => None, - // don't insert the imports before the item list/block expr's opening curly brace - ImportScope::Module(item_list) => item_list.l_curly_token(), - // don't insert the imports before the item list's opening curly brace - ImportScope::Block(block) => block.l_curly_token(), - }; - // there are no imports in this file at all - // so put the import after all inner module attributes and possible license header comments - if let Some(last_inner_element) = scope_syntax - .children_with_tokens() - // skip the curly brace - .skip(l_curly.is_some() as usize) - .take_while(|child| match child { - NodeOrToken::Node(node) => is_inner_attribute(node.clone()), - NodeOrToken::Token(token) => { - [SyntaxKind::WHITESPACE, SyntaxKind::COMMENT, SyntaxKind::SHEBANG] - .contains(&token.kind()) - } - }) - .filter(|child| child.as_token().map_or(true, |t| t.kind() != SyntaxKind::WHITESPACE)) - .last() - { - cov_mark::hit!(insert_empty_inner_attr); - ted::insert(ted::Position::after(&last_inner_element), use_item.syntax()); - ted::insert(ted::Position::after(last_inner_element), make::tokens::single_newline()); - } else { - match l_curly { - Some(b) => { - cov_mark::hit!(insert_empty_module); - ted::insert(ted::Position::after(&b), make::tokens::single_newline()); - ted::insert(ted::Position::after(&b), use_item.syntax()); - } - None => { - cov_mark::hit!(insert_empty_file); - ted::insert( - ted::Position::first_child_of(scope_syntax), - make::tokens::blank_line(), - ); - ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax()); - } - } - } -} - -fn is_inner_attribute(node: SyntaxNode) -> bool { - ast::Attr::cast(node).map(|attr| attr.kind()) == Some(ast::AttrKind::Inner) -} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs deleted file mode 100644 index 59673af3204e6..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs +++ /dev/null @@ -1,1084 +0,0 @@ -use base_db::fixture::WithFixture; -use hir::PrefixKind; -use stdx::trim_indent; -use test_utils::{assert_eq_text, CURSOR_MARKER}; - -use super::*; - -#[test] -fn trailing_comment_in_empty_file() { - check( - "foo::bar", - r#" -struct Struct; -// 0 = 1 -"#, - r#" -use foo::bar; - -struct Struct; -// 0 = 1 -"#, - ImportGranularity::Crate, - ); -} - -#[test] -fn respects_cfg_attr_fn() { - check( - r"bar::Bar", - r#" -#[cfg(test)] -fn foo() {$0} -"#, - r#" -#[cfg(test)] -fn foo() { - use bar::Bar; -} -"#, - ImportGranularity::Crate, - ); -} - -#[test] -fn respects_cfg_attr_const() { - check( - r"bar::Bar", - r#" -#[cfg(test)] -const FOO: Bar = {$0}; -"#, - r#" -#[cfg(test)] -const FOO: Bar = { - use bar::Bar; -}; -"#, - ImportGranularity::Crate, - ); -} - -#[test] -fn insert_skips_lone_glob_imports() { - check( - "use foo::baz::A", - r" -use foo::bar::*; -", - r" -use foo::bar::*; -use foo::baz::A; -", - ImportGranularity::Crate, - ); -} - -#[test] -fn insert_not_group() { - cov_mark::check!(insert_no_grouping_last); - check_with_config( - "use external_crate2::bar::A", - r" -use std::bar::B; -use external_crate::bar::A; -use crate::bar::A; -use self::bar::A; -use super::bar::A;", - r" -use std::bar::B; -use external_crate::bar::A; -use crate::bar::A; -use self::bar::A; -use super::bar::A; -use external_crate2::bar::A;", - &InsertUseConfig { - granularity: ImportGranularity::Item, - enforce_granularity: true, - prefix_kind: PrefixKind::Plain, - group: false, - skip_glob_imports: true, - }, - ); -} - -#[test] -fn insert_existing() { - check_crate("std::fs", "use std::fs;", "use std::fs;") -} - -#[test] -fn insert_start() { - check_none( - "std::bar::AA", - r" -use std::bar::B; -use std::bar::D; -use std::bar::F; -use std::bar::G;", - r" -use std::bar::AA; -use std::bar::B; -use std::bar::D; -use std::bar::F; -use std::bar::G;", - ) -} - -#[test] -fn insert_start_indent() { - check_none( - "std::bar::AA", - r" - use std::bar::B; - use std::bar::C;", - r" - use std::bar::AA; - use std::bar::B; - use std::bar::C;", - ); -} - -#[test] -fn insert_middle() { - cov_mark::check!(insert_group); - check_none( - "std::bar::EE", - r" -use std::bar::A; -use std::bar::D; -use std::bar::F; -use std::bar::G;", - r" -use std::bar::A; -use std::bar::D; -use std::bar::EE; -use std::bar::F; -use std::bar::G;", - ) -} - -#[test] -fn insert_middle_indent() { - check_none( - "std::bar::EE", - r" - use std::bar::A; - use std::bar::D; - use std::bar::F; - use std::bar::G;", - r" - use std::bar::A; - use std::bar::D; - use std::bar::EE; - use std::bar::F; - use std::bar::G;", - ) -} - -#[test] -fn insert_end() { - cov_mark::check!(insert_group_last); - check_none( - "std::bar::ZZ", - r" -use std::bar::A; -use std::bar::D; -use std::bar::F; -use std::bar::G;", - r" -use std::bar::A; -use std::bar::D; -use std::bar::F; -use std::bar::G; -use std::bar::ZZ;", - ) -} - -#[test] -fn insert_end_indent() { - check_none( - "std::bar::ZZ", - r" - use std::bar::A; - use std::bar::D; - use std::bar::F; - use std::bar::G;", - r" - use std::bar::A; - use std::bar::D; - use std::bar::F; - use std::bar::G; - use std::bar::ZZ;", - ) -} - -#[test] -fn insert_middle_nested() { - check_none( - "std::bar::EE", - r" -use std::bar::A; -use std::bar::{D, Z}; // example of weird imports due to user -use std::bar::F; -use std::bar::G;", - r" -use std::bar::A; -use std::bar::EE; -use std::bar::{D, Z}; // example of weird imports due to user -use std::bar::F; -use std::bar::G;", - ) -} - -#[test] -fn insert_middle_groups() { - check_none( - "foo::bar::GG", - r" - use std::bar::A; - use std::bar::D; - - use foo::bar::F; - use foo::bar::H;", - r" - use std::bar::A; - use std::bar::D; - - use foo::bar::F; - use foo::bar::GG; - use foo::bar::H;", - ) -} - -#[test] -fn insert_first_matching_group() { - check_none( - "foo::bar::GG", - r" - use foo::bar::A; - use foo::bar::D; - - use std; - - use foo::bar::F; - use foo::bar::H;", - r" - use foo::bar::A; - use foo::bar::D; - use foo::bar::GG; - - use std; - - use foo::bar::F; - use foo::bar::H;", - ) -} - -#[test] -fn insert_missing_group_std() { - cov_mark::check!(insert_group_new_group); - check_none( - "std::fmt", - r" - use foo::bar::A; - use foo::bar::D;", - r" - use std::fmt; - - use foo::bar::A; - use foo::bar::D;", - ) -} - -#[test] -fn insert_missing_group_self() { - cov_mark::check!(insert_group_no_group); - check_none( - "self::fmt", - r" -use foo::bar::A; -use foo::bar::D;", - r" -use foo::bar::A; -use foo::bar::D; - -use self::fmt;", - ) -} - -#[test] -fn insert_no_imports() { - check_crate( - "foo::bar", - "fn main() {}", - r"use foo::bar; - -fn main() {}", - ) -} - -#[test] -fn insert_empty_file() { - cov_mark::check_count!(insert_empty_file, 2); - - // Default configuration - // empty files will get two trailing newlines - // this is due to the test case insert_no_imports above - check_crate( - "foo::bar", - "", - r"use foo::bar; - -", - ); - - // "not group" configuration - check_with_config( - "use external_crate2::bar::A", - r"", - r"use external_crate2::bar::A; - -", - &InsertUseConfig { - granularity: ImportGranularity::Item, - enforce_granularity: true, - prefix_kind: PrefixKind::Plain, - group: false, - skip_glob_imports: true, - }, - ); -} - -#[test] -fn insert_empty_module() { - cov_mark::check_count!(insert_empty_module, 2); - - // Default configuration - check( - "foo::bar", - r" -mod x {$0} -", - r" -mod x { - use foo::bar; -} -", - ImportGranularity::Item, - ); - - // "not group" configuration - check_with_config( - "foo::bar", - r"mod x {$0}", - r"mod x { - use foo::bar; -}", - &InsertUseConfig { - granularity: ImportGranularity::Item, - enforce_granularity: true, - prefix_kind: PrefixKind::Plain, - group: false, - skip_glob_imports: true, - }, - ); -} - -#[test] -fn insert_after_inner_attr() { - cov_mark::check_count!(insert_empty_inner_attr, 2); - - // Default configuration - check_crate( - "foo::bar", - r"#![allow(unused_imports)]", - r"#![allow(unused_imports)] - -use foo::bar;", - ); - - // "not group" configuration - check_with_config( - "foo::bar", - r"#![allow(unused_imports)]", - r"#![allow(unused_imports)] - -use foo::bar;", - &InsertUseConfig { - granularity: ImportGranularity::Item, - enforce_granularity: true, - prefix_kind: PrefixKind::Plain, - group: false, - skip_glob_imports: true, - }, - ); -} - -#[test] -fn insert_after_inner_attr2() { - check_crate( - "foo::bar", - r"#![allow(unused_imports)] - -#![no_std] -fn main() {}", - r"#![allow(unused_imports)] - -#![no_std] - -use foo::bar; -fn main() {}", - ); -} - -#[test] -fn inserts_after_single_line_inner_comments() { - check_none( - "foo::bar::Baz", - "//! Single line inner comments do not allow any code before them.", - r#"//! Single line inner comments do not allow any code before them. - -use foo::bar::Baz;"#, - ); - check_none( - "foo::bar::Baz", - r"mod foo { - //! Single line inner comments do not allow any code before them. -$0 -}", - r"mod foo { - //! Single line inner comments do not allow any code before them. - - use foo::bar::Baz; - -}", - ); -} - -#[test] -fn inserts_after_single_line_comments() { - check_none( - "foo::bar::Baz", - "// Represents a possible license header and/or general module comments", - r#"// Represents a possible license header and/or general module comments - -use foo::bar::Baz;"#, - ); -} - -#[test] -fn inserts_after_shebang() { - check_none( - "foo::bar::Baz", - "#!/usr/bin/env rust", - r#"#!/usr/bin/env rust - -use foo::bar::Baz;"#, - ); -} - -#[test] -fn inserts_after_multiple_single_line_comments() { - check_none( - "foo::bar::Baz", - "// Represents a possible license header and/or general module comments -// Second single-line comment -// Third single-line comment", - r#"// Represents a possible license header and/or general module comments -// Second single-line comment -// Third single-line comment - -use foo::bar::Baz;"#, - ); -} - -#[test] -fn inserts_before_single_line_item_comments() { - check_none( - "foo::bar::Baz", - r#"// Represents a comment about a function -fn foo() {}"#, - r#"use foo::bar::Baz; - -// Represents a comment about a function -fn foo() {}"#, - ); -} - -#[test] -fn inserts_after_single_line_header_comments_and_before_item() { - check_none( - "foo::bar::Baz", - r#"// Represents a possible license header -// Line two of possible license header - -fn foo() {}"#, - r#"// Represents a possible license header -// Line two of possible license header - -use foo::bar::Baz; - -fn foo() {}"#, - ); -} - -#[test] -fn inserts_after_multiline_inner_comments() { - check_none( - "foo::bar::Baz", - r#"/*! Multiline inner comments do not allow any code before them. */ - -/*! Still an inner comment, cannot place any code before. */ -fn main() {}"#, - r#"/*! Multiline inner comments do not allow any code before them. */ - -/*! Still an inner comment, cannot place any code before. */ - -use foo::bar::Baz; -fn main() {}"#, - ) -} - -#[test] -fn inserts_after_all_inner_items() { - check_none( - "foo::bar::Baz", - r#"#![allow(unused_imports)] -/*! Multiline line comment 2 */ - - -//! Single line comment 1 -#![no_std] -//! Single line comment 2 -fn main() {}"#, - r#"#![allow(unused_imports)] -/*! Multiline line comment 2 */ - - -//! Single line comment 1 -#![no_std] -//! Single line comment 2 - -use foo::bar::Baz; -fn main() {}"#, - ) -} - -#[test] -fn merge_groups() { - check_module("std::io", r"use std::fmt;", r"use std::{fmt, io};") -} - -#[test] -fn merge_groups_last() { - check_module( - "std::io", - r"use std::fmt::{Result, Display};", - r"use std::fmt::{Result, Display}; -use std::io;", - ) -} - -#[test] -fn merge_last_into_self() { - check_module("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};"); -} - -#[test] -fn merge_groups_full() { - check_crate( - "std::io", - r"use std::fmt::{Result, Display};", - r"use std::{fmt::{Result, Display}, io};", - ) -} - -#[test] -fn merge_groups_long_full() { - check_crate("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Qux, Baz};") -} - -#[test] -fn merge_groups_long_last() { - check_module( - "std::foo::bar::Baz", - r"use std::foo::bar::Qux;", - r"use std::foo::bar::{Qux, Baz};", - ) -} - -#[test] -fn merge_groups_long_full_list() { - check_crate( - "std::foo::bar::Baz", - r"use std::foo::bar::{Qux, Quux};", - r"use std::foo::bar::{Qux, Quux, Baz};", - ) -} - -#[test] -fn merge_groups_long_last_list() { - check_module( - "std::foo::bar::Baz", - r"use std::foo::bar::{Qux, Quux};", - r"use std::foo::bar::{Qux, Quux, Baz};", - ) -} - -#[test] -fn merge_groups_long_full_nested() { - check_crate( - "std::foo::bar::Baz", - r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", - r"use std::foo::bar::{Qux, quux::{Fez, Fizz}, Baz};", - ) -} - -#[test] -fn merge_groups_long_last_nested() { - check_module( - "std::foo::bar::Baz", - r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", - r"use std::foo::bar::Baz; -use std::foo::bar::{Qux, quux::{Fez, Fizz}};", - ) -} - -#[test] -fn merge_groups_full_nested_deep() { - check_crate( - "std::foo::bar::quux::Baz", - r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", - r"use std::foo::bar::{Qux, quux::{Fez, Fizz, Baz}};", - ) -} - -#[test] -fn merge_groups_full_nested_long() { - check_crate( - "std::foo::bar::Baz", - r"use std::{foo::bar::Qux};", - r"use std::{foo::bar::{Qux, Baz}};", - ); -} - -#[test] -fn merge_groups_last_nested_long() { - check_crate( - "std::foo::bar::Baz", - r"use std::{foo::bar::Qux};", - r"use std::{foo::bar::{Qux, Baz}};", - ); -} - -#[test] -fn merge_groups_skip_pub() { - check_crate( - "std::io", - r"pub use std::fmt::{Result, Display};", - r"pub use std::fmt::{Result, Display}; -use std::io;", - ) -} - -#[test] -fn merge_groups_skip_pub_crate() { - check_crate( - "std::io", - r"pub(crate) use std::fmt::{Result, Display};", - r"pub(crate) use std::fmt::{Result, Display}; -use std::io;", - ) -} - -#[test] -fn merge_groups_skip_attributed() { - check_crate( - "std::io", - r#" -#[cfg(feature = "gated")] use std::fmt::{Result, Display}; -"#, - r#" -#[cfg(feature = "gated")] use std::fmt::{Result, Display}; -use std::io; -"#, - ) -} - -#[test] -fn split_out_merge() { - // FIXME: This is suboptimal, we want to get `use std::fmt::{self, Result}` - // instead. - check_module( - "std::fmt::Result", - r"use std::{fmt, io};", - r"use std::fmt::Result; -use std::{fmt, io};", - ) -} - -#[test] -fn merge_into_module_import() { - check_crate("std::fmt::Result", r"use std::{fmt, io};", r"use std::{fmt::{self, Result}, io};") -} - -#[test] -fn merge_groups_self() { - check_crate("std::fmt::Debug", r"use std::fmt;", r"use std::fmt::{self, Debug};") -} - -#[test] -fn merge_mod_into_glob() { - check_with_config( - "token::TokenKind", - r"use token::TokenKind::*;", - r"use token::TokenKind::{*, self};", - &InsertUseConfig { - granularity: ImportGranularity::Crate, - enforce_granularity: true, - prefix_kind: PrefixKind::Plain, - group: false, - skip_glob_imports: false, - }, - ) - // FIXME: have it emit `use token::TokenKind::{self, *}`? -} - -#[test] -fn merge_self_glob() { - check_with_config( - "self", - r"use self::*;", - r"use self::{*, self};", - &InsertUseConfig { - granularity: ImportGranularity::Crate, - enforce_granularity: true, - prefix_kind: PrefixKind::Plain, - group: false, - skip_glob_imports: false, - }, - ) - // FIXME: have it emit `use {self, *}`? -} - -#[test] -fn merge_glob() { - check_crate( - "syntax::SyntaxKind", - r" -use syntax::{SyntaxKind::*};", - r" -use syntax::{SyntaxKind::{*, self}};", - ) -} - -#[test] -fn merge_glob_nested() { - check_crate( - "foo::bar::quux::Fez", - r"use foo::bar::{Baz, quux::*};", - r"use foo::bar::{Baz, quux::{*, Fez}};", - ) -} - -#[test] -fn merge_nested_considers_first_segments() { - check_crate( - "hir_ty::display::write_bounds_like_dyn_trait", - r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter}, method_resolution};", - r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter, write_bounds_like_dyn_trait}, method_resolution};", - ); -} - -#[test] -fn skip_merge_last_too_long() { - check_module( - "foo::bar", - r"use foo::bar::baz::Qux;", - r"use foo::bar; -use foo::bar::baz::Qux;", - ); -} - -#[test] -fn skip_merge_last_too_long2() { - check_module( - "foo::bar::baz::Qux", - r"use foo::bar;", - r"use foo::bar; -use foo::bar::baz::Qux;", - ); -} - -#[test] -fn insert_short_before_long() { - check_none( - "foo::bar", - r"use foo::bar::baz::Qux;", - r"use foo::bar; -use foo::bar::baz::Qux;", - ); -} - -#[test] -fn merge_last_fail() { - check_merge_only_fail( - r"use foo::bar::{baz::{Qux, Fez}};", - r"use foo::bar::{baaz::{Quux, Feez}};", - MergeBehavior::Module, - ); -} - -#[test] -fn merge_last_fail1() { - check_merge_only_fail( - r"use foo::bar::{baz::{Qux, Fez}};", - r"use foo::bar::baaz::{Quux, Feez};", - MergeBehavior::Module, - ); -} - -#[test] -fn merge_last_fail2() { - check_merge_only_fail( - r"use foo::bar::baz::{Qux, Fez};", - r"use foo::bar::{baaz::{Quux, Feez}};", - MergeBehavior::Module, - ); -} - -#[test] -fn merge_last_fail3() { - check_merge_only_fail( - r"use foo::bar::baz::{Qux, Fez};", - r"use foo::bar::baaz::{Quux, Feez};", - MergeBehavior::Module, - ); -} - -#[test] -fn guess_empty() { - check_guess("", ImportGranularityGuess::Unknown); -} - -#[test] -fn guess_single() { - check_guess(r"use foo::{baz::{qux, quux}, bar};", ImportGranularityGuess::Crate); - check_guess(r"use foo::bar;", ImportGranularityGuess::Unknown); - check_guess(r"use foo::bar::{baz, qux};", ImportGranularityGuess::CrateOrModule); -} - -#[test] -fn guess_unknown() { - check_guess( - r" -use foo::bar::baz; -use oof::rab::xuq; -", - ImportGranularityGuess::Unknown, - ); -} - -#[test] -fn guess_item() { - check_guess( - r" -use foo::bar::baz; -use foo::bar::qux; -", - ImportGranularityGuess::Item, - ); -} - -#[test] -fn guess_module_or_item() { - check_guess( - r" -use foo::bar::Bar; -use foo::qux; -", - ImportGranularityGuess::ModuleOrItem, - ); - check_guess( - r" -use foo::bar::Bar; -use foo::bar; -", - ImportGranularityGuess::ModuleOrItem, - ); -} - -#[test] -fn guess_module() { - check_guess( - r" -use foo::bar::baz; -use foo::bar::{qux, quux}; -", - ImportGranularityGuess::Module, - ); - // this is a rather odd case, technically this file isn't following any style properly. - check_guess( - r" -use foo::bar::baz; -use foo::{baz::{qux, quux}, bar}; -", - ImportGranularityGuess::Module, - ); - check_guess( - r" -use foo::bar::Bar; -use foo::baz::Baz; -use foo::{Foo, Qux}; -", - ImportGranularityGuess::Module, - ); -} - -#[test] -fn guess_crate_or_module() { - check_guess( - r" -use foo::bar::baz; -use oof::bar::{qux, quux}; -", - ImportGranularityGuess::CrateOrModule, - ); -} - -#[test] -fn guess_crate() { - check_guess( - r" -use frob::bar::baz; -use foo::{baz::{qux, quux}, bar}; -", - ImportGranularityGuess::Crate, - ); -} - -#[test] -fn guess_skips_differing_vis() { - check_guess( - r" -use foo::bar::baz; -pub use foo::bar::qux; -", - ImportGranularityGuess::Unknown, - ); -} - -#[test] -fn guess_skips_differing_attrs() { - check_guess( - r" -pub use foo::bar::baz; -#[doc(hidden)] -pub use foo::bar::qux; -", - ImportGranularityGuess::Unknown, - ); -} - -#[test] -fn guess_grouping_matters() { - check_guess( - r" -use foo::bar::baz; -use oof::bar::baz; -use foo::bar::qux; -", - ImportGranularityGuess::Unknown, - ); -} - -fn check_with_config( - path: &str, - ra_fixture_before: &str, - ra_fixture_after: &str, - config: &InsertUseConfig, -) { - let (db, file_id, pos) = if ra_fixture_before.contains(CURSOR_MARKER) { - let (db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture_before); - (db, file_id, Some(range_or_offset)) - } else { - let (db, file_id) = RootDatabase::with_single_file(ra_fixture_before); - (db, file_id, None) - }; - let sema = &Semantics::new(&db); - let source_file = sema.parse(file_id); - let syntax = source_file.syntax().clone_for_update(); - let file = pos - .and_then(|pos| syntax.token_at_offset(pos.expect_offset()).next()?.parent()) - .and_then(|it| ImportScope::find_insert_use_container(&it, sema)) - .or_else(|| ImportScope::from(syntax)) - .unwrap(); - let path = ast::SourceFile::parse(&format!("use {};", path)) - .tree() - .syntax() - .descendants() - .find_map(ast::Path::cast) - .unwrap(); - - insert_use(&file, path, config); - let result = file.as_syntax_node().ancestors().last().unwrap().to_string(); - assert_eq_text!(&trim_indent(ra_fixture_after), &result); -} - -fn check( - path: &str, - ra_fixture_before: &str, - ra_fixture_after: &str, - granularity: ImportGranularity, -) { - check_with_config( - path, - ra_fixture_before, - ra_fixture_after, - &InsertUseConfig { - granularity, - enforce_granularity: true, - prefix_kind: PrefixKind::Plain, - group: true, - skip_glob_imports: true, - }, - ) -} - -fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { - check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Crate) -} - -fn check_module(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { - check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Module) -} - -fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { - check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Item) -} - -fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior) { - let use0 = ast::SourceFile::parse(ra_fixture0) - .tree() - .syntax() - .descendants() - .find_map(ast::Use::cast) - .unwrap(); - - let use1 = ast::SourceFile::parse(ra_fixture1) - .tree() - .syntax() - .descendants() - .find_map(ast::Use::cast) - .unwrap(); - - let result = try_merge_imports(&use0, &use1, mb); - assert_eq!(result.map(|u| u.to_string()), None); -} - -fn check_guess(ra_fixture: &str, expected: ImportGranularityGuess) { - let syntax = ast::SourceFile::parse(ra_fixture).tree().syntax().clone(); - let file = ImportScope::from(syntax).unwrap(); - assert_eq!(super::guess_granularity_from_scope(&file), expected); -} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs deleted file mode 100644 index 7fb4b90e6d992..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs +++ /dev/null @@ -1,295 +0,0 @@ -//! Handle syntactic aspects of merging UseTrees. -use std::cmp::Ordering; - -use itertools::{EitherOrBoth, Itertools}; -use syntax::{ - ast::{self, AstNode, HasAttrs, HasVisibility, PathSegmentKind}, - ted, -}; - -use crate::syntax_helpers::node_ext::vis_eq; - -/// What type of merges are allowed. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum MergeBehavior { - /// Merge imports from the same crate into a single use statement. - Crate, - /// Merge imports from the same module into a single use statement. - Module, -} - -impl MergeBehavior { - fn is_tree_allowed(&self, tree: &ast::UseTree) -> bool { - match self { - MergeBehavior::Crate => true, - // only simple single segment paths are allowed - MergeBehavior::Module => { - tree.use_tree_list().is_none() && tree.path().map(path_len) <= Some(1) - } - } - } -} - -/// Merge `rhs` into `lhs` keeping both intact. -/// Returned AST is mutable. -pub fn try_merge_imports( - lhs: &ast::Use, - rhs: &ast::Use, - merge_behavior: MergeBehavior, -) -> Option { - // don't merge imports with different visibilities - if !eq_visibility(lhs.visibility(), rhs.visibility()) { - return None; - } - if !eq_attrs(lhs.attrs(), rhs.attrs()) { - return None; - } - - let lhs = lhs.clone_subtree().clone_for_update(); - let rhs = rhs.clone_subtree().clone_for_update(); - let lhs_tree = lhs.use_tree()?; - let rhs_tree = rhs.use_tree()?; - try_merge_trees_mut(&lhs_tree, &rhs_tree, merge_behavior)?; - Some(lhs) -} - -/// Merge `rhs` into `lhs` keeping both intact. -/// Returned AST is mutable. -pub fn try_merge_trees( - lhs: &ast::UseTree, - rhs: &ast::UseTree, - merge: MergeBehavior, -) -> Option { - let lhs = lhs.clone_subtree().clone_for_update(); - let rhs = rhs.clone_subtree().clone_for_update(); - try_merge_trees_mut(&lhs, &rhs, merge)?; - Some(lhs) -} - -fn try_merge_trees_mut(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) -> Option<()> { - let lhs_path = lhs.path()?; - let rhs_path = rhs.path()?; - - let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?; - if !(lhs.is_simple_path() - && rhs.is_simple_path() - && lhs_path == lhs_prefix - && rhs_path == rhs_prefix) - { - lhs.split_prefix(&lhs_prefix); - rhs.split_prefix(&rhs_prefix); - } - recursive_merge(lhs, rhs, merge) -} - -/// Recursively merges rhs to lhs -#[must_use] -fn recursive_merge(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) -> Option<()> { - let mut use_trees: Vec = lhs - .use_tree_list() - .into_iter() - .flat_map(|list| list.use_trees()) - // We use Option here to early return from this function(this is not the - // same as a `filter` op). - .map(|tree| merge.is_tree_allowed(&tree).then(|| tree)) - .collect::>()?; - use_trees.sort_unstable_by(|a, b| path_cmp_for_sort(a.path(), b.path())); - for rhs_t in rhs.use_tree_list().into_iter().flat_map(|list| list.use_trees()) { - if !merge.is_tree_allowed(&rhs_t) { - return None; - } - let rhs_path = rhs_t.path(); - - match use_trees - .binary_search_by(|lhs_t| path_cmp_bin_search(lhs_t.path(), rhs_path.as_ref())) - { - Ok(idx) => { - let lhs_t = &mut use_trees[idx]; - let lhs_path = lhs_t.path()?; - let rhs_path = rhs_path?; - let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?; - if lhs_prefix == lhs_path && rhs_prefix == rhs_path { - let tree_is_self = |tree: &ast::UseTree| { - tree.path().as_ref().map(path_is_self).unwrap_or(false) - }; - // Check if only one of the two trees has a tree list, and - // whether that then contains `self` or not. If this is the - // case we can skip this iteration since the path without - // the list is already included in the other one via `self`. - let tree_contains_self = |tree: &ast::UseTree| { - tree.use_tree_list() - .map(|tree_list| tree_list.use_trees().any(|it| tree_is_self(&it))) - // Glob imports aren't part of the use-tree lists, - // so they need to be handled explicitly - .or_else(|| tree.star_token().map(|_| false)) - }; - match (tree_contains_self(lhs_t), tree_contains_self(&rhs_t)) { - (Some(true), None) => continue, - (None, Some(true)) => { - ted::replace(lhs_t.syntax(), rhs_t.syntax()); - *lhs_t = rhs_t; - continue; - } - _ => (), - } - - if lhs_t.is_simple_path() && rhs_t.is_simple_path() { - continue; - } - } - lhs_t.split_prefix(&lhs_prefix); - rhs_t.split_prefix(&rhs_prefix); - recursive_merge(lhs_t, &rhs_t, merge)?; - } - Err(_) - if merge == MergeBehavior::Module - && !use_trees.is_empty() - && rhs_t.use_tree_list().is_some() => - { - return None - } - Err(idx) => { - use_trees.insert(idx, rhs_t.clone()); - lhs.get_or_create_use_tree_list().add_use_tree(rhs_t); - } - } - } - Some(()) -} - -/// Traverses both paths until they differ, returning the common prefix of both. -pub fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast::Path)> { - let mut res = None; - let mut lhs_curr = lhs.first_qualifier_or_self(); - let mut rhs_curr = rhs.first_qualifier_or_self(); - loop { - match (lhs_curr.segment(), rhs_curr.segment()) { - (Some(lhs), Some(rhs)) if lhs.syntax().text() == rhs.syntax().text() => (), - _ => break res, - } - res = Some((lhs_curr.clone(), rhs_curr.clone())); - - match lhs_curr.parent_path().zip(rhs_curr.parent_path()) { - Some((lhs, rhs)) => { - lhs_curr = lhs; - rhs_curr = rhs; - } - _ => break res, - } - } -} - -/// Orders paths in the following way: -/// the sole self token comes first, after that come uppercase identifiers, then lowercase identifiers -// FIXME: rustfmt sorts lowercase idents before uppercase, in general we want to have the same ordering rustfmt has -// which is `self` and `super` first, then identifier imports with lowercase ones first, then glob imports and at last list imports. -// Example foo::{self, foo, baz, Baz, Qux, *, {Bar}} -fn path_cmp_for_sort(a: Option, b: Option) -> Ordering { - match (a, b) { - (None, None) => Ordering::Equal, - (None, Some(_)) => Ordering::Less, - (Some(_), None) => Ordering::Greater, - (Some(ref a), Some(ref b)) => match (path_is_self(a), path_is_self(b)) { - (true, true) => Ordering::Equal, - (true, false) => Ordering::Less, - (false, true) => Ordering::Greater, - (false, false) => path_cmp_short(a, b), - }, - } -} - -/// Path comparison func for binary searching for merging. -fn path_cmp_bin_search(lhs: Option, rhs: Option<&ast::Path>) -> Ordering { - match (lhs.as_ref().and_then(ast::Path::first_segment), rhs.and_then(ast::Path::first_segment)) - { - (None, None) => Ordering::Equal, - (None, Some(_)) => Ordering::Less, - (Some(_), None) => Ordering::Greater, - (Some(ref a), Some(ref b)) => path_segment_cmp(a, b), - } -} - -/// Short circuiting comparison, if both paths are equal until one of them ends they are considered -/// equal -fn path_cmp_short(a: &ast::Path, b: &ast::Path) -> Ordering { - let a = a.segments(); - let b = b.segments(); - // cmp_by would be useful for us here but that is currently unstable - // cmp doesn't work due the lifetimes on text's return type - a.zip(b) - .find_map(|(a, b)| match path_segment_cmp(&a, &b) { - Ordering::Equal => None, - ord => Some(ord), - }) - .unwrap_or(Ordering::Equal) -} - -/// Compares two paths, if one ends earlier than the other the has_tl parameters decide which is -/// greater as a a path that has a tree list should be greater, while one that just ends without -/// a tree list should be considered less. -pub(super) fn use_tree_path_cmp( - a: &ast::Path, - a_has_tl: bool, - b: &ast::Path, - b_has_tl: bool, -) -> Ordering { - let a_segments = a.segments(); - let b_segments = b.segments(); - // cmp_by would be useful for us here but that is currently unstable - // cmp doesn't work due the lifetimes on text's return type - a_segments - .zip_longest(b_segments) - .find_map(|zipped| match zipped { - EitherOrBoth::Both(ref a, ref b) => match path_segment_cmp(a, b) { - Ordering::Equal => None, - ord => Some(ord), - }, - EitherOrBoth::Left(_) if !b_has_tl => Some(Ordering::Greater), - EitherOrBoth::Left(_) => Some(Ordering::Less), - EitherOrBoth::Right(_) if !a_has_tl => Some(Ordering::Less), - EitherOrBoth::Right(_) => Some(Ordering::Greater), - }) - .unwrap_or(Ordering::Equal) -} - -fn path_segment_cmp(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering { - let a = a.kind().and_then(|kind| match kind { - PathSegmentKind::Name(name_ref) => Some(name_ref), - _ => None, - }); - let b = b.kind().and_then(|kind| match kind { - PathSegmentKind::Name(name_ref) => Some(name_ref), - _ => None, - }); - a.as_ref().map(ast::NameRef::text).cmp(&b.as_ref().map(ast::NameRef::text)) -} - -pub fn eq_visibility(vis0: Option, vis1: Option) -> bool { - match (vis0, vis1) { - (None, None) => true, - (Some(vis0), Some(vis1)) => vis_eq(&vis0, &vis1), - _ => false, - } -} - -pub fn eq_attrs( - attrs0: impl Iterator, - attrs1: impl Iterator, -) -> bool { - // FIXME order of attributes should not matter - let attrs0 = attrs0 - .flat_map(|attr| attr.syntax().descendants_with_tokens()) - .flat_map(|it| it.into_token()); - let attrs1 = attrs1 - .flat_map(|attr| attr.syntax().descendants_with_tokens()) - .flat_map(|it| it.into_token()); - stdx::iter_eq_by(attrs0, attrs1, |tok, tok2| tok.text() == tok2.text()) -} - -fn path_is_self(path: &ast::Path) -> bool { - path.segment().and_then(|seg| seg.self_token()).is_some() && path.qualifier().is_none() -} - -fn path_len(path: ast::Path) -> usize { - path.segments().count() -} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs deleted file mode 100644 index 07a57c883b2d9..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs +++ /dev/null @@ -1,151 +0,0 @@ -//! This module has the functionality to search the project and its dependencies for a certain item, -//! by its name and a few criteria. -//! The main reason for this module to exist is the fact that project's items and dependencies' items -//! are located in different caches, with different APIs. -use either::Either; -use hir::{ - import_map::{self, ImportKind}, - symbols::FileSymbol, - AsAssocItem, Crate, ItemInNs, Semantics, -}; -use limit::Limit; -use syntax::{ast, AstNode, SyntaxKind::NAME}; - -use crate::{ - defs::{Definition, NameClass}, - imports::import_assets::NameToImport, - symbol_index, RootDatabase, -}; - -/// A value to use, when uncertain which limit to pick. -pub static DEFAULT_QUERY_SEARCH_LIMIT: Limit = Limit::new(40); - -/// Three possible ways to search for the name in associated and/or other items. -#[derive(Debug, Clone, Copy)] -pub enum AssocItemSearch { - /// Search for the name in both associated and other items. - Include, - /// Search for the name in other items only. - Exclude, - /// Search for the name in the associated items only. - AssocItemsOnly, -} - -/// Searches for importable items with the given name in the crate and its dependencies. -pub fn items_with_name<'a>( - sema: &'a Semantics<'_, RootDatabase>, - krate: Crate, - name: NameToImport, - assoc_item_search: AssocItemSearch, - limit: Option, -) -> impl Iterator + 'a { - let _p = profile::span("items_with_name").detail(|| { - format!( - "Name: {}, crate: {:?}, assoc items: {:?}, limit: {:?}", - name.text(), - assoc_item_search, - krate.display_name(sema.db).map(|name| name.to_string()), - limit, - ) - }); - - let (mut local_query, mut external_query) = match name { - NameToImport::Exact(exact_name, case_sensitive) => { - let mut local_query = symbol_index::Query::new(exact_name.clone()); - local_query.exact(); - - let external_query = import_map::Query::new(exact_name) - .name_only() - .search_mode(import_map::SearchMode::Equals); - - ( - local_query, - if case_sensitive { external_query.case_sensitive() } else { external_query }, - ) - } - NameToImport::Fuzzy(fuzzy_search_string) => { - let mut local_query = symbol_index::Query::new(fuzzy_search_string.clone()); - - let mut external_query = import_map::Query::new(fuzzy_search_string.clone()) - .search_mode(import_map::SearchMode::Fuzzy) - .name_only(); - match assoc_item_search { - AssocItemSearch::Include => {} - AssocItemSearch::Exclude => { - external_query = external_query.exclude_import_kind(ImportKind::AssociatedItem); - } - AssocItemSearch::AssocItemsOnly => { - external_query = external_query.assoc_items_only(); - } - } - - if fuzzy_search_string.to_lowercase() != fuzzy_search_string { - local_query.case_sensitive(); - external_query = external_query.case_sensitive(); - } - - (local_query, external_query) - } - }; - - if let Some(limit) = limit { - external_query = external_query.limit(limit); - local_query.limit(limit); - } - - find_items(sema, krate, assoc_item_search, local_query, external_query) -} - -fn find_items<'a>( - sema: &'a Semantics<'_, RootDatabase>, - krate: Crate, - assoc_item_search: AssocItemSearch, - local_query: symbol_index::Query, - external_query: import_map::Query, -) -> impl Iterator + 'a { - let _p = profile::span("find_items"); - let db = sema.db; - - let external_importables = - krate.query_external_importables(db, external_query).map(|external_importable| { - match external_importable { - Either::Left(module_def) => ItemInNs::from(module_def), - Either::Right(macro_def) => ItemInNs::from(macro_def), - } - }); - - // Query the local crate using the symbol index. - let local_results = symbol_index::crate_symbols(db, krate, local_query) - .into_iter() - .filter_map(move |local_candidate| get_name_definition(sema, &local_candidate)) - .filter_map(|name_definition_to_import| match name_definition_to_import { - Definition::Macro(macro_def) => Some(ItemInNs::from(macro_def)), - def => >::from(def), - }); - - external_importables.chain(local_results).filter(move |&item| match assoc_item_search { - AssocItemSearch::Include => true, - AssocItemSearch::Exclude => !is_assoc_item(item, sema.db), - AssocItemSearch::AssocItemsOnly => is_assoc_item(item, sema.db), - }) -} - -fn get_name_definition( - sema: &Semantics<'_, RootDatabase>, - import_candidate: &FileSymbol, -) -> Option { - let _p = profile::span("get_name_definition"); - - let candidate_node = import_candidate.loc.syntax(sema)?; - let candidate_name_node = if candidate_node.kind() != NAME { - candidate_node.children().find(|it| it.kind() == NAME)? - } else { - candidate_node - }; - let name = ast::Name::cast(candidate_name_node)?; - NameClass::classify(sema, &name)?.defined() -} - -fn is_assoc_item(item: ItemInNs, db: &RootDatabase) -> bool { - item.as_module_def().and_then(|module_def| module_def.as_assoc_item(db)).is_some() -} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/label.rs b/src/tools/rust-analyzer/crates/ide-db/src/label.rs deleted file mode 100644 index 4b6d54b5eab16..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-db/src/label.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! See [`Label`] -use std::fmt; - -/// A type to specify UI label, like an entry in the list of assists. Enforces -/// proper casing: -/// -/// Frobnicate bar -/// -/// Note the upper-case first letter and the absence of `.` at the end. -#[derive(Clone)] -pub struct Label(String); - -impl PartialEq for Label { - fn eq(&self, other: &str) -> bool { - self.0 == other - } -} - -impl PartialEq<&'_ str> for Label { - fn eq(&self, other: &&str) -> bool { - self == *other - } -} - -impl From = Next(E::Foo); - match n { Next(E::Foo) => {} } - // ^ error: missing match arm: `Next(Bar)` not covered - match n { Next(E::Foo | E::Bar) => {} } - match n { Next(E::Foo | _ ) => {} } - match n { Next(_ | E::Bar) => {} } - match n { _ | Next(E::Bar) => {} } - match &n { Next(E::Foo | E::Bar) => {} } - match &n { _ | Next(E::Bar) => {} } -};", - ); - } - - #[test] - fn binding_mode_by_ref() { - check_diagnostics_no_bails( - r" -enum E{ A, B } -fn foo() { - match &E::A { - E::A => {} - x => {} - } -}", - ); - } - - #[test] - fn macro_or_pat() { - check_diagnostics_no_bails( - r#" -macro_rules! m { - () => { - Enum::Type1 | Enum::Type2 - }; -} - -enum Enum { - Type1, - Type2, - Type3, -} - -fn f(ty: Enum) { - match ty { - //^^ error: missing match arm: `Type3` not covered - m!() => (), - } - - match ty { - m!() | Enum::Type3 => () - } -} -"#, - ); - } - - #[test] - fn unexpected_ty_fndef() { - cov_mark::check!(validate_match_bailed_out); - check_diagnostics( - r" -enum Exp { - Tuple(()), -} -fn f() { - match __unknown { - Exp::Tuple => {} - } -}", - ); - } - - mod false_negatives { - //! The implementation of match checking here is a work in progress. As we roll this out, we - //! prefer false negatives to false positives (ideally there would be no false positives). This - //! test module should document known false negatives. Eventually we will have a complete - //! implementation of match checking and this module will be empty. - //! - //! The reasons for documenting known false negatives: - //! - //! 1. It acts as a backlog of work that can be done to improve the behavior of the system. - //! 2. It ensures the code doesn't panic when handling these cases. - use super::*; - - #[test] - fn integers() { - cov_mark::check_count!(validate_match_bailed_out, 1); - - // We don't currently check integer exhaustiveness. - check_diagnostics( - r#" -fn main() { - match 5 { - 10 => (), - 11..20 => (), - } -} -"#, - ); - } - - #[test] - fn reference_patterns_at_top_level() { - cov_mark::check_count!(validate_match_bailed_out, 1); - - check_diagnostics( - r#" -fn main() { - match &false { - &true => {} - } -} - "#, - ); - } - - #[test] - fn reference_patterns_in_fields() { - cov_mark::check_count!(validate_match_bailed_out, 2); - - check_diagnostics( - r#" -fn main() { - match (&false,) { - (true,) => {} - } - match (&false,) { - (&true,) => {} - } -} - "#, - ); - } - } -} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs deleted file mode 100644 index 7acd9228a89ad..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ /dev/null @@ -1,101 +0,0 @@ -use crate::{Diagnostic, DiagnosticsContext}; - -// Diagnostic: missing-unsafe -// -// This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block. -pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Diagnostic { - Diagnostic::new( - "missing-unsafe", - "this operation is unsafe and requires an unsafe function or block", - ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range, - ) -} - -#[cfg(test)] -mod tests { - use crate::tests::check_diagnostics; - - #[test] - fn missing_unsafe_diagnostic_with_raw_ptr() { - check_diagnostics( - r#" -fn main() { - let x = &5 as *const usize; - unsafe { let y = *x; } - let z = *x; -} //^^ error: this operation is unsafe and requires an unsafe function or block -"#, - ) - } - - #[test] - fn missing_unsafe_diagnostic_with_unsafe_call() { - check_diagnostics( - r#" -struct HasUnsafe; - -impl HasUnsafe { - unsafe fn unsafe_fn(&self) { - let x = &5 as *const usize; - let y = *x; - } -} - -unsafe fn unsafe_fn() { - let x = &5 as *const usize; - let y = *x; -} - -fn main() { - unsafe_fn(); - //^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block - HasUnsafe.unsafe_fn(); - //^^^^^^^^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block - unsafe { - unsafe_fn(); - HasUnsafe.unsafe_fn(); - } -} -"#, - ); - } - - #[test] - fn missing_unsafe_diagnostic_with_static_mut() { - check_diagnostics( - r#" -struct Ty { - a: u8, -} - -static mut STATIC_MUT: Ty = Ty { a: 0 }; - -fn main() { - let x = STATIC_MUT.a; - //^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block - unsafe { - let x = STATIC_MUT.a; - } -} -"#, - ); - } - - #[test] - fn no_missing_unsafe_diagnostic_with_safe_intrinsic() { - check_diagnostics( - r#" -extern "rust-intrinsic" { - pub fn bitreverse(x: u32) -> u32; // Safe intrinsic - pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic -} - -fn main() { - let _ = bitreverse(12); - let _ = floorf32(12.0); - //^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block -} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs deleted file mode 100644 index e032c578f0282..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ /dev/null @@ -1,283 +0,0 @@ -use hir::{db::AstDatabase, HasSource, HirDisplay, Semantics}; -use ide_db::{base_db::FileId, source_change::SourceChange, RootDatabase}; -use syntax::{ - ast::{self, edit::IndentLevel, make}, - AstNode, -}; -use text_edit::TextEdit; - -use crate::{fix, Assist, Diagnostic, DiagnosticsContext}; - -// Diagnostic: no-such-field -// -// This diagnostic is triggered if created structure does not have field provided in record. -pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic { - Diagnostic::new( - "no-such-field", - "no such field", - ctx.sema.diagnostics_display_range(d.field.clone().map(|it| it.into())).range, - ) - .with_fixes(fixes(ctx, d)) -} - -fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Option> { - let root = ctx.sema.db.parse_or_expand(d.field.file_id)?; - missing_record_expr_field_fixes( - &ctx.sema, - d.field.file_id.original_file(ctx.sema.db), - &d.field.value.to_node(&root), - ) -} - -fn missing_record_expr_field_fixes( - sema: &Semantics<'_, RootDatabase>, - usage_file_id: FileId, - record_expr_field: &ast::RecordExprField, -) -> Option> { - let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?; - let def_id = sema.resolve_variant(record_lit)?; - let module; - let def_file_id; - let record_fields = match def_id { - hir::VariantDef::Struct(s) => { - module = s.module(sema.db); - let source = s.source(sema.db)?; - def_file_id = source.file_id; - let fields = source.value.field_list()?; - record_field_list(fields)? - } - hir::VariantDef::Union(u) => { - module = u.module(sema.db); - let source = u.source(sema.db)?; - def_file_id = source.file_id; - source.value.record_field_list()? - } - hir::VariantDef::Variant(e) => { - module = e.module(sema.db); - let source = e.source(sema.db)?; - def_file_id = source.file_id; - let fields = source.value.field_list()?; - record_field_list(fields)? - } - }; - let def_file_id = def_file_id.original_file(sema.db); - - let new_field_type = sema.type_of_expr(&record_expr_field.expr()?)?.adjusted(); - if new_field_type.is_unknown() { - return None; - } - let new_field = make::record_field( - None, - make::name(&record_expr_field.field_name()?.text()), - make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?), - ); - - let last_field = record_fields.fields().last()?; - let last_field_syntax = last_field.syntax(); - let indent = IndentLevel::from_node(last_field_syntax); - - let mut new_field = new_field.to_string(); - if usage_file_id != def_file_id { - new_field = format!("pub(crate) {}", new_field); - } - new_field = format!("\n{}{}", indent, new_field); - - let needs_comma = !last_field_syntax.to_string().ends_with(','); - if needs_comma { - new_field = format!(",{}", new_field); - } - - let source_change = SourceChange::from_text_edit( - def_file_id, - TextEdit::insert(last_field_syntax.text_range().end(), new_field), - ); - - return Some(vec![fix( - "create_field", - "Create field", - source_change, - record_expr_field.syntax().text_range(), - )]); - - fn record_field_list(field_def_list: ast::FieldList) -> Option { - match field_def_list { - ast::FieldList::RecordFieldList(it) => Some(it), - ast::FieldList::TupleFieldList(_) => None, - } - } -} - -#[cfg(test)] -mod tests { - use crate::tests::{check_diagnostics, check_fix}; - - #[test] - fn no_such_field_diagnostics() { - check_diagnostics( - r#" -struct S { foo: i32, bar: () } -impl S { - fn new() -> S { - S { - //^ 💡 error: missing structure fields: - //| - bar - foo: 92, - baz: 62, - //^^^^^^^ 💡 error: no such field - } - } -} -"#, - ); - } - #[test] - fn no_such_field_with_feature_flag_diagnostics() { - check_diagnostics( - r#" -//- /lib.rs crate:foo cfg:feature=foo -struct MyStruct { - my_val: usize, - #[cfg(feature = "foo")] - bar: bool, -} - -impl MyStruct { - #[cfg(feature = "foo")] - pub(crate) fn new(my_val: usize, bar: bool) -> Self { - Self { my_val, bar } - } - #[cfg(not(feature = "foo"))] - pub(crate) fn new(my_val: usize, _bar: bool) -> Self { - Self { my_val } - } -} -"#, - ); - } - - #[test] - fn no_such_field_enum_with_feature_flag_diagnostics() { - check_diagnostics( - r#" -//- /lib.rs crate:foo cfg:feature=foo -enum Foo { - #[cfg(not(feature = "foo"))] - Buz, - #[cfg(feature = "foo")] - Bar, - Baz -} - -fn test_fn(f: Foo) { - match f { - Foo::Bar => {}, - Foo::Baz => {}, - } -} -"#, - ); - } - - #[test] - fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() { - check_diagnostics( - r#" -//- /lib.rs crate:foo cfg:feature=foo -struct S { - #[cfg(feature = "foo")] - foo: u32, - #[cfg(not(feature = "foo"))] - bar: u32, -} - -impl S { - #[cfg(feature = "foo")] - fn new(foo: u32) -> Self { - Self { foo } - } - #[cfg(not(feature = "foo"))] - fn new(bar: u32) -> Self { - Self { bar } - } - fn new2(bar: u32) -> Self { - #[cfg(feature = "foo")] - { Self { foo: bar } } - #[cfg(not(feature = "foo"))] - { Self { bar } } - } - fn new2(val: u32) -> Self { - Self { - #[cfg(feature = "foo")] - foo: val, - #[cfg(not(feature = "foo"))] - bar: val, - } - } -} -"#, - ); - } - - #[test] - fn no_such_field_with_type_macro() { - check_diagnostics( - r#" -macro_rules! Type { () => { u32 }; } -struct Foo { bar: Type![] } - -impl Foo { - fn new() -> Self { - Foo { bar: 0 } - } -} -"#, - ); - } - - #[test] - fn test_add_field_from_usage() { - check_fix( - r" -fn main() { - Foo { bar: 3, baz$0: false}; -} -struct Foo { - bar: i32 -} -", - r" -fn main() { - Foo { bar: 3, baz: false}; -} -struct Foo { - bar: i32, - baz: bool -} -", - ) - } - - #[test] - fn test_add_field_in_other_file_from_usage() { - check_fix( - r#" -//- /main.rs -mod foo; - -fn main() { - foo::Foo { bar: 3, $0baz: false}; -} -//- /foo.rs -struct Foo { - bar: i32 -} -"#, - r#" -struct Foo { - bar: i32, - pub(crate) baz: bool -} -"#, - ) - } -} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs deleted file mode 100644 index 9826e1c707eaa..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs +++ /dev/null @@ -1,131 +0,0 @@ -use hir::{db::AstDatabase, InFile}; -use ide_db::source_change::SourceChange; -use syntax::{ - ast::{self, HasArgList}, - AstNode, TextRange, -}; -use text_edit::TextEdit; - -use crate::{fix, Assist, Diagnostic, DiagnosticsContext, Severity}; - -// Diagnostic: replace-filter-map-next-with-find-map -// -// This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`. -pub(crate) fn replace_filter_map_next_with_find_map( - ctx: &DiagnosticsContext<'_>, - d: &hir::ReplaceFilterMapNextWithFindMap, -) -> Diagnostic { - Diagnostic::new( - "replace-filter-map-next-with-find-map", - "replace filter_map(..).next() with find_map(..)", - ctx.sema.diagnostics_display_range(InFile::new(d.file, d.next_expr.clone().into())).range, - ) - .severity(Severity::WeakWarning) - .with_fixes(fixes(ctx, d)) -} - -fn fixes( - ctx: &DiagnosticsContext<'_>, - d: &hir::ReplaceFilterMapNextWithFindMap, -) -> Option> { - let root = ctx.sema.db.parse_or_expand(d.file)?; - let next_expr = d.next_expr.to_node(&root); - let next_call = ast::MethodCallExpr::cast(next_expr.syntax().clone())?; - - let filter_map_call = ast::MethodCallExpr::cast(next_call.receiver()?.syntax().clone())?; - let filter_map_name_range = filter_map_call.name_ref()?.ident_token()?.text_range(); - let filter_map_args = filter_map_call.arg_list()?; - - let range_to_replace = - TextRange::new(filter_map_name_range.start(), next_expr.syntax().text_range().end()); - let replacement = format!("find_map{}", filter_map_args.syntax().text()); - let trigger_range = next_expr.syntax().text_range(); - - let edit = TextEdit::replace(range_to_replace, replacement); - - let source_change = SourceChange::from_text_edit(d.file.original_file(ctx.sema.db), edit); - - Some(vec![fix( - "replace_with_find_map", - "Replace filter_map(..).next() with find_map()", - source_change, - trigger_range, - )]) -} - -#[cfg(test)] -mod tests { - use crate::tests::{check_diagnostics, check_fix}; - - #[test] - fn replace_filter_map_next_with_find_map2() { - check_diagnostics( - r#" -//- minicore: iterators -fn foo() { - let m = core::iter::repeat(()).filter_map(|()| Some(92)).next(); -} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: replace filter_map(..).next() with find_map(..) -"#, - ); - } - - #[test] - fn replace_filter_map_next_with_find_map_no_diagnostic_without_next() { - check_diagnostics( - r#" -//- minicore: iterators -fn foo() { - let m = core::iter::repeat(()) - .filter_map(|()| Some(92)) - .count(); -} -"#, - ); - } - - #[test] - fn replace_filter_map_next_with_find_map_no_diagnostic_with_intervening_methods() { - check_diagnostics( - r#" -//- minicore: iterators -fn foo() { - let m = core::iter::repeat(()) - .filter_map(|()| Some(92)) - .map(|x| x + 2) - .next(); -} -"#, - ); - } - - #[test] - fn replace_filter_map_next_with_find_map_no_diagnostic_if_not_in_chain() { - check_diagnostics( - r#" -//- minicore: iterators -fn foo() { - let m = core::iter::repeat(()) - .filter_map(|()| Some(92)); - let n = m.next(); -} -"#, - ); - } - - #[test] - fn replace_with_find_map() { - check_fix( - r#" -//- minicore: iterators -fn foo() { - let m = core::iter::repeat(()).$0filter_map(|()| Some(92)).next(); -} -"#, - r#" -fn foo() { - let m = core::iter::repeat(()).find_map(|()| Some(92)); -} -"#, - ) - } -} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs deleted file mode 100644 index 6bf90e645b49a..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ /dev/null @@ -1,573 +0,0 @@ -use hir::{db::AstDatabase, HirDisplay, Type}; -use ide_db::{famous_defs::FamousDefs, source_change::SourceChange}; -use syntax::{ - ast::{self, BlockExpr, ExprStmt}, - AstNode, -}; -use text_edit::TextEdit; - -use crate::{adjusted_display_range, fix, Assist, Diagnostic, DiagnosticsContext}; - -// Diagnostic: type-mismatch -// -// This diagnostic is triggered when the type of an expression does not match -// the expected type. -pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Diagnostic { - let display_range = adjusted_display_range::( - ctx, - d.expr.clone().map(|it| it.into()), - &|block| { - let r_curly_range = block.stmt_list()?.r_curly_token()?.text_range(); - cov_mark::hit!(type_mismatch_on_block); - Some(r_curly_range) - }, - ); - - let mut diag = Diagnostic::new( - "type-mismatch", - format!( - "expected {}, found {}", - d.expected.display(ctx.sema.db), - d.actual.display(ctx.sema.db) - ), - display_range, - ) - .with_fixes(fixes(ctx, d)); - if diag.fixes.is_none() { - diag.experimental = true; - } - diag -} - -fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option> { - let mut fixes = Vec::new(); - - add_reference(ctx, d, &mut fixes); - add_missing_ok_or_some(ctx, d, &mut fixes); - remove_semicolon(ctx, d, &mut fixes); - str_ref_to_owned(ctx, d, &mut fixes); - - if fixes.is_empty() { - None - } else { - Some(fixes) - } -} - -fn add_reference( - ctx: &DiagnosticsContext<'_>, - d: &hir::TypeMismatch, - acc: &mut Vec, -) -> Option<()> { - let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?; - let expr_node = d.expr.value.to_node(&root); - - let range = ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range; - - let (_, mutability) = d.expected.as_reference()?; - let actual_with_ref = Type::reference(&d.actual, mutability); - if !actual_with_ref.could_coerce_to(ctx.sema.db, &d.expected) { - return None; - } - - let ampersands = format!("&{}", mutability.as_keyword_for_ref()); - - let edit = TextEdit::insert(expr_node.syntax().text_range().start(), ampersands); - let source_change = - SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit); - acc.push(fix("add_reference_here", "Add reference here", source_change, range)); - Some(()) -} - -fn add_missing_ok_or_some( - ctx: &DiagnosticsContext<'_>, - d: &hir::TypeMismatch, - acc: &mut Vec, -) -> Option<()> { - let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?; - let expr = d.expr.value.to_node(&root); - let expr_range = expr.syntax().text_range(); - let scope = ctx.sema.scope(expr.syntax())?; - - let expected_adt = d.expected.as_adt()?; - let expected_enum = expected_adt.as_enum()?; - - let famous_defs = FamousDefs(&ctx.sema, scope.krate()); - let core_result = famous_defs.core_result_Result(); - let core_option = famous_defs.core_option_Option(); - - if Some(expected_enum) != core_result && Some(expected_enum) != core_option { - return None; - } - - let variant_name = if Some(expected_enum) == core_result { "Ok" } else { "Some" }; - - let wrapped_actual_ty = expected_adt.ty_with_args(ctx.sema.db, &[d.actual.clone()]); - - if !d.expected.could_unify_with(ctx.sema.db, &wrapped_actual_ty) { - return None; - } - - let mut builder = TextEdit::builder(); - builder.insert(expr.syntax().text_range().start(), format!("{}(", variant_name)); - builder.insert(expr.syntax().text_range().end(), ")".to_string()); - let source_change = - SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), builder.finish()); - let name = format!("Wrap in {}", variant_name); - acc.push(fix("wrap_in_constructor", &name, source_change, expr_range)); - Some(()) -} - -fn remove_semicolon( - ctx: &DiagnosticsContext<'_>, - d: &hir::TypeMismatch, - acc: &mut Vec, -) -> Option<()> { - let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?; - let expr = d.expr.value.to_node(&root); - if !d.actual.is_unit() { - return None; - } - let block = BlockExpr::cast(expr.syntax().clone())?; - let expr_before_semi = - block.statements().last().and_then(|s| ExprStmt::cast(s.syntax().clone()))?; - let type_before_semi = ctx.sema.type_of_expr(&expr_before_semi.expr()?)?.original(); - if !type_before_semi.could_coerce_to(ctx.sema.db, &d.expected) { - return None; - } - let semicolon_range = expr_before_semi.semicolon_token()?.text_range(); - - let edit = TextEdit::delete(semicolon_range); - let source_change = - SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit); - - acc.push(fix("remove_semicolon", "Remove this semicolon", source_change, semicolon_range)); - Some(()) -} - -fn str_ref_to_owned( - ctx: &DiagnosticsContext<'_>, - d: &hir::TypeMismatch, - acc: &mut Vec, -) -> Option<()> { - let expected = d.expected.display(ctx.sema.db); - let actual = d.actual.display(ctx.sema.db); - - if expected.to_string() != "String" || actual.to_string() != "&str" { - return None; - } - - let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?; - let expr = d.expr.value.to_node(&root); - let expr_range = expr.syntax().text_range(); - - let to_owned = format!(".to_owned()"); - - let edit = TextEdit::insert(expr.syntax().text_range().end(), to_owned); - let source_change = - SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit); - acc.push(fix("str_ref_to_owned", "Add .to_owned() here", source_change, expr_range)); - - Some(()) -} - -#[cfg(test)] -mod tests { - use crate::tests::{check_diagnostics, check_fix, check_no_fix}; - - #[test] - fn missing_reference() { - check_diagnostics( - r#" -fn main() { - test(123); - //^^^ 💡 error: expected &i32, found i32 -} -fn test(arg: &i32) {} -"#, - ); - } - - #[test] - fn test_add_reference_to_int() { - check_fix( - r#" -fn main() { - test(123$0); -} -fn test(arg: &i32) {} - "#, - r#" -fn main() { - test(&123); -} -fn test(arg: &i32) {} - "#, - ); - } - - #[test] - fn test_add_mutable_reference_to_int() { - check_fix( - r#" -fn main() { - test($0123); -} -fn test(arg: &mut i32) {} - "#, - r#" -fn main() { - test(&mut 123); -} -fn test(arg: &mut i32) {} - "#, - ); - } - - #[test] - fn test_add_reference_to_array() { - check_fix( - r#" -//- minicore: coerce_unsized -fn main() { - test($0[1, 2, 3]); -} -fn test(arg: &[i32]) {} - "#, - r#" -fn main() { - test(&[1, 2, 3]); -} -fn test(arg: &[i32]) {} - "#, - ); - } - - #[test] - fn test_add_reference_with_autoderef() { - check_fix( - r#" -//- minicore: coerce_unsized, deref -struct Foo; -struct Bar; -impl core::ops::Deref for Foo { - type Target = Bar; -} - -fn main() { - test($0Foo); -} -fn test(arg: &Bar) {} - "#, - r#" -struct Foo; -struct Bar; -impl core::ops::Deref for Foo { - type Target = Bar; -} - -fn main() { - test(&Foo); -} -fn test(arg: &Bar) {} - "#, - ); - } - - #[test] - fn test_add_reference_to_method_call() { - check_fix( - r#" -fn main() { - Test.call_by_ref($0123); -} -struct Test; -impl Test { - fn call_by_ref(&self, arg: &i32) {} -} - "#, - r#" -fn main() { - Test.call_by_ref(&123); -} -struct Test; -impl Test { - fn call_by_ref(&self, arg: &i32) {} -} - "#, - ); - } - - #[test] - fn test_add_reference_to_let_stmt() { - check_fix( - r#" -fn main() { - let test: &i32 = $0123; -} - "#, - r#" -fn main() { - let test: &i32 = &123; -} - "#, - ); - } - - #[test] - fn test_add_mutable_reference_to_let_stmt() { - check_fix( - r#" -fn main() { - let test: &mut i32 = $0123; -} - "#, - r#" -fn main() { - let test: &mut i32 = &mut 123; -} - "#, - ); - } - - #[test] - fn test_wrap_return_type_option() { - check_fix( - r#" -//- minicore: option, result -fn div(x: i32, y: i32) -> Option { - if y == 0 { - return None; - } - x / y$0 -} -"#, - r#" -fn div(x: i32, y: i32) -> Option { - if y == 0 { - return None; - } - Some(x / y) -} -"#, - ); - } - - #[test] - fn const_generic_type_mismatch() { - check_diagnostics( - r#" - pub struct Rate; - fn f() -> Rate { // FIXME: add some error - loop {} - } - fn run(t: Rate<5>) { - } - fn main() { - run(f()) // FIXME: remove this error - //^^^ error: expected Rate<5>, found Rate<_> - } -"#, - ); - } - - #[test] - fn const_generic_unknown() { - check_diagnostics( - r#" - pub struct Rate(T); - fn run(t: Rate) { - } - fn main() { - run(Rate::<_, _, _>(5)); - } -"#, - ); - } - - #[test] - fn test_wrap_return_type_option_tails() { - check_fix( - r#" -//- minicore: option, result -fn div(x: i32, y: i32) -> Option { - if y == 0 { - Some(0) - } else if true { - 100$0 - } else { - None - } -} -"#, - r#" -fn div(x: i32, y: i32) -> Option { - if y == 0 { - Some(0) - } else if true { - Some(100) - } else { - None - } -} -"#, - ); - } - - #[test] - fn test_wrap_return_type() { - check_fix( - r#" -//- minicore: option, result -fn div(x: i32, y: i32) -> Result { - if y == 0 { - return Err(()); - } - x / y$0 -} -"#, - r#" -fn div(x: i32, y: i32) -> Result { - if y == 0 { - return Err(()); - } - Ok(x / y) -} -"#, - ); - } - - #[test] - fn test_wrap_return_type_handles_generic_functions() { - check_fix( - r#" -//- minicore: option, result -fn div(x: T) -> Result { - if x == 0 { - return Err(7); - } - $0x -} -"#, - r#" -fn div(x: T) -> Result { - if x == 0 { - return Err(7); - } - Ok(x) -} -"#, - ); - } - - #[test] - fn test_wrap_return_type_handles_type_aliases() { - check_fix( - r#" -//- minicore: option, result -type MyResult = Result; - -fn div(x: i32, y: i32) -> MyResult { - if y == 0 { - return Err(()); - } - x $0/ y -} -"#, - r#" -type MyResult = Result; - -fn div(x: i32, y: i32) -> MyResult { - if y == 0 { - return Err(()); - } - Ok(x / y) -} -"#, - ); - } - - #[test] - fn test_in_const_and_static() { - check_fix( - r#" -//- minicore: option, result -static A: Option<()> = {($0)}; - "#, - r#" -static A: Option<()> = {Some(())}; - "#, - ); - check_fix( - r#" -//- minicore: option, result -const _: Option<()> = {($0)}; - "#, - r#" -const _: Option<()> = {Some(())}; - "#, - ); - } - - #[test] - fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() { - check_no_fix( - r#" -//- minicore: option, result -fn foo() -> Result<(), i32> { 0$0 } -"#, - ); - } - - #[test] - fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() { - check_no_fix( - r#" -//- minicore: option, result -enum SomeOtherEnum { Ok(i32), Err(String) } - -fn foo() -> SomeOtherEnum { 0$0 } -"#, - ); - } - - #[test] - fn remove_semicolon() { - check_fix(r#"fn f() -> i32 { 92$0; }"#, r#"fn f() -> i32 { 92 }"#); - } - - #[test] - fn str_ref_to_owned() { - check_fix( - r#" -struct String; - -fn test() -> String { - "a"$0 -} - "#, - r#" -struct String; - -fn test() -> String { - "a".to_owned() -} - "#, - ); - } - - #[test] - fn type_mismatch_on_block() { - cov_mark::check!(type_mismatch_on_block); - check_diagnostics( - r#" -fn f() -> i32 { - let x = 1; - let y = 2; - let _ = x + y; - } -//^ error: expected i32, found () -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs deleted file mode 100644 index e879de75cd847..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::{Diagnostic, DiagnosticsContext, Severity}; - -// Diagnostic: unimplemented-builtin-macro -// -// This diagnostic is shown for builtin macros which are not yet implemented by rust-analyzer -pub(crate) fn unimplemented_builtin_macro( - ctx: &DiagnosticsContext<'_>, - d: &hir::UnimplementedBuiltinMacro, -) -> Diagnostic { - Diagnostic::new( - "unimplemented-builtin-macro", - "unimplemented built-in macro".to_string(), - ctx.sema.diagnostics_display_range(d.node.clone()).range, - ) - .severity(Severity::WeakWarning) -} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs deleted file mode 100644 index c626932f196ba..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs +++ /dev/null @@ -1,336 +0,0 @@ -//! Diagnostic emitted for files that aren't part of any crate. - -use hir::db::DefDatabase; -use ide_db::{ - base_db::{FileId, FileLoader, SourceDatabase, SourceDatabaseExt}, - source_change::SourceChange, - RootDatabase, -}; -use syntax::{ - ast::{self, HasModuleItem, HasName}, - AstNode, TextRange, TextSize, -}; -use text_edit::TextEdit; - -use crate::{fix, Assist, Diagnostic, DiagnosticsContext, Severity}; - -// Diagnostic: unlinked-file -// -// This diagnostic is shown for files that are not included in any crate, or files that are part of -// crates rust-analyzer failed to discover. The file will not have IDE features available. -pub(crate) fn unlinked_file( - ctx: &DiagnosticsContext<'_>, - acc: &mut Vec, - file_id: FileId, -) { - // Limit diagnostic to the first few characters in the file. This matches how VS Code - // renders it with the full span, but on other editors, and is less invasive. - let range = ctx.sema.db.parse(file_id).syntax_node().text_range(); - // FIXME: This is wrong if one of the first three characters is not ascii: `//Ы`. - let range = range.intersect(TextRange::up_to(TextSize::of("..."))).unwrap_or(range); - - acc.push( - Diagnostic::new("unlinked-file", "file not included in module tree", range) - .severity(Severity::WeakWarning) - .with_fixes(fixes(ctx, file_id)), - ); -} - -fn fixes(ctx: &DiagnosticsContext<'_>, file_id: FileId) -> Option> { - // If there's an existing module that could add `mod` or `pub mod` items to include the unlinked file, - // suggest that as a fix. - - let source_root = ctx.sema.db.source_root(ctx.sema.db.file_source_root(file_id)); - let our_path = source_root.path_for_file(&file_id)?; - let (mut module_name, _) = our_path.name_and_extension()?; - - // Candidates to look for: - // - `mod.rs`, `main.rs` and `lib.rs` in the same folder - // - `$dir.rs` in the parent folder, where `$dir` is the directory containing `self.file_id` - let parent = our_path.parent()?; - let paths = { - let parent = if module_name == "mod" { - // for mod.rs we need to actually look up one higher - // and take the parent as our to be module name - let (name, _) = parent.name_and_extension()?; - module_name = name; - parent.parent()? - } else { - parent - }; - let mut paths = - vec![parent.join("mod.rs")?, parent.join("lib.rs")?, parent.join("main.rs")?]; - - // `submod/bla.rs` -> `submod.rs` - let parent_mod = (|| { - let (name, _) = parent.name_and_extension()?; - parent.parent()?.join(&format!("{}.rs", name)) - })(); - paths.extend(parent_mod); - paths - }; - - for &parent_id in paths.iter().filter_map(|path| source_root.file_for_path(path)) { - for &krate in ctx.sema.db.relevant_crates(parent_id).iter() { - let crate_def_map = ctx.sema.db.crate_def_map(krate); - for (_, module) in crate_def_map.modules() { - if module.origin.is_inline() { - // We don't handle inline `mod parent {}`s, they use different paths. - continue; - } - - if module.origin.file_id() == Some(parent_id) { - return make_fixes(ctx.sema.db, parent_id, module_name, file_id); - } - } - } - } - - None -} - -fn make_fixes( - db: &RootDatabase, - parent_file_id: FileId, - new_mod_name: &str, - added_file_id: FileId, -) -> Option> { - fn is_outline_mod(item: &ast::Item) -> bool { - matches!(item, ast::Item::Module(m) if m.item_list().is_none()) - } - - let mod_decl = format!("mod {};", new_mod_name); - let pub_mod_decl = format!("pub mod {};", new_mod_name); - - let ast: ast::SourceFile = db.parse(parent_file_id).tree(); - - let mut mod_decl_builder = TextEdit::builder(); - let mut pub_mod_decl_builder = TextEdit::builder(); - - // If there's an existing `mod m;` statement matching the new one, don't emit a fix (it's - // probably `#[cfg]`d out). - for item in ast.items() { - if let ast::Item::Module(m) = item { - if let Some(name) = m.name() { - if m.item_list().is_none() && name.to_string() == new_mod_name { - cov_mark::hit!(unlinked_file_skip_fix_when_mod_already_exists); - return None; - } - } - } - } - - // If there are existing `mod m;` items, append after them (after the first group of them, rather). - match ast.items().skip_while(|item| !is_outline_mod(item)).take_while(is_outline_mod).last() { - Some(last) => { - cov_mark::hit!(unlinked_file_append_to_existing_mods); - let offset = last.syntax().text_range().end(); - mod_decl_builder.insert(offset, format!("\n{}", mod_decl)); - pub_mod_decl_builder.insert(offset, format!("\n{}", pub_mod_decl)); - } - None => { - // Prepend before the first item in the file. - match ast.items().next() { - Some(item) => { - cov_mark::hit!(unlinked_file_prepend_before_first_item); - let offset = item.syntax().text_range().start(); - mod_decl_builder.insert(offset, format!("{}\n\n", mod_decl)); - pub_mod_decl_builder.insert(offset, format!("{}\n\n", pub_mod_decl)); - } - None => { - // No items in the file, so just append at the end. - cov_mark::hit!(unlinked_file_empty_file); - let offset = ast.syntax().text_range().end(); - mod_decl_builder.insert(offset, format!("{}\n", mod_decl)); - pub_mod_decl_builder.insert(offset, format!("{}\n", pub_mod_decl)); - } - } - } - } - - let trigger_range = db.parse(added_file_id).tree().syntax().text_range(); - Some(vec![ - fix( - "add_mod_declaration", - &format!("Insert `{}`", mod_decl), - SourceChange::from_text_edit(parent_file_id, mod_decl_builder.finish()), - trigger_range, - ), - fix( - "add_pub_mod_declaration", - &format!("Insert `{}`", pub_mod_decl), - SourceChange::from_text_edit(parent_file_id, pub_mod_decl_builder.finish()), - trigger_range, - ), - ]) -} - -#[cfg(test)] -mod tests { - - use crate::tests::{check_diagnostics, check_fix, check_fixes, check_no_fix}; - - #[test] - fn unlinked_file_prepend_first_item() { - cov_mark::check!(unlinked_file_prepend_before_first_item); - // Only tests the first one for `pub mod` since the rest are the same - check_fixes( - r#" -//- /main.rs -fn f() {} -//- /foo.rs -$0 -"#, - vec![ - r#" -mod foo; - -fn f() {} -"#, - r#" -pub mod foo; - -fn f() {} -"#, - ], - ); - } - - #[test] - fn unlinked_file_append_mod() { - cov_mark::check!(unlinked_file_append_to_existing_mods); - check_fix( - r#" -//- /main.rs -//! Comment on top - -mod preexisting; - -mod preexisting2; - -struct S; - -mod preexisting_bottom;) -//- /foo.rs -$0 -"#, - r#" -//! Comment on top - -mod preexisting; - -mod preexisting2; -mod foo; - -struct S; - -mod preexisting_bottom;) -"#, - ); - } - - #[test] - fn unlinked_file_insert_in_empty_file() { - cov_mark::check!(unlinked_file_empty_file); - check_fix( - r#" -//- /main.rs -//- /foo.rs -$0 -"#, - r#" -mod foo; -"#, - ); - } - - #[test] - fn unlinked_file_insert_in_empty_file_mod_file() { - check_fix( - r#" -//- /main.rs -//- /foo/mod.rs -$0 -"#, - r#" -mod foo; -"#, - ); - check_fix( - r#" -//- /main.rs -mod bar; -//- /bar.rs -// bar module -//- /bar/foo/mod.rs -$0 -"#, - r#" -// bar module -mod foo; -"#, - ); - } - - #[test] - fn unlinked_file_old_style_modrs() { - check_fix( - r#" -//- /main.rs -mod submod; -//- /submod/mod.rs -// in mod.rs -//- /submod/foo.rs -$0 -"#, - r#" -// in mod.rs -mod foo; -"#, - ); - } - - #[test] - fn unlinked_file_new_style_mod() { - check_fix( - r#" -//- /main.rs -mod submod; -//- /submod.rs -//- /submod/foo.rs -$0 -"#, - r#" -mod foo; -"#, - ); - } - - #[test] - fn unlinked_file_with_cfg_off() { - cov_mark::check!(unlinked_file_skip_fix_when_mod_already_exists); - check_no_fix( - r#" -//- /main.rs -#[cfg(never)] -mod foo; - -//- /foo.rs -$0 -"#, - ); - } - - #[test] - fn unlinked_file_with_cfg_on() { - check_diagnostics( - r#" -//- /main.rs -#[cfg(not(never))] -mod foo; - -//- /foo.rs -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs deleted file mode 100644 index 74e4a69c64b79..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::{Diagnostic, DiagnosticsContext}; - -// Diagnostic: unresolved-extern-crate -// -// This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate. -pub(crate) fn unresolved_extern_crate( - ctx: &DiagnosticsContext<'_>, - d: &hir::UnresolvedExternCrate, -) -> Diagnostic { - Diagnostic::new( - "unresolved-extern-crate", - "unresolved extern crate", - ctx.sema.diagnostics_display_range(d.decl.clone().map(|it| it.into())).range, - ) -} - -#[cfg(test)] -mod tests { - use crate::tests::check_diagnostics; - - #[test] - fn unresolved_extern_crate() { - check_diagnostics( - r#" -//- /main.rs crate:main deps:core -extern crate core; - extern crate doesnotexist; -//^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate -//- /lib.rs crate:core -"#, - ); - } - - #[test] - fn extern_crate_self_as() { - cov_mark::check!(extern_crate_self_as); - check_diagnostics( - r#" -//- /lib.rs - extern crate doesnotexist; -//^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate -// Should not error. -extern crate self as foo; -struct Foo; -use foo::Foo as Bar; -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs deleted file mode 100644 index e52a88459d55a..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::{Diagnostic, DiagnosticsContext}; - -// Diagnostic: unresolved-import -// -// This diagnostic is triggered if rust-analyzer is unable to resolve a path in -// a `use` declaration. -pub(crate) fn unresolved_import( - ctx: &DiagnosticsContext<'_>, - d: &hir::UnresolvedImport, -) -> Diagnostic { - Diagnostic::new( - "unresolved-import", - "unresolved import", - ctx.sema.diagnostics_display_range(d.decl.clone().map(|it| it.into())).range, - ) - // This currently results in false positives in the following cases: - // - `cfg_if!`-generated code in libstd (we don't load the sysroot correctly) - // - `core::arch` (we don't handle `#[path = "../"]` correctly) - // - proc macros and/or proc macro generated code - .experimental() -} - -#[cfg(test)] -mod tests { - use crate::tests::check_diagnostics; - - #[test] - fn unresolved_import() { - check_diagnostics( - r#" -use does_exist; -use does_not_exist; - //^^^^^^^^^^^^^^ error: unresolved import - -mod does_exist {} -"#, - ); - } - - #[test] - fn unresolved_import_in_use_tree() { - // Only the relevant part of a nested `use` item should be highlighted. - check_diagnostics( - r#" -use does_exist::{Exists, DoesntExist}; - //^^^^^^^^^^^ error: unresolved import - -use {does_not_exist::*, does_exist}; - //^^^^^^^^^^^^^^^^^ error: unresolved import - -use does_not_exist::{ - a, - //^ error: unresolved import - b, - //^ error: unresolved import - c, - //^ error: unresolved import -}; - -mod does_exist { - pub struct Exists; -} -"#, - ); - } - - #[test] - fn dedup_unresolved_import_from_unresolved_crate() { - check_diagnostics( - r#" -//- /main.rs crate:main -mod a { - extern crate doesnotexist; - //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate - - // Should not error, since we already errored for the missing crate. - use doesnotexist::{self, bla, *}; - - use crate::doesnotexist; - //^^^^^^^^^^^^^^^^^^^ error: unresolved import -} - -mod m { - use super::doesnotexist; - //^^^^^^^^^^^^^^^^^^^ error: unresolved import -} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs deleted file mode 100644 index 4b43124757f06..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::{Diagnostic, DiagnosticsContext}; - -// Diagnostic: unresolved-macro-call -// -// This diagnostic is triggered if rust-analyzer is unable to resolve the path -// to a macro in a macro invocation. -pub(crate) fn unresolved_macro_call( - ctx: &DiagnosticsContext<'_>, - d: &hir::UnresolvedMacroCall, -) -> Diagnostic { - // Use more accurate position if available. - let display_range = d - .precise_location - .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.macro_call.clone()).range); - - let bang = if d.is_bang { "!" } else { "" }; - Diagnostic::new( - "unresolved-macro-call", - format!("unresolved macro `{}{}`", d.path, bang), - display_range, - ) - .experimental() -} - -#[cfg(test)] -mod tests { - use crate::tests::check_diagnostics; - - #[test] - fn unresolved_macro_diag() { - check_diagnostics( - r#" -fn f() { - m!(); -} //^ error: unresolved macro `m!` - -"#, - ); - } - - #[test] - fn test_unresolved_macro_range() { - check_diagnostics( - r#" -foo::bar!(92); - //^^^ error: unresolved macro `foo::bar!` -"#, - ); - } - - #[test] - fn unresolved_legacy_scope_macro() { - check_diagnostics( - r#" -macro_rules! m { () => {} } - -m!(); m2!(); - //^^ error: unresolved macro `m2!` -"#, - ); - } - - #[test] - fn unresolved_module_scope_macro() { - check_diagnostics( - r#" -mod mac { -#[macro_export] -macro_rules! m { () => {} } } - -self::m!(); self::m2!(); - //^^ error: unresolved macro `self::m2!` -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs deleted file mode 100644 index b8f2a9e94a40e..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs +++ /dev/null @@ -1,156 +0,0 @@ -use hir::db::AstDatabase; -use ide_db::{assists::Assist, base_db::AnchoredPathBuf, source_change::FileSystemEdit}; -use itertools::Itertools; -use syntax::AstNode; - -use crate::{fix, Diagnostic, DiagnosticsContext}; - -// Diagnostic: unresolved-module -// -// This diagnostic is triggered if rust-analyzer is unable to discover referred module. -pub(crate) fn unresolved_module( - ctx: &DiagnosticsContext<'_>, - d: &hir::UnresolvedModule, -) -> Diagnostic { - Diagnostic::new( - "unresolved-module", - match &*d.candidates { - [] => "unresolved module".to_string(), - [candidate] => format!("unresolved module, can't find module file: {}", candidate), - [candidates @ .., last] => { - format!( - "unresolved module, can't find module file: {}, or {}", - candidates.iter().format(", "), - last - ) - } - }, - ctx.sema.diagnostics_display_range(d.decl.clone().map(|it| it.into())).range, - ) - .with_fixes(fixes(ctx, d)) -} - -fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedModule) -> Option> { - let root = ctx.sema.db.parse_or_expand(d.decl.file_id)?; - let unresolved_module = d.decl.value.to_node(&root); - Some( - d.candidates - .iter() - .map(|candidate| { - fix( - "create_module", - &format!("Create module at `{candidate}`"), - FileSystemEdit::CreateFile { - dst: AnchoredPathBuf { - anchor: d.decl.file_id.original_file(ctx.sema.db), - path: candidate.clone(), - }, - initial_contents: "".to_string(), - } - .into(), - unresolved_module.syntax().text_range(), - ) - }) - .collect(), - ) -} - -#[cfg(test)] -mod tests { - use expect_test::expect; - - use crate::tests::{check_diagnostics, check_expect}; - - #[test] - fn unresolved_module() { - check_diagnostics( - r#" -//- /lib.rs -mod foo; - mod bar; -//^^^^^^^^ 💡 error: unresolved module, can't find module file: bar.rs, or bar/mod.rs -mod baz {} -//- /foo.rs -"#, - ); - } - - #[test] - fn test_unresolved_module_diagnostic() { - check_expect( - r#"mod foo;"#, - expect![[r#" - [ - Diagnostic { - code: DiagnosticCode( - "unresolved-module", - ), - message: "unresolved module, can't find module file: foo.rs, or foo/mod.rs", - range: 0..8, - severity: Error, - unused: false, - experimental: false, - fixes: Some( - [ - Assist { - id: AssistId( - "create_module", - QuickFix, - ), - label: "Create module at `foo.rs`", - group: None, - target: 0..8, - source_change: Some( - SourceChange { - source_file_edits: {}, - file_system_edits: [ - CreateFile { - dst: AnchoredPathBuf { - anchor: FileId( - 0, - ), - path: "foo.rs", - }, - initial_contents: "", - }, - ], - is_snippet: false, - }, - ), - trigger_signature_help: false, - }, - Assist { - id: AssistId( - "create_module", - QuickFix, - ), - label: "Create module at `foo/mod.rs`", - group: None, - target: 0..8, - source_change: Some( - SourceChange { - source_file_edits: {}, - file_system_edits: [ - CreateFile { - dst: AnchoredPathBuf { - anchor: FileId( - 0, - ), - path: "foo/mod.rs", - }, - initial_contents: "", - }, - ], - is_snippet: false, - }, - ), - trigger_signature_help: false, - }, - ], - ), - }, - ] - "#]], - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs deleted file mode 100644 index 760f51f90498c..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs +++ /dev/null @@ -1,62 +0,0 @@ -use hir::db::DefDatabase; -use syntax::NodeOrToken; - -use crate::{Diagnostic, DiagnosticsContext, Severity}; - -// Diagnostic: unresolved-proc-macro -// -// This diagnostic is shown when a procedural macro can not be found. This usually means that -// procedural macro support is simply disabled (and hence is only a weak hint instead of an error), -// but can also indicate project setup problems. -// -// If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the -// `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can -// enable support for procedural macros (see `rust-analyzer.procMacro.attributes.enable`). -pub(crate) fn unresolved_proc_macro( - ctx: &DiagnosticsContext<'_>, - d: &hir::UnresolvedProcMacro, - proc_macros_enabled: bool, - proc_attr_macros_enabled: bool, -) -> Diagnostic { - // Use more accurate position if available. - let display_range = (|| { - let precise_location = d.precise_location?; - let root = ctx.sema.parse_or_expand(d.node.file_id)?; - match root.covering_element(precise_location) { - NodeOrToken::Node(it) => Some(ctx.sema.original_range(&it)), - NodeOrToken::Token(it) => d.node.with_value(it).original_file_range_opt(ctx.sema.db), - } - })() - .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.node.clone())) - .range; - - let config_enabled = match d.kind { - hir::MacroKind::Attr => proc_macros_enabled && proc_attr_macros_enabled, - _ => proc_macros_enabled, - }; - - let message = match &d.macro_name { - Some(name) => format!("proc macro `{}` not expanded", name), - None => "proc macro not expanded".to_string(), - }; - let severity = if config_enabled { Severity::Error } else { Severity::WeakWarning }; - let def_map = ctx.sema.db.crate_def_map(d.krate); - let message = format!( - "{message}: {}", - if config_enabled { - match def_map.proc_macro_loading_error() { - Some(e) => e, - None => "proc macro not found in the built dylib", - } - } else { - match d.kind { - hir::MacroKind::Attr if proc_macros_enabled => { - "attribute macro expansion is disabled" - } - _ => "proc-macro expansion is disabled", - } - }, - ); - - Diagnostic::new("unresolved-proc-macro", message, display_range).severity(severity) -} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs deleted file mode 100644 index 8b9330e040137..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs +++ /dev/null @@ -1,148 +0,0 @@ -use ide_db::{base_db::FileId, source_change::SourceChange}; -use itertools::Itertools; -use syntax::{ast, AstNode, SyntaxNode, TextRange}; -use text_edit::TextEdit; - -use crate::{fix, Diagnostic, Severity}; - -// Diagnostic: unnecessary-braces -// -// Diagnostic for unnecessary braces in `use` items. -pub(crate) fn useless_braces( - acc: &mut Vec, - file_id: FileId, - node: &SyntaxNode, -) -> Option<()> { - let use_tree_list = ast::UseTreeList::cast(node.clone())?; - if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { - // If there is a comment inside the bracketed `use`, - // assume it is a commented out module path and don't show diagnostic. - if use_tree_list.has_inner_comment() { - return Some(()); - } - - let use_range = use_tree_list.syntax().text_range(); - let edit = remove_braces(&single_use_tree).unwrap_or_else(|| { - let to_replace = single_use_tree.syntax().text().to_string(); - let mut edit_builder = TextEdit::builder(); - edit_builder.delete(use_range); - edit_builder.insert(use_range.start(), to_replace); - edit_builder.finish() - }); - - acc.push( - Diagnostic::new( - "unnecessary-braces", - "Unnecessary braces in use statement".to_string(), - use_range, - ) - .severity(Severity::WeakWarning) - .with_fixes(Some(vec![fix( - "remove_braces", - "Remove unnecessary braces", - SourceChange::from_text_edit(file_id, edit), - use_range, - )])), - ); - } - - Some(()) -} - -fn remove_braces(single_use_tree: &ast::UseTree) -> Option { - let use_tree_list_node = single_use_tree.syntax().parent()?; - if single_use_tree.path()?.segment()?.self_token().is_some() { - let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); - let end = use_tree_list_node.text_range().end(); - return Some(TextEdit::delete(TextRange::new(start, end))); - } - None -} - -#[cfg(test)] -mod tests { - use crate::tests::{check_diagnostics, check_fix}; - - #[test] - fn test_check_unnecessary_braces_in_use_statement() { - check_diagnostics( - r#" -use a; -use a::{c, d::e}; - -mod a { - mod c {} - mod d { - mod e {} - } -} -"#, - ); - check_diagnostics( - r#" -use a; -use a::{ - c, - // d::e -}; - -mod a { - mod c {} - mod d { - mod e {} - } -} -"#, - ); - check_fix( - r#" -mod b {} -use {$0b}; -"#, - r#" -mod b {} -use b; -"#, - ); - check_fix( - r#" -mod b {} -use {b$0}; -"#, - r#" -mod b {} -use b; -"#, - ); - check_fix( - r#" -mod a { mod c {} } -use a::{c$0}; -"#, - r#" -mod a { mod c {} } -use a::c; -"#, - ); - check_fix( - r#" -mod a {} -use a::{self$0}; -"#, - r#" -mod a {} -use a; -"#, - ); - check_fix( - r#" -mod a { mod c {} mod d { mod e {} } } -use a::{c, d::{e$0}}; -"#, - r#" -mod a { mod c {} mod d { mod e {} } } -use a::{c, d::e}; -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs deleted file mode 100644 index 41abaa836f5fd..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ /dev/null @@ -1,260 +0,0 @@ -//! Diagnostics rendering and fixits. -//! -//! Most of the diagnostics originate from the dark depth of the compiler, and -//! are originally expressed in term of IR. When we emit the diagnostic, we are -//! usually not in the position to decide how to best "render" it in terms of -//! user-authored source code. We are especially not in the position to offer -//! fixits, as the compiler completely lacks the infrastructure to edit the -//! source code. -//! -//! Instead, we "bubble up" raw, structured diagnostics until the `hir` crate, -//! where we "cook" them so that each diagnostic is formulated in terms of `hir` -//! types. Well, at least that's the aspiration, the "cooking" is somewhat -//! ad-hoc at the moment. Anyways, we get a bunch of ide-friendly diagnostic -//! structs from hir, and we want to render them to unified serializable -//! representation (span, level, message) here. If we can, we also provide -//! fixits. By the way, that's why we want to keep diagnostics structured -//! internally -- so that we have all the info to make fixes. -//! -//! We have one "handler" module per diagnostic code. Such a module contains -//! rendering, optional fixes and tests. It's OK if some low-level compiler -//! functionality ends up being tested via a diagnostic. -//! -//! There are also a couple of ad-hoc diagnostics implemented directly here, we -//! don't yet have a great pattern for how to do them properly. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -mod handlers { - pub(crate) mod break_outside_of_loop; - pub(crate) mod inactive_code; - pub(crate) mod incorrect_case; - pub(crate) mod invalid_derive_target; - pub(crate) mod macro_error; - pub(crate) mod malformed_derive; - pub(crate) mod mismatched_arg_count; - pub(crate) mod missing_fields; - pub(crate) mod missing_match_arms; - pub(crate) mod missing_unsafe; - pub(crate) mod no_such_field; - pub(crate) mod replace_filter_map_next_with_find_map; - pub(crate) mod type_mismatch; - pub(crate) mod unimplemented_builtin_macro; - pub(crate) mod unresolved_extern_crate; - pub(crate) mod unresolved_import; - pub(crate) mod unresolved_macro_call; - pub(crate) mod unresolved_module; - pub(crate) mod unresolved_proc_macro; - - // The handlers below are unusual, the implement the diagnostics as well. - pub(crate) mod field_shorthand; - pub(crate) mod useless_braces; - pub(crate) mod unlinked_file; -} - -#[cfg(test)] -mod tests; - -use hir::{diagnostics::AnyDiagnostic, InFile, Semantics}; -use ide_db::{ - assists::{Assist, AssistId, AssistKind, AssistResolveStrategy}, - base_db::{FileId, FileRange, SourceDatabase}, - label::Label, - source_change::SourceChange, - FxHashSet, RootDatabase, -}; -use syntax::{algo::find_node_at_range, ast::AstNode, SyntaxNodePtr, TextRange}; - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct DiagnosticCode(pub &'static str); - -impl DiagnosticCode { - pub fn as_str(&self) -> &str { - self.0 - } -} - -#[derive(Debug)] -pub struct Diagnostic { - pub code: DiagnosticCode, - pub message: String, - pub range: TextRange, - pub severity: Severity, - pub unused: bool, - pub experimental: bool, - pub fixes: Option>, -} - -impl Diagnostic { - fn new(code: &'static str, message: impl Into, range: TextRange) -> Diagnostic { - let message = message.into(); - Diagnostic { - code: DiagnosticCode(code), - message, - range, - severity: Severity::Error, - unused: false, - experimental: false, - fixes: None, - } - } - - fn experimental(mut self) -> Diagnostic { - self.experimental = true; - self - } - - fn severity(mut self, severity: Severity) -> Diagnostic { - self.severity = severity; - self - } - - fn with_fixes(mut self, fixes: Option>) -> Diagnostic { - self.fixes = fixes; - self - } - - fn with_unused(mut self, unused: bool) -> Diagnostic { - self.unused = unused; - self - } -} - -#[derive(Debug, Copy, Clone)] -pub enum Severity { - Error, - // We don't actually emit this one yet, but we should at some point. - // Warning, - WeakWarning, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum ExprFillDefaultMode { - Todo, - Default, -} -impl Default for ExprFillDefaultMode { - fn default() -> Self { - Self::Todo - } -} - -#[derive(Default, Debug, Clone)] -pub struct DiagnosticsConfig { - pub proc_macros_enabled: bool, - pub proc_attr_macros_enabled: bool, - pub disable_experimental: bool, - pub disabled: FxHashSet, - pub expr_fill_default: ExprFillDefaultMode, -} - -struct DiagnosticsContext<'a> { - config: &'a DiagnosticsConfig, - sema: Semantics<'a, RootDatabase>, - resolve: &'a AssistResolveStrategy, -} - -pub fn diagnostics( - db: &RootDatabase, - config: &DiagnosticsConfig, - resolve: &AssistResolveStrategy, - file_id: FileId, -) -> Vec { - let _p = profile::span("diagnostics"); - let sema = Semantics::new(db); - let parse = db.parse(file_id); - let mut res = Vec::new(); - - // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily. - res.extend( - parse.errors().iter().take(128).map(|err| { - Diagnostic::new("syntax-error", format!("Syntax Error: {}", err), err.range()) - }), - ); - - for node in parse.tree().syntax().descendants() { - handlers::useless_braces::useless_braces(&mut res, file_id, &node); - handlers::field_shorthand::field_shorthand(&mut res, file_id, &node); - } - - let module = sema.to_module_def(file_id); - - let ctx = DiagnosticsContext { config, sema, resolve }; - if module.is_none() { - handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id); - } - - let mut diags = Vec::new(); - if let Some(m) = module { - m.diagnostics(db, &mut diags) - } - - for diag in diags { - #[rustfmt::skip] - let d = match diag { - AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d), - AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d), - AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d), - AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d), - AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d), - AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d), - AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d), - AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d), - AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d), - AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d), - AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d), - AnyDiagnostic::UnimplementedBuiltinMacro(d) => handlers::unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d), - AnyDiagnostic::UnresolvedExternCrate(d) => handlers::unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), - AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&ctx, &d), - AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d), - AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d), - AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d, config.proc_macros_enabled, config.proc_attr_macros_enabled), - AnyDiagnostic::InvalidDeriveTarget(d) => handlers::invalid_derive_target::invalid_derive_target(&ctx, &d), - - AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) { - Some(it) => it, - None => continue, - } - }; - res.push(d) - } - - res.retain(|d| { - !ctx.config.disabled.contains(d.code.as_str()) - && !(ctx.config.disable_experimental && d.experimental) - }); - - res -} - -fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist { - let mut res = unresolved_fix(id, label, target); - res.source_change = Some(source_change); - res -} - -fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist { - assert!(!id.contains(' ')); - Assist { - id: AssistId(id, AssistKind::QuickFix), - label: Label::new(label.to_string()), - group: None, - target, - source_change: None, - trigger_signature_help: false, - } -} - -fn adjusted_display_range( - ctx: &DiagnosticsContext<'_>, - diag_ptr: InFile, - adj: &dyn Fn(N) -> Option, -) -> TextRange { - let FileRange { file_id, range } = ctx.sema.diagnostics_display_range(diag_ptr); - - let source_file = ctx.sema.db.parse(file_id); - find_node_at_range::(&source_file.syntax_node(), range) - .filter(|it| it.syntax().text_range() == range) - .and_then(adj) - .unwrap_or(range) -} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs deleted file mode 100644 index 7312bca32fed9..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs +++ /dev/null @@ -1,145 +0,0 @@ -#[cfg(not(feature = "in-rust-tree"))] -mod sourcegen; - -use expect_test::Expect; -use ide_db::{ - assists::AssistResolveStrategy, - base_db::{fixture::WithFixture, SourceDatabaseExt}, - RootDatabase, -}; -use stdx::trim_indent; -use test_utils::{assert_eq_text, extract_annotations}; - -use crate::{DiagnosticsConfig, ExprFillDefaultMode, Severity}; - -/// Takes a multi-file input fixture with annotated cursor positions, -/// and checks that: -/// * a diagnostic is produced -/// * the first diagnostic fix trigger range touches the input cursor position -/// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied -#[track_caller] -pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { - check_nth_fix(0, ra_fixture_before, ra_fixture_after); -} -/// Takes a multi-file input fixture with annotated cursor positions, -/// and checks that: -/// * a diagnostic is produced -/// * every diagnostic fixes trigger range touches the input cursor position -/// * that the contents of the file containing the cursor match `after` after each diagnostic fix is applied -pub(crate) fn check_fixes(ra_fixture_before: &str, ra_fixtures_after: Vec<&str>) { - for (i, ra_fixture_after) in ra_fixtures_after.iter().enumerate() { - check_nth_fix(i, ra_fixture_before, ra_fixture_after) - } -} - -#[track_caller] -fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) { - let after = trim_indent(ra_fixture_after); - - let (db, file_position) = RootDatabase::with_position(ra_fixture_before); - let mut conf = DiagnosticsConfig::default(); - conf.expr_fill_default = ExprFillDefaultMode::Default; - let diagnostic = - super::diagnostics(&db, &conf, &AssistResolveStrategy::All, file_position.file_id) - .pop() - .expect("no diagnostics"); - let fix = &diagnostic.fixes.expect("diagnostic misses fixes")[nth]; - let actual = { - let source_change = fix.source_change.as_ref().unwrap(); - let file_id = *source_change.source_file_edits.keys().next().unwrap(); - let mut actual = db.file_text(file_id).to_string(); - - for edit in source_change.source_file_edits.values() { - edit.apply(&mut actual); - } - actual - }; - - assert!( - fix.target.contains_inclusive(file_position.offset), - "diagnostic fix range {:?} does not touch cursor position {:?}", - fix.target, - file_position.offset - ); - assert_eq_text!(&after, &actual); -} - -/// Checks that there's a diagnostic *without* fix at `$0`. -pub(crate) fn check_no_fix(ra_fixture: &str) { - let (db, file_position) = RootDatabase::with_position(ra_fixture); - let diagnostic = super::diagnostics( - &db, - &DiagnosticsConfig::default(), - &AssistResolveStrategy::All, - file_position.file_id, - ) - .pop() - .unwrap(); - assert!(diagnostic.fixes.is_none(), "got a fix when none was expected: {:?}", diagnostic); -} - -pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) { - let (db, file_id) = RootDatabase::with_single_file(ra_fixture); - let diagnostics = super::diagnostics( - &db, - &DiagnosticsConfig::default(), - &AssistResolveStrategy::All, - file_id, - ); - expect.assert_debug_eq(&diagnostics) -} - -#[track_caller] -pub(crate) fn check_diagnostics(ra_fixture: &str) { - let mut config = DiagnosticsConfig::default(); - config.disabled.insert("inactive-code".to_string()); - check_diagnostics_with_config(config, ra_fixture) -} - -#[track_caller] -pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixture: &str) { - let (db, files) = RootDatabase::with_many_files(ra_fixture); - for file_id in files { - let diagnostics = super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id); - - let expected = extract_annotations(&*db.file_text(file_id)); - let mut actual = diagnostics - .into_iter() - .map(|d| { - let mut annotation = String::new(); - if let Some(fixes) = &d.fixes { - assert!(!fixes.is_empty()); - annotation.push_str("💡 ") - } - annotation.push_str(match d.severity { - Severity::Error => "error", - Severity::WeakWarning => "weak", - }); - annotation.push_str(": "); - annotation.push_str(&d.message); - (d.range, annotation) - }) - .collect::>(); - actual.sort_by_key(|(range, _)| range.start()); - assert_eq!(expected, actual); - } -} - -#[test] -fn test_disabled_diagnostics() { - let mut config = DiagnosticsConfig::default(); - config.disabled.insert("unresolved-module".into()); - - let (db, file_id) = RootDatabase::with_single_file(r#"mod foo;"#); - - let diagnostics = super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id); - assert!(diagnostics.is_empty()); - - let diagnostics = super::diagnostics( - &db, - &DiagnosticsConfig::default(), - &AssistResolveStrategy::All, - file_id, - ); - assert!(!diagnostics.is_empty()); -} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests/sourcegen.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests/sourcegen.rs deleted file mode 100644 index ec6558a46efb4..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests/sourcegen.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! Generates `assists.md` documentation. - -use std::{fmt, fs, io, path::PathBuf}; - -use sourcegen::project_root; - -#[test] -fn sourcegen_diagnostic_docs() { - let diagnostics = Diagnostic::collect().unwrap(); - let contents = - diagnostics.into_iter().map(|it| it.to_string()).collect::>().join("\n\n"); - let contents = sourcegen::add_preamble("sourcegen_diagnostic_docs", contents); - let dst = project_root().join("docs/user/generated_diagnostic.adoc"); - fs::write(&dst, &contents).unwrap(); -} - -#[derive(Debug)] -struct Diagnostic { - id: String, - location: sourcegen::Location, - doc: String, -} - -impl Diagnostic { - fn collect() -> io::Result> { - let handlers_dir = project_root().join("crates/ide-diagnostics/src/handlers"); - - let mut res = Vec::new(); - for path in sourcegen::list_rust_files(&handlers_dir) { - collect_file(&mut res, path)?; - } - res.sort_by(|lhs, rhs| lhs.id.cmp(&rhs.id)); - return Ok(res); - - fn collect_file(acc: &mut Vec, path: PathBuf) -> io::Result<()> { - let text = fs::read_to_string(&path)?; - let comment_blocks = sourcegen::CommentBlock::extract("Diagnostic", &text); - - for block in comment_blocks { - let id = block.id; - if let Err(msg) = is_valid_diagnostic_name(&id) { - panic!("invalid diagnostic name: {:?}:\n {}", id, msg) - } - let doc = block.contents.join("\n"); - let location = sourcegen::Location { file: path.clone(), line: block.line }; - acc.push(Diagnostic { id, location, doc }) - } - - Ok(()) - } - } -} - -fn is_valid_diagnostic_name(diagnostic: &str) -> Result<(), String> { - let diagnostic = diagnostic.trim(); - if diagnostic.find(char::is_whitespace).is_some() { - return Err("Diagnostic names can't contain whitespace symbols".into()); - } - if diagnostic.chars().any(|c| c.is_ascii_uppercase()) { - return Err("Diagnostic names can't contain uppercase symbols".into()); - } - if diagnostic.chars().any(|c| !c.is_ascii()) { - return Err("Diagnostic can't contain non-ASCII symbols".into()); - } - - Ok(()) -} - -impl fmt::Display for Diagnostic { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "=== {}\n**Source:** {}\n{}", self.id, self.location, self.doc) - } -} diff --git a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml deleted file mode 100644 index d36dd02d45c59..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "ide-ssr" -version = "0.0.0" -description = "Structural search and replace of Rust code" -license = "MIT OR Apache-2.0" -repository = "https://github.com/rust-lang/rust-analyzer" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -cov-mark = "2.0.0-pre.1" - -itertools = "0.10.3" - -text-edit = { path = "../text-edit", version = "0.0.0" } -parser = { path = "../parser", version = "0.0.0" } -syntax = { path = "../syntax", version = "0.0.0" } -ide-db = { path = "../ide-db", version = "0.0.0" } -hir = { path = "../hir", version = "0.0.0" } - -[dev-dependencies] -test-utils = { path = "../test-utils" } -expect-test = "1.4.0" diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/errors.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/errors.rs deleted file mode 100644 index c02bacae6bfe6..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/errors.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Code relating to errors produced by SSR. - -/// Constructs an SsrError taking arguments like the format macro. -macro_rules! _error { - ($fmt:expr) => {$crate::SsrError::new(format!($fmt))}; - ($fmt:expr, $($arg:tt)+) => {$crate::SsrError::new(format!($fmt, $($arg)+))} -} -pub(crate) use _error as error; - -/// Returns from the current function with an error, supplied by arguments as for format! -macro_rules! _bail { - ($($tokens:tt)*) => {return Err(crate::errors::error!($($tokens)*))} -} -pub(crate) use _bail as bail; - -#[derive(Debug, PartialEq)] -pub struct SsrError(pub(crate) String); - -impl std::fmt::Display for SsrError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Parse error: {}", self.0) - } -} - -impl SsrError { - pub(crate) fn new(message: impl Into) -> SsrError { - SsrError(message.into()) - } -} diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/fragments.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/fragments.rs deleted file mode 100644 index 503754afe7c26..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/fragments.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! When specifying SSR rule, you generally want to map one *kind* of thing to -//! the same kind of thing: path to path, expression to expression, type to -//! type. -//! -//! The problem is, while this *kind* is generally obvious to the human, the ide -//! needs to determine it somehow. We do this in a stupid way -- by pasting SSR -//! rule into different contexts and checking what works. - -use syntax::{ast, AstNode, SyntaxNode}; - -pub(crate) fn ty(s: &str) -> Result { - fragment::("type T = {};", s) -} - -pub(crate) fn item(s: &str) -> Result { - fragment::("{}", s) -} - -pub(crate) fn pat(s: &str) -> Result { - fragment::("const _: () = {let {} = ();};", s) -} - -pub(crate) fn expr(s: &str) -> Result { - fragment::("const _: () = {};", s) -} - -pub(crate) fn stmt(s: &str) -> Result { - let template = "const _: () = { {}; };"; - let input = template.replace("{}", s); - let parse = syntax::SourceFile::parse(&input); - if !parse.errors().is_empty() { - return Err(()); - } - let mut node = - parse.tree().syntax().descendants().skip(2).find_map(ast::Stmt::cast).ok_or(())?; - if !s.ends_with(';') && node.to_string().ends_with(';') { - node = node.clone_for_update(); - node.syntax().last_token().map(|it| it.detach()); - } - if node.to_string() != s { - return Err(()); - } - Ok(node.syntax().clone_subtree()) -} - -fn fragment(template: &str, s: &str) -> Result { - let s = s.trim(); - let input = template.replace("{}", s); - let parse = syntax::SourceFile::parse(&input); - if !parse.errors().is_empty() { - return Err(()); - } - let node = parse.tree().syntax().descendants().find_map(T::cast).ok_or(())?; - if node.syntax().text() != s { - return Err(()); - } - Ok(node.syntax().clone_subtree()) -} diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/from_comment.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/from_comment.rs deleted file mode 100644 index 5b6e016251b40..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/from_comment.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! This module allows building an SSR MatchFinder by parsing the SSR rule -//! from a comment. - -use ide_db::{ - base_db::{FilePosition, FileRange, SourceDatabase}, - RootDatabase, -}; -use syntax::{ - ast::{self, AstNode, AstToken}, - TextRange, -}; - -use crate::MatchFinder; - -/// Attempts to build an SSR MatchFinder from a comment at the given file -/// range. If successful, returns the MatchFinder and a TextRange covering -/// comment. -pub fn ssr_from_comment( - db: &RootDatabase, - frange: FileRange, -) -> Option<(MatchFinder<'_>, TextRange)> { - let comment = { - let file = db.parse(frange.file_id); - file.tree().syntax().token_at_offset(frange.range.start()).find_map(ast::Comment::cast) - }?; - let comment_text_without_prefix = comment.text().strip_prefix(comment.prefix()).unwrap(); - let ssr_rule = comment_text_without_prefix.parse().ok()?; - - let lookup_context = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; - - let mut match_finder = MatchFinder::in_context(db, lookup_context, vec![]).ok()?; - match_finder.add_rule(ssr_rule).ok()?; - - Some((match_finder, comment.syntax().text_range())) -} diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs deleted file mode 100644 index a5e24daa9fa01..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs +++ /dev/null @@ -1,358 +0,0 @@ -//! Structural Search Replace -//! -//! Allows searching the AST for code that matches one or more patterns and then replacing that code -//! based on a template. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -// Feature: Structural Search and Replace -// -// Search and replace with named wildcards that will match any expression, type, path, pattern or item. -// The syntax for a structural search replace command is ` ==>> `. -// A `$` placeholder in the search pattern will match any AST node and `$` will reference it in the replacement. -// Within a macro call, a placeholder will match up until whatever token follows the placeholder. -// -// All paths in both the search pattern and the replacement template must resolve in the context -// in which this command is invoked. Paths in the search pattern will then match the code if they -// resolve to the same item, even if they're written differently. For example if we invoke the -// command in the module `foo` with a pattern of `Bar`, then code in the parent module that refers -// to `foo::Bar` will match. -// -// Paths in the replacement template will be rendered appropriately for the context in which the -// replacement occurs. For example if our replacement template is `foo::Bar` and we match some -// code in the `foo` module, we'll insert just `Bar`. -// -// Inherent method calls should generally be written in UFCS form. e.g. `foo::Bar::baz($s, $a)` will -// match `$s.baz($a)`, provided the method call `baz` resolves to the method `foo::Bar::baz`. When a -// placeholder is the receiver of a method call in the search pattern (e.g. `$s.foo()`), but not in -// the replacement template (e.g. `bar($s)`), then *, & and &mut will be added as needed to mirror -// whatever autoderef and autoref was happening implicitly in the matched code. -// -// The scope of the search / replace will be restricted to the current selection if any, otherwise -// it will apply to the whole workspace. -// -// Placeholders may be given constraints by writing them as `${::...}`. -// -// Supported constraints: -// -// |=== -// | Constraint | Restricts placeholder -// -// | kind(literal) | Is a literal (e.g. `42` or `"forty two"`) -// | not(a) | Negates the constraint `a` -// |=== -// -// Available via the command `rust-analyzer.ssr`. -// -// ```rust -// // Using structural search replace command [foo($a, $b) ==>> ($a).foo($b)] -// -// // BEFORE -// String::from(foo(y + 5, z)) -// -// // AFTER -// String::from((y + 5).foo(z)) -// ``` -// -// |=== -// | Editor | Action Name -// -// | VS Code | **Rust Analyzer: Structural Search Replace** -// |=== -// -// Also available as an assist, by writing a comment containing the structural -// search and replace rule. You will only see the assist if the comment can -// be parsed as a valid structural search and replace rule. -// -// ```rust -// // Place the cursor on the line below to see the assist 💡. -// // foo($a, $b) ==>> ($a).foo($b) -// ``` - -mod from_comment; -mod matching; -mod nester; -mod parsing; -mod fragments; -mod replacing; -mod resolving; -mod search; -#[macro_use] -mod errors; -#[cfg(test)] -mod tests; - -pub use crate::{errors::SsrError, from_comment::ssr_from_comment, matching::Match}; - -use crate::{errors::bail, matching::MatchFailureReason}; -use hir::Semantics; -use ide_db::{ - base_db::{FileId, FilePosition, FileRange}, - FxHashMap, -}; -use resolving::ResolvedRule; -use syntax::{ast, AstNode, SyntaxNode, TextRange}; -use text_edit::TextEdit; - -// A structured search replace rule. Create by calling `parse` on a str. -#[derive(Debug)] -pub struct SsrRule { - /// A structured pattern that we're searching for. - pattern: parsing::RawPattern, - /// What we'll replace it with. - template: parsing::RawPattern, - parsed_rules: Vec, -} - -#[derive(Debug)] -pub struct SsrPattern { - parsed_rules: Vec, -} - -#[derive(Debug, Default)] -pub struct SsrMatches { - pub matches: Vec, -} - -/// Searches a crate for pattern matches and possibly replaces them with something else. -pub struct MatchFinder<'db> { - /// Our source of information about the user's code. - sema: Semantics<'db, ide_db::RootDatabase>, - rules: Vec, - resolution_scope: resolving::ResolutionScope<'db>, - restrict_ranges: Vec, -} - -impl<'db> MatchFinder<'db> { - /// Constructs a new instance where names will be looked up as if they appeared at - /// `lookup_context`. - pub fn in_context( - db: &'db ide_db::RootDatabase, - lookup_context: FilePosition, - mut restrict_ranges: Vec, - ) -> Result, SsrError> { - restrict_ranges.retain(|range| !range.range.is_empty()); - let sema = Semantics::new(db); - let resolution_scope = resolving::ResolutionScope::new(&sema, lookup_context) - .ok_or_else(|| SsrError("no resolution scope for file".into()))?; - Ok(MatchFinder { sema, rules: Vec::new(), resolution_scope, restrict_ranges }) - } - - /// Constructs an instance using the start of the first file in `db` as the lookup context. - pub fn at_first_file(db: &'db ide_db::RootDatabase) -> Result, SsrError> { - use ide_db::base_db::SourceDatabaseExt; - use ide_db::symbol_index::SymbolsDatabase; - if let Some(first_file_id) = - db.local_roots().iter().next().and_then(|root| db.source_root(*root).iter().next()) - { - MatchFinder::in_context( - db, - FilePosition { file_id: first_file_id, offset: 0.into() }, - vec![], - ) - } else { - bail!("No files to search"); - } - } - - /// Adds a rule to be applied. The order in which rules are added matters. Earlier rules take - /// precedence. If a node is matched by an earlier rule, then later rules won't be permitted to - /// match to it. - pub fn add_rule(&mut self, rule: SsrRule) -> Result<(), SsrError> { - for parsed_rule in rule.parsed_rules { - self.rules.push(ResolvedRule::new( - parsed_rule, - &self.resolution_scope, - self.rules.len(), - )?); - } - Ok(()) - } - - /// Finds matches for all added rules and returns edits for all found matches. - pub fn edits(&self) -> FxHashMap { - use ide_db::base_db::SourceDatabaseExt; - let mut matches_by_file = FxHashMap::default(); - for m in self.matches().matches { - matches_by_file - .entry(m.range.file_id) - .or_insert_with(SsrMatches::default) - .matches - .push(m); - } - matches_by_file - .into_iter() - .map(|(file_id, matches)| { - ( - file_id, - replacing::matches_to_edit( - &matches, - &self.sema.db.file_text(file_id), - &self.rules, - ), - ) - }) - .collect() - } - - /// Adds a search pattern. For use if you intend to only call `find_matches_in_file`. If you - /// intend to do replacement, use `add_rule` instead. - pub fn add_search_pattern(&mut self, pattern: SsrPattern) -> Result<(), SsrError> { - for parsed_rule in pattern.parsed_rules { - self.rules.push(ResolvedRule::new( - parsed_rule, - &self.resolution_scope, - self.rules.len(), - )?); - } - Ok(()) - } - - /// Returns matches for all added rules. - pub fn matches(&self) -> SsrMatches { - let mut matches = Vec::new(); - let mut usage_cache = search::UsageCache::default(); - for rule in &self.rules { - self.find_matches_for_rule(rule, &mut usage_cache, &mut matches); - } - nester::nest_and_remove_collisions(matches, &self.sema) - } - - /// Finds all nodes in `file_id` whose text is exactly equal to `snippet` and attempts to match - /// them, while recording reasons why they don't match. This API is useful for command - /// line-based debugging where providing a range is difficult. - pub fn debug_where_text_equal(&self, file_id: FileId, snippet: &str) -> Vec { - use ide_db::base_db::SourceDatabaseExt; - let file = self.sema.parse(file_id); - let mut res = Vec::new(); - let file_text = self.sema.db.file_text(file_id); - let mut remaining_text = file_text.as_str(); - let mut base = 0; - let len = snippet.len() as u32; - while let Some(offset) = remaining_text.find(snippet) { - let start = base + offset as u32; - let end = start + len; - self.output_debug_for_nodes_at_range( - file.syntax(), - FileRange { file_id, range: TextRange::new(start.into(), end.into()) }, - &None, - &mut res, - ); - remaining_text = &remaining_text[offset + snippet.len()..]; - base = end; - } - res - } - - fn output_debug_for_nodes_at_range( - &self, - node: &SyntaxNode, - range: FileRange, - restrict_range: &Option, - out: &mut Vec, - ) { - for node in node.children() { - let node_range = self.sema.original_range(&node); - if node_range.file_id != range.file_id || !node_range.range.contains_range(range.range) - { - continue; - } - if node_range.range == range.range { - for rule in &self.rules { - // For now we ignore rules that have a different kind than our node, otherwise - // we get lots of noise. If at some point we add support for restricting rules - // to a particular kind of thing (e.g. only match type references), then we can - // relax this. We special-case expressions, since function calls can match - // method calls. - if rule.pattern.node.kind() != node.kind() - && !(ast::Expr::can_cast(rule.pattern.node.kind()) - && ast::Expr::can_cast(node.kind())) - { - continue; - } - out.push(MatchDebugInfo { - matched: matching::get_match(true, rule, &node, restrict_range, &self.sema) - .map_err(|e| MatchFailureReason { - reason: e.reason.unwrap_or_else(|| { - "Match failed, but no reason was given".to_owned() - }), - }), - pattern: rule.pattern.node.clone(), - node: node.clone(), - }); - } - } else if let Some(macro_call) = ast::MacroCall::cast(node.clone()) { - if let Some(expanded) = self.sema.expand(¯o_call) { - if let Some(tt) = macro_call.token_tree() { - self.output_debug_for_nodes_at_range( - &expanded, - range, - &Some(self.sema.original_range(tt.syntax())), - out, - ); - } - } - } - self.output_debug_for_nodes_at_range(&node, range, restrict_range, out); - } - } -} - -pub struct MatchDebugInfo { - node: SyntaxNode, - /// Our search pattern parsed as an expression or item, etc - pattern: SyntaxNode, - matched: Result, -} - -impl std::fmt::Debug for MatchDebugInfo { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match &self.matched { - Ok(_) => writeln!(f, "Node matched")?, - Err(reason) => writeln!(f, "Node failed to match because: {}", reason.reason)?, - } - writeln!( - f, - "============ AST ===========\n\ - {:#?}", - self.node - )?; - writeln!(f, "========= PATTERN ==========")?; - writeln!(f, "{:#?}", self.pattern)?; - writeln!(f, "============================")?; - Ok(()) - } -} - -impl SsrMatches { - /// Returns `self` with any nested matches removed and made into top-level matches. - pub fn flattened(self) -> SsrMatches { - let mut out = SsrMatches::default(); - self.flatten_into(&mut out); - out - } - - fn flatten_into(self, out: &mut SsrMatches) { - for mut m in self.matches { - for p in m.placeholder_values.values_mut() { - std::mem::take(&mut p.inner_matches).flatten_into(out); - } - out.matches.push(m); - } - } -} - -impl Match { - pub fn matched_text(&self) -> String { - self.matched_node.text().to_string() - } -} - -impl std::error::Error for SsrError {} - -#[cfg(test)] -impl MatchDebugInfo { - pub(crate) fn match_failure_reason(&self) -> Option<&str> { - self.matched.as_ref().err().map(|r| r.reason.as_str()) - } -} diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs deleted file mode 100644 index e3a837ddcdb05..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs +++ /dev/null @@ -1,803 +0,0 @@ -//! This module is responsible for matching a search pattern against a node in the AST. In the -//! process of matching, placeholder values are recorded. - -use crate::{ - parsing::{Constraint, NodeKind, Placeholder, Var}, - resolving::{ResolvedPattern, ResolvedRule, UfcsCallInfo}, - SsrMatches, -}; -use hir::Semantics; -use ide_db::{base_db::FileRange, FxHashMap}; -use std::{cell::Cell, iter::Peekable}; -use syntax::{ - ast::{self, AstNode, AstToken}, - SmolStr, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken, -}; - -// Creates a match error. If we're currently attempting to match some code that we thought we were -// going to match, as indicated by the --debug-snippet flag, then populate the reason field. -macro_rules! match_error { - ($e:expr) => {{ - MatchFailed { - reason: if recording_match_fail_reasons() { - Some(format!("{}", $e)) - } else { - None - } - } - }}; - ($fmt:expr, $($arg:tt)+) => {{ - MatchFailed { - reason: if recording_match_fail_reasons() { - Some(format!($fmt, $($arg)+)) - } else { - None - } - } - }}; -} - -// Fails the current match attempt, recording the supplied reason if we're recording match fail reasons. -macro_rules! fail_match { - ($($args:tt)*) => {return Err(match_error!($($args)*))}; -} - -/// Information about a match that was found. -#[derive(Debug)] -pub struct Match { - pub(crate) range: FileRange, - pub(crate) matched_node: SyntaxNode, - pub(crate) placeholder_values: FxHashMap, - pub(crate) ignored_comments: Vec, - pub(crate) rule_index: usize, - /// The depth of matched_node. - pub(crate) depth: usize, - // Each path in the template rendered for the module in which the match was found. - pub(crate) rendered_template_paths: FxHashMap, -} - -/// Information about a placeholder bound in a match. -#[derive(Debug)] -pub(crate) struct PlaceholderMatch { - pub(crate) range: FileRange, - /// More matches, found within `node`. - pub(crate) inner_matches: SsrMatches, - /// How many times the code that the placeholder matched needed to be dereferenced. Will only be - /// non-zero if the placeholder matched to the receiver of a method call. - pub(crate) autoderef_count: usize, - pub(crate) autoref_kind: ast::SelfParamKind, -} - -#[derive(Debug)] -pub(crate) struct MatchFailureReason { - pub(crate) reason: String, -} - -/// An "error" indicating that matching failed. Use the fail_match! macro to create and return this. -#[derive(Clone)] -pub(crate) struct MatchFailed { - /// The reason why we failed to match. Only present when debug_active true in call to - /// `get_match`. - pub(crate) reason: Option, -} - -/// Checks if `code` matches the search pattern found in `search_scope`, returning information about -/// the match, if it does. Since we only do matching in this module and searching is done by the -/// parent module, we don't populate nested matches. -pub(crate) fn get_match( - debug_active: bool, - rule: &ResolvedRule, - code: &SyntaxNode, - restrict_range: &Option, - sema: &Semantics<'_, ide_db::RootDatabase>, -) -> Result { - record_match_fails_reasons_scope(debug_active, || { - Matcher::try_match(rule, code, restrict_range, sema) - }) -} - -/// Checks if our search pattern matches a particular node of the AST. -struct Matcher<'db, 'sema> { - sema: &'sema Semantics<'db, ide_db::RootDatabase>, - /// If any placeholders come from anywhere outside of this range, then the match will be - /// rejected. - restrict_range: Option, - rule: &'sema ResolvedRule, -} - -/// Which phase of matching we're currently performing. We do two phases because most attempted -/// matches will fail and it means we can defer more expensive checks to the second phase. -enum Phase<'a> { - /// On the first phase, we perform cheap checks. No state is mutated and nothing is recorded. - First, - /// On the second phase, we construct the `Match`. Things like what placeholders bind to is - /// recorded. - Second(&'a mut Match), -} - -impl<'db, 'sema> Matcher<'db, 'sema> { - fn try_match( - rule: &ResolvedRule, - code: &SyntaxNode, - restrict_range: &Option, - sema: &'sema Semantics<'db, ide_db::RootDatabase>, - ) -> Result { - let match_state = Matcher { sema, restrict_range: *restrict_range, rule }; - // First pass at matching, where we check that node types and idents match. - match_state.attempt_match_node(&mut Phase::First, &rule.pattern.node, code)?; - match_state.validate_range(&sema.original_range(code))?; - let mut the_match = Match { - range: sema.original_range(code), - matched_node: code.clone(), - placeholder_values: FxHashMap::default(), - ignored_comments: Vec::new(), - rule_index: rule.index, - depth: 0, - rendered_template_paths: FxHashMap::default(), - }; - // Second matching pass, where we record placeholder matches, ignored comments and maybe do - // any other more expensive checks that we didn't want to do on the first pass. - match_state.attempt_match_node( - &mut Phase::Second(&mut the_match), - &rule.pattern.node, - code, - )?; - the_match.depth = sema.ancestors_with_macros(the_match.matched_node.clone()).count(); - if let Some(template) = &rule.template { - the_match.render_template_paths(template, sema)?; - } - Ok(the_match) - } - - /// Checks that `range` is within the permitted range if any. This is applicable when we're - /// processing a macro expansion and we want to fail the match if we're working with a node that - /// didn't originate from the token tree of the macro call. - fn validate_range(&self, range: &FileRange) -> Result<(), MatchFailed> { - if let Some(restrict_range) = &self.restrict_range { - if restrict_range.file_id != range.file_id - || !restrict_range.range.contains_range(range.range) - { - fail_match!("Node originated from a macro"); - } - } - Ok(()) - } - - fn attempt_match_node( - &self, - phase: &mut Phase<'_>, - pattern: &SyntaxNode, - code: &SyntaxNode, - ) -> Result<(), MatchFailed> { - // Handle placeholders. - if let Some(placeholder) = self.get_placeholder_for_node(pattern) { - for constraint in &placeholder.constraints { - self.check_constraint(constraint, code)?; - } - if let Phase::Second(matches_out) = phase { - let original_range = self.sema.original_range(code); - // We validated the range for the node when we started the match, so the placeholder - // probably can't fail range validation, but just to be safe... - self.validate_range(&original_range)?; - matches_out.placeholder_values.insert( - placeholder.ident.clone(), - PlaceholderMatch::from_range(original_range), - ); - } - return Ok(()); - } - // We allow a UFCS call to match a method call, provided they resolve to the same function. - if let Some(pattern_ufcs) = self.rule.pattern.ufcs_function_calls.get(pattern) { - if let Some(code) = ast::MethodCallExpr::cast(code.clone()) { - return self.attempt_match_ufcs_to_method_call(phase, pattern_ufcs, &code); - } - if let Some(code) = ast::CallExpr::cast(code.clone()) { - return self.attempt_match_ufcs_to_ufcs(phase, pattern_ufcs, &code); - } - } - if pattern.kind() != code.kind() { - fail_match!( - "Pattern had `{}` ({:?}), code had `{}` ({:?})", - pattern.text(), - pattern.kind(), - code.text(), - code.kind() - ); - } - // Some kinds of nodes have special handling. For everything else, we fall back to default - // matching. - match code.kind() { - SyntaxKind::RECORD_EXPR_FIELD_LIST => { - self.attempt_match_record_field_list(phase, pattern, code) - } - SyntaxKind::TOKEN_TREE => self.attempt_match_token_tree(phase, pattern, code), - SyntaxKind::PATH => self.attempt_match_path(phase, pattern, code), - _ => self.attempt_match_node_children(phase, pattern, code), - } - } - - fn attempt_match_node_children( - &self, - phase: &mut Phase<'_>, - pattern: &SyntaxNode, - code: &SyntaxNode, - ) -> Result<(), MatchFailed> { - self.attempt_match_sequences( - phase, - PatternIterator::new(pattern), - code.children_with_tokens(), - ) - } - - fn attempt_match_sequences( - &self, - phase: &mut Phase<'_>, - pattern_it: PatternIterator, - mut code_it: SyntaxElementChildren, - ) -> Result<(), MatchFailed> { - let mut pattern_it = pattern_it.peekable(); - loop { - match phase.next_non_trivial(&mut code_it) { - None => { - if let Some(p) = pattern_it.next() { - fail_match!("Part of the pattern was unmatched: {:?}", p); - } - return Ok(()); - } - Some(SyntaxElement::Token(c)) => { - self.attempt_match_token(phase, &mut pattern_it, &c)?; - } - Some(SyntaxElement::Node(c)) => match pattern_it.next() { - Some(SyntaxElement::Node(p)) => { - self.attempt_match_node(phase, &p, &c)?; - } - Some(p) => fail_match!("Pattern wanted '{}', code has {}", p, c.text()), - None => fail_match!("Pattern reached end, code has {}", c.text()), - }, - } - } - } - - fn attempt_match_token( - &self, - phase: &mut Phase<'_>, - pattern: &mut Peekable, - code: &syntax::SyntaxToken, - ) -> Result<(), MatchFailed> { - phase.record_ignored_comments(code); - // Ignore whitespace and comments. - if code.kind().is_trivia() { - return Ok(()); - } - if let Some(SyntaxElement::Token(p)) = pattern.peek() { - // If the code has a comma and the pattern is about to close something, then accept the - // comma without advancing the pattern. i.e. ignore trailing commas. - if code.kind() == SyntaxKind::COMMA && is_closing_token(p.kind()) { - return Ok(()); - } - // Conversely, if the pattern has a comma and the code doesn't, skip that part of the - // pattern and continue to match the code. - if p.kind() == SyntaxKind::COMMA && is_closing_token(code.kind()) { - pattern.next(); - } - } - // Consume an element from the pattern and make sure it matches. - match pattern.next() { - Some(SyntaxElement::Token(p)) => { - if p.kind() != code.kind() || p.text() != code.text() { - fail_match!( - "Pattern wanted token '{}' ({:?}), but code had token '{}' ({:?})", - p.text(), - p.kind(), - code.text(), - code.kind() - ) - } - } - Some(SyntaxElement::Node(p)) => { - // Not sure if this is actually reachable. - fail_match!( - "Pattern wanted {:?}, but code had token '{}' ({:?})", - p, - code.text(), - code.kind() - ); - } - None => { - fail_match!("Pattern exhausted, while code remains: `{}`", code.text()); - } - } - Ok(()) - } - - fn check_constraint( - &self, - constraint: &Constraint, - code: &SyntaxNode, - ) -> Result<(), MatchFailed> { - match constraint { - Constraint::Kind(kind) => { - kind.matches(code)?; - } - Constraint::Not(sub) => { - if self.check_constraint(&*sub, code).is_ok() { - fail_match!("Constraint {:?} failed for '{}'", constraint, code.text()); - } - } - } - Ok(()) - } - - /// Paths are matched based on whether they refer to the same thing, even if they're written - /// differently. - fn attempt_match_path( - &self, - phase: &mut Phase<'_>, - pattern: &SyntaxNode, - code: &SyntaxNode, - ) -> Result<(), MatchFailed> { - if let Some(pattern_resolved) = self.rule.pattern.resolved_paths.get(pattern) { - let pattern_path = ast::Path::cast(pattern.clone()).unwrap(); - let code_path = ast::Path::cast(code.clone()).unwrap(); - if let (Some(pattern_segment), Some(code_segment)) = - (pattern_path.segment(), code_path.segment()) - { - // Match everything within the segment except for the name-ref, which is handled - // separately via comparing what the path resolves to below. - self.attempt_match_opt( - phase, - pattern_segment.generic_arg_list(), - code_segment.generic_arg_list(), - )?; - self.attempt_match_opt( - phase, - pattern_segment.param_list(), - code_segment.param_list(), - )?; - } - if matches!(phase, Phase::Second(_)) { - let resolution = self - .sema - .resolve_path(&code_path) - .ok_or_else(|| match_error!("Failed to resolve path `{}`", code.text()))?; - if pattern_resolved.resolution != resolution { - fail_match!("Pattern had path `{}` code had `{}`", pattern.text(), code.text()); - } - } - } else { - return self.attempt_match_node_children(phase, pattern, code); - } - Ok(()) - } - - fn attempt_match_opt( - &self, - phase: &mut Phase<'_>, - pattern: Option, - code: Option, - ) -> Result<(), MatchFailed> { - match (pattern, code) { - (Some(p), Some(c)) => self.attempt_match_node(phase, p.syntax(), c.syntax()), - (None, None) => Ok(()), - (Some(p), None) => fail_match!("Pattern `{}` had nothing to match", p.syntax().text()), - (None, Some(c)) => { - fail_match!("Nothing in pattern to match code `{}`", c.syntax().text()) - } - } - } - - /// We want to allow the records to match in any order, so we have special matching logic for - /// them. - fn attempt_match_record_field_list( - &self, - phase: &mut Phase<'_>, - pattern: &SyntaxNode, - code: &SyntaxNode, - ) -> Result<(), MatchFailed> { - // Build a map keyed by field name. - let mut fields_by_name: FxHashMap = FxHashMap::default(); - for child in code.children() { - if let Some(record) = ast::RecordExprField::cast(child.clone()) { - if let Some(name) = record.field_name() { - fields_by_name.insert(name.text().into(), child.clone()); - } - } - } - for p in pattern.children_with_tokens() { - if let SyntaxElement::Node(p) = p { - if let Some(name_element) = p.first_child_or_token() { - if self.get_placeholder(&name_element).is_some() { - // If the pattern is using placeholders for field names then order - // independence doesn't make sense. Fall back to regular ordered - // matching. - return self.attempt_match_node_children(phase, pattern, code); - } - if let Some(ident) = only_ident(name_element) { - let code_record = fields_by_name.remove(ident.text()).ok_or_else(|| { - match_error!( - "Placeholder has record field '{}', but code doesn't", - ident - ) - })?; - self.attempt_match_node(phase, &p, &code_record)?; - } - } - } - } - if let Some(unmatched_fields) = fields_by_name.keys().next() { - fail_match!( - "{} field(s) of a record literal failed to match, starting with {}", - fields_by_name.len(), - unmatched_fields - ); - } - Ok(()) - } - - /// Outside of token trees, a placeholder can only match a single AST node, whereas in a token - /// tree it can match a sequence of tokens. Note, that this code will only be used when the - /// pattern matches the macro invocation. For matches within the macro call, we'll already have - /// expanded the macro. - fn attempt_match_token_tree( - &self, - phase: &mut Phase<'_>, - pattern: &SyntaxNode, - code: &syntax::SyntaxNode, - ) -> Result<(), MatchFailed> { - let mut pattern = PatternIterator::new(pattern).peekable(); - let mut children = code.children_with_tokens(); - while let Some(child) = children.next() { - if let Some(placeholder) = pattern.peek().and_then(|p| self.get_placeholder(p)) { - pattern.next(); - let next_pattern_token = pattern - .peek() - .and_then(|p| match p { - SyntaxElement::Token(t) => Some(t.clone()), - SyntaxElement::Node(n) => n.first_token(), - }) - .map(|p| p.text().to_string()); - let first_matched_token = child.clone(); - let mut last_matched_token = child; - // Read code tokens util we reach one equal to the next token from our pattern - // or we reach the end of the token tree. - for next in &mut children { - match &next { - SyntaxElement::Token(t) => { - if Some(t.to_string()) == next_pattern_token { - pattern.next(); - break; - } - } - SyntaxElement::Node(n) => { - if let Some(first_token) = n.first_token() { - if Some(first_token.text()) == next_pattern_token.as_deref() { - if let Some(SyntaxElement::Node(p)) = pattern.next() { - // We have a subtree that starts with the next token in our pattern. - self.attempt_match_token_tree(phase, &p, n)?; - break; - } - } - } - } - }; - last_matched_token = next; - } - if let Phase::Second(match_out) = phase { - match_out.placeholder_values.insert( - placeholder.ident.clone(), - PlaceholderMatch::from_range(FileRange { - file_id: self.sema.original_range(code).file_id, - range: first_matched_token - .text_range() - .cover(last_matched_token.text_range()), - }), - ); - } - continue; - } - // Match literal (non-placeholder) tokens. - match child { - SyntaxElement::Token(token) => { - self.attempt_match_token(phase, &mut pattern, &token)?; - } - SyntaxElement::Node(node) => match pattern.next() { - Some(SyntaxElement::Node(p)) => { - self.attempt_match_token_tree(phase, &p, &node)?; - } - Some(SyntaxElement::Token(p)) => fail_match!( - "Pattern has token '{}', code has subtree '{}'", - p.text(), - node.text() - ), - None => fail_match!("Pattern has nothing, code has '{}'", node.text()), - }, - } - } - if let Some(p) = pattern.next() { - fail_match!("Reached end of token tree in code, but pattern still has {:?}", p); - } - Ok(()) - } - - fn attempt_match_ufcs_to_method_call( - &self, - phase: &mut Phase<'_>, - pattern_ufcs: &UfcsCallInfo, - code: &ast::MethodCallExpr, - ) -> Result<(), MatchFailed> { - use ast::HasArgList; - let code_resolved_function = self - .sema - .resolve_method_call(code) - .ok_or_else(|| match_error!("Failed to resolve method call"))?; - if pattern_ufcs.function != code_resolved_function { - fail_match!("Method call resolved to a different function"); - } - // Check arguments. - let mut pattern_args = pattern_ufcs - .call_expr - .arg_list() - .ok_or_else(|| match_error!("Pattern function call has no args"))? - .args(); - // If the function we're calling takes a self parameter, then we store additional - // information on the placeholder match about autoderef and autoref. This allows us to use - // the placeholder in a context where autoderef and autoref don't apply. - if code_resolved_function.self_param(self.sema.db).is_some() { - if let (Some(pattern_type), Some(expr)) = - (&pattern_ufcs.qualifier_type, &code.receiver()) - { - let deref_count = self.check_expr_type(pattern_type, expr)?; - let pattern_receiver = pattern_args.next(); - self.attempt_match_opt(phase, pattern_receiver.clone(), code.receiver())?; - if let Phase::Second(match_out) = phase { - if let Some(placeholder_value) = pattern_receiver - .and_then(|n| self.get_placeholder_for_node(n.syntax())) - .and_then(|placeholder| { - match_out.placeholder_values.get_mut(&placeholder.ident) - }) - { - placeholder_value.autoderef_count = deref_count; - placeholder_value.autoref_kind = self - .sema - .resolve_method_call_as_callable(code) - .and_then(|callable| callable.receiver_param(self.sema.db)) - .map(|self_param| self_param.kind()) - .unwrap_or(ast::SelfParamKind::Owned); - } - } - } - } else { - self.attempt_match_opt(phase, pattern_args.next(), code.receiver())?; - } - let mut code_args = - code.arg_list().ok_or_else(|| match_error!("Code method call has no args"))?.args(); - loop { - match (pattern_args.next(), code_args.next()) { - (None, None) => return Ok(()), - (p, c) => self.attempt_match_opt(phase, p, c)?, - } - } - } - - fn attempt_match_ufcs_to_ufcs( - &self, - phase: &mut Phase<'_>, - pattern_ufcs: &UfcsCallInfo, - code: &ast::CallExpr, - ) -> Result<(), MatchFailed> { - use ast::HasArgList; - // Check that the first argument is the expected type. - if let (Some(pattern_type), Some(expr)) = ( - &pattern_ufcs.qualifier_type, - &code.arg_list().and_then(|code_args| code_args.args().next()), - ) { - self.check_expr_type(pattern_type, expr)?; - } - self.attempt_match_node_children(phase, pattern_ufcs.call_expr.syntax(), code.syntax()) - } - - /// Verifies that `expr` matches `pattern_type`, possibly after dereferencing some number of - /// times. Returns the number of times it needed to be dereferenced. - fn check_expr_type( - &self, - pattern_type: &hir::Type, - expr: &ast::Expr, - ) -> Result { - use hir::HirDisplay; - let code_type = self - .sema - .type_of_expr(expr) - .ok_or_else(|| { - match_error!("Failed to get receiver type for `{}`", expr.syntax().text()) - })? - .original; - // Temporary needed to make the borrow checker happy. - let res = code_type - .autoderef(self.sema.db) - .enumerate() - .find(|(_, deref_code_type)| pattern_type == deref_code_type) - .map(|(count, _)| count) - .ok_or_else(|| { - match_error!( - "Pattern type `{}` didn't match code type `{}`", - pattern_type.display(self.sema.db), - code_type.display(self.sema.db) - ) - }); - res - } - - fn get_placeholder_for_node(&self, node: &SyntaxNode) -> Option<&Placeholder> { - self.get_placeholder(&SyntaxElement::Node(node.clone())) - } - - fn get_placeholder(&self, element: &SyntaxElement) -> Option<&Placeholder> { - only_ident(element.clone()).and_then(|ident| self.rule.get_placeholder(&ident)) - } -} - -impl Match { - fn render_template_paths( - &mut self, - template: &ResolvedPattern, - sema: &Semantics<'_, ide_db::RootDatabase>, - ) -> Result<(), MatchFailed> { - let module = sema - .scope(&self.matched_node) - .ok_or_else(|| match_error!("Matched node isn't in a module"))? - .module(); - for (path, resolved_path) in &template.resolved_paths { - if let hir::PathResolution::Def(module_def) = resolved_path.resolution { - let mod_path = module.find_use_path(sema.db, module_def).ok_or_else(|| { - match_error!("Failed to render template path `{}` at match location") - })?; - self.rendered_template_paths.insert(path.clone(), mod_path); - } - } - Ok(()) - } -} - -impl Phase<'_> { - fn next_non_trivial(&mut self, code_it: &mut SyntaxElementChildren) -> Option { - loop { - let c = code_it.next(); - if let Some(SyntaxElement::Token(t)) = &c { - self.record_ignored_comments(t); - if t.kind().is_trivia() { - continue; - } - } - return c; - } - } - - fn record_ignored_comments(&mut self, token: &SyntaxToken) { - if token.kind() == SyntaxKind::COMMENT { - if let Phase::Second(match_out) = self { - if let Some(comment) = ast::Comment::cast(token.clone()) { - match_out.ignored_comments.push(comment); - } - } - } - } -} - -fn is_closing_token(kind: SyntaxKind) -> bool { - kind == SyntaxKind::R_PAREN || kind == SyntaxKind::R_CURLY || kind == SyntaxKind::R_BRACK -} - -pub(crate) fn record_match_fails_reasons_scope(debug_active: bool, f: F) -> T -where - F: Fn() -> T, -{ - RECORDING_MATCH_FAIL_REASONS.with(|c| c.set(debug_active)); - let res = f(); - RECORDING_MATCH_FAIL_REASONS.with(|c| c.set(false)); - res -} - -// For performance reasons, we don't want to record the reason why every match fails, only the bit -// of code that the user indicated they thought would match. We use a thread local to indicate when -// we are trying to match that bit of code. This saves us having to pass a boolean into all the bits -// of code that can make the decision to not match. -thread_local! { - pub static RECORDING_MATCH_FAIL_REASONS: Cell = Cell::new(false); -} - -fn recording_match_fail_reasons() -> bool { - RECORDING_MATCH_FAIL_REASONS.with(|c| c.get()) -} - -impl PlaceholderMatch { - fn from_range(range: FileRange) -> Self { - Self { - range, - inner_matches: SsrMatches::default(), - autoderef_count: 0, - autoref_kind: ast::SelfParamKind::Owned, - } - } -} - -impl NodeKind { - fn matches(&self, node: &SyntaxNode) -> Result<(), MatchFailed> { - let ok = match self { - Self::Literal => { - cov_mark::hit!(literal_constraint); - ast::Literal::can_cast(node.kind()) - } - }; - if !ok { - fail_match!("Code '{}' isn't of kind {:?}", node.text(), self); - } - Ok(()) - } -} - -// If `node` contains nothing but an ident then return it, otherwise return None. -fn only_ident(element: SyntaxElement) -> Option { - match element { - SyntaxElement::Token(t) => { - if t.kind() == SyntaxKind::IDENT { - return Some(t); - } - } - SyntaxElement::Node(n) => { - let mut children = n.children_with_tokens(); - if let (Some(only_child), None) = (children.next(), children.next()) { - return only_ident(only_child); - } - } - } - None -} - -struct PatternIterator { - iter: SyntaxElementChildren, -} - -impl Iterator for PatternIterator { - type Item = SyntaxElement; - - fn next(&mut self) -> Option { - for element in &mut self.iter { - if !element.kind().is_trivia() { - return Some(element); - } - } - None - } -} - -impl PatternIterator { - fn new(parent: &SyntaxNode) -> Self { - Self { iter: parent.children_with_tokens() } - } -} - -#[cfg(test)] -mod tests { - use crate::{MatchFinder, SsrRule}; - - #[test] - fn parse_match_replace() { - let rule: SsrRule = "foo($x) ==>> bar($x)".parse().unwrap(); - let input = "fn foo() {} fn bar() {} fn main() { foo(1+2); }"; - - let (db, position, selections) = crate::tests::single_file(input); - let mut match_finder = MatchFinder::in_context(&db, position, selections).unwrap(); - match_finder.add_rule(rule).unwrap(); - let matches = match_finder.matches(); - assert_eq!(matches.matches.len(), 1); - assert_eq!(matches.matches[0].matched_node.text(), "foo(1+2)"); - assert_eq!(matches.matches[0].placeholder_values.len(), 1); - - let edits = match_finder.edits(); - assert_eq!(edits.len(), 1); - let edit = &edits[&position.file_id]; - let mut after = input.to_string(); - edit.apply(&mut after); - assert_eq!(after, "fn foo() {} fn bar() {} fn main() { bar(1+2); }"); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/nester.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/nester.rs deleted file mode 100644 index afaaafd1fb491..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/nester.rs +++ /dev/null @@ -1,99 +0,0 @@ -//! Converts a flat collection of matches into a nested form suitable for replacement. When there -//! are multiple matches for a node, or that overlap, priority is given to the earlier rule. Nested -//! matches are only permitted if the inner match is contained entirely within a placeholder of an -//! outer match. -//! -//! For example, if our search pattern is `foo(foo($a))` and the code had `foo(foo(foo(foo(42))))`, -//! then we'll get 3 matches, however only the outermost and innermost matches can be accepted. The -//! middle match would take the second `foo` from the outer match. - -use ide_db::FxHashMap; -use syntax::SyntaxNode; - -use crate::{Match, SsrMatches}; - -pub(crate) fn nest_and_remove_collisions( - mut matches: Vec, - sema: &hir::Semantics<'_, ide_db::RootDatabase>, -) -> SsrMatches { - // We sort the matches by depth then by rule index. Sorting by depth means that by the time we - // see a match, any parent matches or conflicting matches will have already been seen. Sorting - // by rule_index means that if there are two matches for the same node, the rule added first - // will take precedence. - matches.sort_by(|a, b| a.depth.cmp(&b.depth).then_with(|| a.rule_index.cmp(&b.rule_index))); - let mut collector = MatchCollector::default(); - for m in matches { - collector.add_match(m, sema); - } - collector.into() -} - -#[derive(Default)] -struct MatchCollector { - matches_by_node: FxHashMap, -} - -impl MatchCollector { - /// Attempts to add `m` to matches. If it conflicts with an existing match, it is discarded. If - /// it is entirely within the a placeholder of an existing match, then it is added as a child - /// match of the existing match. - fn add_match(&mut self, m: Match, sema: &hir::Semantics<'_, ide_db::RootDatabase>) { - let matched_node = m.matched_node.clone(); - if let Some(existing) = self.matches_by_node.get_mut(&matched_node) { - try_add_sub_match(m, existing, sema); - return; - } - for ancestor in sema.ancestors_with_macros(m.matched_node.clone()) { - if let Some(existing) = self.matches_by_node.get_mut(&ancestor) { - try_add_sub_match(m, existing, sema); - return; - } - } - self.matches_by_node.insert(matched_node, m); - } -} - -/// Attempts to add `m` as a sub-match of `existing`. -fn try_add_sub_match( - m: Match, - existing: &mut Match, - sema: &hir::Semantics<'_, ide_db::RootDatabase>, -) { - for p in existing.placeholder_values.values_mut() { - // Note, no need to check if p.range.file is equal to m.range.file, since we - // already know we're within `existing`. - if p.range.range.contains_range(m.range.range) { - // Convert the inner matches in `p` into a temporary MatchCollector. When - // we're done, we then convert it back into an SsrMatches. If we expected - // lots of inner matches, it might be worthwhile keeping a MatchCollector - // around for each placeholder match. However we expect most placeholder - // will have 0 and a few will have 1. More than that should hopefully be - // exceptional. - let mut collector = MatchCollector::default(); - for m in std::mem::take(&mut p.inner_matches.matches) { - collector.matches_by_node.insert(m.matched_node.clone(), m); - } - collector.add_match(m, sema); - p.inner_matches = collector.into(); - break; - } - } -} - -impl From for SsrMatches { - fn from(mut match_collector: MatchCollector) -> Self { - let mut matches = SsrMatches::default(); - for (_, m) in match_collector.matches_by_node.drain() { - matches.matches.push(m); - } - matches.matches.sort_by(|a, b| { - // Order matches by file_id then by start range. This should be sufficient since ranges - // shouldn't be overlapping. - a.range - .file_id - .cmp(&b.range.file_id) - .then_with(|| a.range.range.start().cmp(&b.range.range.start())) - }); - matches - } -} diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs deleted file mode 100644 index f6220b928a4c6..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs +++ /dev/null @@ -1,406 +0,0 @@ -//! This file contains code for parsing SSR rules, which look something like `foo($a) ==>> bar($b)`. -//! We first split everything before and after the separator `==>>`. Next, both the search pattern -//! and the replacement template get tokenized by the Rust tokenizer. Tokens are then searched for -//! placeholders, which start with `$`. For replacement templates, this is the final form. For -//! search patterns, we go further and parse the pattern as each kind of thing that we can match. -//! e.g. expressions, type references etc. -use ide_db::{FxHashMap, FxHashSet}; -use std::{fmt::Display, str::FromStr}; -use syntax::{SmolStr, SyntaxKind, SyntaxNode, T}; - -use crate::errors::bail; -use crate::{fragments, SsrError, SsrPattern, SsrRule}; - -#[derive(Debug)] -pub(crate) struct ParsedRule { - pub(crate) placeholders_by_stand_in: FxHashMap, - pub(crate) pattern: SyntaxNode, - pub(crate) template: Option, -} - -#[derive(Debug)] -pub(crate) struct RawPattern { - tokens: Vec, -} - -// Part of a search or replace pattern. -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) enum PatternElement { - Token(Token), - Placeholder(Placeholder), -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct Placeholder { - /// The name of this placeholder. e.g. for "$a", this would be "a" - pub(crate) ident: Var, - /// A unique name used in place of this placeholder when we parse the pattern as Rust code. - stand_in_name: String, - pub(crate) constraints: Vec, -} - -/// Represents a `$var` in an SSR query. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub(crate) struct Var(pub(crate) String); - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) enum Constraint { - Kind(NodeKind), - Not(Box), -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) enum NodeKind { - Literal, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) struct Token { - kind: SyntaxKind, - pub(crate) text: SmolStr, -} - -impl ParsedRule { - fn new( - pattern: &RawPattern, - template: Option<&RawPattern>, - ) -> Result, SsrError> { - let raw_pattern = pattern.as_rust_code(); - let raw_template = template.map(|t| t.as_rust_code()); - let raw_template = raw_template.as_deref(); - let mut builder = RuleBuilder { - placeholders_by_stand_in: pattern.placeholders_by_stand_in(), - rules: Vec::new(), - }; - - let raw_template_stmt = raw_template.map(fragments::stmt); - if let raw_template_expr @ Some(Ok(_)) = raw_template.map(fragments::expr) { - builder.try_add(fragments::expr(&raw_pattern), raw_template_expr); - } else { - builder.try_add(fragments::expr(&raw_pattern), raw_template_stmt.clone()); - } - builder.try_add(fragments::ty(&raw_pattern), raw_template.map(fragments::ty)); - builder.try_add(fragments::item(&raw_pattern), raw_template.map(fragments::item)); - builder.try_add(fragments::pat(&raw_pattern), raw_template.map(fragments::pat)); - builder.try_add(fragments::stmt(&raw_pattern), raw_template_stmt); - builder.build() - } -} - -struct RuleBuilder { - placeholders_by_stand_in: FxHashMap, - rules: Vec, -} - -impl RuleBuilder { - fn try_add( - &mut self, - pattern: Result, - template: Option>, - ) { - match (pattern, template) { - (Ok(pattern), Some(Ok(template))) => self.rules.push(ParsedRule { - placeholders_by_stand_in: self.placeholders_by_stand_in.clone(), - pattern, - template: Some(template), - }), - (Ok(pattern), None) => self.rules.push(ParsedRule { - placeholders_by_stand_in: self.placeholders_by_stand_in.clone(), - pattern, - template: None, - }), - _ => {} - } - } - - fn build(mut self) -> Result, SsrError> { - if self.rules.is_empty() { - bail!("Not a valid Rust expression, type, item, path or pattern"); - } - // If any rules contain paths, then we reject any rules that don't contain paths. Allowing a - // mix leads to strange semantics, since the path-based rules only match things where the - // path refers to semantically the same thing, whereas the non-path-based rules could match - // anything. Specifically, if we have a rule like `foo ==>> bar` we only want to match the - // `foo` that is in the current scope, not any `foo`. However "foo" can be parsed as a - // pattern (IDENT_PAT -> NAME -> IDENT). Allowing such a rule through would result in - // renaming everything called `foo` to `bar`. It'd also be slow, since without a path, we'd - // have to use the slow-scan search mechanism. - if self.rules.iter().any(|rule| contains_path(&rule.pattern)) { - let old_len = self.rules.len(); - self.rules.retain(|rule| contains_path(&rule.pattern)); - if self.rules.len() < old_len { - cov_mark::hit!(pattern_is_a_single_segment_path); - } - } - Ok(self.rules) - } -} - -/// Returns whether there are any paths in `node`. -fn contains_path(node: &SyntaxNode) -> bool { - node.kind() == SyntaxKind::PATH - || node.descendants().any(|node| node.kind() == SyntaxKind::PATH) -} - -impl FromStr for SsrRule { - type Err = SsrError; - - fn from_str(query: &str) -> Result { - let mut it = query.split("==>>"); - let pattern = it.next().expect("at least empty string").trim(); - let template = it - .next() - .ok_or_else(|| SsrError("Cannot find delimiter `==>>`".into()))? - .trim() - .to_string(); - if it.next().is_some() { - return Err(SsrError("More than one delimiter found".into())); - } - let raw_pattern = pattern.parse()?; - let raw_template = template.parse()?; - let parsed_rules = ParsedRule::new(&raw_pattern, Some(&raw_template))?; - let rule = SsrRule { pattern: raw_pattern, template: raw_template, parsed_rules }; - validate_rule(&rule)?; - Ok(rule) - } -} - -impl FromStr for RawPattern { - type Err = SsrError; - - fn from_str(pattern_str: &str) -> Result { - Ok(RawPattern { tokens: parse_pattern(pattern_str)? }) - } -} - -impl RawPattern { - /// Returns this search pattern as Rust source code that we can feed to the Rust parser. - fn as_rust_code(&self) -> String { - let mut res = String::new(); - for t in &self.tokens { - res.push_str(match t { - PatternElement::Token(token) => token.text.as_str(), - PatternElement::Placeholder(placeholder) => placeholder.stand_in_name.as_str(), - }); - } - res - } - - pub(crate) fn placeholders_by_stand_in(&self) -> FxHashMap { - let mut res = FxHashMap::default(); - for t in &self.tokens { - if let PatternElement::Placeholder(placeholder) = t { - res.insert(SmolStr::new(placeholder.stand_in_name.clone()), placeholder.clone()); - } - } - res - } -} - -impl FromStr for SsrPattern { - type Err = SsrError; - - fn from_str(pattern_str: &str) -> Result { - let raw_pattern = pattern_str.parse()?; - let parsed_rules = ParsedRule::new(&raw_pattern, None)?; - Ok(SsrPattern { parsed_rules }) - } -} - -/// Returns `pattern_str`, parsed as a search or replace pattern. If `remove_whitespace` is true, -/// then any whitespace tokens will be removed, which we do for the search pattern, but not for the -/// replace pattern. -fn parse_pattern(pattern_str: &str) -> Result, SsrError> { - let mut res = Vec::new(); - let mut placeholder_names = FxHashSet::default(); - let mut tokens = tokenize(pattern_str)?.into_iter(); - while let Some(token) = tokens.next() { - if token.kind == T![$] { - let placeholder = parse_placeholder(&mut tokens)?; - if !placeholder_names.insert(placeholder.ident.clone()) { - bail!("Placeholder `{}` repeats more than once", placeholder.ident); - } - res.push(PatternElement::Placeholder(placeholder)); - } else { - res.push(PatternElement::Token(token)); - } - } - Ok(res) -} - -/// Checks for errors in a rule. e.g. the replace pattern referencing placeholders that the search -/// pattern didn't define. -fn validate_rule(rule: &SsrRule) -> Result<(), SsrError> { - let mut defined_placeholders = FxHashSet::default(); - for p in &rule.pattern.tokens { - if let PatternElement::Placeholder(placeholder) = p { - defined_placeholders.insert(&placeholder.ident); - } - } - let mut undefined = Vec::new(); - for p in &rule.template.tokens { - if let PatternElement::Placeholder(placeholder) = p { - if !defined_placeholders.contains(&placeholder.ident) { - undefined.push(placeholder.ident.to_string()); - } - if !placeholder.constraints.is_empty() { - bail!("Replacement placeholders cannot have constraints"); - } - } - } - if !undefined.is_empty() { - bail!("Replacement contains undefined placeholders: {}", undefined.join(", ")); - } - Ok(()) -} - -fn tokenize(source: &str) -> Result, SsrError> { - let lexed = parser::LexedStr::new(source); - if let Some((_, first_error)) = lexed.errors().next() { - bail!("Failed to parse pattern: {}", first_error); - } - let mut tokens: Vec = Vec::new(); - for i in 0..lexed.len() { - tokens.push(Token { kind: lexed.kind(i), text: lexed.text(i).into() }); - } - Ok(tokens) -} - -fn parse_placeholder(tokens: &mut std::vec::IntoIter) -> Result { - let mut name = None; - let mut constraints = Vec::new(); - if let Some(token) = tokens.next() { - match token.kind { - SyntaxKind::IDENT => { - name = Some(token.text); - } - T!['{'] => { - let token = - tokens.next().ok_or_else(|| SsrError::new("Unexpected end of placeholder"))?; - if token.kind == SyntaxKind::IDENT { - name = Some(token.text); - } - loop { - let token = tokens - .next() - .ok_or_else(|| SsrError::new("Placeholder is missing closing brace '}'"))?; - match token.kind { - T![:] => { - constraints.push(parse_constraint(tokens)?); - } - T!['}'] => break, - _ => bail!("Unexpected token while parsing placeholder: '{}'", token.text), - } - } - } - _ => { - bail!("Placeholders should either be $name or ${{name:constraints}}"); - } - } - } - let name = name.ok_or_else(|| SsrError::new("Placeholder ($) with no name"))?; - Ok(Placeholder::new(name, constraints)) -} - -fn parse_constraint(tokens: &mut std::vec::IntoIter) -> Result { - let constraint_type = tokens - .next() - .ok_or_else(|| SsrError::new("Found end of placeholder while looking for a constraint"))? - .text - .to_string(); - match constraint_type.as_str() { - "kind" => { - expect_token(tokens, "(")?; - let t = tokens.next().ok_or_else(|| { - SsrError::new("Unexpected end of constraint while looking for kind") - })?; - if t.kind != SyntaxKind::IDENT { - bail!("Expected ident, found {:?} while parsing kind constraint", t.kind); - } - expect_token(tokens, ")")?; - Ok(Constraint::Kind(NodeKind::from(&t.text)?)) - } - "not" => { - expect_token(tokens, "(")?; - let sub = parse_constraint(tokens)?; - expect_token(tokens, ")")?; - Ok(Constraint::Not(Box::new(sub))) - } - x => bail!("Unsupported constraint type '{}'", x), - } -} - -fn expect_token(tokens: &mut std::vec::IntoIter, expected: &str) -> Result<(), SsrError> { - if let Some(t) = tokens.next() { - if t.text == expected { - return Ok(()); - } - bail!("Expected {} found {}", expected, t.text); - } - bail!("Expected {} found end of stream", expected); -} - -impl NodeKind { - fn from(name: &SmolStr) -> Result { - Ok(match name.as_str() { - "literal" => NodeKind::Literal, - _ => bail!("Unknown node kind '{}'", name), - }) - } -} - -impl Placeholder { - fn new(name: SmolStr, constraints: Vec) -> Self { - Self { - stand_in_name: format!("__placeholder_{}", name), - constraints, - ident: Var(name.to_string()), - } - } -} - -impl Display for Var { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "${}", self.0) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn parser_happy_case() { - fn token(kind: SyntaxKind, text: &str) -> PatternElement { - PatternElement::Token(Token { kind, text: SmolStr::new(text) }) - } - fn placeholder(name: &str) -> PatternElement { - PatternElement::Placeholder(Placeholder::new(SmolStr::new(name), Vec::new())) - } - let result: SsrRule = "foo($a, $b) ==>> bar($b, $a)".parse().unwrap(); - assert_eq!( - result.pattern.tokens, - vec![ - token(SyntaxKind::IDENT, "foo"), - token(T!['('], "("), - placeholder("a"), - token(T![,], ","), - token(SyntaxKind::WHITESPACE, " "), - placeholder("b"), - token(T![')'], ")"), - ] - ); - assert_eq!( - result.template.tokens, - vec![ - token(SyntaxKind::IDENT, "bar"), - token(T!['('], "("), - placeholder("b"), - token(T![,], ","), - token(SyntaxKind::WHITESPACE, " "), - placeholder("a"), - token(T![')'], ")"), - ] - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs deleted file mode 100644 index e27ef6e35ef42..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs +++ /dev/null @@ -1,242 +0,0 @@ -//! Code for applying replacement templates for matches that have previously been found. - -use ide_db::{FxHashMap, FxHashSet}; -use itertools::Itertools; -use syntax::{ - ast::{self, AstNode, AstToken}, - SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize, -}; -use text_edit::TextEdit; - -use crate::{fragments, resolving::ResolvedRule, Match, SsrMatches}; - -/// Returns a text edit that will replace each match in `matches` with its corresponding replacement -/// template. Placeholders in the template will have been substituted with whatever they matched to -/// in the original code. -pub(crate) fn matches_to_edit( - matches: &SsrMatches, - file_src: &str, - rules: &[ResolvedRule], -) -> TextEdit { - matches_to_edit_at_offset(matches, file_src, 0.into(), rules) -} - -fn matches_to_edit_at_offset( - matches: &SsrMatches, - file_src: &str, - relative_start: TextSize, - rules: &[ResolvedRule], -) -> TextEdit { - let mut edit_builder = TextEdit::builder(); - for m in &matches.matches { - edit_builder.replace( - m.range.range.checked_sub(relative_start).unwrap(), - render_replace(m, file_src, rules), - ); - } - edit_builder.finish() -} - -struct ReplacementRenderer<'a> { - match_info: &'a Match, - file_src: &'a str, - rules: &'a [ResolvedRule], - rule: &'a ResolvedRule, - out: String, - // Map from a range within `out` to a token in `template` that represents a placeholder. This is - // used to validate that the generated source code doesn't split any placeholder expansions (see - // below). - placeholder_tokens_by_range: FxHashMap, - // Which placeholder tokens need to be wrapped in parenthesis in order to ensure that when `out` - // is parsed, placeholders don't get split. e.g. if a template of `$a.to_string()` results in `1 - // + 2.to_string()` then the placeholder value `1 + 2` was split and needs parenthesis. - placeholder_tokens_requiring_parenthesis: FxHashSet, -} - -fn render_replace(match_info: &Match, file_src: &str, rules: &[ResolvedRule]) -> String { - let rule = &rules[match_info.rule_index]; - let template = rule - .template - .as_ref() - .expect("You called MatchFinder::edits after calling MatchFinder::add_search_pattern"); - let mut renderer = ReplacementRenderer { - match_info, - file_src, - rules, - rule, - out: String::new(), - placeholder_tokens_requiring_parenthesis: FxHashSet::default(), - placeholder_tokens_by_range: FxHashMap::default(), - }; - renderer.render_node(&template.node); - renderer.maybe_rerender_with_extra_parenthesis(&template.node); - for comment in &match_info.ignored_comments { - renderer.out.push_str(&comment.syntax().to_string()); - } - renderer.out -} - -impl ReplacementRenderer<'_> { - fn render_node_children(&mut self, node: &SyntaxNode) { - for node_or_token in node.children_with_tokens() { - self.render_node_or_token(&node_or_token); - } - } - - fn render_node_or_token(&mut self, node_or_token: &SyntaxElement) { - match node_or_token { - SyntaxElement::Token(token) => { - self.render_token(token); - } - SyntaxElement::Node(child_node) => { - self.render_node(child_node); - } - } - } - - fn render_node(&mut self, node: &SyntaxNode) { - if let Some(mod_path) = self.match_info.rendered_template_paths.get(node) { - self.out.push_str(&mod_path.to_string()); - // Emit everything except for the segment's name-ref, since we already effectively - // emitted that as part of `mod_path`. - if let Some(path) = ast::Path::cast(node.clone()) { - if let Some(segment) = path.segment() { - for node_or_token in segment.syntax().children_with_tokens() { - if node_or_token.kind() != SyntaxKind::NAME_REF { - self.render_node_or_token(&node_or_token); - } - } - } - } - } else { - self.render_node_children(node); - } - } - - fn render_token(&mut self, token: &SyntaxToken) { - if let Some(placeholder) = self.rule.get_placeholder(token) { - if let Some(placeholder_value) = - self.match_info.placeholder_values.get(&placeholder.ident) - { - let range = &placeholder_value.range.range; - let mut matched_text = - self.file_src[usize::from(range.start())..usize::from(range.end())].to_owned(); - // If a method call is performed directly on the placeholder, then autoderef and - // autoref will apply, so we can just substitute whatever the placeholder matched to - // directly. If we're not applying a method call, then we need to add explicitly - // deref and ref in order to match whatever was being done implicitly at the match - // site. - if !token_is_method_call_receiver(token) - && (placeholder_value.autoderef_count > 0 - || placeholder_value.autoref_kind != ast::SelfParamKind::Owned) - { - cov_mark::hit!(replace_autoref_autoderef_capture); - let ref_kind = match placeholder_value.autoref_kind { - ast::SelfParamKind::Owned => "", - ast::SelfParamKind::Ref => "&", - ast::SelfParamKind::MutRef => "&mut ", - }; - matched_text = format!( - "{}{}{}", - ref_kind, - "*".repeat(placeholder_value.autoderef_count), - matched_text - ); - } - let edit = matches_to_edit_at_offset( - &placeholder_value.inner_matches, - self.file_src, - range.start(), - self.rules, - ); - let needs_parenthesis = - self.placeholder_tokens_requiring_parenthesis.contains(token); - edit.apply(&mut matched_text); - if needs_parenthesis { - self.out.push('('); - } - self.placeholder_tokens_by_range.insert( - TextRange::new( - TextSize::of(&self.out), - TextSize::of(&self.out) + TextSize::of(&matched_text), - ), - token.clone(), - ); - self.out.push_str(&matched_text); - if needs_parenthesis { - self.out.push(')'); - } - } else { - // We validated that all placeholder references were valid before we - // started, so this shouldn't happen. - panic!( - "Internal error: replacement referenced unknown placeholder {}", - placeholder.ident - ); - } - } else { - self.out.push_str(token.text()); - } - } - - // Checks if the resulting code, when parsed doesn't split any placeholders due to different - // order of operations between the search pattern and the replacement template. If any do, then - // we rerender the template and wrap the problematic placeholders with parenthesis. - fn maybe_rerender_with_extra_parenthesis(&mut self, template: &SyntaxNode) { - if let Some(node) = parse_as_kind(&self.out, template.kind()) { - self.remove_node_ranges(node); - if self.placeholder_tokens_by_range.is_empty() { - return; - } - self.placeholder_tokens_requiring_parenthesis = - self.placeholder_tokens_by_range.values().cloned().collect(); - self.out.clear(); - self.render_node(template); - } - } - - fn remove_node_ranges(&mut self, node: SyntaxNode) { - self.placeholder_tokens_by_range.remove(&node.text_range()); - for child in node.children() { - self.remove_node_ranges(child); - } - } -} - -/// Returns whether token is the receiver of a method call. Note, being within the receiver of a -/// method call doesn't count. e.g. if the token is `$a`, then `$a.foo()` will return true, while -/// `($a + $b).foo()` or `x.foo($a)` will return false. -fn token_is_method_call_receiver(token: &SyntaxToken) -> bool { - // Find the first method call among the ancestors of `token`, then check if the only token - // within the receiver is `token`. - if let Some(receiver) = token - .parent_ancestors() - .find_map(ast::MethodCallExpr::cast) - .and_then(|call| call.receiver()) - { - let tokens = receiver.syntax().descendants_with_tokens().filter_map(|node_or_token| { - match node_or_token { - SyntaxElement::Token(t) => Some(t), - _ => None, - } - }); - if let Some((only_token,)) = tokens.collect_tuple() { - return only_token == *token; - } - } - false -} - -fn parse_as_kind(code: &str, kind: SyntaxKind) -> Option { - if ast::Expr::can_cast(kind) { - if let Ok(expr) = fragments::expr(code) { - return Some(expr); - } - } - if ast::Item::can_cast(kind) { - if let Ok(item) = fragments::item(code) { - return Some(item); - } - } - None -} diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs deleted file mode 100644 index 4731f14f4e623..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs +++ /dev/null @@ -1,308 +0,0 @@ -//! This module is responsible for resolving paths within rules. - -use hir::AsAssocItem; -use ide_db::{base_db::FilePosition, FxHashMap}; -use parsing::Placeholder; -use syntax::{ast, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken}; - -use crate::{errors::error, parsing, SsrError}; - -pub(crate) struct ResolutionScope<'db> { - scope: hir::SemanticsScope<'db>, - node: SyntaxNode, -} - -pub(crate) struct ResolvedRule { - pub(crate) pattern: ResolvedPattern, - pub(crate) template: Option, - pub(crate) index: usize, -} - -pub(crate) struct ResolvedPattern { - pub(crate) placeholders_by_stand_in: FxHashMap, - pub(crate) node: SyntaxNode, - // Paths in `node` that we've resolved. - pub(crate) resolved_paths: FxHashMap, - pub(crate) ufcs_function_calls: FxHashMap, - pub(crate) contains_self: bool, -} - -pub(crate) struct ResolvedPath { - pub(crate) resolution: hir::PathResolution, - /// The depth of the ast::Path that was resolved within the pattern. - pub(crate) depth: u32, -} - -pub(crate) struct UfcsCallInfo { - pub(crate) call_expr: ast::CallExpr, - pub(crate) function: hir::Function, - pub(crate) qualifier_type: Option, -} - -impl ResolvedRule { - pub(crate) fn new( - rule: parsing::ParsedRule, - resolution_scope: &ResolutionScope<'_>, - index: usize, - ) -> Result { - let resolver = - Resolver { resolution_scope, placeholders_by_stand_in: rule.placeholders_by_stand_in }; - let resolved_template = match rule.template { - Some(template) => Some(resolver.resolve_pattern_tree(template)?), - None => None, - }; - Ok(ResolvedRule { - pattern: resolver.resolve_pattern_tree(rule.pattern)?, - template: resolved_template, - index, - }) - } - - pub(crate) fn get_placeholder(&self, token: &SyntaxToken) -> Option<&Placeholder> { - if token.kind() != SyntaxKind::IDENT { - return None; - } - self.pattern.placeholders_by_stand_in.get(token.text()) - } -} - -struct Resolver<'a, 'db> { - resolution_scope: &'a ResolutionScope<'db>, - placeholders_by_stand_in: FxHashMap, -} - -impl Resolver<'_, '_> { - fn resolve_pattern_tree(&self, pattern: SyntaxNode) -> Result { - use syntax::ast::AstNode; - use syntax::{SyntaxElement, T}; - let mut resolved_paths = FxHashMap::default(); - self.resolve(pattern.clone(), 0, &mut resolved_paths)?; - let ufcs_function_calls = resolved_paths - .iter() - .filter_map(|(path_node, resolved)| { - if let Some(grandparent) = path_node.parent().and_then(|parent| parent.parent()) { - if let Some(call_expr) = ast::CallExpr::cast(grandparent.clone()) { - if let hir::PathResolution::Def(hir::ModuleDef::Function(function)) = - resolved.resolution - { - if function.as_assoc_item(self.resolution_scope.scope.db).is_some() { - let qualifier_type = - self.resolution_scope.qualifier_type(path_node); - return Some(( - grandparent, - UfcsCallInfo { call_expr, function, qualifier_type }, - )); - } - } - } - } - None - }) - .collect(); - let contains_self = - pattern.descendants_with_tokens().any(|node_or_token| match node_or_token { - SyntaxElement::Token(t) => t.kind() == T![self], - _ => false, - }); - Ok(ResolvedPattern { - node: pattern, - resolved_paths, - placeholders_by_stand_in: self.placeholders_by_stand_in.clone(), - ufcs_function_calls, - contains_self, - }) - } - - fn resolve( - &self, - node: SyntaxNode, - depth: u32, - resolved_paths: &mut FxHashMap, - ) -> Result<(), SsrError> { - use syntax::ast::AstNode; - if let Some(path) = ast::Path::cast(node.clone()) { - if is_self(&path) { - // Self cannot be resolved like other paths. - return Ok(()); - } - // Check if this is an appropriate place in the path to resolve. If the path is - // something like `a::B::::c` then we want to resolve `a::B`. If the path contains - // a placeholder. e.g. `a::$b::c` then we want to resolve `a`. - if !path_contains_type_arguments(path.qualifier()) - && !self.path_contains_placeholder(&path) - { - let resolution = self - .resolution_scope - .resolve_path(&path) - .ok_or_else(|| error!("Failed to resolve path `{}`", node.text()))?; - if self.ok_to_use_path_resolution(&resolution) { - resolved_paths.insert(node, ResolvedPath { resolution, depth }); - return Ok(()); - } - } - } - for node in node.children() { - self.resolve(node, depth + 1, resolved_paths)?; - } - Ok(()) - } - - /// Returns whether `path` contains a placeholder, but ignores any placeholders within type - /// arguments. - fn path_contains_placeholder(&self, path: &ast::Path) -> bool { - if let Some(segment) = path.segment() { - if let Some(name_ref) = segment.name_ref() { - if self.placeholders_by_stand_in.contains_key(name_ref.text().as_str()) { - return true; - } - } - } - if let Some(qualifier) = path.qualifier() { - return self.path_contains_placeholder(&qualifier); - } - false - } - - fn ok_to_use_path_resolution(&self, resolution: &hir::PathResolution) -> bool { - match resolution { - hir::PathResolution::Def(hir::ModuleDef::Function(function)) - if function.as_assoc_item(self.resolution_scope.scope.db).is_some() => - { - if function.self_param(self.resolution_scope.scope.db).is_some() { - // If we don't use this path resolution, then we won't be able to match method - // calls. e.g. `Foo::bar($s)` should match `x.bar()`. - true - } else { - cov_mark::hit!(replace_associated_trait_default_function_call); - false - } - } - hir::PathResolution::Def( - def @ (hir::ModuleDef::Const(_) | hir::ModuleDef::TypeAlias(_)), - ) if def.as_assoc_item(self.resolution_scope.scope.db).is_some() => { - // Not a function. Could be a constant or an associated type. - cov_mark::hit!(replace_associated_trait_constant); - false - } - _ => true, - } - } -} - -impl<'db> ResolutionScope<'db> { - pub(crate) fn new( - sema: &hir::Semantics<'db, ide_db::RootDatabase>, - resolve_context: FilePosition, - ) -> Option> { - use syntax::ast::AstNode; - let file = sema.parse(resolve_context.file_id); - // Find a node at the requested position, falling back to the whole file. - let node = file - .syntax() - .token_at_offset(resolve_context.offset) - .left_biased() - .and_then(|token| token.parent()) - .unwrap_or_else(|| file.syntax().clone()); - let node = pick_node_for_resolution(node); - let scope = sema.scope(&node)?; - Some(ResolutionScope { scope, node }) - } - - /// Returns the function in which SSR was invoked, if any. - pub(crate) fn current_function(&self) -> Option { - self.node.ancestors().find(|node| node.kind() == SyntaxKind::FN) - } - - fn resolve_path(&self, path: &ast::Path) -> Option { - // First try resolving the whole path. This will work for things like - // `std::collections::HashMap`, but will fail for things like - // `std::collections::HashMap::new`. - if let Some(resolution) = self.scope.speculative_resolve(path) { - return Some(resolution); - } - // Resolution failed, try resolving the qualifier (e.g. `std::collections::HashMap` and if - // that succeeds, then iterate through the candidates on the resolved type with the provided - // name. - let resolved_qualifier = self.scope.speculative_resolve(&path.qualifier()?)?; - if let hir::PathResolution::Def(hir::ModuleDef::Adt(adt)) = resolved_qualifier { - let name = path.segment()?.name_ref()?; - let module = self.scope.module(); - adt.ty(self.scope.db).iterate_path_candidates( - self.scope.db, - &self.scope, - &self.scope.visible_traits().0, - Some(module), - None, - |assoc_item| { - let item_name = assoc_item.name(self.scope.db)?; - if item_name.to_smol_str().as_str() == name.text() { - Some(hir::PathResolution::Def(assoc_item.into())) - } else { - None - } - }, - ) - } else { - None - } - } - - fn qualifier_type(&self, path: &SyntaxNode) -> Option { - use syntax::ast::AstNode; - if let Some(path) = ast::Path::cast(path.clone()) { - if let Some(qualifier) = path.qualifier() { - if let Some(hir::PathResolution::Def(hir::ModuleDef::Adt(adt))) = - self.resolve_path(&qualifier) - { - return Some(adt.ty(self.scope.db)); - } - } - } - None - } -} - -fn is_self(path: &ast::Path) -> bool { - path.segment().map(|segment| segment.self_token().is_some()).unwrap_or(false) -} - -/// Returns a suitable node for resolving paths in the current scope. If we create a scope based on -/// a statement node, then we can't resolve local variables that were defined in the current scope -/// (only in parent scopes). So we find another node, ideally a child of the statement where local -/// variable resolution is permitted. -fn pick_node_for_resolution(node: SyntaxNode) -> SyntaxNode { - match node.kind() { - SyntaxKind::EXPR_STMT => { - if let Some(n) = node.first_child() { - cov_mark::hit!(cursor_after_semicolon); - return n; - } - } - SyntaxKind::LET_STMT | SyntaxKind::IDENT_PAT => { - if let Some(next) = node.next_sibling() { - return pick_node_for_resolution(next); - } - } - SyntaxKind::NAME => { - if let Some(parent) = node.parent() { - return pick_node_for_resolution(parent); - } - } - _ => {} - } - node -} - -/// Returns whether `path` or any of its qualifiers contains type arguments. -fn path_contains_type_arguments(path: Option) -> bool { - if let Some(path) = path { - if let Some(segment) = path.segment() { - if segment.generic_arg_list().is_some() { - cov_mark::hit!(type_arguments_within_path); - return true; - } - } - return path_contains_type_arguments(path.qualifier()); - } - false -} diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs deleted file mode 100644 index 0a85569b60080..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs +++ /dev/null @@ -1,289 +0,0 @@ -//! Searching for matches. - -use crate::{ - matching, - resolving::{ResolvedPath, ResolvedPattern, ResolvedRule}, - Match, MatchFinder, -}; -use ide_db::{ - base_db::{FileId, FileRange}, - defs::Definition, - search::{SearchScope, UsageSearchResult}, - FxHashSet, -}; -use syntax::{ast, AstNode, SyntaxKind, SyntaxNode}; - -/// A cache for the results of find_usages. This is for when we have multiple patterns that have the -/// same path. e.g. if the pattern was `foo::Bar` that can parse as a path, an expression, a type -/// and as a pattern. In each, the usages of `foo::Bar` are the same and we'd like to avoid finding -/// them more than once. -#[derive(Default)] -pub(crate) struct UsageCache { - usages: Vec<(Definition, UsageSearchResult)>, -} - -impl<'db> MatchFinder<'db> { - /// Adds all matches for `rule` to `matches_out`. Matches may overlap in ways that make - /// replacement impossible, so further processing is required in order to properly nest matches - /// and remove overlapping matches. This is done in the `nesting` module. - pub(crate) fn find_matches_for_rule( - &self, - rule: &ResolvedRule, - usage_cache: &mut UsageCache, - matches_out: &mut Vec, - ) { - if rule.pattern.contains_self { - // If the pattern contains `self` we restrict the scope of the search to just the - // current method. No other method can reference the same `self`. This makes the - // behavior of `self` consistent with other variables. - if let Some(current_function) = self.resolution_scope.current_function() { - self.slow_scan_node(¤t_function, rule, &None, matches_out); - } - return; - } - if pick_path_for_usages(&rule.pattern).is_none() { - self.slow_scan(rule, matches_out); - return; - } - self.find_matches_for_pattern_tree(rule, &rule.pattern, usage_cache, matches_out); - } - - fn find_matches_for_pattern_tree( - &self, - rule: &ResolvedRule, - pattern: &ResolvedPattern, - usage_cache: &mut UsageCache, - matches_out: &mut Vec, - ) { - if let Some(resolved_path) = pick_path_for_usages(pattern) { - let definition: Definition = resolved_path.resolution.clone().into(); - for file_range in self.find_usages(usage_cache, definition).file_ranges() { - for node_to_match in self.find_nodes_to_match(resolved_path, file_range) { - if !is_search_permitted_ancestors(&node_to_match) { - cov_mark::hit!(use_declaration_with_braces); - continue; - } - self.try_add_match(rule, &node_to_match, &None, matches_out); - } - } - } - } - - fn find_nodes_to_match( - &self, - resolved_path: &ResolvedPath, - file_range: FileRange, - ) -> Vec { - let file = self.sema.parse(file_range.file_id); - let depth = resolved_path.depth as usize; - let offset = file_range.range.start(); - - let mut paths = self - .sema - .find_nodes_at_offset_with_descend::(file.syntax(), offset) - .peekable(); - - if paths.peek().is_some() { - paths - .filter_map(|path| { - self.sema.ancestors_with_macros(path.syntax().clone()).nth(depth) - }) - .collect::>() - } else { - self.sema - .find_nodes_at_offset_with_descend::(file.syntax(), offset) - .filter_map(|path| { - // If the pattern contained a path and we found a reference to that path that wasn't - // itself a path, but was a method call, then we need to adjust how far up to try - // matching by how deep the path was within a CallExpr. The structure would have been - // CallExpr, PathExpr, Path - i.e. a depth offset of 2. We don't need to check if the - // path was part of a CallExpr because if it wasn't then all that will happen is we'll - // fail to match, which is the desired behavior. - const PATH_DEPTH_IN_CALL_EXPR: usize = 2; - if depth < PATH_DEPTH_IN_CALL_EXPR { - return None; - } - self.sema - .ancestors_with_macros(path.syntax().clone()) - .nth(depth - PATH_DEPTH_IN_CALL_EXPR) - }) - .collect::>() - } - } - - fn find_usages<'a>( - &self, - usage_cache: &'a mut UsageCache, - definition: Definition, - ) -> &'a UsageSearchResult { - // Logically if a lookup succeeds we should just return it. Unfortunately returning it would - // extend the lifetime of the borrow, then we wouldn't be able to do the insertion on a - // cache miss. This is a limitation of NLL and is fixed with Polonius. For now we do two - // lookups in the case of a cache hit. - if usage_cache.find(&definition).is_none() { - let usages = definition.usages(&self.sema).in_scope(self.search_scope()).all(); - usage_cache.usages.push((definition, usages)); - return &usage_cache.usages.last().unwrap().1; - } - usage_cache.find(&definition).unwrap() - } - - /// Returns the scope within which we want to search. We don't want un unrestricted search - /// scope, since we don't want to find references in external dependencies. - fn search_scope(&self) -> SearchScope { - // FIXME: We should ideally have a test that checks that we edit local roots and not library - // roots. This probably would require some changes to fixtures, since currently everything - // seems to get put into a single source root. - let mut files = Vec::new(); - self.search_files_do(|file_id| { - files.push(file_id); - }); - SearchScope::files(&files) - } - - fn slow_scan(&self, rule: &ResolvedRule, matches_out: &mut Vec) { - self.search_files_do(|file_id| { - let file = self.sema.parse(file_id); - let code = file.syntax(); - self.slow_scan_node(code, rule, &None, matches_out); - }) - } - - fn search_files_do(&self, mut callback: impl FnMut(FileId)) { - if self.restrict_ranges.is_empty() { - // Unrestricted search. - use ide_db::base_db::SourceDatabaseExt; - use ide_db::symbol_index::SymbolsDatabase; - for &root in self.sema.db.local_roots().iter() { - let sr = self.sema.db.source_root(root); - for file_id in sr.iter() { - callback(file_id); - } - } - } else { - // Search is restricted, deduplicate file IDs (generally only one). - let mut files = FxHashSet::default(); - for range in &self.restrict_ranges { - if files.insert(range.file_id) { - callback(range.file_id); - } - } - } - } - - fn slow_scan_node( - &self, - code: &SyntaxNode, - rule: &ResolvedRule, - restrict_range: &Option, - matches_out: &mut Vec, - ) { - if !is_search_permitted(code) { - return; - } - self.try_add_match(rule, code, restrict_range, matches_out); - // If we've got a macro call, we already tried matching it pre-expansion, which is the only - // way to match the whole macro, now try expanding it and matching the expansion. - if let Some(macro_call) = ast::MacroCall::cast(code.clone()) { - if let Some(expanded) = self.sema.expand(¯o_call) { - if let Some(tt) = macro_call.token_tree() { - // When matching within a macro expansion, we only want to allow matches of - // nodes that originated entirely from within the token tree of the macro call. - // i.e. we don't want to match something that came from the macro itself. - self.slow_scan_node( - &expanded, - rule, - &Some(self.sema.original_range(tt.syntax())), - matches_out, - ); - } - } - } - for child in code.children() { - self.slow_scan_node(&child, rule, restrict_range, matches_out); - } - } - - fn try_add_match( - &self, - rule: &ResolvedRule, - code: &SyntaxNode, - restrict_range: &Option, - matches_out: &mut Vec, - ) { - if !self.within_range_restrictions(code) { - cov_mark::hit!(replace_nonpath_within_selection); - return; - } - if let Ok(m) = matching::get_match(false, rule, code, restrict_range, &self.sema) { - matches_out.push(m); - } - } - - /// Returns whether `code` is within one of our range restrictions if we have any. No range - /// restrictions is considered unrestricted and always returns true. - fn within_range_restrictions(&self, code: &SyntaxNode) -> bool { - if self.restrict_ranges.is_empty() { - // There is no range restriction. - return true; - } - let node_range = self.sema.original_range(code); - for range in &self.restrict_ranges { - if range.file_id == node_range.file_id && range.range.contains_range(node_range.range) { - return true; - } - } - false - } -} - -/// Returns whether we support matching within `node` and all of its ancestors. -fn is_search_permitted_ancestors(node: &SyntaxNode) -> bool { - if let Some(parent) = node.parent() { - if !is_search_permitted_ancestors(&parent) { - return false; - } - } - is_search_permitted(node) -} - -/// Returns whether we support matching within this kind of node. -fn is_search_permitted(node: &SyntaxNode) -> bool { - // FIXME: Properly handle use declarations. At the moment, if our search pattern is `foo::bar` - // and the code is `use foo::{baz, bar}`, we'll match `bar`, since it resolves to `foo::bar`. - // However we'll then replace just the part we matched `bar`. We probably need to instead remove - // `bar` and insert a new use declaration. - node.kind() != SyntaxKind::USE -} - -impl UsageCache { - fn find(&mut self, definition: &Definition) -> Option<&UsageSearchResult> { - // We expect a very small number of cache entries (generally 1), so a linear scan should be - // fast enough and avoids the need to implement Hash for Definition. - for (d, refs) in &self.usages { - if d == definition { - return Some(refs); - } - } - None - } -} - -/// Returns a path that's suitable for path resolution. We exclude builtin types, since they aren't -/// something that we can find references to. We then somewhat arbitrarily pick the path that is the -/// longest as this is hopefully more likely to be less common, making it faster to find. -fn pick_path_for_usages(pattern: &ResolvedPattern) -> Option<&ResolvedPath> { - // FIXME: Take the scope of the resolved path into account. e.g. if there are any paths that are - // private to the current module, then we definitely would want to pick them over say a path - // from std. Possibly we should go further than this and intersect the search scopes for all - // resolved paths then search only in that scope. - pattern - .resolved_paths - .iter() - .filter(|(_, p)| { - !matches!(p.resolution, hir::PathResolution::Def(hir::ModuleDef::BuiltinType(_))) - }) - .map(|(node, resolved)| (node.text().len(), resolved)) - .max_by(|(a, _), (b, _)| a.cmp(b)) - .map(|(_, resolved)| resolved) -} diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs deleted file mode 100644 index 1ecb7aa9aa701..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs +++ /dev/null @@ -1,1397 +0,0 @@ -use expect_test::{expect, Expect}; -use ide_db::{ - base_db::{salsa::Durability, FileId, FilePosition, FileRange, SourceDatabaseExt}, - FxHashSet, -}; -use std::sync::Arc; -use test_utils::RangeOrOffset; - -use crate::{MatchFinder, SsrRule}; - -fn parse_error_text(query: &str) -> String { - format!("{}", query.parse::().unwrap_err()) -} - -#[test] -fn parser_empty_query() { - assert_eq!(parse_error_text(""), "Parse error: Cannot find delimiter `==>>`"); -} - -#[test] -fn parser_no_delimiter() { - assert_eq!(parse_error_text("foo()"), "Parse error: Cannot find delimiter `==>>`"); -} - -#[test] -fn parser_two_delimiters() { - assert_eq!( - parse_error_text("foo() ==>> a ==>> b "), - "Parse error: More than one delimiter found" - ); -} - -#[test] -fn parser_repeated_name() { - assert_eq!( - parse_error_text("foo($a, $a) ==>>"), - "Parse error: Placeholder `$a` repeats more than once" - ); -} - -#[test] -fn parser_invalid_pattern() { - assert_eq!( - parse_error_text(" ==>> ()"), - "Parse error: Not a valid Rust expression, type, item, path or pattern" - ); -} - -#[test] -fn parser_invalid_template() { - assert_eq!( - parse_error_text("() ==>> )"), - "Parse error: Not a valid Rust expression, type, item, path or pattern" - ); -} - -#[test] -fn parser_undefined_placeholder_in_replacement() { - assert_eq!( - parse_error_text("42 ==>> $a"), - "Parse error: Replacement contains undefined placeholders: $a" - ); -} - -/// `code` may optionally contain a cursor marker `$0`. If it doesn't, then the position will be -/// the start of the file. If there's a second cursor marker, then we'll return a single range. -pub(crate) fn single_file(code: &str) -> (ide_db::RootDatabase, FilePosition, Vec) { - use ide_db::base_db::fixture::WithFixture; - use ide_db::symbol_index::SymbolsDatabase; - let (mut db, file_id, range_or_offset) = if code.contains(test_utils::CURSOR_MARKER) { - ide_db::RootDatabase::with_range_or_offset(code) - } else { - let (db, file_id) = ide_db::RootDatabase::with_single_file(code); - (db, file_id, RangeOrOffset::Offset(0.into())) - }; - let selections; - let position; - match range_or_offset { - RangeOrOffset::Range(range) => { - position = FilePosition { file_id, offset: range.start() }; - selections = vec![FileRange { file_id, range }]; - } - RangeOrOffset::Offset(offset) => { - position = FilePosition { file_id, offset }; - selections = vec![]; - } - } - let mut local_roots = FxHashSet::default(); - local_roots.insert(ide_db::base_db::fixture::WORKSPACE); - db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH); - (db, position, selections) -} - -fn assert_ssr_transform(rule: &str, input: &str, expected: Expect) { - assert_ssr_transforms(&[rule], input, expected); -} - -fn assert_ssr_transforms(rules: &[&str], input: &str, expected: Expect) { - let (db, position, selections) = single_file(input); - let mut match_finder = MatchFinder::in_context(&db, position, selections).unwrap(); - for rule in rules { - let rule: SsrRule = rule.parse().unwrap(); - match_finder.add_rule(rule).unwrap(); - } - let edits = match_finder.edits(); - if edits.is_empty() { - panic!("No edits were made"); - } - // Note, db.file_text is not necessarily the same as `input`, since fixture parsing alters - // stuff. - let mut actual = db.file_text(position.file_id).to_string(); - edits[&position.file_id].apply(&mut actual); - expected.assert_eq(&actual); -} - -fn print_match_debug_info(match_finder: &MatchFinder<'_>, file_id: FileId, snippet: &str) { - let debug_info = match_finder.debug_where_text_equal(file_id, snippet); - println!( - "Match debug info: {} nodes had text exactly equal to '{}'", - debug_info.len(), - snippet - ); - for (index, d) in debug_info.iter().enumerate() { - println!("Node #{}\n{:#?}\n", index, d); - } -} - -fn assert_matches(pattern: &str, code: &str, expected: &[&str]) { - let (db, position, selections) = single_file(code); - let mut match_finder = MatchFinder::in_context(&db, position, selections).unwrap(); - match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap(); - let matched_strings: Vec = - match_finder.matches().flattened().matches.iter().map(|m| m.matched_text()).collect(); - if matched_strings != expected && !expected.is_empty() { - print_match_debug_info(&match_finder, position.file_id, expected[0]); - } - assert_eq!(matched_strings, expected); -} - -fn assert_no_match(pattern: &str, code: &str) { - let (db, position, selections) = single_file(code); - let mut match_finder = MatchFinder::in_context(&db, position, selections).unwrap(); - match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap(); - let matches = match_finder.matches().flattened().matches; - if !matches.is_empty() { - print_match_debug_info(&match_finder, position.file_id, &matches[0].matched_text()); - panic!("Got {} matches when we expected none: {:#?}", matches.len(), matches); - } -} - -fn assert_match_failure_reason(pattern: &str, code: &str, snippet: &str, expected_reason: &str) { - let (db, position, selections) = single_file(code); - let mut match_finder = MatchFinder::in_context(&db, position, selections).unwrap(); - match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap(); - let mut reasons = Vec::new(); - for d in match_finder.debug_where_text_equal(position.file_id, snippet) { - if let Some(reason) = d.match_failure_reason() { - reasons.push(reason.to_owned()); - } - } - assert_eq!(reasons, vec![expected_reason]); -} - -#[test] -fn ssr_let_stmt_in_macro_match() { - assert_matches( - "let a = 0", - r#" - macro_rules! m1 { ($a:stmt) => {$a}; } - fn f() {m1!{ let a = 0 };}"#, - // FIXME: Whitespace is not part of the matched block - &["leta=0"], - ); -} - -#[test] -fn ssr_let_stmt_in_fn_match() { - assert_matches("let $a = 10;", "fn main() { let x = 10; x }", &["let x = 10;"]); - assert_matches("let $a = $b;", "fn main() { let x = 10; x }", &["let x = 10;"]); -} - -#[test] -fn ssr_block_expr_match() { - assert_matches("{ let $a = $b; }", "fn main() { let x = 10; }", &["{ let x = 10; }"]); - assert_matches("{ let $a = $b; $c }", "fn main() { let x = 10; x }", &["{ let x = 10; x }"]); -} - -#[test] -fn ssr_let_stmt_replace() { - // Pattern and template with trailing semicolon - assert_ssr_transform( - "let $a = $b; ==>> let $a = 11;", - "fn main() { let x = 10; x }", - expect![["fn main() { let x = 11; x }"]], - ); -} - -#[test] -fn ssr_let_stmt_replace_expr() { - // Trailing semicolon should be dropped from the new expression - assert_ssr_transform( - "let $a = $b; ==>> $b", - "fn main() { let x = 10; }", - expect![["fn main() { 10 }"]], - ); -} - -#[test] -fn ssr_blockexpr_replace_stmt_with_stmt() { - assert_ssr_transform( - "if $a() {$b;} ==>> $b;", - "{ - if foo() { - bar(); - } - Ok(()) -}", - expect![[r#"{ - bar(); - Ok(()) -}"#]], - ); -} - -#[test] -fn ssr_blockexpr_match_trailing_expr() { - assert_matches( - "if $a() {$b;}", - "{ - if foo() { - bar(); - } -}", - &["if foo() { - bar(); - }"], - ); -} - -#[test] -fn ssr_blockexpr_replace_trailing_expr_with_stmt() { - assert_ssr_transform( - "if $a() {$b;} ==>> $b;", - "{ - if foo() { - bar(); - } -}", - expect![["{ - bar(); -}"]], - ); -} - -#[test] -fn ssr_function_to_method() { - assert_ssr_transform( - "my_function($a, $b) ==>> ($a).my_method($b)", - "fn my_function() {} fn main() { loop { my_function( other_func(x, y), z + w) } }", - expect![["fn my_function() {} fn main() { loop { (other_func(x, y)).my_method(z + w) } }"]], - ) -} - -#[test] -fn ssr_nested_function() { - assert_ssr_transform( - "foo($a, $b, $c) ==>> bar($c, baz($a, $b))", - r#" - //- /lib.rs crate:foo - fn foo() {} - fn bar() {} - fn baz() {} - fn main { foo (x + value.method(b), x+y-z, true && false) } - "#, - expect![[r#" - fn foo() {} - fn bar() {} - fn baz() {} - fn main { bar(true && false, baz(x + value.method(b), x+y-z)) } - "#]], - ) -} - -#[test] -fn ssr_expected_spacing() { - assert_ssr_transform( - "foo($x) + bar() ==>> bar($x)", - "fn foo() {} fn bar() {} fn main() { foo(5) + bar() }", - expect![["fn foo() {} fn bar() {} fn main() { bar(5) }"]], - ); -} - -#[test] -fn ssr_with_extra_space() { - assert_ssr_transform( - "foo($x ) + bar() ==>> bar($x)", - "fn foo() {} fn bar() {} fn main() { foo( 5 ) +bar( ) }", - expect![["fn foo() {} fn bar() {} fn main() { bar(5) }"]], - ); -} - -#[test] -fn ssr_keeps_nested_comment() { - assert_ssr_transform( - "foo($x) ==>> bar($x)", - "fn foo() {} fn bar() {} fn main() { foo(other(5 /* using 5 */)) }", - expect![["fn foo() {} fn bar() {} fn main() { bar(other(5 /* using 5 */)) }"]], - ) -} - -#[test] -fn ssr_keeps_comment() { - assert_ssr_transform( - "foo($x) ==>> bar($x)", - "fn foo() {} fn bar() {} fn main() { foo(5 /* using 5 */) }", - expect![["fn foo() {} fn bar() {} fn main() { bar(5)/* using 5 */ }"]], - ) -} - -#[test] -fn ssr_struct_lit() { - assert_ssr_transform( - "Foo{a: $a, b: $b} ==>> Foo::new($a, $b)", - r#" - struct Foo() {} - impl Foo { fn new() {} } - fn main() { Foo{b:2, a:1} } - "#, - expect![[r#" - struct Foo() {} - impl Foo { fn new() {} } - fn main() { Foo::new(1, 2) } - "#]], - ) -} - -#[test] -fn ssr_struct_def() { - assert_ssr_transform( - "struct Foo { $f: $t } ==>> struct Foo($t);", - r#"struct Foo { field: i32 }"#, - expect![[r#"struct Foo(i32);"#]], - ) -} - -#[test] -fn ignores_whitespace() { - assert_matches("1+2", "fn f() -> i32 {1 + 2}", &["1 + 2"]); - assert_matches("1 + 2", "fn f() -> i32 {1+2}", &["1+2"]); -} - -#[test] -fn no_match() { - assert_no_match("1 + 3", "fn f() -> i32 {1 + 2}"); -} - -#[test] -fn match_fn_definition() { - assert_matches("fn $a($b: $t) {$c}", "fn f(a: i32) {bar()}", &["fn f(a: i32) {bar()}"]); -} - -#[test] -fn match_struct_definition() { - let code = r#" - struct Option {} - struct Bar {} - struct Foo {name: Option}"#; - assert_matches("struct $n {$f: Option}", code, &["struct Foo {name: Option}"]); -} - -#[test] -fn match_expr() { - let code = r#" - fn foo() {} - fn f() -> i32 {foo(40 + 2, 42)}"#; - assert_matches("foo($a, $b)", code, &["foo(40 + 2, 42)"]); - assert_no_match("foo($a, $b, $c)", code); - assert_no_match("foo($a)", code); -} - -#[test] -fn match_nested_method_calls() { - assert_matches( - "$a.z().z().z()", - "fn f() {h().i().j().z().z().z().d().e()}", - &["h().i().j().z().z().z()"], - ); -} - -// Make sure that our node matching semantics don't differ within macro calls. -#[test] -fn match_nested_method_calls_with_macro_call() { - assert_matches( - "$a.z().z().z()", - r#" - macro_rules! m1 { ($a:expr) => {$a}; } - fn f() {m1!(h().i().j().z().z().z().d().e())}"#, - &["h().i().j().z().z().z()"], - ); -} - -#[test] -fn match_complex_expr() { - let code = r#" - fn foo() {} fn bar() {} - fn f() -> i32 {foo(bar(40, 2), 42)}"#; - assert_matches("foo($a, $b)", code, &["foo(bar(40, 2), 42)"]); - assert_no_match("foo($a, $b, $c)", code); - assert_no_match("foo($a)", code); - assert_matches("bar($a, $b)", code, &["bar(40, 2)"]); -} - -// Trailing commas in the code should be ignored. -#[test] -fn match_with_trailing_commas() { - // Code has comma, pattern doesn't. - assert_matches("foo($a, $b)", "fn foo() {} fn f() {foo(1, 2,);}", &["foo(1, 2,)"]); - assert_matches("Foo{$a, $b}", "struct Foo {} fn f() {Foo{1, 2,};}", &["Foo{1, 2,}"]); - - // Pattern has comma, code doesn't. - assert_matches("foo($a, $b,)", "fn foo() {} fn f() {foo(1, 2);}", &["foo(1, 2)"]); - assert_matches("Foo{$a, $b,}", "struct Foo {} fn f() {Foo{1, 2};}", &["Foo{1, 2}"]); -} - -#[test] -fn match_type() { - assert_matches("i32", "fn f() -> i32 {1 + 2}", &["i32"]); - assert_matches( - "Option<$a>", - "struct Option {} fn f() -> Option {42}", - &["Option"], - ); - assert_no_match( - "Option<$a>", - "struct Option {} struct Result {} fn f() -> Result {42}", - ); -} - -#[test] -fn match_struct_instantiation() { - let code = r#" - struct Foo {bar: i32, baz: i32} - fn f() {Foo {bar: 1, baz: 2}}"#; - assert_matches("Foo {bar: 1, baz: 2}", code, &["Foo {bar: 1, baz: 2}"]); - // Now with placeholders for all parts of the struct. - assert_matches("Foo {$a: $b, $c: $d}", code, &["Foo {bar: 1, baz: 2}"]); - assert_matches("Foo {}", "struct Foo {} fn f() {Foo {}}", &["Foo {}"]); -} - -#[test] -fn match_path() { - let code = r#" - mod foo { - pub fn bar() {} - } - fn f() {foo::bar(42)}"#; - assert_matches("foo::bar", code, &["foo::bar"]); - assert_matches("$a::bar", code, &["foo::bar"]); - assert_matches("foo::$b", code, &["foo::bar"]); -} - -#[test] -fn match_pattern() { - assert_matches("Some($a)", "struct Some(); fn f() {if let Some(x) = foo() {}}", &["Some(x)"]); -} - -// If our pattern has a full path, e.g. a::b::c() and the code has c(), but c resolves to -// a::b::c, then we should match. -#[test] -fn match_fully_qualified_fn_path() { - let code = r#" - mod a { - pub mod b { - pub fn c(_: i32) {} - } - } - use a::b::c; - fn f1() { - c(42); - } - "#; - assert_matches("a::b::c($a)", code, &["c(42)"]); -} - -#[test] -fn match_resolved_type_name() { - let code = r#" - mod m1 { - pub mod m2 { - pub trait Foo {} - } - } - mod m3 { - trait Foo {} - fn f1(f: Option<&dyn Foo>) {} - } - mod m4 { - use crate::m1::m2::Foo; - fn f1(f: Option<&dyn Foo>) {} - } - "#; - assert_matches("m1::m2::Foo<$t>", code, &["Foo"]); -} - -#[test] -fn type_arguments_within_path() { - cov_mark::check!(type_arguments_within_path); - let code = r#" - mod foo { - pub struct Bar {t: T} - impl Bar { - pub fn baz() {} - } - } - fn f1() {foo::Bar::::baz();} - "#; - assert_no_match("foo::Bar::::baz()", code); - assert_matches("foo::Bar::::baz()", code, &["foo::Bar::::baz()"]); -} - -#[test] -fn literal_constraint() { - cov_mark::check!(literal_constraint); - let code = r#" - enum Option { Some(T), None } - use Option::Some; - fn f1() { - let x1 = Some(42); - let x2 = Some("foo"); - let x3 = Some(x1); - let x4 = Some(40 + 2); - let x5 = Some(true); - } - "#; - assert_matches("Some(${a:kind(literal)})", code, &["Some(42)", "Some(\"foo\")", "Some(true)"]); - assert_matches("Some(${a:not(kind(literal))})", code, &["Some(x1)", "Some(40 + 2)"]); -} - -#[test] -fn match_reordered_struct_instantiation() { - assert_matches( - "Foo {aa: 1, b: 2, ccc: 3}", - "struct Foo {} fn f() {Foo {b: 2, ccc: 3, aa: 1}}", - &["Foo {b: 2, ccc: 3, aa: 1}"], - ); - assert_no_match("Foo {a: 1}", "struct Foo {} fn f() {Foo {b: 1}}"); - assert_no_match("Foo {a: 1}", "struct Foo {} fn f() {Foo {a: 2}}"); - assert_no_match("Foo {a: 1, b: 2}", "struct Foo {} fn f() {Foo {a: 1}}"); - assert_no_match("Foo {a: 1, b: 2}", "struct Foo {} fn f() {Foo {b: 2}}"); - assert_no_match("Foo {a: 1, }", "struct Foo {} fn f() {Foo {a: 1, b: 2}}"); - assert_no_match("Foo {a: 1, z: 9}", "struct Foo {} fn f() {Foo {a: 1}}"); -} - -#[test] -fn match_macro_invocation() { - assert_matches( - "foo!($a)", - "macro_rules! foo {() => {}} fn() {foo(foo!(foo()))}", - &["foo!(foo())"], - ); - assert_matches( - "foo!(41, $a, 43)", - "macro_rules! foo {() => {}} fn() {foo!(41, 42, 43)}", - &["foo!(41, 42, 43)"], - ); - assert_no_match("foo!(50, $a, 43)", "macro_rules! foo {() => {}} fn() {foo!(41, 42, 43}"); - assert_no_match("foo!(41, $a, 50)", "macro_rules! foo {() => {}} fn() {foo!(41, 42, 43}"); - assert_matches( - "foo!($a())", - "macro_rules! foo {() => {}} fn() {foo!(bar())}", - &["foo!(bar())"], - ); -} - -// When matching within a macro expansion, we only allow matches of nodes that originated from -// the macro call, not from the macro definition. -#[test] -fn no_match_expression_from_macro() { - assert_no_match( - "$a.clone()", - r#" - macro_rules! m1 { - () => {42.clone()} - } - fn f1() {m1!()} - "#, - ); -} - -// We definitely don't want to allow matching of an expression that part originates from the -// macro call `42` and part from the macro definition `.clone()`. -#[test] -fn no_match_split_expression() { - assert_no_match( - "$a.clone()", - r#" - macro_rules! m1 { - ($x:expr) => {$x.clone()} - } - fn f1() {m1!(42)} - "#, - ); -} - -#[test] -fn replace_function_call() { - // This test also makes sure that we ignore empty-ranges. - assert_ssr_transform( - "foo() ==>> bar()", - "fn foo() {$0$0} fn bar() {} fn f1() {foo(); foo();}", - expect![["fn foo() {} fn bar() {} fn f1() {bar(); bar();}"]], - ); -} - -#[test] -fn replace_function_call_with_placeholders() { - assert_ssr_transform( - "foo($a, $b) ==>> bar($b, $a)", - "fn foo() {} fn bar() {} fn f1() {foo(5, 42)}", - expect![["fn foo() {} fn bar() {} fn f1() {bar(42, 5)}"]], - ); -} - -#[test] -fn replace_nested_function_calls() { - assert_ssr_transform( - "foo($a) ==>> bar($a)", - "fn foo() {} fn bar() {} fn f1() {foo(foo(42))}", - expect![["fn foo() {} fn bar() {} fn f1() {bar(bar(42))}"]], - ); -} - -#[test] -fn replace_associated_function_call() { - assert_ssr_transform( - "Foo::new() ==>> Bar::new()", - r#" - struct Foo {} - impl Foo { fn new() {} } - struct Bar {} - impl Bar { fn new() {} } - fn f1() {Foo::new();} - "#, - expect![[r#" - struct Foo {} - impl Foo { fn new() {} } - struct Bar {} - impl Bar { fn new() {} } - fn f1() {Bar::new();} - "#]], - ); -} - -#[test] -fn replace_associated_trait_default_function_call() { - cov_mark::check!(replace_associated_trait_default_function_call); - assert_ssr_transform( - "Bar2::foo() ==>> Bar2::foo2()", - r#" - trait Foo { fn foo() {} } - pub struct Bar {} - impl Foo for Bar {} - pub struct Bar2 {} - impl Foo for Bar2 {} - impl Bar2 { fn foo2() {} } - fn main() { - Bar::foo(); - Bar2::foo(); - } - "#, - expect![[r#" - trait Foo { fn foo() {} } - pub struct Bar {} - impl Foo for Bar {} - pub struct Bar2 {} - impl Foo for Bar2 {} - impl Bar2 { fn foo2() {} } - fn main() { - Bar::foo(); - Bar2::foo2(); - } - "#]], - ); -} - -#[test] -fn replace_associated_trait_constant() { - cov_mark::check!(replace_associated_trait_constant); - assert_ssr_transform( - "Bar2::VALUE ==>> Bar2::VALUE_2222", - r#" - trait Foo { const VALUE: i32; const VALUE_2222: i32; } - pub struct Bar {} - impl Foo for Bar { const VALUE: i32 = 1; const VALUE_2222: i32 = 2; } - pub struct Bar2 {} - impl Foo for Bar2 { const VALUE: i32 = 1; const VALUE_2222: i32 = 2; } - impl Bar2 { fn foo2() {} } - fn main() { - Bar::VALUE; - Bar2::VALUE; - } - "#, - expect![[r#" - trait Foo { const VALUE: i32; const VALUE_2222: i32; } - pub struct Bar {} - impl Foo for Bar { const VALUE: i32 = 1; const VALUE_2222: i32 = 2; } - pub struct Bar2 {} - impl Foo for Bar2 { const VALUE: i32 = 1; const VALUE_2222: i32 = 2; } - impl Bar2 { fn foo2() {} } - fn main() { - Bar::VALUE; - Bar2::VALUE_2222; - } - "#]], - ); -} - -#[test] -fn replace_path_in_different_contexts() { - // Note the $0 inside module a::b which marks the point where the rule is interpreted. We - // replace foo with bar, but both need different path qualifiers in different contexts. In f4, - // foo is unqualified because of a use statement, however the replacement needs to be fully - // qualified. - assert_ssr_transform( - "c::foo() ==>> c::bar()", - r#" - mod a { - pub mod b {$0 - pub mod c { - pub fn foo() {} - pub fn bar() {} - fn f1() { foo() } - } - fn f2() { c::foo() } - } - fn f3() { b::c::foo() } - } - use a::b::c::foo; - fn f4() { foo() } - "#, - expect![[r#" - mod a { - pub mod b { - pub mod c { - pub fn foo() {} - pub fn bar() {} - fn f1() { bar() } - } - fn f2() { c::bar() } - } - fn f3() { b::c::bar() } - } - use a::b::c::foo; - fn f4() { a::b::c::bar() } - "#]], - ); -} - -#[test] -fn replace_associated_function_with_generics() { - assert_ssr_transform( - "c::Foo::<$a>::new() ==>> d::Bar::<$a>::default()", - r#" - mod c { - pub struct Foo {v: T} - impl Foo { pub fn new() {} } - fn f1() { - Foo::::new(); - } - } - mod d { - pub struct Bar {v: T} - impl Bar { pub fn default() {} } - fn f1() { - super::c::Foo::::new(); - } - } - "#, - expect![[r#" - mod c { - pub struct Foo {v: T} - impl Foo { pub fn new() {} } - fn f1() { - crate::d::Bar::::default(); - } - } - mod d { - pub struct Bar {v: T} - impl Bar { pub fn default() {} } - fn f1() { - Bar::::default(); - } - } - "#]], - ); -} - -#[test] -fn replace_type() { - assert_ssr_transform( - "Result<(), $a> ==>> Option<$a>", - "struct Result {} struct Option {} fn f1() -> Result<(), Vec> {foo()}", - expect![[ - "struct Result {} struct Option {} fn f1() -> Option> {foo()}" - ]], - ); - assert_ssr_transform( - "dyn Trait<$a> ==>> DynTrait<$a>", - r#" -trait Trait {} -struct DynTrait {} -fn f1() -> dyn Trait> {foo()} -"#, - expect![[r#" -trait Trait {} -struct DynTrait {} -fn f1() -> DynTrait> {foo()} -"#]], - ); -} - -#[test] -fn replace_macro_invocations() { - assert_ssr_transform( - "try!($a) ==>> $a?", - "macro_rules! try {() => {}} fn f1() -> Result<(), E> {bar(try!(foo()));}", - expect![["macro_rules! try {() => {}} fn f1() -> Result<(), E> {bar(foo()?);}"]], - ); - // FIXME: Figure out why this doesn't work anymore - // assert_ssr_transform( - // "foo!($a($b)) ==>> foo($b, $a)", - // "macro_rules! foo {() => {}} fn f1() {foo!(abc(def() + 2));}", - // expect![["macro_rules! foo {() => {}} fn f1() {foo(def() + 2, abc);}"]], - // ); -} - -#[test] -fn replace_binary_op() { - assert_ssr_transform( - "$a + $b ==>> $b + $a", - "fn f() {2 * 3 + 4 * 5}", - expect![["fn f() {4 * 5 + 2 * 3}"]], - ); - assert_ssr_transform( - "$a + $b ==>> $b + $a", - "fn f() {1 + 2 + 3 + 4}", - expect![[r#"fn f() {4 + (3 + (2 + 1))}"#]], - ); -} - -#[test] -fn match_binary_op() { - assert_matches("$a + $b", "fn f() {1 + 2 + 3 + 4}", &["1 + 2", "1 + 2 + 3", "1 + 2 + 3 + 4"]); -} - -#[test] -fn multiple_rules() { - assert_ssr_transforms( - &["$a + 1 ==>> add_one($a)", "$a + $b ==>> add($a, $b)"], - "fn add() {} fn add_one() {} fn f() -> i32 {3 + 2 + 1}", - expect![["fn add() {} fn add_one() {} fn f() -> i32 {add_one(add(3, 2))}"]], - ) -} - -#[test] -fn multiple_rules_with_nested_matches() { - assert_ssr_transforms( - &["foo1($a) ==>> bar1($a)", "foo2($a) ==>> bar2($a)"], - r#" - fn foo1() {} fn foo2() {} fn bar1() {} fn bar2() {} - fn f() {foo1(foo2(foo1(foo2(foo1(42)))))} - "#, - expect![[r#" - fn foo1() {} fn foo2() {} fn bar1() {} fn bar2() {} - fn f() {bar1(bar2(bar1(bar2(bar1(42)))))} - "#]], - ) -} - -#[test] -fn match_within_macro_invocation() { - let code = r#" - macro_rules! foo { - ($a:stmt; $b:expr) => { - $b - }; - } - struct A {} - impl A { - fn bar() {} - } - fn f1() { - let aaa = A {}; - foo!(macro_ignores_this(); aaa.bar()); - } - "#; - assert_matches("$a.bar()", code, &["aaa.bar()"]); -} - -#[test] -fn replace_within_macro_expansion() { - assert_ssr_transform( - "$a.foo() ==>> bar($a)", - r#" - macro_rules! macro1 { - ($a:expr) => {$a} - } - fn bar() {} - fn f() {macro1!(5.x().foo().o2())} - "#, - expect![[r#" - macro_rules! macro1 { - ($a:expr) => {$a} - } - fn bar() {} - fn f() {macro1!(bar(5.x()).o2())} - "#]], - ) -} - -#[test] -fn replace_outside_and_within_macro_expansion() { - assert_ssr_transform( - "foo($a) ==>> bar($a)", - r#" - fn foo() {} fn bar() {} - macro_rules! macro1 { - ($a:expr) => {$a} - } - fn f() {foo(foo(macro1!(foo(foo(42)))))} - "#, - expect![[r#" - fn foo() {} fn bar() {} - macro_rules! macro1 { - ($a:expr) => {$a} - } - fn f() {bar(bar(macro1!(bar(bar(42)))))} - "#]], - ) -} - -#[test] -fn preserves_whitespace_within_macro_expansion() { - assert_ssr_transform( - "$a + $b ==>> $b - $a", - r#" - macro_rules! macro1 { - ($a:expr) => {$a} - } - fn f() {macro1!(1 * 2 + 3 + 4)} - "#, - expect![[r#" - macro_rules! macro1 { - ($a:expr) => {$a} - } - fn f() {macro1!(4 - (3 - 1 * 2))} - "#]], - ) -} - -#[test] -fn add_parenthesis_when_necessary() { - assert_ssr_transform( - "foo($a) ==>> $a.to_string()", - r#" - fn foo(_: i32) {} - fn bar3(v: i32) { - foo(1 + 2); - foo(-v); - } - "#, - expect![[r#" - fn foo(_: i32) {} - fn bar3(v: i32) { - (1 + 2).to_string(); - (-v).to_string(); - } - "#]], - ) -} - -#[test] -fn match_failure_reasons() { - let code = r#" - fn bar() {} - macro_rules! foo { - ($a:expr) => { - 1 + $a + 2 - }; - } - fn f1() { - bar(1, 2); - foo!(5 + 43.to_string() + 5); - } - "#; - assert_match_failure_reason( - "bar($a, 3)", - code, - "bar(1, 2)", - r#"Pattern wanted token '3' (INT_NUMBER), but code had token '2' (INT_NUMBER)"#, - ); - assert_match_failure_reason( - "42.to_string()", - code, - "43.to_string()", - r#"Pattern wanted token '42' (INT_NUMBER), but code had token '43' (INT_NUMBER)"#, - ); -} - -#[test] -fn overlapping_possible_matches() { - // There are three possible matches here, however the middle one, `foo(foo(foo(42)))` shouldn't - // match because it overlaps with the outer match. The inner match is permitted since it's is - // contained entirely within the placeholder of the outer match. - assert_matches( - "foo(foo($a))", - "fn foo() {} fn main() {foo(foo(foo(foo(42))))}", - &["foo(foo(42))", "foo(foo(foo(foo(42))))"], - ); -} - -#[test] -fn use_declaration_with_braces() { - // It would be OK for a path rule to match and alter a use declaration. We shouldn't mess it up - // though. In particular, we must not change `use foo::{baz, bar}` to `use foo::{baz, - // foo2::bar2}`. - cov_mark::check!(use_declaration_with_braces); - assert_ssr_transform( - "foo::bar ==>> foo2::bar2", - r#" - mod foo { pub fn bar() {} pub fn baz() {} } - mod foo2 { pub fn bar2() {} } - use foo::{baz, bar}; - fn main() { bar() } - "#, - expect![[" - mod foo { pub fn bar() {} pub fn baz() {} } - mod foo2 { pub fn bar2() {} } - use foo::{baz, bar}; - fn main() { foo2::bar2() } - "]], - ) -} - -#[test] -fn ufcs_matches_method_call() { - let code = r#" - struct Foo {} - impl Foo { - fn new(_: i32) -> Foo { Foo {} } - fn do_stuff(&self, _: i32) {} - } - struct Bar {} - impl Bar { - fn new(_: i32) -> Bar { Bar {} } - fn do_stuff(&self, v: i32) {} - } - fn main() { - let b = Bar {}; - let f = Foo {}; - b.do_stuff(1); - f.do_stuff(2); - Foo::new(4).do_stuff(3); - // Too many / too few args - should never match - f.do_stuff(2, 10); - f.do_stuff(); - } - "#; - assert_matches("Foo::do_stuff($a, $b)", code, &["f.do_stuff(2)", "Foo::new(4).do_stuff(3)"]); - // The arguments needs special handling in the case of a function call matching a method call - // and the first argument is different. - assert_matches("Foo::do_stuff($a, 2)", code, &["f.do_stuff(2)"]); - assert_matches("Foo::do_stuff(Foo::new(4), $b)", code, &["Foo::new(4).do_stuff(3)"]); - - assert_ssr_transform( - "Foo::do_stuff(Foo::new($a), $b) ==>> Bar::new($b).do_stuff($a)", - code, - expect![[r#" - struct Foo {} - impl Foo { - fn new(_: i32) -> Foo { Foo {} } - fn do_stuff(&self, _: i32) {} - } - struct Bar {} - impl Bar { - fn new(_: i32) -> Bar { Bar {} } - fn do_stuff(&self, v: i32) {} - } - fn main() { - let b = Bar {}; - let f = Foo {}; - b.do_stuff(1); - f.do_stuff(2); - Bar::new(3).do_stuff(4); - // Too many / too few args - should never match - f.do_stuff(2, 10); - f.do_stuff(); - } - "#]], - ); -} - -#[test] -fn pattern_is_a_single_segment_path() { - cov_mark::check!(pattern_is_a_single_segment_path); - // The first function should not be altered because the `foo` in scope at the cursor position is - // a different `foo`. This case is special because "foo" can be parsed as a pattern (IDENT_PAT -> - // NAME -> IDENT), which contains no path. If we're not careful we'll end up matching the `foo` - // in `let foo` from the first function. Whether we should match the `let foo` in the second - // function is less clear. At the moment, we don't. Doing so sounds like a rename operation, - // which isn't really what SSR is for, especially since the replacement `bar` must be able to be - // resolved, which means if we rename `foo` we'll get a name collision. - assert_ssr_transform( - "foo ==>> bar", - r#" - fn f1() -> i32 { - let foo = 1; - let bar = 2; - foo - } - fn f1() -> i32 { - let foo = 1; - let bar = 2; - foo$0 - } - "#, - expect![[r#" - fn f1() -> i32 { - let foo = 1; - let bar = 2; - foo - } - fn f1() -> i32 { - let foo = 1; - let bar = 2; - bar - } - "#]], - ); -} - -#[test] -fn replace_local_variable_reference() { - // The pattern references a local variable `foo` in the block containing the cursor. We should - // only replace references to this variable `foo`, not other variables that just happen to have - // the same name. - cov_mark::check!(cursor_after_semicolon); - assert_ssr_transform( - "foo + $a ==>> $a - foo", - r#" - fn bar1() -> i32 { - let mut res = 0; - let foo = 5; - res += foo + 1; - let foo = 10; - res += foo + 2;$0 - res += foo + 3; - let foo = 15; - res += foo + 4; - res - } - "#, - expect![[r#" - fn bar1() -> i32 { - let mut res = 0; - let foo = 5; - res += foo + 1; - let foo = 10; - res += 2 - foo; - res += 3 - foo; - let foo = 15; - res += foo + 4; - res - } - "#]], - ) -} - -#[test] -fn replace_path_within_selection() { - assert_ssr_transform( - "foo ==>> bar", - r#" - fn main() { - let foo = 41; - let bar = 42; - do_stuff(foo); - do_stuff(foo);$0 - do_stuff(foo); - do_stuff(foo);$0 - do_stuff(foo); - }"#, - expect![[r#" - fn main() { - let foo = 41; - let bar = 42; - do_stuff(foo); - do_stuff(foo); - do_stuff(bar); - do_stuff(bar); - do_stuff(foo); - }"#]], - ); -} - -#[test] -fn replace_nonpath_within_selection() { - cov_mark::check!(replace_nonpath_within_selection); - assert_ssr_transform( - "$a + $b ==>> $b * $a", - r#" - fn main() { - let v = 1 + 2;$0 - let v2 = 3 + 3; - let v3 = 4 + 5;$0 - let v4 = 6 + 7; - }"#, - expect![[r#" - fn main() { - let v = 1 + 2; - let v2 = 3 * 3; - let v3 = 5 * 4; - let v4 = 6 + 7; - }"#]], - ); -} - -#[test] -fn replace_self() { - // `foo(self)` occurs twice in the code, however only the first occurrence is the `self` that's - // in scope where the rule is invoked. - assert_ssr_transform( - "foo(self) ==>> bar(self)", - r#" - struct S1 {} - fn foo(_: &S1) {} - fn bar(_: &S1) {} - impl S1 { - fn f1(&self) { - foo(self)$0 - } - fn f2(&self) { - foo(self) - } - } - "#, - expect![[r#" - struct S1 {} - fn foo(_: &S1) {} - fn bar(_: &S1) {} - impl S1 { - fn f1(&self) { - bar(self) - } - fn f2(&self) { - foo(self) - } - } - "#]], - ); -} - -#[test] -fn match_trait_method_call() { - // `Bar::foo` and `Bar2::foo` resolve to the same function. Make sure we only match if the type - // matches what's in the pattern. Also checks that we handle autoderef. - let code = r#" - pub struct Bar {} - pub struct Bar2 {} - pub trait Foo { - fn foo(&self, _: i32) {} - } - impl Foo for Bar {} - impl Foo for Bar2 {} - fn main() { - let v1 = Bar {}; - let v2 = Bar2 {}; - let v1_ref = &v1; - let v2_ref = &v2; - v1.foo(1); - v2.foo(2); - Bar::foo(&v1, 3); - Bar2::foo(&v2, 4); - v1_ref.foo(5); - v2_ref.foo(6); - } - "#; - assert_matches("Bar::foo($a, $b)", code, &["v1.foo(1)", "Bar::foo(&v1, 3)", "v1_ref.foo(5)"]); - assert_matches("Bar2::foo($a, $b)", code, &["v2.foo(2)", "Bar2::foo(&v2, 4)", "v2_ref.foo(6)"]); -} - -#[test] -fn replace_autoref_autoderef_capture() { - // Here we have several calls to `$a.foo()`. In the first case autoref is applied, in the - // second, we already have a reference, so it isn't. When $a is used in a context where autoref - // doesn't apply, we need to prefix it with `&`. Finally, we have some cases where autoderef - // needs to be applied. - cov_mark::check!(replace_autoref_autoderef_capture); - let code = r#" - struct Foo {} - impl Foo { - fn foo(&self) {} - fn foo2(&self) {} - } - fn bar(_: &Foo) {} - fn main() { - let f = Foo {}; - let fr = &f; - let fr2 = &fr; - let fr3 = &fr2; - f.foo(); - fr.foo(); - fr2.foo(); - fr3.foo(); - } - "#; - assert_ssr_transform( - "Foo::foo($a) ==>> bar($a)", - code, - expect![[r#" - struct Foo {} - impl Foo { - fn foo(&self) {} - fn foo2(&self) {} - } - fn bar(_: &Foo) {} - fn main() { - let f = Foo {}; - let fr = &f; - let fr2 = &fr; - let fr3 = &fr2; - bar(&f); - bar(&*fr); - bar(&**fr2); - bar(&***fr3); - } - "#]], - ); - // If the placeholder is used as the receiver of another method call, then we don't need to - // explicitly autoderef or autoref. - assert_ssr_transform( - "Foo::foo($a) ==>> $a.foo2()", - code, - expect![[r#" - struct Foo {} - impl Foo { - fn foo(&self) {} - fn foo2(&self) {} - } - fn bar(_: &Foo) {} - fn main() { - let f = Foo {}; - let fr = &f; - let fr2 = &fr; - let fr3 = &fr2; - f.foo2(); - fr.foo2(); - fr2.foo2(); - fr3.foo2(); - } - "#]], - ); -} - -#[test] -fn replace_autoref_mut() { - let code = r#" - struct Foo {} - impl Foo { - fn foo(&mut self) {} - } - fn bar(_: &mut Foo) {} - fn main() { - let mut f = Foo {}; - f.foo(); - let fr = &mut f; - fr.foo(); - } - "#; - assert_ssr_transform( - "Foo::foo($a) ==>> bar($a)", - code, - expect![[r#" - struct Foo {} - impl Foo { - fn foo(&mut self) {} - } - fn bar(_: &mut Foo) {} - fn main() { - let mut f = Foo {}; - bar(&mut f); - let fr = &mut f; - bar(&mut *fr); - } - "#]], - ); -} diff --git a/src/tools/rust-analyzer/crates/ide/Cargo.toml b/src/tools/rust-analyzer/crates/ide/Cargo.toml deleted file mode 100644 index 0e9771cd2ebaf..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/Cargo.toml +++ /dev/null @@ -1,47 +0,0 @@ -[package] -name = "ide" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -cov-mark = "2.0.0-pre.1" -crossbeam-channel = "0.5.5" -either = "1.7.0" -itertools = "0.10.3" -tracing = "0.1.35" -oorandom = "11.1.3" -pulldown-cmark-to-cmark = "10.0.1" -pulldown-cmark = { version = "0.9.1", default-features = false } -url = "2.2.2" -dot = "0.1.4" - -stdx = { path = "../stdx", version = "0.0.0" } -syntax = { path = "../syntax", version = "0.0.0" } -text-edit = { path = "../text-edit", version = "0.0.0" } -ide-db = { path = "../ide-db", version = "0.0.0" } -cfg = { path = "../cfg", version = "0.0.0" } -profile = { path = "../profile", version = "0.0.0" } -ide-assists = { path = "../ide-assists", version = "0.0.0" } -ide-diagnostics = { path = "../ide-diagnostics", version = "0.0.0" } -ide-ssr = { path = "../ide-ssr", version = "0.0.0" } -ide-completion = { path = "../ide-completion", version = "0.0.0" } - -# ide should depend only on the top-level `hir` package. if you need -# something from some `hir-xxx` subpackage, reexport the API via `hir`. -hir = { path = "../hir", version = "0.0.0" } - -[target.'cfg(not(any(target_arch = "wasm32", target_os = "emscripten")))'.dependencies] -toolchain = { path = "../toolchain", version = "0.0.0" } - -[dev-dependencies] -test-utils = { path = "../test-utils" } -expect-test = "1.4.0" - -[features] -in-rust-tree = ["ide-assists/in-rust-tree", "ide-diagnostics/in-rust-tree"] diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations.rs b/src/tools/rust-analyzer/crates/ide/src/annotations.rs deleted file mode 100644 index 210c5c7facd2d..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/annotations.rs +++ /dev/null @@ -1,789 +0,0 @@ -use hir::{HasSource, InFile, Semantics}; -use ide_db::{ - base_db::{FileId, FilePosition, FileRange}, - defs::Definition, - helpers::visit_file_defs, - RootDatabase, -}; -use syntax::{ast::HasName, AstNode, TextRange}; - -use crate::{ - fn_references::find_all_methods, - goto_implementation::goto_implementation, - references::find_all_refs, - runnables::{runnables, Runnable}, - NavigationTarget, RunnableKind, -}; - -// Feature: Annotations -// -// Provides user with annotations above items for looking up references or impl blocks -// and running/debugging binaries. -// -// image::https://user-images.githubusercontent.com/48062697/113020672-b7c34f00-917a-11eb-8f6e-858735660a0e.png[] -#[derive(Debug)] -pub struct Annotation { - pub range: TextRange, - pub kind: AnnotationKind, -} - -#[derive(Debug)] -pub enum AnnotationKind { - Runnable(Runnable), - HasImpls { file_id: FileId, data: Option> }, - HasReferences { file_id: FileId, data: Option> }, -} - -pub struct AnnotationConfig { - pub binary_target: bool, - pub annotate_runnables: bool, - pub annotate_impls: bool, - pub annotate_references: bool, - pub annotate_method_references: bool, - pub annotate_enum_variant_references: bool, -} - -pub(crate) fn annotations( - db: &RootDatabase, - config: &AnnotationConfig, - file_id: FileId, -) -> Vec { - let mut annotations = Vec::default(); - - if config.annotate_runnables { - for runnable in runnables(db, file_id) { - if should_skip_runnable(&runnable.kind, config.binary_target) { - continue; - } - - let range = runnable.nav.focus_or_full_range(); - - annotations.push(Annotation { range, kind: AnnotationKind::Runnable(runnable) }); - } - } - - visit_file_defs(&Semantics::new(db), file_id, &mut |def| { - let range = match def { - Definition::Const(konst) if config.annotate_references => { - konst.source(db).and_then(|node| name_range(db, node, file_id)) - } - Definition::Trait(trait_) if config.annotate_references || config.annotate_impls => { - trait_.source(db).and_then(|node| name_range(db, node, file_id)) - } - Definition::Adt(adt) => match adt { - hir::Adt::Enum(enum_) => { - if config.annotate_enum_variant_references { - enum_ - .variants(db) - .into_iter() - .map(|variant| { - variant.source(db).and_then(|node| name_range(db, node, file_id)) - }) - .flatten() - .for_each(|range| { - annotations.push(Annotation { - range, - kind: AnnotationKind::HasReferences { file_id, data: None }, - }) - }) - } - if config.annotate_references || config.annotate_impls { - enum_.source(db).and_then(|node| name_range(db, node, file_id)) - } else { - None - } - } - _ => { - if config.annotate_references || config.annotate_impls { - adt.source(db).and_then(|node| name_range(db, node, file_id)) - } else { - None - } - } - }, - _ => None, - }; - - let range = match range { - Some(range) => range, - None => return, - }; - - if config.annotate_impls && !matches!(def, Definition::Const(_)) { - annotations - .push(Annotation { range, kind: AnnotationKind::HasImpls { file_id, data: None } }); - } - if config.annotate_references { - annotations.push(Annotation { - range, - kind: AnnotationKind::HasReferences { file_id, data: None }, - }); - } - - fn name_range( - db: &RootDatabase, - node: InFile, - source_file_id: FileId, - ) -> Option { - if let Some(InFile { file_id, value }) = node.original_ast_node(db) { - if file_id == source_file_id.into() { - return value.name().map(|it| it.syntax().text_range()); - } - } - None - } - }); - - if config.annotate_method_references { - annotations.extend(find_all_methods(db, file_id).into_iter().map( - |FileRange { file_id, range }| Annotation { - range, - kind: AnnotationKind::HasReferences { file_id, data: None }, - }, - )); - } - - annotations -} - -pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation { - match annotation.kind { - AnnotationKind::HasImpls { file_id, ref mut data } => { - *data = - goto_implementation(db, FilePosition { file_id, offset: annotation.range.start() }) - .map(|range| range.info); - } - AnnotationKind::HasReferences { file_id, ref mut data } => { - *data = find_all_refs( - &Semantics::new(db), - FilePosition { file_id, offset: annotation.range.start() }, - None, - ) - .map(|result| { - result - .into_iter() - .flat_map(|res| res.references) - .flat_map(|(file_id, access)| { - access.into_iter().map(move |(range, _)| FileRange { file_id, range }) - }) - .collect() - }); - } - _ => {} - }; - - annotation -} - -fn should_skip_runnable(kind: &RunnableKind, binary_target: bool) -> bool { - match kind { - RunnableKind::Bin => !binary_target, - _ => false, - } -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use crate::{fixture, Annotation, AnnotationConfig}; - - fn check(ra_fixture: &str, expect: Expect) { - let (analysis, file_id) = fixture::file(ra_fixture); - - let annotations: Vec = analysis - .annotations( - &AnnotationConfig { - binary_target: true, - annotate_runnables: true, - annotate_impls: true, - annotate_references: true, - annotate_method_references: true, - annotate_enum_variant_references: true, - }, - file_id, - ) - .unwrap() - .into_iter() - .map(|annotation| analysis.resolve_annotation(annotation).unwrap()) - .collect(); - - expect.assert_debug_eq(&annotations); - } - - #[test] - fn const_annotations() { - check( - r#" -const DEMO: i32 = 123; - -const UNUSED: i32 = 123; - -fn main() { - let hello = DEMO; -} - "#, - expect![[r#" - [ - Annotation { - range: 53..57, - kind: Runnable( - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 50..85, - focus_range: 53..57, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - ), - }, - Annotation { - range: 6..10, - kind: HasReferences { - file_id: FileId( - 0, - ), - data: Some( - [ - FileRange { - file_id: FileId( - 0, - ), - range: 78..82, - }, - ], - ), - }, - }, - Annotation { - range: 30..36, - kind: HasReferences { - file_id: FileId( - 0, - ), - data: Some( - [], - ), - }, - }, - Annotation { - range: 53..57, - kind: HasReferences { - file_id: FileId( - 0, - ), - data: Some( - [], - ), - }, - }, - ] - "#]], - ); - } - - #[test] - fn struct_references_annotations() { - check( - r#" -struct Test; - -fn main() { - let test = Test; -} - "#, - expect![[r#" - [ - Annotation { - range: 17..21, - kind: Runnable( - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 14..48, - focus_range: 17..21, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - ), - }, - Annotation { - range: 7..11, - kind: HasImpls { - file_id: FileId( - 0, - ), - data: Some( - [], - ), - }, - }, - Annotation { - range: 7..11, - kind: HasReferences { - file_id: FileId( - 0, - ), - data: Some( - [ - FileRange { - file_id: FileId( - 0, - ), - range: 41..45, - }, - ], - ), - }, - }, - Annotation { - range: 17..21, - kind: HasReferences { - file_id: FileId( - 0, - ), - data: Some( - [], - ), - }, - }, - ] - "#]], - ); - } - - #[test] - fn struct_and_trait_impls_annotations() { - check( - r#" -struct Test; - -trait MyCoolTrait {} - -impl MyCoolTrait for Test {} - -fn main() { - let test = Test; -} - "#, - expect![[r#" - [ - Annotation { - range: 69..73, - kind: Runnable( - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 66..100, - focus_range: 69..73, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - ), - }, - Annotation { - range: 7..11, - kind: HasImpls { - file_id: FileId( - 0, - ), - data: Some( - [ - NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 36..64, - focus_range: 57..61, - name: "impl", - kind: Impl, - }, - ], - ), - }, - }, - Annotation { - range: 7..11, - kind: HasReferences { - file_id: FileId( - 0, - ), - data: Some( - [ - FileRange { - file_id: FileId( - 0, - ), - range: 57..61, - }, - FileRange { - file_id: FileId( - 0, - ), - range: 93..97, - }, - ], - ), - }, - }, - Annotation { - range: 20..31, - kind: HasImpls { - file_id: FileId( - 0, - ), - data: Some( - [ - NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 36..64, - focus_range: 57..61, - name: "impl", - kind: Impl, - }, - ], - ), - }, - }, - Annotation { - range: 20..31, - kind: HasReferences { - file_id: FileId( - 0, - ), - data: Some( - [ - FileRange { - file_id: FileId( - 0, - ), - range: 41..52, - }, - ], - ), - }, - }, - Annotation { - range: 69..73, - kind: HasReferences { - file_id: FileId( - 0, - ), - data: Some( - [], - ), - }, - }, - ] - "#]], - ); - } - - #[test] - fn runnable_annotation() { - check( - r#" -fn main() {} - "#, - expect![[r#" - [ - Annotation { - range: 3..7, - kind: Runnable( - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 3..7, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - ), - }, - Annotation { - range: 3..7, - kind: HasReferences { - file_id: FileId( - 0, - ), - data: Some( - [], - ), - }, - }, - ] - "#]], - ); - } - - #[test] - fn method_annotations() { - check( - r#" -struct Test; - -impl Test { - fn self_by_ref(&self) {} -} - -fn main() { - Test.self_by_ref(); -} - "#, - expect![[r#" - [ - Annotation { - range: 61..65, - kind: Runnable( - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 58..95, - focus_range: 61..65, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - ), - }, - Annotation { - range: 7..11, - kind: HasImpls { - file_id: FileId( - 0, - ), - data: Some( - [ - NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 14..56, - focus_range: 19..23, - name: "impl", - kind: Impl, - }, - ], - ), - }, - }, - Annotation { - range: 7..11, - kind: HasReferences { - file_id: FileId( - 0, - ), - data: Some( - [ - FileRange { - file_id: FileId( - 0, - ), - range: 19..23, - }, - FileRange { - file_id: FileId( - 0, - ), - range: 74..78, - }, - ], - ), - }, - }, - Annotation { - range: 33..44, - kind: HasReferences { - file_id: FileId( - 0, - ), - data: Some( - [ - FileRange { - file_id: FileId( - 0, - ), - range: 79..90, - }, - ], - ), - }, - }, - Annotation { - range: 61..65, - kind: HasReferences { - file_id: FileId( - 0, - ), - data: Some( - [], - ), - }, - }, - ] - "#]], - ); - } - - #[test] - fn test_annotations() { - check( - r#" -fn main() {} - -mod tests { - #[test] - fn my_cool_test() {} -} - "#, - expect![[r#" - [ - Annotation { - range: 3..7, - kind: Runnable( - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 3..7, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - ), - }, - Annotation { - range: 18..23, - kind: Runnable( - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 14..64, - focus_range: 18..23, - name: "tests", - kind: Module, - description: "mod tests", - }, - kind: TestMod { - path: "tests", - }, - cfg: None, - }, - ), - }, - Annotation { - range: 45..57, - kind: Runnable( - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 30..62, - focus_range: 45..57, - name: "my_cool_test", - kind: Function, - }, - kind: Test { - test_id: Path( - "tests::my_cool_test", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - ), - }, - Annotation { - range: 3..7, - kind: HasReferences { - file_id: FileId( - 0, - ), - data: Some( - [], - ), - }, - }, - ] - "#]], - ); - } - - #[test] - fn test_no_annotations_outside_module_tree() { - check( - r#" -//- /foo.rs -struct Foo; -//- /lib.rs -// this file comes last since `check` checks the first file only -"#, - expect![[r#" - [] - "#]], - ); - } - - #[test] - fn test_no_annotations_macro_struct_def() { - check( - r#" -//- /lib.rs -macro_rules! m { - () => { - struct A {} - }; -} - -m!(); -"#, - expect![[r#" - [] - "#]], - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs deleted file mode 100644 index a18a6bea97988..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs +++ /dev/null @@ -1,460 +0,0 @@ -//! Entry point for call-hierarchy - -use hir::Semantics; -use ide_db::{ - defs::{Definition, NameClass, NameRefClass}, - helpers::pick_best_token, - search::FileReference, - FxIndexMap, RootDatabase, -}; -use syntax::{ast, AstNode, SyntaxKind::NAME, TextRange}; - -use crate::{goto_definition, FilePosition, NavigationTarget, RangeInfo, TryToNav}; - -#[derive(Debug, Clone)] -pub struct CallItem { - pub target: NavigationTarget, - pub ranges: Vec, -} - -impl CallItem { - #[cfg(test)] - pub(crate) fn debug_render(&self) -> String { - format!("{} : {:?}", self.target.debug_render(), self.ranges) - } -} - -pub(crate) fn call_hierarchy( - db: &RootDatabase, - position: FilePosition, -) -> Option>> { - goto_definition::goto_definition(db, position) -} - -pub(crate) fn incoming_calls( - db: &RootDatabase, - FilePosition { file_id, offset }: FilePosition, -) -> Option> { - let sema = &Semantics::new(db); - - let file = sema.parse(file_id); - let file = file.syntax(); - let mut calls = CallLocations::default(); - - let references = sema - .find_nodes_at_offset_with_descend(file, offset) - .filter_map(move |node| match node { - ast::NameLike::NameRef(name_ref) => match NameRefClass::classify(sema, &name_ref)? { - NameRefClass::Definition(def @ Definition::Function(_)) => Some(def), - _ => None, - }, - ast::NameLike::Name(name) => match NameClass::classify(sema, &name)? { - NameClass::Definition(def @ Definition::Function(_)) => Some(def), - _ => None, - }, - ast::NameLike::Lifetime(_) => None, - }) - .flat_map(|func| func.usages(sema).all()); - - for (_, references) in references { - let references = references.into_iter().map(|FileReference { name, .. }| name); - for name in references { - // This target is the containing function - let nav = sema.ancestors_with_macros(name.syntax().clone()).find_map(|node| { - let def = ast::Fn::cast(node).and_then(|fn_| sema.to_def(&fn_))?; - def.try_to_nav(sema.db) - }); - if let Some(nav) = nav { - calls.add(nav, sema.original_range(name.syntax()).range); - } - } - } - - Some(calls.into_items()) -} - -pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Option> { - let sema = Semantics::new(db); - let file_id = position.file_id; - let file = sema.parse(file_id); - let file = file.syntax(); - let token = pick_best_token(file.token_at_offset(position.offset), |kind| match kind { - NAME => 1, - _ => 0, - })?; - let mut calls = CallLocations::default(); - - sema.descend_into_macros(token) - .into_iter() - .filter_map(|it| it.parent_ancestors().nth(1).and_then(ast::Item::cast)) - .filter_map(|item| match item { - ast::Item::Const(c) => c.body().map(|it| it.syntax().descendants()), - ast::Item::Fn(f) => f.body().map(|it| it.syntax().descendants()), - ast::Item::Static(s) => s.body().map(|it| it.syntax().descendants()), - _ => None, - }) - .flatten() - .filter_map(ast::CallableExpr::cast) - .filter_map(|call_node| { - let (nav_target, range) = match call_node { - ast::CallableExpr::Call(call) => { - let expr = call.expr()?; - let callable = sema.type_of_expr(&expr)?.original.as_callable(db)?; - match callable.kind() { - hir::CallableKind::Function(it) => { - let range = expr.syntax().text_range(); - it.try_to_nav(db).zip(Some(range)) - } - _ => None, - } - } - ast::CallableExpr::MethodCall(expr) => { - let range = expr.name_ref()?.syntax().text_range(); - let function = sema.resolve_method_call(&expr)?; - function.try_to_nav(db).zip(Some(range)) - } - }?; - Some((nav_target, range)) - }) - .for_each(|(nav, range)| calls.add(nav, range)); - - Some(calls.into_items()) -} - -#[derive(Default)] -struct CallLocations { - funcs: FxIndexMap>, -} - -impl CallLocations { - fn add(&mut self, target: NavigationTarget, range: TextRange) { - self.funcs.entry(target).or_default().push(range); - } - - fn into_items(self) -> Vec { - self.funcs.into_iter().map(|(target, ranges)| CallItem { target, ranges }).collect() - } -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - use ide_db::base_db::FilePosition; - use itertools::Itertools; - - use crate::fixture; - - fn check_hierarchy( - ra_fixture: &str, - expected: Expect, - expected_incoming: Expect, - expected_outgoing: Expect, - ) { - let (analysis, pos) = fixture::position(ra_fixture); - - let mut navs = analysis.call_hierarchy(pos).unwrap().unwrap().info; - assert_eq!(navs.len(), 1); - let nav = navs.pop().unwrap(); - expected.assert_eq(&nav.debug_render()); - - let item_pos = - FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() }; - let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap(); - expected_incoming - .assert_eq(&incoming_calls.into_iter().map(|call| call.debug_render()).join("\n")); - - let outgoing_calls = analysis.outgoing_calls(item_pos).unwrap().unwrap(); - expected_outgoing - .assert_eq(&outgoing_calls.into_iter().map(|call| call.debug_render()).join("\n")); - } - - #[test] - fn test_call_hierarchy_on_ref() { - check_hierarchy( - r#" -//- /lib.rs -fn callee() {} -fn caller() { - call$0ee(); -} -"#, - expect![["callee Function FileId(0) 0..14 3..9"]], - expect![["caller Function FileId(0) 15..44 18..24 : [33..39]"]], - expect![[]], - ); - } - - #[test] - fn test_call_hierarchy_on_def() { - check_hierarchy( - r#" -//- /lib.rs -fn call$0ee() {} -fn caller() { - callee(); -} -"#, - expect![["callee Function FileId(0) 0..14 3..9"]], - expect![["caller Function FileId(0) 15..44 18..24 : [33..39]"]], - expect![[]], - ); - } - - #[test] - fn test_call_hierarchy_in_same_fn() { - check_hierarchy( - r#" -//- /lib.rs -fn callee() {} -fn caller() { - call$0ee(); - callee(); -} -"#, - expect![["callee Function FileId(0) 0..14 3..9"]], - expect![["caller Function FileId(0) 15..58 18..24 : [33..39, 47..53]"]], - expect![[]], - ); - } - - #[test] - fn test_call_hierarchy_in_different_fn() { - check_hierarchy( - r#" -//- /lib.rs -fn callee() {} -fn caller1() { - call$0ee(); -} - -fn caller2() { - callee(); -} -"#, - expect![["callee Function FileId(0) 0..14 3..9"]], - expect![[" - caller1 Function FileId(0) 15..45 18..25 : [34..40] - caller2 Function FileId(0) 47..77 50..57 : [66..72]"]], - expect![[]], - ); - } - - #[test] - fn test_call_hierarchy_in_tests_mod() { - check_hierarchy( - r#" -//- /lib.rs cfg:test -fn callee() {} -fn caller1() { - call$0ee(); -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_caller() { - callee(); - } -} -"#, - expect![["callee Function FileId(0) 0..14 3..9"]], - expect![[r#" - caller1 Function FileId(0) 15..45 18..25 : [34..40] - test_caller Function FileId(0) 95..149 110..121 : [134..140]"#]], - expect![[]], - ); - } - - #[test] - fn test_call_hierarchy_in_different_files() { - check_hierarchy( - r#" -//- /lib.rs -mod foo; -use foo::callee; - -fn caller() { - call$0ee(); -} - -//- /foo/mod.rs -pub fn callee() {} -"#, - expect![["callee Function FileId(1) 0..18 7..13"]], - expect![["caller Function FileId(0) 27..56 30..36 : [45..51]"]], - expect![[]], - ); - } - - #[test] - fn test_call_hierarchy_outgoing() { - check_hierarchy( - r#" -//- /lib.rs -fn callee() {} -fn call$0er() { - callee(); - callee(); -} -"#, - expect![["caller Function FileId(0) 15..58 18..24"]], - expect![[]], - expect![["callee Function FileId(0) 0..14 3..9 : [33..39, 47..53]"]], - ); - } - - #[test] - fn test_call_hierarchy_outgoing_in_different_files() { - check_hierarchy( - r#" -//- /lib.rs -mod foo; -use foo::callee; - -fn call$0er() { - callee(); -} - -//- /foo/mod.rs -pub fn callee() {} -"#, - expect![["caller Function FileId(0) 27..56 30..36"]], - expect![[]], - expect![["callee Function FileId(1) 0..18 7..13 : [45..51]"]], - ); - } - - #[test] - fn test_call_hierarchy_incoming_outgoing() { - check_hierarchy( - r#" -//- /lib.rs -fn caller1() { - call$0er2(); -} - -fn caller2() { - caller3(); -} - -fn caller3() { - -} -"#, - expect![["caller2 Function FileId(0) 33..64 36..43"]], - expect![["caller1 Function FileId(0) 0..31 3..10 : [19..26]"]], - expect![["caller3 Function FileId(0) 66..83 69..76 : [52..59]"]], - ); - } - - #[test] - fn test_call_hierarchy_issue_5103() { - check_hierarchy( - r#" -fn a() { - b() -} - -fn b() {} - -fn main() { - a$0() -} -"#, - expect![["a Function FileId(0) 0..18 3..4"]], - expect![["main Function FileId(0) 31..52 34..38 : [47..48]"]], - expect![["b Function FileId(0) 20..29 23..24 : [13..14]"]], - ); - - check_hierarchy( - r#" -fn a() { - b$0() -} - -fn b() {} - -fn main() { - a() -} -"#, - expect![["b Function FileId(0) 20..29 23..24"]], - expect![["a Function FileId(0) 0..18 3..4 : [13..14]"]], - expect![[]], - ); - } - - #[test] - fn test_call_hierarchy_in_macros_incoming() { - check_hierarchy( - r#" -macro_rules! define { - ($ident:ident) => { - fn $ident {} - } -} -macro_rules! call { - ($ident:ident) => { - $ident() - } -} -define!(callee) -fn caller() { - call!(call$0ee); -} -"#, - expect![[r#"callee Function FileId(0) 144..159 152..158"#]], - expect![[r#"caller Function FileId(0) 160..194 163..169 : [184..190]"#]], - expect![[]], - ); - check_hierarchy( - r#" -macro_rules! define { - ($ident:ident) => { - fn $ident {} - } -} -macro_rules! call { - ($ident:ident) => { - $ident() - } -} -define!(cal$0lee) -fn caller() { - call!(callee); -} -"#, - expect![[r#"callee Function FileId(0) 144..159 152..158"#]], - expect![[r#"caller Function FileId(0) 160..194 163..169 : [184..190]"#]], - expect![[]], - ); - } - - #[test] - fn test_call_hierarchy_in_macros_outgoing() { - check_hierarchy( - r#" -macro_rules! define { - ($ident:ident) => { - fn $ident {} - } -} -macro_rules! call { - ($ident:ident) => { - $ident() - } -} -define!(callee) -fn caller$0() { - call!(callee); -} -"#, - expect![[r#"caller Function FileId(0) 160..194 163..169"#]], - expect![[]], - // FIXME - expect![[]], - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs deleted file mode 100644 index 582e9fe7e808c..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ /dev/null @@ -1,549 +0,0 @@ -//! Extracts, resolves and rewrites links and intra-doc links in markdown documentation. - -#[cfg(test)] -mod tests; - -mod intra_doc_links; - -use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag}; -use pulldown_cmark_to_cmark::{cmark_resume_with_options, Options as CMarkOptions}; -use stdx::format_to; -use url::Url; - -use hir::{db::HirDatabase, Adt, AsAssocItem, AssocItem, AssocItemContainer, HasAttrs}; -use ide_db::{ - base_db::{CrateOrigin, LangCrateOrigin, SourceDatabase}, - defs::{Definition, NameClass, NameRefClass}, - helpers::pick_best_token, - RootDatabase, -}; -use syntax::{ - ast::{self, IsString}, - match_ast, AstNode, AstToken, - SyntaxKind::*, - SyntaxNode, SyntaxToken, TextRange, TextSize, T, -}; - -use crate::{ - doc_links::intra_doc_links::{parse_intra_doc_link, strip_prefixes_suffixes}, - FilePosition, Semantics, -}; - -/// Weblink to an item's documentation. -pub(crate) type DocumentationLink = String; - -const MARKDOWN_OPTIONS: Options = - Options::ENABLE_FOOTNOTES.union(Options::ENABLE_TABLES).union(Options::ENABLE_TASKLISTS); - -/// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs) -pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: Definition) -> String { - let mut cb = broken_link_clone_cb; - let doc = Parser::new_with_broken_link_callback(markdown, MARKDOWN_OPTIONS, Some(&mut cb)); - - let doc = map_links(doc, |target, title| { - // This check is imperfect, there's some overlap between valid intra-doc links - // and valid URLs so we choose to be too eager to try to resolve what might be - // a URL. - if target.contains("://") { - (Some(LinkType::Inline), target.to_string(), title.to_string()) - } else { - // Two possibilities: - // * path-based links: `../../module/struct.MyStruct.html` - // * module-based links (AKA intra-doc links): `super::super::module::MyStruct` - if let Some((target, title)) = rewrite_intra_doc_link(db, definition, target, title) { - return (None, target, title); - } - if let Some(target) = rewrite_url_link(db, definition, target) { - return (Some(LinkType::Inline), target, title.to_string()); - } - - (None, target.to_string(), title.to_string()) - } - }); - let mut out = String::new(); - cmark_resume_with_options( - doc, - &mut out, - None, - CMarkOptions { code_block_token_count: 3, ..Default::default() }, - ) - .ok(); - out -} - -/// Remove all links in markdown documentation. -pub(crate) fn remove_links(markdown: &str) -> String { - let mut drop_link = false; - - let mut cb = |_: BrokenLink<'_>| { - let empty = InlineStr::try_from("").unwrap(); - Some((CowStr::Inlined(empty), CowStr::Inlined(empty))) - }; - let doc = Parser::new_with_broken_link_callback(markdown, MARKDOWN_OPTIONS, Some(&mut cb)); - let doc = doc.filter_map(move |evt| match evt { - Event::Start(Tag::Link(link_type, target, title)) => { - if link_type == LinkType::Inline && target.contains("://") { - Some(Event::Start(Tag::Link(link_type, target, title))) - } else { - drop_link = true; - None - } - } - Event::End(_) if drop_link => { - drop_link = false; - None - } - _ => Some(evt), - }); - - let mut out = String::new(); - cmark_resume_with_options( - doc, - &mut out, - None, - CMarkOptions { code_block_token_count: 3, ..Default::default() }, - ) - .ok(); - out -} - -/// Retrieve a link to documentation for the given symbol. -pub(crate) fn external_docs( - db: &RootDatabase, - position: &FilePosition, -) -> Option { - let sema = &Semantics::new(db); - let file = sema.parse(position.file_id).syntax().clone(); - let token = pick_best_token(file.token_at_offset(position.offset), |kind| match kind { - IDENT | INT_NUMBER | T![self] => 3, - T!['('] | T![')'] => 2, - kind if kind.is_trivia() => 0, - _ => 1, - })?; - let token = sema.descend_into_macros_single(token); - - let node = token.parent()?; - let definition = match_ast! { - match node { - ast::NameRef(name_ref) => match NameRefClass::classify(sema, &name_ref)? { - NameRefClass::Definition(def) => def, - NameRefClass::FieldShorthand { local_ref: _, field_ref } => { - Definition::Field(field_ref) - } - }, - ast::Name(name) => match NameClass::classify(sema, &name)? { - NameClass::Definition(it) | NameClass::ConstReference(it) => it, - NameClass::PatFieldShorthand { local_def: _, field_ref } => Definition::Field(field_ref), - }, - _ => return None, - } - }; - - get_doc_link(db, definition) -} - -/// Extracts all links from a given markdown text returning the definition text range, link-text -/// and the namespace if known. -pub(crate) fn extract_definitions_from_docs( - docs: &hir::Documentation, -) -> Vec<(TextRange, String, Option)> { - Parser::new_with_broken_link_callback( - docs.as_str(), - MARKDOWN_OPTIONS, - Some(&mut broken_link_clone_cb), - ) - .into_offset_iter() - .filter_map(|(event, range)| match event { - Event::Start(Tag::Link(_, target, _)) => { - let (link, ns) = parse_intra_doc_link(&target); - Some(( - TextRange::new(range.start.try_into().ok()?, range.end.try_into().ok()?), - link.to_string(), - ns, - )) - } - _ => None, - }) - .collect() -} - -pub(crate) fn resolve_doc_path_for_def( - db: &dyn HirDatabase, - def: Definition, - link: &str, - ns: Option, -) -> Option { - match def { - Definition::Module(it) => it.resolve_doc_path(db, link, ns), - Definition::Function(it) => it.resolve_doc_path(db, link, ns), - Definition::Adt(it) => it.resolve_doc_path(db, link, ns), - Definition::Variant(it) => it.resolve_doc_path(db, link, ns), - Definition::Const(it) => it.resolve_doc_path(db, link, ns), - Definition::Static(it) => it.resolve_doc_path(db, link, ns), - Definition::Trait(it) => it.resolve_doc_path(db, link, ns), - Definition::TypeAlias(it) => it.resolve_doc_path(db, link, ns), - Definition::Macro(it) => it.resolve_doc_path(db, link, ns), - Definition::Field(it) => it.resolve_doc_path(db, link, ns), - Definition::BuiltinAttr(_) - | Definition::ToolModule(_) - | Definition::BuiltinType(_) - | Definition::SelfType(_) - | Definition::Local(_) - | Definition::GenericParam(_) - | Definition::Label(_) - | Definition::DeriveHelper(_) => None, - } - .map(Definition::from) -} - -pub(crate) fn doc_attributes( - sema: &Semantics<'_, RootDatabase>, - node: &SyntaxNode, -) -> Option<(hir::AttrsWithOwner, Definition)> { - match_ast! { - match node { - ast::SourceFile(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Module(def))), - ast::Module(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Module(def))), - ast::Fn(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Function(def))), - ast::Struct(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Adt(hir::Adt::Struct(def)))), - ast::Union(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Adt(hir::Adt::Union(def)))), - ast::Enum(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Adt(hir::Adt::Enum(def)))), - ast::Variant(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Variant(def))), - ast::Trait(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Trait(def))), - ast::Static(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Static(def))), - ast::Const(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Const(def))), - ast::TypeAlias(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::TypeAlias(def))), - ast::Impl(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))), - ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), - ast::TupleField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), - ast::Macro(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))), - // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), - _ => None - } - } -} - -pub(crate) struct DocCommentToken { - doc_token: SyntaxToken, - prefix_len: TextSize, -} - -pub(crate) fn token_as_doc_comment(doc_token: &SyntaxToken) -> Option { - (match_ast! { - match doc_token { - ast::Comment(comment) => TextSize::try_from(comment.prefix().len()).ok(), - ast::String(string) => doc_token.parent_ancestors().find_map(ast::Attr::cast) - .filter(|attr| attr.simple_name().as_deref() == Some("doc")).and_then(|_| string.open_quote_text_range().map(|it| it.len())), - _ => None, - } - }).map(|prefix_len| DocCommentToken { prefix_len, doc_token: doc_token.clone() }) -} - -impl DocCommentToken { - pub(crate) fn get_definition_with_descend_at( - self, - sema: &Semantics<'_, RootDatabase>, - offset: TextSize, - // Definition, CommentOwner, range of intra doc link in original file - mut cb: impl FnMut(Definition, SyntaxNode, TextRange) -> Option, - ) -> Option { - let DocCommentToken { prefix_len, doc_token } = self; - // offset relative to the comments contents - let original_start = doc_token.text_range().start(); - let relative_comment_offset = offset - original_start - prefix_len; - - sema.descend_into_macros(doc_token).into_iter().find_map(|t| { - let (node, descended_prefix_len) = match_ast! { - match t { - ast::Comment(comment) => (t.parent()?, TextSize::try_from(comment.prefix().len()).ok()?), - ast::String(string) => (t.parent_ancestors().skip_while(|n| n.kind() != ATTR).nth(1)?, string.open_quote_text_range()?.len()), - _ => return None, - } - }; - let token_start = t.text_range().start(); - let abs_in_expansion_offset = token_start + relative_comment_offset + descended_prefix_len; - - let (attributes, def) = doc_attributes(sema, &node)?; - let (docs, doc_mapping) = attributes.docs_with_rangemap(sema.db)?; - let (in_expansion_range, link, ns) = - extract_definitions_from_docs(&docs).into_iter().find_map(|(range, link, ns)| { - let mapped = doc_mapping.map(range)?; - (mapped.value.contains(abs_in_expansion_offset)).then(|| (mapped.value, link, ns)) - })?; - // get the relative range to the doc/attribute in the expansion - let in_expansion_relative_range = in_expansion_range - descended_prefix_len - token_start; - // Apply relative range to the original input comment - let absolute_range = in_expansion_relative_range + original_start + prefix_len; - let def = resolve_doc_path_for_def(sema.db, def, &link, ns)?; - cb(def, node, absolute_range) - }) - } -} - -fn broken_link_clone_cb<'a>(link: BrokenLink<'a>) -> Option<(CowStr<'a>, CowStr<'a>)> { - Some((/*url*/ link.reference.clone(), /*title*/ link.reference)) -} - -// FIXME: -// BUG: For Option::Some -// Returns https://doc.rust-lang.org/nightly/core/prelude/v1/enum.Option.html#variant.Some -// Instead of https://doc.rust-lang.org/nightly/core/option/enum.Option.html -// -// This should cease to be a problem if RFC2988 (Stable Rustdoc URLs) is implemented -// https://github.com/rust-lang/rfcs/pull/2988 -fn get_doc_link(db: &RootDatabase, def: Definition) -> Option { - let (target, file, frag) = filename_and_frag_for_def(db, def)?; - - let mut url = get_doc_base_url(db, target)?; - - if let Some(path) = mod_path_of_def(db, target) { - url = url.join(&path).ok()?; - } - - url = url.join(&file).ok()?; - url.set_fragment(frag.as_deref()); - - Some(url.into()) -} - -fn rewrite_intra_doc_link( - db: &RootDatabase, - def: Definition, - target: &str, - title: &str, -) -> Option<(String, String)> { - let (link, ns) = parse_intra_doc_link(target); - - let resolved = resolve_doc_path_for_def(db, def, link, ns)?; - let mut url = get_doc_base_url(db, resolved)?; - - let (_, file, frag) = filename_and_frag_for_def(db, resolved)?; - if let Some(path) = mod_path_of_def(db, resolved) { - url = url.join(&path).ok()?; - } - - url = url.join(&file).ok()?; - url.set_fragment(frag.as_deref()); - - Some((url.into(), strip_prefixes_suffixes(title).to_string())) -} - -/// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`). -fn rewrite_url_link(db: &RootDatabase, def: Definition, target: &str) -> Option { - if !(target.contains('#') || target.contains(".html")) { - return None; - } - - let mut url = get_doc_base_url(db, def)?; - let (def, file, frag) = filename_and_frag_for_def(db, def)?; - - if let Some(path) = mod_path_of_def(db, def) { - url = url.join(&path).ok()?; - } - - url = url.join(&file).ok()?; - url.set_fragment(frag.as_deref()); - url.join(target).ok().map(Into::into) -} - -fn mod_path_of_def(db: &RootDatabase, def: Definition) -> Option { - def.canonical_module_path(db).map(|it| { - let mut path = String::new(); - it.flat_map(|it| it.name(db)).for_each(|name| format_to!(path, "{}/", name)); - path - }) -} - -/// Rewrites a markdown document, applying 'callback' to each link. -fn map_links<'e>( - events: impl Iterator>, - callback: impl Fn(&str, &str) -> (Option, String, String), -) -> impl Iterator> { - let mut in_link = false; - // holds the origin link target on start event and the rewritten one on end event - let mut end_link_target: Option> = None; - // normally link's type is determined by the type of link tag in the end event, - // however in some cases we want to change the link type, for example, - // `Shortcut` type parsed from Start/End tags doesn't make sense for url links - let mut end_link_type: Option = None; - - events.map(move |evt| match evt { - Event::Start(Tag::Link(link_type, ref target, _)) => { - in_link = true; - end_link_target = Some(target.clone()); - end_link_type = Some(link_type); - evt - } - Event::End(Tag::Link(link_type, target, _)) => { - in_link = false; - Event::End(Tag::Link( - end_link_type.unwrap_or(link_type), - end_link_target.take().unwrap_or(target), - CowStr::Borrowed(""), - )) - } - Event::Text(s) if in_link => { - let (link_type, link_target_s, link_name) = - callback(&end_link_target.take().unwrap(), &s); - end_link_target = Some(CowStr::Boxed(link_target_s.into())); - if !matches!(end_link_type, Some(LinkType::Autolink)) { - end_link_type = link_type; - } - Event::Text(CowStr::Boxed(link_name.into())) - } - Event::Code(s) if in_link => { - let (link_type, link_target_s, link_name) = - callback(&end_link_target.take().unwrap(), &s); - end_link_target = Some(CowStr::Boxed(link_target_s.into())); - if !matches!(end_link_type, Some(LinkType::Autolink)) { - end_link_type = link_type; - } - Event::Code(CowStr::Boxed(link_name.into())) - } - _ => evt, - }) -} - -/// Get the root URL for the documentation of a definition. -/// -/// ```ignore -/// https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next -/// ^^^^^^^^^^^^^^^^^^^^^^^^^^ -/// ``` -fn get_doc_base_url(db: &RootDatabase, def: Definition) -> Option { - // special case base url of `BuiltinType` to core - // https://github.com/rust-lang/rust-analyzer/issues/12250 - if let Definition::BuiltinType(..) = def { - return Url::parse("https://doc.rust-lang.org/nightly/core/").ok(); - }; - - let krate = def.krate(db)?; - let display_name = krate.display_name(db)?; - - let base = match db.crate_graph()[krate.into()].origin { - // std and co do not specify `html_root_url` any longer so we gotta handwrite this ourself. - // FIXME: Use the toolchains channel instead of nightly - CrateOrigin::Lang( - origin @ (LangCrateOrigin::Alloc - | LangCrateOrigin::Core - | LangCrateOrigin::ProcMacro - | LangCrateOrigin::Std - | LangCrateOrigin::Test), - ) => { - format!("https://doc.rust-lang.org/nightly/{origin}") - } - _ => { - krate.get_html_root_url(db).or_else(|| { - let version = krate.version(db); - // Fallback to docs.rs. This uses `display_name` and can never be - // correct, but that's what fallbacks are about. - // - // FIXME: clicking on the link should just open the file in the editor, - // instead of falling back to external urls. - Some(format!( - "https://docs.rs/{krate}/{version}/", - krate = display_name, - version = version.as_deref().unwrap_or("*") - )) - })? - } - }; - Url::parse(&base).ok()?.join(&format!("{}/", display_name)).ok() -} - -/// Get the filename and extension generated for a symbol by rustdoc. -/// -/// ```ignore -/// https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next -/// ^^^^^^^^^^^^^^^^^^^ -/// ``` -fn filename_and_frag_for_def( - db: &dyn HirDatabase, - def: Definition, -) -> Option<(Definition, String, Option)> { - if let Some(assoc_item) = def.as_assoc_item(db) { - let def = match assoc_item.container(db) { - AssocItemContainer::Trait(t) => t.into(), - AssocItemContainer::Impl(i) => i.self_ty(db).as_adt()?.into(), - }; - let (_, file, _) = filename_and_frag_for_def(db, def)?; - let frag = get_assoc_item_fragment(db, assoc_item)?; - return Some((def, file, Some(frag))); - } - - let res = match def { - Definition::Adt(adt) => match adt { - Adt::Struct(s) => format!("struct.{}.html", s.name(db)), - Adt::Enum(e) => format!("enum.{}.html", e.name(db)), - Adt::Union(u) => format!("union.{}.html", u.name(db)), - }, - Definition::Module(m) => match m.name(db) { - // `#[doc(keyword = "...")]` is internal used only by rust compiler - Some(name) => match m.attrs(db).by_key("doc").find_string_value_in_tt("keyword") { - Some(kw) => { - format!("keyword.{}.html", kw.trim_matches('"')) - } - None => format!("{}/index.html", name), - }, - None => String::from("index.html"), - }, - Definition::Trait(t) => format!("trait.{}.html", t.name(db)), - Definition::TypeAlias(t) => format!("type.{}.html", t.name(db)), - Definition::BuiltinType(t) => format!("primitive.{}.html", t.name()), - Definition::Function(f) => format!("fn.{}.html", f.name(db)), - Definition::Variant(ev) => { - format!("enum.{}.html#variant.{}", ev.parent_enum(db).name(db), ev.name(db)) - } - Definition::Const(c) => format!("const.{}.html", c.name(db)?), - Definition::Static(s) => format!("static.{}.html", s.name(db)), - Definition::Macro(mac) => format!("macro.{}.html", mac.name(db)), - Definition::Field(field) => { - let def = match field.parent_def(db) { - hir::VariantDef::Struct(it) => Definition::Adt(it.into()), - hir::VariantDef::Union(it) => Definition::Adt(it.into()), - hir::VariantDef::Variant(it) => Definition::Variant(it), - }; - let (_, file, _) = filename_and_frag_for_def(db, def)?; - return Some((def, file, Some(format!("structfield.{}", field.name(db))))); - } - Definition::SelfType(impl_) => { - let adt = impl_.self_ty(db).as_adt()?.into(); - let (_, file, _) = filename_and_frag_for_def(db, adt)?; - // FIXME fragment numbering - return Some((adt, file, Some(String::from("impl")))); - } - Definition::Local(_) - | Definition::GenericParam(_) - | Definition::Label(_) - | Definition::BuiltinAttr(_) - | Definition::ToolModule(_) - | Definition::DeriveHelper(_) => return None, - }; - - Some((def, res, None)) -} - -/// Get the fragment required to link to a specific field, method, associated type, or associated constant. -/// -/// ```ignore -/// https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next -/// ^^^^^^^^^^^^^^ -/// ``` -fn get_assoc_item_fragment(db: &dyn HirDatabase, assoc_item: hir::AssocItem) -> Option { - Some(match assoc_item { - AssocItem::Function(function) => { - let is_trait_method = - function.as_assoc_item(db).and_then(|assoc| assoc.containing_trait(db)).is_some(); - // This distinction may get more complicated when specialization is available. - // Rustdoc makes this decision based on whether a method 'has defaultness'. - // Currently this is only the case for provided trait methods. - if is_trait_method && !function.has_body(db) { - format!("tymethod.{}", function.name(db)) - } else { - format!("method.{}", function.name(db)) - } - } - AssocItem::Const(constant) => format!("associatedconstant.{}", constant.name(db)?), - AssocItem::TypeAlias(ty) => format!("associatedtype.{}", ty.name(db)), - }) -} diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/intra_doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/intra_doc_links.rs deleted file mode 100644 index 1df9aaae281ee..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links/intra_doc_links.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! Helper tools for intra doc links. - -const TYPES: ([&str; 9], [&str; 0]) = - (["type", "struct", "enum", "mod", "trait", "union", "module", "prim", "primitive"], []); -const VALUES: ([&str; 8], [&str; 1]) = - (["value", "function", "fn", "method", "const", "static", "mod", "module"], ["()"]); -const MACROS: ([&str; 2], [&str; 1]) = (["macro", "derive"], ["!"]); - -/// Extract the specified namespace from an intra-doc-link if one exists. -/// -/// # Examples -/// -/// * `struct MyStruct` -> ("MyStruct", `Namespace::Types`) -/// * `panic!` -> ("panic", `Namespace::Macros`) -/// * `fn@from_intra_spec` -> ("from_intra_spec", `Namespace::Values`) -pub(super) fn parse_intra_doc_link(s: &str) -> (&str, Option) { - let s = s.trim_matches('`'); - - [ - (hir::Namespace::Types, (TYPES.0.iter(), TYPES.1.iter())), - (hir::Namespace::Values, (VALUES.0.iter(), VALUES.1.iter())), - (hir::Namespace::Macros, (MACROS.0.iter(), MACROS.1.iter())), - ] - .into_iter() - .find_map(|(ns, (mut prefixes, mut suffixes))| { - if let Some(prefix) = prefixes.find(|&&prefix| { - s.starts_with(prefix) - && s.chars().nth(prefix.len()).map_or(false, |c| c == '@' || c == ' ') - }) { - Some((&s[prefix.len() + 1..], ns)) - } else { - suffixes.find_map(|&suffix| s.strip_suffix(suffix).zip(Some(ns))) - } - }) - .map_or((s, None), |(s, ns)| (s, Some(ns))) -} - -pub(super) fn strip_prefixes_suffixes(s: &str) -> &str { - [ - (TYPES.0.iter(), TYPES.1.iter()), - (VALUES.0.iter(), VALUES.1.iter()), - (MACROS.0.iter(), MACROS.1.iter()), - ] - .into_iter() - .find_map(|(mut prefixes, mut suffixes)| { - if let Some(prefix) = prefixes.find(|&&prefix| { - s.starts_with(prefix) - && s.chars().nth(prefix.len()).map_or(false, |c| c == '@' || c == ' ') - }) { - Some(&s[prefix.len() + 1..]) - } else { - suffixes.find_map(|&suffix| s.strip_suffix(suffix)) - } - }) - .unwrap_or(s) -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use super::*; - - fn check(link: &str, expected: Expect) { - let (l, a) = parse_intra_doc_link(link); - let a = a.map_or_else(String::new, |a| format!(" ({:?})", a)); - expected.assert_eq(&format!("{}{}", l, a)); - } - - #[test] - fn test_name() { - check("foo", expect![[r#"foo"#]]); - check("struct Struct", expect![[r#"Struct (Types)"#]]); - check("makro!", expect![[r#"makro (Macros)"#]]); - check("fn@function", expect![[r#"function (Values)"#]]); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs deleted file mode 100644 index c6bfb6b9d0975..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs +++ /dev/null @@ -1,491 +0,0 @@ -use expect_test::{expect, Expect}; -use hir::{HasAttrs, Semantics}; -use ide_db::{ - base_db::{FilePosition, FileRange}, - defs::Definition, - RootDatabase, -}; -use itertools::Itertools; -use syntax::{ast, match_ast, AstNode, SyntaxNode}; - -use crate::{ - doc_links::{extract_definitions_from_docs, resolve_doc_path_for_def, rewrite_links}, - fixture, TryToNav, -}; - -fn check_external_docs(ra_fixture: &str, expect: Expect) { - let (analysis, position) = fixture::position(ra_fixture); - let url = analysis.external_docs(position).unwrap().expect("could not find url for symbol"); - - expect.assert_eq(&url) -} - -fn check_rewrite(ra_fixture: &str, expect: Expect) { - let (analysis, position) = fixture::position(ra_fixture); - let sema = &Semantics::new(&*analysis.db); - let (cursor_def, docs) = def_under_cursor(sema, &position); - let res = rewrite_links(sema.db, docs.as_str(), cursor_def); - expect.assert_eq(&res) -} - -fn check_doc_links(ra_fixture: &str) { - let key_fn = |&(FileRange { file_id, range }, _): &_| (file_id, range.start()); - - let (analysis, position, mut expected) = fixture::annotations(ra_fixture); - expected.sort_by_key(key_fn); - let sema = &Semantics::new(&*analysis.db); - let (cursor_def, docs) = def_under_cursor(sema, &position); - let defs = extract_definitions_from_docs(&docs); - let actual: Vec<_> = defs - .into_iter() - .map(|(_, link, ns)| { - let def = resolve_doc_path_for_def(sema.db, cursor_def, &link, ns) - .unwrap_or_else(|| panic!("Failed to resolve {}", link)); - let nav_target = def.try_to_nav(sema.db).unwrap(); - let range = - FileRange { file_id: nav_target.file_id, range: nav_target.focus_or_full_range() }; - (range, link) - }) - .sorted_by_key(key_fn) - .collect(); - assert_eq!(expected, actual); -} - -fn def_under_cursor( - sema: &Semantics<'_, RootDatabase>, - position: &FilePosition, -) -> (Definition, hir::Documentation) { - let (docs, def) = sema - .parse(position.file_id) - .syntax() - .token_at_offset(position.offset) - .left_biased() - .unwrap() - .parent_ancestors() - .find_map(|it| node_to_def(sema, &it)) - .expect("no def found") - .unwrap(); - let docs = docs.expect("no docs found for cursor def"); - (def, docs) -} - -fn node_to_def( - sema: &Semantics<'_, RootDatabase>, - node: &SyntaxNode, -) -> Option, Definition)>> { - Some(match_ast! { - match node { - ast::SourceFile(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Module(def))), - ast::Module(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Module(def))), - ast::Fn(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Function(def))), - ast::Struct(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Struct(def)))), - ast::Union(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Union(def)))), - ast::Enum(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Enum(def)))), - ast::Variant(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Variant(def))), - ast::Trait(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Trait(def))), - ast::Static(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Static(def))), - ast::Const(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Const(def))), - ast::TypeAlias(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::TypeAlias(def))), - ast::Impl(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::SelfType(def))), - ast::RecordField(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Field(def))), - ast::TupleField(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Field(def))), - ast::Macro(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Macro(def))), - // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), - _ => return None, - } - }) -} - -#[test] -fn external_docs_doc_url_crate() { - check_external_docs( - r#" -//- /main.rs crate:main deps:foo -use foo$0::Foo; -//- /lib.rs crate:foo -pub struct Foo; -"#, - expect![[r#"https://docs.rs/foo/*/foo/index.html"#]], - ); -} - -#[test] -fn external_docs_doc_url_std_crate() { - check_external_docs( - r#" -//- /main.rs crate:std -use self$0; -"#, - expect![[r#"https://doc.rust-lang.org/nightly/std/index.html"#]], - ); -} - -#[test] -fn external_docs_doc_url_struct() { - check_external_docs( - r#" -//- /main.rs crate:foo -pub struct Fo$0o; -"#, - expect![[r#"https://docs.rs/foo/*/foo/struct.Foo.html"#]], - ); -} - -#[test] -fn external_docs_doc_url_struct_field() { - check_external_docs( - r#" -//- /main.rs crate:foo -pub struct Foo { - field$0: () -} -"#, - expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#structfield.field"##]], - ); -} - -#[test] -fn external_docs_doc_url_fn() { - check_external_docs( - r#" -//- /main.rs crate:foo -pub fn fo$0o() {} -"#, - expect![[r#"https://docs.rs/foo/*/foo/fn.foo.html"#]], - ); -} - -#[test] -fn external_docs_doc_url_impl_assoc() { - check_external_docs( - r#" -//- /main.rs crate:foo -pub struct Foo; -impl Foo { - pub fn method$0() {} -} -"#, - expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#method.method"##]], - ); - check_external_docs( - r#" -//- /main.rs crate:foo -pub struct Foo; -impl Foo { - const CONST$0: () = (); -} -"#, - expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#associatedconstant.CONST"##]], - ); -} - -#[test] -fn external_docs_doc_url_impl_trait_assoc() { - check_external_docs( - r#" -//- /main.rs crate:foo -pub struct Foo; -pub trait Trait { - fn method() {} -} -impl Trait for Foo { - pub fn method$0() {} -} -"#, - expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#method.method"##]], - ); - check_external_docs( - r#" -//- /main.rs crate:foo -pub struct Foo; -pub trait Trait { - const CONST: () = (); -} -impl Trait for Foo { - const CONST$0: () = (); -} -"#, - expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#associatedconstant.CONST"##]], - ); - check_external_docs( - r#" -//- /main.rs crate:foo -pub struct Foo; -pub trait Trait { - type Type; -} -impl Trait for Foo { - type Type$0 = (); -} -"#, - expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#associatedtype.Type"##]], - ); -} - -#[test] -fn external_docs_doc_url_trait_assoc() { - check_external_docs( - r#" -//- /main.rs crate:foo -pub trait Foo { - fn method$0(); -} -"#, - expect![[r##"https://docs.rs/foo/*/foo/trait.Foo.html#tymethod.method"##]], - ); - check_external_docs( - r#" -//- /main.rs crate:foo -pub trait Foo { - const CONST$0: (); -} -"#, - expect![[r##"https://docs.rs/foo/*/foo/trait.Foo.html#associatedconstant.CONST"##]], - ); - check_external_docs( - r#" -//- /main.rs crate:foo -pub trait Foo { - type Type$0; -} -"#, - expect![[r##"https://docs.rs/foo/*/foo/trait.Foo.html#associatedtype.Type"##]], - ); -} - -#[test] -fn external_docs_trait() { - check_external_docs( - r#" -//- /main.rs crate:foo -trait Trait$0 {} -"#, - expect![[r#"https://docs.rs/foo/*/foo/trait.Trait.html"#]], - ) -} - -#[test] -fn external_docs_module() { - check_external_docs( - r#" -//- /main.rs crate:foo -pub mod foo { - pub mod ba$0r {} -} -"#, - expect![[r#"https://docs.rs/foo/*/foo/foo/bar/index.html"#]], - ) -} - -#[test] -fn external_docs_reexport_order() { - check_external_docs( - r#" -//- /main.rs crate:foo -pub mod wrapper { - pub use module::Item; - - pub mod module { - pub struct Item; - } -} - -fn foo() { - let bar: wrapper::It$0em; -} - "#, - expect![[r#"https://docs.rs/foo/*/foo/wrapper/module/struct.Item.html"#]], - ) -} - -#[test] -fn doc_links_items_simple() { - check_doc_links( - r#" -//- /main.rs crate:main deps:krate -/// [`krate`] -//! [`Trait`] -//! [`function`] -//! [`CONST`] -//! [`STATIC`] -//! [`Struct`] -//! [`Enum`] -//! [`Union`] -//! [`Type`] -//! [`module`] -use self$0; - -const CONST: () = (); - // ^^^^^ CONST -static STATIC: () = (); - // ^^^^^^ STATIC -trait Trait { - // ^^^^^ Trait -} -fn function() {} -// ^^^^^^^^ function -struct Struct; - // ^^^^^^ Struct -enum Enum {} - // ^^^^ Enum -union Union {__: ()} - // ^^^^^ Union -type Type = (); - // ^^^^ Type -mod module {} - // ^^^^^^ module -//- /krate.rs crate:krate -// empty -//^file krate -"#, - ) -} - -#[test] -fn doc_links_inherent_impl_items() { - check_doc_links( - r#" -// /// [`Struct::CONST`] -// /// [`Struct::function`] -/// FIXME #9694 -struct Struct$0; - -impl Struct { - const CONST: () = (); - fn function() {} -} -"#, - ) -} - -#[test] -fn doc_links_trait_impl_items() { - check_doc_links( - r#" -trait Trait { - type Type; - const CONST: usize; - fn function(); -} -// /// [`Struct::Type`] -// /// [`Struct::CONST`] -// /// [`Struct::function`] -/// FIXME #9694 -struct Struct$0; - -impl Trait for Struct { - type Type = (); - const CONST: () = (); - fn function() {} -} -"#, - ) -} - -#[test] -fn doc_links_trait_items() { - check_doc_links( - r#" -/// [`Trait`] -/// [`Trait::Type`] -/// [`Trait::CONST`] -/// [`Trait::function`] -trait Trait$0 { - // ^^^^^ Trait -type Type; - // ^^^^ Trait::Type -const CONST: usize; - // ^^^^^ Trait::CONST -fn function(); -// ^^^^^^^^ Trait::function -} - "#, - ) -} - -#[test] -fn rewrite_html_root_url() { - check_rewrite( - r#" -//- /main.rs crate:foo -#![doc(arbitrary_attribute = "test", html_root_url = "https:/example.com", arbitrary_attribute2)] - -pub mod foo { - pub struct Foo; -} -/// [Foo](foo::Foo) -pub struct B$0ar -"#, - expect![[r#"[Foo](https://example.com/foo/foo/struct.Foo.html)"#]], - ); -} - -#[test] -fn rewrite_on_field() { - check_rewrite( - r#" -//- /main.rs crate:foo -pub struct Foo { - /// [Foo](struct.Foo.html) - fie$0ld: () -} -"#, - expect![[r#"[Foo](https://docs.rs/foo/*/foo/struct.Foo.html)"#]], - ); -} - -#[test] -fn rewrite_struct() { - check_rewrite( - r#" -//- /main.rs crate:foo -/// [Foo] -pub struct $0Foo; -"#, - expect![[r#"[Foo](https://docs.rs/foo/*/foo/struct.Foo.html)"#]], - ); - check_rewrite( - r#" -//- /main.rs crate:foo -/// [`Foo`] -pub struct $0Foo; -"#, - expect![[r#"[`Foo`](https://docs.rs/foo/*/foo/struct.Foo.html)"#]], - ); - check_rewrite( - r#" -//- /main.rs crate:foo -/// [Foo](struct.Foo.html) -pub struct $0Foo; -"#, - expect![[r#"[Foo](https://docs.rs/foo/*/foo/struct.Foo.html)"#]], - ); - check_rewrite( - r#" -//- /main.rs crate:foo -/// [struct Foo](struct.Foo.html) -pub struct $0Foo; -"#, - expect![[r#"[struct Foo](https://docs.rs/foo/*/foo/struct.Foo.html)"#]], - ); - check_rewrite( - r#" -//- /main.rs crate:foo -/// [my Foo][foo] -/// -/// [foo]: Foo -pub struct $0Foo; -"#, - expect![[r#"[my Foo](https://docs.rs/foo/*/foo/struct.Foo.html)"#]], - ); - check_rewrite( - r#" -//- /main.rs crate:foo -/// [`foo`] -/// -/// [`foo`]: Foo -pub struct $0Foo; -"#, - expect![["[`foo`]"]], - ); -} diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs deleted file mode 100644 index efa8551a00d5a..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs +++ /dev/null @@ -1,521 +0,0 @@ -use hir::Semantics; -use ide_db::{ - base_db::FileId, helpers::pick_best_token, - syntax_helpers::insert_whitespace_into_node::insert_ws_into, RootDatabase, -}; -use syntax::{ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T}; - -use crate::FilePosition; - -pub struct ExpandedMacro { - pub name: String, - pub expansion: String, -} - -// Feature: Expand Macro Recursively -// -// Shows the full macro expansion of the macro at current cursor. -// -// |=== -// | Editor | Action Name -// -// | VS Code | **Rust Analyzer: Expand macro recursively** -// |=== -// -// image::https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif[] -pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option { - let sema = Semantics::new(db); - let file = sema.parse(position.file_id); - - let tok = pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind { - SyntaxKind::IDENT => 1, - _ => 0, - })?; - - // due to how Rust Analyzer works internally, we need to special case derive attributes, - // otherwise they might not get found, e.g. here with the cursor at $0 `#[attr]` would expand: - // ``` - // #[attr] - // #[derive($0Foo)] - // struct Bar; - // ``` - - let derive = sema.descend_into_macros(tok.clone()).into_iter().find_map(|descended| { - let hir_file = sema.hir_file_for(&descended.parent()?); - if !hir_file.is_derive_attr_pseudo_expansion(db) { - return None; - } - - let name = descended.parent_ancestors().filter_map(ast::Path::cast).last()?.to_string(); - // up map out of the #[derive] expansion - let token = hir::InFile::new(hir_file, descended).upmap(db)?.value; - let attr = token.parent_ancestors().find_map(ast::Attr::cast)?; - let expansions = sema.expand_derive_macro(&attr)?; - let idx = attr - .token_tree()? - .token_trees_and_tokens() - .filter_map(NodeOrToken::into_token) - .take_while(|it| it != &token) - .filter(|it| it.kind() == T![,]) - .count(); - let expansion = - format(db, SyntaxKind::MACRO_ITEMS, position.file_id, expansions.get(idx).cloned()?); - Some(ExpandedMacro { name, expansion }) - }); - - if derive.is_some() { - return derive; - } - - // FIXME: Intermix attribute and bang! expansions - // currently we only recursively expand one of the two types - let mut anc = tok.parent_ancestors(); - let (name, expanded, kind) = loop { - let node = anc.next()?; - - if let Some(item) = ast::Item::cast(node.clone()) { - if let Some(def) = sema.resolve_attr_macro_call(&item) { - break ( - def.name(db).to_string(), - expand_attr_macro_recur(&sema, &item)?, - SyntaxKind::MACRO_ITEMS, - ); - } - } - if let Some(mac) = ast::MacroCall::cast(node) { - break ( - mac.path()?.segment()?.name_ref()?.to_string(), - expand_macro_recur(&sema, &mac)?, - mac.syntax().parent().map(|it| it.kind()).unwrap_or(SyntaxKind::MACRO_ITEMS), - ); - } - }; - - // FIXME: - // macro expansion may lose all white space information - // But we hope someday we can use ra_fmt for that - let expansion = format(db, kind, position.file_id, expanded); - - Some(ExpandedMacro { name, expansion }) -} - -fn expand_macro_recur( - sema: &Semantics<'_, RootDatabase>, - macro_call: &ast::MacroCall, -) -> Option { - let expanded = sema.expand(macro_call)?.clone_for_update(); - expand(sema, expanded, ast::MacroCall::cast, expand_macro_recur) -} - -fn expand_attr_macro_recur( - sema: &Semantics<'_, RootDatabase>, - item: &ast::Item, -) -> Option { - let expanded = sema.expand_attr_macro(item)?.clone_for_update(); - expand(sema, expanded, ast::Item::cast, expand_attr_macro_recur) -} - -fn expand( - sema: &Semantics<'_, RootDatabase>, - expanded: SyntaxNode, - f: impl FnMut(SyntaxNode) -> Option, - exp: impl Fn(&Semantics<'_, RootDatabase>, &T) -> Option, -) -> Option { - let children = expanded.descendants().filter_map(f); - let mut replacements = Vec::new(); - - for child in children { - if let Some(new_node) = exp(sema, &child) { - // check if the whole original syntax is replaced - if expanded == *child.syntax() { - return Some(new_node); - } - replacements.push((child, new_node)); - } - } - - replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new)); - Some(expanded) -} - -fn format(db: &RootDatabase, kind: SyntaxKind, file_id: FileId, expanded: SyntaxNode) -> String { - let expansion = insert_ws_into(expanded).to_string(); - - _format(db, kind, file_id, &expansion).unwrap_or(expansion) -} - -#[cfg(any(test, target_arch = "wasm32", target_os = "emscripten"))] -fn _format( - _db: &RootDatabase, - _kind: SyntaxKind, - _file_id: FileId, - _expansion: &str, -) -> Option { - None -} - -#[cfg(not(any(test, target_arch = "wasm32", target_os = "emscripten")))] -fn _format( - db: &RootDatabase, - kind: SyntaxKind, - file_id: FileId, - expansion: &str, -) -> Option { - use ide_db::base_db::{FileLoader, SourceDatabase}; - // hack until we get hygiene working (same character amount to preserve formatting as much as possible) - const DOLLAR_CRATE_REPLACE: &str = &"__r_a_"; - let expansion = expansion.replace("$crate", DOLLAR_CRATE_REPLACE); - let (prefix, suffix) = match kind { - SyntaxKind::MACRO_PAT => ("fn __(", ": u32);"), - SyntaxKind::MACRO_EXPR | SyntaxKind::MACRO_STMTS => ("fn __() {", "}"), - SyntaxKind::MACRO_TYPE => ("type __ =", ";"), - _ => ("", ""), - }; - let expansion = format!("{prefix}{expansion}{suffix}"); - - let &crate_id = db.relevant_crates(file_id).iter().next()?; - let edition = db.crate_graph()[crate_id].edition; - - let mut cmd = std::process::Command::new(toolchain::rustfmt()); - cmd.arg("--edition"); - cmd.arg(edition.to_string()); - - let mut rustfmt = cmd - .stdin(std::process::Stdio::piped()) - .stdout(std::process::Stdio::piped()) - .stderr(std::process::Stdio::piped()) - .spawn() - .ok()?; - - std::io::Write::write_all(&mut rustfmt.stdin.as_mut()?, expansion.as_bytes()).ok()?; - - let output = rustfmt.wait_with_output().ok()?; - let captured_stdout = String::from_utf8(output.stdout).ok()?; - - if output.status.success() && !captured_stdout.trim().is_empty() { - let output = captured_stdout.replace(DOLLAR_CRATE_REPLACE, "$crate"); - let output = output.trim().strip_prefix(prefix)?; - let output = match kind { - SyntaxKind::MACRO_PAT => { - output.strip_suffix(suffix).or_else(|| output.strip_suffix(": u32,\n);"))? - } - _ => output.strip_suffix(suffix)?, - }; - let trim_indent = stdx::trim_indent(output); - tracing::debug!("expand_macro: formatting succeeded"); - Some(trim_indent) - } else { - None - } -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use crate::fixture; - - #[track_caller] - fn check(ra_fixture: &str, expect: Expect) { - let (analysis, pos) = fixture::position(ra_fixture); - let expansion = analysis.expand_macro(pos).unwrap().unwrap(); - let actual = format!("{}\n{}", expansion.name, expansion.expansion); - expect.assert_eq(&actual); - } - - #[test] - fn macro_expand_as_keyword() { - check( - r#" -macro_rules! bar { - ($i:tt) => { $i as _ } -} -fn main() { - let x: u64 = ba$0r!(5i64); -} -"#, - expect![[r#" - bar - 5i64 as _"#]], - ); - } - - #[test] - fn macro_expand_underscore() { - check( - r#" -macro_rules! bar { - ($i:tt) => { for _ in 0..$i {} } -} -fn main() { - ba$0r!(42); -} -"#, - expect![[r#" - bar - for _ in 0..42{}"#]], - ); - } - - #[test] - fn macro_expand_recursive_expansion() { - check( - r#" -macro_rules! bar { - () => { fn b() {} } -} -macro_rules! foo { - () => { bar!(); } -} -macro_rules! baz { - () => { foo!(); } -} -f$0oo!(); -"#, - expect![[r#" - foo - fn b(){} - "#]], - ); - } - - #[test] - fn macro_expand_multiple_lines() { - check( - r#" -macro_rules! foo { - () => { - fn some_thing() -> u32 { - let a = 0; - a + 10 - } - } -} -f$0oo!(); - "#, - expect![[r#" - foo - fn some_thing() -> u32 { - let a = 0; - a+10 - }"#]], - ); - } - - #[test] - fn macro_expand_match_ast() { - check( - r#" -macro_rules! match_ast { - (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; - (match ($node:expr) { - $( ast::$ast:ident($it:ident) => $res:block, )* - _ => $catch_all:expr $(,)? - }) => {{ - $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* - { $catch_all } - }}; -} - -fn main() { - mat$0ch_ast! { - match container { - ast::TraitDef(it) => {}, - ast::ImplDef(it) => {}, - _ => { continue }, - } - } -} -"#, - expect![[r#" - match_ast - { - if let Some(it) = ast::TraitDef::cast(container.clone()){} - else if let Some(it) = ast::ImplDef::cast(container.clone()){} - else { - { - continue - } - } - }"#]], - ); - } - - #[test] - fn macro_expand_match_ast_inside_let_statement() { - check( - r#" -macro_rules! match_ast { - (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; - (match ($node:expr) {}) => {{}}; -} - -fn main() { - let p = f(|it| { - let res = mat$0ch_ast! { match c {}}; - Some(res) - })?; -} -"#, - expect![[r#" - match_ast - {}"#]], - ); - } - - #[test] - fn macro_expand_inner_macro_rules() { - check( - r#" -macro_rules! foo { - ($t:tt) => {{ - macro_rules! bar { - () => { - $t - } - } - bar!() - }}; -} - -fn main() { - foo$0!(42); -} - "#, - expect![[r#" - foo - { - macro_rules! bar { - () => { - 42 - } - } - 42 - }"#]], - ); - } - - #[test] - fn macro_expand_inner_macro_fail_to_expand() { - check( - r#" -macro_rules! bar { - (BAD) => {}; -} -macro_rules! foo { - () => {bar!()}; -} - -fn main() { - let res = fo$0o!(); -} -"#, - expect![[r#" - foo - "#]], - ); - } - - #[test] - fn macro_expand_with_dollar_crate() { - check( - r#" -#[macro_export] -macro_rules! bar { - () => {0}; -} -macro_rules! foo { - () => {$crate::bar!()}; -} - -fn main() { - let res = fo$0o!(); -} -"#, - expect![[r#" - foo - 0"#]], - ); - } - - #[test] - fn macro_expand_with_dyn_absolute_path() { - check( - r#" -macro_rules! foo { - () => {fn f(_: &dyn ::std::marker::Copy) {}}; -} - -fn main() { - let res = fo$0o!(); -} -"#, - expect![[r#" - foo - fn f(_: &dyn ::std::marker::Copy){}"#]], - ); - } - - #[test] - fn macro_expand_derive() { - check( - r#" -//- proc_macros: identity -//- minicore: clone, derive - -#[proc_macros::identity] -#[derive(C$0lone)] -struct Foo {} -"#, - expect![[r#" - Clone - impl < >core::clone::Clone for Foo< >{} - "#]], - ); - } - - #[test] - fn macro_expand_derive2() { - check( - r#" -//- minicore: copy, clone, derive - -#[derive(Cop$0y)] -#[derive(Clone)] -struct Foo {} -"#, - expect![[r#" - Copy - impl < >core::marker::Copy for Foo< >{} - "#]], - ); - } - - #[test] - fn macro_expand_derive_multi() { - check( - r#" -//- minicore: copy, clone, derive - -#[derive(Cop$0y, Clone)] -struct Foo {} -"#, - expect![[r#" - Copy - impl < >core::marker::Copy for Foo< >{} - "#]], - ); - check( - r#" -//- minicore: copy, clone, derive - -#[derive(Copy, Cl$0one)] -struct Foo {} -"#, - expect![[r#" - Clone - impl < >core::clone::Clone for Foo< >{} - "#]], - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs deleted file mode 100644 index 45f1fd74841c6..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs +++ /dev/null @@ -1,662 +0,0 @@ -use std::iter::successors; - -use hir::Semantics; -use ide_db::RootDatabase; -use syntax::{ - algo::{self, skip_trivia_token}, - ast::{self, AstNode, AstToken}, - Direction, NodeOrToken, - SyntaxKind::{self, *}, - SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, T, -}; - -use crate::FileRange; - -// Feature: Expand and Shrink Selection -// -// Extends or shrinks the current selection to the encompassing syntactic construct -// (expression, statement, item, module, etc). It works with multiple cursors. -// -// This is a standard LSP feature and not a protocol extension. -// -// |=== -// | Editor | Shortcut -// -// | VS Code | kbd:[Alt+Shift+→], kbd:[Alt+Shift+←] -// |=== -// -// image::https://user-images.githubusercontent.com/48062697/113020651-b42fc800-917a-11eb-8a4f-cf1a07859fac.gif[] -pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange { - let sema = Semantics::new(db); - let src = sema.parse(frange.file_id); - try_extend_selection(&sema, src.syntax(), frange).unwrap_or(frange.range) -} - -fn try_extend_selection( - sema: &Semantics<'_, RootDatabase>, - root: &SyntaxNode, - frange: FileRange, -) -> Option { - let range = frange.range; - - let string_kinds = [COMMENT, STRING, BYTE_STRING]; - let list_kinds = [ - RECORD_PAT_FIELD_LIST, - MATCH_ARM_LIST, - RECORD_FIELD_LIST, - TUPLE_FIELD_LIST, - RECORD_EXPR_FIELD_LIST, - VARIANT_LIST, - USE_TREE_LIST, - GENERIC_PARAM_LIST, - GENERIC_ARG_LIST, - TYPE_BOUND_LIST, - PARAM_LIST, - ARG_LIST, - ARRAY_EXPR, - TUPLE_EXPR, - TUPLE_TYPE, - TUPLE_PAT, - WHERE_CLAUSE, - ]; - - if range.is_empty() { - let offset = range.start(); - let mut leaves = root.token_at_offset(offset); - if leaves.clone().all(|it| it.kind() == WHITESPACE) { - return Some(extend_ws(root, leaves.next()?, offset)); - } - let leaf_range = match leaves { - TokenAtOffset::None => return None, - TokenAtOffset::Single(l) => { - if string_kinds.contains(&l.kind()) { - extend_single_word_in_comment_or_string(&l, offset) - .unwrap_or_else(|| l.text_range()) - } else { - l.text_range() - } - } - TokenAtOffset::Between(l, r) => pick_best(l, r).text_range(), - }; - return Some(leaf_range); - }; - let node = match root.covering_element(range) { - NodeOrToken::Token(token) => { - if token.text_range() != range { - return Some(token.text_range()); - } - if let Some(comment) = ast::Comment::cast(token.clone()) { - if let Some(range) = extend_comments(comment) { - return Some(range); - } - } - token.parent()? - } - NodeOrToken::Node(node) => node, - }; - - // if we are in single token_tree, we maybe live in macro or attr - if node.kind() == TOKEN_TREE { - if let Some(macro_call) = node.ancestors().find_map(ast::MacroCall::cast) { - if let Some(range) = extend_tokens_from_range(sema, macro_call, range) { - return Some(range); - } - } - } - - if node.text_range() != range { - return Some(node.text_range()); - } - - let node = shallowest_node(&node); - - if node.parent().map(|n| list_kinds.contains(&n.kind())) == Some(true) { - if let Some(range) = extend_list_item(&node) { - return Some(range); - } - } - - node.parent().map(|it| it.text_range()) -} - -fn extend_tokens_from_range( - sema: &Semantics<'_, RootDatabase>, - macro_call: ast::MacroCall, - original_range: TextRange, -) -> Option { - let src = macro_call.syntax().covering_element(original_range); - let (first_token, last_token) = match src { - NodeOrToken::Node(it) => (it.first_token()?, it.last_token()?), - NodeOrToken::Token(it) => (it.clone(), it), - }; - - let mut first_token = skip_trivia_token(first_token, Direction::Next)?; - let mut last_token = skip_trivia_token(last_token, Direction::Prev)?; - - while !original_range.contains_range(first_token.text_range()) { - first_token = skip_trivia_token(first_token.next_token()?, Direction::Next)?; - } - while !original_range.contains_range(last_token.text_range()) { - last_token = skip_trivia_token(last_token.prev_token()?, Direction::Prev)?; - } - - // compute original mapped token range - let extended = { - let fst_expanded = sema.descend_into_macros_single(first_token.clone()); - let lst_expanded = sema.descend_into_macros_single(last_token.clone()); - let mut lca = - algo::least_common_ancestor(&fst_expanded.parent()?, &lst_expanded.parent()?)?; - lca = shallowest_node(&lca); - if lca.first_token() == Some(fst_expanded) && lca.last_token() == Some(lst_expanded) { - lca = lca.parent()?; - } - lca - }; - - // Compute parent node range - let validate = |token: &SyntaxToken| -> bool { - let expanded = sema.descend_into_macros_single(token.clone()); - let parent = match expanded.parent() { - Some(it) => it, - None => return false, - }; - algo::least_common_ancestor(&extended, &parent).as_ref() == Some(&extended) - }; - - // Find the first and last text range under expanded parent - let first = successors(Some(first_token), |token| { - let token = token.prev_token()?; - skip_trivia_token(token, Direction::Prev) - }) - .take_while(validate) - .last()?; - - let last = successors(Some(last_token), |token| { - let token = token.next_token()?; - skip_trivia_token(token, Direction::Next) - }) - .take_while(validate) - .last()?; - - let range = first.text_range().cover(last.text_range()); - if range.contains_range(original_range) && original_range != range { - Some(range) - } else { - None - } -} - -/// Find the shallowest node with same range, which allows us to traverse siblings. -fn shallowest_node(node: &SyntaxNode) -> SyntaxNode { - node.ancestors().take_while(|n| n.text_range() == node.text_range()).last().unwrap() -} - -fn extend_single_word_in_comment_or_string( - leaf: &SyntaxToken, - offset: TextSize, -) -> Option { - let text: &str = leaf.text(); - let cursor_position: u32 = (offset - leaf.text_range().start()).into(); - - let (before, after) = text.split_at(cursor_position as usize); - - fn non_word_char(c: char) -> bool { - !(c.is_alphanumeric() || c == '_') - } - - let start_idx = before.rfind(non_word_char)? as u32; - let end_idx = after.find(non_word_char).unwrap_or_else(|| after.len()) as u32; - - let from: TextSize = (start_idx + 1).into(); - let to: TextSize = (cursor_position + end_idx).into(); - - let range = TextRange::new(from, to); - if range.is_empty() { - None - } else { - Some(range + leaf.text_range().start()) - } -} - -fn extend_ws(root: &SyntaxNode, ws: SyntaxToken, offset: TextSize) -> TextRange { - let ws_text = ws.text(); - let suffix = TextRange::new(offset, ws.text_range().end()) - ws.text_range().start(); - let prefix = TextRange::new(ws.text_range().start(), offset) - ws.text_range().start(); - let ws_suffix = &ws_text[suffix]; - let ws_prefix = &ws_text[prefix]; - if ws_text.contains('\n') && !ws_suffix.contains('\n') { - if let Some(node) = ws.next_sibling_or_token() { - let start = match ws_prefix.rfind('\n') { - Some(idx) => ws.text_range().start() + TextSize::from((idx + 1) as u32), - None => node.text_range().start(), - }; - let end = if root.text().char_at(node.text_range().end()) == Some('\n') { - node.text_range().end() + TextSize::of('\n') - } else { - node.text_range().end() - }; - return TextRange::new(start, end); - } - } - ws.text_range() -} - -fn pick_best(l: SyntaxToken, r: SyntaxToken) -> SyntaxToken { - return if priority(&r) > priority(&l) { r } else { l }; - fn priority(n: &SyntaxToken) -> usize { - match n.kind() { - WHITESPACE => 0, - IDENT | T![self] | T![super] | T![crate] | T![Self] | LIFETIME_IDENT => 2, - _ => 1, - } - } -} - -/// Extend list item selection to include nearby delimiter and whitespace. -fn extend_list_item(node: &SyntaxNode) -> Option { - fn is_single_line_ws(node: &SyntaxToken) -> bool { - node.kind() == WHITESPACE && !node.text().contains('\n') - } - - fn nearby_delimiter( - delimiter_kind: SyntaxKind, - node: &SyntaxNode, - dir: Direction, - ) -> Option { - node.siblings_with_tokens(dir) - .skip(1) - .find(|node| match node { - NodeOrToken::Node(_) => true, - NodeOrToken::Token(it) => !is_single_line_ws(it), - }) - .and_then(|it| it.into_token()) - .filter(|node| node.kind() == delimiter_kind) - } - - let delimiter = match node.kind() { - TYPE_BOUND => T![+], - _ => T![,], - }; - - if let Some(delimiter_node) = nearby_delimiter(delimiter, node, Direction::Next) { - // Include any following whitespace when delimiter is after list item. - let final_node = delimiter_node - .next_sibling_or_token() - .and_then(|it| it.into_token()) - .filter(is_single_line_ws) - .unwrap_or(delimiter_node); - - return Some(TextRange::new(node.text_range().start(), final_node.text_range().end())); - } - if let Some(delimiter_node) = nearby_delimiter(delimiter, node, Direction::Prev) { - return Some(TextRange::new(delimiter_node.text_range().start(), node.text_range().end())); - } - - None -} - -fn extend_comments(comment: ast::Comment) -> Option { - let prev = adj_comments(&comment, Direction::Prev); - let next = adj_comments(&comment, Direction::Next); - if prev != next { - Some(TextRange::new(prev.syntax().text_range().start(), next.syntax().text_range().end())) - } else { - None - } -} - -fn adj_comments(comment: &ast::Comment, dir: Direction) -> ast::Comment { - let mut res = comment.clone(); - for element in comment.syntax().siblings_with_tokens(dir) { - let token = match element.as_token() { - None => break, - Some(token) => token, - }; - if let Some(c) = ast::Comment::cast(token.clone()) { - res = c - } else if token.kind() != WHITESPACE || token.text().contains("\n\n") { - break; - } - } - res -} - -#[cfg(test)] -mod tests { - use crate::fixture; - - use super::*; - - fn do_check(before: &str, afters: &[&str]) { - let (analysis, position) = fixture::position(before); - let before = analysis.file_text(position.file_id).unwrap(); - let range = TextRange::empty(position.offset); - let mut frange = FileRange { file_id: position.file_id, range }; - - for &after in afters { - frange.range = analysis.extend_selection(frange).unwrap(); - let actual = &before[frange.range]; - assert_eq!(after, actual); - } - } - - #[test] - fn test_extend_selection_arith() { - do_check(r#"fn foo() { $01 + 1 }"#, &["1", "1 + 1", "{ 1 + 1 }"]); - } - - #[test] - fn test_extend_selection_list() { - do_check(r#"fn foo($0x: i32) {}"#, &["x", "x: i32"]); - do_check(r#"fn foo($0x: i32, y: i32) {}"#, &["x", "x: i32", "x: i32, "]); - do_check(r#"fn foo($0x: i32,y: i32) {}"#, &["x", "x: i32", "x: i32,", "(x: i32,y: i32)"]); - do_check(r#"fn foo(x: i32, $0y: i32) {}"#, &["y", "y: i32", ", y: i32"]); - do_check(r#"fn foo(x: i32, $0y: i32, ) {}"#, &["y", "y: i32", "y: i32, "]); - do_check(r#"fn foo(x: i32,$0y: i32) {}"#, &["y", "y: i32", ",y: i32"]); - - do_check(r#"const FOO: [usize; 2] = [ 22$0 , 33];"#, &["22", "22 , "]); - do_check(r#"const FOO: [usize; 2] = [ 22 , 33$0];"#, &["33", ", 33"]); - do_check(r#"const FOO: [usize; 2] = [ 22 , 33$0 ,];"#, &["33", "33 ,", "[ 22 , 33 ,]"]); - - do_check(r#"fn main() { (1, 2$0) }"#, &["2", ", 2", "(1, 2)"]); - - do_check( - r#" -const FOO: [usize; 2] = [ - 22, - $033, -]"#, - &["33", "33,"], - ); - - do_check( - r#" -const FOO: [usize; 2] = [ - 22 - , 33$0, -]"#, - &["33", "33,"], - ); - } - - #[test] - fn test_extend_selection_start_of_the_line() { - do_check( - r#" -impl S { -$0 fn foo() { - - } -}"#, - &[" fn foo() {\n\n }\n"], - ); - } - - #[test] - fn test_extend_selection_doc_comments() { - do_check( - r#" -struct A; - -/// bla -/// bla -struct B { - $0 -} - "#, - &["\n \n", "{\n \n}", "/// bla\n/// bla\nstruct B {\n \n}"], - ) - } - - #[test] - fn test_extend_selection_comments() { - do_check( - r#" -fn bar(){} - -// fn foo() { -// 1 + $01 -// } - -// fn foo(){} - "#, - &["1", "// 1 + 1", "// fn foo() {\n// 1 + 1\n// }"], - ); - - do_check( - r#" -// #[derive(Debug, Clone, Copy, PartialEq, Eq)] -// pub enum Direction { -// $0 Next, -// Prev -// } -"#, - &[ - "// Next,", - "// #[derive(Debug, Clone, Copy, PartialEq, Eq)]\n// pub enum Direction {\n// Next,\n// Prev\n// }", - ], - ); - - do_check( - r#" -/* -foo -_bar1$0*/ -"#, - &["_bar1", "/*\nfoo\n_bar1*/"], - ); - - do_check(r#"//!$0foo_2 bar"#, &["foo_2", "//!foo_2 bar"]); - - do_check(r#"/$0/foo bar"#, &["//foo bar"]); - } - - #[test] - fn test_extend_selection_prefer_idents() { - do_check( - r#" -fn main() { foo$0+bar;} -"#, - &["foo", "foo+bar"], - ); - do_check( - r#" -fn main() { foo+$0bar;} -"#, - &["bar", "foo+bar"], - ); - } - - #[test] - fn test_extend_selection_prefer_lifetimes() { - do_check(r#"fn foo<$0'a>() {}"#, &["'a", "<'a>"]); - do_check(r#"fn foo<'a$0>() {}"#, &["'a", "<'a>"]); - } - - #[test] - fn test_extend_selection_select_first_word() { - do_check(r#"// foo bar b$0az quxx"#, &["baz", "// foo bar baz quxx"]); - do_check( - r#" -impl S { -fn foo() { -// hel$0lo world -} -} -"#, - &["hello", "// hello world"], - ); - } - - #[test] - fn test_extend_selection_string() { - do_check( - r#" -fn bar(){} - -" fn f$0oo() {" -"#, - &["foo", "\" fn foo() {\""], - ); - } - - #[test] - fn test_extend_trait_bounds_list_in_where_clause() { - do_check( - r#" -fn foo() - where - R: req::Request + 'static, - R::Params: DeserializeOwned$0 + panic::UnwindSafe + 'static, - R::Result: Serialize + 'static, -"#, - &[ - "DeserializeOwned", - "DeserializeOwned + ", - "DeserializeOwned + panic::UnwindSafe + 'static", - "R::Params: DeserializeOwned + panic::UnwindSafe + 'static", - "R::Params: DeserializeOwned + panic::UnwindSafe + 'static,", - ], - ); - do_check(r#"fn foo() where T: $0Copy"#, &["Copy"]); - do_check(r#"fn foo() where T: $0Copy + Display"#, &["Copy", "Copy + "]); - do_check(r#"fn foo() where T: $0Copy +Display"#, &["Copy", "Copy +"]); - do_check(r#"fn foo() where T: $0Copy+Display"#, &["Copy", "Copy+"]); - do_check(r#"fn foo() where T: Copy + $0Display"#, &["Display", "+ Display"]); - do_check(r#"fn foo() where T: Copy + $0Display + Sync"#, &["Display", "Display + "]); - do_check(r#"fn foo() where T: Copy +$0Display"#, &["Display", "+Display"]); - } - - #[test] - fn test_extend_trait_bounds_list_inline() { - do_check(r#"fn foo() {}"#, &["Copy"]); - do_check(r#"fn foo() {}"#, &["Copy", "Copy + "]); - do_check(r#"fn foo() {}"#, &["Copy", "Copy +"]); - do_check(r#"fn foo() {}"#, &["Copy", "Copy+"]); - do_check(r#"fn foo() {}"#, &["Display", "+ Display"]); - do_check(r#"fn foo() {}"#, &["Display", "Display + "]); - do_check(r#"fn foo() {}"#, &["Display", "+Display"]); - do_check( - r#"fn foo() {}"#, - &[ - "Copy", - "Copy + ", - "Copy + Display", - "T: Copy + Display", - "T: Copy + Display, ", - "", - ], - ); - } - - #[test] - fn test_extend_selection_on_tuple_in_type() { - do_check( - r#"fn main() { let _: (krate, $0_crate_def_map, module_id) = (); }"#, - &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], - ); - // white space variations - do_check( - r#"fn main() { let _: (krate,$0_crate_def_map,module_id) = (); }"#, - &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], - ); - do_check( - r#" -fn main() { let _: ( - krate, - _crate$0_def_map, - module_id -) = (); }"#, - &[ - "_crate_def_map", - "_crate_def_map,", - "(\n krate,\n _crate_def_map,\n module_id\n)", - ], - ); - } - - #[test] - fn test_extend_selection_on_tuple_in_rvalue() { - do_check( - r#"fn main() { let var = (krate, _crate_def_map$0, module_id); }"#, - &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], - ); - // white space variations - do_check( - r#"fn main() { let var = (krate,_crate$0_def_map,module_id); }"#, - &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], - ); - do_check( - r#" -fn main() { let var = ( - krate, - _crate_def_map$0, - module_id -); }"#, - &[ - "_crate_def_map", - "_crate_def_map,", - "(\n krate,\n _crate_def_map,\n module_id\n)", - ], - ); - } - - #[test] - fn test_extend_selection_on_tuple_pat() { - do_check( - r#"fn main() { let (krate, _crate_def_map$0, module_id) = var; }"#, - &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], - ); - // white space variations - do_check( - r#"fn main() { let (krate,_crate$0_def_map,module_id) = var; }"#, - &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], - ); - do_check( - r#" -fn main() { let ( - krate, - _crate_def_map$0, - module_id -) = var; }"#, - &[ - "_crate_def_map", - "_crate_def_map,", - "(\n krate,\n _crate_def_map,\n module_id\n)", - ], - ); - } - - #[test] - fn extend_selection_inside_macros() { - do_check( - r#"macro_rules! foo { ($item:item) => {$item} } - foo!{fn hello(na$0me:usize){}}"#, - &[ - "name", - "name:usize", - "(name:usize)", - "fn hello(name:usize){}", - "{fn hello(name:usize){}}", - "foo!{fn hello(name:usize){}}", - ], - ); - } - - #[test] - fn extend_selection_inside_recur_macros() { - do_check( - r#" macro_rules! foo2 { ($item:item) => {$item} } - macro_rules! foo { ($item:item) => {foo2!($item);} } - foo!{fn hello(na$0me:usize){}}"#, - &[ - "name", - "name:usize", - "(name:usize)", - "fn hello(name:usize){}", - "{fn hello(name:usize){}}", - "foo!{fn hello(name:usize){}}", - ], - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs deleted file mode 100644 index 68fd0952b4881..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs +++ /dev/null @@ -1,579 +0,0 @@ -use ide_db::SymbolKind; -use syntax::{ - ast::{self, HasAttrs, HasGenericParams, HasName}, - match_ast, AstNode, AstToken, NodeOrToken, SourceFile, SyntaxNode, SyntaxToken, TextRange, - WalkEvent, -}; - -#[derive(Debug, Clone)] -pub struct StructureNode { - pub parent: Option, - pub label: String, - pub navigation_range: TextRange, - pub node_range: TextRange, - pub kind: StructureNodeKind, - pub detail: Option, - pub deprecated: bool, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum StructureNodeKind { - SymbolKind(SymbolKind), - Region, -} - -// Feature: File Structure -// -// Provides a tree of the symbols defined in the file. Can be used to -// -// * fuzzy search symbol in a file (super useful) -// * draw breadcrumbs to describe the context around the cursor -// * draw outline of the file -// -// |=== -// | Editor | Shortcut -// -// | VS Code | kbd:[Ctrl+Shift+O] -// |=== -// -// image::https://user-images.githubusercontent.com/48062697/113020654-b42fc800-917a-11eb-8388-e7dc4d92b02e.gif[] - -pub(crate) fn file_structure(file: &SourceFile) -> Vec { - let mut res = Vec::new(); - let mut stack = Vec::new(); - - for event in file.syntax().preorder_with_tokens() { - match event { - WalkEvent::Enter(NodeOrToken::Node(node)) => { - if let Some(mut symbol) = structure_node(&node) { - symbol.parent = stack.last().copied(); - stack.push(res.len()); - res.push(symbol); - } - } - WalkEvent::Leave(NodeOrToken::Node(node)) => { - if structure_node(&node).is_some() { - stack.pop().unwrap(); - } - } - WalkEvent::Enter(NodeOrToken::Token(token)) => { - if let Some(mut symbol) = structure_token(token) { - symbol.parent = stack.last().copied(); - stack.push(res.len()); - res.push(symbol); - } - } - WalkEvent::Leave(NodeOrToken::Token(token)) => { - if structure_token(token).is_some() { - stack.pop().unwrap(); - } - } - } - } - res -} - -fn structure_node(node: &SyntaxNode) -> Option { - fn decl(node: N, kind: StructureNodeKind) -> Option { - decl_with_detail(&node, None, kind) - } - - fn decl_with_type_ref( - node: &N, - type_ref: Option, - kind: StructureNodeKind, - ) -> Option { - let detail = type_ref.map(|type_ref| { - let mut detail = String::new(); - collapse_ws(type_ref.syntax(), &mut detail); - detail - }); - decl_with_detail(node, detail, kind) - } - - fn decl_with_detail( - node: &N, - detail: Option, - kind: StructureNodeKind, - ) -> Option { - let name = node.name()?; - - Some(StructureNode { - parent: None, - label: name.text().to_string(), - navigation_range: name.syntax().text_range(), - node_range: node.syntax().text_range(), - kind, - detail, - deprecated: node.attrs().filter_map(|x| x.simple_name()).any(|x| x == "deprecated"), - }) - } - - fn collapse_ws(node: &SyntaxNode, output: &mut String) { - let mut can_insert_ws = false; - node.text().for_each_chunk(|chunk| { - for line in chunk.lines() { - let line = line.trim(); - if line.is_empty() { - if can_insert_ws { - output.push(' '); - can_insert_ws = false; - } - } else { - output.push_str(line); - can_insert_ws = true; - } - } - }) - } - - match_ast! { - match node { - ast::Fn(it) => { - let mut detail = String::from("fn"); - if let Some(type_param_list) = it.generic_param_list() { - collapse_ws(type_param_list.syntax(), &mut detail); - } - if let Some(param_list) = it.param_list() { - collapse_ws(param_list.syntax(), &mut detail); - } - if let Some(ret_type) = it.ret_type() { - detail.push(' '); - collapse_ws(ret_type.syntax(), &mut detail); - } - - decl_with_detail(&it, Some(detail), StructureNodeKind::SymbolKind(SymbolKind::Function)) - }, - ast::Struct(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Struct)), - ast::Union(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Union)), - ast::Enum(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Enum)), - ast::Variant(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Variant)), - ast::Trait(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Trait)), - ast::Module(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Module)), - ast::TypeAlias(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::TypeAlias)), - ast::RecordField(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Field)), - ast::Const(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Const)), - ast::Static(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Static)), - ast::Impl(it) => { - let target_type = it.self_ty()?; - let target_trait = it.trait_(); - let label = match target_trait { - None => format!("impl {}", target_type.syntax().text()), - Some(t) => { - format!("impl {} for {}", t.syntax().text(), target_type.syntax().text(),) - } - }; - - let node = StructureNode { - parent: None, - label, - navigation_range: target_type.syntax().text_range(), - node_range: it.syntax().text_range(), - kind: StructureNodeKind::SymbolKind(SymbolKind::Impl), - detail: None, - deprecated: false, - }; - Some(node) - }, - ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)), - _ => None, - } - } -} - -fn structure_token(token: SyntaxToken) -> Option { - if let Some(comment) = ast::Comment::cast(token) { - let text = comment.text().trim(); - - if let Some(region_name) = text.strip_prefix("// region:").map(str::trim) { - return Some(StructureNode { - parent: None, - label: region_name.to_string(), - navigation_range: comment.syntax().text_range(), - node_range: comment.syntax().text_range(), - kind: StructureNodeKind::Region, - detail: None, - deprecated: false, - }); - } - } - - None -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use super::*; - - fn check(ra_fixture: &str, expect: Expect) { - let file = SourceFile::parse(ra_fixture).ok().unwrap(); - let structure = file_structure(&file); - expect.assert_debug_eq(&structure) - } - - #[test] - fn test_file_structure() { - check( - r#" -struct Foo { - x: i32 -} - -mod m { - fn bar1() {} - fn bar2(t: T) -> T {} - fn bar3(a: A, - b: B) -> Vec< - u32 - > {} -} - -enum E { X, Y(i32) } -type T = (); -static S: i32 = 92; -const C: i32 = 92; - -impl E {} - -impl fmt::Debug for E {} - -macro_rules! mc { - () => {} -} - -#[macro_export] -macro_rules! mcexp { - () => {} -} - -/// Doc comment -macro_rules! mcexp { - () => {} -} - -#[deprecated] -fn obsolete() {} - -#[deprecated(note = "for awhile")] -fn very_obsolete() {} - -// region: Some region name -// endregion - -// region: dontpanic -mod m { -fn f() {} -// endregion -fn g() {} -} -"#, - expect![[r#" - [ - StructureNode { - parent: None, - label: "Foo", - navigation_range: 8..11, - node_range: 1..26, - kind: SymbolKind( - Struct, - ), - detail: None, - deprecated: false, - }, - StructureNode { - parent: Some( - 0, - ), - label: "x", - navigation_range: 18..19, - node_range: 18..24, - kind: SymbolKind( - Field, - ), - detail: Some( - "i32", - ), - deprecated: false, - }, - StructureNode { - parent: None, - label: "m", - navigation_range: 32..33, - node_range: 28..158, - kind: SymbolKind( - Module, - ), - detail: None, - deprecated: false, - }, - StructureNode { - parent: Some( - 2, - ), - label: "bar1", - navigation_range: 43..47, - node_range: 40..52, - kind: SymbolKind( - Function, - ), - detail: Some( - "fn()", - ), - deprecated: false, - }, - StructureNode { - parent: Some( - 2, - ), - label: "bar2", - navigation_range: 60..64, - node_range: 57..81, - kind: SymbolKind( - Function, - ), - detail: Some( - "fn(t: T) -> T", - ), - deprecated: false, - }, - StructureNode { - parent: Some( - 2, - ), - label: "bar3", - navigation_range: 89..93, - node_range: 86..156, - kind: SymbolKind( - Function, - ), - detail: Some( - "fn(a: A, b: B) -> Vec< u32 >", - ), - deprecated: false, - }, - StructureNode { - parent: None, - label: "E", - navigation_range: 165..166, - node_range: 160..180, - kind: SymbolKind( - Enum, - ), - detail: None, - deprecated: false, - }, - StructureNode { - parent: Some( - 6, - ), - label: "X", - navigation_range: 169..170, - node_range: 169..170, - kind: SymbolKind( - Variant, - ), - detail: None, - deprecated: false, - }, - StructureNode { - parent: Some( - 6, - ), - label: "Y", - navigation_range: 172..173, - node_range: 172..178, - kind: SymbolKind( - Variant, - ), - detail: None, - deprecated: false, - }, - StructureNode { - parent: None, - label: "T", - navigation_range: 186..187, - node_range: 181..193, - kind: SymbolKind( - TypeAlias, - ), - detail: Some( - "()", - ), - deprecated: false, - }, - StructureNode { - parent: None, - label: "S", - navigation_range: 201..202, - node_range: 194..213, - kind: SymbolKind( - Static, - ), - detail: Some( - "i32", - ), - deprecated: false, - }, - StructureNode { - parent: None, - label: "C", - navigation_range: 220..221, - node_range: 214..232, - kind: SymbolKind( - Const, - ), - detail: Some( - "i32", - ), - deprecated: false, - }, - StructureNode { - parent: None, - label: "impl E", - navigation_range: 239..240, - node_range: 234..243, - kind: SymbolKind( - Impl, - ), - detail: None, - deprecated: false, - }, - StructureNode { - parent: None, - label: "impl fmt::Debug for E", - navigation_range: 265..266, - node_range: 245..269, - kind: SymbolKind( - Impl, - ), - detail: None, - deprecated: false, - }, - StructureNode { - parent: None, - label: "mc", - navigation_range: 284..286, - node_range: 271..303, - kind: SymbolKind( - Macro, - ), - detail: None, - deprecated: false, - }, - StructureNode { - parent: None, - label: "mcexp", - navigation_range: 334..339, - node_range: 305..356, - kind: SymbolKind( - Macro, - ), - detail: None, - deprecated: false, - }, - StructureNode { - parent: None, - label: "mcexp", - navigation_range: 387..392, - node_range: 358..409, - kind: SymbolKind( - Macro, - ), - detail: None, - deprecated: false, - }, - StructureNode { - parent: None, - label: "obsolete", - navigation_range: 428..436, - node_range: 411..441, - kind: SymbolKind( - Function, - ), - detail: Some( - "fn()", - ), - deprecated: true, - }, - StructureNode { - parent: None, - label: "very_obsolete", - navigation_range: 481..494, - node_range: 443..499, - kind: SymbolKind( - Function, - ), - detail: Some( - "fn()", - ), - deprecated: true, - }, - StructureNode { - parent: None, - label: "Some region name", - navigation_range: 501..528, - node_range: 501..528, - kind: Region, - detail: None, - deprecated: false, - }, - StructureNode { - parent: None, - label: "m", - navigation_range: 568..569, - node_range: 543..606, - kind: SymbolKind( - Module, - ), - detail: None, - deprecated: false, - }, - StructureNode { - parent: Some( - 20, - ), - label: "dontpanic", - navigation_range: 543..563, - node_range: 543..563, - kind: Region, - detail: None, - deprecated: false, - }, - StructureNode { - parent: Some( - 20, - ), - label: "f", - navigation_range: 575..576, - node_range: 572..581, - kind: SymbolKind( - Function, - ), - detail: Some( - "fn()", - ), - deprecated: false, - }, - StructureNode { - parent: Some( - 20, - ), - label: "g", - navigation_range: 598..599, - node_range: 582..604, - kind: SymbolKind( - Function, - ), - detail: Some( - "fn()", - ), - deprecated: false, - }, - ] - "#]], - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/fixture.rs b/src/tools/rust-analyzer/crates/ide/src/fixture.rs deleted file mode 100644 index 2ea6f6a9ab1b6..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/fixture.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! Utilities for creating `Analysis` instances for tests. -use hir::db::DefDatabase; -use ide_db::base_db::fixture::ChangeFixture; -use test_utils::{extract_annotations, RangeOrOffset}; - -use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange}; - -/// Creates analysis for a single file. -pub(crate) fn file(ra_fixture: &str) -> (Analysis, FileId) { - let mut host = AnalysisHost::default(); - let change_fixture = ChangeFixture::parse(ra_fixture); - host.db.set_enable_proc_attr_macros(true); - host.db.apply_change(change_fixture.change); - (host.analysis(), change_fixture.files[0]) -} - -/// Creates analysis from a multi-file fixture, returns positions marked with $0. -pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { - let mut host = AnalysisHost::default(); - let change_fixture = ChangeFixture::parse(ra_fixture); - host.db.set_enable_proc_attr_macros(true); - host.db.apply_change(change_fixture.change); - let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); - let offset = range_or_offset.expect_offset(); - (host.analysis(), FilePosition { file_id, offset }) -} - -/// Creates analysis for a single file, returns range marked with a pair of $0. -pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) { - let mut host = AnalysisHost::default(); - let change_fixture = ChangeFixture::parse(ra_fixture); - host.db.set_enable_proc_attr_macros(true); - host.db.apply_change(change_fixture.change); - let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); - let range = range_or_offset.expect_range(); - (host.analysis(), FileRange { file_id, range }) -} - -/// Creates analysis for a single file, returns range marked with a pair of $0 or a position marked with $0. -pub(crate) fn range_or_position(ra_fixture: &str) -> (Analysis, FileId, RangeOrOffset) { - let mut host = AnalysisHost::default(); - let change_fixture = ChangeFixture::parse(ra_fixture); - host.db.set_enable_proc_attr_macros(true); - host.db.apply_change(change_fixture.change); - let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); - (host.analysis(), file_id, range_or_offset) -} - -/// Creates analysis from a multi-file fixture, returns positions marked with $0. -pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(FileRange, String)>) { - let mut host = AnalysisHost::default(); - let change_fixture = ChangeFixture::parse(ra_fixture); - host.db.set_enable_proc_attr_macros(true); - host.db.apply_change(change_fixture.change); - let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); - let offset = range_or_offset.expect_offset(); - - let annotations = change_fixture - .files - .iter() - .flat_map(|&file_id| { - let file_text = host.analysis().file_text(file_id).unwrap(); - let annotations = extract_annotations(&file_text); - annotations.into_iter().map(move |(range, data)| (FileRange { file_id, range }, data)) - }) - .collect(); - (host.analysis(), FilePosition { file_id, offset }, annotations) -} - -/// Creates analysis from a multi-file fixture with annonations without $0 -pub(crate) fn annotations_without_marker(ra_fixture: &str) -> (Analysis, Vec<(FileRange, String)>) { - let mut host = AnalysisHost::default(); - let change_fixture = ChangeFixture::parse(ra_fixture); - host.db.set_enable_proc_attr_macros(true); - host.db.apply_change(change_fixture.change); - - let annotations = change_fixture - .files - .iter() - .flat_map(|&file_id| { - let file_text = host.analysis().file_text(file_id).unwrap(); - let annotations = extract_annotations(&file_text); - annotations.into_iter().map(move |(range, data)| (FileRange { file_id, range }, data)) - }) - .collect(); - (host.analysis(), annotations) -} diff --git a/src/tools/rust-analyzer/crates/ide/src/fn_references.rs b/src/tools/rust-analyzer/crates/ide/src/fn_references.rs deleted file mode 100644 index 63fb322cea07e..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/fn_references.rs +++ /dev/null @@ -1,94 +0,0 @@ -//! This module implements a methods and free functions search in the specified file. -//! We have to skip tests, so cannot reuse file_structure module. - -use hir::Semantics; -use ide_assists::utils::test_related_attribute; -use ide_db::RootDatabase; -use syntax::{ast, ast::HasName, AstNode, SyntaxNode}; - -use crate::{FileId, FileRange}; - -pub(crate) fn find_all_methods(db: &RootDatabase, file_id: FileId) -> Vec { - let sema = Semantics::new(db); - let source_file = sema.parse(file_id); - source_file.syntax().descendants().filter_map(|it| method_range(it, file_id)).collect() -} - -fn method_range(item: SyntaxNode, file_id: FileId) -> Option { - ast::Fn::cast(item).and_then(|fn_def| { - if test_related_attribute(&fn_def).is_some() { - None - } else { - fn_def.name().map(|name| FileRange { file_id, range: name.syntax().text_range() }) - } - }) -} - -#[cfg(test)] -mod tests { - use crate::fixture; - use crate::{FileRange, TextSize}; - use std::ops::RangeInclusive; - - #[test] - fn test_find_all_methods() { - let (analysis, pos) = fixture::position( - r#" - fn private_fn() {$0} - - pub fn pub_fn() {} - - pub fn generic_fn(arg: T) {} - "#, - ); - - let refs = analysis.find_all_methods(pos.file_id).unwrap(); - check_result(&refs, &[3..=13, 27..=33, 47..=57]); - } - - #[test] - fn test_find_trait_methods() { - let (analysis, pos) = fixture::position( - r#" - trait Foo { - fn bar() {$0} - fn baz() {} - } - "#, - ); - - let refs = analysis.find_all_methods(pos.file_id).unwrap(); - check_result(&refs, &[19..=22, 35..=38]); - } - - #[test] - fn test_skip_tests() { - let (analysis, pos) = fixture::position( - r#" - //- /lib.rs - #[test] - fn foo() {$0} - - pub fn pub_fn() {} - - mod tests { - #[test] - fn bar() {} - } - "#, - ); - - let refs = analysis.find_all_methods(pos.file_id).unwrap(); - check_result(&refs, &[28..=34]); - } - - fn check_result(refs: &[FileRange], expected: &[RangeInclusive]) { - assert_eq!(refs.len(), expected.len()); - - for (i, item) in refs.iter().enumerate() { - let range = &expected[i]; - assert_eq!(TextSize::from(*range.start()), item.range.start()); - assert_eq!(TextSize::from(*range.end()), item.range.end()); - } - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs deleted file mode 100755 index c694d95d537ff..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs +++ /dev/null @@ -1,626 +0,0 @@ -use ide_db::{syntax_helpers::node_ext::vis_eq, FxHashSet}; -use syntax::{ - ast::{self, AstNode, AstToken}, - match_ast, Direction, NodeOrToken, SourceFile, - SyntaxKind::{self, *}, - TextRange, TextSize, -}; - -use std::hash::Hash; - -const REGION_START: &str = "// region:"; -const REGION_END: &str = "// endregion"; - -#[derive(Debug, PartialEq, Eq)] -pub enum FoldKind { - Comment, - Imports, - Mods, - Block, - ArgList, - Region, - Consts, - Statics, - Array, - WhereClause, - ReturnType, - MatchArm, -} - -#[derive(Debug)] -pub struct Fold { - pub range: TextRange, - pub kind: FoldKind, -} - -// Feature: Folding -// -// Defines folding regions for curly braced blocks, runs of consecutive use, mod, const or static -// items, and `region` / `endregion` comment markers. -pub(crate) fn folding_ranges(file: &SourceFile) -> Vec { - let mut res = vec![]; - let mut visited_comments = FxHashSet::default(); - let mut visited_imports = FxHashSet::default(); - let mut visited_mods = FxHashSet::default(); - let mut visited_consts = FxHashSet::default(); - let mut visited_statics = FxHashSet::default(); - - // regions can be nested, here is a LIFO buffer - let mut region_starts: Vec = vec![]; - - for element in file.syntax().descendants_with_tokens() { - // Fold items that span multiple lines - if let Some(kind) = fold_kind(element.kind()) { - let is_multiline = match &element { - NodeOrToken::Node(node) => node.text().contains_char('\n'), - NodeOrToken::Token(token) => token.text().contains('\n'), - }; - if is_multiline { - res.push(Fold { range: element.text_range(), kind }); - continue; - } - } - - match element { - NodeOrToken::Token(token) => { - // Fold groups of comments - if let Some(comment) = ast::Comment::cast(token) { - if visited_comments.contains(&comment) { - continue; - } - let text = comment.text().trim_start(); - if text.starts_with(REGION_START) { - region_starts.push(comment.syntax().text_range().start()); - } else if text.starts_with(REGION_END) { - if let Some(region) = region_starts.pop() { - res.push(Fold { - range: TextRange::new(region, comment.syntax().text_range().end()), - kind: FoldKind::Region, - }) - } - } else if let Some(range) = - contiguous_range_for_comment(comment, &mut visited_comments) - { - res.push(Fold { range, kind: FoldKind::Comment }) - } - } - } - NodeOrToken::Node(node) => { - match_ast! { - match node { - ast::Module(module) => { - if module.item_list().is_none() { - if let Some(range) = contiguous_range_for_item_group( - module, - &mut visited_mods, - ) { - res.push(Fold { range, kind: FoldKind::Mods }) - } - } - }, - ast::Use(use_) => { - if let Some(range) = contiguous_range_for_item_group(use_, &mut visited_imports) { - res.push(Fold { range, kind: FoldKind::Imports }) - } - }, - ast::Const(konst) => { - if let Some(range) = contiguous_range_for_item_group(konst, &mut visited_consts) { - res.push(Fold { range, kind: FoldKind::Consts }) - } - }, - ast::Static(statik) => { - if let Some(range) = contiguous_range_for_item_group(statik, &mut visited_statics) { - res.push(Fold { range, kind: FoldKind::Statics }) - } - }, - ast::WhereClause(where_clause) => { - if let Some(range) = fold_range_for_where_clause(where_clause) { - res.push(Fold { range, kind: FoldKind::WhereClause }) - } - }, - ast::MatchArm(match_arm) => { - if let Some(range) = fold_range_for_multiline_match_arm(match_arm) { - res.push(Fold {range, kind: FoldKind::MatchArm}) - } - }, - _ => (), - } - } - } - } - } - - res -} - -fn fold_kind(kind: SyntaxKind) -> Option { - match kind { - COMMENT => Some(FoldKind::Comment), - ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList), - ARRAY_EXPR => Some(FoldKind::Array), - RET_TYPE => Some(FoldKind::ReturnType), - ASSOC_ITEM_LIST - | RECORD_FIELD_LIST - | RECORD_PAT_FIELD_LIST - | RECORD_EXPR_FIELD_LIST - | ITEM_LIST - | EXTERN_ITEM_LIST - | USE_TREE_LIST - | BLOCK_EXPR - | MATCH_ARM_LIST - | VARIANT_LIST - | TOKEN_TREE => Some(FoldKind::Block), - _ => None, - } -} - -fn contiguous_range_for_item_group(first: N, visited: &mut FxHashSet) -> Option -where - N: ast::HasVisibility + Clone + Hash + Eq, -{ - if !visited.insert(first.clone()) { - return None; - } - - let (mut last, mut last_vis) = (first.clone(), first.visibility()); - for element in first.syntax().siblings_with_tokens(Direction::Next) { - let node = match element { - NodeOrToken::Token(token) => { - if let Some(ws) = ast::Whitespace::cast(token) { - if !ws.spans_multiple_lines() { - // Ignore whitespace without blank lines - continue; - } - } - // There is a blank line or another token, which means that the - // group ends here - break; - } - NodeOrToken::Node(node) => node, - }; - - if let Some(next) = N::cast(node) { - let next_vis = next.visibility(); - if eq_visibility(next_vis.clone(), last_vis) { - visited.insert(next.clone()); - last_vis = next_vis; - last = next; - continue; - } - } - // Stop if we find an item of a different kind or with a different visibility. - break; - } - - if first != last { - Some(TextRange::new(first.syntax().text_range().start(), last.syntax().text_range().end())) - } else { - // The group consists of only one element, therefore it cannot be folded - None - } -} - -fn eq_visibility(vis0: Option, vis1: Option) -> bool { - match (vis0, vis1) { - (None, None) => true, - (Some(vis0), Some(vis1)) => vis_eq(&vis0, &vis1), - _ => false, - } -} - -fn contiguous_range_for_comment( - first: ast::Comment, - visited: &mut FxHashSet, -) -> Option { - visited.insert(first.clone()); - - // Only fold comments of the same flavor - let group_kind = first.kind(); - if !group_kind.shape.is_line() { - return None; - } - - let mut last = first.clone(); - for element in first.syntax().siblings_with_tokens(Direction::Next) { - match element { - NodeOrToken::Token(token) => { - if let Some(ws) = ast::Whitespace::cast(token.clone()) { - if !ws.spans_multiple_lines() { - // Ignore whitespace without blank lines - continue; - } - } - if let Some(c) = ast::Comment::cast(token) { - if c.kind() == group_kind { - let text = c.text().trim_start(); - // regions are not real comments - if !(text.starts_with(REGION_START) || text.starts_with(REGION_END)) { - visited.insert(c.clone()); - last = c; - continue; - } - } - } - // The comment group ends because either: - // * An element of a different kind was reached - // * A comment of a different flavor was reached - break; - } - NodeOrToken::Node(_) => break, - }; - } - - if first != last { - Some(TextRange::new(first.syntax().text_range().start(), last.syntax().text_range().end())) - } else { - // The group consists of only one element, therefore it cannot be folded - None - } -} - -fn fold_range_for_where_clause(where_clause: ast::WhereClause) -> Option { - let first_where_pred = where_clause.predicates().next(); - let last_where_pred = where_clause.predicates().last(); - - if first_where_pred != last_where_pred { - let start = where_clause.where_token()?.text_range().end(); - let end = where_clause.syntax().text_range().end(); - return Some(TextRange::new(start, end)); - } - None -} - -fn fold_range_for_multiline_match_arm(match_arm: ast::MatchArm) -> Option { - if let Some(_) = fold_kind(match_arm.expr()?.syntax().kind()) { - return None; - } - if match_arm.expr()?.syntax().text().contains_char('\n') { - return Some(match_arm.expr()?.syntax().text_range()); - } - None -} - -#[cfg(test)] -mod tests { - use test_utils::extract_tags; - - use super::*; - - fn check(ra_fixture: &str) { - let (ranges, text) = extract_tags(ra_fixture, "fold"); - - let parse = SourceFile::parse(&text); - let mut folds = folding_ranges(&parse.tree()); - folds.sort_by_key(|fold| (fold.range.start(), fold.range.end())); - - assert_eq!( - folds.len(), - ranges.len(), - "The amount of folds is different than the expected amount" - ); - - for (fold, (range, attr)) in folds.iter().zip(ranges.into_iter()) { - assert_eq!(fold.range.start(), range.start(), "mismatched start of folding ranges"); - assert_eq!(fold.range.end(), range.end(), "mismatched end of folding ranges"); - - let kind = match fold.kind { - FoldKind::Comment => "comment", - FoldKind::Imports => "imports", - FoldKind::Mods => "mods", - FoldKind::Block => "block", - FoldKind::ArgList => "arglist", - FoldKind::Region => "region", - FoldKind::Consts => "consts", - FoldKind::Statics => "statics", - FoldKind::Array => "array", - FoldKind::WhereClause => "whereclause", - FoldKind::ReturnType => "returntype", - FoldKind::MatchArm => "matcharm", - }; - assert_eq!(kind, &attr.unwrap()); - } - } - - #[test] - fn test_fold_comments() { - check( - r#" -// Hello -// this is a multiline -// comment -// - -// But this is not - -fn main() { - // We should - // also - // fold - // this one. - //! But this one is different - //! because it has another flavor - /* As does this - multiline comment */ -} -"#, - ); - } - - #[test] - fn test_fold_imports() { - check( - r#" -use std::{ - str, - vec, - io as iop -}; -"#, - ); - } - - #[test] - fn test_fold_mods() { - check( - r#" - -pub mod foo; -mod after_pub; -mod after_pub_next; - -mod before_pub; -mod before_pub_next; -pub mod bar; - -mod not_folding_single; -pub mod foobar; -pub not_folding_single_next; - -#[cfg(test)] -mod with_attribute; -mod with_attribute_next; - -mod inline0 {} -mod inline1 {} - -mod inline2 { - -} -"#, - ); - } - - #[test] - fn test_fold_import_groups() { - check( - r#" -use std::str; -use std::vec; -use std::io as iop; - -use std::mem; -use std::f64; - -use std::collections::HashMap; -// Some random comment -use std::collections::VecDeque; -"#, - ); - } - - #[test] - fn test_fold_import_and_groups() { - check( - r#" -use std::str; -use std::vec; -use std::io as iop; - -use std::mem; -use std::f64; - -use std::collections::{ - HashMap, - VecDeque, -}; -// Some random comment -"#, - ); - } - - #[test] - fn test_folds_structs() { - check( - r#" -struct Foo { -} -"#, - ); - } - - #[test] - fn test_folds_traits() { - check( - r#" -trait Foo { -} -"#, - ); - } - - #[test] - fn test_folds_macros() { - check( - r#" -macro_rules! foo { - ($($tt:tt)*) => { $($tt)* } -} -"#, - ); - } - - #[test] - fn test_fold_match_arms() { - check( - r#" -fn main() { - match 0 { - 0 => 0, - _ => 1, - } -} -"#, - ); - } - - #[test] - fn test_fold_multiline_non_block_match_arm() { - check( - r#" - fn main() { - match foo { - block => { - }, - matcharm => some. - call(). - chain(), - matcharm2 - => 0, - match_expr => match foo2 { - bar => (), - }, - array_list => [ - 1, - 2, - 3, - ], - strustS => StructS { - a: 31, - }, - } - } - "#, - ) - } - - #[test] - fn fold_big_calls() { - check( - r#" -fn main() { - frobnicate( - 1, - 2, - 3, - ) -} -"#, - ) - } - - #[test] - fn fold_record_literals() { - check( - r#" -const _: S = S { - -}; -"#, - ) - } - - #[test] - fn fold_multiline_params() { - check( - r#" -fn foo( - x: i32, - y: String, -) {} -"#, - ) - } - - #[test] - fn fold_multiline_array() { - check( - r#" -const FOO: [usize; 4] = [ - 1, - 2, - 3, - 4, -]; -"#, - ) - } - - #[test] - fn fold_region() { - check( - r#" -// 1. some normal comment -// region: test -// 2. some normal comment -// region: inner -fn f() {} -// endregion -fn f2() {} -// endregion: test -"#, - ) - } - - #[test] - fn fold_consecutive_const() { - check( - r#" -const FIRST_CONST: &str = "first"; -const SECOND_CONST: &str = "second"; -"#, - ) - } - - #[test] - fn fold_consecutive_static() { - check( - r#" -static FIRST_STATIC: &str = "first"; -static SECOND_STATIC: &str = "second"; -"#, - ) - } - - #[test] - fn fold_where_clause() { - // fold multi-line and don't fold single line. - check( - r#" -fn foo() -where - A: Foo, - B: Foo, - C: Foo, - D: Foo, {} - -fn bar() -where - A: Bar, {} -"#, - ) - } - - #[test] - fn fold_return_type() { - check( - r#" -fn foo()-> ( - bool, - bool, -) { (true, true) } - -fn bar() -> (bool, bool) { (true, true) } -"#, - ) - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs deleted file mode 100644 index 926292c9b3ce1..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs +++ /dev/null @@ -1,112 +0,0 @@ -use hir::Semantics; -use ide_db::{ - defs::{Definition, NameClass, NameRefClass}, - RootDatabase, -}; -use syntax::{ast, match_ast, AstNode, SyntaxKind::*, T}; - -use crate::{FilePosition, NavigationTarget, RangeInfo}; - -// Feature: Go to Declaration -// -// Navigates to the declaration of an identifier. -// -// This is currently the same as `Go to Definition` with the exception of outline modules where it -// will navigate to the `mod name;` item declaration. -pub(crate) fn goto_declaration( - db: &RootDatabase, - position: FilePosition, -) -> Option>> { - let sema = Semantics::new(db); - let file = sema.parse(position.file_id).syntax().clone(); - let original_token = file - .token_at_offset(position.offset) - .find(|it| matches!(it.kind(), IDENT | T![self] | T![super] | T![crate] | T![Self]))?; - let range = original_token.text_range(); - let info: Vec = sema - .descend_into_macros(original_token) - .iter() - .filter_map(|token| { - let parent = token.parent()?; - let def = match_ast! { - match parent { - ast::NameRef(name_ref) => match NameRefClass::classify(&sema, &name_ref)? { - NameRefClass::Definition(it) => Some(it), - _ => None - }, - ast::Name(name) => match NameClass::classify(&sema, &name)? { - NameClass::Definition(it) => Some(it), - _ => None - }, - _ => None - } - }; - match def? { - Definition::Module(module) => { - Some(NavigationTarget::from_module_to_decl(db, module)) - } - _ => None, - } - }) - .collect(); - - Some(RangeInfo::new(range, info)) -} - -#[cfg(test)] -mod tests { - use ide_db::base_db::FileRange; - use itertools::Itertools; - - use crate::fixture; - - fn check(ra_fixture: &str) { - let (analysis, position, expected) = fixture::annotations(ra_fixture); - let navs = analysis - .goto_declaration(position) - .unwrap() - .expect("no declaration or definition found") - .info; - if navs.is_empty() { - panic!("unresolved reference") - } - - let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start()); - let navs = navs - .into_iter() - .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) - .sorted_by_key(cmp) - .collect::>(); - let expected = expected - .into_iter() - .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range }) - .sorted_by_key(cmp) - .collect::>(); - assert_eq!(expected, navs); - } - - #[test] - fn goto_decl_module_outline() { - check( - r#" -//- /main.rs -mod foo; - // ^^^ -//- /foo.rs -use self$0; -"#, - ) - } - - #[test] - fn goto_decl_module_inline() { - check( - r#" -mod foo { - // ^^^ - use self$0; -} -"#, - ) - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs deleted file mode 100644 index d9c97751c95c3..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ /dev/null @@ -1,1634 +0,0 @@ -use std::{convert::TryInto, mem::discriminant}; - -use crate::{doc_links::token_as_doc_comment, FilePosition, NavigationTarget, RangeInfo, TryToNav}; -use hir::{AsAssocItem, AssocItem, Semantics}; -use ide_db::{ - base_db::{AnchoredPath, FileId, FileLoader}, - defs::{Definition, IdentClass}, - helpers::pick_best_token, - RootDatabase, -}; -use itertools::Itertools; -use syntax::{ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextRange, T}; - -// Feature: Go to Definition -// -// Navigates to the definition of an identifier. -// -// For outline modules, this will navigate to the source file of the module. -// -// |=== -// | Editor | Shortcut -// -// | VS Code | kbd:[F12] -// |=== -// -// image::https://user-images.githubusercontent.com/48062697/113065563-025fbe00-91b1-11eb-83e4-a5a703610b23.gif[] -pub(crate) fn goto_definition( - db: &RootDatabase, - position: FilePosition, -) -> Option>> { - let sema = &Semantics::new(db); - let file = sema.parse(position.file_id).syntax().clone(); - let original_token = - pick_best_token(file.token_at_offset(position.offset), |kind| match kind { - IDENT - | INT_NUMBER - | LIFETIME_IDENT - | T![self] - | T![super] - | T![crate] - | T![Self] - | COMMENT => 2, - kind if kind.is_trivia() => 0, - _ => 1, - })?; - if let Some(doc_comment) = token_as_doc_comment(&original_token) { - return doc_comment.get_definition_with_descend_at(sema, position.offset, |def, _, _| { - let nav = def.try_to_nav(db)?; - Some(RangeInfo::new(original_token.text_range(), vec![nav])) - }); - } - let navs = sema - .descend_into_macros(original_token.clone()) - .into_iter() - .filter_map(|token| { - let parent = token.parent()?; - if let Some(tt) = ast::TokenTree::cast(parent) { - if let Some(x) = try_lookup_include_path(sema, tt, token.clone(), position.file_id) - { - return Some(vec![x]); - } - } - Some( - IdentClass::classify_token(sema, &token)? - .definitions() - .into_iter() - .flat_map(|def| { - try_filter_trait_item_definition(sema, &def) - .unwrap_or_else(|| def_to_nav(sema.db, def)) - }) - .collect(), - ) - }) - .flatten() - .unique() - .collect::>(); - - Some(RangeInfo::new(original_token.text_range(), navs)) -} - -fn try_lookup_include_path( - sema: &Semantics<'_, RootDatabase>, - tt: ast::TokenTree, - token: SyntaxToken, - file_id: FileId, -) -> Option { - let token = ast::String::cast(token)?; - let path = token.value()?.into_owned(); - let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?; - let name = macro_call.path()?.segment()?.name_ref()?; - if !matches!(&*name.text(), "include" | "include_str" | "include_bytes") { - return None; - } - let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?; - let size = sema.db.file_text(file_id).len().try_into().ok()?; - Some(NavigationTarget { - file_id, - full_range: TextRange::new(0.into(), size), - name: path.into(), - focus_range: None, - kind: None, - container_name: None, - description: None, - docs: None, - }) -} -/// finds the trait definition of an impl'd item, except function -/// e.g. -/// ```rust -/// trait A { type a; } -/// struct S; -/// impl A for S { type a = i32; } // <-- on this associate type, will get the location of a in the trait -/// ``` -fn try_filter_trait_item_definition( - sema: &Semantics<'_, RootDatabase>, - def: &Definition, -) -> Option> { - let db = sema.db; - let assoc = def.as_assoc_item(db)?; - match assoc { - AssocItem::Function(..) => None, - AssocItem::Const(..) | AssocItem::TypeAlias(..) => { - let imp = match assoc.container(db) { - hir::AssocItemContainer::Impl(imp) => imp, - _ => return None, - }; - let trait_ = imp.trait_(db)?; - let name = def.name(db)?; - let discri_value = discriminant(&assoc); - trait_ - .items(db) - .iter() - .filter(|itm| discriminant(*itm) == discri_value) - .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten()) - .map(|it| vec![it]) - } - } -} - -fn def_to_nav(db: &RootDatabase, def: Definition) -> Vec { - def.try_to_nav(db).map(|it| vec![it]).unwrap_or_default() -} - -#[cfg(test)] -mod tests { - use ide_db::base_db::FileRange; - use itertools::Itertools; - - use crate::fixture; - - #[track_caller] - fn check(ra_fixture: &str) { - let (analysis, position, expected) = fixture::annotations(ra_fixture); - let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info; - if navs.is_empty() { - panic!("unresolved reference") - } - - let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start()); - let navs = navs - .into_iter() - .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) - .sorted_by_key(cmp) - .collect::>(); - let expected = expected - .into_iter() - .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range }) - .sorted_by_key(cmp) - .collect::>(); - assert_eq!(expected, navs); - } - - fn check_unresolved(ra_fixture: &str) { - let (analysis, position) = fixture::position(ra_fixture); - let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info; - - assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {:?}", navs) - } - - #[test] - fn goto_def_if_items_same_name() { - check( - r#" -trait Trait { - type A; - const A: i32; - //^ -} - -struct T; -impl Trait for T { - type A = i32; - const A$0: i32 = -9; -}"#, - ); - } - #[test] - fn goto_def_in_mac_call_in_attr_invoc() { - check( - r#" -//- proc_macros: identity -pub struct Struct { - // ^^^^^^ - field: i32, -} - -macro_rules! identity { - ($($tt:tt)*) => {$($tt)*}; -} - -#[proc_macros::identity] -fn function() { - identity!(Struct$0 { field: 0 }); -} - -"#, - ) - } - - #[test] - fn goto_def_for_extern_crate() { - check( - r#" -//- /main.rs crate:main deps:std -extern crate std$0; -//- /std/lib.rs crate:std -// empty -//^file -"#, - ) - } - - #[test] - fn goto_def_for_renamed_extern_crate() { - check( - r#" -//- /main.rs crate:main deps:std -extern crate std as abc$0; -//- /std/lib.rs crate:std -// empty -//^file -"#, - ) - } - - #[test] - fn goto_def_in_items() { - check( - r#" -struct Foo; - //^^^ -enum E { X(Foo$0) } -"#, - ); - } - - #[test] - fn goto_def_at_start_of_item() { - check( - r#" -struct Foo; - //^^^ -enum E { X($0Foo) } -"#, - ); - } - - #[test] - fn goto_definition_resolves_correct_name() { - check( - r#" -//- /lib.rs -use a::Foo; -mod a; -mod b; -enum E { X(Foo$0) } - -//- /a.rs -struct Foo; - //^^^ -//- /b.rs -struct Foo; -"#, - ); - } - - #[test] - fn goto_def_for_module_declaration() { - check( - r#" -//- /lib.rs -mod $0foo; - -//- /foo.rs -// empty -//^file -"#, - ); - - check( - r#" -//- /lib.rs -mod $0foo; - -//- /foo/mod.rs -// empty -//^file -"#, - ); - } - - #[test] - fn goto_def_for_macros() { - check( - r#" -macro_rules! foo { () => { () } } - //^^^ -fn bar() { - $0foo!(); -} -"#, - ); - } - - #[test] - fn goto_def_for_macros_from_other_crates() { - check( - r#" -//- /lib.rs crate:main deps:foo -use foo::foo; -fn bar() { - $0foo!(); -} - -//- /foo/lib.rs crate:foo -#[macro_export] -macro_rules! foo { () => { () } } - //^^^ -"#, - ); - } - - #[test] - fn goto_def_for_macros_in_use_tree() { - check( - r#" -//- /lib.rs crate:main deps:foo -use foo::foo$0; - -//- /foo/lib.rs crate:foo -#[macro_export] -macro_rules! foo { () => { () } } - //^^^ -"#, - ); - } - - #[test] - fn goto_def_for_macro_defined_fn_with_arg() { - check( - r#" -//- /lib.rs -macro_rules! define_fn { - ($name:ident) => (fn $name() {}) -} - -define_fn!(foo); - //^^^ - -fn bar() { - $0foo(); -} -"#, - ); - } - - #[test] - fn goto_def_for_macro_defined_fn_no_arg() { - check( - r#" -//- /lib.rs -macro_rules! define_fn { - () => (fn foo() {}) -} - - define_fn!(); -//^^^^^^^^^^^^^ - -fn bar() { - $0foo(); -} -"#, - ); - } - - #[test] - fn goto_definition_works_for_macro_inside_pattern() { - check( - r#" -//- /lib.rs -macro_rules! foo {() => {0}} - //^^^ - -fn bar() { - match (0,1) { - ($0foo!(), _) => {} - } -} -"#, - ); - } - - #[test] - fn goto_definition_works_for_macro_inside_match_arm_lhs() { - check( - r#" -//- /lib.rs -macro_rules! foo {() => {0}} - //^^^ -fn bar() { - match 0 { - $0foo!() => {} - } -} -"#, - ); - } - - #[test] - fn goto_def_for_use_alias() { - check( - r#" -//- /lib.rs crate:main deps:foo -use foo as bar$0; - -//- /foo/lib.rs crate:foo -// empty -//^file -"#, - ); - } - - #[test] - fn goto_def_for_use_alias_foo_macro() { - check( - r#" -//- /lib.rs crate:main deps:foo -use foo::foo as bar$0; - -//- /foo/lib.rs crate:foo -#[macro_export] -macro_rules! foo { () => { () } } - //^^^ -"#, - ); - } - - #[test] - fn goto_def_for_methods() { - check( - r#" -struct Foo; -impl Foo { - fn frobnicate(&self) { } - //^^^^^^^^^^ -} - -fn bar(foo: &Foo) { - foo.frobnicate$0(); -} -"#, - ); - } - - #[test] - fn goto_def_for_fields() { - check( - r#" -struct Foo { - spam: u32, -} //^^^^ - -fn bar(foo: &Foo) { - foo.spam$0; -} -"#, - ); - } - - #[test] - fn goto_def_for_record_fields() { - check( - r#" -//- /lib.rs -struct Foo { - spam: u32, -} //^^^^ - -fn bar() -> Foo { - Foo { - spam$0: 0, - } -} -"#, - ); - } - - #[test] - fn goto_def_for_record_pat_fields() { - check( - r#" -//- /lib.rs -struct Foo { - spam: u32, -} //^^^^ - -fn bar(foo: Foo) -> Foo { - let Foo { spam$0: _, } = foo -} -"#, - ); - } - - #[test] - fn goto_def_for_record_fields_macros() { - check( - r" -macro_rules! m { () => { 92 };} -struct Foo { spam: u32 } - //^^^^ - -fn bar() -> Foo { - Foo { spam$0: m!() } -} -", - ); - } - - #[test] - fn goto_for_tuple_fields() { - check( - r#" -struct Foo(u32); - //^^^ - -fn bar() { - let foo = Foo(0); - foo.$00; -} -"#, - ); - } - - #[test] - fn goto_def_for_ufcs_inherent_methods() { - check( - r#" -struct Foo; -impl Foo { - fn frobnicate() { } -} //^^^^^^^^^^ - -fn bar(foo: &Foo) { - Foo::frobnicate$0(); -} -"#, - ); - } - - #[test] - fn goto_def_for_ufcs_trait_methods_through_traits() { - check( - r#" -trait Foo { - fn frobnicate(); -} //^^^^^^^^^^ - -fn bar() { - Foo::frobnicate$0(); -} -"#, - ); - } - - #[test] - fn goto_def_for_ufcs_trait_methods_through_self() { - check( - r#" -struct Foo; -trait Trait { - fn frobnicate(); -} //^^^^^^^^^^ -impl Trait for Foo {} - -fn bar() { - Foo::frobnicate$0(); -} -"#, - ); - } - - #[test] - fn goto_definition_on_self() { - check( - r#" -struct Foo; -impl Foo { - //^^^ - pub fn new() -> Self { - Self$0 {} - } -} -"#, - ); - check( - r#" -struct Foo; -impl Foo { - //^^^ - pub fn new() -> Self$0 { - Self {} - } -} -"#, - ); - - check( - r#" -enum Foo { A } -impl Foo { - //^^^ - pub fn new() -> Self$0 { - Foo::A - } -} -"#, - ); - - check( - r#" -enum Foo { A } -impl Foo { - //^^^ - pub fn thing(a: &Self$0) { - } -} -"#, - ); - } - - #[test] - fn goto_definition_on_self_in_trait_impl() { - check( - r#" -struct Foo; -trait Make { - fn new() -> Self; -} -impl Make for Foo { - //^^^ - fn new() -> Self { - Self$0 {} - } -} -"#, - ); - - check( - r#" -struct Foo; -trait Make { - fn new() -> Self; -} -impl Make for Foo { - //^^^ - fn new() -> Self$0 { - Self {} - } -} -"#, - ); - } - - #[test] - fn goto_def_when_used_on_definition_name_itself() { - check( - r#" -struct Foo$0 { value: u32 } - //^^^ - "#, - ); - - check( - r#" -struct Foo { - field$0: string, -} //^^^^^ -"#, - ); - - check( - r#" -fn foo_test$0() { } - //^^^^^^^^ -"#, - ); - - check( - r#" -enum Foo$0 { Variant } - //^^^ -"#, - ); - - check( - r#" -enum Foo { - Variant1, - Variant2$0, - //^^^^^^^^ - Variant3, -} -"#, - ); - - check( - r#" -static INNER$0: &str = ""; - //^^^^^ -"#, - ); - - check( - r#" -const INNER$0: &str = ""; - //^^^^^ -"#, - ); - - check( - r#" -type Thing$0 = Option<()>; - //^^^^^ -"#, - ); - - check( - r#" -trait Foo$0 { } - //^^^ -"#, - ); - - check( - r#" -mod bar$0 { } - //^^^ -"#, - ); - } - - #[test] - fn goto_from_macro() { - check( - r#" -macro_rules! id { - ($($tt:tt)*) => { $($tt)* } -} -fn foo() {} - //^^^ -id! { - fn bar() { - fo$0o(); - } -} -mod confuse_index { fn foo(); } -"#, - ); - } - - #[test] - fn goto_through_format() { - check( - r#" -#[macro_export] -macro_rules! format { - ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*))) -} -#[rustc_builtin_macro] -#[macro_export] -macro_rules! format_args { - ($fmt:expr) => ({ /* compiler built-in */ }); - ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) -} -pub mod __export { - pub use crate::format_args; - fn foo() {} // for index confusion -} -fn foo() -> i8 {} - //^^^ -fn test() { - format!("{}", fo$0o()) -} -"#, - ); - } - - #[test] - fn goto_through_included_file() { - check( - r#" -//- /main.rs -#[rustc_builtin_macro] -macro_rules! include {} - - include!("foo.rs"); -//^^^^^^^^^^^^^^^^^^^ - -fn f() { - foo$0(); -} - -mod confuse_index { - pub fn foo() {} -} - -//- /foo.rs -fn foo() {} - "#, - ); - } - - #[test] - fn goto_for_type_param() { - check( - r#" -struct Foo { t: $0T } - //^ -"#, - ); - } - - #[test] - fn goto_within_macro() { - check( - r#" -macro_rules! id { - ($($tt:tt)*) => ($($tt)*) -} - -fn foo() { - let x = 1; - //^ - id!({ - let y = $0x; - let z = y; - }); -} -"#, - ); - - check( - r#" -macro_rules! id { - ($($tt:tt)*) => ($($tt)*) -} - -fn foo() { - let x = 1; - id!({ - let y = x; - //^ - let z = $0y; - }); -} -"#, - ); - } - - #[test] - fn goto_def_in_local_fn() { - check( - r#" -fn main() { - fn foo() { - let x = 92; - //^ - $0x; - } -} -"#, - ); - } - - #[test] - fn goto_def_in_local_macro() { - check( - r#" -fn bar() { - macro_rules! foo { () => { () } } - //^^^ - $0foo!(); -} -"#, - ); - } - - #[test] - fn goto_def_for_field_init_shorthand() { - check( - r#" -struct Foo { x: i32 } - //^ -fn main() { - let x = 92; - //^ - Foo { x$0 }; -} -"#, - ) - } - - #[test] - fn goto_def_for_enum_variant_field() { - check( - r#" -enum Foo { - Bar { x: i32 } - //^ -} -fn baz(foo: Foo) { - match foo { - Foo::Bar { x$0 } => x - //^ - }; -} -"#, - ); - } - - #[test] - fn goto_def_for_enum_variant_self_pattern_const() { - check( - r#" -enum Foo { Bar } - //^^^ -impl Foo { - fn baz(self) { - match self { Self::Bar$0 => {} } - } -} -"#, - ); - } - - #[test] - fn goto_def_for_enum_variant_self_pattern_record() { - check( - r#" -enum Foo { Bar { val: i32 } } - //^^^ -impl Foo { - fn baz(self) -> i32 { - match self { Self::Bar$0 { val } => {} } - } -} -"#, - ); - } - - #[test] - fn goto_def_for_enum_variant_self_expr_const() { - check( - r#" -enum Foo { Bar } - //^^^ -impl Foo { - fn baz(self) { Self::Bar$0; } -} -"#, - ); - } - - #[test] - fn goto_def_for_enum_variant_self_expr_record() { - check( - r#" -enum Foo { Bar { val: i32 } } - //^^^ -impl Foo { - fn baz(self) { Self::Bar$0 {val: 4}; } -} -"#, - ); - } - - #[test] - fn goto_def_for_type_alias_generic_parameter() { - check( - r#" -type Alias = T$0; - //^ -"#, - ) - } - - #[test] - fn goto_def_for_macro_container() { - check( - r#" -//- /lib.rs crate:main deps:foo -foo::module$0::mac!(); - -//- /foo/lib.rs crate:foo -pub mod module { - //^^^^^^ - #[macro_export] - macro_rules! _mac { () => { () } } - pub use crate::_mac as mac; -} -"#, - ); - } - - #[test] - fn goto_def_for_assoc_ty_in_path() { - check( - r#" -trait Iterator { - type Item; - //^^^^ -} - -fn f() -> impl Iterator {} -"#, - ); - } - - #[test] - fn goto_def_for_super_assoc_ty_in_path() { - check( - r#" -trait Super { - type Item; - //^^^^ -} - -trait Sub: Super {} - -fn f() -> impl Sub {} -"#, - ); - } - - #[test] - fn unknown_assoc_ty() { - check_unresolved( - r#" -trait Iterator { type Item; } -fn f() -> impl Iterator {} -"#, - ) - } - - #[test] - fn goto_def_for_assoc_ty_in_path_multiple() { - check( - r#" -trait Iterator { - type A; - //^ - type B; -} - -fn f() -> impl Iterator {} -"#, - ); - check( - r#" -trait Iterator { - type A; - type B; - //^ -} - -fn f() -> impl Iterator {} -"#, - ); - } - - #[test] - fn goto_def_for_assoc_ty_ufcs() { - check( - r#" -trait Iterator { - type Item; - //^^^^ -} - -fn g() -> <() as Iterator>::Item {} -"#, - ); - } - - #[test] - fn goto_def_for_assoc_ty_ufcs_multiple() { - check( - r#" -trait Iterator { - type A; - //^ - type B; -} - -fn g() -> <() as Iterator>::B {} -"#, - ); - check( - r#" -trait Iterator { - type A; - type B; - //^ -} - -fn g() -> <() as Iterator>::A {} -"#, - ); - } - - #[test] - fn goto_self_param_ty_specified() { - check( - r#" -struct Foo {} - -impl Foo { - fn bar(self: &Foo) { - //^^^^ - let foo = sel$0f; - } -}"#, - ) - } - - #[test] - fn goto_self_param_on_decl() { - check( - r#" -struct Foo {} - -impl Foo { - fn bar(&self$0) { - //^^^^ - } -}"#, - ) - } - - #[test] - fn goto_lifetime_param_on_decl() { - check( - r#" -fn foo<'foobar$0>(_: &'foobar ()) { - //^^^^^^^ -}"#, - ) - } - - #[test] - fn goto_lifetime_param_decl() { - check( - r#" -fn foo<'foobar>(_: &'foobar$0 ()) { - //^^^^^^^ -}"#, - ) - } - - #[test] - fn goto_lifetime_param_decl_nested() { - check( - r#" -fn foo<'foobar>(_: &'foobar ()) { - fn foo<'foobar>(_: &'foobar$0 ()) {} - //^^^^^^^ -}"#, - ) - } - - #[test] - fn goto_lifetime_hrtb() { - // FIXME: requires the HIR to somehow track these hrtb lifetimes - check_unresolved( - r#" -trait Foo {} -fn foo() where for<'a> T: Foo<&'a$0 (u8, u16)>, {} - //^^ -"#, - ); - check_unresolved( - r#" -trait Foo {} -fn foo() where for<'a$0> T: Foo<&'a (u8, u16)>, {} - //^^ -"#, - ); - } - - #[test] - fn goto_lifetime_hrtb_for_type() { - // FIXME: requires ForTypes to be implemented - check_unresolved( - r#"trait Foo {} -fn foo() where T: for<'a> Foo<&'a$0 (u8, u16)>, {} - //^^ -"#, - ); - } - - #[test] - fn goto_label() { - check( - r#" -fn foo<'foo>(_: &'foo ()) { - 'foo: { - //^^^^ - 'bar: loop { - break 'foo$0; - } - } -}"#, - ) - } - - #[test] - fn goto_def_for_intra_doc_link_same_file() { - check( - r#" -/// Blah, [`bar`](bar) .. [`foo`](foo$0) has [`bar`](bar) -pub fn bar() { } - -/// You might want to see [`std::fs::read()`] too. -pub fn foo() { } - //^^^ - -}"#, - ) - } - - #[test] - fn goto_def_for_intra_doc_link_inner() { - check( - r#" -//- /main.rs -mod m; -struct S; - //^ - -//- /m.rs -//! [`super::S$0`] -"#, - ) - } - - #[test] - fn goto_incomplete_field() { - check( - r#" -struct A { a: u32 } - //^ -fn foo() { A { a$0: }; } -"#, - ) - } - - #[test] - fn goto_proc_macro() { - check( - r#" -//- /main.rs crate:main deps:mac -use mac::fn_macro; - -fn_macro$0!(); - -//- /mac.rs crate:mac -#![crate_type="proc-macro"] -#[proc_macro] -fn fn_macro() {} - //^^^^^^^^ - "#, - ) - } - - #[test] - fn goto_intra_doc_links() { - check( - r#" - -pub mod theitem { - /// This is the item. Cool! - pub struct TheItem; - //^^^^^^^ -} - -/// Gives you a [`TheItem$0`]. -/// -/// [`TheItem`]: theitem::TheItem -pub fn gimme() -> theitem::TheItem { - theitem::TheItem -} -"#, - ); - } - - #[test] - fn goto_ident_from_pat_macro() { - check( - r#" -macro_rules! pat { - ($name:ident) => { Enum::Variant1($name) } -} - -enum Enum { - Variant1(u8), - Variant2, -} - -fn f(e: Enum) { - match e { - pat!(bind) => { - //^^^^ - bind$0 - } - Enum::Variant2 => {} - } -} -"#, - ); - } - - #[test] - fn goto_include() { - check( - r#" -//- /main.rs -fn main() { - let str = include_str!("foo.txt$0"); -} -//- /foo.txt -// empty -//^file -"#, - ); - } - #[cfg(test)] - mod goto_impl_of_trait_fn { - use super::check; - #[test] - fn cursor_on_impl() { - check( - r#" -trait Twait { - fn a(); -} - -struct Stwuct; - -impl Twait for Stwuct { - fn a$0(); - //^ -} - "#, - ); - } - #[test] - fn method_call() { - check( - r#" -trait Twait { - fn a(&self); -} - -struct Stwuct; - -impl Twait for Stwuct { - fn a(&self){}; - //^ -} -fn f() { - let s = Stwuct; - s.a$0(); -} - "#, - ); - } - #[test] - fn path_call() { - check( - r#" -trait Twait { - fn a(&self); -} - -struct Stwuct; - -impl Twait for Stwuct { - fn a(&self){}; - //^ -} -fn f() { - let s = Stwuct; - Stwuct::a$0(&s); -} - "#, - ); - } - #[test] - fn where_clause_can_work() { - check( - r#" -trait G { - fn g(&self); -} -trait Bound{} -trait EA{} -struct Gen(T); -impl G for Gen { - fn g(&self) { - } -} -impl G for Gen -where T : Bound -{ - fn g(&self){ - //^ - } -} -struct A; -impl Bound for A{} -fn f() { - let gen = Gen::(A); - gen.g$0(); -} - "#, - ); - } - #[test] - fn wc_case_is_ok() { - check( - r#" -trait G { - fn g(&self); -} -trait BParent{} -trait Bound: BParent{} -struct Gen(T); -impl G for Gen -where T : Bound -{ - fn g(&self){ - //^ - } -} -struct A; -impl Bound for A{} -fn f() { - let gen = Gen::(A); - gen.g$0(); -} -"#, - ); - } - - #[test] - fn method_call_defaulted() { - check( - r#" -trait Twait { - fn a(&self) {} - //^ -} - -struct Stwuct; - -impl Twait for Stwuct { -} -fn f() { - let s = Stwuct; - s.a$0(); -} - "#, - ); - } - - #[test] - fn method_call_on_generic() { - check( - r#" -trait Twait { - fn a(&self) {} - //^ -} - -fn f(s: T) { - s.a$0(); -} - "#, - ); - } - } - - #[test] - fn goto_def_of_trait_impl_const() { - check( - r#" -trait Twait { - const NOMS: bool; - // ^^^^ -} - -struct Stwuct; - -impl Twait for Stwuct { - const NOMS$0: bool = true; -} -"#, - ); - } - - #[test] - fn goto_def_of_trait_impl_type_alias() { - check( - r#" -trait Twait { - type IsBad; - // ^^^^^ -} - -struct Stwuct; - -impl Twait for Stwuct { - type IsBad$0 = !; -} -"#, - ); - } - - #[test] - fn goto_def_derive_input() { - check( - r#" - //- minicore:derive - #[rustc_builtin_macro] - pub macro Copy {} - // ^^^^ - #[derive(Copy$0)] - struct Foo; - "#, - ); - check( - r#" -//- minicore:derive -#[rustc_builtin_macro] -pub macro Copy {} - // ^^^^ -#[cfg_attr(feature = "false", derive)] -#[derive(Copy$0)] -struct Foo; - "#, - ); - check( - r#" -//- minicore:derive -mod foo { - #[rustc_builtin_macro] - pub macro Copy {} - // ^^^^ -} -#[derive(foo::Copy$0)] -struct Foo; - "#, - ); - check( - r#" -//- minicore:derive -mod foo { - // ^^^ - #[rustc_builtin_macro] - pub macro Copy {} -} -#[derive(foo$0::Copy)] -struct Foo; - "#, - ); - } - - #[test] - fn goto_def_in_macro_multi() { - check( - r#" -struct Foo { - foo: () - //^^^ -} -macro_rules! foo { - ($ident:ident) => { - fn $ident(Foo { $ident }: Foo) {} - } -} -foo!(foo$0); - //^^^ - //^^^ -"#, - ); - check( - r#" -fn bar() {} - //^^^ -struct bar; - //^^^ -macro_rules! foo { - ($ident:ident) => { - fn foo() { - let _: $ident = $ident; - } - } -} - -foo!(bar$0); -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs deleted file mode 100644 index 04b51c839407b..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs +++ /dev/null @@ -1,344 +0,0 @@ -use hir::{AsAssocItem, Impl, Semantics}; -use ide_db::{ - defs::{Definition, NameClass, NameRefClass}, - helpers::pick_best_token, - RootDatabase, -}; -use itertools::Itertools; -use syntax::{ast, AstNode, SyntaxKind::*, T}; - -use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav}; - -// Feature: Go to Implementation -// -// Navigates to the impl blocks of types. -// -// |=== -// | Editor | Shortcut -// -// | VS Code | kbd:[Ctrl+F12] -// |=== -// -// image::https://user-images.githubusercontent.com/48062697/113065566-02f85480-91b1-11eb-9288-aaad8abd8841.gif[] -pub(crate) fn goto_implementation( - db: &RootDatabase, - position: FilePosition, -) -> Option>> { - let sema = Semantics::new(db); - let source_file = sema.parse(position.file_id); - let syntax = source_file.syntax().clone(); - - let original_token = - pick_best_token(syntax.token_at_offset(position.offset), |kind| match kind { - IDENT | T![self] => 1, - _ => 0, - })?; - let range = original_token.text_range(); - let navs = sema - .descend_into_macros(original_token) - .into_iter() - .filter_map(|token| token.parent().and_then(ast::NameLike::cast)) - .filter_map(|node| match &node { - ast::NameLike::Name(name) => { - NameClass::classify(&sema, name).map(|class| match class { - NameClass::Definition(it) | NameClass::ConstReference(it) => it, - NameClass::PatFieldShorthand { local_def, field_ref: _ } => { - Definition::Local(local_def) - } - }) - } - ast::NameLike::NameRef(name_ref) => { - NameRefClass::classify(&sema, name_ref).map(|class| match class { - NameRefClass::Definition(def) => def, - NameRefClass::FieldShorthand { local_ref, field_ref: _ } => { - Definition::Local(local_ref) - } - }) - } - ast::NameLike::Lifetime(_) => None, - }) - .unique() - .filter_map(|def| { - let navs = match def { - Definition::Trait(trait_) => impls_for_trait(&sema, trait_), - Definition::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)), - Definition::TypeAlias(alias) => impls_for_ty(&sema, alias.ty(sema.db)), - Definition::BuiltinType(builtin) => impls_for_ty(&sema, builtin.ty(sema.db)), - Definition::Function(f) => { - let assoc = f.as_assoc_item(sema.db)?; - let name = assoc.name(sema.db)?; - let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?; - impls_for_trait_item(&sema, trait_, name) - } - Definition::Const(c) => { - let assoc = c.as_assoc_item(sema.db)?; - let name = assoc.name(sema.db)?; - let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?; - impls_for_trait_item(&sema, trait_, name) - } - _ => return None, - }; - Some(navs) - }) - .flatten() - .collect(); - - Some(RangeInfo { range, info: navs }) -} - -fn impls_for_ty(sema: &Semantics<'_, RootDatabase>, ty: hir::Type) -> Vec { - Impl::all_for_type(sema.db, ty).into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect() -} - -fn impls_for_trait( - sema: &Semantics<'_, RootDatabase>, - trait_: hir::Trait, -) -> Vec { - Impl::all_for_trait(sema.db, trait_) - .into_iter() - .filter_map(|imp| imp.try_to_nav(sema.db)) - .collect() -} - -fn impls_for_trait_item( - sema: &Semantics<'_, RootDatabase>, - trait_: hir::Trait, - fun_name: hir::Name, -) -> Vec { - Impl::all_for_trait(sema.db, trait_) - .into_iter() - .filter_map(|imp| { - let item = imp.items(sema.db).iter().find_map(|itm| { - let itm_name = itm.name(sema.db)?; - (itm_name == fun_name).then(|| *itm) - })?; - item.try_to_nav(sema.db) - }) - .collect() -} - -#[cfg(test)] -mod tests { - use ide_db::base_db::FileRange; - use itertools::Itertools; - - use crate::fixture; - - fn check(ra_fixture: &str) { - let (analysis, position, expected) = fixture::annotations(ra_fixture); - - let navs = analysis.goto_implementation(position).unwrap().unwrap().info; - - let cmp = |frange: &FileRange| (frange.file_id, frange.range.start()); - - let actual = navs - .into_iter() - .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) - .sorted_by_key(cmp) - .collect::>(); - let expected = - expected.into_iter().map(|(range, _)| range).sorted_by_key(cmp).collect::>(); - assert_eq!(expected, actual); - } - - #[test] - fn goto_implementation_works() { - check( - r#" -struct Foo$0; -impl Foo {} - //^^^ -"#, - ); - } - - #[test] - fn goto_implementation_works_multiple_blocks() { - check( - r#" -struct Foo$0; -impl Foo {} - //^^^ -impl Foo {} - //^^^ -"#, - ); - } - - #[test] - fn goto_implementation_works_multiple_mods() { - check( - r#" -struct Foo$0; -mod a { - impl super::Foo {} - //^^^^^^^^^^ -} -mod b { - impl super::Foo {} - //^^^^^^^^^^ -} -"#, - ); - } - - #[test] - fn goto_implementation_works_multiple_files() { - check( - r#" -//- /lib.rs -struct Foo$0; -mod a; -mod b; -//- /a.rs -impl crate::Foo {} - //^^^^^^^^^^ -//- /b.rs -impl crate::Foo {} - //^^^^^^^^^^ -"#, - ); - } - - #[test] - fn goto_implementation_for_trait() { - check( - r#" -trait T$0 {} -struct Foo; -impl T for Foo {} - //^^^ -"#, - ); - } - - #[test] - fn goto_implementation_for_trait_multiple_files() { - check( - r#" -//- /lib.rs -trait T$0 {}; -struct Foo; -mod a; -mod b; -//- /a.rs -impl crate::T for crate::Foo {} - //^^^^^^^^^^ -//- /b.rs -impl crate::T for crate::Foo {} - //^^^^^^^^^^ - "#, - ); - } - - #[test] - fn goto_implementation_all_impls() { - check( - r#" -//- /lib.rs -trait T {} -struct Foo$0; -impl Foo {} - //^^^ -impl T for Foo {} - //^^^ -impl T for &Foo {} - //^^^^ -"#, - ); - } - - #[test] - fn goto_implementation_to_builtin_derive() { - check( - r#" -//- minicore: copy, derive - #[derive(Copy)] -//^^^^^^^^^^^^^^^ -struct Foo$0; -"#, - ); - } - - #[test] - fn goto_implementation_type_alias() { - check( - r#" -struct Foo; - -type Bar$0 = Foo; - -impl Foo {} - //^^^ -impl Bar {} - //^^^ -"#, - ); - } - - #[test] - fn goto_implementation_adt_generic() { - check( - r#" -struct Foo$0; - -impl Foo {} - //^^^^^^ -impl Foo {} - //^^^^^^^^ -"#, - ); - } - - #[test] - fn goto_implementation_builtin() { - check( - r#" -//- /lib.rs crate:main deps:core -fn foo(_: bool$0) {{}} -//- /libcore.rs crate:core -#[lang = "bool"] -impl bool {} - //^^^^ -"#, - ); - } - - #[test] - fn goto_implementation_trait_functions() { - check( - r#" -trait Tr { - fn f$0(); -} - -struct S; - -impl Tr for S { - fn f() { - //^ - println!("Hello, world!"); - } -} -"#, - ); - } - - #[test] - fn goto_implementation_trait_assoc_const() { - check( - r#" -trait Tr { - const C$0: usize; -} - -struct S; - -impl Tr for S { - const C: usize = 4; - //^ -} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs deleted file mode 100644 index 55cdb3200eac9..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs +++ /dev/null @@ -1,296 +0,0 @@ -use ide_db::{base_db::Upcast, defs::Definition, helpers::pick_best_token, RootDatabase}; -use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, T}; - -use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav}; - -// Feature: Go to Type Definition -// -// Navigates to the type of an identifier. -// -// |=== -// | Editor | Action Name -// -// | VS Code | **Go to Type Definition* -// |=== -// -// image::https://user-images.githubusercontent.com/48062697/113020657-b560f500-917a-11eb-9007-0f809733a338.gif[] -pub(crate) fn goto_type_definition( - db: &RootDatabase, - position: FilePosition, -) -> Option>> { - let sema = hir::Semantics::new(db); - - let file: ast::SourceFile = sema.parse(position.file_id); - let token: SyntaxToken = - pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind { - IDENT | INT_NUMBER | T![self] => 2, - kind if kind.is_trivia() => 0, - _ => 1, - })?; - - let mut res = Vec::new(); - let mut push = |def: Definition| { - if let Some(nav) = def.try_to_nav(db) { - if !res.contains(&nav) { - res.push(nav); - } - } - }; - let range = token.text_range(); - sema.descend_into_macros(token) - .iter() - .filter_map(|token| { - let ty = sema.token_ancestors_with_macros(token.clone()).find_map(|node| { - let ty = match_ast! { - match node { - ast::Expr(it) => sema.type_of_expr(&it)?.original, - ast::Pat(it) => sema.type_of_pat(&it)?.original, - ast::SelfParam(it) => sema.type_of_self(&it)?, - ast::Type(it) => sema.resolve_type(&it)?, - ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?, - // can't match on RecordExprField directly as `ast::Expr` will match an iteration too early otherwise - ast::NameRef(it) => { - if let Some(record_field) = ast::RecordExprField::for_name_ref(&it) { - let (_, _, ty) = sema.resolve_record_field(&record_field)?; - ty - } else { - let record_field = ast::RecordPatField::for_field_name_ref(&it)?; - sema.resolve_record_pat_field(&record_field)?.ty(db) - } - }, - _ => return None, - } - }; - - Some(ty) - }); - ty - }) - .for_each(|ty| { - // collect from each `ty` into the `res` result vec - let ty = ty.strip_references(); - ty.walk(db, |t| { - if let Some(adt) = t.as_adt() { - push(adt.into()); - } else if let Some(trait_) = t.as_dyn_trait() { - push(trait_.into()); - } else if let Some(traits) = t.as_impl_traits(db) { - traits.for_each(|it| push(it.into())); - } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { - push(trait_.into()); - } - }); - }); - Some(RangeInfo::new(range, res)) -} - -#[cfg(test)] -mod tests { - use ide_db::base_db::FileRange; - use itertools::Itertools; - - use crate::fixture; - - fn check(ra_fixture: &str) { - let (analysis, position, expected) = fixture::annotations(ra_fixture); - let navs = analysis.goto_type_definition(position).unwrap().unwrap().info; - assert_ne!(navs.len(), 0); - - let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start()); - let navs = navs - .into_iter() - .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) - .sorted_by_key(cmp) - .collect::>(); - let expected = expected - .into_iter() - .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range }) - .sorted_by_key(cmp) - .collect::>(); - assert_eq!(expected, navs); - } - - #[test] - fn goto_type_definition_works_simple() { - check( - r#" -struct Foo; - //^^^ -fn foo() { - let f: Foo; f$0 -} -"#, - ); - } - - #[test] - fn goto_type_definition_record_expr_field() { - check( - r#" -struct Bar; - // ^^^ -struct Foo { foo: Bar } -fn foo() { - Foo { foo$0 } -} -"#, - ); - check( - r#" -struct Bar; - // ^^^ -struct Foo { foo: Bar } -fn foo() { - Foo { foo$0: Bar } -} -"#, - ); - } - - #[test] - fn goto_type_definition_record_pat_field() { - check( - r#" -struct Bar; - // ^^^ -struct Foo { foo: Bar } -fn foo() { - let Foo { foo$0 }; -} -"#, - ); - check( - r#" -struct Bar; - // ^^^ -struct Foo { foo: Bar } -fn foo() { - let Foo { foo$0: bar }; -} -"#, - ); - } - - #[test] - fn goto_type_definition_works_simple_ref() { - check( - r#" -struct Foo; - //^^^ -fn foo() { - let f: &Foo; f$0 -} -"#, - ); - } - - #[test] - fn goto_type_definition_works_through_macro() { - check( - r#" -macro_rules! id { ($($tt:tt)*) => { $($tt)* } } -struct Foo {} - //^^^ -id! { - fn bar() { let f$0 = Foo {}; } -} -"#, - ); - } - - #[test] - fn goto_type_definition_for_param() { - check( - r#" -struct Foo; - //^^^ -fn foo($0f: Foo) {} -"#, - ); - } - - #[test] - fn goto_type_definition_for_tuple_field() { - check( - r#" -struct Foo; - //^^^ -struct Bar(Foo); -fn foo() { - let bar = Bar(Foo); - bar.$00; -} -"#, - ); - } - - #[test] - fn goto_def_for_self_param() { - check( - r#" -struct Foo; - //^^^ -impl Foo { - fn f(&self$0) {} -} -"#, - ) - } - - #[test] - fn goto_def_for_type_fallback() { - check( - r#" -struct Foo; - //^^^ -impl Foo$0 {} -"#, - ) - } - - #[test] - fn goto_def_for_struct_field() { - check( - r#" -struct Bar; - //^^^ - -struct Foo { - bar$0: Bar, -} -"#, - ); - } - - #[test] - fn goto_def_for_enum_struct_field() { - check( - r#" -struct Bar; - //^^^ - -enum Foo { - Bar { - bar$0: Bar - }, -} -"#, - ); - } - - #[test] - fn goto_def_considers_generics() { - check( - r#" -struct Foo; - //^^^ -struct Bar(T, U); - //^^^ -struct Baz(T); - //^^^ - -fn foo(x$0: Bar, Baz) {} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs deleted file mode 100644 index f2d7029eab195..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ /dev/null @@ -1,1377 +0,0 @@ -use hir::Semantics; -use ide_db::{ - base_db::{FileId, FilePosition}, - defs::{Definition, IdentClass}, - helpers::pick_best_token, - search::{FileReference, ReferenceCategory, SearchScope}, - syntax_helpers::node_ext::{for_each_break_and_continue_expr, for_each_tail_expr, walk_expr}, - FxHashSet, RootDatabase, -}; -use syntax::{ - ast::{self, HasLoopBody}, - match_ast, AstNode, - SyntaxKind::{self, IDENT, INT_NUMBER}, - SyntaxNode, SyntaxToken, TextRange, T, -}; - -use crate::{references, NavigationTarget, TryToNav}; - -#[derive(PartialEq, Eq, Hash)] -pub struct HighlightedRange { - pub range: TextRange, - // FIXME: This needs to be more precise. Reference category makes sense only - // for references, but we also have defs. And things like exit points are - // neither. - pub category: Option, -} - -#[derive(Default, Clone)] -pub struct HighlightRelatedConfig { - pub references: bool, - pub exit_points: bool, - pub break_points: bool, - pub yield_points: bool, -} - -// Feature: Highlight Related -// -// Highlights constructs related to the thing under the cursor: -// -// . if on an identifier, highlights all references to that identifier in the current file -// . if on an `async` or `await token, highlights all yield points for that async context -// . if on a `return` or `fn` keyword, `?` character or `->` return type arrow, highlights all exit points for that context -// . if on a `break`, `loop`, `while` or `for` token, highlights all break points for that loop or block context -// -// Note: `?` and `->` do not currently trigger this behavior in the VSCode editor. -pub(crate) fn highlight_related( - sema: &Semantics<'_, RootDatabase>, - config: HighlightRelatedConfig, - FilePosition { offset, file_id }: FilePosition, -) -> Option> { - let _p = profile::span("highlight_related"); - let syntax = sema.parse(file_id).syntax().clone(); - - let token = pick_best_token(syntax.token_at_offset(offset), |kind| match kind { - T![?] => 4, // prefer `?` when the cursor is sandwiched like in `await$0?` - T![->] => 3, - kind if kind.is_keyword() => 2, - IDENT | INT_NUMBER => 1, - _ => 0, - })?; - match token.kind() { - T![?] if config.exit_points && token.parent().and_then(ast::TryExpr::cast).is_some() => { - highlight_exit_points(sema, token) - } - T![fn] | T![return] | T![->] if config.exit_points => highlight_exit_points(sema, token), - T![await] | T![async] if config.yield_points => highlight_yield_points(token), - T![for] if config.break_points && token.parent().and_then(ast::ForExpr::cast).is_some() => { - highlight_break_points(token) - } - T![break] | T![loop] | T![while] | T![continue] if config.break_points => { - highlight_break_points(token) - } - _ if config.references => highlight_references(sema, &syntax, token, file_id), - _ => None, - } -} - -fn highlight_references( - sema: &Semantics<'_, RootDatabase>, - node: &SyntaxNode, - token: SyntaxToken, - file_id: FileId, -) -> Option> { - let defs = find_defs(sema, token); - let usages = defs - .iter() - .filter_map(|&d| { - d.usages(sema) - .set_scope(Some(SearchScope::single_file(file_id))) - .include_self_refs() - .all() - .references - .remove(&file_id) - }) - .flatten() - .map(|FileReference { category: access, range, .. }| HighlightedRange { - range, - category: access, - }); - let mut res = FxHashSet::default(); - - let mut def_to_hl_range = |def| { - let hl_range = match def { - Definition::Module(module) => { - Some(NavigationTarget::from_module_to_decl(sema.db, module)) - } - def => def.try_to_nav(sema.db), - } - .filter(|decl| decl.file_id == file_id) - .and_then(|decl| decl.focus_range) - .map(|range| { - let category = - references::decl_mutability(&def, node, range).then(|| ReferenceCategory::Write); - HighlightedRange { range, category } - }); - if let Some(hl_range) = hl_range { - res.insert(hl_range); - } - }; - for &def in &defs { - match def { - Definition::Local(local) => local - .associated_locals(sema.db) - .iter() - .for_each(|&local| def_to_hl_range(Definition::Local(local))), - def => def_to_hl_range(def), - } - } - - res.extend(usages); - if res.is_empty() { - None - } else { - Some(res.into_iter().collect()) - } -} - -fn highlight_exit_points( - sema: &Semantics<'_, RootDatabase>, - token: SyntaxToken, -) -> Option> { - fn hl( - sema: &Semantics<'_, RootDatabase>, - body: Option, - ) -> Option> { - let mut highlights = Vec::new(); - let body = body?; - walk_expr(&body, &mut |expr| match expr { - ast::Expr::ReturnExpr(expr) => { - if let Some(token) = expr.return_token() { - highlights.push(HighlightedRange { category: None, range: token.text_range() }); - } - } - ast::Expr::TryExpr(try_) => { - if let Some(token) = try_.question_mark_token() { - highlights.push(HighlightedRange { category: None, range: token.text_range() }); - } - } - ast::Expr::MethodCallExpr(_) | ast::Expr::CallExpr(_) | ast::Expr::MacroExpr(_) => { - if sema.type_of_expr(&expr).map_or(false, |ty| ty.original.is_never()) { - highlights.push(HighlightedRange { - category: None, - range: expr.syntax().text_range(), - }); - } - } - _ => (), - }); - let tail = match body { - ast::Expr::BlockExpr(b) => b.tail_expr(), - e => Some(e), - }; - - if let Some(tail) = tail { - for_each_tail_expr(&tail, &mut |tail| { - let range = match tail { - ast::Expr::BreakExpr(b) => b - .break_token() - .map_or_else(|| tail.syntax().text_range(), |tok| tok.text_range()), - _ => tail.syntax().text_range(), - }; - highlights.push(HighlightedRange { category: None, range }) - }); - } - Some(highlights) - } - for anc in token.parent_ancestors() { - return match_ast! { - match anc { - ast::Fn(fn_) => hl(sema, fn_.body().map(ast::Expr::BlockExpr)), - ast::ClosureExpr(closure) => hl(sema, closure.body()), - ast::BlockExpr(block_expr) => if matches!(block_expr.modifier(), Some(ast::BlockModifier::Async(_) | ast::BlockModifier::Try(_)| ast::BlockModifier::Const(_))) { - hl(sema, Some(block_expr.into())) - } else { - continue; - }, - _ => continue, - } - }; - } - None -} - -fn highlight_break_points(token: SyntaxToken) -> Option> { - fn hl( - cursor_token_kind: SyntaxKind, - token: Option, - label: Option, - body: Option, - ) -> Option> { - let mut highlights = Vec::new(); - let range = cover_range( - token.map(|tok| tok.text_range()), - label.as_ref().map(|it| it.syntax().text_range()), - ); - highlights.extend(range.map(|range| HighlightedRange { category: None, range })); - for_each_break_and_continue_expr(label, body, &mut |expr| { - let range: Option = match (cursor_token_kind, expr) { - (T![for] | T![while] | T![loop] | T![break], ast::Expr::BreakExpr(break_)) => { - cover_range( - break_.break_token().map(|it| it.text_range()), - break_.lifetime().map(|it| it.syntax().text_range()), - ) - } - ( - T![for] | T![while] | T![loop] | T![continue], - ast::Expr::ContinueExpr(continue_), - ) => cover_range( - continue_.continue_token().map(|it| it.text_range()), - continue_.lifetime().map(|it| it.syntax().text_range()), - ), - _ => None, - }; - highlights.extend(range.map(|range| HighlightedRange { category: None, range })); - }); - Some(highlights) - } - let parent = token.parent()?; - let lbl = match_ast! { - match parent { - ast::BreakExpr(b) => b.lifetime(), - ast::ContinueExpr(c) => c.lifetime(), - ast::LoopExpr(l) => l.label().and_then(|it| it.lifetime()), - ast::ForExpr(f) => f.label().and_then(|it| it.lifetime()), - ast::WhileExpr(w) => w.label().and_then(|it| it.lifetime()), - ast::BlockExpr(b) => Some(b.label().and_then(|it| it.lifetime())?), - _ => return None, - } - }; - let lbl = lbl.as_ref(); - let label_matches = |def_lbl: Option| match lbl { - Some(lbl) => { - Some(lbl.text()) == def_lbl.and_then(|it| it.lifetime()).as_ref().map(|it| it.text()) - } - None => true, - }; - let token_kind = token.kind(); - for anc in token.parent_ancestors().flat_map(ast::Expr::cast) { - return match anc { - ast::Expr::LoopExpr(l) if label_matches(l.label()) => hl( - token_kind, - l.loop_token(), - l.label(), - l.loop_body().and_then(|it| it.stmt_list()), - ), - ast::Expr::ForExpr(f) if label_matches(f.label()) => hl( - token_kind, - f.for_token(), - f.label(), - f.loop_body().and_then(|it| it.stmt_list()), - ), - ast::Expr::WhileExpr(w) if label_matches(w.label()) => hl( - token_kind, - w.while_token(), - w.label(), - w.loop_body().and_then(|it| it.stmt_list()), - ), - ast::Expr::BlockExpr(e) if e.label().is_some() && label_matches(e.label()) => { - hl(token_kind, None, e.label(), e.stmt_list()) - } - _ => continue, - }; - } - None -} - -fn highlight_yield_points(token: SyntaxToken) -> Option> { - fn hl( - async_token: Option, - body: Option, - ) -> Option> { - let mut highlights = - vec![HighlightedRange { category: None, range: async_token?.text_range() }]; - if let Some(body) = body { - walk_expr(&body, &mut |expr| { - if let ast::Expr::AwaitExpr(expr) = expr { - if let Some(token) = expr.await_token() { - highlights - .push(HighlightedRange { category: None, range: token.text_range() }); - } - } - }); - } - Some(highlights) - } - for anc in token.parent_ancestors() { - return match_ast! { - match anc { - ast::Fn(fn_) => hl(fn_.async_token(), fn_.body().map(ast::Expr::BlockExpr)), - ast::BlockExpr(block_expr) => { - if block_expr.async_token().is_none() { - continue; - } - hl(block_expr.async_token(), Some(block_expr.into())) - }, - ast::ClosureExpr(closure) => hl(closure.async_token(), closure.body()), - _ => continue, - } - }; - } - None -} - -fn cover_range(r0: Option, r1: Option) -> Option { - match (r0, r1) { - (Some(r0), Some(r1)) => Some(r0.cover(r1)), - (Some(range), None) => Some(range), - (None, Some(range)) => Some(range), - (None, None) => None, - } -} - -fn find_defs(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> FxHashSet { - sema.descend_into_macros(token) - .into_iter() - .filter_map(|token| IdentClass::classify_token(sema, &token).map(IdentClass::definitions)) - .flatten() - .collect() -} - -#[cfg(test)] -mod tests { - use crate::fixture; - - use super::*; - - #[track_caller] - fn check(ra_fixture: &str) { - let config = HighlightRelatedConfig { - break_points: true, - exit_points: true, - references: true, - yield_points: true, - }; - - check_with_config(ra_fixture, config); - } - - #[track_caller] - fn check_with_config(ra_fixture: &str, config: HighlightRelatedConfig) { - let (analysis, pos, annotations) = fixture::annotations(ra_fixture); - - let hls = analysis.highlight_related(config, pos).unwrap().unwrap_or_default(); - - let mut expected = annotations - .into_iter() - .map(|(r, access)| (r.range, (!access.is_empty()).then(|| access))) - .collect::>(); - - let mut actual = hls - .into_iter() - .map(|hl| { - ( - hl.range, - hl.category.map(|it| { - match it { - ReferenceCategory::Read => "read", - ReferenceCategory::Write => "write", - } - .to_string() - }), - ) - }) - .collect::>(); - actual.sort_by_key(|(range, _)| range.start()); - expected.sort_by_key(|(range, _)| range.start()); - - assert_eq!(expected, actual); - } - - #[test] - fn test_hl_tuple_fields() { - check( - r#" -struct Tuple(u32, u32); - -fn foo(t: Tuple) { - t.0$0; - // ^ read - t.0; - // ^ read -} -"#, - ); - } - - #[test] - fn test_hl_module() { - check( - r#" -//- /lib.rs -mod foo$0; - // ^^^ -//- /foo.rs -struct Foo; -"#, - ); - } - - #[test] - fn test_hl_self_in_crate_root() { - check( - r#" -use crate$0; - //^^^^^ -use self; - //^^^^ -mod __ { - use super; - //^^^^^ -} -"#, - ); - check( - r#" -//- /main.rs crate:main deps:lib -use lib$0; - //^^^ -//- /lib.rs crate:lib -"#, - ); - } - - #[test] - fn test_hl_self_in_module() { - check( - r#" -//- /lib.rs -mod foo; -//- /foo.rs -use self$0; - // ^^^^ -"#, - ); - } - - #[test] - fn test_hl_local() { - check( - r#" -fn foo() { - let mut bar = 3; - // ^^^ write - bar$0; - // ^^^ read -} -"#, - ); - } - - #[test] - fn test_hl_local_in_attr() { - check( - r#" -//- proc_macros: identity -#[proc_macros::identity] -fn foo() { - let mut bar = 3; - // ^^^ write - bar$0; - // ^^^ read -} -"#, - ); - } - - #[test] - fn test_multi_macro_usage() { - check( - r#" -macro_rules! foo { - ($ident:ident) => { - fn $ident() -> $ident { loop {} } - struct $ident; - } -} - -foo!(bar$0); - // ^^^ -fn foo() { - let bar: bar = bar(); - // ^^^ - // ^^^ -} -"#, - ); - check( - r#" -macro_rules! foo { - ($ident:ident) => { - fn $ident() -> $ident { loop {} } - struct $ident; - } -} - -foo!(bar); - // ^^^ -fn foo() { - let bar: bar$0 = bar(); - // ^^^ -} -"#, - ); - } - - #[test] - fn test_hl_yield_points() { - check( - r#" -pub async fn foo() { - // ^^^^^ - let x = foo() - .await$0 - // ^^^^^ - .await; - // ^^^^^ - || { 0.await }; - (async { 0.await }).await - // ^^^^^ -} -"#, - ); - } - - #[test] - fn test_hl_yield_points2() { - check( - r#" -pub async$0 fn foo() { - // ^^^^^ - let x = foo() - .await - // ^^^^^ - .await; - // ^^^^^ - || { 0.await }; - (async { 0.await }).await - // ^^^^^ -} -"#, - ); - } - - #[test] - fn test_hl_yield_nested_fn() { - check( - r#" -async fn foo() { - async fn foo2() { - // ^^^^^ - async fn foo3() { - 0.await - } - 0.await$0 - // ^^^^^ - } - 0.await -} -"#, - ); - } - - #[test] - fn test_hl_yield_nested_async_blocks() { - check( - r#" -async fn foo() { - (async { - // ^^^^^ - (async { - 0.await - }).await$0 } - // ^^^^^ - ).await; -} -"#, - ); - } - - #[test] - fn test_hl_exit_points() { - check( - r#" -fn foo() -> u32 { - if true { - return$0 0; - // ^^^^^^ - } - - 0?; - // ^ - 0xDEAD_BEEF - // ^^^^^^^^^^^ -} -"#, - ); - } - - #[test] - fn test_hl_exit_points2() { - check( - r#" -fn foo() ->$0 u32 { - if true { - return 0; - // ^^^^^^ - } - - 0?; - // ^ - 0xDEAD_BEEF - // ^^^^^^^^^^^ -} -"#, - ); - } - - #[test] - fn test_hl_exit_points3() { - check( - r#" -fn$0 foo() -> u32 { - if true { - return 0; - // ^^^^^^ - } - - 0?; - // ^ - 0xDEAD_BEEF - // ^^^^^^^^^^^ -} -"#, - ); - } - - #[test] - fn test_hl_prefer_ref_over_tail_exit() { - check( - r#" -fn foo() -> u32 { -// ^^^ - if true { - return 0; - } - - 0?; - - foo$0() - // ^^^ -} -"#, - ); - } - - #[test] - fn test_hl_never_call_is_exit_point() { - check( - r#" -struct Never; -impl Never { - fn never(self) -> ! { loop {} } -} -macro_rules! never { - () => { never() } -} -fn never() -> ! { loop {} } -fn foo() ->$0 u32 { - never(); - // ^^^^^^^ - never!(); - // ^^^^^^^^ - - Never.never(); - // ^^^^^^^^^^^^^ - - 0 - // ^ -} -"#, - ); - } - - #[test] - fn test_hl_inner_tail_exit_points() { - check( - r#" -fn foo() ->$0 u32 { - if true { - unsafe { - return 5; - // ^^^^^^ - 5 - // ^ - } - } else if false { - 0 - // ^ - } else { - match 5 { - 6 => 100, - // ^^^ - 7 => loop { - break 5; - // ^^^^^ - } - 8 => 'a: loop { - 'b: loop { - break 'a 5; - // ^^^^^ - break 'b 5; - break 5; - }; - } - // - _ => 500, - // ^^^ - } - } -} -"#, - ); - } - - #[test] - fn test_hl_inner_tail_exit_points_labeled_block() { - check( - r#" -fn foo() ->$0 u32 { - 'foo: { - break 'foo 0; - // ^^^^^ - loop { - break; - break 'foo 0; - // ^^^^^ - } - 0 - // ^ - } -} -"#, - ); - } - - #[test] - fn test_hl_break_loop() { - check( - r#" -fn foo() { - 'outer: loop { - // ^^^^^^^^^^^^ - break; - // ^^^^^ - 'inner: loop { - break; - 'innermost: loop { - break 'outer; - // ^^^^^^^^^^^^ - break 'inner; - } - break$0 'outer; - // ^^^^^^^^^^^^ - break; - } - break; - // ^^^^^ - } -} -"#, - ); - } - - #[test] - fn test_hl_break_loop2() { - check( - r#" -fn foo() { - 'outer: loop { - break; - 'inner: loop { - // ^^^^^^^^^^^^ - break; - // ^^^^^ - 'innermost: loop { - break 'outer; - break 'inner; - // ^^^^^^^^^^^^ - } - break 'outer; - break$0; - // ^^^^^ - } - break; - } -} -"#, - ); - } - - #[test] - fn test_hl_break_for() { - check( - r#" -fn foo() { - 'outer: for _ in () { - // ^^^^^^^^^^^ - break; - // ^^^^^ - 'inner: for _ in () { - break; - 'innermost: for _ in () { - break 'outer; - // ^^^^^^^^^^^^ - break 'inner; - } - break$0 'outer; - // ^^^^^^^^^^^^ - break; - } - break; - // ^^^^^ - } -} -"#, - ); - } - - #[test] - fn test_hl_break_for_but_not_continue() { - check( - r#" -fn foo() { - 'outer: for _ in () { - // ^^^^^^^^^^^ - break; - // ^^^^^ - continue; - 'inner: for _ in () { - break; - continue; - 'innermost: for _ in () { - continue 'outer; - break 'outer; - // ^^^^^^^^^^^^ - continue 'inner; - break 'inner; - } - break$0 'outer; - // ^^^^^^^^^^^^ - continue 'outer; - break; - continue; - } - break; - // ^^^^^ - continue; - } -} -"#, - ); - } - - #[test] - fn test_hl_continue_for_but_not_break() { - check( - r#" -fn foo() { - 'outer: for _ in () { - // ^^^^^^^^^^^ - break; - continue; - // ^^^^^^^^ - 'inner: for _ in () { - break; - continue; - 'innermost: for _ in () { - continue 'outer; - // ^^^^^^^^^^^^^^^ - break 'outer; - continue 'inner; - break 'inner; - } - break 'outer; - continue$0 'outer; - // ^^^^^^^^^^^^^^^ - break; - continue; - } - break; - continue; - // ^^^^^^^^ - } -} -"#, - ); - } - - #[test] - fn test_hl_break_and_continue() { - check( - r#" -fn foo() { - 'outer: fo$0r _ in () { - // ^^^^^^^^^^^ - break; - // ^^^^^ - continue; - // ^^^^^^^^ - 'inner: for _ in () { - break; - continue; - 'innermost: for _ in () { - continue 'outer; - // ^^^^^^^^^^^^^^^ - break 'outer; - // ^^^^^^^^^^^^ - continue 'inner; - break 'inner; - } - break 'outer; - // ^^^^^^^^^^^^ - continue 'outer; - // ^^^^^^^^^^^^^^^ - break; - continue; - } - break; - // ^^^^^ - continue; - // ^^^^^^^^ - } -} -"#, - ); - } - - #[test] - fn test_hl_break_while() { - check( - r#" -fn foo() { - 'outer: while true { - // ^^^^^^^^^^^^^ - break; - // ^^^^^ - 'inner: while true { - break; - 'innermost: while true { - break 'outer; - // ^^^^^^^^^^^^ - break 'inner; - } - break$0 'outer; - // ^^^^^^^^^^^^ - break; - } - break; - // ^^^^^ - } -} -"#, - ); - } - - #[test] - fn test_hl_break_labeled_block() { - check( - r#" -fn foo() { - 'outer: { - // ^^^^^^^ - break; - // ^^^^^ - 'inner: { - break; - 'innermost: { - break 'outer; - // ^^^^^^^^^^^^ - break 'inner; - } - break$0 'outer; - // ^^^^^^^^^^^^ - break; - } - break; - // ^^^^^ - } -} -"#, - ); - } - - #[test] - fn test_hl_break_unlabeled_loop() { - check( - r#" -fn foo() { - loop { - // ^^^^ - break$0; - // ^^^^^ - } -} -"#, - ); - } - - #[test] - fn test_hl_break_unlabeled_block_in_loop() { - check( - r#" -fn foo() { - loop { - // ^^^^ - { - break$0; - // ^^^^^ - } - } -} -"#, - ); - } - - #[test] - fn test_hl_field_shorthand() { - check( - r#" -struct Struct { field: u32 } - //^^^^^ -fn function(field: u32) { - //^^^^^ - Struct { field$0 } - //^^^^^ read -} -"#, - ); - } - - #[test] - fn test_hl_disabled_ref_local() { - let config = HighlightRelatedConfig { - references: false, - break_points: true, - exit_points: true, - yield_points: true, - }; - - check_with_config( - r#" -fn foo() { - let x$0 = 5; - let y = x * 2; -} -"#, - config, - ); - } - - #[test] - fn test_hl_disabled_ref_local_preserved_break() { - let config = HighlightRelatedConfig { - references: false, - break_points: true, - exit_points: true, - yield_points: true, - }; - - check_with_config( - r#" -fn foo() { - let x$0 = 5; - let y = x * 2; - - loop { - break; - } -} -"#, - config.clone(), - ); - - check_with_config( - r#" -fn foo() { - let x = 5; - let y = x * 2; - - loop$0 { -// ^^^^ - break; -// ^^^^^ - } -} -"#, - config, - ); - } - - #[test] - fn test_hl_disabled_ref_local_preserved_yield() { - let config = HighlightRelatedConfig { - references: false, - break_points: true, - exit_points: true, - yield_points: true, - }; - - check_with_config( - r#" -async fn foo() { - let x$0 = 5; - let y = x * 2; - - 0.await; -} -"#, - config.clone(), - ); - - check_with_config( - r#" - async fn foo() { -// ^^^^^ - let x = 5; - let y = x * 2; - - 0.await$0; -// ^^^^^ -} -"#, - config, - ); - } - - #[test] - fn test_hl_disabled_ref_local_preserved_exit() { - let config = HighlightRelatedConfig { - references: false, - break_points: true, - exit_points: true, - yield_points: true, - }; - - check_with_config( - r#" -fn foo() -> i32 { - let x$0 = 5; - let y = x * 2; - - if true { - return y; - } - - 0? -} -"#, - config.clone(), - ); - - check_with_config( - r#" -fn foo() ->$0 i32 { - let x = 5; - let y = x * 2; - - if true { - return y; -// ^^^^^^ - } - - 0? -// ^ -"#, - config, - ); - } - - #[test] - fn test_hl_disabled_break() { - let config = HighlightRelatedConfig { - references: true, - break_points: false, - exit_points: true, - yield_points: true, - }; - - check_with_config( - r#" -fn foo() { - loop { - break$0; - } -} -"#, - config, - ); - } - - #[test] - fn test_hl_disabled_yield() { - let config = HighlightRelatedConfig { - references: true, - break_points: true, - exit_points: true, - yield_points: false, - }; - - check_with_config( - r#" -async$0 fn foo() { - 0.await; -} -"#, - config, - ); - } - - #[test] - fn test_hl_disabled_exit() { - let config = HighlightRelatedConfig { - references: true, - break_points: true, - exit_points: false, - yield_points: true, - }; - - check_with_config( - r#" -fn foo() ->$0 i32 { - if true { - return -1; - } - - 42 -}"#, - config, - ); - } - - #[test] - fn test_hl_multi_local() { - check( - r#" -fn foo(( - foo$0 - //^^^ - | foo - //^^^ - | foo - //^^^ -): ()) { - foo; - //^^^read - let foo; -} -"#, - ); - check( - r#" -fn foo(( - foo - //^^^ - | foo$0 - //^^^ - | foo - //^^^ -): ()) { - foo; - //^^^read - let foo; -} -"#, - ); - check( - r#" -fn foo(( - foo - //^^^ - | foo - //^^^ - | foo - //^^^ -): ()) { - foo$0; - //^^^read - let foo; -} -"#, - ); - } - - #[test] - fn test_hl_trait_impl_methods() { - check( - r#" -trait Trait { - fn func$0(self) {} - //^^^^ -} - -impl Trait for () { - fn func(self) {} - //^^^^ -} - -fn main() { - <()>::func(()); - //^^^^ - ().func(); - //^^^^ -} -"#, - ); - check( - r#" -trait Trait { - fn func(self) {} - //^^^^ -} - -impl Trait for () { - fn func$0(self) {} - //^^^^ -} - -fn main() { - <()>::func(()); - //^^^^ - ().func(); - //^^^^ -} -"#, - ); - check( - r#" -trait Trait { - fn func(self) {} - //^^^^ -} - -impl Trait for () { - fn func(self) {} - //^^^^ -} - -fn main() { - <()>::func(()); - //^^^^ - ().func$0(); - //^^^^ -} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs deleted file mode 100644 index 59c97f2dcf966..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ /dev/null @@ -1,390 +0,0 @@ -mod render; - -#[cfg(test)] -mod tests; - -use std::iter; - -use either::Either; -use hir::{HasSource, Semantics}; -use ide_db::{ - base_db::FileRange, - defs::{Definition, IdentClass}, - famous_defs::FamousDefs, - helpers::pick_best_token, - FxIndexSet, RootDatabase, -}; -use itertools::Itertools; -use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, T}; - -use crate::{ - doc_links::token_as_doc_comment, - markup::Markup, - runnables::{runnable_fn, runnable_mod}, - FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, TryToNav, -}; -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct HoverConfig { - pub links_in_hover: bool, - pub documentation: Option, -} - -impl HoverConfig { - fn markdown(&self) -> bool { - matches!(self.documentation, Some(HoverDocFormat::Markdown)) - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum HoverDocFormat { - Markdown, - PlainText, -} - -#[derive(Debug, Clone)] -pub enum HoverAction { - Runnable(Runnable), - Implementation(FilePosition), - Reference(FilePosition), - GoToType(Vec), -} - -impl HoverAction { - fn goto_type_from_targets(db: &RootDatabase, targets: Vec) -> Self { - let targets = targets - .into_iter() - .filter_map(|it| { - Some(HoverGotoTypeData { - mod_path: render::path( - db, - it.module(db)?, - it.name(db).map(|name| name.to_string()), - ), - nav: it.try_to_nav(db)?, - }) - }) - .collect(); - HoverAction::GoToType(targets) - } -} - -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct HoverGotoTypeData { - pub mod_path: String, - pub nav: NavigationTarget, -} - -/// Contains the results when hovering over an item -#[derive(Debug, Default)] -pub struct HoverResult { - pub markup: Markup, - pub actions: Vec, -} - -// Feature: Hover -// -// Shows additional information, like the type of an expression or the documentation for a definition when "focusing" code. -// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. -// -// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[] -pub(crate) fn hover( - db: &RootDatabase, - FileRange { file_id, range }: FileRange, - config: &HoverConfig, -) -> Option> { - let sema = &hir::Semantics::new(db); - let file = sema.parse(file_id).syntax().clone(); - - if !range.is_empty() { - return hover_ranged(&file, range, sema, config); - } - let offset = range.start(); - - let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind { - IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self] => 3, - T!['('] | T![')'] => 2, - kind if kind.is_trivia() => 0, - _ => 1, - })?; - - if let Some(doc_comment) = token_as_doc_comment(&original_token) { - cov_mark::hit!(no_highlight_on_comment_hover); - return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| { - let res = hover_for_definition(sema, file_id, def, &node, config)?; - Some(RangeInfo::new(range, res)) - }); - } - - let in_attr = matches!(original_token.parent().and_then(ast::TokenTree::cast), Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind()))); - let descended = if in_attr { - [sema.descend_into_macros_with_kind_preference(original_token.clone())].into() - } else { - sema.descend_into_macros_with_same_text(original_token.clone()) - }; - - // FIXME: Definition should include known lints and the like instead of having this special case here - let hovered_lint = descended.iter().find_map(|token| { - let attr = token.parent_ancestors().find_map(ast::Attr::cast)?; - render::try_for_lint(&attr, token) - }); - if let Some(res) = hovered_lint { - return Some(RangeInfo::new(original_token.text_range(), res)); - } - - let result = descended - .iter() - .filter_map(|token| { - let node = token.parent()?; - let class = IdentClass::classify_token(sema, token)?; - Some(class.definitions().into_iter().zip(iter::once(node).cycle())) - }) - .flatten() - .unique_by(|&(def, _)| def) - .filter_map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config)) - .reduce(|mut acc: HoverResult, HoverResult { markup, actions }| { - acc.actions.extend(actions); - acc.markup = Markup::from(format!("{}\n---\n{}", acc.markup, markup)); - acc - }); - - if result.is_none() { - // fallbacks, show keywords or types - - let res = descended.iter().find_map(|token| render::keyword(sema, config, token)); - if let Some(res) = res { - return Some(RangeInfo::new(original_token.text_range(), res)); - } - let res = descended - .iter() - .find_map(|token| hover_type_fallback(sema, config, token, &original_token)); - if let Some(_) = res { - return res; - } - } - result.map(|mut res: HoverResult| { - res.actions = dedupe_or_merge_hover_actions(res.actions); - RangeInfo::new(original_token.text_range(), res) - }) -} - -pub(crate) fn hover_for_definition( - sema: &Semantics<'_, RootDatabase>, - file_id: FileId, - definition: Definition, - node: &SyntaxNode, - config: &HoverConfig, -) -> Option { - let famous_defs = match &definition { - Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(node)?.krate())), - _ => None, - }; - render::definition(sema.db, definition, famous_defs.as_ref(), config).map(|markup| { - HoverResult { - markup: render::process_markup(sema.db, definition, &markup, config), - actions: show_implementations_action(sema.db, definition) - .into_iter() - .chain(show_fn_references_action(sema.db, definition)) - .chain(runnable_action(sema, definition, file_id)) - .chain(goto_type_action_for_def(sema.db, definition)) - .collect(), - } - }) -} - -fn hover_ranged( - file: &SyntaxNode, - range: syntax::TextRange, - sema: &Semantics<'_, RootDatabase>, - config: &HoverConfig, -) -> Option> { - // FIXME: make this work in attributes - let expr_or_pat = file.covering_element(range).ancestors().find_map(|it| { - match_ast! { - match it { - ast::Expr(expr) => Some(Either::Left(expr)), - ast::Pat(pat) => Some(Either::Right(pat)), - _ => None, - } - } - })?; - let res = match &expr_or_pat { - Either::Left(ast::Expr::TryExpr(try_expr)) => render::try_expr(sema, config, try_expr), - Either::Left(ast::Expr::PrefixExpr(prefix_expr)) - if prefix_expr.op_kind() == Some(ast::UnaryOp::Deref) => - { - render::deref_expr(sema, config, prefix_expr) - } - _ => None, - }; - let res = res.or_else(|| render::type_info(sema, config, &expr_or_pat)); - res.map(|it| { - let range = match expr_or_pat { - Either::Left(it) => it.syntax().text_range(), - Either::Right(it) => it.syntax().text_range(), - }; - RangeInfo::new(range, it) - }) -} - -fn hover_type_fallback( - sema: &Semantics<'_, RootDatabase>, - config: &HoverConfig, - token: &SyntaxToken, - original_token: &SyntaxToken, -) -> Option> { - let node = token - .parent_ancestors() - .take_while(|it| !ast::Item::can_cast(it.kind())) - .find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?; - - let expr_or_pat = match_ast! { - match node { - ast::Expr(it) => Either::Left(it), - ast::Pat(it) => Either::Right(it), - // If this node is a MACRO_CALL, it means that `descend_into_macros_many` failed to resolve. - // (e.g expanding a builtin macro). So we give up here. - ast::MacroCall(_it) => return None, - _ => return None, - } - }; - - let res = render::type_info(sema, config, &expr_or_pat)?; - let range = sema - .original_range_opt(&node) - .map(|frange| frange.range) - .unwrap_or_else(|| original_token.text_range()); - Some(RangeInfo::new(range, res)) -} - -fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option { - fn to_action(nav_target: NavigationTarget) -> HoverAction { - HoverAction::Implementation(FilePosition { - file_id: nav_target.file_id, - offset: nav_target.focus_or_full_range().start(), - }) - } - - let adt = match def { - Definition::Trait(it) => return it.try_to_nav(db).map(to_action), - Definition::Adt(it) => Some(it), - Definition::SelfType(it) => it.self_ty(db).as_adt(), - _ => None, - }?; - adt.try_to_nav(db).map(to_action) -} - -fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option { - match def { - Definition::Function(it) => it.try_to_nav(db).map(|nav_target| { - HoverAction::Reference(FilePosition { - file_id: nav_target.file_id, - offset: nav_target.focus_or_full_range().start(), - }) - }), - _ => None, - } -} - -fn runnable_action( - sema: &hir::Semantics<'_, RootDatabase>, - def: Definition, - file_id: FileId, -) -> Option { - match def { - Definition::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable), - Definition::Function(func) => { - let src = func.source(sema.db)?; - if src.file_id != file_id.into() { - cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment); - cov_mark::hit!(hover_macro_generated_struct_fn_doc_attr); - return None; - } - - runnable_fn(sema, func).map(HoverAction::Runnable) - } - _ => None, - } -} - -fn goto_type_action_for_def(db: &RootDatabase, def: Definition) -> Option { - let mut targets: Vec = Vec::new(); - let mut push_new_def = |item: hir::ModuleDef| { - if !targets.contains(&item) { - targets.push(item); - } - }; - - if let Definition::GenericParam(hir::GenericParam::TypeParam(it)) = def { - it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); - } else { - let ty = match def { - Definition::Local(it) => it.ty(db), - Definition::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db), - Definition::Field(field) => field.ty(db), - Definition::Function(function) => function.ret_type(db), - _ => return None, - }; - - walk_and_push_ty(db, &ty, &mut push_new_def); - } - - Some(HoverAction::goto_type_from_targets(db, targets)) -} - -fn walk_and_push_ty( - db: &RootDatabase, - ty: &hir::Type, - push_new_def: &mut dyn FnMut(hir::ModuleDef), -) { - ty.walk(db, |t| { - if let Some(adt) = t.as_adt() { - push_new_def(adt.into()); - } else if let Some(trait_) = t.as_dyn_trait() { - push_new_def(trait_.into()); - } else if let Some(traits) = t.as_impl_traits(db) { - traits.for_each(|it| push_new_def(it.into())); - } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { - push_new_def(trait_.into()); - } - }); -} - -fn dedupe_or_merge_hover_actions(actions: Vec) -> Vec { - let mut deduped_actions = Vec::with_capacity(actions.len()); - let mut go_to_type_targets = FxIndexSet::default(); - - let mut seen_implementation = false; - let mut seen_reference = false; - let mut seen_runnable = false; - for action in actions { - match action { - HoverAction::GoToType(targets) => { - go_to_type_targets.extend(targets); - } - HoverAction::Implementation(..) => { - if !seen_implementation { - seen_implementation = true; - deduped_actions.push(action); - } - } - HoverAction::Reference(..) => { - if !seen_reference { - seen_reference = true; - deduped_actions.push(action); - } - } - HoverAction::Runnable(..) => { - if !seen_runnable { - seen_runnable = true; - deduped_actions.push(action); - } - } - }; - } - - if !go_to_type_targets.is_empty() { - deduped_actions.push(HoverAction::GoToType(go_to_type_targets.into_iter().collect())); - } - - deduped_actions -} diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs deleted file mode 100644 index 6c50a4e6adc0e..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ /dev/null @@ -1,563 +0,0 @@ -//! Logic for rendering the different hover messages -use std::fmt::Display; - -use either::Either; -use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HirDisplay, Semantics, TypeInfo}; -use ide_db::{ - base_db::SourceDatabase, - defs::Definition, - famous_defs::FamousDefs, - generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES}, - RootDatabase, -}; -use itertools::Itertools; -use stdx::format_to; -use syntax::{ - algo, ast, match_ast, AstNode, Direction, - SyntaxKind::{LET_EXPR, LET_STMT}, - SyntaxToken, T, -}; - -use crate::{ - doc_links::{remove_links, rewrite_links}, - hover::walk_and_push_ty, - markdown_remove::remove_markdown, - HoverAction, HoverConfig, HoverResult, Markup, -}; - -pub(super) fn type_info( - sema: &Semantics<'_, RootDatabase>, - config: &HoverConfig, - expr_or_pat: &Either, -) -> Option { - let TypeInfo { original, adjusted } = match expr_or_pat { - Either::Left(expr) => sema.type_of_expr(expr)?, - Either::Right(pat) => sema.type_of_pat(pat)?, - }; - - let mut res = HoverResult::default(); - let mut targets: Vec = Vec::new(); - let mut push_new_def = |item: hir::ModuleDef| { - if !targets.contains(&item) { - targets.push(item); - } - }; - walk_and_push_ty(sema.db, &original, &mut push_new_def); - - res.markup = if let Some(adjusted_ty) = adjusted { - walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def); - let original = original.display(sema.db).to_string(); - let adjusted = adjusted_ty.display(sema.db).to_string(); - let static_text_diff_len = "Coerced to: ".len() - "Type: ".len(); - format!( - "{bt_start}Type: {:>apad$}\nCoerced to: {:>opad$}\n{bt_end}", - original, - adjusted, - apad = static_text_diff_len + adjusted.len().max(original.len()), - opad = original.len(), - bt_start = if config.markdown() { "```text\n" } else { "" }, - bt_end = if config.markdown() { "```\n" } else { "" } - ) - .into() - } else { - if config.markdown() { - Markup::fenced_block(&original.display(sema.db)) - } else { - original.display(sema.db).to_string().into() - } - }; - res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); - Some(res) -} - -pub(super) fn try_expr( - sema: &Semantics<'_, RootDatabase>, - config: &HoverConfig, - try_expr: &ast::TryExpr, -) -> Option { - let inner_ty = sema.type_of_expr(&try_expr.expr()?)?.original; - let mut ancestors = try_expr.syntax().ancestors(); - let mut body_ty = loop { - let next = ancestors.next()?; - break match_ast! { - match next { - ast::Fn(fn_) => sema.to_def(&fn_)?.ret_type(sema.db), - ast::Item(__) => return None, - ast::ClosureExpr(closure) => sema.type_of_expr(&closure.body()?)?.original, - ast::BlockExpr(block_expr) => if matches!(block_expr.modifier(), Some(ast::BlockModifier::Async(_) | ast::BlockModifier::Try(_)| ast::BlockModifier::Const(_))) { - sema.type_of_expr(&block_expr.into())?.original - } else { - continue; - }, - _ => continue, - } - }; - }; - - if inner_ty == body_ty { - return None; - } - - let mut inner_ty = inner_ty; - let mut s = "Try Target".to_owned(); - - let adts = inner_ty.as_adt().zip(body_ty.as_adt()); - if let Some((hir::Adt::Enum(inner), hir::Adt::Enum(body))) = adts { - let famous_defs = FamousDefs(sema, sema.scope(try_expr.syntax())?.krate()); - // special case for two options, there is no value in showing them - if let Some(option_enum) = famous_defs.core_option_Option() { - if inner == option_enum && body == option_enum { - cov_mark::hit!(hover_try_expr_opt_opt); - return None; - } - } - - // special case two results to show the error variants only - if let Some(result_enum) = famous_defs.core_result_Result() { - if inner == result_enum && body == result_enum { - let error_type_args = - inner_ty.type_arguments().nth(1).zip(body_ty.type_arguments().nth(1)); - if let Some((inner, body)) = error_type_args { - inner_ty = inner; - body_ty = body; - s = "Try Error".to_owned(); - } - } - } - } - - let mut res = HoverResult::default(); - - let mut targets: Vec = Vec::new(); - let mut push_new_def = |item: hir::ModuleDef| { - if !targets.contains(&item) { - targets.push(item); - } - }; - walk_and_push_ty(sema.db, &inner_ty, &mut push_new_def); - walk_and_push_ty(sema.db, &body_ty, &mut push_new_def); - res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); - - let inner_ty = inner_ty.display(sema.db).to_string(); - let body_ty = body_ty.display(sema.db).to_string(); - let ty_len_max = inner_ty.len().max(body_ty.len()); - - let l = "Propagated as: ".len() - " Type: ".len(); - let static_text_len_diff = l as isize - s.len() as isize; - let tpad = static_text_len_diff.max(0) as usize; - let ppad = static_text_len_diff.min(0).abs() as usize; - - res.markup = format!( - "{bt_start}{} Type: {:>pad0$}\nPropagated as: {:>pad1$}\n{bt_end}", - s, - inner_ty, - body_ty, - pad0 = ty_len_max + tpad, - pad1 = ty_len_max + ppad, - bt_start = if config.markdown() { "```text\n" } else { "" }, - bt_end = if config.markdown() { "```\n" } else { "" } - ) - .into(); - Some(res) -} - -pub(super) fn deref_expr( - sema: &Semantics<'_, RootDatabase>, - config: &HoverConfig, - deref_expr: &ast::PrefixExpr, -) -> Option { - let inner_ty = sema.type_of_expr(&deref_expr.expr()?)?.original; - let TypeInfo { original, adjusted } = - sema.type_of_expr(&ast::Expr::from(deref_expr.clone()))?; - - let mut res = HoverResult::default(); - let mut targets: Vec = Vec::new(); - let mut push_new_def = |item: hir::ModuleDef| { - if !targets.contains(&item) { - targets.push(item); - } - }; - walk_and_push_ty(sema.db, &inner_ty, &mut push_new_def); - walk_and_push_ty(sema.db, &original, &mut push_new_def); - - res.markup = if let Some(adjusted_ty) = adjusted { - walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def); - let original = original.display(sema.db).to_string(); - let adjusted = adjusted_ty.display(sema.db).to_string(); - let inner = inner_ty.display(sema.db).to_string(); - let type_len = "To type: ".len(); - let coerced_len = "Coerced to: ".len(); - let deref_len = "Dereferenced from: ".len(); - let max_len = (original.len() + type_len) - .max(adjusted.len() + coerced_len) - .max(inner.len() + deref_len); - format!( - "{bt_start}Dereferenced from: {:>ipad$}\nTo type: {:>apad$}\nCoerced to: {:>opad$}\n{bt_end}", - inner, - original, - adjusted, - ipad = max_len - deref_len, - apad = max_len - type_len, - opad = max_len - coerced_len, - bt_start = if config.markdown() { "```text\n" } else { "" }, - bt_end = if config.markdown() { "```\n" } else { "" } - ) - .into() - } else { - let original = original.display(sema.db).to_string(); - let inner = inner_ty.display(sema.db).to_string(); - let type_len = "To type: ".len(); - let deref_len = "Dereferenced from: ".len(); - let max_len = (original.len() + type_len).max(inner.len() + deref_len); - format!( - "{bt_start}Dereferenced from: {:>ipad$}\nTo type: {:>apad$}\n{bt_end}", - inner, - original, - ipad = max_len - deref_len, - apad = max_len - type_len, - bt_start = if config.markdown() { "```text\n" } else { "" }, - bt_end = if config.markdown() { "```\n" } else { "" } - ) - .into() - }; - res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); - - Some(res) -} - -pub(super) fn keyword( - sema: &Semantics<'_, RootDatabase>, - config: &HoverConfig, - token: &SyntaxToken, -) -> Option { - if !token.kind().is_keyword() || !config.documentation.is_some() { - return None; - } - let parent = token.parent()?; - let famous_defs = FamousDefs(sema, sema.scope(&parent)?.krate()); - - let KeywordHint { description, keyword_mod, actions } = keyword_hints(sema, token, parent); - - let doc_owner = find_std_module(&famous_defs, &keyword_mod)?; - let docs = doc_owner.attrs(sema.db).docs()?; - let markup = process_markup( - sema.db, - Definition::Module(doc_owner), - &markup(Some(docs.into()), description, None)?, - config, - ); - Some(HoverResult { markup, actions }) -} - -pub(super) fn try_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option { - let (path, tt) = attr.as_simple_call()?; - if !tt.syntax().text_range().contains(token.text_range().start()) { - return None; - } - let (is_clippy, lints) = match &*path { - "feature" => (false, FEATURES), - "allow" | "deny" | "forbid" | "warn" => { - let is_clippy = algo::non_trivia_sibling(token.clone().into(), Direction::Prev) - .filter(|t| t.kind() == T![:]) - .and_then(|t| algo::non_trivia_sibling(t, Direction::Prev)) - .filter(|t| t.kind() == T![:]) - .and_then(|t| algo::non_trivia_sibling(t, Direction::Prev)) - .map_or(false, |t| { - t.kind() == T![ident] && t.into_token().map_or(false, |t| t.text() == "clippy") - }); - if is_clippy { - (true, CLIPPY_LINTS) - } else { - (false, DEFAULT_LINTS) - } - } - _ => return None, - }; - - let tmp; - let needle = if is_clippy { - tmp = format!("clippy::{}", token.text()); - &tmp - } else { - &*token.text() - }; - - let lint = - lints.binary_search_by_key(&needle, |lint| lint.label).ok().map(|idx| &lints[idx])?; - Some(HoverResult { - markup: Markup::from(format!("```\n{}\n```\n___\n\n{}", lint.label, lint.description)), - ..Default::default() - }) -} - -pub(super) fn process_markup( - db: &RootDatabase, - def: Definition, - markup: &Markup, - config: &HoverConfig, -) -> Markup { - let markup = markup.as_str(); - let markup = if !config.markdown() { - remove_markdown(markup) - } else if config.links_in_hover { - rewrite_links(db, markup, def) - } else { - remove_links(markup) - }; - Markup::from(markup) -} - -fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option { - match def { - Definition::Field(f) => Some(f.parent_def(db).name(db)), - Definition::Local(l) => l.parent(db).name(db), - Definition::Function(f) => match f.as_assoc_item(db)?.container(db) { - hir::AssocItemContainer::Trait(t) => Some(t.name(db)), - hir::AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)), - }, - Definition::Variant(e) => Some(e.parent_enum(db).name(db)), - _ => None, - } - .map(|name| name.to_string()) -} - -pub(super) fn path(db: &RootDatabase, module: hir::Module, item_name: Option) -> String { - let crate_name = - db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string()); - let module_path = module - .path_to_root(db) - .into_iter() - .rev() - .flat_map(|it| it.name(db).map(|name| name.to_string())); - crate_name.into_iter().chain(module_path).chain(item_name).join("::") -} - -pub(super) fn definition( - db: &RootDatabase, - def: Definition, - famous_defs: Option<&FamousDefs<'_, '_>>, - config: &HoverConfig, -) -> Option { - let mod_path = definition_mod_path(db, &def); - let (label, docs) = match def { - Definition::Macro(it) => label_and_docs(db, it), - Definition::Field(it) => label_and_docs(db, it), - Definition::Module(it) => label_and_docs(db, it), - Definition::Function(it) => label_and_docs(db, it), - Definition::Adt(it) => label_and_docs(db, it), - Definition::Variant(it) => label_and_docs(db, it), - Definition::Const(it) => label_value_and_docs(db, it, |it| { - let body = it.eval(db); - match body { - Ok(x) => Some(format!("{}", x)), - Err(_) => it.value(db).map(|x| format!("{}", x)), - } - }), - Definition::Static(it) => label_value_and_docs(db, it, |it| it.value(db)), - Definition::Trait(it) => label_and_docs(db, it), - Definition::TypeAlias(it) => label_and_docs(db, it), - Definition::BuiltinType(it) => { - return famous_defs - .and_then(|fd| builtin(fd, it)) - .or_else(|| Some(Markup::fenced_block(&it.name()))) - } - Definition::Local(it) => return local(db, it), - Definition::SelfType(impl_def) => { - impl_def.self_ty(db).as_adt().map(|adt| label_and_docs(db, adt))? - } - Definition::GenericParam(it) => label_and_docs(db, it), - Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))), - // FIXME: We should be able to show more info about these - Definition::BuiltinAttr(it) => return render_builtin_attr(db, it), - Definition::ToolModule(it) => return Some(Markup::fenced_block(&it.name(db))), - Definition::DeriveHelper(it) => (format!("derive_helper {}", it.name(db)), None), - }; - - let docs = match config.documentation { - Some(_) => docs.or_else(|| { - // docs are missing, for assoc items of trait impls try to fall back to the docs of the - // original item of the trait - let assoc = def.as_assoc_item(db)?; - let trait_ = assoc.containing_trait_impl(db)?; - let name = Some(assoc.name(db)?); - let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?; - item.docs(db) - }), - None => None, - }; - let docs = docs.filter(|_| config.documentation.is_some()).map(Into::into); - markup(docs, label, mod_path) -} - -fn render_builtin_attr(db: &RootDatabase, attr: hir::BuiltinAttr) -> Option { - let name = attr.name(db); - let desc = format!("#[{}]", name); - - let AttributeTemplate { word, list, name_value_str } = match attr.template(db) { - Some(template) => template, - None => return Some(Markup::fenced_block(&attr.name(db))), - }; - let mut docs = "Valid forms are:".to_owned(); - if word { - format_to!(docs, "\n - #\\[{}]", name); - } - if let Some(list) = list { - format_to!(docs, "\n - #\\[{}({})]", name, list); - } - if let Some(name_value_str) = name_value_str { - format_to!(docs, "\n - #\\[{} = {}]", name, name_value_str); - } - markup(Some(docs.replace('*', "\\*")), desc, None) -} - -fn label_and_docs(db: &RootDatabase, def: D) -> (String, Option) -where - D: HasAttrs + HirDisplay, -{ - let label = def.display(db).to_string(); - let docs = def.attrs(db).docs(); - (label, docs) -} - -fn label_value_and_docs( - db: &RootDatabase, - def: D, - value_extractor: E, -) -> (String, Option) -where - D: HasAttrs + HirDisplay, - E: Fn(&D) -> Option, - V: Display, -{ - let label = if let Some(value) = value_extractor(&def) { - format!("{} = {}", def.display(db), value) - } else { - def.display(db).to_string() - }; - let docs = def.attrs(db).docs(); - (label, docs) -} - -fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option { - if let Definition::GenericParam(_) = def { - return None; - } - def.module(db).map(|module| path(db, module, definition_owner_name(db, def))) -} - -fn markup(docs: Option, desc: String, mod_path: Option) -> Option { - let mut buf = String::new(); - - if let Some(mod_path) = mod_path { - if !mod_path.is_empty() { - format_to!(buf, "```rust\n{}\n```\n\n", mod_path); - } - } - format_to!(buf, "```rust\n{}\n```", desc); - - if let Some(doc) = docs { - format_to!(buf, "\n___\n\n{}", doc); - } - Some(buf.into()) -} - -fn builtin(famous_defs: &FamousDefs<'_, '_>, builtin: hir::BuiltinType) -> Option { - // std exposes prim_{} modules with docstrings on the root to document the builtins - let primitive_mod = format!("prim_{}", builtin.name()); - let doc_owner = find_std_module(famous_defs, &primitive_mod)?; - let docs = doc_owner.attrs(famous_defs.0.db).docs()?; - markup(Some(docs.into()), builtin.name().to_string(), None) -} - -fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option { - let db = famous_defs.0.db; - let std_crate = famous_defs.std()?; - let std_root_module = std_crate.root_module(db); - std_root_module - .children(db) - .find(|module| module.name(db).map_or(false, |module| module.to_string() == name)) -} - -fn local(db: &RootDatabase, it: hir::Local) -> Option { - let ty = it.ty(db); - let ty = ty.display_truncated(db, None); - let is_mut = if it.is_mut(db) { "mut " } else { "" }; - let desc = match it.source(db).value { - Either::Left(ident) => { - let name = it.name(db); - let let_kw = if ident - .syntax() - .parent() - .map_or(false, |p| p.kind() == LET_STMT || p.kind() == LET_EXPR) - { - "let " - } else { - "" - }; - format!("{}{}{}: {}", let_kw, is_mut, name, ty) - } - Either::Right(_) => format!("{}self: {}", is_mut, ty), - }; - markup(None, desc, None) -} - -struct KeywordHint { - description: String, - keyword_mod: String, - actions: Vec, -} - -impl KeywordHint { - fn new(description: String, keyword_mod: String) -> Self { - Self { description, keyword_mod, actions: Vec::default() } - } -} - -fn keyword_hints( - sema: &Semantics<'_, RootDatabase>, - token: &SyntaxToken, - parent: syntax::SyntaxNode, -) -> KeywordHint { - match token.kind() { - T![await] | T![loop] | T![match] | T![unsafe] | T![as] | T![try] | T![if] | T![else] => { - let keyword_mod = format!("{}_keyword", token.text()); - - match ast::Expr::cast(parent).and_then(|site| sema.type_of_expr(&site)) { - // ignore the unit type () - Some(ty) if !ty.adjusted.as_ref().unwrap_or(&ty.original).is_unit() => { - let mut targets: Vec = Vec::new(); - let mut push_new_def = |item: hir::ModuleDef| { - if !targets.contains(&item) { - targets.push(item); - } - }; - walk_and_push_ty(sema.db, &ty.original, &mut push_new_def); - - let ty = ty.adjusted(); - let description = format!("{}: {}", token.text(), ty.display(sema.db)); - - KeywordHint { - description, - keyword_mod, - actions: vec![HoverAction::goto_type_from_targets(sema.db, targets)], - } - } - _ => KeywordHint { - description: token.text().to_string(), - keyword_mod, - actions: Vec::new(), - }, - } - } - T![fn] => { - let module = match ast::FnPtrType::cast(parent) { - // treat fn keyword inside function pointer type as primitive - Some(_) => format!("prim_{}", token.text()), - None => format!("{}_keyword", token.text()), - }; - KeywordHint::new(token.text().to_string(), module) - } - T![Self] => KeywordHint::new(token.text().to_string(), "self_upper_keyword".into()), - _ => KeywordHint::new(token.text().to_string(), format!("{}_keyword", token.text())), - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs deleted file mode 100644 index 867d1f54d4feb..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ /dev/null @@ -1,5053 +0,0 @@ -use expect_test::{expect, Expect}; -use ide_db::base_db::{FileLoader, FileRange}; -use syntax::TextRange; - -use crate::{fixture, hover::HoverDocFormat, HoverConfig}; - -fn check_hover_no_result(ra_fixture: &str) { - let (analysis, position) = fixture::position(ra_fixture); - let hover = analysis - .hover( - &HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::Markdown) }, - FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, - ) - .unwrap(); - assert!(hover.is_none(), "hover not expected but found: {:?}", hover.unwrap()); -} - -#[track_caller] -fn check(ra_fixture: &str, expect: Expect) { - let (analysis, position) = fixture::position(ra_fixture); - let hover = analysis - .hover( - &HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::Markdown) }, - FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, - ) - .unwrap() - .unwrap(); - - let content = analysis.db.file_text(position.file_id); - let hovered_element = &content[hover.range]; - - let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup); - expect.assert_eq(&actual) -} - -fn check_hover_no_links(ra_fixture: &str, expect: Expect) { - let (analysis, position) = fixture::position(ra_fixture); - let hover = analysis - .hover( - &HoverConfig { links_in_hover: false, documentation: Some(HoverDocFormat::Markdown) }, - FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, - ) - .unwrap() - .unwrap(); - - let content = analysis.db.file_text(position.file_id); - let hovered_element = &content[hover.range]; - - let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup); - expect.assert_eq(&actual) -} - -fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { - let (analysis, position) = fixture::position(ra_fixture); - let hover = analysis - .hover( - &HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::PlainText) }, - FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, - ) - .unwrap() - .unwrap(); - - let content = analysis.db.file_text(position.file_id); - let hovered_element = &content[hover.range]; - - let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup); - expect.assert_eq(&actual) -} - -fn check_actions(ra_fixture: &str, expect: Expect) { - let (analysis, file_id, position) = fixture::range_or_position(ra_fixture); - let hover = analysis - .hover( - &HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::Markdown) }, - FileRange { file_id, range: position.range_or_empty() }, - ) - .unwrap() - .unwrap(); - expect.assert_debug_eq(&hover.info.actions) -} - -fn check_hover_range(ra_fixture: &str, expect: Expect) { - let (analysis, range) = fixture::range(ra_fixture); - let hover = analysis - .hover( - &HoverConfig { links_in_hover: false, documentation: Some(HoverDocFormat::Markdown) }, - range, - ) - .unwrap() - .unwrap(); - expect.assert_eq(hover.info.markup.as_str()) -} - -fn check_hover_range_no_results(ra_fixture: &str) { - let (analysis, range) = fixture::range(ra_fixture); - let hover = analysis - .hover( - &HoverConfig { links_in_hover: false, documentation: Some(HoverDocFormat::Markdown) }, - range, - ) - .unwrap(); - assert!(hover.is_none()); -} - -#[test] -fn hover_descend_macros_avoids_duplicates() { - check( - r#" -macro_rules! dupe_use { - ($local:ident) => { - { - $local; - $local; - } - } -} -fn foo() { - let local = 0; - dupe_use!(local$0); -} -"#, - expect![[r#" - *local* - - ```rust - let local: i32 - ``` - "#]], - ); -} - -#[test] -fn hover_shows_all_macro_descends() { - check( - r#" -macro_rules! m { - ($name:ident) => { - /// Outer - fn $name() {} - - mod module { - /// Inner - fn $name() {} - } - }; -} - -m!(ab$0c); - "#, - expect![[r#" - *abc* - - ```rust - test::module - ``` - - ```rust - fn abc() - ``` - - --- - - Inner - --- - - ```rust - test - ``` - - ```rust - fn abc() - ``` - - --- - - Outer - "#]], - ); -} - -#[test] -fn hover_shows_type_of_an_expression() { - check( - r#" -pub fn foo() -> u32 { 1 } - -fn main() { - let foo_test = foo()$0; -} -"#, - expect![[r#" - *foo()* - ```rust - u32 - ``` - "#]], - ); -} - -#[test] -fn hover_remove_markdown_if_configured() { - check_hover_no_markdown( - r#" -pub fn foo() -> u32 { 1 } - -fn main() { - let foo_test = foo()$0; -} -"#, - expect![[r#" - *foo()* - u32 - "#]], - ); -} - -#[test] -fn hover_shows_long_type_of_an_expression() { - check( - r#" -struct Scan { a: A, b: B, c: C } -struct Iter { inner: I } -enum Option { Some(T), None } - -struct OtherStruct { i: T } - -fn scan(a: A, b: B, c: C) -> Iter, B, C>> { - Iter { inner: Scan { a, b, c } } -} - -fn main() { - let num: i32 = 55; - let closure = |memo: &mut u32, value: &u32, _another: &mut u32| -> Option { - Option::Some(*memo + value) - }; - let number = 5u32; - let mut iter$0 = scan(OtherStruct { i: num }, closure, number); -} -"#, - expect![[r#" - *iter* - - ```rust - let mut iter: Iter>, |&mut u32, &u32, &mut u32| -> Option, u32>> - ``` - "#]], - ); -} - -#[test] -fn hover_shows_fn_signature() { - // Single file with result - check( - r#" -pub fn foo() -> u32 { 1 } - -fn main() { let foo_test = fo$0o(); } -"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - pub fn foo() -> u32 - ``` - "#]], - ); - - // Multiple candidates but results are ambiguous. - check( - r#" -//- /a.rs -pub fn foo() -> u32 { 1 } - -//- /b.rs -pub fn foo() -> &str { "" } - -//- /c.rs -pub fn foo(a: u32, b: u32) {} - -//- /main.rs -mod a; -mod b; -mod c; - -fn main() { let foo_test = fo$0o(); } - "#, - expect![[r#" - *foo* - ```rust - {unknown} - ``` - "#]], - ); - - // Use literal `crate` in path - check( - r#" -pub struct X; - -fn foo() -> crate::X { X } - -fn main() { f$0oo(); } - "#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - fn foo() -> crate::X - ``` - "#]], - ); - - // Check `super` in path - check( - r#" -pub struct X; - -mod m { pub fn foo() -> super::X { super::X } } - -fn main() { m::f$0oo(); } - "#, - expect![[r#" - *foo* - - ```rust - test::m - ``` - - ```rust - pub fn foo() -> super::X - ``` - "#]], - ); -} - -#[test] -fn hover_omits_unnamed_where_preds() { - check( - r#" -pub fn foo(bar: impl T) { } - -fn main() { fo$0o(); } - "#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - pub fn foo(bar: impl T) - ``` - "#]], - ); - check( - r#" -pub fn foo>(bar: impl T, baz: V) { } - -fn main() { fo$0o(); } - "#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - pub fn foo(bar: impl T, baz: V) - where - V: AsRef, - ``` - "#]], - ); -} - -#[test] -fn hover_shows_fn_signature_with_type_params() { - check( - r#" -pub fn foo<'a, T: AsRef>(b: &'a T) -> &'a str { } - -fn main() { let foo_test = fo$0o(); } - "#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - pub fn foo<'a, T>(b: &'a T) -> &'a str - where - T: AsRef, - ``` - "#]], - ); -} - -#[test] -fn hover_shows_fn_signature_on_fn_name() { - check( - r#" -pub fn foo$0(a: u32, b: u32) -> u32 {} - -fn main() { } -"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - pub fn foo(a: u32, b: u32) -> u32 - ``` - "#]], - ); -} - -#[test] -fn hover_shows_fn_doc() { - check( - r#" -/// # Example -/// ``` -/// # use std::path::Path; -/// # -/// foo(Path::new("hello, world!")) -/// ``` -pub fn foo$0(_: &Path) {} - -fn main() { } -"#, - expect![[r##" - *foo* - - ```rust - test - ``` - - ```rust - pub fn foo(_: &Path) - ``` - - --- - - # Example - - ``` - # use std::path::Path; - # - foo(Path::new("hello, world!")) - ``` - "##]], - ); -} - -#[test] -fn hover_shows_fn_doc_attr_raw_string() { - check( - r##" -#[doc = r#"Raw string doc attr"#] -pub fn foo$0(_: &Path) {} - -fn main() { } -"##, - expect![[r##" - *foo* - - ```rust - test - ``` - - ```rust - pub fn foo(_: &Path) - ``` - - --- - - Raw string doc attr - "##]], - ); -} - -#[test] -fn hover_shows_struct_field_info() { - // Hovering over the field when instantiating - check( - r#" -struct Foo { field_a: u32 } - -fn main() { - let foo = Foo { field_a$0: 0, }; -} -"#, - expect![[r#" - *field_a* - - ```rust - test::Foo - ``` - - ```rust - field_a: u32 - ``` - "#]], - ); - - // Hovering over the field in the definition - check( - r#" -struct Foo { field_a$0: u32 } - -fn main() { - let foo = Foo { field_a: 0 }; -} -"#, - expect![[r#" - *field_a* - - ```rust - test::Foo - ``` - - ```rust - field_a: u32 - ``` - "#]], - ); -} - -#[test] -fn hover_const_static() { - check( - r#"const foo$0: u32 = 123;"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - const foo: u32 = 123 (0x7B) - ``` - "#]], - ); - check( - r#" -const foo$0: u32 = { - let x = foo(); - x + 100 -};"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - const foo: u32 = { - let x = foo(); - x + 100 - } - ``` - "#]], - ); - - check( - r#"static foo$0: u32 = 456;"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - static foo: u32 = 456 - ``` - "#]], - ); -} - -#[test] -fn hover_default_generic_types() { - check( - r#" -struct Test { k: K, t: T } - -fn main() { - let zz$0 = Test { t: 23u8, k: 33 }; -}"#, - expect![[r#" - *zz* - - ```rust - let zz: Test - ``` - "#]], - ); - check_hover_range( - r#" -struct Test { k: K, t: T } - -fn main() { - let $0zz$0 = Test { t: 23u8, k: 33 }; -}"#, - expect![[r#" - ```rust - Test - ```"#]], - ); -} - -#[test] -fn hover_some() { - check( - r#" -enum Option { Some(T) } -use Option::Some; - -fn main() { So$0me(12); } -"#, - expect![[r#" - *Some* - - ```rust - test::Option - ``` - - ```rust - Some(T) - ``` - "#]], - ); - - check( - r#" -enum Option { Some(T) } -use Option::Some; - -fn main() { let b$0ar = Some(12); } -"#, - expect![[r#" - *bar* - - ```rust - let bar: Option - ``` - "#]], - ); -} - -#[test] -fn hover_enum_variant() { - check( - r#" -enum Option { - /// The None variant - Non$0e -} -"#, - expect![[r#" - *None* - - ```rust - test::Option - ``` - - ```rust - None - ``` - - --- - - The None variant - "#]], - ); - - check( - r#" -enum Option { - /// The Some variant - Some(T) -} -fn main() { - let s = Option::Som$0e(12); -} -"#, - expect![[r#" - *Some* - - ```rust - test::Option - ``` - - ```rust - Some(T) - ``` - - --- - - The Some variant - "#]], - ); -} - -#[test] -fn hover_for_local_variable() { - check( - r#"fn func(foo: i32) { fo$0o; }"#, - expect![[r#" - *foo* - - ```rust - foo: i32 - ``` - "#]], - ) -} - -#[test] -fn hover_for_local_variable_pat() { - check( - r#"fn func(fo$0o: i32) {}"#, - expect![[r#" - *foo* - - ```rust - foo: i32 - ``` - "#]], - ) -} - -#[test] -fn hover_local_var_edge() { - check( - r#"fn func(foo: i32) { if true { $0foo; }; }"#, - expect![[r#" - *foo* - - ```rust - foo: i32 - ``` - "#]], - ) -} - -#[test] -fn hover_for_param_edge() { - check( - r#"fn func($0foo: i32) {}"#, - expect![[r#" - *foo* - - ```rust - foo: i32 - ``` - "#]], - ) -} - -#[test] -fn hover_for_param_with_multiple_traits() { - check( - r#" - //- minicore: sized - trait Deref { - type Target: ?Sized; - } - trait DerefMut { - type Target: ?Sized; - } - fn f(_x$0: impl Deref + DerefMut) {}"#, - expect![[r#" - *_x* - - ```rust - _x: impl Deref + DerefMut - ``` - "#]], - ) -} - -#[test] -fn test_hover_infer_associated_method_result() { - check( - r#" -struct Thing { x: u32 } - -impl Thing { - fn new() -> Thing { Thing { x: 0 } } -} - -fn main() { let foo_$0test = Thing::new(); } -"#, - expect![[r#" - *foo_test* - - ```rust - let foo_test: Thing - ``` - "#]], - ) -} - -#[test] -fn test_hover_infer_associated_method_exact() { - check( - r#" -mod wrapper { - pub struct Thing { x: u32 } - - impl Thing { - pub fn new() -> Thing { Thing { x: 0 } } - } -} - -fn main() { let foo_test = wrapper::Thing::new$0(); } -"#, - expect![[r#" - *new* - - ```rust - test::wrapper::Thing - ``` - - ```rust - pub fn new() -> Thing - ``` - "#]], - ) -} - -#[test] -fn test_hover_infer_associated_const_in_pattern() { - check( - r#" -struct X; -impl X { - const C: u32 = 1; -} - -fn main() { - match 1 { - X::C$0 => {}, - 2 => {}, - _ => {} - }; -} -"#, - expect![[r#" - *C* - - ```rust - test - ``` - - ```rust - const C: u32 = 1 - ``` - "#]], - ) -} - -#[test] -fn test_hover_self() { - check( - r#" -struct Thing { x: u32 } -impl Thing { - fn new() -> Self { Self$0 { x: 0 } } -} -"#, - expect![[r#" - *Self* - - ```rust - test - ``` - - ```rust - struct Thing - ``` - "#]], - ); - check( - r#" -struct Thing { x: u32 } -impl Thing { - fn new() -> Self$0 { Self { x: 0 } } -} -"#, - expect![[r#" - *Self* - - ```rust - test - ``` - - ```rust - struct Thing - ``` - "#]], - ); - check( - r#" -enum Thing { A } -impl Thing { - pub fn new() -> Self$0 { Thing::A } -} -"#, - expect![[r#" - *Self* - - ```rust - test - ``` - - ```rust - enum Thing - ``` - "#]], - ); - check( - r#" - enum Thing { A } - impl Thing { - pub fn thing(a: Self$0) {} - } - "#, - expect![[r#" - *Self* - - ```rust - test - ``` - - ```rust - enum Thing - ``` - "#]], - ); -} - -#[test] -fn test_hover_shadowing_pat() { - check( - r#" -fn x() {} - -fn y() { - let x = 0i32; - x$0; -} -"#, - expect![[r#" - *x* - - ```rust - let x: i32 - ``` - "#]], - ) -} - -#[test] -fn test_hover_macro_invocation() { - check( - r#" -macro_rules! foo { () => {} } - -fn f() { fo$0o!(); } -"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - macro_rules! foo - ``` - "#]], - ) -} - -#[test] -fn test_hover_macro2_invocation() { - check( - r#" -/// foo bar -/// -/// foo bar baz -macro foo() {} - -fn f() { fo$0o!(); } -"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - macro foo - ``` - - --- - - foo bar - - foo bar baz - "#]], - ) -} - -#[test] -fn test_hover_tuple_field() { - check( - r#"struct TS(String, i32$0);"#, - expect![[r#" - *i32* - - ```rust - i32 - ``` - "#]], - ) -} - -#[test] -fn test_hover_through_macro() { - check( - r#" -macro_rules! id { ($($tt:tt)*) => { $($tt)* } } -fn foo() {} -id! { - fn bar() { fo$0o(); } -} -"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - fn foo() - ``` - "#]], - ); -} - -#[test] -fn test_hover_through_attr() { - check( - r#" -//- proc_macros: identity -#[proc_macros::identity] -fn foo$0() {} -"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - fn foo() - ``` - "#]], - ); -} - -#[test] -fn test_hover_through_expr_in_macro() { - check( - r#" -macro_rules! id { ($($tt:tt)*) => { $($tt)* } } -fn foo(bar:u32) { let a = id!(ba$0r); } -"#, - expect![[r#" - *bar* - - ```rust - bar: u32 - ``` - "#]], - ); -} - -#[test] -fn test_hover_through_expr_in_macro_recursive() { - check( - r#" -macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } } -macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } -fn foo(bar:u32) { let a = id!(ba$0r); } -"#, - expect![[r#" - *bar* - - ```rust - bar: u32 - ``` - "#]], - ); -} - -#[test] -fn test_hover_through_func_in_macro_recursive() { - check( - r#" -macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } } -macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } -fn bar() -> u32 { 0 } -fn foo() { let a = id!([0u32, bar($0)] ); } -"#, - expect![[r#" - *bar()* - ```rust - u32 - ``` - "#]], - ); -} - -#[test] -fn test_hover_through_literal_string_in_macro() { - check( - r#" -macro_rules! arr { ($($tt:tt)*) => { [$($tt)*] } } -fn foo() { - let mastered_for_itunes = ""; - let _ = arr!("Tr$0acks", &mastered_for_itunes); -} -"#, - expect![[r#" - *"Tracks"* - ```rust - &str - ``` - "#]], - ); -} - -#[test] -fn test_hover_through_assert_macro() { - check( - r#" -#[rustc_builtin_macro] -macro_rules! assert {} - -fn bar() -> bool { true } -fn foo() { - assert!(ba$0r()); -} -"#, - expect![[r#" - *bar* - - ```rust - test - ``` - - ```rust - fn bar() -> bool - ``` - "#]], - ); -} - -#[test] -fn test_hover_multiple_actions() { - check_actions( - r#" -struct Bar; -struct Foo { bar: Bar } - -fn foo(Foo { b$0ar }: &Foo) {} - "#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Bar", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..11, - focus_range: 7..10, - name: "Bar", - kind: Struct, - description: "struct Bar", - }, - }, - ], - ), - ] - "#]], - ) -} - -#[test] -fn test_hover_through_literal_string_in_builtin_macro() { - check_hover_no_result( - r#" - #[rustc_builtin_macro] - macro_rules! format {} - - fn foo() { - format!("hel$0lo {}", 0); - } -"#, - ); -} - -#[test] -fn test_hover_non_ascii_space_doc() { - check( - " -/// <- `\u{3000}` here -fn foo() { } - -fn bar() { fo$0o(); } -", - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - fn foo() - ``` - - --- - - \<- ` ` here - "#]], - ); -} - -#[test] -fn test_hover_function_show_qualifiers() { - check( - r#"async fn foo$0() {}"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - async fn foo() - ``` - "#]], - ); - check( - r#"pub const unsafe fn foo$0() {}"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - pub const unsafe fn foo() - ``` - "#]], - ); - // Top level `pub(crate)` will be displayed as no visibility. - check( - r#"mod m { pub(crate) async unsafe extern "C" fn foo$0() {} }"#, - expect![[r#" - *foo* - - ```rust - test::m - ``` - - ```rust - pub(crate) async unsafe extern "C" fn foo() - ``` - "#]], - ); -} - -#[test] -fn test_hover_function_show_types() { - check( - r#"fn foo$0(a: i32, b:i32) -> i32 { 0 }"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - fn foo(a: i32, b: i32) -> i32 - ``` - "#]], - ); -} - -#[test] -fn test_hover_function_pointer_show_identifiers() { - check( - r#"type foo$0 = fn(a: i32, b: i32) -> i32;"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - type foo = fn(a: i32, b: i32) -> i32 - ``` - "#]], - ); -} - -#[test] -fn test_hover_function_pointer_no_identifier() { - check( - r#"type foo$0 = fn(i32, _: i32) -> i32;"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - type foo = fn(i32, i32) -> i32 - ``` - "#]], - ); -} - -#[test] -fn test_hover_trait_show_qualifiers() { - check_actions( - r"unsafe trait foo$0() {}", - expect![[r#" - [ - Implementation( - FilePosition { - file_id: FileId( - 0, - ), - offset: 13, - }, - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_extern_crate() { - check( - r#" -//- /main.rs crate:main deps:std -extern crate st$0d; -//- /std/lib.rs crate:std -//! Standard library for this test -//! -//! Printed? -//! abc123 -"#, - expect![[r#" - *std* - - ```rust - extern crate std - ``` - - --- - - Standard library for this test - - Printed? - abc123 - "#]], - ); - check( - r#" -//- /main.rs crate:main deps:std -extern crate std as ab$0c; -//- /std/lib.rs crate:std -//! Standard library for this test -//! -//! Printed? -//! abc123 -"#, - expect![[r#" - *abc* - - ```rust - extern crate std - ``` - - --- - - Standard library for this test - - Printed? - abc123 - "#]], - ); -} - -#[test] -fn test_hover_mod_with_same_name_as_function() { - check( - r#" -use self::m$0y::Bar; -mod my { pub struct Bar; } - -fn my() {} -"#, - expect![[r#" - *my* - - ```rust - test - ``` - - ```rust - mod my - ``` - "#]], - ); -} - -#[test] -fn test_hover_struct_doc_comment() { - check( - r#" -/// This is an example -/// multiline doc -/// -/// # Example -/// -/// ``` -/// let five = 5; -/// -/// assert_eq!(6, my_crate::add_one(5)); -/// ``` -struct Bar; - -fn foo() { let bar = Ba$0r; } -"#, - expect![[r##" - *Bar* - - ```rust - test - ``` - - ```rust - struct Bar - ``` - - --- - - This is an example - multiline doc - - # Example - - ``` - let five = 5; - - assert_eq!(6, my_crate::add_one(5)); - ``` - "##]], - ); -} - -#[test] -fn test_hover_struct_doc_attr() { - check( - r#" -#[doc = "bar docs"] -struct Bar; - -fn foo() { let bar = Ba$0r; } -"#, - expect![[r#" - *Bar* - - ```rust - test - ``` - - ```rust - struct Bar - ``` - - --- - - bar docs - "#]], - ); -} - -#[test] -fn test_hover_struct_doc_attr_multiple_and_mixed() { - check( - r#" -/// bar docs 0 -#[doc = "bar docs 1"] -#[doc = "bar docs 2"] -struct Bar; - -fn foo() { let bar = Ba$0r; } -"#, - expect![[r#" - *Bar* - - ```rust - test - ``` - - ```rust - struct Bar - ``` - - --- - - bar docs 0 - bar docs 1 - bar docs 2 - "#]], - ); -} - -#[test] -fn test_hover_external_url() { - check( - r#" -pub struct Foo; -/// [external](https://www.google.com) -pub struct B$0ar -"#, - expect![[r#" - *Bar* - - ```rust - test - ``` - - ```rust - pub struct Bar - ``` - - --- - - [external](https://www.google.com) - "#]], - ); -} - -// Check that we don't rewrite links which we can't identify -#[test] -fn test_hover_unknown_target() { - check( - r#" -pub struct Foo; -/// [baz](Baz) -pub struct B$0ar -"#, - expect![[r#" - *Bar* - - ```rust - test - ``` - - ```rust - pub struct Bar - ``` - - --- - - [baz](Baz) - "#]], - ); -} - -#[test] -fn test_hover_no_links() { - check_hover_no_links( - r#" -/// Test cases: -/// case 1. bare URL: https://www.example.com/ -/// case 2. inline URL with title: [example](https://www.example.com/) -/// case 3. code reference: [`Result`] -/// case 4. code reference but miss footnote: [`String`] -/// case 5. autolink: -/// case 6. email address: -/// case 7. reference: [example][example] -/// case 8. collapsed link: [example][] -/// case 9. shortcut link: [example] -/// case 10. inline without URL: [example]() -/// case 11. reference: [foo][foo] -/// case 12. reference: [foo][bar] -/// case 13. collapsed link: [foo][] -/// case 14. shortcut link: [foo] -/// case 15. inline without URL: [foo]() -/// case 16. just escaped text: \[foo] -/// case 17. inline link: [Foo](foo::Foo) -/// -/// [`Result`]: ../../std/result/enum.Result.html -/// [^example]: https://www.example.com/ -pub fn fo$0o() {} -"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - pub fn foo() - ``` - - --- - - Test cases: - case 1. bare URL: https://www.example.com/ - case 2. inline URL with title: [example](https://www.example.com/) - case 3. code reference: `Result` - case 4. code reference but miss footnote: `String` - case 5. autolink: http://www.example.com/ - case 6. email address: test@example.com - case 7. reference: example - case 8. collapsed link: example - case 9. shortcut link: example - case 10. inline without URL: example - case 11. reference: foo - case 12. reference: foo - case 13. collapsed link: foo - case 14. shortcut link: foo - case 15. inline without URL: foo - case 16. just escaped text: \[foo\] - case 17. inline link: Foo - - [^example]: https://www.example.com/ - "#]], - ); -} - -#[test] -fn test_hover_macro_generated_struct_fn_doc_comment() { - cov_mark::check!(hover_macro_generated_struct_fn_doc_comment); - - check( - r#" -macro_rules! bar { - () => { - struct Bar; - impl Bar { - /// Do the foo - fn foo(&self) {} - } - } -} - -bar!(); - -fn foo() { let bar = Bar; bar.fo$0o(); } -"#, - expect![[r#" - *foo* - - ```rust - test::Bar - ``` - - ```rust - fn foo(&self) - ``` - - --- - - Do the foo - "#]], - ); -} - -#[test] -fn test_hover_macro_generated_struct_fn_doc_attr() { - cov_mark::check!(hover_macro_generated_struct_fn_doc_attr); - - check( - r#" -macro_rules! bar { - () => { - struct Bar; - impl Bar { - #[doc = "Do the foo"] - fn foo(&self) {} - } - } -} - -bar!(); - -fn foo() { let bar = Bar; bar.fo$0o(); } -"#, - expect![[r#" - *foo* - - ```rust - test::Bar - ``` - - ```rust - fn foo(&self) - ``` - - --- - - Do the foo - "#]], - ); -} - -#[test] -fn test_hover_variadic_function() { - check( - r#" -extern "C" { - pub fn foo(bar: i32, ...) -> i32; -} - -fn main() { let foo_test = unsafe { fo$0o(1, 2, 3); } } -"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - pub unsafe fn foo(bar: i32, ...) -> i32 - ``` - "#]], - ); -} - -#[test] -fn test_hover_trait_has_impl_action() { - check_actions( - r#"trait foo$0() {}"#, - expect![[r#" - [ - Implementation( - FilePosition { - file_id: FileId( - 0, - ), - offset: 6, - }, - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_struct_has_impl_action() { - check_actions( - r"struct foo$0() {}", - expect![[r#" - [ - Implementation( - FilePosition { - file_id: FileId( - 0, - ), - offset: 7, - }, - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_union_has_impl_action() { - check_actions( - r#"union foo$0() {}"#, - expect![[r#" - [ - Implementation( - FilePosition { - file_id: FileId( - 0, - ), - offset: 6, - }, - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_enum_has_impl_action() { - check_actions( - r"enum foo$0() { A, B }", - expect![[r#" - [ - Implementation( - FilePosition { - file_id: FileId( - 0, - ), - offset: 5, - }, - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_self_has_impl_action() { - check_actions( - r#"struct foo where Self$0:;"#, - expect![[r#" - [ - Implementation( - FilePosition { - file_id: FileId( - 0, - ), - offset: 7, - }, - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_test_has_action() { - check_actions( - r#" -#[test] -fn foo_$0test() {} -"#, - expect![[r#" - [ - Reference( - FilePosition { - file_id: FileId( - 0, - ), - offset: 11, - }, - ), - Runnable( - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..24, - focus_range: 11..19, - name: "foo_test", - kind: Function, - }, - kind: Test { - test_id: Path( - "foo_test", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_test_mod_has_action() { - check_actions( - r#" -mod tests$0 { - #[test] - fn foo_test() {} -} -"#, - expect![[r#" - [ - Runnable( - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..46, - focus_range: 4..9, - name: "tests", - kind: Module, - description: "mod tests", - }, - kind: TestMod { - path: "tests", - }, - cfg: None, - }, - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_struct_has_goto_type_action() { - check_actions( - r#" -struct S{ f1: u32 } - -fn main() { let s$0t = S{ f1:0 }; } -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..19, - focus_range: 7..8, - name: "S", - kind: Struct, - description: "struct S", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_generic_struct_has_goto_type_actions() { - check_actions( - r#" -struct Arg(u32); -struct S{ f1: T } - -fn main() { let s$0t = S{ f1:Arg(0) }; } -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 17..37, - focus_range: 24..25, - name: "S", - kind: Struct, - description: "struct S", - }, - }, - HoverGotoTypeData { - mod_path: "test::Arg", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..16, - focus_range: 7..10, - name: "Arg", - kind: Struct, - description: "struct Arg", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_generic_struct_has_flattened_goto_type_actions() { - check_actions( - r#" -struct Arg(u32); -struct S{ f1: T } - -fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; } -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 17..37, - focus_range: 24..25, - name: "S", - kind: Struct, - description: "struct S", - }, - }, - HoverGotoTypeData { - mod_path: "test::Arg", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..16, - focus_range: 7..10, - name: "Arg", - kind: Struct, - description: "struct Arg", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_tuple_has_goto_type_actions() { - check_actions( - r#" -struct A(u32); -struct B(u32); -mod M { - pub struct C(u32); -} - -fn main() { let s$0t = (A(1), B(2), M::C(3) ); } -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::A", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..14, - focus_range: 7..8, - name: "A", - kind: Struct, - description: "struct A", - }, - }, - HoverGotoTypeData { - mod_path: "test::B", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 15..29, - focus_range: 22..23, - name: "B", - kind: Struct, - description: "struct B", - }, - }, - HoverGotoTypeData { - mod_path: "test::M::C", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 42..60, - focus_range: 53..54, - name: "C", - kind: Struct, - description: "pub struct C", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_return_impl_trait_has_goto_type_action() { - check_actions( - r#" -trait Foo {} -fn foo() -> impl Foo {} - -fn main() { let s$0t = foo(); } -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_generic_return_impl_trait_has_goto_type_action() { - check_actions( - r#" -trait Foo {} -struct S; -fn foo() -> impl Foo {} - -fn main() { let s$0t = foo(); } -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..15, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, - }, - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 16..25, - focus_range: 23..24, - name: "S", - kind: Struct, - description: "struct S", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_return_impl_traits_has_goto_type_action() { - check_actions( - r#" -trait Foo {} -trait Bar {} -fn foo() -> impl Foo + Bar {} - -fn main() { let s$0t = foo(); } -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, - }, - HoverGotoTypeData { - mod_path: "test::Bar", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 13..25, - focus_range: 19..22, - name: "Bar", - kind: Trait, - description: "trait Bar", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_generic_return_impl_traits_has_goto_type_action() { - check_actions( - r#" -trait Foo {} -trait Bar {} -struct S1 {} -struct S2 {} - -fn foo() -> impl Foo + Bar {} - -fn main() { let s$0t = foo(); } -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..15, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, - }, - HoverGotoTypeData { - mod_path: "test::Bar", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 16..31, - focus_range: 22..25, - name: "Bar", - kind: Trait, - description: "trait Bar", - }, - }, - HoverGotoTypeData { - mod_path: "test::S1", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 32..44, - focus_range: 39..41, - name: "S1", - kind: Struct, - description: "struct S1", - }, - }, - HoverGotoTypeData { - mod_path: "test::S2", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 45..57, - focus_range: 52..54, - name: "S2", - kind: Struct, - description: "struct S2", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_arg_impl_trait_has_goto_type_action() { - check_actions( - r#" -trait Foo {} -fn foo(ar$0g: &impl Foo) {} -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_arg_impl_traits_has_goto_type_action() { - check_actions( - r#" -trait Foo {} -trait Bar {} -struct S{} - -fn foo(ar$0g: &impl Foo + Bar) {} -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, - }, - HoverGotoTypeData { - mod_path: "test::Bar", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 13..28, - focus_range: 19..22, - name: "Bar", - kind: Trait, - description: "trait Bar", - }, - }, - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 29..39, - focus_range: 36..37, - name: "S", - kind: Struct, - description: "struct S", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_async_block_impl_trait_has_goto_type_action() { - check_actions( - r#" -//- /main.rs crate:main deps:core -// we don't use minicore here so that this test doesn't randomly fail -// when someone edits minicore -struct S; -fn foo() { - let fo$0o = async { S }; -} -//- /core.rs crate:core -pub mod future { - #[lang = "future_trait"] - pub trait Future {} -} -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "core::future::Future", - nav: NavigationTarget { - file_id: FileId( - 1, - ), - full_range: 21..69, - focus_range: 60..66, - name: "Future", - kind: Trait, - description: "pub trait Future", - }, - }, - HoverGotoTypeData { - mod_path: "main::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..110, - focus_range: 108..109, - name: "S", - kind: Struct, - description: "struct S", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_arg_generic_impl_trait_has_goto_type_action() { - check_actions( - r#" -trait Foo {} -struct S {} -fn foo(ar$0g: &impl Foo) {} -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..15, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, - }, - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 16..27, - focus_range: 23..24, - name: "S", - kind: Struct, - description: "struct S", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_dyn_return_has_goto_type_action() { - check_actions( - r#" -trait Foo {} -struct S; -impl Foo for S {} - -struct B{} -fn foo() -> B {} - -fn main() { let s$0t = foo(); } -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::B", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 42..55, - focus_range: 49..50, - name: "B", - kind: Struct, - description: "struct B", - }, - }, - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_dyn_arg_has_goto_type_action() { - check_actions( - r#" -trait Foo {} -fn foo(ar$0g: &dyn Foo) {} -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_generic_dyn_arg_has_goto_type_action() { - check_actions( - r#" -trait Foo {} -struct S {} -fn foo(ar$0g: &dyn Foo) {} -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..15, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, - }, - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 16..27, - focus_range: 23..24, - name: "S", - kind: Struct, - description: "struct S", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_goto_type_action_links_order() { - check_actions( - r#" -trait ImplTrait {} -trait DynTrait {} -struct B {} -struct S {} - -fn foo(a$0rg: &impl ImplTrait>>>) {} -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::ImplTrait", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..21, - focus_range: 6..15, - name: "ImplTrait", - kind: Trait, - description: "trait ImplTrait", - }, - }, - HoverGotoTypeData { - mod_path: "test::B", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 43..57, - focus_range: 50..51, - name: "B", - kind: Struct, - description: "struct B", - }, - }, - HoverGotoTypeData { - mod_path: "test::DynTrait", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 22..42, - focus_range: 28..36, - name: "DynTrait", - kind: Trait, - description: "trait DynTrait", - }, - }, - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 58..69, - focus_range: 65..66, - name: "S", - kind: Struct, - description: "struct S", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_associated_type_has_goto_type_action() { - check_actions( - r#" -trait Foo { - type Item; - fn get(self) -> Self::Item {} -} - -struct Bar{} -struct S{} - -impl Foo for S { type Item = Bar; } - -fn test() -> impl Foo { S {} } - -fn main() { let s$0t = test().get(); } -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..62, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_const_param_has_goto_type_action() { - check_actions( - r#" -struct Bar; -struct Foo; - -impl Foo {} -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Bar", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..11, - focus_range: 7..10, - name: "Bar", - kind: Struct, - description: "struct Bar", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_type_param_has_goto_type_action() { - check_actions( - r#" -trait Foo {} - -fn foo(t: T$0){} -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn test_hover_self_has_go_to_type() { - check_actions( - r#" -struct Foo; -impl Foo { - fn foo(&self$0) {} -} -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..11, - focus_range: 7..10, - name: "Foo", - kind: Struct, - description: "struct Foo", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn hover_displays_normalized_crate_names() { - check( - r#" -//- /lib.rs crate:name-with-dashes -pub mod wrapper { - pub struct Thing { x: u32 } - - impl Thing { - pub fn new() -> Thing { Thing { x: 0 } } - } -} - -//- /main.rs crate:main deps:name-with-dashes -fn main() { let foo_test = name_with_dashes::wrapper::Thing::new$0(); } -"#, - expect![[r#" - *new* - - ```rust - name_with_dashes::wrapper::Thing - ``` - - ```rust - pub fn new() -> Thing - ``` - "#]], - ) -} - -#[test] -fn hover_field_pat_shorthand_ref_match_ergonomics() { - check( - r#" -struct S { - f: i32, -} - -fn main() { - let s = S { f: 0 }; - let S { f$0 } = &s; -} -"#, - expect![[r#" - *f* - - ```rust - f: &i32 - ``` - --- - - ```rust - test::S - ``` - - ```rust - f: i32 - ``` - "#]], - ); -} - -#[test] -fn const_generic_order() { - check( - r#" -struct Foo; -struct S$0T(T); -"#, - expect![[r#" - *ST* - - ```rust - test - ``` - - ```rust - struct ST - ``` - "#]], - ); -} - -#[test] -fn const_generic_positive_i8_literal() { - check( - r#" -struct Const; - -fn main() { - let v$0alue = Const::<1>; -} -"#, - expect![[r#" - *value* - - ```rust - let value: Const<1> - ``` - "#]], - ); -} - -#[test] -fn const_generic_zero_i8_literal() { - check( - r#" -struct Const; - -fn main() { - let v$0alue = Const::<0>; -} -"#, - expect![[r#" - *value* - - ```rust - let value: Const<0> - ``` - "#]], - ); -} - -#[test] -fn const_generic_negative_i8_literal() { - check( - r#" -struct Const; - -fn main() { - let v$0alue = Const::<-1>; -} -"#, - expect![[r#" - *value* - - ```rust - let value: Const<-1> - ``` - "#]], - ); -} - -#[test] -fn const_generic_bool_literal() { - check( - r#" -struct Const; - -fn main() { - let v$0alue = Const::; -} -"#, - expect![[r#" - *value* - - ```rust - let value: Const - ``` - "#]], - ); -} - -#[test] -fn const_generic_char_literal() { - check( - r#" -struct Const; - -fn main() { - let v$0alue = Const::<'🦀'>; -} -"#, - expect![[r#" - *value* - - ```rust - let value: Const<'🦀'> - ``` - "#]], - ); -} - -#[test] -fn hover_self_param_shows_type() { - check( - r#" -struct Foo {} -impl Foo { - fn bar(&sel$0f) {} -} -"#, - expect![[r#" - *self* - - ```rust - self: &Foo - ``` - "#]], - ); -} - -#[test] -fn hover_self_param_shows_type_for_arbitrary_self_type() { - check( - r#" -struct Arc(T); -struct Foo {} -impl Foo { - fn bar(sel$0f: Arc) {} -} -"#, - expect![[r#" - *self* - - ```rust - self: Arc - ``` - "#]], - ); -} - -#[test] -fn hover_doc_outer_inner() { - check( - r#" -/// Be quick; -mod Foo$0 { - //! time is mana - - /// This comment belongs to the function - fn foo() {} -} -"#, - expect![[r#" - *Foo* - - ```rust - test - ``` - - ```rust - mod Foo - ``` - - --- - - Be quick; - time is mana - "#]], - ); -} - -#[test] -fn hover_doc_outer_inner_attribue() { - check( - r#" -#[doc = "Be quick;"] -mod Foo$0 { - #![doc = "time is mana"] - - #[doc = "This comment belongs to the function"] - fn foo() {} -} -"#, - expect![[r#" - *Foo* - - ```rust - test - ``` - - ```rust - mod Foo - ``` - - --- - - Be quick; - time is mana - "#]], - ); -} - -#[test] -fn hover_doc_block_style_indentend() { - check( - r#" -/** - foo - ```rust - let x = 3; - ``` -*/ -fn foo$0() {} -"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - fn foo() - ``` - - --- - - foo - - ```rust - let x = 3; - ``` - "#]], - ); -} - -#[test] -fn hover_comments_dont_highlight_parent() { - cov_mark::check!(no_highlight_on_comment_hover); - check_hover_no_result( - r#" -fn no_hover() { - // no$0hover -} -"#, - ); -} - -#[test] -fn hover_label() { - check( - r#" -fn foo() { - 'label$0: loop {} -} -"#, - expect![[r#" - *'label* - - ```rust - 'label - ``` - "#]], - ); -} - -#[test] -fn hover_lifetime() { - check( - r#"fn foo<'lifetime>(_: &'lifetime$0 ()) {}"#, - expect![[r#" - *'lifetime* - - ```rust - 'lifetime - ``` - "#]], - ); -} - -#[test] -fn hover_type_param() { - check( - r#" -//- minicore: sized -struct Foo(T); -trait TraitA {} -trait TraitB {} -impl Foo where T: Sized {} -"#, - expect![[r#" - *T* - - ```rust - T: TraitA + TraitB - ``` - "#]], - ); - check( - r#" -//- minicore: sized -struct Foo(T); -impl Foo {} -"#, - expect![[r#" - *T* - - ```rust - T - ``` - "#]], - ); - // lifetimes bounds arent being tracked yet - check( - r#" -//- minicore: sized -struct Foo(T); -impl Foo {} -"#, - expect![[r#" - *T* - - ```rust - T - ``` - "#]], - ); -} - -#[test] -fn hover_type_param_sized_bounds() { - // implicit `: Sized` bound - check( - r#" -//- minicore: sized -trait Trait {} -struct Foo(T); -impl Foo {} -"#, - expect![[r#" - *T* - - ```rust - T: Trait - ``` - "#]], - ); - check( - r#" -//- minicore: sized -trait Trait {} -struct Foo(T); -impl Foo {} -"#, - expect![[r#" - *T* - - ```rust - T: Trait + ?Sized - ``` - "#]], - ); -} - -mod type_param_sized_bounds { - use super::*; - - #[test] - fn single_implicit() { - check( - r#" -//- minicore: sized -fn foo() {} -"#, - expect![[r#" - *T* - - ```rust - T - ``` - "#]], - ); - } - - #[test] - fn single_explicit() { - check( - r#" -//- minicore: sized -fn foo() {} -"#, - expect![[r#" - *T* - - ```rust - T - ``` - "#]], - ); - } - - #[test] - fn single_relaxed() { - check( - r#" -//- minicore: sized -fn foo() {} -"#, - expect![[r#" - *T* - - ```rust - T: ?Sized - ``` - "#]], - ); - } - - #[test] - fn multiple_implicit() { - check( - r#" -//- minicore: sized -trait Trait {} -fn foo() {} -"#, - expect![[r#" - *T* - - ```rust - T: Trait - ``` - "#]], - ); - } - - #[test] - fn multiple_explicit() { - check( - r#" -//- minicore: sized -trait Trait {} -fn foo() {} -"#, - expect![[r#" - *T* - - ```rust - T: Trait - ``` - "#]], - ); - } - - #[test] - fn multiple_relaxed() { - check( - r#" -//- minicore: sized -trait Trait {} -fn foo() {} -"#, - expect![[r#" - *T* - - ```rust - T: Trait + ?Sized - ``` - "#]], - ); - } - - #[test] - fn mixed() { - check( - r#" -//- minicore: sized -fn foo() {} -"#, - expect![[r#" - *T* - - ```rust - T - ``` - "#]], - ); - check( - r#" -//- minicore: sized -trait Trait {} -fn foo() {} -"#, - expect![[r#" - *T* - - ```rust - T: Trait - ``` - "#]], - ); - } -} - -#[test] -fn hover_const_generic_type_alias() { - check( - r#" -struct Foo; -type Fo$0o2 = Foo<2>; -"#, - expect![[r#" - *Foo2* - - ```rust - test - ``` - - ```rust - type Foo2 = Foo<2> - ``` - "#]], - ); -} - -#[test] -fn hover_const_param() { - check( - r#" -struct Foo; -impl Foo {} -"#, - expect![[r#" - *LEN* - - ```rust - const LEN: usize - ``` - "#]], - ); -} - -#[test] -fn hover_const_eval() { - // show hex for <10 - check( - r#" -/// This is a doc -const FOO$0: usize = 1 << 3; -"#, - expect![[r#" - *FOO* - - ```rust - test - ``` - - ```rust - const FOO: usize = 8 - ``` - - --- - - This is a doc - "#]], - ); - // show hex for >10 - check( - r#" -/// This is a doc -const FOO$0: usize = (1 << 3) + (1 << 2); -"#, - expect![[r#" - *FOO* - - ```rust - test - ``` - - ```rust - const FOO: usize = 12 (0xC) - ``` - - --- - - This is a doc - "#]], - ); - // show original body when const eval fails - check( - r#" -/// This is a doc -const FOO$0: usize = 2 - 3; -"#, - expect![[r#" - *FOO* - - ```rust - test - ``` - - ```rust - const FOO: usize = 2 - 3 - ``` - - --- - - This is a doc - "#]], - ); - // don't show hex for negatives - check( - r#" -/// This is a doc -const FOO$0: i32 = 2 - 3; -"#, - expect![[r#" - *FOO* - - ```rust - test - ``` - - ```rust - const FOO: i32 = -1 - ``` - - --- - - This is a doc - "#]], - ); - check( - r#" -/// This is a doc -const FOO$0: &str = "bar"; -"#, - expect![[r#" - *FOO* - - ```rust - test - ``` - - ```rust - const FOO: &str = "bar" - ``` - - --- - - This is a doc - "#]], - ); - // show char literal - check( - r#" -/// This is a doc -const FOO$0: char = 'a'; -"#, - expect![[r#" - *FOO* - - ```rust - test - ``` - - ```rust - const FOO: char = 'a' - ``` - - --- - - This is a doc - "#]], - ); - // show escaped char literal - check( - r#" -/// This is a doc -const FOO$0: char = '\x61'; -"#, - expect![[r#" - *FOO* - - ```rust - test - ``` - - ```rust - const FOO: char = 'a' - ``` - - --- - - This is a doc - "#]], - ); - // show byte literal - check( - r#" -/// This is a doc -const FOO$0: u8 = b'a'; -"#, - expect![[r#" - *FOO* - - ```rust - test - ``` - - ```rust - const FOO: u8 = 97 (0x61) - ``` - - --- - - This is a doc - "#]], - ); - // show escaped byte literal - check( - r#" -/// This is a doc -const FOO$0: u8 = b'\x61'; -"#, - expect![[r#" - *FOO* - - ```rust - test - ``` - - ```rust - const FOO: u8 = 97 (0x61) - ``` - - --- - - This is a doc - "#]], - ); - // show float literal - check( - r#" - /// This is a doc - const FOO$0: f64 = 1.0234; - "#, - expect![[r#" - *FOO* - - ```rust - test - ``` - - ```rust - const FOO: f64 = 1.0234 - ``` - - --- - - This is a doc - "#]], - ); - //show float typecasted from int - check( - r#" -/// This is a doc -const FOO$0: f32 = 1f32; -"#, - expect![[r#" - *FOO* - - ```rust - test - ``` - - ```rust - const FOO: f32 = 1.0 - ``` - - --- - - This is a doc - "#]], - ); - //show f64 typecasted from float - check( - r#" -/// This is a doc -const FOO$0: f64 = 1.0f64; -"#, - expect![[r#" - *FOO* - - ```rust - test - ``` - - ```rust - const FOO: f64 = 1.0 - ``` - - --- - - This is a doc - "#]], - ); -} - -#[test] -fn hover_const_pat() { - check( - r#" -/// This is a doc -const FOO: usize = 3; -fn foo() { - match 5 { - FOO$0 => (), - _ => () - } -} -"#, - expect![[r#" - *FOO* - - ```rust - test - ``` - - ```rust - const FOO: usize = 3 - ``` - - --- - - This is a doc - "#]], - ); -} - -#[test] -fn array_repeat_exp() { - check( - r#" -fn main() { - let til$0e4 = [0_u32; (4 * 8 * 8) / 32]; -} - "#, - expect![[r#" - *tile4* - - ```rust - let tile4: [u32; 8] - ``` - "#]], - ); -} - -#[test] -fn hover_mod_def() { - check( - r#" -//- /main.rs -mod foo$0; -//- /foo.rs -//! For the horde! -"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - mod foo - ``` - - --- - - For the horde! - "#]], - ); -} - -#[test] -fn hover_self_in_use() { - check( - r#" -//! This should not appear -mod foo { - /// But this should appear - pub mod bar {} -} -use foo::bar::{self$0}; -"#, - expect![[r#" - *self* - - ```rust - test::foo - ``` - - ```rust - mod bar - ``` - - --- - - But this should appear - "#]], - ) -} - -#[test] -fn hover_keyword() { - check( - r#" -//- /main.rs crate:main deps:std -fn f() { retur$0n; } -//- /libstd.rs crate:std -/// Docs for return_keyword -mod return_keyword {} -"#, - expect![[r#" - *return* - - ```rust - return - ``` - - --- - - Docs for return_keyword - "#]], - ); -} - -#[test] -fn hover_keyword_doc() { - check( - r#" -//- /main.rs crate:main deps:std -fn foo() { - let bar = mov$0e || {}; -} -//- /libstd.rs crate:std -#[doc(keyword = "move")] -/// [closure] -/// [closures][closure] -/// [threads] -/// -/// -/// [closure]: ../book/ch13-01-closures.html -/// [threads]: ../book/ch16-01-threads.html#using-move-closures-with-threads -mod move_keyword {} -"#, - expect![[r##" - *move* - - ```rust - move - ``` - - --- - - [closure](https://doc.rust-lang.org/nightly/book/ch13-01-closures.html) - [closures](https://doc.rust-lang.org/nightly/book/ch13-01-closures.html) - [threads](https://doc.rust-lang.org/nightly/book/ch16-01-threads.html#using-move-closures-with-threads) - - "##]], - ); -} - -#[test] -fn hover_keyword_as_primitive() { - check( - r#" -//- /main.rs crate:main deps:std -type F = f$0n(i32) -> i32; -//- /libstd.rs crate:std -/// Docs for prim_fn -mod prim_fn {} -"#, - expect![[r#" - *fn* - - ```rust - fn - ``` - - --- - - Docs for prim_fn - "#]], - ); -} - -#[test] -fn hover_builtin() { - check( - r#" -//- /main.rs crate:main deps:std -cosnt _: &str$0 = ""; } - -//- /libstd.rs crate:std -/// Docs for prim_str -/// [`foo`](../std/keyword.foo.html) -mod prim_str {} -"#, - expect![[r#" - *str* - - ```rust - str - ``` - - --- - - Docs for prim_str - [`foo`](https://doc.rust-lang.org/nightly/std/keyword.foo.html) - "#]], - ); -} - -#[test] -fn hover_macro_expanded_function() { - check( - r#" -struct S<'a, T>(&'a T); -trait Clone {} -macro_rules! foo { - () => { - fn bar<'t, T: Clone + 't>(s: &mut S<'t, T>, t: u32) -> *mut u32 where - 't: 't + 't, - for<'a> T: Clone + 'a - { 0 as _ } - }; -} - -foo!(); - -fn main() { - bar$0; -} -"#, - expect![[r#" - *bar* - - ```rust - test - ``` - - ```rust - fn bar<'t, T>(s: &mut S<'t, T>, t: u32) -> *mut u32 - where - T: Clone + 't, - 't: 't + 't, - for<'a> T: Clone + 'a, - ``` - "#]], - ) -} - -#[test] -fn hover_intra_doc_links() { - check( - r#" - -pub mod theitem { - /// This is the item. Cool! - pub struct TheItem; -} - -/// Gives you a [`TheItem$0`]. -/// -/// [`TheItem`]: theitem::TheItem -pub fn gimme() -> theitem::TheItem { - theitem::TheItem -} -"#, - expect![[r#" - *[`TheItem`]* - - ```rust - test::theitem - ``` - - ```rust - pub struct TheItem - ``` - - --- - - This is the item. Cool! - "#]], - ); -} - -#[test] -fn test_hover_trait_assoc_typealias() { - check( - r#" - fn main() {} - -trait T1 { - type Bar; - type Baz; -} - -struct Foo; - -mod t2 { - pub trait T2 { - type Bar; - } -} - -use t2::T2; - -impl T2 for Foo { - type Bar = String; -} - -impl T1 for Foo { - type Bar = ::Ba$0r; - // ^^^ unresolvedReference -} - "#, - expect![[r#" -*Bar* - -```rust -test::t2 -``` - -```rust -pub type Bar -``` -"#]], - ); -} -#[test] -fn hover_generic_assoc() { - check( - r#" -fn foo() where T::Assoc$0: {} - -trait A { - type Assoc; -}"#, - expect![[r#" - *Assoc* - - ```rust - test - ``` - - ```rust - type Assoc - ``` - "#]], - ); - check( - r#" -fn foo() { - let _: ::Assoc$0; -} - -trait A { - type Assoc; -}"#, - expect![[r#" - *Assoc* - - ```rust - test - ``` - - ```rust - type Assoc - ``` - "#]], - ); - check( - r#" -trait A where - Self::Assoc$0: , -{ - type Assoc; -}"#, - expect![[r#" - *Assoc* - - ```rust - test - ``` - - ```rust - type Assoc - ``` - "#]], - ); -} - -#[test] -fn string_shadowed_with_inner_items() { - check( - r#" -//- /main.rs crate:main deps:alloc - -/// Custom `String` type. -struct String; - -fn f() { - let _: String$0; - - fn inner() {} -} - -//- /alloc.rs crate:alloc -#[prelude_import] -pub use string::*; - -mod string { - /// This is `alloc::String`. - pub struct String; -} -"#, - expect![[r#" - *String* - - ```rust - main - ``` - - ```rust - struct String - ``` - - --- - - Custom `String` type. - "#]], - ) -} - -#[test] -fn function_doesnt_shadow_crate_in_use_tree() { - check( - r#" -//- /main.rs crate:main deps:foo -use foo$0::{foo}; - -//- /foo.rs crate:foo -pub fn foo() {} -"#, - expect![[r#" - *foo* - - ```rust - extern crate foo - ``` - "#]], - ) -} - -#[test] -fn hover_feature() { - check( - r#"#![feature(box_syntax$0)]"#, - expect![[r##" - *box_syntax* - ``` - box_syntax - ``` - ___ - - # `box_syntax` - - The tracking issue for this feature is: [#49733] - - [#49733]: https://github.com/rust-lang/rust/issues/49733 - - See also [`box_patterns`](box-patterns.md) - - ------------------------ - - Currently the only stable way to create a `Box` is via the `Box::new` method. - Also it is not possible in stable Rust to destructure a `Box` in a match - pattern. The unstable `box` keyword can be used to create a `Box`. An example - usage would be: - - ```rust - #![feature(box_syntax)] - - fn main() { - let b = box 5; - } - ``` - - "##]], - ) -} - -#[test] -fn hover_lint() { - check( - r#"#![allow(arithmetic_overflow$0)]"#, - expect![[r#" - *arithmetic_overflow* - ``` - arithmetic_overflow - ``` - ___ - - arithmetic operation overflows - "#]], - ) -} - -#[test] -fn hover_clippy_lint() { - check( - r#"#![allow(clippy::almost_swapped$0)]"#, - expect![[r#" - *almost_swapped* - ``` - clippy::almost_swapped - ``` - ___ - - Checks for `foo = bar; bar = foo` sequences. - "#]], - ) -} - -#[test] -fn hover_attr_path_qualifier() { - check( - r#" -//- /foo.rs crate:foo - -//- /lib.rs crate:main.rs deps:foo -#[fo$0o::bar()] -struct Foo; -"#, - expect![[r#" - *foo* - - ```rust - extern crate foo - ``` - "#]], - ) -} - -#[test] -fn hover_rename() { - check( - r#" -use self as foo$0; -"#, - expect![[r#" - *foo* - - ```rust - extern crate test - ``` - "#]], - ); - check( - r#" -mod bar {} -use bar::{self as foo$0}; -"#, - expect![[r#" - *foo* - - ```rust - test - ``` - - ```rust - mod bar - ``` - "#]], - ); - check( - r#" -mod bar { - use super as foo$0; -} -"#, - expect![[r#" - *foo* - - ```rust - extern crate test - ``` - "#]], - ); - check( - r#" -use crate as foo$0; -"#, - expect![[r#" - *foo* - - ```rust - extern crate test - ``` - "#]], - ); -} - -#[test] -fn hover_attribute_in_macro() { - check( - r#" -//- minicore:derive -macro_rules! identity { - ($struct:item) => { - $struct - }; -} -#[rustc_builtin_macro] -pub macro Copy {} -identity!{ - #[derive(Copy$0)] - struct Foo; -} -"#, - expect![[r#" - *Copy* - - ```rust - test - ``` - - ```rust - macro Copy - ``` - "#]], - ); -} - -#[test] -fn hover_derive_input() { - check( - r#" -//- minicore:derive -#[rustc_builtin_macro] -pub macro Copy {} -#[derive(Copy$0)] -struct Foo; -"#, - expect![[r#" - *Copy* - - ```rust - test - ``` - - ```rust - macro Copy - ``` - "#]], - ); - check( - r#" -//- minicore:derive -mod foo { - #[rustc_builtin_macro] - pub macro Copy {} -} -#[derive(foo::Copy$0)] -struct Foo; -"#, - expect![[r#" - *Copy* - - ```rust - test::foo - ``` - - ```rust - macro Copy - ``` - "#]], - ); -} - -#[test] -fn hover_range_math() { - check_hover_range( - r#" -fn f() { let expr = $01 + 2 * 3$0 } -"#, - expect![[r#" - ```rust - i32 - ```"#]], - ); - - check_hover_range( - r#" -fn f() { let expr = 1 $0+ 2 * $03 } -"#, - expect![[r#" - ```rust - i32 - ```"#]], - ); - - check_hover_range( - r#" -fn f() { let expr = 1 + $02 * 3$0 } -"#, - expect![[r#" - ```rust - i32 - ```"#]], - ); -} - -#[test] -fn hover_range_arrays() { - check_hover_range( - r#" -fn f() { let expr = $0[1, 2, 3, 4]$0 } -"#, - expect![[r#" - ```rust - [i32; 4] - ```"#]], - ); - - check_hover_range( - r#" -fn f() { let expr = [1, 2, $03, 4]$0 } -"#, - expect![[r#" - ```rust - [i32; 4] - ```"#]], - ); - - check_hover_range( - r#" -fn f() { let expr = [1, 2, $03$0, 4] } -"#, - expect![[r#" - ```rust - i32 - ```"#]], - ); -} - -#[test] -fn hover_range_functions() { - check_hover_range( - r#" -fn f(a: &[T]) { } -fn b() { $0f$0(&[1, 2, 3, 4, 5]); } -"#, - expect![[r#" - ```rust - fn f(&[i32]) - ```"#]], - ); - - check_hover_range( - r#" -fn f(a: &[T]) { } -fn b() { f($0&[1, 2, 3, 4, 5]$0); } -"#, - expect![[r#" - ```rust - &[i32; 5] - ```"#]], - ); -} - -#[test] -fn hover_range_shows_nothing_when_invalid() { - check_hover_range_no_results( - r#" -fn f(a: &[T]) { } -fn b()$0 { f(&[1, 2, 3, 4, 5]); }$0 -"#, - ); - - check_hover_range_no_results( - r#" -fn f$0(a: &[T]) { } -fn b() { f(&[1, 2, 3,$0 4, 5]); } -"#, - ); - - check_hover_range_no_results( - r#" -fn $0f() { let expr = [1, 2, 3, 4]$0 } -"#, - ); -} - -#[test] -fn hover_range_shows_unit_for_statements() { - check_hover_range( - r#" -fn f(a: &[T]) { } -fn b() { $0f(&[1, 2, 3, 4, 5]); }$0 -"#, - expect![[r#" - ```rust - () - ```"#]], - ); - - check_hover_range( - r#" -fn f() { let expr$0 = $0[1, 2, 3, 4] } -"#, - expect![[r#" - ```rust - () - ```"#]], - ); -} - -#[test] -fn hover_range_for_pat() { - check_hover_range( - r#" -fn foo() { - let $0x$0 = 0; -} -"#, - expect![[r#" - ```rust - i32 - ```"#]], - ); - - check_hover_range( - r#" -fn foo() { - let $0x$0 = ""; -} -"#, - expect![[r#" - ```rust - &str - ```"#]], - ); -} - -#[test] -fn hover_range_shows_coercions_if_applicable_expr() { - check_hover_range( - r#" -fn foo() { - let x: &u32 = $0&&&&&0$0; -} -"#, - expect![[r#" - ```text - Type: &&&&&u32 - Coerced to: &u32 - ``` - "#]], - ); - check_hover_range( - r#" -fn foo() { - let x: *const u32 = $0&0$0; -} -"#, - expect![[r#" - ```text - Type: &u32 - Coerced to: *const u32 - ``` - "#]], - ); -} - -#[test] -fn hover_range_shows_type_actions() { - check_actions( - r#" -struct Foo; -fn foo() { - let x: &Foo = $0&&&&&Foo$0; -} -"#, - expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..11, - focus_range: 7..10, - name: "Foo", - kind: Struct, - description: "struct Foo", - }, - }, - ], - ), - ] - "#]], - ); -} - -#[test] -fn hover_try_expr_res() { - check_hover_range( - r#" -//- minicore:result -struct FooError; - -fn foo() -> Result<(), FooError> { - Ok($0Result::<(), FooError>::Ok(())?$0) -} -"#, - expect![[r#" - ```rust - () - ```"#]], - ); - check_hover_range( - r#" -//- minicore:result -struct FooError; -struct BarError; - -fn foo() -> Result<(), FooError> { - Ok($0Result::<(), BarError>::Ok(())?$0) -} -"#, - expect![[r#" - ```text - Try Error Type: BarError - Propagated as: FooError - ``` - "#]], - ); -} - -#[test] -fn hover_try_expr() { - check_hover_range( - r#" -struct NotResult(T, U); -struct Short; -struct Looooong; - -fn foo() -> NotResult<(), Looooong> { - $0NotResult((), Short)?$0; -} -"#, - expect![[r#" - ```text - Try Target Type: NotResult<(), Short> - Propagated as: NotResult<(), Looooong> - ``` - "#]], - ); - check_hover_range( - r#" -struct NotResult(T, U); -struct Short; -struct Looooong; - -fn foo() -> NotResult<(), Short> { - $0NotResult((), Looooong)?$0; -} -"#, - expect![[r#" - ```text - Try Target Type: NotResult<(), Looooong> - Propagated as: NotResult<(), Short> - ``` - "#]], - ); -} - -#[test] -fn hover_try_expr_option() { - cov_mark::check!(hover_try_expr_opt_opt); - check_hover_range( - r#" -//- minicore: option, try - -fn foo() -> Option<()> { - $0Some(0)?$0; - None -} -"#, - expect![[r#" - ```rust - as Try>::Output - ```"#]], - ); -} - -#[test] -fn hover_deref_expr() { - check_hover_range( - r#" -//- minicore: deref -use core::ops::Deref; - -struct DerefExample { - value: T -} - -impl Deref for DerefExample { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.value - } -} - -fn foo() { - let x = DerefExample { value: 0 }; - let y: i32 = $0*x$0; -} -"#, - expect![[r#" - ```text - Dereferenced from: DerefExample - To type: i32 - ``` - "#]], - ); -} - -#[test] -fn hover_deref_expr_with_coercion() { - check_hover_range( - r#" -//- minicore: deref -use core::ops::Deref; - -struct DerefExample { - value: T -} - -impl Deref for DerefExample { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.value - } -} - -fn foo() { - let x = DerefExample { value: &&&&&0 }; - let y: &i32 = $0*x$0; -} -"#, - expect![[r#" - ```text - Dereferenced from: DerefExample<&&&&&i32> - To type: &&&&&i32 - Coerced to: &i32 - ``` - "#]], - ); -} - -#[test] -fn hover_intra_in_macro() { - check( - r#" -macro_rules! foo_macro { - ($(#[$attr:meta])* $name:ident) => { - $(#[$attr])* - pub struct $name; - } -} - -foo_macro!( - /// Doc comment for [`Foo$0`] - Foo -); -"#, - expect![[r#" - *[`Foo`]* - - ```rust - test - ``` - - ```rust - pub struct Foo - ``` - - --- - - Doc comment for [`Foo`](https://docs.rs/test/*/test/struct.Foo.html) - "#]], - ); -} - -#[test] -fn hover_intra_in_attr() { - check( - r#" -#[doc = "Doc comment for [`Foo$0`]"] -pub struct Foo; -"#, - expect![[r#" - *[`Foo`]* - - ```rust - test - ``` - - ```rust - pub struct Foo - ``` - - --- - - Doc comment for [`Foo`](https://docs.rs/test/*/test/struct.Foo.html) - "#]], - ); -} - -#[test] -fn hover_inert_attr() { - check( - r#" -#[doc$0 = ""] -pub struct Foo; -"#, - expect![[r##" - *doc* - - ```rust - #[doc] - ``` - - --- - - Valid forms are: - - * \#\[doc(hidden|inline|...)\] - * \#\[doc = string\] - "##]], - ); - check( - r#" -#[allow$0()] -pub struct Foo; -"#, - expect![[r##" - *allow* - - ```rust - #[allow] - ``` - - --- - - Valid forms are: - - * \#\[allow(lint1, lint2, ..., /\*opt\*/ reason = "...")\] - "##]], - ); -} - -#[test] -fn hover_dollar_crate() { - // $crate should be resolved to the right crate name. - - check( - r#" -//- /main.rs crate:main deps:dep -dep::m!(KONST$0); -//- /dep.rs crate:dep -#[macro_export] -macro_rules! m { - ( $name:ident ) => { const $name: $crate::Type = $crate::Type; }; -} - -pub struct Type; -"#, - expect![[r#" - *KONST* - - ```rust - main - ``` - - ```rust - const KONST: dep::Type = $crate::Type - ``` - "#]], - ); -} - -#[test] -fn hover_record_variant() { - check( - r#" -enum Enum { - RecordV$0 { field: u32 } -} -"#, - expect![[r#" - *RecordV* - - ```rust - test::Enum - ``` - - ```rust - RecordV { field: u32 } - ``` - "#]], - ); -} - -#[test] -fn hover_trait_impl_assoc_item_def_doc_forwarding() { - check( - r#" -trait T { - /// Trait docs - fn func() {} -} -impl T for () { - fn func$0() {} -} -"#, - expect![[r#" - *func* - - ```rust - test - ``` - - ```rust - fn func() - ``` - - --- - - Trait docs - "#]], - ); -} - -#[test] -fn hover_ranged_macro_call() { - check_hover_range( - r#" -macro_rules! __rust_force_expr { - ($e:expr) => { - $e - }; -} -macro_rules! vec { - ($elem:expr) => { - __rust_force_expr!($elem) - }; -} - -struct Struct; -impl Struct { - fn foo(self) {} -} - -fn f() { - $0vec![Struct]$0; -} -"#, - expect![[r#" - ```rust - Struct - ```"#]], - ); -} diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs deleted file mode 100644 index 5aae669aa4d6d..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ /dev/null @@ -1,2818 +0,0 @@ -use either::Either; -use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo}; -use ide_db::{ - base_db::FileRange, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty, FxHashMap, - RootDatabase, -}; -use itertools::Itertools; -use stdx::to_lower_snake_case; -use syntax::{ - ast::{self, AstNode, HasArgList, HasGenericParams, HasName, UnaryOp}, - match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, - TextSize, T, -}; - -use crate::FileId; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct InlayHintsConfig { - pub render_colons: bool, - pub type_hints: bool, - pub parameter_hints: bool, - pub chaining_hints: bool, - pub reborrow_hints: ReborrowHints, - pub closure_return_type_hints: ClosureReturnTypeHints, - pub binding_mode_hints: bool, - pub lifetime_elision_hints: LifetimeElisionHints, - pub param_names_for_lifetime_elision_hints: bool, - pub hide_named_constructor_hints: bool, - pub hide_closure_initialization_hints: bool, - pub max_length: Option, - pub closing_brace_hints_min_lines: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum ClosureReturnTypeHints { - Always, - WithBlock, - Never, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum LifetimeElisionHints { - Always, - SkipTrivial, - Never, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum ReborrowHints { - Always, - MutableOnly, - Never, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum InlayKind { - BindingModeHint, - ChainingHint, - ClosingBraceHint, - ClosureReturnTypeHint, - GenericParamListHint, - ImplicitReborrowHint, - LifetimeHint, - ParameterHint, - TypeHint, -} - -#[derive(Debug)] -pub struct InlayHint { - pub range: TextRange, - pub kind: InlayKind, - pub label: String, - pub tooltip: Option, -} - -#[derive(Debug)] -pub enum InlayTooltip { - String(String), - HoverRanged(FileId, TextRange), - HoverOffset(FileId, TextSize), -} - -// Feature: Inlay Hints -// -// rust-analyzer shows additional information inline with the source code. -// Editors usually render this using read-only virtual text snippets interspersed with code. -// -// rust-analyzer by default shows hints for -// -// * types of local variables -// * names of function arguments -// * types of chained expressions -// -// Optionally, one can enable additional hints for -// -// * return types of closure expressions -// * elided lifetimes -// * compiler inserted reborrows -// -// |=== -// | Editor | Action Name -// -// | VS Code | **Rust Analyzer: Toggle inlay hints* -// |=== -// -// image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[] -pub(crate) fn inlay_hints( - db: &RootDatabase, - file_id: FileId, - range_limit: Option, - config: &InlayHintsConfig, -) -> Vec { - let _p = profile::span("inlay_hints"); - let sema = Semantics::new(db); - let file = sema.parse(file_id); - let file = file.syntax(); - - let mut acc = Vec::new(); - - if let Some(scope) = sema.scope(&file) { - let famous_defs = FamousDefs(&sema, scope.krate()); - - let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node); - match range_limit { - Some(FileRange { range, .. }) => match file.covering_element(range) { - NodeOrToken::Token(_) => return acc, - NodeOrToken::Node(n) => n - .descendants() - .filter(|descendant| range.intersect(descendant.text_range()).is_some()) - .for_each(hints), - }, - None => file.descendants().for_each(hints), - }; - } - - acc -} - -fn hints( - hints: &mut Vec, - famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, - file_id: FileId, - node: SyntaxNode, -) { - closing_brace_hints(hints, sema, config, file_id, node.clone()); - match_ast! { - match node { - ast::Expr(expr) => { - chaining_hints(hints, sema, &famous_defs, config, file_id, &expr); - match expr { - ast::Expr::CallExpr(it) => param_name_hints(hints, sema, config, ast::Expr::from(it)), - ast::Expr::MethodCallExpr(it) => { - param_name_hints(hints, sema, config, ast::Expr::from(it)) - } - ast::Expr::ClosureExpr(it) => closure_ret_hints(hints, sema, &famous_defs, config, file_id, it), - // We could show reborrows for all expressions, but usually that is just noise to the user - // and the main point here is to show why "moving" a mutable reference doesn't necessarily move it - ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr), - _ => None, - } - }, - ast::Pat(it) => { - binding_mode_hints(hints, sema, config, &it); - if let ast::Pat::IdentPat(it) = it { - bind_pat_hints(hints, sema, config, file_id, &it); - } - Some(()) - }, - ast::Item(it) => match it { - // FIXME: record impl lifetimes so they aren't being reused in assoc item lifetime inlay hints - ast::Item::Impl(_) => None, - ast::Item::Fn(it) => fn_lifetime_fn_hints(hints, config, it), - // static type elisions - ast::Item::Static(it) => implicit_static_hints(hints, config, Either::Left(it)), - ast::Item::Const(it) => implicit_static_hints(hints, config, Either::Right(it)), - _ => None, - }, - // FIXME: fn-ptr type, dyn fn type, and trait object type elisions - ast::Type(_) => None, - _ => None, - } - }; -} - -fn closing_brace_hints( - acc: &mut Vec, - sema: &Semantics<'_, RootDatabase>, - config: &InlayHintsConfig, - file_id: FileId, - node: SyntaxNode, -) -> Option<()> { - let min_lines = config.closing_brace_hints_min_lines?; - - let name = |it: ast::Name| it.syntax().text_range().start(); - - let mut closing_token; - let (label, name_offset) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) { - closing_token = item_list.r_curly_token()?; - - let parent = item_list.syntax().parent()?; - match_ast! { - match parent { - ast::Impl(imp) => { - let imp = sema.to_def(&imp)?; - let ty = imp.self_ty(sema.db); - let trait_ = imp.trait_(sema.db); - - (match trait_ { - Some(tr) => format!("impl {} for {}", tr.name(sema.db), ty.display_truncated(sema.db, config.max_length)), - None => format!("impl {}", ty.display_truncated(sema.db, config.max_length)), - }, None) - }, - ast::Trait(tr) => { - (format!("trait {}", tr.name()?), tr.name().map(name)) - }, - _ => return None, - } - } - } else if let Some(list) = ast::ItemList::cast(node.clone()) { - closing_token = list.r_curly_token()?; - - let module = ast::Module::cast(list.syntax().parent()?)?; - (format!("mod {}", module.name()?), module.name().map(name)) - } else if let Some(block) = ast::BlockExpr::cast(node.clone()) { - closing_token = block.stmt_list()?.r_curly_token()?; - - let parent = block.syntax().parent()?; - match_ast! { - match parent { - ast::Fn(it) => { - // FIXME: this could include parameters, but `HirDisplay` prints too much info - // and doesn't respect the max length either, so the hints end up way too long - (format!("fn {}", it.name()?), it.name().map(name)) - }, - ast::Static(it) => (format!("static {}", it.name()?), it.name().map(name)), - ast::Const(it) => { - if it.underscore_token().is_some() { - ("const _".into(), None) - } else { - (format!("const {}", it.name()?), it.name().map(name)) - } - }, - _ => return None, - } - } - } else if let Some(mac) = ast::MacroCall::cast(node.clone()) { - let last_token = mac.syntax().last_token()?; - if last_token.kind() != T![;] && last_token.kind() != SyntaxKind::R_CURLY { - return None; - } - closing_token = last_token; - - ( - format!("{}!", mac.path()?), - mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range().start()), - ) - } else { - return None; - }; - - if let Some(mut next) = closing_token.next_token() { - if next.kind() == T![;] { - if let Some(tok) = next.next_token() { - closing_token = next; - next = tok; - } - } - if !(next.kind() == SyntaxKind::WHITESPACE && next.text().contains('\n')) { - // Only display the hint if the `}` is the last token on the line - return None; - } - } - - let mut lines = 1; - node.text().for_each_chunk(|s| lines += s.matches('\n').count()); - if lines < min_lines { - return None; - } - - acc.push(InlayHint { - range: closing_token.text_range(), - kind: InlayKind::ClosingBraceHint, - label, - tooltip: name_offset.map(|it| InlayTooltip::HoverOffset(file_id, it)), - }); - - None -} - -fn implicit_static_hints( - acc: &mut Vec, - config: &InlayHintsConfig, - statik_or_const: Either, -) -> Option<()> { - if config.lifetime_elision_hints != LifetimeElisionHints::Always { - return None; - } - - if let Either::Right(it) = &statik_or_const { - if ast::AssocItemList::can_cast( - it.syntax().parent().map_or(SyntaxKind::EOF, |it| it.kind()), - ) { - return None; - } - } - - if let Some(ast::Type::RefType(ty)) = statik_or_const.either(|it| it.ty(), |it| it.ty()) { - if ty.lifetime().is_none() { - let t = ty.amp_token()?; - acc.push(InlayHint { - range: t.text_range(), - kind: InlayKind::LifetimeHint, - label: "'static".to_owned(), - tooltip: Some(InlayTooltip::String("Elided static lifetime".into())), - }); - } - } - - Some(()) -} - -fn fn_lifetime_fn_hints( - acc: &mut Vec, - config: &InlayHintsConfig, - func: ast::Fn, -) -> Option<()> { - if config.lifetime_elision_hints == LifetimeElisionHints::Never { - return None; - } - - let mk_lt_hint = |t: SyntaxToken, label| InlayHint { - range: t.text_range(), - kind: InlayKind::LifetimeHint, - label, - tooltip: Some(InlayTooltip::String("Elided lifetime".into())), - }; - - let param_list = func.param_list()?; - let generic_param_list = func.generic_param_list(); - let ret_type = func.ret_type(); - let self_param = param_list.self_param().filter(|it| it.amp_token().is_some()); - - let is_elided = |lt: &Option| match lt { - Some(lt) => matches!(lt.text().as_str(), "'_"), - None => true, - }; - - let potential_lt_refs = { - let mut acc: Vec<_> = vec![]; - if let Some(self_param) = &self_param { - let lifetime = self_param.lifetime(); - let is_elided = is_elided(&lifetime); - acc.push((None, self_param.amp_token(), lifetime, is_elided)); - } - param_list.params().filter_map(|it| Some((it.pat(), it.ty()?))).for_each(|(pat, ty)| { - // FIXME: check path types - walk_ty(&ty, &mut |ty| match ty { - ast::Type::RefType(r) => { - let lifetime = r.lifetime(); - let is_elided = is_elided(&lifetime); - acc.push(( - pat.as_ref().and_then(|it| match it { - ast::Pat::IdentPat(p) => p.name(), - _ => None, - }), - r.amp_token(), - lifetime, - is_elided, - )) - } - _ => (), - }) - }); - acc - }; - - // allocate names - let mut gen_idx_name = { - let mut gen = (0u8..).map(|idx| match idx { - idx if idx < 10 => SmolStr::from_iter(['\'', (idx + 48) as char]), - idx => format!("'{idx}").into(), - }); - move || gen.next().unwrap_or_default() - }; - let mut allocated_lifetimes = vec![]; - - let mut used_names: FxHashMap = - match config.param_names_for_lifetime_elision_hints { - true => generic_param_list - .iter() - .flat_map(|gpl| gpl.lifetime_params()) - .filter_map(|param| param.lifetime()) - .filter_map(|lt| Some((SmolStr::from(lt.text().as_str().get(1..)?), 0))) - .collect(), - false => Default::default(), - }; - { - let mut potential_lt_refs = potential_lt_refs.iter().filter(|&&(.., is_elided)| is_elided); - if let Some(_) = &self_param { - if let Some(_) = potential_lt_refs.next() { - allocated_lifetimes.push(if config.param_names_for_lifetime_elision_hints { - // self can't be used as a lifetime, so no need to check for collisions - "'self".into() - } else { - gen_idx_name() - }); - } - } - potential_lt_refs.for_each(|(name, ..)| { - let name = match name { - Some(it) if config.param_names_for_lifetime_elision_hints => { - if let Some(c) = used_names.get_mut(it.text().as_str()) { - *c += 1; - SmolStr::from(format!("'{text}{c}", text = it.text().as_str())) - } else { - used_names.insert(it.text().as_str().into(), 0); - SmolStr::from_iter(["\'", it.text().as_str()]) - } - } - _ => gen_idx_name(), - }; - allocated_lifetimes.push(name); - }); - } - - // fetch output lifetime if elision rule applies - let output = match potential_lt_refs.as_slice() { - [(_, _, lifetime, _), ..] if self_param.is_some() || potential_lt_refs.len() == 1 => { - match lifetime { - Some(lt) => match lt.text().as_str() { - "'_" => allocated_lifetimes.get(0).cloned(), - "'static" => None, - name => Some(name.into()), - }, - None => allocated_lifetimes.get(0).cloned(), - } - } - [..] => None, - }; - - if allocated_lifetimes.is_empty() && output.is_none() { - return None; - } - - // apply hints - // apply output if required - let mut is_trivial = true; - if let (Some(output_lt), Some(r)) = (&output, ret_type) { - if let Some(ty) = r.ty() { - walk_ty(&ty, &mut |ty| match ty { - ast::Type::RefType(ty) if ty.lifetime().is_none() => { - if let Some(amp) = ty.amp_token() { - is_trivial = false; - acc.push(mk_lt_hint(amp, output_lt.to_string())); - } - } - _ => (), - }) - } - } - - if config.lifetime_elision_hints == LifetimeElisionHints::SkipTrivial && is_trivial { - return None; - } - - let mut a = allocated_lifetimes.iter(); - for (_, amp_token, _, is_elided) in potential_lt_refs { - if is_elided { - let t = amp_token?; - let lt = a.next()?; - acc.push(mk_lt_hint(t, lt.to_string())); - } - } - - // generate generic param list things - match (generic_param_list, allocated_lifetimes.as_slice()) { - (_, []) => (), - (Some(gpl), allocated_lifetimes) => { - let angle_tok = gpl.l_angle_token()?; - let is_empty = gpl.generic_params().next().is_none(); - acc.push(InlayHint { - range: angle_tok.text_range(), - kind: InlayKind::LifetimeHint, - label: format!( - "{}{}", - allocated_lifetimes.iter().format(", "), - if is_empty { "" } else { ", " } - ), - tooltip: Some(InlayTooltip::String("Elided lifetimes".into())), - }); - } - (None, allocated_lifetimes) => acc.push(InlayHint { - range: func.name()?.syntax().text_range(), - kind: InlayKind::GenericParamListHint, - label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(), - tooltip: Some(InlayTooltip::String("Elided lifetimes".into())), - }), - } - Some(()) -} - -fn closure_ret_hints( - acc: &mut Vec, - sema: &Semantics<'_, RootDatabase>, - famous_defs: &FamousDefs<'_, '_>, - config: &InlayHintsConfig, - file_id: FileId, - closure: ast::ClosureExpr, -) -> Option<()> { - if config.closure_return_type_hints == ClosureReturnTypeHints::Never { - return None; - } - - if closure.ret_type().is_some() { - return None; - } - - if !closure_has_block_body(&closure) - && config.closure_return_type_hints == ClosureReturnTypeHints::WithBlock - { - return None; - } - - let param_list = closure.param_list()?; - - let closure = sema.descend_node_into_attributes(closure.clone()).pop()?; - let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(closure))?.adjusted(); - let callable = ty.as_callable(sema.db)?; - let ty = callable.return_type(); - if ty.is_unit() { - return None; - } - acc.push(InlayHint { - range: param_list.syntax().text_range(), - kind: InlayKind::ClosureReturnTypeHint, - label: hint_iterator(sema, &famous_defs, config, &ty) - .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string()), - tooltip: Some(InlayTooltip::HoverRanged(file_id, param_list.syntax().text_range())), - }); - Some(()) -} - -fn reborrow_hints( - acc: &mut Vec, - sema: &Semantics<'_, RootDatabase>, - config: &InlayHintsConfig, - expr: &ast::Expr, -) -> Option<()> { - if config.reborrow_hints == ReborrowHints::Never { - return None; - } - - let descended = sema.descend_node_into_attributes(expr.clone()).pop(); - let desc_expr = descended.as_ref().unwrap_or(expr); - let mutability = sema.is_implicit_reborrow(desc_expr)?; - let label = match mutability { - hir::Mutability::Shared if config.reborrow_hints != ReborrowHints::MutableOnly => "&*", - hir::Mutability::Mut => "&mut *", - _ => return None, - }; - acc.push(InlayHint { - range: expr.syntax().text_range(), - kind: InlayKind::ImplicitReborrowHint, - label: label.to_string(), - tooltip: Some(InlayTooltip::String("Compiler inserted reborrow".into())), - }); - Some(()) -} - -fn chaining_hints( - acc: &mut Vec, - sema: &Semantics<'_, RootDatabase>, - famous_defs: &FamousDefs<'_, '_>, - config: &InlayHintsConfig, - file_id: FileId, - expr: &ast::Expr, -) -> Option<()> { - if !config.chaining_hints { - return None; - } - - if matches!(expr, ast::Expr::RecordExpr(_)) { - return None; - } - - let descended = sema.descend_node_into_attributes(expr.clone()).pop(); - let desc_expr = descended.as_ref().unwrap_or(expr); - - let mut tokens = expr - .syntax() - .siblings_with_tokens(Direction::Next) - .filter_map(NodeOrToken::into_token) - .filter(|t| match t.kind() { - SyntaxKind::WHITESPACE if !t.text().contains('\n') => false, - SyntaxKind::COMMENT => false, - _ => true, - }); - - // Chaining can be defined as an expression whose next sibling tokens are newline and dot - // Ignoring extra whitespace and comments - let next = tokens.next()?.kind(); - if next == SyntaxKind::WHITESPACE { - let mut next_next = tokens.next()?.kind(); - while next_next == SyntaxKind::WHITESPACE { - next_next = tokens.next()?.kind(); - } - if next_next == T![.] { - let ty = sema.type_of_expr(desc_expr)?.original; - if ty.is_unknown() { - return None; - } - if matches!(expr, ast::Expr::PathExpr(_)) { - if let Some(hir::Adt::Struct(st)) = ty.as_adt() { - if st.fields(sema.db).is_empty() { - return None; - } - } - } - acc.push(InlayHint { - range: expr.syntax().text_range(), - kind: InlayKind::ChainingHint, - label: hint_iterator(sema, &famous_defs, config, &ty).unwrap_or_else(|| { - ty.display_truncated(sema.db, config.max_length).to_string() - }), - tooltip: Some(InlayTooltip::HoverRanged(file_id, expr.syntax().text_range())), - }); - } - } - Some(()) -} - -fn param_name_hints( - acc: &mut Vec, - sema: &Semantics<'_, RootDatabase>, - config: &InlayHintsConfig, - expr: ast::Expr, -) -> Option<()> { - if !config.parameter_hints { - return None; - } - - let (callable, arg_list) = get_callable(sema, &expr)?; - let hints = callable - .params(sema.db) - .into_iter() - .zip(arg_list.args()) - .filter_map(|((param, _ty), arg)| { - // Only annotate hints for expressions that exist in the original file - let range = sema.original_range_opt(arg.syntax())?; - let (param_name, name_syntax) = match param.as_ref()? { - Either::Left(pat) => ("self".to_string(), pat.name()), - Either::Right(pat) => match pat { - ast::Pat::IdentPat(it) => (it.name()?.to_string(), it.name()), - _ => return None, - }, - }; - Some((name_syntax, param_name, arg, range)) - }) - .filter(|(_, param_name, arg, _)| { - !should_hide_param_name_hint(sema, &callable, param_name, arg) - }) - .map(|(param, param_name, _, FileRange { range, .. })| { - let mut tooltip = None; - if let Some(name) = param { - if let hir::CallableKind::Function(f) = callable.kind() { - // assert the file is cached so we can map out of macros - if let Some(_) = sema.source(f) { - tooltip = sema.original_range_opt(name.syntax()); - } - } - } - - InlayHint { - range, - kind: InlayKind::ParameterHint, - label: param_name, - tooltip: tooltip.map(|it| InlayTooltip::HoverOffset(it.file_id, it.range.start())), - } - }); - - acc.extend(hints); - Some(()) -} - -fn binding_mode_hints( - acc: &mut Vec, - sema: &Semantics<'_, RootDatabase>, - config: &InlayHintsConfig, - pat: &ast::Pat, -) -> Option<()> { - if !config.binding_mode_hints { - return None; - } - - let range = pat.syntax().text_range(); - sema.pattern_adjustments(&pat).iter().for_each(|ty| { - let reference = ty.is_reference(); - let mut_reference = ty.is_mutable_reference(); - let r = match (reference, mut_reference) { - (true, true) => "&mut", - (true, false) => "&", - _ => return, - }; - acc.push(InlayHint { - range, - kind: InlayKind::BindingModeHint, - label: r.to_string(), - tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), - }); - }); - match pat { - ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => { - let bm = sema.binding_mode_of_pat(pat)?; - let bm = match bm { - hir::BindingMode::Move => return None, - hir::BindingMode::Ref(Mutability::Mut) => "ref mut", - hir::BindingMode::Ref(Mutability::Shared) => "ref", - }; - acc.push(InlayHint { - range, - kind: InlayKind::BindingModeHint, - label: bm.to_string(), - tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), - }); - } - _ => (), - } - - Some(()) -} - -fn bind_pat_hints( - acc: &mut Vec, - sema: &Semantics<'_, RootDatabase>, - config: &InlayHintsConfig, - file_id: FileId, - pat: &ast::IdentPat, -) -> Option<()> { - if !config.type_hints { - return None; - } - - let descended = sema.descend_node_into_attributes(pat.clone()).pop(); - let desc_pat = descended.as_ref().unwrap_or(pat); - let ty = sema.type_of_pat(&desc_pat.clone().into())?.original; - - if should_not_display_type_hint(sema, config, pat, &ty) { - return None; - } - - let krate = sema.scope(desc_pat.syntax())?.krate(); - let famous_defs = FamousDefs(sema, krate); - let label = hint_iterator(sema, &famous_defs, config, &ty); - - let label = match label { - Some(label) => label, - None => { - let ty_name = ty.display_truncated(sema.db, config.max_length).to_string(); - if config.hide_named_constructor_hints - && is_named_constructor(sema, pat, &ty_name).is_some() - { - return None; - } - ty_name - } - }; - - acc.push(InlayHint { - range: match pat.name() { - Some(name) => name.syntax().text_range(), - None => pat.syntax().text_range(), - }, - kind: InlayKind::TypeHint, - label, - tooltip: pat - .name() - .map(|it| it.syntax().text_range()) - .map(|it| InlayTooltip::HoverRanged(file_id, it)), - }); - - Some(()) -} - -fn is_named_constructor( - sema: &Semantics<'_, RootDatabase>, - pat: &ast::IdentPat, - ty_name: &str, -) -> Option<()> { - let let_node = pat.syntax().parent()?; - let expr = match_ast! { - match let_node { - ast::LetStmt(it) => it.initializer(), - ast::LetExpr(it) => it.expr(), - _ => None, - } - }?; - - let expr = sema.descend_node_into_attributes(expr.clone()).pop().unwrap_or(expr); - // unwrap postfix expressions - let expr = match expr { - ast::Expr::TryExpr(it) => it.expr(), - ast::Expr::AwaitExpr(it) => it.expr(), - expr => Some(expr), - }?; - let expr = match expr { - ast::Expr::CallExpr(call) => match call.expr()? { - ast::Expr::PathExpr(path) => path, - _ => return None, - }, - ast::Expr::PathExpr(path) => path, - _ => return None, - }; - let path = expr.path()?; - - let callable = sema.type_of_expr(&ast::Expr::PathExpr(expr))?.original.as_callable(sema.db); - let callable_kind = callable.map(|it| it.kind()); - let qual_seg = match callable_kind { - Some(hir::CallableKind::Function(_) | hir::CallableKind::TupleEnumVariant(_)) => { - path.qualifier()?.segment() - } - _ => path.segment(), - }?; - - let ctor_name = match qual_seg.kind()? { - ast::PathSegmentKind::Name(name_ref) => { - match qual_seg.generic_arg_list().map(|it| it.generic_args()) { - Some(generics) => format!("{}<{}>", name_ref, generics.format(", ")), - None => name_ref.to_string(), - } - } - ast::PathSegmentKind::Type { type_ref: Some(ty), trait_ref: None } => ty.to_string(), - _ => return None, - }; - (ctor_name == ty_name).then(|| ()) -} - -/// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator`. -fn hint_iterator( - sema: &Semantics<'_, RootDatabase>, - famous_defs: &FamousDefs<'_, '_>, - config: &InlayHintsConfig, - ty: &hir::Type, -) -> Option { - let db = sema.db; - let strukt = ty.strip_references().as_adt()?; - let krate = strukt.module(db).krate(); - if krate != famous_defs.core()? { - return None; - } - let iter_trait = famous_defs.core_iter_Iterator()?; - let iter_mod = famous_defs.core_iter()?; - - // Assert that this struct comes from `core::iter`. - if !(strukt.visibility(db) == hir::Visibility::Public - && strukt.module(db).path_to_root(db).contains(&iter_mod)) - { - return None; - } - - if ty.impls_trait(db, iter_trait, &[]) { - let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item { - hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias), - _ => None, - })?; - if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) { - const LABEL_START: &str = "impl Iterator bool { - if let Some(hir::Adt::Enum(enum_data)) = pat_ty.as_adt() { - let pat_text = bind_pat.to_string(); - enum_data - .variants(db) - .into_iter() - .map(|variant| variant.name(db).to_smol_str()) - .any(|enum_name| enum_name == pat_text) - } else { - false - } -} - -fn should_not_display_type_hint( - sema: &Semantics<'_, RootDatabase>, - config: &InlayHintsConfig, - bind_pat: &ast::IdentPat, - pat_ty: &hir::Type, -) -> bool { - let db = sema.db; - - if pat_ty.is_unknown() { - return true; - } - - if let Some(hir::Adt::Struct(s)) = pat_ty.as_adt() { - if s.fields(db).is_empty() && s.name(db).to_smol_str() == bind_pat.to_string() { - return true; - } - } - - if config.hide_closure_initialization_hints { - if let Some(parent) = bind_pat.syntax().parent() { - if let Some(it) = ast::LetStmt::cast(parent.clone()) { - if let Some(ast::Expr::ClosureExpr(closure)) = it.initializer() { - if closure_has_block_body(&closure) { - return true; - } - } - } - } - } - - for node in bind_pat.syntax().ancestors() { - match_ast! { - match node { - ast::LetStmt(it) => return it.ty().is_some(), - // FIXME: We might wanna show type hints in parameters for non-top level patterns as well - ast::Param(it) => return it.ty().is_some(), - ast::MatchArm(_) => return pat_is_enum_variant(db, bind_pat, pat_ty), - ast::LetExpr(_) => return pat_is_enum_variant(db, bind_pat, pat_ty), - ast::IfExpr(_) => return false, - ast::WhileExpr(_) => return false, - ast::ForExpr(it) => { - // We *should* display hint only if user provided "in {expr}" and we know the type of expr (and it's not unit). - // Type of expr should be iterable. - return it.in_token().is_none() || - it.iterable() - .and_then(|iterable_expr| sema.type_of_expr(&iterable_expr)) - .map(TypeInfo::original) - .map_or(true, |iterable_ty| iterable_ty.is_unknown() || iterable_ty.is_unit()) - }, - _ => (), - } - } - } - false -} - -fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool { - matches!(closure.body(), Some(ast::Expr::BlockExpr(_))) -} - -fn should_hide_param_name_hint( - sema: &Semantics<'_, RootDatabase>, - callable: &hir::Callable, - param_name: &str, - argument: &ast::Expr, -) -> bool { - // These are to be tested in the `parameter_hint_heuristics` test - // hide when: - // - the parameter name is a suffix of the function's name - // - the argument is a qualified constructing or call expression where the qualifier is an ADT - // - exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix - // of argument with _ splitting it off - // - param starts with `ra_fixture` - // - param is a well known name in a unary function - - let param_name = param_name.trim_start_matches('_'); - if param_name.is_empty() { - return true; - } - - if matches!(argument, ast::Expr::PrefixExpr(prefix) if prefix.op_kind() == Some(UnaryOp::Not)) { - return false; - } - - let fn_name = match callable.kind() { - hir::CallableKind::Function(it) => Some(it.name(sema.db).to_smol_str()), - _ => None, - }; - let fn_name = fn_name.as_deref(); - is_param_name_suffix_of_fn_name(param_name, callable, fn_name) - || is_argument_similar_to_param_name(argument, param_name) - || param_name.starts_with("ra_fixture") - || (callable.n_params() == 1 && is_obvious_param(param_name)) - || is_adt_constructor_similar_to_param_name(sema, argument, param_name) -} - -fn is_argument_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool { - // check whether param_name and argument are the same or - // whether param_name is a prefix/suffix of argument(split at `_`) - let argument = match get_string_representation(argument) { - Some(argument) => argument, - None => return false, - }; - - // std is honestly too panic happy... - let str_split_at = |str: &str, at| str.is_char_boundary(at).then(|| argument.split_at(at)); - - let param_name = param_name.trim_start_matches('_'); - let argument = argument.trim_start_matches('_'); - - match str_split_at(argument, param_name.len()) { - Some((prefix, rest)) if prefix.eq_ignore_ascii_case(param_name) => { - return rest.is_empty() || rest.starts_with('_'); - } - _ => (), - } - match argument.len().checked_sub(param_name.len()).and_then(|at| str_split_at(argument, at)) { - Some((rest, suffix)) if param_name.eq_ignore_ascii_case(suffix) => { - return rest.is_empty() || rest.ends_with('_'); - } - _ => (), - } - false -} - -/// Hide the parameter name of a unary function if it is a `_` - prefixed suffix of the function's name, or equal. -/// -/// `fn strip_suffix(suffix)` will be hidden. -/// `fn stripsuffix(suffix)` will not be hidden. -fn is_param_name_suffix_of_fn_name( - param_name: &str, - callable: &Callable, - fn_name: Option<&str>, -) -> bool { - match (callable.n_params(), fn_name) { - (1, Some(function)) => { - function == param_name - || function - .len() - .checked_sub(param_name.len()) - .and_then(|at| function.is_char_boundary(at).then(|| function.split_at(at))) - .map_or(false, |(prefix, suffix)| { - suffix.eq_ignore_ascii_case(param_name) && prefix.ends_with('_') - }) - } - _ => false, - } -} - -fn is_adt_constructor_similar_to_param_name( - sema: &Semantics<'_, RootDatabase>, - argument: &ast::Expr, - param_name: &str, -) -> bool { - let path = match argument { - ast::Expr::CallExpr(c) => c.expr().and_then(|e| match e { - ast::Expr::PathExpr(p) => p.path(), - _ => None, - }), - ast::Expr::PathExpr(p) => p.path(), - ast::Expr::RecordExpr(r) => r.path(), - _ => return false, - }; - let path = match path { - Some(it) => it, - None => return false, - }; - (|| match sema.resolve_path(&path)? { - hir::PathResolution::Def(hir::ModuleDef::Adt(_)) => { - Some(to_lower_snake_case(&path.segment()?.name_ref()?.text()) == param_name) - } - hir::PathResolution::Def(hir::ModuleDef::Function(_) | hir::ModuleDef::Variant(_)) => { - if to_lower_snake_case(&path.segment()?.name_ref()?.text()) == param_name { - return Some(true); - } - let qual = path.qualifier()?; - match sema.resolve_path(&qual)? { - hir::PathResolution::Def(hir::ModuleDef::Adt(_)) => { - Some(to_lower_snake_case(&qual.segment()?.name_ref()?.text()) == param_name) - } - _ => None, - } - } - _ => None, - })() - .unwrap_or(false) -} - -fn get_string_representation(expr: &ast::Expr) -> Option { - match expr { - ast::Expr::MethodCallExpr(method_call_expr) => { - let name_ref = method_call_expr.name_ref()?; - match name_ref.text().as_str() { - "clone" | "as_ref" => method_call_expr.receiver().map(|rec| rec.to_string()), - name_ref => Some(name_ref.to_owned()), - } - } - ast::Expr::MacroExpr(macro_expr) => { - Some(macro_expr.macro_call()?.path()?.segment()?.to_string()) - } - ast::Expr::FieldExpr(field_expr) => Some(field_expr.name_ref()?.to_string()), - ast::Expr::PathExpr(path_expr) => Some(path_expr.path()?.segment()?.to_string()), - ast::Expr::PrefixExpr(prefix_expr) => get_string_representation(&prefix_expr.expr()?), - ast::Expr::RefExpr(ref_expr) => get_string_representation(&ref_expr.expr()?), - ast::Expr::CastExpr(cast_expr) => get_string_representation(&cast_expr.expr()?), - _ => None, - } -} - -fn is_obvious_param(param_name: &str) -> bool { - // avoid displaying hints for common functions like map, filter, etc. - // or other obvious words used in std - let is_obvious_param_name = - matches!(param_name, "predicate" | "value" | "pat" | "rhs" | "other"); - param_name.len() == 1 || is_obvious_param_name -} - -fn get_callable( - sema: &Semantics<'_, RootDatabase>, - expr: &ast::Expr, -) -> Option<(hir::Callable, ast::ArgList)> { - match expr { - ast::Expr::CallExpr(expr) => { - let descended = sema.descend_node_into_attributes(expr.clone()).pop(); - let expr = descended.as_ref().unwrap_or(expr); - sema.type_of_expr(&expr.expr()?)?.original.as_callable(sema.db).zip(expr.arg_list()) - } - ast::Expr::MethodCallExpr(expr) => { - let descended = sema.descend_node_into_attributes(expr.clone()).pop(); - let expr = descended.as_ref().unwrap_or(expr); - sema.resolve_method_call_as_callable(expr).zip(expr.arg_list()) - } - _ => None, - } -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - use ide_db::base_db::FileRange; - use itertools::Itertools; - use syntax::{TextRange, TextSize}; - use test_utils::extract_annotations; - - use crate::inlay_hints::ReborrowHints; - use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints}; - - use super::ClosureReturnTypeHints; - - const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig { - render_colons: false, - type_hints: false, - parameter_hints: false, - chaining_hints: false, - lifetime_elision_hints: LifetimeElisionHints::Never, - closure_return_type_hints: ClosureReturnTypeHints::Never, - reborrow_hints: ReborrowHints::Always, - binding_mode_hints: false, - hide_named_constructor_hints: false, - hide_closure_initialization_hints: false, - param_names_for_lifetime_elision_hints: false, - max_length: None, - closing_brace_hints_min_lines: None, - }; - const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig { - type_hints: true, - parameter_hints: true, - chaining_hints: true, - reborrow_hints: ReborrowHints::Always, - closure_return_type_hints: ClosureReturnTypeHints::WithBlock, - binding_mode_hints: true, - lifetime_elision_hints: LifetimeElisionHints::Always, - ..DISABLED_CONFIG - }; - - #[track_caller] - fn check(ra_fixture: &str) { - check_with_config(TEST_CONFIG, ra_fixture); - } - - #[track_caller] - fn check_params(ra_fixture: &str) { - check_with_config( - InlayHintsConfig { parameter_hints: true, ..DISABLED_CONFIG }, - ra_fixture, - ); - } - - #[track_caller] - fn check_types(ra_fixture: &str) { - check_with_config(InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, ra_fixture); - } - - #[track_caller] - fn check_chains(ra_fixture: &str) { - check_with_config(InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG }, ra_fixture); - } - - #[track_caller] - fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { - let (analysis, file_id) = fixture::file(ra_fixture); - let mut expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); - let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); - let actual = inlay_hints - .into_iter() - .map(|it| (it.range, it.label.to_string())) - .sorted_by_key(|(range, _)| range.start()) - .collect::>(); - expected.sort_by_key(|(range, _)| range.start()); - - assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual); - } - - #[track_caller] - fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { - let (analysis, file_id) = fixture::file(ra_fixture); - let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); - expect.assert_debug_eq(&inlay_hints) - } - - #[test] - fn hints_disabled() { - check_with_config( - InlayHintsConfig { render_colons: true, ..DISABLED_CONFIG }, - r#" -fn foo(a: i32, b: i32) -> i32 { a + b } -fn main() { - let _x = foo(4, 4); -}"#, - ); - } - - // Parameter hint tests - - #[test] - fn param_hints_only() { - check_params( - r#" -fn foo(a: i32, b: i32) -> i32 { a + b } -fn main() { - let _x = foo( - 4, - //^ a - 4, - //^ b - ); -}"#, - ); - } - - #[test] - fn param_hints_on_closure() { - check_params( - r#" -fn main() { - let clo = |a: u8, b: u8| a + b; - clo( - 1, - //^ a - 2, - //^ b - ); -} - "#, - ); - } - - #[test] - fn param_name_similar_to_fn_name_still_hints() { - check_params( - r#" -fn max(x: i32, y: i32) -> i32 { x + y } -fn main() { - let _x = max( - 4, - //^ x - 4, - //^ y - ); -}"#, - ); - } - - #[test] - fn param_name_similar_to_fn_name() { - check_params( - r#" -fn param_with_underscore(with_underscore: i32) -> i32 { with_underscore } -fn main() { - let _x = param_with_underscore( - 4, - ); -}"#, - ); - check_params( - r#" -fn param_with_underscore(underscore: i32) -> i32 { underscore } -fn main() { - let _x = param_with_underscore( - 4, - ); -}"#, - ); - } - - #[test] - fn param_name_same_as_fn_name() { - check_params( - r#" -fn foo(foo: i32) -> i32 { foo } -fn main() { - let _x = foo( - 4, - ); -}"#, - ); - } - - #[test] - fn never_hide_param_when_multiple_params() { - check_params( - r#" -fn foo(foo: i32, bar: i32) -> i32 { bar + baz } -fn main() { - let _x = foo( - 4, - //^ foo - 8, - //^ bar - ); -}"#, - ); - } - - #[test] - fn param_hints_look_through_as_ref_and_clone() { - check_params( - r#" -fn foo(bar: i32, baz: f32) {} - -fn main() { - let bar = 3; - let baz = &"baz"; - let fez = 1.0; - foo(bar.clone(), bar.clone()); - //^^^^^^^^^^^ baz - foo(bar.as_ref(), bar.as_ref()); - //^^^^^^^^^^^^ baz -} -"#, - ); - } - - #[test] - fn self_param_hints() { - check_params( - r#" -struct Foo; - -impl Foo { - fn foo(self: Self) {} - fn bar(self: &Self) {} -} - -fn main() { - Foo::foo(Foo); - //^^^ self - Foo::bar(&Foo); - //^^^^ self -} -"#, - ) - } - - #[test] - fn param_name_hints_show_for_literals() { - check_params( - r#"pub fn test(a: i32, b: i32) -> [i32; 2] { [a, b] } -fn main() { - test( - 0xa_b, - //^^^^^ a - 0xa_b, - //^^^^^ b - ); -}"#, - ) - } - - #[test] - fn function_call_parameter_hint() { - check_params( - r#" -//- minicore: option -struct FileId {} -struct SmolStr {} - -struct TextRange {} -struct SyntaxKind {} -struct NavigationTarget {} - -struct Test {} - -impl Test { - fn method(&self, mut param: i32) -> i32 { param * 2 } - - fn from_syntax( - file_id: FileId, - name: SmolStr, - focus_range: Option, - full_range: TextRange, - kind: SyntaxKind, - docs: Option, - ) -> NavigationTarget { - NavigationTarget {} - } -} - -fn test_func(mut foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 { - foo + bar -} - -fn main() { - let not_literal = 1; - let _: i32 = test_func(1, 2, "hello", 3, not_literal); - //^ foo ^ bar ^^^^^^^ msg ^^^^^^^^^^^ last - let t: Test = Test {}; - t.method(123); - //^^^ param - Test::method(&t, 3456); - //^^ self ^^^^ param - Test::from_syntax( - FileId {}, - "impl".into(), - //^^^^^^^^^^^^^ name - None, - //^^^^ focus_range - TextRange {}, - //^^^^^^^^^^^^ full_range - SyntaxKind {}, - //^^^^^^^^^^^^^ kind - None, - //^^^^ docs - ); -}"#, - ); - } - - #[test] - fn parameter_hint_heuristics() { - check_params( - r#" -fn check(ra_fixture_thing: &str) {} - -fn map(f: i32) {} -fn filter(predicate: i32) {} - -fn strip_suffix(suffix: &str) {} -fn stripsuffix(suffix: &str) {} -fn same(same: u32) {} -fn same2(_same2: u32) {} - -fn enum_matches_param_name(completion_kind: CompletionKind) {} - -fn foo(param: u32) {} -fn bar(param_eter: u32) {} - -enum CompletionKind { - Keyword, -} - -fn non_ident_pat((a, b): (u32, u32)) {} - -fn main() { - const PARAM: u32 = 0; - foo(PARAM); - foo(!PARAM); - // ^^^^^^ param - check(""); - - map(0); - filter(0); - - strip_suffix(""); - stripsuffix(""); - //^^ suffix - same(0); - same2(0); - - enum_matches_param_name(CompletionKind::Keyword); - - let param = 0; - foo(param); - foo(param as _); - let param_end = 0; - foo(param_end); - let start_param = 0; - foo(start_param); - let param2 = 0; - foo(param2); - //^^^^^^ param - - macro_rules! param { - () => {}; - }; - foo(param!()); - - let param_eter = 0; - bar(param_eter); - let param_eter_end = 0; - bar(param_eter_end); - let start_param_eter = 0; - bar(start_param_eter); - let param_eter2 = 0; - bar(param_eter2); - //^^^^^^^^^^^ param_eter - - non_ident_pat((0, 0)); -}"#, - ); - } - - // Type-Hint tests - - #[test] - fn type_hints_only() { - check_types( - r#" -fn foo(a: i32, b: i32) -> i32 { a + b } -fn main() { - let _x = foo(4, 4); - //^^ i32 -}"#, - ); - } - - #[test] - fn type_hints_bindings_after_at() { - check_types( - r#" -//- minicore: option -fn main() { - let ref foo @ bar @ ref mut baz = 0; - //^^^ &i32 - //^^^ i32 - //^^^ &mut i32 - let [x @ ..] = [0]; - //^ [i32; 1] - if let x @ Some(_) = Some(0) {} - //^ Option - let foo @ (bar, baz) = (3, 3); - //^^^ (i32, i32) - //^^^ i32 - //^^^ i32 -}"#, - ); - } - - #[test] - fn default_generic_types_should_not_be_displayed() { - check( - r#" -struct Test { k: K, t: T } - -fn main() { - let zz = Test { t: 23u8, k: 33 }; - //^^ Test - let zz_ref = &zz; - //^^^^^^ &Test - let test = || zz; - //^^^^ || -> Test -}"#, - ); - } - - #[test] - fn shorten_iterators_in_associated_params() { - check_types( - r#" -//- minicore: iterators -use core::iter; - -pub struct SomeIter {} - -impl SomeIter { - pub fn new() -> Self { SomeIter {} } - pub fn push(&mut self, t: T) {} -} - -impl Iterator for SomeIter { - type Item = T; - fn next(&mut self) -> Option { - None - } -} - -fn main() { - let mut some_iter = SomeIter::new(); - //^^^^^^^^^ SomeIter>> - some_iter.push(iter::repeat(2).take(2)); - let iter_of_iters = some_iter.take(2); - //^^^^^^^^^^^^^ impl Iterator> -} -"#, - ); - } - - #[test] - fn infer_call_method_return_associated_types_with_generic() { - check_types( - r#" - pub trait Default { - fn default() -> Self; - } - pub trait Foo { - type Bar: Default; - } - - pub fn quux() -> T::Bar { - let y = Default::default(); - //^ ::Bar - - y - } - "#, - ); - } - - #[test] - fn fn_hints() { - check_types( - r#" -//- minicore: fn, sized -fn foo() -> impl Fn() { loop {} } -fn foo1() -> impl Fn(f64) { loop {} } -fn foo2() -> impl Fn(f64, f64) { loop {} } -fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} } -fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} } -fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} } -fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} } -fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} } - -fn main() { - let foo = foo(); - // ^^^ impl Fn() - let foo = foo1(); - // ^^^ impl Fn(f64) - let foo = foo2(); - // ^^^ impl Fn(f64, f64) - let foo = foo3(); - // ^^^ impl Fn(f64, f64) -> u32 - let foo = foo4(); - // ^^^ &dyn Fn(f64, f64) -> u32 - let foo = foo5(); - // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32 - let foo = foo6(); - // ^^^ impl Fn(f64, f64) -> u32 - let foo = foo7(); - // ^^^ *const impl Fn(f64, f64) -> u32 -} -"#, - ) - } - - #[test] - fn check_hint_range_limit() { - let fixture = r#" - //- minicore: fn, sized - fn foo() -> impl Fn() { loop {} } - fn foo1() -> impl Fn(f64) { loop {} } - fn foo2() -> impl Fn(f64, f64) { loop {} } - fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} } - fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} } - fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} } - fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} } - fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} } - - fn main() { - let foo = foo(); - let foo = foo1(); - let foo = foo2(); - // ^^^ impl Fn(f64, f64) - let foo = foo3(); - // ^^^ impl Fn(f64, f64) -> u32 - let foo = foo4(); - let foo = foo5(); - let foo = foo6(); - let foo = foo7(); - } - "#; - let (analysis, file_id) = fixture::file(fixture); - let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); - let inlay_hints = analysis - .inlay_hints( - &InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, - file_id, - Some(FileRange { - file_id, - range: TextRange::new(TextSize::from(500), TextSize::from(600)), - }), - ) - .unwrap(); - let actual = - inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::>(); - assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual); - } - - #[test] - fn fn_hints_ptr_rpit_fn_parentheses() { - check_types( - r#" -//- minicore: fn, sized -trait Trait {} - -fn foo1() -> *const impl Fn() { loop {} } -fn foo2() -> *const (impl Fn() + Sized) { loop {} } -fn foo3() -> *const (impl Fn() + ?Sized) { loop {} } -fn foo4() -> *const (impl Sized + Fn()) { loop {} } -fn foo5() -> *const (impl ?Sized + Fn()) { loop {} } -fn foo6() -> *const (impl Fn() + Trait) { loop {} } -fn foo7() -> *const (impl Fn() + Sized + Trait) { loop {} } -fn foo8() -> *const (impl Fn() + ?Sized + Trait) { loop {} } -fn foo9() -> *const (impl Fn() -> u8 + ?Sized) { loop {} } -fn foo10() -> *const (impl Fn() + Sized + ?Sized) { loop {} } - -fn main() { - let foo = foo1(); - // ^^^ *const impl Fn() - let foo = foo2(); - // ^^^ *const impl Fn() - let foo = foo3(); - // ^^^ *const (impl Fn() + ?Sized) - let foo = foo4(); - // ^^^ *const impl Fn() - let foo = foo5(); - // ^^^ *const (impl Fn() + ?Sized) - let foo = foo6(); - // ^^^ *const (impl Fn() + Trait) - let foo = foo7(); - // ^^^ *const (impl Fn() + Trait) - let foo = foo8(); - // ^^^ *const (impl Fn() + Trait + ?Sized) - let foo = foo9(); - // ^^^ *const (impl Fn() -> u8 + ?Sized) - let foo = foo10(); - // ^^^ *const impl Fn() -} -"#, - ) - } - - #[test] - fn unit_structs_have_no_type_hints() { - check_types( - r#" -//- minicore: result -struct SyntheticSyntax; - -fn main() { - match Ok(()) { - Ok(_) => (), - Err(SyntheticSyntax) => (), - } -}"#, - ); - } - - #[test] - fn let_statement() { - check_types( - r#" -#[derive(PartialEq)] -enum Option { None, Some(T) } - -#[derive(PartialEq)] -struct Test { a: Option, b: u8 } - -fn main() { - struct InnerStruct {} - - let test = 54; - //^^^^ i32 - let test: i32 = 33; - let mut test = 33; - //^^^^ i32 - let _ = 22; - let test = "test"; - //^^^^ &str - let test = InnerStruct {}; - //^^^^ InnerStruct - - let test = unresolved(); - - let test = (42, 'a'); - //^^^^ (i32, char) - let (a, (b, (c,)) = (2, (3, (9.2,)); - //^ i32 ^ i32 ^ f64 - let &x = &92; - //^ i32 -}"#, - ); - } - - #[test] - fn if_expr() { - check_types( - r#" -//- minicore: option -struct Test { a: Option, b: u8 } - -fn main() { - let test = Some(Test { a: Some(3), b: 1 }); - //^^^^ Option - if let None = &test {}; - if let test = &test {}; - //^^^^ &Option - if let Some(test) = &test {}; - //^^^^ &Test - if let Some(Test { a, b }) = &test {}; - //^ &Option ^ &u8 - if let Some(Test { a: x, b: y }) = &test {}; - //^ &Option ^ &u8 - if let Some(Test { a: Some(x), b: y }) = &test {}; - //^ &u32 ^ &u8 - if let Some(Test { a: None, b: y }) = &test {}; - //^ &u8 - if let Some(Test { b: y, .. }) = &test {}; - //^ &u8 - if test == None {} -}"#, - ); - } - - #[test] - fn while_expr() { - check_types( - r#" -//- minicore: option -struct Test { a: Option, b: u8 } - -fn main() { - let test = Some(Test { a: Some(3), b: 1 }); - //^^^^ Option - while let Some(Test { a: Some(x), b: y }) = &test {}; - //^ &u32 ^ &u8 -}"#, - ); - } - - #[test] - fn match_arm_list() { - check_types( - r#" -//- minicore: option -struct Test { a: Option, b: u8 } - -fn main() { - match Some(Test { a: Some(3), b: 1 }) { - None => (), - test => (), - //^^^^ Option - Some(Test { a: Some(x), b: y }) => (), - //^ u32 ^ u8 - _ => {} - } -}"#, - ); - } - - #[test] - fn complete_for_hint() { - check_types( - r#" -//- minicore: iterator -pub struct Vec {} - -impl Vec { - pub fn new() -> Self { Vec {} } - pub fn push(&mut self, t: T) {} -} - -impl IntoIterator for Vec { - type Item=T; -} - -fn main() { - let mut data = Vec::new(); - //^^^^ Vec<&str> - data.push("foo"); - for i in data { - //^ &str - let z = i; - //^ &str - } -} -"#, - ); - } - - #[test] - fn multi_dyn_trait_bounds() { - check_types( - r#" -pub struct Vec {} - -impl Vec { - pub fn new() -> Self { Vec {} } -} - -pub struct Box {} - -trait Display {} -trait Sync {} - -fn main() { - // The block expression wrapping disables the constructor hint hiding logic - let _v = { Vec::>::new() }; - //^^ Vec> - let _v = { Vec::>::new() }; - //^^ Vec> - let _v = { Vec::>::new() }; - //^^ Vec> -} -"#, - ); - } - - #[test] - fn shorten_iterator_hints() { - check_types( - r#" -//- minicore: iterators -use core::iter; - -struct MyIter; - -impl Iterator for MyIter { - type Item = (); - fn next(&mut self) -> Option { - None - } -} - -fn main() { - let _x = MyIter; - //^^ MyIter - let _x = iter::repeat(0); - //^^ impl Iterator - fn generic(t: T) { - let _x = iter::repeat(t); - //^^ impl Iterator - let _chained = iter::repeat(t).take(10); - //^^^^^^^^ impl Iterator - } -} -"#, - ); - } - - #[test] - fn skip_constructor_and_enum_type_hints() { - check_with_config( - InlayHintsConfig { - type_hints: true, - hide_named_constructor_hints: true, - ..DISABLED_CONFIG - }, - r#" -//- minicore: try, option -use core::ops::ControlFlow; - -mod x { - pub mod y { pub struct Foo; } - pub struct Foo; - pub enum AnotherEnum { - Variant() - }; -} -struct Struct; -struct TupleStruct(); - -impl Struct { - fn new() -> Self { - Struct - } - fn try_new() -> ControlFlow<(), Self> { - ControlFlow::Continue(Struct) - } -} - -struct Generic(T); -impl Generic { - fn new() -> Self { - Generic(0) - } -} - -enum Enum { - Variant(u32) -} - -fn times2(value: i32) -> i32 { - 2 * value -} - -fn main() { - let enumb = Enum::Variant(0); - - let strukt = x::Foo; - let strukt = x::y::Foo; - let strukt = Struct; - let strukt = Struct::new(); - - let tuple_struct = TupleStruct(); - - let generic0 = Generic::new(); - // ^^^^^^^^ Generic - let generic1 = Generic(0); - // ^^^^^^^^ Generic - let generic2 = Generic::::new(); - let generic3 = >::new(); - let generic4 = Generic::(0); - - - let option = Some(0); - // ^^^^^^ Option - let func = times2; - // ^^^^ fn times2(i32) -> i32 - let closure = |x: i32| x * 2; - // ^^^^^^^ |i32| -> i32 -} - -fn fallible() -> ControlFlow<()> { - let strukt = Struct::try_new()?; -} -"#, - ); - } - - #[test] - fn shows_constructor_type_hints_when_enabled() { - check_types( - r#" -//- minicore: try -use core::ops::ControlFlow; - -struct Struct; -struct TupleStruct(); - -impl Struct { - fn new() -> Self { - Struct - } - fn try_new() -> ControlFlow<(), Self> { - ControlFlow::Continue(Struct) - } -} - -struct Generic(T); -impl Generic { - fn new() -> Self { - Generic(0) - } -} - -fn main() { - let strukt = Struct::new(); - // ^^^^^^ Struct - let tuple_struct = TupleStruct(); - // ^^^^^^^^^^^^ TupleStruct - let generic0 = Generic::new(); - // ^^^^^^^^ Generic - let generic1 = Generic::::new(); - // ^^^^^^^^ Generic - let generic2 = >::new(); - // ^^^^^^^^ Generic -} - -fn fallible() -> ControlFlow<()> { - let strukt = Struct::try_new()?; - // ^^^^^^ Struct -} -"#, - ); - } - - #[test] - fn closures() { - check( - r#" -fn main() { - let mut start = 0; - //^^^^^ i32 - (0..2).for_each(|increment | { start += increment; }); - //^^^^^^^^^ i32 - - let multiply = - //^^^^^^^^ |i32, i32| -> i32 - | a, b| a * b - //^ i32 ^ i32 - - ; - - let _: i32 = multiply(1, 2); - //^ a ^ b - let multiply_ref = &multiply; - //^^^^^^^^^^^^ &|i32, i32| -> i32 - - let return_42 = || 42; - //^^^^^^^^^ || -> i32 - || { 42 }; - //^^ i32 -}"#, - ); - } - - #[test] - fn return_type_hints_for_closure_without_block() { - check_with_config( - InlayHintsConfig { - closure_return_type_hints: ClosureReturnTypeHints::Always, - ..DISABLED_CONFIG - }, - r#" -fn main() { - let a = || { 0 }; - //^^ i32 - let b = || 0; - //^^ i32 -}"#, - ); - } - - #[test] - fn skip_closure_type_hints() { - check_with_config( - InlayHintsConfig { - type_hints: true, - hide_closure_initialization_hints: true, - ..DISABLED_CONFIG - }, - r#" -//- minicore: fn -fn main() { - let multiple_2 = |x: i32| { x * 2 }; - - let multiple_2 = |x: i32| x * 2; - // ^^^^^^^^^^ |i32| -> i32 - - let (not) = (|x: bool| { !x }); - // ^^^ |bool| -> bool - - let (is_zero, _b) = (|x: usize| { x == 0 }, false); - // ^^^^^^^ |usize| -> bool - // ^^ bool - - let plus_one = |x| { x + 1 }; - // ^ u8 - foo(plus_one); - - let add_mul = bar(|x: u8| { x + 1 }); - // ^^^^^^^ impl FnOnce(u8) -> u8 + ?Sized - - let closure = if let Some(6) = add_mul(2).checked_sub(1) { - // ^^^^^^^ fn(i32) -> i32 - |x: i32| { x * 2 } - } else { - |x: i32| { x * 3 } - }; -} - -fn foo(f: impl FnOnce(u8) -> u8) {} - -fn bar(f: impl FnOnce(u8) -> u8) -> impl FnOnce(u8) -> u8 { - move |x: u8| f(x) * 2 -} -"#, - ); - } - - #[test] - fn hint_truncation() { - check_with_config( - InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, - r#" -struct Smol(T); - -struct VeryLongOuterName(T); - -fn main() { - let a = Smol(0u32); - //^ Smol - let b = VeryLongOuterName(0usize); - //^ VeryLongOuterName<…> - let c = Smol(Smol(0u32)) - //^ Smol> -}"#, - ); - } - - // Chaining hint tests - - #[test] - fn chaining_hints_ignore_comments() { - check_expect( - InlayHintsConfig { type_hints: false, chaining_hints: true, ..DISABLED_CONFIG }, - r#" -struct A(B); -impl A { fn into_b(self) -> B { self.0 } } -struct B(C); -impl B { fn into_c(self) -> C { self.0 } } -struct C; - -fn main() { - let c = A(B(C)) - .into_b() // This is a comment - // This is another comment - .into_c(); -} -"#, - expect![[r#" - [ - InlayHint { - range: 147..172, - kind: ChainingHint, - label: "B", - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 147..172, - ), - ), - }, - InlayHint { - range: 147..154, - kind: ChainingHint, - label: "A", - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 147..154, - ), - ), - }, - ] - "#]], - ); - } - - #[test] - fn chaining_hints_without_newlines() { - check_chains( - r#" -struct A(B); -impl A { fn into_b(self) -> B { self.0 } } -struct B(C); -impl B { fn into_c(self) -> C { self.0 } } -struct C; - -fn main() { - let c = A(B(C)).into_b().into_c(); -}"#, - ); - } - - #[test] - fn struct_access_chaining_hints() { - check_expect( - InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG }, - r#" -struct A { pub b: B } -struct B { pub c: C } -struct C(pub bool); -struct D; - -impl D { - fn foo(&self) -> i32 { 42 } -} - -fn main() { - let x = A { b: B { c: C(true) } } - .b - .c - .0; - let x = D - .foo(); -}"#, - expect![[r#" - [ - InlayHint { - range: 143..190, - kind: ChainingHint, - label: "C", - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 143..190, - ), - ), - }, - InlayHint { - range: 143..179, - kind: ChainingHint, - label: "B", - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 143..179, - ), - ), - }, - ] - "#]], - ); - } - - #[test] - fn generic_chaining_hints() { - check_expect( - InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG }, - r#" -struct A(T); -struct B(T); -struct C(T); -struct X(T, R); - -impl A { - fn new(t: T) -> Self { A(t) } - fn into_b(self) -> B { B(self.0) } -} -impl B { - fn into_c(self) -> C { C(self.0) } -} -fn main() { - let c = A::new(X(42, true)) - .into_b() - .into_c(); -} -"#, - expect![[r#" - [ - InlayHint { - range: 246..283, - kind: ChainingHint, - label: "B>", - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 246..283, - ), - ), - }, - InlayHint { - range: 246..265, - kind: ChainingHint, - label: "A>", - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 246..265, - ), - ), - }, - ] - "#]], - ); - } - - #[test] - fn shorten_iterator_chaining_hints() { - check_expect( - InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG }, - r#" -//- minicore: iterators -use core::iter; - -struct MyIter; - -impl Iterator for MyIter { - type Item = (); - fn next(&mut self) -> Option { - None - } -} - -fn main() { - let _x = MyIter.by_ref() - .take(5) - .by_ref() - .take(5) - .by_ref(); -} -"#, - expect![[r#" - [ - InlayHint { - range: 174..241, - kind: ChainingHint, - label: "impl Iterator", - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 174..241, - ), - ), - }, - InlayHint { - range: 174..224, - kind: ChainingHint, - label: "impl Iterator", - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 174..224, - ), - ), - }, - InlayHint { - range: 174..206, - kind: ChainingHint, - label: "impl Iterator", - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 174..206, - ), - ), - }, - InlayHint { - range: 174..189, - kind: ChainingHint, - label: "&mut MyIter", - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 174..189, - ), - ), - }, - ] - "#]], - ); - } - - #[test] - fn hints_in_attr_call() { - check_expect( - TEST_CONFIG, - r#" -//- proc_macros: identity, input_replace -struct Struct; -impl Struct { - fn chain(self) -> Self { - self - } -} -#[proc_macros::identity] -fn main() { - let strukt = Struct; - strukt - .chain() - .chain() - .chain(); - Struct::chain(strukt); -} -"#, - expect![[r#" - [ - InlayHint { - range: 124..130, - kind: TypeHint, - label: "Struct", - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 124..130, - ), - ), - }, - InlayHint { - range: 145..185, - kind: ChainingHint, - label: "Struct", - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 145..185, - ), - ), - }, - InlayHint { - range: 145..168, - kind: ChainingHint, - label: "Struct", - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 145..168, - ), - ), - }, - InlayHint { - range: 222..228, - kind: ParameterHint, - label: "self", - tooltip: Some( - HoverOffset( - FileId( - 0, - ), - 42, - ), - ), - }, - ] - "#]], - ); - } - - #[test] - fn hints_lifetimes() { - check( - r#" -fn empty() {} - -fn no_gpl(a: &()) {} - //^^^^^^<'0> - // ^'0 -fn empty_gpl<>(a: &()) {} - // ^'0 ^'0 -fn partial<'b>(a: &(), b: &'b ()) {} -// ^'0, $ ^'0 -fn partial<'a>(a: &'a (), b: &()) {} -// ^'0, $ ^'0 - -fn single_ret(a: &()) -> &() {} -// ^^^^^^^^^^<'0> - // ^'0 ^'0 -fn full_mul(a: &(), b: &()) {} -// ^^^^^^^^<'0, '1> - // ^'0 ^'1 - -fn foo<'c>(a: &'c ()) -> &() {} - // ^'c - -fn nested_in(a: & &X< &()>) {} -// ^^^^^^^^^<'0, '1, '2> - //^'0 ^'1 ^'2 -fn nested_out(a: &()) -> & &X< &()>{} -// ^^^^^^^^^^<'0> - //^'0 ^'0 ^'0 ^'0 - -impl () { - fn foo(&self) {} - // ^^^<'0> - // ^'0 - fn foo(&self) -> &() {} - // ^^^<'0> - // ^'0 ^'0 - fn foo(&self, a: &()) -> &() {} - // ^^^<'0, '1> - // ^'0 ^'1 ^'0 -} -"#, - ); - } - - #[test] - fn hints_lifetimes_named() { - check_with_config( - InlayHintsConfig { param_names_for_lifetime_elision_hints: true, ..TEST_CONFIG }, - r#" -fn nested_in<'named>(named: & &X< &()>) {} -// ^'named1, 'named2, 'named3, $ - //^'named1 ^'named2 ^'named3 -"#, - ); - } - - #[test] - fn hints_lifetimes_trivial_skip() { - check_with_config( - InlayHintsConfig { - lifetime_elision_hints: LifetimeElisionHints::SkipTrivial, - ..TEST_CONFIG - }, - r#" -fn no_gpl(a: &()) {} -fn empty_gpl<>(a: &()) {} -fn partial<'b>(a: &(), b: &'b ()) {} -fn partial<'a>(a: &'a (), b: &()) {} - -fn single_ret(a: &()) -> &() {} -// ^^^^^^^^^^<'0> - // ^'0 ^'0 -fn full_mul(a: &(), b: &()) {} - -fn foo<'c>(a: &'c ()) -> &() {} - // ^'c - -fn nested_in(a: & &X< &()>) {} -fn nested_out(a: &()) -> & &X< &()>{} -// ^^^^^^^^^^<'0> - //^'0 ^'0 ^'0 ^'0 - -impl () { - fn foo(&self) {} - fn foo(&self) -> &() {} - // ^^^<'0> - // ^'0 ^'0 - fn foo(&self, a: &()) -> &() {} - // ^^^<'0, '1> - // ^'0 ^'1 ^'0 -} -"#, - ); - } - - #[test] - fn hints_lifetimes_static() { - check_with_config( - InlayHintsConfig { - lifetime_elision_hints: LifetimeElisionHints::Always, - ..TEST_CONFIG - }, - r#" -trait Trait {} -static S: &str = ""; -// ^'static -const C: &str = ""; -// ^'static -const C: &dyn Trait = panic!(); -// ^'static - -impl () { - const C: &str = ""; - const C: &dyn Trait = panic!(); -} -"#, - ); - } - - #[test] - fn hints_implicit_reborrow() { - check_with_config( - InlayHintsConfig { - reborrow_hints: ReborrowHints::Always, - parameter_hints: true, - ..DISABLED_CONFIG - }, - r#" -fn __() { - let unique = &mut (); - let r_mov = unique; - let foo: &mut _ = unique; - //^^^^^^ &mut * - ref_mut_id(unique); - //^^^^^^ mut_ref - //^^^^^^ &mut * - let shared = ref_id(unique); - //^^^^^^ shared_ref - //^^^^^^ &* - let mov = shared; - let r_mov: &_ = shared; - ref_id(shared); - //^^^^^^ shared_ref - - identity(unique); - identity(shared); -} -fn identity(t: T) -> T { - t -} -fn ref_mut_id(mut_ref: &mut ()) -> &mut () { - mut_ref - //^^^^^^^ &mut * -} -fn ref_id(shared_ref: &()) -> &() { - shared_ref -} -"#, - ); - } - - #[test] - fn hints_binding_modes() { - check_with_config( - InlayHintsConfig { binding_mode_hints: true, ..DISABLED_CONFIG }, - r#" -fn __( - (x,): (u32,), - (x,): &(u32,), - //^^^^& - //^ ref - (x,): &mut (u32,) - //^^^^&mut - //^ ref mut -) { - let (x,) = (0,); - let (x,) = &(0,); - //^^^^ & - //^ ref - let (x,) = &mut (0,); - //^^^^ &mut - //^ ref mut - let &mut (x,) = &mut (0,); - let (ref mut x,) = &mut (0,); - //^^^^^^^^^^^^ &mut - let &mut (ref mut x,) = &mut (0,); - let (mut x,) = &mut (0,); - //^^^^^^^^ &mut - match (0,) { - (x,) => () - } - match &(0,) { - (x,) => () - //^^^^ & - //^ ref - } - match &mut (0,) { - (x,) => () - //^^^^ &mut - //^ ref mut - } -}"#, - ); - } - - #[test] - fn hints_closing_brace() { - check_with_config( - InlayHintsConfig { closing_brace_hints_min_lines: Some(2), ..DISABLED_CONFIG }, - r#" -fn a() {} - -fn f() { -} // no hint unless `}` is the last token on the line - -fn g() { - } -//^ fn g - -fn h(with: T, arguments: u8, ...) { - } -//^ fn h - -trait Tr { - fn f(); - fn g() { - } - //^ fn g - } -//^ trait Tr -impl Tr for () { - } -//^ impl Tr for () -impl dyn Tr { - } -//^ impl dyn Tr - -static S0: () = 0; -static S1: () = {}; -static S2: () = { - }; -//^ static S2 -const _: () = { - }; -//^ const _ - -mod m { - } -//^ mod m - -m! {} -m!(); -m!( - ); -//^ m! - -m! { - } -//^ m! - -fn f() { - let v = vec![ - ]; - } -//^ fn f -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs deleted file mode 100644 index 08621addeef4d..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs +++ /dev/null @@ -1,1087 +0,0 @@ -use ide_assists::utils::extract_trivial_expression; -use ide_db::syntax_helpers::node_ext::expr_as_name_ref; -use itertools::Itertools; -use syntax::{ - ast::{self, AstNode, AstToken, IsString}, - NodeOrToken, SourceFile, SyntaxElement, - SyntaxKind::{self, USE_TREE, WHITESPACE}, - SyntaxToken, TextRange, TextSize, T, -}; - -use text_edit::{TextEdit, TextEditBuilder}; - -pub struct JoinLinesConfig { - pub join_else_if: bool, - pub remove_trailing_comma: bool, - pub unwrap_trivial_blocks: bool, - pub join_assignments: bool, -} - -// Feature: Join Lines -// -// Join selected lines into one, smartly fixing up whitespace, trailing commas, and braces. -// -// See -// https://user-images.githubusercontent.com/1711539/124515923-4504e800-dde9-11eb-8d58-d97945a1a785.gif[this gif] -// for the cases handled specially by joined lines. -// -// |=== -// | Editor | Action Name -// -// | VS Code | **Rust Analyzer: Join lines** -// |=== -// -// image::https://user-images.githubusercontent.com/48062697/113020661-b6922200-917a-11eb-87c4-b75acc028f11.gif[] -pub(crate) fn join_lines( - config: &JoinLinesConfig, - file: &SourceFile, - range: TextRange, -) -> TextEdit { - let range = if range.is_empty() { - let syntax = file.syntax(); - let text = syntax.text().slice(range.start()..); - let pos = match text.find_char('\n') { - None => return TextEdit::builder().finish(), - Some(pos) => pos, - }; - TextRange::at(range.start() + pos, TextSize::of('\n')) - } else { - range - }; - - let mut edit = TextEdit::builder(); - match file.syntax().covering_element(range) { - NodeOrToken::Node(node) => { - for token in node.descendants_with_tokens().filter_map(|it| it.into_token()) { - remove_newlines(config, &mut edit, &token, range) - } - } - NodeOrToken::Token(token) => remove_newlines(config, &mut edit, &token, range), - }; - edit.finish() -} - -fn remove_newlines( - config: &JoinLinesConfig, - edit: &mut TextEditBuilder, - token: &SyntaxToken, - range: TextRange, -) { - let intersection = match range.intersect(token.text_range()) { - Some(range) => range, - None => return, - }; - - let range = intersection - token.text_range().start(); - let text = token.text(); - for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') { - let pos: TextSize = (pos as u32).into(); - let offset = token.text_range().start() + range.start() + pos; - if !edit.invalidates_offset(offset) { - remove_newline(config, edit, token, offset); - } - } -} - -fn remove_newline( - config: &JoinLinesConfig, - edit: &mut TextEditBuilder, - token: &SyntaxToken, - offset: TextSize, -) { - if token.kind() != WHITESPACE || token.text().bytes().filter(|&b| b == b'\n').count() != 1 { - let n_spaces_after_line_break = { - let suff = &token.text()[TextRange::new( - offset - token.text_range().start() + TextSize::of('\n'), - TextSize::of(token.text()), - )]; - suff.bytes().take_while(|&b| b == b' ').count() - }; - - let mut no_space = false; - if let Some(string) = ast::String::cast(token.clone()) { - if let Some(range) = string.open_quote_text_range() { - cov_mark::hit!(join_string_literal_open_quote); - no_space |= range.end() == offset; - } - if let Some(range) = string.close_quote_text_range() { - cov_mark::hit!(join_string_literal_close_quote); - no_space |= range.start() - == offset - + TextSize::of('\n') - + TextSize::try_from(n_spaces_after_line_break).unwrap(); - } - } - - let range = TextRange::at(offset, ((n_spaces_after_line_break + 1) as u32).into()); - let replace_with = if no_space { "" } else { " " }; - edit.replace(range, replace_with.to_string()); - return; - } - - // The node is between two other nodes - let (prev, next) = match (token.prev_sibling_or_token(), token.next_sibling_or_token()) { - (Some(prev), Some(next)) => (prev, next), - _ => return, - }; - - if config.remove_trailing_comma && prev.kind() == T![,] { - match next.kind() { - T![')'] | T![']'] => { - // Removes: trailing comma, newline (incl. surrounding whitespace) - edit.delete(TextRange::new(prev.text_range().start(), token.text_range().end())); - return; - } - T!['}'] => { - // Removes: comma, newline (incl. surrounding whitespace) - let space = match prev.prev_sibling_or_token() { - Some(left) => compute_ws(left.kind(), next.kind()), - None => " ", - }; - edit.replace( - TextRange::new(prev.text_range().start(), token.text_range().end()), - space.to_string(), - ); - return; - } - _ => (), - } - } - - if config.join_else_if { - if let (Some(prev), Some(_next)) = (as_if_expr(&prev), as_if_expr(&next)) { - match prev.else_token() { - Some(_) => cov_mark::hit!(join_two_ifs_with_existing_else), - None => { - cov_mark::hit!(join_two_ifs); - edit.replace(token.text_range(), " else ".to_string()); - return; - } - } - } - } - - if config.join_assignments { - if join_assignments(edit, &prev, &next).is_some() { - return; - } - } - - if config.unwrap_trivial_blocks { - // Special case that turns something like: - // - // ``` - // my_function({$0 - // - // }) - // ``` - // - // into `my_function()` - if join_single_expr_block(edit, token).is_some() { - return; - } - // ditto for - // - // ``` - // use foo::{$0 - // bar - // }; - // ``` - if join_single_use_tree(edit, token).is_some() { - return; - } - } - - if let (Some(_), Some(next)) = ( - prev.as_token().cloned().and_then(ast::Comment::cast), - next.as_token().cloned().and_then(ast::Comment::cast), - ) { - // Removes: newline (incl. surrounding whitespace), start of the next comment - edit.delete(TextRange::new( - token.text_range().start(), - next.syntax().text_range().start() + TextSize::of(next.prefix()), - )); - return; - } - - // Remove newline but add a computed amount of whitespace characters - edit.replace(token.text_range(), compute_ws(prev.kind(), next.kind()).to_string()); -} - -fn join_single_expr_block(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Option<()> { - let block_expr = ast::BlockExpr::cast(token.parent_ancestors().nth(1)?)?; - if !block_expr.is_standalone() { - return None; - } - let expr = extract_trivial_expression(&block_expr)?; - - let block_range = block_expr.syntax().text_range(); - let mut buf = expr.syntax().text().to_string(); - - // Match block needs to have a comma after the block - if let Some(match_arm) = block_expr.syntax().parent().and_then(ast::MatchArm::cast) { - if match_arm.comma_token().is_none() { - buf.push(','); - } - } - - edit.replace(block_range, buf); - - Some(()) -} - -fn join_single_use_tree(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Option<()> { - let use_tree_list = ast::UseTreeList::cast(token.parent()?)?; - let (tree,) = use_tree_list.use_trees().collect_tuple()?; - edit.replace(use_tree_list.syntax().text_range(), tree.syntax().text().to_string()); - Some(()) -} - -fn join_assignments( - edit: &mut TextEditBuilder, - prev: &SyntaxElement, - next: &SyntaxElement, -) -> Option<()> { - let let_stmt = ast::LetStmt::cast(prev.as_node()?.clone())?; - if let_stmt.eq_token().is_some() { - cov_mark::hit!(join_assignments_already_initialized); - return None; - } - let let_ident_pat = match let_stmt.pat()? { - ast::Pat::IdentPat(it) => it, - _ => return None, - }; - - let expr_stmt = ast::ExprStmt::cast(next.as_node()?.clone())?; - let bin_expr = match expr_stmt.expr()? { - ast::Expr::BinExpr(it) => it, - _ => return None, - }; - if !matches!(bin_expr.op_kind()?, ast::BinaryOp::Assignment { op: None }) { - return None; - } - let lhs = bin_expr.lhs()?; - let name_ref = expr_as_name_ref(&lhs)?; - - if name_ref.to_string() != let_ident_pat.syntax().to_string() { - cov_mark::hit!(join_assignments_mismatch); - return None; - } - - edit.delete(let_stmt.semicolon_token()?.text_range().cover(lhs.syntax().text_range())); - Some(()) -} - -fn as_if_expr(element: &SyntaxElement) -> Option { - let mut node = element.as_node()?.clone(); - if let Some(stmt) = ast::ExprStmt::cast(node.clone()) { - node = stmt.expr()?.syntax().clone(); - } - ast::IfExpr::cast(node) -} - -fn compute_ws(left: SyntaxKind, right: SyntaxKind) -> &'static str { - match left { - T!['('] | T!['['] => return "", - T!['{'] => { - if let USE_TREE = right { - return ""; - } - } - _ => (), - } - match right { - T![')'] | T![']'] => return "", - T!['}'] => { - if let USE_TREE = left { - return ""; - } - } - T![.] => return "", - _ => (), - } - " " -} - -#[cfg(test)] -mod tests { - use syntax::SourceFile; - use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; - - use super::*; - - fn check_join_lines(ra_fixture_before: &str, ra_fixture_after: &str) { - let config = JoinLinesConfig { - join_else_if: true, - remove_trailing_comma: true, - unwrap_trivial_blocks: true, - join_assignments: true, - }; - - let (before_cursor_pos, before) = extract_offset(ra_fixture_before); - let file = SourceFile::parse(&before).ok().unwrap(); - - let range = TextRange::empty(before_cursor_pos); - let result = join_lines(&config, &file, range); - - let actual = { - let mut actual = before; - result.apply(&mut actual); - actual - }; - let actual_cursor_pos = result - .apply_to_offset(before_cursor_pos) - .expect("cursor position is affected by the edit"); - let actual = add_cursor(&actual, actual_cursor_pos); - assert_eq_text!(ra_fixture_after, &actual); - } - - fn check_join_lines_sel(ra_fixture_before: &str, ra_fixture_after: &str) { - let config = JoinLinesConfig { - join_else_if: true, - remove_trailing_comma: true, - unwrap_trivial_blocks: true, - join_assignments: true, - }; - - let (sel, before) = extract_range(ra_fixture_before); - let parse = SourceFile::parse(&before); - let result = join_lines(&config, &parse.tree(), sel); - let actual = { - let mut actual = before; - result.apply(&mut actual); - actual - }; - assert_eq_text!(ra_fixture_after, &actual); - } - - #[test] - fn test_join_lines_comma() { - check_join_lines( - r" -fn foo() { - $0foo(1, - ) -} -", - r" -fn foo() { - $0foo(1) -} -", - ); - } - - #[test] - fn test_join_lines_lambda_block() { - check_join_lines( - r" -pub fn reparse(&self, edit: &AtomTextEdit) -> File { - $0self.incremental_reparse(edit).unwrap_or_else(|| { - self.full_reparse(edit) - }) -} -", - r" -pub fn reparse(&self, edit: &AtomTextEdit) -> File { - $0self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) -} -", - ); - } - - #[test] - fn test_join_lines_block() { - check_join_lines( - r" -fn foo() { - foo($0{ - 92 - }) -}", - r" -fn foo() { - foo($092) -}", - ); - } - - #[test] - fn test_join_lines_diverging_block() { - check_join_lines( - r" -fn foo() { - loop { - match x { - 92 => $0{ - continue; - } - } - } -} - ", - r" -fn foo() { - loop { - match x { - 92 => $0continue, - } - } -} - ", - ); - } - - #[test] - fn join_lines_adds_comma_for_block_in_match_arm() { - check_join_lines( - r" -fn foo(e: Result) { - match e { - Ok(u) => $0{ - u.foo() - } - Err(v) => v, - } -}", - r" -fn foo(e: Result) { - match e { - Ok(u) => $0u.foo(), - Err(v) => v, - } -}", - ); - } - - #[test] - fn join_lines_multiline_in_block() { - check_join_lines( - r" -fn foo() { - match ty { - $0 Some(ty) => { - match ty { - _ => false, - } - } - _ => true, - } -} -", - r" -fn foo() { - match ty { - $0 Some(ty) => match ty { - _ => false, - }, - _ => true, - } -} -", - ); - } - - #[test] - fn join_lines_keeps_comma_for_block_in_match_arm() { - // We already have a comma - check_join_lines( - r" -fn foo(e: Result) { - match e { - Ok(u) => $0{ - u.foo() - }, - Err(v) => v, - } -}", - r" -fn foo(e: Result) { - match e { - Ok(u) => $0u.foo(), - Err(v) => v, - } -}", - ); - - // comma with whitespace between brace and , - check_join_lines( - r" -fn foo(e: Result) { - match e { - Ok(u) => $0{ - u.foo() - } , - Err(v) => v, - } -}", - r" -fn foo(e: Result) { - match e { - Ok(u) => $0u.foo() , - Err(v) => v, - } -}", - ); - - // comma with newline between brace and , - check_join_lines( - r" -fn foo(e: Result) { - match e { - Ok(u) => $0{ - u.foo() - } - , - Err(v) => v, - } -}", - r" -fn foo(e: Result) { - match e { - Ok(u) => $0u.foo() - , - Err(v) => v, - } -}", - ); - } - - #[test] - fn join_lines_keeps_comma_with_single_arg_tuple() { - // A single arg tuple - check_join_lines( - r" -fn foo() { - let x = ($0{ - 4 - },); -}", - r" -fn foo() { - let x = ($04,); -}", - ); - - // single arg tuple with whitespace between brace and comma - check_join_lines( - r" -fn foo() { - let x = ($0{ - 4 - } ,); -}", - r" -fn foo() { - let x = ($04 ,); -}", - ); - - // single arg tuple with newline between brace and comma - check_join_lines( - r" -fn foo() { - let x = ($0{ - 4 - } - ,); -}", - r" -fn foo() { - let x = ($04 - ,); -}", - ); - } - - #[test] - fn test_join_lines_use_items_left() { - // No space after the '{' - check_join_lines( - r" -$0use syntax::{ - TextSize, TextRange, -};", - r" -$0use syntax::{TextSize, TextRange, -};", - ); - } - - #[test] - fn test_join_lines_use_items_right() { - // No space after the '}' - check_join_lines( - r" -use syntax::{ -$0 TextSize, TextRange -};", - r" -use syntax::{ -$0 TextSize, TextRange};", - ); - } - - #[test] - fn test_join_lines_use_items_right_comma() { - // No space after the '}' - check_join_lines( - r" -use syntax::{ -$0 TextSize, TextRange, -};", - r" -use syntax::{ -$0 TextSize, TextRange};", - ); - } - - #[test] - fn test_join_lines_use_tree() { - check_join_lines( - r" -use syntax::{ - algo::$0{ - find_token_at_offset, - }, - ast, -};", - r" -use syntax::{ - algo::$0find_token_at_offset, - ast, -};", - ); - } - - #[test] - fn test_join_lines_normal_comments() { - check_join_lines( - r" -fn foo() { - // Hello$0 - // world! -} -", - r" -fn foo() { - // Hello$0 world! -} -", - ); - } - - #[test] - fn test_join_lines_doc_comments() { - check_join_lines( - r" -fn foo() { - /// Hello$0 - /// world! -} -", - r" -fn foo() { - /// Hello$0 world! -} -", - ); - } - - #[test] - fn test_join_lines_mod_comments() { - check_join_lines( - r" -fn foo() { - //! Hello$0 - //! world! -} -", - r" -fn foo() { - //! Hello$0 world! -} -", - ); - } - - #[test] - fn test_join_lines_multiline_comments_1() { - check_join_lines( - r" -fn foo() { - // Hello$0 - /* world! */ -} -", - r" -fn foo() { - // Hello$0 world! */ -} -", - ); - } - - #[test] - fn test_join_lines_multiline_comments_2() { - check_join_lines( - r" -fn foo() { - // The$0 - /* quick - brown - fox! */ -} -", - r" -fn foo() { - // The$0 quick - brown - fox! */ -} -", - ); - } - - #[test] - fn test_join_lines_selection_fn_args() { - check_join_lines_sel( - r" -fn foo() { - $0foo(1, - 2, - 3, - $0) -} - ", - r" -fn foo() { - foo(1, 2, 3) -} - ", - ); - } - - #[test] - fn test_join_lines_selection_struct() { - check_join_lines_sel( - r" -struct Foo $0{ - f: u32, -}$0 - ", - r" -struct Foo { f: u32 } - ", - ); - } - - #[test] - fn test_join_lines_selection_dot_chain() { - check_join_lines_sel( - r" -fn foo() { - join($0type_params.type_params() - .filter_map(|it| it.name()) - .map(|it| it.text())$0) -}", - r" -fn foo() { - join(type_params.type_params().filter_map(|it| it.name()).map(|it| it.text())) -}", - ); - } - - #[test] - fn test_join_lines_selection_lambda_block_body() { - check_join_lines_sel( - r" -pub fn handle_find_matching_brace() { - params.offsets - .map(|offset| $0{ - world.analysis().matching_brace(&file, offset).unwrap_or(offset) - }$0) - .collect(); -}", - r" -pub fn handle_find_matching_brace() { - params.offsets - .map(|offset| world.analysis().matching_brace(&file, offset).unwrap_or(offset)) - .collect(); -}", - ); - } - - #[test] - fn test_join_lines_commented_block() { - check_join_lines( - r" -fn main() { - let _ = { - // $0foo - // bar - 92 - }; -} - ", - r" -fn main() { - let _ = { - // $0foo bar - 92 - }; -} - ", - ) - } - - #[test] - fn join_lines_mandatory_blocks_block() { - check_join_lines( - r" -$0fn foo() { - 92 -} - ", - r" -$0fn foo() { 92 -} - ", - ); - - check_join_lines( - r" -fn foo() { - $0if true { - 92 - } -} - ", - r" -fn foo() { - $0if true { 92 - } -} - ", - ); - - check_join_lines( - r" -fn foo() { - $0loop { - 92 - } -} - ", - r" -fn foo() { - $0loop { 92 - } -} - ", - ); - - check_join_lines( - r" -fn foo() { - $0unsafe { - 92 - } -} - ", - r" -fn foo() { - $0unsafe { 92 - } -} - ", - ); - } - - #[test] - fn join_string_literal() { - { - cov_mark::check!(join_string_literal_open_quote); - check_join_lines( - r#" -fn main() { - $0" -hello -"; -} -"#, - r#" -fn main() { - $0"hello -"; -} -"#, - ); - } - - { - cov_mark::check!(join_string_literal_close_quote); - check_join_lines( - r#" -fn main() { - $0"hello -"; -} -"#, - r#" -fn main() { - $0"hello"; -} -"#, - ); - check_join_lines( - r#" -fn main() { - $0r"hello - "; -} -"#, - r#" -fn main() { - $0r"hello"; -} -"#, - ); - } - - check_join_lines( - r#" -fn main() { - " -$0hello -world -"; -} -"#, - r#" -fn main() { - " -$0hello world -"; -} -"#, - ); - } - - #[test] - fn join_last_line_empty() { - check_join_lines( - r#" -fn main() {$0} -"#, - r#" -fn main() {$0} -"#, - ); - } - - #[test] - fn join_two_ifs() { - cov_mark::check!(join_two_ifs); - check_join_lines( - r#" -fn main() { - if foo { - - }$0 - if bar { - - } -} -"#, - r#" -fn main() { - if foo { - - }$0 else if bar { - - } -} -"#, - ); - } - - #[test] - fn join_two_ifs_with_existing_else() { - cov_mark::check!(join_two_ifs_with_existing_else); - check_join_lines( - r#" -fn main() { - if foo { - - } else { - - }$0 - if bar { - - } -} -"#, - r#" -fn main() { - if foo { - - } else { - - }$0 if bar { - - } -} -"#, - ); - } - - #[test] - fn join_assignments() { - check_join_lines( - r#" -fn foo() { - $0let foo; - foo = "bar"; -} -"#, - r#" -fn foo() { - $0let foo = "bar"; -} -"#, - ); - - cov_mark::check!(join_assignments_mismatch); - check_join_lines( - r#" -fn foo() { - let foo; - let qux;$0 - foo = "bar"; -} -"#, - r#" -fn foo() { - let foo; - let qux;$0 foo = "bar"; -} -"#, - ); - - cov_mark::check!(join_assignments_already_initialized); - check_join_lines( - r#" -fn foo() { - let foo = "bar";$0 - foo = "bar"; -} -"#, - r#" -fn foo() { - let foo = "bar";$0 foo = "bar"; -} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs deleted file mode 100644 index dd108fa799970..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ /dev/null @@ -1,702 +0,0 @@ -//! ide crate provides "ide-centric" APIs for the rust-analyzer. That is, -//! it generally operates with files and text ranges, and returns results as -//! Strings, suitable for displaying to the human. -//! -//! What powers this API are the `RootDatabase` struct, which defines a `salsa` -//! database, and the `hir` crate, where majority of the analysis happens. -//! However, IDE specific bits of the analysis (most notably completion) happen -//! in this crate. - -// For proving that RootDatabase is RefUnwindSafe. -#![recursion_limit = "128"] -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -#[allow(unused)] -macro_rules! eprintln { - ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; -} - -#[cfg(test)] -mod fixture; - -mod markup; -mod prime_caches; -mod navigation_target; - -mod annotations; -mod call_hierarchy; -mod signature_help; -mod doc_links; -mod highlight_related; -mod expand_macro; -mod extend_selection; -mod file_structure; -mod fn_references; -mod folding_ranges; -mod goto_declaration; -mod goto_definition; -mod goto_implementation; -mod goto_type_definition; -mod hover; -mod inlay_hints; -mod join_lines; -mod markdown_remove; -mod matching_brace; -mod moniker; -mod move_item; -mod parent_module; -mod references; -mod rename; -mod runnables; -mod ssr; -mod static_index; -mod status; -mod syntax_highlighting; -mod syntax_tree; -mod typing; -mod view_crate_graph; -mod view_hir; -mod view_item_tree; -mod shuffle_crate_graph; - -use std::sync::Arc; - -use cfg::CfgOptions; -use ide_db::{ - base_db::{ - salsa::{self, ParallelDatabase}, - CrateOrigin, Env, FileLoader, FileSet, SourceDatabase, VfsPath, - }, - symbol_index, LineIndexDatabase, -}; -use syntax::SourceFile; - -use crate::navigation_target::{ToNav, TryToNav}; - -pub use crate::{ - annotations::{Annotation, AnnotationConfig, AnnotationKind}, - call_hierarchy::CallItem, - expand_macro::ExpandedMacro, - file_structure::{StructureNode, StructureNodeKind}, - folding_ranges::{Fold, FoldKind}, - highlight_related::{HighlightRelatedConfig, HighlightedRange}, - hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult}, - inlay_hints::{ - ClosureReturnTypeHints, InlayHint, InlayHintsConfig, InlayKind, InlayTooltip, - LifetimeElisionHints, ReborrowHints, - }, - join_lines::JoinLinesConfig, - markup::Markup, - moniker::{MonikerKind, MonikerResult, PackageInformation}, - move_item::Direction, - navigation_target::NavigationTarget, - prime_caches::ParallelPrimeCachesProgress, - references::ReferenceSearchResult, - rename::RenameError, - runnables::{Runnable, RunnableKind, TestId}, - signature_help::SignatureHelp, - static_index::{StaticIndex, StaticIndexedFile, TokenId, TokenStaticData}, - syntax_highlighting::{ - tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag}, - HlRange, - }, -}; -pub use hir::{Documentation, Semantics}; -pub use ide_assists::{ - Assist, AssistConfig, AssistId, AssistKind, AssistResolveStrategy, SingleResolve, -}; -pub use ide_completion::{ - CallableSnippets, CompletionConfig, CompletionItem, CompletionItemKind, CompletionRelevance, - Snippet, SnippetScope, -}; -pub use ide_db::{ - base_db::{ - Cancelled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, - SourceRoot, SourceRootId, - }, - label::Label, - line_index::{LineCol, LineColUtf16, LineIndex}, - search::{ReferenceCategory, SearchScope}, - source_change::{FileSystemEdit, SourceChange}, - symbol_index::Query, - RootDatabase, SymbolKind, -}; -pub use ide_diagnostics::{Diagnostic, DiagnosticsConfig, ExprFillDefaultMode, Severity}; -pub use ide_ssr::SsrError; -pub use syntax::{TextRange, TextSize}; -pub use text_edit::{Indel, TextEdit}; - -pub type Cancellable = Result; - -/// Info associated with a text range. -#[derive(Debug)] -pub struct RangeInfo { - pub range: TextRange, - pub info: T, -} - -impl RangeInfo { - pub fn new(range: TextRange, info: T) -> RangeInfo { - RangeInfo { range, info } - } -} - -/// `AnalysisHost` stores the current state of the world. -#[derive(Debug)] -pub struct AnalysisHost { - db: RootDatabase, -} - -impl AnalysisHost { - pub fn new(lru_capacity: Option) -> AnalysisHost { - AnalysisHost { db: RootDatabase::new(lru_capacity) } - } - - pub fn update_lru_capacity(&mut self, lru_capacity: Option) { - self.db.update_lru_capacity(lru_capacity); - } - - /// Returns a snapshot of the current state, which you can query for - /// semantic information. - pub fn analysis(&self) -> Analysis { - Analysis { db: self.db.snapshot() } - } - - /// Applies changes to the current state of the world. If there are - /// outstanding snapshots, they will be canceled. - pub fn apply_change(&mut self, change: Change) { - self.db.apply_change(change) - } - - /// NB: this clears the database - pub fn per_query_memory_usage(&mut self) -> Vec<(String, profile::Bytes)> { - self.db.per_query_memory_usage() - } - pub fn request_cancellation(&mut self) { - self.db.request_cancellation(); - } - pub fn raw_database(&self) -> &RootDatabase { - &self.db - } - pub fn raw_database_mut(&mut self) -> &mut RootDatabase { - &mut self.db - } - - pub fn shuffle_crate_graph(&mut self) { - shuffle_crate_graph::shuffle_crate_graph(&mut self.db); - } -} - -impl Default for AnalysisHost { - fn default() -> AnalysisHost { - AnalysisHost::new(None) - } -} - -/// Analysis is a snapshot of a world state at a moment in time. It is the main -/// entry point for asking semantic information about the world. When the world -/// state is advanced using `AnalysisHost::apply_change` method, all existing -/// `Analysis` are canceled (most method return `Err(Canceled)`). -#[derive(Debug)] -pub struct Analysis { - db: salsa::Snapshot, -} - -// As a general design guideline, `Analysis` API are intended to be independent -// from the language server protocol. That is, when exposing some functionality -// we should think in terms of "what API makes most sense" and not in terms of -// "what types LSP uses". Although currently LSP is the only consumer of the -// API, the API should in theory be usable as a library, or via a different -// protocol. -impl Analysis { - // Creates an analysis instance for a single file, without any external - // dependencies, stdlib support or ability to apply changes. See - // `AnalysisHost` for creating a fully-featured analysis. - pub fn from_single_file(text: String) -> (Analysis, FileId) { - let mut host = AnalysisHost::default(); - let file_id = FileId(0); - let mut file_set = FileSet::default(); - file_set.insert(file_id, VfsPath::new_virtual_path("/main.rs".to_string())); - let source_root = SourceRoot::new_local(file_set); - - let mut change = Change::new(); - change.set_roots(vec![source_root]); - let mut crate_graph = CrateGraph::default(); - // FIXME: cfg options - // Default to enable test for single file. - let mut cfg_options = CfgOptions::default(); - cfg_options.insert_atom("test".into()); - crate_graph.add_crate_root( - file_id, - Edition::CURRENT, - None, - None, - cfg_options.clone(), - cfg_options, - Env::default(), - Ok(Vec::new()), - false, - CrateOrigin::CratesIo { repo: None }, - ); - change.change_file(file_id, Some(Arc::new(text))); - change.set_crate_graph(crate_graph); - host.apply_change(change); - (host.analysis(), file_id) - } - - /// Debug info about the current state of the analysis. - pub fn status(&self, file_id: Option) -> Cancellable { - self.with_db(|db| status::status(&*db, file_id)) - } - - pub fn parallel_prime_caches(&self, num_worker_threads: u8, cb: F) -> Cancellable<()> - where - F: Fn(ParallelPrimeCachesProgress) + Sync + std::panic::UnwindSafe, - { - self.with_db(move |db| prime_caches::parallel_prime_caches(db, num_worker_threads, &cb)) - } - - /// Gets the text of the source file. - pub fn file_text(&self, file_id: FileId) -> Cancellable> { - self.with_db(|db| db.file_text(file_id)) - } - - /// Gets the syntax tree of the file. - pub fn parse(&self, file_id: FileId) -> Cancellable { - self.with_db(|db| db.parse(file_id).tree()) - } - - /// Returns true if this file belongs to an immutable library. - pub fn is_library_file(&self, file_id: FileId) -> Cancellable { - use ide_db::base_db::SourceDatabaseExt; - self.with_db(|db| db.source_root(db.file_source_root(file_id)).is_library) - } - - /// Gets the file's `LineIndex`: data structure to convert between absolute - /// offsets and line/column representation. - pub fn file_line_index(&self, file_id: FileId) -> Cancellable> { - self.with_db(|db| db.line_index(file_id)) - } - - /// Selects the next syntactic nodes encompassing the range. - pub fn extend_selection(&self, frange: FileRange) -> Cancellable { - self.with_db(|db| extend_selection::extend_selection(db, frange)) - } - - /// Returns position of the matching brace (all types of braces are - /// supported). - pub fn matching_brace(&self, position: FilePosition) -> Cancellable> { - self.with_db(|db| { - let parse = db.parse(position.file_id); - let file = parse.tree(); - matching_brace::matching_brace(&file, position.offset) - }) - } - - /// Returns a syntax tree represented as `String`, for debug purposes. - // FIXME: use a better name here. - pub fn syntax_tree( - &self, - file_id: FileId, - text_range: Option, - ) -> Cancellable { - self.with_db(|db| syntax_tree::syntax_tree(db, file_id, text_range)) - } - - pub fn view_hir(&self, position: FilePosition) -> Cancellable { - self.with_db(|db| view_hir::view_hir(db, position)) - } - - pub fn view_item_tree(&self, file_id: FileId) -> Cancellable { - self.with_db(|db| view_item_tree::view_item_tree(db, file_id)) - } - - /// Renders the crate graph to GraphViz "dot" syntax. - pub fn view_crate_graph(&self, full: bool) -> Cancellable> { - self.with_db(|db| view_crate_graph::view_crate_graph(db, full)) - } - - pub fn expand_macro(&self, position: FilePosition) -> Cancellable> { - self.with_db(|db| expand_macro::expand_macro(db, position)) - } - - /// Returns an edit to remove all newlines in the range, cleaning up minor - /// stuff like trailing commas. - pub fn join_lines(&self, config: &JoinLinesConfig, frange: FileRange) -> Cancellable { - self.with_db(|db| { - let parse = db.parse(frange.file_id); - join_lines::join_lines(config, &parse.tree(), frange.range) - }) - } - - /// Returns an edit which should be applied when opening a new line, fixing - /// up minor stuff like continuing the comment. - /// The edit will be a snippet (with `$0`). - pub fn on_enter(&self, position: FilePosition) -> Cancellable> { - self.with_db(|db| typing::on_enter(db, position)) - } - - /// Returns an edit which should be applied after a character was typed. - /// - /// This is useful for some on-the-fly fixups, like adding `;` to `let =` - /// automatically. - pub fn on_char_typed( - &self, - position: FilePosition, - char_typed: char, - autoclose: bool, - ) -> Cancellable> { - // Fast path to not even parse the file. - if !typing::TRIGGER_CHARS.contains(char_typed) { - return Ok(None); - } - if char_typed == '<' && !autoclose { - return Ok(None); - } - - self.with_db(|db| typing::on_char_typed(db, position, char_typed)) - } - - /// Returns a tree representation of symbols in the file. Useful to draw a - /// file outline. - pub fn file_structure(&self, file_id: FileId) -> Cancellable> { - self.with_db(|db| file_structure::file_structure(&db.parse(file_id).tree())) - } - - /// Returns a list of the places in the file where type hints can be displayed. - pub fn inlay_hints( - &self, - config: &InlayHintsConfig, - file_id: FileId, - range: Option, - ) -> Cancellable> { - self.with_db(|db| inlay_hints::inlay_hints(db, file_id, range, config)) - } - - /// Returns the set of folding ranges. - pub fn folding_ranges(&self, file_id: FileId) -> Cancellable> { - self.with_db(|db| folding_ranges::folding_ranges(&db.parse(file_id).tree())) - } - - /// Fuzzy searches for a symbol. - pub fn symbol_search(&self, query: Query) -> Cancellable> { - self.with_db(|db| { - symbol_index::world_symbols(db, query) - .into_iter() // xx: should we make this a par iter? - .filter_map(|s| s.try_to_nav(db)) - .collect::>() - }) - } - - /// Returns the definitions from the symbol at `position`. - pub fn goto_definition( - &self, - position: FilePosition, - ) -> Cancellable>>> { - self.with_db(|db| goto_definition::goto_definition(db, position)) - } - - /// Returns the declaration from the symbol at `position`. - pub fn goto_declaration( - &self, - position: FilePosition, - ) -> Cancellable>>> { - self.with_db(|db| goto_declaration::goto_declaration(db, position)) - } - - /// Returns the impls from the symbol at `position`. - pub fn goto_implementation( - &self, - position: FilePosition, - ) -> Cancellable>>> { - self.with_db(|db| goto_implementation::goto_implementation(db, position)) - } - - /// Returns the type definitions for the symbol at `position`. - pub fn goto_type_definition( - &self, - position: FilePosition, - ) -> Cancellable>>> { - self.with_db(|db| goto_type_definition::goto_type_definition(db, position)) - } - - /// Finds all usages of the reference at point. - pub fn find_all_refs( - &self, - position: FilePosition, - search_scope: Option, - ) -> Cancellable>> { - self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, search_scope)) - } - - /// Finds all methods and free functions for the file. Does not return tests! - pub fn find_all_methods(&self, file_id: FileId) -> Cancellable> { - self.with_db(|db| fn_references::find_all_methods(db, file_id)) - } - - /// Returns a short text describing element at position. - pub fn hover( - &self, - config: &HoverConfig, - range: FileRange, - ) -> Cancellable>> { - self.with_db(|db| hover::hover(db, range, config)) - } - - /// Returns moniker of symbol at position. - pub fn moniker( - &self, - position: FilePosition, - ) -> Cancellable>>> { - self.with_db(|db| moniker::moniker(db, position)) - } - - /// Return URL(s) for the documentation of the symbol under the cursor. - pub fn external_docs( - &self, - position: FilePosition, - ) -> Cancellable> { - self.with_db(|db| doc_links::external_docs(db, &position)) - } - - /// Computes parameter information at the given position. - pub fn signature_help(&self, position: FilePosition) -> Cancellable> { - self.with_db(|db| signature_help::signature_help(db, position)) - } - - /// Computes call hierarchy candidates for the given file position. - pub fn call_hierarchy( - &self, - position: FilePosition, - ) -> Cancellable>>> { - self.with_db(|db| call_hierarchy::call_hierarchy(db, position)) - } - - /// Computes incoming calls for the given file position. - pub fn incoming_calls(&self, position: FilePosition) -> Cancellable>> { - self.with_db(|db| call_hierarchy::incoming_calls(db, position)) - } - - /// Computes outgoing calls for the given file position. - pub fn outgoing_calls(&self, position: FilePosition) -> Cancellable>> { - self.with_db(|db| call_hierarchy::outgoing_calls(db, position)) - } - - /// Returns a `mod name;` declaration which created the current module. - pub fn parent_module(&self, position: FilePosition) -> Cancellable> { - self.with_db(|db| parent_module::parent_module(db, position)) - } - - /// Returns crates this file belongs too. - pub fn crate_for(&self, file_id: FileId) -> Cancellable> { - self.with_db(|db| parent_module::crate_for(db, file_id)) - } - - /// Returns the edition of the given crate. - pub fn crate_edition(&self, crate_id: CrateId) -> Cancellable { - self.with_db(|db| db.crate_graph()[crate_id].edition) - } - - /// Returns the root file of the given crate. - pub fn crate_root(&self, crate_id: CrateId) -> Cancellable { - self.with_db(|db| db.crate_graph()[crate_id].root_file_id) - } - - /// Returns the set of possible targets to run for the current file. - pub fn runnables(&self, file_id: FileId) -> Cancellable> { - self.with_db(|db| runnables::runnables(db, file_id)) - } - - /// Returns the set of tests for the given file position. - pub fn related_tests( - &self, - position: FilePosition, - search_scope: Option, - ) -> Cancellable> { - self.with_db(|db| runnables::related_tests(db, position, search_scope)) - } - - /// Computes syntax highlighting for the given file - pub fn highlight(&self, file_id: FileId) -> Cancellable> { - self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false)) - } - - /// Computes all ranges to highlight for a given item in a file. - pub fn highlight_related( - &self, - config: HighlightRelatedConfig, - position: FilePosition, - ) -> Cancellable>> { - self.with_db(|db| { - highlight_related::highlight_related(&Semantics::new(db), config, position) - }) - } - - /// Computes syntax highlighting for the given file range. - pub fn highlight_range(&self, frange: FileRange) -> Cancellable> { - self.with_db(|db| { - syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false) - }) - } - - /// Computes syntax highlighting for the given file. - pub fn highlight_as_html(&self, file_id: FileId, rainbow: bool) -> Cancellable { - self.with_db(|db| syntax_highlighting::highlight_as_html(db, file_id, rainbow)) - } - - /// Computes completions at the given position. - pub fn completions( - &self, - config: &CompletionConfig, - position: FilePosition, - trigger_character: Option, - ) -> Cancellable>> { - self.with_db(|db| { - ide_completion::completions(db, config, position, trigger_character).map(Into::into) - }) - } - - /// Resolves additional completion data at the position given. - pub fn resolve_completion_edits( - &self, - config: &CompletionConfig, - position: FilePosition, - imports: impl IntoIterator + std::panic::UnwindSafe, - ) -> Cancellable> { - Ok(self - .with_db(|db| ide_completion::resolve_completion_edits(db, config, position, imports))? - .unwrap_or_default()) - } - - /// Computes the set of diagnostics for the given file. - pub fn diagnostics( - &self, - config: &DiagnosticsConfig, - resolve: AssistResolveStrategy, - file_id: FileId, - ) -> Cancellable> { - self.with_db(|db| ide_diagnostics::diagnostics(db, config, &resolve, file_id)) - } - - /// Convenience function to return assists + quick fixes for diagnostics - pub fn assists_with_fixes( - &self, - assist_config: &AssistConfig, - diagnostics_config: &DiagnosticsConfig, - resolve: AssistResolveStrategy, - frange: FileRange, - ) -> Cancellable> { - let include_fixes = match &assist_config.allowed { - Some(it) => it.iter().any(|&it| it == AssistKind::None || it == AssistKind::QuickFix), - None => true, - }; - - self.with_db(|db| { - let diagnostic_assists = if include_fixes { - ide_diagnostics::diagnostics(db, diagnostics_config, &resolve, frange.file_id) - .into_iter() - .flat_map(|it| it.fixes.unwrap_or_default()) - .filter(|it| it.target.intersect(frange.range).is_some()) - .collect() - } else { - Vec::new() - }; - let ssr_assists = ssr::ssr_assists(db, &resolve, frange); - let assists = ide_assists::assists(db, assist_config, resolve, frange); - - let mut res = diagnostic_assists; - res.extend(ssr_assists.into_iter()); - res.extend(assists.into_iter()); - - res - }) - } - - /// Returns the edit required to rename reference at the position to the new - /// name. - pub fn rename( - &self, - position: FilePosition, - new_name: &str, - ) -> Cancellable> { - self.with_db(|db| rename::rename(db, position, new_name)) - } - - pub fn prepare_rename( - &self, - position: FilePosition, - ) -> Cancellable, RenameError>> { - self.with_db(|db| rename::prepare_rename(db, position)) - } - - pub fn will_rename_file( - &self, - file_id: FileId, - new_name_stem: &str, - ) -> Cancellable> { - self.with_db(|db| rename::will_rename_file(db, file_id, new_name_stem)) - } - - pub fn structural_search_replace( - &self, - query: &str, - parse_only: bool, - resolve_context: FilePosition, - selections: Vec, - ) -> Cancellable> { - self.with_db(|db| { - let rule: ide_ssr::SsrRule = query.parse()?; - let mut match_finder = - ide_ssr::MatchFinder::in_context(db, resolve_context, selections)?; - match_finder.add_rule(rule)?; - let edits = if parse_only { Default::default() } else { match_finder.edits() }; - Ok(SourceChange::from(edits)) - }) - } - - pub fn annotations( - &self, - config: &AnnotationConfig, - file_id: FileId, - ) -> Cancellable> { - self.with_db(|db| annotations::annotations(db, config, file_id)) - } - - pub fn resolve_annotation(&self, annotation: Annotation) -> Cancellable { - self.with_db(|db| annotations::resolve_annotation(db, annotation)) - } - - pub fn move_item( - &self, - range: FileRange, - direction: Direction, - ) -> Cancellable> { - self.with_db(|db| move_item::move_item(db, range, direction)) - } - - /// Performs an operation on the database that may be canceled. - /// - /// rust-analyzer needs to be able to answer semantic questions about the - /// code while the code is being modified. A common problem is that a - /// long-running query is being calculated when a new change arrives. - /// - /// We can't just apply the change immediately: this will cause the pending - /// query to see inconsistent state (it will observe an absence of - /// repeatable read). So what we do is we **cancel** all pending queries - /// before applying the change. - /// - /// Salsa implements cancellation by unwinding with a special value and - /// catching it on the API boundary. - fn with_db(&self, f: F) -> Cancellable - where - F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe, - { - Cancelled::catch(|| f(&self.db)) - } -} - -#[test] -fn analysis_is_send() { - fn is_send() {} - is_send::(); -} diff --git a/src/tools/rust-analyzer/crates/ide/src/markdown_remove.rs b/src/tools/rust-analyzer/crates/ide/src/markdown_remove.rs deleted file mode 100644 index 3ec5c629e4f26..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/markdown_remove.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! Removes markdown from strings. -use pulldown_cmark::{Event, Parser, Tag}; - -/// Removes all markdown, keeping the text and code blocks -/// -/// Currently limited in styling, i.e. no ascii tables or lists -pub(crate) fn remove_markdown(markdown: &str) -> String { - let mut out = String::new(); - let parser = Parser::new(markdown); - - for event in parser { - match event { - Event::Text(text) | Event::Code(text) => out.push_str(&text), - Event::SoftBreak | Event::HardBreak | Event::Rule | Event::End(Tag::CodeBlock(_)) => { - out.push('\n') - } - _ => {} - } - } - - out -} diff --git a/src/tools/rust-analyzer/crates/ide/src/markup.rs b/src/tools/rust-analyzer/crates/ide/src/markup.rs deleted file mode 100644 index 60c193c40aba2..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/markup.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! Markdown formatting. -//! -//! Sometimes, we want to display a "rich text" in the UI. At the moment, we use -//! markdown for this purpose. It doesn't feel like a right option, but that's -//! what is used by LSP, so let's keep it simple. -use std::fmt; - -#[derive(Default, Debug)] -pub struct Markup { - text: String, -} - -impl From for String { - fn from(markup: Markup) -> Self { - markup.text - } -} - -impl From for Markup { - fn from(text: String) -> Self { - Markup { text } - } -} - -impl fmt::Display for Markup { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.text, f) - } -} - -impl Markup { - pub fn as_str(&self) -> &str { - self.text.as_str() - } - pub fn fenced_block(contents: &impl fmt::Display) -> Markup { - format!("```rust\n{}\n```", contents).into() - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs b/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs deleted file mode 100644 index da70cecdd8e11..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs +++ /dev/null @@ -1,78 +0,0 @@ -use syntax::{ - ast::{self, AstNode}, - SourceFile, SyntaxKind, TextSize, T, -}; - -// Feature: Matching Brace -// -// If the cursor is on any brace (`<>(){}[]||`) which is a part of a brace-pair, -// moves cursor to the matching brace. It uses the actual parser to determine -// braces, so it won't confuse generics with comparisons. -// -// |=== -// | Editor | Action Name -// -// | VS Code | **Rust Analyzer: Find matching brace** -// |=== -// -// image::https://user-images.githubusercontent.com/48062697/113065573-04298180-91b1-11eb-8dec-d4e2a202f304.gif[] -pub(crate) fn matching_brace(file: &SourceFile, offset: TextSize) -> Option { - const BRACES: &[SyntaxKind] = - &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>], T![|], T![|]]; - let (brace_token, brace_idx) = file - .syntax() - .token_at_offset(offset) - .filter_map(|node| { - let idx = BRACES.iter().position(|&brace| brace == node.kind())?; - Some((node, idx)) - }) - .last()?; - let parent = brace_token.parent()?; - if brace_token.kind() == T![|] && !ast::ParamList::can_cast(parent.kind()) { - cov_mark::hit!(pipes_not_braces); - return None; - } - let matching_kind = BRACES[brace_idx ^ 1]; - let matching_node = parent - .children_with_tokens() - .filter_map(|it| it.into_token()) - .find(|node| node.kind() == matching_kind && node != &brace_token)?; - Some(matching_node.text_range().start()) -} - -#[cfg(test)] -mod tests { - use test_utils::{add_cursor, assert_eq_text, extract_offset}; - - use super::*; - - #[test] - fn test_matching_brace() { - fn do_check(before: &str, after: &str) { - let (pos, before) = extract_offset(before); - let parse = SourceFile::parse(&before); - let new_pos = match matching_brace(&parse.tree(), pos) { - None => pos, - Some(pos) => pos, - }; - let actual = add_cursor(&before, new_pos); - assert_eq_text!(after, &actual); - } - - do_check("struct Foo { a: i32, }$0", "struct Foo $0{ a: i32, }"); - do_check("fn main() { |x: i32|$0 x * 2;}", "fn main() { $0|x: i32| x * 2;}"); - do_check("fn main() { $0|x: i32| x * 2;}", "fn main() { |x: i32$0| x * 2;}"); - do_check( - "fn func(x) { return (2 * (x + 3)$0) + 5;}", - "fn func(x) { return $0(2 * (x + 3)) + 5;}", - ); - - { - cov_mark::check!(pipes_not_braces); - do_check( - "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }", - "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }", - ); - } - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs deleted file mode 100644 index 6bab9fa1ebbb8..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ /dev/null @@ -1,342 +0,0 @@ -//! This module generates [moniker](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/#exportsImports) -//! for LSIF and LSP. - -use hir::{db::DefDatabase, AsAssocItem, AssocItemContainer, Crate, Name, Semantics}; -use ide_db::{ - base_db::{CrateOrigin, FileId, FileLoader, FilePosition, LangCrateOrigin}, - defs::{Definition, IdentClass}, - helpers::pick_best_token, - RootDatabase, -}; -use itertools::Itertools; -use syntax::{AstNode, SyntaxKind::*, T}; - -use crate::{doc_links::token_as_doc_comment, RangeInfo}; - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct MonikerIdentifier { - crate_name: String, - path: Vec, -} - -impl ToString for MonikerIdentifier { - fn to_string(&self) -> String { - match self { - MonikerIdentifier { path, crate_name } => { - format!("{}::{}", crate_name, path.iter().map(|x| x.to_string()).join("::")) - } - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum MonikerKind { - Import, - Export, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct MonikerResult { - pub identifier: MonikerIdentifier, - pub kind: MonikerKind, - pub package_information: PackageInformation, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct PackageInformation { - pub name: String, - pub repo: String, - pub version: String, -} - -pub(crate) fn crate_for_file(db: &RootDatabase, file_id: FileId) -> Option { - for &krate in db.relevant_crates(file_id).iter() { - let crate_def_map = db.crate_def_map(krate); - for (_, data) in crate_def_map.modules() { - if data.origin.file_id() == Some(file_id) { - return Some(krate.into()); - } - } - } - None -} - -pub(crate) fn moniker( - db: &RootDatabase, - FilePosition { file_id, offset }: FilePosition, -) -> Option>> { - let sema = &Semantics::new(db); - let file = sema.parse(file_id).syntax().clone(); - let current_crate = crate_for_file(db, file_id)?; - let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind { - IDENT - | INT_NUMBER - | LIFETIME_IDENT - | T![self] - | T![super] - | T![crate] - | T![Self] - | COMMENT => 2, - kind if kind.is_trivia() => 0, - _ => 1, - })?; - if let Some(doc_comment) = token_as_doc_comment(&original_token) { - return doc_comment.get_definition_with_descend_at(sema, offset, |def, _, _| { - let m = def_to_moniker(db, def, current_crate)?; - Some(RangeInfo::new(original_token.text_range(), vec![m])) - }); - } - let navs = sema - .descend_into_macros(original_token.clone()) - .into_iter() - .filter_map(|token| { - IdentClass::classify_token(sema, &token).map(IdentClass::definitions).map(|it| { - it.into_iter().flat_map(|def| def_to_moniker(sema.db, def, current_crate)) - }) - }) - .flatten() - .unique() - .collect::>(); - Some(RangeInfo::new(original_token.text_range(), navs)) -} - -pub(crate) fn def_to_moniker( - db: &RootDatabase, - def: Definition, - from_crate: Crate, -) -> Option { - if matches!(def, Definition::GenericParam(_) | Definition::SelfType(_) | Definition::Local(_)) { - return None; - } - let module = def.module(db)?; - let krate = module.krate(); - let mut path = vec![]; - path.extend(module.path_to_root(db).into_iter().filter_map(|x| x.name(db))); - - // Handle associated items within a trait - if let Some(assoc) = def.as_assoc_item(db) { - let container = assoc.container(db); - match container { - AssocItemContainer::Trait(trait_) => { - // Because different traits can have functions with the same name, - // we have to include the trait name as part of the moniker for uniqueness. - path.push(trait_.name(db)); - } - AssocItemContainer::Impl(impl_) => { - // Because a struct can implement multiple traits, for implementations - // we add both the struct name and the trait name to the path - if let Some(adt) = impl_.self_ty(db).as_adt() { - path.push(adt.name(db)); - } - - if let Some(trait_) = impl_.trait_(db) { - path.push(trait_.name(db)); - } - } - } - } - - if let Definition::Field(it) = def { - path.push(it.parent_def(db).name(db)); - } - - path.push(def.name(db)?); - Some(MonikerResult { - identifier: MonikerIdentifier { - crate_name: krate.display_name(db)?.crate_name().to_string(), - path, - }, - kind: if krate == from_crate { MonikerKind::Export } else { MonikerKind::Import }, - package_information: { - let name = krate.display_name(db)?.to_string(); - let (repo, version) = match krate.origin(db) { - CrateOrigin::CratesIo { repo } => (repo?, krate.version(db)?), - CrateOrigin::Lang(lang) => ( - "https://github.com/rust-lang/rust/".to_string(), - match lang { - LangCrateOrigin::Other => { - "https://github.com/rust-lang/rust/library/".into() - } - lang => format!("https://github.com/rust-lang/rust/library/{lang}",), - }, - ), - }; - PackageInformation { name, repo, version } - }, - }) -} - -#[cfg(test)] -mod tests { - use crate::fixture; - - use super::MonikerKind; - - #[track_caller] - fn no_moniker(ra_fixture: &str) { - let (analysis, position) = fixture::position(ra_fixture); - if let Some(x) = analysis.moniker(position).unwrap() { - assert_eq!(x.info.len(), 0, "Moniker founded but no moniker expected: {:?}", x); - } - } - - #[track_caller] - fn check_moniker(ra_fixture: &str, identifier: &str, package: &str, kind: MonikerKind) { - let (analysis, position) = fixture::position(ra_fixture); - let x = analysis.moniker(position).unwrap().expect("no moniker found").info; - assert_eq!(x.len(), 1); - let x = x.into_iter().next().unwrap(); - assert_eq!(identifier, x.identifier.to_string()); - assert_eq!(package, format!("{:?}", x.package_information)); - assert_eq!(kind, x.kind); - } - - #[test] - fn basic() { - check_moniker( - r#" -//- /lib.rs crate:main deps:foo -use foo::module::func; -fn main() { - func$0(); -} -//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git -pub mod module { - pub fn func() {} -} -"#, - "foo::module::func", - r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#, - MonikerKind::Import, - ); - check_moniker( - r#" -//- /lib.rs crate:main deps:foo -use foo::module::func; -fn main() { - func(); -} -//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git -pub mod module { - pub fn func$0() {} -} -"#, - "foo::module::func", - r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#, - MonikerKind::Export, - ); - } - - #[test] - fn moniker_for_trait() { - check_moniker( - r#" -//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git -pub mod module { - pub trait MyTrait { - pub fn func$0() {} - } -} -"#, - "foo::module::MyTrait::func", - r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#, - MonikerKind::Export, - ); - } - - #[test] - fn moniker_for_trait_constant() { - check_moniker( - r#" -//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git -pub mod module { - pub trait MyTrait { - const MY_CONST$0: u8; - } -} -"#, - "foo::module::MyTrait::MY_CONST", - r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#, - MonikerKind::Export, - ); - } - - #[test] - fn moniker_for_trait_type() { - check_moniker( - r#" -//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git -pub mod module { - pub trait MyTrait { - type MyType$0; - } -} -"#, - "foo::module::MyTrait::MyType", - r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#, - MonikerKind::Export, - ); - } - - #[test] - fn moniker_for_trait_impl_function() { - check_moniker( - r#" -//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git -pub mod module { - pub trait MyTrait { - pub fn func() {} - } - - struct MyStruct {} - - impl MyTrait for MyStruct { - pub fn func$0() {} - } -} -"#, - "foo::module::MyStruct::MyTrait::func", - r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#, - MonikerKind::Export, - ); - } - - #[test] - fn moniker_for_field() { - check_moniker( - r#" -//- /lib.rs crate:main deps:foo -use foo::St; -fn main() { - let x = St { a$0: 2 }; -} -//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git -pub struct St { - pub a: i32, -} -"#, - "foo::St::a", - r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#, - MonikerKind::Import, - ); - } - - #[test] - fn no_moniker_for_local() { - no_moniker( - r#" -//- /lib.rs crate:main deps:foo -use foo::module::func; -fn main() { - func(); -} -//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git -pub mod module { - pub fn func() { - let x$0 = 2; - } -} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/move_item.rs b/src/tools/rust-analyzer/crates/ide/src/move_item.rs deleted file mode 100644 index 02e9fb8b5e288..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/move_item.rs +++ /dev/null @@ -1,890 +0,0 @@ -use std::{iter::once, mem}; - -use hir::Semantics; -use ide_db::{base_db::FileRange, helpers::pick_best_token, RootDatabase}; -use itertools::Itertools; -use syntax::{algo, ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange}; -use text_edit::{TextEdit, TextEditBuilder}; - -#[derive(Copy, Clone, Debug)] -pub enum Direction { - Up, - Down, -} - -// Feature: Move Item -// -// Move item under cursor or selection up and down. -// -// |=== -// | Editor | Action Name -// -// | VS Code | **Rust Analyzer: Move item up** -// | VS Code | **Rust Analyzer: Move item down** -// |=== -// -// image::https://user-images.githubusercontent.com/48062697/113065576-04298180-91b1-11eb-91ce-4505e99ed598.gif[] -pub(crate) fn move_item( - db: &RootDatabase, - range: FileRange, - direction: Direction, -) -> Option { - let sema = Semantics::new(db); - let file = sema.parse(range.file_id); - - let item = if range.range.is_empty() { - SyntaxElement::Token(pick_best_token( - file.syntax().token_at_offset(range.range.start()), - |kind| match kind { - SyntaxKind::IDENT | SyntaxKind::LIFETIME_IDENT => 2, - kind if kind.is_trivia() => 0, - _ => 1, - }, - )?) - } else { - file.syntax().covering_element(range.range) - }; - - find_ancestors(item, direction, range.range) -} - -fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -> Option { - let root = match item { - SyntaxElement::Node(node) => node, - SyntaxElement::Token(token) => token.parent()?, - }; - - let movable = [ - SyntaxKind::ARG_LIST, - SyntaxKind::GENERIC_PARAM_LIST, - SyntaxKind::GENERIC_ARG_LIST, - SyntaxKind::VARIANT_LIST, - SyntaxKind::TYPE_BOUND_LIST, - SyntaxKind::MATCH_ARM, - SyntaxKind::PARAM, - SyntaxKind::LET_STMT, - SyntaxKind::EXPR_STMT, - SyntaxKind::IF_EXPR, - SyntaxKind::FOR_EXPR, - SyntaxKind::LOOP_EXPR, - SyntaxKind::WHILE_EXPR, - SyntaxKind::RETURN_EXPR, - SyntaxKind::MATCH_EXPR, - SyntaxKind::MACRO_CALL, - SyntaxKind::TYPE_ALIAS, - SyntaxKind::TRAIT, - SyntaxKind::IMPL, - SyntaxKind::MACRO_DEF, - SyntaxKind::STRUCT, - SyntaxKind::UNION, - SyntaxKind::ENUM, - SyntaxKind::FN, - SyntaxKind::MODULE, - SyntaxKind::USE, - SyntaxKind::STATIC, - SyntaxKind::CONST, - SyntaxKind::MACRO_RULES, - SyntaxKind::MACRO_DEF, - ]; - - let ancestor = once(root.clone()) - .chain(root.ancestors()) - .find(|ancestor| movable.contains(&ancestor.kind()))?; - - move_in_direction(&ancestor, direction, range) -} - -fn move_in_direction( - node: &SyntaxNode, - direction: Direction, - range: TextRange, -) -> Option { - match_ast! { - match node { - ast::ArgList(it) => swap_sibling_in_list(node, it.args(), range, direction), - ast::GenericParamList(it) => swap_sibling_in_list(node, it.generic_params(), range, direction), - ast::GenericArgList(it) => swap_sibling_in_list(node, it.generic_args(), range, direction), - ast::VariantList(it) => swap_sibling_in_list(node, it.variants(), range, direction), - ast::TypeBoundList(it) => swap_sibling_in_list(node, it.bounds(), range, direction), - _ => Some(replace_nodes(range, node, &match direction { - Direction::Up => node.prev_sibling(), - Direction::Down => node.next_sibling(), - }?)) - } - } -} - -fn swap_sibling_in_list>( - node: &SyntaxNode, - list: I, - range: TextRange, - direction: Direction, -) -> Option { - let list_lookup = list.tuple_windows().find(|(l, r)| match direction { - Direction::Up => r.syntax().text_range().contains_range(range), - Direction::Down => l.syntax().text_range().contains_range(range), - }); - - if let Some((l, r)) = list_lookup { - Some(replace_nodes(range, l.syntax(), r.syntax())) - } else { - // Cursor is beyond any movable list item (for example, on curly brace in enum). - // It's not necessary, that parent of list is movable (arg list's parent is not, for example), - // and we have to continue tree traversal to find suitable node. - find_ancestors(SyntaxElement::Node(node.parent()?), direction, range) - } -} - -fn replace_nodes<'a>( - range: TextRange, - mut first: &'a SyntaxNode, - mut second: &'a SyntaxNode, -) -> TextEdit { - let cursor_offset = if range.is_empty() { - // FIXME: `applySnippetTextEdits` does not support non-empty selection ranges - if first.text_range().contains_range(range) { - Some(range.start() - first.text_range().start()) - } else if second.text_range().contains_range(range) { - mem::swap(&mut first, &mut second); - Some(range.start() - first.text_range().start()) - } else { - None - } - } else { - None - }; - - let first_with_cursor = match cursor_offset { - Some(offset) => { - let mut item_text = first.text().to_string(); - item_text.insert_str(offset.into(), "$0"); - item_text - } - None => first.text().to_string(), - }; - - let mut edit = TextEditBuilder::default(); - - algo::diff(first, second).into_text_edit(&mut edit); - edit.replace(second.text_range(), first_with_cursor); - - edit.finish() -} - -#[cfg(test)] -mod tests { - use crate::fixture; - use expect_test::{expect, Expect}; - - use crate::Direction; - - fn check(ra_fixture: &str, expect: Expect, direction: Direction) { - let (analysis, range) = fixture::range(ra_fixture); - let edit = analysis.move_item(range, direction).unwrap().unwrap_or_default(); - let mut file = analysis.file_text(range.file_id).unwrap().to_string(); - edit.apply(&mut file); - expect.assert_eq(&file); - } - - #[test] - fn test_moves_match_arm_up() { - check( - r#" -fn main() { - match true { - true => { - println!("Hello, world"); - }, - false =>$0$0 { - println!("Test"); - } - }; -} -"#, - expect![[r#" - fn main() { - match true { - false =>$0 { - println!("Test"); - } - true => { - println!("Hello, world"); - }, - }; - } - "#]], - Direction::Up, - ); - } - - #[test] - fn test_moves_match_arm_down() { - check( - r#" -fn main() { - match true { - true =>$0$0 { - println!("Hello, world"); - }, - false => { - println!("Test"); - } - }; -} -"#, - expect![[r#" - fn main() { - match true { - false => { - println!("Test"); - } - true =>$0 { - println!("Hello, world"); - }, - }; - } - "#]], - Direction::Down, - ); - } - - #[test] - fn test_nowhere_to_move() { - check( - r#" -fn main() { - match true { - true =>$0$0 { - println!("Hello, world"); - }, - false => { - println!("Test"); - } - }; -} -"#, - expect![[r#" - fn main() { - match true { - true => { - println!("Hello, world"); - }, - false => { - println!("Test"); - } - }; - } - "#]], - Direction::Up, - ); - } - - #[test] - fn test_moves_let_stmt_up() { - check( - r#" -fn main() { - let test = 123; - let test2$0$0 = 456; -} -"#, - expect![[r#" - fn main() { - let test2$0 = 456; - let test = 123; - } - "#]], - Direction::Up, - ); - } - - #[test] - fn test_moves_expr_up() { - check( - r#" -fn main() { - println!("Hello, world"); - println!("All I want to say is...");$0$0 -} -"#, - expect![[r#" - fn main() { - println!("All I want to say is...");$0 - println!("Hello, world"); - } - "#]], - Direction::Up, - ); - check( - r#" -fn main() { - println!("Hello, world"); - - if true { - println!("Test"); - }$0$0 -} -"#, - expect![[r#" - fn main() { - if true { - println!("Test"); - }$0 - - println!("Hello, world"); - } - "#]], - Direction::Up, - ); - check( - r#" -fn main() { - println!("Hello, world"); - - for i in 0..10 { - println!("Test"); - }$0$0 -} -"#, - expect![[r#" - fn main() { - for i in 0..10 { - println!("Test"); - }$0 - - println!("Hello, world"); - } - "#]], - Direction::Up, - ); - check( - r#" -fn main() { - println!("Hello, world"); - - loop { - println!("Test"); - }$0$0 -} -"#, - expect![[r#" - fn main() { - loop { - println!("Test"); - }$0 - - println!("Hello, world"); - } - "#]], - Direction::Up, - ); - check( - r#" -fn main() { - println!("Hello, world"); - - while true { - println!("Test"); - }$0$0 -} -"#, - expect![[r#" - fn main() { - while true { - println!("Test"); - }$0 - - println!("Hello, world"); - } - "#]], - Direction::Up, - ); - check( - r#" -fn main() { - println!("Hello, world"); - - return 123;$0$0 -} -"#, - expect![[r#" - fn main() { - return 123;$0 - - println!("Hello, world"); - } - "#]], - Direction::Up, - ); - } - - #[test] - fn test_nowhere_to_move_stmt() { - check( - r#" -fn main() { - println!("All I want to say is...");$0$0 - println!("Hello, world"); -} -"#, - expect![[r#" - fn main() { - println!("All I want to say is..."); - println!("Hello, world"); - } - "#]], - Direction::Up, - ); - } - - #[test] - fn test_move_item() { - check( - r#" -fn main() {} - -fn foo() {}$0$0 -"#, - expect![[r#" - fn foo() {}$0 - - fn main() {} - "#]], - Direction::Up, - ); - } - - #[test] - fn test_move_impl_up() { - check( - r#" -struct Yay; - -trait Wow {} - -impl Wow for Yay $0$0{} -"#, - expect![[r#" - struct Yay; - - impl Wow for Yay $0{} - - trait Wow {} - "#]], - Direction::Up, - ); - } - - #[test] - fn test_move_use_up() { - check( - r#" -use std::vec::Vec; -use std::collections::HashMap$0$0; -"#, - expect![[r#" - use std::collections::HashMap$0; - use std::vec::Vec; - "#]], - Direction::Up, - ); - } - - #[test] - fn test_moves_match_expr_up() { - check( - r#" -fn main() { - let test = 123; - - $0match test { - 456 => {}, - _ => {} - };$0 -} -"#, - expect![[r#" - fn main() { - match test { - 456 => {}, - _ => {} - }; - - let test = 123; - } - "#]], - Direction::Up, - ); - } - - #[test] - fn test_moves_param() { - check( - r#" -fn test(one: i32, two$0$0: u32) {} - -fn main() { - test(123, 456); -} -"#, - expect![[r#" - fn test(two$0: u32, one: i32) {} - - fn main() { - test(123, 456); - } - "#]], - Direction::Up, - ); - check( - r#" -fn f($0$0arg: u8, arg2: u16) {} -"#, - expect![[r#" - fn f(arg2: u16, $0arg: u8) {} - "#]], - Direction::Down, - ); - } - - #[test] - fn test_moves_arg_up() { - check( - r#" -fn test(one: i32, two: u32) {} - -fn main() { - test(123, 456$0$0); -} -"#, - expect![[r#" - fn test(one: i32, two: u32) {} - - fn main() { - test(456$0, 123); - } - "#]], - Direction::Up, - ); - } - - #[test] - fn test_moves_arg_down() { - check( - r#" -fn test(one: i32, two: u32) {} - -fn main() { - test(123$0$0, 456); -} -"#, - expect![[r#" - fn test(one: i32, two: u32) {} - - fn main() { - test(456, 123$0); - } - "#]], - Direction::Down, - ); - } - - #[test] - fn test_nowhere_to_move_arg() { - check( - r#" -fn test(one: i32, two: u32) {} - -fn main() { - test(123$0$0, 456); -} -"#, - expect![[r#" - fn test(one: i32, two: u32) {} - - fn main() { - test(123, 456); - } - "#]], - Direction::Up, - ); - } - - #[test] - fn test_moves_generic_param_up() { - check( - r#" -struct Test(A, B); - -fn main() {} -"#, - expect![[r#" - struct Test(A, B); - - fn main() {} - "#]], - Direction::Up, - ); - } - - #[test] - fn test_moves_generic_arg_up() { - check( - r#" -struct Test(A, B); - -fn main() { - let t = Test::(123, "yay"); -} -"#, - expect![[r#" - struct Test(A, B); - - fn main() { - let t = Test::<&str$0, i32>(123, "yay"); - } - "#]], - Direction::Up, - ); - } - - #[test] - fn test_moves_variant_up() { - check( - r#" -enum Hello { - One, - Two$0$0 -} - -fn main() {} -"#, - expect![[r#" - enum Hello { - Two$0, - One - } - - fn main() {} - "#]], - Direction::Up, - ); - } - - #[test] - fn test_moves_type_bound_up() { - check( - r#" -trait One {} - -trait Two {} - -fn test(t: T) {} - -fn main() {} -"#, - expect![[r#" - trait One {} - - trait Two {} - - fn test(t: T) {} - - fn main() {} - "#]], - Direction::Up, - ); - } - - #[test] - fn test_prioritizes_trait_items() { - check( - r#" -struct Test; - -trait Yay { - type One; - - type Two; - - fn inner(); -} - -impl Yay for Test { - type One = i32; - - type Two = u32; - - fn inner() {$0$0 - println!("Mmmm"); - } -} -"#, - expect![[r#" - struct Test; - - trait Yay { - type One; - - type Two; - - fn inner(); - } - - impl Yay for Test { - type One = i32; - - fn inner() {$0 - println!("Mmmm"); - } - - type Two = u32; - } - "#]], - Direction::Up, - ); - } - - #[test] - fn test_weird_nesting() { - check( - r#" -fn test() { - mod hello { - fn inner() {} - } - - mod hi {$0$0 - fn inner() {} - } -} -"#, - expect![[r#" - fn test() { - mod hi {$0 - fn inner() {} - } - - mod hello { - fn inner() {} - } - } - "#]], - Direction::Up, - ); - } - - #[test] - fn test_cursor_at_item_start() { - check( - r#" -$0$0#[derive(Debug)] -enum FooBar { - Foo, - Bar, -} - -fn main() {} -"#, - expect![[r##" - fn main() {} - - $0#[derive(Debug)] - enum FooBar { - Foo, - Bar, - } - "##]], - Direction::Down, - ); - check( - r#" -$0$0enum FooBar { - Foo, - Bar, -} - -fn main() {} -"#, - expect![[r#" - fn main() {} - - $0enum FooBar { - Foo, - Bar, - } - "#]], - Direction::Down, - ); - check( - r#" -struct Test; - -trait SomeTrait {} - -$0$0impl SomeTrait for Test {} - -fn main() {} -"#, - expect![[r#" - struct Test; - - $0impl SomeTrait for Test {} - - trait SomeTrait {} - - fn main() {} - "#]], - Direction::Up, - ); - } - - #[test] - fn test_cursor_at_item_end() { - check( - r#" -enum FooBar { - Foo, - Bar, -}$0$0 - -fn main() {} -"#, - expect![[r#" - fn main() {} - - enum FooBar { - Foo, - Bar, - }$0 - "#]], - Direction::Down, - ); - check( - r#" -struct Test; - -trait SomeTrait {} - -impl SomeTrait for Test {}$0$0 - -fn main() {} -"#, - expect![[r#" - struct Test; - - impl SomeTrait for Test {}$0 - - trait SomeTrait {} - - fn main() {} - "#]], - Direction::Up, - ); - } - - #[test] - fn handles_empty_file() { - check(r#"$0$0"#, expect![[r#""#]], Direction::Up); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs deleted file mode 100644 index 9f049e298ad11..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ /dev/null @@ -1,623 +0,0 @@ -//! See [`NavigationTarget`]. - -use std::fmt; - -use either::Either; -use hir::{ - symbols::FileSymbol, AssocItem, Documentation, FieldSource, HasAttrs, HasSource, HirDisplay, - InFile, ModuleSource, Semantics, -}; -use ide_db::{ - base_db::{FileId, FileRange}, - SymbolKind, -}; -use ide_db::{defs::Definition, RootDatabase}; -use stdx::never; -use syntax::{ - ast::{self, HasName}, - match_ast, AstNode, SmolStr, SyntaxNode, TextRange, -}; - -/// `NavigationTarget` represents an element in the editor's UI which you can -/// click on to navigate to a particular piece of code. -/// -/// Typically, a `NavigationTarget` corresponds to some element in the source -/// code, like a function or a struct, but this is not strictly required. -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct NavigationTarget { - pub file_id: FileId, - /// Range which encompasses the whole element. - /// - /// Should include body, doc comments, attributes, etc. - /// - /// Clients should use this range to answer "is the cursor inside the - /// element?" question. - pub full_range: TextRange, - /// A "most interesting" range within the `full_range`. - /// - /// Typically, `full_range` is the whole syntax node, including doc - /// comments, and `focus_range` is the range of the identifier. - /// - /// Clients should place the cursor on this range when navigating to this target. - pub focus_range: Option, - pub name: SmolStr, - pub kind: Option, - pub container_name: Option, - pub description: Option, - pub docs: Option, -} - -impl fmt::Debug for NavigationTarget { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut f = f.debug_struct("NavigationTarget"); - macro_rules! opt { - ($($name:ident)*) => {$( - if let Some(it) = &self.$name { - f.field(stringify!($name), it); - } - )*} - } - f.field("file_id", &self.file_id).field("full_range", &self.full_range); - opt!(focus_range); - f.field("name", &self.name); - opt!(kind container_name description docs); - f.finish() - } -} - -pub(crate) trait ToNav { - fn to_nav(&self, db: &RootDatabase) -> NavigationTarget; -} - -pub(crate) trait TryToNav { - fn try_to_nav(&self, db: &RootDatabase) -> Option; -} - -impl TryToNav for Either { - fn try_to_nav(&self, db: &RootDatabase) -> Option { - match self { - Either::Left(it) => it.try_to_nav(db), - Either::Right(it) => it.try_to_nav(db), - } - } -} - -impl NavigationTarget { - pub fn focus_or_full_range(&self) -> TextRange { - self.focus_range.unwrap_or(self.full_range) - } - - pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { - let name = module.name(db).map(|it| it.to_smol_str()).unwrap_or_default(); - if let Some(src @ InFile { value, .. }) = &module.declaration_source(db) { - let FileRange { file_id, range: full_range } = src.syntax().original_file_range(db); - let focus_range = - value.name().and_then(|it| orig_focus_range(db, src.file_id, it.syntax())); - let mut res = NavigationTarget::from_syntax( - file_id, - name, - focus_range, - full_range, - SymbolKind::Module, - ); - res.docs = module.attrs(db).docs(); - res.description = Some(module.display(db).to_string()); - return res; - } - module.to_nav(db) - } - - #[cfg(test)] - pub(crate) fn debug_render(&self) -> String { - let mut buf = format!( - "{} {:?} {:?} {:?}", - self.name, - self.kind.unwrap(), - self.file_id, - self.full_range - ); - if let Some(focus_range) = self.focus_range { - buf.push_str(&format!(" {:?}", focus_range)) - } - if let Some(container_name) = &self.container_name { - buf.push_str(&format!(" {}", container_name)) - } - buf - } - - /// Allows `NavigationTarget` to be created from a `NameOwner` - pub(crate) fn from_named( - db: &RootDatabase, - node @ InFile { file_id, value }: InFile<&dyn ast::HasName>, - kind: SymbolKind, - ) -> NavigationTarget { - let name = value.name().map(|it| it.text().into()).unwrap_or_else(|| "_".into()); - let focus_range = value.name().and_then(|it| orig_focus_range(db, file_id, it.syntax())); - let FileRange { file_id, range } = node.map(|it| it.syntax()).original_file_range(db); - - NavigationTarget::from_syntax(file_id, name, focus_range, range, kind) - } - - fn from_syntax( - file_id: FileId, - name: SmolStr, - focus_range: Option, - full_range: TextRange, - kind: SymbolKind, - ) -> NavigationTarget { - NavigationTarget { - file_id, - name, - kind: Some(kind), - full_range, - focus_range, - container_name: None, - description: None, - docs: None, - } - } -} - -impl TryToNav for FileSymbol { - fn try_to_nav(&self, db: &RootDatabase) -> Option { - let full_range = self.loc.original_range(db)?; - let name_range = self.loc.original_name_range(db)?; - - Some(NavigationTarget { - file_id: full_range.file_id, - name: self.name.clone(), - kind: Some(self.kind.into()), - full_range: full_range.range, - focus_range: Some(name_range.range), - container_name: self.container_name.clone(), - description: description_from_symbol(db, self), - docs: None, - }) - } -} - -impl TryToNav for Definition { - fn try_to_nav(&self, db: &RootDatabase) -> Option { - match self { - Definition::Local(it) => Some(it.to_nav(db)), - Definition::Label(it) => Some(it.to_nav(db)), - Definition::Module(it) => Some(it.to_nav(db)), - Definition::Macro(it) => it.try_to_nav(db), - Definition::Field(it) => it.try_to_nav(db), - Definition::SelfType(it) => it.try_to_nav(db), - Definition::GenericParam(it) => it.try_to_nav(db), - Definition::Function(it) => it.try_to_nav(db), - Definition::Adt(it) => it.try_to_nav(db), - Definition::Variant(it) => it.try_to_nav(db), - Definition::Const(it) => it.try_to_nav(db), - Definition::Static(it) => it.try_to_nav(db), - Definition::Trait(it) => it.try_to_nav(db), - Definition::TypeAlias(it) => it.try_to_nav(db), - Definition::BuiltinType(_) => None, - Definition::ToolModule(_) => None, - Definition::BuiltinAttr(_) => None, - // FIXME: The focus range should be set to the helper declaration - Definition::DeriveHelper(it) => it.derive().try_to_nav(db), - } - } -} - -impl TryToNav for hir::ModuleDef { - fn try_to_nav(&self, db: &RootDatabase) -> Option { - match self { - hir::ModuleDef::Module(it) => Some(it.to_nav(db)), - hir::ModuleDef::Function(it) => it.try_to_nav(db), - hir::ModuleDef::Adt(it) => it.try_to_nav(db), - hir::ModuleDef::Variant(it) => it.try_to_nav(db), - hir::ModuleDef::Const(it) => it.try_to_nav(db), - hir::ModuleDef::Static(it) => it.try_to_nav(db), - hir::ModuleDef::Trait(it) => it.try_to_nav(db), - hir::ModuleDef::TypeAlias(it) => it.try_to_nav(db), - hir::ModuleDef::Macro(it) => it.try_to_nav(db), - hir::ModuleDef::BuiltinType(_) => None, - } - } -} - -pub(crate) trait ToNavFromAst { - const KIND: SymbolKind; -} -impl ToNavFromAst for hir::Function { - const KIND: SymbolKind = SymbolKind::Function; -} -impl ToNavFromAst for hir::Const { - const KIND: SymbolKind = SymbolKind::Const; -} -impl ToNavFromAst for hir::Static { - const KIND: SymbolKind = SymbolKind::Static; -} -impl ToNavFromAst for hir::Struct { - const KIND: SymbolKind = SymbolKind::Struct; -} -impl ToNavFromAst for hir::Enum { - const KIND: SymbolKind = SymbolKind::Enum; -} -impl ToNavFromAst for hir::Variant { - const KIND: SymbolKind = SymbolKind::Variant; -} -impl ToNavFromAst for hir::Union { - const KIND: SymbolKind = SymbolKind::Union; -} -impl ToNavFromAst for hir::TypeAlias { - const KIND: SymbolKind = SymbolKind::TypeAlias; -} -impl ToNavFromAst for hir::Trait { - const KIND: SymbolKind = SymbolKind::Trait; -} - -impl TryToNav for D -where - D: HasSource + ToNavFromAst + Copy + HasAttrs + HirDisplay, - D::Ast: ast::HasName, -{ - fn try_to_nav(&self, db: &RootDatabase) -> Option { - let src = self.source(db)?; - let mut res = NavigationTarget::from_named( - db, - src.as_ref().map(|it| it as &dyn ast::HasName), - D::KIND, - ); - res.docs = self.docs(db); - res.description = Some(self.display(db).to_string()); - Some(res) - } -} - -impl ToNav for hir::Module { - fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { - let InFile { file_id, value } = self.definition_source(db); - - let name = self.name(db).map(|it| it.to_smol_str()).unwrap_or_default(); - let (syntax, focus) = match &value { - ModuleSource::SourceFile(node) => (node.syntax(), None), - ModuleSource::Module(node) => ( - node.syntax(), - node.name().and_then(|it| orig_focus_range(db, file_id, it.syntax())), - ), - ModuleSource::BlockExpr(node) => (node.syntax(), None), - }; - let FileRange { file_id, range: full_range } = - InFile::new(file_id, syntax).original_file_range(db); - NavigationTarget::from_syntax(file_id, name, focus, full_range, SymbolKind::Module) - } -} - -impl TryToNav for hir::Impl { - fn try_to_nav(&self, db: &RootDatabase) -> Option { - let InFile { file_id, value } = self.source(db)?; - let derive_attr = self.is_builtin_derive(db); - - let focus_range = if derive_attr.is_some() { - None - } else { - value.self_ty().and_then(|ty| orig_focus_range(db, file_id, ty.syntax())) - }; - - let FileRange { file_id, range: full_range } = match &derive_attr { - Some(attr) => attr.syntax().original_file_range(db), - None => InFile::new(file_id, value.syntax()).original_file_range(db), - }; - - Some(NavigationTarget::from_syntax( - file_id, - "impl".into(), - focus_range, - full_range, - SymbolKind::Impl, - )) - } -} - -impl TryToNav for hir::Field { - fn try_to_nav(&self, db: &RootDatabase) -> Option { - let src = self.source(db)?; - - let field_source = match &src.value { - FieldSource::Named(it) => { - let mut res = - NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field); - res.docs = self.docs(db); - res.description = Some(self.display(db).to_string()); - res - } - FieldSource::Pos(it) => { - let FileRange { file_id, range } = - src.with_value(it.syntax()).original_file_range(db); - NavigationTarget::from_syntax(file_id, "".into(), None, range, SymbolKind::Field) - } - }; - Some(field_source) - } -} - -impl TryToNav for hir::Macro { - fn try_to_nav(&self, db: &RootDatabase) -> Option { - let src = self.source(db)?; - let name_owner: &dyn ast::HasName = match &src.value { - Either::Left(it) => it, - Either::Right(it) => it, - }; - let mut res = NavigationTarget::from_named( - db, - src.as_ref().with_value(name_owner), - self.kind(db).into(), - ); - res.docs = self.docs(db); - Some(res) - } -} - -impl TryToNav for hir::Adt { - fn try_to_nav(&self, db: &RootDatabase) -> Option { - match self { - hir::Adt::Struct(it) => it.try_to_nav(db), - hir::Adt::Union(it) => it.try_to_nav(db), - hir::Adt::Enum(it) => it.try_to_nav(db), - } - } -} - -impl TryToNav for hir::AssocItem { - fn try_to_nav(&self, db: &RootDatabase) -> Option { - match self { - AssocItem::Function(it) => it.try_to_nav(db), - AssocItem::Const(it) => it.try_to_nav(db), - AssocItem::TypeAlias(it) => it.try_to_nav(db), - } - } -} - -impl TryToNav for hir::GenericParam { - fn try_to_nav(&self, db: &RootDatabase) -> Option { - match self { - hir::GenericParam::TypeParam(it) => it.try_to_nav(db), - hir::GenericParam::ConstParam(it) => it.try_to_nav(db), - hir::GenericParam::LifetimeParam(it) => it.try_to_nav(db), - } - } -} - -impl ToNav for hir::Local { - fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { - let InFile { file_id, value } = self.source(db); - let (node, name) = match &value { - Either::Left(bind_pat) => (bind_pat.syntax(), bind_pat.name()), - Either::Right(it) => (it.syntax(), it.name()), - }; - let focus_range = name.and_then(|it| orig_focus_range(db, file_id, it.syntax())); - let FileRange { file_id, range: full_range } = - InFile::new(file_id, node).original_file_range(db); - - let name = self.name(db).to_smol_str(); - let kind = if self.is_self(db) { - SymbolKind::SelfParam - } else if self.is_param(db) { - SymbolKind::ValueParam - } else { - SymbolKind::Local - }; - NavigationTarget { - file_id, - name, - kind: Some(kind), - full_range, - focus_range, - container_name: None, - description: None, - docs: None, - } - } -} - -impl ToNav for hir::Label { - fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { - let InFile { file_id, value } = self.source(db); - let name = self.name(db).to_smol_str(); - - let range = |syntax: &_| InFile::new(file_id, syntax).original_file_range(db); - let FileRange { file_id, range: full_range } = range(value.syntax()); - let focus_range = value.lifetime().map(|lt| range(lt.syntax()).range); - - NavigationTarget { - file_id, - name, - kind: Some(SymbolKind::Label), - full_range, - focus_range, - container_name: None, - description: None, - docs: None, - } - } -} - -impl TryToNav for hir::TypeParam { - fn try_to_nav(&self, db: &RootDatabase) -> Option { - let InFile { file_id, value } = self.merge().source(db)?; - let name = self.name(db).to_smol_str(); - - let value = match value { - Either::Left(ast::TypeOrConstParam::Type(x)) => Either::Left(x), - Either::Left(ast::TypeOrConstParam::Const(_)) => { - never!(); - return None; - } - Either::Right(x) => Either::Right(x), - }; - - let range = |syntax: &_| InFile::new(file_id, syntax).original_file_range(db); - let focus_range = |syntax: &_| InFile::new(file_id, syntax).original_file_range_opt(db); - let FileRange { file_id, range: full_range } = match &value { - Either::Left(type_param) => range(type_param.syntax()), - Either::Right(trait_) => trait_ - .name() - .and_then(|name| focus_range(name.syntax())) - .unwrap_or_else(|| range(trait_.syntax())), - }; - let focus_range = value - .either(|it| it.name(), |it| it.name()) - .and_then(|it| focus_range(it.syntax())) - .map(|it| it.range); - Some(NavigationTarget { - file_id, - name, - kind: Some(SymbolKind::TypeParam), - full_range, - focus_range, - container_name: None, - description: None, - docs: None, - }) - } -} - -impl TryToNav for hir::TypeOrConstParam { - fn try_to_nav(&self, db: &RootDatabase) -> Option { - self.split(db).try_to_nav(db) - } -} - -impl TryToNav for hir::LifetimeParam { - fn try_to_nav(&self, db: &RootDatabase) -> Option { - let InFile { file_id, value } = self.source(db)?; - let name = self.name(db).to_smol_str(); - - let FileRange { file_id, range: full_range } = - InFile::new(file_id, value.syntax()).original_file_range(db); - Some(NavigationTarget { - file_id, - name, - kind: Some(SymbolKind::LifetimeParam), - full_range, - focus_range: Some(full_range), - container_name: None, - description: None, - docs: None, - }) - } -} - -impl TryToNav for hir::ConstParam { - fn try_to_nav(&self, db: &RootDatabase) -> Option { - let InFile { file_id, value } = self.merge().source(db)?; - let name = self.name(db).to_smol_str(); - - let value = match value { - Either::Left(ast::TypeOrConstParam::Const(x)) => x, - _ => { - never!(); - return None; - } - }; - - let focus_range = value.name().and_then(|it| orig_focus_range(db, file_id, it.syntax())); - let FileRange { file_id, range: full_range } = - InFile::new(file_id, value.syntax()).original_file_range(db); - Some(NavigationTarget { - file_id, - name, - kind: Some(SymbolKind::ConstParam), - full_range, - focus_range, - container_name: None, - description: None, - docs: None, - }) - } -} - -/// Get a description of a symbol. -/// -/// e.g. `struct Name`, `enum Name`, `fn Name` -pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option { - let sema = Semantics::new(db); - let node = symbol.loc.syntax(&sema)?; - - match_ast! { - match node { - ast::Fn(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::Struct(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::Enum(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::Trait(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::Module(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::TypeAlias(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::Const(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::Static(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::RecordField(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::Variant(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::Union(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - _ => None, - } - } -} - -fn orig_focus_range( - db: &RootDatabase, - file_id: hir::HirFileId, - syntax: &SyntaxNode, -) -> Option { - InFile::new(file_id, syntax).original_file_range_opt(db).map(|it| it.range) -} - -#[cfg(test)] -mod tests { - use expect_test::expect; - - use crate::{fixture, Query}; - - #[test] - fn test_nav_for_symbol() { - let (analysis, _) = fixture::file( - r#" -enum FooInner { } -fn foo() { enum FooInner { } } -"#, - ); - - let navs = analysis.symbol_search(Query::new("FooInner".to_string())).unwrap(); - expect![[r#" - [ - NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..17, - focus_range: 5..13, - name: "FooInner", - kind: Enum, - description: "enum FooInner", - }, - NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 29..46, - focus_range: 34..42, - name: "FooInner", - kind: Enum, - container_name: "foo", - description: "enum FooInner", - }, - ] - "#]] - .assert_debug_eq(&navs); - } - - #[test] - fn test_world_symbols_are_case_sensitive() { - let (analysis, _) = fixture::file( - r#" -fn foo() {} -struct Foo; -"#, - ); - - let navs = analysis.symbol_search(Query::new("foo".to_string())).unwrap(); - assert_eq!(navs.len(), 2) - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs deleted file mode 100644 index 9b1f480446aa9..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs +++ /dev/null @@ -1,167 +0,0 @@ -use hir::Semantics; -use ide_db::{ - base_db::{CrateId, FileId, FilePosition}, - RootDatabase, -}; -use itertools::Itertools; -use syntax::{ - algo::find_node_at_offset, - ast::{self, AstNode}, -}; - -use crate::NavigationTarget; - -// Feature: Parent Module -// -// Navigates to the parent module of the current module. -// -// |=== -// | Editor | Action Name -// -// | VS Code | **Rust Analyzer: Locate parent module** -// |=== -// -// image::https://user-images.githubusercontent.com/48062697/113065580-04c21800-91b1-11eb-9a32-00086161c0bd.gif[] - -/// This returns `Vec` because a module may be included from several places. -pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec { - let sema = Semantics::new(db); - let source_file = sema.parse(position.file_id); - - let mut module = find_node_at_offset::(source_file.syntax(), position.offset); - - // If cursor is literally on `mod foo`, go to the grandpa. - if let Some(m) = &module { - if !m - .item_list() - .map_or(false, |it| it.syntax().text_range().contains_inclusive(position.offset)) - { - cov_mark::hit!(test_resolve_parent_module_on_module_decl); - module = m.syntax().ancestors().skip(1).find_map(ast::Module::cast); - } - } - - match module { - Some(module) => sema - .to_def(&module) - .into_iter() - .map(|module| NavigationTarget::from_module_to_decl(db, module)) - .collect(), - None => sema - .to_module_defs(position.file_id) - .map(|module| NavigationTarget::from_module_to_decl(db, module)) - .collect(), - } -} - -/// Returns `Vec` for the same reason as `parent_module` -pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec { - let sema = Semantics::new(db); - sema.to_module_defs(file_id).map(|module| module.krate().into()).unique().collect() -} - -#[cfg(test)] -mod tests { - use ide_db::base_db::FileRange; - - use crate::fixture; - - fn check(ra_fixture: &str) { - let (analysis, position, expected) = fixture::annotations(ra_fixture); - let navs = analysis.parent_module(position).unwrap(); - let navs = navs - .iter() - .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) - .collect::>(); - assert_eq!(expected.into_iter().map(|(fr, _)| fr).collect::>(), navs); - } - - #[test] - fn test_resolve_parent_module() { - check( - r#" -//- /lib.rs -mod foo; - //^^^ - -//- /foo.rs -$0// empty -"#, - ); - } - - #[test] - fn test_resolve_parent_module_on_module_decl() { - cov_mark::check!(test_resolve_parent_module_on_module_decl); - check( - r#" -//- /lib.rs -mod foo; - //^^^ -//- /foo.rs -mod $0bar; - -//- /foo/bar.rs -// empty -"#, - ); - } - - #[test] - fn test_resolve_parent_module_for_inline() { - check( - r#" -//- /lib.rs -mod foo { - mod bar { - mod baz { $0 } - } //^^^ -} -"#, - ); - } - - #[test] - fn test_resolve_multi_parent_module() { - check( - r#" -//- /main.rs -mod foo; - //^^^ -#[path = "foo.rs"] -mod bar; - //^^^ -//- /foo.rs -$0 -"#, - ); - } - - #[test] - fn test_resolve_crate_root() { - let (analysis, file_id) = fixture::file( - r#" -//- /foo.rs -$0 -//- /main.rs -mod foo; -"#, - ); - assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1); - } - - #[test] - fn test_resolve_multi_parent_crate() { - let (analysis, file_id) = fixture::file( - r#" -//- /baz.rs -$0 -//- /foo.rs crate:foo -mod baz; -//- /bar.rs crate:bar -mod baz; -"#, - ); - assert_eq!(analysis.crate_for(file_id).unwrap().len(), 2); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide/src/prime_caches.rs deleted file mode 100644 index 296270036002b..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/prime_caches.rs +++ /dev/null @@ -1,158 +0,0 @@ -//! rust-analyzer is lazy and doesn't compute anything unless asked. This -//! sometimes is counter productive when, for example, the first goto definition -//! request takes longer to compute. This modules implemented prepopulation of -//! various caches, it's not really advanced at the moment. -mod topologic_sort; - -use std::time::Duration; - -use hir::db::DefDatabase; -use ide_db::{ - base_db::{ - salsa::{Database, ParallelDatabase, Snapshot}, - Cancelled, CrateGraph, CrateId, SourceDatabase, SourceDatabaseExt, - }, - FxHashSet, FxIndexMap, -}; - -use crate::RootDatabase; - -/// We're indexing many crates. -#[derive(Debug)] -pub struct ParallelPrimeCachesProgress { - /// the crates that we are currently priming. - pub crates_currently_indexing: Vec, - /// the total number of crates we want to prime. - pub crates_total: usize, - /// the total number of crates that have finished priming - pub crates_done: usize, -} - -pub(crate) fn parallel_prime_caches( - db: &RootDatabase, - num_worker_threads: u8, - cb: &(dyn Fn(ParallelPrimeCachesProgress) + Sync), -) { - let _p = profile::span("prime_caches"); - - let graph = db.crate_graph(); - let mut crates_to_prime = { - let crate_ids = compute_crates_to_prime(db, &graph); - - let mut builder = topologic_sort::TopologicalSortIter::builder(); - - for &crate_id in &crate_ids { - let crate_data = &graph[crate_id]; - let dependencies = crate_data - .dependencies - .iter() - .map(|d| d.crate_id) - .filter(|i| crate_ids.contains(i)); - - builder.add(crate_id, dependencies); - } - - builder.build() - }; - - enum ParallelPrimeCacheWorkerProgress { - BeginCrate { crate_id: CrateId, crate_name: String }, - EndCrate { crate_id: CrateId }, - } - - let (work_sender, progress_receiver) = { - let (progress_sender, progress_receiver) = crossbeam_channel::unbounded(); - let (work_sender, work_receiver) = crossbeam_channel::unbounded(); - let prime_caches_worker = move |db: Snapshot| { - while let Ok((crate_id, crate_name)) = work_receiver.recv() { - progress_sender - .send(ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name })?; - - // This also computes the DefMap - db.import_map(crate_id); - - progress_sender.send(ParallelPrimeCacheWorkerProgress::EndCrate { crate_id })?; - } - - Ok::<_, crossbeam_channel::SendError<_>>(()) - }; - - for _ in 0..num_worker_threads { - let worker = prime_caches_worker.clone(); - let db = db.snapshot(); - std::thread::spawn(move || Cancelled::catch(|| worker(db))); - } - - (work_sender, progress_receiver) - }; - - let crates_total = crates_to_prime.pending(); - let mut crates_done = 0; - - // an index map is used to preserve ordering so we can sort the progress report in order of - // "longest crate to index" first - let mut crates_currently_indexing = - FxIndexMap::with_capacity_and_hasher(num_worker_threads as _, Default::default()); - - while crates_done < crates_total { - db.unwind_if_cancelled(); - - for crate_id in &mut crates_to_prime { - work_sender - .send(( - crate_id, - graph[crate_id].display_name.as_deref().unwrap_or_default().to_string(), - )) - .ok(); - } - - // recv_timeout is somewhat a hack, we need a way to from this thread check to see if the current salsa revision - // is cancelled on a regular basis. workers will only exit if they are processing a task that is cancelled, or - // if this thread exits, and closes the work channel. - let worker_progress = match progress_receiver.recv_timeout(Duration::from_millis(10)) { - Ok(p) => p, - Err(crossbeam_channel::RecvTimeoutError::Timeout) => { - continue; - } - Err(crossbeam_channel::RecvTimeoutError::Disconnected) => { - // our workers may have died from a cancelled task, so we'll check and re-raise here. - db.unwind_if_cancelled(); - break; - } - }; - match worker_progress { - ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name } => { - crates_currently_indexing.insert(crate_id, crate_name); - } - ParallelPrimeCacheWorkerProgress::EndCrate { crate_id } => { - crates_currently_indexing.remove(&crate_id); - crates_to_prime.mark_done(crate_id); - crates_done += 1; - } - }; - - let progress = ParallelPrimeCachesProgress { - crates_currently_indexing: crates_currently_indexing.values().cloned().collect(), - crates_done, - crates_total, - }; - - cb(progress); - } -} - -fn compute_crates_to_prime(db: &RootDatabase, graph: &CrateGraph) -> FxHashSet { - // We're only interested in the workspace crates and the `ImportMap`s of their direct - // dependencies, though in practice the latter also compute the `DefMap`s. - // We don't prime transitive dependencies because they're generally not visible in - // the current workspace. - graph - .iter() - .filter(|&id| { - let file_id = graph[id].root_file_id; - let root_id = db.file_source_root(file_id); - !db.source_root(root_id).is_library - }) - .flat_map(|id| graph[id].dependencies.iter().map(|krate| krate.crate_id)) - .collect() -} diff --git a/src/tools/rust-analyzer/crates/ide/src/prime_caches/topologic_sort.rs b/src/tools/rust-analyzer/crates/ide/src/prime_caches/topologic_sort.rs deleted file mode 100644 index 9c3ceedbb691d..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/prime_caches/topologic_sort.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! helper data structure to schedule work for parallel prime caches. -use std::{collections::VecDeque, hash::Hash}; - -use ide_db::FxHashMap; - -pub(crate) struct TopologicSortIterBuilder { - nodes: FxHashMap>, -} - -impl TopologicSortIterBuilder -where - T: Copy + Eq + PartialEq + Hash, -{ - fn new() -> Self { - Self { nodes: Default::default() } - } - - fn get_or_create_entry(&mut self, item: T) -> &mut Entry { - self.nodes.entry(item).or_default() - } - - pub(crate) fn add(&mut self, item: T, predecessors: impl IntoIterator) { - let mut num_predecessors = 0; - - for predecessor in predecessors.into_iter() { - self.get_or_create_entry(predecessor).successors.push(item); - num_predecessors += 1; - } - - let entry = self.get_or_create_entry(item); - entry.num_predecessors += num_predecessors; - } - - pub(crate) fn build(self) -> TopologicalSortIter { - let ready = self - .nodes - .iter() - .filter_map( - |(item, entry)| if entry.num_predecessors == 0 { Some(*item) } else { None }, - ) - .collect(); - - TopologicalSortIter { nodes: self.nodes, ready } - } -} - -pub(crate) struct TopologicalSortIter { - ready: VecDeque, - nodes: FxHashMap>, -} - -impl TopologicalSortIter -where - T: Copy + Eq + PartialEq + Hash, -{ - pub(crate) fn builder() -> TopologicSortIterBuilder { - TopologicSortIterBuilder::new() - } - - pub(crate) fn pending(&self) -> usize { - self.nodes.len() - } - - pub(crate) fn mark_done(&mut self, item: T) { - let entry = self.nodes.remove(&item).expect("invariant: unknown item marked as done"); - - for successor in entry.successors { - let succ_entry = self - .nodes - .get_mut(&successor) - .expect("invariant: unknown successor referenced by entry"); - - succ_entry.num_predecessors -= 1; - if succ_entry.num_predecessors == 0 { - self.ready.push_back(successor); - } - } - } -} - -impl Iterator for TopologicalSortIter { - type Item = T; - - fn next(&mut self) -> Option { - self.ready.pop_front() - } -} - -struct Entry { - successors: Vec, - num_predecessors: usize, -} - -impl Default for Entry { - fn default() -> Self { - Self { successors: Default::default(), num_predecessors: 0 } - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs deleted file mode 100644 index 1a6beec1881b0..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ /dev/null @@ -1,1636 +0,0 @@ -//! This module implements a reference search. -//! First, the element at the cursor position must be either an `ast::Name` -//! or `ast::NameRef`. If it's an `ast::NameRef`, at the classification step we -//! try to resolve the direct tree parent of this element, otherwise we -//! already have a definition and just need to get its HIR together with -//! some information that is needed for further steps of searching. -//! After that, we collect files that might contain references and look -//! for text occurrences of the identifier. If there's an `ast::NameRef` -//! at the index that the match starts at and its tree parent is -//! resolved to the search element definition, we get a reference. - -use hir::{PathResolution, Semantics}; -use ide_db::{ - base_db::FileId, - defs::{Definition, NameClass, NameRefClass}, - search::{ReferenceCategory, SearchScope, UsageSearchResult}, - FxHashMap, RootDatabase, -}; -use syntax::{ - algo::find_node_at_offset, - ast::{self, HasName}, - match_ast, AstNode, - SyntaxKind::*, - SyntaxNode, TextRange, TextSize, T, -}; - -use crate::{FilePosition, NavigationTarget, TryToNav}; - -#[derive(Debug, Clone)] -pub struct ReferenceSearchResult { - pub declaration: Option, - pub references: FxHashMap)>>, -} - -#[derive(Debug, Clone)] -pub struct Declaration { - pub nav: NavigationTarget, - pub is_mut: bool, -} - -// Feature: Find All References -// -// Shows all references of the item at the cursor location -// -// |=== -// | Editor | Shortcut -// -// | VS Code | kbd:[Shift+Alt+F12] -// |=== -// -// image::https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif[] -pub(crate) fn find_all_refs( - sema: &Semantics<'_, RootDatabase>, - position: FilePosition, - search_scope: Option, -) -> Option> { - let _p = profile::span("find_all_refs"); - let syntax = sema.parse(position.file_id).syntax().clone(); - let make_searcher = |literal_search: bool| { - move |def: Definition| { - let declaration = match def { - Definition::Module(module) => { - Some(NavigationTarget::from_module_to_decl(sema.db, module)) - } - def => def.try_to_nav(sema.db), - } - .map(|nav| { - let decl_range = nav.focus_or_full_range(); - Declaration { - is_mut: decl_mutability(&def, sema.parse(nav.file_id).syntax(), decl_range), - nav, - } - }); - let mut usages = - def.usages(sema).set_scope(search_scope.clone()).include_self_refs().all(); - - if literal_search { - retain_adt_literal_usages(&mut usages, def, sema); - } - - let references = usages - .into_iter() - .map(|(file_id, refs)| { - ( - file_id, - refs.into_iter() - .map(|file_ref| (file_ref.range, file_ref.category)) - .collect(), - ) - }) - .collect(); - - ReferenceSearchResult { declaration, references } - } - }; - - match name_for_constructor_search(&syntax, position) { - Some(name) => { - let def = match NameClass::classify(sema, &name)? { - NameClass::Definition(it) | NameClass::ConstReference(it) => it, - NameClass::PatFieldShorthand { local_def: _, field_ref } => { - Definition::Field(field_ref) - } - }; - Some(vec![make_searcher(true)(def)]) - } - None => { - let search = make_searcher(false); - Some(find_defs(sema, &syntax, position.offset)?.map(search).collect()) - } - } -} - -pub(crate) fn find_defs<'a>( - sema: &'a Semantics<'_, RootDatabase>, - syntax: &SyntaxNode, - offset: TextSize, -) -> Option + 'a> { - let token = syntax.token_at_offset(offset).find(|t| { - matches!( - t.kind(), - IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self] - ) - }); - token.map(|token| { - sema.descend_into_macros_with_same_text(token) - .into_iter() - .filter_map(|it| ast::NameLike::cast(it.parent()?)) - .filter_map(move |name_like| { - let def = match name_like { - ast::NameLike::NameRef(name_ref) => { - match NameRefClass::classify(sema, &name_ref)? { - NameRefClass::Definition(def) => def, - NameRefClass::FieldShorthand { local_ref, field_ref: _ } => { - Definition::Local(local_ref) - } - } - } - ast::NameLike::Name(name) => match NameClass::classify(sema, &name)? { - NameClass::Definition(it) | NameClass::ConstReference(it) => it, - NameClass::PatFieldShorthand { local_def, field_ref: _ } => { - Definition::Local(local_def) - } - }, - ast::NameLike::Lifetime(lifetime) => { - NameRefClass::classify_lifetime(sema, &lifetime) - .and_then(|class| match class { - NameRefClass::Definition(it) => Some(it), - _ => None, - }) - .or_else(|| { - NameClass::classify_lifetime(sema, &lifetime) - .and_then(NameClass::defined) - })? - } - }; - Some(def) - }) - }) -} - -pub(crate) fn decl_mutability(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> bool { - match def { - Definition::Local(_) | Definition::Field(_) => {} - _ => return false, - }; - - match find_node_at_offset::(syntax, range.start()) { - Some(stmt) if stmt.initializer().is_some() => match stmt.pat() { - Some(ast::Pat::IdentPat(it)) => it.mut_token().is_some(), - _ => false, - }, - _ => false, - } -} - -/// Filter out all non-literal usages for adt-defs -fn retain_adt_literal_usages( - usages: &mut UsageSearchResult, - def: Definition, - sema: &Semantics<'_, RootDatabase>, -) { - let refs = usages.references.values_mut(); - match def { - Definition::Adt(hir::Adt::Enum(enum_)) => { - refs.for_each(|it| { - it.retain(|reference| { - reference - .name - .as_name_ref() - .map_or(false, |name_ref| is_enum_lit_name_ref(sema, enum_, name_ref)) - }) - }); - usages.references.retain(|_, it| !it.is_empty()); - } - Definition::Adt(_) | Definition::Variant(_) => { - refs.for_each(|it| { - it.retain(|reference| reference.name.as_name_ref().map_or(false, is_lit_name_ref)) - }); - usages.references.retain(|_, it| !it.is_empty()); - } - _ => {} - } -} - -/// Returns `Some` if the cursor is at a position for an item to search for all its constructor/literal usages -fn name_for_constructor_search(syntax: &SyntaxNode, position: FilePosition) -> Option { - let token = syntax.token_at_offset(position.offset).right_biased()?; - let token_parent = token.parent()?; - let kind = token.kind(); - if kind == T![;] { - ast::Struct::cast(token_parent) - .filter(|struct_| struct_.field_list().is_none()) - .and_then(|struct_| struct_.name()) - } else if kind == T!['{'] { - match_ast! { - match token_parent { - ast::RecordFieldList(rfl) => match_ast! { - match (rfl.syntax().parent()?) { - ast::Variant(it) => it.name(), - ast::Struct(it) => it.name(), - ast::Union(it) => it.name(), - _ => None, - } - }, - ast::VariantList(vl) => ast::Enum::cast(vl.syntax().parent()?)?.name(), - _ => None, - } - } - } else if kind == T!['('] { - let tfl = ast::TupleFieldList::cast(token_parent)?; - match_ast! { - match (tfl.syntax().parent()?) { - ast::Variant(it) => it.name(), - ast::Struct(it) => it.name(), - _ => None, - } - } - } else { - None - } -} - -fn is_enum_lit_name_ref( - sema: &Semantics<'_, RootDatabase>, - enum_: hir::Enum, - name_ref: &ast::NameRef, -) -> bool { - let path_is_variant_of_enum = |path: ast::Path| { - matches!( - sema.resolve_path(&path), - Some(PathResolution::Def(hir::ModuleDef::Variant(variant))) - if variant.parent_enum(sema.db) == enum_ - ) - }; - name_ref - .syntax() - .ancestors() - .find_map(|ancestor| { - match_ast! { - match ancestor { - ast::PathExpr(path_expr) => path_expr.path().map(path_is_variant_of_enum), - ast::RecordExpr(record_expr) => record_expr.path().map(path_is_variant_of_enum), - _ => None, - } - } - }) - .unwrap_or(false) -} - -fn path_ends_with(path: Option, name_ref: &ast::NameRef) -> bool { - path.and_then(|path| path.segment()) - .and_then(|segment| segment.name_ref()) - .map_or(false, |segment| segment == *name_ref) -} - -fn is_lit_name_ref(name_ref: &ast::NameRef) -> bool { - name_ref.syntax().ancestors().find_map(|ancestor| { - match_ast! { - match ancestor { - ast::PathExpr(path_expr) => Some(path_ends_with(path_expr.path(), name_ref)), - ast::RecordExpr(record_expr) => Some(path_ends_with(record_expr.path(), name_ref)), - _ => None, - } - } - }).unwrap_or(false) -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - use ide_db::{base_db::FileId, search::ReferenceCategory}; - use stdx::format_to; - - use crate::{fixture, SearchScope}; - - #[test] - fn test_struct_literal_after_space() { - check( - r#" -struct Foo $0{ - a: i32, -} -impl Foo { - fn f() -> i32 { 42 } -} -fn main() { - let f: Foo; - f = Foo {a: Foo::f()}; -} -"#, - expect![[r#" - Foo Struct FileId(0) 0..26 7..10 - - FileId(0) 101..104 - "#]], - ); - } - - #[test] - fn test_struct_literal_before_space() { - check( - r#" -struct Foo$0 {} - fn main() { - let f: Foo; - f = Foo {}; -} -"#, - expect![[r#" - Foo Struct FileId(0) 0..13 7..10 - - FileId(0) 41..44 - FileId(0) 54..57 - "#]], - ); - } - - #[test] - fn test_struct_literal_with_generic_type() { - check( - r#" -struct Foo $0{} - fn main() { - let f: Foo::; - f = Foo {}; -} -"#, - expect![[r#" - Foo Struct FileId(0) 0..16 7..10 - - FileId(0) 64..67 - "#]], - ); - } - - #[test] - fn test_struct_literal_for_tuple() { - check( - r#" -struct Foo$0(i32); - -fn main() { - let f: Foo; - f = Foo(1); -} -"#, - expect![[r#" - Foo Struct FileId(0) 0..16 7..10 - - FileId(0) 54..57 - "#]], - ); - } - - #[test] - fn test_struct_literal_for_union() { - check( - r#" -union Foo $0{ - x: u32 -} - -fn main() { - let f: Foo; - f = Foo { x: 1 }; -} -"#, - expect![[r#" - Foo Union FileId(0) 0..24 6..9 - - FileId(0) 62..65 - "#]], - ); - } - - #[test] - fn test_enum_after_space() { - check( - r#" -enum Foo $0{ - A, - B(), - C{}, -} -fn main() { - let f: Foo; - f = Foo::A; - f = Foo::B(); - f = Foo::C{}; -} -"#, - expect![[r#" - Foo Enum FileId(0) 0..37 5..8 - - FileId(0) 74..77 - FileId(0) 90..93 - FileId(0) 108..111 - "#]], - ); - } - - #[test] - fn test_variant_record_after_space() { - check( - r#" -enum Foo { - A $0{ n: i32 }, - B, -} -fn main() { - let f: Foo; - f = Foo::B; - f = Foo::A { n: 92 }; -} -"#, - expect![[r#" - A Variant FileId(0) 15..27 15..16 - - FileId(0) 95..96 - "#]], - ); - } - #[test] - fn test_variant_tuple_before_paren() { - check( - r#" -enum Foo { - A$0(i32), - B, -} -fn main() { - let f: Foo; - f = Foo::B; - f = Foo::A(92); -} -"#, - expect![[r#" - A Variant FileId(0) 15..21 15..16 - - FileId(0) 89..90 - "#]], - ); - } - - #[test] - fn test_enum_before_space() { - check( - r#" -enum Foo$0 { - A, - B, -} -fn main() { - let f: Foo; - f = Foo::A; -} -"#, - expect![[r#" - Foo Enum FileId(0) 0..26 5..8 - - FileId(0) 50..53 - FileId(0) 63..66 - "#]], - ); - } - - #[test] - fn test_enum_with_generic_type() { - check( - r#" -enum Foo $0{ - A(T), - B, -} -fn main() { - let f: Foo; - f = Foo::A(1); -} -"#, - expect![[r#" - Foo Enum FileId(0) 0..32 5..8 - - FileId(0) 73..76 - "#]], - ); - } - - #[test] - fn test_enum_for_tuple() { - check( - r#" -enum Foo$0{ - A(i8), - B(i8), -} -fn main() { - let f: Foo; - f = Foo::A(1); -} -"#, - expect![[r#" - Foo Enum FileId(0) 0..33 5..8 - - FileId(0) 70..73 - "#]], - ); - } - - #[test] - fn test_find_all_refs_for_local() { - check( - r#" -fn main() { - let mut i = 1; - let j = 1; - i = i$0 + j; - - { - i = 0; - } - - i = 5; -}"#, - expect![[r#" - i Local FileId(0) 20..25 24..25 Write - - FileId(0) 50..51 Write - FileId(0) 54..55 Read - FileId(0) 76..77 Write - FileId(0) 94..95 Write - "#]], - ); - } - - #[test] - fn search_filters_by_range() { - check( - r#" -fn foo() { - let spam$0 = 92; - spam + spam -} -fn bar() { - let spam = 92; - spam + spam -} -"#, - expect![[r#" - spam Local FileId(0) 19..23 19..23 - - FileId(0) 34..38 Read - FileId(0) 41..45 Read - "#]], - ); - } - - #[test] - fn test_find_all_refs_for_param_inside() { - check( - r#" -fn foo(i : u32) -> u32 { i$0 } -"#, - expect![[r#" - i ValueParam FileId(0) 7..8 7..8 - - FileId(0) 25..26 Read - "#]], - ); - } - - #[test] - fn test_find_all_refs_for_fn_param() { - check( - r#" -fn foo(i$0 : u32) -> u32 { i } -"#, - expect![[r#" - i ValueParam FileId(0) 7..8 7..8 - - FileId(0) 25..26 Read - "#]], - ); - } - - #[test] - fn test_find_all_refs_field_name() { - check( - r#" -//- /lib.rs -struct Foo { - pub spam$0: u32, -} - -fn main(s: Foo) { - let f = s.spam; -} -"#, - expect![[r#" - spam Field FileId(0) 17..30 21..25 - - FileId(0) 67..71 Read - "#]], - ); - } - - #[test] - fn test_find_all_refs_impl_item_name() { - check( - r#" -struct Foo; -impl Foo { - fn f$0(&self) { } -} -"#, - expect![[r#" - f Function FileId(0) 27..43 30..31 - - (no references) - "#]], - ); - } - - #[test] - fn test_find_all_refs_enum_var_name() { - check( - r#" -enum Foo { - A, - B$0, - C, -} -"#, - expect![[r#" - B Variant FileId(0) 22..23 22..23 - - (no references) - "#]], - ); - } - - #[test] - fn test_find_all_refs_enum_var_field() { - check( - r#" -enum Foo { - A, - B { field$0: u8 }, - C, -} -"#, - expect![[r#" - field Field FileId(0) 26..35 26..31 - - (no references) - "#]], - ); - } - - #[test] - fn test_find_all_refs_two_modules() { - check( - r#" -//- /lib.rs -pub mod foo; -pub mod bar; - -fn f() { - let i = foo::Foo { n: 5 }; -} - -//- /foo.rs -use crate::bar; - -pub struct Foo { - pub n: u32, -} - -fn f() { - let i = bar::Bar { n: 5 }; -} - -//- /bar.rs -use crate::foo; - -pub struct Bar { - pub n: u32, -} - -fn f() { - let i = foo::Foo$0 { n: 5 }; -} -"#, - expect![[r#" - Foo Struct FileId(1) 17..51 28..31 - - FileId(0) 53..56 - FileId(2) 79..82 - "#]], - ); - } - - #[test] - fn test_find_all_refs_decl_module() { - check( - r#" -//- /lib.rs -mod foo$0; - -use foo::Foo; - -fn f() { - let i = Foo { n: 5 }; -} - -//- /foo.rs -pub struct Foo { - pub n: u32, -} -"#, - expect![[r#" - foo Module FileId(0) 0..8 4..7 - - FileId(0) 14..17 - "#]], - ); - } - - #[test] - fn test_find_all_refs_decl_module_on_self() { - check( - r#" -//- /lib.rs -mod foo; - -//- /foo.rs -use self$0; -"#, - expect![[r#" - foo Module FileId(0) 0..8 4..7 - - FileId(1) 4..8 - "#]], - ); - } - - #[test] - fn test_find_all_refs_decl_module_on_self_crate_root() { - check( - r#" -//- /lib.rs -use self$0; -"#, - expect![[r#" - Module FileId(0) 0..10 - - FileId(0) 4..8 - "#]], - ); - } - - #[test] - fn test_find_all_refs_super_mod_vis() { - check( - r#" -//- /lib.rs -mod foo; - -//- /foo.rs -mod some; -use some::Foo; - -fn f() { - let i = Foo { n: 5 }; -} - -//- /foo/some.rs -pub(super) struct Foo$0 { - pub n: u32, -} -"#, - expect![[r#" - Foo Struct FileId(2) 0..41 18..21 - - FileId(1) 20..23 - FileId(1) 47..50 - "#]], - ); - } - - #[test] - fn test_find_all_refs_with_scope() { - let code = r#" - //- /lib.rs - mod foo; - mod bar; - - pub fn quux$0() {} - - //- /foo.rs - fn f() { super::quux(); } - - //- /bar.rs - fn f() { super::quux(); } - "#; - - check_with_scope( - code, - None, - expect![[r#" - quux Function FileId(0) 19..35 26..30 - - FileId(1) 16..20 - FileId(2) 16..20 - "#]], - ); - - check_with_scope( - code, - Some(SearchScope::single_file(FileId(2))), - expect![[r#" - quux Function FileId(0) 19..35 26..30 - - FileId(2) 16..20 - "#]], - ); - } - - #[test] - fn test_find_all_refs_macro_def() { - check( - r#" -#[macro_export] -macro_rules! m1$0 { () => (()) } - -fn foo() { - m1(); - m1(); -} -"#, - expect![[r#" - m1 Macro FileId(0) 0..46 29..31 - - FileId(0) 63..65 - FileId(0) 73..75 - "#]], - ); - } - - #[test] - fn test_basic_highlight_read_write() { - check( - r#" -fn foo() { - let mut i$0 = 0; - i = i + 1; -} -"#, - expect![[r#" - i Local FileId(0) 19..24 23..24 Write - - FileId(0) 34..35 Write - FileId(0) 38..39 Read - "#]], - ); - } - - #[test] - fn test_basic_highlight_field_read_write() { - check( - r#" -struct S { - f: u32, -} - -fn foo() { - let mut s = S{f: 0}; - s.f$0 = 0; -} -"#, - expect![[r#" - f Field FileId(0) 15..21 15..16 - - FileId(0) 55..56 Read - FileId(0) 68..69 Write - "#]], - ); - } - - #[test] - fn test_basic_highlight_decl_no_write() { - check( - r#" -fn foo() { - let i$0; - i = 1; -} -"#, - expect![[r#" - i Local FileId(0) 19..20 19..20 - - FileId(0) 26..27 Write - "#]], - ); - } - - #[test] - fn test_find_struct_function_refs_outside_module() { - check( - r#" -mod foo { - pub struct Foo; - - impl Foo { - pub fn new$0() -> Foo { Foo } - } -} - -fn main() { - let _f = foo::Foo::new(); -} -"#, - expect![[r#" - new Function FileId(0) 54..81 61..64 - - FileId(0) 126..129 - "#]], - ); - } - - #[test] - fn test_find_all_refs_nested_module() { - check( - r#" -//- /lib.rs -mod foo { mod bar; } - -fn f$0() {} - -//- /foo/bar.rs -use crate::f; - -fn g() { f(); } -"#, - expect![[r#" - f Function FileId(0) 22..31 25..26 - - FileId(1) 11..12 - FileId(1) 24..25 - "#]], - ); - } - - #[test] - fn test_find_all_refs_struct_pat() { - check( - r#" -struct S { - field$0: u8, -} - -fn f(s: S) { - match s { - S { field } => {} - } -} -"#, - expect![[r#" - field Field FileId(0) 15..24 15..20 - - FileId(0) 68..73 Read - "#]], - ); - } - - #[test] - fn test_find_all_refs_enum_var_pat() { - check( - r#" -enum En { - Variant { - field$0: u8, - } -} - -fn f(e: En) { - match e { - En::Variant { field } => {} - } -} -"#, - expect![[r#" - field Field FileId(0) 32..41 32..37 - - FileId(0) 102..107 Read - "#]], - ); - } - - #[test] - fn test_find_all_refs_enum_var_privacy() { - check( - r#" -mod m { - pub enum En { - Variant { - field$0: u8, - } - } -} - -fn f() -> m::En { - m::En::Variant { field: 0 } -} -"#, - expect![[r#" - field Field FileId(0) 56..65 56..61 - - FileId(0) 125..130 Read - "#]], - ); - } - - #[test] - fn test_find_self_refs() { - check( - r#" -struct Foo { bar: i32 } - -impl Foo { - fn foo(self) { - let x = self$0.bar; - if true { - let _ = match () { - () => self, - }; - } - } -} -"#, - expect![[r#" - self SelfParam FileId(0) 47..51 47..51 - - FileId(0) 71..75 Read - FileId(0) 152..156 Read - "#]], - ); - } - - #[test] - fn test_find_self_refs_decl() { - check( - r#" -struct Foo { bar: i32 } - -impl Foo { - fn foo(self$0) { - self; - } -} -"#, - expect![[r#" - self SelfParam FileId(0) 47..51 47..51 - - FileId(0) 63..67 Read - "#]], - ); - } - - fn check(ra_fixture: &str, expect: Expect) { - check_with_scope(ra_fixture, None, expect) - } - - fn check_with_scope(ra_fixture: &str, search_scope: Option, expect: Expect) { - let (analysis, pos) = fixture::position(ra_fixture); - let refs = analysis.find_all_refs(pos, search_scope).unwrap().unwrap(); - - let mut actual = String::new(); - for refs in refs { - actual += "\n\n"; - - if let Some(decl) = refs.declaration { - format_to!(actual, "{}", decl.nav.debug_render()); - if decl.is_mut { - format_to!(actual, " {:?}", ReferenceCategory::Write) - } - actual += "\n\n"; - } - - for (file_id, references) in &refs.references { - for (range, access) in references { - format_to!(actual, "{:?} {:?}", file_id, range); - if let Some(access) = access { - format_to!(actual, " {:?}", access); - } - actual += "\n"; - } - } - - if refs.references.is_empty() { - actual += "(no references)\n"; - } - } - expect.assert_eq(actual.trim_start()) - } - - #[test] - fn test_find_lifetimes_function() { - check( - r#" -trait Foo<'a> {} -impl<'a> Foo<'a> for &'a () {} -fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> { - fn bar<'a>(_: &'a ()) {} - x -} -"#, - expect![[r#" - 'a LifetimeParam FileId(0) 55..57 55..57 - - FileId(0) 63..65 - FileId(0) 71..73 - FileId(0) 82..84 - FileId(0) 95..97 - FileId(0) 106..108 - "#]], - ); - } - - #[test] - fn test_find_lifetimes_type_alias() { - check( - r#" -type Foo<'a, T> where T: 'a$0 = &'a T; -"#, - expect![[r#" - 'a LifetimeParam FileId(0) 9..11 9..11 - - FileId(0) 25..27 - FileId(0) 31..33 - "#]], - ); - } - - #[test] - fn test_find_lifetimes_trait_impl() { - check( - r#" -trait Foo<'a> { - fn foo() -> &'a (); -} -impl<'a> Foo<'a> for &'a () { - fn foo() -> &'a$0 () { - unimplemented!() - } -} -"#, - expect![[r#" - 'a LifetimeParam FileId(0) 47..49 47..49 - - FileId(0) 55..57 - FileId(0) 64..66 - FileId(0) 89..91 - "#]], - ); - } - - #[test] - fn test_map_range_to_original() { - check( - r#" -macro_rules! foo {($i:ident) => {$i} } -fn main() { - let a$0 = "test"; - foo!(a); -} -"#, - expect![[r#" - a Local FileId(0) 59..60 59..60 - - FileId(0) 80..81 Read - "#]], - ); - } - - #[test] - fn test_map_range_to_original_ref() { - check( - r#" -macro_rules! foo {($i:ident) => {$i} } -fn main() { - let a = "test"; - foo!(a$0); -} -"#, - expect![[r#" - a Local FileId(0) 59..60 59..60 - - FileId(0) 80..81 Read - "#]], - ); - } - - #[test] - fn test_find_labels() { - check( - r#" -fn foo<'a>() -> &'a () { - 'a: loop { - 'b: loop { - continue 'a$0; - } - break 'a; - } -} -"#, - expect![[r#" - 'a Label FileId(0) 29..32 29..31 - - FileId(0) 80..82 - FileId(0) 108..110 - "#]], - ); - } - - #[test] - fn test_find_const_param() { - check( - r#" -fn foo() -> usize { - FOO -} -"#, - expect![[r#" - FOO ConstParam FileId(0) 7..23 13..16 - - FileId(0) 42..45 - "#]], - ); - } - - #[test] - fn test_trait() { - check( - r#" -trait Foo$0 where Self: {} - -impl Foo for () {} -"#, - expect![[r#" - Foo Trait FileId(0) 0..24 6..9 - - FileId(0) 31..34 - "#]], - ); - } - - #[test] - fn test_trait_self() { - check( - r#" -trait Foo where Self$0 { - fn f() -> Self; -} - -impl Foo for () {} -"#, - expect![[r#" - Self TypeParam FileId(0) 6..9 6..9 - - FileId(0) 16..20 - FileId(0) 37..41 - "#]], - ); - } - - #[test] - fn test_self_ty() { - check( - r#" - struct $0Foo; - - impl Foo where Self: { - fn f() -> Self; - } - "#, - expect![[r#" - Foo Struct FileId(0) 0..11 7..10 - - FileId(0) 18..21 - FileId(0) 28..32 - FileId(0) 50..54 - "#]], - ); - check( - r#" -struct Foo; - -impl Foo where Self: { - fn f() -> Self$0; -} -"#, - expect![[r#" - impl Impl FileId(0) 13..57 18..21 - - FileId(0) 18..21 - FileId(0) 28..32 - FileId(0) 50..54 - "#]], - ); - } - #[test] - fn test_self_variant_with_payload() { - check( - r#" -enum Foo { Bar() } - -impl Foo { - fn foo(self) { - match self { - Self::Bar$0() => (), - } - } -} - -"#, - expect![[r#" - Bar Variant FileId(0) 11..16 11..14 - - FileId(0) 89..92 - "#]], - ); - } - - #[test] - fn test_attr_differs_from_fn_with_same_name() { - check( - r#" -#[test] -fn test$0() { - test(); -} -"#, - expect![[r#" - test Function FileId(0) 0..33 11..15 - - FileId(0) 24..28 - "#]], - ); - } - - #[test] - fn test_const_in_pattern() { - check( - r#" -const A$0: i32 = 42; - -fn main() { - match A { - A => (), - _ => (), - } - if let A = A {} -} -"#, - expect![[r#" - A Const FileId(0) 0..18 6..7 - - FileId(0) 42..43 - FileId(0) 54..55 - FileId(0) 97..98 - FileId(0) 101..102 - "#]], - ); - } - - #[test] - fn test_primitives() { - check( - r#" -fn foo(_: bool) -> bo$0ol { true } -"#, - expect![[r#" - FileId(0) 10..14 - FileId(0) 19..23 - "#]], - ); - } - - #[test] - fn test_transitive() { - check( - r#" -//- /level3.rs new_source_root:local crate:level3 -pub struct Fo$0o; -//- /level2.rs new_source_root:local crate:level2 deps:level3 -pub use level3::Foo; -//- /level1.rs new_source_root:local crate:level1 deps:level2 -pub use level2::Foo; -//- /level0.rs new_source_root:local crate:level0 deps:level1 -pub use level1::Foo; -"#, - expect![[r#" - Foo Struct FileId(0) 0..15 11..14 - - FileId(1) 16..19 - FileId(2) 16..19 - FileId(3) 16..19 - "#]], - ); - } - - #[test] - fn test_decl_macro_references() { - check( - r#" -//- /lib.rs crate:lib -#[macro_use] -mod qux; -mod bar; - -pub use self::foo; -//- /qux.rs -#[macro_export] -macro_rules! foo$0 { - () => {struct Foo;}; -} -//- /bar.rs -foo!(); -//- /other.rs crate:other deps:lib new_source_root:local -lib::foo!(); -"#, - expect![[r#" - foo Macro FileId(1) 0..61 29..32 - - FileId(0) 46..49 - FileId(2) 0..3 - FileId(3) 5..8 - "#]], - ); - } - - #[test] - fn macro_doesnt_reference_attribute_on_call() { - check( - r#" -macro_rules! m { - () => {}; -} - -#[proc_macro_test::attr_noop] -m$0!(); - -"#, - expect![[r#" - m Macro FileId(0) 0..32 13..14 - - FileId(0) 64..65 - "#]], - ); - } - - #[test] - fn multi_def() { - check( - r#" -macro_rules! m { - ($name:ident) => { - mod module { - pub fn $name() {} - } - - pub fn $name() {} - } -} - -m!(func$0); - -fn f() { - func(); - module::func(); -} - "#, - expect![[r#" - func Function FileId(0) 137..146 140..144 - - FileId(0) 161..165 - - - func Function FileId(0) 137..146 140..144 - - FileId(0) 181..185 - "#]], - ) - } - - #[test] - fn attr_expanded() { - check( - r#" -//- proc_macros: identity -#[proc_macros::identity] -fn func$0() { - func(); -} -"#, - expect![[r#" - func Function FileId(0) 25..50 28..32 - - FileId(0) 41..45 - "#]], - ) - } - - #[test] - fn attr_assoc_item() { - check( - r#" -//- proc_macros: identity - -trait Trait { - #[proc_macros::identity] - fn func() { - Self::func$0(); - } -} -"#, - expect![[r#" - func Function FileId(0) 48..87 51..55 - - FileId(0) 74..78 - "#]], - ) - } - - // FIXME: import is classified as function - #[test] - fn attr() { - check( - r#" -//- proc_macros: identity -use proc_macros::identity; - -#[proc_macros::$0identity] -fn func() {} -"#, - expect![[r#" - identity Attribute FileId(1) 1..107 32..40 - - FileId(0) 43..51 - "#]], - ); - check( - r#" -#![crate_type="proc-macro"] -#[proc_macro_attribute] -fn func$0() {} -"#, - expect![[r#" - func Attribute FileId(0) 28..64 55..59 - - (no references) - "#]], - ); - } - - // FIXME: import is classified as function - #[test] - fn proc_macro() { - check( - r#" -//- proc_macros: mirror -use proc_macros::mirror; - -mirror$0! {} -"#, - expect![[r#" - mirror Macro FileId(1) 1..77 22..28 - - FileId(0) 26..32 - "#]], - ) - } - - #[test] - fn derive() { - check( - r#" -//- proc_macros: derive_identity -//- minicore: derive -use proc_macros::DeriveIdentity; - -#[derive(proc_macros::DeriveIdentity$0)] -struct Foo; -"#, - expect![[r#" - derive_identity Derive FileId(2) 1..107 45..60 - - FileId(0) 17..31 - FileId(0) 56..70 - "#]], - ); - check( - r#" -#![crate_type="proc-macro"] -#[proc_macro_derive(Derive, attributes(x))] -pub fn deri$0ve(_stream: TokenStream) -> TokenStream {} -"#, - expect![[r#" - derive Derive FileId(0) 28..125 79..85 - - (no references) - "#]], - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs deleted file mode 100644 index fe44856dcad2a..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ /dev/null @@ -1,2252 +0,0 @@ -//! Renaming functionality. -//! -//! This is mostly front-end for [`ide_db::rename`], but it also includes the -//! tests. This module also implements a couple of magic tricks, like renaming -//! `self` and to `self` (to switch between associated function and method). - -use hir::{AsAssocItem, InFile, Semantics}; -use ide_db::{ - base_db::FileId, - defs::{Definition, NameClass, NameRefClass}, - rename::{bail, format_err, source_edit_from_references, IdentifierKind}, - RootDatabase, -}; -use itertools::Itertools; -use stdx::{always, never}; -use syntax::{ast, AstNode, SyntaxNode}; - -use text_edit::TextEdit; - -use crate::{FilePosition, RangeInfo, SourceChange}; - -pub use ide_db::rename::RenameError; - -type RenameResult = Result; - -/// Prepares a rename. The sole job of this function is to return the TextRange of the thing that is -/// being targeted for a rename. -pub(crate) fn prepare_rename( - db: &RootDatabase, - position: FilePosition, -) -> RenameResult> { - let sema = Semantics::new(db); - let source_file = sema.parse(position.file_id); - let syntax = source_file.syntax(); - - let res = find_definitions(&sema, syntax, position)? - .map(|(name_like, def)| { - // ensure all ranges are valid - - if def.range_for_rename(&sema).is_none() { - bail!("No references found at position") - } - let frange = sema.original_range(name_like.syntax()); - - always!( - frange.range.contains_inclusive(position.offset) - && frange.file_id == position.file_id - ); - Ok(frange.range) - }) - .reduce(|acc, cur| match (acc, cur) { - // ensure all ranges are the same - (Ok(acc_inner), Ok(cur_inner)) if acc_inner == cur_inner => Ok(acc_inner), - (Err(e), _) => Err(e), - _ => bail!("inconsistent text range"), - }); - - match res { - // ensure at least one definition was found - Some(res) => res.map(|range| RangeInfo::new(range, ())), - None => bail!("No references found at position"), - } -} - -// Feature: Rename -// -// Renames the item below the cursor and all of its references -// -// |=== -// | Editor | Shortcut -// -// | VS Code | kbd:[F2] -// |=== -// -// image::https://user-images.githubusercontent.com/48062697/113065582-055aae80-91b1-11eb-8ade-2b58e6d81883.gif[] -pub(crate) fn rename( - db: &RootDatabase, - position: FilePosition, - new_name: &str, -) -> RenameResult { - let sema = Semantics::new(db); - let source_file = sema.parse(position.file_id); - let syntax = source_file.syntax(); - - let defs = find_definitions(&sema, syntax, position)?; - - let ops: RenameResult> = defs - .map(|(_namelike, def)| { - if let Definition::Local(local) = def { - if let Some(self_param) = local.as_self_param(sema.db) { - cov_mark::hit!(rename_self_to_param); - return rename_self_to_param(&sema, local, self_param, new_name); - } - if new_name == "self" { - cov_mark::hit!(rename_to_self); - return rename_to_self(&sema, local); - } - } - def.rename(&sema, new_name) - }) - .collect(); - - ops?.into_iter() - .reduce(|acc, elem| acc.merge(elem)) - .ok_or_else(|| format_err!("No references found at position")) -} - -/// Called by the client when it is about to rename a file. -pub(crate) fn will_rename_file( - db: &RootDatabase, - file_id: FileId, - new_name_stem: &str, -) -> Option { - let sema = Semantics::new(db); - let module = sema.to_module_def(file_id)?; - let def = Definition::Module(module); - let mut change = def.rename(&sema, new_name_stem).ok()?; - change.file_system_edits.clear(); - Some(change) -} - -fn find_definitions( - sema: &Semantics<'_, RootDatabase>, - syntax: &SyntaxNode, - position: FilePosition, -) -> RenameResult> { - let symbols = sema - .find_nodes_at_offset_with_descend::(syntax, position.offset) - .map(|name_like| { - let res = match &name_like { - // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet - ast::NameLike::Name(name) - if name - .syntax() - .parent() - .map_or(false, |it| ast::Rename::can_cast(it.kind())) => - { - bail!("Renaming aliases is currently unsupported") - } - ast::NameLike::Name(name) => NameClass::classify(sema, name) - .map(|class| match class { - NameClass::Definition(it) | NameClass::ConstReference(it) => it, - NameClass::PatFieldShorthand { local_def, field_ref: _ } => { - Definition::Local(local_def) - } - }) - .map(|def| (name_like.clone(), def)) - .ok_or_else(|| format_err!("No references found at position")), - ast::NameLike::NameRef(name_ref) => { - NameRefClass::classify(sema, name_ref) - .map(|class| match class { - NameRefClass::Definition(def) => def, - NameRefClass::FieldShorthand { local_ref, field_ref: _ } => { - Definition::Local(local_ref) - } - }) - .ok_or_else(|| format_err!("No references found at position")) - .and_then(|def| { - // if the name differs from the definitions name it has to be an alias - if def - .name(sema.db) - .map_or(false, |it| it.to_smol_str() != name_ref.text().as_str()) - { - Err(format_err!("Renaming aliases is currently unsupported")) - } else { - Ok((name_like.clone(), def)) - } - }) - } - ast::NameLike::Lifetime(lifetime) => { - NameRefClass::classify_lifetime(sema, lifetime) - .and_then(|class| match class { - NameRefClass::Definition(def) => Some(def), - _ => None, - }) - .or_else(|| { - NameClass::classify_lifetime(sema, lifetime).and_then(|it| match it { - NameClass::Definition(it) => Some(it), - _ => None, - }) - }) - .map(|def| (name_like, def)) - .ok_or_else(|| format_err!("No references found at position")) - } - }; - res - }); - - let res: RenameResult> = symbols.collect(); - match res { - Ok(v) => { - if v.is_empty() { - // FIXME: some semantic duplication between "empty vec" and "Err()" - Err(format_err!("No references found at position")) - } else { - // remove duplicates, comparing `Definition`s - Ok(v.into_iter().unique_by(|t| t.1)) - } - } - Err(e) => Err(e), - } -} - -fn rename_to_self( - sema: &Semantics<'_, RootDatabase>, - local: hir::Local, -) -> RenameResult { - if never!(local.is_self(sema.db)) { - bail!("rename_to_self invoked on self"); - } - - let fn_def = match local.parent(sema.db) { - hir::DefWithBody::Function(func) => func, - _ => bail!("Cannot rename local to self outside of function"), - }; - - if fn_def.self_param(sema.db).is_some() { - bail!("Method already has a self parameter"); - } - - let params = fn_def.assoc_fn_params(sema.db); - let first_param = params - .first() - .ok_or_else(|| format_err!("Cannot rename local to self unless it is a parameter"))?; - match first_param.as_local(sema.db) { - Some(plocal) => { - if plocal != local { - bail!("Only the first parameter may be renamed to self"); - } - } - None => bail!("rename_to_self invoked on destructuring parameter"), - } - - let assoc_item = fn_def - .as_assoc_item(sema.db) - .ok_or_else(|| format_err!("Cannot rename parameter to self for free function"))?; - let impl_ = match assoc_item.container(sema.db) { - hir::AssocItemContainer::Trait(_) => { - bail!("Cannot rename parameter to self for trait functions"); - } - hir::AssocItemContainer::Impl(impl_) => impl_, - }; - let first_param_ty = first_param.ty(); - let impl_ty = impl_.self_ty(sema.db); - let (ty, self_param) = if impl_ty.remove_ref().is_some() { - // if the impl is a ref to the type we can just match the `&T` with self directly - (first_param_ty.clone(), "self") - } else { - first_param_ty.remove_ref().map_or((first_param_ty.clone(), "self"), |ty| { - (ty, if first_param_ty.is_mutable_reference() { "&mut self" } else { "&self" }) - }) - }; - - if ty != impl_ty { - bail!("Parameter type differs from impl block type"); - } - - let InFile { file_id, value: param_source } = - first_param.source(sema.db).ok_or_else(|| format_err!("No source for parameter found"))?; - - let def = Definition::Local(local); - let usages = def.usages(sema).all(); - let mut source_change = SourceChange::default(); - source_change.extend(usages.iter().map(|(&file_id, references)| { - (file_id, source_edit_from_references(references, def, "self")) - })); - source_change.insert_source_edit( - file_id.original_file(sema.db), - TextEdit::replace(param_source.syntax().text_range(), String::from(self_param)), - ); - Ok(source_change) -} - -fn rename_self_to_param( - sema: &Semantics<'_, RootDatabase>, - local: hir::Local, - self_param: hir::SelfParam, - new_name: &str, -) -> RenameResult { - if new_name == "self" { - // Let's do nothing rather than complain. - cov_mark::hit!(rename_self_to_self); - return Ok(SourceChange::default()); - } - - let identifier_kind = IdentifierKind::classify(new_name)?; - - let InFile { file_id, value: self_param } = - self_param.source(sema.db).ok_or_else(|| format_err!("cannot find function source"))?; - - let def = Definition::Local(local); - let usages = def.usages(sema).all(); - let edit = text_edit_from_self_param(&self_param, new_name) - .ok_or_else(|| format_err!("No target type found"))?; - if usages.len() > 1 && identifier_kind == IdentifierKind::Underscore { - bail!("Cannot rename reference to `_` as it is being referenced multiple times"); - } - let mut source_change = SourceChange::default(); - source_change.insert_source_edit(file_id.original_file(sema.db), edit); - source_change.extend(usages.iter().map(|(&file_id, references)| { - (file_id, source_edit_from_references(references, def, new_name)) - })); - Ok(source_change) -} - -fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Option { - fn target_type_name(impl_def: &ast::Impl) -> Option { - if let Some(ast::Type::PathType(p)) = impl_def.self_ty() { - return Some(p.path()?.segment()?.name_ref()?.text().to_string()); - } - None - } - - let impl_def = self_param.syntax().ancestors().find_map(ast::Impl::cast)?; - let type_name = target_type_name(&impl_def)?; - - let mut replacement_text = String::from(new_name); - replacement_text.push_str(": "); - match (self_param.amp_token(), self_param.mut_token()) { - (Some(_), None) => replacement_text.push('&'), - (Some(_), Some(_)) => replacement_text.push_str("&mut "), - (_, _) => (), - }; - replacement_text.push_str(type_name.as_str()); - - Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text)) -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - use stdx::trim_indent; - use test_utils::assert_eq_text; - use text_edit::TextEdit; - - use crate::{fixture, FileId}; - - use super::{RangeInfo, RenameError}; - - #[track_caller] - fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) { - let ra_fixture_after = &trim_indent(ra_fixture_after); - let (analysis, position) = fixture::position(ra_fixture_before); - let rename_result = analysis - .rename(position, new_name) - .unwrap_or_else(|err| panic!("Rename to '{}' was cancelled: {}", new_name, err)); - match rename_result { - Ok(source_change) => { - let mut text_edit_builder = TextEdit::builder(); - let mut file_id: Option = None; - for edit in source_change.source_file_edits { - file_id = Some(edit.0); - for indel in edit.1.into_iter() { - text_edit_builder.replace(indel.delete, indel.insert); - } - } - if let Some(file_id) = file_id { - let mut result = analysis.file_text(file_id).unwrap().to_string(); - text_edit_builder.finish().apply(&mut result); - assert_eq_text!(ra_fixture_after, &*result); - } - } - Err(err) => { - if ra_fixture_after.starts_with("error:") { - let error_message = ra_fixture_after - .chars() - .into_iter() - .skip("error:".len()) - .collect::(); - assert_eq!(error_message.trim(), err.to_string()); - } else { - panic!("Rename to '{}' failed unexpectedly: {}", new_name, err) - } - } - }; - } - - fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) { - let (analysis, position) = fixture::position(ra_fixture); - let source_change = - analysis.rename(position, new_name).unwrap().expect("Expect returned a RenameError"); - expect.assert_debug_eq(&source_change) - } - - fn check_expect_will_rename_file(new_name: &str, ra_fixture: &str, expect: Expect) { - let (analysis, position) = fixture::position(ra_fixture); - let source_change = analysis - .will_rename_file(position.file_id, new_name) - .unwrap() - .expect("Expect returned a RenameError"); - expect.assert_debug_eq(&source_change) - } - - fn check_prepare(ra_fixture: &str, expect: Expect) { - let (analysis, position) = fixture::position(ra_fixture); - let result = analysis - .prepare_rename(position) - .unwrap_or_else(|err| panic!("PrepareRename was cancelled: {}", err)); - match result { - Ok(RangeInfo { range, info: () }) => { - let source = analysis.file_text(position.file_id).unwrap(); - expect.assert_eq(&format!("{:?}: {}", range, &source[range])) - } - Err(RenameError(err)) => expect.assert_eq(&err), - }; - } - - #[test] - fn test_prepare_rename_namelikes() { - check_prepare(r"fn name$0<'lifetime>() {}", expect![[r#"3..7: name"#]]); - check_prepare(r"fn name<'lifetime$0>() {}", expect![[r#"8..17: 'lifetime"#]]); - check_prepare(r"fn name<'lifetime>() { name$0(); }", expect![[r#"23..27: name"#]]); - } - - #[test] - fn test_prepare_rename_in_macro() { - check_prepare( - r"macro_rules! foo { - ($ident:ident) => { - pub struct $ident; - } -} -foo!(Foo$0);", - expect![[r#"83..86: Foo"#]], - ); - } - - #[test] - fn test_prepare_rename_keyword() { - check_prepare(r"struct$0 Foo;", expect![[r#"No references found at position"#]]); - } - - #[test] - fn test_prepare_rename_tuple_field() { - check_prepare( - r#" -struct Foo(i32); - -fn baz() { - let mut x = Foo(4); - x.0$0 = 5; -} -"#, - expect![[r#"No references found at position"#]], - ); - } - - #[test] - fn test_prepare_rename_builtin() { - check_prepare( - r#" -fn foo() { - let x: i32$0 = 0; -} -"#, - expect![[r#"No references found at position"#]], - ); - } - - #[test] - fn test_prepare_rename_self() { - check_prepare( - r#" -struct Foo {} - -impl Foo { - fn foo(self) -> Self$0 { - self - } -} -"#, - expect![[r#"No references found at position"#]], - ); - } - - #[test] - fn test_rename_to_underscore() { - check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#); - } - - #[test] - fn test_rename_to_raw_identifier() { - check("r#fn", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let r#fn = 1; }"#); - } - - #[test] - fn test_rename_to_invalid_identifier1() { - check( - "invalid!", - r#"fn main() { let i$0 = 1; }"#, - "error: Invalid name `invalid!`: not an identifier", - ); - } - - #[test] - fn test_rename_to_invalid_identifier2() { - check( - "multiple tokens", - r#"fn main() { let i$0 = 1; }"#, - "error: Invalid name `multiple tokens`: not an identifier", - ); - } - - #[test] - fn test_rename_to_invalid_identifier3() { - check( - "let", - r#"fn main() { let i$0 = 1; }"#, - "error: Invalid name `let`: not an identifier", - ); - } - - #[test] - fn test_rename_to_invalid_identifier_lifetime() { - cov_mark::check!(rename_not_an_ident_ref); - check( - "'foo", - r#"fn main() { let i$0 = 1; }"#, - "error: Invalid name `'foo`: not an identifier", - ); - } - - #[test] - fn test_rename_to_invalid_identifier_lifetime2() { - cov_mark::check!(rename_not_a_lifetime_ident_ref); - check( - "foo", - r#"fn main<'a>(_: &'a$0 ()) {}"#, - "error: Invalid name `foo`: not a lifetime identifier", - ); - } - - #[test] - fn test_rename_to_underscore_invalid() { - cov_mark::check!(rename_underscore_multiple); - check( - "_", - r#"fn main(foo$0: ()) {foo;}"#, - "error: Cannot rename reference to `_` as it is being referenced multiple times", - ); - } - - #[test] - fn test_rename_mod_invalid() { - check( - "'foo", - r#"mod foo$0 {}"#, - "error: Invalid name `'foo`: cannot rename module to 'foo", - ); - } - - #[test] - fn test_rename_for_local() { - check( - "k", - r#" -fn main() { - let mut i = 1; - let j = 1; - i = i$0 + j; - - { i = 0; } - - i = 5; -} -"#, - r#" -fn main() { - let mut k = 1; - let j = 1; - k = k + j; - - { k = 0; } - - k = 5; -} -"#, - ); - } - - #[test] - fn test_rename_unresolved_reference() { - check( - "new_name", - r#"fn main() { let _ = unresolved_ref$0; }"#, - "error: No references found at position", - ); - } - - #[test] - fn test_rename_macro_multiple_occurrences() { - check( - "Baaah", - r#"macro_rules! foo { - ($ident:ident) => { - const $ident: () = (); - struct $ident {} - }; -} - -foo!($0Foo); -const _: () = Foo; -const _: Foo = Foo {}; - "#, - r#" -macro_rules! foo { - ($ident:ident) => { - const $ident: () = (); - struct $ident {} - }; -} - -foo!(Baaah); -const _: () = Baaah; -const _: Baaah = Baaah {}; - "#, - ) - } - - #[test] - fn test_rename_for_macro_args() { - check( - "b", - r#" -macro_rules! foo {($i:ident) => {$i} } -fn main() { - let a$0 = "test"; - foo!(a); -} -"#, - r#" -macro_rules! foo {($i:ident) => {$i} } -fn main() { - let b = "test"; - foo!(b); -} -"#, - ); - } - - #[test] - fn test_rename_for_macro_args_rev() { - check( - "b", - r#" -macro_rules! foo {($i:ident) => {$i} } -fn main() { - let a = "test"; - foo!(a$0); -} -"#, - r#" -macro_rules! foo {($i:ident) => {$i} } -fn main() { - let b = "test"; - foo!(b); -} -"#, - ); - } - - #[test] - fn test_rename_for_macro_define_fn() { - check( - "bar", - r#" -macro_rules! define_fn {($id:ident) => { fn $id{} }} -define_fn!(foo); -fn main() { - fo$0o(); -} -"#, - r#" -macro_rules! define_fn {($id:ident) => { fn $id{} }} -define_fn!(bar); -fn main() { - bar(); -} -"#, - ); - } - - #[test] - fn test_rename_for_macro_define_fn_rev() { - check( - "bar", - r#" -macro_rules! define_fn {($id:ident) => { fn $id{} }} -define_fn!(fo$0o); -fn main() { - foo(); -} -"#, - r#" -macro_rules! define_fn {($id:ident) => { fn $id{} }} -define_fn!(bar); -fn main() { - bar(); -} -"#, - ); - } - - #[test] - fn test_rename_for_param_inside() { - check("j", r#"fn foo(i : u32) -> u32 { i$0 }"#, r#"fn foo(j : u32) -> u32 { j }"#); - } - - #[test] - fn test_rename_refs_for_fn_param() { - check("j", r#"fn foo(i$0 : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#); - } - - #[test] - fn test_rename_for_mut_param() { - check("j", r#"fn foo(mut i$0 : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#); - } - - #[test] - fn test_rename_struct_field() { - check( - "foo", - r#" -struct Foo { field$0: i32 } - -impl Foo { - fn new(i: i32) -> Self { - Self { field: i } - } -} -"#, - r#" -struct Foo { foo: i32 } - -impl Foo { - fn new(i: i32) -> Self { - Self { foo: i } - } -} -"#, - ); - } - - #[test] - fn test_rename_field_in_field_shorthand() { - cov_mark::check!(test_rename_field_in_field_shorthand); - check( - "field", - r#" -struct Foo { foo$0: i32 } - -impl Foo { - fn new(foo: i32) -> Self { - Self { foo } - } -} -"#, - r#" -struct Foo { field: i32 } - -impl Foo { - fn new(foo: i32) -> Self { - Self { field: foo } - } -} -"#, - ); - } - - #[test] - fn test_rename_local_in_field_shorthand() { - cov_mark::check!(test_rename_local_in_field_shorthand); - check( - "j", - r#" -struct Foo { i: i32 } - -impl Foo { - fn new(i$0: i32) -> Self { - Self { i } - } -} -"#, - r#" -struct Foo { i: i32 } - -impl Foo { - fn new(j: i32) -> Self { - Self { i: j } - } -} -"#, - ); - } - - #[test] - fn test_field_shorthand_correct_struct() { - check( - "j", - r#" -struct Foo { i$0: i32 } -struct Bar { i: i32 } - -impl Bar { - fn new(i: i32) -> Self { - Self { i } - } -} -"#, - r#" -struct Foo { j: i32 } -struct Bar { i: i32 } - -impl Bar { - fn new(i: i32) -> Self { - Self { i } - } -} -"#, - ); - } - - #[test] - fn test_shadow_local_for_struct_shorthand() { - check( - "j", - r#" -struct Foo { i: i32 } - -fn baz(i$0: i32) -> Self { - let x = Foo { i }; - { - let i = 0; - Foo { i } - } -} -"#, - r#" -struct Foo { i: i32 } - -fn baz(j: i32) -> Self { - let x = Foo { i: j }; - { - let i = 0; - Foo { i } - } -} -"#, - ); - } - - #[test] - fn test_rename_mod() { - check_expect( - "foo2", - r#" -//- /lib.rs -mod bar; - -//- /bar.rs -mod foo$0; - -//- /bar/foo.rs -// empty -"#, - expect![[r#" - SourceChange { - source_file_edits: { - FileId( - 1, - ): TextEdit { - indels: [ - Indel { - insert: "foo2", - delete: 4..7, - }, - ], - }, - }, - file_system_edits: [ - MoveFile { - src: FileId( - 2, - ), - dst: AnchoredPathBuf { - anchor: FileId( - 2, - ), - path: "foo2.rs", - }, - }, - ], - is_snippet: false, - } - "#]], - ); - } - - #[test] - fn test_rename_mod_in_use_tree() { - check_expect( - "quux", - r#" -//- /main.rs -pub mod foo; -pub mod bar; -fn main() {} - -//- /foo.rs -pub struct FooContent; - -//- /bar.rs -use crate::foo$0::FooContent; -"#, - expect![[r#" - SourceChange { - source_file_edits: { - FileId( - 0, - ): TextEdit { - indels: [ - Indel { - insert: "quux", - delete: 8..11, - }, - ], - }, - FileId( - 2, - ): TextEdit { - indels: [ - Indel { - insert: "quux", - delete: 11..14, - }, - ], - }, - }, - file_system_edits: [ - MoveFile { - src: FileId( - 1, - ), - dst: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "quux.rs", - }, - }, - ], - is_snippet: false, - } - "#]], - ); - } - - #[test] - fn test_rename_mod_in_dir() { - check_expect( - "foo2", - r#" -//- /lib.rs -mod fo$0o; -//- /foo/mod.rs -// empty -"#, - expect![[r#" - SourceChange { - source_file_edits: { - FileId( - 0, - ): TextEdit { - indels: [ - Indel { - insert: "foo2", - delete: 4..7, - }, - ], - }, - }, - file_system_edits: [ - MoveDir { - src: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "../foo", - }, - src_id: FileId( - 1, - ), - dst: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "../foo2", - }, - }, - ], - is_snippet: false, - } - "#]], - ); - } - - #[test] - fn test_rename_unusually_nested_mod() { - check_expect( - "bar", - r#" -//- /lib.rs -mod outer { mod fo$0o; } - -//- /outer/foo.rs -// empty -"#, - expect![[r#" - SourceChange { - source_file_edits: { - FileId( - 0, - ): TextEdit { - indels: [ - Indel { - insert: "bar", - delete: 16..19, - }, - ], - }, - }, - file_system_edits: [ - MoveFile { - src: FileId( - 1, - ), - dst: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "bar.rs", - }, - }, - ], - is_snippet: false, - } - "#]], - ); - } - - #[test] - fn test_module_rename_in_path() { - check( - "baz", - r#" -mod $0foo { - pub use self::bar as qux; - pub fn bar() {} -} - -fn main() { foo::bar(); } -"#, - r#" -mod baz { - pub use self::bar as qux; - pub fn bar() {} -} - -fn main() { baz::bar(); } -"#, - ); - } - - #[test] - fn test_rename_mod_filename_and_path() { - check_expect( - "foo2", - r#" -//- /lib.rs -mod bar; -fn f() { - bar::foo::fun() -} - -//- /bar.rs -pub mod foo$0; - -//- /bar/foo.rs -// pub fn fun() {} -"#, - expect![[r#" - SourceChange { - source_file_edits: { - FileId( - 0, - ): TextEdit { - indels: [ - Indel { - insert: "foo2", - delete: 27..30, - }, - ], - }, - FileId( - 1, - ): TextEdit { - indels: [ - Indel { - insert: "foo2", - delete: 8..11, - }, - ], - }, - }, - file_system_edits: [ - MoveFile { - src: FileId( - 2, - ), - dst: AnchoredPathBuf { - anchor: FileId( - 2, - ), - path: "foo2.rs", - }, - }, - ], - is_snippet: false, - } - "#]], - ); - } - - #[test] - fn test_rename_mod_recursive() { - check_expect( - "foo2", - r#" -//- /lib.rs -mod foo$0; - -//- /foo.rs -mod bar; -mod corge; - -//- /foo/bar.rs -mod qux; - -//- /foo/bar/qux.rs -mod quux; - -//- /foo/bar/qux/quux/mod.rs -// empty - -//- /foo/corge.rs -// empty -"#, - expect![[r#" - SourceChange { - source_file_edits: { - FileId( - 0, - ): TextEdit { - indels: [ - Indel { - insert: "foo2", - delete: 4..7, - }, - ], - }, - }, - file_system_edits: [ - MoveFile { - src: FileId( - 1, - ), - dst: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "foo2.rs", - }, - }, - MoveDir { - src: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "foo", - }, - src_id: FileId( - 1, - ), - dst: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "foo2", - }, - }, - ], - is_snippet: false, - } - "#]], - ) - } - #[test] - fn test_rename_mod_ref_by_super() { - check( - "baz", - r#" - mod $0foo { - struct X; - - mod bar { - use super::X; - } - } - "#, - r#" - mod baz { - struct X; - - mod bar { - use super::X; - } - } - "#, - ) - } - - #[test] - fn test_rename_mod_in_macro() { - check( - "bar", - r#" -//- /foo.rs - -//- /lib.rs -macro_rules! submodule { - ($name:ident) => { - mod $name; - }; -} - -submodule!($0foo); -"#, - r#" -macro_rules! submodule { - ($name:ident) => { - mod $name; - }; -} - -submodule!(bar); -"#, - ) - } - - #[test] - fn test_rename_mod_for_crate_root() { - check_expect_will_rename_file( - "main", - r#" -//- /lib.rs -use crate::foo as bar; -fn foo() {} -mod bar$0; -"#, - expect![[r#" - SourceChange { - source_file_edits: {}, - file_system_edits: [], - is_snippet: false, - } - "#]], - ) - } - - #[test] - fn test_enum_variant_from_module_1() { - cov_mark::check!(rename_non_local); - check( - "Baz", - r#" -mod foo { - pub enum Foo { Bar$0 } -} - -fn func(f: foo::Foo) { - match f { - foo::Foo::Bar => {} - } -} -"#, - r#" -mod foo { - pub enum Foo { Baz } -} - -fn func(f: foo::Foo) { - match f { - foo::Foo::Baz => {} - } -} -"#, - ); - } - - #[test] - fn test_enum_variant_from_module_2() { - check( - "baz", - r#" -mod foo { - pub struct Foo { pub bar$0: uint } -} - -fn foo(f: foo::Foo) { - let _ = f.bar; -} -"#, - r#" -mod foo { - pub struct Foo { pub baz: uint } -} - -fn foo(f: foo::Foo) { - let _ = f.baz; -} -"#, - ); - } - - #[test] - fn test_parameter_to_self() { - cov_mark::check!(rename_to_self); - check( - "self", - r#" -struct Foo { i: i32 } - -impl Foo { - fn f(foo$0: &mut Foo) -> i32 { - foo.i - } -} -"#, - r#" -struct Foo { i: i32 } - -impl Foo { - fn f(&mut self) -> i32 { - self.i - } -} -"#, - ); - check( - "self", - r#" -struct Foo { i: i32 } - -impl Foo { - fn f(foo$0: Foo) -> i32 { - foo.i - } -} -"#, - r#" -struct Foo { i: i32 } - -impl Foo { - fn f(self) -> i32 { - self.i - } -} -"#, - ); - } - - #[test] - fn test_parameter_to_self_error_no_impl() { - check( - "self", - r#" -struct Foo { i: i32 } - -fn f(foo$0: &mut Foo) -> i32 { - foo.i -} -"#, - "error: Cannot rename parameter to self for free function", - ); - check( - "self", - r#" -struct Foo { i: i32 } -struct Bar; - -impl Bar { - fn f(foo$0: &mut Foo) -> i32 { - foo.i - } -} -"#, - "error: Parameter type differs from impl block type", - ); - } - - #[test] - fn test_parameter_to_self_error_not_first() { - check( - "self", - r#" -struct Foo { i: i32 } -impl Foo { - fn f(x: (), foo$0: &mut Foo) -> i32 { - foo.i - } -} -"#, - "error: Only the first parameter may be renamed to self", - ); - } - - #[test] - fn test_parameter_to_self_impl_ref() { - check( - "self", - r#" -struct Foo { i: i32 } -impl &Foo { - fn f(foo$0: &Foo) -> i32 { - foo.i - } -} -"#, - r#" -struct Foo { i: i32 } -impl &Foo { - fn f(self) -> i32 { - self.i - } -} -"#, - ); - } - - #[test] - fn test_self_to_parameter() { - check( - "foo", - r#" -struct Foo { i: i32 } - -impl Foo { - fn f(&mut $0self) -> i32 { - self.i - } -} -"#, - r#" -struct Foo { i: i32 } - -impl Foo { - fn f(foo: &mut Foo) -> i32 { - foo.i - } -} -"#, - ); - } - - #[test] - fn test_owned_self_to_parameter() { - cov_mark::check!(rename_self_to_param); - check( - "foo", - r#" -struct Foo { i: i32 } - -impl Foo { - fn f($0self) -> i32 { - self.i - } -} -"#, - r#" -struct Foo { i: i32 } - -impl Foo { - fn f(foo: Foo) -> i32 { - foo.i - } -} -"#, - ); - } - - #[test] - fn test_self_in_path_to_parameter() { - check( - "foo", - r#" -struct Foo { i: i32 } - -impl Foo { - fn f(&self) -> i32 { - let self_var = 1; - self$0.i - } -} -"#, - r#" -struct Foo { i: i32 } - -impl Foo { - fn f(foo: &Foo) -> i32 { - let self_var = 1; - foo.i - } -} -"#, - ); - } - - #[test] - fn test_rename_field_put_init_shorthand() { - cov_mark::check!(test_rename_field_put_init_shorthand); - check( - "bar", - r#" -struct Foo { i$0: i32 } - -fn foo(bar: i32) -> Foo { - Foo { i: bar } -} -"#, - r#" -struct Foo { bar: i32 } - -fn foo(bar: i32) -> Foo { - Foo { bar } -} -"#, - ); - } - - #[test] - fn test_rename_local_put_init_shorthand() { - cov_mark::check!(test_rename_local_put_init_shorthand); - check( - "i", - r#" -struct Foo { i: i32 } - -fn foo(bar$0: i32) -> Foo { - Foo { i: bar } -} -"#, - r#" -struct Foo { i: i32 } - -fn foo(i: i32) -> Foo { - Foo { i } -} -"#, - ); - } - - #[test] - fn test_struct_field_pat_into_shorthand() { - cov_mark::check!(test_rename_field_put_init_shorthand_pat); - check( - "baz", - r#" -struct Foo { i$0: i32 } - -fn foo(foo: Foo) { - let Foo { i: ref baz @ qux } = foo; - let _ = qux; -} -"#, - r#" -struct Foo { baz: i32 } - -fn foo(foo: Foo) { - let Foo { baz: ref baz @ qux } = foo; - let _ = qux; -} -"#, - ); - check( - "baz", - r#" -struct Foo { i$0: i32 } - -fn foo(foo: Foo) { - let Foo { i: ref baz } = foo; - let _ = qux; -} -"#, - r#" -struct Foo { baz: i32 } - -fn foo(foo: Foo) { - let Foo { ref baz } = foo; - let _ = qux; -} -"#, - ); - } - - #[test] - fn test_struct_local_pat_into_shorthand() { - cov_mark::check!(test_rename_local_put_init_shorthand_pat); - check( - "field", - r#" -struct Foo { field: i32 } - -fn foo(foo: Foo) { - let Foo { field: qux$0 } = foo; - let _ = qux; -} -"#, - r#" -struct Foo { field: i32 } - -fn foo(foo: Foo) { - let Foo { field } = foo; - let _ = field; -} -"#, - ); - check( - "field", - r#" -struct Foo { field: i32 } - -fn foo(foo: Foo) { - let Foo { field: x @ qux$0 } = foo; - let _ = qux; -} -"#, - r#" -struct Foo { field: i32 } - -fn foo(foo: Foo) { - let Foo { field: x @ field } = foo; - let _ = field; -} -"#, - ); - } - - #[test] - fn test_rename_binding_in_destructure_pat() { - let expected_fixture = r#" -struct Foo { - i: i32, -} - -fn foo(foo: Foo) { - let Foo { i: bar } = foo; - let _ = bar; -} -"#; - check( - "bar", - r#" -struct Foo { - i: i32, -} - -fn foo(foo: Foo) { - let Foo { i: b } = foo; - let _ = b$0; -} -"#, - expected_fixture, - ); - check( - "bar", - r#" -struct Foo { - i: i32, -} - -fn foo(foo: Foo) { - let Foo { i } = foo; - let _ = i$0; -} -"#, - expected_fixture, - ); - } - - #[test] - fn test_rename_binding_in_destructure_param_pat() { - check( - "bar", - r#" -struct Foo { - i: i32 -} - -fn foo(Foo { i }: Foo) -> i32 { - i$0 -} -"#, - r#" -struct Foo { - i: i32 -} - -fn foo(Foo { i: bar }: Foo) -> i32 { - bar -} -"#, - ) - } - - #[test] - fn test_struct_field_complex_ident_pat() { - cov_mark::check!(rename_record_pat_field_name_split); - check( - "baz", - r#" -struct Foo { i$0: i32 } - -fn foo(foo: Foo) { - let Foo { ref i } = foo; -} -"#, - r#" -struct Foo { baz: i32 } - -fn foo(foo: Foo) { - let Foo { baz: ref i } = foo; -} -"#, - ); - } - - #[test] - fn test_rename_lifetimes() { - cov_mark::check!(rename_lifetime); - check( - "'yeeee", - r#" -trait Foo<'a> { - fn foo() -> &'a (); -} -impl<'a> Foo<'a> for &'a () { - fn foo() -> &'a$0 () { - unimplemented!() - } -} -"#, - r#" -trait Foo<'a> { - fn foo() -> &'a (); -} -impl<'yeeee> Foo<'yeeee> for &'yeeee () { - fn foo() -> &'yeeee () { - unimplemented!() - } -} -"#, - ) - } - - #[test] - fn test_rename_bind_pat() { - check( - "new_name", - r#" -fn main() { - enum CustomOption { - None, - Some(T), - } - - let test_variable = CustomOption::Some(22); - - match test_variable { - CustomOption::Some(foo$0) if foo == 11 => {} - _ => (), - } -}"#, - r#" -fn main() { - enum CustomOption { - None, - Some(T), - } - - let test_variable = CustomOption::Some(22); - - match test_variable { - CustomOption::Some(new_name) if new_name == 11 => {} - _ => (), - } -}"#, - ); - } - - #[test] - fn test_rename_label() { - check( - "'foo", - r#" -fn foo<'a>() -> &'a () { - 'a: { - 'b: loop { - break 'a$0; - } - } -} -"#, - r#" -fn foo<'a>() -> &'a () { - 'foo: { - 'b: loop { - break 'foo; - } - } -} -"#, - ) - } - - #[test] - fn test_self_to_self() { - cov_mark::check!(rename_self_to_self); - check( - "self", - r#" -struct Foo; -impl Foo { - fn foo(self$0) {} -} -"#, - r#" -struct Foo; -impl Foo { - fn foo(self) {} -} -"#, - ) - } - - #[test] - fn test_rename_field_in_pat_in_macro_doesnt_shorthand() { - // ideally we would be able to make this emit a short hand, but I doubt this is easily possible - check( - "baz", - r#" -macro_rules! foo { - ($pattern:pat) => { - let $pattern = loop {}; - }; -} -struct Foo { - bar$0: u32, -} -fn foo() { - foo!(Foo { bar: baz }); -} -"#, - r#" -macro_rules! foo { - ($pattern:pat) => { - let $pattern = loop {}; - }; -} -struct Foo { - baz: u32, -} -fn foo() { - foo!(Foo { baz: baz }); -} -"#, - ) - } - - #[test] - fn test_rename_tuple_field() { - check( - "foo", - r#" -struct Foo(i32); - -fn baz() { - let mut x = Foo(4); - x.0$0 = 5; -} -"#, - "error: No identifier available to rename", - ); - } - - #[test] - fn test_rename_builtin() { - check( - "foo", - r#" -fn foo() { - let x: i32$0 = 0; -} -"#, - "error: Cannot rename builtin type", - ); - } - - #[test] - fn test_rename_self() { - check( - "foo", - r#" -struct Foo {} - -impl Foo { - fn foo(self) -> Self$0 { - self - } -} -"#, - "error: Cannot rename `Self`", - ); - } - - #[test] - fn test_rename_ignores_self_ty() { - check( - "Fo0", - r#" -struct $0Foo; - -impl Foo where Self: {} -"#, - r#" -struct Fo0; - -impl Fo0 where Self: {} -"#, - ); - } - - #[test] - fn test_rename_fails_on_aliases() { - check( - "Baz", - r#" -struct Foo; -use Foo as Bar$0; -"#, - "error: Renaming aliases is currently unsupported", - ); - check( - "Baz", - r#" -struct Foo; -use Foo as Bar; -use Bar$0; -"#, - "error: Renaming aliases is currently unsupported", - ); - } - - #[test] - fn test_rename_trait_method() { - let res = r" -trait Foo { - fn foo(&self) { - self.foo(); - } -} - -impl Foo for () { - fn foo(&self) { - self.foo(); - } -}"; - check( - "foo", - r#" -trait Foo { - fn bar$0(&self) { - self.bar(); - } -} - -impl Foo for () { - fn bar(&self) { - self.bar(); - } -}"#, - res, - ); - check( - "foo", - r#" -trait Foo { - fn bar(&self) { - self.bar$0(); - } -} - -impl Foo for () { - fn bar(&self) { - self.bar(); - } -}"#, - res, - ); - check( - "foo", - r#" -trait Foo { - fn bar(&self) { - self.bar(); - } -} - -impl Foo for () { - fn bar$0(&self) { - self.bar(); - } -}"#, - res, - ); - check( - "foo", - r#" -trait Foo { - fn bar(&self) { - self.bar(); - } -} - -impl Foo for () { - fn bar(&self) { - self.bar$0(); - } -}"#, - res, - ); - } - - #[test] - fn test_rename_trait_method_prefix_of_second() { - check( - "qux", - r#" -trait Foo { - fn foo$0() {} - fn foobar() {} -} -"#, - r#" -trait Foo { - fn qux() {} - fn foobar() {} -} -"#, - ); - } - - #[test] - fn test_rename_trait_const() { - let res = r" -trait Foo { - const FOO: (); -} - -impl Foo for () { - const FOO: (); -} -fn f() { <()>::FOO; }"; - check( - "FOO", - r#" -trait Foo { - const BAR$0: (); -} - -impl Foo for () { - const BAR: (); -} -fn f() { <()>::BAR; }"#, - res, - ); - check( - "FOO", - r#" -trait Foo { - const BAR: (); -} - -impl Foo for () { - const BAR$0: (); -} -fn f() { <()>::BAR; }"#, - res, - ); - check( - "FOO", - r#" -trait Foo { - const BAR: (); -} - -impl Foo for () { - const BAR: (); -} -fn f() { <()>::BAR$0; }"#, - res, - ); - } - - #[test] - fn defs_from_macros_arent_renamed() { - check( - "lol", - r#" -macro_rules! m { () => { fn f() {} } } -m!(); -fn main() { f$0() } -"#, - "error: No identifier available to rename", - ) - } - - #[test] - fn attributed_item() { - check( - "function", - r#" -//- proc_macros: identity - -#[proc_macros::identity] -fn func$0() { - func(); -} -"#, - r#" - -#[proc_macros::identity] -fn function() { - function(); -} -"#, - ) - } - - #[test] - fn in_macro_multi_mapping() { - check( - "a", - r#" -fn foo() { - macro_rules! match_ast2 { - ($node:ident { - $( $res:expr, )* - }) => {{ - $( if $node { $res } else )* - { loop {} } - }}; - } - let $0d = 3; - match_ast2! { - d { - d, - d, - } - }; -} -"#, - r#" -fn foo() { - macro_rules! match_ast2 { - ($node:ident { - $( $res:expr, )* - }) => {{ - $( if $node { $res } else )* - { loop {} } - }}; - } - let a = 3; - match_ast2! { - a { - a, - a, - } - }; -} -"#, - ) - } - - #[test] - fn rename_multi_local() { - check( - "bar", - r#" -fn foo((foo$0 | foo | foo): ()) { - foo; - let foo; -} -"#, - r#" -fn foo((bar | bar | bar): ()) { - bar; - let foo; -} -"#, - ); - check( - "bar", - r#" -fn foo((foo | foo$0 | foo): ()) { - foo; - let foo; -} -"#, - r#" -fn foo((bar | bar | bar): ()) { - bar; - let foo; -} -"#, - ); - check( - "bar", - r#" -fn foo((foo | foo | foo): ()) { - foo$0; - let foo; -} -"#, - r#" -fn foo((bar | bar | bar): ()) { - bar; - let foo; -} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs deleted file mode 100644 index bec770ed99f16..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ /dev/null @@ -1,2163 +0,0 @@ -use std::fmt; - -use ast::HasName; -use cfg::CfgExpr; -use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics}; -use ide_assists::utils::test_related_attribute; -use ide_db::{ - base_db::{FilePosition, FileRange}, - defs::Definition, - helpers::visit_file_defs, - search::SearchScope, - FxHashMap, FxHashSet, RootDatabase, SymbolKind, -}; -use itertools::Itertools; -use stdx::{always, format_to}; -use syntax::{ - ast::{self, AstNode, HasAttrs as _}, - SmolStr, SyntaxNode, -}; - -use crate::{references, FileId, NavigationTarget, ToNav, TryToNav}; - -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub struct Runnable { - pub use_name_in_title: bool, - pub nav: NavigationTarget, - pub kind: RunnableKind, - pub cfg: Option, -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub enum TestId { - Name(SmolStr), - Path(String), -} - -impl fmt::Display for TestId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - TestId::Name(name) => name.fmt(f), - TestId::Path(path) => path.fmt(f), - } - } -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub enum RunnableKind { - Test { test_id: TestId, attr: TestAttr }, - TestMod { path: String }, - Bench { test_id: TestId }, - DocTest { test_id: TestId }, - Bin, -} - -#[cfg(test)] -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -enum RunnableTestKind { - Test, - TestMod, - DocTest, - Bench, - Bin, -} - -impl Runnable { - // test package::module::testname - pub fn label(&self, target: Option) -> String { - match &self.kind { - RunnableKind::Test { test_id, .. } => format!("test {}", test_id), - RunnableKind::TestMod { path } => format!("test-mod {}", path), - RunnableKind::Bench { test_id } => format!("bench {}", test_id), - RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id), - RunnableKind::Bin => { - target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) - } - } - } - - pub fn title(&self) -> String { - let mut s = String::from("▶\u{fe0e} Run "); - if self.use_name_in_title { - format_to!(s, "{}", self.nav.name); - if !matches!(self.kind, RunnableKind::Bin) { - s.push(' '); - } - } - let suffix = match &self.kind { - RunnableKind::TestMod { .. } => "Tests", - RunnableKind::Test { .. } => "Test", - RunnableKind::DocTest { .. } => "Doctest", - RunnableKind::Bench { .. } => "Bench", - RunnableKind::Bin => return s, - }; - s.push_str(suffix); - s - } - - #[cfg(test)] - fn test_kind(&self) -> RunnableTestKind { - match &self.kind { - RunnableKind::TestMod { .. } => RunnableTestKind::TestMod, - RunnableKind::Test { .. } => RunnableTestKind::Test, - RunnableKind::DocTest { .. } => RunnableTestKind::DocTest, - RunnableKind::Bench { .. } => RunnableTestKind::Bench, - RunnableKind::Bin => RunnableTestKind::Bin, - } - } -} - -// Feature: Run -// -// Shows a popup suggesting to run a test/benchmark/binary **at the current cursor -// location**. Super useful for repeatedly running just a single test. Do bind this -// to a shortcut! -// -// |=== -// | Editor | Action Name -// -// | VS Code | **Rust Analyzer: Run** -// |=== -// image::https://user-images.githubusercontent.com/48062697/113065583-055aae80-91b1-11eb-958f-d67efcaf6a2f.gif[] -pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec { - let sema = Semantics::new(db); - - let mut res = Vec::new(); - // Record all runnables that come from macro expansions here instead. - // In case an expansion creates multiple runnables we want to name them to avoid emitting a bunch of equally named runnables. - let mut in_macro_expansion = FxHashMap::>::default(); - let mut add_opt = |runnable: Option, def| { - if let Some(runnable) = runnable.filter(|runnable| { - always!( - runnable.nav.file_id == file_id, - "tried adding a runnable pointing to a different file: {:?} for {:?}", - runnable.kind, - file_id - ) - }) { - if let Some(def) = def { - let file_id = match def { - Definition::Module(it) => it.declaration_source(db).map(|src| src.file_id), - Definition::Function(it) => it.source(db).map(|src| src.file_id), - _ => None, - }; - if let Some(file_id) = file_id.filter(|file| file.call_node(db).is_some()) { - in_macro_expansion.entry(file_id).or_default().push(runnable); - return; - } - } - res.push(runnable); - } - }; - visit_file_defs(&sema, file_id, &mut |def| { - let runnable = match def { - Definition::Module(it) => runnable_mod(&sema, it), - Definition::Function(it) => runnable_fn(&sema, it), - Definition::SelfType(impl_) => runnable_impl(&sema, &impl_), - _ => None, - }; - add_opt( - runnable - .or_else(|| module_def_doctest(sema.db, def)) - // #[macro_export] mbe macros are declared in the root, while their definition may reside in a different module - .filter(|it| it.nav.file_id == file_id), - Some(def), - ); - if let Definition::SelfType(impl_) = def { - impl_.items(db).into_iter().for_each(|assoc| { - let runnable = match assoc { - hir::AssocItem::Function(it) => { - runnable_fn(&sema, it).or_else(|| module_def_doctest(sema.db, it.into())) - } - hir::AssocItem::Const(it) => module_def_doctest(sema.db, it.into()), - hir::AssocItem::TypeAlias(it) => module_def_doctest(sema.db, it.into()), - }; - add_opt(runnable, Some(assoc.into())) - }); - } - }); - - sema.to_module_defs(file_id) - .map(|it| runnable_mod_outline_definition(&sema, it)) - .for_each(|it| add_opt(it, None)); - - res.extend(in_macro_expansion.into_iter().flat_map(|(_, runnables)| { - let use_name_in_title = runnables.len() != 1; - runnables.into_iter().map(move |mut r| { - r.use_name_in_title = use_name_in_title; - r - }) - })); - res -} - -// Feature: Related Tests -// -// Provides a sneak peek of all tests where the current item is used. -// -// The simplest way to use this feature is via the context menu: -// - Right-click on the selected item. The context menu opens. -// - Select **Peek related tests** -// -// |=== -// | Editor | Action Name -// -// | VS Code | **Rust Analyzer: Peek related tests** -// |=== -pub(crate) fn related_tests( - db: &RootDatabase, - position: FilePosition, - search_scope: Option, -) -> Vec { - let sema = Semantics::new(db); - let mut res: FxHashSet = FxHashSet::default(); - let syntax = sema.parse(position.file_id).syntax().clone(); - - find_related_tests(&sema, &syntax, position, search_scope, &mut res); - - res.into_iter().collect() -} - -fn find_related_tests( - sema: &Semantics<'_, RootDatabase>, - syntax: &SyntaxNode, - position: FilePosition, - search_scope: Option, - tests: &mut FxHashSet, -) { - // FIXME: why is this using references::find_defs, this should use ide_db::search - let defs = match references::find_defs(sema, syntax, position.offset) { - Some(defs) => defs, - None => return, - }; - for def in defs { - let defs = def - .usages(sema) - .set_scope(search_scope.clone()) - .all() - .references - .into_values() - .flatten(); - for ref_ in defs { - let name_ref = match ref_.name { - ast::NameLike::NameRef(name_ref) => name_ref, - _ => continue, - }; - if let Some(fn_def) = - sema.ancestors_with_macros(name_ref.syntax().clone()).find_map(ast::Fn::cast) - { - if let Some(runnable) = as_test_runnable(sema, &fn_def) { - // direct test - tests.insert(runnable); - } else if let Some(module) = parent_test_module(sema, &fn_def) { - // indirect test - find_related_tests_in_module(sema, syntax, &fn_def, &module, tests); - } - } - } - } -} - -fn find_related_tests_in_module( - sema: &Semantics<'_, RootDatabase>, - syntax: &SyntaxNode, - fn_def: &ast::Fn, - parent_module: &hir::Module, - tests: &mut FxHashSet, -) { - let fn_name = match fn_def.name() { - Some(it) => it, - _ => return, - }; - let mod_source = parent_module.definition_source(sema.db); - let range = match &mod_source.value { - hir::ModuleSource::Module(m) => m.syntax().text_range(), - hir::ModuleSource::BlockExpr(b) => b.syntax().text_range(), - hir::ModuleSource::SourceFile(f) => f.syntax().text_range(), - }; - - let file_id = mod_source.file_id.original_file(sema.db); - let mod_scope = SearchScope::file_range(FileRange { file_id, range }); - let fn_pos = FilePosition { file_id, offset: fn_name.syntax().text_range().start() }; - find_related_tests(sema, syntax, fn_pos, Some(mod_scope), tests) -} - -fn as_test_runnable(sema: &Semantics<'_, RootDatabase>, fn_def: &ast::Fn) -> Option { - if test_related_attribute(fn_def).is_some() { - let function = sema.to_def(fn_def)?; - runnable_fn(sema, function) - } else { - None - } -} - -fn parent_test_module(sema: &Semantics<'_, RootDatabase>, fn_def: &ast::Fn) -> Option { - fn_def.syntax().ancestors().find_map(|node| { - let module = ast::Module::cast(node)?; - let module = sema.to_def(&module)?; - - if has_test_function_or_multiple_test_submodules(sema, &module) { - Some(module) - } else { - None - } - }) -} - -pub(crate) fn runnable_fn( - sema: &Semantics<'_, RootDatabase>, - def: hir::Function, -) -> Option { - let func = def.source(sema.db)?; - let name = def.name(sema.db).to_smol_str(); - - let root = def.module(sema.db).krate().root_module(sema.db); - - let kind = if name == "main" && def.module(sema.db) == root { - RunnableKind::Bin - } else { - let test_id = || { - let canonical_path = { - let def: hir::ModuleDef = def.into(); - def.canonical_path(sema.db) - }; - canonical_path.map(TestId::Path).unwrap_or(TestId::Name(name)) - }; - - if test_related_attribute(&func.value).is_some() { - let attr = TestAttr::from_fn(&func.value); - RunnableKind::Test { test_id: test_id(), attr } - } else if func.value.has_atom_attr("bench") { - RunnableKind::Bench { test_id: test_id() } - } else { - return None; - } - }; - - let nav = NavigationTarget::from_named( - sema.db, - func.as_ref().map(|it| it as &dyn ast::HasName), - SymbolKind::Function, - ); - let cfg = def.attrs(sema.db).cfg(); - Some(Runnable { use_name_in_title: false, nav, kind, cfg }) -} - -pub(crate) fn runnable_mod( - sema: &Semantics<'_, RootDatabase>, - def: hir::Module, -) -> Option { - if !has_test_function_or_multiple_test_submodules(sema, &def) { - return None; - } - let path = - def.path_to_root(sema.db).into_iter().rev().filter_map(|it| it.name(sema.db)).join("::"); - - let attrs = def.attrs(sema.db); - let cfg = attrs.cfg(); - let nav = NavigationTarget::from_module_to_decl(sema.db, def); - Some(Runnable { use_name_in_title: false, nav, kind: RunnableKind::TestMod { path }, cfg }) -} - -pub(crate) fn runnable_impl( - sema: &Semantics<'_, RootDatabase>, - def: &hir::Impl, -) -> Option { - let attrs = def.attrs(sema.db); - if !has_runnable_doc_test(&attrs) { - return None; - } - let cfg = attrs.cfg(); - let nav = def.try_to_nav(sema.db)?; - let ty = def.self_ty(sema.db); - let adt_name = ty.as_adt()?.name(sema.db); - let mut ty_args = ty.type_arguments().peekable(); - let params = if ty_args.peek().is_some() { - format!("<{}>", ty_args.format_with(", ", |ty, cb| cb(&ty.display(sema.db)))) - } else { - String::new() - }; - let test_id = TestId::Path(format!("{}{}", adt_name, params)); - - Some(Runnable { use_name_in_title: false, nav, kind: RunnableKind::DocTest { test_id }, cfg }) -} - -/// Creates a test mod runnable for outline modules at the top of their definition. -fn runnable_mod_outline_definition( - sema: &Semantics<'_, RootDatabase>, - def: hir::Module, -) -> Option { - if !has_test_function_or_multiple_test_submodules(sema, &def) { - return None; - } - let path = - def.path_to_root(sema.db).into_iter().rev().filter_map(|it| it.name(sema.db)).join("::"); - - let attrs = def.attrs(sema.db); - let cfg = attrs.cfg(); - match def.definition_source(sema.db).value { - hir::ModuleSource::SourceFile(_) => Some(Runnable { - use_name_in_title: false, - nav: def.to_nav(sema.db), - kind: RunnableKind::TestMod { path }, - cfg, - }), - _ => None, - } -} - -fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option { - let attrs = match def { - Definition::Module(it) => it.attrs(db), - Definition::Function(it) => it.attrs(db), - Definition::Adt(it) => it.attrs(db), - Definition::Variant(it) => it.attrs(db), - Definition::Const(it) => it.attrs(db), - Definition::Static(it) => it.attrs(db), - Definition::Trait(it) => it.attrs(db), - Definition::TypeAlias(it) => it.attrs(db), - Definition::Macro(it) => it.attrs(db), - Definition::SelfType(it) => it.attrs(db), - _ => return None, - }; - if !has_runnable_doc_test(&attrs) { - return None; - } - let def_name = def.name(db)?; - let path = (|| { - let mut path = String::new(); - def.canonical_module_path(db)? - .flat_map(|it| it.name(db)) - .for_each(|name| format_to!(path, "{}::", name)); - // This probably belongs to canonical_path? - if let Some(assoc_item) = def.as_assoc_item(db) { - if let hir::AssocItemContainer::Impl(imp) = assoc_item.container(db) { - let ty = imp.self_ty(db); - if let Some(adt) = ty.as_adt() { - let name = adt.name(db); - let mut ty_args = ty.type_arguments().peekable(); - format_to!(path, "{}", name); - if ty_args.peek().is_some() { - format_to!( - path, - "<{}>", - ty_args.format_with(", ", |ty, cb| cb(&ty.display(db))) - ); - } - format_to!(path, "::{}", def_name); - return Some(path); - } - } - } - format_to!(path, "{}", def_name); - Some(path) - })(); - - let test_id = path.map_or_else(|| TestId::Name(def_name.to_smol_str()), TestId::Path); - - let mut nav = match def { - Definition::Module(def) => NavigationTarget::from_module_to_decl(db, def), - def => def.try_to_nav(db)?, - }; - nav.focus_range = None; - nav.description = None; - nav.docs = None; - nav.kind = None; - let res = Runnable { - use_name_in_title: false, - nav, - kind: RunnableKind::DocTest { test_id }, - cfg: attrs.cfg(), - }; - Some(res) -} - -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub struct TestAttr { - pub ignore: bool, -} - -impl TestAttr { - fn from_fn(fn_def: &ast::Fn) -> TestAttr { - let ignore = fn_def - .attrs() - .filter_map(|attr| attr.simple_name()) - .any(|attribute_text| attribute_text == "ignore"); - TestAttr { ignore } - } -} - -const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"]; -const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = - &["", "rust", "should_panic", "edition2015", "edition2018", "edition2021"]; - -fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { - attrs.docs().map_or(false, |doc| { - let mut in_code_block = false; - - for line in String::from(doc).lines() { - if let Some(header) = - RUSTDOC_FENCES.into_iter().find_map(|fence| line.strip_prefix(fence)) - { - in_code_block = !in_code_block; - - if in_code_block - && header - .split(',') - .all(|sub| RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE.contains(&sub.trim())) - { - return true; - } - } - } - - false - }) -} - -// We could create runnables for modules with number_of_test_submodules > 0, -// but that bloats the runnables for no real benefit, since all tests can be run by the submodule already -fn has_test_function_or_multiple_test_submodules( - sema: &Semantics<'_, RootDatabase>, - module: &hir::Module, -) -> bool { - let mut number_of_test_submodules = 0; - - for item in module.declarations(sema.db) { - match item { - hir::ModuleDef::Function(f) => { - if let Some(it) = f.source(sema.db) { - if test_related_attribute(&it.value).is_some() { - return true; - } - } - } - hir::ModuleDef::Module(submodule) => { - if has_test_function_or_multiple_test_submodules(sema, &submodule) { - number_of_test_submodules += 1; - } - } - _ => (), - } - } - - number_of_test_submodules > 1 -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use crate::fixture; - - use super::{RunnableTestKind::*, *}; - - fn check( - ra_fixture: &str, - // FIXME: fold this into `expect` as well - actions: &[RunnableTestKind], - expect: Expect, - ) { - let (analysis, position) = fixture::position(ra_fixture); - let mut runnables = analysis.runnables(position.file_id).unwrap(); - runnables.sort_by_key(|it| (it.nav.full_range.start(), it.nav.name.clone())); - expect.assert_debug_eq(&runnables); - assert_eq!( - actions, - runnables.into_iter().map(|it| it.test_kind()).collect::>().as_slice() - ); - } - - fn check_tests(ra_fixture: &str, expect: Expect) { - let (analysis, position) = fixture::position(ra_fixture); - let tests = analysis.related_tests(position, None).unwrap(); - expect.assert_debug_eq(&tests); - } - - #[test] - fn test_runnables() { - check( - r#" -//- /lib.rs -$0 -fn main() {} - -#[test] -fn test_foo() {} - -#[test] -#[ignore] -fn test_foo() {} - -#[bench] -fn bench() {} - -mod not_a_root { - fn main() {} -} -"#, - &[TestMod, Bin, Test, Test, Bench], - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..137, - name: "", - kind: Module, - }, - kind: TestMod { - path: "", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..13, - focus_range: 4..8, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 15..39, - focus_range: 26..34, - name: "test_foo", - kind: Function, - }, - kind: Test { - test_id: Path( - "test_foo", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 41..75, - focus_range: 62..70, - name: "test_foo", - kind: Function, - }, - kind: Test { - test_id: Path( - "test_foo", - ), - attr: TestAttr { - ignore: true, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 77..99, - focus_range: 89..94, - name: "bench", - kind: Function, - }, - kind: Bench { - test_id: Path( - "bench", - ), - }, - cfg: None, - }, - ] - "#]], - ); - } - - #[test] - fn test_runnables_doc_test() { - check( - r#" -//- /lib.rs -$0 -fn main() {} - -/// ``` -/// let x = 5; -/// ``` -fn should_have_runnable() {} - -/// ```edition2018 -/// let x = 5; -/// ``` -fn should_have_runnable_1() {} - -/// ``` -/// let z = 55; -/// ``` -/// -/// ```ignore -/// let z = 56; -/// ``` -fn should_have_runnable_2() {} - -/** -```rust -let z = 55; -``` -*/ -fn should_have_no_runnable_3() {} - -/** - ```rust - let z = 55; - ``` -*/ -fn should_have_no_runnable_4() {} - -/// ```no_run -/// let z = 55; -/// ``` -fn should_have_no_runnable() {} - -/// ```ignore -/// let z = 55; -/// ``` -fn should_have_no_runnable_2() {} - -/// ```compile_fail -/// let z = 55; -/// ``` -fn should_have_no_runnable_3() {} - -/// ```text -/// arbitrary plain text -/// ``` -fn should_have_no_runnable_4() {} - -/// ```text -/// arbitrary plain text -/// ``` -/// -/// ```sh -/// $ shell code -/// ``` -fn should_have_no_runnable_5() {} - -/// ```rust,no_run -/// let z = 55; -/// ``` -fn should_have_no_runnable_6() {} - -/// ``` -/// let x = 5; -/// ``` -struct StructWithRunnable(String); - -/// ``` -/// let x = 5; -/// ``` -impl StructWithRunnable {} - -trait Test { - fn test() -> usize { - 5usize - } -} - -/// ``` -/// let x = 5; -/// ``` -impl Test for StructWithRunnable {} -"#, - &[Bin, DocTest, DocTest, DocTest, DocTest, DocTest, DocTest, DocTest, DocTest], - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..13, - focus_range: 4..8, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 15..74, - name: "should_have_runnable", - }, - kind: DocTest { - test_id: Path( - "should_have_runnable", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 76..148, - name: "should_have_runnable_1", - }, - kind: DocTest { - test_id: Path( - "should_have_runnable_1", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 150..254, - name: "should_have_runnable_2", - }, - kind: DocTest { - test_id: Path( - "should_have_runnable_2", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 256..320, - name: "should_have_no_runnable_3", - }, - kind: DocTest { - test_id: Path( - "should_have_no_runnable_3", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 322..398, - name: "should_have_no_runnable_4", - }, - kind: DocTest { - test_id: Path( - "should_have_no_runnable_4", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 900..965, - name: "StructWithRunnable", - }, - kind: DocTest { - test_id: Path( - "StructWithRunnable", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 967..1024, - focus_range: 1003..1021, - name: "impl", - kind: Impl, - }, - kind: DocTest { - test_id: Path( - "StructWithRunnable", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1088..1154, - focus_range: 1133..1151, - name: "impl", - kind: Impl, - }, - kind: DocTest { - test_id: Path( - "StructWithRunnable", - ), - }, - cfg: None, - }, - ] - "#]], - ); - } - - #[test] - fn test_runnables_doc_test_in_impl() { - check( - r#" -//- /lib.rs -$0 -fn main() {} - -struct Data; -impl Data { - /// ``` - /// let x = 5; - /// ``` - fn foo() {} -} -"#, - &[Bin, DocTest], - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..13, - focus_range: 4..8, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 44..98, - name: "foo", - }, - kind: DocTest { - test_id: Path( - "Data::foo", - ), - }, - cfg: None, - }, - ] - "#]], - ); - } - - #[test] - fn test_runnables_module() { - check( - r#" -//- /lib.rs -$0 -mod test_mod { - #[test] - fn test_foo1() {} -} -"#, - &[TestMod, Test], - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..51, - focus_range: 5..13, - name: "test_mod", - kind: Module, - description: "mod test_mod", - }, - kind: TestMod { - path: "test_mod", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 20..49, - focus_range: 35..44, - name: "test_foo1", - kind: Function, - }, - kind: Test { - test_id: Path( - "test_mod::test_foo1", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - ] - "#]], - ); - } - - #[test] - fn only_modules_with_test_functions_or_more_than_one_test_submodule_have_runners() { - check( - r#" -//- /lib.rs -$0 -mod root_tests { - mod nested_tests_0 { - mod nested_tests_1 { - #[test] - fn nested_test_11() {} - - #[test] - fn nested_test_12() {} - } - - mod nested_tests_2 { - #[test] - fn nested_test_2() {} - } - - mod nested_tests_3 {} - } - - mod nested_tests_4 {} -} -"#, - &[TestMod, TestMod, Test, Test, TestMod, Test], - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 22..323, - focus_range: 26..40, - name: "nested_tests_0", - kind: Module, - description: "mod nested_tests_0", - }, - kind: TestMod { - path: "root_tests::nested_tests_0", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 51..192, - focus_range: 55..69, - name: "nested_tests_1", - kind: Module, - description: "mod nested_tests_1", - }, - kind: TestMod { - path: "root_tests::nested_tests_0::nested_tests_1", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 84..126, - focus_range: 107..121, - name: "nested_test_11", - kind: Function, - }, - kind: Test { - test_id: Path( - "root_tests::nested_tests_0::nested_tests_1::nested_test_11", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 140..182, - focus_range: 163..177, - name: "nested_test_12", - kind: Function, - }, - kind: Test { - test_id: Path( - "root_tests::nested_tests_0::nested_tests_1::nested_test_12", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 202..286, - focus_range: 206..220, - name: "nested_tests_2", - kind: Module, - description: "mod nested_tests_2", - }, - kind: TestMod { - path: "root_tests::nested_tests_0::nested_tests_2", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 235..276, - focus_range: 258..271, - name: "nested_test_2", - kind: Function, - }, - kind: Test { - test_id: Path( - "root_tests::nested_tests_0::nested_tests_2::nested_test_2", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - ] - "#]], - ); - } - - #[test] - fn test_runnables_with_feature() { - check( - r#" -//- /lib.rs crate:foo cfg:feature=foo -$0 -#[test] -#[cfg(feature = "foo")] -fn test_foo1() {} -"#, - &[TestMod, Test], - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..51, - name: "", - kind: Module, - }, - kind: TestMod { - path: "", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..50, - focus_range: 36..45, - name: "test_foo1", - kind: Function, - }, - kind: Test { - test_id: Path( - "test_foo1", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: Some( - Atom( - KeyValue { - key: "feature", - value: "foo", - }, - ), - ), - }, - ] - "#]], - ); - } - - #[test] - fn test_runnables_with_features() { - check( - r#" -//- /lib.rs crate:foo cfg:feature=foo,feature=bar -$0 -#[test] -#[cfg(all(feature = "foo", feature = "bar"))] -fn test_foo1() {} -"#, - &[TestMod, Test], - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..73, - name: "", - kind: Module, - }, - kind: TestMod { - path: "", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..72, - focus_range: 58..67, - name: "test_foo1", - kind: Function, - }, - kind: Test { - test_id: Path( - "test_foo1", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: Some( - All( - [ - Atom( - KeyValue { - key: "feature", - value: "foo", - }, - ), - Atom( - KeyValue { - key: "feature", - value: "bar", - }, - ), - ], - ), - ), - }, - ] - "#]], - ); - } - - #[test] - fn test_runnables_no_test_function_in_module() { - check( - r#" -//- /lib.rs -$0 -mod test_mod { - fn foo1() {} -} -"#, - &[], - expect![[r#" - [] - "#]], - ); - } - - #[test] - fn test_doc_runnables_impl_mod() { - check( - r#" -//- /lib.rs -mod foo; -//- /foo.rs -struct Foo;$0 -impl Foo { - /// ``` - /// let x = 5; - /// ``` - fn foo() {} -} - "#, - &[DocTest], - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 1, - ), - full_range: 27..81, - name: "foo", - }, - kind: DocTest { - test_id: Path( - "foo::Foo::foo", - ), - }, - cfg: None, - }, - ] - "#]], - ); - } - - #[test] - fn test_runnables_in_macro() { - check( - r#" -//- /lib.rs -$0 -macro_rules! gen { - () => { - #[test] - fn foo_test() {} - } -} -macro_rules! gen2 { - () => { - mod tests2 { - #[test] - fn foo_test2() {} - } - } -} -mod tests { - gen!(); -} -gen2!(); -"#, - &[TestMod, TestMod, Test, Test, TestMod], - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..237, - name: "", - kind: Module, - }, - kind: TestMod { - path: "", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 202..227, - focus_range: 206..211, - name: "tests", - kind: Module, - description: "mod tests", - }, - kind: TestMod { - path: "tests", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 218..225, - name: "foo_test", - kind: Function, - }, - kind: Test { - test_id: Path( - "tests::foo_test", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 228..236, - name: "foo_test2", - kind: Function, - }, - kind: Test { - test_id: Path( - "tests2::foo_test2", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 228..236, - name: "tests2", - kind: Module, - description: "mod tests2", - }, - kind: TestMod { - path: "tests2", - }, - cfg: None, - }, - ] - "#]], - ); - } - - #[test] - fn big_mac() { - check( - r#" -//- /lib.rs -$0 -macro_rules! foo { - () => { - mod foo_tests { - #[test] - fn foo0() {} - #[test] - fn foo1() {} - #[test] - fn foo2() {} - } - }; -} -foo!(); -"#, - &[Test, Test, Test, TestMod], - expect![[r#" - [ - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 210..217, - name: "foo0", - kind: Function, - }, - kind: Test { - test_id: Path( - "foo_tests::foo0", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 210..217, - name: "foo1", - kind: Function, - }, - kind: Test { - test_id: Path( - "foo_tests::foo1", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 210..217, - name: "foo2", - kind: Function, - }, - kind: Test { - test_id: Path( - "foo_tests::foo2", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 210..217, - name: "foo_tests", - kind: Module, - description: "mod foo_tests", - }, - kind: TestMod { - path: "foo_tests", - }, - cfg: None, - }, - ] - "#]], - ); - } - - #[test] - fn dont_recurse_in_outline_submodules() { - check( - r#" -//- /lib.rs -$0 -mod m; -//- /m.rs -mod tests { - #[test] - fn t() {} -} -"#, - &[], - expect![[r#" - [] - "#]], - ); - } - - #[test] - fn outline_submodule1() { - check( - r#" -//- /lib.rs -$0 -mod m; -//- /m.rs -#[test] -fn t0() {} -#[test] -fn t1() {} -"#, - &[TestMod], - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..7, - focus_range: 5..6, - name: "m", - kind: Module, - description: "mod m", - }, - kind: TestMod { - path: "m", - }, - cfg: None, - }, - ] - "#]], - ); - } - - #[test] - fn outline_submodule2() { - check( - r#" -//- /lib.rs -mod m; -//- /m.rs -$0 -#[test] -fn t0() {} -#[test] -fn t1() {} -"#, - &[TestMod, Test, Test], - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 1, - ), - full_range: 0..39, - name: "m", - kind: Module, - }, - kind: TestMod { - path: "m", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 1, - ), - full_range: 1..19, - focus_range: 12..14, - name: "t0", - kind: Function, - }, - kind: Test { - test_id: Path( - "m::t0", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 1, - ), - full_range: 20..38, - focus_range: 31..33, - name: "t1", - kind: Function, - }, - kind: Test { - test_id: Path( - "m::t1", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - ] - "#]], - ); - } - - #[test] - fn attributed_module() { - check( - r#" -//- proc_macros: identity -//- /lib.rs -$0 -#[proc_macros::identity] -mod module { - #[test] - fn t0() {} - #[test] - fn t1() {} -} -"#, - &[TestMod, Test, Test], - expect![[r#" - [ - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 26..94, - focus_range: 30..36, - name: "module", - kind: Module, - description: "mod module", - }, - kind: TestMod { - path: "module", - }, - cfg: None, - }, - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 43..65, - focus_range: 58..60, - name: "t0", - kind: Function, - }, - kind: Test { - test_id: Path( - "module::t0", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 70..92, - focus_range: 85..87, - name: "t1", - kind: Function, - }, - kind: Test { - test_id: Path( - "module::t1", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - ] - "#]], - ); - } - - #[test] - fn find_no_tests() { - check_tests( - r#" -//- /lib.rs -fn foo$0() { }; -"#, - expect![[r#" - [] - "#]], - ); - } - - #[test] - fn find_direct_fn_test() { - check_tests( - r#" -//- /lib.rs -fn foo$0() { }; - -mod tests { - #[test] - fn foo_test() { - super::foo() - } -} -"#, - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 31..85, - focus_range: 46..54, - name: "foo_test", - kind: Function, - }, - kind: Test { - test_id: Path( - "tests::foo_test", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - ] - "#]], - ); - } - - #[test] - fn find_direct_struct_test() { - check_tests( - r#" -//- /lib.rs -struct Fo$0o; -fn foo(arg: &Foo) { }; - -mod tests { - use super::*; - - #[test] - fn foo_test() { - foo(Foo); - } -} -"#, - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 71..122, - focus_range: 86..94, - name: "foo_test", - kind: Function, - }, - kind: Test { - test_id: Path( - "tests::foo_test", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - ] - "#]], - ); - } - - #[test] - fn find_indirect_fn_test() { - check_tests( - r#" -//- /lib.rs -fn foo$0() { }; - -mod tests { - use super::foo; - - fn check1() { - check2() - } - - fn check2() { - foo() - } - - #[test] - fn foo_test() { - check1() - } -} -"#, - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 133..183, - focus_range: 148..156, - name: "foo_test", - kind: Function, - }, - kind: Test { - test_id: Path( - "tests::foo_test", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - ] - "#]], - ); - } - - #[test] - fn tests_are_unique() { - check_tests( - r#" -//- /lib.rs -fn foo$0() { }; - -mod tests { - use super::foo; - - #[test] - fn foo_test() { - foo(); - foo(); - } - - #[test] - fn foo2_test() { - foo(); - foo(); - } - -} -"#, - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 52..115, - focus_range: 67..75, - name: "foo_test", - kind: Function, - }, - kind: Test { - test_id: Path( - "tests::foo_test", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 121..185, - focus_range: 136..145, - name: "foo2_test", - kind: Function, - }, - kind: Test { - test_id: Path( - "tests::foo2_test", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - ] - "#]], - ); - } - - #[test] - fn doc_test_type_params() { - check( - r#" -//- /lib.rs -$0 -struct Foo; - -impl Foo { - /// ```rust - /// ```` - fn t() {} -} -"#, - &[DocTest], - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 47..85, - name: "t", - }, - kind: DocTest { - test_id: Path( - "Foo::t", - ), - }, - cfg: None, - }, - ] - "#]], - ); - } - - #[test] - fn doc_test_macro_export_mbe() { - check( - r#" -//- /lib.rs -$0 -mod foo; - -//- /foo.rs -/// ``` -/// fn foo() { -/// } -/// ``` -#[macro_export] -macro_rules! foo { - () => { - - }; -} -"#, - &[], - expect![[r#" - [] - "#]], - ); - check( - r#" -//- /lib.rs -$0 -/// ``` -/// fn foo() { -/// } -/// ``` -#[macro_export] -macro_rules! foo { - () => { - - }; -} -"#, - &[DocTest], - expect![[r#" - [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..94, - name: "foo", - }, - kind: DocTest { - test_id: Path( - "foo", - ), - }, - cfg: None, - }, - ] - "#]], - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/shuffle_crate_graph.rs b/src/tools/rust-analyzer/crates/ide/src/shuffle_crate_graph.rs deleted file mode 100644 index 15cb89dcce95f..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/shuffle_crate_graph.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::sync::Arc; - -use ide_db::{ - base_db::{salsa::Durability, CrateGraph, SourceDatabase}, - FxHashMap, RootDatabase, -}; - -// Feature: Shuffle Crate Graph -// -// Randomizes all crate IDs in the crate graph, for debugging. -// -// |=== -// | Editor | Action Name -// -// | VS Code | **Rust Analyzer: Shuffle Crate Graph** -// |=== -pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) { - let crate_graph = db.crate_graph(); - - let mut shuffled_ids = crate_graph.iter().collect::>(); - shuffle(&mut shuffled_ids); - - let mut new_graph = CrateGraph::default(); - - let mut map = FxHashMap::default(); - for old_id in shuffled_ids.iter().copied() { - let data = &crate_graph[old_id]; - let new_id = new_graph.add_crate_root( - data.root_file_id, - data.edition, - data.display_name.clone(), - data.version.clone(), - data.cfg_options.clone(), - data.potential_cfg_options.clone(), - data.env.clone(), - data.proc_macro.clone(), - data.is_proc_macro, - data.origin.clone(), - ); - map.insert(old_id, new_id); - } - - for old_id in shuffled_ids.iter().copied() { - let data = &crate_graph[old_id]; - for dep in &data.dependencies { - let mut new_dep = dep.clone(); - new_dep.crate_id = map[&dep.crate_id]; - new_graph.add_dep(map[&old_id], new_dep).unwrap(); - } - } - - db.set_crate_graph_with_durability(Arc::new(new_graph), Durability::HIGH); -} - -fn shuffle(slice: &mut [T]) { - let mut rng = oorandom::Rand32::new(seed()); - - let mut remaining = slice.len() - 1; - while remaining > 0 { - let index = rng.rand_range(0..remaining as u32); - slice.swap(remaining, index as usize); - remaining -= 1; - } -} - -fn seed() -> u64 { - use std::collections::hash_map::RandomState; - use std::hash::{BuildHasher, Hasher}; - - RandomState::new().build_hasher().finish() -} diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs deleted file mode 100644 index fedc1a4358272..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ /dev/null @@ -1,1334 +0,0 @@ -//! This module provides primitives for showing type and function parameter information when editing -//! a call or use-site. - -use std::collections::BTreeSet; - -use either::Either; -use hir::{AssocItem, GenericParam, HasAttrs, HirDisplay, Semantics, Trait}; -use ide_db::{active_parameter::callable_for_node, base_db::FilePosition}; -use stdx::format_to; -use syntax::{ - algo, - ast::{self, HasArgList}, - match_ast, AstNode, Direction, SyntaxToken, TextRange, TextSize, -}; - -use crate::RootDatabase; - -/// Contains information about an item signature as seen from a use site. -/// -/// This includes the "active parameter", which is the parameter whose value is currently being -/// edited. -#[derive(Debug)] -pub struct SignatureHelp { - pub doc: Option, - pub signature: String, - pub active_parameter: Option, - parameters: Vec, -} - -impl SignatureHelp { - pub fn parameter_labels(&self) -> impl Iterator + '_ { - self.parameters.iter().map(move |&it| &self.signature[it]) - } - - pub fn parameter_ranges(&self) -> &[TextRange] { - &self.parameters - } - - fn push_call_param(&mut self, param: &str) { - self.push_param('(', param); - } - - fn push_generic_param(&mut self, param: &str) { - self.push_param('<', param); - } - - fn push_param(&mut self, opening_delim: char, param: &str) { - if !self.signature.ends_with(opening_delim) { - self.signature.push_str(", "); - } - let start = TextSize::of(&self.signature); - self.signature.push_str(param); - let end = TextSize::of(&self.signature); - self.parameters.push(TextRange::new(start, end)) - } -} - -/// Computes parameter information for the given position. -pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Option { - let sema = Semantics::new(db); - let file = sema.parse(position.file_id); - let file = file.syntax(); - let token = file - .token_at_offset(position.offset) - .left_biased() - // if the cursor is sandwiched between two space tokens and the call is unclosed - // this prevents us from leaving the CallExpression - .and_then(|tok| algo::skip_trivia_token(tok, Direction::Prev))?; - let token = sema.descend_into_macros_single(token); - - for node in token.parent_ancestors() { - match_ast! { - match node { - ast::ArgList(arg_list) => { - let cursor_outside = arg_list.r_paren_token().as_ref() == Some(&token); - if cursor_outside { - return None; - } - return signature_help_for_call(&sema, token); - }, - ast::GenericArgList(garg_list) => { - let cursor_outside = garg_list.r_angle_token().as_ref() == Some(&token); - if cursor_outside { - return None; - } - return signature_help_for_generics(&sema, token); - }, - _ => (), - } - } - } - - None -} - -fn signature_help_for_call( - sema: &Semantics<'_, RootDatabase>, - token: SyntaxToken, -) -> Option { - // Find the calling expression and its NameRef - let mut node = token.parent()?; - let calling_node = loop { - if let Some(callable) = ast::CallableExpr::cast(node.clone()) { - if callable - .arg_list() - .map_or(false, |it| it.syntax().text_range().contains(token.text_range().start())) - { - break callable; - } - } - - // Stop at multi-line expressions, since the signature of the outer call is not very - // helpful inside them. - if let Some(expr) = ast::Expr::cast(node.clone()) { - if expr.syntax().text().contains_char('\n') { - return None; - } - } - - node = node.parent()?; - }; - - let (callable, active_parameter) = callable_for_node(sema, &calling_node, &token)?; - - let mut res = - SignatureHelp { doc: None, signature: String::new(), parameters: vec![], active_parameter }; - - let db = sema.db; - let mut fn_params = None; - match callable.kind() { - hir::CallableKind::Function(func) => { - res.doc = func.docs(db).map(|it| it.into()); - format_to!(res.signature, "fn {}", func.name(db)); - fn_params = Some(match callable.receiver_param(db) { - Some(_self) => func.params_without_self(db), - None => func.assoc_fn_params(db), - }); - } - hir::CallableKind::TupleStruct(strukt) => { - res.doc = strukt.docs(db).map(|it| it.into()); - format_to!(res.signature, "struct {}", strukt.name(db)); - } - hir::CallableKind::TupleEnumVariant(variant) => { - res.doc = variant.docs(db).map(|it| it.into()); - format_to!( - res.signature, - "enum {}::{}", - variant.parent_enum(db).name(db), - variant.name(db) - ); - } - hir::CallableKind::Closure | hir::CallableKind::FnPtr => (), - } - - res.signature.push('('); - { - if let Some(self_param) = callable.receiver_param(db) { - format_to!(res.signature, "{}", self_param) - } - let mut buf = String::new(); - for (idx, (pat, ty)) in callable.params(db).into_iter().enumerate() { - buf.clear(); - if let Some(pat) = pat { - match pat { - Either::Left(_self) => format_to!(buf, "self: "), - Either::Right(pat) => format_to!(buf, "{}: ", pat), - } - } - // APITs (argument position `impl Trait`s) are inferred as {unknown} as the user is - // in the middle of entering call arguments. - // In that case, fall back to render definitions of the respective parameters. - // This is overly conservative: we do not substitute known type vars - // (see FIXME in tests::impl_trait) and falling back on any unknowns. - match (ty.contains_unknown(), fn_params.as_deref()) { - (true, Some(fn_params)) => format_to!(buf, "{}", fn_params[idx].ty().display(db)), - _ => format_to!(buf, "{}", ty.display(db)), - } - res.push_call_param(&buf); - } - } - res.signature.push(')'); - - let mut render = |ret_type: hir::Type| { - if !ret_type.is_unit() { - format_to!(res.signature, " -> {}", ret_type.display(db)); - } - }; - match callable.kind() { - hir::CallableKind::Function(func) if callable.return_type().contains_unknown() => { - render(func.ret_type(db)) - } - hir::CallableKind::Function(_) | hir::CallableKind::Closure | hir::CallableKind::FnPtr => { - render(callable.return_type()) - } - hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {} - } - Some(res) -} - -fn signature_help_for_generics( - sema: &Semantics<'_, RootDatabase>, - token: SyntaxToken, -) -> Option { - let parent = token.parent()?; - let arg_list = parent - .ancestors() - .filter_map(ast::GenericArgList::cast) - .find(|list| list.syntax().text_range().contains(token.text_range().start()))?; - - let mut active_parameter = arg_list - .generic_args() - .take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start()) - .count(); - - let first_arg_is_non_lifetime = arg_list - .generic_args() - .next() - .map_or(false, |arg| !matches!(arg, ast::GenericArg::LifetimeArg(_))); - - let mut generics_def = if let Some(path) = - arg_list.syntax().ancestors().find_map(ast::Path::cast) - { - let res = sema.resolve_path(&path)?; - let generic_def: hir::GenericDef = match res { - hir::PathResolution::Def(hir::ModuleDef::Adt(it)) => it.into(), - hir::PathResolution::Def(hir::ModuleDef::Function(it)) => it.into(), - hir::PathResolution::Def(hir::ModuleDef::Trait(it)) => it.into(), - hir::PathResolution::Def(hir::ModuleDef::TypeAlias(it)) => it.into(), - hir::PathResolution::Def(hir::ModuleDef::Variant(it)) => it.into(), - hir::PathResolution::Def(hir::ModuleDef::BuiltinType(_)) - | hir::PathResolution::Def(hir::ModuleDef::Const(_)) - | hir::PathResolution::Def(hir::ModuleDef::Macro(_)) - | hir::PathResolution::Def(hir::ModuleDef::Module(_)) - | hir::PathResolution::Def(hir::ModuleDef::Static(_)) => return None, - hir::PathResolution::BuiltinAttr(_) - | hir::PathResolution::ToolModule(_) - | hir::PathResolution::Local(_) - | hir::PathResolution::TypeParam(_) - | hir::PathResolution::ConstParam(_) - | hir::PathResolution::SelfType(_) - | hir::PathResolution::DeriveHelper(_) => return None, - }; - - generic_def - } else if let Some(method_call) = arg_list.syntax().parent().and_then(ast::MethodCallExpr::cast) - { - // recv.method::<$0>() - let method = sema.resolve_method_call(&method_call)?; - method.into() - } else { - return None; - }; - - let mut res = SignatureHelp { - doc: None, - signature: String::new(), - parameters: vec![], - active_parameter: None, - }; - - let db = sema.db; - match generics_def { - hir::GenericDef::Function(it) => { - res.doc = it.docs(db).map(|it| it.into()); - format_to!(res.signature, "fn {}", it.name(db)); - } - hir::GenericDef::Adt(hir::Adt::Enum(it)) => { - res.doc = it.docs(db).map(|it| it.into()); - format_to!(res.signature, "enum {}", it.name(db)); - } - hir::GenericDef::Adt(hir::Adt::Struct(it)) => { - res.doc = it.docs(db).map(|it| it.into()); - format_to!(res.signature, "struct {}", it.name(db)); - } - hir::GenericDef::Adt(hir::Adt::Union(it)) => { - res.doc = it.docs(db).map(|it| it.into()); - format_to!(res.signature, "union {}", it.name(db)); - } - hir::GenericDef::Trait(it) => { - res.doc = it.docs(db).map(|it| it.into()); - format_to!(res.signature, "trait {}", it.name(db)); - } - hir::GenericDef::TypeAlias(it) => { - res.doc = it.docs(db).map(|it| it.into()); - format_to!(res.signature, "type {}", it.name(db)); - } - hir::GenericDef::Variant(it) => { - // In paths, generics of an enum can be specified *after* one of its variants. - // eg. `None::` - // We'll use the signature of the enum, but include the docs of the variant. - res.doc = it.docs(db).map(|it| it.into()); - let it = it.parent_enum(db); - format_to!(res.signature, "enum {}", it.name(db)); - generics_def = it.into(); - } - // These don't have generic args that can be specified - hir::GenericDef::Impl(_) | hir::GenericDef::Const(_) => return None, - } - - let params = generics_def.params(sema.db); - let num_lifetime_params = - params.iter().take_while(|param| matches!(param, GenericParam::LifetimeParam(_))).count(); - if first_arg_is_non_lifetime { - // Lifetime parameters were omitted. - active_parameter += num_lifetime_params; - } - res.active_parameter = Some(active_parameter); - - res.signature.push('<'); - let mut buf = String::new(); - for param in params { - if let hir::GenericParam::TypeParam(ty) = param { - if ty.is_implicit(db) { - continue; - } - } - - buf.clear(); - format_to!(buf, "{}", param.display(db)); - res.push_generic_param(&buf); - } - if let hir::GenericDef::Trait(tr) = generics_def { - add_assoc_type_bindings(db, &mut res, tr, arg_list); - } - res.signature.push('>'); - - Some(res) -} - -fn add_assoc_type_bindings( - db: &RootDatabase, - res: &mut SignatureHelp, - tr: Trait, - args: ast::GenericArgList, -) { - if args.syntax().ancestors().find_map(ast::TypeBound::cast).is_none() { - // Assoc type bindings are only valid in type bound position. - return; - } - - let present_bindings = args - .generic_args() - .filter_map(|arg| match arg { - ast::GenericArg::AssocTypeArg(arg) => arg.name_ref().map(|n| n.to_string()), - _ => None, - }) - .collect::>(); - - let mut buf = String::new(); - for binding in &present_bindings { - buf.clear(); - format_to!(buf, "{} = …", binding); - res.push_generic_param(&buf); - } - - for item in tr.items_with_supertraits(db) { - if let AssocItem::TypeAlias(ty) = item { - let name = ty.name(db).to_smol_str(); - if !present_bindings.contains(&*name) { - buf.clear(); - format_to!(buf, "{} = …", name); - res.push_generic_param(&buf); - } - } - } -} - -#[cfg(test)] -mod tests { - use std::iter; - - use expect_test::{expect, Expect}; - use ide_db::base_db::{fixture::ChangeFixture, FilePosition}; - use stdx::format_to; - - use crate::RootDatabase; - - /// Creates analysis from a multi-file fixture, returns positions marked with $0. - pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { - let change_fixture = ChangeFixture::parse(ra_fixture); - let mut database = RootDatabase::default(); - database.apply_change(change_fixture.change); - let (file_id, range_or_offset) = - change_fixture.file_position.expect("expected a marker ($0)"); - let offset = range_or_offset.expect_offset(); - (database, FilePosition { file_id, offset }) - } - - fn check(ra_fixture: &str, expect: Expect) { - // Implicitly add `Sized` to avoid noisy `T: ?Sized` in the results. - let fixture = format!( - r#" -#[lang = "sized"] trait Sized {{}} -{ra_fixture} - "# - ); - let (db, position) = position(&fixture); - let sig_help = crate::signature_help::signature_help(&db, position); - let actual = match sig_help { - Some(sig_help) => { - let mut rendered = String::new(); - if let Some(docs) = &sig_help.doc { - format_to!(rendered, "{}\n------\n", docs.as_str()); - } - format_to!(rendered, "{}\n", sig_help.signature); - let mut offset = 0; - for (i, range) in sig_help.parameter_ranges().iter().enumerate() { - let is_active = sig_help.active_parameter == Some(i); - - let start = u32::from(range.start()); - let gap = start.checked_sub(offset).unwrap_or_else(|| { - panic!("parameter ranges out of order: {:?}", sig_help.parameter_ranges()) - }); - rendered.extend(iter::repeat(' ').take(gap as usize)); - let param_text = &sig_help.signature[*range]; - let width = param_text.chars().count(); // … - let marker = if is_active { '^' } else { '-' }; - rendered.extend(iter::repeat(marker).take(width)); - offset += gap + u32::from(range.len()); - } - if !sig_help.parameter_ranges().is_empty() { - format_to!(rendered, "\n"); - } - rendered - } - None => String::new(), - }; - expect.assert_eq(&actual); - } - - #[test] - fn test_fn_signature_two_args() { - check( - r#" -fn foo(x: u32, y: u32) -> u32 {x + y} -fn bar() { foo($03, ); } -"#, - expect![[r#" - fn foo(x: u32, y: u32) -> u32 - ^^^^^^ ------ - "#]], - ); - check( - r#" -fn foo(x: u32, y: u32) -> u32 {x + y} -fn bar() { foo(3$0, ); } -"#, - expect![[r#" - fn foo(x: u32, y: u32) -> u32 - ^^^^^^ ------ - "#]], - ); - check( - r#" -fn foo(x: u32, y: u32) -> u32 {x + y} -fn bar() { foo(3,$0 ); } -"#, - expect![[r#" - fn foo(x: u32, y: u32) -> u32 - ------ ^^^^^^ - "#]], - ); - check( - r#" -fn foo(x: u32, y: u32) -> u32 {x + y} -fn bar() { foo(3, $0); } -"#, - expect![[r#" - fn foo(x: u32, y: u32) -> u32 - ------ ^^^^^^ - "#]], - ); - } - - #[test] - fn test_fn_signature_two_args_empty() { - check( - r#" -fn foo(x: u32, y: u32) -> u32 {x + y} -fn bar() { foo($0); } -"#, - expect![[r#" - fn foo(x: u32, y: u32) -> u32 - ^^^^^^ ------ - "#]], - ); - } - - #[test] - fn test_fn_signature_two_args_first_generics() { - check( - r#" -fn foo(x: T, y: U) -> u32 - where T: Copy + Display, U: Debug -{ x + y } - -fn bar() { foo($03, ); } -"#, - expect![[r#" - fn foo(x: i32, y: U) -> u32 - ^^^^^^ ---- - "#]], - ); - } - - #[test] - fn test_fn_signature_no_params() { - check( - r#" -fn foo() -> T where T: Copy + Display {} -fn bar() { foo($0); } -"#, - expect![[r#" - fn foo() -> T - "#]], - ); - } - - #[test] - fn test_fn_signature_for_impl() { - check( - r#" -struct F; -impl F { pub fn new() { } } -fn bar() { - let _ : F = F::new($0); -} -"#, - expect![[r#" - fn new() - "#]], - ); - } - - #[test] - fn test_fn_signature_for_method_self() { - check( - r#" -struct S; -impl S { pub fn do_it(&self) {} } - -fn bar() { - let s: S = S; - s.do_it($0); -} -"#, - expect![[r#" - fn do_it(&self) - "#]], - ); - } - - #[test] - fn test_fn_signature_for_method_with_arg() { - check( - r#" -struct S; -impl S { - fn foo(&self, x: i32) {} -} - -fn main() { S.foo($0); } -"#, - expect![[r#" - fn foo(&self, x: i32) - ^^^^^^ - "#]], - ); - } - - #[test] - fn test_fn_signature_for_generic_method() { - check( - r#" -struct S(T); -impl S { - fn foo(&self, x: T) {} -} - -fn main() { S(1u32).foo($0); } -"#, - expect![[r#" - fn foo(&self, x: u32) - ^^^^^^ - "#]], - ); - } - - #[test] - fn test_fn_signature_for_method_with_arg_as_assoc_fn() { - check( - r#" -struct S; -impl S { - fn foo(&self, x: i32) {} -} - -fn main() { S::foo($0); } -"#, - expect![[r#" - fn foo(self: &S, x: i32) - ^^^^^^^^ ------ - "#]], - ); - } - - #[test] - fn test_fn_signature_with_docs_simple() { - check( - r#" -/// test -// non-doc-comment -fn foo(j: u32) -> u32 { - j -} - -fn bar() { - let _ = foo($0); -} -"#, - expect![[r#" - test - ------ - fn foo(j: u32) -> u32 - ^^^^^^ - "#]], - ); - } - - #[test] - fn test_fn_signature_with_docs() { - check( - r#" -/// Adds one to the number given. -/// -/// # Examples -/// -/// ``` -/// let five = 5; -/// -/// assert_eq!(6, my_crate::add_one(5)); -/// ``` -pub fn add_one(x: i32) -> i32 { - x + 1 -} - -pub fn do() { - add_one($0 -}"#, - expect![[r##" - Adds one to the number given. - - # Examples - - ``` - let five = 5; - - assert_eq!(6, my_crate::add_one(5)); - ``` - ------ - fn add_one(x: i32) -> i32 - ^^^^^^ - "##]], - ); - } - - #[test] - fn test_fn_signature_with_docs_impl() { - check( - r#" -struct addr; -impl addr { - /// Adds one to the number given. - /// - /// # Examples - /// - /// ``` - /// let five = 5; - /// - /// assert_eq!(6, my_crate::add_one(5)); - /// ``` - pub fn add_one(x: i32) -> i32 { - x + 1 - } -} - -pub fn do_it() { - addr {}; - addr::add_one($0); -} -"#, - expect![[r##" - Adds one to the number given. - - # Examples - - ``` - let five = 5; - - assert_eq!(6, my_crate::add_one(5)); - ``` - ------ - fn add_one(x: i32) -> i32 - ^^^^^^ - "##]], - ); - } - - #[test] - fn test_fn_signature_with_docs_from_actix() { - check( - r#" -trait Actor { - /// Actor execution context type - type Context; -} -trait WriteHandler -where - Self: Actor -{ - /// Method is called when writer finishes. - /// - /// By default this method stops actor's `Context`. - fn finished(&mut self, ctx: &mut Self::Context) {} -} - -fn foo(mut r: impl WriteHandler<()>) { - r.finished($0); -} -"#, - expect![[r#" - Method is called when writer finishes. - - By default this method stops actor's `Context`. - ------ - fn finished(&mut self, ctx: &mut as Actor>::Context) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - "#]], - ); - } - - #[test] - fn call_info_bad_offset() { - check( - r#" -fn foo(x: u32, y: u32) -> u32 {x + y} -fn bar() { foo $0 (3, ); } -"#, - expect![[""]], - ); - } - - #[test] - fn outside_of_arg_list() { - check( - r#" -fn foo(a: u8) {} -fn f() { - foo(123)$0 -} -"#, - expect![[]], - ); - check( - r#" -fn foo(a: u8) {} -fn f() { - foo::$0() -} -"#, - expect![[]], - ); - } - - #[test] - fn test_nested_method_in_lambda() { - check( - r#" -struct Foo; -impl Foo { fn bar(&self, _: u32) { } } - -fn bar(_: u32) { } - -fn main() { - let foo = Foo; - std::thread::spawn(move || foo.bar($0)); -} -"#, - expect![[r#" - fn bar(&self, _: u32) - ^^^^^^ - "#]], - ); - } - - #[test] - fn works_for_tuple_structs() { - check( - r#" -/// A cool tuple struct -struct S(u32, i32); -fn main() { - let s = S(0, $0); -} -"#, - expect![[r#" - A cool tuple struct - ------ - struct S(u32, i32) - --- ^^^ - "#]], - ); - } - - #[test] - fn generic_struct() { - check( - r#" -struct S(T); -fn main() { - let s = S($0); -} -"#, - expect![[r#" - struct S({unknown}) - ^^^^^^^^^ - "#]], - ); - } - - #[test] - fn works_for_enum_variants() { - check( - r#" -enum E { - /// A Variant - A(i32), - /// Another - B, - /// And C - C { a: i32, b: i32 } -} - -fn main() { - let a = E::A($0); -} -"#, - expect![[r#" - A Variant - ------ - enum E::A(i32) - ^^^ - "#]], - ); - } - - #[test] - fn cant_call_struct_record() { - check( - r#" -struct S { x: u32, y: i32 } -fn main() { - let s = S($0); -} -"#, - expect![[""]], - ); - } - - #[test] - fn cant_call_enum_record() { - check( - r#" -enum E { - /// A Variant - A(i32), - /// Another - B, - /// And C - C { a: i32, b: i32 } -} - -fn main() { - let a = E::C($0); -} -"#, - expect![[""]], - ); - } - - #[test] - fn fn_signature_for_call_in_macro() { - check( - r#" -macro_rules! id { ($($tt:tt)*) => { $($tt)* } } -fn foo() { } -id! { - fn bar() { foo($0); } -} -"#, - expect![[r#" - fn foo() - "#]], - ); - } - - #[test] - fn call_info_for_lambdas() { - check( - r#" -struct S; -fn foo(s: S) -> i32 { 92 } -fn main() { - (|s| foo(s))($0) -} - "#, - expect![[r#" - (s: S) -> i32 - ^^^^ - "#]], - ) - } - - #[test] - fn call_info_for_fn_ptr() { - check( - r#" -fn main(f: fn(i32, f64) -> char) { - f(0, $0) -} - "#, - expect![[r#" - (i32, f64) -> char - --- ^^^ - "#]], - ) - } - - #[test] - fn call_info_for_unclosed_call() { - check( - r#" -fn foo(foo: u32, bar: u32) {} -fn main() { - foo($0 -}"#, - expect![[r#" - fn foo(foo: u32, bar: u32) - ^^^^^^^^ -------- - "#]], - ); - // check with surrounding space - check( - r#" -fn foo(foo: u32, bar: u32) {} -fn main() { - foo( $0 -}"#, - expect![[r#" - fn foo(foo: u32, bar: u32) - ^^^^^^^^ -------- - "#]], - ) - } - - #[test] - fn test_multiline_argument() { - check( - r#" -fn callee(a: u8, b: u8) {} -fn main() { - callee(match 0 { - 0 => 1,$0 - }) -}"#, - expect![[r#""#]], - ); - check( - r#" -fn callee(a: u8, b: u8) {} -fn main() { - callee(match 0 { - 0 => 1, - },$0) -}"#, - expect![[r#" - fn callee(a: u8, b: u8) - ----- ^^^^^ - "#]], - ); - check( - r#" -fn callee(a: u8, b: u8) {} -fn main() { - callee($0match 0 { - 0 => 1, - }) -}"#, - expect![[r#" - fn callee(a: u8, b: u8) - ^^^^^ ----- - "#]], - ); - } - - #[test] - fn test_generics_simple() { - check( - r#" -/// Option docs. -enum Option { - Some(T), - None, -} - -fn f() { - let opt: Option<$0 -} - "#, - expect![[r#" - Option docs. - ------ - enum Option - ^ - "#]], - ); - } - - #[test] - fn test_generics_on_variant() { - check( - r#" -/// Option docs. -enum Option { - /// Some docs. - Some(T), - /// None docs. - None, -} - -use Option::*; - -fn f() { - None::<$0 -} - "#, - expect![[r#" - None docs. - ------ - enum Option - ^ - "#]], - ); - } - - #[test] - fn test_lots_of_generics() { - check( - r#" -trait Tr {} - -struct S(T); - -impl S { - fn f(g: G, h: impl Tr) where G: Tr<()> {} -} - -fn f() { - S::::f::<(), $0 -} - "#, - expect![[r#" - fn f, H> - --------- ^ - "#]], - ); - } - - #[test] - fn test_generics_in_trait_ufcs() { - check( - r#" -trait Tr { - fn f() {} -} - -struct S; - -impl Tr for S {} - -fn f() { - ::f::<$0 -} - "#, - expect![[r#" - fn f - ^^^^^ - - "#]], - ); - } - - #[test] - fn test_generics_in_method_call() { - check( - r#" -struct S; - -impl S { - fn f(&self) {} -} - -fn f() { - S.f::<$0 -} - "#, - expect![[r#" - fn f - ^ - "#]], - ); - } - - #[test] - fn test_generic_param_in_method_call() { - check( - r#" -struct Foo; -impl Foo { - fn test(&mut self, val: V) {} -} -fn sup() { - Foo.test($0) -} -"#, - expect![[r#" - fn test(&mut self, val: V) - ^^^^^^ - "#]], - ); - } - - #[test] - fn test_generic_kinds() { - check( - r#" -fn callee<'a, const A: u8, T, const C: u8>() {} - -fn f() { - callee::<'static, $0 -} - "#, - expect![[r#" - fn callee<'a, const A: u8, T, const C: u8> - -- ^^^^^^^^^^^ - ----------- - "#]], - ); - check( - r#" -fn callee<'a, const A: u8, T, const C: u8>() {} - -fn f() { - callee:: - -- ^^^^^^^^^^^ - ----------- - "#]], - ); - } - - #[test] - fn test_trait_assoc_types() { - check( - r#" -trait Trait<'a, T> { - type Assoc; -} -fn f() -> impl Trait<(), $0 - "#, - expect![[r#" - trait Trait<'a, T, Assoc = …> - -- - ^^^^^^^^^ - "#]], - ); - check( - r#" -trait Iterator { - type Item; -} -fn f() -> impl Iterator<$0 - "#, - expect![[r#" - trait Iterator - ^^^^^^^^ - "#]], - ); - check( - r#" -trait Iterator { - type Item; -} -fn f() -> impl Iterator - ^^^^^^^^ - "#]], - ); - check( - r#" -trait Tr { - type A; - type B; -} -fn f() -> impl Tr<$0 - "#, - expect![[r#" - trait Tr - ^^^^^ ----- - "#]], - ); - check( - r#" -trait Tr { - type A; - type B; -} -fn f() -> impl Tr - ^^^^^ ----- - "#]], - ); - check( - r#" -trait Tr { - type A; - type B; -} -fn f() -> impl Tr - ^^^^^ ----- - "#]], - ); - check( - r#" -trait Tr { - type A; - type B; -} -fn f() -> impl Tr - ----- ^^^^^ - "#]], - ); - } - - #[test] - fn test_supertrait_assoc() { - check( - r#" -trait Super { - type SuperTy; -} -trait Sub: Super + Super { - type SubTy; -} -fn f() -> impl Sub<$0 - "#, - expect![[r#" - trait Sub - ^^^^^^^^^ ----------- - "#]], - ); - } - - #[test] - fn no_assoc_types_outside_type_bounds() { - check( - r#" -trait Tr { - type Assoc; -} - -impl Tr<$0 - "#, - expect![[r#" - trait Tr - ^ - "#]], - ); - } - - #[test] - fn impl_trait() { - // FIXME: Substitute type vars in impl trait (`U` -> `i8`) - check( - r#" -trait Trait {} -struct Wrap(T); -fn foo(x: Wrap>) {} -fn f() { - foo::($0) -} -"#, - expect![[r#" - fn foo(x: Wrap>) - ^^^^^^^^^^^^^^^^^^^^^^ - "#]], - ); - } - - #[test] - fn fully_qualified_syntax() { - check( - r#" -fn f() { - trait A { fn foo(&self, other: Self); } - A::foo(&self$0, other); -} -"#, - expect![[r#" - fn foo(self: &Self, other: Self) - ^^^^^^^^^^^ ----------- - "#]], - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/ssr.rs b/src/tools/rust-analyzer/crates/ide/src/ssr.rs deleted file mode 100644 index 497eb1cc130d5..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/ssr.rs +++ /dev/null @@ -1,255 +0,0 @@ -//! This module provides an SSR assist. It is not desirable to include this -//! assist in ide_assists because that would require the ide_assists crate -//! depend on the ide_ssr crate. - -use ide_assists::{Assist, AssistId, AssistKind, AssistResolveStrategy, GroupLabel}; -use ide_db::{base_db::FileRange, label::Label, source_change::SourceChange, RootDatabase}; - -pub(crate) fn ssr_assists( - db: &RootDatabase, - resolve: &AssistResolveStrategy, - frange: FileRange, -) -> Vec { - let mut ssr_assists = Vec::with_capacity(2); - - let (match_finder, comment_range) = match ide_ssr::ssr_from_comment(db, frange) { - Some(ssr_data) => ssr_data, - None => return ssr_assists, - }; - let id = AssistId("ssr", AssistKind::RefactorRewrite); - - let (source_change_for_file, source_change_for_workspace) = if resolve.should_resolve(&id) { - let edits = match_finder.edits(); - - let source_change_for_file = { - let text_edit_for_file = edits.get(&frange.file_id).cloned().unwrap_or_default(); - SourceChange::from_text_edit(frange.file_id, text_edit_for_file) - }; - - let source_change_for_workspace = SourceChange::from(match_finder.edits()); - - (Some(source_change_for_file), Some(source_change_for_workspace)) - } else { - (None, None) - }; - - let assists = vec![ - ("Apply SSR in file", source_change_for_file), - ("Apply SSR in workspace", source_change_for_workspace), - ]; - - for (label, source_change) in assists.into_iter() { - let assist = Assist { - id, - label: Label::new(label.to_string()), - group: Some(GroupLabel("Apply SSR".into())), - target: comment_range, - source_change, - trigger_signature_help: false, - }; - - ssr_assists.push(assist); - } - - ssr_assists -} - -#[cfg(test)] -mod tests { - use std::sync::Arc; - - use expect_test::expect; - use ide_assists::{Assist, AssistResolveStrategy}; - use ide_db::{ - base_db::{fixture::WithFixture, salsa::Durability, FileRange}, - symbol_index::SymbolsDatabase, - FxHashSet, RootDatabase, - }; - - use super::ssr_assists; - - fn get_assists(ra_fixture: &str, resolve: AssistResolveStrategy) -> Vec { - let (mut db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture); - let mut local_roots = FxHashSet::default(); - local_roots.insert(ide_db::base_db::fixture::WORKSPACE); - db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH); - ssr_assists(&db, &resolve, FileRange { file_id, range: range_or_offset.into() }) - } - - #[test] - fn not_applicable_comment_not_ssr() { - let ra_fixture = r#" - //- /lib.rs - - // This is foo $0 - fn foo() {} - "#; - let assists = get_assists(ra_fixture, AssistResolveStrategy::All); - - assert_eq!(0, assists.len()); - } - - #[test] - fn resolve_edits_true() { - let assists = get_assists( - r#" - //- /lib.rs - mod bar; - - // 2 ==>> 3$0 - fn foo() { 2 } - - //- /bar.rs - fn bar() { 2 } - "#, - AssistResolveStrategy::All, - ); - - assert_eq!(2, assists.len()); - let mut assists = assists.into_iter(); - - let apply_in_file_assist = assists.next().unwrap(); - expect![[r#" - Assist { - id: AssistId( - "ssr", - RefactorRewrite, - ), - label: "Apply SSR in file", - group: Some( - GroupLabel( - "Apply SSR", - ), - ), - target: 10..21, - source_change: Some( - SourceChange { - source_file_edits: { - FileId( - 0, - ): TextEdit { - indels: [ - Indel { - insert: "3", - delete: 33..34, - }, - ], - }, - }, - file_system_edits: [], - is_snippet: false, - }, - ), - trigger_signature_help: false, - } - "#]] - .assert_debug_eq(&apply_in_file_assist); - - let apply_in_workspace_assist = assists.next().unwrap(); - expect![[r#" - Assist { - id: AssistId( - "ssr", - RefactorRewrite, - ), - label: "Apply SSR in workspace", - group: Some( - GroupLabel( - "Apply SSR", - ), - ), - target: 10..21, - source_change: Some( - SourceChange { - source_file_edits: { - FileId( - 0, - ): TextEdit { - indels: [ - Indel { - insert: "3", - delete: 33..34, - }, - ], - }, - FileId( - 1, - ): TextEdit { - indels: [ - Indel { - insert: "3", - delete: 11..12, - }, - ], - }, - }, - file_system_edits: [], - is_snippet: false, - }, - ), - trigger_signature_help: false, - } - "#]] - .assert_debug_eq(&apply_in_workspace_assist); - } - - #[test] - fn resolve_edits_false() { - let assists = get_assists( - r#" - //- /lib.rs - mod bar; - - // 2 ==>> 3$0 - fn foo() { 2 } - - //- /bar.rs - fn bar() { 2 } - "#, - AssistResolveStrategy::None, - ); - - assert_eq!(2, assists.len()); - let mut assists = assists.into_iter(); - - let apply_in_file_assist = assists.next().unwrap(); - expect![[r#" - Assist { - id: AssistId( - "ssr", - RefactorRewrite, - ), - label: "Apply SSR in file", - group: Some( - GroupLabel( - "Apply SSR", - ), - ), - target: 10..21, - source_change: None, - trigger_signature_help: false, - } - "#]] - .assert_debug_eq(&apply_in_file_assist); - - let apply_in_workspace_assist = assists.next().unwrap(); - expect![[r#" - Assist { - id: AssistId( - "ssr", - RefactorRewrite, - ), - label: "Apply SSR in workspace", - group: Some( - GroupLabel( - "Apply SSR", - ), - ), - target: 10..21, - source_change: None, - trigger_signature_help: false, - } - "#]] - .assert_debug_eq(&apply_in_workspace_assist); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs deleted file mode 100644 index d74b640415c76..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ /dev/null @@ -1,321 +0,0 @@ -//! This module provides `StaticIndex` which is used for powering -//! read-only code browsers and emitting LSIF - -use std::collections::HashMap; - -use hir::{db::HirDatabase, Crate, Module, Semantics}; -use ide_db::{ - base_db::{FileId, FileRange, SourceDatabaseExt}, - defs::{Definition, IdentClass}, - FxHashSet, RootDatabase, -}; -use syntax::{AstNode, SyntaxKind::*, SyntaxToken, TextRange, T}; - -use crate::{ - hover::hover_for_definition, - moniker::{crate_for_file, def_to_moniker, MonikerResult}, - Analysis, Fold, HoverConfig, HoverDocFormat, HoverResult, InlayHint, InlayHintsConfig, - TryToNav, -}; - -/// A static representation of fully analyzed source code. -/// -/// The intended use-case is powering read-only code browsers and emitting LSIF -#[derive(Debug)] -pub struct StaticIndex<'a> { - pub files: Vec, - pub tokens: TokenStore, - analysis: &'a Analysis, - db: &'a RootDatabase, - def_map: HashMap, -} - -#[derive(Debug)] -pub struct ReferenceData { - pub range: FileRange, - pub is_definition: bool, -} - -#[derive(Debug)] -pub struct TokenStaticData { - pub hover: Option, - pub definition: Option, - pub references: Vec, - pub moniker: Option, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct TokenId(usize); - -impl TokenId { - pub fn raw(self) -> usize { - self.0 - } -} - -#[derive(Default, Debug)] -pub struct TokenStore(Vec); - -impl TokenStore { - pub fn insert(&mut self, data: TokenStaticData) -> TokenId { - let id = TokenId(self.0.len()); - self.0.push(data); - id - } - - pub fn get_mut(&mut self, id: TokenId) -> Option<&mut TokenStaticData> { - self.0.get_mut(id.0) - } - - pub fn get(&self, id: TokenId) -> Option<&TokenStaticData> { - self.0.get(id.0) - } - - pub fn iter(self) -> impl Iterator { - self.0.into_iter().enumerate().map(|(i, x)| (TokenId(i), x)) - } -} - -#[derive(Debug)] -pub struct StaticIndexedFile { - pub file_id: FileId, - pub folds: Vec, - pub inlay_hints: Vec, - pub tokens: Vec<(TextRange, TokenId)>, -} - -fn all_modules(db: &dyn HirDatabase) -> Vec { - let mut worklist: Vec<_> = - Crate::all(db).into_iter().map(|krate| krate.root_module(db)).collect(); - let mut modules = Vec::new(); - - while let Some(module) = worklist.pop() { - modules.push(module); - worklist.extend(module.children(db)); - } - - modules -} - -impl StaticIndex<'_> { - fn add_file(&mut self, file_id: FileId) { - let current_crate = crate_for_file(self.db, file_id); - let folds = self.analysis.folding_ranges(file_id).unwrap(); - let inlay_hints = self - .analysis - .inlay_hints( - &InlayHintsConfig { - render_colons: true, - type_hints: true, - parameter_hints: true, - chaining_hints: true, - closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock, - lifetime_elision_hints: crate::LifetimeElisionHints::Never, - reborrow_hints: crate::ReborrowHints::Never, - hide_named_constructor_hints: false, - hide_closure_initialization_hints: false, - param_names_for_lifetime_elision_hints: false, - binding_mode_hints: false, - max_length: Some(25), - closing_brace_hints_min_lines: Some(25), - }, - file_id, - None, - ) - .unwrap(); - // hovers - let sema = hir::Semantics::new(self.db); - let tokens_or_nodes = sema.parse(file_id).syntax().clone(); - let tokens = tokens_or_nodes.descendants_with_tokens().filter_map(|x| match x { - syntax::NodeOrToken::Node(_) => None, - syntax::NodeOrToken::Token(x) => Some(x), - }); - let hover_config = - HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::Markdown) }; - let tokens = tokens.filter(|token| { - matches!( - token.kind(), - IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self] - ) - }); - let mut result = StaticIndexedFile { file_id, inlay_hints, folds, tokens: vec![] }; - for token in tokens { - let range = token.text_range(); - let node = token.parent().unwrap(); - let def = match get_definition(&sema, token.clone()) { - Some(x) => x, - None => continue, - }; - let id = if let Some(x) = self.def_map.get(&def) { - *x - } else { - let x = self.tokens.insert(TokenStaticData { - hover: hover_for_definition(&sema, file_id, def, &node, &hover_config), - definition: def - .try_to_nav(self.db) - .map(|x| FileRange { file_id: x.file_id, range: x.focus_or_full_range() }), - references: vec![], - moniker: current_crate.and_then(|cc| def_to_moniker(self.db, def, cc)), - }); - self.def_map.insert(def, x); - x - }; - let token = self.tokens.get_mut(id).unwrap(); - token.references.push(ReferenceData { - range: FileRange { range, file_id }, - is_definition: match def.try_to_nav(self.db) { - Some(x) => x.file_id == file_id && x.focus_or_full_range() == range, - None => false, - }, - }); - result.tokens.push((range, id)); - } - self.files.push(result); - } - - pub fn compute(analysis: &Analysis) -> StaticIndex<'_> { - let db = &*analysis.db; - let work = all_modules(db).into_iter().filter(|module| { - let file_id = module.definition_source(db).file_id.original_file(db); - let source_root = db.file_source_root(file_id); - let source_root = db.source_root(source_root); - !source_root.is_library - }); - let mut this = StaticIndex { - files: vec![], - tokens: Default::default(), - analysis, - db, - def_map: Default::default(), - }; - let mut visited_files = FxHashSet::default(); - for module in work { - let file_id = module.definition_source(db).file_id.original_file(db); - if visited_files.contains(&file_id) { - continue; - } - this.add_file(file_id); - // mark the file - visited_files.insert(file_id); - } - this - } -} - -fn get_definition(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option { - for token in sema.descend_into_macros(token) { - let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions); - if let Some(&[x]) = def.as_deref() { - return Some(x); - } else { - continue; - }; - } - None -} - -#[cfg(test)] -mod tests { - use crate::{fixture, StaticIndex}; - use ide_db::base_db::FileRange; - use std::collections::HashSet; - use syntax::TextSize; - - fn check_all_ranges(ra_fixture: &str) { - let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture); - let s = StaticIndex::compute(&analysis); - let mut range_set: HashSet<_> = ranges.iter().map(|x| x.0).collect(); - for f in s.files { - for (range, _) in f.tokens { - let x = FileRange { file_id: f.file_id, range }; - if !range_set.contains(&x) { - panic!("additional range {:?}", x); - } - range_set.remove(&x); - } - } - if !range_set.is_empty() { - panic!("unfound ranges {:?}", range_set); - } - } - - fn check_definitions(ra_fixture: &str) { - let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture); - let s = StaticIndex::compute(&analysis); - let mut range_set: HashSet<_> = ranges.iter().map(|x| x.0).collect(); - for (_, t) in s.tokens.iter() { - if let Some(x) = t.definition { - if x.range.start() == TextSize::from(0) { - // ignore definitions that are whole of file - continue; - } - if !range_set.contains(&x) { - panic!("additional definition {:?}", x); - } - range_set.remove(&x); - } - } - if !range_set.is_empty() { - panic!("unfound definitions {:?}", range_set); - } - } - - #[test] - fn struct_and_enum() { - check_all_ranges( - r#" -struct Foo; - //^^^ -enum E { X(Foo) } - //^ ^ ^^^ -"#, - ); - check_definitions( - r#" -struct Foo; - //^^^ -enum E { X(Foo) } - //^ ^ -"#, - ); - } - - #[test] - fn multi_crate() { - check_definitions( - r#" -//- /main.rs crate:main deps:foo - - -use foo::func; - -fn main() { - //^^^^ - func(); -} -//- /foo/lib.rs crate:foo - -pub func() { - -} -"#, - ); - } - - #[test] - fn derives() { - check_all_ranges( - r#" -//- minicore:derive -#[rustc_builtin_macro] -//^^^^^^^^^^^^^^^^^^^ -pub macro Copy {} - //^^^^ -#[derive(Copy)] -//^^^^^^ ^^^^ -struct Hello(i32); - //^^^^^ ^^^ -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/status.rs b/src/tools/rust-analyzer/crates/ide/src/status.rs deleted file mode 100644 index 3191870eb5e8f..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/status.rs +++ /dev/null @@ -1,164 +0,0 @@ -use std::{fmt, iter::FromIterator, sync::Arc}; - -use hir::{ExpandResult, MacroFile}; -use ide_db::base_db::{ - salsa::debug::{DebugQueryTable, TableEntry}, - CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId, -}; -use ide_db::{ - symbol_index::{LibrarySymbolsQuery, SymbolIndex}, - RootDatabase, -}; -use itertools::Itertools; -use profile::{memory_usage, Bytes}; -use std::env; -use stdx::format_to; -use syntax::{ast, Parse, SyntaxNode}; - -fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { - ide_db::base_db::ParseQuery.in_db(db).entries::() -} -fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { - hir::db::ParseMacroExpansionQuery.in_db(db).entries::() -} - -// Feature: Status -// -// Shows internal statistic about memory usage of rust-analyzer. -// -// |=== -// | Editor | Action Name -// -// | VS Code | **Rust Analyzer: Status** -// |=== -// image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[] -pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { - let mut buf = String::new(); - format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::()); - format_to!(buf, "{}\n", LibrarySymbolsQuery.in_db(db).entries::()); - format_to!(buf, "{}\n", syntax_tree_stats(db)); - format_to!(buf, "{} (Macros)\n", macro_syntax_tree_stats(db)); - format_to!(buf, "{} in total\n", memory_usage()); - if env::var("RA_COUNT").is_ok() { - format_to!(buf, "\nCounts:\n{}", profile::countme::get_all()); - } - - if let Some(file_id) = file_id { - format_to!(buf, "\nFile info:\n"); - let crates = crate::parent_module::crate_for(db, file_id); - if crates.is_empty() { - format_to!(buf, "Does not belong to any crate"); - } - let crate_graph = db.crate_graph(); - for krate in crates { - let display_crate = |krate: CrateId| match &crate_graph[krate].display_name { - Some(it) => format!("{}({:?})", it, krate), - None => format!("{:?}", krate), - }; - format_to!(buf, "Crate: {}\n", display_crate(krate)); - let deps = crate_graph[krate] - .dependencies - .iter() - .map(|dep| format!("{}={:?}", dep.name, dep.crate_id)) - .format(", "); - format_to!(buf, "Dependencies: {}\n", deps); - } - } - - buf.trim().to_string() -} - -#[derive(Default)] -struct FilesStats { - total: usize, - size: Bytes, -} - -impl fmt::Display for FilesStats { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "{} of files", self.size) - } -} - -impl FromIterator>> for FilesStats { - fn from_iter(iter: T) -> FilesStats - where - T: IntoIterator>>, - { - let mut res = FilesStats::default(); - for entry in iter { - res.total += 1; - res.size += entry.value.unwrap().len(); - } - res - } -} - -#[derive(Default)] -pub(crate) struct SyntaxTreeStats { - total: usize, - pub(crate) retained: usize, -} - -impl fmt::Display for SyntaxTreeStats { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "{} trees, {} preserved", self.total, self.retained) - } -} - -impl FromIterator>> for SyntaxTreeStats { - fn from_iter(iter: T) -> SyntaxTreeStats - where - T: IntoIterator>>, - { - let mut res = SyntaxTreeStats::default(); - for entry in iter { - res.total += 1; - res.retained += entry.value.is_some() as usize; - } - res - } -} - -impl FromIterator, M)>>>> - for SyntaxTreeStats -{ - fn from_iter(iter: T) -> SyntaxTreeStats - where - T: IntoIterator, M)>>>>, - { - let mut res = SyntaxTreeStats::default(); - for entry in iter { - res.total += 1; - res.retained += entry.value.is_some() as usize; - } - res - } -} - -#[derive(Default)] -struct LibrarySymbolsStats { - total: usize, - size: Bytes, -} - -impl fmt::Display for LibrarySymbolsStats { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "{} of index symbols ({})", self.size, self.total) - } -} - -impl FromIterator>> for LibrarySymbolsStats { - fn from_iter(iter: T) -> LibrarySymbolsStats - where - T: IntoIterator>>, - { - let mut res = LibrarySymbolsStats::default(); - for entry in iter { - let symbols = entry.value.unwrap(); - res.total += symbols.len(); - res.size += symbols.memory_size(); - } - res - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs deleted file mode 100644 index d013d6f4b19ff..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ /dev/null @@ -1,449 +0,0 @@ -pub(crate) mod tags; - -mod highlights; -mod injector; - -mod highlight; -mod format; -mod macro_; -mod inject; -mod escape; - -mod html; -#[cfg(test)] -mod tests; - -use hir::{InFile, Name, Semantics}; -use ide_db::{FxHashMap, RootDatabase}; -use syntax::{ - ast, AstNode, AstToken, NodeOrToken, SyntaxKind::*, SyntaxNode, TextRange, WalkEvent, T, -}; - -use crate::{ - syntax_highlighting::{ - escape::highlight_escape_string, format::highlight_format_string, highlights::Highlights, - macro_::MacroHighlighter, tags::Highlight, - }, - FileId, HlMod, HlTag, -}; - -pub(crate) use html::highlight_as_html; - -#[derive(Debug, Clone, Copy)] -pub struct HlRange { - pub range: TextRange, - pub highlight: Highlight, - pub binding_hash: Option, -} - -// Feature: Semantic Syntax Highlighting -// -// rust-analyzer highlights the code semantically. -// For example, `Bar` in `foo::Bar` might be colored differently depending on whether `Bar` is an enum or a trait. -// rust-analyzer does not specify colors directly, instead it assigns a tag (like `struct`) and a set of modifiers (like `declaration`) to each token. -// It's up to the client to map those to specific colors. -// -// The general rule is that a reference to an entity gets colored the same way as the entity itself. -// We also give special modifier for `mut` and `&mut` local variables. -// -// -// .Token Tags -// -// Rust-analyzer currently emits the following token tags: -// -// - For items: -// + -// [horizontal] -// attribute:: Emitted for attribute macros. -// enum:: Emitted for enums. -// function:: Emitted for free-standing functions. -// derive:: Emitted for derive macros. -// macro:: Emitted for function-like macros. -// method:: Emitted for associated functions, also knowns as methods. -// namespace:: Emitted for modules. -// struct:: Emitted for structs. -// trait:: Emitted for traits. -// typeAlias:: Emitted for type aliases and `Self` in `impl`s. -// union:: Emitted for unions. -// -// - For literals: -// + -// [horizontal] -// boolean:: Emitted for the boolean literals `true` and `false`. -// character:: Emitted for character literals. -// number:: Emitted for numeric literals. -// string:: Emitted for string literals. -// escapeSequence:: Emitted for escaped sequences inside strings like `\n`. -// formatSpecifier:: Emitted for format specifiers `{:?}` in `format!`-like macros. -// -// - For operators: -// + -// [horizontal] -// operator:: Emitted for general operators. -// arithmetic:: Emitted for the arithmetic operators `+`, `-`, `*`, `/`, `+=`, `-=`, `*=`, `/=`. -// bitwise:: Emitted for the bitwise operators `|`, `&`, `!`, `^`, `|=`, `&=`, `^=`. -// comparison:: Emitted for the comparison operators `>`, `<`, `==`, `>=`, `<=`, `!=`. -// logical:: Emitted for the logical operators `||`, `&&`, `!`. -// -// - For punctuation: -// + -// [horizontal] -// punctuation:: Emitted for general punctuation. -// attributeBracket:: Emitted for attribute invocation brackets, that is the `#[` and `]` tokens. -// angle:: Emitted for `<>` angle brackets. -// brace:: Emitted for `{}` braces. -// bracket:: Emitted for `[]` brackets. -// parenthesis:: Emitted for `()` parentheses. -// colon:: Emitted for the `:` token. -// comma:: Emitted for the `,` token. -// dot:: Emitted for the `.` token. -// semi:: Emitted for the `;` token. -// macroBang:: Emitted for the `!` token in macro calls. -// -// //- -// -// [horizontal] -// builtinAttribute:: Emitted for names to builtin attributes in attribute path, the `repr` in `#[repr(u8)]` for example. -// builtinType:: Emitted for builtin types like `u32`, `str` and `f32`. -// comment:: Emitted for comments. -// constParameter:: Emitted for const parameters. -// deriveHelper:: Emitted for derive helper attributes. -// enumMember:: Emitted for enum variants. -// generic:: Emitted for generic tokens that have no mapping. -// keyword:: Emitted for keywords. -// label:: Emitted for labels. -// lifetime:: Emitted for lifetimes. -// parameter:: Emitted for non-self function parameters. -// property:: Emitted for struct and union fields. -// selfKeyword:: Emitted for the self function parameter and self path-specifier. -// selfTypeKeyword:: Emitted for the Self type parameter. -// toolModule:: Emitted for tool modules. -// typeParameter:: Emitted for type parameters. -// unresolvedReference:: Emitted for unresolved references, names that rust-analyzer can't find the definition of. -// variable:: Emitted for locals, constants and statics. -// -// -// .Token Modifiers -// -// Token modifiers allow to style some elements in the source code more precisely. -// -// Rust-analyzer currently emits the following token modifiers: -// -// [horizontal] -// async:: Emitted for async functions and the `async` and `await` keywords. -// attribute:: Emitted for tokens inside attributes. -// callable:: Emitted for locals whose types implements one of the `Fn*` traits. -// constant:: Emitted for consts. -// consuming:: Emitted for locals that are being consumed when use in a function call. -// controlFlow:: Emitted for control-flow related tokens, this includes the `?` operator. -// crateRoot:: Emitted for crate names, like `serde` and `crate`. -// declaration:: Emitted for names of definitions, like `foo` in `fn foo() {}`. -// defaultLibrary:: Emitted for items from built-in crates (std, core, alloc, test and proc_macro). -// documentation:: Emitted for documentation comments. -// injected:: Emitted for doc-string injected highlighting like rust source blocks in documentation. -// intraDocLink:: Emitted for intra doc links in doc-strings. -// library:: Emitted for items that are defined outside of the current crate. -// mutable:: Emitted for mutable locals and statics as well as functions taking `&mut self`. -// public:: Emitted for items that are from the current crate and are `pub`. -// reference:: Emitted for locals behind a reference and functions taking `self` by reference. -// static:: Emitted for "static" functions, also known as functions that do not take a `self` param, as well as statics and consts. -// trait:: Emitted for associated trait items. -// unsafe:: Emitted for unsafe operations, like unsafe function calls, as well as the `unsafe` token. -// -// -// image::https://user-images.githubusercontent.com/48062697/113164457-06cfb980-9239-11eb-819b-0f93e646acf8.png[] -// image::https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png[] -pub(crate) fn highlight( - db: &RootDatabase, - file_id: FileId, - range_to_highlight: Option, - syntactic_name_ref_highlighting: bool, -) -> Vec { - let _p = profile::span("highlight"); - let sema = Semantics::new(db); - - // Determine the root based on the given range. - let (root, range_to_highlight) = { - let source_file = sema.parse(file_id); - let source_file = source_file.syntax(); - match range_to_highlight { - Some(range) => { - let node = match source_file.covering_element(range) { - NodeOrToken::Node(it) => it, - NodeOrToken::Token(it) => it.parent().unwrap_or_else(|| source_file.clone()), - }; - (node, range) - } - None => (source_file.clone(), source_file.text_range()), - } - }; - - let mut hl = highlights::Highlights::new(root.text_range()); - let krate = match sema.scope(&root) { - Some(it) => it.krate(), - None => return hl.to_vec(), - }; - traverse( - &mut hl, - &sema, - file_id, - &root, - krate, - range_to_highlight, - syntactic_name_ref_highlighting, - ); - hl.to_vec() -} - -fn traverse( - hl: &mut Highlights, - sema: &Semantics<'_, RootDatabase>, - file_id: FileId, - root: &SyntaxNode, - krate: hir::Crate, - range_to_highlight: TextRange, - syntactic_name_ref_highlighting: bool, -) { - let is_unlinked = sema.to_module_def(file_id).is_none(); - let mut bindings_shadow_count: FxHashMap = FxHashMap::default(); - - enum AttrOrDerive { - Attr(ast::Item), - Derive(ast::Item), - } - - impl AttrOrDerive { - fn item(&self) -> &ast::Item { - match self { - AttrOrDerive::Attr(item) | AttrOrDerive::Derive(item) => item, - } - } - } - - let mut tt_level = 0; - let mut attr_or_derive_item = None; - let mut current_macro: Option = None; - let mut macro_highlighter = MacroHighlighter::default(); - let mut inside_attribute = false; - - // Walk all nodes, keeping track of whether we are inside a macro or not. - // If in macro, expand it first and highlight the expanded code. - for event in root.preorder_with_tokens() { - use WalkEvent::{Enter, Leave}; - - let range = match &event { - Enter(it) | Leave(it) => it.text_range(), - }; - - // Element outside of the viewport, no need to highlight - if range_to_highlight.intersect(range).is_none() { - continue; - } - - // set macro and attribute highlighting states - match event.clone() { - Enter(NodeOrToken::Node(node)) if ast::TokenTree::can_cast(node.kind()) => { - tt_level += 1; - } - Leave(NodeOrToken::Node(node)) if ast::TokenTree::can_cast(node.kind()) => { - tt_level -= 1; - } - Enter(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => { - inside_attribute = true - } - Leave(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => { - inside_attribute = false - } - - Enter(NodeOrToken::Node(node)) if ast::Item::can_cast(node.kind()) => { - match ast::Item::cast(node.clone()) { - Some(ast::Item::MacroRules(mac)) => { - macro_highlighter.init(); - current_macro = Some(mac.into()); - continue; - } - Some(ast::Item::MacroDef(mac)) => { - macro_highlighter.init(); - current_macro = Some(mac.into()); - continue; - } - Some(item) => { - if matches!(node.kind(), FN | CONST | STATIC) { - bindings_shadow_count.clear(); - } - - if attr_or_derive_item.is_none() { - if sema.is_attr_macro_call(&item) { - attr_or_derive_item = Some(AttrOrDerive::Attr(item)); - } else { - let adt = match item { - ast::Item::Enum(it) => Some(ast::Adt::Enum(it)), - ast::Item::Struct(it) => Some(ast::Adt::Struct(it)), - ast::Item::Union(it) => Some(ast::Adt::Union(it)), - _ => None, - }; - match adt { - Some(adt) if sema.is_derive_annotated(&adt) => { - attr_or_derive_item = - Some(AttrOrDerive::Derive(ast::Item::from(adt))); - } - _ => (), - } - } - } - } - _ => (), - } - } - Leave(NodeOrToken::Node(node)) if ast::Item::can_cast(node.kind()) => { - match ast::Item::cast(node.clone()) { - Some(ast::Item::MacroRules(mac)) => { - assert_eq!(current_macro, Some(mac.into())); - current_macro = None; - macro_highlighter = MacroHighlighter::default(); - } - Some(ast::Item::MacroDef(mac)) => { - assert_eq!(current_macro, Some(mac.into())); - current_macro = None; - macro_highlighter = MacroHighlighter::default(); - } - Some(item) - if attr_or_derive_item.as_ref().map_or(false, |it| *it.item() == item) => - { - attr_or_derive_item = None; - } - _ => (), - } - } - _ => (), - } - - let element = match event { - Enter(NodeOrToken::Token(tok)) if tok.kind() == WHITESPACE => continue, - Enter(it) => it, - Leave(NodeOrToken::Token(_)) => continue, - Leave(NodeOrToken::Node(node)) => { - // Doc comment highlighting injection, we do this when leaving the node - // so that we overwrite the highlighting of the doc comment itself. - inject::doc_comment(hl, sema, InFile::new(file_id.into(), &node)); - continue; - } - }; - - if current_macro.is_some() { - if let Some(tok) = element.as_token() { - macro_highlighter.advance(tok); - } - } - - let element = match element.clone() { - NodeOrToken::Node(n) => match ast::NameLike::cast(n) { - Some(n) => NodeOrToken::Node(n), - None => continue, - }, - NodeOrToken::Token(t) => NodeOrToken::Token(t), - }; - let token = element.as_token().cloned(); - - // Descending tokens into macros is expensive even if no descending occurs, so make sure - // that we actually are in a position where descending is possible. - let in_macro = tt_level > 0 - || match attr_or_derive_item { - Some(AttrOrDerive::Attr(_)) => true, - Some(AttrOrDerive::Derive(_)) => inside_attribute, - None => false, - }; - let descended_element = if in_macro { - // Attempt to descend tokens into macro-calls. - match element { - NodeOrToken::Token(token) if token.kind() != COMMENT => { - let token = match attr_or_derive_item { - Some(AttrOrDerive::Attr(_)) => { - sema.descend_into_macros_with_kind_preference(token) - } - Some(AttrOrDerive::Derive(_)) | None => { - sema.descend_into_macros_single(token) - } - }; - match token.parent().and_then(ast::NameLike::cast) { - // Remap the token into the wrapping single token nodes - Some(parent) => match (token.kind(), parent.syntax().kind()) { - (T![self] | T![ident], NAME | NAME_REF) => NodeOrToken::Node(parent), - (T![self] | T![super] | T![crate] | T![Self], NAME_REF) => { - NodeOrToken::Node(parent) - } - (INT_NUMBER, NAME_REF) => NodeOrToken::Node(parent), - (LIFETIME_IDENT, LIFETIME) => NodeOrToken::Node(parent), - _ => NodeOrToken::Token(token), - }, - None => NodeOrToken::Token(token), - } - } - e => e, - } - } else { - element - }; - - // FIXME: do proper macro def highlighting https://github.com/rust-lang/rust-analyzer/issues/6232 - // Skip metavariables from being highlighted to prevent keyword highlighting in them - if descended_element.as_token().and_then(|t| macro_highlighter.highlight(t)).is_some() { - continue; - } - - // string highlight injections, note this does not use the descended element as proc-macros - // can rewrite string literals which invalidates our indices - if let (Some(token), Some(descended_token)) = (token, descended_element.as_token()) { - if ast::String::can_cast(token.kind()) && ast::String::can_cast(descended_token.kind()) - { - let string = ast::String::cast(token); - let string_to_highlight = ast::String::cast(descended_token.clone()); - if let Some((string, expanded_string)) = string.zip(string_to_highlight) { - if string.is_raw() { - if inject::ra_fixture(hl, sema, &string, &expanded_string).is_some() { - continue; - } - } - highlight_format_string(hl, &string, &expanded_string, range); - highlight_escape_string(hl, &string, range.start()); - } - } else if ast::ByteString::can_cast(token.kind()) - && ast::ByteString::can_cast(descended_token.kind()) - { - if let Some(byte_string) = ast::ByteString::cast(token) { - highlight_escape_string(hl, &byte_string, range.start()); - } - } - } - - let element = match descended_element { - NodeOrToken::Node(name_like) => highlight::name_like( - sema, - krate, - &mut bindings_shadow_count, - syntactic_name_ref_highlighting, - name_like, - ), - NodeOrToken::Token(token) => highlight::token(sema, token).zip(Some(None)), - }; - if let Some((mut highlight, binding_hash)) = element { - if is_unlinked && highlight.tag == HlTag::UnresolvedReference { - // do not emit unresolved references if the file is unlinked - // let the editor do its highlighting for these tokens instead - continue; - } - if highlight.tag == HlTag::UnresolvedReference - && matches!(attr_or_derive_item, Some(AttrOrDerive::Derive(_)) if inside_attribute) - { - // do not emit unresolved references in derive helpers if the token mapping maps to - // something unresolvable. FIXME: There should be a way to prevent that - continue; - } - if inside_attribute { - highlight |= HlMod::Attribute - } - - hl.add(HlRange { range, highlight, binding_hash }); - } - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs deleted file mode 100644 index 6a1236c793b83..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Syntax highlighting for escape sequences -use crate::syntax_highlighting::highlights::Highlights; -use crate::{HlRange, HlTag}; -use syntax::ast::IsString; -use syntax::TextSize; - -pub(super) fn highlight_escape_string( - stack: &mut Highlights, - string: &T, - start: TextSize, -) { - string.escaped_char_ranges(&mut |piece_range, char| { - if char.is_err() { - return; - } - - if string.text()[piece_range.start().into()..].starts_with('\\') { - stack.add(HlRange { - range: piece_range + start, - highlight: HlTag::EscapeSequence.into(), - binding_hash: None, - }); - } - }); -} diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs deleted file mode 100644 index 2ed57e2013023..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! Syntax highlighting for format macro strings. -use ide_db::{ - syntax_helpers::format_string::{is_format_string, lex_format_specifiers, FormatSpecifier}, - SymbolKind, -}; -use syntax::{ast, TextRange}; - -use crate::{syntax_highlighting::highlights::Highlights, HlRange, HlTag}; - -pub(super) fn highlight_format_string( - stack: &mut Highlights, - string: &ast::String, - expanded_string: &ast::String, - range: TextRange, -) { - if !is_format_string(expanded_string) { - return; - } - - lex_format_specifiers(string, &mut |piece_range, kind| { - if let Some(highlight) = highlight_format_specifier(kind) { - stack.add(HlRange { - range: piece_range + range.start(), - highlight: highlight.into(), - binding_hash: None, - }); - } - }); -} - -fn highlight_format_specifier(kind: FormatSpecifier) -> Option { - Some(match kind { - FormatSpecifier::Open - | FormatSpecifier::Close - | FormatSpecifier::Colon - | FormatSpecifier::Fill - | FormatSpecifier::Align - | FormatSpecifier::Sign - | FormatSpecifier::NumberSign - | FormatSpecifier::DollarSign - | FormatSpecifier::Dot - | FormatSpecifier::Asterisk - | FormatSpecifier::QuestionMark => HlTag::FormatSpecifier, - - FormatSpecifier::Integer | FormatSpecifier::Zero => HlTag::NumericLiteral, - - FormatSpecifier::Identifier => HlTag::Symbol(SymbolKind::Local), - FormatSpecifier::Escape => HlTag::EscapeSequence, - }) -} diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs deleted file mode 100644 index 9395e914c43aa..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs +++ /dev/null @@ -1,690 +0,0 @@ -//! Computes color for a single element. - -use hir::{AsAssocItem, HasVisibility, Semantics}; -use ide_db::{ - defs::{Definition, IdentClass, NameClass, NameRefClass}, - FxHashMap, RootDatabase, SymbolKind, -}; -use syntax::{ - ast, match_ast, AstNode, AstToken, NodeOrToken, - SyntaxKind::{self, *}, - SyntaxNode, SyntaxToken, T, -}; - -use crate::{ - syntax_highlighting::tags::{HlOperator, HlPunct}, - Highlight, HlMod, HlTag, -}; - -pub(super) fn token(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option { - if let Some(comment) = ast::Comment::cast(token.clone()) { - let h = HlTag::Comment; - return Some(match comment.kind().doc { - Some(_) => h | HlMod::Documentation, - None => h.into(), - }); - } - - let highlight: Highlight = match token.kind() { - STRING | BYTE_STRING => HlTag::StringLiteral.into(), - INT_NUMBER if token.parent_ancestors().nth(1).map(|it| it.kind()) == Some(FIELD_EXPR) => { - SymbolKind::Field.into() - } - INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(), - BYTE => HlTag::ByteLiteral.into(), - CHAR => HlTag::CharLiteral.into(), - IDENT if token.parent().and_then(ast::TokenTree::cast).is_some() => { - // from this point on we are inside a token tree, this only happens for identifiers - // that were not mapped down into macro invocations - HlTag::None.into() - } - p if p.is_punct() => punctuation(sema, token, p), - k if k.is_keyword() => keyword(sema, token, k)?, - _ => return None, - }; - Some(highlight) -} - -pub(super) fn name_like( - sema: &Semantics<'_, RootDatabase>, - krate: hir::Crate, - bindings_shadow_count: &mut FxHashMap, - syntactic_name_ref_highlighting: bool, - name_like: ast::NameLike, -) -> Option<(Highlight, Option)> { - let mut binding_hash = None; - let highlight = match name_like { - ast::NameLike::NameRef(name_ref) => highlight_name_ref( - sema, - krate, - bindings_shadow_count, - &mut binding_hash, - syntactic_name_ref_highlighting, - name_ref, - ), - ast::NameLike::Name(name) => { - highlight_name(sema, bindings_shadow_count, &mut binding_hash, krate, name) - } - ast::NameLike::Lifetime(lifetime) => match IdentClass::classify_lifetime(sema, &lifetime) { - Some(IdentClass::NameClass(NameClass::Definition(def))) => { - highlight_def(sema, krate, def) | HlMod::Definition - } - Some(IdentClass::NameRefClass(NameRefClass::Definition(def))) => { - highlight_def(sema, krate, def) - } - // FIXME: Fallback for 'static and '_, as we do not resolve these yet - _ => SymbolKind::LifetimeParam.into(), - }, - }; - Some((highlight, binding_hash)) -} - -fn punctuation( - sema: &Semantics<'_, RootDatabase>, - token: SyntaxToken, - kind: SyntaxKind, -) -> Highlight { - let parent = token.parent(); - let parent_kind = parent.as_ref().map_or(EOF, SyntaxNode::kind); - match (kind, parent_kind) { - (T![?], _) => HlTag::Operator(HlOperator::Other) | HlMod::ControlFlow, - (T![&], BIN_EXPR) => HlOperator::Bitwise.into(), - (T![&], _) => { - let h = HlTag::Operator(HlOperator::Other).into(); - let is_unsafe = parent - .and_then(ast::RefExpr::cast) - .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr)); - if let Some(true) = is_unsafe { - h | HlMod::Unsafe - } else { - h - } - } - (T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.], _) => HlOperator::Other.into(), - (T![!], MACRO_CALL | MACRO_RULES) => HlPunct::MacroBang.into(), - (T![!], NEVER_TYPE) => HlTag::BuiltinType.into(), - (T![!], PREFIX_EXPR) => HlOperator::Logical.into(), - (T![*], PTR_TYPE) => HlTag::Keyword.into(), - (T![*], PREFIX_EXPR) => { - let is_raw_ptr = (|| { - let prefix_expr = parent.and_then(ast::PrefixExpr::cast)?; - let expr = prefix_expr.expr()?; - sema.type_of_expr(&expr)?.original.is_raw_ptr().then(|| ()) - })(); - if let Some(()) = is_raw_ptr { - HlTag::Operator(HlOperator::Other) | HlMod::Unsafe - } else { - HlOperator::Other.into() - } - } - (T![-], PREFIX_EXPR) => { - let prefix_expr = parent.and_then(ast::PrefixExpr::cast).and_then(|e| e.expr()); - match prefix_expr { - Some(ast::Expr::Literal(_)) => HlTag::NumericLiteral, - _ => HlTag::Operator(HlOperator::Other), - } - .into() - } - (T![+] | T![-] | T![*] | T![/] | T![%], BIN_EXPR) => HlOperator::Arithmetic.into(), - (T![+=] | T![-=] | T![*=] | T![/=] | T![%=], BIN_EXPR) => { - Highlight::from(HlOperator::Arithmetic) | HlMod::Mutable - } - (T![|] | T![&] | T![!] | T![^] | T![>>] | T![<<], BIN_EXPR) => HlOperator::Bitwise.into(), - (T![|=] | T![&=] | T![^=] | T![>>=] | T![<<=], BIN_EXPR) => { - Highlight::from(HlOperator::Bitwise) | HlMod::Mutable - } - (T![&&] | T![||], BIN_EXPR) => HlOperator::Logical.into(), - (T![>] | T![<] | T![==] | T![>=] | T![<=] | T![!=], BIN_EXPR) => { - HlOperator::Comparison.into() - } - (_, PREFIX_EXPR | BIN_EXPR | RANGE_EXPR | RANGE_PAT | REST_PAT) => HlOperator::Other.into(), - (_, ATTR) => HlTag::AttributeBracket.into(), - (kind, _) => match kind { - T!['['] | T![']'] => HlPunct::Bracket, - T!['{'] | T!['}'] => HlPunct::Brace, - T!['('] | T![')'] => HlPunct::Parenthesis, - T![<] | T![>] => HlPunct::Angle, - T![,] => HlPunct::Comma, - T![:] => HlPunct::Colon, - T![;] => HlPunct::Semi, - T![.] => HlPunct::Dot, - _ => HlPunct::Other, - } - .into(), - } -} - -fn keyword( - sema: &Semantics<'_, RootDatabase>, - token: SyntaxToken, - kind: SyntaxKind, -) -> Option { - let h = Highlight::new(HlTag::Keyword); - let h = match kind { - T![await] => h | HlMod::Async | HlMod::ControlFlow, - T![async] => h | HlMod::Async, - T![break] - | T![continue] - | T![else] - | T![if] - | T![in] - | T![loop] - | T![match] - | T![return] - | T![while] - | T![yield] => h | HlMod::ControlFlow, - T![for] if parent_matches::(&token) => h | HlMod::ControlFlow, - T![unsafe] => h | HlMod::Unsafe, - T![true] | T![false] => HlTag::BoolLiteral.into(), - // crate is handled just as a token if it's in an `extern crate` - T![crate] if parent_matches::(&token) => h, - // self, crate, super and `Self` are handled as either a Name or NameRef already, unless they - // are inside unmapped token trees - T![self] | T![crate] | T![super] | T![Self] if parent_matches::(&token) => { - return None - } - T![self] if parent_matches::(&token) => return None, - T![ref] => match token.parent().and_then(ast::IdentPat::cast) { - Some(ident) if sema.is_unsafe_ident_pat(&ident) => h | HlMod::Unsafe, - _ => h, - }, - _ => h, - }; - Some(h) -} - -fn highlight_name_ref( - sema: &Semantics<'_, RootDatabase>, - krate: hir::Crate, - bindings_shadow_count: &mut FxHashMap, - binding_hash: &mut Option, - syntactic_name_ref_highlighting: bool, - name_ref: ast::NameRef, -) -> Highlight { - let db = sema.db; - if let Some(res) = highlight_method_call_by_name_ref(sema, krate, &name_ref) { - return res; - } - - let name_class = match NameRefClass::classify(sema, &name_ref) { - Some(name_kind) => name_kind, - None if syntactic_name_ref_highlighting => { - return highlight_name_ref_by_syntax(name_ref, sema, krate) - } - // FIXME: This is required for helper attributes used by proc-macros, as those do not map down - // to anything when used. - // We can fix this for derive attributes since derive helpers are recorded, but not for - // general attributes. - None if name_ref.syntax().ancestors().any(|it| it.kind() == ATTR) => { - return HlTag::Symbol(SymbolKind::Attribute).into(); - } - None => return HlTag::UnresolvedReference.into(), - }; - let mut h = match name_class { - NameRefClass::Definition(def) => { - if let Definition::Local(local) = &def { - let name = local.name(db); - let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); - *binding_hash = Some(calc_binding_hash(&name, *shadow_count)) - }; - - let mut h = highlight_def(sema, krate, def); - - match def { - Definition::Local(local) if is_consumed_lvalue(name_ref.syntax(), &local, db) => { - h |= HlMod::Consuming; - } - Definition::Trait(trait_) if trait_.is_unsafe(db) => { - if ast::Impl::for_trait_name_ref(&name_ref) - .map_or(false, |impl_| impl_.unsafe_token().is_some()) - { - h |= HlMod::Unsafe; - } - } - Definition::Field(field) => { - if let Some(parent) = name_ref.syntax().parent() { - if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) { - if let hir::VariantDef::Union(_) = field.parent_def(db) { - h |= HlMod::Unsafe; - } - } - } - } - Definition::Macro(_) => { - if let Some(macro_call) = - ide_db::syntax_helpers::node_ext::full_path_of_name_ref(&name_ref) - .and_then(|it| it.syntax().parent().and_then(ast::MacroCall::cast)) - { - if sema.is_unsafe_macro_call(¯o_call) { - h |= HlMod::Unsafe; - } - } - } - _ => (), - } - - h - } - NameRefClass::FieldShorthand { .. } => SymbolKind::Field.into(), - }; - - h.tag = match name_ref.token_kind() { - T![Self] => HlTag::Symbol(SymbolKind::SelfType), - T![self] => HlTag::Symbol(SymbolKind::SelfParam), - T![super] | T![crate] => HlTag::Keyword, - _ => h.tag, - }; - h -} - -fn highlight_name( - sema: &Semantics<'_, RootDatabase>, - bindings_shadow_count: &mut FxHashMap, - binding_hash: &mut Option, - krate: hir::Crate, - name: ast::Name, -) -> Highlight { - let name_kind = NameClass::classify(sema, &name); - if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind { - let name = local.name(sema.db); - let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); - *shadow_count += 1; - *binding_hash = Some(calc_binding_hash(&name, *shadow_count)) - }; - match name_kind { - Some(NameClass::Definition(def)) => { - let mut h = highlight_def(sema, krate, def) | HlMod::Definition; - if let Definition::Trait(trait_) = &def { - if trait_.is_unsafe(sema.db) { - h |= HlMod::Unsafe; - } - } - h - } - Some(NameClass::ConstReference(def)) => highlight_def(sema, krate, def), - Some(NameClass::PatFieldShorthand { field_ref, .. }) => { - let mut h = HlTag::Symbol(SymbolKind::Field).into(); - if let hir::VariantDef::Union(_) = field_ref.parent_def(sema.db) { - h |= HlMod::Unsafe; - } - h - } - None => highlight_name_by_syntax(name) | HlMod::Definition, - } -} - -fn calc_binding_hash(name: &hir::Name, shadow_count: u32) -> u64 { - fn hash(x: T) -> u64 { - use std::{collections::hash_map::DefaultHasher, hash::Hasher}; - - let mut hasher = DefaultHasher::new(); - x.hash(&mut hasher); - hasher.finish() - } - - hash((name, shadow_count)) -} - -fn highlight_def( - sema: &Semantics<'_, RootDatabase>, - krate: hir::Crate, - def: Definition, -) -> Highlight { - let db = sema.db; - let mut h = match def { - Definition::Macro(m) => Highlight::new(HlTag::Symbol(m.kind(sema.db).into())), - Definition::Field(_) => Highlight::new(HlTag::Symbol(SymbolKind::Field)), - Definition::Module(module) => { - let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Module)); - if module.is_crate_root(db) { - h |= HlMod::CrateRoot; - } - h - } - Definition::Function(func) => { - let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function)); - if let Some(item) = func.as_assoc_item(db) { - h |= HlMod::Associated; - match func.self_param(db) { - Some(sp) => match sp.access(db) { - hir::Access::Exclusive => { - h |= HlMod::Mutable; - h |= HlMod::Reference; - } - hir::Access::Shared => h |= HlMod::Reference, - hir::Access::Owned => h |= HlMod::Consuming, - }, - None => h |= HlMod::Static, - } - - match item.container(db) { - hir::AssocItemContainer::Impl(i) => { - if i.trait_(db).is_some() { - h |= HlMod::Trait; - } - } - hir::AssocItemContainer::Trait(_t) => { - h |= HlMod::Trait; - } - } - } - - if func.is_unsafe_to_call(db) { - h |= HlMod::Unsafe; - } - if func.is_async(db) { - h |= HlMod::Async; - } - - h - } - Definition::Adt(adt) => { - let h = match adt { - hir::Adt::Struct(_) => HlTag::Symbol(SymbolKind::Struct), - hir::Adt::Enum(_) => HlTag::Symbol(SymbolKind::Enum), - hir::Adt::Union(_) => HlTag::Symbol(SymbolKind::Union), - }; - - Highlight::new(h) - } - Definition::Variant(_) => Highlight::new(HlTag::Symbol(SymbolKind::Variant)), - Definition::Const(konst) => { - let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const)); - - if let Some(item) = konst.as_assoc_item(db) { - h |= HlMod::Associated; - match item.container(db) { - hir::AssocItemContainer::Impl(i) => { - if i.trait_(db).is_some() { - h |= HlMod::Trait; - } - } - hir::AssocItemContainer::Trait(_t) => { - h |= HlMod::Trait; - } - } - } - - h - } - Definition::Trait(_) => Highlight::new(HlTag::Symbol(SymbolKind::Trait)), - Definition::TypeAlias(type_) => { - let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); - - if let Some(item) = type_.as_assoc_item(db) { - h |= HlMod::Associated; - match item.container(db) { - hir::AssocItemContainer::Impl(i) => { - if i.trait_(db).is_some() { - h |= HlMod::Trait; - } - } - hir::AssocItemContainer::Trait(_t) => { - h |= HlMod::Trait; - } - } - } - - h - } - Definition::BuiltinType(_) => Highlight::new(HlTag::BuiltinType), - Definition::Static(s) => { - let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static)); - - if s.is_mut(db) { - h |= HlMod::Mutable; - h |= HlMod::Unsafe; - } - - h - } - Definition::SelfType(_) => Highlight::new(HlTag::Symbol(SymbolKind::Impl)), - Definition::GenericParam(it) => match it { - hir::GenericParam::TypeParam(_) => Highlight::new(HlTag::Symbol(SymbolKind::TypeParam)), - hir::GenericParam::ConstParam(_) => { - Highlight::new(HlTag::Symbol(SymbolKind::ConstParam)) - } - hir::GenericParam::LifetimeParam(_) => { - Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)) - } - }, - Definition::Local(local) => { - let tag = if local.is_self(db) { - HlTag::Symbol(SymbolKind::SelfParam) - } else if local.is_param(db) { - HlTag::Symbol(SymbolKind::ValueParam) - } else { - HlTag::Symbol(SymbolKind::Local) - }; - let mut h = Highlight::new(tag); - let ty = local.ty(db); - if local.is_mut(db) || ty.is_mutable_reference() { - h |= HlMod::Mutable; - } - if local.is_ref(db) || ty.is_reference() { - h |= HlMod::Reference; - } - if ty.as_callable(db).is_some() || ty.impls_fnonce(db) { - h |= HlMod::Callable; - } - h - } - Definition::Label(_) => Highlight::new(HlTag::Symbol(SymbolKind::Label)), - Definition::BuiltinAttr(_) => Highlight::new(HlTag::Symbol(SymbolKind::BuiltinAttr)), - Definition::ToolModule(_) => Highlight::new(HlTag::Symbol(SymbolKind::ToolModule)), - Definition::DeriveHelper(_) => Highlight::new(HlTag::Symbol(SymbolKind::DeriveHelper)), - }; - - let def_crate = def.krate(db); - let is_from_other_crate = def_crate != Some(krate); - let is_from_builtin_crate = def_crate.map_or(false, |def_crate| def_crate.is_builtin(db)); - let is_builtin_type = matches!(def, Definition::BuiltinType(_)); - let is_public = def.visibility(db) == Some(hir::Visibility::Public); - - match (is_from_other_crate, is_builtin_type, is_public) { - (true, false, _) => h |= HlMod::Library, - (false, _, true) => h |= HlMod::Public, - _ => {} - } - - if is_from_builtin_crate { - h |= HlMod::DefaultLibrary; - } - - h -} - -fn highlight_method_call_by_name_ref( - sema: &Semantics<'_, RootDatabase>, - krate: hir::Crate, - name_ref: &ast::NameRef, -) -> Option { - let mc = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?; - highlight_method_call(sema, krate, &mc) -} - -fn highlight_method_call( - sema: &Semantics<'_, RootDatabase>, - krate: hir::Crate, - method_call: &ast::MethodCallExpr, -) -> Option { - let func = sema.resolve_method_call(method_call)?; - - let mut h = SymbolKind::Function.into(); - h |= HlMod::Associated; - - if func.is_unsafe_to_call(sema.db) || sema.is_unsafe_method_call(method_call) { - h |= HlMod::Unsafe; - } - if func.is_async(sema.db) { - h |= HlMod::Async; - } - if func - .as_assoc_item(sema.db) - .and_then(|it| it.containing_trait_or_trait_impl(sema.db)) - .is_some() - { - h |= HlMod::Trait; - } - - let def_crate = func.module(sema.db).krate(); - let is_from_other_crate = def_crate != krate; - let is_from_builtin_crate = def_crate.is_builtin(sema.db); - let is_public = func.visibility(sema.db) == hir::Visibility::Public; - - if is_from_other_crate { - h |= HlMod::Library; - } else if is_public { - h |= HlMod::Public; - } - - if is_from_builtin_crate { - h |= HlMod::DefaultLibrary; - } - - if let Some(self_param) = func.self_param(sema.db) { - match self_param.access(sema.db) { - hir::Access::Shared => h |= HlMod::Reference, - hir::Access::Exclusive => { - h |= HlMod::Mutable; - h |= HlMod::Reference; - } - hir::Access::Owned => { - if let Some(receiver_ty) = - method_call.receiver().and_then(|it| sema.type_of_expr(&it)) - { - if !receiver_ty.adjusted().is_copy(sema.db) { - h |= HlMod::Consuming - } - } - } - } - } - Some(h) -} - -fn highlight_name_by_syntax(name: ast::Name) -> Highlight { - let default = HlTag::UnresolvedReference; - - let parent = match name.syntax().parent() { - Some(it) => it, - _ => return default.into(), - }; - - let tag = match parent.kind() { - STRUCT => SymbolKind::Struct, - ENUM => SymbolKind::Enum, - VARIANT => SymbolKind::Variant, - UNION => SymbolKind::Union, - TRAIT => SymbolKind::Trait, - TYPE_ALIAS => SymbolKind::TypeAlias, - TYPE_PARAM => SymbolKind::TypeParam, - RECORD_FIELD => SymbolKind::Field, - MODULE => SymbolKind::Module, - FN => SymbolKind::Function, - CONST => SymbolKind::Const, - STATIC => SymbolKind::Static, - IDENT_PAT => SymbolKind::Local, - _ => return default.into(), - }; - - tag.into() -} - -fn highlight_name_ref_by_syntax( - name: ast::NameRef, - sema: &Semantics<'_, RootDatabase>, - krate: hir::Crate, -) -> Highlight { - let default = HlTag::UnresolvedReference; - - let parent = match name.syntax().parent() { - Some(it) => it, - _ => return default.into(), - }; - - match parent.kind() { - METHOD_CALL_EXPR => ast::MethodCallExpr::cast(parent) - .and_then(|it| highlight_method_call(sema, krate, &it)) - .unwrap_or_else(|| SymbolKind::Function.into()), - FIELD_EXPR => { - let h = HlTag::Symbol(SymbolKind::Field); - let is_union = ast::FieldExpr::cast(parent) - .and_then(|field_expr| sema.resolve_field(&field_expr)) - .map_or(false, |field| { - matches!(field.parent_def(sema.db), hir::VariantDef::Union(_)) - }); - if is_union { - h | HlMod::Unsafe - } else { - h.into() - } - } - PATH_SEGMENT => { - let name_based_fallback = || { - if name.text().chars().next().unwrap_or_default().is_uppercase() { - SymbolKind::Struct.into() - } else { - SymbolKind::Module.into() - } - }; - let path = match parent.parent().and_then(ast::Path::cast) { - Some(it) => it, - _ => return name_based_fallback(), - }; - let expr = match path.syntax().parent() { - Some(parent) => match_ast! { - match parent { - ast::PathExpr(path) => path, - ast::MacroCall(_) => return SymbolKind::Macro.into(), - _ => return name_based_fallback(), - } - }, - // within path, decide whether it is module or adt by checking for uppercase name - None => return name_based_fallback(), - }; - let parent = match expr.syntax().parent() { - Some(it) => it, - None => return default.into(), - }; - - match parent.kind() { - CALL_EXPR => SymbolKind::Function.into(), - _ => if name.text().chars().next().unwrap_or_default().is_uppercase() { - SymbolKind::Struct - } else { - SymbolKind::Const - } - .into(), - } - } - _ => default.into(), - } -} - -fn is_consumed_lvalue(node: &SyntaxNode, local: &hir::Local, db: &RootDatabase) -> bool { - // When lvalues are passed as arguments and they're not Copy, then mark them as Consuming. - parents_match(node.clone().into(), &[PATH_SEGMENT, PATH, PATH_EXPR, ARG_LIST]) - && !local.ty(db).is_copy(db) -} - -/// Returns true if the parent nodes of `node` all match the `SyntaxKind`s in `kinds` exactly. -fn parents_match(mut node: NodeOrToken, mut kinds: &[SyntaxKind]) -> bool { - while let (Some(parent), [kind, rest @ ..]) = (&node.parent(), kinds) { - if parent.kind() != *kind { - return false; - } - - // FIXME: Would be nice to get parent out of the match, but binding by-move and by-value - // in the same pattern is unstable: rust-lang/rust#68354. - node = node.parent().unwrap().into(); - kinds = rest; - } - - // Only true if we matched all expected kinds - kinds.is_empty() -} - -fn parent_matches(token: &SyntaxToken) -> bool { - token.parent().map_or(false, |it| N::can_cast(it.kind())) -} diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlights.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlights.rs deleted file mode 100644 index 340290eafedbe..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlights.rs +++ /dev/null @@ -1,92 +0,0 @@ -//! Collects a tree of highlighted ranges and flattens it. -use std::iter; - -use stdx::equal_range_by; -use syntax::TextRange; - -use crate::{HlRange, HlTag}; - -pub(super) struct Highlights { - root: Node, -} - -struct Node { - hl_range: HlRange, - nested: Vec, -} - -impl Highlights { - pub(super) fn new(range: TextRange) -> Highlights { - Highlights { - root: Node::new(HlRange { range, highlight: HlTag::None.into(), binding_hash: None }), - } - } - - pub(super) fn add(&mut self, hl_range: HlRange) { - self.root.add(hl_range); - } - - pub(super) fn to_vec(&self) -> Vec { - let mut res = Vec::new(); - self.root.flatten(&mut res); - res - } -} - -impl Node { - fn new(hl_range: HlRange) -> Node { - Node { hl_range, nested: Vec::new() } - } - - fn add(&mut self, hl_range: HlRange) { - assert!(self.hl_range.range.contains_range(hl_range.range)); - - // Fast path - if let Some(last) = self.nested.last_mut() { - if last.hl_range.range.contains_range(hl_range.range) { - return last.add(hl_range); - } - if last.hl_range.range.end() <= hl_range.range.start() { - return self.nested.push(Node::new(hl_range)); - } - } - - let overlapping = - equal_range_by(&self.nested, |n| TextRange::ordering(n.hl_range.range, hl_range.range)); - - if overlapping.len() == 1 - && self.nested[overlapping.start].hl_range.range.contains_range(hl_range.range) - { - return self.nested[overlapping.start].add(hl_range); - } - - let nested = self - .nested - .splice(overlapping.clone(), iter::once(Node::new(hl_range))) - .collect::>(); - self.nested[overlapping.start].nested = nested; - } - - fn flatten(&self, acc: &mut Vec) { - let mut start = self.hl_range.range.start(); - let mut nested = self.nested.iter(); - loop { - let next = nested.next(); - let end = next.map_or(self.hl_range.range.end(), |it| it.hl_range.range.start()); - if start < end { - acc.push(HlRange { - range: TextRange::new(start, end), - highlight: self.hl_range.highlight, - binding_hash: self.hl_range.binding_hash, - }); - } - start = match next { - Some(child) => { - child.flatten(acc); - child.hl_range.range.end() - } - None => break, - } - } - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs deleted file mode 100644 index 9777c014c7a16..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs +++ /dev/null @@ -1,97 +0,0 @@ -//! Renders a bit of code as HTML. - -use ide_db::base_db::SourceDatabase; -use oorandom::Rand32; -use stdx::format_to; -use syntax::AstNode; - -use crate::{syntax_highlighting::highlight, FileId, RootDatabase}; - -pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String { - let parse = db.parse(file_id); - - fn rainbowify(seed: u64) -> String { - let mut rng = Rand32::new(seed); - format!( - "hsl({h},{s}%,{l}%)", - h = rng.rand_range(0..361), - s = rng.rand_range(42..99), - l = rng.rand_range(40..91), - ) - } - - let hl_ranges = highlight(db, file_id, None, false); - let text = parse.tree().syntax().to_string(); - let mut buf = String::new(); - buf.push_str(STYLE); - buf.push_str("
");
-    for r in &hl_ranges {
-        let chunk = html_escape(&text[r.range]);
-        if r.highlight.is_empty() {
-            format_to!(buf, "{}", chunk);
-            continue;
-        }
-
-        let class = r.highlight.to_string().replace('.', " ");
-        let color = match (rainbow, r.binding_hash) {
-            (true, Some(hash)) => {
-                format!(" data-binding-hash=\"{}\" style=\"color: {};\"", hash, rainbowify(hash))
-            }
-            _ => "".into(),
-        };
-        format_to!(buf, "{}", class, color, chunk);
-    }
-    buf.push_str("
"); - buf -} - -//FIXME: like, real html escaping -fn html_escape(text: &str) -> String { - text.replace('<', "<").replace('>', ">") -} - -const STYLE: &str = " - -"; diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs deleted file mode 100644 index f779a985a99ae..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs +++ /dev/null @@ -1,276 +0,0 @@ -//! "Recursive" Syntax highlighting for code in doctests and fixtures. - -use std::mem; - -use either::Either; -use hir::{InFile, Semantics}; -use ide_db::{ - active_parameter::ActiveParameter, defs::Definition, rust_doc::is_rust_fence, SymbolKind, -}; -use syntax::{ - ast::{self, AstNode, IsString, QuoteOffsets}, - AstToken, NodeOrToken, SyntaxNode, TextRange, TextSize, -}; - -use crate::{ - doc_links::{doc_attributes, extract_definitions_from_docs, resolve_doc_path_for_def}, - syntax_highlighting::{highlights::Highlights, injector::Injector}, - Analysis, HlMod, HlRange, HlTag, RootDatabase, -}; - -pub(super) fn ra_fixture( - hl: &mut Highlights, - sema: &Semantics<'_, RootDatabase>, - literal: &ast::String, - expanded: &ast::String, -) -> Option<()> { - let active_parameter = ActiveParameter::at_token(sema, expanded.syntax().clone())?; - if !active_parameter.ident().map_or(false, |name| name.text().starts_with("ra_fixture")) { - return None; - } - let value = literal.value()?; - - if let Some(range) = literal.open_quote_text_range() { - hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None }) - } - - let mut inj = Injector::default(); - - let mut text = &*value; - let mut offset: TextSize = 0.into(); - - while !text.is_empty() { - let marker = "$0"; - let idx = text.find(marker).unwrap_or(text.len()); - let (chunk, next) = text.split_at(idx); - inj.add(chunk, TextRange::at(offset, TextSize::of(chunk))); - - text = next; - offset += TextSize::of(chunk); - - if let Some(next) = text.strip_prefix(marker) { - if let Some(range) = literal.map_range_up(TextRange::at(offset, TextSize::of(marker))) { - hl.add(HlRange { range, highlight: HlTag::Keyword.into(), binding_hash: None }); - } - - text = next; - - let marker_len = TextSize::of(marker); - offset += marker_len; - } - } - - let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text()); - - for mut hl_range in analysis.highlight(tmp_file_id).unwrap() { - for range in inj.map_range_up(hl_range.range) { - if let Some(range) = literal.map_range_up(range) { - hl_range.range = range; - hl.add(hl_range); - } - } - } - - if let Some(range) = literal.close_quote_text_range() { - hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None }) - } - - Some(()) -} - -const RUSTDOC_FENCE_LENGTH: usize = 3; -const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"]; - -/// Injection of syntax highlighting of doctests. -pub(super) fn doc_comment( - hl: &mut Highlights, - sema: &Semantics<'_, RootDatabase>, - InFile { file_id: src_file_id, value: node }: InFile<&SyntaxNode>, -) { - let (attributes, def) = match doc_attributes(sema, node) { - Some(it) => it, - None => return, - }; - - // Extract intra-doc links and emit highlights for them. - if let Some((docs, doc_mapping)) = attributes.docs_with_rangemap(sema.db) { - extract_definitions_from_docs(&docs) - .into_iter() - .filter_map(|(range, link, ns)| { - doc_mapping.map(range).filter(|mapping| mapping.file_id == src_file_id).and_then( - |InFile { value: mapped_range, .. }| { - Some(mapped_range).zip(resolve_doc_path_for_def(sema.db, def, &link, ns)) - }, - ) - }) - .for_each(|(range, def)| { - hl.add(HlRange { - range, - highlight: module_def_to_hl_tag(def) - | HlMod::Documentation - | HlMod::Injected - | HlMod::IntraDocLink, - binding_hash: None, - }) - }); - } - - // Extract doc-test sources from the docs and calculate highlighting for them. - - let mut inj = Injector::default(); - inj.add_unmapped("fn doctest() {\n"); - - let attrs_source_map = attributes.source_map(sema.db); - - let mut is_codeblock = false; - let mut is_doctest = false; - - let mut new_comments = Vec::new(); - let mut string; - - for attr in attributes.by_key("doc").attrs() { - let InFile { file_id, value: src } = attrs_source_map.source_of(attr); - if file_id != src_file_id { - continue; - } - let (line, range) = match &src { - Either::Left(it) => { - string = match find_doc_string_in_attr(attr, it) { - Some(it) => it, - None => continue, - }; - let text = string.text(); - let text_range = string.syntax().text_range(); - match string.quote_offsets() { - Some(QuoteOffsets { contents, .. }) => { - (&text[contents - text_range.start()], contents) - } - None => (text, text_range), - } - } - Either::Right(comment) => { - let value = comment.prefix().len(); - let range = comment.syntax().text_range(); - ( - &comment.text()[value..], - TextRange::new(range.start() + TextSize::try_from(value).unwrap(), range.end()), - ) - } - }; - - let mut range_start = range.start(); - for line in line.split('\n') { - let line_len = TextSize::from(line.len() as u32); - let prev_range_start = { - let next_range_start = range_start + line_len + TextSize::from(1); - mem::replace(&mut range_start, next_range_start) - }; - let mut pos = TextSize::from(0); - - match RUSTDOC_FENCES.into_iter().find_map(|fence| line.find(fence)) { - Some(idx) => { - is_codeblock = !is_codeblock; - // Check whether code is rust by inspecting fence guards - let guards = &line[idx + RUSTDOC_FENCE_LENGTH..]; - let is_rust = is_rust_fence(guards); - is_doctest = is_codeblock && is_rust; - continue; - } - None if !is_doctest => continue, - None => (), - } - - // whitespace after comment is ignored - if let Some(ws) = line[pos.into()..].chars().next().filter(|c| c.is_whitespace()) { - pos += TextSize::of(ws); - } - // lines marked with `#` should be ignored in output, we skip the `#` char - if line[pos.into()..].starts_with('#') { - pos += TextSize::of('#'); - } - - new_comments.push(TextRange::at(prev_range_start, pos)); - inj.add(&line[pos.into()..], TextRange::new(pos, line_len) + prev_range_start); - inj.add_unmapped("\n"); - } - } - - if new_comments.is_empty() { - return; // no need to run an analysis on an empty file - } - - inj.add_unmapped("\n}"); - - let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text()); - - if let Ok(ranges) = analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)) { - for HlRange { range, highlight, binding_hash } in ranges { - for range in inj.map_range_up(range) { - hl.add(HlRange { range, highlight: highlight | HlMod::Injected, binding_hash }); - } - } - } - - for range in new_comments { - hl.add(HlRange { - range, - highlight: HlTag::Comment | HlMod::Documentation, - binding_hash: None, - }); - } -} - -fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option { - match it.expr() { - // #[doc = lit] - Some(ast::Expr::Literal(lit)) => match lit.kind() { - ast::LiteralKind::String(it) => Some(it), - _ => None, - }, - // #[cfg_attr(..., doc = "", ...)] - None => { - // We gotta hunt the string token manually here - let text = attr.string_value()?; - // FIXME: We just pick the first string literal that has the same text as the doc attribute - // This means technically we might highlight the wrong one - it.syntax() - .descendants_with_tokens() - .filter_map(NodeOrToken::into_token) - .filter_map(ast::String::cast) - .find(|string| { - string.text().get(1..string.text().len() - 1).map_or(false, |it| it == text) - }) - } - _ => None, - } -} - -fn module_def_to_hl_tag(def: Definition) -> HlTag { - let symbol = match def { - Definition::Module(_) => SymbolKind::Module, - Definition::Function(_) => SymbolKind::Function, - Definition::Adt(hir::Adt::Struct(_)) => SymbolKind::Struct, - Definition::Adt(hir::Adt::Enum(_)) => SymbolKind::Enum, - Definition::Adt(hir::Adt::Union(_)) => SymbolKind::Union, - Definition::Variant(_) => SymbolKind::Variant, - Definition::Const(_) => SymbolKind::Const, - Definition::Static(_) => SymbolKind::Static, - Definition::Trait(_) => SymbolKind::Trait, - Definition::TypeAlias(_) => SymbolKind::TypeAlias, - Definition::BuiltinType(_) => return HlTag::BuiltinType, - Definition::Macro(_) => SymbolKind::Macro, - Definition::Field(_) => SymbolKind::Field, - Definition::SelfType(_) => SymbolKind::Impl, - Definition::Local(_) => SymbolKind::Local, - Definition::GenericParam(gp) => match gp { - hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam, - hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam, - hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam, - }, - Definition::Label(_) => SymbolKind::Label, - Definition::BuiltinAttr(_) => SymbolKind::BuiltinAttr, - Definition::ToolModule(_) => SymbolKind::ToolModule, - Definition::DeriveHelper(_) => SymbolKind::DeriveHelper, - }; - HlTag::Symbol(symbol) -} diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/injector.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/injector.rs deleted file mode 100644 index a902fd717f099..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/injector.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! Extracts a subsequence of a text document, remembering the mapping of ranges -//! between original and extracted texts. -use std::ops::{self, Sub}; - -use stdx::equal_range_by; -use syntax::{TextRange, TextSize}; - -#[derive(Default)] -pub(super) struct Injector { - buf: String, - ranges: Vec<(TextRange, Option>)>, -} - -impl Injector { - pub(super) fn add(&mut self, text: &str, source_range: TextRange) { - let len = TextSize::of(text); - assert_eq!(len, source_range.len()); - self.add_impl(text, Some(source_range.start())); - } - - pub(super) fn add_unmapped(&mut self, text: &str) { - self.add_impl(text, None); - } - - fn add_impl(&mut self, text: &str, source: Option) { - let len = TextSize::of(text); - let target_range = TextRange::at(TextSize::of(&self.buf), len); - self.ranges.push((target_range, source.map(|it| Delta::new(target_range.start(), it)))); - self.buf.push_str(text); - } - - pub(super) fn take_text(&mut self) -> String { - std::mem::take(&mut self.buf) - } - - pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator + '_ { - equal_range_by(&self.ranges, |&(r, _)| TextRange::ordering(r, range)).filter_map(move |i| { - let (target_range, delta) = self.ranges[i]; - let intersection = target_range.intersect(range).unwrap(); - Some(intersection + delta?) - }) - } -} - -#[derive(Clone, Copy)] -enum Delta { - Add(T), - Sub(T), -} - -impl Delta { - fn new(from: T, to: T) -> Delta - where - T: Ord + Sub, - { - if to >= from { - Delta::Add(to - from) - } else { - Delta::Sub(from - to) - } - } -} - -impl ops::Add> for TextSize { - type Output = TextSize; - - fn add(self, rhs: Delta) -> TextSize { - match rhs { - Delta::Add(it) => self + it, - Delta::Sub(it) => self - it, - } - } -} - -impl ops::Add> for TextRange { - type Output = TextRange; - - fn add(self, rhs: Delta) -> TextRange { - TextRange::at(self.start() + rhs, self.len()) - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/macro_.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/macro_.rs deleted file mode 100644 index 1099d9c23b721..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/macro_.rs +++ /dev/null @@ -1,128 +0,0 @@ -//! Syntax highlighting for macro_rules!. -use syntax::{SyntaxKind, SyntaxToken, TextRange, T}; - -use crate::{HlRange, HlTag}; - -#[derive(Default)] -pub(super) struct MacroHighlighter { - state: Option, -} - -impl MacroHighlighter { - pub(super) fn init(&mut self) { - self.state = Some(MacroMatcherParseState::default()); - } - - pub(super) fn advance(&mut self, token: &SyntaxToken) { - if let Some(state) = self.state.as_mut() { - update_macro_state(state, token); - } - } - - pub(super) fn highlight(&self, token: &SyntaxToken) -> Option { - if let Some(state) = self.state.as_ref() { - if matches!(state.rule_state, RuleState::Matcher | RuleState::Expander) { - if let Some(range) = is_metavariable(token) { - return Some(HlRange { - range, - highlight: HlTag::UnresolvedReference.into(), - binding_hash: None, - }); - } - } - } - None - } -} - -struct MacroMatcherParseState { - /// Opening and corresponding closing bracket of the matcher or expander of the current rule - paren_ty: Option<(SyntaxKind, SyntaxKind)>, - paren_level: usize, - rule_state: RuleState, - /// Whether we are inside the outer `{` `}` macro block that holds the rules - in_invoc_body: bool, -} - -impl Default for MacroMatcherParseState { - fn default() -> Self { - MacroMatcherParseState { - paren_ty: None, - paren_level: 0, - in_invoc_body: false, - rule_state: RuleState::None, - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq)] -enum RuleState { - Matcher, - Expander, - Between, - None, -} - -impl RuleState { - fn transition(&mut self) { - *self = match self { - RuleState::Matcher => RuleState::Between, - RuleState::Expander => RuleState::None, - RuleState::Between => RuleState::Expander, - RuleState::None => RuleState::Matcher, - }; - } -} - -fn update_macro_state(state: &mut MacroMatcherParseState, tok: &SyntaxToken) { - if !state.in_invoc_body { - if tok.kind() == T!['{'] || tok.kind() == T!['('] { - state.in_invoc_body = true; - } - return; - } - - match state.paren_ty { - Some((open, close)) => { - if tok.kind() == open { - state.paren_level += 1; - } else if tok.kind() == close { - state.paren_level -= 1; - if state.paren_level == 0 { - state.rule_state.transition(); - state.paren_ty = None; - } - } - } - None => { - match tok.kind() { - T!['('] => { - state.paren_ty = Some((T!['('], T![')'])); - } - T!['{'] => { - state.paren_ty = Some((T!['{'], T!['}'])); - } - T!['['] => { - state.paren_ty = Some((T!['['], T![']'])); - } - _ => (), - } - if state.paren_ty.is_some() { - state.paren_level = 1; - state.rule_state.transition(); - } - } - } -} - -fn is_metavariable(token: &SyntaxToken) -> Option { - match token.kind() { - kind if kind == SyntaxKind::IDENT || kind.is_keyword() => { - if let Some(_dollar) = token.prev_token().filter(|t| t.kind() == T![$]) { - return Some(token.text_range()); - } - } - _ => (), - }; - None -} diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs deleted file mode 100644 index 5262770f30317..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs +++ /dev/null @@ -1,340 +0,0 @@ -//! Defines token tags we use for syntax highlighting. -//! A tag is not unlike a CSS class. - -use std::{ - fmt::{self, Write}, - ops, -}; - -use ide_db::SymbolKind; - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Highlight { - pub tag: HlTag, - pub mods: HlMods, -} - -#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct HlMods(u32); - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum HlTag { - Symbol(SymbolKind), - - AttributeBracket, - BoolLiteral, - BuiltinType, - ByteLiteral, - CharLiteral, - Comment, - EscapeSequence, - FormatSpecifier, - Keyword, - NumericLiteral, - Operator(HlOperator), - Punctuation(HlPunct), - StringLiteral, - UnresolvedReference, - - // For things which don't have a specific highlight. - None, -} - -// Don't forget to adjust the feature description in crates/ide/src/syntax_highlighting.rs. -// And make sure to use the lsp strings used when converting to the protocol in crates\rust-analyzer\src\semantic_tokens.rs, not the names of the variants here. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(u8)] -pub enum HlMod { - /// Used for items in traits and impls. - Associated = 0, - /// Used with keywords like `async` and `await`. - Async, - /// Used to differentiate individual elements within attributes. - Attribute, - /// Callable item or value. - Callable, - /// Value that is being consumed in a function call - Consuming, - /// Used with keywords like `if` and `break`. - ControlFlow, - /// Used for crate names, like `serde`. - CrateRoot, - /// Used for items from built-in crates (std, core, alloc, test and proc_macro). - DefaultLibrary, - /// `foo` in `fn foo(x: i32)` is a definition, `foo` in `foo(90 + 2)` is - /// not. - Definition, - /// Doc-strings like this one. - Documentation, - /// Highlighting injection like rust code in doc strings or ra_fixture. - Injected, - /// Used for intra doc links in doc injection. - IntraDocLink, - /// Used for items from other crates. - Library, - /// Mutable binding. - Mutable, - /// Used for public items. - Public, - /// Immutable reference. - Reference, - /// Used for associated functions. - Static, - /// Used for items in traits and trait impls. - Trait, - // Keep this last! - /// Used for unsafe functions, unsafe traits, mutable statics, union accesses and unsafe operations. - Unsafe, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum HlPunct { - /// [] - Bracket, - /// {} - Brace, - /// () - Parenthesis, - /// <> - Angle, - /// , - Comma, - /// . - Dot, - /// : - Colon, - /// ; - Semi, - /// ! (only for macro calls) - MacroBang, - /// - Other, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum HlOperator { - /// |, &, !, ^, |=, &=, ^= - Bitwise, - /// +, -, *, /, +=, -=, *=, /= - Arithmetic, - /// &&, ||, ! - Logical, - /// >, <, ==, >=, <=, != - Comparison, - /// - Other, -} - -impl HlTag { - fn as_str(self) -> &'static str { - match self { - HlTag::Symbol(symbol) => match symbol { - SymbolKind::Attribute => "attribute", - SymbolKind::BuiltinAttr => "builtin_attr", - SymbolKind::Const => "constant", - SymbolKind::ConstParam => "const_param", - SymbolKind::Derive => "derive", - SymbolKind::DeriveHelper => "derive_helper", - SymbolKind::Enum => "enum", - SymbolKind::Field => "field", - SymbolKind::Function => "function", - SymbolKind::Impl => "self_type", - SymbolKind::Label => "label", - SymbolKind::LifetimeParam => "lifetime", - SymbolKind::Local => "variable", - SymbolKind::Macro => "macro", - SymbolKind::Module => "module", - SymbolKind::SelfParam => "self_keyword", - SymbolKind::SelfType => "self_type_keyword", - SymbolKind::Static => "static", - SymbolKind::Struct => "struct", - SymbolKind::ToolModule => "tool_module", - SymbolKind::Trait => "trait", - SymbolKind::TypeAlias => "type_alias", - SymbolKind::TypeParam => "type_param", - SymbolKind::Union => "union", - SymbolKind::ValueParam => "value_param", - SymbolKind::Variant => "enum_variant", - }, - HlTag::AttributeBracket => "attribute_bracket", - HlTag::BoolLiteral => "bool_literal", - HlTag::BuiltinType => "builtin_type", - HlTag::ByteLiteral => "byte_literal", - HlTag::CharLiteral => "char_literal", - HlTag::Comment => "comment", - HlTag::EscapeSequence => "escape_sequence", - HlTag::FormatSpecifier => "format_specifier", - HlTag::Keyword => "keyword", - HlTag::Punctuation(punct) => match punct { - HlPunct::Bracket => "bracket", - HlPunct::Brace => "brace", - HlPunct::Parenthesis => "parenthesis", - HlPunct::Angle => "angle", - HlPunct::Comma => "comma", - HlPunct::Dot => "dot", - HlPunct::Colon => "colon", - HlPunct::Semi => "semicolon", - HlPunct::MacroBang => "macro_bang", - HlPunct::Other => "punctuation", - }, - HlTag::NumericLiteral => "numeric_literal", - HlTag::Operator(op) => match op { - HlOperator::Bitwise => "bitwise", - HlOperator::Arithmetic => "arithmetic", - HlOperator::Logical => "logical", - HlOperator::Comparison => "comparison", - HlOperator::Other => "operator", - }, - HlTag::StringLiteral => "string_literal", - HlTag::UnresolvedReference => "unresolved_reference", - HlTag::None => "none", - } - } -} - -impl fmt::Display for HlTag { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.as_str(), f) - } -} - -impl HlMod { - const ALL: &'static [HlMod; HlMod::Unsafe as u8 as usize + 1] = &[ - HlMod::Associated, - HlMod::Async, - HlMod::Attribute, - HlMod::Callable, - HlMod::Consuming, - HlMod::ControlFlow, - HlMod::CrateRoot, - HlMod::DefaultLibrary, - HlMod::Definition, - HlMod::Documentation, - HlMod::Injected, - HlMod::IntraDocLink, - HlMod::Library, - HlMod::Mutable, - HlMod::Public, - HlMod::Reference, - HlMod::Static, - HlMod::Trait, - HlMod::Unsafe, - ]; - - fn as_str(self) -> &'static str { - match self { - HlMod::Associated => "associated", - HlMod::Async => "async", - HlMod::Attribute => "attribute", - HlMod::Callable => "callable", - HlMod::Consuming => "consuming", - HlMod::ControlFlow => "control", - HlMod::CrateRoot => "crate_root", - HlMod::DefaultLibrary => "default_library", - HlMod::Definition => "declaration", - HlMod::Documentation => "documentation", - HlMod::Injected => "injected", - HlMod::IntraDocLink => "intra_doc_link", - HlMod::Library => "library", - HlMod::Mutable => "mutable", - HlMod::Public => "public", - HlMod::Reference => "reference", - HlMod::Static => "static", - HlMod::Trait => "trait", - HlMod::Unsafe => "unsafe", - } - } - - fn mask(self) -> u32 { - 1 << (self as u32) - } -} - -impl fmt::Display for HlMod { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.as_str(), f) - } -} - -impl fmt::Display for Highlight { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.tag.fmt(f)?; - for modifier in self.mods.iter() { - f.write_char('.')?; - modifier.fmt(f)?; - } - Ok(()) - } -} - -impl From for Highlight { - fn from(tag: HlTag) -> Highlight { - Highlight::new(tag) - } -} - -impl From for Highlight { - fn from(op: HlOperator) -> Highlight { - Highlight::new(HlTag::Operator(op)) - } -} - -impl From for Highlight { - fn from(punct: HlPunct) -> Highlight { - Highlight::new(HlTag::Punctuation(punct)) - } -} - -impl From for Highlight { - fn from(sym: SymbolKind) -> Highlight { - Highlight::new(HlTag::Symbol(sym)) - } -} - -impl Highlight { - pub(crate) fn new(tag: HlTag) -> Highlight { - Highlight { tag, mods: HlMods::default() } - } - pub fn is_empty(&self) -> bool { - self.tag == HlTag::None && self.mods == HlMods::default() - } -} - -impl ops::BitOr for HlTag { - type Output = Highlight; - - fn bitor(self, rhs: HlMod) -> Highlight { - Highlight::new(self) | rhs - } -} - -impl ops::BitOrAssign for HlMods { - fn bitor_assign(&mut self, rhs: HlMod) { - self.0 |= rhs.mask(); - } -} - -impl ops::BitOrAssign for Highlight { - fn bitor_assign(&mut self, rhs: HlMod) { - self.mods |= rhs; - } -} - -impl ops::BitOr for Highlight { - type Output = Highlight; - - fn bitor(mut self, rhs: HlMod) -> Highlight { - self |= rhs; - self - } -} - -impl HlMods { - pub fn contains(self, m: HlMod) -> bool { - self.0 & m.mask() == m.mask() - } - - pub fn iter(self) -> impl Iterator { - HlMod::ALL.iter().copied().filter(move |it| self.0 & it.mask() == it.mask()) - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html deleted file mode 100644 index e07fd3925c784..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html +++ /dev/null @@ -1,62 +0,0 @@ - - -
fn not_static() {}
-
-struct foo {}
-
-impl foo {
-    pub fn is_static() {}
-    pub fn is_not_static(&self) {}
-}
-
-trait t {
-    fn t_is_static() {}
-    fn t_is_not_static(&self) {}
-}
-
-impl t for foo {
-    pub fn is_static() {}
-    pub fn is_not_static(&self) {}
-}
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html deleted file mode 100644 index 1a4398814760b..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html +++ /dev/null @@ -1,58 +0,0 @@ - - -
#[allow(dead_code)]
-#[rustfmt::skip]
-#[proc_macros::identity]
-#[derive(Copy)]
-/// This is a doc comment
-// This is a normal comment
-/// This is a doc comment
-#[derive(Copy)]
-// This is another normal comment
-/// This is another doc comment
-// This is another normal comment
-#[derive(Copy)]
-// The reason for these being here is to test AttrIds
-struct Foo;
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html deleted file mode 100644 index 1e4c06df7ea0b..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html +++ /dev/null @@ -1,66 +0,0 @@ - - -
extern crate foo;
-use core::iter;
-
-pub const NINETY_TWO: u8 = 92;
-
-use foo as foooo;
-
-pub(crate) fn main() {
-    let baz = iter::repeat(92);
-}
-
-mod bar {
-    pub(in super) const FORTY_TWO: u8 = 42;
-
-    mod baz {
-        use super::super::NINETY_TWO;
-        use crate::foooo::Point;
-
-        pub(in super::super) const TWENTY_NINE: u8 = 29;
-    }
-}
-
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html deleted file mode 100644 index 5d66f832daf94..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html +++ /dev/null @@ -1,50 +0,0 @@ - - -
use core::iter;
-
-fn main() {
-    let foo = Some(92);
-    let nums = iter::repeat(foo.unwrap());
-}
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html deleted file mode 100644 index a747b4bc1f9c0..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ /dev/null @@ -1,190 +0,0 @@ - - -
//! This is a module to test doc injection.
-//! ```
-//! fn test() {}
-//! ```
-
-mod outline_module;
-
-/// ```
-/// let _ = "early doctests should not go boom";
-/// ```
-struct Foo {
-    bar: bool,
-}
-
-/// This is an impl with a code block.
-///
-/// ```
-/// fn foo() {
-///
-/// }
-/// ```
-impl Foo {
-    /// ```
-    /// let _ = "Call me
-    //    KILLER WHALE
-    ///     Ishmael.";
-    /// ```
-    pub const bar: bool = true;
-
-    /// Constructs a new `Foo`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # #![allow(unused_mut)]
-    /// let mut foo: Foo = Foo::new();
-    /// ```
-    pub const fn new() -> Foo {
-        Foo { bar: true }
-    }
-
-    /// `bar` method on `Foo`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use x::y;
-    ///
-    /// let foo = Foo::new();
-    ///
-    /// // calls bar on foo
-    /// assert!(foo.bar());
-    ///
-    /// let bar = foo.bar || Foo::bar;
-    ///
-    /// /* multi-line
-    ///        comment */
-    ///
-    /// let multi_line_string = "Foo
-    ///   bar\n
-    ///          ";
-    ///
-    /// ```
-    ///
-    /// ```rust,no_run
-    /// let foobar = Foo::new().bar();
-    /// ```
-    ///
-    /// ~~~rust,no_run
-    /// // code block with tilde.
-    /// let foobar = Foo::new().bar();
-    /// ~~~
-    ///
-    /// ```
-    /// // functions
-    /// fn foo<T, const X: usize>(arg: i32) {
-    ///     let x: T = X;
-    /// }
-    /// ```
-    ///
-    /// ```sh
-    /// echo 1
-    /// ```
-    pub fn foo(&self) -> bool {
-        true
-    }
-}
-
-/// [`Foo`](Foo) is a struct
-/// This function is > [`all_the_links`](all_the_links) <
-/// [`noop`](noop) is a macro below
-/// [`Item`] is a struct in the module [`module`]
-///
-/// [`Item`]: module::Item
-/// [mix_and_match]: ThisShouldntResolve
-pub fn all_the_links() {}
-
-pub mod module {
-    pub struct Item;
-}
-
-/// ```
-/// macro_rules! noop { ($expr:expr) => { $expr }}
-/// noop!(1);
-/// ```
-macro_rules! noop {
-    ($expr:expr) => {
-        $expr
-    }
-}
-
-/// ```rust
-/// let _ = example(&[1, 2, 3]);
-/// ```
-///
-/// ```
-/// loop {}
-#[cfg_attr(not(feature = "false"), doc = "loop {}")]
-#[doc = "loop {}"]
-/// ```
-///
-#[cfg_attr(feature = "alloc", doc = "```rust")]
-#[cfg_attr(not(feature = "alloc"), doc = "```ignore")]
-/// let _ = example(&alloc::vec![1, 2, 3]);
-/// ```
-pub fn mix_and_match() {}
-
-/**
-It is beyond me why you'd use these when you got ///
-```rust
-let _ = example(&[1, 2, 3]);
-```
-[`block_comments2`] tests these with indentation
- */
-pub fn block_comments() {}
-
-/**
-    Really, I don't get it
-    ```rust
-    let _ = example(&[1, 2, 3]);
-    ```
-    [`block_comments`] tests these without indentation
-*/
-pub fn block_comments2() {}
-
-
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html deleted file mode 100644 index af41796e2169b..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html +++ /dev/null @@ -1,47 +0,0 @@ - - -
extern crate std;
-extern crate alloc as abc;
-
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html deleted file mode 100644 index a97802cbbd0f9..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html +++ /dev/null @@ -1,233 +0,0 @@ - - -
use inner::{self as inner_mod};
-mod inner {}
-
-pub mod ops {
-    #[lang = "fn_once"]
-    pub trait FnOnce<Args> {}
-
-    #[lang = "fn_mut"]
-    pub trait FnMut<Args>: FnOnce<Args> {}
-
-    #[lang = "fn"]
-    pub trait Fn<Args>: FnMut<Args> {}
-}
-
-struct Foo {
-    x: u32,
-}
-
-trait Bar {
-    fn bar(&self) -> i32;
-}
-
-impl Bar for Foo {
-    fn bar(&self) -> i32 {
-        self.x
-    }
-}
-
-impl Foo {
-    fn baz(mut self, f: Foo) -> i32 {
-        f.baz(self)
-    }
-
-    fn qux(&mut self) {
-        self.x = 0;
-    }
-
-    fn quop(&self) -> i32 {
-        self.x
-    }
-}
-
-use self::FooCopy::{self as BarCopy};
-
-#[derive(Copy)]
-struct FooCopy {
-    x: u32,
-}
-
-impl FooCopy {
-    fn baz(self, f: FooCopy) -> u32 {
-        f.baz(self)
-    }
-
-    fn qux(&mut self) {
-        self.x = 0;
-    }
-
-    fn quop(&self) -> u32 {
-        self.x
-    }
-}
-
-fn str() {
-    str();
-}
-
-fn foo<'a, T>() -> T {
-    foo::<'a, i32>()
-}
-
-fn never() -> ! {
-    loop {}
-}
-
-fn const_param<const FOO: usize>() -> usize {
-    const_param::<{ FOO }>();
-    FOO
-}
-
-use ops::Fn;
-fn baz<F: Fn() -> ()>(f: F) {
-    f()
-}
-
-fn foobar() -> impl Copy {}
-
-fn foo() {
-    let bar = foobar();
-}
-
-// comment
-fn main() {
-    let mut x = 42;
-    x += 1;
-    let y = &mut x;
-    let z = &y;
-
-    let Foo { x: z, y } = Foo { x: z, y };
-
-    y;
-
-    let mut foo = Foo { x, y: x };
-    let foo2 = Foo { x, y: x };
-    foo.quop();
-    foo.qux();
-    foo.baz(foo2);
-
-    let mut copy = FooCopy { x };
-    copy.quop();
-    copy.qux();
-    copy.baz(copy);
-
-    let a = |x| x;
-    let bar = Foo::baz;
-
-    let baz = (-42,);
-    let baz = -baz.0;
-
-    let _ = !true;
-
-    'foo: loop {
-        break 'foo;
-        continue 'foo;
-    }
-}
-
-enum Option<T> {
-    Some(T),
-    None,
-}
-use Option::*;
-
-impl<T> Option<T> {
-    fn and<U>(self, other: Option<U>) -> Option<(T, U)> {
-        match other {
-            None => unimplemented!(),
-            Nope => Nope,
-        }
-    }
-}
-
-async fn learn_and_sing() {
-    let song = learn_song().await;
-    sing_song(song).await;
-}
-
-async fn async_main() {
-    let f1 = learn_and_sing();
-    let f2 = dance();
-    futures::join!(f1, f2);
-}
-
-fn use_foo_items() {
-    let bob = foo::Person {
-        name: "Bob",
-        age: foo::consts::NUMBER,
-    };
-
-    let control_flow = foo::identity(foo::ControlFlow::Continue);
-
-    if control_flow.should_die() {
-        foo::die!();
-    }
-}
-
-pub enum Bool { True, False }
-
-impl Bool {
-    pub const fn to_primitive(self) -> bool {
-        true
-    }
-}
-const USAGE_OF_BOOL:bool = Bool::True.to_primitive();
-
-trait Baz {
-    type Qux;
-}
-
-fn baz<T>(t: T)
-where
-    T: Baz,
-    <T as Baz>::Qux: Bar {}
-
-fn gp_shadows_trait<Baz: Bar>() {
-    Baz::bar;
-}
-
-
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html deleted file mode 100644 index ced7d22f03e47..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html +++ /dev/null @@ -1,62 +0,0 @@ - - -
fn fixture(ra_fixture: &str) {}
-
-fn main() {
-    fixture(r#"
-trait Foo {
-    fn foo() {
-        println!("2 + 2 = {}", 4);
-    }
-}"#
-    );
-    fixture(r"
-fn foo() {
-    foo($0{
-        92
-    }$0)
-}"
-    );
-}
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html deleted file mode 100644 index 66f9ede96295f..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html +++ /dev/null @@ -1,58 +0,0 @@ - - -
extern crate self;
-
-use crate;
-use self;
-mod __ {
-    use super::*;
-}
-
-macro_rules! void {
-    ($($tt:tt)*) => {}
-}
-void!(Self);
-struct __ where Self:;
-fn __(_: Self) {}
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html deleted file mode 100644 index 2d85fc8c925b7..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html +++ /dev/null @@ -1,55 +0,0 @@ - - -

-#[derive()]
-struct Foo<'a, 'b, 'c> where 'a: 'a, 'static: 'static {
-    field: &'a (),
-    field2: &'static (),
-}
-impl<'a> Foo<'_, 'a, 'static>
-where
-    'a: 'a,
-    'static: 'static
-{}
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html deleted file mode 100644 index 54d4279525dd5..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html +++ /dev/null @@ -1,96 +0,0 @@ - - -
proc_macros::mirror! {
-    {
-        ,i32 :x pub
-        ,i32 :y pub
-    } Foo struct
-}
-macro_rules! def_fn {
-    ($($tt:tt)*) => {$($tt)*}
-}
-
-def_fn! {
-    fn bar() -> u32 {
-        100
-    }
-}
-
-macro_rules! dont_color_me_braces {
-    () => {0}
-}
-
-macro_rules! noop {
-    ($expr:expr) => {
-        $expr
-    }
-}
-
-/// textually shadow previous definition
-macro_rules! noop {
-    ($expr:expr) => {
-        $expr
-    }
-}
-
-macro_rules! keyword_frag {
-    ($type:ty) => ($type)
-}
-
-macro with_args($i:ident) {
-    $i
-}
-
-macro without_args {
-    ($i:ident) => {
-        $i
-    }
-}
-
-fn main() {
-    println!("Hello, {}!", 92);
-    dont_color_me_braces!();
-    noop!(noop!(1));
-}
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html deleted file mode 100644 index 2369071ae2aae..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html +++ /dev/null @@ -1,58 +0,0 @@ - - -
fn main() {
-    1 + 1 - 1 * 1 / 1 % 1 | 1 & 1 ! 1 ^ 1 >> 1 << 1;
-    let mut a = 0;
-    a += 1;
-    a -= 1;
-    a *= 1;
-    a /= 1;
-    a %= 1;
-    a |= 1;
-    a &= 1;
-    a ^= 1;
-    a >>= 1;
-    a <<= 1;
-}
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html deleted file mode 100644 index bff35c897e1da..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html +++ /dev/null @@ -1,56 +0,0 @@ - - -
fn main() {
-    let hello = "hello";
-    let x = hello.to_string();
-    let y = hello.to_string();
-
-    let x = "other color please!";
-    let y = x.to_string();
-}
-
-fn bar() {
-    let mut hello = "hello";
-}
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html deleted file mode 100644 index c627bc9b09ab0..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ /dev/null @@ -1,164 +0,0 @@ - - -
macro_rules! println {
-    ($($arg:tt)*) => ({
-        $crate::io::_print($crate::format_args_nl!($($arg)*));
-    })
-}
-#[rustc_builtin_macro]
-#[macro_export]
-macro_rules! format_args {}
-#[rustc_builtin_macro]
-#[macro_export]
-macro_rules! const_format_args {}
-#[rustc_builtin_macro]
-#[macro_export]
-macro_rules! format_args_nl {}
-
-mod panic {
-    pub macro panic_2015 {
-        () => (
-            $crate::panicking::panic("explicit panic")
-        ),
-        ($msg:literal $(,)?) => (
-            $crate::panicking::panic($msg)
-        ),
-        // Use `panic_str` instead of `panic_display::<&str>` for non_fmt_panic lint.
-        ($msg:expr $(,)?) => (
-            $crate::panicking::panic_str($msg)
-        ),
-        // Special-case the single-argument case for const_panic.
-        ("{}", $arg:expr $(,)?) => (
-            $crate::panicking::panic_display(&$arg)
-        ),
-        ($fmt:expr, $($arg:tt)+) => (
-            $crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+))
-        ),
-    }
-}
-
-#[rustc_builtin_macro(std_panic)]
-#[macro_export]
-macro_rules! panic {}
-#[rustc_builtin_macro]
-macro_rules! assert {}
-#[rustc_builtin_macro]
-macro_rules! asm {}
-
-macro_rules! toho {
-    () => ($crate::panic!("not yet implemented"));
-    ($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", $crate::format_args!($($arg)+)));
-}
-
-fn main() {
-    println!("Hello {{Hello}}");
-    // from https://doc.rust-lang.org/std/fmt/index.html
-    println!("Hello");                 // => "Hello"
-    println!("Hello, {}!", "world");   // => "Hello, world!"
-    println!("The number is {}", 1);   // => "The number is 1"
-    println!("{:?}", (3, 4));          // => "(3, 4)"
-    println!("{value}", value=4);      // => "4"
-    println!("{} {}", 1, 2);           // => "1 2"
-    println!("{:04}", 42);             // => "0042" with leading zerosV
-    println!("{1} {} {0} {}", 1, 2);   // => "2 1 1 2"
-    println!("{argument}", argument = "test");   // => "test"
-    println!("{name} {}", 1, name = 2);          // => "2 1"
-    println!("{a} {c} {b}", a="a", b='b', c=3);  // => "a 3 b"
-    println!("{{{}}}", 2);                       // => "{2}"
-    println!("Hello {:5}!", "x");
-    println!("Hello {:1$}!", "x", 5);
-    println!("Hello {1:0$}!", 5, "x");
-    println!("Hello {:width$}!", "x", width = 5);
-    println!("Hello {:<5}!", "x");
-    println!("Hello {:-<5}!", "x");
-    println!("Hello {:^5}!", "x");
-    println!("Hello {:>5}!", "x");
-    println!("Hello {:+}!", 5);
-    println!("{:#x}!", 27);
-    println!("Hello {:05}!", 5);
-    println!("Hello {:05}!", -5);
-    println!("{:#010x}!", 27);
-    println!("Hello {0} is {1:.5}", "x", 0.01);
-    println!("Hello {1} is {2:.0$}", 5, "x", 0.01);
-    println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
-    println!("Hello {} is {:.*}",    "x", 5, 0.01);
-    println!("Hello {} is {2:.*}",   "x", 5, 0.01);
-    println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01);
-    println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56);
-    println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56");
-    println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56");
-
-    let _ = "{}"
-    let _ = "{{}}";
-
-    println!("Hello {{}}");
-    println!("{{ Hello");
-    println!("Hello }}");
-    println!("{{Hello}}");
-    println!("{{ Hello }}");
-    println!("{{Hello }}");
-    println!("{{ Hello}}");
-
-    println!(r"Hello, {}!", "world");
-
-    // escape sequences
-    println!("Hello\nWorld");
-    println!("\u{48}\x65\x6C\x6C\x6F World");
-
-    let _ = "\x28\x28\x00\x63\n";
-    let _ = b"\x28\x28\x00\x63\n";
-
-    println!("{\x41}", A = 92);
-    println!("{ничоси}", ничоси = 92);
-
-    println!("{:x?} {} ", thingy, n2);
-    panic!("{}", 0);
-    panic!("more {}", 1);
-    assert!(true, "{}", 1);
-    assert!(true, "{} asdasd", 1);
-    toho!("{}fmt", 0);
-    asm!("mov eax, {0}");
-    format_args!(concat!("{}"), "{}");
-}
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html deleted file mode 100644 index 0716bae7513b9..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html +++ /dev/null @@ -1,126 +0,0 @@ - - -
macro_rules! id {
-    ($($tt:tt)*) => {
-        $($tt)*
-    };
-}
-macro_rules! unsafe_deref {
-    () => {
-        *(&() as *const ())
-    };
-}
-static mut MUT_GLOBAL: Struct = Struct { field: 0 };
-static GLOBAL: Struct = Struct { field: 0 };
-unsafe fn unsafe_fn() {}
-
-union Union {
-    a: u32,
-    b: f32,
-}
-
-struct Struct { field: i32 }
-impl Struct {
-    unsafe fn unsafe_method(&self) {}
-}
-
-#[repr(packed)]
-struct Packed {
-    a: u16,
-}
-
-unsafe trait UnsafeTrait {}
-unsafe impl UnsafeTrait for Packed {}
-impl !UnsafeTrait for () {}
-
-fn unsafe_trait_bound<T: UnsafeTrait>(_: T) {}
-
-trait DoTheAutoref {
-    fn calls_autoref(&self);
-}
-
-impl DoTheAutoref for u16 {
-    fn calls_autoref(&self) {}
-}
-
-fn main() {
-    let x = &5 as *const _ as *const usize;
-    let u = Union { b: 0 };
-
-    id! {
-        unsafe { unsafe_deref!() }
-    };
-
-    unsafe {
-        unsafe_deref!();
-        id! { unsafe_deref!() };
-
-        // unsafe fn and method calls
-        unsafe_fn();
-        let b = u.b;
-        match u {
-            Union { b: 0 } => (),
-            Union { a } => (),
-        }
-        Struct { field: 0 }.unsafe_method();
-
-        // unsafe deref
-        *x;
-
-        // unsafe access to a static mut
-        MUT_GLOBAL.field;
-        GLOBAL.field;
-
-        // unsafe ref of packed fields
-        let packed = Packed { a: 0 };
-        let a = &packed.a;
-        let ref a = packed.a;
-        let Packed { ref a } = packed;
-        let Packed { a: ref _a } = packed;
-
-        // unsafe auto ref of packed field
-        packed.a.calls_autoref();
-    }
-}
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs deleted file mode 100644 index 6ba6153178da9..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs +++ /dev/null @@ -1,1050 +0,0 @@ -use std::time::Instant; - -use expect_test::{expect_file, ExpectFile}; -use ide_db::SymbolKind; -use test_utils::{bench, bench_fixture, skip_slow_tests, AssertLinear}; - -use crate::{fixture, FileRange, HlTag, TextRange}; - -#[test] -fn attributes() { - check_highlighting( - r#" -//- proc_macros: identity -//- minicore: derive, copy -#[allow(dead_code)] -#[rustfmt::skip] -#[proc_macros::identity] -#[derive(Copy)] -/// This is a doc comment -// This is a normal comment -/// This is a doc comment -#[derive(Copy)] -// This is another normal comment -/// This is another doc comment -// This is another normal comment -#[derive(Copy)] -// The reason for these being here is to test AttrIds -struct Foo; -"#, - expect_file!["./test_data/highlight_attributes.html"], - false, - ); -} - -#[test] -fn macros() { - check_highlighting( - r#" -//- proc_macros: mirror -proc_macros::mirror! { - { - ,i32 :x pub - ,i32 :y pub - } Foo struct -} -macro_rules! def_fn { - ($($tt:tt)*) => {$($tt)*} -} - -def_fn! { - fn bar() -> u32 { - 100 - } -} - -macro_rules! dont_color_me_braces { - () => {0} -} - -macro_rules! noop { - ($expr:expr) => { - $expr - } -} - -/// textually shadow previous definition -macro_rules! noop { - ($expr:expr) => { - $expr - } -} - -macro_rules! keyword_frag { - ($type:ty) => ($type) -} - -macro with_args($i:ident) { - $i -} - -macro without_args { - ($i:ident) => { - $i - } -} - -fn main() { - println!("Hello, {}!", 92); - dont_color_me_braces!(); - noop!(noop!(1)); -} -"#, - expect_file!["./test_data/highlight_macros.html"], - false, - ); -} - -/// If what you want to test feels like a specific entity consider making a new test instead, -/// this test fixture here in fact should shrink instead of grow ideally. -#[test] -fn test_highlighting() { - check_highlighting( - r#" -//- minicore: derive, copy -//- /main.rs crate:main deps:foo -use inner::{self as inner_mod}; -mod inner {} - -pub mod ops { - #[lang = "fn_once"] - pub trait FnOnce {} - - #[lang = "fn_mut"] - pub trait FnMut: FnOnce {} - - #[lang = "fn"] - pub trait Fn: FnMut {} -} - -struct Foo { - x: u32, -} - -trait Bar { - fn bar(&self) -> i32; -} - -impl Bar for Foo { - fn bar(&self) -> i32 { - self.x - } -} - -impl Foo { - fn baz(mut self, f: Foo) -> i32 { - f.baz(self) - } - - fn qux(&mut self) { - self.x = 0; - } - - fn quop(&self) -> i32 { - self.x - } -} - -use self::FooCopy::{self as BarCopy}; - -#[derive(Copy)] -struct FooCopy { - x: u32, -} - -impl FooCopy { - fn baz(self, f: FooCopy) -> u32 { - f.baz(self) - } - - fn qux(&mut self) { - self.x = 0; - } - - fn quop(&self) -> u32 { - self.x - } -} - -fn str() { - str(); -} - -fn foo<'a, T>() -> T { - foo::<'a, i32>() -} - -fn never() -> ! { - loop {} -} - -fn const_param() -> usize { - const_param::<{ FOO }>(); - FOO -} - -use ops::Fn; -fn baz ()>(f: F) { - f() -} - -fn foobar() -> impl Copy {} - -fn foo() { - let bar = foobar(); -} - -// comment -fn main() { - let mut x = 42; - x += 1; - let y = &mut x; - let z = &y; - - let Foo { x: z, y } = Foo { x: z, y }; - - y; - - let mut foo = Foo { x, y: x }; - let foo2 = Foo { x, y: x }; - foo.quop(); - foo.qux(); - foo.baz(foo2); - - let mut copy = FooCopy { x }; - copy.quop(); - copy.qux(); - copy.baz(copy); - - let a = |x| x; - let bar = Foo::baz; - - let baz = (-42,); - let baz = -baz.0; - - let _ = !true; - - 'foo: loop { - break 'foo; - continue 'foo; - } -} - -enum Option { - Some(T), - None, -} -use Option::*; - -impl Option { - fn and(self, other: Option) -> Option<(T, U)> { - match other { - None => unimplemented!(), - Nope => Nope, - } - } -} - -async fn learn_and_sing() { - let song = learn_song().await; - sing_song(song).await; -} - -async fn async_main() { - let f1 = learn_and_sing(); - let f2 = dance(); - futures::join!(f1, f2); -} - -fn use_foo_items() { - let bob = foo::Person { - name: "Bob", - age: foo::consts::NUMBER, - }; - - let control_flow = foo::identity(foo::ControlFlow::Continue); - - if control_flow.should_die() { - foo::die!(); - } -} - -pub enum Bool { True, False } - -impl Bool { - pub const fn to_primitive(self) -> bool { - true - } -} -const USAGE_OF_BOOL:bool = Bool::True.to_primitive(); - -trait Baz { - type Qux; -} - -fn baz(t: T) -where - T: Baz, - ::Qux: Bar {} - -fn gp_shadows_trait() { - Baz::bar; -} - -//- /foo.rs crate:foo -pub struct Person { - pub name: &'static str, - pub age: u8, -} - -pub enum ControlFlow { - Continue, - Die, -} - -impl ControlFlow { - pub fn should_die(self) -> bool { - matches!(self, ControlFlow::Die) - } -} - -pub fn identity(x: T) -> T { x } - -pub mod consts { - pub const NUMBER: i64 = 92; -} - -macro_rules! die { - () => { - panic!(); - }; -} -"#, - expect_file!["./test_data/highlight_general.html"], - false, - ); -} - -#[test] -fn test_lifetime_highlighting() { - check_highlighting( - r#" -//- minicore: derive - -#[derive()] -struct Foo<'a, 'b, 'c> where 'a: 'a, 'static: 'static { - field: &'a (), - field2: &'static (), -} -impl<'a> Foo<'_, 'a, 'static> -where - 'a: 'a, - 'static: 'static -{} -"#, - expect_file!["./test_data/highlight_lifetimes.html"], - false, - ); -} - -#[test] -fn test_keyword_highlighting() { - check_highlighting( - r#" -extern crate self; - -use crate; -use self; -mod __ { - use super::*; -} - -macro_rules! void { - ($($tt:tt)*) => {} -} -void!(Self); -struct __ where Self:; -fn __(_: Self) {} -"#, - expect_file!["./test_data/highlight_keywords.html"], - false, - ); -} - -#[test] -fn test_string_highlighting() { - // The format string detection is based on macro-expansion, - // thus, we have to copy the macro definition from `std` - check_highlighting( - r#" -macro_rules! println { - ($($arg:tt)*) => ({ - $crate::io::_print($crate::format_args_nl!($($arg)*)); - }) -} -#[rustc_builtin_macro] -#[macro_export] -macro_rules! format_args {} -#[rustc_builtin_macro] -#[macro_export] -macro_rules! const_format_args {} -#[rustc_builtin_macro] -#[macro_export] -macro_rules! format_args_nl {} - -mod panic { - pub macro panic_2015 { - () => ( - $crate::panicking::panic("explicit panic") - ), - ($msg:literal $(,)?) => ( - $crate::panicking::panic($msg) - ), - // Use `panic_str` instead of `panic_display::<&str>` for non_fmt_panic lint. - ($msg:expr $(,)?) => ( - $crate::panicking::panic_str($msg) - ), - // Special-case the single-argument case for const_panic. - ("{}", $arg:expr $(,)?) => ( - $crate::panicking::panic_display(&$arg) - ), - ($fmt:expr, $($arg:tt)+) => ( - $crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+)) - ), - } -} - -#[rustc_builtin_macro(std_panic)] -#[macro_export] -macro_rules! panic {} -#[rustc_builtin_macro] -macro_rules! assert {} -#[rustc_builtin_macro] -macro_rules! asm {} - -macro_rules! toho { - () => ($crate::panic!("not yet implemented")); - ($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", $crate::format_args!($($arg)+))); -} - -fn main() { - println!("Hello {{Hello}}"); - // from https://doc.rust-lang.org/std/fmt/index.html - println!("Hello"); // => "Hello" - println!("Hello, {}!", "world"); // => "Hello, world!" - println!("The number is {}", 1); // => "The number is 1" - println!("{:?}", (3, 4)); // => "(3, 4)" - println!("{value}", value=4); // => "4" - println!("{} {}", 1, 2); // => "1 2" - println!("{:04}", 42); // => "0042" with leading zerosV - println!("{1} {} {0} {}", 1, 2); // => "2 1 1 2" - println!("{argument}", argument = "test"); // => "test" - println!("{name} {}", 1, name = 2); // => "2 1" - println!("{a} {c} {b}", a="a", b='b', c=3); // => "a 3 b" - println!("{{{}}}", 2); // => "{2}" - println!("Hello {:5}!", "x"); - println!("Hello {:1$}!", "x", 5); - println!("Hello {1:0$}!", 5, "x"); - println!("Hello {:width$}!", "x", width = 5); - println!("Hello {:<5}!", "x"); - println!("Hello {:-<5}!", "x"); - println!("Hello {:^5}!", "x"); - println!("Hello {:>5}!", "x"); - println!("Hello {:+}!", 5); - println!("{:#x}!", 27); - println!("Hello {:05}!", 5); - println!("Hello {:05}!", -5); - println!("{:#010x}!", 27); - println!("Hello {0} is {1:.5}", "x", 0.01); - println!("Hello {1} is {2:.0$}", 5, "x", 0.01); - println!("Hello {0} is {2:.1$}", "x", 5, 0.01); - println!("Hello {} is {:.*}", "x", 5, 0.01); - println!("Hello {} is {2:.*}", "x", 5, 0.01); - println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01); - println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56); - println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56"); - println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56"); - - let _ = "{}" - let _ = "{{}}"; - - println!("Hello {{}}"); - println!("{{ Hello"); - println!("Hello }}"); - println!("{{Hello}}"); - println!("{{ Hello }}"); - println!("{{Hello }}"); - println!("{{ Hello}}"); - - println!(r"Hello, {}!", "world"); - - // escape sequences - println!("Hello\nWorld"); - println!("\u{48}\x65\x6C\x6C\x6F World"); - - let _ = "\x28\x28\x00\x63\n"; - let _ = b"\x28\x28\x00\x63\n"; - - println!("{\x41}", A = 92); - println!("{ничоси}", ничоси = 92); - - println!("{:x?} {} ", thingy, n2); - panic!("{}", 0); - panic!("more {}", 1); - assert!(true, "{}", 1); - assert!(true, "{} asdasd", 1); - toho!("{}fmt", 0); - asm!("mov eax, {0}"); - format_args!(concat!("{}"), "{}"); -}"#, - expect_file!["./test_data/highlight_strings.html"], - false, - ); -} - -#[test] -fn test_unsafe_highlighting() { - check_highlighting( - r#" -macro_rules! id { - ($($tt:tt)*) => { - $($tt)* - }; -} -macro_rules! unsafe_deref { - () => { - *(&() as *const ()) - }; -} -static mut MUT_GLOBAL: Struct = Struct { field: 0 }; -static GLOBAL: Struct = Struct { field: 0 }; -unsafe fn unsafe_fn() {} - -union Union { - a: u32, - b: f32, -} - -struct Struct { field: i32 } -impl Struct { - unsafe fn unsafe_method(&self) {} -} - -#[repr(packed)] -struct Packed { - a: u16, -} - -unsafe trait UnsafeTrait {} -unsafe impl UnsafeTrait for Packed {} -impl !UnsafeTrait for () {} - -fn unsafe_trait_bound(_: T) {} - -trait DoTheAutoref { - fn calls_autoref(&self); -} - -impl DoTheAutoref for u16 { - fn calls_autoref(&self) {} -} - -fn main() { - let x = &5 as *const _ as *const usize; - let u = Union { b: 0 }; - - id! { - unsafe { unsafe_deref!() } - }; - - unsafe { - unsafe_deref!(); - id! { unsafe_deref!() }; - - // unsafe fn and method calls - unsafe_fn(); - let b = u.b; - match u { - Union { b: 0 } => (), - Union { a } => (), - } - Struct { field: 0 }.unsafe_method(); - - // unsafe deref - *x; - - // unsafe access to a static mut - MUT_GLOBAL.field; - GLOBAL.field; - - // unsafe ref of packed fields - let packed = Packed { a: 0 }; - let a = &packed.a; - let ref a = packed.a; - let Packed { ref a } = packed; - let Packed { a: ref _a } = packed; - - // unsafe auto ref of packed field - packed.a.calls_autoref(); - } -} -"#, - expect_file!["./test_data/highlight_unsafe.html"], - false, - ); -} - -#[test] -fn test_highlight_doc_comment() { - check_highlighting( - r#" -//- /main.rs -//! This is a module to test doc injection. -//! ``` -//! fn test() {} -//! ``` - -mod outline_module; - -/// ``` -/// let _ = "early doctests should not go boom"; -/// ``` -struct Foo { - bar: bool, -} - -/// This is an impl with a code block. -/// -/// ``` -/// fn foo() { -/// -/// } -/// ``` -impl Foo { - /// ``` - /// let _ = "Call me - // KILLER WHALE - /// Ishmael."; - /// ``` - pub const bar: bool = true; - - /// Constructs a new `Foo`. - /// - /// # Examples - /// - /// ``` - /// # #![allow(unused_mut)] - /// let mut foo: Foo = Foo::new(); - /// ``` - pub const fn new() -> Foo { - Foo { bar: true } - } - - /// `bar` method on `Foo`. - /// - /// # Examples - /// - /// ``` - /// use x::y; - /// - /// let foo = Foo::new(); - /// - /// // calls bar on foo - /// assert!(foo.bar()); - /// - /// let bar = foo.bar || Foo::bar; - /// - /// /* multi-line - /// comment */ - /// - /// let multi_line_string = "Foo - /// bar\n - /// "; - /// - /// ``` - /// - /// ```rust,no_run - /// let foobar = Foo::new().bar(); - /// ``` - /// - /// ~~~rust,no_run - /// // code block with tilde. - /// let foobar = Foo::new().bar(); - /// ~~~ - /// - /// ``` - /// // functions - /// fn foo(arg: i32) { - /// let x: T = X; - /// } - /// ``` - /// - /// ```sh - /// echo 1 - /// ``` - pub fn foo(&self) -> bool { - true - } -} - -/// [`Foo`](Foo) is a struct -/// This function is > [`all_the_links`](all_the_links) < -/// [`noop`](noop) is a macro below -/// [`Item`] is a struct in the module [`module`] -/// -/// [`Item`]: module::Item -/// [mix_and_match]: ThisShouldntResolve -pub fn all_the_links() {} - -pub mod module { - pub struct Item; -} - -/// ``` -/// macro_rules! noop { ($expr:expr) => { $expr }} -/// noop!(1); -/// ``` -macro_rules! noop { - ($expr:expr) => { - $expr - } -} - -/// ```rust -/// let _ = example(&[1, 2, 3]); -/// ``` -/// -/// ``` -/// loop {} -#[cfg_attr(not(feature = "false"), doc = "loop {}")] -#[doc = "loop {}"] -/// ``` -/// -#[cfg_attr(feature = "alloc", doc = "```rust")] -#[cfg_attr(not(feature = "alloc"), doc = "```ignore")] -/// let _ = example(&alloc::vec![1, 2, 3]); -/// ``` -pub fn mix_and_match() {} - -/** -It is beyond me why you'd use these when you got /// -```rust -let _ = example(&[1, 2, 3]); -``` -[`block_comments2`] tests these with indentation - */ -pub fn block_comments() {} - -/** - Really, I don't get it - ```rust - let _ = example(&[1, 2, 3]); - ``` - [`block_comments`] tests these without indentation -*/ -pub fn block_comments2() {} - -//- /outline_module.rs -//! This is an outline module whose purpose is to test that its inline attribute injection does not -//! spill into its parent. -//! ``` -//! fn test() {} -//! ``` -"#, - expect_file!["./test_data/highlight_doctest.html"], - false, - ); -} - -#[test] -fn test_extern_crate() { - check_highlighting( - r#" -//- /main.rs crate:main deps:std,alloc -extern crate std; -extern crate alloc as abc; -//- /std/lib.rs crate:std -pub struct S; -//- /alloc/lib.rs crate:alloc -pub struct A -"#, - expect_file!["./test_data/highlight_extern_crate.html"], - false, - ); -} - -#[test] -fn test_crate_root() { - check_highlighting( - r#" -//- minicore: iterators -//- /main.rs crate:main deps:foo -extern crate foo; -use core::iter; - -pub const NINETY_TWO: u8 = 92; - -use foo as foooo; - -pub(crate) fn main() { - let baz = iter::repeat(92); -} - -mod bar { - pub(in super) const FORTY_TWO: u8 = 42; - - mod baz { - use super::super::NINETY_TWO; - use crate::foooo::Point; - - pub(in super::super) const TWENTY_NINE: u8 = 29; - } -} -//- /foo.rs crate:foo -struct Point { - x: u8, - y: u8, -} - -mod inner { - pub(super) fn swap(p: crate::Point) -> crate::Point { - crate::Point { x: p.y, y: p.x } - } -} -"#, - expect_file!["./test_data/highlight_crate_root.html"], - false, - ); -} - -#[test] -fn test_default_library() { - check_highlighting( - r#" -//- minicore: option, iterators -use core::iter; - -fn main() { - let foo = Some(92); - let nums = iter::repeat(foo.unwrap()); -} -"#, - expect_file!["./test_data/highlight_default_library.html"], - false, - ); -} - -#[test] -fn test_associated_function() { - check_highlighting( - r#" -fn not_static() {} - -struct foo {} - -impl foo { - pub fn is_static() {} - pub fn is_not_static(&self) {} -} - -trait t { - fn t_is_static() {} - fn t_is_not_static(&self) {} -} - -impl t for foo { - pub fn is_static() {} - pub fn is_not_static(&self) {} -} -"#, - expect_file!["./test_data/highlight_assoc_functions.html"], - false, - ) -} - -#[test] -fn test_injection() { - check_highlighting( - r##" -fn fixture(ra_fixture: &str) {} - -fn main() { - fixture(r#" -trait Foo { - fn foo() { - println!("2 + 2 = {}", 4); - } -}"# - ); - fixture(r" -fn foo() { - foo(\$0{ - 92 - }\$0) -}" - ); -} -"##, - expect_file!["./test_data/highlight_injection.html"], - false, - ); -} - -#[test] -fn test_operators() { - check_highlighting( - r##" -fn main() { - 1 + 1 - 1 * 1 / 1 % 1 | 1 & 1 ! 1 ^ 1 >> 1 << 1; - let mut a = 0; - a += 1; - a -= 1; - a *= 1; - a /= 1; - a %= 1; - a |= 1; - a &= 1; - a ^= 1; - a >>= 1; - a <<= 1; -} -"##, - expect_file!["./test_data/highlight_operators.html"], - false, - ); -} - -#[test] -fn test_rainbow_highlighting() { - check_highlighting( - r#" -fn main() { - let hello = "hello"; - let x = hello.to_string(); - let y = hello.to_string(); - - let x = "other color please!"; - let y = x.to_string(); -} - -fn bar() { - let mut hello = "hello"; -} -"#, - expect_file!["./test_data/highlight_rainbow.html"], - true, - ); -} - -#[test] -fn test_ranges() { - let (analysis, file_id) = fixture::file( - r#" -#[derive(Clone, Debug)] -struct Foo { - pub x: i32, - pub y: i32, -} -"#, - ); - - // The "x" - let highlights = &analysis - .highlight_range(FileRange { file_id, range: TextRange::at(45.into(), 1.into()) }) - .unwrap(); - - assert_eq!(&highlights[0].highlight.to_string(), "field.declaration.public"); -} - -#[test] -fn ranges_sorted() { - let (analysis, file_id) = fixture::file( - r#" -#[foo(bar = "bar")] -macro_rules! test {} -}"# - .trim(), - ); - let _ = analysis.highlight(file_id).unwrap(); -} - -/// Highlights the code given by the `ra_fixture` argument, renders the -/// result as HTML, and compares it with the HTML file given as `snapshot`. -/// Note that the `snapshot` file is overwritten by the rendered HTML. -fn check_highlighting(ra_fixture: &str, expect: ExpectFile, rainbow: bool) { - let (analysis, file_id) = fixture::file(ra_fixture.trim()); - let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap(); - expect.assert_eq(actual_html) -} - -#[test] -fn benchmark_syntax_highlighting_long_struct() { - if skip_slow_tests() { - return; - } - - let fixture = bench_fixture::big_struct(); - let (analysis, file_id) = fixture::file(&fixture); - - let hash = { - let _pt = bench("syntax highlighting long struct"); - analysis - .highlight(file_id) - .unwrap() - .iter() - .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct)) - .count() - }; - assert_eq!(hash, 2001); -} - -#[test] -fn syntax_highlighting_not_quadratic() { - if skip_slow_tests() { - return; - } - - let mut al = AssertLinear::default(); - while al.next_round() { - for i in 6..=10 { - let n = 1 << i; - - let fixture = bench_fixture::big_struct_n(n); - let (analysis, file_id) = fixture::file(&fixture); - - let time = Instant::now(); - - let hash = analysis - .highlight(file_id) - .unwrap() - .iter() - .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct)) - .count(); - assert!(hash > n as usize); - - let elapsed = time.elapsed(); - al.sample(n as f64, elapsed.as_millis() as f64); - } - } -} - -#[test] -fn benchmark_syntax_highlighting_parser() { - if skip_slow_tests() { - return; - } - - let fixture = bench_fixture::glorious_old_parser(); - let (analysis, file_id) = fixture::file(&fixture); - - let hash = { - let _pt = bench("syntax highlighting parser"); - analysis - .highlight(file_id) - .unwrap() - .iter() - .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function)) - .count() - }; - assert_eq!(hash, 1609); -} diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs deleted file mode 100644 index 9003e7cd34d09..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs +++ /dev/null @@ -1,339 +0,0 @@ -use ide_db::base_db::{FileId, SourceDatabase}; -use ide_db::RootDatabase; -use syntax::{ - AstNode, NodeOrToken, SourceFile, SyntaxKind::STRING, SyntaxToken, TextRange, TextSize, -}; - -// Feature: Show Syntax Tree -// -// Shows the parse tree of the current file. It exists mostly for debugging -// rust-analyzer itself. -// -// |=== -// | Editor | Action Name -// -// | VS Code | **Rust Analyzer: Show Syntax Tree** -// |=== -// image::https://user-images.githubusercontent.com/48062697/113065586-068bdb80-91b1-11eb-9507-fee67f9f45a0.gif[] -pub(crate) fn syntax_tree( - db: &RootDatabase, - file_id: FileId, - text_range: Option, -) -> String { - let parse = db.parse(file_id); - if let Some(text_range) = text_range { - let node = match parse.tree().syntax().covering_element(text_range) { - NodeOrToken::Node(node) => node, - NodeOrToken::Token(token) => { - if let Some(tree) = syntax_tree_for_string(&token, text_range) { - return tree; - } - token.parent().unwrap() - } - }; - - format!("{:#?}", node) - } else { - format!("{:#?}", parse.tree().syntax()) - } -} - -/// Attempts parsing the selected contents of a string literal -/// as rust syntax and returns its syntax tree -fn syntax_tree_for_string(token: &SyntaxToken, text_range: TextRange) -> Option { - // When the range is inside a string - // we'll attempt parsing it as rust syntax - // to provide the syntax tree of the contents of the string - match token.kind() { - STRING => syntax_tree_for_token(token, text_range), - _ => None, - } -} - -fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option { - // Range of the full node - let node_range = node.text_range(); - let text = node.text().to_string(); - - // We start at some point inside the node - // Either we have selected the whole string - // or our selection is inside it - let start = text_range.start() - node_range.start(); - - // how many characters we have selected - let len = text_range.len(); - - let node_len = node_range.len(); - - let start = start; - - // We want to cap our length - let len = len.min(node_len); - - // Ensure our slice is inside the actual string - let end = - if start + len < TextSize::of(&text) { start + len } else { TextSize::of(&text) - start }; - - let text = &text[TextRange::new(start, end)]; - - // Remove possible extra string quotes from the start - // and the end of the string - let text = text - .trim_start_matches('r') - .trim_start_matches('#') - .trim_start_matches('"') - .trim_end_matches('#') - .trim_end_matches('"') - .trim() - // Remove custom markers - .replace("$0", ""); - - let parsed = SourceFile::parse(&text); - - // If the "file" parsed without errors, - // return its syntax - if parsed.errors().is_empty() { - return Some(format!("{:#?}", parsed.tree().syntax())); - } - - None -} - -#[cfg(test)] -mod tests { - use expect_test::expect; - - use crate::fixture; - - fn check(ra_fixture: &str, expect: expect_test::Expect) { - let (analysis, file_id) = fixture::file(ra_fixture); - let syn = analysis.syntax_tree(file_id, None).unwrap(); - expect.assert_eq(&syn) - } - fn check_range(ra_fixture: &str, expect: expect_test::Expect) { - let (analysis, frange) = fixture::range(ra_fixture); - let syn = analysis.syntax_tree(frange.file_id, Some(frange.range)).unwrap(); - expect.assert_eq(&syn) - } - - #[test] - fn test_syntax_tree_without_range() { - // Basic syntax - check( - r#"fn foo() {}"#, - expect![[r#" - SOURCE_FILE@0..11 - FN@0..11 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..6 - IDENT@3..6 "foo" - PARAM_LIST@6..8 - L_PAREN@6..7 "(" - R_PAREN@7..8 ")" - WHITESPACE@8..9 " " - BLOCK_EXPR@9..11 - STMT_LIST@9..11 - L_CURLY@9..10 "{" - R_CURLY@10..11 "}" - "#]], - ); - - check( - r#" -fn test() { - assert!(" - fn foo() { - } - ", ""); -}"#, - expect![[r#" - SOURCE_FILE@0..60 - FN@0..60 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..7 - IDENT@3..7 "test" - PARAM_LIST@7..9 - L_PAREN@7..8 "(" - R_PAREN@8..9 ")" - WHITESPACE@9..10 " " - BLOCK_EXPR@10..60 - STMT_LIST@10..60 - L_CURLY@10..11 "{" - WHITESPACE@11..16 "\n " - EXPR_STMT@16..58 - MACRO_EXPR@16..57 - MACRO_CALL@16..57 - PATH@16..22 - PATH_SEGMENT@16..22 - NAME_REF@16..22 - IDENT@16..22 "assert" - BANG@22..23 "!" - TOKEN_TREE@23..57 - L_PAREN@23..24 "(" - STRING@24..52 "\"\n fn foo() {\n ..." - COMMA@52..53 "," - WHITESPACE@53..54 " " - STRING@54..56 "\"\"" - R_PAREN@56..57 ")" - SEMICOLON@57..58 ";" - WHITESPACE@58..59 "\n" - R_CURLY@59..60 "}" - "#]], - ) - } - - #[test] - fn test_syntax_tree_with_range() { - check_range( - r#"$0fn foo() {}$0"#, - expect![[r#" - FN@0..11 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..6 - IDENT@3..6 "foo" - PARAM_LIST@6..8 - L_PAREN@6..7 "(" - R_PAREN@7..8 ")" - WHITESPACE@8..9 " " - BLOCK_EXPR@9..11 - STMT_LIST@9..11 - L_CURLY@9..10 "{" - R_CURLY@10..11 "}" - "#]], - ); - - check_range( - r#" -fn test() { - $0assert!(" - fn foo() { - } - ", "");$0 -}"#, - expect![[r#" - EXPR_STMT@16..58 - MACRO_EXPR@16..57 - MACRO_CALL@16..57 - PATH@16..22 - PATH_SEGMENT@16..22 - NAME_REF@16..22 - IDENT@16..22 "assert" - BANG@22..23 "!" - TOKEN_TREE@23..57 - L_PAREN@23..24 "(" - STRING@24..52 "\"\n fn foo() {\n ..." - COMMA@52..53 "," - WHITESPACE@53..54 " " - STRING@54..56 "\"\"" - R_PAREN@56..57 ")" - SEMICOLON@57..58 ";" - "#]], - ); - } - - #[test] - fn test_syntax_tree_inside_string() { - check_range( - r#"fn test() { - assert!(" -$0fn foo() { -}$0 -fn bar() { -} - ", ""); -}"#, - expect![[r#" - SOURCE_FILE@0..12 - FN@0..12 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..6 - IDENT@3..6 "foo" - PARAM_LIST@6..8 - L_PAREN@6..7 "(" - R_PAREN@7..8 ")" - WHITESPACE@8..9 " " - BLOCK_EXPR@9..12 - STMT_LIST@9..12 - L_CURLY@9..10 "{" - WHITESPACE@10..11 "\n" - R_CURLY@11..12 "}" - "#]], - ); - - // With a raw string - check_range( - r###"fn test() { - assert!(r#" -$0fn foo() { -}$0 -fn bar() { -} - "#, ""); -}"###, - expect![[r#" - SOURCE_FILE@0..12 - FN@0..12 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..6 - IDENT@3..6 "foo" - PARAM_LIST@6..8 - L_PAREN@6..7 "(" - R_PAREN@7..8 ")" - WHITESPACE@8..9 " " - BLOCK_EXPR@9..12 - STMT_LIST@9..12 - L_CURLY@9..10 "{" - WHITESPACE@10..11 "\n" - R_CURLY@11..12 "}" - "#]], - ); - - // With a raw string - check_range( - r###"fn test() { - assert!(r$0#" -fn foo() { -} -fn bar() { -}"$0#, ""); -}"###, - expect![[r#" - SOURCE_FILE@0..25 - FN@0..12 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..6 - IDENT@3..6 "foo" - PARAM_LIST@6..8 - L_PAREN@6..7 "(" - R_PAREN@7..8 ")" - WHITESPACE@8..9 " " - BLOCK_EXPR@9..12 - STMT_LIST@9..12 - L_CURLY@9..10 "{" - WHITESPACE@10..11 "\n" - R_CURLY@11..12 "}" - WHITESPACE@12..13 "\n" - FN@13..25 - FN_KW@13..15 "fn" - WHITESPACE@15..16 " " - NAME@16..19 - IDENT@16..19 "bar" - PARAM_LIST@19..21 - L_PAREN@19..20 "(" - R_PAREN@20..21 ")" - WHITESPACE@21..22 " " - BLOCK_EXPR@22..25 - STMT_LIST@22..25 - L_CURLY@22..23 "{" - WHITESPACE@23..24 "\n" - R_CURLY@24..25 "}" - "#]], - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs deleted file mode 100644 index 9118f3c699c0c..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/typing.rs +++ /dev/null @@ -1,1210 +0,0 @@ -//! This module handles auto-magic editing actions applied together with users -//! edits. For example, if the user typed -//! -//! ```text -//! foo -//! .bar() -//! .baz() -//! | // <- cursor is here -//! ``` -//! -//! and types `.` next, we want to indent the dot. -//! -//! Language server executes such typing assists synchronously. That is, they -//! block user's typing and should be pretty fast for this reason! - -mod on_enter; - -use ide_db::{ - base_db::{FilePosition, SourceDatabase}, - RootDatabase, -}; -use syntax::{ - algo::{ancestors_at_offset, find_node_at_offset}, - ast::{self, edit::IndentLevel, AstToken}, - AstNode, Parse, SourceFile, SyntaxKind, TextRange, TextSize, T, -}; - -use text_edit::{Indel, TextEdit}; - -use crate::SourceChange; - -pub(crate) use on_enter::on_enter; - -// Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`. -pub(crate) const TRIGGER_CHARS: &str = ".=<>{"; - -struct ExtendedTextEdit { - edit: TextEdit, - is_snippet: bool, -} - -// Feature: On Typing Assists -// -// Some features trigger on typing certain characters: -// -// - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression -// - typing `=` between two expressions adds `;` when in statement position -// - typing `=` to turn an assignment into an equality comparison removes `;` when in expression position -// - typing `.` in a chain method call auto-indents -// - typing `{` in front of an expression inserts a closing `}` after the expression -// - typing `{` in a use item adds a closing `}` in the right place -// -// VS Code:: -// -// Add the following to `settings.json`: -// [source,json] -// ---- -// "editor.formatOnType": true, -// ---- -// -// image::https://user-images.githubusercontent.com/48062697/113166163-69758500-923a-11eb-81ee-eb33ec380399.gif[] -// image::https://user-images.githubusercontent.com/48062697/113171066-105c2000-923f-11eb-87ab-f4a263346567.gif[] -pub(crate) fn on_char_typed( - db: &RootDatabase, - position: FilePosition, - char_typed: char, -) -> Option { - if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) { - return None; - } - let file = &db.parse(position.file_id); - if !stdx::always!(file.tree().syntax().text().char_at(position.offset) == Some(char_typed)) { - return None; - } - let edit = on_char_typed_inner(file, position.offset, char_typed)?; - let mut sc = SourceChange::from_text_edit(position.file_id, edit.edit); - sc.is_snippet = edit.is_snippet; - Some(sc) -} - -fn on_char_typed_inner( - file: &Parse, - offset: TextSize, - char_typed: char, -) -> Option { - if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) { - return None; - } - return match char_typed { - '.' => conv(on_dot_typed(&file.tree(), offset)), - '=' => conv(on_eq_typed(&file.tree(), offset)), - '<' => on_left_angle_typed(&file.tree(), offset), - '>' => conv(on_right_angle_typed(&file.tree(), offset)), - '{' => conv(on_opening_brace_typed(file, offset)), - _ => return None, - }; - - fn conv(text_edit: Option) -> Option { - Some(ExtendedTextEdit { edit: text_edit?, is_snippet: false }) - } -} - -/// Inserts a closing `}` when the user types an opening `{`, wrapping an existing expression in a -/// block, or a part of a `use` item. -fn on_opening_brace_typed(file: &Parse, offset: TextSize) -> Option { - if !stdx::always!(file.tree().syntax().text().char_at(offset) == Some('{')) { - return None; - } - - let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?; - if brace_token.kind() != SyntaxKind::L_CURLY { - return None; - } - - // Remove the `{` to get a better parse tree, and reparse. - let range = brace_token.text_range(); - if !stdx::always!(range.len() == TextSize::of('{')) { - return None; - } - let file = file.reparse(&Indel::delete(range)); - - if let Some(edit) = brace_expr(&file.tree(), offset) { - return Some(edit); - } - - if let Some(edit) = brace_use_path(&file.tree(), offset) { - return Some(edit); - } - - return None; - - fn brace_use_path(file: &SourceFile, offset: TextSize) -> Option { - let segment: ast::PathSegment = find_node_at_offset(file.syntax(), offset)?; - if segment.syntax().text_range().start() != offset { - return None; - } - - let tree: ast::UseTree = find_node_at_offset(file.syntax(), offset)?; - - Some(TextEdit::insert( - tree.syntax().text_range().end() + TextSize::of("{"), - "}".to_string(), - )) - } - - fn brace_expr(file: &SourceFile, offset: TextSize) -> Option { - let mut expr: ast::Expr = find_node_at_offset(file.syntax(), offset)?; - if expr.syntax().text_range().start() != offset { - return None; - } - - // Enclose the outermost expression starting at `offset` - while let Some(parent) = expr.syntax().parent() { - if parent.text_range().start() != expr.syntax().text_range().start() { - break; - } - - match ast::Expr::cast(parent) { - Some(parent) => expr = parent, - None => break, - } - } - - // If it's a statement in a block, we don't know how many statements should be included - if ast::ExprStmt::can_cast(expr.syntax().parent()?.kind()) { - return None; - } - - // Insert `}` right after the expression. - Some(TextEdit::insert( - expr.syntax().text_range().end() + TextSize::of("{"), - "}".to_string(), - )) - } -} - -/// Returns an edit which should be applied after `=` was typed. Primarily, -/// this works when adding `let =`. -// FIXME: use a snippet completion instead of this hack here. -fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option { - if !stdx::always!(file.syntax().text().char_at(offset) == Some('=')) { - return None; - } - - if let Some(edit) = let_stmt(file, offset) { - return Some(edit); - } - if let Some(edit) = assign_expr(file, offset) { - return Some(edit); - } - if let Some(edit) = assign_to_eq(file, offset) { - return Some(edit); - } - - return None; - - fn assign_expr(file: &SourceFile, offset: TextSize) -> Option { - let binop: ast::BinExpr = find_node_at_offset(file.syntax(), offset)?; - if !matches!(binop.op_kind(), Some(ast::BinaryOp::Assignment { op: None })) { - return None; - } - - // Parent must be `ExprStmt` or `StmtList` for `;` to be valid. - if let Some(expr_stmt) = ast::ExprStmt::cast(binop.syntax().parent()?) { - if expr_stmt.semicolon_token().is_some() { - return None; - } - } else { - if !ast::StmtList::can_cast(binop.syntax().parent()?.kind()) { - return None; - } - } - - let expr = binop.rhs()?; - let expr_range = expr.syntax().text_range(); - if expr_range.contains(offset) && offset != expr_range.start() { - return None; - } - if file.syntax().text().slice(offset..expr_range.start()).contains_char('\n') { - return None; - } - let offset = expr.syntax().text_range().end(); - Some(TextEdit::insert(offset, ";".to_string())) - } - - /// `a =$0 b;` removes the semicolon if an expression is valid in this context. - fn assign_to_eq(file: &SourceFile, offset: TextSize) -> Option { - let binop: ast::BinExpr = find_node_at_offset(file.syntax(), offset)?; - if !matches!(binop.op_kind(), Some(ast::BinaryOp::CmpOp(ast::CmpOp::Eq { negated: false }))) - { - return None; - } - - let expr_stmt = ast::ExprStmt::cast(binop.syntax().parent()?)?; - let semi = expr_stmt.semicolon_token()?; - - if expr_stmt.syntax().next_sibling().is_some() { - // Not the last statement in the list. - return None; - } - - Some(TextEdit::delete(semi.text_range())) - } - - fn let_stmt(file: &SourceFile, offset: TextSize) -> Option { - let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?; - if let_stmt.semicolon_token().is_some() { - return None; - } - let expr = let_stmt.initializer()?; - let expr_range = expr.syntax().text_range(); - if expr_range.contains(offset) && offset != expr_range.start() { - return None; - } - if file.syntax().text().slice(offset..expr_range.start()).contains_char('\n') { - return None; - } - let offset = let_stmt.syntax().text_range().end(); - Some(TextEdit::insert(offset, ";".to_string())) - } -} - -/// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. -fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option { - if !stdx::always!(file.syntax().text().char_at(offset) == Some('.')) { - return None; - } - let whitespace = - file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?; - - // if prior is fn call over multiple lines dont indent - // or if previous is method call over multiples lines keep that indent - let current_indent = { - let text = whitespace.text(); - let (_prefix, suffix) = text.rsplit_once('\n')?; - suffix - }; - let current_indent_len = TextSize::of(current_indent); - - let parent = whitespace.syntax().parent()?; - // Make sure dot is a part of call chain - let receiver = if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { - field_expr.expr()? - } else if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent.clone()) { - method_call_expr.receiver()? - } else { - return None; - }; - - let receiver_is_multiline = receiver.syntax().text().find_char('\n').is_some(); - let target_indent = match (receiver, receiver_is_multiline) { - // if receiver is multiline field or method call, just take the previous `.` indentation - (ast::Expr::MethodCallExpr(expr), true) => { - expr.dot_token().as_ref().map(IndentLevel::from_token) - } - (ast::Expr::FieldExpr(expr), true) => { - expr.dot_token().as_ref().map(IndentLevel::from_token) - } - // if receiver is multiline expression, just keeps its indentation - (_, true) => Some(IndentLevel::from_node(&parent)), - _ => None, - }; - let target_indent = match target_indent { - Some(x) => x, - // in all other cases, take previous indentation and indent once - None => IndentLevel::from_node(&parent) + 1, - } - .to_string(); - - if current_indent_len == TextSize::of(&target_indent) { - return None; - } - - Some(TextEdit::replace(TextRange::new(offset - current_indent_len, offset), target_indent)) -} - -/// Add closing `>` for generic arguments/parameters. -fn on_left_angle_typed(file: &SourceFile, offset: TextSize) -> Option { - let file_text = file.syntax().text(); - if !stdx::always!(file_text.char_at(offset) == Some('<')) { - return None; - } - - // Find the next non-whitespace char in the line. - let mut next_offset = offset + TextSize::of('<'); - while file_text.char_at(next_offset) == Some(' ') { - next_offset += TextSize::of(' ') - } - if file_text.char_at(next_offset) == Some('>') { - return None; - } - - let range = TextRange::at(offset, TextSize::of('<')); - if let Some(t) = file.syntax().token_at_offset(offset).left_biased() { - if T![impl] == t.kind() { - return Some(ExtendedTextEdit { - edit: TextEdit::replace(range, "<$0>".to_string()), - is_snippet: true, - }); - } - } - - if ancestors_at_offset(file.syntax(), offset) - .find(|n| { - ast::GenericParamList::can_cast(n.kind()) || ast::GenericArgList::can_cast(n.kind()) - }) - .is_some() - { - return Some(ExtendedTextEdit { - edit: TextEdit::replace(range, "<$0>".to_string()), - is_snippet: true, - }); - } - - None -} - -/// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }` -fn on_right_angle_typed(file: &SourceFile, offset: TextSize) -> Option { - let file_text = file.syntax().text(); - if !stdx::always!(file_text.char_at(offset) == Some('>')) { - return None; - } - let after_arrow = offset + TextSize::of('>'); - if file_text.char_at(after_arrow) != Some('{') { - return None; - } - if find_node_at_offset::(file.syntax(), offset).is_none() { - return None; - } - - Some(TextEdit::insert(after_arrow, " ".to_string())) -} - -#[cfg(test)] -mod tests { - use test_utils::{assert_eq_text, extract_offset}; - - use super::*; - - impl ExtendedTextEdit { - fn apply(&self, text: &mut String) { - self.edit.apply(text); - } - } - - fn do_type_char(char_typed: char, before: &str) -> Option { - let (offset, mut before) = extract_offset(before); - let edit = TextEdit::insert(offset, char_typed.to_string()); - edit.apply(&mut before); - let parse = SourceFile::parse(&before); - on_char_typed_inner(&parse, offset, char_typed).map(|it| { - it.apply(&mut before); - before.to_string() - }) - } - - fn type_char(char_typed: char, ra_fixture_before: &str, ra_fixture_after: &str) { - let actual = do_type_char(char_typed, ra_fixture_before) - .unwrap_or_else(|| panic!("typing `{}` did nothing", char_typed)); - - assert_eq_text!(ra_fixture_after, &actual); - } - - fn type_char_noop(char_typed: char, ra_fixture_before: &str) { - let file_change = do_type_char(char_typed, ra_fixture_before); - assert!(file_change.is_none()) - } - - #[test] - fn test_semi_after_let() { - // do_check(r" - // fn foo() { - // let foo =$0 - // } - // ", r" - // fn foo() { - // let foo =; - // } - // "); - type_char( - '=', - r#" -fn foo() { - let foo $0 1 + 1 -} -"#, - r#" -fn foo() { - let foo = 1 + 1; -} -"#, - ); - // do_check(r" - // fn foo() { - // let foo =$0 - // let bar = 1; - // } - // ", r" - // fn foo() { - // let foo =; - // let bar = 1; - // } - // "); - } - - #[test] - fn test_semi_after_assign() { - type_char( - '=', - r#" -fn f() { - i $0 0 -} -"#, - r#" -fn f() { - i = 0; -} -"#, - ); - type_char( - '=', - r#" -fn f() { - i $0 0 - i -} -"#, - r#" -fn f() { - i = 0; - i -} -"#, - ); - type_char_noop( - '=', - r#" -fn f(x: u8) { - if x $0 -} -"#, - ); - type_char_noop( - '=', - r#" -fn f(x: u8) { - if x $0 {} -} -"#, - ); - type_char_noop( - '=', - r#" -fn f(x: u8) { - if x $0 0 {} -} -"#, - ); - type_char_noop( - '=', - r#" -fn f() { - g(i $0 0); -} -"#, - ); - } - - #[test] - fn assign_to_eq() { - type_char( - '=', - r#" -fn f(a: u8) { - a =$0 0; -} -"#, - r#" -fn f(a: u8) { - a == 0 -} -"#, - ); - type_char( - '=', - r#" -fn f(a: u8) { - a $0= 0; -} -"#, - r#" -fn f(a: u8) { - a == 0 -} -"#, - ); - type_char_noop( - '=', - r#" -fn f(a: u8) { - let e = a =$0 0; -} -"#, - ); - type_char_noop( - '=', - r#" -fn f(a: u8) { - let e = a =$0 0; - e -} -"#, - ); - } - - #[test] - fn indents_new_chain_call() { - type_char( - '.', - r#" -fn main() { - xs.foo() - $0 -} - "#, - r#" -fn main() { - xs.foo() - . -} - "#, - ); - type_char_noop( - '.', - r#" -fn main() { - xs.foo() - $0 -} - "#, - ) - } - - #[test] - fn indents_new_chain_call_with_semi() { - type_char( - '.', - r" -fn main() { - xs.foo() - $0; -} - ", - r#" -fn main() { - xs.foo() - .; -} - "#, - ); - type_char_noop( - '.', - r#" -fn main() { - xs.foo() - $0; -} - "#, - ) - } - - #[test] - fn indents_new_chain_call_with_let() { - type_char( - '.', - r#" -fn main() { - let _ = foo - $0 - bar() -} -"#, - r#" -fn main() { - let _ = foo - . - bar() -} -"#, - ); - } - - #[test] - fn indents_continued_chain_call() { - type_char( - '.', - r#" -fn main() { - xs.foo() - .first() - $0 -} - "#, - r#" -fn main() { - xs.foo() - .first() - . -} - "#, - ); - type_char_noop( - '.', - r#" -fn main() { - xs.foo() - .first() - $0 -} - "#, - ); - } - - #[test] - fn indents_middle_of_chain_call() { - type_char( - '.', - r#" -fn source_impl() { - let var = enum_defvariant_list().unwrap() - $0 - .nth(92) - .unwrap(); -} - "#, - r#" -fn source_impl() { - let var = enum_defvariant_list().unwrap() - . - .nth(92) - .unwrap(); -} - "#, - ); - type_char_noop( - '.', - r#" -fn source_impl() { - let var = enum_defvariant_list().unwrap() - $0 - .nth(92) - .unwrap(); -} - "#, - ); - } - - #[test] - fn dont_indent_freestanding_dot() { - type_char_noop( - '.', - r#" -fn main() { - $0 -} - "#, - ); - type_char_noop( - '.', - r#" -fn main() { -$0 -} - "#, - ); - } - - #[test] - fn adds_space_after_return_type() { - type_char( - '>', - r#" -fn foo() -$0{ 92 } -"#, - r#" -fn foo() -> { 92 } -"#, - ); - } - - #[test] - fn adds_closing_brace_for_expr() { - type_char( - '{', - r#" -fn f() { match () { _ => $0() } } - "#, - r#" -fn f() { match () { _ => {()} } } - "#, - ); - type_char( - '{', - r#" -fn f() { $0() } - "#, - r#" -fn f() { {()} } - "#, - ); - type_char( - '{', - r#" -fn f() { let x = $0(); } - "#, - r#" -fn f() { let x = {()}; } - "#, - ); - type_char( - '{', - r#" -fn f() { let x = $0a.b(); } - "#, - r#" -fn f() { let x = {a.b()}; } - "#, - ); - type_char( - '{', - r#" -const S: () = $0(); -fn f() {} - "#, - r#" -const S: () = {()}; -fn f() {} - "#, - ); - type_char( - '{', - r#" -const S: () = $0a.b(); -fn f() {} - "#, - r#" -const S: () = {a.b()}; -fn f() {} - "#, - ); - type_char( - '{', - r#" -fn f() { - match x { - 0 => $0(), - 1 => (), - } -} - "#, - r#" -fn f() { - match x { - 0 => {()}, - 1 => (), - } -} - "#, - ); - } - - #[test] - fn noop_in_string_literal() { - // Regression test for #9351 - type_char_noop( - '{', - r##" -fn check_with(ra_fixture: &str, expect: Expect) { - let base = r#" -enum E { T(), R$0, C } -use self::E::X; -const Z: E = E::C; -mod m {} -asdasdasdasdasdasda -sdasdasdasdasdasda -sdasdasdasdasd -"#; - let actual = completion_list(&format!("{}\n{}", base, ra_fixture)); - expect.assert_eq(&actual) -} - "##, - ); - } - - #[test] - fn noop_in_item_position_with_macro() { - type_char_noop('{', r#"$0println!();"#); - type_char_noop( - '{', - r#" -fn main() $0println!("hello"); -}"#, - ); - } - - #[test] - fn adds_closing_brace_for_use_tree() { - type_char( - '{', - r#" -use some::$0Path; - "#, - r#" -use some::{Path}; - "#, - ); - type_char( - '{', - r#" -use some::{Path, $0Other}; - "#, - r#" -use some::{Path, {Other}}; - "#, - ); - type_char( - '{', - r#" -use some::{$0Path, Other}; - "#, - r#" -use some::{{Path}, Other}; - "#, - ); - type_char( - '{', - r#" -use some::path::$0to::Item; - "#, - r#" -use some::path::{to::Item}; - "#, - ); - type_char( - '{', - r#" -use some::$0path::to::Item; - "#, - r#" -use some::{path::to::Item}; - "#, - ); - type_char( - '{', - r#" -use $0some::path::to::Item; - "#, - r#" -use {some::path::to::Item}; - "#, - ); - type_char( - '{', - r#" -use some::path::$0to::{Item}; - "#, - r#" -use some::path::{to::{Item}}; - "#, - ); - type_char( - '{', - r#" -use $0Thing as _; - "#, - r#" -use {Thing as _}; - "#, - ); - - type_char_noop( - '{', - r#" -use some::pa$0th::to::Item; - "#, - ); - } - - #[test] - fn adds_closing_angle_bracket_for_generic_args() { - type_char( - '<', - r#" -fn foo() { - bar::$0 -} - "#, - r#" -fn foo() { - bar::<$0> -} - "#, - ); - - type_char( - '<', - r#" -fn foo(bar: &[u64]) { - bar.iter().collect::$0(); -} - "#, - r#" -fn foo(bar: &[u64]) { - bar.iter().collect::<$0>(); -} - "#, - ); - } - - #[test] - fn adds_closing_angle_bracket_for_generic_params() { - type_char( - '<', - r#" -fn foo$0() {} - "#, - r#" -fn foo<$0>() {} - "#, - ); - type_char( - '<', - r#" -fn foo$0 - "#, - r#" -fn foo<$0> - "#, - ); - type_char( - '<', - r#" -struct Foo$0 {} - "#, - r#" -struct Foo<$0> {} - "#, - ); - type_char( - '<', - r#" -struct Foo$0(); - "#, - r#" -struct Foo<$0>(); - "#, - ); - type_char( - '<', - r#" -struct Foo$0 - "#, - r#" -struct Foo<$0> - "#, - ); - type_char( - '<', - r#" -enum Foo$0 - "#, - r#" -enum Foo<$0> - "#, - ); - type_char( - '<', - r#" -trait Foo$0 - "#, - r#" -trait Foo<$0> - "#, - ); - type_char( - '<', - r#" -type Foo$0 = Bar; - "#, - r#" -type Foo<$0> = Bar; - "#, - ); - type_char( - '<', - r#" -impl$0 Foo {} - "#, - r#" -impl<$0> Foo {} - "#, - ); - type_char( - '<', - r#" -impl Foo$0 {} - "#, - r#" -impl Foo<$0> {} - "#, - ); - type_char( - '<', - r#" -impl Foo$0 {} - "#, - r#" -impl Foo<$0> {} - "#, - ); - } - - #[test] - fn dont_add_closing_angle_bracket_for_comparison() { - type_char_noop( - '<', - r#" -fn main() { - 42$0 -} - "#, - ); - type_char_noop( - '<', - r#" -fn main() { - 42 $0 -} - "#, - ); - type_char_noop( - '<', - r#" -fn main() { - let foo = 42; - foo $0 -} - "#, - ); - } - - #[test] - fn dont_add_closing_angle_bracket_if_it_is_already_there() { - type_char_noop( - '<', - r#" -fn foo() { - bar::$0> -} - "#, - ); - type_char_noop( - '<', - r#" -fn foo(bar: &[u64]) { - bar.iter().collect::$0 >(); -} - "#, - ); - type_char_noop( - '<', - r#" -fn foo$0>() {} - "#, - ); - type_char_noop( - '<', - r#" -fn foo$0> - "#, - ); - type_char_noop( - '<', - r#" -struct Foo$0> {} - "#, - ); - type_char_noop( - '<', - r#" -struct Foo$0>(); - "#, - ); - type_char_noop( - '<', - r#" -struct Foo$0> - "#, - ); - type_char_noop( - '<', - r#" -enum Foo$0> - "#, - ); - type_char_noop( - '<', - r#" -trait Foo$0> - "#, - ); - type_char_noop( - '<', - r#" -type Foo$0> = Bar; - "#, - ); - type_char_noop( - '<', - r#" -impl$0> Foo {} - "#, - ); - type_char_noop( - '<', - r#" -impl Foo$0> {} - "#, - ); - type_char_noop( - '<', - r#" -impl Foo$0> {} - "#, - ); - } - - #[test] - fn regression_629() { - type_char_noop( - '.', - r#" -fn foo() { - CompletionItem::new( - CompletionKind::Reference, - ctx.source_range(), - field.name().to_string(), - ) - .foo() - $0 -} -"#, - ); - type_char_noop( - '.', - r#" -fn foo() { - CompletionItem::new( - CompletionKind::Reference, - ctx.source_range(), - field.name().to_string(), - ) - $0 -} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs deleted file mode 100644 index 48c1713270b6c..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs +++ /dev/null @@ -1,616 +0,0 @@ -//! Handles the `Enter` key press. At the momently, this only continues -//! comments, but should handle indent some time in the future as well. - -use ide_db::base_db::{FilePosition, SourceDatabase}; -use ide_db::RootDatabase; -use syntax::{ - algo::find_node_at_offset, - ast::{self, edit::IndentLevel, AstToken}, - AstNode, SmolStr, SourceFile, - SyntaxKind::*, - SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, -}; - -use text_edit::TextEdit; - -// Feature: On Enter -// -// rust-analyzer can override kbd:[Enter] key to make it smarter: -// -// - kbd:[Enter] inside triple-slash comments automatically inserts `///` -// - kbd:[Enter] in the middle or after a trailing space in `//` inserts `//` -// - kbd:[Enter] inside `//!` doc comments automatically inserts `//!` -// - kbd:[Enter] after `{` indents contents and closing `}` of single-line block -// -// This action needs to be assigned to shortcut explicitly. -// -// Note that, depending on the other installed extensions, this feature can visibly slow down typing. -// Similarly, if rust-analyzer crashes or stops responding, `Enter` might not work. -// In that case, you can still press `Shift-Enter` to insert a newline. -// -// VS Code:: -// -// Add the following to `keybindings.json`: -// [source,json] -// ---- -// { -// "key": "Enter", -// "command": "rust-analyzer.onEnter", -// "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust" -// } -// ---- -// -// When using the Vim plugin: -// [source,json] -// ---- -// { -// "key": "Enter", -// "command": "rust-analyzer.onEnter", -// "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust && vim.mode == 'Insert'" -// } -// ---- -// -// image::https://user-images.githubusercontent.com/48062697/113065578-04c21800-91b1-11eb-82b8-22b8c481e645.gif[] -pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option { - let parse = db.parse(position.file_id); - let file = parse.tree(); - let token = file.syntax().token_at_offset(position.offset).left_biased()?; - - if let Some(comment) = ast::Comment::cast(token.clone()) { - return on_enter_in_comment(&comment, &file, position.offset); - } - - if token.kind() == L_CURLY { - // Typing enter after the `{` of a block expression, where the `}` is on the same line - if let Some(edit) = find_node_at_offset(file.syntax(), position.offset - TextSize::of('{')) - .and_then(|block| on_enter_in_block(block, position)) - { - cov_mark::hit!(indent_block_contents); - return Some(edit); - } - - // Typing enter after the `{` of a use tree list. - if let Some(edit) = find_node_at_offset(file.syntax(), position.offset - TextSize::of('{')) - .and_then(|list| on_enter_in_use_tree_list(list, position)) - { - cov_mark::hit!(indent_block_contents); - return Some(edit); - } - } - - None -} - -fn on_enter_in_comment( - comment: &ast::Comment, - file: &ast::SourceFile, - offset: TextSize, -) -> Option { - if comment.kind().shape.is_block() { - return None; - } - - let prefix = comment.prefix(); - let comment_range = comment.syntax().text_range(); - if offset < comment_range.start() + TextSize::of(prefix) { - return None; - } - - let mut remove_trailing_whitespace = false; - // Continuing single-line non-doc comments (like this one :) ) is annoying - if prefix == "//" && comment_range.end() == offset { - if comment.text().ends_with(' ') { - cov_mark::hit!(continues_end_of_line_comment_with_space); - remove_trailing_whitespace = true; - } else if !followed_by_comment(comment) { - return None; - } - } - - let indent = node_indent(file, comment.syntax())?; - let inserted = format!("\n{}{} $0", indent, prefix); - let delete = if remove_trailing_whitespace { - let trimmed_len = comment.text().trim_end().len() as u32; - let trailing_whitespace_len = comment.text().len() as u32 - trimmed_len; - TextRange::new(offset - TextSize::from(trailing_whitespace_len), offset) - } else { - TextRange::empty(offset) - }; - let edit = TextEdit::replace(delete, inserted); - Some(edit) -} - -fn on_enter_in_block(block: ast::BlockExpr, position: FilePosition) -> Option { - let contents = block_contents(&block)?; - - if block.syntax().text().contains_char('\n') { - return None; - } - - let indent = IndentLevel::from_node(block.syntax()); - let mut edit = TextEdit::insert(position.offset, format!("\n{}$0", indent + 1)); - edit.union(TextEdit::insert(contents.text_range().end(), format!("\n{}", indent))).ok()?; - Some(edit) -} - -fn on_enter_in_use_tree_list(list: ast::UseTreeList, position: FilePosition) -> Option { - if list.syntax().text().contains_char('\n') { - return None; - } - - let indent = IndentLevel::from_node(list.syntax()); - let mut edit = TextEdit::insert(position.offset, format!("\n{}$0", indent + 1)); - edit.union(TextEdit::insert( - list.r_curly_token()?.text_range().start(), - format!("\n{}", indent), - )) - .ok()?; - Some(edit) -} - -fn block_contents(block: &ast::BlockExpr) -> Option { - let mut node = block.tail_expr().map(|e| e.syntax().clone()); - - for stmt in block.statements() { - if node.is_some() { - // More than 1 node in the block - return None; - } - - node = Some(stmt.syntax().clone()); - } - - node -} - -fn followed_by_comment(comment: &ast::Comment) -> bool { - let ws = match comment.syntax().next_token().and_then(ast::Whitespace::cast) { - Some(it) => it, - None => return false, - }; - if ws.spans_multiple_lines() { - return false; - } - ws.syntax().next_token().and_then(ast::Comment::cast).is_some() -} - -fn node_indent(file: &SourceFile, token: &SyntaxToken) -> Option { - let ws = match file.syntax().token_at_offset(token.text_range().start()) { - TokenAtOffset::Between(l, r) => { - assert!(r == *token); - l - } - TokenAtOffset::Single(n) => { - assert!(n == *token); - return Some("".into()); - } - TokenAtOffset::None => unreachable!(), - }; - if ws.kind() != WHITESPACE { - return None; - } - let text = ws.text(); - let pos = text.rfind('\n').map(|it| it + 1).unwrap_or(0); - Some(text[pos..].into()) -} - -#[cfg(test)] -mod tests { - use stdx::trim_indent; - use test_utils::assert_eq_text; - - use crate::fixture; - - fn apply_on_enter(before: &str) -> Option { - let (analysis, position) = fixture::position(before); - let result = analysis.on_enter(position).unwrap()?; - - let mut actual = analysis.file_text(position.file_id).unwrap().to_string(); - result.apply(&mut actual); - Some(actual) - } - - fn do_check(ra_fixture_before: &str, ra_fixture_after: &str) { - let ra_fixture_after = &trim_indent(ra_fixture_after); - let actual = apply_on_enter(ra_fixture_before).unwrap(); - assert_eq_text!(ra_fixture_after, &actual); - } - - fn do_check_noop(ra_fixture_text: &str) { - assert!(apply_on_enter(ra_fixture_text).is_none()) - } - - #[test] - fn continues_doc_comment() { - do_check( - r" -/// Some docs$0 -fn foo() { -} -", - r" -/// Some docs -/// $0 -fn foo() { -} -", - ); - - do_check( - r" -impl S { - /// Some$0 docs. - fn foo() {} -} -", - r" -impl S { - /// Some - /// $0 docs. - fn foo() {} -} -", - ); - - do_check( - r" -///$0 Some docs -fn foo() { -} -", - r" -/// -/// $0 Some docs -fn foo() { -} -", - ); - } - - #[test] - fn does_not_continue_before_doc_comment() { - do_check_noop(r"$0//! docz"); - } - - #[test] - fn continues_another_doc_comment() { - do_check( - r#" -fn main() { - //! Documentation for$0 on enter - let x = 1 + 1; -} -"#, - r#" -fn main() { - //! Documentation for - //! $0 on enter - let x = 1 + 1; -} -"#, - ); - } - - #[test] - fn continues_code_comment_in_the_middle_of_line() { - do_check( - r" -fn main() { - // Fix$0 me - let x = 1 + 1; -} -", - r" -fn main() { - // Fix - // $0 me - let x = 1 + 1; -} -", - ); - } - - #[test] - fn continues_code_comment_in_the_middle_several_lines() { - do_check( - r" -fn main() { - // Fix$0 - // me - let x = 1 + 1; -} -", - r" -fn main() { - // Fix - // $0 - // me - let x = 1 + 1; -} -", - ); - } - - #[test] - fn does_not_continue_end_of_line_comment() { - do_check_noop( - r" -fn main() { - // Fix me$0 - let x = 1 + 1; -} -", - ); - } - - #[test] - fn continues_end_of_line_comment_with_space() { - cov_mark::check!(continues_end_of_line_comment_with_space); - do_check( - r#" -fn main() { - // Fix me $0 - let x = 1 + 1; -} -"#, - r#" -fn main() { - // Fix me - // $0 - let x = 1 + 1; -} -"#, - ); - } - - #[test] - fn trims_all_trailing_whitespace() { - do_check( - " -fn main() { - // Fix me \t\t $0 - let x = 1 + 1; -} -", - " -fn main() { - // Fix me - // $0 - let x = 1 + 1; -} -", - ); - } - - #[test] - fn indents_fn_body_block() { - cov_mark::check!(indent_block_contents); - do_check( - r#" -fn f() {$0()} - "#, - r#" -fn f() { - $0() -} - "#, - ); - } - - #[test] - fn indents_block_expr() { - do_check( - r#" -fn f() { - let x = {$0()}; -} - "#, - r#" -fn f() { - let x = { - $0() - }; -} - "#, - ); - } - - #[test] - fn indents_match_arm() { - do_check( - r#" -fn f() { - match 6 { - 1 => {$0f()}, - _ => (), - } -} - "#, - r#" -fn f() { - match 6 { - 1 => { - $0f() - }, - _ => (), - } -} - "#, - ); - } - - #[test] - fn indents_block_with_statement() { - do_check( - r#" -fn f() {$0a = b} - "#, - r#" -fn f() { - $0a = b -} - "#, - ); - do_check( - r#" -fn f() {$0fn f() {}} - "#, - r#" -fn f() { - $0fn f() {} -} - "#, - ); - } - - #[test] - fn indents_nested_blocks() { - do_check( - r#" -fn f() {$0{}} - "#, - r#" -fn f() { - $0{} -} - "#, - ); - } - - #[test] - fn does_not_indent_empty_block() { - do_check_noop( - r#" -fn f() {$0} - "#, - ); - do_check_noop( - r#" -fn f() {{$0}} - "#, - ); - } - - #[test] - fn does_not_indent_block_with_too_much_content() { - do_check_noop( - r#" -fn f() {$0 a = b; ()} - "#, - ); - do_check_noop( - r#" -fn f() {$0 a = b; a = b; } - "#, - ); - } - - #[test] - fn does_not_indent_multiline_block() { - do_check_noop( - r#" -fn f() {$0 -} - "#, - ); - do_check_noop( - r#" -fn f() {$0 - -} - "#, - ); - } - - #[test] - fn indents_use_tree_list() { - do_check( - r#" -use crate::{$0}; - "#, - r#" -use crate::{ - $0 -}; - "#, - ); - do_check( - r#" -use crate::{$0Object, path::to::OtherThing}; - "#, - r#" -use crate::{ - $0Object, path::to::OtherThing -}; - "#, - ); - do_check( - r#" -use {crate::{$0Object, path::to::OtherThing}}; - "#, - r#" -use {crate::{ - $0Object, path::to::OtherThing -}}; - "#, - ); - do_check( - r#" -use { - crate::{$0Object, path::to::OtherThing} -}; - "#, - r#" -use { - crate::{ - $0Object, path::to::OtherThing - } -}; - "#, - ); - } - - #[test] - fn does_not_indent_use_tree_list_when_not_at_curly_brace() { - do_check_noop( - r#" -use path::{Thing$0}; - "#, - ); - } - - #[test] - fn does_not_indent_use_tree_list_without_curly_braces() { - do_check_noop( - r#" -use path::Thing$0; - "#, - ); - do_check_noop( - r#" -use path::$0Thing; - "#, - ); - do_check_noop( - r#" -use path::Thing$0}; - "#, - ); - do_check_noop( - r#" -use path::{$0Thing; - "#, - ); - } - - #[test] - fn does_not_indent_multiline_use_tree_list() { - do_check_noop( - r#" -use path::{$0 - Thing -}; - "#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs deleted file mode 100644 index 51291a64532fe..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs +++ /dev/null @@ -1,93 +0,0 @@ -use std::sync::Arc; - -use dot::{Id, LabelText}; -use ide_db::{ - base_db::{CrateGraph, CrateId, Dependency, SourceDatabase, SourceDatabaseExt}, - FxHashSet, RootDatabase, -}; - -// Feature: View Crate Graph -// -// Renders the currently loaded crate graph as an SVG graphic. Requires the `dot` tool, which -// is part of graphviz, to be installed. -// -// Only workspace crates are included, no crates.io dependencies or sysroot crates. -// -// |=== -// | Editor | Action Name -// -// | VS Code | **Rust Analyzer: View Crate Graph** -// |=== -pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result { - let crate_graph = db.crate_graph(); - let crates_to_render = crate_graph - .iter() - .filter(|krate| { - if full { - true - } else { - // Only render workspace crates - let root_id = db.file_source_root(crate_graph[*krate].root_file_id); - !db.source_root(root_id).is_library - } - }) - .collect(); - let graph = DotCrateGraph { graph: crate_graph, crates_to_render }; - - let mut dot = Vec::new(); - dot::render(&graph, &mut dot).unwrap(); - Ok(String::from_utf8(dot).unwrap()) -} - -struct DotCrateGraph { - graph: Arc, - crates_to_render: FxHashSet, -} - -type Edge<'a> = (CrateId, &'a Dependency); - -impl<'a> dot::GraphWalk<'a, CrateId, Edge<'a>> for DotCrateGraph { - fn nodes(&'a self) -> dot::Nodes<'a, CrateId> { - self.crates_to_render.iter().copied().collect() - } - - fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { - self.crates_to_render - .iter() - .flat_map(|krate| { - self.graph[*krate] - .dependencies - .iter() - .filter(|dep| self.crates_to_render.contains(&dep.crate_id)) - .map(move |dep| (*krate, dep)) - }) - .collect() - } - - fn source(&'a self, edge: &Edge<'a>) -> CrateId { - edge.0 - } - - fn target(&'a self, edge: &Edge<'a>) -> CrateId { - edge.1.crate_id - } -} - -impl<'a> dot::Labeller<'a, CrateId, Edge<'a>> for DotCrateGraph { - fn graph_id(&'a self) -> Id<'a> { - Id::new("rust_analyzer_crate_graph").unwrap() - } - - fn node_id(&'a self, n: &CrateId) -> Id<'a> { - Id::new(format!("_{}", n.0)).unwrap() - } - - fn node_shape(&'a self, _node: &CrateId) -> Option> { - Some(LabelText::LabelStr("box".into())) - } - - fn node_label(&'a self, n: &CrateId) -> LabelText<'a> { - let name = self.graph[*n].display_name.as_ref().map_or("(unnamed crate)", |name| &*name); - LabelText::LabelStr(name.into()) - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/view_hir.rs b/src/tools/rust-analyzer/crates/ide/src/view_hir.rs deleted file mode 100644 index 7312afe5310b4..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/view_hir.rs +++ /dev/null @@ -1,26 +0,0 @@ -use hir::{Function, Semantics}; -use ide_db::base_db::FilePosition; -use ide_db::RootDatabase; -use syntax::{algo::find_node_at_offset, ast, AstNode}; - -// Feature: View Hir -// -// |=== -// | Editor | Action Name -// -// | VS Code | **Rust Analyzer: View Hir** -// |=== -// image::https://user-images.githubusercontent.com/48062697/113065588-068bdb80-91b1-11eb-9a78-0b4ef1e972fb.gif[] -pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String { - body_hir(db, position).unwrap_or_else(|| "Not inside a function body".to_string()) -} - -fn body_hir(db: &RootDatabase, position: FilePosition) -> Option { - let sema = Semantics::new(db); - let source_file = sema.parse(position.file_id); - - let function = find_node_at_offset::(source_file.syntax(), position.offset)?; - - let function: Function = sema.to_def(&function)?; - Some(function.debug_hir(db)) -} diff --git a/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs b/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs deleted file mode 100644 index 3dc03085d651c..0000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs +++ /dev/null @@ -1,16 +0,0 @@ -use hir::db::DefDatabase; -use ide_db::base_db::FileId; -use ide_db::RootDatabase; - -// Feature: Debug ItemTree -// -// Displays the ItemTree of the currently open file, for debugging. -// -// |=== -// | Editor | Action Name -// -// | VS Code | **Rust Analyzer: Debug ItemTree** -// |=== -pub(crate) fn view_item_tree(db: &RootDatabase, file_id: FileId) -> String { - db.file_item_tree(file_id.into()).pretty_print() -} diff --git a/src/tools/rust-analyzer/crates/limit/Cargo.toml b/src/tools/rust-analyzer/crates/limit/Cargo.toml deleted file mode 100644 index 893db436d8b73..0000000000000 --- a/src/tools/rust-analyzer/crates/limit/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "limit" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[features] -tracking = [] -default = ["tracking"] diff --git a/src/tools/rust-analyzer/crates/limit/src/lib.rs b/src/tools/rust-analyzer/crates/limit/src/lib.rs deleted file mode 100644 index 3c1da80edb98b..0000000000000 --- a/src/tools/rust-analyzer/crates/limit/src/lib.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! limit defines a struct to enforce limits. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -use std::sync::atomic::AtomicUsize; - -/// Represents a struct used to enforce a numerical limit. -pub struct Limit { - upper_bound: usize, - #[allow(unused)] - max: AtomicUsize, -} - -impl Limit { - /// Creates a new limit. - #[inline] - pub const fn new(upper_bound: usize) -> Self { - Self { upper_bound, max: AtomicUsize::new(0) } - } - - /// Creates a new limit. - #[inline] - #[cfg(feature = "tracking")] - pub const fn new_tracking(upper_bound: usize) -> Self { - Self { upper_bound, max: AtomicUsize::new(1) } - } - - /// Gets the underlying numeric limit. - #[inline] - pub const fn inner(&self) -> usize { - self.upper_bound - } - - /// Checks whether the given value is below the limit. - /// Returns `Ok` when `other` is below `self`, and `Err` otherwise. - #[inline] - pub fn check(&self, other: usize) -> Result<(), ()> { - if other > self.upper_bound { - Err(()) - } else { - #[cfg(feature = "tracking")] - loop { - use std::sync::atomic::Ordering; - let old_max = self.max.load(Ordering::Relaxed); - if other <= old_max || old_max == 0 { - break; - } - if self - .max - .compare_exchange_weak(old_max, other, Ordering::Relaxed, Ordering::Relaxed) - .is_ok() - { - eprintln!("new max: {}", other); - } - } - - Ok(()) - } - } -} diff --git a/src/tools/rust-analyzer/crates/mbe/Cargo.toml b/src/tools/rust-analyzer/crates/mbe/Cargo.toml deleted file mode 100644 index 5ff3448a19ca7..0000000000000 --- a/src/tools/rust-analyzer/crates/mbe/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "mbe" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -cov-mark = "2.0.0-pre.1" -rustc-hash = "1.1.0" -smallvec = "1.9.0" -tracing = "0.1.35" - -syntax = { path = "../syntax", version = "0.0.0" } -parser = { path = "../parser", version = "0.0.0" } -tt = { path = "../tt", version = "0.0.0" } -stdx = { path = "../stdx", version = "0.0.0" } - -[dev-dependencies] -test-utils = { path = "../test-utils" } diff --git a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs deleted file mode 100644 index ac691578d8873..0000000000000 --- a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs +++ /dev/null @@ -1,222 +0,0 @@ -//! This module add real world mbe example for benchmark tests - -use rustc_hash::FxHashMap; -use syntax::{ - ast::{self, HasName}, - AstNode, SmolStr, -}; -use test_utils::{bench, bench_fixture, skip_slow_tests}; - -use crate::{ - parser::{Op, RepeatKind, Separator}, - syntax_node_to_token_tree, DeclarativeMacro, -}; - -#[test] -fn benchmark_parse_macro_rules() { - if skip_slow_tests() { - return; - } - let rules = macro_rules_fixtures_tt(); - let hash: usize = { - let _pt = bench("mbe parse macro rules"); - rules.values().map(|it| DeclarativeMacro::parse_macro_rules(it).unwrap().rules.len()).sum() - }; - assert_eq!(hash, 1144); -} - -#[test] -fn benchmark_expand_macro_rules() { - if skip_slow_tests() { - return; - } - let rules = macro_rules_fixtures(); - let invocations = invocation_fixtures(&rules); - - let hash: usize = { - let _pt = bench("mbe expand macro rules"); - invocations - .into_iter() - .map(|(id, tt)| { - let res = rules[&id].expand(&tt); - assert!(res.err.is_none()); - res.value.token_trees.len() - }) - .sum() - }; - assert_eq!(hash, 69413); -} - -fn macro_rules_fixtures() -> FxHashMap { - macro_rules_fixtures_tt() - .into_iter() - .map(|(id, tt)| (id, DeclarativeMacro::parse_macro_rules(&tt).unwrap())) - .collect() -} - -fn macro_rules_fixtures_tt() -> FxHashMap { - let fixture = bench_fixture::numerous_macro_rules(); - let source_file = ast::SourceFile::parse(&fixture).ok().unwrap(); - - source_file - .syntax() - .descendants() - .filter_map(ast::MacroRules::cast) - .map(|rule| { - let id = rule.name().unwrap().to_string(); - let (def_tt, _) = syntax_node_to_token_tree(rule.token_tree().unwrap().syntax()); - (id, def_tt) - }) - .collect() -} - -/// Generate random invocation fixtures from rules -fn invocation_fixtures(rules: &FxHashMap) -> Vec<(String, tt::Subtree)> { - let mut seed = 123456789; - let mut res = Vec::new(); - - for (name, it) in rules { - for rule in &it.rules { - // Generate twice - for _ in 0..2 { - // The input are generated by filling the `Op` randomly. - // However, there are some cases generated are ambiguous for expanding, for example: - // ```rust - // macro_rules! m { - // ($($t:ident),* as $ty:ident) => {} - // } - // m!(as u32); // error: local ambiguity: multiple parsing options: built-in NTs ident ('t') or 1 other option. - // ``` - // - // So we just skip any error cases and try again - let mut try_cnt = 0; - loop { - let mut subtree = tt::Subtree::default(); - for op in rule.lhs.iter() { - collect_from_op(op, &mut subtree, &mut seed); - } - if it.expand(&subtree).err.is_none() { - res.push((name.clone(), subtree)); - break; - } - try_cnt += 1; - if try_cnt > 100 { - panic!("invocaton fixture {} cannot be generated.\n", name); - } - } - } - } - } - return res; - - fn collect_from_op(op: &Op, parent: &mut tt::Subtree, seed: &mut usize) { - return match op { - Op::Var { kind, .. } => match kind.as_ref().map(|it| it.as_str()) { - Some("ident") => parent.token_trees.push(make_ident("foo")), - Some("ty") => parent.token_trees.push(make_ident("Foo")), - Some("tt") => parent.token_trees.push(make_ident("foo")), - Some("vis") => parent.token_trees.push(make_ident("pub")), - Some("pat") => parent.token_trees.push(make_ident("foo")), - Some("path") => parent.token_trees.push(make_ident("foo")), - Some("literal") => parent.token_trees.push(make_literal("1")), - Some("expr") => parent.token_trees.push(make_ident("foo")), - Some("lifetime") => { - parent.token_trees.push(make_punct('\'')); - parent.token_trees.push(make_ident("a")); - } - Some("block") => { - parent.token_trees.push(make_subtree(tt::DelimiterKind::Brace, None)) - } - Some("item") => { - parent.token_trees.push(make_ident("fn")); - parent.token_trees.push(make_ident("foo")); - parent.token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None)); - parent.token_trees.push(make_subtree(tt::DelimiterKind::Brace, None)); - } - Some("meta") => { - parent.token_trees.push(make_ident("foo")); - parent.token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None)); - } - - None => (), - Some(kind) => panic!("Unhandled kind {}", kind), - }, - Op::Leaf(leaf) => parent.token_trees.push(leaf.clone().into()), - Op::Repeat { tokens, kind, separator } => { - let max = 10; - let cnt = match kind { - RepeatKind::ZeroOrMore => rand(seed) % max, - RepeatKind::OneOrMore => 1 + rand(seed) % max, - RepeatKind::ZeroOrOne => rand(seed) % 2, - }; - for i in 0..cnt { - for it in tokens.iter() { - collect_from_op(it, parent, seed); - } - if i + 1 != cnt { - if let Some(sep) = separator { - match sep { - Separator::Literal(it) => { - parent.token_trees.push(tt::Leaf::Literal(it.clone()).into()) - } - Separator::Ident(it) => { - parent.token_trees.push(tt::Leaf::Ident(it.clone()).into()) - } - Separator::Puncts(puncts) => { - for it in puncts { - parent.token_trees.push(tt::Leaf::Punct(*it).into()) - } - } - }; - } - } - } - } - Op::Subtree { tokens, delimiter } => { - let mut subtree = tt::Subtree { delimiter: *delimiter, token_trees: Vec::new() }; - tokens.iter().for_each(|it| { - collect_from_op(it, &mut subtree, seed); - }); - parent.token_trees.push(subtree.into()); - } - Op::Ignore { .. } | Op::Index { .. } => {} - }; - - // Simple linear congruential generator for determistic result - fn rand(seed: &mut usize) -> usize { - let a = 1664525; - let c = 1013904223; - *seed = usize::wrapping_add(usize::wrapping_mul(*seed, a), c); - *seed - } - fn make_ident(ident: &str) -> tt::TokenTree { - tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), text: SmolStr::new(ident) }) - .into() - } - fn make_punct(char: char) -> tt::TokenTree { - tt::Leaf::Punct(tt::Punct { - id: tt::TokenId::unspecified(), - char, - spacing: tt::Spacing::Alone, - }) - .into() - } - fn make_literal(lit: &str) -> tt::TokenTree { - tt::Leaf::Literal(tt::Literal { - id: tt::TokenId::unspecified(), - text: SmolStr::new(lit), - }) - .into() - } - fn make_subtree( - kind: tt::DelimiterKind, - token_trees: Option>, - ) -> tt::TokenTree { - tt::Subtree { - delimiter: Some(tt::Delimiter { id: tt::TokenId::unspecified(), kind }), - token_trees: token_trees.unwrap_or_default(), - } - .into() - } - } -} diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander.rs b/src/tools/rust-analyzer/crates/mbe/src/expander.rs deleted file mode 100644 index 1e1bfa5505583..0000000000000 --- a/src/tools/rust-analyzer/crates/mbe/src/expander.rs +++ /dev/null @@ -1,121 +0,0 @@ -//! This module takes a (parsed) definition of `macro_rules` invocation, a -//! `tt::TokenTree` representing an argument of macro invocation, and produces a -//! `tt::TokenTree` for the result of the expansion. - -mod matcher; -mod transcriber; - -use rustc_hash::FxHashMap; -use syntax::SmolStr; - -use crate::{ExpandError, ExpandResult}; - -pub(crate) fn expand_rules( - rules: &[crate::Rule], - input: &tt::Subtree, -) -> ExpandResult { - let mut match_: Option<(matcher::Match, &crate::Rule)> = None; - for rule in rules { - let new_match = matcher::match_(&rule.lhs, input); - - if new_match.err.is_none() { - // If we find a rule that applies without errors, we're done. - // Unconditionally returning the transcription here makes the - // `test_repeat_bad_var` test fail. - let ExpandResult { value, err: transcribe_err } = - transcriber::transcribe(&rule.rhs, &new_match.bindings); - if transcribe_err.is_none() { - return ExpandResult::ok(value); - } - } - // Use the rule if we matched more tokens, or bound variables count - if let Some((prev_match, _)) = &match_ { - if (new_match.unmatched_tts, -(new_match.bound_count as i32)) - < (prev_match.unmatched_tts, -(prev_match.bound_count as i32)) - { - match_ = Some((new_match, rule)); - } - } else { - match_ = Some((new_match, rule)); - } - } - if let Some((match_, rule)) = match_ { - // if we got here, there was no match without errors - let ExpandResult { value, err: transcribe_err } = - transcriber::transcribe(&rule.rhs, &match_.bindings); - ExpandResult { value, err: match_.err.or(transcribe_err) } - } else { - ExpandResult::only_err(ExpandError::NoMatchingRule) - } -} - -/// The actual algorithm for expansion is not too hard, but is pretty tricky. -/// `Bindings` structure is the key to understanding what we are doing here. -/// -/// On the high level, it stores mapping from meta variables to the bits of -/// syntax it should be substituted with. For example, if `$e:expr` is matched -/// with `1 + 1` by macro_rules, the `Binding` will store `$e -> 1 + 1`. -/// -/// The tricky bit is dealing with repetitions (`$()*`). Consider this example: -/// -/// ```not_rust -/// macro_rules! foo { -/// ($($ i:ident $($ e:expr),*);*) => { -/// $(fn $ i() { $($ e);*; })* -/// } -/// } -/// foo! { foo 1,2,3; bar 4,5,6 } -/// ``` -/// -/// Here, the `$i` meta variable is matched first with `foo` and then with -/// `bar`, and `$e` is matched in turn with `1`, `2`, `3`, `4`, `5`, `6`. -/// -/// To represent such "multi-mappings", we use a recursive structures: we map -/// variables not to values, but to *lists* of values or other lists (that is, -/// to the trees). -/// -/// For the above example, the bindings would store -/// -/// ```not_rust -/// i -> [foo, bar] -/// e -> [[1, 2, 3], [4, 5, 6]] -/// ``` -/// -/// We construct `Bindings` in the `match_lhs`. The interesting case is -/// `TokenTree::Repeat`, where we use `push_nested` to create the desired -/// nesting structure. -/// -/// The other side of the puzzle is `expand_subtree`, where we use the bindings -/// to substitute meta variables in the output template. When expanding, we -/// maintain a `nesting` stack of indices which tells us which occurrence from -/// the `Bindings` we should take. We push to the stack when we enter a -/// repetition. -/// -/// In other words, `Bindings` is a *multi* mapping from `SmolStr` to -/// `tt::TokenTree`, where the index to select a particular `TokenTree` among -/// many is not a plain `usize`, but a `&[usize]`. -#[derive(Debug, Default, Clone, PartialEq, Eq)] -struct Bindings { - inner: FxHashMap, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -enum Binding { - Fragment(Fragment), - Nested(Vec), - Empty, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -enum Fragment { - /// token fragments are just copy-pasted into the output - Tokens(tt::TokenTree), - /// Expr ast fragments are surrounded with `()` on insertion to preserve - /// precedence. Note that this impl is different from the one currently in - /// `rustc` -- `rustc` doesn't translate fragments into token trees at all. - /// - /// At one point in time, we tried to to use "fake" delimiters here a-la - /// proc-macro delimiter=none. As we later discovered, "none" delimiters are - /// tricky to handle in the parser, and rustc doesn't handle those either. - Expr(tt::TokenTree), -} diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs deleted file mode 100644 index 5020e9abaf315..0000000000000 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs +++ /dev/null @@ -1,914 +0,0 @@ -//! An NFA-based parser, which is porting from rustc mbe parsing code -//! -//! See -//! Here is a quick intro to how the parser works, copied from rustc: -//! -//! A 'position' is a dot in the middle of a matcher, usually represented as a -//! dot. For example `· a $( a )* a b` is a position, as is `a $( · a )* a b`. -//! -//! The parser walks through the input a character at a time, maintaining a list -//! of threads consistent with the current position in the input string: `cur_items`. -//! -//! As it processes them, it fills up `eof_items` with threads that would be valid if -//! the macro invocation is now over, `bb_items` with threads that are waiting on -//! a Rust non-terminal like `$e:expr`, and `next_items` with threads that are waiting -//! on a particular token. Most of the logic concerns moving the · through the -//! repetitions indicated by Kleene stars. The rules for moving the · without -//! consuming any input are called epsilon transitions. It only advances or calls -//! out to the real Rust parser when no `cur_items` threads remain. -//! -//! Example: -//! -//! ```text, ignore -//! Start parsing a a a a b against [· a $( a )* a b]. -//! -//! Remaining input: a a a a b -//! next: [· a $( a )* a b] -//! -//! - - - Advance over an a. - - - -//! -//! Remaining input: a a a b -//! cur: [a · $( a )* a b] -//! Descend/Skip (first item). -//! next: [a $( · a )* a b] [a $( a )* · a b]. -//! -//! - - - Advance over an a. - - - -//! -//! Remaining input: a a b -//! cur: [a $( a · )* a b] [a $( a )* a · b] -//! Follow epsilon transition: Finish/Repeat (first item) -//! next: [a $( a )* · a b] [a $( · a )* a b] [a $( a )* a · b] -//! -//! - - - Advance over an a. - - - (this looks exactly like the last step) -//! -//! Remaining input: a b -//! cur: [a $( a · )* a b] [a $( a )* a · b] -//! Follow epsilon transition: Finish/Repeat (first item) -//! next: [a $( a )* · a b] [a $( · a )* a b] [a $( a )* a · b] -//! -//! - - - Advance over an a. - - - (this looks exactly like the last step) -//! -//! Remaining input: b -//! cur: [a $( a · )* a b] [a $( a )* a · b] -//! Follow epsilon transition: Finish/Repeat (first item) -//! next: [a $( a )* · a b] [a $( · a )* a b] [a $( a )* a · b] -//! -//! - - - Advance over a b. - - - -//! -//! Remaining input: '' -//! eof: [a $( a )* a b ·] -//! ``` - -use std::rc::Rc; - -use smallvec::{smallvec, SmallVec}; -use syntax::SmolStr; - -use crate::{ - expander::{Binding, Bindings, ExpandResult, Fragment}, - parser::{Op, RepeatKind, Separator}, - tt_iter::TtIter, - ExpandError, MetaTemplate, -}; - -impl Bindings { - fn push_optional(&mut self, name: &SmolStr) { - // FIXME: Do we have a better way to represent an empty token ? - // Insert an empty subtree for empty token - let tt = tt::Subtree::default().into(); - self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt))); - } - - fn push_empty(&mut self, name: &SmolStr) { - self.inner.insert(name.clone(), Binding::Empty); - } - - fn bindings(&self) -> impl Iterator { - self.inner.values() - } -} - -#[derive(Clone, Debug, Default, PartialEq, Eq)] -pub(super) struct Match { - pub(super) bindings: Bindings, - /// We currently just keep the first error and count the rest to compare matches. - pub(super) err: Option, - pub(super) err_count: usize, - /// How many top-level token trees were left to match. - pub(super) unmatched_tts: usize, - /// The number of bound variables - pub(super) bound_count: usize, -} - -impl Match { - fn add_err(&mut self, err: ExpandError) { - let prev_err = self.err.take(); - self.err = prev_err.or(Some(err)); - self.err_count += 1; - } -} - -/// Matching errors are added to the `Match`. -pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree) -> Match { - let mut res = match_loop(pattern, input); - res.bound_count = count(res.bindings.bindings()); - return res; - - fn count<'a>(bindings: impl Iterator) -> usize { - bindings - .map(|it| match it { - Binding::Fragment(_) => 1, - Binding::Empty => 1, - Binding::Nested(it) => count(it.iter()), - }) - .sum() - } -} - -#[derive(Debug, Clone)] -enum BindingKind { - Empty(SmolStr), - Optional(SmolStr), - Fragment(SmolStr, Fragment), - Nested(usize, usize), -} - -#[derive(Debug, Clone)] -struct BindingsIdx(usize, usize); - -#[derive(Debug, Clone)] -enum LinkNode { - Node(T), - Parent { idx: usize, len: usize }, -} - -#[derive(Default)] -struct BindingsBuilder { - nodes: Vec>>>, - nested: Vec>>, -} - -impl BindingsBuilder { - fn alloc(&mut self) -> BindingsIdx { - let idx = self.nodes.len(); - self.nodes.push(Vec::new()); - let nidx = self.nested.len(); - self.nested.push(Vec::new()); - BindingsIdx(idx, nidx) - } - - fn copy(&mut self, bindings: &BindingsIdx) -> BindingsIdx { - let idx = copy_parent(bindings.0, &mut self.nodes); - let nidx = copy_parent(bindings.1, &mut self.nested); - return BindingsIdx(idx, nidx); - - fn copy_parent(idx: usize, target: &mut Vec>>) -> usize - where - T: Clone, - { - let new_idx = target.len(); - let len = target[idx].len(); - if len < 4 { - target.push(target[idx].clone()) - } else { - target.push(vec![LinkNode::Parent { idx, len }]); - } - new_idx - } - } - - fn push_empty(&mut self, idx: &mut BindingsIdx, var: &SmolStr) { - self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Empty(var.clone())))); - } - - fn push_optional(&mut self, idx: &mut BindingsIdx, var: &SmolStr) { - self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Optional(var.clone())))); - } - - fn push_fragment(&mut self, idx: &mut BindingsIdx, var: &SmolStr, fragment: Fragment) { - self.nodes[idx.0] - .push(LinkNode::Node(Rc::new(BindingKind::Fragment(var.clone(), fragment)))); - } - - fn push_nested(&mut self, parent: &mut BindingsIdx, child: &BindingsIdx) { - let BindingsIdx(idx, nidx) = self.copy(child); - self.nodes[parent.0].push(LinkNode::Node(Rc::new(BindingKind::Nested(idx, nidx)))); - } - - fn push_default(&mut self, idx: &mut BindingsIdx) { - self.nested[idx.1].push(LinkNode::Node(idx.0)); - let new_idx = self.nodes.len(); - self.nodes.push(Vec::new()); - idx.0 = new_idx; - } - - fn build(self, idx: &BindingsIdx) -> Bindings { - let mut bindings = Bindings::default(); - self.build_inner(&mut bindings, &self.nodes[idx.0]); - bindings - } - - fn build_inner(&self, bindings: &mut Bindings, link_nodes: &[LinkNode>]) { - let mut nodes = Vec::new(); - self.collect_nodes(link_nodes, &mut nodes); - - for cmd in nodes { - match &**cmd { - BindingKind::Empty(name) => { - bindings.push_empty(name); - } - BindingKind::Optional(name) => { - bindings.push_optional(name); - } - BindingKind::Fragment(name, fragment) => { - bindings.inner.insert(name.clone(), Binding::Fragment(fragment.clone())); - } - BindingKind::Nested(idx, nested_idx) => { - let mut nested_nodes = Vec::new(); - self.collect_nested(*idx, *nested_idx, &mut nested_nodes); - - for (idx, iter) in nested_nodes.into_iter().enumerate() { - for (key, value) in &iter.inner { - let bindings = bindings - .inner - .entry(key.clone()) - .or_insert_with(|| Binding::Nested(Vec::new())); - - if let Binding::Nested(it) = bindings { - // insert empty nested bindings before this one - while it.len() < idx { - it.push(Binding::Nested(Vec::new())); - } - it.push(value.clone()); - } - } - } - } - } - } - } - - fn collect_nested_ref<'a>( - &'a self, - id: usize, - len: usize, - nested_refs: &mut Vec<&'a Vec>>>, - ) { - self.nested[id].iter().take(len).for_each(|it| match it { - LinkNode::Node(id) => nested_refs.push(&self.nodes[*id]), - LinkNode::Parent { idx, len } => self.collect_nested_ref(*idx, *len, nested_refs), - }); - } - - fn collect_nested(&self, idx: usize, nested_idx: usize, nested: &mut Vec) { - let last = &self.nodes[idx]; - let mut nested_refs = Vec::new(); - self.nested[nested_idx].iter().for_each(|it| match *it { - LinkNode::Node(idx) => nested_refs.push(&self.nodes[idx]), - LinkNode::Parent { idx, len } => self.collect_nested_ref(idx, len, &mut nested_refs), - }); - nested_refs.push(last); - - nested_refs.into_iter().for_each(|iter| { - let mut child_bindings = Bindings::default(); - self.build_inner(&mut child_bindings, iter); - nested.push(child_bindings) - }) - } - - fn collect_nodes_ref<'a>( - &'a self, - id: usize, - len: usize, - nodes: &mut Vec<&'a Rc>, - ) { - self.nodes[id].iter().take(len).for_each(|it| match it { - LinkNode::Node(it) => nodes.push(it), - LinkNode::Parent { idx, len } => self.collect_nodes_ref(*idx, *len, nodes), - }); - } - - fn collect_nodes<'a>( - &'a self, - link_nodes: &'a [LinkNode>], - nodes: &mut Vec<&'a Rc>, - ) { - link_nodes.iter().for_each(|it| match it { - LinkNode::Node(it) => nodes.push(it), - LinkNode::Parent { idx, len } => self.collect_nodes_ref(*idx, *len, nodes), - }); - } -} - -#[derive(Debug, Clone)] -struct MatchState<'t> { - /// The position of the "dot" in this matcher - dot: OpDelimitedIter<'t>, - - /// Token subtree stack - /// When matching against matchers with nested delimited submatchers (e.g., `pat ( pat ( .. ) - /// pat ) pat`), we need to keep track of the matchers we are descending into. This stack does - /// that where the bottom of the stack is the outermost matcher. - stack: SmallVec<[OpDelimitedIter<'t>; 4]>, - - /// The "parent" matcher position if we are in a repetition. That is, the matcher position just - /// before we enter the repetition. - up: Option>>, - - /// The separator if we are in a repetition. - sep: Option, - - /// The KleeneOp of this sequence if we are in a repetition. - sep_kind: Option, - - /// Number of tokens of seperator parsed - sep_parsed: Option, - - /// Matched meta variables bindings - bindings: BindingsIdx, - - /// Cached result of meta variable parsing - meta_result: Option<(TtIter<'t>, ExpandResult>)>, - - /// Is error occuried in this state, will `poised` to "parent" - is_error: bool, -} - -/// Process the matcher positions of `cur_items` until it is empty. In the process, this will -/// produce more items in `next_items`, `eof_items`, and `bb_items`. -/// -/// For more info about the how this happens, see the module-level doc comments and the inline -/// comments of this function. -/// -/// # Parameters -/// -/// - `src`: the current token of the parser. -/// - `stack`: the "parent" frames of the token tree -/// - `res`: the match result to store errors -/// - `cur_items`: the set of current items to be processed. This should be empty by the end of a -/// successful execution of this function. -/// - `next_items`: the set of newly generated items. These are used to replenish `cur_items` in -/// the function `parse`. -/// - `eof_items`: the set of items that would be valid if this was the EOF. -/// - `bb_items`: the set of items that are waiting for the black-box parser. -/// - `error_items`: the set of items in errors, used for error-resilient parsing -fn match_loop_inner<'t>( - src: TtIter<'t>, - stack: &[TtIter<'t>], - res: &mut Match, - bindings_builder: &mut BindingsBuilder, - cur_items: &mut SmallVec<[MatchState<'t>; 1]>, - bb_items: &mut SmallVec<[MatchState<'t>; 1]>, - next_items: &mut Vec>, - eof_items: &mut SmallVec<[MatchState<'t>; 1]>, - error_items: &mut SmallVec<[MatchState<'t>; 1]>, -) { - macro_rules! try_push { - ($items: expr, $it:expr) => { - if $it.is_error { - error_items.push($it); - } else { - $items.push($it); - } - }; - } - - while let Some(mut item) = cur_items.pop() { - while item.dot.is_eof() { - match item.stack.pop() { - Some(frame) => { - item.dot = frame; - item.dot.next(); - } - None => break, - } - } - let op = match item.dot.peek() { - None => { - // We are at or past the end of the matcher of `item`. - if item.up.is_some() { - if item.sep_parsed.is_none() { - // Get the `up` matcher - let mut new_pos = *item.up.clone().unwrap(); - new_pos.bindings = bindings_builder.copy(&new_pos.bindings); - // Add matches from this repetition to the `matches` of `up` - bindings_builder.push_nested(&mut new_pos.bindings, &item.bindings); - - // Move the "dot" past the repetition in `up` - new_pos.dot.next(); - new_pos.is_error = new_pos.is_error || item.is_error; - cur_items.push(new_pos); - } - - // Check if we need a separator. - // We check the separator one by one - let sep_idx = *item.sep_parsed.as_ref().unwrap_or(&0); - let sep_len = item.sep.as_ref().map_or(0, Separator::tt_count); - if item.sep.is_some() && sep_idx != sep_len { - let sep = item.sep.as_ref().unwrap(); - if src.clone().expect_separator(sep, sep_idx) { - item.dot.next(); - item.sep_parsed = Some(sep_idx + 1); - try_push!(next_items, item); - } - } - // We don't need a separator. Move the "dot" back to the beginning of the matcher - // and try to match again UNLESS we are only allowed to have _one_ repetition. - else if item.sep_kind != Some(RepeatKind::ZeroOrOne) { - item.dot = item.dot.reset(); - item.sep_parsed = None; - bindings_builder.push_default(&mut item.bindings); - cur_items.push(item); - } - } else { - // If we are not in a repetition, then being at the end of a matcher means that we have - // reached the potential end of the input. - try_push!(eof_items, item); - } - continue; - } - Some(it) => it, - }; - - // We are in the middle of a matcher. - match op { - OpDelimited::Op(Op::Repeat { tokens, kind, separator }) => { - if matches!(kind, RepeatKind::ZeroOrMore | RepeatKind::ZeroOrOne) { - let mut new_item = item.clone(); - new_item.bindings = bindings_builder.copy(&new_item.bindings); - new_item.dot.next(); - collect_vars( - &mut |s| { - bindings_builder.push_empty(&mut new_item.bindings, &s); - }, - tokens, - ); - cur_items.push(new_item); - } - cur_items.push(MatchState { - dot: tokens.iter_delimited(None), - stack: Default::default(), - up: Some(Box::new(item)), - sep: separator.clone(), - sep_kind: Some(*kind), - sep_parsed: None, - bindings: bindings_builder.alloc(), - meta_result: None, - is_error: false, - }) - } - OpDelimited::Op(Op::Subtree { tokens, delimiter }) => { - if let Ok(subtree) = src.clone().expect_subtree() { - if subtree.delimiter_kind() == delimiter.map(|it| it.kind) { - item.stack.push(item.dot); - item.dot = tokens.iter_delimited(delimiter.as_ref()); - cur_items.push(item); - } - } - } - OpDelimited::Op(Op::Var { kind, name, .. }) => { - if let Some(kind) = kind { - let mut fork = src.clone(); - let match_res = match_meta_var(kind.as_str(), &mut fork); - match match_res.err { - None => { - // Some meta variables are optional (e.g. vis) - if match_res.value.is_some() { - item.meta_result = Some((fork, match_res)); - try_push!(bb_items, item); - } else { - bindings_builder.push_optional(&mut item.bindings, name); - item.dot.next(); - cur_items.push(item); - } - } - Some(err) => { - res.add_err(err); - if let Some(fragment) = match_res.value { - bindings_builder.push_fragment(&mut item.bindings, name, fragment); - } - item.is_error = true; - error_items.push(item); - } - } - } - } - OpDelimited::Op(Op::Leaf(leaf)) => { - if let Err(err) = match_leaf(leaf, &mut src.clone()) { - res.add_err(err); - item.is_error = true; - } else { - item.dot.next(); - } - try_push!(next_items, item); - } - OpDelimited::Op(Op::Ignore { .. } | Op::Index { .. }) => {} - OpDelimited::Open => { - if matches!(src.clone().next(), Some(tt::TokenTree::Subtree(..))) { - item.dot.next(); - try_push!(next_items, item); - } - } - OpDelimited::Close => { - let is_delim_closed = src.peek_n(0).is_none() && !stack.is_empty(); - if is_delim_closed { - item.dot.next(); - try_push!(next_items, item); - } - } - } - } -} - -fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match { - let mut src = TtIter::new(src); - let mut stack: SmallVec<[TtIter<'_>; 1]> = SmallVec::new(); - let mut res = Match::default(); - let mut error_recover_item = None; - - let mut bindings_builder = BindingsBuilder::default(); - - let mut cur_items = smallvec![MatchState { - dot: pattern.iter_delimited(None), - stack: Default::default(), - up: None, - sep: None, - sep_kind: None, - sep_parsed: None, - bindings: bindings_builder.alloc(), - is_error: false, - meta_result: None, - }]; - - let mut next_items = vec![]; - - loop { - let mut bb_items = SmallVec::new(); - let mut eof_items = SmallVec::new(); - let mut error_items = SmallVec::new(); - - stdx::always!(next_items.is_empty()); - - match_loop_inner( - src.clone(), - &stack, - &mut res, - &mut bindings_builder, - &mut cur_items, - &mut bb_items, - &mut next_items, - &mut eof_items, - &mut error_items, - ); - stdx::always!(cur_items.is_empty()); - - if !error_items.is_empty() { - error_recover_item = error_items.pop().map(|it| it.bindings); - } else if let [state, ..] = &*eof_items { - error_recover_item = Some(state.bindings.clone()); - } - - // We need to do some post processing after the `match_loop_inner`. - // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise, - // either the parse is ambiguous (which should never happen) or there is a syntax error. - if src.peek_n(0).is_none() && stack.is_empty() { - if let [state] = &*eof_items { - // remove all errors, because it is the correct answer ! - res = Match::default(); - res.bindings = bindings_builder.build(&state.bindings); - } else { - // Error recovery - if let Some(item) = error_recover_item { - res.bindings = bindings_builder.build(&item); - } - res.add_err(ExpandError::UnexpectedToken); - } - return res; - } - - // If there are no possible next positions AND we aren't waiting for the black-box parser, - // then there is a syntax error. - // - // Another possibility is that we need to call out to parse some rust nonterminal - // (black-box) parser. However, if there is not EXACTLY ONE of these, something is wrong. - let has_leftover_tokens = (bb_items.is_empty() && next_items.is_empty()) - || !(bb_items.is_empty() || next_items.is_empty()) - || bb_items.len() > 1; - if has_leftover_tokens { - res.unmatched_tts += src.len(); - while let Some(it) = stack.pop() { - src = it; - res.unmatched_tts += src.len(); - } - res.add_err(ExpandError::LeftoverTokens); - - if let Some(error_reover_item) = error_recover_item { - res.bindings = bindings_builder.build(&error_reover_item); - } - return res; - } - // Dump all possible `next_items` into `cur_items` for the next iteration. - else if !next_items.is_empty() { - // Now process the next token - cur_items.extend(next_items.drain(..)); - - match src.next() { - Some(tt::TokenTree::Subtree(subtree)) => { - stack.push(src.clone()); - src = TtIter::new(subtree); - } - None => { - if let Some(iter) = stack.pop() { - src = iter; - } - } - _ => (), - } - } - // Finally, we have the case where we need to call the black-box parser to get some - // nonterminal. - else { - stdx::always!(bb_items.len() == 1); - let mut item = bb_items.pop().unwrap(); - - if let Some(OpDelimited::Op(Op::Var { name, .. })) = item.dot.peek() { - let (iter, match_res) = item.meta_result.take().unwrap(); - match match_res.value { - Some(fragment) => { - bindings_builder.push_fragment(&mut item.bindings, name, fragment); - } - None if match_res.err.is_none() => { - bindings_builder.push_optional(&mut item.bindings, name); - } - None => {} - } - if let Some(err) = match_res.err { - res.add_err(err); - } - src = iter.clone(); - item.dot.next(); - } else { - unreachable!() - } - cur_items.push(item); - } - stdx::always!(!cur_items.is_empty()); - } -} - -fn match_leaf(lhs: &tt::Leaf, src: &mut TtIter<'_>) -> Result<(), ExpandError> { - let rhs = src - .expect_leaf() - .map_err(|()| ExpandError::binding_error(format!("expected leaf: `{lhs}`")))?; - match (lhs, rhs) { - ( - tt::Leaf::Punct(tt::Punct { char: lhs, .. }), - tt::Leaf::Punct(tt::Punct { char: rhs, .. }), - ) if lhs == rhs => Ok(()), - ( - tt::Leaf::Ident(tt::Ident { text: lhs, .. }), - tt::Leaf::Ident(tt::Ident { text: rhs, .. }), - ) if lhs == rhs => Ok(()), - ( - tt::Leaf::Literal(tt::Literal { text: lhs, .. }), - tt::Leaf::Literal(tt::Literal { text: rhs, .. }), - ) if lhs == rhs => Ok(()), - _ => Err(ExpandError::UnexpectedToken), - } -} - -fn match_meta_var(kind: &str, input: &mut TtIter<'_>) -> ExpandResult> { - let fragment = match kind { - "path" => parser::PrefixEntryPoint::Path, - "ty" => parser::PrefixEntryPoint::Ty, - // FIXME: These two should actually behave differently depending on the edition. - // - // https://doc.rust-lang.org/edition-guide/rust-2021/or-patterns-macro-rules.html - "pat" | "pat_param" => parser::PrefixEntryPoint::Pat, - "stmt" => parser::PrefixEntryPoint::Stmt, - "block" => parser::PrefixEntryPoint::Block, - "meta" => parser::PrefixEntryPoint::MetaItem, - "item" => parser::PrefixEntryPoint::Item, - "vis" => parser::PrefixEntryPoint::Vis, - "expr" => { - // `expr` should not match underscores. - // HACK: Macro expansion should not be done using "rollback and try another alternative". - // rustc [explicitly checks the next token][0]. - // [0]: https://github.com/rust-lang/rust/blob/f0c4da499/compiler/rustc_expand/src/mbe/macro_parser.rs#L576 - match input.peek_n(0) { - Some(tt::TokenTree::Leaf(tt::Leaf::Ident(it))) if it.text == "_" => { - return ExpandResult::only_err(ExpandError::NoMatchingRule) - } - _ => {} - }; - return input - .expect_fragment(parser::PrefixEntryPoint::Expr) - .map(|tt| tt.map(Fragment::Expr)); - } - _ => { - let tt_result = match kind { - "ident" => input - .expect_ident() - .map(|ident| tt::Leaf::from(ident.clone()).into()) - .map_err(|()| ExpandError::binding_error("expected ident")), - "tt" => input - .expect_tt() - .map_err(|()| ExpandError::binding_error("expected token tree")), - "lifetime" => input - .expect_lifetime() - .map_err(|()| ExpandError::binding_error("expected lifetime")), - "literal" => { - let neg = input.eat_char('-'); - input - .expect_literal() - .map(|literal| { - let lit = literal.clone(); - match neg { - None => lit.into(), - Some(neg) => tt::TokenTree::Subtree(tt::Subtree { - delimiter: None, - token_trees: vec![neg, lit.into()], - }), - } - }) - .map_err(|()| ExpandError::binding_error("expected literal")) - } - _ => Err(ExpandError::UnexpectedToken), - }; - return tt_result.map(|it| Some(Fragment::Tokens(it))).into(); - } - }; - input.expect_fragment(fragment).map(|it| it.map(Fragment::Tokens)) -} - -fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate) { - for op in pattern.iter() { - match op { - Op::Var { name, .. } => collector_fun(name.clone()), - Op::Leaf(_) => (), - Op::Subtree { tokens, .. } => collect_vars(collector_fun, tokens), - Op::Repeat { tokens, .. } => collect_vars(collector_fun, tokens), - Op::Ignore { .. } | Op::Index { .. } => {} - } - } -} -impl MetaTemplate { - fn iter_delimited<'a>(&'a self, delimited: Option<&'a tt::Delimiter>) -> OpDelimitedIter<'a> { - OpDelimitedIter { inner: &self.0, idx: 0, delimited } - } -} - -#[derive(Debug, Clone, Copy)] -enum OpDelimited<'a> { - Op(&'a Op), - Open, - Close, -} - -#[derive(Debug, Clone, Copy)] -struct OpDelimitedIter<'a> { - inner: &'a [Op], - delimited: Option<&'a tt::Delimiter>, - idx: usize, -} - -impl<'a> OpDelimitedIter<'a> { - fn is_eof(&self) -> bool { - let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 }; - self.idx >= len - } - - fn peek(&self) -> Option> { - match self.delimited { - None => self.inner.get(self.idx).map(OpDelimited::Op), - Some(_) => match self.idx { - 0 => Some(OpDelimited::Open), - i if i == self.inner.len() + 1 => Some(OpDelimited::Close), - i => self.inner.get(i - 1).map(OpDelimited::Op), - }, - } - } - - fn reset(&self) -> Self { - Self { inner: self.inner, idx: 0, delimited: self.delimited } - } -} - -impl<'a> Iterator for OpDelimitedIter<'a> { - type Item = OpDelimited<'a>; - - fn next(&mut self) -> Option { - let res = self.peek(); - self.idx += 1; - res - } - - fn size_hint(&self) -> (usize, Option) { - let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 }; - let remain = len.saturating_sub(self.idx); - (remain, Some(remain)) - } -} - -impl<'a> TtIter<'a> { - fn expect_separator(&mut self, separator: &Separator, idx: usize) -> bool { - let mut fork = self.clone(); - let ok = match separator { - Separator::Ident(lhs) if idx == 0 => match fork.expect_ident_or_underscore() { - Ok(rhs) => rhs.text == lhs.text, - Err(_) => false, - }, - Separator::Literal(lhs) if idx == 0 => match fork.expect_literal() { - Ok(rhs) => match rhs { - tt::Leaf::Literal(rhs) => rhs.text == lhs.text, - tt::Leaf::Ident(rhs) => rhs.text == lhs.text, - tt::Leaf::Punct(_) => false, - }, - Err(_) => false, - }, - Separator::Puncts(lhss) if idx < lhss.len() => match fork.expect_punct() { - Ok(rhs) => rhs.char == lhss[idx].char, - Err(_) => false, - }, - _ => false, - }; - if ok { - *self = fork; - } - ok - } - - fn expect_tt(&mut self) -> Result { - match self.peek_n(0) { - Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) if punct.char == '\'' => { - return self.expect_lifetime(); - } - _ => (), - } - - let tt = self.next().ok_or(())?.clone(); - let punct = match tt { - tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if punct.spacing == tt::Spacing::Joint => { - punct - } - _ => return Ok(tt), - }; - - let (second, third) = match (self.peek_n(0), self.peek_n(1)) { - ( - Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p2))), - Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p3))), - ) if p2.spacing == tt::Spacing::Joint => (p2.char, Some(p3.char)), - (Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p2))), _) => (p2.char, None), - _ => return Ok(tt), - }; - - match (punct.char, second, third) { - ('.', '.', Some('.' | '=')) | ('<', '<', Some('=')) | ('>', '>', Some('=')) => { - let tt2 = self.next().unwrap().clone(); - let tt3 = self.next().unwrap().clone(); - Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2, tt3] }.into()) - } - ('-' | '!' | '*' | '/' | '&' | '%' | '^' | '+' | '<' | '=' | '>' | '|', '=', _) - | ('-' | '=' | '>', '>', _) - | (':', ':', _) - | ('.', '.', _) - | ('&', '&', _) - | ('<', '<', _) - | ('|', '|', _) => { - let tt2 = self.next().unwrap().clone(); - Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2] }.into()) - } - _ => Ok(tt), - } - } - - fn expect_lifetime(&mut self) -> Result { - let punct = self.expect_punct()?; - if punct.char != '\'' { - return Err(()); - } - let ident = self.expect_ident_or_underscore()?; - - Ok(tt::Subtree { - delimiter: None, - token_trees: vec![ - tt::Leaf::Punct(*punct).into(), - tt::Leaf::Ident(ident.clone()).into(), - ], - } - .into()) - } - - fn eat_char(&mut self, c: char) -> Option { - let mut fork = self.clone(); - match fork.expect_char(c) { - Ok(_) => { - let tt = self.next().cloned(); - *self = fork; - tt - } - Err(_) => None, - } - } -} diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs deleted file mode 100644 index 7bcc84740f186..0000000000000 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs +++ /dev/null @@ -1,272 +0,0 @@ -//! Transcriber takes a template, like `fn $ident() {}`, a set of bindings like -//! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}` - -use syntax::SmolStr; -use tt::{Delimiter, Subtree}; - -use crate::{ - expander::{Binding, Bindings, Fragment}, - parser::{Op, RepeatKind, Separator}, - ExpandError, ExpandResult, MetaTemplate, -}; - -impl Bindings { - fn contains(&self, name: &str) -> bool { - self.inner.contains_key(name) - } - - fn get(&self, name: &str, nesting: &mut [NestingState]) -> Result<&Fragment, ExpandError> { - macro_rules! binding_err { - ($($arg:tt)*) => { ExpandError::binding_error(format!($($arg)*)) }; - } - - let mut b: &Binding = - self.inner.get(name).ok_or_else(|| binding_err!("could not find binding `{name}`"))?; - for nesting_state in nesting.iter_mut() { - nesting_state.hit = true; - b = match b { - Binding::Fragment(_) => break, - Binding::Nested(bs) => bs.get(nesting_state.idx).ok_or_else(|| { - nesting_state.at_end = true; - binding_err!("could not find nested binding `{name}`") - })?, - Binding::Empty => { - nesting_state.at_end = true; - return Err(binding_err!("could not find empty binding `{name}`")); - } - }; - } - match b { - Binding::Fragment(it) => Ok(it), - Binding::Nested(_) => { - Err(binding_err!("expected simple binding, found nested binding `{name}`")) - } - Binding::Empty => { - Err(binding_err!("expected simple binding, found empty binding `{name}`")) - } - } - } -} - -pub(super) fn transcribe( - template: &MetaTemplate, - bindings: &Bindings, -) -> ExpandResult { - let mut ctx = ExpandCtx { bindings, nesting: Vec::new() }; - let mut arena: Vec = Vec::new(); - expand_subtree(&mut ctx, template, None, &mut arena) -} - -#[derive(Debug)] -struct NestingState { - idx: usize, - /// `hit` is currently necessary to tell `expand_repeat` if it should stop - /// because there is no variable in use by the current repetition - hit: bool, - /// `at_end` is currently necessary to tell `expand_repeat` if it should stop - /// because there is no more value available for the current repetition - at_end: bool, -} - -#[derive(Debug)] -struct ExpandCtx<'a> { - bindings: &'a Bindings, - nesting: Vec, -} - -fn expand_subtree( - ctx: &mut ExpandCtx<'_>, - template: &MetaTemplate, - delimiter: Option, - arena: &mut Vec, -) -> ExpandResult { - // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation - let start_elements = arena.len(); - let mut err = None; - for op in template.iter() { - match op { - Op::Leaf(tt) => arena.push(tt.clone().into()), - Op::Subtree { tokens, delimiter } => { - let ExpandResult { value: tt, err: e } = - expand_subtree(ctx, tokens, *delimiter, arena); - err = err.or(e); - arena.push(tt.into()); - } - Op::Var { name, id, .. } => { - let ExpandResult { value: fragment, err: e } = expand_var(ctx, name, *id); - err = err.or(e); - push_fragment(arena, fragment); - } - Op::Repeat { tokens: subtree, kind, separator } => { - let ExpandResult { value: fragment, err: e } = - expand_repeat(ctx, subtree, *kind, separator, arena); - err = err.or(e); - push_fragment(arena, fragment) - } - Op::Ignore { name, id } => { - // Expand the variable, but ignore the result. This registers the repetition count. - expand_var(ctx, name, *id); - } - Op::Index { depth } => { - let index = ctx - .nesting - .get(ctx.nesting.len() - 1 - (*depth as usize)) - .map_or(0, |nest| nest.idx); - arena.push( - tt::Leaf::Literal(tt::Literal { - text: index.to_string().into(), - id: tt::TokenId::unspecified(), - }) - .into(), - ); - } - } - } - // drain the elements added in this instance of expand_subtree - let tts = arena.drain(start_elements..).collect(); - ExpandResult { value: tt::Subtree { delimiter, token_trees: tts }, err } -} - -fn expand_var(ctx: &mut ExpandCtx<'_>, v: &SmolStr, id: tt::TokenId) -> ExpandResult { - // We already handle $crate case in mbe parser - debug_assert!(v != "crate"); - - if !ctx.bindings.contains(v) { - // Note that it is possible to have a `$var` inside a macro which is not bound. - // For example: - // ``` - // macro_rules! foo { - // ($a:ident, $b:ident, $c:tt) => { - // macro_rules! bar { - // ($bi:ident) => { - // fn $bi() -> u8 {$c} - // } - // } - // } - // ``` - // We just treat it a normal tokens - let tt = tt::Subtree { - delimiter: None, - token_trees: vec![ - tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, id }).into(), - tt::Leaf::from(tt::Ident { text: v.clone(), id }).into(), - ], - } - .into(); - ExpandResult::ok(Fragment::Tokens(tt)) - } else { - ctx.bindings.get(v, &mut ctx.nesting).map_or_else( - |e| ExpandResult { value: Fragment::Tokens(tt::TokenTree::empty()), err: Some(e) }, - |b| ExpandResult::ok(b.clone()), - ) - } -} - -fn expand_repeat( - ctx: &mut ExpandCtx<'_>, - template: &MetaTemplate, - kind: RepeatKind, - separator: &Option, - arena: &mut Vec, -) -> ExpandResult { - let mut buf: Vec = Vec::new(); - ctx.nesting.push(NestingState { idx: 0, at_end: false, hit: false }); - // Dirty hack to make macro-expansion terminate. - // This should be replaced by a proper macro-by-example implementation - let limit = 65536; - let mut has_seps = 0; - let mut counter = 0; - - loop { - let ExpandResult { value: mut t, err: e } = expand_subtree(ctx, template, None, arena); - let nesting_state = ctx.nesting.last_mut().unwrap(); - if nesting_state.at_end || !nesting_state.hit { - break; - } - nesting_state.idx += 1; - nesting_state.hit = false; - - counter += 1; - if counter == limit { - tracing::warn!( - "expand_tt in repeat pattern exceed limit => {:#?}\n{:#?}", - template, - ctx - ); - return ExpandResult { - value: Fragment::Tokens(Subtree::default().into()), - err: Some(ExpandError::LimitExceeded), - }; - } - - if e.is_some() { - continue; - } - - t.delimiter = None; - push_subtree(&mut buf, t); - - if let Some(sep) = separator { - has_seps = match sep { - Separator::Ident(ident) => { - buf.push(tt::Leaf::from(ident.clone()).into()); - 1 - } - Separator::Literal(lit) => { - buf.push(tt::Leaf::from(lit.clone()).into()); - 1 - } - Separator::Puncts(puncts) => { - for &punct in puncts { - buf.push(tt::Leaf::from(punct).into()); - } - puncts.len() - } - }; - } - - if RepeatKind::ZeroOrOne == kind { - break; - } - } - - ctx.nesting.pop().unwrap(); - for _ in 0..has_seps { - buf.pop(); - } - - // Check if it is a single token subtree without any delimiter - // e.g {Delimiter:None> ['>'] /Delimiter:None>} - let tt = tt::Subtree { delimiter: None, token_trees: buf }.into(); - - if RepeatKind::OneOrMore == kind && counter == 0 { - return ExpandResult { - value: Fragment::Tokens(tt), - err: Some(ExpandError::UnexpectedToken), - }; - } - ExpandResult::ok(Fragment::Tokens(tt)) -} - -fn push_fragment(buf: &mut Vec, fragment: Fragment) { - match fragment { - Fragment::Tokens(tt::TokenTree::Subtree(tt)) => push_subtree(buf, tt), - Fragment::Expr(tt::TokenTree::Subtree(mut tt)) => { - if tt.delimiter.is_none() { - tt.delimiter = Some(tt::Delimiter { - id: tt::TokenId::unspecified(), - kind: tt::DelimiterKind::Parenthesis, - }) - } - buf.push(tt.into()) - } - Fragment::Tokens(tt) | Fragment::Expr(tt) => buf.push(tt), - } -} - -fn push_subtree(buf: &mut Vec, tt: tt::Subtree) { - match tt.delimiter { - None => buf.extend(tt.token_trees), - Some(_) => buf.push(tt.into()), - } -} diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs deleted file mode 100644 index 79da84f4a0226..0000000000000 --- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs +++ /dev/null @@ -1,352 +0,0 @@ -//! `mbe` (short for Macro By Example) crate contains code for handling -//! `macro_rules` macros. It uses `TokenTree` (from `tt` package) as the -//! interface, although it contains some code to bridge `SyntaxNode`s and -//! `TokenTree`s as well! -//! -//! The tes for this functionality live in another crate: -//! `hir_def::macro_expansion_tests::mbe`. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -mod parser; -mod expander; -mod syntax_bridge; -mod tt_iter; -mod to_parser_input; - -#[cfg(test)] -mod benchmark; -mod token_map; - -use std::fmt; - -use crate::{ - parser::{MetaTemplate, Op}, - tt_iter::TtIter, -}; - -// FIXME: we probably should re-think `token_tree_to_syntax_node` interfaces -pub use ::parser::TopEntryPoint; -pub use tt::{Delimiter, DelimiterKind, Punct}; - -pub use crate::{ - syntax_bridge::{ - parse_exprs_with_sep, parse_to_token_tree, syntax_node_to_token_tree, - syntax_node_to_token_tree_with_modifications, token_tree_to_syntax_node, SyntheticToken, - SyntheticTokenId, - }, - token_map::TokenMap, -}; - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum ParseError { - UnexpectedToken(Box), - Expected(Box), - InvalidRepeat, - RepetitionEmptyTokenTree, -} - -impl ParseError { - fn expected(e: &str) -> ParseError { - ParseError::Expected(e.into()) - } - - fn unexpected(e: &str) -> ParseError { - ParseError::UnexpectedToken(e.into()) - } -} - -impl fmt::Display for ParseError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ParseError::UnexpectedToken(it) => f.write_str(it), - ParseError::Expected(it) => f.write_str(it), - ParseError::InvalidRepeat => f.write_str("invalid repeat"), - ParseError::RepetitionEmptyTokenTree => f.write_str("empty token tree in repetition"), - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum ExpandError { - BindingError(Box>), - LeftoverTokens, - ConversionError, - LimitExceeded, - NoMatchingRule, - UnexpectedToken, -} - -impl ExpandError { - fn binding_error(e: impl Into>) -> ExpandError { - ExpandError::BindingError(Box::new(e.into())) - } -} - -impl fmt::Display for ExpandError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ExpandError::NoMatchingRule => f.write_str("no rule matches input tokens"), - ExpandError::UnexpectedToken => f.write_str("unexpected token in input"), - ExpandError::BindingError(e) => f.write_str(e), - ExpandError::ConversionError => f.write_str("could not convert tokens"), - ExpandError::LimitExceeded => f.write_str("Expand exceed limit"), - ExpandError::LeftoverTokens => f.write_str("leftover tokens"), - } - } -} - -/// This struct contains AST for a single `macro_rules` definition. What might -/// be very confusing is that AST has almost exactly the same shape as -/// `tt::TokenTree`, but there's a crucial difference: in macro rules, `$ident` -/// and `$()*` have special meaning (see `Var` and `Repeat` data structures) -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct DeclarativeMacro { - rules: Vec, - /// Highest id of the token we have in TokenMap - shift: Shift, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -struct Rule { - lhs: MetaTemplate, - rhs: MetaTemplate, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct Shift(u32); - -impl Shift { - pub fn new(tt: &tt::Subtree) -> Shift { - // Note that TokenId is started from zero, - // We have to add 1 to prevent duplication. - let value = max_id(tt).map_or(0, |it| it + 1); - return Shift(value); - - // Find the max token id inside a subtree - fn max_id(subtree: &tt::Subtree) -> Option { - let filter = |tt: &_| match tt { - tt::TokenTree::Subtree(subtree) => { - let tree_id = max_id(subtree); - match subtree.delimiter { - Some(it) if it.id != tt::TokenId::unspecified() => { - Some(tree_id.map_or(it.id.0, |t| t.max(it.id.0))) - } - _ => tree_id, - } - } - tt::TokenTree::Leaf(leaf) => { - let &(tt::Leaf::Ident(tt::Ident { id, .. }) - | tt::Leaf::Punct(tt::Punct { id, .. }) - | tt::Leaf::Literal(tt::Literal { id, .. })) = leaf; - - (id != tt::TokenId::unspecified()).then(|| id.0) - } - }; - subtree.token_trees.iter().filter_map(filter).max() - } - } - - /// Shift given TokenTree token id - pub fn shift_all(self, tt: &mut tt::Subtree) { - for t in &mut tt.token_trees { - match t { - tt::TokenTree::Leaf( - tt::Leaf::Ident(tt::Ident { id, .. }) - | tt::Leaf::Punct(tt::Punct { id, .. }) - | tt::Leaf::Literal(tt::Literal { id, .. }), - ) => *id = self.shift(*id), - tt::TokenTree::Subtree(tt) => { - if let Some(it) = tt.delimiter.as_mut() { - it.id = self.shift(it.id); - } - self.shift_all(tt) - } - } - } - } - - pub fn shift(self, id: tt::TokenId) -> tt::TokenId { - if id == tt::TokenId::unspecified() { - id - } else { - tt::TokenId(id.0 + self.0) - } - } - - pub fn unshift(self, id: tt::TokenId) -> Option { - id.0.checked_sub(self.0).map(tt::TokenId) - } -} - -#[derive(Debug, Eq, PartialEq)] -pub enum Origin { - Def, - Call, -} - -impl DeclarativeMacro { - /// The old, `macro_rules! m {}` flavor. - pub fn parse_macro_rules(tt: &tt::Subtree) -> Result { - // Note: this parsing can be implemented using mbe machinery itself, by - // matching against `$($lhs:tt => $rhs:tt);*` pattern, but implementing - // manually seems easier. - let mut src = TtIter::new(tt); - let mut rules = Vec::new(); - while src.len() > 0 { - let rule = Rule::parse(&mut src, true)?; - rules.push(rule); - if let Err(()) = src.expect_char(';') { - if src.len() > 0 { - return Err(ParseError::expected("expected `;`")); - } - break; - } - } - - for Rule { lhs, .. } in &rules { - validate(lhs)?; - } - - Ok(DeclarativeMacro { rules, shift: Shift::new(tt) }) - } - - /// The new, unstable `macro m {}` flavor. - pub fn parse_macro2(tt: &tt::Subtree) -> Result { - let mut src = TtIter::new(tt); - let mut rules = Vec::new(); - - if Some(tt::DelimiterKind::Brace) == tt.delimiter_kind() { - cov_mark::hit!(parse_macro_def_rules); - while src.len() > 0 { - let rule = Rule::parse(&mut src, true)?; - rules.push(rule); - if let Err(()) = src.expect_any_char(&[';', ',']) { - if src.len() > 0 { - return Err(ParseError::expected("expected `;` or `,` to delimit rules")); - } - break; - } - } - } else { - cov_mark::hit!(parse_macro_def_simple); - let rule = Rule::parse(&mut src, false)?; - if src.len() != 0 { - return Err(ParseError::expected("remaining tokens in macro def")); - } - rules.push(rule); - } - - for Rule { lhs, .. } in &rules { - validate(lhs)?; - } - - Ok(DeclarativeMacro { rules, shift: Shift::new(tt) }) - } - - pub fn expand(&self, tt: &tt::Subtree) -> ExpandResult { - // apply shift - let mut tt = tt.clone(); - self.shift.shift_all(&mut tt); - expander::expand_rules(&self.rules, &tt) - } - - pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { - self.shift.shift(id) - } - - pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, Origin) { - match self.shift.unshift(id) { - Some(id) => (id, Origin::Call), - None => (id, Origin::Def), - } - } - - pub fn shift(&self) -> Shift { - self.shift - } -} - -impl Rule { - fn parse(src: &mut TtIter<'_>, expect_arrow: bool) -> Result { - let lhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?; - if expect_arrow { - src.expect_char('=').map_err(|()| ParseError::expected("expected `=`"))?; - src.expect_char('>').map_err(|()| ParseError::expected("expected `>`"))?; - } - let rhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?; - - let lhs = MetaTemplate::parse_pattern(lhs)?; - let rhs = MetaTemplate::parse_template(rhs)?; - - Ok(crate::Rule { lhs, rhs }) - } -} - -fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> { - for op in pattern.iter() { - match op { - Op::Subtree { tokens, .. } => validate(tokens)?, - Op::Repeat { tokens: subtree, separator, .. } => { - // Checks that no repetition which could match an empty token - // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558 - let lsh_is_empty_seq = separator.is_none() && subtree.iter().all(|child_op| { - match child_op { - // vis is optional - Op::Var { kind: Some(kind), .. } => kind == "vis", - Op::Repeat { - kind: parser::RepeatKind::ZeroOrMore | parser::RepeatKind::ZeroOrOne, - .. - } => true, - _ => false, - } - }); - if lsh_is_empty_seq { - return Err(ParseError::RepetitionEmptyTokenTree); - } - validate(subtree)? - } - _ => (), - } - } - Ok(()) -} - -pub type ExpandResult = ValueResult; - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct ValueResult { - pub value: T, - pub err: Option, -} - -impl ValueResult { - pub fn ok(value: T) -> Self { - Self { value, err: None } - } - - pub fn only_err(err: E) -> Self - where - T: Default, - { - Self { value: Default::default(), err: Some(err) } - } - - pub fn map(self, f: impl FnOnce(T) -> U) -> ValueResult { - ValueResult { value: f(self.value), err: self.err } - } - - pub fn map_err(self, f: impl FnOnce(E) -> E2) -> ValueResult { - ValueResult { value: self.value, err: self.err.map(f) } - } - - pub fn result(self) -> Result { - self.err.map_or(Ok(self.value), Err) - } -} - -impl From> for ValueResult { - fn from(result: Result) -> Self { - result.map_or_else(Self::only_err, Self::ok) - } -} diff --git a/src/tools/rust-analyzer/crates/mbe/src/parser.rs b/src/tools/rust-analyzer/crates/mbe/src/parser.rs deleted file mode 100644 index acb4be5846de1..0000000000000 --- a/src/tools/rust-analyzer/crates/mbe/src/parser.rs +++ /dev/null @@ -1,261 +0,0 @@ -//! Parser recognizes special macro syntax, `$var` and `$(repeat)*`, in token -//! trees. - -use smallvec::SmallVec; -use syntax::SmolStr; - -use crate::{tt_iter::TtIter, ParseError}; - -/// Consider -/// -/// ``` -/// macro_rules! an_macro { -/// ($x:expr + $y:expr) => ($y * $x) -/// } -/// ``` -/// -/// Stuff to the left of `=>` is a [`MetaTemplate`] pattern (which is matched -/// with input). -/// -/// Stuff to the right is a [`MetaTemplate`] template which is used to produce -/// output. -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct MetaTemplate(pub(crate) Vec); - -impl MetaTemplate { - pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Result { - MetaTemplate::parse(pattern, Mode::Pattern) - } - - pub(crate) fn parse_template(template: &tt::Subtree) -> Result { - MetaTemplate::parse(template, Mode::Template) - } - - pub(crate) fn iter(&self) -> impl Iterator { - self.0.iter() - } - - fn parse(tt: &tt::Subtree, mode: Mode) -> Result { - let mut src = TtIter::new(tt); - - let mut res = Vec::new(); - while let Some(first) = src.next() { - let op = next_op(first, &mut src, mode)?; - res.push(op); - } - - Ok(MetaTemplate(res)) - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) enum Op { - Var { name: SmolStr, kind: Option, id: tt::TokenId }, - Ignore { name: SmolStr, id: tt::TokenId }, - Index { depth: u32 }, - Repeat { tokens: MetaTemplate, kind: RepeatKind, separator: Option }, - Leaf(tt::Leaf), - Subtree { tokens: MetaTemplate, delimiter: Option }, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub(crate) enum RepeatKind { - ZeroOrMore, - OneOrMore, - ZeroOrOne, -} - -#[derive(Clone, Debug, Eq)] -pub(crate) enum Separator { - Literal(tt::Literal), - Ident(tt::Ident), - Puncts(SmallVec<[tt::Punct; 3]>), -} - -// Note that when we compare a Separator, we just care about its textual value. -impl PartialEq for Separator { - fn eq(&self, other: &Separator) -> bool { - use Separator::*; - - match (self, other) { - (Ident(a), Ident(b)) => a.text == b.text, - (Literal(a), Literal(b)) => a.text == b.text, - (Puncts(a), Puncts(b)) if a.len() == b.len() => { - let a_iter = a.iter().map(|a| a.char); - let b_iter = b.iter().map(|b| b.char); - a_iter.eq(b_iter) - } - _ => false, - } - } -} - -impl Separator { - pub(crate) fn tt_count(&self) -> usize { - match self { - Separator::Literal(_) => 1, - Separator::Ident(_) => 1, - Separator::Puncts(it) => it.len(), - } - } -} - -#[derive(Clone, Copy)] -enum Mode { - Pattern, - Template, -} - -fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Result { - let res = match first { - tt::TokenTree::Leaf(leaf @ tt::Leaf::Punct(tt::Punct { char: '$', .. })) => { - // Note that the '$' itself is a valid token inside macro_rules. - let second = match src.next() { - None => return Ok(Op::Leaf(leaf.clone())), - Some(it) => it, - }; - match second { - tt::TokenTree::Subtree(subtree) => match subtree.delimiter_kind() { - Some(tt::DelimiterKind::Parenthesis) => { - let (separator, kind) = parse_repeat(src)?; - let tokens = MetaTemplate::parse(subtree, mode)?; - Op::Repeat { tokens, separator, kind } - } - Some(tt::DelimiterKind::Brace) => match mode { - Mode::Template => { - parse_metavar_expr(&mut TtIter::new(subtree)).map_err(|()| { - ParseError::unexpected("invalid metavariable expression") - })? - } - Mode::Pattern => { - return Err(ParseError::unexpected( - "`${}` metavariable expressions are not allowed in matchers", - )) - } - }, - _ => { - return Err(ParseError::expected( - "expected `$()` repetition or `${}` expression", - )) - } - }, - tt::TokenTree::Leaf(leaf) => match leaf { - tt::Leaf::Ident(ident) if ident.text == "crate" => { - // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. - Op::Leaf(tt::Leaf::from(tt::Ident { text: "$crate".into(), id: ident.id })) - } - tt::Leaf::Ident(ident) => { - let kind = eat_fragment_kind(src, mode)?; - let name = ident.text.clone(); - let id = ident.id; - Op::Var { name, kind, id } - } - tt::Leaf::Literal(lit) if is_boolean_literal(lit) => { - let kind = eat_fragment_kind(src, mode)?; - let name = lit.text.clone(); - let id = lit.id; - Op::Var { name, kind, id } - } - tt::Leaf::Punct(punct @ tt::Punct { char: '$', .. }) => match mode { - Mode::Pattern => { - return Err(ParseError::unexpected( - "`$$` is not allowed on the pattern side", - )) - } - Mode::Template => Op::Leaf(tt::Leaf::Punct(*punct)), - }, - tt::Leaf::Punct(_) | tt::Leaf::Literal(_) => { - return Err(ParseError::expected("expected ident")) - } - }, - } - } - tt::TokenTree::Leaf(tt) => Op::Leaf(tt.clone()), - tt::TokenTree::Subtree(subtree) => { - let tokens = MetaTemplate::parse(subtree, mode)?; - Op::Subtree { tokens, delimiter: subtree.delimiter } - } - }; - Ok(res) -} - -fn eat_fragment_kind(src: &mut TtIter<'_>, mode: Mode) -> Result, ParseError> { - if let Mode::Pattern = mode { - src.expect_char(':').map_err(|()| ParseError::unexpected("missing fragment specifier"))?; - let ident = src - .expect_ident() - .map_err(|()| ParseError::unexpected("missing fragment specifier"))?; - return Ok(Some(ident.text.clone())); - }; - Ok(None) -} - -fn is_boolean_literal(lit: &tt::Literal) -> bool { - matches!(lit.text.as_str(), "true" | "false") -} - -fn parse_repeat(src: &mut TtIter<'_>) -> Result<(Option, RepeatKind), ParseError> { - let mut separator = Separator::Puncts(SmallVec::new()); - for tt in src { - let tt = match tt { - tt::TokenTree::Leaf(leaf) => leaf, - tt::TokenTree::Subtree(_) => return Err(ParseError::InvalidRepeat), - }; - let has_sep = match &separator { - Separator::Puncts(puncts) => !puncts.is_empty(), - _ => true, - }; - match tt { - tt::Leaf::Ident(_) | tt::Leaf::Literal(_) if has_sep => { - return Err(ParseError::InvalidRepeat) - } - tt::Leaf::Ident(ident) => separator = Separator::Ident(ident.clone()), - tt::Leaf::Literal(lit) => separator = Separator::Literal(lit.clone()), - tt::Leaf::Punct(punct) => { - let repeat_kind = match punct.char { - '*' => RepeatKind::ZeroOrMore, - '+' => RepeatKind::OneOrMore, - '?' => RepeatKind::ZeroOrOne, - _ => match &mut separator { - Separator::Puncts(puncts) if puncts.len() != 3 => { - puncts.push(*punct); - continue; - } - _ => return Err(ParseError::InvalidRepeat), - }, - }; - return Ok((has_sep.then(|| separator), repeat_kind)); - } - } - } - Err(ParseError::InvalidRepeat) -} - -fn parse_metavar_expr(src: &mut TtIter<'_>) -> Result { - let func = src.expect_ident()?; - let args = src.expect_subtree()?; - - if args.delimiter_kind() != Some(tt::DelimiterKind::Parenthesis) { - return Err(()); - } - - let mut args = TtIter::new(args); - - let op = match &*func.text { - "ignore" => { - let ident = args.expect_ident()?; - Op::Ignore { name: ident.text.clone(), id: ident.id } - } - "index" => { - let depth = if args.len() == 0 { 0 } else { args.expect_u32_literal()? }; - Op::Index { depth } - } - _ => return Err(()), - }; - - if args.next().is_some() { - return Err(()); - } - - Ok(op) -} diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs deleted file mode 100644 index aca6ecd424e40..0000000000000 --- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs +++ /dev/null @@ -1,844 +0,0 @@ -//! Conversions between [`SyntaxNode`] and [`tt::TokenTree`]. - -use rustc_hash::FxHashMap; -use stdx::{always, non_empty_vec::NonEmptyVec}; -use syntax::{ - ast::{self, make::tokens::doc_comment}, - AstToken, Parse, PreorderWithTokens, SmolStr, SyntaxElement, SyntaxKind, - SyntaxKind::*, - SyntaxNode, SyntaxToken, SyntaxTreeBuilder, TextRange, TextSize, WalkEvent, T, -}; -use tt::buffer::{Cursor, TokenBuffer}; - -use crate::{to_parser_input::to_parser_input, tt_iter::TtIter, TokenMap}; - -/// Convert the syntax node to a `TokenTree` (what macro -/// will consume). -pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> (tt::Subtree, TokenMap) { - let (subtree, token_map, _) = syntax_node_to_token_tree_with_modifications( - node, - Default::default(), - 0, - Default::default(), - Default::default(), - ); - (subtree, token_map) -} - -/// Convert the syntax node to a `TokenTree` (what macro will consume) -/// with the censored range excluded. -pub fn syntax_node_to_token_tree_with_modifications( - node: &SyntaxNode, - existing_token_map: TokenMap, - next_id: u32, - replace: FxHashMap>, - append: FxHashMap>, -) -> (tt::Subtree, TokenMap, u32) { - let global_offset = node.text_range().start(); - let mut c = Convertor::new(node, global_offset, existing_token_map, next_id, replace, append); - let subtree = convert_tokens(&mut c); - c.id_alloc.map.shrink_to_fit(); - always!(c.replace.is_empty(), "replace: {:?}", c.replace); - always!(c.append.is_empty(), "append: {:?}", c.append); - (subtree, c.id_alloc.map, c.id_alloc.next_id) -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SyntheticTokenId(pub u32); - -#[derive(Debug, Clone)] -pub struct SyntheticToken { - pub kind: SyntaxKind, - pub text: SmolStr, - pub range: TextRange, - pub id: SyntheticTokenId, -} - -// The following items are what `rustc` macro can be parsed into : -// link: https://github.com/rust-lang/rust/blob/9ebf47851a357faa4cd97f4b1dc7835f6376e639/src/libsyntax/ext/expand.rs#L141 -// * Expr(P) -> token_tree_to_expr -// * Pat(P) -> token_tree_to_pat -// * Ty(P) -> token_tree_to_ty -// * Stmts(SmallVec<[ast::Stmt; 1]>) -> token_tree_to_stmts -// * Items(SmallVec<[P; 1]>) -> token_tree_to_items -// -// * TraitItems(SmallVec<[ast::TraitItem; 1]>) -// * AssocItems(SmallVec<[ast::AssocItem; 1]>) -// * ForeignItems(SmallVec<[ast::ForeignItem; 1]> - -pub fn token_tree_to_syntax_node( - tt: &tt::Subtree, - entry_point: parser::TopEntryPoint, -) -> (Parse, TokenMap) { - let buffer = match tt { - tt::Subtree { delimiter: None, token_trees } => { - TokenBuffer::from_tokens(token_trees.as_slice()) - } - _ => TokenBuffer::from_subtree(tt), - }; - let parser_input = to_parser_input(&buffer); - let parser_output = entry_point.parse(&parser_input); - let mut tree_sink = TtTreeSink::new(buffer.begin()); - for event in parser_output.iter() { - match event { - parser::Step::Token { kind, n_input_tokens: n_raw_tokens } => { - tree_sink.token(kind, n_raw_tokens) - } - parser::Step::Enter { kind } => tree_sink.start_node(kind), - parser::Step::Exit => tree_sink.finish_node(), - parser::Step::Error { msg } => tree_sink.error(msg.to_string()), - } - } - let (parse, range_map) = tree_sink.finish(); - (parse, range_map) -} - -/// Convert a string to a `TokenTree` -pub fn parse_to_token_tree(text: &str) -> Option<(tt::Subtree, TokenMap)> { - let lexed = parser::LexedStr::new(text); - if lexed.errors().next().is_some() { - return None; - } - - let mut conv = RawConvertor { - lexed, - pos: 0, - id_alloc: TokenIdAlloc { - map: Default::default(), - global_offset: TextSize::default(), - next_id: 0, - }, - }; - - let subtree = convert_tokens(&mut conv); - Some((subtree, conv.id_alloc.map)) -} - -/// Split token tree with separate expr: $($e:expr)SEP* -pub fn parse_exprs_with_sep(tt: &tt::Subtree, sep: char) -> Vec { - if tt.token_trees.is_empty() { - return Vec::new(); - } - - let mut iter = TtIter::new(tt); - let mut res = Vec::new(); - - while iter.peek_n(0).is_some() { - let expanded = iter.expect_fragment(parser::PrefixEntryPoint::Expr); - - res.push(match expanded.value { - None => break, - Some(tt @ tt::TokenTree::Leaf(_)) => { - tt::Subtree { delimiter: None, token_trees: vec![tt] } - } - Some(tt::TokenTree::Subtree(tt)) => tt, - }); - - let mut fork = iter.clone(); - if fork.expect_char(sep).is_err() { - break; - } - iter = fork; - } - - if iter.peek_n(0).is_some() { - res.push(tt::Subtree { delimiter: None, token_trees: iter.into_iter().cloned().collect() }); - } - - res -} - -fn convert_tokens(conv: &mut C) -> tt::Subtree { - struct StackEntry { - subtree: tt::Subtree, - idx: usize, - open_range: TextRange, - } - - let entry = StackEntry { - subtree: tt::Subtree { delimiter: None, ..Default::default() }, - // never used (delimiter is `None`) - idx: !0, - open_range: TextRange::empty(TextSize::of('.')), - }; - let mut stack = NonEmptyVec::new(entry); - - loop { - let StackEntry { subtree, .. } = stack.last_mut(); - let result = &mut subtree.token_trees; - let (token, range) = match conv.bump() { - Some(it) => it, - None => break, - }; - let synth_id = token.synthetic_id(conv); - - let kind = token.kind(conv); - if kind == COMMENT { - if let Some(tokens) = conv.convert_doc_comment(&token) { - // FIXME: There has to be a better way to do this - // Add the comments token id to the converted doc string - let id = conv.id_alloc().alloc(range, synth_id); - result.extend(tokens.into_iter().map(|mut tt| { - if let tt::TokenTree::Subtree(sub) = &mut tt { - if let Some(tt::TokenTree::Leaf(tt::Leaf::Literal(lit))) = - sub.token_trees.get_mut(2) - { - lit.id = id - } - } - tt - })); - } - continue; - } - let tt = if kind.is_punct() && kind != UNDERSCORE { - if synth_id.is_none() { - assert_eq!(range.len(), TextSize::of('.')); - } - - if let Some(delim) = subtree.delimiter { - let expected = match delim.kind { - tt::DelimiterKind::Parenthesis => T![')'], - tt::DelimiterKind::Brace => T!['}'], - tt::DelimiterKind::Bracket => T![']'], - }; - - if kind == expected { - if let Some(entry) = stack.pop() { - conv.id_alloc().close_delim(entry.idx, Some(range)); - stack.last_mut().subtree.token_trees.push(entry.subtree.into()); - } - continue; - } - } - - let delim = match kind { - T!['('] => Some(tt::DelimiterKind::Parenthesis), - T!['{'] => Some(tt::DelimiterKind::Brace), - T!['['] => Some(tt::DelimiterKind::Bracket), - _ => None, - }; - - if let Some(kind) = delim { - let mut subtree = tt::Subtree::default(); - let (id, idx) = conv.id_alloc().open_delim(range, synth_id); - subtree.delimiter = Some(tt::Delimiter { id, kind }); - stack.push(StackEntry { subtree, idx, open_range: range }); - continue; - } - - let spacing = match conv.peek().map(|next| next.kind(conv)) { - Some(kind) - if !kind.is_trivia() - && kind.is_punct() - && kind != T!['['] - && kind != T!['{'] - && kind != T!['('] - && kind != UNDERSCORE => - { - tt::Spacing::Joint - } - _ => tt::Spacing::Alone, - }; - let char = match token.to_char(conv) { - Some(c) => c, - None => { - panic!("Token from lexer must be single char: token = {:#?}", token); - } - }; - tt::Leaf::from(tt::Punct { char, spacing, id: conv.id_alloc().alloc(range, synth_id) }) - .into() - } else { - macro_rules! make_leaf { - ($i:ident) => { - tt::$i { id: conv.id_alloc().alloc(range, synth_id), text: token.to_text(conv) } - .into() - }; - } - let leaf: tt::Leaf = match kind { - T![true] | T![false] => make_leaf!(Ident), - IDENT => make_leaf!(Ident), - UNDERSCORE => make_leaf!(Ident), - k if k.is_keyword() => make_leaf!(Ident), - k if k.is_literal() => make_leaf!(Literal), - LIFETIME_IDENT => { - let char_unit = TextSize::of('\''); - let r = TextRange::at(range.start(), char_unit); - let apostrophe = tt::Leaf::from(tt::Punct { - char: '\'', - spacing: tt::Spacing::Joint, - id: conv.id_alloc().alloc(r, synth_id), - }); - result.push(apostrophe.into()); - - let r = TextRange::at(range.start() + char_unit, range.len() - char_unit); - let ident = tt::Leaf::from(tt::Ident { - text: SmolStr::new(&token.to_text(conv)[1..]), - id: conv.id_alloc().alloc(r, synth_id), - }); - result.push(ident.into()); - continue; - } - _ => continue, - }; - - leaf.into() - }; - result.push(tt); - } - - // If we get here, we've consumed all input tokens. - // We might have more than one subtree in the stack, if the delimiters are improperly balanced. - // Merge them so we're left with one. - while let Some(entry) = stack.pop() { - let parent = stack.last_mut(); - - conv.id_alloc().close_delim(entry.idx, None); - let leaf: tt::Leaf = tt::Punct { - id: conv.id_alloc().alloc(entry.open_range, None), - char: match entry.subtree.delimiter.unwrap().kind { - tt::DelimiterKind::Parenthesis => '(', - tt::DelimiterKind::Brace => '{', - tt::DelimiterKind::Bracket => '[', - }, - spacing: tt::Spacing::Alone, - } - .into(); - parent.subtree.token_trees.push(leaf.into()); - parent.subtree.token_trees.extend(entry.subtree.token_trees); - } - - let subtree = stack.into_last().subtree; - if let [tt::TokenTree::Subtree(first)] = &*subtree.token_trees { - first.clone() - } else { - subtree - } -} - -/// Returns the textual content of a doc comment block as a quoted string -/// That is, strips leading `///` (or `/**`, etc) -/// and strips the ending `*/` -/// And then quote the string, which is needed to convert to `tt::Literal` -fn doc_comment_text(comment: &ast::Comment) -> SmolStr { - let prefix_len = comment.prefix().len(); - let mut text = &comment.text()[prefix_len..]; - - // Remove ending "*/" - if comment.kind().shape == ast::CommentShape::Block { - text = &text[0..text.len() - 2]; - } - - // Quote the string - // Note that `tt::Literal` expect an escaped string - let text = format!("\"{}\"", text.escape_debug()); - text.into() -} - -fn convert_doc_comment(token: &syntax::SyntaxToken) -> Option> { - cov_mark::hit!(test_meta_doc_comments); - let comment = ast::Comment::cast(token.clone())?; - let doc = comment.kind().doc?; - - // Make `doc="\" Comments\"" - let meta_tkns = vec![mk_ident("doc"), mk_punct('='), mk_doc_literal(&comment)]; - - // Make `#![]` - let mut token_trees = Vec::with_capacity(3); - token_trees.push(mk_punct('#')); - if let ast::CommentPlacement::Inner = doc { - token_trees.push(mk_punct('!')); - } - token_trees.push(tt::TokenTree::from(tt::Subtree { - delimiter: Some(tt::Delimiter { - kind: tt::DelimiterKind::Bracket, - id: tt::TokenId::unspecified(), - }), - token_trees: meta_tkns, - })); - - return Some(token_trees); - - // Helper functions - fn mk_ident(s: &str) -> tt::TokenTree { - tt::TokenTree::from(tt::Leaf::from(tt::Ident { - text: s.into(), - id: tt::TokenId::unspecified(), - })) - } - - fn mk_punct(c: char) -> tt::TokenTree { - tt::TokenTree::from(tt::Leaf::from(tt::Punct { - char: c, - spacing: tt::Spacing::Alone, - id: tt::TokenId::unspecified(), - })) - } - - fn mk_doc_literal(comment: &ast::Comment) -> tt::TokenTree { - let lit = tt::Literal { text: doc_comment_text(comment), id: tt::TokenId::unspecified() }; - - tt::TokenTree::from(tt::Leaf::from(lit)) - } -} - -struct TokenIdAlloc { - map: TokenMap, - global_offset: TextSize, - next_id: u32, -} - -impl TokenIdAlloc { - fn alloc( - &mut self, - absolute_range: TextRange, - synthetic_id: Option, - ) -> tt::TokenId { - let relative_range = absolute_range - self.global_offset; - let token_id = tt::TokenId(self.next_id); - self.next_id += 1; - self.map.insert(token_id, relative_range); - if let Some(id) = synthetic_id { - self.map.insert_synthetic(token_id, id); - } - token_id - } - - fn open_delim( - &mut self, - open_abs_range: TextRange, - synthetic_id: Option, - ) -> (tt::TokenId, usize) { - let token_id = tt::TokenId(self.next_id); - self.next_id += 1; - let idx = self.map.insert_delim( - token_id, - open_abs_range - self.global_offset, - open_abs_range - self.global_offset, - ); - if let Some(id) = synthetic_id { - self.map.insert_synthetic(token_id, id); - } - (token_id, idx) - } - - fn close_delim(&mut self, idx: usize, close_abs_range: Option) { - match close_abs_range { - None => { - self.map.remove_delim(idx); - } - Some(close) => { - self.map.update_close_delim(idx, close - self.global_offset); - } - } - } -} - -/// A raw token (straight from lexer) convertor -struct RawConvertor<'a> { - lexed: parser::LexedStr<'a>, - pos: usize, - id_alloc: TokenIdAlloc, -} - -trait SrcToken: std::fmt::Debug { - fn kind(&self, ctx: &Ctx) -> SyntaxKind; - - fn to_char(&self, ctx: &Ctx) -> Option; - - fn to_text(&self, ctx: &Ctx) -> SmolStr; - - fn synthetic_id(&self, ctx: &Ctx) -> Option; -} - -trait TokenConvertor: Sized { - type Token: SrcToken; - - fn convert_doc_comment(&self, token: &Self::Token) -> Option>; - - fn bump(&mut self) -> Option<(Self::Token, TextRange)>; - - fn peek(&self) -> Option; - - fn id_alloc(&mut self) -> &mut TokenIdAlloc; -} - -impl<'a> SrcToken> for usize { - fn kind(&self, ctx: &RawConvertor<'a>) -> SyntaxKind { - ctx.lexed.kind(*self) - } - - fn to_char(&self, ctx: &RawConvertor<'a>) -> Option { - ctx.lexed.text(*self).chars().next() - } - - fn to_text(&self, ctx: &RawConvertor<'_>) -> SmolStr { - ctx.lexed.text(*self).into() - } - - fn synthetic_id(&self, _ctx: &RawConvertor<'a>) -> Option { - None - } -} - -impl<'a> TokenConvertor for RawConvertor<'a> { - type Token = usize; - - fn convert_doc_comment(&self, &token: &usize) -> Option> { - let text = self.lexed.text(token); - convert_doc_comment(&doc_comment(text)) - } - - fn bump(&mut self) -> Option<(Self::Token, TextRange)> { - if self.pos == self.lexed.len() { - return None; - } - let token = self.pos; - self.pos += 1; - let range = self.lexed.text_range(token); - let range = TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap()); - - Some((token, range)) - } - - fn peek(&self) -> Option { - if self.pos == self.lexed.len() { - return None; - } - Some(self.pos) - } - - fn id_alloc(&mut self) -> &mut TokenIdAlloc { - &mut self.id_alloc - } -} - -struct Convertor { - id_alloc: TokenIdAlloc, - current: Option, - current_synthetic: Vec, - preorder: PreorderWithTokens, - replace: FxHashMap>, - append: FxHashMap>, - range: TextRange, - punct_offset: Option<(SyntaxToken, TextSize)>, -} - -impl Convertor { - fn new( - node: &SyntaxNode, - global_offset: TextSize, - existing_token_map: TokenMap, - next_id: u32, - mut replace: FxHashMap>, - mut append: FxHashMap>, - ) -> Convertor { - let range = node.text_range(); - let mut preorder = node.preorder_with_tokens(); - let (first, synthetic) = Self::next_token(&mut preorder, &mut replace, &mut append); - Convertor { - id_alloc: { TokenIdAlloc { map: existing_token_map, global_offset, next_id } }, - current: first, - current_synthetic: synthetic, - preorder, - range, - replace, - append, - punct_offset: None, - } - } - - fn next_token( - preorder: &mut PreorderWithTokens, - replace: &mut FxHashMap>, - append: &mut FxHashMap>, - ) -> (Option, Vec) { - while let Some(ev) = preorder.next() { - let ele = match ev { - WalkEvent::Enter(ele) => ele, - WalkEvent::Leave(ele) => { - if let Some(mut v) = append.remove(&ele) { - if !v.is_empty() { - v.reverse(); - return (None, v); - } - } - continue; - } - }; - if let Some(mut v) = replace.remove(&ele) { - preorder.skip_subtree(); - if !v.is_empty() { - v.reverse(); - return (None, v); - } - } - match ele { - SyntaxElement::Token(t) => return (Some(t), Vec::new()), - _ => {} - } - } - (None, Vec::new()) - } -} - -#[derive(Debug)] -enum SynToken { - Ordinary(SyntaxToken), - // FIXME is this supposed to be `Punct`? - Punch(SyntaxToken, TextSize), - Synthetic(SyntheticToken), -} - -impl SynToken { - fn token(&self) -> Option<&SyntaxToken> { - match self { - SynToken::Ordinary(it) | SynToken::Punch(it, _) => Some(it), - SynToken::Synthetic(_) => None, - } - } -} - -impl SrcToken for SynToken { - fn kind(&self, _ctx: &Convertor) -> SyntaxKind { - match self { - SynToken::Ordinary(token) => token.kind(), - SynToken::Punch(token, _) => token.kind(), - SynToken::Synthetic(token) => token.kind, - } - } - fn to_char(&self, _ctx: &Convertor) -> Option { - match self { - SynToken::Ordinary(_) => None, - SynToken::Punch(it, i) => it.text().chars().nth((*i).into()), - SynToken::Synthetic(token) if token.text.len() == 1 => token.text.chars().next(), - SynToken::Synthetic(_) => None, - } - } - fn to_text(&self, _ctx: &Convertor) -> SmolStr { - match self { - SynToken::Ordinary(token) => token.text().into(), - SynToken::Punch(token, _) => token.text().into(), - SynToken::Synthetic(token) => token.text.clone(), - } - } - - fn synthetic_id(&self, _ctx: &Convertor) -> Option { - match self { - SynToken::Synthetic(token) => Some(token.id), - _ => None, - } - } -} - -impl TokenConvertor for Convertor { - type Token = SynToken; - fn convert_doc_comment(&self, token: &Self::Token) -> Option> { - convert_doc_comment(token.token()?) - } - - fn bump(&mut self) -> Option<(Self::Token, TextRange)> { - if let Some((punct, offset)) = self.punct_offset.clone() { - if usize::from(offset) + 1 < punct.text().len() { - let offset = offset + TextSize::of('.'); - let range = punct.text_range(); - self.punct_offset = Some((punct.clone(), offset)); - let range = TextRange::at(range.start() + offset, TextSize::of('.')); - return Some((SynToken::Punch(punct, offset), range)); - } - } - - if let Some(synth_token) = self.current_synthetic.pop() { - if self.current_synthetic.is_empty() { - let (new_current, new_synth) = - Self::next_token(&mut self.preorder, &mut self.replace, &mut self.append); - self.current = new_current; - self.current_synthetic = new_synth; - } - let range = synth_token.range; - return Some((SynToken::Synthetic(synth_token), range)); - } - - let curr = self.current.clone()?; - if !&self.range.contains_range(curr.text_range()) { - return None; - } - let (new_current, new_synth) = - Self::next_token(&mut self.preorder, &mut self.replace, &mut self.append); - self.current = new_current; - self.current_synthetic = new_synth; - let token = if curr.kind().is_punct() { - self.punct_offset = Some((curr.clone(), 0.into())); - let range = curr.text_range(); - let range = TextRange::at(range.start(), TextSize::of('.')); - (SynToken::Punch(curr, 0.into()), range) - } else { - self.punct_offset = None; - let range = curr.text_range(); - (SynToken::Ordinary(curr), range) - }; - - Some(token) - } - - fn peek(&self) -> Option { - if let Some((punct, mut offset)) = self.punct_offset.clone() { - offset += TextSize::of('.'); - if usize::from(offset) < punct.text().len() { - return Some(SynToken::Punch(punct, offset)); - } - } - - if let Some(synth_token) = self.current_synthetic.last() { - return Some(SynToken::Synthetic(synth_token.clone())); - } - - let curr = self.current.clone()?; - if !self.range.contains_range(curr.text_range()) { - return None; - } - - let token = if curr.kind().is_punct() { - SynToken::Punch(curr, 0.into()) - } else { - SynToken::Ordinary(curr) - }; - Some(token) - } - - fn id_alloc(&mut self) -> &mut TokenIdAlloc { - &mut self.id_alloc - } -} - -struct TtTreeSink<'a> { - buf: String, - cursor: Cursor<'a>, - open_delims: FxHashMap, - text_pos: TextSize, - inner: SyntaxTreeBuilder, - token_map: TokenMap, -} - -impl<'a> TtTreeSink<'a> { - fn new(cursor: Cursor<'a>) -> Self { - TtTreeSink { - buf: String::new(), - cursor, - open_delims: FxHashMap::default(), - text_pos: 0.into(), - inner: SyntaxTreeBuilder::default(), - token_map: TokenMap::default(), - } - } - - fn finish(mut self) -> (Parse, TokenMap) { - self.token_map.shrink_to_fit(); - (self.inner.finish(), self.token_map) - } -} - -fn delim_to_str(d: tt::DelimiterKind, closing: bool) -> &'static str { - let texts = match d { - tt::DelimiterKind::Parenthesis => "()", - tt::DelimiterKind::Brace => "{}", - tt::DelimiterKind::Bracket => "[]", - }; - - let idx = closing as usize; - &texts[idx..texts.len() - (1 - idx)] -} - -impl<'a> TtTreeSink<'a> { - fn token(&mut self, kind: SyntaxKind, mut n_tokens: u8) { - if kind == LIFETIME_IDENT { - n_tokens = 2; - } - - let mut last = self.cursor; - for _ in 0..n_tokens { - let tmp: u8; - if self.cursor.eof() { - break; - } - last = self.cursor; - let text: &str = loop { - break match self.cursor.token_tree() { - Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => { - // Mark the range if needed - let (text, id) = match leaf { - tt::Leaf::Ident(ident) => (ident.text.as_str(), ident.id), - tt::Leaf::Punct(punct) => { - assert!(punct.char.is_ascii()); - tmp = punct.char as u8; - (std::str::from_utf8(std::slice::from_ref(&tmp)).unwrap(), punct.id) - } - tt::Leaf::Literal(lit) => (lit.text.as_str(), lit.id), - }; - let range = TextRange::at(self.text_pos, TextSize::of(text)); - self.token_map.insert(id, range); - self.cursor = self.cursor.bump(); - text - } - Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => { - self.cursor = self.cursor.subtree().unwrap(); - match subtree.delimiter { - Some(d) => { - self.open_delims.insert(d.id, self.text_pos); - delim_to_str(d.kind, false) - } - None => continue, - } - } - None => { - let parent = self.cursor.end().unwrap(); - self.cursor = self.cursor.bump(); - match parent.delimiter { - Some(d) => { - if let Some(open_delim) = self.open_delims.get(&d.id) { - let open_range = TextRange::at(*open_delim, TextSize::of('(')); - let close_range = - TextRange::at(self.text_pos, TextSize::of('(')); - self.token_map.insert_delim(d.id, open_range, close_range); - } - delim_to_str(d.kind, true) - } - None => continue, - } - } - }; - }; - self.buf += text; - self.text_pos += TextSize::of(text); - } - - self.inner.token(kind, self.buf.as_str()); - self.buf.clear(); - // Add whitespace between adjoint puncts - let next = last.bump(); - if let ( - Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(curr), _)), - Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(_), _)), - ) = (last.token_tree(), next.token_tree()) - { - // Note: We always assume the semi-colon would be the last token in - // other parts of RA such that we don't add whitespace here. - if curr.spacing == tt::Spacing::Alone && curr.char != ';' { - self.inner.token(WHITESPACE, " "); - self.text_pos += TextSize::of(' '); - } - } - } - - fn start_node(&mut self, kind: SyntaxKind) { - self.inner.start_node(kind); - } - - fn finish_node(&mut self) { - self.inner.finish_node(); - } - - fn error(&mut self, error: String) { - self.inner.error(error, self.text_pos) - } -} diff --git a/src/tools/rust-analyzer/crates/mbe/src/to_parser_input.rs b/src/tools/rust-analyzer/crates/mbe/src/to_parser_input.rs deleted file mode 100644 index 783c3ca4a89f7..0000000000000 --- a/src/tools/rust-analyzer/crates/mbe/src/to_parser_input.rs +++ /dev/null @@ -1,99 +0,0 @@ -//! Convert macro-by-example tokens which are specific to macro expansion into a -//! format that works for our parser. - -use syntax::{SyntaxKind, SyntaxKind::*, T}; -use tt::buffer::TokenBuffer; - -pub(crate) fn to_parser_input(buffer: &TokenBuffer<'_>) -> parser::Input { - let mut res = parser::Input::default(); - - let mut current = buffer.begin(); - - while !current.eof() { - let cursor = current; - let tt = cursor.token_tree(); - - // Check if it is lifetime - if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(punct), _)) = tt { - if punct.char == '\'' { - let next = cursor.bump(); - match next.token_tree() { - Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Ident(_ident), _)) => { - res.push(LIFETIME_IDENT); - current = next.bump(); - continue; - } - _ => panic!("Next token must be ident : {:#?}", next.token_tree()), - } - } - } - - current = match tt { - Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => { - match leaf { - tt::Leaf::Literal(lit) => { - let is_negated = lit.text.starts_with('-'); - let inner_text = &lit.text[if is_negated { 1 } else { 0 }..]; - - let kind = parser::LexedStr::single_token(inner_text) - .map(|(kind, _error)| kind) - .filter(|kind| { - kind.is_literal() - && (!is_negated || matches!(kind, FLOAT_NUMBER | INT_NUMBER)) - }) - .unwrap_or_else(|| panic!("Fail to convert given literal {:#?}", &lit)); - - res.push(kind); - } - tt::Leaf::Ident(ident) => match ident.text.as_ref() { - "_" => res.push(T![_]), - i if i.starts_with('\'') => res.push(LIFETIME_IDENT), - _ => match SyntaxKind::from_keyword(&ident.text) { - Some(kind) => res.push(kind), - None => { - let contextual_keyword = - SyntaxKind::from_contextual_keyword(&ident.text) - .unwrap_or(SyntaxKind::IDENT); - res.push_ident(contextual_keyword); - } - }, - }, - tt::Leaf::Punct(punct) => { - let kind = SyntaxKind::from_char(punct.char) - .unwrap_or_else(|| panic!("{:#?} is not a valid punct", punct)); - res.push(kind); - if punct.spacing == tt::Spacing::Joint { - res.was_joint(); - } - } - } - cursor.bump() - } - Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => { - if let Some(d) = subtree.delimiter_kind() { - res.push(match d { - tt::DelimiterKind::Parenthesis => T!['('], - tt::DelimiterKind::Brace => T!['{'], - tt::DelimiterKind::Bracket => T!['['], - }); - } - cursor.subtree().unwrap() - } - None => match cursor.end() { - Some(subtree) => { - if let Some(d) = subtree.delimiter_kind() { - res.push(match d { - tt::DelimiterKind::Parenthesis => T![')'], - tt::DelimiterKind::Brace => T!['}'], - tt::DelimiterKind::Bracket => T![']'], - }) - } - cursor.bump() - } - None => continue, - }, - }; - } - - res -} diff --git a/src/tools/rust-analyzer/crates/mbe/src/token_map.rs b/src/tools/rust-analyzer/crates/mbe/src/token_map.rs deleted file mode 100644 index c923e7a69a1bc..0000000000000 --- a/src/tools/rust-analyzer/crates/mbe/src/token_map.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! Mapping between `TokenId`s and the token's position in macro definitions or inputs. - -use std::hash::Hash; - -use parser::{SyntaxKind, T}; -use syntax::{TextRange, TextSize}; - -use crate::syntax_bridge::SyntheticTokenId; - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -enum TokenTextRange { - Token(TextRange), - Delimiter(TextRange), -} - -impl TokenTextRange { - fn by_kind(self, kind: SyntaxKind) -> Option { - match self { - TokenTextRange::Token(it) => Some(it), - TokenTextRange::Delimiter(it) => match kind { - T!['{'] | T!['('] | T!['['] => Some(TextRange::at(it.start(), 1.into())), - T!['}'] | T![')'] | T![']'] => { - Some(TextRange::at(it.end() - TextSize::of('}'), 1.into())) - } - _ => None, - }, - } - } -} - -/// Maps `tt::TokenId` to the relative range of the original token. -#[derive(Debug, PartialEq, Eq, Clone, Default, Hash)] -pub struct TokenMap { - /// Maps `tt::TokenId` to the *relative* source range. - entries: Vec<(tt::TokenId, TokenTextRange)>, - pub synthetic_entries: Vec<(tt::TokenId, SyntheticTokenId)>, -} - -impl TokenMap { - pub fn token_by_range(&self, relative_range: TextRange) -> Option { - let &(token_id, _) = self.entries.iter().find(|(_, range)| match range { - TokenTextRange::Token(it) => *it == relative_range, - TokenTextRange::Delimiter(it) => { - let open = TextRange::at(it.start(), 1.into()); - let close = TextRange::at(it.end() - TextSize::of('}'), 1.into()); - open == relative_range || close == relative_range - } - })?; - Some(token_id) - } - - pub fn ranges_by_token( - &self, - token_id: tt::TokenId, - kind: SyntaxKind, - ) -> impl Iterator + '_ { - self.entries - .iter() - .filter(move |&&(tid, _)| tid == token_id) - .filter_map(move |(_, range)| range.by_kind(kind)) - } - - pub fn synthetic_token_id(&self, token_id: tt::TokenId) -> Option { - self.synthetic_entries.iter().find(|(tid, _)| *tid == token_id).map(|(_, id)| *id) - } - - pub fn first_range_by_token( - &self, - token_id: tt::TokenId, - kind: SyntaxKind, - ) -> Option { - self.ranges_by_token(token_id, kind).next() - } - - pub(crate) fn shrink_to_fit(&mut self) { - self.entries.shrink_to_fit(); - self.synthetic_entries.shrink_to_fit(); - } - - pub(crate) fn insert(&mut self, token_id: tt::TokenId, relative_range: TextRange) { - self.entries.push((token_id, TokenTextRange::Token(relative_range))); - } - - pub(crate) fn insert_synthetic(&mut self, token_id: tt::TokenId, id: SyntheticTokenId) { - self.synthetic_entries.push((token_id, id)); - } - - pub(crate) fn insert_delim( - &mut self, - token_id: tt::TokenId, - open_relative_range: TextRange, - close_relative_range: TextRange, - ) -> usize { - let res = self.entries.len(); - let cover = open_relative_range.cover(close_relative_range); - - self.entries.push((token_id, TokenTextRange::Delimiter(cover))); - res - } - - pub(crate) fn update_close_delim(&mut self, idx: usize, close_relative_range: TextRange) { - let (_, token_text_range) = &mut self.entries[idx]; - if let TokenTextRange::Delimiter(dim) = token_text_range { - let cover = dim.cover(close_relative_range); - *token_text_range = TokenTextRange::Delimiter(cover); - } - } - - pub(crate) fn remove_delim(&mut self, idx: usize) { - // FIXME: This could be accidentally quadratic - self.entries.remove(idx); - } -} diff --git a/src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs b/src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs deleted file mode 100644 index 7aceb676c749e..0000000000000 --- a/src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs +++ /dev/null @@ -1,160 +0,0 @@ -//! A "Parser" structure for token trees. We use this when parsing a declarative -//! macro definition into a list of patterns and templates. - -use syntax::SyntaxKind; -use tt::buffer::TokenBuffer; - -use crate::{to_parser_input::to_parser_input, ExpandError, ExpandResult}; - -#[derive(Debug, Clone)] -pub(crate) struct TtIter<'a> { - pub(crate) inner: std::slice::Iter<'a, tt::TokenTree>, -} - -impl<'a> TtIter<'a> { - pub(crate) fn new(subtree: &'a tt::Subtree) -> TtIter<'a> { - TtIter { inner: subtree.token_trees.iter() } - } - - pub(crate) fn expect_char(&mut self, char: char) -> Result<(), ()> { - match self.next() { - Some(&tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: c, .. }))) if c == char => { - Ok(()) - } - _ => Err(()), - } - } - - pub(crate) fn expect_any_char(&mut self, chars: &[char]) -> Result<(), ()> { - match self.next() { - Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: c, .. }))) - if chars.contains(c) => - { - Ok(()) - } - _ => Err(()), - } - } - - pub(crate) fn expect_subtree(&mut self) -> Result<&'a tt::Subtree, ()> { - match self.next() { - Some(tt::TokenTree::Subtree(it)) => Ok(it), - _ => Err(()), - } - } - - pub(crate) fn expect_leaf(&mut self) -> Result<&'a tt::Leaf, ()> { - match self.next() { - Some(tt::TokenTree::Leaf(it)) => Ok(it), - _ => Err(()), - } - } - - pub(crate) fn expect_ident(&mut self) -> Result<&'a tt::Ident, ()> { - match self.expect_leaf()? { - tt::Leaf::Ident(it) if it.text != "_" => Ok(it), - _ => Err(()), - } - } - - pub(crate) fn expect_ident_or_underscore(&mut self) -> Result<&'a tt::Ident, ()> { - match self.expect_leaf()? { - tt::Leaf::Ident(it) => Ok(it), - _ => Err(()), - } - } - - pub(crate) fn expect_literal(&mut self) -> Result<&'a tt::Leaf, ()> { - let it = self.expect_leaf()?; - match it { - tt::Leaf::Literal(_) => Ok(it), - tt::Leaf::Ident(ident) if ident.text == "true" || ident.text == "false" => Ok(it), - _ => Err(()), - } - } - - pub(crate) fn expect_u32_literal(&mut self) -> Result { - match self.expect_literal()? { - tt::Leaf::Literal(lit) => lit.text.parse().map_err(drop), - _ => Err(()), - } - } - - pub(crate) fn expect_punct(&mut self) -> Result<&'a tt::Punct, ()> { - match self.expect_leaf()? { - tt::Leaf::Punct(it) => Ok(it), - _ => Err(()), - } - } - - pub(crate) fn expect_fragment( - &mut self, - entry_point: parser::PrefixEntryPoint, - ) -> ExpandResult> { - let buffer = TokenBuffer::from_tokens(self.inner.as_slice()); - let parser_input = to_parser_input(&buffer); - let tree_traversal = entry_point.parse(&parser_input); - - let mut cursor = buffer.begin(); - let mut error = false; - for step in tree_traversal.iter() { - match step { - parser::Step::Token { kind, mut n_input_tokens } => { - if kind == SyntaxKind::LIFETIME_IDENT { - n_input_tokens = 2; - } - for _ in 0..n_input_tokens { - cursor = cursor.bump_subtree(); - } - } - parser::Step::Enter { .. } | parser::Step::Exit => (), - parser::Step::Error { .. } => error = true, - } - } - - let err = if error || !cursor.is_root() { - Some(ExpandError::binding_error(format!("expected {entry_point:?}"))) - } else { - None - }; - - let mut curr = buffer.begin(); - let mut res = vec![]; - - if cursor.is_root() { - while curr != cursor { - if let Some(token) = curr.token_tree() { - res.push(token); - } - curr = curr.bump(); - } - } - self.inner = self.inner.as_slice()[res.len()..].iter(); - let res = match res.len() { - 1 => Some(res[0].cloned()), - 0 => None, - _ => Some(tt::TokenTree::Subtree(tt::Subtree { - delimiter: None, - token_trees: res.into_iter().map(|it| it.cloned()).collect(), - })), - }; - ExpandResult { value: res, err } - } - - pub(crate) fn peek_n(&self, n: usize) -> Option<&tt::TokenTree> { - self.inner.as_slice().get(n) - } -} - -impl<'a> Iterator for TtIter<'a> { - type Item = &'a tt::TokenTree; - fn next(&mut self) -> Option { - self.inner.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -impl<'a> std::iter::ExactSizeIterator for TtIter<'a> {} diff --git a/src/tools/rust-analyzer/crates/parser/Cargo.toml b/src/tools/rust-analyzer/crates/parser/Cargo.toml deleted file mode 100644 index a286a6bcdddec..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "parser" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -drop_bomb = "0.1.5" -rustc_lexer = { version = "725.0.0", package = "rustc-ap-rustc_lexer" } -limit = { path = "../limit", version = "0.0.0" } - -[dev-dependencies] -expect-test = "1.4.0" -sourcegen = { path = "../sourcegen" } diff --git a/src/tools/rust-analyzer/crates/parser/src/event.rs b/src/tools/rust-analyzer/crates/parser/src/event.rs deleted file mode 100644 index b0e70e794303c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/event.rs +++ /dev/null @@ -1,133 +0,0 @@ -//! This module provides a way to construct a `File`. -//! It is intended to be completely decoupled from the -//! parser, so as to allow to evolve the tree representation -//! and the parser algorithm independently. -//! -//! The `TreeSink` trait is the bridge between the parser and the -//! tree builder: the parser produces a stream of events like -//! `start node`, `finish node`, and `FileBuilder` converts -//! this stream to a real tree. -use std::mem; - -use crate::{ - output::Output, - SyntaxKind::{self, *}, -}; - -/// `Parser` produces a flat list of `Event`s. -/// They are converted to a tree-structure in -/// a separate pass, via `TreeBuilder`. -#[derive(Debug)] -pub(crate) enum Event { - /// This event signifies the start of the node. - /// It should be either abandoned (in which case the - /// `kind` is `TOMBSTONE`, and the event is ignored), - /// or completed via a `Finish` event. - /// - /// All tokens between a `Start` and a `Finish` would - /// become the children of the respective node. - /// - /// For left-recursive syntactic constructs, the parser produces - /// a child node before it sees a parent. `forward_parent` - /// saves the position of current event's parent. - /// - /// Consider this path - /// - /// foo::bar - /// - /// The events for it would look like this: - /// - /// ```text - /// START(PATH) IDENT('foo') FINISH START(PATH) T![::] IDENT('bar') FINISH - /// | /\ - /// | | - /// +------forward-parent------+ - /// ``` - /// - /// And the tree would look like this - /// - /// ```text - /// +--PATH---------+ - /// | | | - /// | | | - /// | '::' 'bar' - /// | - /// PATH - /// | - /// 'foo' - /// ``` - /// - /// See also `CompletedMarker::precede`. - Start { - kind: SyntaxKind, - forward_parent: Option, - }, - - /// Complete the previous `Start` event - Finish, - - /// Produce a single leaf-element. - /// `n_raw_tokens` is used to glue complex contextual tokens. - /// For example, lexer tokenizes `>>` as `>`, `>`, and - /// `n_raw_tokens = 2` is used to produced a single `>>`. - Token { - kind: SyntaxKind, - n_raw_tokens: u8, - }, - - Error { - msg: String, - }, -} - -impl Event { - pub(crate) fn tombstone() -> Self { - Event::Start { kind: TOMBSTONE, forward_parent: None } - } -} - -/// Generate the syntax tree with the control of events. -pub(super) fn process(mut events: Vec) -> Output { - let mut res = Output::default(); - let mut forward_parents = Vec::new(); - - for i in 0..events.len() { - match mem::replace(&mut events[i], Event::tombstone()) { - Event::Start { kind, forward_parent } => { - // For events[A, B, C], B is A's forward_parent, C is B's forward_parent, - // in the normal control flow, the parent-child relation: `A -> B -> C`, - // while with the magic forward_parent, it writes: `C <- B <- A`. - - // append `A` into parents. - forward_parents.push(kind); - let mut idx = i; - let mut fp = forward_parent; - while let Some(fwd) = fp { - idx += fwd as usize; - // append `A`'s forward_parent `B` - fp = match mem::replace(&mut events[idx], Event::tombstone()) { - Event::Start { kind, forward_parent } => { - forward_parents.push(kind); - forward_parent - } - _ => unreachable!(), - }; - // append `B`'s forward_parent `C` in the next stage. - } - - for kind in forward_parents.drain(..).rev() { - if kind != TOMBSTONE { - res.enter_node(kind); - } - } - } - Event::Finish => res.leave_node(), - Event::Token { kind, n_raw_tokens } => { - res.token(kind, n_raw_tokens); - } - Event::Error { msg } => res.error(msg), - } - } - - res -} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar.rs b/src/tools/rust-analyzer/crates/parser/src/grammar.rs deleted file mode 100644 index b7468329610a7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/grammar.rs +++ /dev/null @@ -1,342 +0,0 @@ -//! This is the actual "grammar" of the Rust language. -//! -//! Each function in this module and its children corresponds -//! to a production of the formal grammar. Submodules roughly -//! correspond to different *areas* of the grammar. By convention, -//! each submodule starts with `use super::*` import and exports -//! "public" productions via `pub(super)`. -//! -//! See docs for [`Parser`](super::parser::Parser) to learn about API, -//! available to the grammar, and see docs for [`Event`](super::event::Event) -//! to learn how this actually manages to produce parse trees. -//! -//! Code in this module also contains inline tests, which start with -//! `// test name-of-the-test` comment and look like this: -//! -//! ``` -//! // test function_with_zero_parameters -//! // fn foo() {} -//! ``` -//! -//! After adding a new inline-test, run `cargo test -p xtask` to -//! extract it as a standalone text-fixture into -//! `crates/syntax/test_data/parser/`, and run `cargo test` once to -//! create the "gold" value. -//! -//! Coding convention: rules like `where_clause` always produce either a -//! node or an error, rules like `opt_where_clause` may produce nothing. -//! Non-opt rules typically start with `assert!(p.at(FIRST_TOKEN))`, the -//! caller is responsible for branching on the first token. - -mod attributes; -mod expressions; -mod items; -mod params; -mod paths; -mod patterns; -mod generic_args; -mod generic_params; -mod types; - -use crate::{ - parser::{CompletedMarker, Marker, Parser}, - SyntaxKind::{self, *}, - TokenSet, T, -}; - -pub(crate) mod entry { - use super::*; - - pub(crate) mod prefix { - use super::*; - - pub(crate) fn vis(p: &mut Parser<'_>) { - let _ = opt_visibility(p, false); - } - - pub(crate) fn block(p: &mut Parser<'_>) { - expressions::block_expr(p); - } - - pub(crate) fn stmt(p: &mut Parser<'_>) { - expressions::stmt(p, expressions::Semicolon::Forbidden); - } - - pub(crate) fn pat(p: &mut Parser<'_>) { - patterns::pattern_single(p); - } - - pub(crate) fn ty(p: &mut Parser<'_>) { - types::type_(p); - } - pub(crate) fn expr(p: &mut Parser<'_>) { - let _ = expressions::expr(p); - } - pub(crate) fn path(p: &mut Parser<'_>) { - let _ = paths::type_path(p); - } - pub(crate) fn item(p: &mut Parser<'_>) { - items::item_or_macro(p, true); - } - // Parse a meta item , which excluded [], e.g : #[ MetaItem ] - pub(crate) fn meta_item(p: &mut Parser<'_>) { - attributes::meta(p); - } - } - - pub(crate) mod top { - use super::*; - - pub(crate) fn source_file(p: &mut Parser<'_>) { - let m = p.start(); - p.eat(SHEBANG); - items::mod_contents(p, false); - m.complete(p, SOURCE_FILE); - } - - pub(crate) fn macro_stmts(p: &mut Parser<'_>) { - let m = p.start(); - - while !p.at(EOF) { - expressions::stmt(p, expressions::Semicolon::Optional); - } - - m.complete(p, MACRO_STMTS); - } - - pub(crate) fn macro_items(p: &mut Parser<'_>) { - let m = p.start(); - items::mod_contents(p, false); - m.complete(p, MACRO_ITEMS); - } - - pub(crate) fn pattern(p: &mut Parser<'_>) { - let m = p.start(); - patterns::pattern_top(p); - if p.at(EOF) { - m.abandon(p); - return; - } - while !p.at(EOF) { - p.bump_any(); - } - m.complete(p, ERROR); - } - - pub(crate) fn type_(p: &mut Parser<'_>) { - let m = p.start(); - types::type_(p); - if p.at(EOF) { - m.abandon(p); - return; - } - while !p.at(EOF) { - p.bump_any(); - } - m.complete(p, ERROR); - } - - pub(crate) fn expr(p: &mut Parser<'_>) { - let m = p.start(); - expressions::expr(p); - if p.at(EOF) { - m.abandon(p); - return; - } - while !p.at(EOF) { - p.bump_any(); - } - m.complete(p, ERROR); - } - - pub(crate) fn meta_item(p: &mut Parser<'_>) { - let m = p.start(); - attributes::meta(p); - if p.at(EOF) { - m.abandon(p); - return; - } - while !p.at(EOF) { - p.bump_any(); - } - m.complete(p, ERROR); - } - } -} - -pub(crate) fn reparser( - node: SyntaxKind, - first_child: Option, - parent: Option, -) -> Option)> { - let res = match node { - BLOCK_EXPR => expressions::block_expr, - RECORD_FIELD_LIST => items::record_field_list, - RECORD_EXPR_FIELD_LIST => items::record_expr_field_list, - VARIANT_LIST => items::variant_list, - MATCH_ARM_LIST => items::match_arm_list, - USE_TREE_LIST => items::use_tree_list, - EXTERN_ITEM_LIST => items::extern_item_list, - TOKEN_TREE if first_child? == T!['{'] => items::token_tree, - ASSOC_ITEM_LIST => match parent? { - IMPL | TRAIT => items::assoc_item_list, - _ => return None, - }, - ITEM_LIST => items::item_list, - _ => return None, - }; - Some(res) -} - -#[derive(Clone, Copy, PartialEq, Eq)] -enum BlockLike { - Block, - NotBlock, -} - -impl BlockLike { - fn is_block(self) -> bool { - self == BlockLike::Block - } -} - -fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool { - match p.current() { - T![pub] => { - let m = p.start(); - p.bump(T![pub]); - if p.at(T!['(']) { - match p.nth(1) { - // test crate_visibility - // pub(crate) struct S; - // pub(self) struct S; - // pub(super) struct S; - - // test pub_parens_typepath - // struct B(pub (super::A)); - // struct B(pub (crate::A,)); - T![crate] | T![self] | T![super] | T![ident] if p.nth(2) != T![:] => { - // If we are in a tuple struct, then the parens following `pub` - // might be an tuple field, not part of the visibility. So in that - // case we don't want to consume an identifier. - - // test pub_tuple_field - // struct MyStruct(pub (u32, u32)); - if !(in_tuple_field && matches!(p.nth(1), T![ident])) { - p.bump(T!['(']); - paths::use_path(p); - p.expect(T![')']); - } - } - // test crate_visibility_in - // pub(in super::A) struct S; - // pub(in crate) struct S; - T![in] => { - p.bump(T!['(']); - p.bump(T![in]); - paths::use_path(p); - p.expect(T![')']); - } - _ => (), - } - } - m.complete(p, VISIBILITY); - true - } - // test crate_keyword_vis - // crate fn main() { } - // struct S { crate field: u32 } - // struct T(crate u32); - T![crate] => { - if p.nth_at(1, T![::]) { - // test crate_keyword_path - // fn foo() { crate::foo(); } - return false; - } - let m = p.start(); - p.bump(T![crate]); - m.complete(p, VISIBILITY); - true - } - _ => false, - } -} - -fn opt_rename(p: &mut Parser<'_>) { - if p.at(T![as]) { - let m = p.start(); - p.bump(T![as]); - if !p.eat(T![_]) { - name(p); - } - m.complete(p, RENAME); - } -} - -fn abi(p: &mut Parser<'_>) { - assert!(p.at(T![extern])); - let abi = p.start(); - p.bump(T![extern]); - p.eat(STRING); - abi.complete(p, ABI); -} - -fn opt_ret_type(p: &mut Parser<'_>) -> bool { - if p.at(T![->]) { - let m = p.start(); - p.bump(T![->]); - types::type_no_bounds(p); - m.complete(p, RET_TYPE); - true - } else { - false - } -} - -fn name_r(p: &mut Parser<'_>, recovery: TokenSet) { - if p.at(IDENT) { - let m = p.start(); - p.bump(IDENT); - m.complete(p, NAME); - } else { - p.err_recover("expected a name", recovery); - } -} - -fn name(p: &mut Parser<'_>) { - name_r(p, TokenSet::EMPTY); -} - -fn name_ref(p: &mut Parser<'_>) { - if p.at(IDENT) { - let m = p.start(); - p.bump(IDENT); - m.complete(p, NAME_REF); - } else { - p.err_and_bump("expected identifier"); - } -} - -fn name_ref_or_index(p: &mut Parser<'_>) { - assert!(p.at(IDENT) || p.at(INT_NUMBER)); - let m = p.start(); - p.bump_any(); - m.complete(p, NAME_REF); -} - -fn lifetime(p: &mut Parser<'_>) { - assert!(p.at(LIFETIME_IDENT)); - let m = p.start(); - p.bump(LIFETIME_IDENT); - m.complete(p, LIFETIME); -} - -fn error_block(p: &mut Parser<'_>, message: &str) { - assert!(p.at(T!['{'])); - let m = p.start(); - p.error(message); - p.bump(T!['{']); - expressions::expr_block_contents(p); - p.eat(T!['}']); - m.complete(p, ERROR); -} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs deleted file mode 100644 index 0cf6a16f86a57..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs +++ /dev/null @@ -1,53 +0,0 @@ -use super::*; - -pub(super) fn inner_attrs(p: &mut Parser<'_>) { - while p.at(T![#]) && p.nth(1) == T![!] { - attr(p, true); - } -} - -pub(super) fn outer_attrs(p: &mut Parser<'_>) { - while p.at(T![#]) { - attr(p, false); - } -} - -fn attr(p: &mut Parser<'_>, inner: bool) { - assert!(p.at(T![#])); - - let attr = p.start(); - p.bump(T![#]); - - if inner { - p.bump(T![!]); - } - - if p.eat(T!['[']) { - meta(p); - - if !p.eat(T![']']) { - p.error("expected `]`"); - } - } else { - p.error("expected `[`"); - } - attr.complete(p, ATTR); -} - -pub(super) fn meta(p: &mut Parser<'_>) { - let meta = p.start(); - paths::use_path(p); - - match p.current() { - T![=] => { - p.bump(T![=]); - if !expressions::expr(p) { - p.error("expected expression"); - } - } - T!['('] | T!['['] | T!['{'] => items::token_tree(p), - _ => {} - } - - meta.complete(p, META); -} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs deleted file mode 100644 index e7402104eb83f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs +++ /dev/null @@ -1,625 +0,0 @@ -mod atom; - -use super::*; - -pub(crate) use self::atom::{block_expr, match_arm_list}; -pub(super) use self::atom::{literal, LITERAL_FIRST}; - -#[derive(PartialEq, Eq)] -pub(super) enum Semicolon { - Required, - Optional, - Forbidden, -} - -const EXPR_FIRST: TokenSet = LHS_FIRST; - -pub(super) fn expr(p: &mut Parser<'_>) -> bool { - let r = Restrictions { forbid_structs: false, prefer_stmt: false }; - expr_bp(p, None, r, 1).is_some() -} - -pub(super) fn expr_stmt( - p: &mut Parser<'_>, - m: Option, -) -> Option<(CompletedMarker, BlockLike)> { - let r = Restrictions { forbid_structs: false, prefer_stmt: true }; - expr_bp(p, m, r, 1) -} - -fn expr_no_struct(p: &mut Parser<'_>) { - let r = Restrictions { forbid_structs: true, prefer_stmt: false }; - expr_bp(p, None, r, 1); -} - -/// Parses the expression in `let pattern = expression`. -/// It needs to be parsed with lower precedence than `&&`, so that -/// `if let true = true && false` is parsed as `if (let true = true) && (true)` -/// and not `if let true = (true && true)`. -fn expr_let(p: &mut Parser<'_>) { - let r = Restrictions { forbid_structs: true, prefer_stmt: false }; - expr_bp(p, None, r, 5); -} - -pub(super) fn stmt(p: &mut Parser<'_>, semicolon: Semicolon) { - if p.eat(T![;]) { - return; - } - - let m = p.start(); - // test attr_on_expr_stmt - // fn foo() { - // #[A] foo(); - // #[B] bar!{} - // #[C] #[D] {} - // #[D] return (); - // } - attributes::outer_attrs(p); - - if p.at(T![let]) { - let_stmt(p, m, semicolon); - return; - } - - // test block_items - // fn a() { fn b() {} } - let m = match items::opt_item(p, m) { - Ok(()) => return, - Err(m) => m, - }; - - if let Some((cm, blocklike)) = expr_stmt(p, Some(m)) { - if !(p.at(T!['}']) || (semicolon != Semicolon::Required && p.at(EOF))) { - // test no_semi_after_block - // fn foo() { - // if true {} - // loop {} - // match () {} - // while true {} - // for _ in () {} - // {} - // {} - // macro_rules! test { - // () => {} - // } - // test!{} - // } - let m = cm.precede(p); - match semicolon { - Semicolon::Required => { - if blocklike.is_block() { - p.eat(T![;]); - } else { - p.expect(T![;]); - } - } - Semicolon::Optional => { - p.eat(T![;]); - } - Semicolon::Forbidden => (), - } - m.complete(p, EXPR_STMT); - } - } - - // test let_stmt - // fn f() { let x: i32 = 92; } - fn let_stmt(p: &mut Parser<'_>, m: Marker, with_semi: Semicolon) { - p.bump(T![let]); - patterns::pattern(p); - if p.at(T![:]) { - // test let_stmt_ascription - // fn f() { let x: i32; } - types::ascription(p); - } - if p.eat(T![=]) { - // test let_stmt_init - // fn f() { let x = 92; } - expressions::expr(p); - } - - if p.at(T![else]) { - // test let_else - // fn f() { let Some(x) = opt else { return }; } - - let m = p.start(); - p.bump(T![else]); - block_expr(p); - m.complete(p, LET_ELSE); - } - - match with_semi { - Semicolon::Forbidden => (), - Semicolon::Optional => { - p.eat(T![;]); - } - Semicolon::Required => { - p.expect(T![;]); - } - } - m.complete(p, LET_STMT); - } -} - -pub(super) fn expr_block_contents(p: &mut Parser<'_>) { - attributes::inner_attrs(p); - - while !p.at(EOF) && !p.at(T!['}']) { - // test nocontentexpr - // fn foo(){ - // ;;;some_expr();;;;{;;;};;;;Ok(()) - // } - - // test nocontentexpr_after_item - // fn simple_function() { - // enum LocalEnum { - // One, - // Two, - // }; - // fn f() {}; - // struct S {}; - // } - stmt(p, Semicolon::Required); - } -} - -#[derive(Clone, Copy)] -struct Restrictions { - forbid_structs: bool, - prefer_stmt: bool, -} - -/// Binding powers of operators for a Pratt parser. -/// -/// See -#[rustfmt::skip] -fn current_op(p: &Parser<'_>) -> (u8, SyntaxKind) { - const NOT_AN_OP: (u8, SyntaxKind) = (0, T![@]); - match p.current() { - T![|] if p.at(T![||]) => (3, T![||]), - T![|] if p.at(T![|=]) => (1, T![|=]), - T![|] => (6, T![|]), - T![>] if p.at(T![>>=]) => (1, T![>>=]), - T![>] if p.at(T![>>]) => (9, T![>>]), - T![>] if p.at(T![>=]) => (5, T![>=]), - T![>] => (5, T![>]), - T![=] if p.at(T![=>]) => NOT_AN_OP, - T![=] if p.at(T![==]) => (5, T![==]), - T![=] => (1, T![=]), - T![<] if p.at(T![<=]) => (5, T![<=]), - T![<] if p.at(T![<<=]) => (1, T![<<=]), - T![<] if p.at(T![<<]) => (9, T![<<]), - T![<] => (5, T![<]), - T![+] if p.at(T![+=]) => (1, T![+=]), - T![+] => (10, T![+]), - T![^] if p.at(T![^=]) => (1, T![^=]), - T![^] => (7, T![^]), - T![%] if p.at(T![%=]) => (1, T![%=]), - T![%] => (11, T![%]), - T![&] if p.at(T![&=]) => (1, T![&=]), - // If you update this, remember to update `expr_let()` too. - T![&] if p.at(T![&&]) => (4, T![&&]), - T![&] => (8, T![&]), - T![/] if p.at(T![/=]) => (1, T![/=]), - T![/] => (11, T![/]), - T![*] if p.at(T![*=]) => (1, T![*=]), - T![*] => (11, T![*]), - T![.] if p.at(T![..=]) => (2, T![..=]), - T![.] if p.at(T![..]) => (2, T![..]), - T![!] if p.at(T![!=]) => (5, T![!=]), - T![-] if p.at(T![-=]) => (1, T![-=]), - T![-] => (10, T![-]), - T![as] => (12, T![as]), - - _ => NOT_AN_OP - } -} - -// Parses expression with binding power of at least bp. -fn expr_bp( - p: &mut Parser<'_>, - m: Option, - mut r: Restrictions, - bp: u8, -) -> Option<(CompletedMarker, BlockLike)> { - let m = m.unwrap_or_else(|| { - let m = p.start(); - attributes::outer_attrs(p); - m - }); - let mut lhs = match lhs(p, r) { - Some((lhs, blocklike)) => { - let lhs = lhs.extend_to(p, m); - if r.prefer_stmt && blocklike.is_block() { - // test stmt_bin_expr_ambiguity - // fn f() { - // let _ = {1} & 2; - // {1} &2; - // } - return Some((lhs, BlockLike::Block)); - } - lhs - } - None => { - m.abandon(p); - return None; - } - }; - - loop { - let is_range = p.at(T![..]) || p.at(T![..=]); - let (op_bp, op) = current_op(p); - if op_bp < bp { - break; - } - // test as_precedence - // fn f() { let _ = &1 as *const i32; } - if p.at(T![as]) { - lhs = cast_expr(p, lhs); - continue; - } - let m = lhs.precede(p); - p.bump(op); - - // test binop_resets_statementness - // fn f() { v = {1}&2; } - r = Restrictions { prefer_stmt: false, ..r }; - - if is_range { - // test postfix_range - // fn foo() { - // let x = 1..; - // match 1.. { _ => () }; - // match a.b()..S { _ => () }; - // } - let has_trailing_expression = - p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])); - if !has_trailing_expression { - // no RHS - lhs = m.complete(p, RANGE_EXPR); - break; - } - } - - expr_bp(p, None, Restrictions { prefer_stmt: false, ..r }, op_bp + 1); - lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); - } - Some((lhs, BlockLike::NotBlock)) -} - -const LHS_FIRST: TokenSet = - atom::ATOM_EXPR_FIRST.union(TokenSet::new(&[T![&], T![*], T![!], T![.], T![-]])); - -fn lhs(p: &mut Parser<'_>, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> { - let m; - let kind = match p.current() { - // test ref_expr - // fn foo() { - // // reference operator - // let _ = &1; - // let _ = &mut &f(); - // let _ = &raw; - // let _ = &raw.0; - // // raw reference operator - // let _ = &raw mut foo; - // let _ = &raw const foo; - // } - T![&] => { - m = p.start(); - p.bump(T![&]); - if p.at_contextual_kw(T![raw]) && (p.nth_at(1, T![mut]) || p.nth_at(1, T![const])) { - p.bump_remap(T![raw]); - p.bump_any(); - } else { - p.eat(T![mut]); - } - REF_EXPR - } - // test unary_expr - // fn foo() { - // **&1; - // !!true; - // --1; - // } - T![*] | T![!] | T![-] => { - m = p.start(); - p.bump_any(); - PREFIX_EXPR - } - _ => { - // test full_range_expr - // fn foo() { xs[..]; } - for op in [T![..=], T![..]] { - if p.at(op) { - m = p.start(); - p.bump(op); - if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) { - expr_bp(p, None, r, 2); - } - let cm = m.complete(p, RANGE_EXPR); - return Some((cm, BlockLike::NotBlock)); - } - } - - // test expression_after_block - // fn foo() { - // let mut p = F{x: 5}; - // {p}.x = 10; - // } - let (lhs, blocklike) = atom::atom_expr(p, r)?; - let (cm, block_like) = - postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block())); - return Some((cm, block_like)); - } - }; - // parse the interior of the unary expression - expr_bp(p, None, r, 255); - let cm = m.complete(p, kind); - Some((cm, BlockLike::NotBlock)) -} - -fn postfix_expr( - p: &mut Parser<'_>, - mut lhs: CompletedMarker, - // Calls are disallowed if the type is a block and we prefer statements because the call cannot be disambiguated from a tuple - // E.g. `while true {break}();` is parsed as - // `while true {break}; ();` - mut block_like: BlockLike, - mut allow_calls: bool, -) -> (CompletedMarker, BlockLike) { - loop { - lhs = match p.current() { - // test stmt_postfix_expr_ambiguity - // fn foo() { - // match () { - // _ => {} - // () => {} - // [] => {} - // } - // } - T!['('] if allow_calls => call_expr(p, lhs), - T!['['] if allow_calls => index_expr(p, lhs), - T![.] => match postfix_dot_expr(p, lhs) { - Ok(it) => it, - Err(it) => { - lhs = it; - break; - } - }, - T![?] => try_expr(p, lhs), - _ => break, - }; - allow_calls = true; - block_like = BlockLike::NotBlock; - } - return (lhs, block_like); - - fn postfix_dot_expr( - p: &mut Parser<'_>, - lhs: CompletedMarker, - ) -> Result { - assert!(p.at(T![.])); - if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) { - return Ok(method_call_expr(p, lhs)); - } - - // test await_expr - // fn foo() { - // x.await; - // x.0.await; - // x.0().await?.hello(); - // } - if p.nth(1) == T![await] { - let m = lhs.precede(p); - p.bump(T![.]); - p.bump(T![await]); - return Ok(m.complete(p, AWAIT_EXPR)); - } - - if p.at(T![..=]) || p.at(T![..]) { - return Err(lhs); - } - - Ok(field_expr(p, lhs)) - } -} - -// test call_expr -// fn foo() { -// let _ = f(); -// let _ = f()(1)(1, 2,); -// let _ = f(::func()); -// f(::func()); -// } -fn call_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker { - assert!(p.at(T!['('])); - let m = lhs.precede(p); - arg_list(p); - m.complete(p, CALL_EXPR) -} - -// test index_expr -// fn foo() { -// x[1][2]; -// } -fn index_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker { - assert!(p.at(T!['['])); - let m = lhs.precede(p); - p.bump(T!['[']); - expr(p); - p.expect(T![']']); - m.complete(p, INDEX_EXPR) -} - -// test method_call_expr -// fn foo() { -// x.foo(); -// y.bar::(1, 2,); -// } -fn method_call_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker { - assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::]))); - let m = lhs.precede(p); - p.bump_any(); - name_ref(p); - generic_args::opt_generic_arg_list(p, true); - if p.at(T!['(']) { - arg_list(p); - } - m.complete(p, METHOD_CALL_EXPR) -} - -// test field_expr -// fn foo() { -// x.foo; -// x.0.bar; -// x.0(); -// } -fn field_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker { - assert!(p.at(T![.])); - let m = lhs.precede(p); - p.bump(T![.]); - if p.at(IDENT) || p.at(INT_NUMBER) { - name_ref_or_index(p); - } else if p.at(FLOAT_NUMBER) { - // FIXME: How to recover and instead parse INT + T![.]? - p.bump_any(); - } else { - p.error("expected field name or number"); - } - m.complete(p, FIELD_EXPR) -} - -// test try_expr -// fn foo() { -// x?; -// } -fn try_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker { - assert!(p.at(T![?])); - let m = lhs.precede(p); - p.bump(T![?]); - m.complete(p, TRY_EXPR) -} - -// test cast_expr -// fn foo() { -// 82 as i32; -// 81 as i8 + 1; -// 79 as i16 - 1; -// 0x36 as u8 <= 0x37; -// } -fn cast_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker { - assert!(p.at(T![as])); - let m = lhs.precede(p); - p.bump(T![as]); - // Use type_no_bounds(), because cast expressions are not - // allowed to have bounds. - types::type_no_bounds(p); - m.complete(p, CAST_EXPR) -} - -fn arg_list(p: &mut Parser<'_>) { - assert!(p.at(T!['('])); - let m = p.start(); - p.bump(T!['(']); - while !p.at(T![')']) && !p.at(EOF) { - // test arg_with_attr - // fn main() { - // foo(#[attr] 92) - // } - if !expr(p) { - break; - } - if !p.at(T![')']) && !p.expect(T![,]) { - break; - } - } - p.eat(T![')']); - m.complete(p, ARG_LIST); -} - -// test path_expr -// fn foo() { -// let _ = a; -// let _ = a::b; -// let _ = ::a::; -// let _ = format!(); -// } -fn path_expr(p: &mut Parser<'_>, r: Restrictions) -> (CompletedMarker, BlockLike) { - assert!(paths::is_path_start(p)); - let m = p.start(); - paths::expr_path(p); - match p.current() { - T!['{'] if !r.forbid_structs => { - record_expr_field_list(p); - (m.complete(p, RECORD_EXPR), BlockLike::NotBlock) - } - T![!] if !p.at(T![!=]) => { - let block_like = items::macro_call_after_excl(p); - (m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_EXPR), block_like) - } - _ => (m.complete(p, PATH_EXPR), BlockLike::NotBlock), - } -} - -// test record_lit -// fn foo() { -// S {}; -// S { x, y: 32, }; -// S { x, y: 32, ..Default::default() }; -// TupleStruct { 0: 1 }; -// } -pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) { - assert!(p.at(T!['{'])); - let m = p.start(); - p.bump(T!['{']); - while !p.at(EOF) && !p.at(T!['}']) { - let m = p.start(); - // test record_literal_field_with_attr - // fn main() { - // S { #[cfg(test)] field: 1 } - // } - attributes::outer_attrs(p); - - match p.current() { - IDENT | INT_NUMBER => { - // test_err record_literal_before_ellipsis_recovery - // fn main() { - // S { field ..S::default() } - // } - if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) { - name_ref_or_index(p); - p.expect(T![:]); - } - expr(p); - m.complete(p, RECORD_EXPR_FIELD); - } - T![.] if p.at(T![..]) => { - m.abandon(p); - p.bump(T![..]); - - // test destructuring_assignment_struct_rest_pattern - // fn foo() { - // S { .. } = S {}; - // } - - // We permit `.. }` on the left-hand side of a destructuring assignment. - if !p.at(T!['}']) { - expr(p); - } - } - T!['{'] => { - error_block(p, "expected a field"); - m.abandon(p); - } - _ => { - p.err_and_bump("expected identifier"); - m.abandon(p); - } - } - if !p.at(T!['}']) { - p.expect(T![,]); - } - } - p.expect(T!['}']); - m.complete(p, RECORD_EXPR_FIELD_LIST); -} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs deleted file mode 100644 index 99f42a2662348..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs +++ /dev/null @@ -1,643 +0,0 @@ -use super::*; - -// test expr_literals -// fn foo() { -// let _ = true; -// let _ = false; -// let _ = 1; -// let _ = 2.0; -// let _ = b'a'; -// let _ = 'b'; -// let _ = "c"; -// let _ = r"d"; -// let _ = b"e"; -// let _ = br"f"; -// } -pub(crate) const LITERAL_FIRST: TokenSet = TokenSet::new(&[ - T![true], - T![false], - INT_NUMBER, - FLOAT_NUMBER, - BYTE, - CHAR, - STRING, - BYTE_STRING, -]); - -pub(crate) fn literal(p: &mut Parser<'_>) -> Option { - if !p.at_ts(LITERAL_FIRST) { - return None; - } - let m = p.start(); - p.bump_any(); - Some(m.complete(p, LITERAL)) -} - -// E.g. for after the break in `if break {}`, this should not match -pub(super) const ATOM_EXPR_FIRST: TokenSet = - LITERAL_FIRST.union(paths::PATH_FIRST).union(TokenSet::new(&[ - T!['('], - T!['{'], - T!['['], - T![|], - T![move], - T![box], - T![if], - T![while], - T![match], - T![unsafe], - T![return], - T![yield], - T![break], - T![continue], - T![async], - T![try], - T![const], - T![loop], - T![for], - LIFETIME_IDENT, - ])); - -const EXPR_RECOVERY_SET: TokenSet = TokenSet::new(&[T![let]]); - -pub(super) fn atom_expr( - p: &mut Parser<'_>, - r: Restrictions, -) -> Option<(CompletedMarker, BlockLike)> { - if let Some(m) = literal(p) { - return Some((m, BlockLike::NotBlock)); - } - if paths::is_path_start(p) { - return Some(path_expr(p, r)); - } - let la = p.nth(1); - let done = match p.current() { - T!['('] => tuple_expr(p), - T!['['] => array_expr(p), - T![if] => if_expr(p), - T![let] => let_expr(p), - T![_] => { - // test destructuring_assignment_wildcard_pat - // fn foo() { - // _ = 1; - // Some(_) = None; - // } - let m = p.start(); - p.bump(T![_]); - m.complete(p, UNDERSCORE_EXPR) - } - T![loop] => loop_expr(p, None), - T![box] => box_expr(p, None), - T![while] => while_expr(p, None), - T![try] => try_block_expr(p, None), - T![match] => match_expr(p), - T![return] => return_expr(p), - T![yield] => yield_expr(p), - T![continue] => continue_expr(p), - T![break] => break_expr(p, r), - - LIFETIME_IDENT if la == T![:] => { - let m = p.start(); - label(p); - match p.current() { - T![loop] => loop_expr(p, Some(m)), - T![for] => for_expr(p, Some(m)), - T![while] => while_expr(p, Some(m)), - // test labeled_block - // fn f() { 'label: {}; } - T!['{'] => { - stmt_list(p); - m.complete(p, BLOCK_EXPR) - } - _ => { - // test_err misplaced_label_err - // fn main() { - // 'loop: impl - // } - p.error("expected a loop"); - m.complete(p, ERROR); - return None; - } - } - } - // test effect_blocks - // fn f() { unsafe { } } - // fn f() { const { } } - // fn f() { async { } } - // fn f() { async move { } } - T![const] | T![unsafe] | T![async] if la == T!['{'] => { - let m = p.start(); - p.bump_any(); - stmt_list(p); - m.complete(p, BLOCK_EXPR) - } - T![async] if la == T![move] && p.nth(2) == T!['{'] => { - let m = p.start(); - p.bump(T![async]); - p.eat(T![move]); - stmt_list(p); - m.complete(p, BLOCK_EXPR) - } - T!['{'] => { - // test for_range_from - // fn foo() { - // for x in 0 .. { - // break; - // } - // } - let m = p.start(); - stmt_list(p); - m.complete(p, BLOCK_EXPR) - } - - T![static] | T![async] | T![move] | T![|] => closure_expr(p), - T![for] if la == T![<] => closure_expr(p), - T![for] => for_expr(p, None), - - _ => { - p.err_recover("expected expression", EXPR_RECOVERY_SET); - return None; - } - }; - let blocklike = match done.kind() { - IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR => BlockLike::Block, - _ => BlockLike::NotBlock, - }; - Some((done, blocklike)) -} - -// test tuple_expr -// fn foo() { -// (); -// (1); -// (1,); -// } -fn tuple_expr(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T!['('])); - let m = p.start(); - p.expect(T!['(']); - - let mut saw_comma = false; - let mut saw_expr = false; - while !p.at(EOF) && !p.at(T![')']) { - saw_expr = true; - - // test tuple_attrs - // const A: (i64, i64) = (1, #[cfg(test)] 2); - if !expr(p) { - break; - } - - if !p.at(T![')']) { - saw_comma = true; - p.expect(T![,]); - } - } - p.expect(T![')']); - m.complete(p, if saw_expr && !saw_comma { PAREN_EXPR } else { TUPLE_EXPR }) -} - -// test array_expr -// fn foo() { -// []; -// [1]; -// [1, 2,]; -// [1; 2]; -// } -fn array_expr(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T!['['])); - let m = p.start(); - - let mut n_exprs = 0u32; - let mut has_semi = false; - - p.bump(T!['[']); - while !p.at(EOF) && !p.at(T![']']) { - n_exprs += 1; - - // test array_attrs - // const A: &[i64] = &[1, #[cfg(test)] 2]; - if !expr(p) { - break; - } - - if n_exprs == 1 && p.eat(T![;]) { - has_semi = true; - continue; - } - - if has_semi || !p.at(T![']']) && !p.expect(T![,]) { - break; - } - } - p.expect(T![']']); - - m.complete(p, ARRAY_EXPR) -} - -// test lambda_expr -// fn foo() { -// || (); -// || -> i32 { 92 }; -// |x| x; -// move |x: i32,| x; -// async || {}; -// move || {}; -// async move || {}; -// static || {}; -// static move || {}; -// static async || {}; -// static async move || {}; -// for<'a> || {}; -// for<'a> move || {}; -// } -fn closure_expr(p: &mut Parser<'_>) -> CompletedMarker { - assert!(match p.current() { - T![static] | T![async] | T![move] | T![|] => true, - T![for] => p.nth(1) == T![<], - _ => false, - }); - - let m = p.start(); - - if p.at(T![for]) { - types::for_binder(p); - } - - p.eat(T![static]); - p.eat(T![async]); - p.eat(T![move]); - - if !p.at(T![|]) { - p.error("expected `|`"); - return m.complete(p, CLOSURE_EXPR); - } - params::param_list_closure(p); - if opt_ret_type(p) { - // test lambda_ret_block - // fn main() { || -> i32 { 92 }(); } - block_expr(p); - } else if p.at_ts(EXPR_FIRST) { - expr(p); - } else { - p.error("expected expression"); - } - m.complete(p, CLOSURE_EXPR) -} - -// test if_expr -// fn foo() { -// if true {}; -// if true {} else {}; -// if true {} else if false {} else {}; -// if S {}; -// if { true } { } else { }; -// } -fn if_expr(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T![if])); - let m = p.start(); - p.bump(T![if]); - expr_no_struct(p); - block_expr(p); - if p.at(T![else]) { - p.bump(T![else]); - if p.at(T![if]) { - if_expr(p); - } else { - block_expr(p); - } - } - m.complete(p, IF_EXPR) -} - -// test label -// fn foo() { -// 'a: loop {} -// 'b: while true {} -// 'c: for x in () {} -// } -fn label(p: &mut Parser<'_>) { - assert!(p.at(LIFETIME_IDENT) && p.nth(1) == T![:]); - let m = p.start(); - lifetime(p); - p.bump_any(); - m.complete(p, LABEL); -} - -// test loop_expr -// fn foo() { -// loop {}; -// } -fn loop_expr(p: &mut Parser<'_>, m: Option) -> CompletedMarker { - assert!(p.at(T![loop])); - let m = m.unwrap_or_else(|| p.start()); - p.bump(T![loop]); - block_expr(p); - m.complete(p, LOOP_EXPR) -} - -// test while_expr -// fn foo() { -// while true {}; -// while let Some(x) = it.next() {}; -// while { true } {}; -// } -fn while_expr(p: &mut Parser<'_>, m: Option) -> CompletedMarker { - assert!(p.at(T![while])); - let m = m.unwrap_or_else(|| p.start()); - p.bump(T![while]); - expr_no_struct(p); - block_expr(p); - m.complete(p, WHILE_EXPR) -} - -// test for_expr -// fn foo() { -// for x in [] {}; -// } -fn for_expr(p: &mut Parser<'_>, m: Option) -> CompletedMarker { - assert!(p.at(T![for])); - let m = m.unwrap_or_else(|| p.start()); - p.bump(T![for]); - patterns::pattern(p); - p.expect(T![in]); - expr_no_struct(p); - block_expr(p); - m.complete(p, FOR_EXPR) -} - -// test let_expr -// fn foo() { -// if let Some(_) = None && true {} -// while 1 == 5 && (let None = None) {} -// } -fn let_expr(p: &mut Parser<'_>) -> CompletedMarker { - let m = p.start(); - p.bump(T![let]); - patterns::pattern_top(p); - p.expect(T![=]); - expr_let(p); - m.complete(p, LET_EXPR) -} - -// test match_expr -// fn foo() { -// match () { }; -// match S {}; -// match { } { _ => () }; -// match { S {} } {}; -// } -fn match_expr(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T![match])); - let m = p.start(); - p.bump(T![match]); - expr_no_struct(p); - if p.at(T!['{']) { - match_arm_list(p); - } else { - p.error("expected `{`"); - } - m.complete(p, MATCH_EXPR) -} - -pub(crate) fn match_arm_list(p: &mut Parser<'_>) { - assert!(p.at(T!['{'])); - let m = p.start(); - p.eat(T!['{']); - - // test match_arms_inner_attribute - // fn foo() { - // match () { - // #![doc("Inner attribute")] - // #![doc("Can be")] - // #![doc("Stacked")] - // _ => (), - // } - // } - attributes::inner_attrs(p); - - while !p.at(EOF) && !p.at(T!['}']) { - if p.at(T!['{']) { - error_block(p, "expected match arm"); - continue; - } - match_arm(p); - } - p.expect(T!['}']); - m.complete(p, MATCH_ARM_LIST); -} - -// test match_arm -// fn foo() { -// match () { -// _ => (), -// _ if Test > Test{field: 0} => (), -// X | Y if Z => (), -// | X | Y if Z => (), -// | X => (), -// }; -// } -fn match_arm(p: &mut Parser<'_>) { - let m = p.start(); - // test match_arms_outer_attributes - // fn foo() { - // match () { - // #[cfg(feature = "some")] - // _ => (), - // #[cfg(feature = "other")] - // _ => (), - // #[cfg(feature = "many")] - // #[cfg(feature = "attributes")] - // #[cfg(feature = "before")] - // _ => (), - // } - // } - attributes::outer_attrs(p); - - patterns::pattern_top_r(p, TokenSet::EMPTY); - if p.at(T![if]) { - match_guard(p); - } - p.expect(T![=>]); - let blocklike = match expr_stmt(p, None) { - Some((_, blocklike)) => blocklike, - None => BlockLike::NotBlock, - }; - - // test match_arms_commas - // fn foo() { - // match () { - // _ => (), - // _ => {} - // _ => () - // } - // } - if !p.eat(T![,]) && !blocklike.is_block() && !p.at(T!['}']) { - p.error("expected `,`"); - } - m.complete(p, MATCH_ARM); -} - -// test match_guard -// fn foo() { -// match () { -// _ if foo => (), -// _ if let foo = bar => (), -// } -// } -fn match_guard(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T![if])); - let m = p.start(); - p.bump(T![if]); - expr(p); - m.complete(p, MATCH_GUARD) -} - -// test block -// fn a() {} -// fn b() { let _ = 1; } -// fn c() { 1; 2; } -// fn d() { 1; 2 } -pub(crate) fn block_expr(p: &mut Parser<'_>) { - if !p.at(T!['{']) { - p.error("expected a block"); - return; - } - let m = p.start(); - stmt_list(p); - m.complete(p, BLOCK_EXPR); -} - -fn stmt_list(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T!['{'])); - let m = p.start(); - p.bump(T!['{']); - expr_block_contents(p); - p.expect(T!['}']); - m.complete(p, STMT_LIST) -} - -// test return_expr -// fn foo() { -// return; -// return 92; -// } -fn return_expr(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T![return])); - let m = p.start(); - p.bump(T![return]); - if p.at_ts(EXPR_FIRST) { - expr(p); - } - m.complete(p, RETURN_EXPR) -} -// test yield_expr -// fn foo() { -// yield; -// yield 1; -// } -fn yield_expr(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T![yield])); - let m = p.start(); - p.bump(T![yield]); - if p.at_ts(EXPR_FIRST) { - expr(p); - } - m.complete(p, YIELD_EXPR) -} - -// test continue_expr -// fn foo() { -// loop { -// continue; -// continue 'l; -// } -// } -fn continue_expr(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T![continue])); - let m = p.start(); - p.bump(T![continue]); - if p.at(LIFETIME_IDENT) { - lifetime(p); - } - m.complete(p, CONTINUE_EXPR) -} - -// test break_expr -// fn foo() { -// loop { -// break; -// break 'l; -// break 92; -// break 'l 92; -// } -// } -fn break_expr(p: &mut Parser<'_>, r: Restrictions) -> CompletedMarker { - assert!(p.at(T![break])); - let m = p.start(); - p.bump(T![break]); - if p.at(LIFETIME_IDENT) { - lifetime(p); - } - // test break_ambiguity - // fn foo(){ - // if break {} - // while break {} - // for i in break {} - // match break {} - // } - if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) { - expr(p); - } - m.complete(p, BREAK_EXPR) -} - -// test try_block_expr -// fn foo() { -// let _ = try {}; -// } -fn try_block_expr(p: &mut Parser<'_>, m: Option) -> CompletedMarker { - assert!(p.at(T![try])); - let m = m.unwrap_or_else(|| p.start()); - // Special-case `try!` as macro. - // This is a hack until we do proper edition support - if p.nth_at(1, T![!]) { - // test try_macro_fallback - // fn foo() { try!(Ok(())); } - let macro_call = p.start(); - let path = p.start(); - let path_segment = p.start(); - let name_ref = p.start(); - p.bump_remap(IDENT); - name_ref.complete(p, NAME_REF); - path_segment.complete(p, PATH_SEGMENT); - path.complete(p, PATH); - let _block_like = items::macro_call_after_excl(p); - macro_call.complete(p, MACRO_CALL); - return m.complete(p, MACRO_EXPR); - } - - p.bump(T![try]); - if p.at(T!['{']) { - stmt_list(p); - } else { - p.error("expected a block"); - } - m.complete(p, BLOCK_EXPR) -} - -// test box_expr -// fn foo() { -// let x = box 1i32; -// let y = (box 1i32, box 2i32); -// let z = Foo(box 1i32, box 2i32); -// } -fn box_expr(p: &mut Parser<'_>, m: Option) -> CompletedMarker { - assert!(p.at(T![box])); - let m = m.unwrap_or_else(|| p.start()); - p.bump(T![box]); - if p.at_ts(EXPR_FIRST) { - expr(p); - } - m.complete(p, BOX_EXPR) -} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs deleted file mode 100644 index c438943a00262..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs +++ /dev/null @@ -1,131 +0,0 @@ -use super::*; - -pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: bool) { - let m; - if p.at(T![::]) && p.nth(2) == T![<] { - m = p.start(); - p.bump(T![::]); - p.bump(T![<]); - } else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] { - m = p.start(); - p.bump(T![<]); - } else { - return; - } - - while !p.at(EOF) && !p.at(T![>]) { - generic_arg(p); - if !p.at(T![>]) && !p.expect(T![,]) { - break; - } - } - p.expect(T![>]); - m.complete(p, GENERIC_ARG_LIST); -} - -// test generic_arg -// type T = S; -fn generic_arg(p: &mut Parser<'_>) { - match p.current() { - LIFETIME_IDENT => lifetime_arg(p), - T!['{'] | T![true] | T![false] | T![-] => const_arg(p), - k if k.is_literal() => const_arg(p), - // test associated_type_bounds - // fn print_all, Item: Display, Item<'a> = Item>>(printables: T) {} - - // test macro_inside_generic_arg - // type A = Foo; - IDENT if [T![<], T![=], T![:]].contains(&p.nth(1)) && !p.nth_at(1, T![::]) => { - let m = p.start(); - name_ref(p); - opt_generic_arg_list(p, false); - match p.current() { - T![=] => { - p.bump_any(); - if types::TYPE_FIRST.contains(p.current()) { - // test assoc_type_eq - // type T = StreamingIterator = &'a T>; - types::type_(p); - } else { - // test assoc_const_eq - // fn foo>() {} - // const TEST: usize = 3; - // fn bar>() {} - const_arg(p); - } - m.complete(p, ASSOC_TYPE_ARG); - } - // test assoc_type_bound - // type T = StreamingIterator: Clone>; - T![:] if !p.at(T![::]) => { - generic_params::bounds(p); - m.complete(p, ASSOC_TYPE_ARG); - } - _ => { - let m = m.complete(p, PATH_SEGMENT).precede(p).complete(p, PATH); - let m = paths::type_path_for_qualifier(p, m); - m.precede(p).complete(p, PATH_TYPE).precede(p).complete(p, TYPE_ARG); - } - } - } - _ => type_arg(p), - } -} - -// test lifetime_arg -// type T = S<'static>; -fn lifetime_arg(p: &mut Parser<'_>) { - let m = p.start(); - lifetime(p); - m.complete(p, LIFETIME_ARG); -} - -pub(super) fn const_arg_expr(p: &mut Parser<'_>) { - // The tests in here are really for `const_arg`, which wraps the content - // CONST_ARG. - match p.current() { - // test const_arg_block - // type T = S<{90 + 2}>; - T!['{'] => { - expressions::block_expr(p); - } - // test const_arg_literal - // type T = S<"hello", 0xdeadbeef>; - k if k.is_literal() => { - expressions::literal(p); - } - // test const_arg_bool_literal - // type T = S; - T![true] | T![false] => { - expressions::literal(p); - } - // test const_arg_negative_number - // type T = S<-92>; - T![-] => { - let lm = p.start(); - p.bump(T![-]); - expressions::literal(p); - lm.complete(p, PREFIX_EXPR); - } - _ => { - // This shouldn't be hit by `const_arg` - let lm = p.start(); - paths::use_path(p); - lm.complete(p, PATH_EXPR); - } - } -} - -// test const_arg -// type T = S<92>; -pub(super) fn const_arg(p: &mut Parser<'_>) { - let m = p.start(); - const_arg_expr(p); - m.complete(p, CONST_ARG); -} - -fn type_arg(p: &mut Parser<'_>) { - let m = p.start(); - types::type_(p); - m.complete(p, TYPE_ARG); -} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs deleted file mode 100644 index 6db28ef13239c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs +++ /dev/null @@ -1,242 +0,0 @@ -use super::*; - -pub(super) fn opt_generic_param_list(p: &mut Parser<'_>) { - if p.at(T![<]) { - generic_param_list(p); - } -} - -// test generic_param_list -// fn f() {} -fn generic_param_list(p: &mut Parser<'_>) { - assert!(p.at(T![<])); - let m = p.start(); - p.bump(T![<]); - - while !p.at(EOF) && !p.at(T![>]) { - generic_param(p); - if !p.at(T![>]) && !p.expect(T![,]) { - break; - } - } - p.expect(T![>]); - m.complete(p, GENERIC_PARAM_LIST); -} - -fn generic_param(p: &mut Parser<'_>) { - let m = p.start(); - // test generic_param_attribute - // fn foo<#[lt_attr] 'a, #[t_attr] T>() {} - attributes::outer_attrs(p); - match p.current() { - LIFETIME_IDENT => lifetime_param(p, m), - IDENT => type_param(p, m), - T![const] => const_param(p, m), - _ => { - m.abandon(p); - p.err_and_bump("expected type parameter"); - } - } -} - -// test lifetime_param -// fn f<'a: 'b>() {} -fn lifetime_param(p: &mut Parser<'_>, m: Marker) { - assert!(p.at(LIFETIME_IDENT)); - lifetime(p); - if p.at(T![:]) { - lifetime_bounds(p); - } - m.complete(p, LIFETIME_PARAM); -} - -// test type_param -// fn f() {} -fn type_param(p: &mut Parser<'_>, m: Marker) { - assert!(p.at(IDENT)); - name(p); - if p.at(T![:]) { - bounds(p); - } - if p.at(T![=]) { - // test type_param_default - // struct S; - p.bump(T![=]); - types::type_(p); - } - m.complete(p, TYPE_PARAM); -} - -// test const_param -// struct S; -fn const_param(p: &mut Parser<'_>, m: Marker) { - p.bump(T![const]); - name(p); - if p.at(T![:]) { - types::ascription(p); - } else { - p.error("missing type for const parameter"); - } - - if p.at(T![=]) { - // test const_param_default_literal - // struct A; - p.bump(T![=]); - - // test const_param_default_expression - // struct A; - - // test const_param_default_path - // struct A; - generic_args::const_arg_expr(p); - } - - m.complete(p, CONST_PARAM); -} - -fn lifetime_bounds(p: &mut Parser<'_>) { - assert!(p.at(T![:])); - p.bump(T![:]); - while p.at(LIFETIME_IDENT) { - lifetime(p); - if !p.eat(T![+]) { - break; - } - } -} - -// test type_param_bounds -// struct S; -pub(super) fn bounds(p: &mut Parser<'_>) { - assert!(p.at(T![:])); - p.bump(T![:]); - bounds_without_colon(p); -} - -pub(super) fn bounds_without_colon(p: &mut Parser<'_>) { - let m = p.start(); - bounds_without_colon_m(p, m); -} - -pub(super) fn bounds_without_colon_m(p: &mut Parser<'_>, marker: Marker) -> CompletedMarker { - while type_bound(p) { - if !p.eat(T![+]) { - break; - } - } - marker.complete(p, TYPE_BOUND_LIST) -} - -fn type_bound(p: &mut Parser<'_>) -> bool { - let m = p.start(); - let has_paren = p.eat(T!['(']); - match p.current() { - LIFETIME_IDENT => lifetime(p), - T![for] => types::for_type(p, false), - T![?] if p.nth_at(1, T![for]) => { - // test question_for_type_trait_bound - // fn f() where T: ?for<> Sized {} - p.bump_any(); - types::for_type(p, false) - } - current => { - match current { - T![?] => p.bump_any(), - T![~] => { - p.bump_any(); - p.expect(T![const]); - } - _ => (), - } - if paths::is_use_path_start(p) { - types::path_type_(p, false); - } else { - m.abandon(p); - return false; - } - } - } - if has_paren { - p.expect(T![')']); - } - m.complete(p, TYPE_BOUND); - - true -} - -// test where_clause -// fn foo() -// where -// 'a: 'b + 'c, -// T: Clone + Copy + 'static, -// Iterator::Item: 'a, -// ::Item: 'a -// {} -pub(super) fn opt_where_clause(p: &mut Parser<'_>) { - if !p.at(T![where]) { - return; - } - let m = p.start(); - p.bump(T![where]); - - while is_where_predicate(p) { - where_predicate(p); - - let comma = p.eat(T![,]); - - match p.current() { - T!['{'] | T![;] | T![=] => break, - _ => (), - } - - if !comma { - p.error("expected comma"); - } - } - - m.complete(p, WHERE_CLAUSE); - - fn is_where_predicate(p: &mut Parser<'_>) -> bool { - match p.current() { - LIFETIME_IDENT => true, - T![impl] => false, - token => types::TYPE_FIRST.contains(token), - } - } -} - -fn where_predicate(p: &mut Parser<'_>) { - let m = p.start(); - match p.current() { - LIFETIME_IDENT => { - lifetime(p); - if p.at(T![:]) { - bounds(p); - } else { - p.error("expected colon"); - } - } - T![impl] => { - p.error("expected lifetime or type"); - } - _ => { - if p.at(T![for]) { - // test where_pred_for - // fn for_trait() - // where - // for<'a> F: Fn(&'a str) - // { } - types::for_binder(p); - } - - types::type_(p); - - if p.at(T![:]) { - bounds(p); - } else { - p.error("expected colon"); - } - } - } - m.complete(p, WHERE_PRED); -} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs deleted file mode 100644 index 5e0951bf8b50a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs +++ /dev/null @@ -1,465 +0,0 @@ -mod consts; -mod adt; -mod traits; -mod use_item; - -pub(crate) use self::{ - adt::{record_field_list, variant_list}, - expressions::{match_arm_list, record_expr_field_list}, - traits::assoc_item_list, - use_item::use_tree_list, -}; -use super::*; - -// test mod_contents -// fn foo() {} -// macro_rules! foo {} -// foo::bar!(); -// super::baz! {} -// struct S; -pub(super) fn mod_contents(p: &mut Parser<'_>, stop_on_r_curly: bool) { - attributes::inner_attrs(p); - while !p.at(EOF) && !(p.at(T!['}']) && stop_on_r_curly) { - item_or_macro(p, stop_on_r_curly); - } -} - -pub(super) const ITEM_RECOVERY_SET: TokenSet = TokenSet::new(&[ - T![fn], - T![struct], - T![enum], - T![impl], - T![trait], - T![const], - T![static], - T![let], - T![mod], - T![pub], - T![crate], - T![use], - T![macro], - T![;], -]); - -pub(super) fn item_or_macro(p: &mut Parser<'_>, stop_on_r_curly: bool) { - let m = p.start(); - attributes::outer_attrs(p); - - let m = match opt_item(p, m) { - Ok(()) => { - if p.at(T![;]) { - p.err_and_bump( - "expected item, found `;`\n\ - consider removing this semicolon", - ); - } - return; - } - Err(m) => m, - }; - - if paths::is_use_path_start(p) { - match macro_call(p) { - BlockLike::Block => (), - BlockLike::NotBlock => { - p.expect(T![;]); - } - } - m.complete(p, MACRO_CALL); - return; - } - - m.abandon(p); - match p.current() { - T!['{'] => error_block(p, "expected an item"), - T!['}'] if !stop_on_r_curly => { - let e = p.start(); - p.error("unmatched `}`"); - p.bump(T!['}']); - e.complete(p, ERROR); - } - EOF | T!['}'] => p.error("expected an item"), - _ => p.err_and_bump("expected an item"), - } -} - -/// Try to parse an item, completing `m` in case of success. -pub(super) fn opt_item(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> { - // test_err pub_expr - // fn foo() { pub 92; } - let has_visibility = opt_visibility(p, false); - - let m = match opt_item_without_modifiers(p, m) { - Ok(()) => return Ok(()), - Err(m) => m, - }; - - let mut has_mods = false; - let mut has_extern = false; - - // modifiers - if p.at(T![const]) && p.nth(1) != T!['{'] { - p.eat(T![const]); - has_mods = true; - } - - // test_err async_without_semicolon - // fn foo() { let _ = async {} } - if p.at(T![async]) && !matches!(p.nth(1), T!['{'] | T![move] | T![|]) { - p.eat(T![async]); - has_mods = true; - } - - // test_err unsafe_block_in_mod - // fn foo(){} unsafe { } fn bar(){} - if p.at(T![unsafe]) && p.nth(1) != T!['{'] { - p.eat(T![unsafe]); - has_mods = true; - } - - if p.at(T![extern]) { - has_extern = true; - has_mods = true; - abi(p); - } - if p.at_contextual_kw(T![auto]) && p.nth(1) == T![trait] { - p.bump_remap(T![auto]); - has_mods = true; - } - - // test default_item - // default impl T for Foo {} - if p.at_contextual_kw(T![default]) { - match p.nth(1) { - T![fn] | T![type] | T![const] | T![impl] => { - p.bump_remap(T![default]); - has_mods = true; - } - // test default_unsafe_item - // default unsafe impl T for Foo { - // default unsafe fn foo() {} - // } - T![unsafe] if matches!(p.nth(2), T![impl] | T![fn]) => { - p.bump_remap(T![default]); - p.bump(T![unsafe]); - has_mods = true; - } - // test default_async_fn - // impl T for Foo { - // default async fn foo() {} - // } - T![async] => { - let mut maybe_fn = p.nth(2); - let is_unsafe = if matches!(maybe_fn, T![unsafe]) { - // test default_async_unsafe_fn - // impl T for Foo { - // default async unsafe fn foo() {} - // } - maybe_fn = p.nth(3); - true - } else { - false - }; - - if matches!(maybe_fn, T![fn]) { - p.bump_remap(T![default]); - p.bump(T![async]); - if is_unsafe { - p.bump(T![unsafe]); - } - has_mods = true; - } - } - _ => (), - } - } - - // test existential_type - // existential type Foo: Fn() -> usize; - if p.at_contextual_kw(T![existential]) && p.nth(1) == T![type] { - p.bump_remap(T![existential]); - has_mods = true; - } - - // items - match p.current() { - T![fn] => fn_(p, m), - - T![const] if p.nth(1) != T!['{'] => consts::konst(p, m), - - T![trait] => traits::trait_(p, m), - T![impl] => traits::impl_(p, m), - - T![type] => type_alias(p, m), - - // test extern_block - // unsafe extern "C" {} - // extern {} - T!['{'] if has_extern => { - extern_item_list(p); - m.complete(p, EXTERN_BLOCK); - } - - _ if has_visibility || has_mods => { - if has_mods { - p.error("expected existential, fn, trait or impl"); - } else { - p.error("expected an item"); - } - m.complete(p, ERROR); - } - - _ => return Err(m), - } - Ok(()) -} - -fn opt_item_without_modifiers(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> { - let la = p.nth(1); - match p.current() { - T![extern] if la == T![crate] => extern_crate(p, m), - T![use] => use_item::use_(p, m), - T![mod] => mod_item(p, m), - - T![type] => type_alias(p, m), - T![struct] => adt::strukt(p, m), - T![enum] => adt::enum_(p, m), - IDENT if p.at_contextual_kw(T![union]) && p.nth(1) == IDENT => adt::union(p, m), - - T![macro] => macro_def(p, m), - IDENT if p.at_contextual_kw(T![macro_rules]) && p.nth(1) == BANG => macro_rules(p, m), - - T![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::konst(p, m), - T![static] if (la == IDENT || la == T![_] || la == T![mut]) => consts::static_(p, m), - - _ => return Err(m), - }; - Ok(()) -} - -// test extern_crate -// extern crate foo; -fn extern_crate(p: &mut Parser<'_>, m: Marker) { - p.bump(T![extern]); - p.bump(T![crate]); - - if p.at(T![self]) { - // test extern_crate_self - // extern crate self; - let m = p.start(); - p.bump(T![self]); - m.complete(p, NAME_REF); - } else { - name_ref(p); - } - - // test extern_crate_rename - // extern crate foo as bar; - opt_rename(p); - p.expect(T![;]); - m.complete(p, EXTERN_CRATE); -} - -// test mod_item -// mod a; -pub(crate) fn mod_item(p: &mut Parser<'_>, m: Marker) { - p.bump(T![mod]); - name(p); - if p.at(T!['{']) { - // test mod_item_curly - // mod b { } - item_list(p); - } else if !p.eat(T![;]) { - p.error("expected `;` or `{`"); - } - m.complete(p, MODULE); -} - -// test type_alias -// type Foo = Bar; -fn type_alias(p: &mut Parser<'_>, m: Marker) { - p.bump(T![type]); - - name(p); - - // test type_item_type_params - // type Result = (); - generic_params::opt_generic_param_list(p); - - if p.at(T![:]) { - generic_params::bounds(p); - } - - // test type_item_where_clause_deprecated - // type Foo where Foo: Copy = (); - generic_params::opt_where_clause(p); - if p.eat(T![=]) { - types::type_(p); - } - - // test type_item_where_clause - // type Foo = () where Foo: Copy; - generic_params::opt_where_clause(p); - - p.expect(T![;]); - m.complete(p, TYPE_ALIAS); -} - -pub(crate) fn item_list(p: &mut Parser<'_>) { - assert!(p.at(T!['{'])); - let m = p.start(); - p.bump(T!['{']); - mod_contents(p, true); - p.expect(T!['}']); - m.complete(p, ITEM_LIST); -} - -pub(crate) fn extern_item_list(p: &mut Parser<'_>) { - assert!(p.at(T!['{'])); - let m = p.start(); - p.bump(T!['{']); - mod_contents(p, true); - p.expect(T!['}']); - m.complete(p, EXTERN_ITEM_LIST); -} - -fn macro_rules(p: &mut Parser<'_>, m: Marker) { - assert!(p.at_contextual_kw(T![macro_rules])); - p.bump_remap(T![macro_rules]); - p.expect(T![!]); - - if p.at(IDENT) { - name(p); - } - // Special-case `macro_rules! try`. - // This is a hack until we do proper edition support - - // test try_macro_rules - // macro_rules! try { () => {} } - if p.at(T![try]) { - let m = p.start(); - p.bump_remap(IDENT); - m.complete(p, NAME); - } - - match p.current() { - // test macro_rules_non_brace - // macro_rules! m ( ($i:ident) => {} ); - // macro_rules! m [ ($i:ident) => {} ]; - T!['['] | T!['('] => { - token_tree(p); - p.expect(T![;]); - } - T!['{'] => token_tree(p), - _ => p.error("expected `{`, `[`, `(`"), - } - m.complete(p, MACRO_RULES); -} - -// test macro_def -// macro m($i:ident) {} -fn macro_def(p: &mut Parser<'_>, m: Marker) { - p.expect(T![macro]); - name_r(p, ITEM_RECOVERY_SET); - if p.at(T!['{']) { - // test macro_def_curly - // macro m { ($i:ident) => {} } - token_tree(p); - } else if p.at(T!['(']) { - let m = p.start(); - token_tree(p); - match p.current() { - T!['{'] | T!['['] | T!['('] => token_tree(p), - _ => p.error("expected `{`, `[`, `(`"), - } - m.complete(p, TOKEN_TREE); - } else { - p.error("unmatched `(`"); - } - - m.complete(p, MACRO_DEF); -} - -// test fn -// fn foo() {} -fn fn_(p: &mut Parser<'_>, m: Marker) { - p.bump(T![fn]); - - name_r(p, ITEM_RECOVERY_SET); - // test function_type_params - // fn foo(){} - generic_params::opt_generic_param_list(p); - - if p.at(T!['(']) { - params::param_list_fn_def(p); - } else { - p.error("expected function arguments"); - } - // test function_ret_type - // fn foo() {} - // fn bar() -> () {} - opt_ret_type(p); - - // test function_where_clause - // fn foo() where T: Copy {} - generic_params::opt_where_clause(p); - - if p.at(T![;]) { - // test fn_decl - // trait T { fn foo(); } - p.bump(T![;]); - } else { - expressions::block_expr(p); - } - m.complete(p, FN); -} - -fn macro_call(p: &mut Parser<'_>) -> BlockLike { - assert!(paths::is_use_path_start(p)); - paths::use_path(p); - macro_call_after_excl(p) -} - -pub(super) fn macro_call_after_excl(p: &mut Parser<'_>) -> BlockLike { - p.expect(T![!]); - - match p.current() { - T!['{'] => { - token_tree(p); - BlockLike::Block - } - T!['('] | T!['['] => { - token_tree(p); - BlockLike::NotBlock - } - _ => { - p.error("expected `{`, `[`, `(`"); - BlockLike::NotBlock - } - } -} - -pub(crate) fn token_tree(p: &mut Parser<'_>) { - let closing_paren_kind = match p.current() { - T!['{'] => T!['}'], - T!['('] => T![')'], - T!['['] => T![']'], - _ => unreachable!(), - }; - let m = p.start(); - p.bump_any(); - while !p.at(EOF) && !p.at(closing_paren_kind) { - match p.current() { - T!['{'] | T!['('] | T!['['] => token_tree(p), - T!['}'] => { - p.error("unmatched `}`"); - m.complete(p, TOKEN_TREE); - return; - } - T![')'] | T![']'] => p.err_and_bump("unmatched brace"), - _ => p.bump_any(), - } - } - p.expect(closing_paren_kind); - m.complete(p, TOKEN_TREE); -} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs deleted file mode 100644 index e7d30516b9510..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs +++ /dev/null @@ -1,168 +0,0 @@ -use super::*; - -// test struct_item -// struct S {} -pub(super) fn strukt(p: &mut Parser<'_>, m: Marker) { - p.bump(T![struct]); - struct_or_union(p, m, true); -} - -// test union_item -// struct U { i: i32, f: f32 } -pub(super) fn union(p: &mut Parser<'_>, m: Marker) { - assert!(p.at_contextual_kw(T![union])); - p.bump_remap(T![union]); - struct_or_union(p, m, false); -} - -fn struct_or_union(p: &mut Parser<'_>, m: Marker, is_struct: bool) { - name_r(p, ITEM_RECOVERY_SET); - generic_params::opt_generic_param_list(p); - match p.current() { - T![where] => { - generic_params::opt_where_clause(p); - match p.current() { - T![;] => p.bump(T![;]), - T!['{'] => record_field_list(p), - _ => { - //FIXME: special case `(` error message - p.error("expected `;` or `{`"); - } - } - } - T!['{'] => record_field_list(p), - // test unit_struct - // struct S; - T![;] if is_struct => { - p.bump(T![;]); - } - // test tuple_struct - // struct S(String, usize); - T!['('] if is_struct => { - tuple_field_list(p); - // test tuple_struct_where - // struct S(T) where T: Clone; - generic_params::opt_where_clause(p); - p.expect(T![;]); - } - _ => p.error(if is_struct { "expected `;`, `{`, or `(`" } else { "expected `{`" }), - } - m.complete(p, if is_struct { STRUCT } else { UNION }); -} - -pub(super) fn enum_(p: &mut Parser<'_>, m: Marker) { - p.bump(T![enum]); - name_r(p, ITEM_RECOVERY_SET); - generic_params::opt_generic_param_list(p); - generic_params::opt_where_clause(p); - if p.at(T!['{']) { - variant_list(p); - } else { - p.error("expected `{`"); - } - m.complete(p, ENUM); -} - -pub(crate) fn variant_list(p: &mut Parser<'_>) { - assert!(p.at(T!['{'])); - let m = p.start(); - p.bump(T!['{']); - while !p.at(EOF) && !p.at(T!['}']) { - if p.at(T!['{']) { - error_block(p, "expected enum variant"); - continue; - } - variant(p); - if !p.at(T!['}']) { - p.expect(T![,]); - } - } - p.expect(T!['}']); - m.complete(p, VARIANT_LIST); - - fn variant(p: &mut Parser<'_>) { - let m = p.start(); - attributes::outer_attrs(p); - if p.at(IDENT) { - name(p); - match p.current() { - T!['{'] => record_field_list(p), - T!['('] => tuple_field_list(p), - _ => (), - } - - // test variant_discriminant - // enum E { X(i32) = 10 } - if p.eat(T![=]) { - expressions::expr(p); - } - m.complete(p, VARIANT); - } else { - m.abandon(p); - p.err_and_bump("expected enum variant"); - } - } -} - -// test record_field_list -// struct S { a: i32, b: f32 } -pub(crate) fn record_field_list(p: &mut Parser<'_>) { - assert!(p.at(T!['{'])); - let m = p.start(); - p.bump(T!['{']); - while !p.at(T!['}']) && !p.at(EOF) { - if p.at(T!['{']) { - error_block(p, "expected field"); - continue; - } - record_field(p); - if !p.at(T!['}']) { - p.expect(T![,]); - } - } - p.expect(T!['}']); - m.complete(p, RECORD_FIELD_LIST); - - fn record_field(p: &mut Parser<'_>) { - let m = p.start(); - // test record_field_attrs - // struct S { #[attr] f: f32 } - attributes::outer_attrs(p); - opt_visibility(p, false); - if p.at(IDENT) { - name(p); - p.expect(T![:]); - types::type_(p); - m.complete(p, RECORD_FIELD); - } else { - m.abandon(p); - p.err_and_bump("expected field declaration"); - } - } -} - -fn tuple_field_list(p: &mut Parser<'_>) { - assert!(p.at(T!['('])); - let m = p.start(); - p.bump(T!['(']); - while !p.at(T![')']) && !p.at(EOF) { - let m = p.start(); - // test tuple_field_attrs - // struct S (#[attr] f32); - attributes::outer_attrs(p); - opt_visibility(p, true); - if !p.at_ts(types::TYPE_FIRST) { - p.error("expected a type"); - m.complete(p, ERROR); - break; - } - types::type_(p); - m.complete(p, TUPLE_FIELD); - - if !p.at(T![')']) { - p.expect(T![,]); - } - } - p.expect(T![')']); - m.complete(p, TUPLE_FIELD_LIST); -} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs deleted file mode 100644 index 9549ec9b4005e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs +++ /dev/null @@ -1,37 +0,0 @@ -use super::*; - -// test const_item -// const C: u32 = 92; -pub(super) fn konst(p: &mut Parser<'_>, m: Marker) { - p.bump(T![const]); - const_or_static(p, m, true); -} - -pub(super) fn static_(p: &mut Parser<'_>, m: Marker) { - p.bump(T![static]); - const_or_static(p, m, false); -} - -fn const_or_static(p: &mut Parser<'_>, m: Marker, is_const: bool) { - p.eat(T![mut]); - - if is_const && p.eat(T![_]) { - // test anonymous_const - // const _: u32 = 0; - } else { - // test_err anonymous_static - // static _: i32 = 5; - name(p); - } - - if p.at(T![:]) { - types::ascription(p); - } else { - p.error("missing type for `const` or `static`"); - } - if p.eat(T![=]) { - expressions::expr(p); - } - p.expect(T![;]); - m.complete(p, if is_const { CONST } else { STATIC }); -} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/traits.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/traits.rs deleted file mode 100644 index c982e2d564c90..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items/traits.rs +++ /dev/null @@ -1,140 +0,0 @@ -use super::*; - -// test trait_item -// trait T { fn new() -> Self; } -pub(super) fn trait_(p: &mut Parser<'_>, m: Marker) { - p.bump(T![trait]); - name_r(p, ITEM_RECOVERY_SET); - - // test trait_item_generic_params - // trait X {} - generic_params::opt_generic_param_list(p); - - if p.eat(T![=]) { - // test trait_alias - // trait Z = T; - generic_params::bounds_without_colon(p); - - // test trait_alias_where_clause - // trait Z = T where U: Copy; - // trait Z = where Self: T; - generic_params::opt_where_clause(p); - p.expect(T![;]); - m.complete(p, TRAIT); - return; - } - - if p.at(T![:]) { - // test trait_item_bounds - // trait T: Hash + Clone {} - generic_params::bounds(p); - } - - // test trait_item_where_clause - // trait T where Self: Copy {} - generic_params::opt_where_clause(p); - - if p.at(T!['{']) { - assoc_item_list(p); - } else { - p.error("expected `{`"); - } - m.complete(p, TRAIT); -} - -// test impl_item -// impl S {} -pub(super) fn impl_(p: &mut Parser<'_>, m: Marker) { - p.bump(T![impl]); - if p.at(T![<]) && not_a_qualified_path(p) { - generic_params::opt_generic_param_list(p); - } - - // test impl_item_const - // impl const Send for S {} - p.eat(T![const]); - - // FIXME: never type - // impl ! {} - - // test impl_item_neg - // impl !Send for S {} - p.eat(T![!]); - impl_type(p); - if p.eat(T![for]) { - impl_type(p); - } - generic_params::opt_where_clause(p); - if p.at(T!['{']) { - assoc_item_list(p); - } else { - p.error("expected `{`"); - } - m.complete(p, IMPL); -} - -// test assoc_item_list -// impl F { -// type A = i32; -// const B: i32 = 92; -// fn foo() {} -// fn bar(&self) {} -// } -pub(crate) fn assoc_item_list(p: &mut Parser<'_>) { - assert!(p.at(T!['{'])); - - let m = p.start(); - p.bump(T!['{']); - // test assoc_item_list_inner_attrs - // impl S { #![attr] } - attributes::inner_attrs(p); - - while !p.at(EOF) && !p.at(T!['}']) { - if p.at(T!['{']) { - error_block(p, "expected an item"); - continue; - } - item_or_macro(p, true); - } - p.expect(T!['}']); - m.complete(p, ASSOC_ITEM_LIST); -} - -// test impl_type_params -// impl Bar {} -fn not_a_qualified_path(p: &Parser<'_>) -> bool { - // There's an ambiguity between generic parameters and qualified paths in impls. - // If we see `<` it may start both, so we have to inspect some following tokens. - // The following combinations can only start generics, - // but not qualified paths (with one exception): - // `<` `>` - empty generic parameters - // `<` `#` - generic parameters with attributes - // `<` `const` - const generic parameters - // `<` (LIFETIME_IDENT|IDENT) `>` - single generic parameter - // `<` (LIFETIME_IDENT|IDENT) `,` - first generic parameter in a list - // `<` (LIFETIME_IDENT|IDENT) `:` - generic parameter with bounds - // `<` (LIFETIME_IDENT|IDENT) `=` - generic parameter with a default - // The only truly ambiguous case is - // `<` IDENT `>` `::` IDENT ... - // we disambiguate it in favor of generics (`impl ::absolute::Path { ... }`) - // because this is what almost always expected in practice, qualified paths in impls - // (`impl ::AssocTy { ... }`) aren't even allowed by type checker at the moment. - if p.nth(1) == T![#] || p.nth(1) == T![>] || p.nth(1) == T![const] { - return true; - } - (p.nth(1) == LIFETIME_IDENT || p.nth(1) == IDENT) - && (p.nth(2) == T![>] || p.nth(2) == T![,] || p.nth(2) == T![:] || p.nth(2) == T![=]) -} - -// test_err impl_type -// impl Type {} -// impl Trait1 for T {} -// impl impl NotType {} -// impl Trait2 for impl NotType {} -pub(crate) fn impl_type(p: &mut Parser<'_>) { - if p.at(T![impl]) { - p.error("expected trait or type"); - return; - } - types::type_(p); -} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/use_item.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/use_item.rs deleted file mode 100644 index 69880b7946b69..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items/use_item.rs +++ /dev/null @@ -1,93 +0,0 @@ -use super::*; - -// test use_item -// use std::collections; -pub(super) fn use_(p: &mut Parser<'_>, m: Marker) { - p.bump(T![use]); - use_tree(p, true); - p.expect(T![;]); - m.complete(p, USE); -} - -// test use_tree -// use outer::tree::{inner::tree}; -fn use_tree(p: &mut Parser<'_>, top_level: bool) { - let m = p.start(); - match p.current() { - // test use_tree_star - // use *; - // use std::{*}; - T![*] => p.bump(T![*]), - // test use_tree_abs_star - // use ::*; - // use std::{::*}; - T![:] if p.at(T![::]) && p.nth(2) == T![*] => { - p.bump(T![::]); - p.bump(T![*]); - } - T!['{'] => use_tree_list(p), - T![:] if p.at(T![::]) && p.nth(2) == T!['{'] => { - p.bump(T![::]); - use_tree_list(p); - } - - // test use_tree_path - // use ::std; - // use std::collections; - // - // use self::m; - // use super::m; - // use crate::m; - _ if paths::is_use_path_start(p) => { - paths::use_path(p); - match p.current() { - // test use_tree_alias - // use std as stdlib; - // use Trait as _; - T![as] => opt_rename(p), - T![:] if p.at(T![::]) => { - p.bump(T![::]); - match p.current() { - // test use_tree_path_star - // use std::*; - T![*] => p.bump(T![*]), - // test use_tree_path_use_tree - // use std::{collections}; - T!['{'] => use_tree_list(p), - _ => p.error("expected `{` or `*`"), - } - } - _ => (), - } - } - _ => { - m.abandon(p); - let msg = "expected one of `*`, `::`, `{`, `self`, `super` or an identifier"; - if top_level { - p.err_recover(msg, ITEM_RECOVERY_SET); - } else { - // if we are parsing a nested tree, we have to eat a token to - // main balanced `{}` - p.err_and_bump(msg); - } - return; - } - } - m.complete(p, USE_TREE); -} - -// test use_tree_list -// use {a, b, c}; -pub(crate) fn use_tree_list(p: &mut Parser<'_>) { - assert!(p.at(T!['{'])); - let m = p.start(); - p.bump(T!['{']); - while !p.at(EOF) && !p.at(T!['}']) { - use_tree(p, false); - if !p.at(T!['}']) { - p.expect(T![,]); - } - } - p.expect(T!['}']); - m.complete(p, USE_TREE_LIST); -} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs deleted file mode 100644 index 20e8e95f0662c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs +++ /dev/null @@ -1,209 +0,0 @@ -use super::*; - -// test param_list -// fn a() {} -// fn b(x: i32) {} -// fn c(x: i32, ) {} -// fn d(x: i32, y: ()) {} -pub(super) fn param_list_fn_def(p: &mut Parser<'_>) { - list_(p, Flavor::FnDef); -} - -// test param_list_opt_patterns -// fn foo)>(){} -pub(super) fn param_list_fn_trait(p: &mut Parser<'_>) { - list_(p, Flavor::FnTrait); -} - -pub(super) fn param_list_fn_ptr(p: &mut Parser<'_>) { - list_(p, Flavor::FnPointer); -} - -pub(super) fn param_list_closure(p: &mut Parser<'_>) { - list_(p, Flavor::Closure); -} - -#[derive(Debug, Clone, Copy)] -enum Flavor { - FnDef, // Includes trait fn params; omitted param idents are not supported - FnTrait, // Params for `Fn(...)`/`FnMut(...)`/`FnOnce(...)` annotations - FnPointer, - Closure, -} - -fn list_(p: &mut Parser<'_>, flavor: Flavor) { - use Flavor::*; - - let (bra, ket) = match flavor { - Closure => (T![|], T![|]), - FnDef | FnTrait | FnPointer => (T!['('], T![')']), - }; - - let list_marker = p.start(); - p.bump(bra); - - let mut param_marker = None; - if let FnDef = flavor { - // test self_param_outer_attr - // fn f(#[must_use] self) {} - let m = p.start(); - attributes::outer_attrs(p); - match opt_self_param(p, m) { - Ok(()) => {} - Err(m) => param_marker = Some(m), - } - } - - while !p.at(EOF) && !p.at(ket) { - // test param_outer_arg - // fn f(#[attr1] pat: Type) {} - let m = match param_marker.take() { - Some(m) => m, - None => { - let m = p.start(); - attributes::outer_attrs(p); - m - } - }; - - if !p.at_ts(PARAM_FIRST) { - p.error("expected value parameter"); - m.abandon(p); - break; - } - param(p, m, flavor); - if !p.at(ket) { - p.expect(T![,]); - } - } - - if let Some(m) = param_marker { - m.abandon(p); - } - - p.expect(ket); - list_marker.complete(p, PARAM_LIST); -} - -const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST); - -fn param(p: &mut Parser<'_>, m: Marker, flavor: Flavor) { - match flavor { - // test param_list_vararg - // extern "C" { fn printf(format: *const i8, ..., _: u8) -> i32; } - Flavor::FnDef | Flavor::FnPointer if p.eat(T![...]) => {} - - // test fn_def_param - // fn foo(..., (x, y): (i32, i32)) {} - Flavor::FnDef => { - patterns::pattern(p); - if !variadic_param(p) { - if p.at(T![:]) { - types::ascription(p); - } else { - // test_err missing_fn_param_type - // fn f(x y: i32, z, t: i32) {} - p.error("missing type for function parameter"); - } - } - } - // test value_parameters_no_patterns - // type F = Box; - Flavor::FnTrait => { - types::type_(p); - } - // test fn_pointer_param_ident_path - // type Foo = fn(Bar::Baz); - // type Qux = fn(baz: Bar::Baz); - - // test fn_pointer_unnamed_arg - // type Foo = fn(_: bar); - Flavor::FnPointer => { - if (p.at(IDENT) || p.at(UNDERSCORE)) && p.nth(1) == T![:] && !p.nth_at(1, T![::]) { - patterns::pattern_single(p); - if !variadic_param(p) { - if p.at(T![:]) { - types::ascription(p); - } else { - p.error("missing type for function parameter"); - } - } - } else { - types::type_(p); - } - } - // test closure_params - // fn main() { - // let foo = |bar, baz: Baz, qux: Qux::Quux| (); - // } - Flavor::Closure => { - patterns::pattern_single(p); - if p.at(T![:]) && !p.at(T![::]) { - types::ascription(p); - } - } - } - m.complete(p, PARAM); -} - -fn variadic_param(p: &mut Parser<'_>) -> bool { - if p.at(T![:]) && p.nth_at(1, T![...]) { - p.bump(T![:]); - p.bump(T![...]); - true - } else { - false - } -} - -// test self_param -// impl S { -// fn a(self) {} -// fn b(&self,) {} -// fn c(&'a self,) {} -// fn d(&'a mut self, x: i32) {} -// fn e(mut self) {} -// } -fn opt_self_param(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> { - if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] { - p.eat(T![mut]); - self_as_name(p); - // test arb_self_types - // impl S { - // fn a(self: &Self) {} - // fn b(mut self: Box) {} - // } - if p.at(T![:]) { - types::ascription(p); - } - } else { - let la1 = p.nth(1); - let la2 = p.nth(2); - let la3 = p.nth(3); - if !matches!( - (p.current(), la1, la2, la3), - (T![&], T![self], _, _) - | (T![&], T![mut] | LIFETIME_IDENT, T![self], _) - | (T![&], LIFETIME_IDENT, T![mut], T![self]) - ) { - return Err(m); - } - p.bump(T![&]); - if p.at(LIFETIME_IDENT) { - lifetime(p); - } - p.eat(T![mut]); - self_as_name(p); - } - m.complete(p, SELF_PARAM); - if !p.at(T![')']) { - p.expect(T![,]); - } - Ok(()) -} - -fn self_as_name(p: &mut Parser<'_>) { - let m = p.start(); - p.bump(T![self]); - m.complete(p, NAME); -} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs deleted file mode 100644 index f9efcef92a610..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs +++ /dev/null @@ -1,132 +0,0 @@ -use super::*; - -pub(super) const PATH_FIRST: TokenSet = - TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![Self], T![:], T![<]]); - -pub(super) fn is_path_start(p: &Parser<'_>) -> bool { - is_use_path_start(p) || p.at(T![<]) || p.at(T![Self]) -} - -pub(super) fn is_use_path_start(p: &Parser<'_>) -> bool { - match p.current() { - IDENT | T![self] | T![super] | T![crate] => true, - T![:] if p.at(T![::]) => true, - _ => false, - } -} - -pub(super) fn use_path(p: &mut Parser<'_>) { - path(p, Mode::Use); -} - -pub(crate) fn type_path(p: &mut Parser<'_>) { - path(p, Mode::Type); -} - -pub(super) fn expr_path(p: &mut Parser<'_>) { - path(p, Mode::Expr); -} - -pub(crate) fn type_path_for_qualifier( - p: &mut Parser<'_>, - qual: CompletedMarker, -) -> CompletedMarker { - path_for_qualifier(p, Mode::Type, qual) -} - -#[derive(Clone, Copy, Eq, PartialEq)] -enum Mode { - Use, - Type, - Expr, -} - -fn path(p: &mut Parser<'_>, mode: Mode) { - let path = p.start(); - path_segment(p, mode, true); - let qual = path.complete(p, PATH); - path_for_qualifier(p, mode, qual); -} - -fn path_for_qualifier( - p: &mut Parser<'_>, - mode: Mode, - mut qual: CompletedMarker, -) -> CompletedMarker { - loop { - let use_tree = matches!(p.nth(2), T![*] | T!['{']); - if p.at(T![::]) && !use_tree { - let path = qual.precede(p); - p.bump(T![::]); - path_segment(p, mode, false); - let path = path.complete(p, PATH); - qual = path; - } else { - return qual; - } - } -} - -fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) { - let m = p.start(); - // test qual_paths - // type X =
::Output; - // fn foo() { ::default(); } - if first && p.eat(T![<]) { - types::type_(p); - if p.eat(T![as]) { - if is_use_path_start(p) { - types::path_type(p); - } else { - p.error("expected a trait"); - } - } - p.expect(T![>]); - } else { - let mut empty = true; - if first { - p.eat(T![::]); - empty = false; - } - match p.current() { - IDENT => { - name_ref(p); - opt_path_type_args(p, mode); - } - // test crate_path - // use crate::foo; - T![self] | T![super] | T![crate] | T![Self] => { - let m = p.start(); - p.bump_any(); - m.complete(p, NAME_REF); - } - _ => { - p.err_recover("expected identifier", items::ITEM_RECOVERY_SET); - if empty { - // test_err empty_segment - // use crate::; - m.abandon(p); - return; - } - } - }; - } - m.complete(p, PATH_SEGMENT); -} - -fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) { - match mode { - Mode::Use => {} - Mode::Type => { - // test path_fn_trait_args - // type F = Box ()>; - if p.at(T!['(']) { - params::param_list_fn_trait(p); - opt_ret_type(p); - } else { - generic_args::opt_generic_arg_list(p, false); - } - } - Mode::Expr => generic_args::opt_generic_arg_list(p, true), - } -} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs deleted file mode 100644 index 4cbf103061497..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs +++ /dev/null @@ -1,440 +0,0 @@ -use super::*; - -pub(super) const PATTERN_FIRST: TokenSet = - expressions::LITERAL_FIRST.union(paths::PATH_FIRST).union(TokenSet::new(&[ - T![box], - T![ref], - T![mut], - T!['('], - T!['['], - T![&], - T![_], - T![-], - T![.], - ])); - -pub(crate) fn pattern(p: &mut Parser<'_>) { - pattern_r(p, PAT_RECOVERY_SET); -} - -/// Parses a pattern list separated by pipes `|`. -pub(super) fn pattern_top(p: &mut Parser<'_>) { - pattern_top_r(p, PAT_RECOVERY_SET); -} - -pub(crate) fn pattern_single(p: &mut Parser<'_>) { - pattern_single_r(p, PAT_RECOVERY_SET); -} - -/// Parses a pattern list separated by pipes `|` -/// using the given `recovery_set`. -pub(super) fn pattern_top_r(p: &mut Parser<'_>, recovery_set: TokenSet) { - p.eat(T![|]); - pattern_r(p, recovery_set); -} - -/// Parses a pattern list separated by pipes `|`, with no leading `|`,using the -/// given `recovery_set`. - -// test or_pattern -// fn main() { -// match () { -// (_ | _) => (), -// &(_ | _) => (), -// (_ | _,) => (), -// [_ | _,] => (), -// } -// } -fn pattern_r(p: &mut Parser<'_>, recovery_set: TokenSet) { - let m = p.start(); - pattern_single_r(p, recovery_set); - - if !p.at(T![|]) { - m.abandon(p); - return; - } - while p.eat(T![|]) { - pattern_single_r(p, recovery_set); - } - m.complete(p, OR_PAT); -} - -fn pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet) { - if let Some(lhs) = atom_pat(p, recovery_set) { - // test range_pat - // fn main() { - // match 92 { - // 0 ... 100 => (), - // 101 ..= 200 => (), - // 200 .. 301 => (), - // 302 .. => (), - // } - // - // match Some(10 as u8) { - // Some(0) | None => (), - // Some(1..) => () - // } - // - // match (10 as u8, 5 as u8) { - // (0, _) => (), - // (1.., _) => () - // } - // } - - // FIXME: support half_open_range_patterns (`..=2`), - // exclusive_range_pattern (`..5`) with missing lhs - for range_op in [T![...], T![..=], T![..]] { - if p.at(range_op) { - let m = lhs.precede(p); - p.bump(range_op); - - // `0 .. =>` or `let 0 .. =` or `Some(0 .. )` - // ^ ^ ^ - if p.at(T![=]) | p.at(T![')']) | p.at(T![,]) { - // test half_open_range_pat - // fn f() { let 0 .. = 1u32; } - } else { - atom_pat(p, recovery_set); - } - m.complete(p, RANGE_PAT); - return; - } - } - } -} - -const PAT_RECOVERY_SET: TokenSet = - TokenSet::new(&[T![let], T![if], T![while], T![loop], T![match], T![')'], T![,], T![=]]); - -fn atom_pat(p: &mut Parser<'_>, recovery_set: TokenSet) -> Option { - let m = match p.current() { - T![box] => box_pat(p), - T![ref] | T![mut] => ident_pat(p, true), - T![const] => const_block_pat(p), - IDENT => match p.nth(1) { - // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro - // (T![x]). - T!['('] | T!['{'] | T![!] => path_or_macro_pat(p), - T![:] if p.nth_at(1, T![::]) => path_or_macro_pat(p), - _ => ident_pat(p, true), - }, - - // test type_path_in_pattern - // fn main() { let <_>::Foo = (); } - _ if paths::is_path_start(p) => path_or_macro_pat(p), - _ if is_literal_pat_start(p) => literal_pat(p), - - T![.] if p.at(T![..]) => rest_pat(p), - T![_] => wildcard_pat(p), - T![&] => ref_pat(p), - T!['('] => tuple_pat(p), - T!['['] => slice_pat(p), - - _ => { - p.err_recover("expected pattern", recovery_set); - return None; - } - }; - - Some(m) -} - -fn is_literal_pat_start(p: &Parser<'_>) -> bool { - p.at(T![-]) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER) - || p.at_ts(expressions::LITERAL_FIRST) -} - -// test literal_pattern -// fn main() { -// match () { -// -1 => (), -// 92 => (), -// 'c' => (), -// "hello" => (), -// } -// } -fn literal_pat(p: &mut Parser<'_>) -> CompletedMarker { - assert!(is_literal_pat_start(p)); - let m = p.start(); - if p.at(T![-]) { - p.bump(T![-]); - } - expressions::literal(p); - m.complete(p, LITERAL_PAT) -} - -// test path_part -// fn foo() { -// let foo::Bar = (); -// let ::Bar = (); -// let Bar { .. } = (); -// let Bar(..) = (); -// } -fn path_or_macro_pat(p: &mut Parser<'_>) -> CompletedMarker { - assert!(paths::is_path_start(p)); - let m = p.start(); - paths::expr_path(p); - let kind = match p.current() { - T!['('] => { - tuple_pat_fields(p); - TUPLE_STRUCT_PAT - } - T!['{'] => { - record_pat_field_list(p); - RECORD_PAT - } - // test marco_pat - // fn main() { - // let m!(x) = 0; - // } - T![!] => { - items::macro_call_after_excl(p); - return m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_PAT); - } - _ => PATH_PAT, - }; - m.complete(p, kind) -} - -// test tuple_pat_fields -// fn foo() { -// let S() = (); -// let S(_) = (); -// let S(_,) = (); -// let S(_, .. , x) = (); -// } -fn tuple_pat_fields(p: &mut Parser<'_>) { - assert!(p.at(T!['('])); - p.bump(T!['(']); - pat_list(p, T![')']); - p.expect(T![')']); -} - -// test record_pat_field -// fn foo() { -// let S { 0: 1 } = (); -// let S { x: 1 } = (); -// let S { #[cfg(any())] x: 1 } = (); -// } -fn record_pat_field(p: &mut Parser<'_>) { - match p.current() { - IDENT | INT_NUMBER if p.nth(1) == T![:] => { - name_ref_or_index(p); - p.bump(T![:]); - pattern(p); - } - T![box] => { - // FIXME: not all box patterns should be allowed - box_pat(p); - } - T![ref] | T![mut] | IDENT => { - ident_pat(p, false); - } - _ => { - p.err_and_bump("expected identifier"); - } - } -} - -// test record_pat_field_list -// fn foo() { -// let S {} = (); -// let S { f, ref mut g } = (); -// let S { h: _, ..} = (); -// let S { h: _, } = (); -// let S { #[cfg(any())] .. } = (); -// } -fn record_pat_field_list(p: &mut Parser<'_>) { - assert!(p.at(T!['{'])); - let m = p.start(); - p.bump(T!['{']); - while !p.at(EOF) && !p.at(T!['}']) { - let m = p.start(); - attributes::outer_attrs(p); - - match p.current() { - // A trailing `..` is *not* treated as a REST_PAT. - T![.] if p.at(T![..]) => { - p.bump(T![..]); - m.complete(p, REST_PAT); - } - T!['{'] => { - error_block(p, "expected ident"); - m.abandon(p); - } - _ => { - record_pat_field(p); - m.complete(p, RECORD_PAT_FIELD); - } - } - if !p.at(T!['}']) { - p.expect(T![,]); - } - } - p.expect(T!['}']); - m.complete(p, RECORD_PAT_FIELD_LIST); -} - -// test placeholder_pat -// fn main() { let _ = (); } -fn wildcard_pat(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T![_])); - let m = p.start(); - p.bump(T![_]); - m.complete(p, WILDCARD_PAT) -} - -// test dot_dot_pat -// fn main() { -// let .. = (); -// // -// // Tuples -// // -// let (a, ..) = (); -// let (a, ..,) = (); -// let Tuple(a, ..) = (); -// let Tuple(a, ..,) = (); -// let (.., ..) = (); -// let Tuple(.., ..) = (); -// let (.., a, ..) = (); -// let Tuple(.., a, ..) = (); -// // -// // Slices -// // -// let [..] = (); -// let [head, ..] = (); -// let [head, tail @ ..] = (); -// let [head, .., cons] = (); -// let [head, mid @ .., cons] = (); -// let [head, .., .., cons] = (); -// let [head, .., mid, tail @ ..] = (); -// let [head, .., mid, .., cons] = (); -// } -fn rest_pat(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T![..])); - let m = p.start(); - p.bump(T![..]); - m.complete(p, REST_PAT) -} - -// test ref_pat -// fn main() { -// let &a = (); -// let &mut b = (); -// } -fn ref_pat(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T![&])); - let m = p.start(); - p.bump(T![&]); - p.eat(T![mut]); - pattern_single(p); - m.complete(p, REF_PAT) -} - -// test tuple_pat -// fn main() { -// let (a, b, ..) = (); -// let (a,) = (); -// let (..) = (); -// let () = (); -// } -fn tuple_pat(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T!['('])); - let m = p.start(); - p.bump(T!['(']); - let mut has_comma = false; - let mut has_pat = false; - let mut has_rest = false; - while !p.at(EOF) && !p.at(T![')']) { - has_pat = true; - if !p.at_ts(PATTERN_FIRST) { - p.error("expected a pattern"); - break; - } - has_rest |= p.at(T![..]); - - pattern(p); - if !p.at(T![')']) { - has_comma = true; - p.expect(T![,]); - } - } - p.expect(T![')']); - - m.complete(p, if !has_comma && !has_rest && has_pat { PAREN_PAT } else { TUPLE_PAT }) -} - -// test slice_pat -// fn main() { -// let [a, b, ..] = []; -// } -fn slice_pat(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T!['['])); - let m = p.start(); - p.bump(T!['[']); - pat_list(p, T![']']); - p.expect(T![']']); - m.complete(p, SLICE_PAT) -} - -fn pat_list(p: &mut Parser<'_>, ket: SyntaxKind) { - while !p.at(EOF) && !p.at(ket) { - if !p.at_ts(PATTERN_FIRST) { - p.error("expected a pattern"); - break; - } - - pattern(p); - if !p.at(ket) { - p.expect(T![,]); - } - } -} - -// test bind_pat -// fn main() { -// let a = (); -// let mut b = (); -// let ref c = (); -// let ref mut d = (); -// let e @ _ = (); -// let ref mut f @ g @ _ = (); -// } -fn ident_pat(p: &mut Parser<'_>, with_at: bool) -> CompletedMarker { - assert!(matches!(p.current(), T![ref] | T![mut] | IDENT)); - let m = p.start(); - p.eat(T![ref]); - p.eat(T![mut]); - name_r(p, PAT_RECOVERY_SET); - if with_at && p.eat(T![@]) { - pattern_single(p); - } - m.complete(p, IDENT_PAT) -} - -// test box_pat -// fn main() { -// let box i = (); -// let box Outer { box i, j: box Inner(box &x) } = (); -// let box ref mut i = (); -// } -fn box_pat(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T![box])); - let m = p.start(); - p.bump(T![box]); - pattern_single(p); - m.complete(p, BOX_PAT) -} - -// test const_block_pat -// fn main() { -// let const { 15 } = (); -// let const { foo(); bar() } = (); -// } -fn const_block_pat(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T![const])); - let m = p.start(); - p.bump(T![const]); - expressions::block_expr(p); - m.complete(p, CONST_BLOCK_PAT) -} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs deleted file mode 100644 index 5c6e18fee8bff..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs +++ /dev/null @@ -1,352 +0,0 @@ -use super::*; - -pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(TokenSet::new(&[ - T!['('], - T!['['], - T![<], - T![!], - T![*], - T![&], - T![_], - T![fn], - T![unsafe], - T![extern], - T![for], - T![impl], - T![dyn], - T![Self], -])); - -const TYPE_RECOVERY_SET: TokenSet = TokenSet::new(&[ - T![')'], - T![,], - // test_err struct_field_recover - // struct S { f pub g: () } - T![pub], -]); - -pub(crate) fn type_(p: &mut Parser<'_>) { - type_with_bounds_cond(p, true); -} - -pub(super) fn type_no_bounds(p: &mut Parser<'_>) { - type_with_bounds_cond(p, false); -} - -fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) { - match p.current() { - T!['('] => paren_or_tuple_type(p), - T![!] => never_type(p), - T![*] => ptr_type(p), - T!['['] => array_or_slice_type(p), - T![&] => ref_type(p), - T![_] => infer_type(p), - T![fn] | T![unsafe] | T![extern] => fn_ptr_type(p), - T![for] => for_type(p, allow_bounds), - T![impl] => impl_trait_type(p), - T![dyn] => dyn_trait_type(p), - // Some path types are not allowed to have bounds (no plus) - T![<] => path_type_(p, allow_bounds), - _ if paths::is_path_start(p) => path_or_macro_type_(p, allow_bounds), - _ => { - p.err_recover("expected type", TYPE_RECOVERY_SET); - } - } -} - -pub(super) fn ascription(p: &mut Parser<'_>) { - assert!(p.at(T![:])); - p.bump(T![:]); - if p.at(T![=]) { - // recover from `let x: = expr;`, `const X: = expr;` and similars - // hopefully no type starts with `=` - p.error("missing type"); - return; - } - type_(p); -} - -fn paren_or_tuple_type(p: &mut Parser<'_>) { - assert!(p.at(T!['('])); - let m = p.start(); - p.bump(T!['(']); - let mut n_types: u32 = 0; - let mut trailing_comma: bool = false; - while !p.at(EOF) && !p.at(T![')']) { - n_types += 1; - type_(p); - if p.eat(T![,]) { - trailing_comma = true; - } else { - trailing_comma = false; - break; - } - } - p.expect(T![')']); - - let kind = if n_types == 1 && !trailing_comma { - // test paren_type - // type T = (i32); - PAREN_TYPE - } else { - // test unit_type - // type T = (); - - // test singleton_tuple_type - // type T = (i32,); - TUPLE_TYPE - }; - m.complete(p, kind); -} - -// test never_type -// type Never = !; -fn never_type(p: &mut Parser<'_>) { - assert!(p.at(T![!])); - let m = p.start(); - p.bump(T![!]); - m.complete(p, NEVER_TYPE); -} - -fn ptr_type(p: &mut Parser<'_>) { - assert!(p.at(T![*])); - let m = p.start(); - p.bump(T![*]); - - match p.current() { - // test pointer_type_mut - // type M = *mut (); - // type C = *mut (); - T![mut] | T![const] => p.bump_any(), - _ => { - // test_err pointer_type_no_mutability - // type T = *(); - p.error( - "expected mut or const in raw pointer type \ - (use `*mut T` or `*const T` as appropriate)", - ); - } - }; - - type_no_bounds(p); - m.complete(p, PTR_TYPE); -} - -fn array_or_slice_type(p: &mut Parser<'_>) { - assert!(p.at(T!['['])); - let m = p.start(); - p.bump(T!['[']); - - type_(p); - let kind = match p.current() { - // test slice_type - // type T = [()]; - T![']'] => { - p.bump(T![']']); - SLICE_TYPE - } - - // test array_type - // type T = [(); 92]; - T![;] => { - p.bump(T![;]); - expressions::expr(p); - p.expect(T![']']); - ARRAY_TYPE - } - // test_err array_type_missing_semi - // type T = [() 92]; - _ => { - p.error("expected `;` or `]`"); - SLICE_TYPE - } - }; - m.complete(p, kind); -} - -// test reference_type; -// type A = &(); -// type B = &'static (); -// type C = &mut (); -fn ref_type(p: &mut Parser<'_>) { - assert!(p.at(T![&])); - let m = p.start(); - p.bump(T![&]); - if p.at(LIFETIME_IDENT) { - lifetime(p); - } - p.eat(T![mut]); - type_no_bounds(p); - m.complete(p, REF_TYPE); -} - -// test placeholder_type -// type Placeholder = _; -fn infer_type(p: &mut Parser<'_>) { - assert!(p.at(T![_])); - let m = p.start(); - p.bump(T![_]); - m.complete(p, INFER_TYPE); -} - -// test fn_pointer_type -// type A = fn(); -// type B = unsafe fn(); -// type C = unsafe extern "C" fn(); -// type D = extern "C" fn ( u8 , ... ) -> u8; -fn fn_ptr_type(p: &mut Parser<'_>) { - let m = p.start(); - p.eat(T![unsafe]); - if p.at(T![extern]) { - abi(p); - } - // test_err fn_pointer_type_missing_fn - // type F = unsafe (); - if !p.eat(T![fn]) { - m.abandon(p); - p.error("expected `fn`"); - return; - } - if p.at(T!['(']) { - params::param_list_fn_ptr(p); - } else { - p.error("expected parameters"); - } - // test fn_pointer_type_with_ret - // type F = fn() -> (); - opt_ret_type(p); - m.complete(p, FN_PTR_TYPE); -} - -pub(super) fn for_binder(p: &mut Parser<'_>) { - assert!(p.at(T![for])); - p.bump(T![for]); - if p.at(T![<]) { - generic_params::opt_generic_param_list(p); - } else { - p.error("expected `<`"); - } -} - -// test for_type -// type A = for<'a> fn() -> (); -// type B = for<'a> unsafe extern "C" fn(&'a ()) -> (); -// type Obj = for<'a> PartialEq<&'a i32>; -pub(super) fn for_type(p: &mut Parser<'_>, allow_bounds: bool) { - assert!(p.at(T![for])); - let m = p.start(); - for_binder(p); - match p.current() { - T![fn] | T![unsafe] | T![extern] => {} - // OK: legacy trait object format - _ if paths::is_use_path_start(p) => {} - _ => { - p.error("expected a function pointer or path"); - } - } - type_no_bounds(p); - let completed = m.complete(p, FOR_TYPE); - - // test no_dyn_trait_leading_for - // type A = for<'a> Test<'a> + Send; - if allow_bounds { - opt_type_bounds_as_dyn_trait_type(p, completed); - } -} - -// test impl_trait_type -// type A = impl Iterator> + 'a; -fn impl_trait_type(p: &mut Parser<'_>) { - assert!(p.at(T![impl])); - let m = p.start(); - p.bump(T![impl]); - generic_params::bounds_without_colon(p); - m.complete(p, IMPL_TRAIT_TYPE); -} - -// test dyn_trait_type -// type A = dyn Iterator> + 'a; -fn dyn_trait_type(p: &mut Parser<'_>) { - assert!(p.at(T![dyn])); - let m = p.start(); - p.bump(T![dyn]); - generic_params::bounds_without_colon(p); - m.complete(p, DYN_TRAIT_TYPE); -} - -// test path_type -// type A = Foo; -// type B = ::Foo; -// type C = self::Foo; -// type D = super::Foo; -pub(super) fn path_type(p: &mut Parser<'_>) { - path_type_(p, true); -} - -// test macro_call_type -// type A = foo!(); -// type B = crate::foo!(); -fn path_or_macro_type_(p: &mut Parser<'_>, allow_bounds: bool) { - assert!(paths::is_path_start(p)); - let r = p.start(); - let m = p.start(); - - paths::type_path(p); - - let kind = if p.at(T![!]) && !p.at(T![!=]) { - items::macro_call_after_excl(p); - m.complete(p, MACRO_CALL); - MACRO_TYPE - } else { - m.abandon(p); - PATH_TYPE - }; - - let path = r.complete(p, kind); - - if allow_bounds { - opt_type_bounds_as_dyn_trait_type(p, path); - } -} - -pub(super) fn path_type_(p: &mut Parser<'_>, allow_bounds: bool) { - assert!(paths::is_path_start(p)); - let m = p.start(); - paths::type_path(p); - - // test path_type_with_bounds - // fn foo() -> Box {} - // fn foo() -> Box {} - let path = m.complete(p, PATH_TYPE); - if allow_bounds { - opt_type_bounds_as_dyn_trait_type(p, path); - } -} - -/// This turns a parsed PATH_TYPE or FOR_TYPE optionally into a DYN_TRAIT_TYPE -/// with a TYPE_BOUND_LIST -fn opt_type_bounds_as_dyn_trait_type(p: &mut Parser<'_>, type_marker: CompletedMarker) { - assert!(matches!( - type_marker.kind(), - SyntaxKind::PATH_TYPE | SyntaxKind::FOR_TYPE | SyntaxKind::MACRO_TYPE - )); - if !p.at(T![+]) { - return; - } - - // First create a TYPE_BOUND from the completed PATH_TYPE - let m = type_marker.precede(p).complete(p, TYPE_BOUND); - - // Next setup a marker for the TYPE_BOUND_LIST - let m = m.precede(p); - - // This gets consumed here so it gets properly set - // in the TYPE_BOUND_LIST - p.eat(T![+]); - - // Parse rest of the bounds into the TYPE_BOUND_LIST - let m = generic_params::bounds_without_colon_m(p, m); - - // Finally precede everything with DYN_TRAIT_TYPE - m.precede(p).complete(p, DYN_TRAIT_TYPE); -} diff --git a/src/tools/rust-analyzer/crates/parser/src/input.rs b/src/tools/rust-analyzer/crates/parser/src/input.rs deleted file mode 100644 index 9504bd4d9ec83..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/input.rs +++ /dev/null @@ -1,88 +0,0 @@ -//! See [`Input`]. - -use crate::SyntaxKind; - -#[allow(non_camel_case_types)] -type bits = u64; - -/// Input for the parser -- a sequence of tokens. -/// -/// As of now, parser doesn't have access to the *text* of the tokens, and makes -/// decisions based solely on their classification. Unlike `LexerToken`, the -/// `Tokens` doesn't include whitespace and comments. Main input to the parser. -/// -/// Struct of arrays internally, but this shouldn't really matter. -#[derive(Default)] -pub struct Input { - kind: Vec, - joint: Vec, - contextual_kind: Vec, -} - -/// `pub` impl used by callers to create `Tokens`. -impl Input { - #[inline] - pub fn push(&mut self, kind: SyntaxKind) { - self.push_impl(kind, SyntaxKind::EOF) - } - #[inline] - pub fn push_ident(&mut self, contextual_kind: SyntaxKind) { - self.push_impl(SyntaxKind::IDENT, contextual_kind) - } - /// Sets jointness for the last token we've pushed. - /// - /// This is a separate API rather than an argument to the `push` to make it - /// convenient both for textual and mbe tokens. With text, you know whether - /// the *previous* token was joint, with mbe, you know whether the *current* - /// one is joint. This API allows for styles of usage: - /// - /// ``` - /// // In text: - /// tokens.was_joint(prev_joint); - /// tokens.push(curr); - /// - /// // In MBE: - /// token.push(curr); - /// tokens.push(curr_joint) - /// ``` - #[inline] - pub fn was_joint(&mut self) { - let n = self.len() - 1; - let (idx, b_idx) = self.bit_index(n); - self.joint[idx] |= 1 << b_idx; - } - #[inline] - fn push_impl(&mut self, kind: SyntaxKind, contextual_kind: SyntaxKind) { - let idx = self.len(); - if idx % (bits::BITS as usize) == 0 { - self.joint.push(0); - } - self.kind.push(kind); - self.contextual_kind.push(contextual_kind); - } -} - -/// pub(crate) impl used by the parser to consume `Tokens`. -impl Input { - pub(crate) fn kind(&self, idx: usize) -> SyntaxKind { - self.kind.get(idx).copied().unwrap_or(SyntaxKind::EOF) - } - pub(crate) fn contextual_kind(&self, idx: usize) -> SyntaxKind { - self.contextual_kind.get(idx).copied().unwrap_or(SyntaxKind::EOF) - } - pub(crate) fn is_joint(&self, n: usize) -> bool { - let (idx, b_idx) = self.bit_index(n); - self.joint[idx] & 1 << b_idx != 0 - } -} - -impl Input { - fn bit_index(&self, n: usize) -> (usize, usize) { - let idx = n / (bits::BITS as usize); - let b_idx = n % (bits::BITS as usize); - (idx, b_idx) - } - fn len(&self) -> usize { - self.kind.len() - } -} diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs deleted file mode 100644 index f4b9988eacb0c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ /dev/null @@ -1,300 +0,0 @@ -//! Lexing `&str` into a sequence of Rust tokens. -//! -//! Note that strictly speaking the parser in this crate is not required to work -//! on tokens which originated from text. Macros, eg, can synthesize tokens out -//! of thin air. So, ideally, lexer should be an orthogonal crate. It is however -//! convenient to include a text-based lexer here! -//! -//! Note that these tokens, unlike the tokens we feed into the parser, do -//! include info about comments and whitespace. - -use std::ops; - -use crate::{ - SyntaxKind::{self, *}, - T, -}; - -pub struct LexedStr<'a> { - text: &'a str, - kind: Vec, - start: Vec, - error: Vec, -} - -struct LexError { - msg: String, - token: u32, -} - -impl<'a> LexedStr<'a> { - pub fn new(text: &'a str) -> LexedStr<'a> { - let mut conv = Converter::new(text); - if let Some(shebang_len) = rustc_lexer::strip_shebang(text) { - conv.res.push(SHEBANG, conv.offset); - conv.offset = shebang_len; - }; - - for token in rustc_lexer::tokenize(&text[conv.offset..]) { - let token_text = &text[conv.offset..][..token.len]; - - conv.extend_token(&token.kind, token_text); - } - - conv.finalize_with_eof() - } - - pub fn single_token(text: &'a str) -> Option<(SyntaxKind, Option)> { - if text.is_empty() { - return None; - } - - let token = rustc_lexer::first_token(text); - if token.len != text.len() { - return None; - } - - let mut conv = Converter::new(text); - conv.extend_token(&token.kind, text); - match &*conv.res.kind { - [kind] => Some((*kind, conv.res.error.pop().map(|it| it.msg.clone()))), - _ => None, - } - } - - pub fn as_str(&self) -> &str { - self.text - } - - pub fn len(&self) -> usize { - self.kind.len() - 1 - } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - pub fn kind(&self, i: usize) -> SyntaxKind { - assert!(i < self.len()); - self.kind[i] - } - - pub fn text(&self, i: usize) -> &str { - self.range_text(i..i + 1) - } - pub fn range_text(&self, r: ops::Range) -> &str { - assert!(r.start < r.end && r.end <= self.len()); - let lo = self.start[r.start] as usize; - let hi = self.start[r.end] as usize; - &self.text[lo..hi] - } - - // Naming is hard. - pub fn text_range(&self, i: usize) -> ops::Range { - assert!(i < self.len()); - let lo = self.start[i] as usize; - let hi = self.start[i + 1] as usize; - lo..hi - } - pub fn text_start(&self, i: usize) -> usize { - assert!(i <= self.len()); - self.start[i] as usize - } - pub fn text_len(&self, i: usize) -> usize { - assert!(i < self.len()); - let r = self.text_range(i); - r.end - r.start - } - - pub fn error(&self, i: usize) -> Option<&str> { - assert!(i < self.len()); - let err = self.error.binary_search_by_key(&(i as u32), |i| i.token).ok()?; - Some(self.error[err].msg.as_str()) - } - - pub fn errors(&self) -> impl Iterator + '_ { - self.error.iter().map(|it| (it.token as usize, it.msg.as_str())) - } - - fn push(&mut self, kind: SyntaxKind, offset: usize) { - self.kind.push(kind); - self.start.push(offset as u32); - } -} - -struct Converter<'a> { - res: LexedStr<'a>, - offset: usize, -} - -impl<'a> Converter<'a> { - fn new(text: &'a str) -> Self { - Self { - res: LexedStr { text, kind: Vec::new(), start: Vec::new(), error: Vec::new() }, - offset: 0, - } - } - - fn finalize_with_eof(mut self) -> LexedStr<'a> { - self.res.push(EOF, self.offset); - self.res - } - - fn push(&mut self, kind: SyntaxKind, len: usize, err: Option<&str>) { - self.res.push(kind, self.offset); - self.offset += len; - - if let Some(err) = err { - let token = self.res.len() as u32; - let msg = err.to_string(); - self.res.error.push(LexError { msg, token }); - } - } - - fn extend_token(&mut self, kind: &rustc_lexer::TokenKind, token_text: &str) { - // A note on an intended tradeoff: - // We drop some useful information here (see patterns with double dots `..`) - // Storing that info in `SyntaxKind` is not possible due to its layout requirements of - // being `u16` that come from `rowan::SyntaxKind`. - let mut err = ""; - - let syntax_kind = { - match kind { - rustc_lexer::TokenKind::LineComment { doc_style: _ } => COMMENT, - rustc_lexer::TokenKind::BlockComment { doc_style: _, terminated } => { - if !terminated { - err = "Missing trailing `*/` symbols to terminate the block comment"; - } - COMMENT - } - - rustc_lexer::TokenKind::Whitespace => WHITESPACE, - - rustc_lexer::TokenKind::Ident if token_text == "_" => UNDERSCORE, - rustc_lexer::TokenKind::Ident => { - SyntaxKind::from_keyword(token_text).unwrap_or(IDENT) - } - - rustc_lexer::TokenKind::RawIdent => IDENT, - rustc_lexer::TokenKind::Literal { kind, .. } => { - self.extend_literal(token_text.len(), kind); - return; - } - - rustc_lexer::TokenKind::Lifetime { starts_with_number } => { - if *starts_with_number { - err = "Lifetime name cannot start with a number"; - } - LIFETIME_IDENT - } - - rustc_lexer::TokenKind::Semi => T![;], - rustc_lexer::TokenKind::Comma => T![,], - rustc_lexer::TokenKind::Dot => T![.], - rustc_lexer::TokenKind::OpenParen => T!['('], - rustc_lexer::TokenKind::CloseParen => T![')'], - rustc_lexer::TokenKind::OpenBrace => T!['{'], - rustc_lexer::TokenKind::CloseBrace => T!['}'], - rustc_lexer::TokenKind::OpenBracket => T!['['], - rustc_lexer::TokenKind::CloseBracket => T![']'], - rustc_lexer::TokenKind::At => T![@], - rustc_lexer::TokenKind::Pound => T![#], - rustc_lexer::TokenKind::Tilde => T![~], - rustc_lexer::TokenKind::Question => T![?], - rustc_lexer::TokenKind::Colon => T![:], - rustc_lexer::TokenKind::Dollar => T![$], - rustc_lexer::TokenKind::Eq => T![=], - rustc_lexer::TokenKind::Bang => T![!], - rustc_lexer::TokenKind::Lt => T![<], - rustc_lexer::TokenKind::Gt => T![>], - rustc_lexer::TokenKind::Minus => T![-], - rustc_lexer::TokenKind::And => T![&], - rustc_lexer::TokenKind::Or => T![|], - rustc_lexer::TokenKind::Plus => T![+], - rustc_lexer::TokenKind::Star => T![*], - rustc_lexer::TokenKind::Slash => T![/], - rustc_lexer::TokenKind::Caret => T![^], - rustc_lexer::TokenKind::Percent => T![%], - rustc_lexer::TokenKind::Unknown => ERROR, - } - }; - - let err = if err.is_empty() { None } else { Some(err) }; - self.push(syntax_kind, token_text.len(), err); - } - - fn extend_literal(&mut self, len: usize, kind: &rustc_lexer::LiteralKind) { - let mut err = ""; - - let syntax_kind = match *kind { - rustc_lexer::LiteralKind::Int { empty_int, base: _ } => { - if empty_int { - err = "Missing digits after the integer base prefix"; - } - INT_NUMBER - } - rustc_lexer::LiteralKind::Float { empty_exponent, base: _ } => { - if empty_exponent { - err = "Missing digits after the exponent symbol"; - } - FLOAT_NUMBER - } - rustc_lexer::LiteralKind::Char { terminated } => { - if !terminated { - err = "Missing trailing `'` symbol to terminate the character literal"; - } - CHAR - } - rustc_lexer::LiteralKind::Byte { terminated } => { - if !terminated { - err = "Missing trailing `'` symbol to terminate the byte literal"; - } - BYTE - } - rustc_lexer::LiteralKind::Str { terminated } => { - if !terminated { - err = "Missing trailing `\"` symbol to terminate the string literal"; - } - STRING - } - rustc_lexer::LiteralKind::ByteStr { terminated } => { - if !terminated { - err = "Missing trailing `\"` symbol to terminate the byte string literal"; - } - BYTE_STRING - } - rustc_lexer::LiteralKind::RawStr { err: raw_str_err, .. } => { - if let Some(raw_str_err) = raw_str_err { - err = match raw_str_err { - rustc_lexer::RawStrError::InvalidStarter { .. } => "Missing `\"` symbol after `#` symbols to begin the raw string literal", - rustc_lexer::RawStrError::NoTerminator { expected, found, .. } => if expected == found { - "Missing trailing `\"` to terminate the raw string literal" - } else { - "Missing trailing `\"` with `#` symbols to terminate the raw string literal" - }, - rustc_lexer::RawStrError::TooManyDelimiters { .. } => "Too many `#` symbols: raw strings may be delimited by up to 65535 `#` symbols", - }; - }; - STRING - } - rustc_lexer::LiteralKind::RawByteStr { err: raw_str_err, .. } => { - if let Some(raw_str_err) = raw_str_err { - err = match raw_str_err { - rustc_lexer::RawStrError::InvalidStarter { .. } => "Missing `\"` symbol after `#` symbols to begin the raw byte string literal", - rustc_lexer::RawStrError::NoTerminator { expected, found, .. } => if expected == found { - "Missing trailing `\"` to terminate the raw byte string literal" - } else { - "Missing trailing `\"` with `#` symbols to terminate the raw byte string literal" - }, - rustc_lexer::RawStrError::TooManyDelimiters { .. } => "Too many `#` symbols: raw byte strings may be delimited by up to 65535 `#` symbols", - }; - }; - - BYTE_STRING - } - }; - - let err = if err.is_empty() { None } else { Some(err) }; - self.push(syntax_kind, len, err); - } -} diff --git a/src/tools/rust-analyzer/crates/parser/src/lib.rs b/src/tools/rust-analyzer/crates/parser/src/lib.rs deleted file mode 100644 index 87be47927735a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/lib.rs +++ /dev/null @@ -1,181 +0,0 @@ -//! The Rust parser. -//! -//! NOTE: The crate is undergoing refactors, don't believe everything the docs -//! say :-) -//! -//! The parser doesn't know about concrete representation of tokens and syntax -//! trees. Abstract [`TokenSource`] and [`TreeSink`] traits are used instead. As -//! a consequence, this crate does not contain a lexer. -//! -//! The [`Parser`] struct from the [`parser`] module is a cursor into the -//! sequence of tokens. Parsing routines use [`Parser`] to inspect current -//! state and advance the parsing. -//! -//! The actual parsing happens in the [`grammar`] module. -//! -//! Tests for this crate live in the `syntax` crate. -//! -//! [`Parser`]: crate::parser::Parser - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] -#![allow(rustdoc::private_intra_doc_links)] - -mod lexed_str; -mod token_set; -mod syntax_kind; -mod event; -mod parser; -mod grammar; -mod input; -mod output; -mod shortcuts; - -#[cfg(test)] -mod tests; - -pub(crate) use token_set::TokenSet; - -pub use crate::{ - input::Input, - lexed_str::LexedStr, - output::{Output, Step}, - shortcuts::StrStep, - syntax_kind::SyntaxKind, -}; - -/// Parse the whole of the input as a given syntactic construct. -/// -/// This covers two main use-cases: -/// -/// * Parsing a Rust file. -/// * Parsing a result of macro expansion. -/// -/// That is, for something like -/// -/// ``` -/// quick_check! { -/// fn prop() {} -/// } -/// ``` -/// -/// the input to the macro will be parsed with [`PrefixEntryPoint::Item`], and -/// the result will be [`TopEntryPoint::MacroItems`]. -/// -/// [`TopEntryPoint::parse`] makes a guarantee that -/// * all input is consumed -/// * the result is a valid tree (there's one root node) -#[derive(Debug)] -pub enum TopEntryPoint { - SourceFile, - MacroStmts, - MacroItems, - Pattern, - Type, - Expr, - /// Edge case -- macros generally don't expand to attributes, with the - /// exception of `cfg_attr` which does! - MetaItem, -} - -impl TopEntryPoint { - pub fn parse(&self, input: &Input) -> Output { - let entry_point: fn(&'_ mut parser::Parser<'_>) = match self { - TopEntryPoint::SourceFile => grammar::entry::top::source_file, - TopEntryPoint::MacroStmts => grammar::entry::top::macro_stmts, - TopEntryPoint::MacroItems => grammar::entry::top::macro_items, - TopEntryPoint::Pattern => grammar::entry::top::pattern, - TopEntryPoint::Type => grammar::entry::top::type_, - TopEntryPoint::Expr => grammar::entry::top::expr, - TopEntryPoint::MetaItem => grammar::entry::top::meta_item, - }; - let mut p = parser::Parser::new(input); - entry_point(&mut p); - let events = p.finish(); - let res = event::process(events); - - if cfg!(debug_assertions) { - let mut depth = 0; - let mut first = true; - for step in res.iter() { - assert!(depth > 0 || first); - first = false; - match step { - Step::Enter { .. } => depth += 1, - Step::Exit => depth -= 1, - Step::Token { .. } | Step::Error { .. } => (), - } - } - assert!(!first, "no tree at all"); - } - - res - } -} - -/// Parse a prefix of the input as a given syntactic construct. -/// -/// This is used by macro-by-example parser to implement things like `$i:item` -/// and the naming of variants follows the naming of macro fragments. -/// -/// Note that this is generally non-optional -- the result is intentionally not -/// `Option`. The way MBE work, by the time we *try* to parse `$e:expr` -/// we already commit to expression. In other words, this API by design can't be -/// used to implement "rollback and try another alternative" logic. -#[derive(Debug)] -pub enum PrefixEntryPoint { - Vis, - Block, - Stmt, - Pat, - Ty, - Expr, - Path, - Item, - MetaItem, -} - -impl PrefixEntryPoint { - pub fn parse(&self, input: &Input) -> Output { - let entry_point: fn(&'_ mut parser::Parser<'_>) = match self { - PrefixEntryPoint::Vis => grammar::entry::prefix::vis, - PrefixEntryPoint::Block => grammar::entry::prefix::block, - PrefixEntryPoint::Stmt => grammar::entry::prefix::stmt, - PrefixEntryPoint::Pat => grammar::entry::prefix::pat, - PrefixEntryPoint::Ty => grammar::entry::prefix::ty, - PrefixEntryPoint::Expr => grammar::entry::prefix::expr, - PrefixEntryPoint::Path => grammar::entry::prefix::path, - PrefixEntryPoint::Item => grammar::entry::prefix::item, - PrefixEntryPoint::MetaItem => grammar::entry::prefix::meta_item, - }; - let mut p = parser::Parser::new(input); - entry_point(&mut p); - let events = p.finish(); - event::process(events) - } -} - -/// A parsing function for a specific braced-block. -pub struct Reparser(fn(&mut parser::Parser<'_>)); - -impl Reparser { - /// If the node is a braced block, return the corresponding `Reparser`. - pub fn for_node( - node: SyntaxKind, - first_child: Option, - parent: Option, - ) -> Option { - grammar::reparser(node, first_child, parent).map(Reparser) - } - - /// Re-parse given tokens using this `Reparser`. - /// - /// Tokens must start with `{`, end with `}` and form a valid brace - /// sequence. - pub fn parse(self, tokens: &Input) -> Output { - let Reparser(r) = self; - let mut p = parser::Parser::new(tokens); - r(&mut p); - let events = p.finish(); - event::process(events) - } -} diff --git a/src/tools/rust-analyzer/crates/parser/src/output.rs b/src/tools/rust-analyzer/crates/parser/src/output.rs deleted file mode 100644 index e9ec9822d68c3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/output.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! See [`Output`] - -use crate::SyntaxKind; - -/// Output of the parser -- a DFS traversal of a concrete syntax tree. -/// -/// Use the [`Output::iter`] method to iterate over traversal steps and consume -/// a syntax tree. -/// -/// In a sense, this is just a sequence of [`SyntaxKind`]-colored parenthesis -/// interspersed into the original [`crate::Input`]. The output is fundamentally -/// coordinated with the input and `n_input_tokens` refers to the number of -/// times [`crate::Input::push`] was called. -#[derive(Default)] -pub struct Output { - /// 32-bit encoding of events. If LSB is zero, then that's an index into the - /// error vector. Otherwise, it's one of the thee other variants, with data encoded as - /// - /// |16 bit kind|8 bit n_input_tokens|4 bit tag|4 bit leftover| - /// - event: Vec, - error: Vec, -} - -#[derive(Debug)] -pub enum Step<'a> { - Token { kind: SyntaxKind, n_input_tokens: u8 }, - Enter { kind: SyntaxKind }, - Exit, - Error { msg: &'a str }, -} - -impl Output { - pub fn iter(&self) -> impl Iterator> { - self.event.iter().map(|&event| { - if event & 0b1 == 0 { - return Step::Error { msg: self.error[(event as usize) >> 1].as_str() }; - } - let tag = ((event & 0x0000_00F0) >> 4) as u8; - match tag { - 0 => { - let kind: SyntaxKind = (((event & 0xFFFF_0000) >> 16) as u16).into(); - let n_input_tokens = ((event & 0x0000_FF00) >> 8) as u8; - Step::Token { kind, n_input_tokens } - } - 1 => { - let kind: SyntaxKind = (((event & 0xFFFF_0000) >> 16) as u16).into(); - Step::Enter { kind } - } - 2 => Step::Exit, - _ => unreachable!(), - } - }) - } - - pub(crate) fn token(&mut self, kind: SyntaxKind, n_tokens: u8) { - let e = ((kind as u16 as u32) << 16) | ((n_tokens as u32) << 8) | (0 << 4) | 1; - self.event.push(e) - } - - pub(crate) fn enter_node(&mut self, kind: SyntaxKind) { - let e = ((kind as u16 as u32) << 16) | (1 << 4) | 1; - self.event.push(e) - } - - pub(crate) fn leave_node(&mut self) { - let e = 2 << 4 | 1; - self.event.push(e) - } - - pub(crate) fn error(&mut self, error: String) { - let idx = self.error.len(); - self.error.push(error); - let e = (idx as u32) << 1; - self.event.push(e); - } -} diff --git a/src/tools/rust-analyzer/crates/parser/src/parser.rs b/src/tools/rust-analyzer/crates/parser/src/parser.rs deleted file mode 100644 index 48d8350e07ee8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/parser.rs +++ /dev/null @@ -1,340 +0,0 @@ -//! See [`Parser`]. - -use std::cell::Cell; - -use drop_bomb::DropBomb; -use limit::Limit; - -use crate::{ - event::Event, - input::Input, - SyntaxKind::{self, EOF, ERROR, TOMBSTONE}, - TokenSet, T, -}; - -/// `Parser` struct provides the low-level API for -/// navigating through the stream of tokens and -/// constructing the parse tree. The actual parsing -/// happens in the [`grammar`](super::grammar) module. -/// -/// However, the result of this `Parser` is not a real -/// tree, but rather a flat stream of events of the form -/// "start expression, consume number literal, -/// finish expression". See `Event` docs for more. -pub(crate) struct Parser<'t> { - inp: &'t Input, - pos: usize, - events: Vec, - steps: Cell, -} - -static PARSER_STEP_LIMIT: Limit = Limit::new(15_000_000); - -impl<'t> Parser<'t> { - pub(super) fn new(inp: &'t Input) -> Parser<'t> { - Parser { inp, pos: 0, events: Vec::new(), steps: Cell::new(0) } - } - - pub(crate) fn finish(self) -> Vec { - self.events - } - - /// Returns the kind of the current token. - /// If parser has already reached the end of input, - /// the special `EOF` kind is returned. - pub(crate) fn current(&self) -> SyntaxKind { - self.nth(0) - } - - /// Lookahead operation: returns the kind of the next nth - /// token. - pub(crate) fn nth(&self, n: usize) -> SyntaxKind { - assert!(n <= 3); - - let steps = self.steps.get(); - assert!(PARSER_STEP_LIMIT.check(steps as usize).is_ok(), "the parser seems stuck"); - self.steps.set(steps + 1); - - self.inp.kind(self.pos + n) - } - - /// Checks if the current token is `kind`. - pub(crate) fn at(&self, kind: SyntaxKind) -> bool { - self.nth_at(0, kind) - } - - pub(crate) fn nth_at(&self, n: usize, kind: SyntaxKind) -> bool { - match kind { - T![-=] => self.at_composite2(n, T![-], T![=]), - T![->] => self.at_composite2(n, T![-], T![>]), - T![::] => self.at_composite2(n, T![:], T![:]), - T![!=] => self.at_composite2(n, T![!], T![=]), - T![..] => self.at_composite2(n, T![.], T![.]), - T![*=] => self.at_composite2(n, T![*], T![=]), - T![/=] => self.at_composite2(n, T![/], T![=]), - T![&&] => self.at_composite2(n, T![&], T![&]), - T![&=] => self.at_composite2(n, T![&], T![=]), - T![%=] => self.at_composite2(n, T![%], T![=]), - T![^=] => self.at_composite2(n, T![^], T![=]), - T![+=] => self.at_composite2(n, T![+], T![=]), - T![<<] => self.at_composite2(n, T![<], T![<]), - T![<=] => self.at_composite2(n, T![<], T![=]), - T![==] => self.at_composite2(n, T![=], T![=]), - T![=>] => self.at_composite2(n, T![=], T![>]), - T![>=] => self.at_composite2(n, T![>], T![=]), - T![>>] => self.at_composite2(n, T![>], T![>]), - T![|=] => self.at_composite2(n, T![|], T![=]), - T![||] => self.at_composite2(n, T![|], T![|]), - - T![...] => self.at_composite3(n, T![.], T![.], T![.]), - T![..=] => self.at_composite3(n, T![.], T![.], T![=]), - T![<<=] => self.at_composite3(n, T![<], T![<], T![=]), - T![>>=] => self.at_composite3(n, T![>], T![>], T![=]), - - _ => self.inp.kind(self.pos + n) == kind, - } - } - - /// Consume the next token if `kind` matches. - pub(crate) fn eat(&mut self, kind: SyntaxKind) -> bool { - if !self.at(kind) { - return false; - } - let n_raw_tokens = match kind { - T![-=] - | T![->] - | T![::] - | T![!=] - | T![..] - | T![*=] - | T![/=] - | T![&&] - | T![&=] - | T![%=] - | T![^=] - | T![+=] - | T![<<] - | T![<=] - | T![==] - | T![=>] - | T![>=] - | T![>>] - | T![|=] - | T![||] => 2, - - T![...] | T![..=] | T![<<=] | T![>>=] => 3, - _ => 1, - }; - self.do_bump(kind, n_raw_tokens); - true - } - - fn at_composite2(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind) -> bool { - self.inp.kind(self.pos + n) == k1 - && self.inp.kind(self.pos + n + 1) == k2 - && self.inp.is_joint(self.pos + n) - } - - fn at_composite3(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind, k3: SyntaxKind) -> bool { - self.inp.kind(self.pos + n) == k1 - && self.inp.kind(self.pos + n + 1) == k2 - && self.inp.kind(self.pos + n + 2) == k3 - && self.inp.is_joint(self.pos + n) - && self.inp.is_joint(self.pos + n + 1) - } - - /// Checks if the current token is in `kinds`. - pub(crate) fn at_ts(&self, kinds: TokenSet) -> bool { - kinds.contains(self.current()) - } - - /// Checks if the current token is contextual keyword with text `t`. - pub(crate) fn at_contextual_kw(&self, kw: SyntaxKind) -> bool { - self.inp.contextual_kind(self.pos) == kw - } - - /// Starts a new node in the syntax tree. All nodes and tokens - /// consumed between the `start` and the corresponding `Marker::complete` - /// belong to the same node. - pub(crate) fn start(&mut self) -> Marker { - let pos = self.events.len() as u32; - self.push_event(Event::tombstone()); - Marker::new(pos) - } - - /// Consume the next token if `kind` matches. - pub(crate) fn bump(&mut self, kind: SyntaxKind) { - assert!(self.eat(kind)); - } - - /// Advances the parser by one token - pub(crate) fn bump_any(&mut self) { - let kind = self.nth(0); - if kind == EOF { - return; - } - self.do_bump(kind, 1); - } - - /// Advances the parser by one token, remapping its kind. - /// This is useful to create contextual keywords from - /// identifiers. For example, the lexer creates a `union` - /// *identifier* token, but the parser remaps it to the - /// `union` keyword, and keyword is what ends up in the - /// final tree. - pub(crate) fn bump_remap(&mut self, kind: SyntaxKind) { - if self.nth(0) == EOF { - // FIXME: panic!? - return; - } - self.do_bump(kind, 1); - } - - /// Emit error with the `message` - /// FIXME: this should be much more fancy and support - /// structured errors with spans and notes, like rustc - /// does. - pub(crate) fn error>(&mut self, message: T) { - let msg = message.into(); - self.push_event(Event::Error { msg }); - } - - /// Consume the next token if it is `kind` or emit an error - /// otherwise. - pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool { - if self.eat(kind) { - return true; - } - self.error(format!("expected {:?}", kind)); - false - } - - /// Create an error node and consume the next token. - pub(crate) fn err_and_bump(&mut self, message: &str) { - self.err_recover(message, TokenSet::EMPTY); - } - - /// Create an error node and consume the next token. - pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) { - match self.current() { - T!['{'] | T!['}'] => { - self.error(message); - return; - } - _ => (), - } - - if self.at_ts(recovery) { - self.error(message); - return; - } - - let m = self.start(); - self.error(message); - self.bump_any(); - m.complete(self, ERROR); - } - - fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) { - self.pos += n_raw_tokens as usize; - self.push_event(Event::Token { kind, n_raw_tokens }); - } - - fn push_event(&mut self, event: Event) { - self.events.push(event); - } -} - -/// See [`Parser::start`]. -pub(crate) struct Marker { - pos: u32, - bomb: DropBomb, -} - -impl Marker { - fn new(pos: u32) -> Marker { - Marker { pos, bomb: DropBomb::new("Marker must be either completed or abandoned") } - } - - /// Finishes the syntax tree node and assigns `kind` to it, - /// and mark the create a `CompletedMarker` for possible future - /// operation like `.precede()` to deal with forward_parent. - pub(crate) fn complete(mut self, p: &mut Parser<'_>, kind: SyntaxKind) -> CompletedMarker { - self.bomb.defuse(); - let idx = self.pos as usize; - match &mut p.events[idx] { - Event::Start { kind: slot, .. } => { - *slot = kind; - } - _ => unreachable!(), - } - p.push_event(Event::Finish); - CompletedMarker::new(self.pos, kind) - } - - /// Abandons the syntax tree node. All its children - /// are attached to its parent instead. - pub(crate) fn abandon(mut self, p: &mut Parser<'_>) { - self.bomb.defuse(); - let idx = self.pos as usize; - if idx == p.events.len() - 1 { - match p.events.pop() { - Some(Event::Start { kind: TOMBSTONE, forward_parent: None }) => (), - _ => unreachable!(), - } - } - } -} - -pub(crate) struct CompletedMarker { - pos: u32, - kind: SyntaxKind, -} - -impl CompletedMarker { - fn new(pos: u32, kind: SyntaxKind) -> Self { - CompletedMarker { pos, kind } - } - - /// This method allows to create a new node which starts - /// *before* the current one. That is, parser could start - /// node `A`, then complete it, and then after parsing the - /// whole `A`, decide that it should have started some node - /// `B` before starting `A`. `precede` allows to do exactly - /// that. See also docs about - /// [`Event::Start::forward_parent`](crate::event::Event::Start::forward_parent). - /// - /// Given completed events `[START, FINISH]` and its corresponding - /// `CompletedMarker(pos: 0, _)`. - /// Append a new `START` events as `[START, FINISH, NEWSTART]`, - /// then mark `NEWSTART` as `START`'s parent with saving its relative - /// distance to `NEWSTART` into forward_parent(=2 in this case); - pub(crate) fn precede(self, p: &mut Parser<'_>) -> Marker { - let new_pos = p.start(); - let idx = self.pos as usize; - match &mut p.events[idx] { - Event::Start { forward_parent, .. } => { - *forward_parent = Some(new_pos.pos - self.pos); - } - _ => unreachable!(), - } - new_pos - } - - /// Extends this completed marker *to the left* up to `m`. - pub(crate) fn extend_to(self, p: &mut Parser<'_>, mut m: Marker) -> CompletedMarker { - m.bomb.defuse(); - let idx = m.pos as usize; - match &mut p.events[idx] { - Event::Start { forward_parent, .. } => { - *forward_parent = Some(self.pos - m.pos); - } - _ => unreachable!(), - } - self - } - - pub(crate) fn kind(&self) -> SyntaxKind { - self.kind - } -} diff --git a/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs b/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs deleted file mode 100644 index 4b805faddcba9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs +++ /dev/null @@ -1,215 +0,0 @@ -//! Shortcuts that span lexer/parser abstraction. -//! -//! The way Rust works, parser doesn't necessary parse text, and you might -//! tokenize text without parsing it further. So, it makes sense to keep -//! abstract token parsing, and string tokenization as completely separate -//! layers. -//! -//! However, often you do pares text into syntax trees and the glue code for -//! that needs to live somewhere. Rather than putting it to lexer or parser, we -//! use a separate shortcuts module for that. - -use std::mem; - -use crate::{ - LexedStr, Step, - SyntaxKind::{self, *}, -}; - -#[derive(Debug)] -pub enum StrStep<'a> { - Token { kind: SyntaxKind, text: &'a str }, - Enter { kind: SyntaxKind }, - Exit, - Error { msg: &'a str, pos: usize }, -} - -impl<'a> LexedStr<'a> { - pub fn to_input(&self) -> crate::Input { - let mut res = crate::Input::default(); - let mut was_joint = false; - for i in 0..self.len() { - let kind = self.kind(i); - if kind.is_trivia() { - was_joint = false - } else { - if kind == SyntaxKind::IDENT { - let token_text = self.text(i); - let contextual_kw = SyntaxKind::from_contextual_keyword(token_text) - .unwrap_or(SyntaxKind::IDENT); - res.push_ident(contextual_kw); - } else { - if was_joint { - res.was_joint(); - } - res.push(kind); - } - was_joint = true; - } - } - res - } - - /// NB: only valid to call with Output from Reparser/TopLevelEntry. - pub fn intersperse_trivia( - &self, - output: &crate::Output, - sink: &mut dyn FnMut(StrStep<'_>), - ) -> bool { - let mut builder = Builder { lexed: self, pos: 0, state: State::PendingEnter, sink }; - - for event in output.iter() { - match event { - Step::Token { kind, n_input_tokens: n_raw_tokens } => { - builder.token(kind, n_raw_tokens) - } - Step::Enter { kind } => builder.enter(kind), - Step::Exit => builder.exit(), - Step::Error { msg } => { - let text_pos = builder.lexed.text_start(builder.pos); - (builder.sink)(StrStep::Error { msg, pos: text_pos }); - } - } - } - - match mem::replace(&mut builder.state, State::Normal) { - State::PendingExit => { - builder.eat_trivias(); - (builder.sink)(StrStep::Exit); - } - State::PendingEnter | State::Normal => unreachable!(), - } - - let is_eof = builder.pos == builder.lexed.len(); - is_eof - } -} - -struct Builder<'a, 'b> { - lexed: &'a LexedStr<'a>, - pos: usize, - state: State, - sink: &'b mut dyn FnMut(StrStep<'_>), -} - -enum State { - PendingEnter, - Normal, - PendingExit, -} - -impl Builder<'_, '_> { - fn token(&mut self, kind: SyntaxKind, n_tokens: u8) { - match mem::replace(&mut self.state, State::Normal) { - State::PendingEnter => unreachable!(), - State::PendingExit => (self.sink)(StrStep::Exit), - State::Normal => (), - } - self.eat_trivias(); - self.do_token(kind, n_tokens as usize); - } - - fn enter(&mut self, kind: SyntaxKind) { - match mem::replace(&mut self.state, State::Normal) { - State::PendingEnter => { - (self.sink)(StrStep::Enter { kind }); - // No need to attach trivias to previous node: there is no - // previous node. - return; - } - State::PendingExit => (self.sink)(StrStep::Exit), - State::Normal => (), - } - - let n_trivias = - (self.pos..self.lexed.len()).take_while(|&it| self.lexed.kind(it).is_trivia()).count(); - let leading_trivias = self.pos..self.pos + n_trivias; - let n_attached_trivias = n_attached_trivias( - kind, - leading_trivias.rev().map(|it| (self.lexed.kind(it), self.lexed.text(it))), - ); - self.eat_n_trivias(n_trivias - n_attached_trivias); - (self.sink)(StrStep::Enter { kind }); - self.eat_n_trivias(n_attached_trivias); - } - - fn exit(&mut self) { - match mem::replace(&mut self.state, State::PendingExit) { - State::PendingEnter => unreachable!(), - State::PendingExit => (self.sink)(StrStep::Exit), - State::Normal => (), - } - } - - fn eat_trivias(&mut self) { - while self.pos < self.lexed.len() { - let kind = self.lexed.kind(self.pos); - if !kind.is_trivia() { - break; - } - self.do_token(kind, 1); - } - } - - fn eat_n_trivias(&mut self, n: usize) { - for _ in 0..n { - let kind = self.lexed.kind(self.pos); - assert!(kind.is_trivia()); - self.do_token(kind, 1); - } - } - - fn do_token(&mut self, kind: SyntaxKind, n_tokens: usize) { - let text = &self.lexed.range_text(self.pos..self.pos + n_tokens); - self.pos += n_tokens; - (self.sink)(StrStep::Token { kind, text }); - } -} - -fn n_attached_trivias<'a>( - kind: SyntaxKind, - trivias: impl Iterator, -) -> usize { - match kind { - CONST | ENUM | FN | IMPL | MACRO_CALL | MACRO_DEF | MACRO_RULES | MODULE | RECORD_FIELD - | STATIC | STRUCT | TRAIT | TUPLE_FIELD | TYPE_ALIAS | UNION | USE | VARIANT => { - let mut res = 0; - let mut trivias = trivias.enumerate().peekable(); - - while let Some((i, (kind, text))) = trivias.next() { - match kind { - WHITESPACE if text.contains("\n\n") => { - // we check whether the next token is a doc-comment - // and skip the whitespace in this case - if let Some((COMMENT, peek_text)) = trivias.peek().map(|(_, pair)| pair) { - if is_outer(peek_text) { - continue; - } - } - break; - } - COMMENT => { - if is_inner(text) { - break; - } - res = i + 1; - } - _ => (), - } - } - res - } - _ => 0, - } -} - -fn is_outer(text: &str) -> bool { - if text.starts_with("////") || text.starts_with("/***") { - return false; - } - text.starts_with("///") || text.starts_with("/**") -} - -fn is_inner(text: &str) -> bool { - text.starts_with("//!") || text.starts_with("/*!") -} diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs deleted file mode 100644 index 0483adc776fa6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Defines [`SyntaxKind`] -- a fieldless enum of all possible syntactic -//! constructs of the Rust language. - -mod generated; - -#[allow(unreachable_pub)] -pub use self::generated::{SyntaxKind, T}; - -impl From for SyntaxKind { - #[inline] - fn from(d: u16) -> SyntaxKind { - assert!(d <= (SyntaxKind::__LAST as u16)); - unsafe { std::mem::transmute::(d) } - } -} - -impl From for u16 { - #[inline] - fn from(k: SyntaxKind) -> u16 { - k as u16 - } -} - -impl SyntaxKind { - #[inline] - pub fn is_trivia(self) -> bool { - matches!(self, SyntaxKind::WHITESPACE | SyntaxKind::COMMENT) - } -} diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs deleted file mode 100644 index 628fa745e752d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs +++ /dev/null @@ -1,390 +0,0 @@ -//! Generated by `sourcegen_ast`, do not edit by hand. - -#![allow(bad_style, missing_docs, unreachable_pub)] -#[doc = r" The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`."] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[repr(u16)] -pub enum SyntaxKind { - #[doc(hidden)] - TOMBSTONE, - #[doc(hidden)] - EOF, - SEMICOLON, - COMMA, - L_PAREN, - R_PAREN, - L_CURLY, - R_CURLY, - L_BRACK, - R_BRACK, - L_ANGLE, - R_ANGLE, - AT, - POUND, - TILDE, - QUESTION, - DOLLAR, - AMP, - PIPE, - PLUS, - STAR, - SLASH, - CARET, - PERCENT, - UNDERSCORE, - DOT, - DOT2, - DOT3, - DOT2EQ, - COLON, - COLON2, - EQ, - EQ2, - FAT_ARROW, - BANG, - NEQ, - MINUS, - THIN_ARROW, - LTEQ, - GTEQ, - PLUSEQ, - MINUSEQ, - PIPEEQ, - AMPEQ, - CARETEQ, - SLASHEQ, - STAREQ, - PERCENTEQ, - AMP2, - PIPE2, - SHL, - SHR, - SHLEQ, - SHREQ, - AS_KW, - ASYNC_KW, - AWAIT_KW, - BOX_KW, - BREAK_KW, - CONST_KW, - CONTINUE_KW, - CRATE_KW, - DYN_KW, - ELSE_KW, - ENUM_KW, - EXTERN_KW, - FALSE_KW, - FN_KW, - FOR_KW, - IF_KW, - IMPL_KW, - IN_KW, - LET_KW, - LOOP_KW, - MACRO_KW, - MATCH_KW, - MOD_KW, - MOVE_KW, - MUT_KW, - PUB_KW, - REF_KW, - RETURN_KW, - SELF_KW, - SELF_TYPE_KW, - STATIC_KW, - STRUCT_KW, - SUPER_KW, - TRAIT_KW, - TRUE_KW, - TRY_KW, - TYPE_KW, - UNSAFE_KW, - USE_KW, - WHERE_KW, - WHILE_KW, - YIELD_KW, - AUTO_KW, - DEFAULT_KW, - EXISTENTIAL_KW, - UNION_KW, - RAW_KW, - MACRO_RULES_KW, - INT_NUMBER, - FLOAT_NUMBER, - CHAR, - BYTE, - STRING, - BYTE_STRING, - ERROR, - IDENT, - WHITESPACE, - LIFETIME_IDENT, - COMMENT, - SHEBANG, - SOURCE_FILE, - STRUCT, - UNION, - ENUM, - FN, - RET_TYPE, - EXTERN_CRATE, - MODULE, - USE, - STATIC, - CONST, - TRAIT, - IMPL, - TYPE_ALIAS, - MACRO_CALL, - MACRO_RULES, - MACRO_ARM, - TOKEN_TREE, - MACRO_DEF, - PAREN_TYPE, - TUPLE_TYPE, - MACRO_TYPE, - NEVER_TYPE, - PATH_TYPE, - PTR_TYPE, - ARRAY_TYPE, - SLICE_TYPE, - REF_TYPE, - INFER_TYPE, - FN_PTR_TYPE, - FOR_TYPE, - IMPL_TRAIT_TYPE, - DYN_TRAIT_TYPE, - OR_PAT, - PAREN_PAT, - REF_PAT, - BOX_PAT, - IDENT_PAT, - WILDCARD_PAT, - REST_PAT, - PATH_PAT, - RECORD_PAT, - RECORD_PAT_FIELD_LIST, - RECORD_PAT_FIELD, - TUPLE_STRUCT_PAT, - TUPLE_PAT, - SLICE_PAT, - RANGE_PAT, - LITERAL_PAT, - MACRO_PAT, - CONST_BLOCK_PAT, - TUPLE_EXPR, - ARRAY_EXPR, - PAREN_EXPR, - PATH_EXPR, - CLOSURE_EXPR, - IF_EXPR, - WHILE_EXPR, - LOOP_EXPR, - FOR_EXPR, - CONTINUE_EXPR, - BREAK_EXPR, - LABEL, - BLOCK_EXPR, - STMT_LIST, - RETURN_EXPR, - YIELD_EXPR, - LET_EXPR, - UNDERSCORE_EXPR, - MACRO_EXPR, - MATCH_EXPR, - MATCH_ARM_LIST, - MATCH_ARM, - MATCH_GUARD, - RECORD_EXPR, - RECORD_EXPR_FIELD_LIST, - RECORD_EXPR_FIELD, - BOX_EXPR, - CALL_EXPR, - INDEX_EXPR, - METHOD_CALL_EXPR, - FIELD_EXPR, - AWAIT_EXPR, - TRY_EXPR, - CAST_EXPR, - REF_EXPR, - PREFIX_EXPR, - RANGE_EXPR, - BIN_EXPR, - EXTERN_BLOCK, - EXTERN_ITEM_LIST, - VARIANT, - RECORD_FIELD_LIST, - RECORD_FIELD, - TUPLE_FIELD_LIST, - TUPLE_FIELD, - VARIANT_LIST, - ITEM_LIST, - ASSOC_ITEM_LIST, - ATTR, - META, - USE_TREE, - USE_TREE_LIST, - PATH, - PATH_SEGMENT, - LITERAL, - RENAME, - VISIBILITY, - WHERE_CLAUSE, - WHERE_PRED, - ABI, - NAME, - NAME_REF, - LET_STMT, - LET_ELSE, - EXPR_STMT, - GENERIC_PARAM_LIST, - GENERIC_PARAM, - LIFETIME_PARAM, - TYPE_PARAM, - CONST_PARAM, - GENERIC_ARG_LIST, - LIFETIME, - LIFETIME_ARG, - TYPE_ARG, - ASSOC_TYPE_ARG, - CONST_ARG, - PARAM_LIST, - PARAM, - SELF_PARAM, - ARG_LIST, - TYPE_BOUND, - TYPE_BOUND_LIST, - MACRO_ITEMS, - MACRO_STMTS, - #[doc(hidden)] - __LAST, -} -use self::SyntaxKind::*; -impl SyntaxKind { - pub fn is_keyword(self) -> bool { - match self { - AS_KW | ASYNC_KW | AWAIT_KW | BOX_KW | BREAK_KW | CONST_KW | CONTINUE_KW | CRATE_KW - | DYN_KW | ELSE_KW | ENUM_KW | EXTERN_KW | FALSE_KW | FN_KW | FOR_KW | IF_KW - | IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW - | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | SELF_TYPE_KW | STATIC_KW - | STRUCT_KW | SUPER_KW | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW - | WHERE_KW | WHILE_KW | YIELD_KW | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW - | RAW_KW | MACRO_RULES_KW => true, - _ => false, - } - } - pub fn is_punct(self) -> bool { - match self { - SEMICOLON | COMMA | L_PAREN | R_PAREN | L_CURLY | R_CURLY | L_BRACK | R_BRACK - | L_ANGLE | R_ANGLE | AT | POUND | TILDE | QUESTION | DOLLAR | AMP | PIPE | PLUS - | STAR | SLASH | CARET | PERCENT | UNDERSCORE | DOT | DOT2 | DOT3 | DOT2EQ | COLON - | COLON2 | EQ | EQ2 | FAT_ARROW | BANG | NEQ | MINUS | THIN_ARROW | LTEQ | GTEQ - | PLUSEQ | MINUSEQ | PIPEEQ | AMPEQ | CARETEQ | SLASHEQ | STAREQ | PERCENTEQ | AMP2 - | PIPE2 | SHL | SHR | SHLEQ | SHREQ => true, - _ => false, - } - } - pub fn is_literal(self) -> bool { - match self { - INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING => true, - _ => false, - } - } - pub fn from_keyword(ident: &str) -> Option { - let kw = match ident { - "as" => AS_KW, - "async" => ASYNC_KW, - "await" => AWAIT_KW, - "box" => BOX_KW, - "break" => BREAK_KW, - "const" => CONST_KW, - "continue" => CONTINUE_KW, - "crate" => CRATE_KW, - "dyn" => DYN_KW, - "else" => ELSE_KW, - "enum" => ENUM_KW, - "extern" => EXTERN_KW, - "false" => FALSE_KW, - "fn" => FN_KW, - "for" => FOR_KW, - "if" => IF_KW, - "impl" => IMPL_KW, - "in" => IN_KW, - "let" => LET_KW, - "loop" => LOOP_KW, - "macro" => MACRO_KW, - "match" => MATCH_KW, - "mod" => MOD_KW, - "move" => MOVE_KW, - "mut" => MUT_KW, - "pub" => PUB_KW, - "ref" => REF_KW, - "return" => RETURN_KW, - "self" => SELF_KW, - "Self" => SELF_TYPE_KW, - "static" => STATIC_KW, - "struct" => STRUCT_KW, - "super" => SUPER_KW, - "trait" => TRAIT_KW, - "true" => TRUE_KW, - "try" => TRY_KW, - "type" => TYPE_KW, - "unsafe" => UNSAFE_KW, - "use" => USE_KW, - "where" => WHERE_KW, - "while" => WHILE_KW, - "yield" => YIELD_KW, - _ => return None, - }; - Some(kw) - } - pub fn from_contextual_keyword(ident: &str) -> Option { - let kw = match ident { - "auto" => AUTO_KW, - "default" => DEFAULT_KW, - "existential" => EXISTENTIAL_KW, - "union" => UNION_KW, - "raw" => RAW_KW, - "macro_rules" => MACRO_RULES_KW, - _ => return None, - }; - Some(kw) - } - pub fn from_char(c: char) -> Option { - let tok = match c { - ';' => SEMICOLON, - ',' => COMMA, - '(' => L_PAREN, - ')' => R_PAREN, - '{' => L_CURLY, - '}' => R_CURLY, - '[' => L_BRACK, - ']' => R_BRACK, - '<' => L_ANGLE, - '>' => R_ANGLE, - '@' => AT, - '#' => POUND, - '~' => TILDE, - '?' => QUESTION, - '$' => DOLLAR, - '&' => AMP, - '|' => PIPE, - '+' => PLUS, - '*' => STAR, - '/' => SLASH, - '^' => CARET, - '%' => PERCENT, - '_' => UNDERSCORE, - '.' => DOT, - ':' => COLON, - '=' => EQ, - '!' => BANG, - '-' => MINUS, - _ => return None, - }; - Some(tok) - } -} -#[macro_export] -macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; } -pub use T; diff --git a/src/tools/rust-analyzer/crates/parser/src/tests.rs b/src/tools/rust-analyzer/crates/parser/src/tests.rs deleted file mode 100644 index 735c0b3e40204..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/tests.rs +++ /dev/null @@ -1,166 +0,0 @@ -mod sourcegen_inline_tests; -mod top_entries; -mod prefix_entries; - -use std::{ - fmt::Write, - fs, - path::{Path, PathBuf}, -}; - -use expect_test::expect_file; - -use crate::{LexedStr, TopEntryPoint}; - -#[test] -fn lex_ok() { - for case in TestCase::list("lexer/ok") { - let actual = lex(&case.text); - expect_file![case.rast].assert_eq(&actual) - } -} - -#[test] -fn lex_err() { - for case in TestCase::list("lexer/err") { - let actual = lex(&case.text); - expect_file![case.rast].assert_eq(&actual) - } -} - -fn lex(text: &str) -> String { - let lexed = LexedStr::new(text); - - let mut res = String::new(); - for i in 0..lexed.len() { - let kind = lexed.kind(i); - let text = lexed.text(i); - let error = lexed.error(i); - - let error = error.map(|err| format!(" error: {}", err)).unwrap_or_default(); - writeln!(res, "{:?} {:?}{}", kind, text, error).unwrap(); - } - res -} - -#[test] -fn parse_ok() { - for case in TestCase::list("parser/ok") { - let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text); - assert!(!errors, "errors in an OK file {}:\n{}", case.rs.display(), actual); - expect_file![case.rast].assert_eq(&actual); - } -} - -#[test] -fn parse_inline_ok() { - for case in TestCase::list("parser/inline/ok") { - let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text); - assert!(!errors, "errors in an OK file {}:\n{}", case.rs.display(), actual); - expect_file![case.rast].assert_eq(&actual); - } -} - -#[test] -fn parse_err() { - for case in TestCase::list("parser/err") { - let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text); - assert!(errors, "no errors in an ERR file {}:\n{}", case.rs.display(), actual); - expect_file![case.rast].assert_eq(&actual) - } -} - -#[test] -fn parse_inline_err() { - for case in TestCase::list("parser/inline/err") { - let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text); - assert!(errors, "no errors in an ERR file {}:\n{}", case.rs.display(), actual); - expect_file![case.rast].assert_eq(&actual) - } -} - -fn parse(entry: TopEntryPoint, text: &str) -> (String, bool) { - let lexed = LexedStr::new(text); - let input = lexed.to_input(); - let output = entry.parse(&input); - - let mut buf = String::new(); - let mut errors = Vec::new(); - let mut indent = String::new(); - let mut depth = 0; - let mut len = 0; - lexed.intersperse_trivia(&output, &mut |step| match step { - crate::StrStep::Token { kind, text } => { - assert!(depth > 0); - len += text.len(); - write!(buf, "{}", indent).unwrap(); - write!(buf, "{:?} {:?}\n", kind, text).unwrap(); - } - crate::StrStep::Enter { kind } => { - assert!(depth > 0 || len == 0); - depth += 1; - write!(buf, "{}", indent).unwrap(); - write!(buf, "{:?}\n", kind).unwrap(); - indent.push_str(" "); - } - crate::StrStep::Exit => { - assert!(depth > 0); - depth -= 1; - indent.pop(); - indent.pop(); - } - crate::StrStep::Error { msg, pos } => { - assert!(depth > 0); - errors.push(format!("error {}: {}\n", pos, msg)) - } - }); - assert_eq!( - len, - text.len(), - "didn't parse all text.\nParsed:\n{}\n\nAll:\n{}\n", - &text[..len], - text - ); - - for (token, msg) in lexed.errors() { - let pos = lexed.text_start(token); - errors.push(format!("error {}: {}\n", pos, msg)); - } - - let has_errors = !errors.is_empty(); - for e in errors { - buf.push_str(&e); - } - (buf, has_errors) -} - -#[derive(PartialEq, Eq, PartialOrd, Ord)] -struct TestCase { - rs: PathBuf, - rast: PathBuf, - text: String, -} - -impl TestCase { - fn list(path: &'static str) -> Vec { - let crate_root_dir = Path::new(env!("CARGO_MANIFEST_DIR")); - let test_data_dir = crate_root_dir.join("test_data"); - let dir = test_data_dir.join(path); - - let mut res = Vec::new(); - let read_dir = fs::read_dir(&dir) - .unwrap_or_else(|err| panic!("can't `read_dir` {}: {}", dir.display(), err)); - for file in read_dir { - let file = file.unwrap(); - let path = file.path(); - if path.extension().unwrap_or_default() == "rs" { - let rs = path; - let rast = rs.with_extension("rast"); - let text = fs::read_to_string(&rs).unwrap(); - res.push(TestCase { rs, rast, text }); - } - } - res.sort(); - res - } -} diff --git a/src/tools/rust-analyzer/crates/parser/src/tests/prefix_entries.rs b/src/tools/rust-analyzer/crates/parser/src/tests/prefix_entries.rs deleted file mode 100644 index e626b4f27e0c3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/tests/prefix_entries.rs +++ /dev/null @@ -1,107 +0,0 @@ -use crate::{LexedStr, PrefixEntryPoint, Step}; - -#[test] -fn vis() { - check(PrefixEntryPoint::Vis, "pub(crate) fn foo() {}", "pub(crate)"); - check(PrefixEntryPoint::Vis, "fn foo() {}", ""); - check(PrefixEntryPoint::Vis, "pub(fn foo() {}", "pub"); - check(PrefixEntryPoint::Vis, "pub(crate fn foo() {}", "pub(crate"); - check(PrefixEntryPoint::Vis, "crate fn foo() {}", "crate"); -} - -#[test] -fn block() { - check(PrefixEntryPoint::Block, "{}, 92", "{}"); - check(PrefixEntryPoint::Block, "{, 92)", "{, 92)"); - check(PrefixEntryPoint::Block, "()", ""); -} - -#[test] -fn stmt() { - check(PrefixEntryPoint::Stmt, "92; fn", "92"); - check(PrefixEntryPoint::Stmt, "let _ = 92; 1", "let _ = 92"); - check(PrefixEntryPoint::Stmt, "pub fn f() {} = 92", "pub fn f() {}"); - check(PrefixEntryPoint::Stmt, "struct S;;", "struct S;"); - check(PrefixEntryPoint::Stmt, "fn f() {};", "fn f() {}"); - check(PrefixEntryPoint::Stmt, ";;;", ";"); - check(PrefixEntryPoint::Stmt, "+", "+"); - check(PrefixEntryPoint::Stmt, "@", "@"); - check(PrefixEntryPoint::Stmt, "loop {} - 1", "loop {}"); -} - -#[test] -fn pat() { - check(PrefixEntryPoint::Pat, "x y", "x"); - check(PrefixEntryPoint::Pat, "fn f() {}", "fn"); - // FIXME: This one is wrong, we should consume only one pattern. - check(PrefixEntryPoint::Pat, ".. ..", ".. .."); -} - -#[test] -fn ty() { - check(PrefixEntryPoint::Ty, "fn() foo", "fn()"); - check(PrefixEntryPoint::Ty, "Clone + Copy + fn", "Clone + Copy +"); - check(PrefixEntryPoint::Ty, "struct f", "struct"); -} - -#[test] -fn expr() { - check(PrefixEntryPoint::Expr, "92 92", "92"); - check(PrefixEntryPoint::Expr, "+1", "+"); - check(PrefixEntryPoint::Expr, "-1", "-1"); - check(PrefixEntryPoint::Expr, "fn foo() {}", "fn"); - check(PrefixEntryPoint::Expr, "#[attr] ()", "#[attr] ()"); -} - -#[test] -fn path() { - check(PrefixEntryPoint::Path, "foo::bar baz", "foo::bar"); - check(PrefixEntryPoint::Path, "foo::<> baz", "foo::<>"); - check(PrefixEntryPoint::Path, "foo<> baz", "foo<>"); - check(PrefixEntryPoint::Path, "Fn() -> i32?", "Fn() -> i32"); - // FIXME: This shouldn't be accepted as path actually. - check(PrefixEntryPoint::Path, "<_>::foo", "<_>::foo"); -} - -#[test] -fn item() { - // FIXME: This shouldn't consume the semicolon. - check(PrefixEntryPoint::Item, "fn foo() {};", "fn foo() {};"); - check(PrefixEntryPoint::Item, "#[attr] pub struct S {} 92", "#[attr] pub struct S {}"); - check(PrefixEntryPoint::Item, "item!{}?", "item!{}"); - check(PrefixEntryPoint::Item, "????", "?"); -} - -#[test] -fn meta_item() { - check(PrefixEntryPoint::MetaItem, "attr, ", "attr"); - check(PrefixEntryPoint::MetaItem, "attr(some token {stream});", "attr(some token {stream})"); - check(PrefixEntryPoint::MetaItem, "path::attr = 2 * 2!", "path::attr = 2 * 2"); -} - -#[track_caller] -fn check(entry: PrefixEntryPoint, input: &str, prefix: &str) { - let lexed = LexedStr::new(input); - let input = lexed.to_input(); - - let mut n_tokens = 0; - for step in entry.parse(&input).iter() { - match step { - Step::Token { n_input_tokens, .. } => n_tokens += n_input_tokens as usize, - Step::Enter { .. } | Step::Exit | Step::Error { .. } => (), - } - } - - let mut i = 0; - loop { - if n_tokens == 0 { - break; - } - if !lexed.kind(i).is_trivia() { - n_tokens -= 1; - } - i += 1; - } - let buf = &lexed.as_str()[..lexed.text_start(i)]; - assert_eq!(buf, prefix); -} diff --git a/src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs b/src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs deleted file mode 100644 index 7b2b703deb699..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs +++ /dev/null @@ -1,123 +0,0 @@ -//! This module greps parser's code for specially formatted comments and turns -//! them into tests. - -use std::{ - collections::HashMap, - fs, iter, - path::{Path, PathBuf}, -}; - -#[test] -fn sourcegen_parser_tests() { - let grammar_dir = sourcegen::project_root().join(Path::new("crates/parser/src/grammar")); - let tests = tests_from_dir(&grammar_dir); - - install_tests(&tests.ok, "crates/parser/test_data/parser/inline/ok"); - install_tests(&tests.err, "crates/parser/test_data/parser/inline/err"); - - fn install_tests(tests: &HashMap, into: &str) { - let tests_dir = sourcegen::project_root().join(into); - if !tests_dir.is_dir() { - fs::create_dir_all(&tests_dir).unwrap(); - } - // ok is never actually read, but it needs to be specified to create a Test in existing_tests - let existing = existing_tests(&tests_dir, true); - for t in existing.keys().filter(|&t| !tests.contains_key(t)) { - panic!("Test is deleted: {}", t); - } - - let mut new_idx = existing.len() + 1; - for (name, test) in tests { - let path = match existing.get(name) { - Some((path, _test)) => path.clone(), - None => { - let file_name = format!("{:04}_{}.rs", new_idx, name); - new_idx += 1; - tests_dir.join(file_name) - } - }; - sourcegen::ensure_file_contents(&path, &test.text); - } - } -} - -#[derive(Debug)] -struct Test { - name: String, - text: String, - ok: bool, -} - -#[derive(Default, Debug)] -struct Tests { - ok: HashMap, - err: HashMap, -} - -fn collect_tests(s: &str) -> Vec { - let mut res = Vec::new(); - for comment_block in sourcegen::CommentBlock::extract_untagged(s) { - let first_line = &comment_block.contents[0]; - let (name, ok) = if let Some(name) = first_line.strip_prefix("test ") { - (name.to_string(), true) - } else if let Some(name) = first_line.strip_prefix("test_err ") { - (name.to_string(), false) - } else { - continue; - }; - let text: String = comment_block.contents[1..] - .iter() - .cloned() - .chain(iter::once(String::new())) - .collect::>() - .join("\n"); - assert!(!text.trim().is_empty() && text.ends_with('\n')); - res.push(Test { name, text, ok }) - } - res -} - -fn tests_from_dir(dir: &Path) -> Tests { - let mut res = Tests::default(); - for entry in sourcegen::list_rust_files(dir) { - process_file(&mut res, entry.as_path()); - } - let grammar_rs = dir.parent().unwrap().join("grammar.rs"); - process_file(&mut res, &grammar_rs); - return res; - - fn process_file(res: &mut Tests, path: &Path) { - let text = fs::read_to_string(path).unwrap(); - - for test in collect_tests(&text) { - if test.ok { - if let Some(old_test) = res.ok.insert(test.name.clone(), test) { - panic!("Duplicate test: {}", old_test.name); - } - } else if let Some(old_test) = res.err.insert(test.name.clone(), test) { - panic!("Duplicate test: {}", old_test.name); - } - } - } -} - -fn existing_tests(dir: &Path, ok: bool) -> HashMap { - let mut res = HashMap::default(); - for file in fs::read_dir(dir).unwrap() { - let file = file.unwrap(); - let path = file.path(); - if path.extension().unwrap_or_default() != "rs" { - continue; - } - let name = { - let file_name = path.file_name().unwrap().to_str().unwrap(); - file_name[5..file_name.len() - 3].to_string() - }; - let text = fs::read_to_string(&path).unwrap(); - let test = Test { name: name.clone(), text, ok }; - if let Some(old) = res.insert(name, (path, test)) { - println!("Duplicate test: {:?}", old); - } - } - res -} diff --git a/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs b/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs deleted file mode 100644 index eb640dc7fc74b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs +++ /dev/null @@ -1,312 +0,0 @@ -use expect_test::expect; - -use crate::TopEntryPoint; - -#[test] -fn source_file() { - check( - TopEntryPoint::SourceFile, - "", - expect![[r#" - SOURCE_FILE - "#]], - ); - - check( - TopEntryPoint::SourceFile, - "struct S;", - expect![[r#" - SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - SEMICOLON ";" - "#]], - ); - - check( - TopEntryPoint::SourceFile, - "@error@", - expect![[r#" - SOURCE_FILE - ERROR - AT "@" - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "error" - ERROR - AT "@" - error 0: expected an item - error 6: expected BANG - error 6: expected `{`, `[`, `(` - error 6: expected SEMICOLON - error 6: expected an item - "#]], - ); -} - -#[test] -fn macro_stmt() { - check( - TopEntryPoint::MacroStmts, - "", - expect![[r#" - MACRO_STMTS - "#]], - ); - check( - TopEntryPoint::MacroStmts, - "#!/usr/bin/rust", - expect![[r##" - MACRO_STMTS - ERROR - SHEBANG "#!/usr/bin/rust" - error 0: expected expression - "##]], - ); - check( - TopEntryPoint::MacroStmts, - "let x = 1 2 struct S;", - expect![[r#" - MACRO_STMTS - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "x" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - WHITESPACE " " - EXPR_STMT - LITERAL - INT_NUMBER "2" - WHITESPACE " " - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - SEMICOLON ";" - "#]], - ); -} - -#[test] -fn macro_items() { - check( - TopEntryPoint::MacroItems, - "", - expect![[r#" - MACRO_ITEMS - "#]], - ); - check( - TopEntryPoint::MacroItems, - "#!/usr/bin/rust", - expect![[r##" - MACRO_ITEMS - ERROR - SHEBANG "#!/usr/bin/rust" - error 0: expected an item - "##]], - ); - check( - TopEntryPoint::MacroItems, - "struct S; foo!{}", - expect![[r#" - MACRO_ITEMS - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - SEMICOLON ";" - WHITESPACE " " - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - BANG "!" - TOKEN_TREE - L_CURLY "{" - R_CURLY "}" - "#]], - ); -} - -#[test] -fn macro_pattern() { - check( - TopEntryPoint::Pattern, - "", - expect![[r#" - ERROR - error 0: expected pattern - "#]], - ); - check( - TopEntryPoint::Pattern, - "Some(_)", - expect![[r#" - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - L_PAREN "(" - WILDCARD_PAT - UNDERSCORE "_" - R_PAREN ")" - "#]], - ); - - check( - TopEntryPoint::Pattern, - "None leftover tokens", - expect![[r#" - ERROR - IDENT_PAT - NAME - IDENT "None" - WHITESPACE " " - IDENT "leftover" - WHITESPACE " " - IDENT "tokens" - "#]], - ); - - check( - TopEntryPoint::Pattern, - "@err", - expect![[r#" - ERROR - ERROR - AT "@" - IDENT "err" - error 0: expected pattern - "#]], - ); -} - -#[test] -fn type_() { - check( - TopEntryPoint::Type, - "", - expect![[r#" - ERROR - error 0: expected type - "#]], - ); - - check( - TopEntryPoint::Type, - "Option", - expect![[r#" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Option" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - NEVER_TYPE - BANG "!" - R_ANGLE ">" - "#]], - ); - check( - TopEntryPoint::Type, - "() () ()", - expect![[r#" - ERROR - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - L_PAREN "(" - R_PAREN ")" - "#]], - ); - check( - TopEntryPoint::Type, - "$$$", - expect![[r#" - ERROR - ERROR - DOLLAR "$" - DOLLAR "$" - DOLLAR "$" - error 0: expected type - "#]], - ); -} - -#[test] -fn expr() { - check( - TopEntryPoint::Expr, - "", - expect![[r#" - ERROR - error 0: expected expression - "#]], - ); - check( - TopEntryPoint::Expr, - "2 + 2 == 5", - expect![[r#" - BIN_EXPR - BIN_EXPR - LITERAL - INT_NUMBER "2" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LITERAL - INT_NUMBER "2" - WHITESPACE " " - EQ2 "==" - WHITESPACE " " - LITERAL - INT_NUMBER "5" - "#]], - ); - check( - TopEntryPoint::Expr, - "let _ = 0;", - expect![[r#" - ERROR - LET_EXPR - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - SEMICOLON ";" - "#]], - ); -} - -#[track_caller] -fn check(entry: TopEntryPoint, input: &str, expect: expect_test::Expect) { - let (parsed, _errors) = super::parse(entry, input); - expect.assert_eq(&parsed) -} diff --git a/src/tools/rust-analyzer/crates/parser/src/token_set.rs b/src/tools/rust-analyzer/crates/parser/src/token_set.rs deleted file mode 100644 index cd4894c1e8b5f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/src/token_set.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! A bit-set of `SyntaxKind`s. - -use crate::SyntaxKind; - -/// A bit-set of `SyntaxKind`s -#[derive(Clone, Copy)] -pub(crate) struct TokenSet(u128); - -impl TokenSet { - pub(crate) const EMPTY: TokenSet = TokenSet(0); - - pub(crate) const fn new(kinds: &[SyntaxKind]) -> TokenSet { - let mut res = 0u128; - let mut i = 0; - while i < kinds.len() { - res |= mask(kinds[i]); - i += 1; - } - TokenSet(res) - } - - pub(crate) const fn union(self, other: TokenSet) -> TokenSet { - TokenSet(self.0 | other.0) - } - - pub(crate) const fn contains(&self, kind: SyntaxKind) -> bool { - self.0 & mask(kind) != 0 - } -} - -const fn mask(kind: SyntaxKind) -> u128 { - 1u128 << (kind as usize) -} - -#[test] -fn token_set_works_for_tokens() { - use crate::SyntaxKind::*; - let ts = TokenSet::new(&[EOF, SHEBANG]); - assert!(ts.contains(EOF)); - assert!(ts.contains(SHEBANG)); - assert!(!ts.contains(PLUS)); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.rast deleted file mode 100644 index af03d73ced9a6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.rast +++ /dev/null @@ -1,48 +0,0 @@ -FLOAT_NUMBER "0e" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "0E" error: Missing digits after the exponent symbol -WHITESPACE "\n\n" -FLOAT_NUMBER "42e+" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42e-" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42E+" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42E-" error: Missing digits after the exponent symbol -WHITESPACE "\n\n" -INT_NUMBER "42" -DOT "." -IDENT "e" -PLUS "+" -WHITESPACE "\n" -INT_NUMBER "42" -DOT "." -IDENT "e" -MINUS "-" -WHITESPACE "\n" -INT_NUMBER "42" -DOT "." -IDENT "E" -PLUS "+" -WHITESPACE "\n" -INT_NUMBER "42" -DOT "." -IDENT "E" -MINUS "-" -WHITESPACE "\n\n" -FLOAT_NUMBER "42.2e+" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42.2e-" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42.2E+" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42.2E-" error: Missing digits after the exponent symbol -WHITESPACE "\n\n" -FLOAT_NUMBER "42.2e+f32" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42.2e-f32" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42.2E+f32" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42.2E-f32" error: Missing digits after the exponent symbol -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.rs deleted file mode 100644 index 286584c887f11..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.rs +++ /dev/null @@ -1,22 +0,0 @@ -0e -0E - -42e+ -42e- -42E+ -42E- - -42.e+ -42.e- -42.E+ -42.E- - -42.2e+ -42.2e- -42.2E+ -42.2E- - -42.2e+f32 -42.2e-f32 -42.2E+f32 -42.2E-f32 diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.txt deleted file mode 100644 index af03d73ced9a6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.txt +++ /dev/null @@ -1,48 +0,0 @@ -FLOAT_NUMBER "0e" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "0E" error: Missing digits after the exponent symbol -WHITESPACE "\n\n" -FLOAT_NUMBER "42e+" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42e-" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42E+" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42E-" error: Missing digits after the exponent symbol -WHITESPACE "\n\n" -INT_NUMBER "42" -DOT "." -IDENT "e" -PLUS "+" -WHITESPACE "\n" -INT_NUMBER "42" -DOT "." -IDENT "e" -MINUS "-" -WHITESPACE "\n" -INT_NUMBER "42" -DOT "." -IDENT "E" -PLUS "+" -WHITESPACE "\n" -INT_NUMBER "42" -DOT "." -IDENT "E" -MINUS "-" -WHITESPACE "\n\n" -FLOAT_NUMBER "42.2e+" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42.2e-" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42.2E+" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42.2E-" error: Missing digits after the exponent symbol -WHITESPACE "\n\n" -FLOAT_NUMBER "42.2e+f32" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42.2e-f32" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42.2E+f32" error: Missing digits after the exponent symbol -WHITESPACE "\n" -FLOAT_NUMBER "42.2E-f32" error: Missing digits after the exponent symbol -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.rast deleted file mode 100644 index 7f7194f4522ec..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.rast +++ /dev/null @@ -1,26 +0,0 @@ -INT_NUMBER "0b" error: Missing digits after the integer base prefix -WHITESPACE "\n" -INT_NUMBER "0o" error: Missing digits after the integer base prefix -WHITESPACE "\n" -INT_NUMBER "0x" error: Missing digits after the integer base prefix -WHITESPACE "\n\n" -INT_NUMBER "0b_" error: Missing digits after the integer base prefix -WHITESPACE "\n" -INT_NUMBER "0o_" error: Missing digits after the integer base prefix -WHITESPACE "\n" -INT_NUMBER "0x_" error: Missing digits after the integer base prefix -WHITESPACE "\n\n" -INT_NUMBER "0bnoDigit" error: Missing digits after the integer base prefix -WHITESPACE "\n" -INT_NUMBER "0onoDigit" error: Missing digits after the integer base prefix -WHITESPACE "\n" -INT_NUMBER "0xnoDigit" error: Missing digits after the integer base prefix -WHITESPACE "\n\n" -INT_NUMBER "0xG" error: Missing digits after the integer base prefix -WHITESPACE "\n" -INT_NUMBER "0xg" error: Missing digits after the integer base prefix -WHITESPACE "\n\n" -INT_NUMBER "0x_g" error: Missing digits after the integer base prefix -WHITESPACE "\n" -INT_NUMBER "0x_G" error: Missing digits after the integer base prefix -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.rs deleted file mode 100644 index aa2a9fdca17e0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.rs +++ /dev/null @@ -1,17 +0,0 @@ -0b -0o -0x - -0b_ -0o_ -0x_ - -0bnoDigit -0onoDigit -0xnoDigit - -0xG -0xg - -0x_g -0x_G diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.txt deleted file mode 100644 index 7f7194f4522ec..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.txt +++ /dev/null @@ -1,26 +0,0 @@ -INT_NUMBER "0b" error: Missing digits after the integer base prefix -WHITESPACE "\n" -INT_NUMBER "0o" error: Missing digits after the integer base prefix -WHITESPACE "\n" -INT_NUMBER "0x" error: Missing digits after the integer base prefix -WHITESPACE "\n\n" -INT_NUMBER "0b_" error: Missing digits after the integer base prefix -WHITESPACE "\n" -INT_NUMBER "0o_" error: Missing digits after the integer base prefix -WHITESPACE "\n" -INT_NUMBER "0x_" error: Missing digits after the integer base prefix -WHITESPACE "\n\n" -INT_NUMBER "0bnoDigit" error: Missing digits after the integer base prefix -WHITESPACE "\n" -INT_NUMBER "0onoDigit" error: Missing digits after the integer base prefix -WHITESPACE "\n" -INT_NUMBER "0xnoDigit" error: Missing digits after the integer base prefix -WHITESPACE "\n\n" -INT_NUMBER "0xG" error: Missing digits after the integer base prefix -WHITESPACE "\n" -INT_NUMBER "0xg" error: Missing digits after the integer base prefix -WHITESPACE "\n\n" -INT_NUMBER "0x_g" error: Missing digits after the integer base prefix -WHITESPACE "\n" -INT_NUMBER "0x_G" error: Missing digits after the integer base prefix -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rast deleted file mode 100644 index e919bf2a4aef2..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rast +++ /dev/null @@ -1,4 +0,0 @@ -LIFETIME_IDENT "'1" error: Lifetime name cannot start with a number -WHITESPACE "\n" -LIFETIME_IDENT "'1lifetime" error: Lifetime name cannot start with a number -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rs deleted file mode 100644 index a7698a404a87d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rs +++ /dev/null @@ -1,2 +0,0 @@ -'1 -'1lifetime diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.txt deleted file mode 100644 index e919bf2a4aef2..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.txt +++ /dev/null @@ -1,4 +0,0 @@ -LIFETIME_IDENT "'1" error: Lifetime name cannot start with a number -WHITESPACE "\n" -LIFETIME_IDENT "'1lifetime" error: Lifetime name cannot start with a number -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.rast deleted file mode 100644 index 7d2c329762163..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.rast +++ /dev/null @@ -1 +0,0 @@ -COMMENT "/*" error: Missing trailing `*/` symbols to terminate the block comment diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.rs deleted file mode 100644 index 22e83649f7d52..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.rs +++ /dev/null @@ -1 +0,0 @@ -/* \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.txt deleted file mode 100644 index 7d2c329762163..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.txt +++ /dev/null @@ -1 +0,0 @@ -COMMENT "/*" error: Missing trailing `*/` symbols to terminate the block comment diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.rast deleted file mode 100644 index 227a20660f72b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.rast +++ /dev/null @@ -1 +0,0 @@ -COMMENT "/* comment\n" error: Missing trailing `*/` symbols to terminate the block comment diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.rs deleted file mode 100644 index c45c2844dbcc1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.rs +++ /dev/null @@ -1 +0,0 @@ -/* comment diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.txt deleted file mode 100644 index 227a20660f72b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.txt +++ /dev/null @@ -1 +0,0 @@ -COMMENT "/* comment\n" error: Missing trailing `*/` symbols to terminate the block comment diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.rast deleted file mode 100644 index 36944dbb2de01..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE "b'" error: Missing trailing `'` symbol to terminate the byte literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.rs deleted file mode 100644 index 795dc7e25c587..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.rs +++ /dev/null @@ -1 +0,0 @@ -b' \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.txt deleted file mode 100644 index 36944dbb2de01..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE "b'" error: Missing trailing `'` symbol to terminate the byte literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.rast deleted file mode 100644 index 534a3cadcc95e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "b\"" error: Missing trailing `"` symbol to terminate the byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.rs deleted file mode 100644 index 36f4f432187d6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.rs +++ /dev/null @@ -1 +0,0 @@ -b" \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.txt deleted file mode 100644 index 534a3cadcc95e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "b\"" error: Missing trailing `"` symbol to terminate the byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.rast deleted file mode 100644 index 03f61de9a842f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "b\"\\x7f" error: Missing trailing `"` symbol to terminate the byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.rs deleted file mode 100644 index 836c112c1572f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.rs +++ /dev/null @@ -1 +0,0 @@ -b"\x7f \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.txt deleted file mode 100644 index 03f61de9a842f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "b\"\\x7f" error: Missing trailing `"` symbol to terminate the byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.rast deleted file mode 100644 index e11d49d1ee187..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "b\"🦀" error: Missing trailing `"` symbol to terminate the byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.rs deleted file mode 100644 index 3c23a03722873..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.rs +++ /dev/null @@ -1 +0,0 @@ -b"🦀 \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.txt deleted file mode 100644 index e11d49d1ee187..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "b\"🦀" error: Missing trailing `"` symbol to terminate the byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.rast deleted file mode 100644 index 4e374b1206cde..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "b\"\\" error: Missing trailing `"` symbol to terminate the byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.rs deleted file mode 100644 index cce6615381d5e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.rs +++ /dev/null @@ -1 +0,0 @@ -b"\ \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.txt deleted file mode 100644 index 4e374b1206cde..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "b\"\\" error: Missing trailing `"` symbol to terminate the byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.rast deleted file mode 100644 index ee19975860154..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "b\"\\\"" error: Missing trailing `"` symbol to terminate the byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.rs deleted file mode 100644 index f2ff58ba9a883..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.rs +++ /dev/null @@ -1 +0,0 @@ -b"\" \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.txt deleted file mode 100644 index ee19975860154..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "b\"\\\"" error: Missing trailing `"` symbol to terminate the byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.rast deleted file mode 100644 index b109d8629c9ee..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "b\"\\n" error: Missing trailing `"` symbol to terminate the byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.rs deleted file mode 100644 index 5e680aabb7b1c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.rs +++ /dev/null @@ -1 +0,0 @@ -b"\n \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.txt deleted file mode 100644 index b109d8629c9ee..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "b\"\\n" error: Missing trailing `"` symbol to terminate the byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.rast deleted file mode 100644 index eaca94fa41e24..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "b\" " error: Missing trailing `"` symbol to terminate the byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.rs deleted file mode 100644 index d6898541e623c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.rs +++ /dev/null @@ -1 +0,0 @@ -b" \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.txt deleted file mode 100644 index eaca94fa41e24..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "b\" " error: Missing trailing `"` symbol to terminate the byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.rast deleted file mode 100644 index 3b79f48bcd265..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "b\"\\u{20AA}" error: Missing trailing `"` symbol to terminate the byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.rs deleted file mode 100644 index 1c6df1d00e4e6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.rs +++ /dev/null @@ -1 +0,0 @@ -b"\u{20AA} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.txt deleted file mode 100644 index 3b79f48bcd265..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "b\"\\u{20AA}" error: Missing trailing `"` symbol to terminate the byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.rast deleted file mode 100644 index 5525376f4502f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE "b'\\x7f" error: Missing trailing `'` symbol to terminate the byte literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.rs deleted file mode 100644 index d146a8090d185..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.rs +++ /dev/null @@ -1 +0,0 @@ -b'\x7f \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.txt deleted file mode 100644 index 5525376f4502f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE "b'\\x7f" error: Missing trailing `'` symbol to terminate the byte literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.rast deleted file mode 100644 index e7a8be4f6e085..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE "b'🦀" error: Missing trailing `'` symbol to terminate the byte literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.rs deleted file mode 100644 index c9230dc24ea44..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.rs +++ /dev/null @@ -1 +0,0 @@ -b'🦀 \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.txt deleted file mode 100644 index e7a8be4f6e085..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE "b'🦀" error: Missing trailing `'` symbol to terminate the byte literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.rast deleted file mode 100644 index d9937135a9b4c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE "b'\\" error: Missing trailing `'` symbol to terminate the byte literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.rs deleted file mode 100644 index abffa5037c0da..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.rs +++ /dev/null @@ -1 +0,0 @@ -b'\ \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.txt deleted file mode 100644 index d9937135a9b4c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE "b'\\" error: Missing trailing `'` symbol to terminate the byte literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.rast deleted file mode 100644 index c408cdb2b57cb..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE "b'\\n" error: Missing trailing `'` symbol to terminate the byte literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.rs deleted file mode 100644 index 4f46836a935e3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.rs +++ /dev/null @@ -1 +0,0 @@ -b'\n \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.txt deleted file mode 100644 index c408cdb2b57cb..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE "b'\\n" error: Missing trailing `'` symbol to terminate the byte literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.rast deleted file mode 100644 index b331f95607416..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE "b'\\'" error: Missing trailing `'` symbol to terminate the byte literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.rs deleted file mode 100644 index 645b641eedb66..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.rs +++ /dev/null @@ -1 +0,0 @@ -b'\' \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.txt deleted file mode 100644 index b331f95607416..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE "b'\\'" error: Missing trailing `'` symbol to terminate the byte literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.rast deleted file mode 100644 index 80c0e1c00a1ec..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE "b' " error: Missing trailing `'` symbol to terminate the byte literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.rs deleted file mode 100644 index 93b7f9c87c914..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.rs +++ /dev/null @@ -1 +0,0 @@ -b' \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.txt deleted file mode 100644 index 80c0e1c00a1ec..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE "b' " error: Missing trailing `'` symbol to terminate the byte literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.rast deleted file mode 100644 index e1c3dc141e89d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE "b'\\u{20AA}" error: Missing trailing `'` symbol to terminate the byte literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.rs deleted file mode 100644 index a3dec7c255d0e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.rs +++ /dev/null @@ -1 +0,0 @@ -b'\u{20AA} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.txt deleted file mode 100644 index e1c3dc141e89d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE "b'\\u{20AA}" error: Missing trailing `'` symbol to terminate the byte literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.rast deleted file mode 100644 index 218c7a2d7660b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.rast +++ /dev/null @@ -1 +0,0 @@ -CHAR "'" error: Missing trailing `'` symbol to terminate the character literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.rs deleted file mode 100644 index ad2823b48f78a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.rs +++ /dev/null @@ -1 +0,0 @@ -' \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.txt deleted file mode 100644 index 218c7a2d7660b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.txt +++ /dev/null @@ -1 +0,0 @@ -CHAR "'" error: Missing trailing `'` symbol to terminate the character literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.rast deleted file mode 100644 index a0d8e1b83a0f6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.rast +++ /dev/null @@ -1 +0,0 @@ -CHAR "'\\x7f" error: Missing trailing `'` symbol to terminate the character literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.rs deleted file mode 100644 index cf74b4dad3b89..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.rs +++ /dev/null @@ -1 +0,0 @@ -'\x7f \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.txt deleted file mode 100644 index a0d8e1b83a0f6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.txt +++ /dev/null @@ -1 +0,0 @@ -CHAR "'\\x7f" error: Missing trailing `'` symbol to terminate the character literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rast deleted file mode 100644 index 56f19cce0784e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rast +++ /dev/null @@ -1 +0,0 @@ -CHAR "'🦀" error: Missing trailing `'` symbol to terminate the character literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rs deleted file mode 100644 index e264a4152801b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rs +++ /dev/null @@ -1 +0,0 @@ -'🦀 \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.txt deleted file mode 100644 index 56f19cce0784e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.txt +++ /dev/null @@ -1 +0,0 @@ -CHAR "'🦀" error: Missing trailing `'` symbol to terminate the character literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.rast deleted file mode 100644 index cfa0e0752aae8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.rast +++ /dev/null @@ -1 +0,0 @@ -CHAR "'\\" error: Missing trailing `'` symbol to terminate the character literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.rs deleted file mode 100644 index 6ba258b10932b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.rs +++ /dev/null @@ -1 +0,0 @@ -'\ \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.txt deleted file mode 100644 index cfa0e0752aae8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.txt +++ /dev/null @@ -1 +0,0 @@ -CHAR "'\\" error: Missing trailing `'` symbol to terminate the character literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.rast deleted file mode 100644 index 6a42a4e22b998..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.rast +++ /dev/null @@ -1 +0,0 @@ -CHAR "'\\n" error: Missing trailing `'` symbol to terminate the character literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.rs deleted file mode 100644 index 78bef7e3eb291..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.rs +++ /dev/null @@ -1 +0,0 @@ -'\n \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.txt deleted file mode 100644 index 6a42a4e22b998..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.txt +++ /dev/null @@ -1 +0,0 @@ -CHAR "'\\n" error: Missing trailing `'` symbol to terminate the character literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.rast deleted file mode 100644 index 1275f6aa857fd..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.rast +++ /dev/null @@ -1 +0,0 @@ -CHAR "'\\'" error: Missing trailing `'` symbol to terminate the character literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.rs deleted file mode 100644 index a0e722065bd70..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.rs +++ /dev/null @@ -1 +0,0 @@ -'\' \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.txt deleted file mode 100644 index 1275f6aa857fd..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.txt +++ /dev/null @@ -1 +0,0 @@ -CHAR "'\\'" error: Missing trailing `'` symbol to terminate the character literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.rast deleted file mode 100644 index 746c425c4e06c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.rast +++ /dev/null @@ -1 +0,0 @@ -CHAR "' " error: Missing trailing `'` symbol to terminate the character literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.rs deleted file mode 100644 index 309ecfe478646..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.rs +++ /dev/null @@ -1 +0,0 @@ -' \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.txt deleted file mode 100644 index 746c425c4e06c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.txt +++ /dev/null @@ -1 +0,0 @@ -CHAR "' " error: Missing trailing `'` symbol to terminate the character literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.rast deleted file mode 100644 index 9abd5909821e9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.rast +++ /dev/null @@ -1 +0,0 @@ -CHAR "'\\u{20AA}" error: Missing trailing `'` symbol to terminate the character literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.rs deleted file mode 100644 index 50be91f685248..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.rs +++ /dev/null @@ -1 +0,0 @@ -'\u{20AA} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.txt deleted file mode 100644 index 9abd5909821e9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.txt +++ /dev/null @@ -1 +0,0 @@ -CHAR "'\\u{20AA}" error: Missing trailing `'` symbol to terminate the character literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.rast deleted file mode 100644 index 15ce8905a995b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.rast +++ /dev/null @@ -1 +0,0 @@ -COMMENT "/* /* /*\n" error: Missing trailing `*/` symbols to terminate the block comment diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.rs deleted file mode 100644 index 3fcfc96600a7f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.rs +++ /dev/null @@ -1 +0,0 @@ -/* /* /* diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.txt deleted file mode 100644 index 15ce8905a995b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.txt +++ /dev/null @@ -1 +0,0 @@ -COMMENT "/* /* /*\n" error: Missing trailing `*/` symbols to terminate the block comment diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.rast deleted file mode 100644 index e9b74ee7f8276..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.rast +++ /dev/null @@ -1 +0,0 @@ -COMMENT "/** /*! /* comment */ */\n" error: Missing trailing `*/` symbols to terminate the block comment diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.rs deleted file mode 100644 index 26c898f019d68..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.rs +++ /dev/null @@ -1 +0,0 @@ -/** /*! /* comment */ */ diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.txt deleted file mode 100644 index e9b74ee7f8276..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.txt +++ /dev/null @@ -1 +0,0 @@ -COMMENT "/** /*! /* comment */ */\n" error: Missing trailing `*/` symbols to terminate the block comment diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rast deleted file mode 100644 index 6ec1780c30b85..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "br##\"" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rs deleted file mode 100644 index ae5bae6223085..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rs +++ /dev/null @@ -1 +0,0 @@ -br##" \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.txt deleted file mode 100644 index 6ec1780c30b85..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "br##\"" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rast deleted file mode 100644 index d65f1bb2ff049..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "br##\"\\x7f" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rs deleted file mode 100644 index d50270afe1e1c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rs +++ /dev/null @@ -1 +0,0 @@ -br##"\x7f \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.txt deleted file mode 100644 index d65f1bb2ff049..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "br##\"\\x7f" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rast deleted file mode 100644 index 0f9e0a1657ad4..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "br##\"🦀" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rs deleted file mode 100644 index 9ef01207a173f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rs +++ /dev/null @@ -1 +0,0 @@ -br##"🦀 \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.txt deleted file mode 100644 index 0f9e0a1657ad4..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "br##\"🦀" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rast deleted file mode 100644 index 202dcd2d43e38..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "br##\"\\" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rs deleted file mode 100644 index 0b3c015d74d48..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rs +++ /dev/null @@ -1 +0,0 @@ -br##"\ \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.txt deleted file mode 100644 index 202dcd2d43e38..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "br##\"\\" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rast deleted file mode 100644 index d45485b529ed6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "br##\"\\n" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rs deleted file mode 100644 index 0d8b0e7ab04f7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rs +++ /dev/null @@ -1 +0,0 @@ -br##"\n \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.txt deleted file mode 100644 index d45485b529ed6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "br##\"\\n" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rast deleted file mode 100644 index 1bfabbc3ab622..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "br##\" " error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rs deleted file mode 100644 index 14c602fd2b35a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rs +++ /dev/null @@ -1 +0,0 @@ -br##" \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.txt deleted file mode 100644 index 1bfabbc3ab622..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "br##\" " error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rast deleted file mode 100644 index 104ab8aaeefa4..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "br##\"\\u{20AA}" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rs deleted file mode 100644 index 90e299a1a977c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rs +++ /dev/null @@ -1 +0,0 @@ -br##"\u{20AA} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.txt deleted file mode 100644 index 104ab8aaeefa4..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "br##\"\\u{20AA}" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rast deleted file mode 100644 index 71b20fd19db7c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rast +++ /dev/null @@ -1 +0,0 @@ -STRING "r##\"" error: Missing trailing `"` with `#` symbols to terminate the raw string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rs deleted file mode 100644 index 557c59b625190..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rs +++ /dev/null @@ -1 +0,0 @@ -r##" \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.txt deleted file mode 100644 index 71b20fd19db7c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.txt +++ /dev/null @@ -1 +0,0 @@ -STRING "r##\"" error: Missing trailing `"` with `#` symbols to terminate the raw string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rast deleted file mode 100644 index dc106dd24a111..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rast +++ /dev/null @@ -1 +0,0 @@ -STRING "r##\"\\x7f" error: Missing trailing `"` with `#` symbols to terminate the raw string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rs deleted file mode 100644 index 5bec883dc7ae1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rs +++ /dev/null @@ -1 +0,0 @@ -r##"\x7f \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.txt deleted file mode 100644 index dc106dd24a111..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.txt +++ /dev/null @@ -1 +0,0 @@ -STRING "r##\"\\x7f" error: Missing trailing `"` with `#` symbols to terminate the raw string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rast deleted file mode 100644 index 30ee029f65679..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rast +++ /dev/null @@ -1 +0,0 @@ -STRING "r##\"🦀" error: Missing trailing `"` with `#` symbols to terminate the raw string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rs deleted file mode 100644 index bd046e4bb9148..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rs +++ /dev/null @@ -1 +0,0 @@ -r##"🦀 \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.txt deleted file mode 100644 index 30ee029f65679..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.txt +++ /dev/null @@ -1 +0,0 @@ -STRING "r##\"🦀" error: Missing trailing `"` with `#` symbols to terminate the raw string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rast deleted file mode 100644 index 8a6f6cc436662..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rast +++ /dev/null @@ -1 +0,0 @@ -STRING "r##\"\\" error: Missing trailing `"` with `#` symbols to terminate the raw string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rs deleted file mode 100644 index 9242077b8b7c5..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rs +++ /dev/null @@ -1 +0,0 @@ -r##"\ \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.txt deleted file mode 100644 index 8a6f6cc436662..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.txt +++ /dev/null @@ -1 +0,0 @@ -STRING "r##\"\\" error: Missing trailing `"` with `#` symbols to terminate the raw string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rast deleted file mode 100644 index f46eff2516ac4..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rast +++ /dev/null @@ -1 +0,0 @@ -STRING "r##\"\\n" error: Missing trailing `"` with `#` symbols to terminate the raw string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rs deleted file mode 100644 index db1c16f2ba5ac..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rs +++ /dev/null @@ -1 +0,0 @@ -r##"\n \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.txt deleted file mode 100644 index f46eff2516ac4..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.txt +++ /dev/null @@ -1 +0,0 @@ -STRING "r##\"\\n" error: Missing trailing `"` with `#` symbols to terminate the raw string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rast deleted file mode 100644 index 49b6afea45a5c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rast +++ /dev/null @@ -1 +0,0 @@ -STRING "r##\" " error: Missing trailing `"` with `#` symbols to terminate the raw string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rs deleted file mode 100644 index f104bae4f2cdf..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rs +++ /dev/null @@ -1 +0,0 @@ -r##" \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.txt deleted file mode 100644 index 49b6afea45a5c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.txt +++ /dev/null @@ -1 +0,0 @@ -STRING "r##\" " error: Missing trailing `"` with `#` symbols to terminate the raw string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rast deleted file mode 100644 index d10d6d8e8c2fd..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rast +++ /dev/null @@ -1 +0,0 @@ -STRING "r##\"\\u{20AA}" error: Missing trailing `"` with `#` symbols to terminate the raw string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rs deleted file mode 100644 index bf05c39134bd0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rs +++ /dev/null @@ -1 +0,0 @@ -r##"\u{20AA} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.txt deleted file mode 100644 index d10d6d8e8c2fd..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.txt +++ /dev/null @@ -1 +0,0 @@ -STRING "r##\"\\u{20AA}" error: Missing trailing `"` with `#` symbols to terminate the raw string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.rast deleted file mode 100644 index 3b89ce0ca1cae..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.rast +++ /dev/null @@ -1 +0,0 @@ -STRING "\"" error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.rs deleted file mode 100644 index 9d68933c44f13..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.rs +++ /dev/null @@ -1 +0,0 @@ -" \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.txt deleted file mode 100644 index 3b89ce0ca1cae..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.txt +++ /dev/null @@ -1 +0,0 @@ -STRING "\"" error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.rast deleted file mode 100644 index 6694cf17a6c59..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.rast +++ /dev/null @@ -1 +0,0 @@ -STRING "\"\\x7f" error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.rs deleted file mode 100644 index 56186a34444f4..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.rs +++ /dev/null @@ -1 +0,0 @@ -"\x7f \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.txt deleted file mode 100644 index 6694cf17a6c59..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.txt +++ /dev/null @@ -1 +0,0 @@ -STRING "\"\\x7f" error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.rast deleted file mode 100644 index 5f4501c18e519..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.rast +++ /dev/null @@ -1 +0,0 @@ -STRING "\"🦀" error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.rs deleted file mode 100644 index d439b8d2a1d6c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.rs +++ /dev/null @@ -1 +0,0 @@ -"🦀 \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.txt deleted file mode 100644 index 5f4501c18e519..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.txt +++ /dev/null @@ -1 +0,0 @@ -STRING "\"🦀" error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.rast deleted file mode 100644 index a8ac565ac8425..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.rast +++ /dev/null @@ -1 +0,0 @@ -STRING "\"\\" error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.rs deleted file mode 100644 index 00a2584008719..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.rs +++ /dev/null @@ -1 +0,0 @@ -"\ \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.txt deleted file mode 100644 index a8ac565ac8425..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.txt +++ /dev/null @@ -1 +0,0 @@ -STRING "\"\\" error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.rast deleted file mode 100644 index 919183b919382..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.rast +++ /dev/null @@ -1 +0,0 @@ -STRING "\"\\\"" error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.rs deleted file mode 100644 index 403c2d6ddc698..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.rs +++ /dev/null @@ -1 +0,0 @@ -"\" \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.txt deleted file mode 100644 index 919183b919382..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.txt +++ /dev/null @@ -1 +0,0 @@ -STRING "\"\\\"" error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.rast deleted file mode 100644 index 39e288af965b1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.rast +++ /dev/null @@ -1 +0,0 @@ -STRING "\"\\n" error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.rs deleted file mode 100644 index a0c29b8cff7fc..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.rs +++ /dev/null @@ -1 +0,0 @@ -"\n \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.txt deleted file mode 100644 index 39e288af965b1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.txt +++ /dev/null @@ -1 +0,0 @@ -STRING "\"\\n" error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.rast deleted file mode 100644 index dcff94d7ed3c8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.rast +++ /dev/null @@ -1 +0,0 @@ -STRING "\" " error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.rs deleted file mode 100644 index 72cdc841fbd78..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.rs +++ /dev/null @@ -1 +0,0 @@ -" \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.txt deleted file mode 100644 index dcff94d7ed3c8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.txt +++ /dev/null @@ -1 +0,0 @@ -STRING "\" " error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.rast deleted file mode 100644 index ac232b530daab..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.rast +++ /dev/null @@ -1 +0,0 @@ -STRING "\"\\u{20AA}" error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.rs deleted file mode 100644 index ed24095c3d4fc..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.rs +++ /dev/null @@ -1 +0,0 @@ -"\u{20AA} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.txt deleted file mode 100644 index ac232b530daab..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.txt +++ /dev/null @@ -1 +0,0 @@ -STRING "\"\\u{20AA}" error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rast deleted file mode 100644 index cf942c92f3b19..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rast +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "br##" error: Missing `"` symbol after `#` symbols to begin the raw byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rs deleted file mode 100644 index 7e8cadf4f4928..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rs +++ /dev/null @@ -1 +0,0 @@ -br## \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.txt deleted file mode 100644 index cf942c92f3b19..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.txt +++ /dev/null @@ -1 +0,0 @@ -BYTE_STRING "br##" error: Missing `"` symbol after `#` symbols to begin the raw byte string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rast deleted file mode 100644 index 042769c275642..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rast +++ /dev/null @@ -1,9 +0,0 @@ -BYTE_STRING "br## " error: Missing `"` symbol after `#` symbols to begin the raw byte string literal -IDENT "I" -WHITESPACE " " -IDENT "lack" -WHITESPACE " " -IDENT "a" -WHITESPACE " " -IDENT "quote" -BANG "!" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rs deleted file mode 100644 index d9b55455ac40c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rs +++ /dev/null @@ -1 +0,0 @@ -br## I lack a quote! \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.txt deleted file mode 100644 index 042769c275642..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.txt +++ /dev/null @@ -1,9 +0,0 @@ -BYTE_STRING "br## " error: Missing `"` symbol after `#` symbols to begin the raw byte string literal -IDENT "I" -WHITESPACE " " -IDENT "lack" -WHITESPACE " " -IDENT "a" -WHITESPACE " " -IDENT "quote" -BANG "!" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rast deleted file mode 100644 index 2f7c7529a95c0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rast +++ /dev/null @@ -1 +0,0 @@ -STRING "r##" error: Missing `"` symbol after `#` symbols to begin the raw string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rs deleted file mode 100644 index eddf8d0809445..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rs +++ /dev/null @@ -1 +0,0 @@ -r## \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.txt deleted file mode 100644 index 2f7c7529a95c0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.txt +++ /dev/null @@ -1 +0,0 @@ -STRING "r##" error: Missing `"` symbol after `#` symbols to begin the raw string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rast deleted file mode 100644 index 4a06b0abe748e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rast +++ /dev/null @@ -1,9 +0,0 @@ -STRING "r## " error: Missing `"` symbol after `#` symbols to begin the raw string literal -IDENT "I" -WHITESPACE " " -IDENT "lack" -WHITESPACE " " -IDENT "a" -WHITESPACE " " -IDENT "quote" -BANG "!" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rs deleted file mode 100644 index 534668a9b6622..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rs +++ /dev/null @@ -1 +0,0 @@ -r## I lack a quote! \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.txt deleted file mode 100644 index 4a06b0abe748e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.txt +++ /dev/null @@ -1,9 +0,0 @@ -STRING "r## " error: Missing `"` symbol after `#` symbols to begin the raw string literal -IDENT "I" -WHITESPACE " " -IDENT "lack" -WHITESPACE " " -IDENT "a" -WHITESPACE " " -IDENT "quote" -BANG "!" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.rast deleted file mode 100644 index 18bb5cad87f0f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.rast +++ /dev/null @@ -1,6 +0,0 @@ -COMMENT "/* */" -WHITESPACE "\n" -COMMENT "/**/" -WHITESPACE "\n" -COMMENT "/* /* */ */" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.rs deleted file mode 100644 index b880a59d952f9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.rs +++ /dev/null @@ -1,3 +0,0 @@ -/* */ -/**/ -/* /* */ */ diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.txt deleted file mode 100644 index 18bb5cad87f0f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.txt +++ /dev/null @@ -1,6 +0,0 @@ -COMMENT "/* */" -WHITESPACE "\n" -COMMENT "/**/" -WHITESPACE "\n" -COMMENT "/* /* */ */" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.rast deleted file mode 100644 index c848ac368e4f6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.rast +++ /dev/null @@ -1,22 +0,0 @@ -BYTE "b''" -WHITESPACE " " -BYTE "b'x'" -WHITESPACE " " -BYTE_STRING "b\"foo\"" -WHITESPACE " " -BYTE_STRING "br\"\"" -WHITESPACE "\n" -BYTE "b''suf" -WHITESPACE " " -BYTE_STRING "b\"\"ix" -WHITESPACE " " -BYTE_STRING "br\"\"br" -WHITESPACE "\n" -BYTE "b'\\n'" -WHITESPACE " " -BYTE "b'\\\\'" -WHITESPACE " " -BYTE "b'\\''" -WHITESPACE " " -BYTE "b'hello'" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.rs deleted file mode 100644 index b54930f5e699c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.rs +++ /dev/null @@ -1,3 +0,0 @@ -b'' b'x' b"foo" br"" -b''suf b""ix br""br -b'\n' b'\\' b'\'' b'hello' diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.txt deleted file mode 100644 index c848ac368e4f6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.txt +++ /dev/null @@ -1,22 +0,0 @@ -BYTE "b''" -WHITESPACE " " -BYTE "b'x'" -WHITESPACE " " -BYTE_STRING "b\"foo\"" -WHITESPACE " " -BYTE_STRING "br\"\"" -WHITESPACE "\n" -BYTE "b''suf" -WHITESPACE " " -BYTE_STRING "b\"\"ix" -WHITESPACE " " -BYTE_STRING "br\"\"br" -WHITESPACE "\n" -BYTE "b'\\n'" -WHITESPACE " " -BYTE "b'\\\\'" -WHITESPACE " " -BYTE "b'\\''" -WHITESPACE " " -BYTE "b'hello'" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.rast deleted file mode 100644 index 66e58cc298f40..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.rast +++ /dev/null @@ -1,16 +0,0 @@ -CHAR "'x'" -WHITESPACE " " -CHAR "' '" -WHITESPACE " " -CHAR "'0'" -WHITESPACE " " -CHAR "'hello'" -WHITESPACE " " -CHAR "'\\x7f'" -WHITESPACE " " -CHAR "'\\n'" -WHITESPACE " " -CHAR "'\\\\'" -WHITESPACE " " -CHAR "'\\''" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.rs deleted file mode 100644 index 454ee0a5f6172..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.rs +++ /dev/null @@ -1 +0,0 @@ -'x' ' ' '0' 'hello' '\x7f' '\n' '\\' '\'' diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.txt deleted file mode 100644 index 66e58cc298f40..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.txt +++ /dev/null @@ -1,16 +0,0 @@ -CHAR "'x'" -WHITESPACE " " -CHAR "' '" -WHITESPACE " " -CHAR "'0'" -WHITESPACE " " -CHAR "'hello'" -WHITESPACE " " -CHAR "'\\x7f'" -WHITESPACE " " -CHAR "'\\n'" -WHITESPACE " " -CHAR "'\\\\'" -WHITESPACE " " -CHAR "'\\''" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.rast deleted file mode 100644 index 7f5ce9de1b659..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.rast +++ /dev/null @@ -1,3 +0,0 @@ -IDENT "hello" -WHITESPACE " " -IDENT "world" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.rs deleted file mode 100644 index 95d09f2b10159..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.rs +++ /dev/null @@ -1 +0,0 @@ -hello world \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.txt deleted file mode 100644 index 7f5ce9de1b659..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.txt +++ /dev/null @@ -1,3 +0,0 @@ -IDENT "hello" -WHITESPACE " " -IDENT "world" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.rast deleted file mode 100644 index 5689644c07e79..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.rast +++ /dev/null @@ -1,14 +0,0 @@ -IDENT "foo" -WHITESPACE " " -IDENT "foo_" -WHITESPACE " " -IDENT "_foo" -WHITESPACE " " -UNDERSCORE "_" -WHITESPACE " " -IDENT "__" -WHITESPACE " " -IDENT "x" -WHITESPACE " " -IDENT "привет" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.rs deleted file mode 100644 index c05c9c009d7e6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.rs +++ /dev/null @@ -1 +0,0 @@ -foo foo_ _foo _ __ x привет diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.txt deleted file mode 100644 index 5689644c07e79..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.txt +++ /dev/null @@ -1,14 +0,0 @@ -IDENT "foo" -WHITESPACE " " -IDENT "foo_" -WHITESPACE " " -IDENT "_foo" -WHITESPACE " " -UNDERSCORE "_" -WHITESPACE " " -IDENT "__" -WHITESPACE " " -IDENT "x" -WHITESPACE " " -IDENT "привет" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.rast deleted file mode 100644 index e19b1399aa1d6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.rast +++ /dev/null @@ -1,64 +0,0 @@ -ASYNC_KW "async" -WHITESPACE " " -FN_KW "fn" -WHITESPACE " " -USE_KW "use" -WHITESPACE " " -STRUCT_KW "struct" -WHITESPACE " " -TRAIT_KW "trait" -WHITESPACE " " -ENUM_KW "enum" -WHITESPACE " " -IMPL_KW "impl" -WHITESPACE " " -TRUE_KW "true" -WHITESPACE " " -FALSE_KW "false" -WHITESPACE " " -AS_KW "as" -WHITESPACE " " -EXTERN_KW "extern" -WHITESPACE " " -CRATE_KW "crate" -WHITESPACE "\n" -MOD_KW "mod" -WHITESPACE " " -PUB_KW "pub" -WHITESPACE " " -SELF_KW "self" -WHITESPACE " " -SUPER_KW "super" -WHITESPACE " " -IN_KW "in" -WHITESPACE " " -WHERE_KW "where" -WHITESPACE " " -FOR_KW "for" -WHITESPACE " " -LOOP_KW "loop" -WHITESPACE " " -WHILE_KW "while" -WHITESPACE " " -IF_KW "if" -WHITESPACE " " -MATCH_KW "match" -WHITESPACE " " -CONST_KW "const" -WHITESPACE "\n" -STATIC_KW "static" -WHITESPACE " " -MUT_KW "mut" -WHITESPACE " " -TYPE_KW "type" -WHITESPACE " " -REF_KW "ref" -WHITESPACE " " -LET_KW "let" -WHITESPACE " " -ELSE_KW "else" -WHITESPACE " " -MOVE_KW "move" -WHITESPACE " " -RETURN_KW "return" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.rs deleted file mode 100644 index 1e91bff4e7d83..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.rs +++ /dev/null @@ -1,3 +0,0 @@ -async fn use struct trait enum impl true false as extern crate -mod pub self super in where for loop while if match const -static mut type ref let else move return diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.txt deleted file mode 100644 index e19b1399aa1d6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.txt +++ /dev/null @@ -1,64 +0,0 @@ -ASYNC_KW "async" -WHITESPACE " " -FN_KW "fn" -WHITESPACE " " -USE_KW "use" -WHITESPACE " " -STRUCT_KW "struct" -WHITESPACE " " -TRAIT_KW "trait" -WHITESPACE " " -ENUM_KW "enum" -WHITESPACE " " -IMPL_KW "impl" -WHITESPACE " " -TRUE_KW "true" -WHITESPACE " " -FALSE_KW "false" -WHITESPACE " " -AS_KW "as" -WHITESPACE " " -EXTERN_KW "extern" -WHITESPACE " " -CRATE_KW "crate" -WHITESPACE "\n" -MOD_KW "mod" -WHITESPACE " " -PUB_KW "pub" -WHITESPACE " " -SELF_KW "self" -WHITESPACE " " -SUPER_KW "super" -WHITESPACE " " -IN_KW "in" -WHITESPACE " " -WHERE_KW "where" -WHITESPACE " " -FOR_KW "for" -WHITESPACE " " -LOOP_KW "loop" -WHITESPACE " " -WHILE_KW "while" -WHITESPACE " " -IF_KW "if" -WHITESPACE " " -MATCH_KW "match" -WHITESPACE " " -CONST_KW "const" -WHITESPACE "\n" -STATIC_KW "static" -WHITESPACE " " -MUT_KW "mut" -WHITESPACE " " -TYPE_KW "type" -WHITESPACE " " -REF_KW "ref" -WHITESPACE " " -LET_KW "let" -WHITESPACE " " -ELSE_KW "else" -WHITESPACE " " -MOVE_KW "move" -WHITESPACE " " -RETURN_KW "return" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.rast deleted file mode 100644 index eeb1e95414ea1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.rast +++ /dev/null @@ -1,8 +0,0 @@ -LIFETIME_IDENT "'a" -WHITESPACE " " -LIFETIME_IDENT "'foo" -WHITESPACE " " -LIFETIME_IDENT "'foo_bar_baz" -WHITESPACE " " -LIFETIME_IDENT "'_" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.rs deleted file mode 100644 index b764f1dce3c05..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.rs +++ /dev/null @@ -1 +0,0 @@ -'a 'foo 'foo_bar_baz '_ diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.txt deleted file mode 100644 index eeb1e95414ea1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.txt +++ /dev/null @@ -1,8 +0,0 @@ -LIFETIME_IDENT "'a" -WHITESPACE " " -LIFETIME_IDENT "'foo" -WHITESPACE " " -LIFETIME_IDENT "'foo_bar_baz" -WHITESPACE " " -LIFETIME_IDENT "'_" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.rast deleted file mode 100644 index 8d13c3f610681..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.rast +++ /dev/null @@ -1,57 +0,0 @@ -INT_NUMBER "0" -WHITESPACE " " -INT_NUMBER "00" -WHITESPACE " " -INT_NUMBER "0_" -WHITESPACE " " -FLOAT_NUMBER "0." -WHITESPACE " " -INT_NUMBER "0z" -WHITESPACE "\n" -INT_NUMBER "01790" -WHITESPACE " " -INT_NUMBER "0b1790" -WHITESPACE " " -INT_NUMBER "0o1790" -WHITESPACE " " -INT_NUMBER "0x1790aAbBcCdDeEfF" -WHITESPACE " " -INT_NUMBER "001279" -WHITESPACE " " -INT_NUMBER "0_1279" -WHITESPACE " " -FLOAT_NUMBER "0.1279" -WHITESPACE " " -FLOAT_NUMBER "0e1279" -WHITESPACE " " -FLOAT_NUMBER "0E1279" -WHITESPACE "\n" -INT_NUMBER "0" -DOT "." -DOT "." -INT_NUMBER "2" -WHITESPACE "\n" -INT_NUMBER "0" -DOT "." -IDENT "foo" -L_PAREN "(" -R_PAREN ")" -WHITESPACE "\n" -FLOAT_NUMBER "0e+1" -WHITESPACE "\n" -INT_NUMBER "0" -DOT "." -IDENT "e" -PLUS "+" -INT_NUMBER "1" -WHITESPACE "\n" -FLOAT_NUMBER "0.0E-2" -WHITESPACE "\n" -FLOAT_NUMBER "0___0.10000____0000e+111__" -WHITESPACE "\n" -INT_NUMBER "1i64" -WHITESPACE " " -FLOAT_NUMBER "92.0f32" -WHITESPACE " " -INT_NUMBER "11__s" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.rs deleted file mode 100644 index bc761c235d897..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.rs +++ /dev/null @@ -1,9 +0,0 @@ -0 00 0_ 0. 0z -01790 0b1790 0o1790 0x1790aAbBcCdDeEfF 001279 0_1279 0.1279 0e1279 0E1279 -0..2 -0.foo() -0e+1 -0.e+1 -0.0E-2 -0___0.10000____0000e+111__ -1i64 92.0f32 11__s diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.txt deleted file mode 100644 index 8d13c3f610681..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.txt +++ /dev/null @@ -1,57 +0,0 @@ -INT_NUMBER "0" -WHITESPACE " " -INT_NUMBER "00" -WHITESPACE " " -INT_NUMBER "0_" -WHITESPACE " " -FLOAT_NUMBER "0." -WHITESPACE " " -INT_NUMBER "0z" -WHITESPACE "\n" -INT_NUMBER "01790" -WHITESPACE " " -INT_NUMBER "0b1790" -WHITESPACE " " -INT_NUMBER "0o1790" -WHITESPACE " " -INT_NUMBER "0x1790aAbBcCdDeEfF" -WHITESPACE " " -INT_NUMBER "001279" -WHITESPACE " " -INT_NUMBER "0_1279" -WHITESPACE " " -FLOAT_NUMBER "0.1279" -WHITESPACE " " -FLOAT_NUMBER "0e1279" -WHITESPACE " " -FLOAT_NUMBER "0E1279" -WHITESPACE "\n" -INT_NUMBER "0" -DOT "." -DOT "." -INT_NUMBER "2" -WHITESPACE "\n" -INT_NUMBER "0" -DOT "." -IDENT "foo" -L_PAREN "(" -R_PAREN ")" -WHITESPACE "\n" -FLOAT_NUMBER "0e+1" -WHITESPACE "\n" -INT_NUMBER "0" -DOT "." -IDENT "e" -PLUS "+" -INT_NUMBER "1" -WHITESPACE "\n" -FLOAT_NUMBER "0.0E-2" -WHITESPACE "\n" -FLOAT_NUMBER "0___0.10000____0000e+111__" -WHITESPACE "\n" -INT_NUMBER "1i64" -WHITESPACE " " -FLOAT_NUMBER "92.0f32" -WHITESPACE " " -INT_NUMBER "11__s" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.rast deleted file mode 100644 index fddad998216ac..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.rast +++ /dev/null @@ -1,2 +0,0 @@ -IDENT "r#raw_ident" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.rs deleted file mode 100644 index b40a1b6a248d3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.rs +++ /dev/null @@ -1 +0,0 @@ -r#raw_ident diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.txt deleted file mode 100644 index fddad998216ac..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.txt +++ /dev/null @@ -1,2 +0,0 @@ -IDENT "r#raw_ident" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.rast deleted file mode 100644 index 13cf733b7d173..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.rast +++ /dev/null @@ -1,2 +0,0 @@ -STRING "r###\"this is a r##\"raw\"## string\"###" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.rs deleted file mode 100644 index e5ed0b693b390..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.rs +++ /dev/null @@ -1 +0,0 @@ -r###"this is a r##"raw"## string"### diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.txt deleted file mode 100644 index 13cf733b7d173..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.txt +++ /dev/null @@ -1,2 +0,0 @@ -STRING "r###\"this is a r##\"raw\"## string\"###" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rast deleted file mode 100644 index a7681e9f5086a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rast +++ /dev/null @@ -1,22 +0,0 @@ -SHEBANG "#!/usr/bin/env bash" -WHITESPACE "\n" -COMMENT "// hello" -WHITESPACE "\n" -COMMENT "//! World" -WHITESPACE "\n" -COMMENT "//!! Inner line doc" -WHITESPACE "\n" -COMMENT "/// Outer line doc" -WHITESPACE "\n" -COMMENT "//// Just a comment" -WHITESPACE "\n\n" -COMMENT "//" -WHITESPACE "\n" -COMMENT "//!" -WHITESPACE "\n" -COMMENT "//!!" -WHITESPACE "\n" -COMMENT "///" -WHITESPACE "\n" -COMMENT "////" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rs deleted file mode 100644 index 4b6653f9cc9d2..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rs +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash -// hello -//! World -//!! Inner line doc -/// Outer line doc -//// Just a comment - -// -//! -//!! -/// -//// diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.txt deleted file mode 100644 index a7681e9f5086a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.txt +++ /dev/null @@ -1,22 +0,0 @@ -SHEBANG "#!/usr/bin/env bash" -WHITESPACE "\n" -COMMENT "// hello" -WHITESPACE "\n" -COMMENT "//! World" -WHITESPACE "\n" -COMMENT "//!! Inner line doc" -WHITESPACE "\n" -COMMENT "/// Outer line doc" -WHITESPACE "\n" -COMMENT "//// Just a comment" -WHITESPACE "\n\n" -COMMENT "//" -WHITESPACE "\n" -COMMENT "//!" -WHITESPACE "\n" -COMMENT "//!!" -WHITESPACE "\n" -COMMENT "///" -WHITESPACE "\n" -COMMENT "////" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.rast deleted file mode 100644 index ec222591bd393..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.rast +++ /dev/null @@ -1,8 +0,0 @@ -STRING "\"hello\"" -WHITESPACE " " -STRING "r\"world\"" -WHITESPACE " " -STRING "\"\\n\\\"\\\\no escape\"" -WHITESPACE " " -STRING "\"multi\nline\"" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.rs deleted file mode 100644 index 4ddb5bffccc55..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.rs +++ /dev/null @@ -1,2 +0,0 @@ -"hello" r"world" "\n\"\\no escape" "multi -line" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.txt deleted file mode 100644 index ec222591bd393..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.txt +++ /dev/null @@ -1,8 +0,0 @@ -STRING "\"hello\"" -WHITESPACE " " -STRING "r\"world\"" -WHITESPACE " " -STRING "\"\\n\\\"\\\\no escape\"" -WHITESPACE " " -STRING "\"multi\nline\"" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.rast deleted file mode 100644 index 533ccff9a8734..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.rast +++ /dev/null @@ -1,77 +0,0 @@ -SEMICOLON ";" -WHITESPACE " " -COMMA "," -WHITESPACE " " -L_PAREN "(" -WHITESPACE " " -R_PAREN ")" -WHITESPACE " " -L_CURLY "{" -WHITESPACE " " -R_CURLY "}" -WHITESPACE " " -L_BRACK "[" -WHITESPACE " " -R_BRACK "]" -WHITESPACE " " -L_ANGLE "<" -WHITESPACE " " -R_ANGLE ">" -WHITESPACE " " -AT "@" -WHITESPACE " " -POUND "#" -WHITESPACE " " -TILDE "~" -WHITESPACE " " -QUESTION "?" -WHITESPACE " " -DOLLAR "$" -WHITESPACE " " -AMP "&" -WHITESPACE " " -PIPE "|" -WHITESPACE " " -PLUS "+" -WHITESPACE " " -STAR "*" -WHITESPACE " " -SLASH "/" -WHITESPACE " " -CARET "^" -WHITESPACE " " -PERCENT "%" -WHITESPACE "\n" -DOT "." -WHITESPACE " " -DOT "." -DOT "." -WHITESPACE " " -DOT "." -DOT "." -DOT "." -WHITESPACE " " -DOT "." -DOT "." -EQ "=" -WHITESPACE "\n" -COLON ":" -WHITESPACE " " -COLON ":" -COLON ":" -WHITESPACE "\n" -EQ "=" -WHITESPACE " " -EQ "=" -R_ANGLE ">" -WHITESPACE "\n" -BANG "!" -WHITESPACE " " -BANG "!" -EQ "=" -WHITESPACE "\n" -MINUS "-" -WHITESPACE " " -MINUS "-" -R_ANGLE ">" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.rs deleted file mode 100644 index 487569b5ae3c4..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.rs +++ /dev/null @@ -1,6 +0,0 @@ -; , ( ) { } [ ] < > @ # ~ ? $ & | + * / ^ % -. .. ... ..= -: :: -= => -! != -- -> diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.txt deleted file mode 100644 index 533ccff9a8734..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.txt +++ /dev/null @@ -1,77 +0,0 @@ -SEMICOLON ";" -WHITESPACE " " -COMMA "," -WHITESPACE " " -L_PAREN "(" -WHITESPACE " " -R_PAREN ")" -WHITESPACE " " -L_CURLY "{" -WHITESPACE " " -R_CURLY "}" -WHITESPACE " " -L_BRACK "[" -WHITESPACE " " -R_BRACK "]" -WHITESPACE " " -L_ANGLE "<" -WHITESPACE " " -R_ANGLE ">" -WHITESPACE " " -AT "@" -WHITESPACE " " -POUND "#" -WHITESPACE " " -TILDE "~" -WHITESPACE " " -QUESTION "?" -WHITESPACE " " -DOLLAR "$" -WHITESPACE " " -AMP "&" -WHITESPACE " " -PIPE "|" -WHITESPACE " " -PLUS "+" -WHITESPACE " " -STAR "*" -WHITESPACE " " -SLASH "/" -WHITESPACE " " -CARET "^" -WHITESPACE " " -PERCENT "%" -WHITESPACE "\n" -DOT "." -WHITESPACE " " -DOT "." -DOT "." -WHITESPACE " " -DOT "." -DOT "." -DOT "." -WHITESPACE " " -DOT "." -DOT "." -EQ "=" -WHITESPACE "\n" -COLON ":" -WHITESPACE " " -COLON ":" -COLON ":" -WHITESPACE "\n" -EQ "=" -WHITESPACE " " -EQ "=" -R_ANGLE ">" -WHITESPACE "\n" -BANG "!" -WHITESPACE " " -BANG "!" -EQ "=" -WHITESPACE "\n" -MINUS "-" -WHITESPACE " " -MINUS "-" -R_ANGLE ">" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.rast deleted file mode 100644 index 8ccb79e4ec74d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.rast +++ /dev/null @@ -1,12 +0,0 @@ -IDENT "a" -WHITESPACE " " -IDENT "b" -WHITESPACE " " -IDENT "c" -WHITESPACE "\n" -IDENT "d" -WHITESPACE "\n\n" -IDENT "e" -WHITESPACE "\t" -IDENT "f" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.rs deleted file mode 100644 index 08fce1418a736..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.rs +++ /dev/null @@ -1,4 +0,0 @@ -a b c -d - -e f diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.txt deleted file mode 100644 index 8ccb79e4ec74d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.txt +++ /dev/null @@ -1,12 +0,0 @@ -IDENT "a" -WHITESPACE " " -IDENT "b" -WHITESPACE " " -IDENT "c" -WHITESPACE "\n" -IDENT "d" -WHITESPACE "\n\n" -IDENT "e" -WHITESPACE "\t" -IDENT "f" -WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0000_struct_field_missing_comma.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0000_struct_field_missing_comma.rast deleted file mode 100644 index b30328c8270c3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0000_struct_field_missing_comma.rast +++ /dev/null @@ -1,34 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE "\n " - RECORD_FIELD - NAME - IDENT "a" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - WHITESPACE "\n " - RECORD_FIELD - NAME - IDENT "b" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - WHITESPACE "\n" - R_CURLY "}" -error 21: expected COMMA diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0000_struct_field_missing_comma.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0000_struct_field_missing_comma.rs deleted file mode 100644 index fe5030d893f92..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0000_struct_field_missing_comma.rs +++ /dev/null @@ -1,4 +0,0 @@ -struct S { - a: u32 - b: u32 -} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0001_item_recovery_in_file.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0001_item_recovery_in_file.rast deleted file mode 100644 index 959b87ebbc593..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0001_item_recovery_in_file.rast +++ /dev/null @@ -1,18 +0,0 @@ -SOURCE_FILE - ERROR - IF_KW "if" - WHITESPACE " " - ERROR - MATCH_KW "match" - WHITESPACE "\n\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - R_CURLY "}" -error 0: expected an item -error 3: expected an item diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0001_item_recovery_in_file.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0001_item_recovery_in_file.rs deleted file mode 100644 index 98f23de1f2259..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0001_item_recovery_in_file.rs +++ /dev/null @@ -1,3 +0,0 @@ -if match - -struct S {} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast deleted file mode 100644 index ec6c3151005c6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast +++ /dev/null @@ -1,45 +0,0 @@ -SOURCE_FILE - SHEBANG "#!/use/bin/env rusti" - WHITESPACE "\n" - ATTR - POUND "#" - BANG "!" - ERROR - SLASH "/" - USE - USE_KW "use" - ERROR - SLASH "/" - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "bin" - ERROR - SLASH "/" - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "env" - WHITESPACE " " - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "rusti" - WHITESPACE "\n" -error 23: expected `[` -error 23: expected an item -error 27: expected one of `*`, `::`, `{`, `self`, `super` or an identifier -error 28: expected SEMICOLON -error 31: expected BANG -error 31: expected `{`, `[`, `(` -error 31: expected SEMICOLON -error 31: expected an item -error 35: expected BANG -error 35: expected `{`, `[`, `(` -error 35: expected SEMICOLON -error 41: expected BANG -error 41: expected `{`, `[`, `(` -error 41: expected SEMICOLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rs deleted file mode 100644 index 48a3a3980baed..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rs +++ /dev/null @@ -1,2 +0,0 @@ -#!/use/bin/env rusti -#!/use/bin/env rusti diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0003_C++_semicolon.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0003_C++_semicolon.rast deleted file mode 100644 index 00131bea51d68..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0003_C++_semicolon.rast +++ /dev/null @@ -1,39 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE "\n " - RECORD_FIELD - NAME - IDENT "a" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE "\n " - RECORD_FIELD - NAME - IDENT "b" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "String" - COMMA "," - WHITESPACE "\n" - R_CURLY "}" - ERROR - SEMICOLON ";" -error 39: expected item, found `;` -consider removing this semicolon diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0003_C++_semicolon.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0003_C++_semicolon.rs deleted file mode 100644 index 009312270fed0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0003_C++_semicolon.rs +++ /dev/null @@ -1,4 +0,0 @@ -struct S { - a: i32, - b: String, -}; \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast deleted file mode 100644 index 44e192a5fcbcf..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast +++ /dev/null @@ -1,15 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - COLON2 "::" - ERROR - INT_NUMBER "92" - SEMICOLON ";" -error 9: expected identifier diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rs deleted file mode 100644 index 060e65d06d2e0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rs +++ /dev/null @@ -1 +0,0 @@ -use foo::92; \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0005_attribute_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0005_attribute_recover.rast deleted file mode 100644 index 6ff072e207cda..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0005_attribute_recover.rast +++ /dev/null @@ -1,62 +0,0 @@ -SOURCE_FILE - FN - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - TOKEN_TREE - L_PAREN "(" - IDENT "foo" - COMMA "," - WHITESPACE " " - PLUS "+" - COMMA "," - WHITESPACE " " - INT_NUMBER "92" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n" - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n\n" - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - TOKEN_TREE - L_PAREN "(" - WHITESPACE "\n" - FN_KW "fn" - WHITESPACE " " - IDENT "foo" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 53: expected R_PAREN -error 53: expected `]` -error 53: expected an item diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0005_attribute_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0005_attribute_recover.rs deleted file mode 100644 index de7f816283904..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0005_attribute_recover.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[foo(foo, +, 92)] -fn foo() { -} - - -#[foo( -fn foo() { -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0006_named_field_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0006_named_field_recovery.rast deleted file mode 100644 index 7a4aa93b24658..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0006_named_field_recovery.rast +++ /dev/null @@ -1,74 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE "\n " - RECORD_FIELD - NAME - IDENT "f" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - COMMA "," - WHITESPACE "\n " - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - ERROR - INT_NUMBER "92" - WHITESPACE "\n " - ERROR - PLUS "+" - WHITESPACE " " - ERROR - MINUS "-" - WHITESPACE " " - ERROR - STAR "*" - WHITESPACE "\n " - RECORD_FIELD - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - NAME - IDENT "x" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - COMMA "," - WHITESPACE "\n " - RECORD_FIELD - NAME - IDENT "z" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "f64" - COMMA "," - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 31: expected field declaration -error 33: expected COMMA -error 38: expected field declaration -error 39: expected COMMA -error 40: expected field declaration -error 41: expected COMMA -error 42: expected field declaration -error 43: expected COMMA diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0006_named_field_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0006_named_field_recovery.rs deleted file mode 100644 index 8069c111b4bee..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0006_named_field_recovery.rs +++ /dev/null @@ -1,7 +0,0 @@ -struct S { - f: u32, - pub 92 - + - * - pub x: u32, - z: f64, -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0007_stray_curly_in_file.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0007_stray_curly_in_file.rast deleted file mode 100644 index 5d87ff866b257..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0007_stray_curly_in_file.rast +++ /dev/null @@ -1,33 +0,0 @@ -SOURCE_FILE - ERROR - R_CURLY "}" - WHITESPACE "\n\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - SEMICOLON ";" - WHITESPACE "\n\n" - ERROR - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n" - ERROR - R_CURLY "}" - WHITESPACE "\n" -error 0: unmatched `}` -error 14: unmatched `}` -error 29: unmatched `}` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0007_stray_curly_in_file.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0007_stray_curly_in_file.rs deleted file mode 100644 index dc869fb785efa..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0007_stray_curly_in_file.rs +++ /dev/null @@ -1,9 +0,0 @@ -} - -struct S; - -} - -fn foo(){} - -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0008_item_block_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0008_item_block_recovery.rast deleted file mode 100644 index 60b2fe98755e0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0008_item_block_recovery.rast +++ /dev/null @@ -1,80 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "bar" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - ERROR - L_CURLY "{" - WHITESPACE "\n " - IF_EXPR - IF_KW "if" - WHITESPACE " " - LITERAL - TRUE_KW "true" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LITERAL - INT_NUMBER "1" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE " " - ELSE_KW "else" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - BIN_EXPR - LITERAL - INT_NUMBER "2" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LITERAL - INT_NUMBER "3" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "baz" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 17: expected BANG -error 19: expected SEMICOLON -error 20: expected an item diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0008_item_block_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0008_item_block_recovery.rs deleted file mode 100644 index 9fcac19b5ce06..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0008_item_block_recovery.rs +++ /dev/null @@ -1,13 +0,0 @@ -fn foo() { -} - -bar() { - if true { - 1 - } else { - 2 + 3 - } -} - -fn baz() { -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0009_broken_struct_type_parameter.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0009_broken_struct_type_parameter.rast deleted file mode 100644 index a0154321718b6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0009_broken_struct_type_parameter.rast +++ /dev/null @@ -1,56 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - GENERIC_PARAM_LIST - L_ANGLE "<" - ERROR - INT_NUMBER "90" - WHITESPACE " " - ERROR - PLUS "+" - WHITESPACE " " - ERROR - INT_NUMBER "2" - ERROR - R_ANGLE ">" - WHITESPACE " " - ERROR - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "f" - ERROR - COLON ":" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "T" - SEMICOLON ";" - WHITESPACE "\n" -error 9: expected type parameter -error 11: expected COMMA -error 11: expected R_ANGLE -error 11: expected `;`, `{`, or `(` -error 12: expected an item -error 14: expected an item -error 15: expected an item -error 17: expected an item -error 24: expected SEMICOLON -error 24: expected expression diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0009_broken_struct_type_parameter.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0009_broken_struct_type_parameter.rs deleted file mode 100644 index 0dd30d0bd68dc..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0009_broken_struct_type_parameter.rs +++ /dev/null @@ -1,5 +0,0 @@ -struct S<90 + 2> { - f: u32 -} - -struct T; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0010_unsafe_lambda_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0010_unsafe_lambda_block.rast deleted file mode 100644 index 9427ee5c0e527..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0010_unsafe_lambda_block.rast +++ /dev/null @@ -1,45 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - CLOSURE_EXPR - PARAM_LIST - PIPE "|" - PIPE "|" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - EXPR_STMT - BLOCK_EXPR - UNSAFE_KW "unsafe" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 24: expected a block -error 24: expected SEMICOLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0010_unsafe_lambda_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0010_unsafe_lambda_block.rs deleted file mode 100644 index 9857752824ab5..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0010_unsafe_lambda_block.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - || -> () unsafe { () }; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0011_extern_struct.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0011_extern_struct.rast deleted file mode 100644 index bd5ec4b7c291e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0011_extern_struct.rast +++ /dev/null @@ -1,13 +0,0 @@ -SOURCE_FILE - ERROR - ABI - EXTERN_KW "extern" - WHITESPACE " " - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "Foo" - SEMICOLON ";" - WHITESPACE "\n" -error 6: expected existential, fn, trait or impl diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0011_extern_struct.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0011_extern_struct.rs deleted file mode 100644 index c1bd0a2d1be07..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0011_extern_struct.rs +++ /dev/null @@ -1 +0,0 @@ -extern struct Foo; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0012_broken_lambda.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0012_broken_lambda.rast deleted file mode 100644 index f31c27633982c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0012_broken_lambda.rast +++ /dev/null @@ -1,387 +0,0 @@ -SOURCE_FILE@0..389 - FN@0..389 - VISIBILITY@0..10 - PUB_KW@0..3 - L_PAREN@3..4 - SUPER_KW@4..9 - R_PAREN@9..10 - WHITESPACE@10..11 - FN_KW@11..13 - WHITESPACE@13..14 - NAME@14..21 - IDENT@14..21 "process" - GENERIC_PARAM_LIST@21..38 - L_ANGLE@21..22 - LIFETIME_PARAM@22..24 - LIFETIME@22..24 "'a" - COMMA@24..25 - WHITESPACE@25..26 - TYPE_PARAM@26..37 - NAME@26..27 - IDENT@26..27 "S" - COLON@27..28 - WHITESPACE@28..29 - PATH@29..37 - PATH_SEGMENT@29..37 - NAME_REF@29..33 - IDENT@29..33 "Sink" - GENERIC_ARG_LIST@33..37 - L_ANGLE@33..34 - LIFETIME_ARG@34..36 - LIFETIME@34..36 "'a" - R_ANGLE@36..37 - R_ANGLE@37..38 - PARAM_LIST@38..93 - L_PAREN@38..39 - PARAM@39..54 - IDENT_PAT@39..46 - NAME@39..46 - IDENT@39..46 "builder" - COLON@46..47 - WHITESPACE@47..48 - REF_TYPE@48..54 - AMP@48..49 - MUT_KW@49..52 - WHITESPACE@52..53 - PATH_TYPE@53..54 - PATH@53..54 - PATH_SEGMENT@53..54 - NAME_REF@53..54 - IDENT@53..54 "S" - COMMA@54..55 - WHITESPACE@55..56 - PARAM@56..72 - IDENT_PAT@56..62 - NAME@56..62 - IDENT@56..62 "tokens" - COLON@62..63 - WHITESPACE@63..64 - REF_TYPE@64..72 - AMP@64..65 - SLICE_TYPE@65..72 - L_BRACK@65..66 - PATH_TYPE@66..71 - PATH@66..71 - PATH_SEGMENT@66..71 - NAME_REF@66..71 - IDENT@66..71 "Token" - R_BRACK@71..72 - COMMA@72..73 - WHITESPACE@73..74 - PARAM@74..92 - IDENT_PAT@74..80 - NAME@74..80 - IDENT@74..80 "events" - COLON@80..81 - WHITESPACE@81..82 - PATH_TYPE@82..92 - PATH@82..92 - PATH_SEGMENT@82..92 - NAME_REF@82..85 - IDENT@82..85 "Vec" - GENERIC_ARG_LIST@85..92 - L_ANGLE@85..86 - TYPE_ARG@86..91 - PATH_TYPE@86..91 - PATH@86..91 - PATH_SEGMENT@86..91 - NAME_REF@86..91 - IDENT@86..91 "Event" - R_ANGLE@91..92 - R_PAREN@92..93 - WHITESPACE@93..94 - BLOCK_EXPR@94..389 - L_CURLY@94..95 - WHITESPACE@95..100 - LET_STMT@100..125 - LET_KW@100..103 - WHITESPACE@103..104 - IDENT_PAT@104..120 - MUT_KW@104..107 - WHITESPACE@107..108 - NAME@108..120 - IDENT@108..120 "next_tok_idx" - WHITESPACE@120..121 - EQ@121..122 - WHITESPACE@122..123 - LITERAL@123..124 - INT_NUMBER@123..124 "0" - SEMICOLON@124..125 - WHITESPACE@125..130 - LET_STMT@130..389 - LET_KW@130..133 - WHITESPACE@133..134 - IDENT_PAT@134..140 - NAME@134..140 - IDENT@134..140 "eat_ws" - WHITESPACE@140..141 - EQ@141..142 - WHITESPACE@142..143 - CLOSURE_EXPR@143..389 - PARAM_LIST@143..388 - PIPE@143..144 - PARAM@144..159 - IDENT_PAT@144..147 - NAME@144..147 - IDENT@144..147 "idx" - COLON@147..148 - WHITESPACE@148..149 - REF_TYPE@149..159 - AMP@149..150 - MUT_KW@150..153 - WHITESPACE@153..154 - PATH_TYPE@154..159 - PATH@154..159 - PATH_SEGMENT@154..159 - NAME_REF@154..159 - IDENT@154..159 "usize" - COMMA@159..160 - WHITESPACE@160..161 - PARAM@161..167 - REF_PAT@161..167 - AMP@161..162 - MUT_KW@162..165 - WHITESPACE@165..166 - err: `expected pattern` - ERROR@166..167 - PIPE@166..167 - err: `expected COMMA` - WHITESPACE@167..168 - err: `expected pattern` - PARAM@168..169 - ERROR@168..169 - L_CURLY@168..169 - err: `expected COMMA` - WHITESPACE@169..178 - err: `expected pattern` - PARAM@178..183 - ERROR@178..183 - WHILE_KW@178..183 - err: `expected COMMA` - WHITESPACE@183..184 - err: `expected pattern` - PARAM@184..187 - ERROR@184..187 - LET_KW@184..187 - err: `expected COMMA` - WHITESPACE@187..188 - PARAM@188..199 - TUPLE_STRUCT_PAT@188..199 - PATH@188..192 - PATH_SEGMENT@188..192 - NAME_REF@188..192 - IDENT@188..192 "Some" - L_PAREN@192..193 - IDENT_PAT@193..198 - NAME@193..198 - IDENT@193..198 "token" - R_PAREN@198..199 - err: `expected COMMA` - WHITESPACE@199..200 - err: `expected pattern` - PARAM@200..201 - ERROR@200..201 - EQ@200..201 - err: `expected COMMA` - WHITESPACE@201..202 - PARAM@202..208 - IDENT_PAT@202..208 - NAME@202..208 - IDENT@202..208 "tokens" - err: `expected COMMA` - err: `expected pattern` - PARAM@208..209 - ERROR@208..209 - DOT@208..209 - err: `expected COMMA` - PARAM@209..218 - TUPLE_STRUCT_PAT@209..218 - PATH@209..212 - PATH_SEGMENT@209..212 - NAME_REF@209..212 - IDENT@209..212 "get" - L_PAREN@212..213 - err: `expected pattern` - ERROR@213..214 - STAR@213..214 - err: `expected COMMA` - IDENT_PAT@214..217 - NAME@214..217 - IDENT@214..217 "idx" - R_PAREN@217..218 - err: `expected COMMA` - WHITESPACE@218..219 - err: `expected pattern` - PARAM@219..220 - ERROR@219..220 - L_CURLY@219..220 - err: `expected COMMA` - WHITESPACE@220..233 - err: `expected pattern` - PARAM@233..235 - ERROR@233..235 - IF_KW@233..235 - err: `expected COMMA` - WHITESPACE@235..236 - err: `expected pattern` - PARAM@236..237 - ERROR@236..237 - BANG@236..237 - err: `expected COMMA` - PARAM@237..242 - IDENT_PAT@237..242 - NAME@237..242 - IDENT@237..242 "token" - err: `expected COMMA` - err: `expected pattern` - PARAM@242..243 - ERROR@242..243 - DOT@242..243 - err: `expected COMMA` - PARAM@243..247 - IDENT_PAT@243..247 - NAME@243..247 - IDENT@243..247 "kind" - err: `expected COMMA` - err: `expected pattern` - PARAM@247..248 - ERROR@247..248 - DOT@247..248 - err: `expected COMMA` - PARAM@248..259 - TUPLE_STRUCT_PAT@248..259 - PATH@248..257 - PATH_SEGMENT@248..257 - NAME_REF@248..257 - IDENT@248..257 "is_trivia" - L_PAREN@257..258 - R_PAREN@258..259 - err: `expected COMMA` - WHITESPACE@259..260 - err: `expected pattern` - PARAM@260..261 - ERROR@260..261 - L_CURLY@260..261 - err: `expected COMMA` - WHITESPACE@261..278 - PARAM@278..283 - IDENT_PAT@278..283 - NAME@278..283 - IDENT@278..283 "break" - err: `expected COMMA` - err: `expected pattern` - PARAM@283..284 - ERROR@283..284 - SEMICOLON@283..284 - err: `expected COMMA` - WHITESPACE@284..297 - err: `expected pattern` - PARAM@297..298 - ERROR@297..298 - R_CURLY@297..298 - err: `expected COMMA` - WHITESPACE@298..311 - PARAM@311..318 - IDENT_PAT@311..318 - NAME@311..318 - IDENT@311..318 "builder" - err: `expected COMMA` - err: `expected pattern` - PARAM@318..319 - ERROR@318..319 - DOT@318..319 - err: `expected COMMA` - PARAM@319..346 - TUPLE_STRUCT_PAT@319..346 - PATH@319..323 - PATH_SEGMENT@319..323 - NAME_REF@319..323 - IDENT@319..323 "leaf" - L_PAREN@323..324 - IDENT_PAT@324..329 - NAME@324..329 - IDENT@324..329 "token" - err: `expected COMMA` - err: `expected pattern` - ERROR@329..330 - DOT@329..330 - err: `expected COMMA` - IDENT_PAT@330..334 - NAME@330..334 - IDENT@330..334 "kind" - COMMA@334..335 - WHITESPACE@335..336 - IDENT_PAT@336..341 - NAME@336..341 - IDENT@336..341 "token" - err: `expected COMMA` - err: `expected pattern` - ERROR@341..342 - DOT@341..342 - err: `expected COMMA` - IDENT_PAT@342..345 - NAME@342..345 - IDENT@342..345 "len" - R_PAREN@345..346 - err: `expected COMMA` - err: `expected pattern` - PARAM@346..347 - ERROR@346..347 - SEMICOLON@346..347 - err: `expected COMMA` - WHITESPACE@347..360 - err: `expected pattern` - PARAM@360..361 - ERROR@360..361 - STAR@360..361 - err: `expected COMMA` - PARAM@361..364 - IDENT_PAT@361..364 - NAME@361..364 - IDENT@361..364 "idx" - err: `expected COMMA` - WHITESPACE@364..365 - err: `expected pattern` - PARAM@365..366 - ERROR@365..366 - PLUS@365..366 - err: `expected COMMA` - err: `expected pattern` - PARAM@366..367 - ERROR@366..367 - EQ@366..367 - err: `expected COMMA` - WHITESPACE@367..368 - PARAM@368..369 - LITERAL@368..369 - INT_NUMBER@368..369 "1" - err: `expected COMMA` - WHITESPACE@369..378 - err: `expected pattern` - PARAM@378..379 - ERROR@378..379 - R_CURLY@378..379 - err: `expected COMMA` - WHITESPACE@379..384 - err: `expected pattern` - PARAM@384..385 - ERROR@384..385 - R_CURLY@384..385 - err: `expected COMMA` - err: `expected pattern` - PARAM@385..386 - ERROR@385..386 - SEMICOLON@385..386 - err: `expected COMMA` - WHITESPACE@386..387 - err: `expected pattern` - PARAM@387..388 - ERROR@387..388 - R_CURLY@387..388 - err: `expected COMMA` - err: `expected PIPE` - WHITESPACE@388..389 - err: `expected expression` - err: `expected SEMI` - err: `expected R_CURLY` - ERROR@389..389 diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0013_invalid_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0013_invalid_type.rast deleted file mode 100644 index eec84a0c67d9e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0013_invalid_type.rast +++ /dev/null @@ -1,89 +0,0 @@ -SOURCE_FILE - STRUCT - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "Cache" - TUPLE_FIELD_LIST - L_PAREN "(" - WHITESPACE "\n " - TUPLE_FIELD - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "RefCell" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "HashMap" - GENERIC_ARG_LIST - L_ANGLE "<" - WHITESPACE "\n " - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "TypeId" - COMMA "," - WHITESPACE "\n " - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Box" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - ERROR - AT "@" - WHITESPACE " " - TUPLE_FIELD - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Any" - ERROR - ERROR - R_ANGLE ">" - ERROR - COMMA "," - WHITESPACE "\n " - ERROR - R_ANGLE ">" - ERROR - R_ANGLE ">" - WHITESPACE "\n" - ERROR - R_PAREN ")" - ERROR - SEMICOLON ";" - WHITESPACE "\n\n" -error 67: expected type -error 68: expected COMMA -error 68: expected R_ANGLE -error 68: expected COMMA -error 68: expected R_ANGLE -error 68: expected COMMA -error 68: expected R_ANGLE -error 68: expected COMMA -error 72: expected COMMA -error 72: expected a type -error 72: expected R_PAREN -error 72: expected SEMICOLON -error 72: expected an item -error 73: expected an item -error 79: expected an item -error 80: expected an item -error 82: expected an item -error 83: expected an item diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0013_invalid_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0013_invalid_type.rs deleted file mode 100644 index 20dde3bc30fda..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0013_invalid_type.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub struct Cache( - RefCell, - >> -); - diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0014_where_no_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0014_where_no_bounds.rast deleted file mode 100644 index fd2f9ada33db0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0014_where_no_bounds.rast +++ /dev/null @@ -1,32 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE " " - WHERE_PRED - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" -error 19: expected colon diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0014_where_no_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0014_where_no_bounds.rs deleted file mode 100644 index 75c1d2f98610a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0014_where_no_bounds.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo() where T {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0015_curly_in_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0015_curly_in_params.rast deleted file mode 100644 index 8e169320d9540..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0015_curly_in_params.rast +++ /dev/null @@ -1,24 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - ERROR - R_CURLY "}" - ERROR - R_PAREN ")" - WHITESPACE " " - ERROR - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 7: expected value parameter -error 7: expected R_PAREN -error 7: expected a block -error 7: unmatched `}` -error 8: expected an item -error 10: expected an item diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0015_curly_in_params.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0015_curly_in_params.rs deleted file mode 100644 index 156e70251a109..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0015_curly_in_params.rs +++ /dev/null @@ -1,2 +0,0 @@ -fn foo(}) { -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0016_missing_semi.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0016_missing_semi.rast deleted file mode 100644 index c48c35bf822a9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0016_missing_semi.rast +++ /dev/null @@ -1,44 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - ARG_LIST - L_PAREN "(" - WHITESPACE "\n " - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - LITERAL - INT_NUMBER "2" - WHITESPACE "\n " - R_PAREN ")" - WHITESPACE "\n " - EXPR_STMT - RETURN_EXPR - RETURN_KW "return" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 38: expected SEMICOLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0016_missing_semi.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0016_missing_semi.rs deleted file mode 100644 index 9ae8576861908..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0016_missing_semi.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn foo() { - foo( - 1, 2 - ) - return 92; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0017_incomplete_binexpr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0017_incomplete_binexpr.rast deleted file mode 100644 index 80735646290b2..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0017_incomplete_binexpr.rast +++ /dev/null @@ -1,47 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "foo" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "bar" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - SEMICOLON ";" - WHITESPACE "\n " - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - PLUS "+" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 44: expected expression diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0017_incomplete_binexpr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0017_incomplete_binexpr.rs deleted file mode 100644 index 17bd497777719..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0017_incomplete_binexpr.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn foo(foo: i32) { - let bar = 92; - 1 + -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0018_incomplete_fn.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0018_incomplete_fn.rast deleted file mode 100644 index 6524d8e8fa9fe..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0018_incomplete_fn.rast +++ /dev/null @@ -1,134 +0,0 @@ -SOURCE_FILE - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "FnScopes" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "new_scope" - PARAM_LIST - L_PAREN "(" - PARAM - REF_PAT - AMP "&" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "ScopeId" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "res" - WHITESPACE " " - EQ "=" - WHITESPACE " " - METHOD_CALL_EXPR - FIELD_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - SELF_KW "self" - DOT "." - NAME_REF - IDENT "scopes" - DOT "." - NAME_REF - IDENT "len" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - METHOD_CALL_EXPR - FIELD_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - SELF_KW "self" - DOT "." - NAME_REF - IDENT "scopes" - DOT "." - NAME_REF - IDENT "push" - ARG_LIST - L_PAREN "(" - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "ScopeData" - WHITESPACE " " - RECORD_EXPR_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_EXPR_FIELD - NAME_REF - IDENT "parent" - COLON ":" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "None" - COMMA "," - WHITESPACE " " - RECORD_EXPR_FIELD - NAME_REF - IDENT "entries" - COLON ":" - WHITESPACE " " - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "vec" - BANG "!" - TOKEN_TREE - L_BRACK "[" - R_BRACK "]" - WHITESPACE " " - R_CURLY "}" - R_PAREN ")" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "set_parent" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 34: expected pattern -error 34: missing type for function parameter -error 180: expected function arguments -error 180: expected a block diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0018_incomplete_fn.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0018_incomplete_fn.rs deleted file mode 100644 index fe604006c9ec0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0018_incomplete_fn.rs +++ /dev/null @@ -1,8 +0,0 @@ -impl FnScopes { - fn new_scope(&) -> ScopeId { - let res = self.scopes.len(); - self.scopes.push(ScopeData { parent: None, entries: vec![] }) - } - - fn set_parent -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0019_let_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0019_let_recover.rast deleted file mode 100644 index 7d62e0cc14f50..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0019_let_recover.rast +++ /dev/null @@ -1,107 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "foo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "11" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "bar" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "baz" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE "\n " - EXPR_STMT - IF_EXPR - IF_KW "if" - WHITESPACE " " - LITERAL - TRUE_KW "true" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE "\n " - EXPR_STMT - WHILE_EXPR - WHILE_KW "while" - WHITESPACE " " - LITERAL - TRUE_KW "true" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE "\n " - LOOP_EXPR - LOOP_KW "loop" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 27: expected SEMICOLON -error 52: expected pattern -error 52: expected SEMICOLON -error 78: expected pattern -error 78: expected SEMICOLON -error 101: expected pattern -error 101: expected SEMICOLON -error 127: expected pattern -error 127: expected SEMICOLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0019_let_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0019_let_recover.rs deleted file mode 100644 index 5108d5a49be32..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0019_let_recover.rs +++ /dev/null @@ -1,12 +0,0 @@ -fn foo() { - let foo = 11 - let bar = 1; - let - let baz = 92; - let - if true {} - let - while true {} - let - loop {} -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0020_fn_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0020_fn_recover.rast deleted file mode 100644 index 56d124cb95b27..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0020_fn_recover.rast +++ /dev/null @@ -1,21 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" -error 2: expected a name -error 2: expected function arguments -error 2: expected a block diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0020_fn_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0020_fn_recover.rs deleted file mode 100644 index 3393b668b419f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0020_fn_recover.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn - -fn foo() {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0021_incomplete_param.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0021_incomplete_param.rast deleted file mode 100644 index 762840aa2a942..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0021_incomplete_param.rast +++ /dev/null @@ -1,34 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "x" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "y" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 16: missing type for function parameter diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0021_incomplete_param.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0021_incomplete_param.rs deleted file mode 100644 index 7a6c264f6d713..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0021_incomplete_param.rs +++ /dev/null @@ -1,2 +0,0 @@ -fn foo(x: i32, y) { -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rast deleted file mode 100644 index 900394bd96018..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rast +++ /dev/null @@ -1,171 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "a" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - ARRAY_EXPR - L_BRACK "[" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - LITERAL - INT_NUMBER "2" - COMMA "," - WHITESPACE " " - ERROR - AT "@" - ERROR - COMMA "," - WHITESPACE " " - STRUCT - STRUCT_KW "struct" - ERROR - COMMA "," - WHITESPACE " " - LET_STMT - LET_KW "let" - ERROR - R_BRACK "]" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "b" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - ARG_LIST - L_PAREN "(" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - LITERAL - INT_NUMBER "2" - COMMA "," - WHITESPACE " " - ERROR - AT "@" - ERROR - COMMA "," - WHITESPACE " " - IMPL - IMPL_KW "impl" - ERROR - COMMA "," - WHITESPACE " " - LET_STMT - LET_KW "let" - ERROR - R_PAREN ")" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "c" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - METHOD_CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - DOT "." - NAME_REF - IDENT "bar" - ARG_LIST - L_PAREN "(" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - LITERAL - INT_NUMBER "2" - COMMA "," - WHITESPACE " " - ERROR - AT "@" - ERROR - COMMA "," - WHITESPACE " " - ERROR - R_BRACK "]" - ERROR - COMMA "," - WHITESPACE " " - TRAIT - TRAIT_KW "trait" - ERROR - COMMA "," - WHITESPACE " " - LET_STMT - LET_KW "let" - ERROR - R_PAREN ")" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" -error 16: expected expression -error 17: expected R_BRACK -error 17: expected SEMICOLON -error 17: expected expression -error 25: expected a name -error 26: expected `;`, `{`, or `(` -error 30: expected pattern -error 31: expected SEMICOLON -error 53: expected expression -error 54: expected SEMICOLON -error 54: expected expression -error 60: expected type -error 60: expected `{` -error 60: expected expression -error 65: expected pattern -error 65: expected SEMICOLON -error 65: expected expression -error 92: expected expression -error 93: expected SEMICOLON -error 93: expected expression -error 95: expected expression -error 96: expected expression -error 103: expected a name -error 104: expected `{` -error 108: expected pattern -error 108: expected SEMICOLON -error 108: expected expression diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rs deleted file mode 100644 index cd2d493a10cdc..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn a() { [1, 2, @, struct, let] } -fn b() { foo(1, 2, @, impl, let) } -fn c() { foo.bar(1, 2, @, ], trait, let) } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0023_mismatched_paren.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0023_mismatched_paren.rast deleted file mode 100644 index 4064a7a1ff2de..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0023_mismatched_paren.rast +++ /dev/null @@ -1,45 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - BANG "!" - WHITESPACE " " - TOKEN_TREE - L_PAREN "(" - WHITESPACE "\n " - IDENT "bar" - COMMA "," - WHITESPACE " " - STRING "\"baz\"" - COMMA "," - WHITESPACE " " - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - FLOAT_NUMBER "2.0" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE " " - COMMENT "//~ ERROR incorrect close delimiter" - WHITESPACE "\n" - ERROR - R_CURLY "}" - WHITESPACE "\n" -error 49: unmatched `}` -error 92: unmatched `}` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0023_mismatched_paren.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0023_mismatched_paren.rs deleted file mode 100644 index 0206d563ea78e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0023_mismatched_paren.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - foo! ( - bar, "baz", 1, 2.0 - } //~ ERROR incorrect close delimiter -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast deleted file mode 100644 index d374f86610b28..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast +++ /dev/null @@ -1,327 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - L_PAREN "(" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Copy" - R_PAREN ")" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - L_PAREN "(" - QUESTION "?" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Sized" - R_PAREN ")" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - L_PAREN "(" - FOR_TYPE - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Trait" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - R_PAREN ")" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - COLON ":" - WHITESPACE " " - DYN_TRAIT_TYPE - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Box" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PAREN_TYPE - L_PAREN "(" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Copy" - R_PAREN ")" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - L_PAREN "(" - QUESTION "?" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Sized" - R_PAREN ")" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - L_PAREN "(" - FOR_TYPE - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Trait" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - R_PAREN ")" - ERROR - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Box" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PAREN_TYPE - L_PAREN "(" - ERROR - QUESTION "?" - EXPR_STMT - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Sized" - ERROR - R_PAREN ")" - WHITESPACE " " - ERROR - PLUS "+" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - CLOSURE_EXPR - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - BIN_EXPR - BIN_EXPR - BIN_EXPR - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Trait" - L_ANGLE "<" - ERROR - LIFETIME_IDENT "'a" - R_ANGLE ">" - ERROR - R_PAREN ")" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Copy" - R_PAREN ")" - R_ANGLE ">" - ERROR - SEMICOLON ";" - WHITESPACE "\n " - LET_EXPR - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - ERROR - COLON ":" - WHITESPACE " " - BIN_EXPR - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Box" - L_ANGLE "<" - TUPLE_EXPR - L_PAREN "(" - CLOSURE_EXPR - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - BIN_EXPR - BIN_EXPR - BIN_EXPR - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Trait" - L_ANGLE "<" - ERROR - LIFETIME_IDENT "'a" - R_ANGLE ">" - ERROR - R_PAREN ")" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Copy" - R_PAREN ")" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - ERROR - QUESTION "?" - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Sized" - R_PAREN ")" - R_ANGLE ">" - ERROR - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 88: expected COMMA -error 88: expected R_ANGLE -error 121: expected SEMICOLON -error 121: expected expression -error 140: expected type -error 141: expected R_PAREN -error 141: expected COMMA -error 141: expected R_ANGLE -error 141: expected SEMICOLON -error 146: expected SEMICOLON -error 146: expected expression -error 148: expected expression -error 158: expected `|` -error 158: expected COMMA -error 165: expected expression -error 168: expected expression -error 179: expected expression -error 180: expected COMMA -error 190: expected EQ -error 190: expected expression -error 191: expected COMMA -error 204: expected `|` -error 204: expected COMMA -error 211: expected expression -error 214: expected expression -error 228: expected expression -error 229: expected R_PAREN -error 229: expected COMMA -error 236: expected expression -error 237: expected COMMA -error 237: expected expression -error 237: expected R_PAREN diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rs deleted file mode 100644 index 6c2e95c02966d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn f Trait<'a>)>() {} - -fn main() { - let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>; - let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>; - let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rast deleted file mode 100644 index 6b49724ec9aa1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rast +++ /dev/null @@ -1,209 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - ENUM - ENUM_KW "enum" - WHITESPACE " " - NAME - IDENT "Test" - WHITESPACE " " - VARIANT_LIST - L_CURLY "{" - WHITESPACE "\n " - VARIANT - NAME - IDENT "Var1" - COMMA "," - WHITESPACE "\n " - VARIANT - NAME - IDENT "Var2" - TUPLE_FIELD_LIST - L_PAREN "(" - TUPLE_FIELD - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "String" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - VARIANT - NAME - IDENT "Var3" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE "\n " - RECORD_FIELD - NAME - IDENT "abc" - COLON ":" - WHITESPACE " " - ERROR - L_CURLY "{" - R_CURLY "}" - ERROR - COMMA "," - WHITESPACE " " - COMMENT "//~ ERROR: expected type, found `{`" - WHITESPACE "\n " - R_CURLY "}" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n\n " - COMMENT "// recover..." - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "a" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n " - ENUM - ENUM_KW "enum" - WHITESPACE " " - NAME - IDENT "Test2" - WHITESPACE " " - VARIANT_LIST - L_CURLY "{" - WHITESPACE "\n " - VARIANT - NAME - IDENT "Fine" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n\n " - ENUM - ENUM_KW "enum" - WHITESPACE " " - NAME - IDENT "Test3" - WHITESPACE " " - VARIANT_LIST - L_CURLY "{" - WHITESPACE "\n " - VARIANT - NAME - IDENT "StillFine" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE "\n " - RECORD_FIELD - NAME - IDENT "def" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n\n " - EXPR_STMT - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - ENUM - COMMENT "// fail again" - WHITESPACE "\n " - ENUM_KW "enum" - WHITESPACE " " - NAME - IDENT "Test4" - WHITESPACE " " - VARIANT_LIST - L_CURLY "{" - WHITESPACE "\n " - VARIANT - NAME - IDENT "Nope" - TUPLE_FIELD_LIST - L_PAREN "(" - TUPLE_FIELD - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - WHITESPACE " " - ERROR - ERROR - L_CURLY "{" - R_CURLY "}" - ERROR - R_PAREN ")" - WHITESPACE " " - COMMENT "//~ ERROR: found `{`" - WHITESPACE "\n " - COMMENT "//~^ ERROR: found `{`" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n " - COMMENT "// still recover later" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - ERROR - SEMICOLON ";" - WHITESPACE " " - COMMENT "//~ ERROR: expected pattern" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 95: expected type -error 95: expected COMMA -error 96: expected field -error 98: expected field declaration -error 371: expected COMMA -error 372: expected a type -error 372: expected R_PAREN -error 372: expected COMMA -error 372: expected enum variant -error 374: expected enum variant -error 494: expected pattern -error 495: expected SEMICOLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rs deleted file mode 100644 index c78abe80ab7e1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rs +++ /dev/null @@ -1,32 +0,0 @@ -fn main() { - enum Test { - Var1, - Var2(String), - Var3 { - abc: {}, //~ ERROR: expected type, found `{` - }, - } - - // recover... - let a = 1; - enum Test2 { - Fine, - } - - enum Test3 { - StillFine { - def: i32, - }, - } - - { - // fail again - enum Test4 { - Nope(i32 {}) //~ ERROR: found `{` - //~^ ERROR: found `{` - } - } - // still recover later - let; //~ ERROR: expected pattern - let _ = 0; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0026_imp_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0026_imp_recovery.rast deleted file mode 100644 index 1068418e0d84b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0026_imp_recovery.rast +++ /dev/null @@ -1,49 +0,0 @@ -SOURCE_FILE - IMPL - IMPL_KW "impl" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Clone" - R_ANGLE ">" - WHITESPACE "\n" - IMPL - IMPL_KW "impl" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - R_ANGLE ">" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "OnceCell" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - R_ANGLE ">" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" -error 14: expected trait or type -error 14: expected `{` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0026_imp_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0026_imp_recovery.rs deleted file mode 100644 index 829ca1c4be9f7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0026_imp_recovery.rs +++ /dev/null @@ -1,2 +0,0 @@ -impl -impl OnceCell {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplere_where_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplere_where_for.rast deleted file mode 100644 index 674c8d536cac5..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplere_where_for.rast +++ /dev/null @@ -1,29 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n " - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE " " - WHERE_PRED - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE "\n" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" -error 26: expected type -error 26: expected colon diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplere_where_for.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplere_where_for.rs deleted file mode 100644 index 2792c20843a83..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplere_where_for.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn foo() - where for<'a> -{} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0029_field_completion.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0029_field_completion.rast deleted file mode 100644 index fb037112fa3f2..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0029_field_completion.rast +++ /dev/null @@ -1,36 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "a" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "A" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - FIELD_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - DOT "." - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 21: expected field name or number diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0029_field_completion.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0029_field_completion.rs deleted file mode 100644 index a7cdc17bb112a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0029_field_completion.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn foo(a: A) { - a. -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rast deleted file mode 100644 index 327bf94a49e63..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rast +++ /dev/null @@ -1,205 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - ATTR - POUND "#" - ERROR - BANG "!" - ARRAY_EXPR - L_BRACK "[" - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "doc" - ARG_LIST - L_PAREN "(" - LITERAL - STRING "\"Not allowed here\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n\n " - EXPR_STMT - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - ATTR - POUND "#" - ERROR - BANG "!" - ARRAY_EXPR - L_BRACK "[" - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "doc" - ARG_LIST - L_PAREN "(" - LITERAL - STRING "\"Nor here\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n\n " - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "cfg" - TOKEN_TREE - L_PAREN "(" - IDENT "test" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - ATTR - POUND "#" - ERROR - BANG "!" - ARRAY_EXPR - L_BRACK "[" - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "doc" - ARG_LIST - L_PAREN "(" - LITERAL - STRING "\"Nor here\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 52: expected `[` -error 52: expected pattern -error 53: expected FAT_ARROW -error 78: expected `,` -error 161: expected `[` -error 161: expected pattern -error 162: expected FAT_ARROW -error 232: expected `[` -error 232: expected pattern -error 233: expected FAT_ARROW -error 250: expected `,` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rs deleted file mode 100644 index 06aa477704340..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rs +++ /dev/null @@ -1,20 +0,0 @@ -fn foo() { - match () { - _ => (), - #![doc("Not allowed here")] - _ => (), - } - - match () { - _ => (), - _ => (), - #![doc("Nor here")] - } - - match () { - #[cfg(test)] - #![doc("Nor here")] - _ => (), - _ => (), - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0033_match_arms_outer_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0033_match_arms_outer_attrs.rast deleted file mode 100644 index b5bc3d84df096..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0033_match_arms_outer_attrs.rast +++ /dev/null @@ -1,68 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "cfg" - TOKEN_TREE - L_PAREN "(" - IDENT "test" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 80: expected pattern -error 80: expected FAT_ARROW -error 80: expected expression diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0033_match_arms_outer_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0033_match_arms_outer_attrs.rs deleted file mode 100644 index 4635222da2821..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0033_match_arms_outer_attrs.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn foo() { - match () { - _ => (), - _ => (), - #[cfg(test)] - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0034_bad_box_pattern.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0034_bad_box_pattern.rast deleted file mode 100644 index 7a2ae9103fd9c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0034_bad_box_pattern.rast +++ /dev/null @@ -1,96 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - REF_KW "ref" - WHITESPACE " " - ERROR - BOX_KW "box" - WHITESPACE " " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "i" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - MUT_KW "mut" - WHITESPACE " " - ERROR - BOX_KW "box" - WHITESPACE " " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "i" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - REF_KW "ref" - WHITESPACE " " - MUT_KW "mut" - WHITESPACE " " - ERROR - BOX_KW "box" - WHITESPACE " " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "i" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" -error 24: expected a name -error 27: expected SEMICOLON -error 48: expected a name -error 51: expected SEMICOLON -error 76: expected a name -error 79: expected SEMICOLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0034_bad_box_pattern.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0034_bad_box_pattern.rs deleted file mode 100644 index d3fa2e468cc76..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0034_bad_box_pattern.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() { - let ref box i = (); - let mut box i = (); - let ref mut box i = (); -} - diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0035_use_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0035_use_recover.rast deleted file mode 100644 index f9287d42e20ec..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0035_use_recover.rast +++ /dev/null @@ -1,55 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "bar" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - CRATE_KW "crate" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "baz" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" -error 17: expected one of `*`, `::`, `{`, `self`, `super` or an identifier -error 17: expected SEMICOLON -error 37: expected one of `*`, `::`, `{`, `self`, `super` or an identifier -error 37: expected SEMICOLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0035_use_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0035_use_recover.rs deleted file mode 100644 index 4a26681262836..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0035_use_recover.rs +++ /dev/null @@ -1,5 +0,0 @@ -use foo::bar; -use -use crate::baz; -use -fn f() {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rast deleted file mode 100644 index 13e76e68307e6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rast +++ /dev/null @@ -1,51 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "std" - COLON2 "::" - USE_TREE_LIST - L_CURLY "{" - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "error" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Error" - ERROR - SEMICOLON ";" - WHITESPACE "\n" - ERROR - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "std" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "io" - ERROR - SEMICOLON ";" - WHITESPACE "\n" -error 22: expected COMMA -error 22: expected one of `*`, `::`, `{`, `self`, `super` or an identifier -error 23: expected COMMA -error 24: expected one of `*`, `::`, `{`, `self`, `super` or an identifier -error 27: expected COMMA -error 35: expected COMMA -error 35: expected one of `*`, `::`, `{`, `self`, `super` or an identifier -error 36: expected COMMA -error 36: expected R_CURLY -error 36: expected SEMICOLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rs deleted file mode 100644 index d521a5bb2deef..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rs +++ /dev/null @@ -1,2 +0,0 @@ -use std::{error::Error; -use std::io; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0039_lambda_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0039_lambda_recovery.rast deleted file mode 100644 index 8ca160601534d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0039_lambda_recovery.rast +++ /dev/null @@ -1,83 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - METHOD_CALL_EXPR - METHOD_CALL_EXPR - METHOD_CALL_EXPR - ARRAY_EXPR - L_BRACK "[" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - LITERAL - INT_NUMBER "2" - COMMA "," - WHITESPACE " " - LITERAL - INT_NUMBER "3" - R_BRACK "]" - DOT "." - NAME_REF - IDENT "iter" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n " - DOT "." - NAME_REF - IDENT "map" - ARG_LIST - L_PAREN "(" - CLOSURE_EXPR - PARAM_LIST - PIPE "|" - PARAM - IDENT_PAT - NAME - IDENT "it" - PIPE "|" - R_PAREN ")" - WHITESPACE "\n " - DOT "." - NAME_REF - IDENT "max" - GENERIC_ARG_LIST - COLON2 "::" - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_ANGLE ">" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 56: expected expression diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0039_lambda_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0039_lambda_recovery.rs deleted file mode 100644 index a2f74bd879aee..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0039_lambda_recovery.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn foo() -> i32 { - [1, 2, 3].iter() - .map(|it|) - .max::(); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0042_weird_blocks.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0042_weird_blocks.rast deleted file mode 100644 index 9cea337ce9c49..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0042_weird_blocks.rast +++ /dev/null @@ -1,75 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - ERROR - UNSAFE_KW "unsafe" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - ERROR - ASYNC_KW "async" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - BLOCK_EXPR - TRY_KW "try" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - ERROR - LABEL - LIFETIME - LIFETIME_IDENT "'label" - COLON ":" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 24: expected existential, fn, trait or impl -error 41: expected existential, fn, trait or impl -error 56: expected a block -error 75: expected a loop diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0042_weird_blocks.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0042_weird_blocks.rs deleted file mode 100644 index 8fa324c1a14f7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0042_weird_blocks.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() { - { unsafe 92 } - { async 92 } - { try 92 } - { 'label: 92 } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rast deleted file mode 100644 index cb4fb1642d954..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rast +++ /dev/null @@ -1,256 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "ForRef" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FOR_TYPE - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "ForTup" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FOR_TYPE - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - COMMA "," - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "ForSlice" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FOR_TYPE - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - SLICE_TYPE - L_BRACK "[" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - R_BRACK "]" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "ForForFn" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FOR_TYPE - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - FOR_TYPE - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'b" - R_ANGLE ">" - WHITESPACE " " - FN_PTR_TYPE - FN_KW "fn" - PARAM_LIST - L_PAREN "(" - PARAM - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PARAM - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'b" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "for_for_for" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n" - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE "\n " - WHERE_PRED - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - FOR_TYPE - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'b" - R_ANGLE ">" - WHITESPACE " " - FOR_TYPE - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'c" - R_ANGLE ">" - WHITESPACE " " - FN_PTR_TYPE - FN_KW "fn" - PARAM_LIST - L_PAREN "(" - PARAM - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - COMMA "," - WHITESPACE " " - PARAM - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'b" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - COMMA "," - WHITESPACE " " - PARAM - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'c" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - R_PAREN ")" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Copy" - COMMA "," - WHITESPACE "\n" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 21: expected a function pointer or path -error 52: expected a function pointer or path -error 88: expected a function pointer or path -error 119: expected a function pointer or path -error 195: expected a function pointer or path diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rs deleted file mode 100644 index 0e9f8ccb4f84b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rs +++ /dev/null @@ -1,9 +0,0 @@ -type ForRef = for<'a> &'a u32; -type ForTup = for<'a> (&'a u32,); -type ForSlice = for<'a> [u32]; -type ForForFn = for<'a> for<'b> fn(&'a i32, &'b i32); -fn for_for_for() -where - for<'a> for<'b> for<'c> fn(&'a T, &'b T, &'c T): Copy, -{ -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rast deleted file mode 100644 index 96e471a69a781..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rast +++ /dev/null @@ -1,48 +0,0 @@ -SOURCE_FILE - ERROR - UNSAFE_KW "unsafe" - WHITESPACE " " - FN - ASYNC_KW "async" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - CONST - UNSAFE_KW "unsafe" - WHITESPACE " " - CONST_KW "const" - WHITESPACE " " - ERROR - FN_KW "fn" - WHITESPACE " " - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "bar" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - ERROR - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" -error 6: expected existential, fn, trait or impl -error 38: expected a name -error 40: missing type for `const` or `static` -error 40: expected SEMICOLON -error 44: expected BANG -error 46: expected SEMICOLON -error 47: expected an item diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rs deleted file mode 100644 index 731e58013bd87..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rs +++ /dev/null @@ -1,2 +0,0 @@ -unsafe async fn foo() {} -unsafe const fn bar() {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rast deleted file mode 100644 index 4b2a740362ed1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rast +++ /dev/null @@ -1,15 +0,0 @@ -SOURCE_FILE - ERROR - ABI - EXTERN_KW "extern" - WHITESPACE " " - STRING "\"C\"" - WHITESPACE " " - ERROR - ABI - EXTERN_KW "extern" - WHITESPACE " " - STRING "\"C\"" - WHITESPACE "\n" -error 10: expected existential, fn, trait or impl -error 21: expected existential, fn, trait or impl diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rs deleted file mode 100644 index db32b98dfb05d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rs +++ /dev/null @@ -1 +0,0 @@ -extern "C" extern "C" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast deleted file mode 100644 index 3a05bfee1ee9b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast +++ /dev/null @@ -1,123 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - COLON2 "::" - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - GENERIC_ARG_LIST - COLON2 "::" - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "lol" - R_ANGLE ">" - COLON2 "::" - ERROR - L_ANGLE "<" - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "nope" - SHR ">>" - ERROR - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "g" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - GENERIC_ARG_LIST - COLON2 "::" - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "lol" - R_ANGLE ">" - COLON2 "::" - ERROR - L_ANGLE "<" - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "nope" - R_ANGLE ">" - WHITESPACE " " - ERROR - EQ "=" - WHITESPACE " " - EXPR_STMT - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 30: expected identifier -error 31: expected COMMA -error 31: expected R_ANGLE -error 31: expected SEMICOLON -error 37: expected expression -error 75: expected identifier -error 76: expected SEMICOLON -error 82: expected expression -error 83: expected SEMICOLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rs deleted file mode 100644 index 31c12bfff9f9f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn f() { - S::::>; -} - -fn g() { - let _: Item:::: = (); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0001_array_type_missing_semi.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0001_array_type_missing_semi.rast deleted file mode 100644 index ed739a7e39831..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0001_array_type_missing_semi.rast +++ /dev/null @@ -1,27 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - SLICE_TYPE - L_BRACK "[" - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - ERROR - INT_NUMBER "92" - ERROR - R_BRACK "]" - ERROR - SEMICOLON ";" - WHITESPACE "\n" -error 12: expected `;` or `]` -error 12: expected SEMICOLON -error 13: expected an item -error 15: expected an item -error 16: expected an item diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0001_array_type_missing_semi.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0001_array_type_missing_semi.rs deleted file mode 100644 index a948514432072..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0001_array_type_missing_semi.rs +++ /dev/null @@ -1 +0,0 @@ -type T = [() 92]; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0002_misplaced_label_err.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0002_misplaced_label_err.rast deleted file mode 100644 index 56cea4b15674c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0002_misplaced_label_err.rast +++ /dev/null @@ -1,28 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - ERROR - LABEL - LIFETIME - LIFETIME_IDENT "'loop" - COLON ":" - WHITESPACE " " - IMPL - IMPL_KW "impl" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 22: expected a loop -error 27: expected type -error 27: expected `{` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0002_misplaced_label_err.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0002_misplaced_label_err.rs deleted file mode 100644 index a2164c5105c1a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0002_misplaced_label_err.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - 'loop: impl -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0003_pointer_type_no_mutability.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0003_pointer_type_no_mutability.rast deleted file mode 100644 index 354c4135a4d07..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0003_pointer_type_no_mutability.rast +++ /dev/null @@ -1,17 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PTR_TYPE - STAR "*" - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" -error 10: expected mut or const in raw pointer type (use `*mut T` or `*const T` as appropriate) diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0003_pointer_type_no_mutability.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0003_pointer_type_no_mutability.rs deleted file mode 100644 index fae7051313348..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0003_pointer_type_no_mutability.rs +++ /dev/null @@ -1 +0,0 @@ -type T = *(); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0004_impl_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0004_impl_type.rast deleted file mode 100644 index dbeb878a2e884..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0004_impl_type.rast +++ /dev/null @@ -1,79 +0,0 @@ -SOURCE_FILE - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Type" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Trait1" - WHITESPACE " " - FOR_KW "for" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - IMPL - IMPL_KW "impl" - WHITESPACE " " - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "NotType" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Trait2" - WHITESPACE " " - FOR_KW "for" - WHITESPACE " " - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "NotType" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" -error 38: expected trait or type -error 38: expected `{` -error 70: expected trait or type -error 70: expected `{` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0004_impl_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0004_impl_type.rs deleted file mode 100644 index b8c7b65e31d75..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0004_impl_type.rs +++ /dev/null @@ -1,4 +0,0 @@ -impl Type {} -impl Trait1 for T {} -impl impl NotType {} -impl Trait2 for impl NotType {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rast deleted file mode 100644 index eb059529396dc..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rast +++ /dev/null @@ -1,23 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "F" - WHITESPACE " " - EQ "=" - WHITESPACE " " - UNSAFE_KW "unsafe" - WHITESPACE " " - ERROR - L_PAREN "(" - ERROR - R_PAREN ")" - ERROR - SEMICOLON ";" - WHITESPACE "\n" -error 15: expected `fn` -error 15: expected SEMICOLON -error 16: expected an item -error 17: expected an item -error 18: expected an item diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rs deleted file mode 100644 index f014914ff9f49..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rs +++ /dev/null @@ -1 +0,0 @@ -type F = unsafe (); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0006_unsafe_block_in_mod.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0006_unsafe_block_in_mod.rast deleted file mode 100644 index 77c2b56adf26d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0006_unsafe_block_in_mod.rast +++ /dev/null @@ -1,37 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE " " - ERROR - UNSAFE_KW "unsafe" - WHITESPACE " " - ERROR - L_CURLY "{" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "bar" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" -error 11: expected an item -error 18: expected an item diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0006_unsafe_block_in_mod.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0006_unsafe_block_in_mod.rs deleted file mode 100644 index 26141e9049106..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0006_unsafe_block_in_mod.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo(){} unsafe { } fn bar(){} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0007_async_without_semicolon.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0007_async_without_semicolon.rast deleted file mode 100644 index bf20d5fa4f699..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0007_async_without_semicolon.rast +++ /dev/null @@ -1,32 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BLOCK_EXPR - ASYNC_KW "async" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" -error 27: expected SEMICOLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0007_async_without_semicolon.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0007_async_without_semicolon.rs deleted file mode 100644 index 9a423248c2747..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0007_async_without_semicolon.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo() { let _ = async {} } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0008_pub_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0008_pub_expr.rast deleted file mode 100644 index 0ae9f64e7e635..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0008_pub_expr.rast +++ /dev/null @@ -1,26 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - ERROR - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - EXPR_STMT - LITERAL - INT_NUMBER "92" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" -error 14: expected an item diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0008_pub_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0008_pub_expr.rs deleted file mode 100644 index 2976f68625fb3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0008_pub_expr.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo() { pub 92; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0013_anonymous_static.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0013_anonymous_static.rast deleted file mode 100644 index 823db94f58a30..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0013_anonymous_static.rast +++ /dev/null @@ -1,21 +0,0 @@ -SOURCE_FILE - STATIC - STATIC_KW "static" - WHITESPACE " " - ERROR - UNDERSCORE "_" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "5" - SEMICOLON ";" - WHITESPACE "\n" -error 7: expected a name diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0013_anonymous_static.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0013_anonymous_static.rs deleted file mode 100644 index df8cecb43262b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0013_anonymous_static.rs +++ /dev/null @@ -1 +0,0 @@ -static _: i32 = 5; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast deleted file mode 100644 index f511960040d5f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast +++ /dev/null @@ -1,49 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_EXPR_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_EXPR_FIELD - NAME_REF - IDENT "field" - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - CALL_EXPR - PATH_EXPR - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "default" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" -error 25: expected COLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rs deleted file mode 100644 index a4e5b2f69336f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - S { field ..S::default() } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_struct_field_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_struct_field_recover.rast deleted file mode 100644 index 458d7f4e2fa22..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_struct_field_recover.rast +++ /dev/null @@ -1,31 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_FIELD - NAME - IDENT "f" - WHITESPACE " " - RECORD_FIELD - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - NAME - IDENT "g" - COLON ":" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" -error 12: expected COLON -error 12: expected type -error 12: expected COMMA diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_struct_field_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_struct_field_recover.rs deleted file mode 100644 index da32227adcd7d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_struct_field_recover.rs +++ /dev/null @@ -1 +0,0 @@ -struct S { f pub g: () } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_empty_segment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_empty_segment.rast deleted file mode 100644 index b03f5ad9f7ea0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_empty_segment.rast +++ /dev/null @@ -1,14 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - CRATE_KW "crate" - COLON2 "::" - SEMICOLON ";" - WHITESPACE "\n" -error 11: expected identifier diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_empty_segment.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_empty_segment.rs deleted file mode 100644 index 7510664e10259..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_empty_segment.rs +++ /dev/null @@ -1 +0,0 @@ -use crate::; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_missing_fn_param_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_missing_fn_param_type.rast deleted file mode 100644 index e72df374d1bcf..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_missing_fn_param_type.rast +++ /dev/null @@ -1,53 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "x" - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "y" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "z" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "t" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" -error 6: missing type for function parameter -error 6: expected COMMA -error 16: missing type for function parameter diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_missing_fn_param_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_missing_fn_param_type.rs deleted file mode 100644 index 4a95b908435f2..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_missing_fn_param_type.rs +++ /dev/null @@ -1 +0,0 @@ -fn f(x y: i32, z, t: i32) {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0002_use_tree_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0002_use_tree_list.rast deleted file mode 100644 index f3b1129f277a6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0002_use_tree_list.rast +++ /dev/null @@ -1,29 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - USE_TREE_LIST - L_CURLY "{" - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - COMMA "," - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "b" - COMMA "," - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "c" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0002_use_tree_list.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0002_use_tree_list.rs deleted file mode 100644 index 6fa175f542969..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0002_use_tree_list.rs +++ /dev/null @@ -1 +0,0 @@ -use {a, b, c}; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0003_where_pred_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0003_where_pred_for.rast deleted file mode 100644 index 8407e99f614f0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0003_where_pred_for.rast +++ /dev/null @@ -1,63 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "for_trait" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "F" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n" - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE "\n " - WHERE_PRED - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "F" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "str" - R_PAREN ")" - WHITESPACE "\n" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0003_where_pred_for.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0003_where_pred_for.rs deleted file mode 100644 index 423bc105bd7b4..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0003_where_pred_for.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn for_trait() -where - for<'a> F: Fn(&'a str) -{ } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rast deleted file mode 100644 index 902b06484c81d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rast +++ /dev/null @@ -1,60 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "F" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Box" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PARAM - REF_TYPE - AMP "&" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PARAM - REF_TYPE - AMP "&" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PARAM - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rs deleted file mode 100644 index 93636e926e167..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rs +++ /dev/null @@ -1 +0,0 @@ -type F = Box; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0005_function_type_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0005_function_type_params.rast deleted file mode 100644 index 3858e3eed577b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0005_function_type_params.rast +++ /dev/null @@ -1,38 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Clone" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Copy" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0005_function_type_params.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0005_function_type_params.rs deleted file mode 100644 index 9df40ed396c06..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0005_function_type_params.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo(){} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0006_self_param.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0006_self_param.rast deleted file mode 100644 index 67e28236397f6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0006_self_param.rast +++ /dev/null @@ -1,128 +0,0 @@ -SOURCE_FILE - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "a" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - NAME - SELF_KW "self" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "b" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - AMP "&" - NAME - SELF_KW "self" - COMMA "," - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "c" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - NAME - SELF_KW "self" - COMMA "," - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "d" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - MUT_KW "mut" - WHITESPACE " " - NAME - SELF_KW "self" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "x" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "e" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - MUT_KW "mut" - WHITESPACE " " - NAME - SELF_KW "self" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0006_self_param.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0006_self_param.rs deleted file mode 100644 index 80c0a43f5de0d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0006_self_param.rs +++ /dev/null @@ -1,7 +0,0 @@ -impl S { - fn a(self) {} - fn b(&self,) {} - fn c(&'a self,) {} - fn d(&'a mut self, x: i32) {} - fn e(mut self) {} -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0007_type_param_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0007_type_param_bounds.rast deleted file mode 100644 index dee860c2418f6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0007_type_param_bounds.rast +++ /dev/null @@ -1,53 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - QUESTION "?" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Sized" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - L_PAREN "(" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Copy" - R_PAREN ")" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - TILDE "~" - CONST_KW "const" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Drop" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0007_type_param_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0007_type_param_bounds.rs deleted file mode 100644 index 5da3083b9c56d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0007_type_param_bounds.rs +++ /dev/null @@ -1 +0,0 @@ -struct S; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0008_path_part.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0008_path_part.rast deleted file mode 100644 index 4ccda19a8d7d6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0008_path_part.rast +++ /dev/null @@ -1,98 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - PATH_PAT - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Bar" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - PATH_PAT - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "Bar" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - RECORD_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Bar" - WHITESPACE " " - RECORD_PAT_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - REST_PAT - DOT2 ".." - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Bar" - L_PAREN "(" - REST_PAT - DOT2 ".." - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0008_path_part.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0008_path_part.rs deleted file mode 100644 index f6e32c7c1493a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0008_path_part.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn foo() { - let foo::Bar = (); - let ::Bar = (); - let Bar { .. } = (); - let Bar(..) = (); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0009_loop_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0009_loop_expr.rast deleted file mode 100644 index ab3b49b0d6c5e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0009_loop_expr.rast +++ /dev/null @@ -1,26 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - LOOP_EXPR - LOOP_KW "loop" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0009_loop_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0009_loop_expr.rs deleted file mode 100644 index 9f078fa4816c5..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0009_loop_expr.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn foo() { - loop {}; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0010_extern_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0010_extern_block.rast deleted file mode 100644 index 7a3cd6a0dfdb9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0010_extern_block.rast +++ /dev/null @@ -1,21 +0,0 @@ -SOURCE_FILE - EXTERN_BLOCK - UNSAFE_KW "unsafe" - WHITESPACE " " - ABI - EXTERN_KW "extern" - WHITESPACE " " - STRING "\"C\"" - WHITESPACE " " - EXTERN_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - EXTERN_BLOCK - ABI - EXTERN_KW "extern" - WHITESPACE " " - EXTERN_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0010_extern_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0010_extern_block.rs deleted file mode 100644 index bee5ac8453ed5..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0010_extern_block.rs +++ /dev/null @@ -1,2 +0,0 @@ -unsafe extern "C" {} -extern {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0011_field_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0011_field_expr.rast deleted file mode 100644 index 8498724b9ef07..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0011_field_expr.rast +++ /dev/null @@ -1,60 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - FIELD_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - DOT "." - NAME_REF - IDENT "foo" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - FIELD_EXPR - FIELD_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - DOT "." - NAME_REF - INT_NUMBER "0" - DOT "." - NAME_REF - IDENT "bar" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - FIELD_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - DOT "." - NAME_REF - INT_NUMBER "0" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0011_field_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0011_field_expr.rs deleted file mode 100644 index b8da2ddc30947..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0011_field_expr.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn foo() { - x.foo; - x.0.bar; - x.0(); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rast deleted file mode 100644 index 31c87d1b30935..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rast +++ /dev/null @@ -1,33 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "Foo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE " " - WHERE_PRED - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Copy" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rs deleted file mode 100644 index 2d30e85218708..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rs +++ /dev/null @@ -1 +0,0 @@ -type Foo = () where Foo: Copy; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0013_pointer_type_mut.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0013_pointer_type_mut.rast deleted file mode 100644 index bfe7ed5b40031..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0013_pointer_type_mut.rast +++ /dev/null @@ -1,35 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "M" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PTR_TYPE - STAR "*" - MUT_KW "mut" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "C" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PTR_TYPE - STAR "*" - MUT_KW "mut" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0013_pointer_type_mut.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0013_pointer_type_mut.rs deleted file mode 100644 index 04b2bb9ba5c95..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0013_pointer_type_mut.rs +++ /dev/null @@ -1,2 +0,0 @@ -type M = *mut (); -type C = *mut (); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0014_never_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0014_never_type.rast deleted file mode 100644 index 53dbf3999b2a0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0014_never_type.rast +++ /dev/null @@ -1,13 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "Never" - WHITESPACE " " - EQ "=" - WHITESPACE " " - NEVER_TYPE - BANG "!" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0014_never_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0014_never_type.rs deleted file mode 100644 index de399fcf4a21b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0014_never_type.rs +++ /dev/null @@ -1 +0,0 @@ -type Never = !; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0015_continue_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0015_continue_expr.rast deleted file mode 100644 index 5d80a57a2e49b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0015_continue_expr.rast +++ /dev/null @@ -1,38 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LOOP_EXPR - LOOP_KW "loop" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - CONTINUE_EXPR - CONTINUE_KW "continue" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CONTINUE_EXPR - CONTINUE_KW "continue" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'l" - SEMICOLON ";" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0015_continue_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0015_continue_expr.rs deleted file mode 100644 index 474cc3f0e0c48..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0015_continue_expr.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn foo() { - loop { - continue; - continue 'l; - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rast deleted file mode 100644 index 2a5c644d46713..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rast +++ /dev/null @@ -1,21 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - ARRAY_TYPE - L_BRACK "[" - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - R_BRACK "]" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rs deleted file mode 100644 index 27eb22f2238ad..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rs +++ /dev/null @@ -1 +0,0 @@ -type T = [(); 92]; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.rast deleted file mode 100644 index a0b562629624e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.rast +++ /dev/null @@ -1,76 +0,0 @@ -SOURCE_FILE - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "a" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - NAME - SELF_KW "self" - COLON ":" - WHITESPACE " " - REF_TYPE - AMP "&" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - SELF_TYPE_KW "Self" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "b" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - MUT_KW "mut" - WHITESPACE " " - NAME - SELF_KW "self" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Box" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - SELF_TYPE_KW "Self" - R_ANGLE ">" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.rs deleted file mode 100644 index 6a170d5ac1d38..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.rs +++ /dev/null @@ -1,4 +0,0 @@ -impl S { - fn a(self: &Self) {} - fn b(mut self: Box) {} -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0019_unary_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0019_unary_expr.rast deleted file mode 100644 index 525b267458735..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0019_unary_expr.rast +++ /dev/null @@ -1,45 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - PREFIX_EXPR - STAR "*" - PREFIX_EXPR - STAR "*" - REF_EXPR - AMP "&" - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - PREFIX_EXPR - BANG "!" - PREFIX_EXPR - BANG "!" - LITERAL - TRUE_KW "true" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - PREFIX_EXPR - MINUS "-" - PREFIX_EXPR - MINUS "-" - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0019_unary_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0019_unary_expr.rs deleted file mode 100644 index f1c3f7118b2da..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0019_unary_expr.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn foo() { - **&1; - !!true; - --1; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0021_assoc_item_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0021_assoc_item_list.rast deleted file mode 100644 index def7373c9de0c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0021_assoc_item_list.rast +++ /dev/null @@ -1,81 +0,0 @@ -SOURCE_FILE - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "F" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - SEMICOLON ";" - WHITESPACE "\n " - CONST - CONST_KW "const" - WHITESPACE " " - NAME - IDENT "B" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - SEMICOLON ";" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "bar" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - AMP "&" - NAME - SELF_KW "self" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0021_assoc_item_list.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0021_assoc_item_list.rs deleted file mode 100644 index f108514879dbb..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0021_assoc_item_list.rs +++ /dev/null @@ -1,6 +0,0 @@ -impl F { - type A = i32; - const B: i32 = 92; - fn foo() {} - fn bar(&self) {} -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0022_crate_visibility.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0022_crate_visibility.rast deleted file mode 100644 index 8738292a9f7fe..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0022_crate_visibility.rast +++ /dev/null @@ -1,49 +0,0 @@ -SOURCE_FILE - STRUCT - VISIBILITY - PUB_KW "pub" - L_PAREN "(" - PATH - PATH_SEGMENT - NAME_REF - CRATE_KW "crate" - R_PAREN ")" - WHITESPACE " " - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - VISIBILITY - PUB_KW "pub" - L_PAREN "(" - PATH - PATH_SEGMENT - NAME_REF - SELF_KW "self" - R_PAREN ")" - WHITESPACE " " - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - VISIBILITY - PUB_KW "pub" - L_PAREN "(" - PATH - PATH_SEGMENT - NAME_REF - SUPER_KW "super" - R_PAREN ")" - WHITESPACE " " - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0022_crate_visibility.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0022_crate_visibility.rs deleted file mode 100644 index a790a485f9fa7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0022_crate_visibility.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub(crate) struct S; -pub(self) struct S; -pub(super) struct S; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0023_placeholder_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0023_placeholder_type.rast deleted file mode 100644 index d9db1c34bf866..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0023_placeholder_type.rast +++ /dev/null @@ -1,13 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "Placeholder" - WHITESPACE " " - EQ "=" - WHITESPACE " " - INFER_TYPE - UNDERSCORE "_" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0023_placeholder_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0023_placeholder_type.rs deleted file mode 100644 index 7952dbd57d67b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0023_placeholder_type.rs +++ /dev/null @@ -1 +0,0 @@ -type Placeholder = _; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rast deleted file mode 100644 index 235a9d7f404cf..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rast +++ /dev/null @@ -1,42 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - SLICE_PAT - L_BRACK "[" - IDENT_PAT - NAME - IDENT "a" - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "b" - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - R_BRACK "]" - WHITESPACE " " - EQ "=" - WHITESPACE " " - ARRAY_EXPR - L_BRACK "[" - R_BRACK "]" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rs deleted file mode 100644 index 7955973b952a7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - let [a, b, ..] = []; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0025_slice_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0025_slice_type.rast deleted file mode 100644 index 0bcb315248190..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0025_slice_type.rast +++ /dev/null @@ -1,17 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - SLICE_TYPE - L_BRACK "[" - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - R_BRACK "]" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0025_slice_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0025_slice_type.rs deleted file mode 100644 index 4da1af8270571..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0025_slice_type.rs +++ /dev/null @@ -1 +0,0 @@ -type T = [()]; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rast deleted file mode 100644 index 3cdaf32b5721c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rast +++ /dev/null @@ -1,105 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - L_PAREN "(" - WILDCARD_PAT - UNDERSCORE "_" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - L_PAREN "(" - WILDCARD_PAT - UNDERSCORE "_" - COMMA "," - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - L_PAREN "(" - WILDCARD_PAT - UNDERSCORE "_" - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - WHITESPACE " " - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "x" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rs deleted file mode 100644 index 0dfe63629679b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn foo() { - let S() = (); - let S(_) = (); - let S(_,) = (); - let S(_, .. , x) = (); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0027_ref_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0027_ref_pat.rast deleted file mode 100644 index 4516fd0113274..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0027_ref_pat.rast +++ /dev/null @@ -1,50 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - REF_PAT - AMP "&" - IDENT_PAT - NAME - IDENT "a" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - REF_PAT - AMP "&" - MUT_KW "mut" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "b" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0027_ref_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0027_ref_pat.rs deleted file mode 100644 index de41f5cae0f3e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0027_ref_pat.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - let &a = (); - let &mut b = (); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0028_impl_trait_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0028_impl_trait_type.rast deleted file mode 100644 index c7478da942b53..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0028_impl_trait_type.rast +++ /dev/null @@ -1,45 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - EQ "=" - WHITESPACE " " - IMPL_TRAIT_TYPE - IMPL_KW "impl" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Iterator" - GENERIC_ARG_LIST - L_ANGLE "<" - ASSOC_TYPE_ARG - NAME_REF - IDENT "Item" - EQ "=" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - R_ANGLE ">" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'a" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0028_impl_trait_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0028_impl_trait_type.rs deleted file mode 100644 index 54c5a7c4604d5..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0028_impl_trait_type.rs +++ /dev/null @@ -1 +0,0 @@ -type A = impl Iterator> + 'a; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0029_cast_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0029_cast_expr.rast deleted file mode 100644 index d53dde53811bd..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0029_cast_expr.rast +++ /dev/null @@ -1,90 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - CAST_EXPR - LITERAL - INT_NUMBER "82" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - CAST_EXPR - LITERAL - INT_NUMBER "81" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i8" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - CAST_EXPR - LITERAL - INT_NUMBER "79" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i16" - WHITESPACE " " - MINUS "-" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - CAST_EXPR - LITERAL - INT_NUMBER "0x36" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - WHITESPACE " " - LTEQ "<=" - WHITESPACE " " - LITERAL - INT_NUMBER "0x37" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0029_cast_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0029_cast_expr.rs deleted file mode 100644 index bfe8e4b362a19..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0029_cast_expr.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn foo() { - 82 as i32; - 81 as i8 + 1; - 79 as i16 - 1; - 0x36 as u8 <= 0x37; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0030_let_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0030_let_expr.rast deleted file mode 100644 index dcffcb1ce2f6a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0030_let_expr.rast +++ /dev/null @@ -1,90 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - IF_EXPR - IF_KW "if" - WHITESPACE " " - BIN_EXPR - LET_EXPR - LET_KW "let" - WHITESPACE " " - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - L_PAREN "(" - WILDCARD_PAT - UNDERSCORE "_" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "None" - WHITESPACE " " - AMP2 "&&" - WHITESPACE " " - LITERAL - TRUE_KW "true" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - WHILE_EXPR - WHILE_KW "while" - WHITESPACE " " - BIN_EXPR - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - EQ2 "==" - WHITESPACE " " - LITERAL - INT_NUMBER "5" - WHITESPACE " " - AMP2 "&&" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - LET_EXPR - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "None" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "None" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0030_let_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0030_let_expr.rs deleted file mode 100644 index 0131d5e338290..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0030_let_expr.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn foo() { - if let Some(_) = None && true {} - while 1 == 5 && (let None = None) {} -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0031_while_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0031_while_expr.rast deleted file mode 100644 index 16c522414af49..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0031_while_expr.rast +++ /dev/null @@ -1,87 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - WHILE_EXPR - WHILE_KW "while" - WHITESPACE " " - LITERAL - TRUE_KW "true" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - WHILE_EXPR - WHILE_KW "while" - WHITESPACE " " - LET_EXPR - LET_KW "let" - WHITESPACE " " - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - L_PAREN "(" - IDENT_PAT - NAME - IDENT "x" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - METHOD_CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "it" - DOT "." - NAME_REF - IDENT "next" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - WHILE_EXPR - WHILE_KW "while" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LITERAL - TRUE_KW "true" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0031_while_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0031_while_expr.rs deleted file mode 100644 index 2f818816025ec..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0031_while_expr.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn foo() { - while true {}; - while let Some(x) = it.next() {}; - while { true } {}; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0032_fn_pointer_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0032_fn_pointer_type.rast deleted file mode 100644 index 608b0be160a63..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0032_fn_pointer_type.rast +++ /dev/null @@ -1,98 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FN_PTR_TYPE - FN_KW "fn" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "B" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FN_PTR_TYPE - UNSAFE_KW "unsafe" - WHITESPACE " " - FN_KW "fn" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "C" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FN_PTR_TYPE - UNSAFE_KW "unsafe" - WHITESPACE " " - ABI - EXTERN_KW "extern" - WHITESPACE " " - STRING "\"C\"" - WHITESPACE " " - FN_KW "fn" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "D" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FN_PTR_TYPE - ABI - EXTERN_KW "extern" - WHITESPACE " " - STRING "\"C\"" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - PARAM_LIST - L_PAREN "(" - WHITESPACE " " - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - WHITESPACE " " - COMMA "," - WHITESPACE " " - PARAM - DOT3 "..." - WHITESPACE " " - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0032_fn_pointer_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0032_fn_pointer_type.rs deleted file mode 100644 index 9493da83d56c3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0032_fn_pointer_type.rs +++ /dev/null @@ -1,4 +0,0 @@ -type A = fn(); -type B = unsafe fn(); -type C = unsafe extern "C" fn(); -type D = extern "C" fn ( u8 , ... ) -> u8; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0033_reference_type;.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0033_reference_type;.rast deleted file mode 100644 index b5c9d7a8dfb30..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0033_reference_type;.rast +++ /dev/null @@ -1,51 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - EQ "=" - WHITESPACE " " - REF_TYPE - AMP "&" - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "B" - WHITESPACE " " - EQ "=" - WHITESPACE " " - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'static" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "C" - WHITESPACE " " - EQ "=" - WHITESPACE " " - REF_TYPE - AMP "&" - MUT_KW "mut" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0033_reference_type;.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0033_reference_type;.rs deleted file mode 100644 index 3ac0badabc5a7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0033_reference_type;.rs +++ /dev/null @@ -1,3 +0,0 @@ -type A = &(); -type B = &'static (); -type C = &mut (); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0034_break_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0034_break_expr.rast deleted file mode 100644 index 06c053d0f823d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0034_break_expr.rast +++ /dev/null @@ -1,57 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LOOP_EXPR - LOOP_KW "loop" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - BREAK_EXPR - BREAK_KW "break" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BREAK_EXPR - BREAK_KW "break" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'l" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BREAK_EXPR - BREAK_KW "break" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BREAK_EXPR - BREAK_KW "break" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'l" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - SEMICOLON ";" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0034_break_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0034_break_expr.rs deleted file mode 100644 index 1b40946365f26..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0034_break_expr.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn foo() { - loop { - break; - break 'l; - break 92; - break 'l 92; - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0037_qual_paths.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0037_qual_paths.rast deleted file mode 100644 index 8c66cfe599f2a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0037_qual_paths.rast +++ /dev/null @@ -1,79 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "X" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH - PATH_SEGMENT - L_ANGLE "<" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "A" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "B" - R_ANGLE ">" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Output" - SEMICOLON ";" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH - PATH_SEGMENT - L_ANGLE "<" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "usize" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Default" - R_ANGLE ">" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "default" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0037_qual_paths.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0037_qual_paths.rs deleted file mode 100644 index d140692e210ba..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0037_qual_paths.rs +++ /dev/null @@ -1,2 +0,0 @@ -type X = ::Output; -fn foo() { ::default(); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0038_full_range_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0038_full_range_expr.rast deleted file mode 100644 index 9ffc076304191..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0038_full_range_expr.rast +++ /dev/null @@ -1,29 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - INDEX_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "xs" - L_BRACK "[" - RANGE_EXPR - DOT2 ".." - R_BRACK "]" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0038_full_range_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0038_full_range_expr.rs deleted file mode 100644 index ae21ad94cb384..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0038_full_range_expr.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo() { xs[..]; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rast deleted file mode 100644 index 07b0210e44d03..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rast +++ /dev/null @@ -1,63 +0,0 @@ -SOURCE_FILE - FN - VISIBILITY - CRATE_KW "crate" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_FIELD - VISIBILITY - CRATE_KW "crate" - WHITESPACE " " - NAME - IDENT "field" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "T" - TUPLE_FIELD_LIST - L_PAREN "(" - TUPLE_FIELD - VISIBILITY - CRATE_KW "crate" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rs deleted file mode 100644 index e2b5f2161dfc1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rs +++ /dev/null @@ -1,3 +0,0 @@ -crate fn main() { } -struct S { crate field: u32 } -struct T(crate u32); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0041_trait_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0041_trait_item.rast deleted file mode 100644 index dd7f76eb93970..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0041_trait_item.rast +++ /dev/null @@ -1,31 +0,0 @@ -SOURCE_FILE - TRAIT - TRAIT_KW "trait" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE " " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "new" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - SELF_TYPE_KW "Self" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0041_trait_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0041_trait_item.rs deleted file mode 100644 index dcd9a71144fd5..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0041_trait_item.rs +++ /dev/null @@ -1 +0,0 @@ -trait T { fn new() -> Self; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0042_call_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0042_call_expr.rast deleted file mode 100644 index 19cc8d5ac7cf1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0042_call_expr.rast +++ /dev/null @@ -1,148 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "f" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - CALL_EXPR - CALL_EXPR - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "f" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - ARG_LIST - L_PAREN "(" - LITERAL - INT_NUMBER "1" - R_PAREN ")" - ARG_LIST - L_PAREN "(" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - LITERAL - INT_NUMBER "2" - COMMA "," - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "f" - ARG_LIST - L_PAREN "(" - CALL_EXPR - PATH_EXPR - PATH - PATH - PATH_SEGMENT - L_ANGLE "<" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - R_ANGLE ">" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "func" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "f" - ARG_LIST - L_PAREN "(" - CALL_EXPR - PATH_EXPR - PATH - PATH - PATH_SEGMENT - L_ANGLE "<" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Trait" - R_ANGLE ">" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "func" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0042_call_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0042_call_expr.rs deleted file mode 100644 index ffbf46d6d1f39..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0042_call_expr.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn foo() { - let _ = f(); - let _ = f()(1)(1, 2,); - let _ = f(::func()); - f(::func()); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0044_block_items.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0044_block_items.rast deleted file mode 100644 index 2e4b515cab99b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0044_block_items.rast +++ /dev/null @@ -1,30 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "a" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "b" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0044_block_items.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0044_block_items.rs deleted file mode 100644 index d9868718c791e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0044_block_items.rs +++ /dev/null @@ -1 +0,0 @@ -fn a() { fn b() {} } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast deleted file mode 100644 index e9d93a0d0a4ef..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast +++ /dev/null @@ -1,48 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "F" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "FnMut" - PARAM_LIST - L_PAREN "(" - PARAM - REF_TYPE - AMP "&" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - R_PAREN ")" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0045_param_list_opt_patterns.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0045_param_list_opt_patterns.rs deleted file mode 100644 index 9b93442c0f21c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0045_param_list_opt_patterns.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo)>(){} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0046_singleton_tuple_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0046_singleton_tuple_type.rast deleted file mode 100644 index 0129955d13633..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0046_singleton_tuple_type.rast +++ /dev/null @@ -1,20 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0046_singleton_tuple_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0046_singleton_tuple_type.rs deleted file mode 100644 index cb66bad2470f9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0046_singleton_tuple_type.rs +++ /dev/null @@ -1 +0,0 @@ -type T = (i32,); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0048_path_type_with_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0048_path_type_with_bounds.rast deleted file mode 100644 index a059e124ae424..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0048_path_type_with_bounds.rast +++ /dev/null @@ -1,85 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Box" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - DYN_TRAIT_TYPE - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'f" - R_ANGLE ">" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Box" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - DYN_TRAIT_TYPE - DYN_KW "dyn" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'f" - R_ANGLE ">" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0048_path_type_with_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0048_path_type_with_bounds.rs deleted file mode 100644 index 4bb0f63b73927..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0048_path_type_with_bounds.rs +++ /dev/null @@ -1,2 +0,0 @@ -fn foo() -> Box {} -fn foo() -> Box {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0050_fn_decl.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0050_fn_decl.rast deleted file mode 100644 index f7fac807f4960..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0050_fn_decl.rast +++ /dev/null @@ -1,22 +0,0 @@ -SOURCE_FILE - TRAIT - TRAIT_KW "trait" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE " " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0050_fn_decl.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0050_fn_decl.rs deleted file mode 100644 index c9f74f7f5c842..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0050_fn_decl.rs +++ /dev/null @@ -1 +0,0 @@ -trait T { fn foo(); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0051_unit_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0051_unit_type.rast deleted file mode 100644 index b3df315354623..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0051_unit_type.rast +++ /dev/null @@ -1,14 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0051_unit_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0051_unit_type.rs deleted file mode 100644 index c039cf7d324a8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0051_unit_type.rs +++ /dev/null @@ -1 +0,0 @@ -type T = (); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0052_path_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0052_path_type.rast deleted file mode 100644 index d498d3721890c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0052_path_type.rast +++ /dev/null @@ -1,72 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "B" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "Foo" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "C" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - SELF_KW "self" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Foo" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "D" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - SUPER_KW "super" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Foo" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0052_path_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0052_path_type.rs deleted file mode 100644 index bf94f32e1968a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0052_path_type.rs +++ /dev/null @@ -1,4 +0,0 @@ -type A = Foo; -type B = ::Foo; -type C = self::Foo; -type D = super::Foo; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0053_path_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0053_path_expr.rast deleted file mode 100644 index 48e123ab11b4d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0053_path_expr.rast +++ /dev/null @@ -1,97 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_EXPR - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "b" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "a" - GENERIC_ARG_LIST - COLON2 "::" - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "b" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "format" - BANG "!" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0053_path_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0053_path_expr.rs deleted file mode 100644 index 333ebabef48ae..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0053_path_expr.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn foo() { - let _ = a; - let _ = a::b; - let _ = ::a::; - let _ = format!(); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0054_record_field_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0054_record_field_attrs.rast deleted file mode 100644 index 639ee0eb77702..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0054_record_field_attrs.rast +++ /dev/null @@ -1,33 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_FIELD - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - NAME - IDENT "f" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "f32" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0054_record_field_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0054_record_field_attrs.rs deleted file mode 100644 index d7f0b4382dac6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0054_record_field_attrs.rs +++ /dev/null @@ -1 +0,0 @@ -struct S { #[attr] f: f32 } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0055_literal_pattern.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0055_literal_pattern.rast deleted file mode 100644 index c83ea7ade719f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0055_literal_pattern.rast +++ /dev/null @@ -1,77 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - LITERAL_PAT - MINUS "-" - LITERAL - INT_NUMBER "1" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - LITERAL_PAT - LITERAL - INT_NUMBER "92" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - LITERAL_PAT - LITERAL - CHAR "'c'" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - LITERAL_PAT - LITERAL - STRING "\"hello\"" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0055_literal_pattern.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0055_literal_pattern.rs deleted file mode 100644 index 6dfd67b4ce932..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0055_literal_pattern.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - match () { - -1 => (), - 92 => (), - 'c' => (), - "hello" => (), - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0056_where_clause.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0056_where_clause.rast deleted file mode 100644 index a3cbe457e1ac9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0056_where_clause.rast +++ /dev/null @@ -1,117 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n" - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE "\n " - WHERE_PRED - LIFETIME - LIFETIME_IDENT "'a" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'b" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'c" - COMMA "," - WHITESPACE "\n " - WHERE_PRED - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Clone" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Copy" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'static" - COMMA "," - WHITESPACE "\n " - WHERE_PRED - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "Iterator" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Item" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'a" - COMMA "," - WHITESPACE "\n " - WHERE_PRED - PATH_TYPE - PATH - PATH - PATH_SEGMENT - L_ANGLE "<" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Iterator" - R_ANGLE ">" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Item" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE "\n" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0056_where_clause.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0056_where_clause.rs deleted file mode 100644 index 19d7e571b0ca6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0056_where_clause.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn foo() -where - 'a: 'b + 'c, - T: Clone + Copy + 'static, - Iterator::Item: 'a, - ::Item: 'a -{} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast deleted file mode 100644 index 44c967e8dc597..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast +++ /dev/null @@ -1,251 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - RANGE_PAT - LITERAL_PAT - LITERAL - INT_NUMBER "0" - WHITESPACE " " - DOT3 "..." - WHITESPACE " " - LITERAL_PAT - LITERAL - INT_NUMBER "100" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - RANGE_PAT - LITERAL_PAT - LITERAL - INT_NUMBER "101" - WHITESPACE " " - DOT2EQ "..=" - WHITESPACE " " - LITERAL_PAT - LITERAL - INT_NUMBER "200" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - RANGE_PAT - LITERAL_PAT - LITERAL - INT_NUMBER "200" - WHITESPACE " " - DOT2 ".." - WHITESPACE " " - LITERAL_PAT - LITERAL - INT_NUMBER "301" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - RANGE_PAT - LITERAL_PAT - LITERAL - INT_NUMBER "302" - WHITESPACE " " - DOT2 ".." - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n\n " - EXPR_STMT - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - ARG_LIST - L_PAREN "(" - CAST_EXPR - LITERAL - INT_NUMBER "10" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - OR_PAT - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - L_PAREN "(" - LITERAL_PAT - LITERAL - INT_NUMBER "0" - R_PAREN ")" - WHITESPACE " " - PIPE "|" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "None" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - L_PAREN "(" - RANGE_PAT - LITERAL_PAT - LITERAL - INT_NUMBER "1" - DOT2 ".." - R_PAREN ")" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n\n " - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - CAST_EXPR - LITERAL - INT_NUMBER "10" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - COMMA "," - WHITESPACE " " - CAST_EXPR - LITERAL - INT_NUMBER "5" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - TUPLE_PAT - L_PAREN "(" - LITERAL_PAT - LITERAL - INT_NUMBER "0" - COMMA "," - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - R_PAREN ")" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - TUPLE_PAT - L_PAREN "(" - RANGE_PAT - LITERAL_PAT - LITERAL - INT_NUMBER "1" - DOT2 ".." - COMMA "," - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - R_PAREN ")" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs deleted file mode 100644 index 6c586a8956098..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs +++ /dev/null @@ -1,18 +0,0 @@ -fn main() { - match 92 { - 0 ... 100 => (), - 101 ..= 200 => (), - 200 .. 301 => (), - 302 .. => (), - } - - match Some(10 as u8) { - Some(0) | None => (), - Some(1..) => () - } - - match (10 as u8, 5 as u8) { - (0, _) => (), - (1.., _) => () - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0059_match_arms_commas.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0059_match_arms_commas.rast deleted file mode 100644 index 94897c2d20478..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0059_match_arms_commas.rast +++ /dev/null @@ -1,60 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0059_match_arms_commas.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0059_match_arms_commas.rs deleted file mode 100644 index 1f25d577a9550..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0059_match_arms_commas.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn foo() { - match () { - _ => (), - _ => {} - _ => () - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0060_extern_crate.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0060_extern_crate.rast deleted file mode 100644 index 0a660957d152a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0060_extern_crate.rast +++ /dev/null @@ -1,10 +0,0 @@ -SOURCE_FILE - EXTERN_CRATE - EXTERN_KW "extern" - WHITESPACE " " - CRATE_KW "crate" - WHITESPACE " " - NAME_REF - IDENT "foo" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0060_extern_crate.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0060_extern_crate.rs deleted file mode 100644 index 49af74e1b7489..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0060_extern_crate.rs +++ /dev/null @@ -1 +0,0 @@ -extern crate foo; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rast deleted file mode 100644 index 9997d0ae348c4..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rast +++ /dev/null @@ -1,125 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_EXPR_FIELD_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_EXPR_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_EXPR_FIELD - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - COMMA "," - WHITESPACE " " - RECORD_EXPR_FIELD - NAME_REF - IDENT "y" - COLON ":" - WHITESPACE " " - LITERAL - INT_NUMBER "32" - COMMA "," - WHITESPACE " " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_EXPR_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_EXPR_FIELD - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - COMMA "," - WHITESPACE " " - RECORD_EXPR_FIELD - NAME_REF - IDENT "y" - COLON ":" - WHITESPACE " " - LITERAL - INT_NUMBER "32" - COMMA "," - WHITESPACE " " - DOT2 ".." - CALL_EXPR - PATH_EXPR - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "Default" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "default" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "TupleStruct" - WHITESPACE " " - RECORD_EXPR_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_EXPR_FIELD - NAME_REF - INT_NUMBER "0" - COLON ":" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - WHITESPACE " " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rs deleted file mode 100644 index 6285e55497722..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn foo() { - S {}; - S { x, y: 32, }; - S { x, y: 32, ..Default::default() }; - TupleStruct { 0: 1 }; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0062_mod_contents.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0062_mod_contents.rast deleted file mode 100644 index 5f60e03d446e3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0062_mod_contents.rast +++ /dev/null @@ -1,65 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - MACRO_RULES - MACRO_RULES_KW "macro_rules" - BANG "!" - WHITESPACE " " - NAME - IDENT "foo" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - MACRO_CALL - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "bar" - BANG "!" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - MACRO_CALL - PATH - PATH - PATH_SEGMENT - NAME_REF - SUPER_KW "super" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "baz" - BANG "!" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0062_mod_contents.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0062_mod_contents.rs deleted file mode 100644 index 24a15c5c5c943..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0062_mod_contents.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn foo() {} -macro_rules! foo {} -foo::bar!(); -super::baz! {} -struct S; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0063_impl_item_neg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0063_impl_item_neg.rast deleted file mode 100644 index 805052fbcae43..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0063_impl_item_neg.rast +++ /dev/null @@ -1,23 +0,0 @@ -SOURCE_FILE - IMPL - IMPL_KW "impl" - WHITESPACE " " - BANG "!" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Send" - WHITESPACE " " - FOR_KW "for" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0063_impl_item_neg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0063_impl_item_neg.rs deleted file mode 100644 index a7bd4b048d6c7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0063_impl_item_neg.rs +++ /dev/null @@ -1 +0,0 @@ -impl !Send for S {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0064_if_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0064_if_expr.rast deleted file mode 100644 index e2e964e44d125..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0064_if_expr.rast +++ /dev/null @@ -1,126 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - IF_EXPR - IF_KW "if" - WHITESPACE " " - LITERAL - TRUE_KW "true" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - IF_EXPR - IF_KW "if" - WHITESPACE " " - LITERAL - TRUE_KW "true" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE " " - ELSE_KW "else" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - IF_EXPR - IF_KW "if" - WHITESPACE " " - LITERAL - TRUE_KW "true" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE " " - ELSE_KW "else" - WHITESPACE " " - IF_EXPR - IF_KW "if" - WHITESPACE " " - LITERAL - FALSE_KW "false" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE " " - ELSE_KW "else" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - IF_EXPR - IF_KW "if" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - IF_EXPR - IF_KW "if" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LITERAL - TRUE_KW "true" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - ELSE_KW "else" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0064_if_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0064_if_expr.rs deleted file mode 100644 index 40f227ba3a46a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0064_if_expr.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn foo() { - if true {}; - if true {} else {}; - if true {} else if false {} else {}; - if S {}; - if { true } { } else { }; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0065_dyn_trait_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0065_dyn_trait_type.rast deleted file mode 100644 index e37d43aac6c28..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0065_dyn_trait_type.rast +++ /dev/null @@ -1,45 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - EQ "=" - WHITESPACE " " - DYN_TRAIT_TYPE - DYN_KW "dyn" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Iterator" - GENERIC_ARG_LIST - L_ANGLE "<" - ASSOC_TYPE_ARG - NAME_REF - IDENT "Item" - EQ "=" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - R_ANGLE ">" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'a" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0065_dyn_trait_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0065_dyn_trait_type.rs deleted file mode 100644 index c3ecabb992b33..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0065_dyn_trait_type.rs +++ /dev/null @@ -1 +0,0 @@ -type A = dyn Iterator> + 'a; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0066_match_arm.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0066_match_arm.rast deleted file mode 100644 index 8189cf0a8e51a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0066_match_arm.rast +++ /dev/null @@ -1,152 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - MATCH_GUARD - IF_KW "if" - WHITESPACE " " - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Test" - WHITESPACE " " - R_ANGLE ">" - WHITESPACE " " - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Test" - RECORD_EXPR_FIELD_LIST - L_CURLY "{" - RECORD_EXPR_FIELD - NAME_REF - IDENT "field" - COLON ":" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - R_CURLY "}" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - OR_PAT - IDENT_PAT - NAME - IDENT "X" - WHITESPACE " " - PIPE "|" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "Y" - WHITESPACE " " - MATCH_GUARD - IF_KW "if" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Z" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - PIPE "|" - WHITESPACE " " - OR_PAT - IDENT_PAT - NAME - IDENT "X" - WHITESPACE " " - PIPE "|" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "Y" - WHITESPACE " " - MATCH_GUARD - IF_KW "if" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Z" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - PIPE "|" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "X" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0066_match_arm.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0066_match_arm.rs deleted file mode 100644 index 9e009e24f4e36..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0066_match_arm.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn foo() { - match () { - _ => (), - _ if Test > Test{field: 0} => (), - X | Y if Z => (), - | X | Y if Z => (), - | X => (), - }; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0067_crate_path.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0067_crate_path.rast deleted file mode 100644 index f71367ae1e43e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0067_crate_path.rast +++ /dev/null @@ -1,16 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - CRATE_KW "crate" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "foo" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0067_crate_path.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0067_crate_path.rs deleted file mode 100644 index 1bbb5930bf623..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0067_crate_path.rs +++ /dev/null @@ -1 +0,0 @@ -use crate::foo; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rast deleted file mode 100644 index e387e14d14fa6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rast +++ /dev/null @@ -1,53 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - LITERAL - INT_NUMBER "1" - R_CURLY "}" - WHITESPACE " " - AMP "&" - WHITESPACE " " - LITERAL - INT_NUMBER "2" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - LITERAL - INT_NUMBER "1" - R_CURLY "}" - WHITESPACE " " - EXPR_STMT - REF_EXPR - AMP "&" - LITERAL - INT_NUMBER "2" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rs deleted file mode 100644 index 7e8bd87bf1cfa..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn f() { - let _ = {1} & 2; - {1} &2; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0071_match_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0071_match_expr.rast deleted file mode 100644 index 0d6cd390ea07d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0071_match_expr.rast +++ /dev/null @@ -1,96 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE " " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE " " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_EXPR_FIELD_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0071_match_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0071_match_expr.rs deleted file mode 100644 index c4021dc104878..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0071_match_expr.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn foo() { - match () { }; - match S {}; - match { } { _ => () }; - match { S {} } {}; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0072_return_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0072_return_expr.rast deleted file mode 100644 index 62cff12202667..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0072_return_expr.rast +++ /dev/null @@ -1,29 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - RETURN_EXPR - RETURN_KW "return" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - RETURN_EXPR - RETURN_KW "return" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0072_return_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0072_return_expr.rs deleted file mode 100644 index 5733666b605fa..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0072_return_expr.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn foo() { - return; - return 92; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0073_type_item_type_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0073_type_item_type_params.rast deleted file mode 100644 index 60ac3b3c4af0c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0073_type_item_type_params.rast +++ /dev/null @@ -1,20 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "Result" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - R_ANGLE ">" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0073_type_item_type_params.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0073_type_item_type_params.rs deleted file mode 100644 index defd110c4922e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0073_type_item_type_params.rs +++ /dev/null @@ -1 +0,0 @@ -type Result = (); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rast deleted file mode 100644 index 950421feb70b2..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rast +++ /dev/null @@ -1,63 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - MATCH_ARM - TUPLE_PAT - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - MATCH_ARM - SLICE_PAT - L_BRACK "[" - R_BRACK "]" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rs deleted file mode 100644 index 2edd578f9d731..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn foo() { - match () { - _ => {} - () => {} - [] => {} - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0075_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0075_block.rast deleted file mode 100644 index a23364d152c63..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0075_block.rast +++ /dev/null @@ -1,90 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "a" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "b" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "c" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE " " - EXPR_STMT - LITERAL - INT_NUMBER "2" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "d" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE " " - LITERAL - INT_NUMBER "2" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0075_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0075_block.rs deleted file mode 100644 index 81f44c53307db..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0075_block.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn a() {} -fn b() { let _ = 1; } -fn c() { 1; 2; } -fn d() { 1; 2 } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0076_function_where_clause.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0076_function_where_clause.rast deleted file mode 100644 index a000d7e5928f2..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0076_function_where_clause.rast +++ /dev/null @@ -1,40 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE " " - WHERE_PRED - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Copy" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0076_function_where_clause.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0076_function_where_clause.rs deleted file mode 100644 index f0920b2a8ad6a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0076_function_where_clause.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo() where T: Copy {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0077_try_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0077_try_expr.rast deleted file mode 100644 index c3aa8c15ded0d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0077_try_expr.rast +++ /dev/null @@ -1,26 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - TRY_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - QUESTION "?" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0077_try_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0077_try_expr.rs deleted file mode 100644 index 8b74f7bc81449..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0077_try_expr.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn foo() { - x?; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0078_type_alias.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0078_type_alias.rast deleted file mode 100644 index c5da799741f9b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0078_type_alias.rast +++ /dev/null @@ -1,16 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "Foo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Bar" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0078_type_alias.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0078_type_alias.rs deleted file mode 100644 index 04c0344fa3641..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0078_type_alias.rs +++ /dev/null @@ -1 +0,0 @@ -type Foo = Bar; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0079_impl_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0079_impl_item.rast deleted file mode 100644 index 879676309a2c6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0079_impl_item.rast +++ /dev/null @@ -1,14 +0,0 @@ -SOURCE_FILE - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0079_impl_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0079_impl_item.rs deleted file mode 100644 index 647799d7c14f9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0079_impl_item.rs +++ /dev/null @@ -1 +0,0 @@ -impl S {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0080_postfix_range.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0080_postfix_range.rast deleted file mode 100644 index 3a59cf7b83252..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0080_postfix_range.rast +++ /dev/null @@ -1,96 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "x" - WHITESPACE " " - EQ "=" - WHITESPACE " " - RANGE_EXPR - LITERAL - INT_NUMBER "1" - DOT2 ".." - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - RANGE_EXPR - LITERAL - INT_NUMBER "1" - DOT2 ".." - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE " " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - RANGE_EXPR - METHOD_CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - DOT "." - NAME_REF - IDENT "b" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - DOT2 ".." - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE " " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0080_postfix_range.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0080_postfix_range.rs deleted file mode 100644 index e7b7cfc6b1af9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0080_postfix_range.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn foo() { - let x = 1..; - match 1.. { _ => () }; - match a.b()..S { _ => () }; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0081_for_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0081_for_type.rast deleted file mode 100644 index 7600457a9b8b3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0081_for_type.rast +++ /dev/null @@ -1,117 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FOR_TYPE - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - FN_PTR_TYPE - FN_KW "fn" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "B" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FOR_TYPE - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - FN_PTR_TYPE - UNSAFE_KW "unsafe" - WHITESPACE " " - ABI - EXTERN_KW "extern" - WHITESPACE " " - STRING "\"C\"" - WHITESPACE " " - FN_KW "fn" - PARAM_LIST - L_PAREN "(" - PARAM - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "Obj" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FOR_TYPE - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "PartialEq" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0081_for_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0081_for_type.rs deleted file mode 100644 index 8ac7b9e103800..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0081_for_type.rs +++ /dev/null @@ -1,3 +0,0 @@ -type A = for<'a> fn() -> (); -type B = for<'a> unsafe extern "C" fn(&'a ()) -> (); -type Obj = for<'a> PartialEq<&'a i32>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0082_ref_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0082_ref_expr.rast deleted file mode 100644 index 108b0802c3345..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0082_ref_expr.rast +++ /dev/null @@ -1,139 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - COMMENT "// reference operator" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - REF_EXPR - AMP "&" - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - REF_EXPR - AMP "&" - MUT_KW "mut" - WHITESPACE " " - REF_EXPR - AMP "&" - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "f" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - REF_EXPR - AMP "&" - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "raw" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - REF_EXPR - AMP "&" - FIELD_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "raw" - DOT "." - NAME_REF - INT_NUMBER "0" - SEMICOLON ";" - WHITESPACE "\n " - COMMENT "// raw reference operator" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - REF_EXPR - AMP "&" - RAW_KW "raw" - WHITESPACE " " - MUT_KW "mut" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - REF_EXPR - AMP "&" - RAW_KW "raw" - WHITESPACE " " - CONST_KW "const" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0082_ref_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0082_ref_expr.rs deleted file mode 100644 index c5262f4469b06..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0082_ref_expr.rs +++ /dev/null @@ -1,10 +0,0 @@ -fn foo() { - // reference operator - let _ = &1; - let _ = &mut &f(); - let _ = &raw; - let _ = &raw.0; - // raw reference operator - let _ = &raw mut foo; - let _ = &raw const foo; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0083_struct_items.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0083_struct_items.rast deleted file mode 100644 index cdbc40fe0b2fb..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0083_struct_items.rast +++ /dev/null @@ -1,87 +0,0 @@ -SOURCE_FILE@0..106 - STRUCT@0..11 - STRUCT_KW@0..6 "struct" - WHITESPACE@6..7 " " - NAME@7..10 - IDENT@7..10 "Foo" - SEMICOLON@10..11 ";" - WHITESPACE@11..12 "\n" - STRUCT@12..25 - STRUCT_KW@12..18 "struct" - WHITESPACE@18..19 " " - NAME@19..22 - IDENT@19..22 "Foo" - WHITESPACE@22..23 " " - RECORD_FIELD_LIST@23..25 - L_CURLY@23..24 "{" - R_CURLY@24..25 "}" - WHITESPACE@25..26 "\n" - STRUCT@26..39 - STRUCT_KW@26..32 "struct" - WHITESPACE@32..33 " " - NAME@33..36 - IDENT@33..36 "Foo" - TUPLE_FIELD_LIST@36..38 - L_PAREN@36..37 "(" - R_PAREN@37..38 ")" - SEMICOLON@38..39 ";" - WHITESPACE@39..40 "\n" - STRUCT@40..66 - STRUCT_KW@40..46 "struct" - WHITESPACE@46..47 " " - NAME@47..50 - IDENT@47..50 "Foo" - TUPLE_FIELD_LIST@50..65 - L_PAREN@50..51 "(" - TUPLE_FIELD@51..57 - PATH_TYPE@51..57 - PATH@51..57 - PATH_SEGMENT@51..57 - NAME_REF@51..57 - IDENT@51..57 "String" - COMMA@57..58 "," - WHITESPACE@58..59 " " - TUPLE_FIELD@59..64 - PATH_TYPE@59..64 - PATH@59..64 - PATH_SEGMENT@59..64 - NAME_REF@59..64 - IDENT@59..64 "usize" - R_PAREN@64..65 ")" - SEMICOLON@65..66 ";" - WHITESPACE@66..67 "\n" - STRUCT@67..105 - STRUCT_KW@67..73 "struct" - WHITESPACE@73..74 " " - NAME@74..77 - IDENT@74..77 "Foo" - WHITESPACE@77..78 " " - RECORD_FIELD_LIST@78..105 - L_CURLY@78..79 "{" - WHITESPACE@79..84 "\n " - RECORD_FIELD@84..90 - NAME@84..85 - IDENT@84..85 "a" - COLON@85..86 ":" - WHITESPACE@86..87 " " - PATH_TYPE@87..90 - PATH@87..90 - PATH_SEGMENT@87..90 - NAME_REF@87..90 - IDENT@87..90 "i32" - COMMA@90..91 "," - WHITESPACE@91..96 "\n " - RECORD_FIELD@96..102 - NAME@96..97 - IDENT@96..97 "b" - COLON@97..98 ":" - WHITESPACE@98..99 " " - PATH_TYPE@99..102 - PATH@99..102 - PATH_SEGMENT@99..102 - NAME_REF@99..102 - IDENT@99..102 "f32" - COMMA@102..103 "," - WHITESPACE@103..104 "\n" - R_CURLY@104..105 "}" - WHITESPACE@105..106 "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0084_paren_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0084_paren_type.rast deleted file mode 100644 index 29995bb752fca..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0084_paren_type.rast +++ /dev/null @@ -1,19 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PAREN_TYPE - L_PAREN "(" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0084_paren_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0084_paren_type.rs deleted file mode 100644 index 6e1b25101245c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0084_paren_type.rs +++ /dev/null @@ -1 +0,0 @@ -type T = (i32); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rast deleted file mode 100644 index 403c265ea35be..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rast +++ /dev/null @@ -1,136 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - TRUE_KW "true" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - FALSE_KW "false" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - FLOAT_NUMBER "2.0" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - BYTE "b'a'" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - CHAR "'b'" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - STRING "\"c\"" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - STRING "r\"d\"" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - BYTE_STRING "b\"e\"" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - BYTE_STRING "br\"f\"" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rs deleted file mode 100644 index 2e11a5a6e68c8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rs +++ /dev/null @@ -1,12 +0,0 @@ -fn foo() { - let _ = true; - let _ = false; - let _ = 1; - let _ = 2.0; - let _ = b'a'; - let _ = 'b'; - let _ = "c"; - let _ = r"d"; - let _ = b"e"; - let _ = br"f"; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0086_function_ret_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0086_function_ret_type.rast deleted file mode 100644 index 6687c843fbbe1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0086_function_ret_type.rast +++ /dev/null @@ -1,36 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "bar" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0086_function_ret_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0086_function_ret_type.rs deleted file mode 100644 index d22d8cada690d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0086_function_ret_type.rs +++ /dev/null @@ -1,2 +0,0 @@ -fn foo() {} -fn bar() -> () {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0088_break_ambiguity.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0088_break_ambiguity.rast deleted file mode 100644 index cbf5e84e8cdc7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0088_break_ambiguity.rast +++ /dev/null @@ -1,67 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - IF_EXPR - IF_KW "if" - WHITESPACE " " - BREAK_EXPR - BREAK_KW "break" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - WHILE_EXPR - WHILE_KW "while" - WHITESPACE " " - BREAK_EXPR - BREAK_KW "break" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - FOR_EXPR - FOR_KW "for" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "i" - WHITESPACE " " - IN_KW "in" - WHITESPACE " " - BREAK_EXPR - BREAK_KW "break" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - BREAK_EXPR - BREAK_KW "break" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0088_break_ambiguity.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0088_break_ambiguity.rs deleted file mode 100644 index 560eb05b949e1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0088_break_ambiguity.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn foo(){ - if break {} - while break {} - for i in break {} - match break {} -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0090_type_param_default.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0090_type_param_default.rast deleted file mode 100644 index cf7236f62e6b3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0090_type_param_default.rast +++ /dev/null @@ -1,22 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0090_type_param_default.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0090_type_param_default.rs deleted file mode 100644 index 540eacb027750..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0090_type_param_default.rs +++ /dev/null @@ -1 +0,0 @@ -struct S; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rast deleted file mode 100644 index 372c867ae6d8d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rast +++ /dev/null @@ -1,23 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "F" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FN_PTR_TYPE - FN_KW "fn" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rs deleted file mode 100644 index e3ba5e87f5d4e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rs +++ /dev/null @@ -1 +0,0 @@ -type F = fn() -> (); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0093_index_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0093_index_expr.rast deleted file mode 100644 index 6969259fc089c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0093_index_expr.rast +++ /dev/null @@ -1,34 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - INDEX_EXPR - INDEX_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - L_BRACK "[" - LITERAL - INT_NUMBER "1" - R_BRACK "]" - L_BRACK "[" - LITERAL - INT_NUMBER "2" - R_BRACK "]" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0093_index_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0093_index_expr.rs deleted file mode 100644 index b9ba78a6cbdd6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0093_index_expr.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn foo() { - x[1][2]; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0095_placeholder_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0095_placeholder_pat.rast deleted file mode 100644 index d39c3df2b7ef6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0095_placeholder_pat.rast +++ /dev/null @@ -1,29 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0095_placeholder_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0095_placeholder_pat.rs deleted file mode 100644 index 4d719c4335bcd..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0095_placeholder_pat.rs +++ /dev/null @@ -1 +0,0 @@ -fn main() { let _ = (); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0096_no_semi_after_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0096_no_semi_after_block.rast deleted file mode 100644 index f89cc15e72108..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0096_no_semi_after_block.rast +++ /dev/null @@ -1,125 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - IF_EXPR - IF_KW "if" - WHITESPACE " " - LITERAL - TRUE_KW "true" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - LOOP_EXPR - LOOP_KW "loop" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - WHILE_EXPR - WHILE_KW "while" - WHITESPACE " " - LITERAL - TRUE_KW "true" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - FOR_EXPR - FOR_KW "for" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - IN_KW "in" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - MACRO_RULES - MACRO_RULES_KW "macro_rules" - BANG "!" - WHITESPACE " " - NAME - IDENT "test" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - WHITESPACE "\n " - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - EQ "=" - R_ANGLE ">" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n " - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "test" - BANG "!" - TOKEN_TREE - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0096_no_semi_after_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0096_no_semi_after_block.rs deleted file mode 100644 index 4919665cb5781..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0096_no_semi_after_block.rs +++ /dev/null @@ -1,13 +0,0 @@ -fn foo() { - if true {} - loop {} - match () {} - while true {} - for _ in () {} - {} - {} - macro_rules! test { - () => {} - } - test!{} -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0099_param_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0099_param_list.rast deleted file mode 100644 index d240a52f6ff15..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0099_param_list.rast +++ /dev/null @@ -1,103 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "a" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "b" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "x" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "c" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "x" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "d" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "x" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "y" - COLON ":" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0099_param_list.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0099_param_list.rs deleted file mode 100644 index 9d55bedbba747..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0099_param_list.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn a() {} -fn b(x: i32) {} -fn c(x: i32, ) {} -fn d(x: i32, y: ()) {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0100_for_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0100_for_expr.rast deleted file mode 100644 index 6bc3c0fb05770..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0100_for_expr.rast +++ /dev/null @@ -1,36 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - FOR_EXPR - FOR_KW "for" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "x" - WHITESPACE " " - IN_KW "in" - WHITESPACE " " - ARRAY_EXPR - L_BRACK "[" - R_BRACK "]" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0100_for_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0100_for_expr.rs deleted file mode 100644 index 972197d2a1752..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0100_for_expr.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn foo() { - for x in [] {}; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0102_record_pat_field_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0102_record_pat_field_list.rast deleted file mode 100644 index f69ae1d6445f9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0102_record_pat_field_list.rast +++ /dev/null @@ -1,175 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - RECORD_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_PAT_FIELD_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - RECORD_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_PAT_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_PAT_FIELD - IDENT_PAT - NAME - IDENT "f" - COMMA "," - WHITESPACE " " - RECORD_PAT_FIELD - IDENT_PAT - REF_KW "ref" - WHITESPACE " " - MUT_KW "mut" - WHITESPACE " " - NAME - IDENT "g" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - RECORD_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_PAT_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_PAT_FIELD - NAME_REF - IDENT "h" - COLON ":" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - R_CURLY "}" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - RECORD_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_PAT_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_PAT_FIELD - NAME_REF - IDENT "h" - COLON ":" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - COMMA "," - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - RECORD_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_PAT_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - REST_PAT - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "cfg" - TOKEN_TREE - L_PAREN "(" - IDENT "any" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - R_BRACK "]" - WHITESPACE " " - DOT2 ".." - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0102_record_pat_field_list.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0102_record_pat_field_list.rs deleted file mode 100644 index 0bfaae7c4d026..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0102_record_pat_field_list.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn foo() { - let S {} = (); - let S { f, ref mut g } = (); - let S { h: _, ..} = (); - let S { h: _, } = (); - let S { #[cfg(any())] .. } = (); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0103_array_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0103_array_expr.rast deleted file mode 100644 index 60395948c185b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0103_array_expr.rast +++ /dev/null @@ -1,55 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - ARRAY_EXPR - L_BRACK "[" - R_BRACK "]" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - ARRAY_EXPR - L_BRACK "[" - LITERAL - INT_NUMBER "1" - R_BRACK "]" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - ARRAY_EXPR - L_BRACK "[" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - LITERAL - INT_NUMBER "2" - COMMA "," - R_BRACK "]" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - ARRAY_EXPR - L_BRACK "[" - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE " " - LITERAL - INT_NUMBER "2" - R_BRACK "]" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0103_array_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0103_array_expr.rs deleted file mode 100644 index 4dc1999d14083..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0103_array_expr.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn foo() { - []; - [1]; - [1, 2,]; - [1; 2]; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0104_path_fn_trait_args.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0104_path_fn_trait_args.rast deleted file mode 100644 index fd83daf841f04..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0104_path_fn_trait_args.rast +++ /dev/null @@ -1,41 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "F" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Box" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0104_path_fn_trait_args.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0104_path_fn_trait_args.rs deleted file mode 100644 index 17ed20e5b13c5..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0104_path_fn_trait_args.rs +++ /dev/null @@ -1 +0,0 @@ -type F = Box ()>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0106_lambda_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0106_lambda_expr.rast deleted file mode 100644 index c25ad8430d0d0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0106_lambda_expr.rast +++ /dev/null @@ -1,246 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - CLOSURE_EXPR - PARAM_LIST - PIPE "|" - PIPE "|" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CLOSURE_EXPR - PARAM_LIST - PIPE "|" - PIPE "|" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - WHITESPACE " " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CLOSURE_EXPR - PARAM_LIST - PIPE "|" - PARAM - IDENT_PAT - NAME - IDENT "x" - PIPE "|" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CLOSURE_EXPR - MOVE_KW "move" - WHITESPACE " " - PARAM_LIST - PIPE "|" - PARAM - IDENT_PAT - NAME - IDENT "x" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - PIPE "|" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CLOSURE_EXPR - ASYNC_KW "async" - WHITESPACE " " - PARAM_LIST - PIPE "|" - PIPE "|" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CLOSURE_EXPR - MOVE_KW "move" - WHITESPACE " " - PARAM_LIST - PIPE "|" - PIPE "|" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CLOSURE_EXPR - ASYNC_KW "async" - WHITESPACE " " - MOVE_KW "move" - WHITESPACE " " - PARAM_LIST - PIPE "|" - PIPE "|" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CLOSURE_EXPR - STATIC_KW "static" - WHITESPACE " " - PARAM_LIST - PIPE "|" - PIPE "|" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CLOSURE_EXPR - STATIC_KW "static" - WHITESPACE " " - MOVE_KW "move" - WHITESPACE " " - PARAM_LIST - PIPE "|" - PIPE "|" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CLOSURE_EXPR - STATIC_KW "static" - WHITESPACE " " - ASYNC_KW "async" - WHITESPACE " " - PARAM_LIST - PIPE "|" - PIPE "|" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CLOSURE_EXPR - STATIC_KW "static" - WHITESPACE " " - ASYNC_KW "async" - WHITESPACE " " - MOVE_KW "move" - WHITESPACE " " - PARAM_LIST - PIPE "|" - PIPE "|" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CLOSURE_EXPR - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - PARAM_LIST - PIPE "|" - PIPE "|" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CLOSURE_EXPR - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - MOVE_KW "move" - WHITESPACE " " - PARAM_LIST - PIPE "|" - PIPE "|" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0106_lambda_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0106_lambda_expr.rs deleted file mode 100644 index 75516d258456f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0106_lambda_expr.rs +++ /dev/null @@ -1,15 +0,0 @@ -fn foo() { - || (); - || -> i32 { 92 }; - |x| x; - move |x: i32,| x; - async || {}; - move || {}; - async move || {}; - static || {}; - static move || {}; - static async || {}; - static async move || {}; - for<'a> || {}; - for<'a> move || {}; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0107_method_call_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0107_method_call_expr.rast deleted file mode 100644 index dcbcfe1231e62..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0107_method_call_expr.rast +++ /dev/null @@ -1,63 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - METHOD_CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - DOT "." - NAME_REF - IDENT "foo" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - METHOD_CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "y" - DOT "." - NAME_REF - IDENT "bar" - GENERIC_ARG_LIST - COLON2 "::" - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - R_ANGLE ">" - ARG_LIST - L_PAREN "(" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - LITERAL - INT_NUMBER "2" - COMMA "," - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0107_method_call_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0107_method_call_expr.rs deleted file mode 100644 index 1a3aa35ae8e73..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0107_method_call_expr.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn foo() { - x.foo(); - y.bar::(1, 2,); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0108_tuple_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0108_tuple_expr.rast deleted file mode 100644 index ac5a717031575..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0108_tuple_expr.rast +++ /dev/null @@ -1,39 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - PAREN_EXPR - L_PAREN "(" - LITERAL - INT_NUMBER "1" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - TUPLE_EXPR - L_PAREN "(" - LITERAL - INT_NUMBER "1" - COMMA "," - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0108_tuple_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0108_tuple_expr.rs deleted file mode 100644 index e4f774280ca35..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0108_tuple_expr.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn foo() { - (); - (1); - (1,); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0109_label.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0109_label.rast deleted file mode 100644 index 48d0bde845a59..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0109_label.rast +++ /dev/null @@ -1,70 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - LOOP_EXPR - LABEL - LIFETIME - LIFETIME_IDENT "'a" - COLON ":" - WHITESPACE " " - LOOP_KW "loop" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - WHILE_EXPR - LABEL - LIFETIME - LIFETIME_IDENT "'b" - COLON ":" - WHITESPACE " " - WHILE_KW "while" - WHITESPACE " " - LITERAL - TRUE_KW "true" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FOR_EXPR - LABEL - LIFETIME - LIFETIME_IDENT "'c" - COLON ":" - WHITESPACE " " - FOR_KW "for" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "x" - WHITESPACE " " - IN_KW "in" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0109_label.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0109_label.rs deleted file mode 100644 index 48e83f263b912..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0109_label.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn foo() { - 'a: loop {} - 'b: while true {} - 'c: for x in () {} -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rast deleted file mode 100644 index cebe98c43aa62..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rast +++ /dev/null @@ -1,90 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_PAT - L_PAREN "(" - IDENT_PAT - NAME - IDENT "a" - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "b" - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_PAT - L_PAREN "(" - IDENT_PAT - NAME - IDENT "a" - COMMA "," - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_PAT - L_PAREN "(" - REST_PAT - DOT2 ".." - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_PAT - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rs deleted file mode 100644 index ba719879d4c1a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() { - let (a, b, ..) = (); - let (a,) = (); - let (..) = (); - let () = (); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0112_bind_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0112_bind_pat.rast deleted file mode 100644 index eb1c32474a241..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0112_bind_pat.rast +++ /dev/null @@ -1,128 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "a" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - MUT_KW "mut" - WHITESPACE " " - NAME - IDENT "b" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - REF_KW "ref" - WHITESPACE " " - NAME - IDENT "c" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - REF_KW "ref" - WHITESPACE " " - MUT_KW "mut" - WHITESPACE " " - NAME - IDENT "d" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "e" - WHITESPACE " " - AT "@" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - REF_KW "ref" - WHITESPACE " " - MUT_KW "mut" - WHITESPACE " " - NAME - IDENT "f" - WHITESPACE " " - AT "@" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "g" - WHITESPACE " " - AT "@" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0112_bind_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0112_bind_pat.rs deleted file mode 100644 index 820a9e72ce563..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0112_bind_pat.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let a = (); - let mut b = (); - let ref c = (); - let ref mut d = (); - let e @ _ = (); - let ref mut f @ g @ _ = (); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0113_nocontentexpr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0113_nocontentexpr.rast deleted file mode 100644 index 8bd90a7f675a8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0113_nocontentexpr.rast +++ /dev/null @@ -1,57 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - SEMICOLON ";" - SEMICOLON ";" - SEMICOLON ";" - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "some_expr" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - SEMICOLON ";" - SEMICOLON ";" - SEMICOLON ";" - EXPR_STMT - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - SEMICOLON ";" - SEMICOLON ";" - SEMICOLON ";" - R_CURLY "}" - SEMICOLON ";" - SEMICOLON ";" - SEMICOLON ";" - SEMICOLON ";" - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Ok" - ARG_LIST - L_PAREN "(" - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0113_nocontentexpr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0113_nocontentexpr.rs deleted file mode 100644 index bbf09e367cf2a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0113_nocontentexpr.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn foo(){ - ;;;some_expr();;;;{;;;};;;;Ok(()) -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0114_tuple_struct_where.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0114_tuple_struct_where.rast deleted file mode 100644 index aab7741657067..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0114_tuple_struct_where.rast +++ /dev/null @@ -1,42 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - R_ANGLE ">" - TUPLE_FIELD_LIST - L_PAREN "(" - TUPLE_FIELD - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - R_PAREN ")" - WHITESPACE " " - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE " " - WHERE_PRED - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Clone" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0114_tuple_struct_where.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0114_tuple_struct_where.rs deleted file mode 100644 index a602e0018275a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0114_tuple_struct_where.rs +++ /dev/null @@ -1 +0,0 @@ -struct S(T) where T: Clone; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0115_tuple_field_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0115_tuple_field_attrs.rast deleted file mode 100644 index 1699602f4fbaf..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0115_tuple_field_attrs.rast +++ /dev/null @@ -1,28 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - WHITESPACE " " - TUPLE_FIELD_LIST - L_PAREN "(" - TUPLE_FIELD - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "f32" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0115_tuple_field_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0115_tuple_field_attrs.rs deleted file mode 100644 index 648ffe5654810..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0115_tuple_field_attrs.rs +++ /dev/null @@ -1 +0,0 @@ -struct S (#[attr] f32); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0117_macro_call_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0117_macro_call_type.rast deleted file mode 100644 index 8165cb7d9baf4..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0117_macro_call_type.rast +++ /dev/null @@ -1,46 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - EQ "=" - WHITESPACE " " - MACRO_TYPE - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - BANG "!" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "B" - WHITESPACE " " - EQ "=" - WHITESPACE " " - MACRO_TYPE - MACRO_CALL - PATH - PATH - PATH_SEGMENT - NAME_REF - CRATE_KW "crate" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "foo" - BANG "!" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0117_macro_call_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0117_macro_call_type.rs deleted file mode 100644 index edb470c899972..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0117_macro_call_type.rs +++ /dev/null @@ -1,2 +0,0 @@ -type A = foo!(); -type B = crate::foo!(); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0118_match_guard.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0118_match_guard.rast deleted file mode 100644 index 96318b52195ec..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0118_match_guard.rast +++ /dev/null @@ -1,77 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - MATCH_GUARD - IF_KW "if" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - MATCH_GUARD - IF_KW "if" - WHITESPACE " " - LET_EXPR - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "foo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "bar" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0118_match_guard.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0118_match_guard.rs deleted file mode 100644 index cfe05ce4e18fc..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0118_match_guard.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn foo() { - match () { - _ if foo => (), - _ if let foo = bar => (), - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast deleted file mode 100644 index 6fd9f424676b6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast +++ /dev/null @@ -1,84 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "doc" - TOKEN_TREE - L_PAREN "(" - STRING "\"Inner attribute\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "doc" - TOKEN_TREE - L_PAREN "(" - STRING "\"Can be\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "doc" - TOKEN_TREE - L_PAREN "(" - STRING "\"Stacked\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rs deleted file mode 100644 index 54a67c9d7b7a1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn foo() { - match () { - #![doc("Inner attribute")] - #![doc("Can be")] - #![doc("Stacked")] - _ => (), - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast deleted file mode 100644 index 0f7580c1a3392..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast +++ /dev/null @@ -1,151 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "cfg" - TOKEN_TREE - L_PAREN "(" - IDENT "feature" - WHITESPACE " " - EQ "=" - WHITESPACE " " - STRING "\"some\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "cfg" - TOKEN_TREE - L_PAREN "(" - IDENT "feature" - WHITESPACE " " - EQ "=" - WHITESPACE " " - STRING "\"other\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "cfg" - TOKEN_TREE - L_PAREN "(" - IDENT "feature" - WHITESPACE " " - EQ "=" - WHITESPACE " " - STRING "\"many\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "cfg" - TOKEN_TREE - L_PAREN "(" - IDENT "feature" - WHITESPACE " " - EQ "=" - WHITESPACE " " - STRING "\"attributes\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "cfg" - TOKEN_TREE - L_PAREN "(" - IDENT "feature" - WHITESPACE " " - EQ "=" - WHITESPACE " " - STRING "\"before\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rs deleted file mode 100644 index 676db42d1a70b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rs +++ /dev/null @@ -1,12 +0,0 @@ -fn foo() { - match () { - #[cfg(feature = "some")] - _ => (), - #[cfg(feature = "other")] - _ => (), - #[cfg(feature = "many")] - #[cfg(feature = "attributes")] - #[cfg(feature = "before")] - _ => (), - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rast deleted file mode 100644 index 338d53995ae53..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rast +++ /dev/null @@ -1,62 +0,0 @@ -SOURCE_FILE - EXTERN_BLOCK - ABI - EXTERN_KW "extern" - WHITESPACE " " - STRING "\"C\"" - WHITESPACE " " - EXTERN_ITEM_LIST - L_CURLY "{" - WHITESPACE " " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "printf" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "format" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - CONST_KW "const" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i8" - COMMA "," - WHITESPACE " " - PARAM - DOT3 "..." - COMMA "," - WHITESPACE " " - PARAM - WILDCARD_PAT - UNDERSCORE "_" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rs deleted file mode 100644 index 533096cd5bbd5..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rs +++ /dev/null @@ -1 +0,0 @@ -extern "C" { fn printf(format: *const i8, ..., _: u8) -> i32; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rast deleted file mode 100644 index 8d9b61630ae68..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rast +++ /dev/null @@ -1,33 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH - PATH_SEGMENT - NAME_REF - CRATE_KW "crate" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "foo" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rs deleted file mode 100644 index 0f454d121d698..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo() { crate::foo(); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast deleted file mode 100644 index a1df70841e854..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast +++ /dev/null @@ -1,49 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_EXPR_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_EXPR_FIELD - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "cfg" - TOKEN_TREE - L_PAREN "(" - IDENT "test" - R_PAREN ")" - R_BRACK "]" - WHITESPACE " " - NAME_REF - IDENT "field" - COLON ":" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rs deleted file mode 100644 index a6c7760c7672b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - S { #[cfg(test)] field: 1 } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast deleted file mode 100644 index 81b7f2b3cbbea..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast +++ /dev/null @@ -1,105 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "A" - R_BRACK "]" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - MACRO_EXPR - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "B" - R_BRACK "]" - WHITESPACE " " - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "bar" - BANG "!" - TOKEN_TREE - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - BLOCK_EXPR - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "C" - R_BRACK "]" - WHITESPACE " " - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "D" - R_BRACK "]" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - RETURN_EXPR - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "D" - R_BRACK "]" - WHITESPACE " " - RETURN_KW "return" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rs deleted file mode 100644 index b28c078f9359b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn foo() { - #[A] foo(); - #[B] bar!{} - #[C] #[D] {} - #[D] return (); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0129_marco_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0129_marco_pat.rast deleted file mode 100644 index cedaa904533af..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0129_marco_pat.rast +++ /dev/null @@ -1,37 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - MACRO_PAT - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "m" - BANG "!" - TOKEN_TREE - L_PAREN "(" - IDENT "x" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0129_marco_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0129_marco_pat.rs deleted file mode 100644 index 811181d9ba821..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0129_marco_pat.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - let m!(x) = 0; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_let_stmt.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_let_stmt.rast deleted file mode 100644 index de9d0fc19ee1f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_let_stmt.rast +++ /dev/null @@ -1,36 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "x" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_let_stmt.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_let_stmt.rs deleted file mode 100644 index 8003999fd08f7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_let_stmt.rs +++ /dev/null @@ -1 +0,0 @@ -fn f() { let x: i32 = 92; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_try_block_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_try_block_expr.rast deleted file mode 100644 index aec8fbf4775c6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_try_block_expr.rast +++ /dev/null @@ -1,32 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BLOCK_EXPR - TRY_KW "try" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_try_block_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_try_block_expr.rs deleted file mode 100644 index 0f1b41eb64b47..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_try_block_expr.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn foo() { - let _ = try {}; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rast deleted file mode 100644 index b73780261baa2..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rast +++ /dev/null @@ -1,31 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - EXISTENTIAL_KW "existential" - WHITESPACE " " - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "Foo" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "usize" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rs deleted file mode 100644 index 23baf7145cccb..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rs +++ /dev/null @@ -1 +0,0 @@ -existential type Foo: Fn() -> usize; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rast deleted file mode 100644 index b21f37cd85afd..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rast +++ /dev/null @@ -1,90 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "x" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BOX_EXPR - BOX_KW "box" - WHITESPACE " " - LITERAL - INT_NUMBER "1i32" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "y" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - BOX_EXPR - BOX_KW "box" - WHITESPACE " " - LITERAL - INT_NUMBER "1i32" - COMMA "," - WHITESPACE " " - BOX_EXPR - BOX_KW "box" - WHITESPACE " " - LITERAL - INT_NUMBER "2i32" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "z" - WHITESPACE " " - EQ "=" - WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - ARG_LIST - L_PAREN "(" - BOX_EXPR - BOX_KW "box" - WHITESPACE " " - LITERAL - INT_NUMBER "1i32" - COMMA "," - WHITESPACE " " - BOX_EXPR - BOX_KW "box" - WHITESPACE " " - LITERAL - INT_NUMBER "2i32" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rs deleted file mode 100644 index fc9923b7137ed..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn foo() { - let x = box 1i32; - let y = (box 1i32, box 2i32); - let z = Foo(box 1i32, box 2i32); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rast deleted file mode 100644 index f5ee12fe96788..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rast +++ /dev/null @@ -1,64 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "simple_function" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - ENUM - ENUM_KW "enum" - WHITESPACE " " - NAME - IDENT "LocalEnum" - WHITESPACE " " - VARIANT_LIST - L_CURLY "{" - WHITESPACE "\n " - VARIANT - NAME - IDENT "One" - COMMA "," - WHITESPACE "\n " - VARIANT - NAME - IDENT "Two" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rs deleted file mode 100644 index eadc7fffb1362..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn simple_function() { - enum LocalEnum { - One, - Two, - }; - fn f() {}; - struct S {}; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0137_await_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0137_await_expr.rast deleted file mode 100644 index 9d37ada0da8de..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0137_await_expr.rast +++ /dev/null @@ -1,70 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - AWAIT_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - DOT "." - AWAIT_KW "await" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - AWAIT_EXPR - FIELD_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - DOT "." - NAME_REF - INT_NUMBER "0" - DOT "." - AWAIT_KW "await" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - METHOD_CALL_EXPR - TRY_EXPR - AWAIT_EXPR - CALL_EXPR - FIELD_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - DOT "." - NAME_REF - INT_NUMBER "0" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - DOT "." - AWAIT_KW "await" - QUESTION "?" - DOT "." - NAME_REF - IDENT "hello" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0137_await_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0137_await_expr.rs deleted file mode 100644 index d2ba89ca60758..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0137_await_expr.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn foo() { - x.await; - x.0.await; - x.0().await?.hello(); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_associated_type_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_associated_type_bounds.rast deleted file mode 100644 index 8cbc98c51ca8f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_associated_type_bounds.rast +++ /dev/null @@ -1,111 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "print_all" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Iterator" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - COMMA "," - WHITESPACE " " - TYPE_ARG - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Item" - COMMA "," - WHITESPACE " " - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - GENERIC_ARG_LIST - COLON2 "::" - L_ANGLE "<" - CONST_ARG - LITERAL - TRUE_KW "true" - R_ANGLE ">" - COMMA "," - WHITESPACE " " - ASSOC_TYPE_ARG - NAME_REF - IDENT "Item" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Display" - COMMA "," - WHITESPACE " " - ASSOC_TYPE_ARG - NAME_REF - IDENT "Item" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - R_ANGLE ">" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "printables" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_associated_type_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_associated_type_bounds.rs deleted file mode 100644 index 0f7a2d1608308..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_associated_type_bounds.rs +++ /dev/null @@ -1 +0,0 @@ -fn print_all, Item: Display, Item<'a> = Item>>(printables: T) {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_expression_after_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_expression_after_block.rast deleted file mode 100644 index 553ac356d73c5..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_expression_after_block.rast +++ /dev/null @@ -1,66 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - MUT_KW "mut" - WHITESPACE " " - NAME - IDENT "p" - WHITESPACE " " - EQ "=" - WHITESPACE " " - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "F" - RECORD_EXPR_FIELD_LIST - L_CURLY "{" - RECORD_EXPR_FIELD - NAME_REF - IDENT "x" - COLON ":" - WHITESPACE " " - LITERAL - INT_NUMBER "5" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - FIELD_EXPR - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "p" - R_CURLY "}" - DOT "." - NAME_REF - IDENT "x" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "10" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_expression_after_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_expression_after_block.rs deleted file mode 100644 index 76007e3ee7741..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_expression_after_block.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn foo() { - let mut p = F{x: 5}; - {p}.x = 10; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_self_param_outer_attr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_self_param_outer_attr.rast deleted file mode 100644 index db583f7d5266e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_self_param_outer_attr.rast +++ /dev/null @@ -1,28 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "must_use" - R_BRACK "]" - WHITESPACE " " - NAME - SELF_KW "self" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_self_param_outer_attr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_self_param_outer_attr.rs deleted file mode 100644 index 35155057a687d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_self_param_outer_attr.rs +++ /dev/null @@ -1 +0,0 @@ -fn f(#[must_use] self) {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0139_param_outer_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0139_param_outer_arg.rast deleted file mode 100644 index c63ea020a3f7a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0139_param_outer_arg.rast +++ /dev/null @@ -1,36 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr1" - R_BRACK "]" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "pat" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Type" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0139_param_outer_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0139_param_outer_arg.rs deleted file mode 100644 index c238be791bd60..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0139_param_outer_arg.rs +++ /dev/null @@ -1 +0,0 @@ -fn f(#[attr1] pat: Type) {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0142_for_range_from.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0142_for_range_from.rast deleted file mode 100644 index 90cf3101c1371..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0142_for_range_from.rast +++ /dev/null @@ -1,42 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - FOR_EXPR - FOR_KW "for" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "x" - WHITESPACE " " - IN_KW "in" - WHITESPACE " " - RANGE_EXPR - LITERAL - INT_NUMBER "0" - WHITESPACE " " - DOT2 ".." - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - BREAK_EXPR - BREAK_KW "break" - SEMICOLON ";" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0142_for_range_from.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0142_for_range_from.rs deleted file mode 100644 index af0d40a7aa20c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0142_for_range_from.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn foo() { - for x in 0 .. { - break; - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0143_box_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0143_box_pat.rast deleted file mode 100644 index df22decde1242..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0143_box_pat.rast +++ /dev/null @@ -1,111 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - BOX_PAT - BOX_KW "box" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "i" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - BOX_PAT - BOX_KW "box" - WHITESPACE " " - RECORD_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Outer" - WHITESPACE " " - RECORD_PAT_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_PAT_FIELD - BOX_PAT - BOX_KW "box" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "i" - COMMA "," - WHITESPACE " " - RECORD_PAT_FIELD - NAME_REF - IDENT "j" - COLON ":" - WHITESPACE " " - BOX_PAT - BOX_KW "box" - WHITESPACE " " - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Inner" - L_PAREN "(" - BOX_PAT - BOX_KW "box" - WHITESPACE " " - REF_PAT - AMP "&" - IDENT_PAT - NAME - IDENT "x" - R_PAREN ")" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - BOX_PAT - BOX_KW "box" - WHITESPACE " " - IDENT_PAT - REF_KW "ref" - WHITESPACE " " - MUT_KW "mut" - WHITESPACE " " - NAME - IDENT "i" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0143_box_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0143_box_pat.rs deleted file mode 100644 index 9d458aa1e6bb8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0143_box_pat.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let box i = (); - let box Outer { box i, j: box Inner(box &x) } = (); - let box ref mut i = (); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0144_dot_dot_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0144_dot_dot_pat.rast deleted file mode 100644 index 4d4011e6b4aa7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0144_dot_dot_pat.rast +++ /dev/null @@ -1,456 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - REST_PAT - DOT2 ".." - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - COMMENT "//" - WHITESPACE "\n " - COMMENT "// Tuples" - WHITESPACE "\n " - COMMENT "//" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_PAT - L_PAREN "(" - IDENT_PAT - NAME - IDENT "a" - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_PAT - L_PAREN "(" - IDENT_PAT - NAME - IDENT "a" - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - COMMA "," - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Tuple" - L_PAREN "(" - IDENT_PAT - NAME - IDENT "a" - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Tuple" - L_PAREN "(" - IDENT_PAT - NAME - IDENT "a" - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - COMMA "," - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_PAT - L_PAREN "(" - REST_PAT - DOT2 ".." - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Tuple" - L_PAREN "(" - REST_PAT - DOT2 ".." - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_PAT - L_PAREN "(" - REST_PAT - DOT2 ".." - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "a" - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Tuple" - L_PAREN "(" - REST_PAT - DOT2 ".." - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "a" - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - COMMENT "//" - WHITESPACE "\n " - COMMENT "// Slices" - WHITESPACE "\n " - COMMENT "//" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - SLICE_PAT - L_BRACK "[" - REST_PAT - DOT2 ".." - R_BRACK "]" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - SLICE_PAT - L_BRACK "[" - IDENT_PAT - NAME - IDENT "head" - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - R_BRACK "]" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - SLICE_PAT - L_BRACK "[" - IDENT_PAT - NAME - IDENT "head" - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "tail" - WHITESPACE " " - AT "@" - WHITESPACE " " - REST_PAT - DOT2 ".." - R_BRACK "]" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - SLICE_PAT - L_BRACK "[" - IDENT_PAT - NAME - IDENT "head" - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "cons" - R_BRACK "]" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - SLICE_PAT - L_BRACK "[" - IDENT_PAT - NAME - IDENT "head" - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "mid" - WHITESPACE " " - AT "@" - WHITESPACE " " - REST_PAT - DOT2 ".." - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "cons" - R_BRACK "]" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - SLICE_PAT - L_BRACK "[" - IDENT_PAT - NAME - IDENT "head" - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "cons" - R_BRACK "]" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - SLICE_PAT - L_BRACK "[" - IDENT_PAT - NAME - IDENT "head" - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "mid" - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "tail" - WHITESPACE " " - AT "@" - WHITESPACE " " - REST_PAT - DOT2 ".." - R_BRACK "]" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - SLICE_PAT - L_BRACK "[" - IDENT_PAT - NAME - IDENT "head" - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "mid" - COMMA "," - WHITESPACE " " - REST_PAT - DOT2 ".." - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "cons" - R_BRACK "]" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0144_dot_dot_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0144_dot_dot_pat.rs deleted file mode 100644 index 3262f27e140ea..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0144_dot_dot_pat.rs +++ /dev/null @@ -1,25 +0,0 @@ -fn main() { - let .. = (); - // - // Tuples - // - let (a, ..) = (); - let (a, ..,) = (); - let Tuple(a, ..) = (); - let Tuple(a, ..,) = (); - let (.., ..) = (); - let Tuple(.., ..) = (); - let (.., a, ..) = (); - let Tuple(.., a, ..) = (); - // - // Slices - // - let [..] = (); - let [head, ..] = (); - let [head, tail @ ..] = (); - let [head, .., cons] = (); - let [head, mid @ .., cons] = (); - let [head, .., .., cons] = (); - let [head, .., mid, tail @ ..] = (); - let [head, .., mid, .., cons] = (); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0145_record_pat_field.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0145_record_pat_field.rast deleted file mode 100644 index f3d2fde466983..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0145_record_pat_field.rast +++ /dev/null @@ -1,123 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - RECORD_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_PAT_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_PAT_FIELD - NAME_REF - INT_NUMBER "0" - COLON ":" - WHITESPACE " " - LITERAL_PAT - LITERAL - INT_NUMBER "1" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - RECORD_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_PAT_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_PAT_FIELD - NAME_REF - IDENT "x" - COLON ":" - WHITESPACE " " - LITERAL_PAT - LITERAL - INT_NUMBER "1" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - RECORD_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_PAT_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_PAT_FIELD - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "cfg" - TOKEN_TREE - L_PAREN "(" - IDENT "any" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - R_BRACK "]" - WHITESPACE " " - NAME_REF - IDENT "x" - COLON ":" - WHITESPACE " " - LITERAL_PAT - LITERAL - INT_NUMBER "1" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0145_record_pat_field.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0145_record_pat_field.rs deleted file mode 100644 index 53cfdc22dd808..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0145_record_pat_field.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn foo() { - let S { 0: 1 } = (); - let S { x: 1 } = (); - let S { #[cfg(any())] x: 1 } = (); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0146_as_precedence.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0146_as_precedence.rast deleted file mode 100644 index 4079d2a9915d8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0146_as_precedence.rast +++ /dev/null @@ -1,43 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - CAST_EXPR - REF_EXPR - AMP "&" - LITERAL - INT_NUMBER "1" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PTR_TYPE - STAR "*" - CONST_KW "const" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0146_as_precedence.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0146_as_precedence.rs deleted file mode 100644 index 70559c5ef5a59..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0146_as_precedence.rs +++ /dev/null @@ -1 +0,0 @@ -fn f() { let _ = &1 as *const i32; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_const_param.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_const_param.rast deleted file mode 100644 index 24595a1a185b0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_const_param.rast +++ /dev/null @@ -1,23 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - GENERIC_PARAM_LIST - L_ANGLE "<" - CONST_PARAM - CONST_KW "const" - WHITESPACE " " - NAME - IDENT "N" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_const_param.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_const_param.rs deleted file mode 100644 index 8cdb3b7036788..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_const_param.rs +++ /dev/null @@ -1 +0,0 @@ -struct S; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rast deleted file mode 100644 index 01de13a907d05..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rast +++ /dev/null @@ -1,19 +0,0 @@ -SOURCE_FILE - MACRO_DEF - MACRO_KW "macro" - WHITESPACE " " - NAME - IDENT "m" - TOKEN_TREE - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - IDENT "i" - COLON ":" - IDENT "ident" - R_PAREN ")" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rs deleted file mode 100644 index a014ae5464e52..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rs +++ /dev/null @@ -1 +0,0 @@ -macro m($i:ident) {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_array_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_array_attrs.rast deleted file mode 100644 index 6eb8af3311955..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_array_attrs.rast +++ /dev/null @@ -1,48 +0,0 @@ -SOURCE_FILE - CONST - CONST_KW "const" - WHITESPACE " " - NAME - IDENT "A" - COLON ":" - WHITESPACE " " - REF_TYPE - AMP "&" - SLICE_TYPE - L_BRACK "[" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i64" - R_BRACK "]" - WHITESPACE " " - EQ "=" - WHITESPACE " " - REF_EXPR - AMP "&" - ARRAY_EXPR - L_BRACK "[" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - LITERAL - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "cfg" - TOKEN_TREE - L_PAREN "(" - IDENT "test" - R_PAREN ")" - R_BRACK "]" - WHITESPACE " " - INT_NUMBER "2" - R_BRACK "]" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_array_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_array_attrs.rs deleted file mode 100644 index 2ac310924fdeb..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_array_attrs.rs +++ /dev/null @@ -1 +0,0 @@ -const A: &[i64] = &[1, #[cfg(test)] 2]; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_impl_type_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_impl_type_params.rast deleted file mode 100644 index 24977a22a5fcd..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_impl_type_params.rast +++ /dev/null @@ -1,38 +0,0 @@ -SOURCE_FILE - IMPL - IMPL_KW "impl" - GENERIC_PARAM_LIST - L_ANGLE "<" - CONST_PARAM - CONST_KW "const" - WHITESPACE " " - NAME - IDENT "N" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - R_ANGLE ">" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Bar" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "N" - R_ANGLE ">" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_impl_type_params.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_impl_type_params.rs deleted file mode 100644 index cb0a105c29f36..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_impl_type_params.rs +++ /dev/null @@ -1 +0,0 @@ -impl Bar {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_fn.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_fn.rast deleted file mode 100644 index a88b3393f2959..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_fn.rast +++ /dev/null @@ -1,15 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_fn.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_fn.rs deleted file mode 100644 index 8f3b7ef112a0f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_fn.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo() {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_trait_alias.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_trait_alias.rast deleted file mode 100644 index 2ef66484ae48f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_trait_alias.rast +++ /dev/null @@ -1,33 +0,0 @@ -SOURCE_FILE - TRAIT - TRAIT_KW "trait" - WHITESPACE " " - NAME - IDENT "Z" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "U" - R_ANGLE ">" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "U" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_trait_alias.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_trait_alias.rs deleted file mode 100644 index 71d76789faed3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_trait_alias.rs +++ /dev/null @@ -1 +0,0 @@ -trait Z = T; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0152_arg_with_attr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0152_arg_with_attr.rast deleted file mode 100644 index ae1074c3680ca..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0152_arg_with_attr.rast +++ /dev/null @@ -1,38 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - ARG_LIST - L_PAREN "(" - LITERAL - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - INT_NUMBER "92" - R_PAREN ")" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0152_arg_with_attr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0152_arg_with_attr.rs deleted file mode 100644 index 5daf1d7b0be91..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0152_arg_with_attr.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - foo(#[attr] 92) -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0153_pub_parens_typepath.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0153_pub_parens_typepath.rast deleted file mode 100644 index 2dede8359872b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0153_pub_parens_typepath.rast +++ /dev/null @@ -1,56 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "B" - TUPLE_FIELD_LIST - L_PAREN "(" - TUPLE_FIELD - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - PAREN_TYPE - L_PAREN "(" - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - SUPER_KW "super" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "A" - R_PAREN ")" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "B" - TUPLE_FIELD_LIST - L_PAREN "(" - TUPLE_FIELD - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - CRATE_KW "crate" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "A" - COMMA "," - R_PAREN ")" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0153_pub_parens_typepath.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0153_pub_parens_typepath.rs deleted file mode 100644 index d4c1638226ea2..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0153_pub_parens_typepath.rs +++ /dev/null @@ -1,2 +0,0 @@ -struct B(pub (super::A)); -struct B(pub (crate::A,)); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rast deleted file mode 100644 index ee8465e6ca9d6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rast +++ /dev/null @@ -1,58 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "Foo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FN_PTR_TYPE - FN_KW "fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "Bar" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Baz" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "Qux" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FN_PTR_TYPE - FN_KW "fn" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "baz" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "Bar" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Baz" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rs deleted file mode 100644 index 80a1701fd66f9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rs +++ /dev/null @@ -1,2 +0,0 @@ -type Foo = fn(Bar::Baz); -type Qux = fn(baz: Bar::Baz); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast deleted file mode 100644 index 30a2842e5388d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast +++ /dev/null @@ -1,43 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - EQ "=" - WHITESPACE " " - DYN_TRAIT_TYPE - TYPE_BOUND_LIST - TYPE_BOUND - FOR_TYPE - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Test" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Send" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs deleted file mode 100644 index 47a71fd1915a9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs +++ /dev/null @@ -1 +0,0 @@ -type A = for<'a> Test<'a> + Send; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_tuple_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_tuple_attrs.rast deleted file mode 100644 index 39857b23c6e39..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_tuple_attrs.rast +++ /dev/null @@ -1,51 +0,0 @@ -SOURCE_FILE - CONST - CONST_KW "const" - WHITESPACE " " - NAME - IDENT "A" - COLON ":" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i64" - COMMA "," - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i64" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - LITERAL - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "cfg" - TOKEN_TREE - L_PAREN "(" - IDENT "test" - R_PAREN ")" - R_BRACK "]" - WHITESPACE " " - INT_NUMBER "2" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_tuple_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_tuple_attrs.rs deleted file mode 100644 index f84b7ab31dc04..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_tuple_attrs.rs +++ /dev/null @@ -1 +0,0 @@ -const A: (i64, i64) = (1, #[cfg(test)] 2); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0155_closure_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0155_closure_params.rast deleted file mode 100644 index 318eb89deaa1f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0155_closure_params.rast +++ /dev/null @@ -1,70 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "foo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - CLOSURE_EXPR - PARAM_LIST - PIPE "|" - PARAM - IDENT_PAT - NAME - IDENT "bar" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "baz" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Baz" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "qux" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "Qux" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Quux" - PIPE "|" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0155_closure_params.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0155_closure_params.rs deleted file mode 100644 index 6ca8dd2d6a9b3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0155_closure_params.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - let foo = |bar, baz: Baz, qux: Qux::Quux| (); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rast deleted file mode 100644 index 59de2b9f1633c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rast +++ /dev/null @@ -1,79 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - CONST_BLOCK_PAT - CONST_KW "const" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LITERAL - INT_NUMBER "15" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - CONST_BLOCK_PAT - CONST_KW "const" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "bar" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rs deleted file mode 100644 index dce9defac2f9f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - let const { 15 } = (); - let const { foo(); bar() } = (); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rast deleted file mode 100644 index ce425a1afde65..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rast +++ /dev/null @@ -1,48 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - PARAM - DOT3 "..." - COMMA "," - WHITESPACE " " - PARAM - TUPLE_PAT - L_PAREN "(" - IDENT_PAT - NAME - IDENT "x" - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "y" - R_PAREN ")" - COLON ":" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rs deleted file mode 100644 index 7b4c62658294a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo(..., (x, y): (i32, i32)) {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_or_pattern.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_or_pattern.rast deleted file mode 100644 index 6a2046d9e99ef..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_or_pattern.rast +++ /dev/null @@ -1,112 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - PAREN_PAT - L_PAREN "(" - OR_PAT - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - PIPE "|" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - R_PAREN ")" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - REF_PAT - AMP "&" - PAREN_PAT - L_PAREN "(" - OR_PAT - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - PIPE "|" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - R_PAREN ")" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - TUPLE_PAT - L_PAREN "(" - OR_PAT - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - PIPE "|" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - COMMA "," - R_PAREN ")" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - SLICE_PAT - L_BRACK "[" - OR_PAT - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - PIPE "|" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - COMMA "," - R_BRACK "]" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_or_pattern.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_or_pattern.rs deleted file mode 100644 index a2631660550f3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_or_pattern.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - match () { - (_ | _) => (), - &(_ | _) => (), - (_ | _,) => (), - [_ | _,] => (), - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rast deleted file mode 100644 index 8a525c6e05e16..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rast +++ /dev/null @@ -1,26 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "Foo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FN_PTR_TYPE - FN_KW "fn" - PARAM_LIST - L_PAREN "(" - PARAM - WILDCARD_PAT - UNDERSCORE "_" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "bar" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rs deleted file mode 100644 index 1ebbe5b0355c3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rs +++ /dev/null @@ -1 +0,0 @@ -type Foo = fn(_: bar); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_variant_discriminant.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_variant_discriminant.rast deleted file mode 100644 index 9f0c5a76108d8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_variant_discriminant.rast +++ /dev/null @@ -1,30 +0,0 @@ -SOURCE_FILE - ENUM - ENUM_KW "enum" - WHITESPACE " " - NAME - IDENT "E" - WHITESPACE " " - VARIANT_LIST - L_CURLY "{" - WHITESPACE " " - VARIANT - NAME - IDENT "X" - TUPLE_FIELD_LIST - L_PAREN "(" - TUPLE_FIELD - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "10" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_variant_discriminant.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_variant_discriminant.rs deleted file mode 100644 index c8c5c0f174e2d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_variant_discriminant.rs +++ /dev/null @@ -1 +0,0 @@ -enum E { X(i32) = 10 } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_binop_resets_statementness.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_binop_resets_statementness.rast deleted file mode 100644 index f667c1972dd04..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_binop_resets_statementness.rast +++ /dev/null @@ -1,38 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "v" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - LITERAL - INT_NUMBER "1" - R_CURLY "}" - AMP "&" - LITERAL - INT_NUMBER "2" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_binop_resets_statementness.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_binop_resets_statementness.rs deleted file mode 100644 index e325e46676fcb..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_binop_resets_statementness.rs +++ /dev/null @@ -1 +0,0 @@ -fn f() { v = {1}&2; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_lambda_ret_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_lambda_ret_block.rast deleted file mode 100644 index 93238bd8f17da..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_lambda_ret_block.rast +++ /dev/null @@ -1,45 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - CALL_EXPR - CLOSURE_EXPR - PARAM_LIST - PIPE "|" - PIPE "|" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - WHITESPACE " " - R_CURLY "}" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_lambda_ret_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_lambda_ret_block.rs deleted file mode 100644 index 061118d3aab8a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_lambda_ret_block.rs +++ /dev/null @@ -1 +0,0 @@ -fn main() { || -> i32 { 92 }(); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_macro_rules_non_brace.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_macro_rules_non_brace.rast deleted file mode 100644 index 45cd4d2aa1209..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_macro_rules_non_brace.rast +++ /dev/null @@ -1,57 +0,0 @@ -SOURCE_FILE - MACRO_RULES - MACRO_RULES_KW "macro_rules" - BANG "!" - WHITESPACE " " - NAME - IDENT "m" - WHITESPACE " " - TOKEN_TREE - L_PAREN "(" - WHITESPACE " " - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - IDENT "i" - COLON ":" - IDENT "ident" - R_PAREN ")" - WHITESPACE " " - EQ "=" - R_ANGLE ">" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - R_CURLY "}" - WHITESPACE " " - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - MACRO_RULES - MACRO_RULES_KW "macro_rules" - BANG "!" - WHITESPACE " " - NAME - IDENT "m" - WHITESPACE " " - TOKEN_TREE - L_BRACK "[" - WHITESPACE " " - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - IDENT "i" - COLON ":" - IDENT "ident" - R_PAREN ")" - WHITESPACE " " - EQ "=" - R_ANGLE ">" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - R_CURLY "}" - WHITESPACE " " - R_BRACK "]" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_macro_rules_non_brace.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_macro_rules_non_brace.rs deleted file mode 100644 index 6033a28cd6454..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_macro_rules_non_brace.rs +++ /dev/null @@ -1,2 +0,0 @@ -macro_rules! m ( ($i:ident) => {} ); -macro_rules! m [ ($i:ident) => {} ]; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_try_macro_fallback.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_try_macro_fallback.rast deleted file mode 100644 index 0adb678fa65d8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_try_macro_fallback.rast +++ /dev/null @@ -1,36 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "try" - BANG "!" - TOKEN_TREE - L_PAREN "(" - IDENT "Ok" - TOKEN_TREE - L_PAREN "(" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_try_macro_fallback.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_try_macro_fallback.rs deleted file mode 100644 index 61a6b46a0b342..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_try_macro_fallback.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo() { try!(Ok(())); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_yield_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_yield_expr.rast deleted file mode 100644 index 31aa58de299cb..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_yield_expr.rast +++ /dev/null @@ -1,29 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - YIELD_EXPR - YIELD_KW "yield" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - YIELD_EXPR - YIELD_KW "yield" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_yield_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_yield_expr.rs deleted file mode 100644 index 596e221f741ae..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_yield_expr.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn foo() { - yield; - yield 1; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_crate_visibility_in.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_crate_visibility_in.rast deleted file mode 100644 index ac45c56956790..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_crate_visibility_in.rast +++ /dev/null @@ -1,42 +0,0 @@ -SOURCE_FILE - STRUCT - VISIBILITY - PUB_KW "pub" - L_PAREN "(" - IN_KW "in" - WHITESPACE " " - PATH - PATH - PATH_SEGMENT - NAME_REF - SUPER_KW "super" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "A" - R_PAREN ")" - WHITESPACE " " - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - VISIBILITY - PUB_KW "pub" - L_PAREN "(" - IN_KW "in" - WHITESPACE " " - PATH - PATH_SEGMENT - NAME_REF - CRATE_KW "crate" - R_PAREN ")" - WHITESPACE " " - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_crate_visibility_in.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_crate_visibility_in.rs deleted file mode 100644 index 2856dbd848f11..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_crate_visibility_in.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub(in super::A) struct S; -pub(in crate) struct S; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_try_macro_rules.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_try_macro_rules.rast deleted file mode 100644 index e6916ae976ea4..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_try_macro_rules.rast +++ /dev/null @@ -1,24 +0,0 @@ -SOURCE_FILE - MACRO_RULES - MACRO_RULES_KW "macro_rules" - BANG "!" - WHITESPACE " " - NAME - IDENT "try" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - WHITESPACE " " - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - EQ "=" - R_ANGLE ">" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - R_CURLY "}" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_try_macro_rules.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_try_macro_rules.rs deleted file mode 100644 index 2e2ab6e60b641..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_try_macro_rules.rs +++ /dev/null @@ -1 +0,0 @@ -macro_rules! try { () => {} } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_impl_item_const.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_impl_item_const.rast deleted file mode 100644 index f7c7aaabc7cb9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_impl_item_const.rast +++ /dev/null @@ -1,24 +0,0 @@ -SOURCE_FILE - IMPL - IMPL_KW "impl" - WHITESPACE " " - CONST_KW "const" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Send" - WHITESPACE " " - FOR_KW "for" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_impl_item_const.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_impl_item_const.rs deleted file mode 100644 index 3252d6f362a8c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_impl_item_const.rs +++ /dev/null @@ -1 +0,0 @@ -impl const Send for S {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_labeled_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_labeled_block.rast deleted file mode 100644 index 181251d4f4f6f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_labeled_block.rast +++ /dev/null @@ -1,28 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - BLOCK_EXPR - LABEL - LIFETIME - LIFETIME_IDENT "'label" - COLON ":" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_labeled_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_labeled_block.rs deleted file mode 100644 index 18b4ff4b1bada..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_labeled_block.rs +++ /dev/null @@ -1 +0,0 @@ -fn f() { 'label: {}; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0162_default_async_unsafe_fn.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0162_default_async_unsafe_fn.rast deleted file mode 100644 index 7c2f7b34c74f1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0162_default_async_unsafe_fn.rast +++ /dev/null @@ -1,43 +0,0 @@ -SOURCE_FILE - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - WHITESPACE " " - FOR_KW "for" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - DEFAULT_KW "default" - WHITESPACE " " - ASYNC_KW "async" - WHITESPACE " " - UNSAFE_KW "unsafe" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0162_default_async_unsafe_fn.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0162_default_async_unsafe_fn.rs deleted file mode 100644 index 05c20a68fe827..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0162_default_async_unsafe_fn.rs +++ /dev/null @@ -1,3 +0,0 @@ -impl T for Foo { - default async unsafe fn foo() {} -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_async_fn.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_async_fn.rast deleted file mode 100644 index 06b37e23938ef..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_async_fn.rast +++ /dev/null @@ -1,41 +0,0 @@ -SOURCE_FILE - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - WHITESPACE " " - FOR_KW "for" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - DEFAULT_KW "default" - WHITESPACE " " - ASYNC_KW "async" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_async_fn.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_async_fn.rs deleted file mode 100644 index 78c3b4d85fb28..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_async_fn.rs +++ /dev/null @@ -1,3 +0,0 @@ -impl T for Foo { - default async fn foo() {} -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_unsafe_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_unsafe_item.rast deleted file mode 100644 index b180d0b72cc9a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_unsafe_item.rast +++ /dev/null @@ -1,45 +0,0 @@ -SOURCE_FILE - IMPL - DEFAULT_KW "default" - WHITESPACE " " - UNSAFE_KW "unsafe" - WHITESPACE " " - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - WHITESPACE " " - FOR_KW "for" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - DEFAULT_KW "default" - WHITESPACE " " - UNSAFE_KW "unsafe" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_unsafe_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_unsafe_item.rs deleted file mode 100644 index 96340f84ab30d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_unsafe_item.rs +++ /dev/null @@ -1,3 +0,0 @@ -default unsafe impl T for Foo { - default unsafe fn foo() {} -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_default_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_default_item.rast deleted file mode 100644 index 7a8e8cf1dd283..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_default_item.rast +++ /dev/null @@ -1,24 +0,0 @@ -SOURCE_FILE - IMPL - DEFAULT_KW "default" - WHITESPACE " " - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - WHITESPACE " " - FOR_KW "for" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_default_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_default_item.rs deleted file mode 100644 index a6836cbd577c6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_default_item.rs +++ /dev/null @@ -1 +0,0 @@ -default impl T for Foo {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_type_path_in_pattern.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_type_path_in_pattern.rast deleted file mode 100644 index 297f7575ca6e7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_type_path_in_pattern.rast +++ /dev/null @@ -1,39 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LET_STMT - LET_KW "let" - WHITESPACE " " - PATH_PAT - PATH - PATH - PATH_SEGMENT - L_ANGLE "<" - INFER_TYPE - UNDERSCORE "_" - R_ANGLE ">" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Foo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_type_path_in_pattern.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_type_path_in_pattern.rs deleted file mode 100644 index ebe26834d883f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_type_path_in_pattern.rs +++ /dev/null @@ -1 +0,0 @@ -fn main() { let <_>::Foo = (); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast deleted file mode 100644 index 3d3587a706334..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast +++ /dev/null @@ -1,32 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LET_STMT - LET_KW "let" - WHITESPACE " " - RANGE_PAT - LITERAL_PAT - LITERAL - INT_NUMBER "0" - WHITESPACE " " - DOT2 ".." - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "1u32" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs deleted file mode 100644 index 1360eda056583..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs +++ /dev/null @@ -1 +0,0 @@ -fn f() { let 0 .. = 1u32; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_rename.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_rename.rast deleted file mode 100644 index 5a5aca96f9144..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_rename.rast +++ /dev/null @@ -1,16 +0,0 @@ -SOURCE_FILE - EXTERN_CRATE - EXTERN_KW "extern" - WHITESPACE " " - CRATE_KW "crate" - WHITESPACE " " - NAME_REF - IDENT "foo" - WHITESPACE " " - RENAME - AS_KW "as" - WHITESPACE " " - NAME - IDENT "bar" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_rename.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_rename.rs deleted file mode 100644 index fc76e17dda478..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_rename.rs +++ /dev/null @@ -1 +0,0 @@ -extern crate foo as bar; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_self.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_self.rast deleted file mode 100644 index edea4245f20ea..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_self.rast +++ /dev/null @@ -1,10 +0,0 @@ -SOURCE_FILE - EXTERN_CRATE - EXTERN_KW "extern" - WHITESPACE " " - CRATE_KW "crate" - WHITESPACE " " - NAME_REF - SELF_KW "self" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_self.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_self.rs deleted file mode 100644 index c969ed109361b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_self.rs +++ /dev/null @@ -1 +0,0 @@ -extern crate self; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0169_mod_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0169_mod_item.rast deleted file mode 100644 index 4d505916cf65a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0169_mod_item.rast +++ /dev/null @@ -1,8 +0,0 @@ -SOURCE_FILE - MODULE - MOD_KW "mod" - WHITESPACE " " - NAME - IDENT "a" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0169_mod_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0169_mod_item.rs deleted file mode 100644 index f21af614da057..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0169_mod_item.rs +++ /dev/null @@ -1 +0,0 @@ -mod a; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_mod_item_curly.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_mod_item_curly.rast deleted file mode 100644 index d5e3f3493c39d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_mod_item_curly.rast +++ /dev/null @@ -1,12 +0,0 @@ -SOURCE_FILE - MODULE - MOD_KW "mod" - WHITESPACE " " - NAME - IDENT "b" - WHITESPACE " " - ITEM_LIST - L_CURLY "{" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_mod_item_curly.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_mod_item_curly.rs deleted file mode 100644 index 16b1b43e8773e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_mod_item_curly.rs +++ /dev/null @@ -1 +0,0 @@ -mod b { } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_tuple_struct.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_tuple_struct.rast deleted file mode 100644 index 6e5f6c2d2bb22..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_tuple_struct.rast +++ /dev/null @@ -1,25 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - TUPLE_FIELD_LIST - L_PAREN "(" - TUPLE_FIELD - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "String" - COMMA "," - WHITESPACE " " - TUPLE_FIELD - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "usize" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_tuple_struct.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_tuple_struct.rs deleted file mode 100644 index b4e05717ed387..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_tuple_struct.rs +++ /dev/null @@ -1 +0,0 @@ -struct S(String, usize); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0171_struct_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0171_struct_item.rast deleted file mode 100644 index 78f96820723ff..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0171_struct_item.rast +++ /dev/null @@ -1,11 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0171_struct_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0171_struct_item.rs deleted file mode 100644 index 5f1a34f49b96c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0171_struct_item.rs +++ /dev/null @@ -1 +0,0 @@ -struct S {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_const_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_const_item.rast deleted file mode 100644 index 909983c9a2a25..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_const_item.rast +++ /dev/null @@ -1,20 +0,0 @@ -SOURCE_FILE - CONST - CONST_KW "const" - WHITESPACE " " - NAME - IDENT "C" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_const_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_const_item.rs deleted file mode 100644 index 6d5f5be65dc5f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_const_item.rs +++ /dev/null @@ -1 +0,0 @@ -const C: u32 = 92; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_record_field_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_record_field_list.rast deleted file mode 100644 index 065d7e7e81f24..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_record_field_list.rast +++ /dev/null @@ -1,35 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_FIELD - NAME - IDENT "a" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - RECORD_FIELD - NAME - IDENT "b" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "f32" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_record_field_list.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_record_field_list.rs deleted file mode 100644 index a3bd7787db77c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_record_field_list.rs +++ /dev/null @@ -1 +0,0 @@ -struct S { a: i32, b: f32 } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_anonymous_const.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_anonymous_const.rast deleted file mode 100644 index d81b4ff267024..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_anonymous_const.rast +++ /dev/null @@ -1,19 +0,0 @@ -SOURCE_FILE - CONST - CONST_KW "const" - WHITESPACE " " - UNDERSCORE "_" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_anonymous_const.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_anonymous_const.rs deleted file mode 100644 index c1d5cdfc621b7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_anonymous_const.rs +++ /dev/null @@ -1 +0,0 @@ -const _: u32 = 0; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_macro_def_curly.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_macro_def_curly.rast deleted file mode 100644 index 5cf305d26581e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_macro_def_curly.rast +++ /dev/null @@ -1,27 +0,0 @@ -SOURCE_FILE - MACRO_DEF - MACRO_KW "macro" - WHITESPACE " " - NAME - IDENT "m" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - WHITESPACE " " - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - IDENT "i" - COLON ":" - IDENT "ident" - R_PAREN ")" - WHITESPACE " " - EQ "=" - R_ANGLE ">" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - R_CURLY "}" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_macro_def_curly.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_macro_def_curly.rs deleted file mode 100644 index 5ed0c777dc942..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_macro_def_curly.rs +++ /dev/null @@ -1 +0,0 @@ -macro m { ($i:ident) => {} } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_union_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_union_item.rast deleted file mode 100644 index af608fc4acba7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_union_item.rast +++ /dev/null @@ -1,35 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "U" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_FIELD - NAME - IDENT "i" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - RECORD_FIELD - NAME - IDENT "f" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "f32" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_union_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_union_item.rs deleted file mode 100644 index 5edf50de3bd5e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_union_item.rs +++ /dev/null @@ -1 +0,0 @@ -struct U { i: i32, f: f32 } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_trait_item_generic_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_trait_item_generic_params.rast deleted file mode 100644 index 01f212e718482..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_trait_item_generic_params.rast +++ /dev/null @@ -1,35 +0,0 @@ -SOURCE_FILE - TRAIT - TRAIT_KW "trait" - WHITESPACE " " - NAME - IDENT "X" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "U" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Debug" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Display" - R_ANGLE ">" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_trait_item_generic_params.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_trait_item_generic_params.rs deleted file mode 100644 index 4a51926a6b57b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_trait_item_generic_params.rs +++ /dev/null @@ -1 +0,0 @@ -trait X {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_unit_struct.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_unit_struct.rast deleted file mode 100644 index 438dea6f40879..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_unit_struct.rast +++ /dev/null @@ -1,8 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_unit_struct.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_unit_struct.rs deleted file mode 100644 index 28377c2760ba8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_unit_struct.rs +++ /dev/null @@ -1 +0,0 @@ -struct S; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_use_tree_star.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_use_tree_star.rast deleted file mode 100644 index 8662423f5d2cc..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_use_tree_star.rast +++ /dev/null @@ -1,24 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - STAR "*" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "std" - COLON2 "::" - USE_TREE_LIST - L_CURLY "{" - USE_TREE - STAR "*" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_use_tree_star.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_use_tree_star.rs deleted file mode 100644 index b8c613440d504..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_use_tree_star.rs +++ /dev/null @@ -1,2 +0,0 @@ -use *; -use std::{*}; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0175_trait_item_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0175_trait_item_bounds.rast deleted file mode 100644 index bab831456221b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0175_trait_item_bounds.rast +++ /dev/null @@ -1,29 +0,0 @@ -SOURCE_FILE - TRAIT - TRAIT_KW "trait" - WHITESPACE " " - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Hash" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Clone" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0175_trait_item_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0175_trait_item_bounds.rs deleted file mode 100644 index e6ad2b56af8c0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0175_trait_item_bounds.rs +++ /dev/null @@ -1 +0,0 @@ -trait T: Hash + Clone {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.rast deleted file mode 100644 index 46cd8ee66545e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.rast +++ /dev/null @@ -1,30 +0,0 @@ -SOURCE_FILE - TRAIT - TRAIT_KW "trait" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE " " - WHERE_PRED - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - SELF_TYPE_KW "Self" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Copy" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.rs deleted file mode 100644 index 52a6a806f3508..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.rs +++ /dev/null @@ -1 +0,0 @@ -trait T where Self: Copy {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_use_tree_alias.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_use_tree_alias.rast deleted file mode 100644 index ef0dd6ba11ce7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_use_tree_alias.rast +++ /dev/null @@ -1,32 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "std" - WHITESPACE " " - RENAME - AS_KW "as" - WHITESPACE " " - NAME - IDENT "stdlib" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Trait" - WHITESPACE " " - RENAME - AS_KW "as" - WHITESPACE " " - UNDERSCORE "_" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_use_tree_alias.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_use_tree_alias.rs deleted file mode 100644 index 19a6906a26844..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_use_tree_alias.rs +++ /dev/null @@ -1,2 +0,0 @@ -use std as stdlib; -use Trait as _; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_assoc_item_list_inner_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_assoc_item_list_inner_attrs.rast deleted file mode 100644 index 9cb3c8a5c3b44..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_assoc_item_list_inner_attrs.rast +++ /dev/null @@ -1,26 +0,0 @@ -SOURCE_FILE - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE " " - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_assoc_item_list_inner_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_assoc_item_list_inner_attrs.rs deleted file mode 100644 index 915e2c932723a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_assoc_item_list_inner_attrs.rs +++ /dev/null @@ -1 +0,0 @@ -impl S { #![attr] } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.rast deleted file mode 100644 index 4443d9d142630..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.rast +++ /dev/null @@ -1,96 +0,0 @@ -SOURCE_FILE - TRAIT - TRAIT_KW "trait" - WHITESPACE " " - NAME - IDENT "Z" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "U" - R_ANGLE ">" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "U" - R_ANGLE ">" - WHITESPACE " " - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE " " - WHERE_PRED - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "U" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Copy" - SEMICOLON ";" - WHITESPACE "\n" - TRAIT - TRAIT_KW "trait" - WHITESPACE " " - NAME - IDENT "Z" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "U" - R_ANGLE ">" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TYPE_BOUND_LIST - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE " " - WHERE_PRED - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - SELF_TYPE_KW "Self" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "U" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.rs deleted file mode 100644 index a90d54b010925..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.rs +++ /dev/null @@ -1,2 +0,0 @@ -trait Z = T where U: Copy; -trait Z = where Self: T; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree.rast deleted file mode 100644 index 98231cdc217fb..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree.rast +++ /dev/null @@ -1,30 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "outer" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "tree" - COLON2 "::" - USE_TREE_LIST - L_CURLY "{" - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "inner" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "tree" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree.rs deleted file mode 100644 index 3cc39434820bd..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree.rs +++ /dev/null @@ -1 +0,0 @@ -use outer::tree::{inner::tree}; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree_path.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree_path.rast deleted file mode 100644 index ede22dbaf5d40..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree_path.rast +++ /dev/null @@ -1,72 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "std" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "std" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "collections" - SEMICOLON ";" - WHITESPACE "\n\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - SELF_KW "self" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "m" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - SUPER_KW "super" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "m" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - CRATE_KW "crate" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "m" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree_path.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree_path.rs deleted file mode 100644 index 5b22f88523ba2..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree_path.rs +++ /dev/null @@ -1,6 +0,0 @@ -use ::std; -use std::collections; - -use self::m; -use super::m; -use crate::m; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0178_use_tree_path_use_tree.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0178_use_tree_path_use_tree.rast deleted file mode 100644 index ed3cafae13b42..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0178_use_tree_path_use_tree.rast +++ /dev/null @@ -1,20 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "std" - COLON2 "::" - USE_TREE_LIST - L_CURLY "{" - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "collections" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0178_use_tree_path_use_tree.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0178_use_tree_path_use_tree.rs deleted file mode 100644 index c3086f51a2e78..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0178_use_tree_path_use_tree.rs +++ /dev/null @@ -1 +0,0 @@ -use std::{collections}; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rast deleted file mode 100644 index b4dc1f25d9ad2..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rast +++ /dev/null @@ -1,26 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - COLON2 "::" - STAR "*" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "std" - COLON2 "::" - USE_TREE_LIST - L_CURLY "{" - USE_TREE - COLON2 "::" - STAR "*" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rs deleted file mode 100644 index caae0ba026aa9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rs +++ /dev/null @@ -1,2 +0,0 @@ -use ::*; -use std::{::*}; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0180_use_tree_path_star.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0180_use_tree_path_star.rast deleted file mode 100644 index d255adb5a47db..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0180_use_tree_path_star.rast +++ /dev/null @@ -1,13 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "std" - COLON2 "::" - STAR "*" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0180_use_tree_path_star.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0180_use_tree_path_star.rs deleted file mode 100644 index dd601cffe5dd1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0180_use_tree_path_star.rs +++ /dev/null @@ -1 +0,0 @@ -use std::*; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_generic_param_attribute.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_generic_param_attribute.rast deleted file mode 100644 index 28a216e873097..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_generic_param_attribute.rast +++ /dev/null @@ -1,46 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "lt_attr" - R_BRACK "]" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'a" - COMMA "," - WHITESPACE " " - TYPE_PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "t_attr" - R_BRACK "]" - WHITESPACE " " - NAME - IDENT "T" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_generic_param_attribute.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_generic_param_attribute.rs deleted file mode 100644 index 0509f81da7ed7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_generic_param_attribute.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo<#[lt_attr] 'a, #[t_attr] T>() {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_use_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_use_item.rast deleted file mode 100644 index 25761ed8c77e2..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_use_item.rast +++ /dev/null @@ -1,16 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "std" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "collections" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_use_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_use_item.rs deleted file mode 100644 index 48ac87b14a0f4..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_use_item.rs +++ /dev/null @@ -1 +0,0 @@ -use std::collections; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0182_lifetime_param.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0182_lifetime_param.rast deleted file mode 100644 index c595031f35863..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0182_lifetime_param.rast +++ /dev/null @@ -1,25 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - COLON ":" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0182_lifetime_param.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0182_lifetime_param.rs deleted file mode 100644 index 2bb38ece8c6a0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0182_lifetime_param.rs +++ /dev/null @@ -1 +0,0 @@ -fn f<'a: 'b>() {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_const_arg_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_const_arg_block.rast deleted file mode 100644 index ea8866da2770f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_const_arg_block.rast +++ /dev/null @@ -1,32 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - CONST_ARG - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - BIN_EXPR - LITERAL - INT_NUMBER "90" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LITERAL - INT_NUMBER "2" - R_CURLY "}" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_const_arg_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_const_arg_block.rs deleted file mode 100644 index 1c279db289c2f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_const_arg_block.rs +++ /dev/null @@ -1 +0,0 @@ -type T = S<{90 + 2}>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_type_param.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_type_param.rast deleted file mode 100644 index becb77e042f10..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_type_param.rast +++ /dev/null @@ -1,30 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Clone" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_type_param.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_type_param.rs deleted file mode 100644 index b250bc6bf07ce..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_type_param.rs +++ /dev/null @@ -1 +0,0 @@ -fn f() {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_const_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_const_arg.rast deleted file mode 100644 index 1e030071723b7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_const_arg.rast +++ /dev/null @@ -1,22 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - CONST_ARG - LITERAL - INT_NUMBER "92" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_const_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_const_arg.rs deleted file mode 100644 index 8b5e5dbe13c22..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_const_arg.rs +++ /dev/null @@ -1 +0,0 @@ -type T = S<92>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_generic_param_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_generic_param_list.rast deleted file mode 100644 index becb77e042f10..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_generic_param_list.rast +++ /dev/null @@ -1,30 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Clone" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_generic_param_list.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_generic_param_list.rs deleted file mode 100644 index b250bc6bf07ce..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_generic_param_list.rs +++ /dev/null @@ -1 +0,0 @@ -fn f() {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0185_assoc_type_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0185_assoc_type_bound.rast deleted file mode 100644 index f2e4e01069c10..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0185_assoc_type_bound.rast +++ /dev/null @@ -1,37 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "StreamingIterator" - GENERIC_ARG_LIST - L_ANGLE "<" - ASSOC_TYPE_ARG - NAME_REF - IDENT "Item" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Clone" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0185_assoc_type_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0185_assoc_type_bound.rs deleted file mode 100644 index daae97e4fd50a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0185_assoc_type_bound.rs +++ /dev/null @@ -1 +0,0 @@ -type T = StreamingIterator: Clone>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0186_lifetime_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0186_lifetime_arg.rast deleted file mode 100644 index dbd7ff3061a20..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0186_lifetime_arg.rast +++ /dev/null @@ -1,22 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'static" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0186_lifetime_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0186_lifetime_arg.rs deleted file mode 100644 index 41715aa273fb8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0186_lifetime_arg.rs +++ /dev/null @@ -1 +0,0 @@ -type T = S<'static>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0187_assoc_type_eq.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0187_assoc_type_eq.rast deleted file mode 100644 index 970431840364f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0187_assoc_type_eq.rast +++ /dev/null @@ -1,41 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "StreamingIterator" - GENERIC_ARG_LIST - L_ANGLE "<" - ASSOC_TYPE_ARG - NAME_REF - IDENT "Item" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - EQ "=" - WHITESPACE " " - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0187_assoc_type_eq.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0187_assoc_type_eq.rs deleted file mode 100644 index 3591417473e93..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0187_assoc_type_eq.rs +++ /dev/null @@ -1 +0,0 @@ -type T = StreamingIterator = &'a T>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rast deleted file mode 100644 index 11002bf98d01f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rast +++ /dev/null @@ -1,36 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "A" - GENERIC_PARAM_LIST - L_ANGLE "<" - CONST_PARAM - CONST_KW "const" - WHITESPACE " " - NAME - IDENT "N" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_EXPR - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "MAX" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rs deleted file mode 100644 index f3da43ca06cbd..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rs +++ /dev/null @@ -1 +0,0 @@ -struct A; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0189_const_arg_literal.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0189_const_arg_literal.rast deleted file mode 100644 index 03d414e336659..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0189_const_arg_literal.rast +++ /dev/null @@ -1,27 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - CONST_ARG - LITERAL - STRING "\"hello\"" - COMMA "," - WHITESPACE " " - CONST_ARG - LITERAL - INT_NUMBER "0xdeadbeef" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0189_const_arg_literal.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0189_const_arg_literal.rs deleted file mode 100644 index 7eacada73ada8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0189_const_arg_literal.rs +++ /dev/null @@ -1 +0,0 @@ -type T = S<"hello", 0xdeadbeef>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0190_generic_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0190_generic_arg.rast deleted file mode 100644 index 5a01f154bad4d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0190_generic_arg.rast +++ /dev/null @@ -1,25 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0190_generic_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0190_generic_arg.rs deleted file mode 100644 index f2ccc558bb5da..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0190_generic_arg.rs +++ /dev/null @@ -1 +0,0 @@ -type T = S; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0191_const_arg_negative_number.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0191_const_arg_negative_number.rast deleted file mode 100644 index e504badbd3db7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0191_const_arg_negative_number.rast +++ /dev/null @@ -1,24 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - CONST_ARG - PREFIX_EXPR - MINUS "-" - LITERAL - INT_NUMBER "92" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0191_const_arg_negative_number.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0191_const_arg_negative_number.rs deleted file mode 100644 index d0a87bdc03963..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0191_const_arg_negative_number.rs +++ /dev/null @@ -1 +0,0 @@ -type T = S<-92>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0192_const_arg_bool_literal.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0192_const_arg_bool_literal.rast deleted file mode 100644 index aea23e463daa8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0192_const_arg_bool_literal.rast +++ /dev/null @@ -1,22 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - CONST_ARG - LITERAL - TRUE_KW "true" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0192_const_arg_bool_literal.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0192_const_arg_bool_literal.rs deleted file mode 100644 index 4b92e2d487ace..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0192_const_arg_bool_literal.rs +++ /dev/null @@ -1 +0,0 @@ -type T = S; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0193_let_stmt_init.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0193_let_stmt_init.rast deleted file mode 100644 index 1b639915878c6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0193_let_stmt_init.rast +++ /dev/null @@ -1,29 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "x" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0193_let_stmt_init.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0193_let_stmt_init.rs deleted file mode 100644 index 232c0db411e08..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0193_let_stmt_init.rs +++ /dev/null @@ -1 +0,0 @@ -fn f() { let x = 92; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_else.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_else.rast deleted file mode 100644 index ce7f1a35e8d31..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_else.rast +++ /dev/null @@ -1,51 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - L_PAREN "(" - IDENT_PAT - NAME - IDENT "x" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "opt" - WHITESPACE " " - LET_ELSE - ELSE_KW "else" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - RETURN_EXPR - RETURN_KW "return" - WHITESPACE " " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_else.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_else.rs deleted file mode 100644 index 8303de06f1e8e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_else.rs +++ /dev/null @@ -1 +0,0 @@ -fn f() { let Some(x) = opt else { return }; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_stmt_ascription.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_stmt_ascription.rast deleted file mode 100644 index ac8e1d93cb6ea..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_stmt_ascription.rast +++ /dev/null @@ -1,31 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "x" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_stmt_ascription.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_stmt_ascription.rs deleted file mode 100644 index a94161dffa268..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_stmt_ascription.rs +++ /dev/null @@ -1 +0,0 @@ -fn f() { let x: i32; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_macro_inside_generic_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_macro_inside_generic_arg.rast deleted file mode 100644 index 88f8a73450fac..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_macro_inside_generic_arg.rast +++ /dev/null @@ -1,36 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - MACRO_TYPE - MACRO_CALL - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "syn" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Token" - BANG "!" - TOKEN_TREE - L_BRACK "[" - UNDERSCORE "_" - R_BRACK "]" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_macro_inside_generic_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_macro_inside_generic_arg.rs deleted file mode 100644 index 8d43a53d97f70..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_macro_inside_generic_arg.rs +++ /dev/null @@ -1 +0,0 @@ -type A = Foo; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rast deleted file mode 100644 index a23ddf69f25fc..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rast +++ /dev/null @@ -1,30 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "MyStruct" - TUPLE_FIELD_LIST - L_PAREN "(" - TUPLE_FIELD - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - COMMA "," - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - R_PAREN ")" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rs deleted file mode 100644 index 00d8feba96748..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rs +++ /dev/null @@ -1 +0,0 @@ -struct MyStruct(pub (u32, u32)); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0197_destructuring_assignment_struct_rest_pattern.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0197_destructuring_assignment_struct_rest_pattern.rast deleted file mode 100644 index fb8aa5accb5a7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0197_destructuring_assignment_struct_rest_pattern.rast +++ /dev/null @@ -1,44 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_EXPR_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - DOT2 ".." - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - EQ "=" - WHITESPACE " " - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_EXPR_FIELD_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0197_destructuring_assignment_struct_rest_pattern.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0197_destructuring_assignment_struct_rest_pattern.rs deleted file mode 100644 index 22a5b5f3e31a0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0197_destructuring_assignment_struct_rest_pattern.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn foo() { - S { .. } = S {}; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0198_destructuring_assignment_wildcard_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0198_destructuring_assignment_wildcard_pat.rast deleted file mode 100644 index 5f53d34510e72..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0198_destructuring_assignment_wildcard_pat.rast +++ /dev/null @@ -1,50 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - UNDERSCORE_EXPR - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - ARG_LIST - L_PAREN "(" - UNDERSCORE_EXPR - UNDERSCORE "_" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "None" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0198_destructuring_assignment_wildcard_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0198_destructuring_assignment_wildcard_pat.rs deleted file mode 100644 index 91acfb3a0aedb..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0198_destructuring_assignment_wildcard_pat.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn foo() { - _ = 1; - Some(_) = None; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rast deleted file mode 100644 index 0607ff54fbb7c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rast +++ /dev/null @@ -1,34 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "A" - GENERIC_PARAM_LIST - L_ANGLE "<" - CONST_PARAM - CONST_KW "const" - WHITESPACE " " - NAME - IDENT "N" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - WHITESPACE " " - R_CURLY "}" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rs deleted file mode 100644 index 551bde0b00862..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rs +++ /dev/null @@ -1 +0,0 @@ -struct A; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_effect_blocks.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_effect_blocks.rast deleted file mode 100644 index f14080c90ea48..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_effect_blocks.rast +++ /dev/null @@ -1,95 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - BLOCK_EXPR - UNSAFE_KW "unsafe" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - BLOCK_EXPR - CONST_KW "const" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - BLOCK_EXPR - ASYNC_KW "async" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - BLOCK_EXPR - ASYNC_KW "async" - WHITESPACE " " - MOVE_KW "move" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_effect_blocks.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_effect_blocks.rs deleted file mode 100644 index c57d24b2f7bb1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_effect_blocks.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn f() { unsafe { } } -fn f() { const { } } -fn f() { async { } } -fn f() { async move { } } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_type_item_where_clause_deprecated.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_type_item_where_clause_deprecated.rast deleted file mode 100644 index 7210b738958b9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_type_item_where_clause_deprecated.rast +++ /dev/null @@ -1,33 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "Foo" - WHITESPACE " " - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE " " - WHERE_PRED - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Copy" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_type_item_where_clause_deprecated.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_type_item_where_clause_deprecated.rs deleted file mode 100644 index a602d07f03bdb..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_type_item_where_clause_deprecated.rs +++ /dev/null @@ -1 +0,0 @@ -type Foo where Foo: Copy = (); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_assoc_const_eq.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_assoc_const_eq.rast deleted file mode 100644 index fa2733e7f96c3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_assoc_const_eq.rast +++ /dev/null @@ -1,105 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "F" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - GENERIC_ARG_LIST - L_ANGLE "<" - ASSOC_TYPE_ARG - NAME_REF - IDENT "N" - EQ "=" - CONST_ARG - LITERAL - INT_NUMBER "3" - R_ANGLE ">" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - CONST - CONST_KW "const" - WHITESPACE " " - NAME - IDENT "TEST" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "usize" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "3" - SEMICOLON ";" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "bar" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "F" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - GENERIC_ARG_LIST - L_ANGLE "<" - ASSOC_TYPE_ARG - NAME_REF - IDENT "N" - EQ "=" - CONST_ARG - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "TEST" - R_CURLY "}" - R_ANGLE ">" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_assoc_const_eq.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_assoc_const_eq.rs deleted file mode 100644 index b43c4e36acd99..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_assoc_const_eq.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn foo>() {} -const TEST: usize = 3; -fn bar>() {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rast deleted file mode 100644 index 8e52313651ce0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rast +++ /dev/null @@ -1,30 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "A" - GENERIC_PARAM_LIST - L_ANGLE "<" - CONST_PARAM - CONST_KW "const" - WHITESPACE " " - NAME - IDENT "N" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PREFIX_EXPR - MINUS "-" - LITERAL - INT_NUMBER "1" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rs deleted file mode 100644 index 879ecffa75d3a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rs +++ /dev/null @@ -1 +0,0 @@ -struct A; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0201_question_for_type_trait_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0201_question_for_type_trait_bound.rast deleted file mode 100644 index 56e2d1095d29b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0201_question_for_type_trait_bound.rast +++ /dev/null @@ -1,47 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE " " - WHERE_PRED - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - QUESTION "?" - FOR_TYPE - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - R_ANGLE ">" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Sized" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0201_question_for_type_trait_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0201_question_for_type_trait_bound.rs deleted file mode 100644 index f80dd90d446c5..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0201_question_for_type_trait_bound.rs +++ /dev/null @@ -1 +0,0 @@ -fn f() where T: ?for<> Sized {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0000_empty.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0000_empty.rast deleted file mode 100644 index 40b9ef804c219..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0000_empty.rast +++ /dev/null @@ -1 +0,0 @@ -SOURCE_FILE diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0000_empty.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0000_empty.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0001_struct_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0001_struct_item.rast deleted file mode 100644 index 0e9639f23db61..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0001_struct_item.rast +++ /dev/null @@ -1,39 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Copy" - R_ANGLE ">" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE "\n " - RECORD_FIELD - NAME - IDENT "f" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - COMMA "," - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0001_struct_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0001_struct_item.rs deleted file mode 100644 index 512aeb3e7a0f8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0001_struct_item.rs +++ /dev/null @@ -1,3 +0,0 @@ -struct S { - f: T, -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0002_struct_item_field.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0002_struct_item_field.rast deleted file mode 100644 index dd52e5850e551..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0002_struct_item_field.rast +++ /dev/null @@ -1,22 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE "\n " - RECORD_FIELD - NAME - IDENT "foo" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - WHITESPACE "\n" - R_CURLY "}" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0002_struct_item_field.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0002_struct_item_field.rs deleted file mode 100644 index cc3866d2511ed..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0002_struct_item_field.rs +++ /dev/null @@ -1,3 +0,0 @@ -struct S { - foo: u32 -} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0004_file_shebang.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0004_file_shebang.rast deleted file mode 100644 index 698957189fe22..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0004_file_shebang.rast +++ /dev/null @@ -1,2 +0,0 @@ -SOURCE_FILE - SHEBANG "#!/use/bin/env rusti" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0004_file_shebang.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0004_file_shebang.rs deleted file mode 100644 index 53dc9e6173375..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0004_file_shebang.rs +++ /dev/null @@ -1 +0,0 @@ -#!/use/bin/env rusti \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0005_fn_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0005_fn_item.rast deleted file mode 100644 index 756d20e4d6d8d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0005_fn_item.rast +++ /dev/null @@ -1,16 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0005_fn_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0005_fn_item.rs deleted file mode 100644 index 03210551cb174..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0005_fn_item.rs +++ /dev/null @@ -1,2 +0,0 @@ -fn foo() { -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0006_inner_attributes.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0006_inner_attributes.rast deleted file mode 100644 index cb63ba80e77d1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0006_inner_attributes.rast +++ /dev/null @@ -1,194 +0,0 @@ -SOURCE_FILE - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE "\n" - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - TOKEN_TREE - L_PAREN "(" - TRUE_KW "true" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n" - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - TOKEN_TREE - L_PAREN "(" - IDENT "ident" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n" - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - TOKEN_TREE - L_PAREN "(" - IDENT "ident" - COMMA "," - WHITESPACE " " - INT_NUMBER "100" - COMMA "," - WHITESPACE " " - TRUE_KW "true" - COMMA "," - WHITESPACE " " - STRING "\"true\"" - COMMA "," - WHITESPACE " " - IDENT "ident" - WHITESPACE " " - EQ "=" - WHITESPACE " " - INT_NUMBER "100" - COMMA "," - WHITESPACE " " - IDENT "ident" - WHITESPACE " " - EQ "=" - WHITESPACE " " - STRING "\"hello\"" - COMMA "," - WHITESPACE " " - IDENT "ident" - TOKEN_TREE - L_PAREN "(" - INT_NUMBER "100" - R_PAREN ")" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n" - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - TOKEN_TREE - L_PAREN "(" - INT_NUMBER "100" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n" - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - TOKEN_TREE - L_PAREN "(" - IDENT "enabled" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TRUE_KW "true" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n" - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "enabled" - TOKEN_TREE - L_PAREN "(" - TRUE_KW "true" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n" - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - TOKEN_TREE - L_PAREN "(" - STRING "\"hello\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n" - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "repr" - TOKEN_TREE - L_PAREN "(" - IDENT "C" - COMMA "," - WHITESPACE " " - IDENT "align" - WHITESPACE " " - EQ "=" - WHITESPACE " " - INT_NUMBER "4" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n" - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "repr" - TOKEN_TREE - L_PAREN "(" - IDENT "C" - COMMA "," - WHITESPACE " " - IDENT "align" - TOKEN_TREE - L_PAREN "(" - INT_NUMBER "4" - R_PAREN ")" - R_PAREN ")" - R_BRACK "]" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0006_inner_attributes.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0006_inner_attributes.rs deleted file mode 100644 index e81f8b1e84fbc..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0006_inner_attributes.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![attr] -#![attr(true)] -#![attr(ident)] -#![attr(ident, 100, true, "true", ident = 100, ident = "hello", ident(100))] -#![attr(100)] -#![attr(enabled = true)] -#![enabled(true)] -#![attr("hello")] -#![repr(C, align = 4)] -#![repr(C, align(4))] \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0007_extern_crate.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0007_extern_crate.rast deleted file mode 100644 index 8b9259fd6b96e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0007_extern_crate.rast +++ /dev/null @@ -1,40 +0,0 @@ -SOURCE_FILE - EXTERN_CRATE - EXTERN_KW "extern" - WHITESPACE " " - CRATE_KW "crate" - WHITESPACE " " - NAME_REF - IDENT "foo" - SEMICOLON ";" - WHITESPACE "\n" - EXTERN_CRATE - EXTERN_KW "extern" - WHITESPACE " " - CRATE_KW "crate" - WHITESPACE " " - NAME_REF - IDENT "foo" - WHITESPACE " " - RENAME - AS_KW "as" - WHITESPACE " " - NAME - IDENT "bar" - SEMICOLON ";" - WHITESPACE "\n" - EXTERN_CRATE - EXTERN_KW "extern" - WHITESPACE " " - CRATE_KW "crate" - WHITESPACE " " - NAME_REF - SELF_KW "self" - WHITESPACE " " - RENAME - AS_KW "as" - WHITESPACE " " - NAME - IDENT "baz" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0007_extern_crate.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0007_extern_crate.rs deleted file mode 100644 index ab81a608cb511..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0007_extern_crate.rs +++ /dev/null @@ -1,3 +0,0 @@ -extern crate foo; -extern crate foo as bar; -extern crate self as baz; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0008_mod_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0008_mod_item.rast deleted file mode 100644 index adee67181b1a3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0008_mod_item.rast +++ /dev/null @@ -1,77 +0,0 @@ -SOURCE_FILE - MODULE - MOD_KW "mod" - WHITESPACE " " - NAME - IDENT "c" - WHITESPACE " " - ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n " - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - MODULE - MOD_KW "mod" - WHITESPACE " " - NAME - IDENT "d" - WHITESPACE " " - ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE "\n " - MODULE - MOD_KW "mod" - WHITESPACE " " - NAME - IDENT "e" - SEMICOLON ";" - WHITESPACE "\n " - MODULE - MOD_KW "mod" - WHITESPACE " " - NAME - IDENT "f" - WHITESPACE " " - ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0008_mod_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0008_mod_item.rs deleted file mode 100644 index 4ff0d9795c781..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0008_mod_item.rs +++ /dev/null @@ -1,12 +0,0 @@ -mod c { - fn foo() { - } - struct S {} -} - -mod d { - #![attr] - mod e; - mod f { - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0009_use_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0009_use_item.rast deleted file mode 100644 index 04a44ef7e4b0f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0009_use_item.rast +++ /dev/null @@ -1,21 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "bar" - SEMICOLON ";" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0009_use_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0009_use_item.rs deleted file mode 100644 index 05a6aff83fc08..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0009_use_item.rs +++ /dev/null @@ -1,2 +0,0 @@ -use foo; -use ::bar; \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0010_use_path_segments.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0010_use_path_segments.rast deleted file mode 100644 index ddadec817b8da..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0010_use_path_segments.rast +++ /dev/null @@ -1,42 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "foo" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "bar" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "baz" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "bar" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "baz" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0010_use_path_segments.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0010_use_path_segments.rs deleted file mode 100644 index 1e71b7a6c5de3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0010_use_path_segments.rs +++ /dev/null @@ -1,2 +0,0 @@ -use ::foo::bar::baz; -use foo::bar::baz; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0011_outer_attribute.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0011_outer_attribute.rast deleted file mode 100644 index dbb9bc54da8d7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0011_outer_attribute.rast +++ /dev/null @@ -1,61 +0,0 @@ -SOURCE_FILE - FN - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "cfg" - TOKEN_TREE - L_PAREN "(" - IDENT "test" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n" - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "Ignore" - R_BRACK "]" - WHITESPACE "\n" - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n" - MODULE - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "path" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - STRING "\"a.rs\"" - R_BRACK "]" - WHITESPACE "\n" - MOD_KW "mod" - WHITESPACE " " - NAME - IDENT "b" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0011_outer_attribute.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0011_outer_attribute.rs deleted file mode 100644 index 6f04cb1717f6b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0011_outer_attribute.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[cfg(test)] -#[Ignore] -fn foo() {} - -#[path = "a.rs"] -mod b; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rast deleted file mode 100644 index a95bc23016bb8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rast +++ /dev/null @@ -1,133 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "a" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "b" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - MACRO_DEF - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - MACRO_KW "macro" - WHITESPACE " " - NAME - IDENT "m" - TOKEN_TREE - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - COLON ":" - IDENT "ident" - R_PAREN ")" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - VISIBILITY - PUB_KW "pub" - L_PAREN "(" - PATH - PATH_SEGMENT - NAME_REF - CRATE_KW "crate" - R_PAREN ")" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "c" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - VISIBILITY - PUB_KW "pub" - L_PAREN "(" - PATH - PATH_SEGMENT - NAME_REF - SUPER_KW "super" - R_PAREN ")" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "d" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - VISIBILITY - PUB_KW "pub" - L_PAREN "(" - IN_KW "in" - WHITESPACE " " - PATH - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "bar" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "baz" - R_PAREN ")" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "e" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rs deleted file mode 100644 index 129d486fae2aa..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn a() {} -pub fn b() {} -pub macro m($:ident) {} -pub(crate) fn c() {} -pub(super) fn d() {} -pub(in foo::bar::baz) fn e() {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0013_use_path_self_super.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0013_use_path_self_super.rast deleted file mode 100644 index 8a0149caca15d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0013_use_path_self_super.rast +++ /dev/null @@ -1,36 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - SELF_KW "self" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "foo" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH - PATH_SEGMENT - NAME_REF - SUPER_KW "super" - COLON2 "::" - PATH_SEGMENT - NAME_REF - SUPER_KW "super" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "bar" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0013_use_path_self_super.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0013_use_path_self_super.rs deleted file mode 100644 index 9d9eb99175b36..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0013_use_path_self_super.rs +++ /dev/null @@ -1,2 +0,0 @@ -use self::foo; -use super::super::bar; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0014_use_tree.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0014_use_tree.rast deleted file mode 100644 index b37edc365b43e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0014_use_tree.rast +++ /dev/null @@ -1,95 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - STAR "*" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - COLON2 "::" - STAR "*" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - COLON2 "::" - USE_TREE_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - USE_TREE_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - COLON2 "::" - STAR "*" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - COLON2 "::" - USE_TREE_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "foo" - COLON2 "::" - USE_TREE_LIST - L_CURLY "{" - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - COMMA "," - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "b" - COMMA "," - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "c" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0014_use_tree.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0014_use_tree.rs deleted file mode 100644 index 5e4aa3a33210b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0014_use_tree.rs +++ /dev/null @@ -1,7 +0,0 @@ -use *; -use ::*; -use ::{}; -use {}; -use foo::*; -use foo::{}; -use ::foo::{a, b, c}; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rast deleted file mode 100644 index ddf8aad6fcd6f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rast +++ /dev/null @@ -1,65 +0,0 @@ -SOURCE_FILE - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - WHITESPACE " " - RENAME - AS_KW "as" - WHITESPACE " " - NAME - IDENT "bar" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - COLON2 "::" - USE_TREE_LIST - L_CURLY "{" - USE_TREE - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - WHITESPACE " " - RENAME - AS_KW "as" - WHITESPACE " " - NAME - IDENT "b" - COMMA "," - WHITESPACE " " - USE_TREE - STAR "*" - COMMA "," - WHITESPACE " " - USE_TREE - COLON2 "::" - STAR "*" - COMMA "," - WHITESPACE " " - USE_TREE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "foo" - WHITESPACE " " - RENAME - AS_KW "as" - WHITESPACE " " - NAME - IDENT "x" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rs deleted file mode 100644 index 46a0783a2bdff..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rs +++ /dev/null @@ -1,2 +0,0 @@ -use foo as bar; -use foo::{a as b, *, ::*, ::foo as x}; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0016_struct_flavors.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0016_struct_flavors.rast deleted file mode 100644 index eb2724e2f3667..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0016_struct_flavors.rast +++ /dev/null @@ -1,93 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "A" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "B" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "C" - TUPLE_FIELD_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "D" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE "\n " - RECORD_FIELD - NAME - IDENT "a" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - COMMA "," - WHITESPACE "\n " - RECORD_FIELD - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - NAME - IDENT "b" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "E" - TUPLE_FIELD_LIST - L_PAREN "(" - TUPLE_FIELD - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - COMMA "," - WHITESPACE " " - TUPLE_FIELD - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "y" - COMMA "," - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0016_struct_flavors.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0016_struct_flavors.rs deleted file mode 100644 index 69638350c46fc..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0016_struct_flavors.rs +++ /dev/null @@ -1,10 +0,0 @@ -struct A; -struct B {} -struct C(); - -struct D { - a: u32, - pub b: u32 -} - -struct E(pub x, y,); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0017_attr_trailing_comma.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0017_attr_trailing_comma.rast deleted file mode 100644 index 7c914e2542eb7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0017_attr_trailing_comma.rast +++ /dev/null @@ -1,30 +0,0 @@ -SOURCE_FILE - FN - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - TOKEN_TREE - L_PAREN "(" - IDENT "a" - COMMA "," - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n" - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0017_attr_trailing_comma.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0017_attr_trailing_comma.rs deleted file mode 100644 index fe0a7bb97e372..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0017_attr_trailing_comma.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[foo(a,)] -fn foo() {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast deleted file mode 100644 index 11ebc7efb9f38..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast +++ /dev/null @@ -1,274 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S1" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S2" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - R_ANGLE ">" - TUPLE_FIELD_LIST - L_PAREN "(" - TUPLE_FIELD - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S3" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - R_ANGLE ">" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_FIELD - NAME - IDENT "u" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S4" - GENERIC_PARAM_LIST - L_ANGLE "<" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S5" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S6" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - COLON ":" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S7" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - COLON ":" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S8" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - COLON ":" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S9" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - COLON ":" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'c" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S10" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - COMMA "," - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S11" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - COMMA "," - WHITESPACE " " - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'b" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S12" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - COLON ":" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" - PLUS "+" - COMMA "," - WHITESPACE " " - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'b" - COLON ":" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'c" - COMMA "," - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S13" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S14" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COMMA "," - WHITESPACE " " - TYPE_PARAM - NAME - IDENT "U" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S15" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - COMMA "," - WHITESPACE " " - TYPE_PARAM - NAME - IDENT "T" - COMMA "," - WHITESPACE " " - TYPE_PARAM - NAME - IDENT "U" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rs deleted file mode 100644 index 88c544923b54d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rs +++ /dev/null @@ -1,17 +0,0 @@ -struct S1; -struct S2(u32); -struct S3 { u: u32 } - -struct S4<>; -struct S5<'a>; -struct S6<'a:>; -struct S7<'a: 'b>; -struct S8<'a: 'b + >; -struct S9<'a: 'b + 'c>; -struct S10<'a,>; -struct S11<'a, 'b>; -struct S12<'a: 'b+, 'b: 'c,>; - -struct S13; -struct S14; -struct S15<'a, T, U>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rast deleted file mode 100644 index dd47e3aa47ad6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rast +++ /dev/null @@ -1,155 +0,0 @@ -SOURCE_FILE - ENUM - ENUM_KW "enum" - WHITESPACE " " - NAME - IDENT "E1" - WHITESPACE " " - VARIANT_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - ENUM - ENUM_KW "enum" - WHITESPACE " " - NAME - IDENT "E2" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - R_ANGLE ">" - WHITESPACE " " - VARIANT_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - ENUM - ENUM_KW "enum" - WHITESPACE " " - NAME - IDENT "E3" - WHITESPACE " " - VARIANT_LIST - L_CURLY "{" - WHITESPACE "\n " - VARIANT - NAME - IDENT "X" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - ENUM - ENUM_KW "enum" - WHITESPACE " " - NAME - IDENT "E4" - WHITESPACE " " - VARIANT_LIST - L_CURLY "{" - WHITESPACE "\n " - VARIANT - NAME - IDENT "X" - COMMA "," - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - ENUM - ENUM_KW "enum" - WHITESPACE " " - NAME - IDENT "E5" - WHITESPACE " " - VARIANT_LIST - L_CURLY "{" - WHITESPACE "\n " - VARIANT - NAME - IDENT "A" - COMMA "," - WHITESPACE "\n " - VARIANT - NAME - IDENT "B" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - COMMA "," - WHITESPACE "\n " - VARIANT - NAME - IDENT "C" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE "\n " - RECORD_FIELD - NAME - IDENT "a" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - COMMA "," - WHITESPACE "\n " - RECORD_FIELD - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - NAME - IDENT "b" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "f64" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - COMMA "," - WHITESPACE "\n " - VARIANT - NAME - IDENT "F" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - R_CURLY "}" - COMMA "," - WHITESPACE "\n " - VARIANT - NAME - IDENT "D" - TUPLE_FIELD_LIST - L_PAREN "(" - TUPLE_FIELD - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - COMMA "," - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - VARIANT - NAME - IDENT "E" - TUPLE_FIELD_LIST - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rs deleted file mode 100644 index 7a1afa0e62f18..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rs +++ /dev/null @@ -1,25 +0,0 @@ -enum E1 { -} - -enum E2 { -} - -enum E3 { - X -} - -enum E4 { - X, -} - -enum E5 { - A, - B = 92, - C { - a: u32, - pub b: f64, - }, - F {}, - D(u32,), - E(), -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast deleted file mode 100644 index 043a966ff9784..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast +++ /dev/null @@ -1,283 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "A" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "B" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - TYPE_BOUND_LIST - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "C" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "D" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "E" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'d" - WHITESPACE " " - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "F" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'d" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Clone" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "G" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Clone" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Copy" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "H" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "Foo" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - SELF_KW "self" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Bar" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "I" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - TYPE_BOUND_LIST - COMMA "," - WHITESPACE " " - TYPE_PARAM - NAME - IDENT "U" - COLON ":" - TYPE_BOUND_LIST - COMMA "," - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "K" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - COLON ":" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'d" - COMMA "," - WHITESPACE " " - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'d" - COLON ":" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" - COMMA "," - WHITESPACE " " - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'d" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Clone" - R_ANGLE ">" - SEMICOLON ";" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rs deleted file mode 100644 index 7128989789a7d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rs +++ /dev/null @@ -1,10 +0,0 @@ -struct A; -struct B; -struct C; -struct D; -struct E; -struct F; -struct G; -struct H; -struct I; -struct K<'a: 'd, 'd: 'a + 'b, T: 'a + 'd + Clone>; \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0022_empty_extern_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0022_empty_extern_block.rast deleted file mode 100644 index ef2fb66dd5241..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0022_empty_extern_block.rast +++ /dev/null @@ -1,21 +0,0 @@ -SOURCE_FILE - EXTERN_BLOCK - ABI - EXTERN_KW "extern" - WHITESPACE " " - EXTERN_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - EXTERN_BLOCK - ABI - EXTERN_KW "extern" - WHITESPACE " " - STRING "\"C\"" - WHITESPACE " " - EXTERN_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0022_empty_extern_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0022_empty_extern_block.rs deleted file mode 100644 index f5fe0e6ef3097..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0022_empty_extern_block.rs +++ /dev/null @@ -1,5 +0,0 @@ -extern { -} - -extern "C" { -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0023_static_items.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0023_static_items.rast deleted file mode 100644 index b164e828e3016..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0023_static_items.rast +++ /dev/null @@ -1,41 +0,0 @@ -SOURCE_FILE - STATIC - STATIC_KW "static" - WHITESPACE " " - NAME - IDENT "FOO" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n" - STATIC - STATIC_KW "static" - WHITESPACE " " - MUT_KW "mut" - WHITESPACE " " - NAME - IDENT "BAR" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0023_static_items.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0023_static_items.rs deleted file mode 100644 index 5fb92ce33f0d4..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0023_static_items.rs +++ /dev/null @@ -1,2 +0,0 @@ -static FOO: u32 = 1; -static mut BAR: i32 = 92; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0024_const_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0024_const_item.rast deleted file mode 100644 index 40b9ef804c219..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0024_const_item.rast +++ /dev/null @@ -1 +0,0 @@ -SOURCE_FILE diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0024_const_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0024_const_item.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0025_extern_fn_in_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0025_extern_fn_in_block.rast deleted file mode 100644 index 9c5f5ac64e98b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0025_extern_fn_in_block.rast +++ /dev/null @@ -1,33 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - ABI - EXTERN_KW "extern" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0025_extern_fn_in_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0025_extern_fn_in_block.rs deleted file mode 100644 index 289809809a6b6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0025_extern_fn_in_block.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - extern fn f() {} -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0026_const_fn_in_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0026_const_fn_in_block.rast deleted file mode 100644 index ca9a3df86f6ed..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0026_const_fn_in_block.rast +++ /dev/null @@ -1,32 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - CONST_KW "const" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0026_const_fn_in_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0026_const_fn_in_block.rs deleted file mode 100644 index 7641a3d28e666..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0026_const_fn_in_block.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - const fn f() {} -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0027_unsafe_fn_in_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0027_unsafe_fn_in_block.rast deleted file mode 100644 index 88ebd10952015..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0027_unsafe_fn_in_block.rast +++ /dev/null @@ -1,43 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - UNSAFE_KW "unsafe" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - BLOCK_EXPR - UNSAFE_KW "unsafe" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0027_unsafe_fn_in_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0027_unsafe_fn_in_block.rs deleted file mode 100644 index f3c5ff93863e9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0027_unsafe_fn_in_block.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - unsafe fn f() {} - unsafe { 92 } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0028_operator_binding_power.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0028_operator_binding_power.rast deleted file mode 100644 index ae08c0756aa3a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0028_operator_binding_power.rast +++ /dev/null @@ -1,186 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "binding_power" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "x" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - BIN_EXPR - BIN_EXPR - LITERAL - INT_NUMBER "2" - WHITESPACE " " - STAR "*" - WHITESPACE " " - LITERAL - INT_NUMBER "3" - WHITESPACE " " - PERCENT "%" - WHITESPACE " " - LITERAL - INT_NUMBER "4" - WHITESPACE " " - MINUS "-" - WHITESPACE " " - BIN_EXPR - LITERAL - INT_NUMBER "5" - WHITESPACE " " - SLASH "/" - WHITESPACE " " - LITERAL - INT_NUMBER "6" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - BIN_EXPR - LITERAL - INT_NUMBER "2" - WHITESPACE " " - STAR "*" - WHITESPACE " " - LITERAL - INT_NUMBER "3" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - SHL "<<" - WHITESPACE " " - BIN_EXPR - LITERAL - INT_NUMBER "2" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LITERAL - INT_NUMBER "3" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - AMP "&" - WHITESPACE " " - BIN_EXPR - LITERAL - INT_NUMBER "2" - WHITESPACE " " - SHR ">>" - WHITESPACE " " - LITERAL - INT_NUMBER "3" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - CARET "^" - WHITESPACE " " - BIN_EXPR - LITERAL - INT_NUMBER "2" - WHITESPACE " " - AMP "&" - WHITESPACE " " - LITERAL - INT_NUMBER "3" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - PIPE "|" - WHITESPACE " " - BIN_EXPR - LITERAL - INT_NUMBER "2" - WHITESPACE " " - CARET "^" - WHITESPACE " " - LITERAL - INT_NUMBER "3" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - EQ2 "==" - WHITESPACE " " - BIN_EXPR - LITERAL - INT_NUMBER "2" - WHITESPACE " " - PIPE "|" - WHITESPACE " " - LITERAL - INT_NUMBER "3" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - AMP2 "&&" - WHITESPACE " " - BIN_EXPR - LITERAL - INT_NUMBER "2" - WHITESPACE " " - EQ2 "==" - WHITESPACE " " - LITERAL - INT_NUMBER "3" - SEMICOLON ";" - WHITESPACE "\n " - COMMENT "//1 || 2 && 2;" - WHITESPACE "\n " - COMMENT "//1 .. 2 || 3;" - WHITESPACE "\n " - COMMENT "//1 = 2 .. 3;" - WHITESPACE "\n " - COMMENT "//---&*1 - --2 * 9;" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0028_operator_binding_power.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0028_operator_binding_power.rs deleted file mode 100644 index cc9598470d84c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0028_operator_binding_power.rs +++ /dev/null @@ -1,14 +0,0 @@ -fn binding_power() { - let x = 1 + 2 * 3 % 4 - 5 / 6; - 1 + 2 * 3; - 1 << 2 + 3; - 1 & 2 >> 3; - 1 ^ 2 & 3; - 1 | 2 ^ 3; - 1 == 2 | 3; - 1 && 2 == 3; - //1 || 2 && 2; - //1 .. 2 || 3; - //1 = 2 .. 3; - //---&*1 - --2 * 9; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rast deleted file mode 100644 index 5acc54e713ea4..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rast +++ /dev/null @@ -1,152 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - RANGE_EXPR - DOT2 ".." - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - RANGE_EXPR - DOT2 ".." - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "z" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "2" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - WHITESPACE " " - EQ "=" - WHITESPACE " " - RANGE_EXPR - LITERAL - FALSE_KW "false" - DOT2 ".." - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - EQ2 "==" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "x" - WHITESPACE " " - EQ "=" - WHITESPACE " " - RANGE_EXPR - LITERAL - INT_NUMBER "1" - DOT2 ".." - SEMICOLON ";" - WHITESPACE "\n \n " - EXPR_STMT - RANGE_EXPR - DOT2EQ "..=" - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - RANGE_EXPR - DOT2EQ "..=" - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "z" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "2" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - WHITESPACE " " - EQ "=" - WHITESPACE " " - RANGE_EXPR - LITERAL - FALSE_KW "false" - DOT2EQ "..=" - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - EQ2 "==" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "x" - WHITESPACE " " - EQ "=" - WHITESPACE " " - RANGE_EXPR - LITERAL - INT_NUMBER "1" - DOT2 ".." - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rs deleted file mode 100644 index f9ff444d400c3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rs +++ /dev/null @@ -1,11 +0,0 @@ -fn foo() { - ..1 + 1; - ..z = 2; - x = false..1 == 1; - let x = 1..; - - ..=1 + 1; - ..=z = 2; - x = false..=1 == 1; - let x = 1..; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_string_suffixes.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_string_suffixes.rast deleted file mode 100644 index 44211c7c42006..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_string_suffixes.rast +++ /dev/null @@ -1,64 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - CHAR "'c'u32" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - STRING "\"string\"invalid" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - BYTE "b'b'_suff" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - BYTE_STRING "b\"bs\"invalid" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_string_suffixes.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_string_suffixes.rs deleted file mode 100644 index 261aad1fb6b40..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_string_suffixes.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() { - let _ = 'c'u32; - let _ = "string"invalid; - let _ = b'b'_suff; - let _ = b"bs"invalid; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rast deleted file mode 100644 index 44423581e6abd..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rast +++ /dev/null @@ -1,61 +0,0 @@ -SOURCE_FILE - TRAIT - TRAIT_KW "trait" - WHITESPACE " " - NAME - IDENT "Runnable" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "handler" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - TRAIT - TRAIT_KW "trait" - WHITESPACE " " - NAME - IDENT "TraitWithExpr" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "fn_with_expr" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "x" - COLON ":" - WHITESPACE " " - ARRAY_TYPE - L_BRACK "[" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - SEMICOLON ";" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - R_BRACK "]" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rs deleted file mode 100644 index ac30843eff649..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rs +++ /dev/null @@ -1,7 +0,0 @@ -trait Runnable { - fn handler(); -} - -trait TraitWithExpr { - fn fn_with_expr(x: [i32; 1]); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0031_extern.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0031_extern.rast deleted file mode 100644 index 70b5278086288..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0031_extern.rast +++ /dev/null @@ -1,973 +0,0 @@ -SOURCE_FILE - EXTERN_BLOCK - ABI - EXTERN_KW "extern" - WHITESPACE " " - EXTERN_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "socket" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "domain" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "ty" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "protocol" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - SEMICOLON ";" - WHITESPACE "\n " - FN - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "bind" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "fd" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "addr" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - CONST_KW "const" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "sockaddr" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "len" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "socklen_t" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - SEMICOLON ";" - WHITESPACE "\n " - FN - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "connect" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "socket" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "address" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - CONST_KW "const" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "sockaddr" - COMMA "," - WHITESPACE "\n " - PARAM - IDENT_PAT - NAME - IDENT "len" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "socklen_t" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - SEMICOLON ";" - WHITESPACE "\n " - FN - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "listen" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "socket" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "backlog" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - SEMICOLON ";" - WHITESPACE "\n " - FN - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "getsockname" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "socket" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "address" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "sockaddr" - COMMA "," - WHITESPACE "\n " - PARAM - IDENT_PAT - NAME - IDENT "address_len" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "socklen_t" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - SEMICOLON ";" - WHITESPACE "\n " - FN - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "getsockopt" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "sockfd" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE "\n " - PARAM - IDENT_PAT - NAME - IDENT "level" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE "\n " - PARAM - IDENT_PAT - NAME - IDENT "optname" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE "\n " - PARAM - IDENT_PAT - NAME - IDENT "optval" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_void" - COMMA "," - WHITESPACE "\n " - PARAM - IDENT_PAT - NAME - IDENT "optlen" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "socklen_t" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - SEMICOLON ";" - WHITESPACE "\n " - FN - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "setsockopt" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "socket" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "level" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "name" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE "\n " - PARAM - IDENT_PAT - NAME - IDENT "value" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - CONST_KW "const" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_void" - COMMA "," - WHITESPACE "\n " - PARAM - IDENT_PAT - NAME - IDENT "option_len" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "socklen_t" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - SEMICOLON ";" - WHITESPACE "\n " - FN - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "getpeername" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "socket" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "address" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "sockaddr" - COMMA "," - WHITESPACE "\n " - PARAM - IDENT_PAT - NAME - IDENT "address_len" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "socklen_t" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - SEMICOLON ";" - WHITESPACE "\n " - FN - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "sendto" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "socket" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "buf" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - CONST_KW "const" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_void" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "len" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "size_t" - COMMA "," - WHITESPACE "\n " - PARAM - IDENT_PAT - NAME - IDENT "flags" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "addr" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - CONST_KW "const" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "sockaddr" - COMMA "," - WHITESPACE "\n " - PARAM - IDENT_PAT - NAME - IDENT "addrlen" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "socklen_t" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "ssize_t" - SEMICOLON ";" - WHITESPACE "\n " - FN - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "send" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "socket" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "buf" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - CONST_KW "const" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_void" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "len" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "size_t" - COMMA "," - WHITESPACE "\n " - PARAM - IDENT_PAT - NAME - IDENT "flags" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "ssize_t" - SEMICOLON ";" - WHITESPACE "\n " - FN - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "recvfrom" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "socket" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "buf" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_void" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "len" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "size_t" - COMMA "," - WHITESPACE "\n " - PARAM - IDENT_PAT - NAME - IDENT "flags" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "addr" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "sockaddr" - COMMA "," - WHITESPACE "\n " - PARAM - IDENT_PAT - NAME - IDENT "addrlen" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "socklen_t" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "ssize_t" - SEMICOLON ";" - WHITESPACE "\n " - FN - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "recv" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "socket" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "buf" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_void" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "len" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "size_t" - COMMA "," - WHITESPACE "\n " - PARAM - IDENT_PAT - NAME - IDENT "flags" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "c_int" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "ssize_t" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0031_extern.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0031_extern.rs deleted file mode 100644 index b33ac273ca6e8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0031_extern.rs +++ /dev/null @@ -1,29 +0,0 @@ -extern { - pub fn socket(domain: ::c_int, ty: ::c_int, protocol: ::c_int) -> ::c_int; - pub fn bind(fd: ::c_int, addr: *const sockaddr, len: socklen_t) -> ::c_int; - pub fn connect(socket: ::c_int, address: *const sockaddr, - len: socklen_t) -> ::c_int; - pub fn listen(socket: ::c_int, backlog: ::c_int) -> ::c_int; - pub fn getsockname(socket: ::c_int, address: *mut sockaddr, - address_len: *mut socklen_t) -> ::c_int; - pub fn getsockopt(sockfd: ::c_int, - level: ::c_int, - optname: ::c_int, - optval: *mut ::c_void, - optlen: *mut ::socklen_t) -> ::c_int; - pub fn setsockopt(socket: ::c_int, level: ::c_int, name: ::c_int, - value: *const ::c_void, - option_len: socklen_t) -> ::c_int; - pub fn getpeername(socket: ::c_int, address: *mut sockaddr, - address_len: *mut socklen_t) -> ::c_int; - pub fn sendto(socket: ::c_int, buf: *const ::c_void, len: ::size_t, - flags: ::c_int, addr: *const sockaddr, - addrlen: socklen_t) -> ::ssize_t; - pub fn send(socket: ::c_int, buf: *const ::c_void, len: ::size_t, - flags: ::c_int) -> ::ssize_t; - pub fn recvfrom(socket: ::c_int, buf: *mut ::c_void, len: ::size_t, - flags: ::c_int, addr: *mut ::sockaddr, - addrlen: *mut ::socklen_t) -> ::ssize_t; - pub fn recv(socket: ::c_int, buf: *mut ::c_void, len: ::size_t, - flags: ::c_int) -> ::ssize_t; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rast deleted file mode 100644 index 86f6af97c735a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rast +++ /dev/null @@ -1,93 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "test_serialization" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "SER" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n" - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE "\n " - WHERE_PRED - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "SER" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Serialize" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - FOR_TYPE - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'de" - R_ANGLE ">" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Deserialize" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'de" - R_ANGLE ">" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "PartialEq" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "std" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "fmt" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Debug" - COMMA "," - WHITESPACE "\n" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rs deleted file mode 100644 index 588170fbef53a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn test_serialization() -where - SER: Serialize + for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug, -{} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0033_label_break.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0033_label_break.rast deleted file mode 100644 index df1acd6b83b93..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0033_label_break.rast +++ /dev/null @@ -1,223 +0,0 @@ -SOURCE_FILE - FN - COMMENT "// format with label break value." - WHITESPACE "\n" - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - BLOCK_EXPR - LABEL - LIFETIME - LIFETIME_IDENT "'empty_block" - COLON ":" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n " - EXPR_STMT - BLOCK_EXPR - LABEL - LIFETIME - LIFETIME_IDENT "'block" - COLON ":" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "do_thing" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - IF_EXPR - IF_KW "if" - WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "condition_not_met" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - BREAK_EXPR - BREAK_KW "break" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'block" - SEMICOLON ";" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "do_next_thing" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - IF_EXPR - IF_KW "if" - WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "condition_not_met" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - BREAK_EXPR - BREAK_KW "break" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'block" - SEMICOLON ";" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "do_last_thing" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "result" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BLOCK_EXPR - LABEL - LIFETIME - LIFETIME_IDENT "'block" - COLON ":" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - IF_EXPR - IF_KW "if" - WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - COMMENT "// comment" - WHITESPACE "\n " - EXPR_STMT - BREAK_EXPR - BREAK_KW "break" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'block" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - IF_EXPR - IF_KW "if" - WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "bar" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - COMMENT "/* comment */" - WHITESPACE "\n " - EXPR_STMT - BREAK_EXPR - BREAK_KW "break" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'block" - WHITESPACE " " - LITERAL - INT_NUMBER "2" - SEMICOLON ";" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n " - LITERAL - INT_NUMBER "3" - WHITESPACE "\n " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0033_label_break.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0033_label_break.rs deleted file mode 100644 index 728d78137c99e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0033_label_break.rs +++ /dev/null @@ -1,28 +0,0 @@ -// format with label break value. -fn main() { - 'empty_block: {} - - 'block: { - do_thing(); - if condition_not_met() { - break 'block; - } - do_next_thing(); - if condition_not_met() { - break 'block; - } - do_last_thing(); - } - - let result = 'block: { - if foo() { - // comment - break 'block 1; - } - if bar() { - /* comment */ - break 'block 2; - } - 3 - }; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0034_crate_path_in_call.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0034_crate_path_in_call.rast deleted file mode 100644 index 2b3b86ebf2d05..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0034_crate_path_in_call.rast +++ /dev/null @@ -1,43 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "make_query" - ARG_LIST - L_PAREN "(" - PATH_EXPR - PATH - PATH - PATH - PATH_SEGMENT - NAME_REF - CRATE_KW "crate" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "module_map" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "module_tree" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0034_crate_path_in_call.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0034_crate_path_in_call.rs deleted file mode 100644 index f1ed30220ae68..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0034_crate_path_in_call.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - make_query(crate::module_map::module_tree); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0035_weird_exprs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0035_weird_exprs.rast deleted file mode 100644 index 318d492ab4a57..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0035_weird_exprs.rast +++ /dev/null @@ -1,2339 +0,0 @@ -SOURCE_FILE - COMMENT "//! Adapted from a `rustc` test, which can be found at " - WHITESPACE "\n" - COMMENT "//! https://github.com/rust-lang/rust/blob/6d34ec18c7d7e574553f6347ecf08e1e1c45c13d/src/test/run-pass/weird-exprs.rs." - WHITESPACE "\n" - COMMENT "//! " - WHITESPACE "\n" - COMMENT "//! Reported to rust-analyzer in https://github.com/rust-lang/rust-analyzer/issues/290" - WHITESPACE "\n\n" - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "allow" - TOKEN_TREE - L_PAREN "(" - IDENT "non_camel_case_types" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n" - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "allow" - TOKEN_TREE - L_PAREN "(" - IDENT "dead_code" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n" - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "allow" - TOKEN_TREE - L_PAREN "(" - IDENT "unreachable_code" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n" - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "allow" - TOKEN_TREE - L_PAREN "(" - IDENT "unused_parens" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n\n" - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "recursion_limit" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - STRING "\"128\"" - R_BRACK "]" - WHITESPACE "\n\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "std" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "cell" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Cell" - SEMICOLON ";" - WHITESPACE "\n" - USE - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "std" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "mem" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "swap" - SEMICOLON ";" - WHITESPACE "\n\n" - COMMENT "// Just a grab bag of stuff that you wouldn't want to actually write." - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "strange" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "bool" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "_x" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "bool" - WHITESPACE " " - EQ "=" - WHITESPACE " " - RETURN_EXPR - RETURN_KW "return" - WHITESPACE " " - LITERAL - TRUE_KW "true" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "funny" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "_x" - COLON ":" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "f" - ARG_LIST - L_PAREN "(" - RETURN_EXPR - RETURN_KW "return" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "what" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "the" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "x" - COLON ":" - WHITESPACE " " - REF_TYPE - AMP "&" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Cell" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "bool" - R_ANGLE ">" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - RETURN_EXPR - RETURN_KW "return" - WHITESPACE " " - WHILE_EXPR - WHILE_KW "while" - WHITESPACE " " - PREFIX_EXPR - BANG "!" - METHOD_CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - DOT "." - NAME_REF - IDENT "get" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - METHOD_CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - DOT "." - NAME_REF - IDENT "set" - ARG_LIST - L_PAREN "(" - LITERAL - TRUE_KW "true" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "i" - WHITESPACE " " - EQ "=" - WHITESPACE " " - REF_EXPR - AMP "&" - CALL_EXPR - PATH_EXPR - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "Cell" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "new" - ARG_LIST - L_PAREN "(" - LITERAL - FALSE_KW "false" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "dont" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - CLOSURE_EXPR - PARAM_LIST - PIPE "|" - PIPE "|" - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "the" - ARG_LIST - L_PAREN "(" - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "i" - R_PAREN ")" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "dont" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "assert" - BANG "!" - TOKEN_TREE - L_PAREN "(" - TOKEN_TREE - L_PAREN "(" - IDENT "i" - DOT "." - IDENT "get" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "zombiejesus" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LOOP_EXPR - LOOP_KW "loop" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - WHILE_EXPR - WHILE_KW "while" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - RETURN_EXPR - RETURN_KW "return" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - IF_EXPR - IF_KW "if" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - RETURN_EXPR - RETURN_KW "return" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - RETURN_EXPR - RETURN_KW "return" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - LITERAL_PAT - LITERAL - INT_NUMBER "1" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - IF_EXPR - IF_KW "if" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - RETURN_EXPR - RETURN_KW "return" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - RETURN_EXPR - RETURN_KW "return" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE " " - ELSE_KW "else" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - RETURN_EXPR - RETURN_KW "return" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - RETURN_EXPR - RETURN_KW "return" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE " " - ELSE_KW "else" - WHITESPACE " " - IF_EXPR - IF_KW "if" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - RETURN_EXPR - RETURN_KW "return" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - RETURN_EXPR - RETURN_KW "return" - SEMICOLON ";" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n " - IF_EXPR - IF_KW "if" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - RETURN_EXPR - RETURN_KW "return" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - BREAK_EXPR - BREAK_KW "break" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "notsure" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - MUT_KW "mut" - WHITESPACE " " - NAME - IDENT "_x" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "isize" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - MUT_KW "mut" - WHITESPACE " " - NAME - IDENT "_y" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - PAREN_EXPR - L_PAREN "(" - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "_x" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - R_PAREN ")" - WHITESPACE " " - EQ2 "==" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "_x" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - MUT_KW "mut" - WHITESPACE " " - NAME - IDENT "_z" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - PAREN_EXPR - L_PAREN "(" - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "_x" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - R_PAREN ")" - WHITESPACE " " - L_ANGLE "<" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "_x" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "_a" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - PAREN_EXPR - L_PAREN "(" - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "_x" - WHITESPACE " " - PLUSEQ "+=" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - R_PAREN ")" - WHITESPACE " " - EQ2 "==" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "_x" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "_b" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "swap" - ARG_LIST - L_PAREN "(" - REF_EXPR - AMP "&" - MUT_KW "mut" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "_y" - COMMA "," - WHITESPACE " " - REF_EXPR - AMP "&" - MUT_KW "mut" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "_z" - R_PAREN ")" - WHITESPACE " " - EQ2 "==" - WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "swap" - ARG_LIST - L_PAREN "(" - REF_EXPR - AMP "&" - MUT_KW "mut" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "_y" - COMMA "," - WHITESPACE " " - REF_EXPR - AMP "&" - MUT_KW "mut" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "_z" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "canttouchthis" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "usize" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "p" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "bool" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LITERAL - TRUE_KW "true" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "_a" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - BIN_EXPR - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "assert" - BANG "!" - TOKEN_TREE - L_PAREN "(" - TOKEN_TREE - L_PAREN "(" - TRUE_KW "true" - R_PAREN ")" - R_PAREN ")" - WHITESPACE " " - EQ2 "==" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "assert" - BANG "!" - TOKEN_TREE - L_PAREN "(" - IDENT "p" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - R_PAREN ")" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "_c" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - BIN_EXPR - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "assert" - BANG "!" - TOKEN_TREE - L_PAREN "(" - TOKEN_TREE - L_PAREN "(" - IDENT "p" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - R_PAREN ")" - WHITESPACE " " - EQ2 "==" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "_b" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "bool" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - BIN_EXPR - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "println" - BANG "!" - TOKEN_TREE - L_PAREN "(" - STRING "\"{}\"" - COMMA "," - WHITESPACE " " - INT_NUMBER "0" - R_PAREN ")" - WHITESPACE " " - EQ2 "==" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - RETURN_EXPR - RETURN_KW "return" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - R_PAREN ")" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "angrydome" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - LOOP_EXPR - LOOP_KW "loop" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - IF_EXPR - IF_KW "if" - WHITESPACE " " - BREAK_EXPR - BREAK_KW "break" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - MUT_KW "mut" - WHITESPACE " " - NAME - IDENT "i" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - SEMICOLON ";" - WHITESPACE "\n " - LOOP_EXPR - LOOP_KW "loop" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "i" - WHITESPACE " " - PLUSEQ "+=" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE " " - EXPR_STMT - IF_EXPR - IF_KW "if" - WHITESPACE " " - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "i" - WHITESPACE " " - EQ2 "==" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - CONTINUE_EXPR - CONTINUE_KW "continue" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE " " - MATCH_ARM - LITERAL_PAT - LITERAL - INT_NUMBER "1" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - R_CURLY "}" - COMMA "," - WHITESPACE " " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "panic" - BANG "!" - TOKEN_TREE - L_PAREN "(" - STRING "\"wat\"" - R_PAREN ")" - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - BREAK_EXPR - BREAK_KW "break" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "evil_lincoln" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "_evil" - WHITESPACE " " - EQ "=" - WHITESPACE " " - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "println" - BANG "!" - TOKEN_TREE - L_PAREN "(" - STRING "\"lincoln\"" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "dots" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "assert_eq" - BANG "!" - TOKEN_TREE - L_PAREN "(" - IDENT "String" - COLON ":" - COLON ":" - IDENT "from" - TOKEN_TREE - L_PAREN "(" - STRING "\"..................................................\"" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - IDENT "format" - BANG "!" - TOKEN_TREE - L_PAREN "(" - STRING "\"{:?}\"" - COMMA "," - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE "\n " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - WHITESPACE " " - DOT "." - DOT "." - R_PAREN ")" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "u8" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "u8" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - IF_EXPR - IF_KW "if" - WHITESPACE " " - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - WHITESPACE " " - NEQ "!=" - WHITESPACE " " - LITERAL - INT_NUMBER "0u8" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "assert_eq" - BANG "!" - TOKEN_TREE - L_PAREN "(" - INT_NUMBER "8u8" - COMMA "," - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - WHITESPACE "\n " - IDENT "macro_rules" - BANG "!" - WHITESPACE " " - IDENT "u8" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - WHITESPACE "\n " - TOKEN_TREE - L_PAREN "(" - IDENT "u8" - R_PAREN ")" - WHITESPACE " " - EQ "=" - R_ANGLE ">" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - WHITESPACE "\n " - MOD_KW "mod" - WHITESPACE " " - IDENT "u8" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - WHITESPACE "\n " - PUB_KW "pub" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - IDENT "u8" - L_ANGLE "<" - LIFETIME_IDENT "'u8" - COLON ":" - WHITESPACE " " - LIFETIME_IDENT "'u8" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LIFETIME_IDENT "'u8" - R_ANGLE ">" - TOKEN_TREE - L_PAREN "(" - IDENT "u8" - COLON ":" - WHITESPACE " " - AMP "&" - LIFETIME_IDENT "'u8" - WHITESPACE " " - IDENT "u8" - R_PAREN ")" - WHITESPACE " " - MINUS "-" - R_ANGLE ">" - WHITESPACE " " - AMP "&" - LIFETIME_IDENT "'u8" - WHITESPACE " " - IDENT "u8" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - WHITESPACE "\n " - STRING "\"u8\"" - SEMICOLON ";" - WHITESPACE "\n " - IDENT "u8" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n\n " - IDENT "u8" - BANG "!" - TOKEN_TREE - L_PAREN "(" - IDENT "u8" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - LET_KW "let" - WHITESPACE " " - AMP "&" - IDENT "u8" - COLON ":" - WHITESPACE " " - AMP "&" - IDENT "u8" - WHITESPACE " " - EQ "=" - WHITESPACE " " - IDENT "u8" - COLON ":" - COLON ":" - IDENT "u8" - TOKEN_TREE - L_PAREN "(" - AMP "&" - INT_NUMBER "8u8" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - CRATE_KW "crate" - COLON ":" - COLON ":" - IDENT "u8" - TOKEN_TREE - L_PAREN "(" - INT_NUMBER "0u8" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - IDENT "u8" - WHITESPACE "\n " - R_CURLY "}" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "fishy" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "assert_eq" - BANG "!" - TOKEN_TREE - L_PAREN "(" - IDENT "String" - COLON ":" - COLON ":" - IDENT "from" - TOKEN_TREE - L_PAREN "(" - STRING "\"><>\"" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - IDENT "String" - COLON ":" - COLON ":" - L_ANGLE "<" - R_ANGLE ">" - COLON ":" - COLON ":" - IDENT "from" - COLON ":" - COLON ":" - L_ANGLE "<" - R_ANGLE ">" - TOKEN_TREE - L_PAREN "(" - STRING "\"><>\"" - R_PAREN ")" - DOT "." - IDENT "chars" - COLON ":" - COLON ":" - L_ANGLE "<" - R_ANGLE ">" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - DOT "." - IDENT "rev" - COLON ":" - COLON ":" - L_ANGLE "<" - R_ANGLE ">" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - DOT "." - IDENT "collect" - COLON ":" - COLON ":" - L_ANGLE "<" - IDENT "String" - R_ANGLE ">" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "union" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - UNION - UNION_KW "union" - WHITESPACE " " - NAME - IDENT "union" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'union" - R_ANGLE ">" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_FIELD - NAME - IDENT "union" - COLON ":" - WHITESPACE " " - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'union" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "union" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'union" - R_ANGLE ">" - COMMA "," - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "special_characters" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "val" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PREFIX_EXPR - BANG "!" - PAREN_EXPR - L_PAREN "(" - BIN_EXPR - CALL_EXPR - PAREN_EXPR - L_PAREN "(" - CLOSURE_EXPR - PARAM_LIST - PIPE "|" - PARAM - TUPLE_PAT - L_PAREN "(" - REST_PAT - DOT2 ".." - R_PAREN ")" - COLON ":" - TUPLE_TYPE - L_PAREN "(" - INFER_TYPE - UNDERSCORE "_" - COMMA "," - INFER_TYPE - UNDERSCORE "_" - R_PAREN ")" - COMMA "," - PARAM - IDENT_PAT - NAME - IDENT "__" - AT "@" - WILDCARD_PAT - UNDERSCORE "_" - PIPE "|" - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "__" - R_PAREN ")" - ARG_LIST - L_PAREN "(" - TUPLE_EXPR - L_PAREN "(" - REF_EXPR - AMP "&" - PREFIX_EXPR - STAR "*" - LITERAL - STRING "\"\\\\\"" - COMMA "," - LITERAL - CHAR "'🤔'" - R_PAREN ")" - COMMENT "/**/" - COMMA "," - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - R_PAREN ")" - EQ2 "==" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - EXPR_STMT - REF_EXPR - AMP "&" - INDEX_EXPR - ARRAY_EXPR - L_BRACK "[" - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - R_BRACK "]" - L_BRACK "[" - RANGE_EXPR - DOT2 ".." - R_BRACK "]" - SEMICOLON ";" - R_CURLY "}" - R_PAREN ")" - COMMENT "//" - WHITESPACE "\n " - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "assert" - BANG "!" - TOKEN_TREE - L_PAREN "(" - BANG "!" - IDENT "val" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "punch_card" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - IMPL_TRAIT_TYPE - IMPL_KW "impl" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "std" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "fmt" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Debug" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE "\n " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE "\n " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE "\n " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE "\n " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE "\n " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE "\n " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2EQ "..=" - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "ktulhu" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - SEMICOLON ";" - SEMICOLON ";" - SEMICOLON ";" - EXPR_STMT - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - SEMICOLON ";" - SEMICOLON ";" - SEMICOLON ";" - SEMICOLON ";" - SEMICOLON ";" - SEMICOLON ";" - SEMICOLON ";" - SEMICOLON ";" - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "strange" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "funny" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "what" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "zombiejesus" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "notsure" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "canttouchthis" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "angrydome" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "evil_lincoln" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "dots" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - ARG_LIST - L_PAREN "(" - LITERAL - INT_NUMBER "8u8" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "fishy" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "union" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "special_characters" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "punch_card" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "ktulhu" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0035_weird_exprs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0035_weird_exprs.rs deleted file mode 100644 index fb7d706b05b2a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0035_weird_exprs.rs +++ /dev/null @@ -1,154 +0,0 @@ -//! Adapted from a `rustc` test, which can be found at -//! https://github.com/rust-lang/rust/blob/6d34ec18c7d7e574553f6347ecf08e1e1c45c13d/src/test/run-pass/weird-exprs.rs. -//! -//! Reported to rust-analyzer in https://github.com/rust-lang/rust-analyzer/issues/290 - -#![allow(non_camel_case_types)] -#![allow(dead_code)] -#![allow(unreachable_code)] -#![allow(unused_parens)] - -#![recursion_limit = "128"] - -use std::cell::Cell; -use std::mem::swap; - -// Just a grab bag of stuff that you wouldn't want to actually write. - -fn strange() -> bool { let _x: bool = return true; } - -fn funny() { - fn f(_x: ()) { } - f(return); -} - -fn what() { - fn the(x: &Cell) { - return while !x.get() { x.set(true); }; - } - let i = &Cell::new(false); - let dont = {||the(i)}; - dont(); - assert!((i.get())); -} - -fn zombiejesus() { - loop { - while (return) { - if (return) { - match (return) { - 1 => { - if (return) { - return - } else { - return - } - } - _ => { return } - }; - } else if (return) { - return; - } - } - if (return) { break; } - } -} - -fn notsure() { - let mut _x: isize; - let mut _y = (_x = 0) == (_x = 0); - let mut _z = (_x = 0) < (_x = 0); - let _a = (_x += 0) == (_x = 0); - let _b = swap(&mut _y, &mut _z) == swap(&mut _y, &mut _z); -} - -fn canttouchthis() -> usize { - fn p() -> bool { true } - let _a = (assert!((true)) == (assert!(p()))); - let _c = (assert!((p())) == ()); - let _b: bool = (println!("{}", 0) == (return 0)); -} - -fn angrydome() { - loop { if break { } } - let mut i = 0; - loop { i += 1; if i == 1 { match (continue) { 1 => { }, _ => panic!("wat") } } - break; } -} - -fn evil_lincoln() { let _evil = println!("lincoln"); } - -fn dots() { - assert_eq!(String::from(".................................................."), - format!("{:?}", .. .. .. .. .. .. .. .. .. .. .. .. .. - .. .. .. .. .. .. .. .. .. .. .. ..)); -} - -fn u8(u8: u8) { - if u8 != 0u8 { - assert_eq!(8u8, { - macro_rules! u8 { - (u8) => { - mod u8 { - pub fn u8<'u8: 'u8 + 'u8>(u8: &'u8 u8) -> &'u8 u8 { - "u8"; - u8 - } - } - }; - } - - u8!(u8); - let &u8: &u8 = u8::u8(&8u8); - crate::u8(0u8); - u8 - }); - } -} - -fn fishy() { - assert_eq!(String::from("><>"), - String::<>::from::<>("><>").chars::<>().rev::<>().collect::()); -} - -fn union() { - union union<'union> { union: &'union union<'union>, } -} - -fn special_characters() { - let val = !((|(..):(_,_),__@_|__)((&*"\\",'🤔')/**/,{})=={&[..=..][..];})// - ; - assert!(!val); -} - -fn punch_card() -> impl std::fmt::Debug { - ..=..=.. .. .. .. .. .. .. .. .. .. .. ..=.. .. - ..=.. ..=.. .. .. .. .. .. .. .. .. ..=..=..=.. - ..=.. ..=.. ..=.. ..=.. .. ..=..=.. .. ..=.. .. - ..=..=.. .. ..=.. ..=.. ..=.. .. .. .. ..=.. .. - ..=.. ..=.. ..=.. ..=.. .. ..=.. .. .. ..=.. .. - ..=.. ..=.. ..=.. ..=.. .. .. ..=.. .. ..=.. .. - ..=.. ..=.. .. ..=..=.. ..=..=.. .. .. ..=.. .. -} - -fn ktulhu() { - ;;;();;;;;;;;;() -} - -pub fn main() { - strange(); - funny(); - what(); - zombiejesus(); - notsure(); - canttouchthis(); - angrydome(); - evil_lincoln(); - dots(); - u8(8u8); - fishy(); - union(); - special_characters(); - punch_card(); - ktulhu(); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rast deleted file mode 100644 index 9382020e2f608..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rast +++ /dev/null @@ -1,93 +0,0 @@ -SOURCE_FILE - COMMENT "// https://github.com/rust-lang/rust-analyzer/issues/311" - WHITESPACE "\n\n" - FN - VISIBILITY - PUB_KW "pub" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "S" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Iterator" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "String" - WHITESPACE "\n" - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE "\n " - WHERE_PRED - PATH_TYPE - PATH - PATH - PATH_SEGMENT - L_ANGLE "<" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Iterator" - R_ANGLE ">" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Item" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Eq" - COMMA "," - WHITESPACE "\n" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - METHOD_CALL_EXPR - LITERAL - STRING "\"\"" - DOT "." - NAME_REF - IDENT "to_owned" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rs deleted file mode 100644 index f8a085dc7da3a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rs +++ /dev/null @@ -1,8 +0,0 @@ -// https://github.com/rust-lang/rust-analyzer/issues/311 - -pub fn foo() -> String -where - ::Item: Eq, -{ - "".to_owned() -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0037_mod.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0037_mod.rast deleted file mode 100644 index b4a3fc6292e96..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0037_mod.rast +++ /dev/null @@ -1,16 +0,0 @@ -SOURCE_FILE - COMMENT "// https://github.com/rust-lang/rust-analyzer/issues/357" - WHITESPACE "\n\n" - COMMENT "//! docs" - WHITESPACE "\n" - MODULE - COMMENT "// non-docs" - WHITESPACE "\n" - MOD_KW "mod" - WHITESPACE " " - NAME - IDENT "foo" - WHITESPACE " " - ITEM_LIST - L_CURLY "{" - R_CURLY "}" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0037_mod.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0037_mod.rs deleted file mode 100644 index 05f6cf05cb40f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0037_mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -// https://github.com/rust-lang/rust-analyzer/issues/357 - -//! docs -// non-docs -mod foo {} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0038_where_pred_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0038_where_pred_type.rast deleted file mode 100644 index e897630420268..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0038_where_pred_type.rast +++ /dev/null @@ -1,43 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "test" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE " " - WHERE_PRED - TUPLE_TYPE - L_PAREN "(" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u64" - COMMA "," - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u64" - R_PAREN ")" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0038_where_pred_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0038_where_pred_type.rs deleted file mode 100644 index 8bfc341a50a1e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0038_where_pred_type.rs +++ /dev/null @@ -1 +0,0 @@ -fn test() where (u64, u64): Foo {} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0039_raw_fn_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0039_raw_fn_item.rast deleted file mode 100644 index 2eeed781c1a96..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0039_raw_fn_item.rast +++ /dev/null @@ -1,16 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "r#foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0039_raw_fn_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0039_raw_fn_item.rs deleted file mode 100644 index 8380d1e79bcf7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0039_raw_fn_item.rs +++ /dev/null @@ -1,2 +0,0 @@ -fn r#foo() { -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0040_raw_struct_item_field.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0040_raw_struct_item_field.rast deleted file mode 100644 index ceb918420f567..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0040_raw_struct_item_field.rast +++ /dev/null @@ -1,22 +0,0 @@ -SOURCE_FILE - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE "\n " - RECORD_FIELD - NAME - IDENT "r#foo" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - WHITESPACE "\n" - R_CURLY "}" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0040_raw_struct_item_field.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0040_raw_struct_item_field.rs deleted file mode 100644 index 098a60a72bfbb..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0040_raw_struct_item_field.rs +++ /dev/null @@ -1,3 +0,0 @@ -struct S { - r#foo: u32 -} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0041_raw_keywords.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0041_raw_keywords.rast deleted file mode 100644 index dacf0ce742600..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0041_raw_keywords.rast +++ /dev/null @@ -1,50 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "r#struct" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "92" - SEMICOLON ";" - WHITESPACE " " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "r#trait" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "r#struct" - WHITESPACE " " - STAR "*" - WHITESPACE " " - LITERAL - INT_NUMBER "2" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0041_raw_keywords.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0041_raw_keywords.rs deleted file mode 100644 index d59a6d3476bb9..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0041_raw_keywords.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo() { let r#struct = 92; let r#trait = r#struct * 2; } \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rast deleted file mode 100644 index a536b0e881f0e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rast +++ /dev/null @@ -1,127 +0,0 @@ -SOURCE_FILE - COMMENT "// https://github.com/rust-lang/rust-analyzer/issues/596" - WHITESPACE "\n\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "Foo" - SEMICOLON ";" - WHITESPACE "\n\n" - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "bar" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "bool" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "unimplemented" - BANG "!" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "baz" - PARAM_LIST - L_PAREN "(" - PARAM - WILDCARD_PAT - UNDERSCORE "_" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "bool" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "baz" - ARG_LIST - L_PAREN "(" - CALL_EXPR - PATH_EXPR - PATH - PATH - PATH_SEGMENT - L_ANGLE "<" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - R_ANGLE ">" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "bar" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rs deleted file mode 100644 index 09b18982effe1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rs +++ /dev/null @@ -1,15 +0,0 @@ -// https://github.com/rust-lang/rust-analyzer/issues/596 - -struct Foo; - -impl Foo { - fn bar() -> bool { - unimplemented!() - } -} - -fn baz(_: bool) {} - -fn main() { - baz(::bar()) -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rast deleted file mode 100644 index 3b02c3f96ae02..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rast +++ /dev/null @@ -1,110 +0,0 @@ -SOURCE_FILE - COMMENT "// https://github.com/rust-lang/rust-analyzer/issues/674" - WHITESPACE "\n\n" - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "Repr" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_FIELD - NAME - IDENT "raw" - COLON ":" - WHITESPACE " " - ARRAY_TYPE - L_BRACK "[" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - SEMICOLON ";" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - R_BRACK "]" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "abc" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - INDEX_EXPR - FIELD_EXPR - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Repr" - WHITESPACE " " - RECORD_EXPR_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_EXPR_FIELD - NAME_REF - IDENT "raw" - COLON ":" - WHITESPACE " " - ARRAY_EXPR - L_BRACK "[" - LITERAL - INT_NUMBER "0" - R_BRACK "]" - WHITESPACE " " - R_CURLY "}" - DOT "." - NAME_REF - IDENT "raw" - L_BRACK "[" - LITERAL - INT_NUMBER "0" - R_BRACK "]" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Repr" - RECORD_EXPR_FIELD_LIST - L_CURLY "{" - RECORD_EXPR_FIELD - NAME_REF - IDENT "raw" - COLON ":" - ARRAY_EXPR - L_BRACK "[" - LITERAL - INT_NUMBER "0" - R_BRACK "]" - R_CURLY "}" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rs deleted file mode 100644 index 961dc8c7d1aa1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rs +++ /dev/null @@ -1,8 +0,0 @@ -// https://github.com/rust-lang/rust-analyzer/issues/674 - -struct Repr { raw: [u8; 1] } - -fn abc() { - Repr { raw: [0] }.raw[0] = 0; - Repr{raw:[0]}(); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0044_let_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0044_let_attrs.rast deleted file mode 100644 index f3c20337e43fb..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0044_let_attrs.rast +++ /dev/null @@ -1,77 +0,0 @@ -SOURCE_FILE - FN - COMMENT "// https://github.com/rust-lang/rust-analyzer/issues/677" - WHITESPACE "\n" - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "cfg" - TOKEN_TREE - L_PAREN "(" - IDENT "feature" - WHITESPACE " " - EQ "=" - WHITESPACE " " - STRING "\"backtrace\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "exit_code" - WHITESPACE " " - EQ "=" - WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "panic" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "catch_unwind" - ARG_LIST - L_PAREN "(" - CLOSURE_EXPR - MOVE_KW "move" - WHITESPACE " " - PARAM_LIST - PIPE "|" - PIPE "|" - WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "main" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0044_let_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0044_let_attrs.rs deleted file mode 100644 index 7d15248790915..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0044_let_attrs.rs +++ /dev/null @@ -1,5 +0,0 @@ -// https://github.com/rust-lang/rust-analyzer/issues/677 -fn main() { - #[cfg(feature = "backtrace")] - let exit_code = panic::catch_unwind(move || main()); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast deleted file mode 100644 index bef1380711630..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast +++ /dev/null @@ -1,230 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "inner" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "doc" - TOKEN_TREE - L_PAREN "(" - STRING "\"Inner attributes allowed here\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - COMMENT "//! As are ModuleDoc style comments" - WHITESPACE "\n " - EXPR_STMT - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "doc" - TOKEN_TREE - L_PAREN "(" - STRING "\"Inner attributes are allowed in blocks used as statements\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "doc" - TOKEN_TREE - L_PAREN "(" - STRING "\"Being validated is not affected by duplcates\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - COMMENT "//! As are ModuleDoc style comments" - WHITESPACE "\n " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "doc" - TOKEN_TREE - L_PAREN "(" - STRING "\"Inner attributes are allowed in blocks when they are the last statement of another block\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - COMMENT "//! As are ModuleDoc style comments" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "outer" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BLOCK_EXPR - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "doc" - TOKEN_TREE - L_PAREN "(" - STRING "\"Outer attributes are always allowed\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - IMPL - COMMENT "// https://github.com/rust-lang/rust-analyzer/issues/689" - WHITESPACE "\n" - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Whatever" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "salsa_event" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - AMP "&" - NAME - SELF_KW "self" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - NAME - IDENT "event_fn" - COLON ":" - WHITESPACE " " - IMPL_TRAIT_TYPE - IMPL_KW "impl" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Event" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - SELF_TYPE_KW "Self" - R_ANGLE ">" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "allow" - TOKEN_TREE - L_PAREN "(" - IDENT "unused_variables" - R_PAREN ")" - R_BRACK "]" - WHITESPACE " " - COMMENT "// this is `inner_attr` of the block" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rs deleted file mode 100644 index f16c4566e77c3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rs +++ /dev/null @@ -1,24 +0,0 @@ -fn inner() { - #![doc("Inner attributes allowed here")] - //! As are ModuleDoc style comments - { - #![doc("Inner attributes are allowed in blocks used as statements")] - #![doc("Being validated is not affected by duplcates")] - //! As are ModuleDoc style comments - }; - { - #![doc("Inner attributes are allowed in blocks when they are the last statement of another block")] - //! As are ModuleDoc style comments - } -} - -fn outer() { - let _ = #[doc("Outer attributes are always allowed")] {}; -} - -// https://github.com/rust-lang/rust-analyzer/issues/689 -impl Whatever { - fn salsa_event(&self, event_fn: impl Fn() -> Event) { - #![allow(unused_variables)] // this is `inner_attr` of the block - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0046_extern_inner_attributes.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0046_extern_inner_attributes.rast deleted file mode 100644 index 4eb51cfdf09e2..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0046_extern_inner_attributes.rast +++ /dev/null @@ -1,29 +0,0 @@ -SOURCE_FILE - EXTERN_BLOCK - ABI - EXTERN_KW "extern" - WHITESPACE " " - STRING "\"C\"" - WHITESPACE " " - EXTERN_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - COMMENT "//! This is a doc comment" - WHITESPACE "\n " - ATTR - POUND "#" - BANG "!" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "doc" - TOKEN_TREE - L_PAREN "(" - STRING "\"This is also a doc comment\"" - R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0046_extern_inner_attributes.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0046_extern_inner_attributes.rs deleted file mode 100644 index fe67e2df43c87..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0046_extern_inner_attributes.rs +++ /dev/null @@ -1,4 +0,0 @@ -extern "C" { - //! This is a doc comment - #![doc("This is also a doc comment")] -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0047_minus_in_inner_pattern.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0047_minus_in_inner_pattern.rast deleted file mode 100644 index c7eb3687deec6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0047_minus_in_inner_pattern.rast +++ /dev/null @@ -1,323 +0,0 @@ -SOURCE_FILE - COMMENT "// https://github.com/rust-lang/rust-analyzer/issues/972" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - ARG_LIST - L_PAREN "(" - PREFIX_EXPR - MINUS "-" - LITERAL - INT_NUMBER "1" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - L_PAREN "(" - LITERAL_PAT - MINUS "-" - LITERAL - INT_NUMBER "1" - R_PAREN ")" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n\n " - EXPR_STMT - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - ARG_LIST - L_PAREN "(" - TUPLE_EXPR - L_PAREN "(" - PREFIX_EXPR - MINUS "-" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - PREFIX_EXPR - MINUS "-" - LITERAL - INT_NUMBER "1" - R_PAREN ")" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - L_PAREN "(" - TUPLE_PAT - L_PAREN "(" - LITERAL_PAT - MINUS "-" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - LITERAL_PAT - MINUS "-" - LITERAL - INT_NUMBER "1" - R_PAREN ")" - R_PAREN ")" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n\n " - EXPR_STMT - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "A" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "B" - ARG_LIST - L_PAREN "(" - PREFIX_EXPR - MINUS "-" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - PREFIX_EXPR - MINUS "-" - LITERAL - INT_NUMBER "1" - R_PAREN ")" - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_ARM - TUPLE_STRUCT_PAT - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "A" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "B" - L_PAREN "(" - LITERAL_PAT - MINUS "-" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - LITERAL_PAT - MINUS "-" - LITERAL - INT_NUMBER "1" - R_PAREN ")" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n\n " - IF_EXPR - IF_KW "if" - WHITESPACE " " - LET_EXPR - LET_KW "let" - WHITESPACE " " - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - L_PAREN "(" - LITERAL_PAT - MINUS "-" - LITERAL - INT_NUMBER "1" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - ARG_LIST - L_PAREN "(" - PREFIX_EXPR - MINUS "-" - LITERAL - INT_NUMBER "1" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - ENUM - ENUM_KW "enum" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - VARIANT_LIST - L_CURLY "{" - WHITESPACE "\n " - VARIANT - NAME - IDENT "B" - TUPLE_FIELD_LIST - L_PAREN "(" - TUPLE_FIELD - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i8" - COMMA "," - WHITESPACE " " - TUPLE_FIELD - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i8" - R_PAREN ")" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - PARAM - RANGE_PAT - LITERAL_PAT - MINUS "-" - LITERAL - INT_NUMBER "128" - DOT2EQ "..=" - LITERAL_PAT - LITERAL - INT_NUMBER "127" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i8" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0047_minus_in_inner_pattern.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0047_minus_in_inner_pattern.rs deleted file mode 100644 index 13dc46afa94a3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0047_minus_in_inner_pattern.rs +++ /dev/null @@ -1,27 +0,0 @@ -// https://github.com/rust-lang/rust-analyzer/issues/972 - -fn main() { - match Some(-1) { - Some(-1) => (), - _ => (), - } - - match Some((-1, -1)) { - Some((-1, -1)) => (), - _ => (), - } - - match A::B(-1, -1) { - A::B(-1, -1) => (), - _ => (), - } - - if let Some(-1) = Some(-1) { - } -} - -enum A { - B(i8, i8) -} - -fn foo(-128..=127: i8) {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0048_compound_assignment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0048_compound_assignment.rast deleted file mode 100644 index e0f163b1a1f8e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0048_compound_assignment.rast +++ /dev/null @@ -1,201 +0,0 @@ -SOURCE_FILE - COMMENT "// https://github.com/rust-lang/rust-analyzer/pull/983" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "compound_assignment" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - MUT_KW "mut" - WHITESPACE " " - NAME - IDENT "a" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - WHITESPACE " " - PLUSEQ "+=" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - WHITESPACE " " - MINUSEQ "-=" - WHITESPACE " " - LITERAL - INT_NUMBER "2" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - WHITESPACE " " - STAREQ "*=" - WHITESPACE " " - LITERAL - INT_NUMBER "3" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - WHITESPACE " " - PERCENTEQ "%=" - WHITESPACE " " - LITERAL - INT_NUMBER "4" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - WHITESPACE " " - SLASHEQ "/=" - WHITESPACE " " - LITERAL - INT_NUMBER "5" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - WHITESPACE " " - PIPEEQ "|=" - WHITESPACE " " - LITERAL - INT_NUMBER "6" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - WHITESPACE " " - AMPEQ "&=" - WHITESPACE " " - LITERAL - INT_NUMBER "7" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - WHITESPACE " " - CARETEQ "^=" - WHITESPACE " " - LITERAL - INT_NUMBER "8" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - WHITESPACE " " - LTEQ "<=" - WHITESPACE " " - LITERAL - INT_NUMBER "9" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - WHITESPACE " " - GTEQ ">=" - WHITESPACE " " - LITERAL - INT_NUMBER "10" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - WHITESPACE " " - SHREQ ">>=" - WHITESPACE " " - LITERAL - INT_NUMBER "11" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - WHITESPACE " " - SHLEQ "<<=" - WHITESPACE " " - LITERAL - INT_NUMBER "12" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0048_compound_assignment.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0048_compound_assignment.rs deleted file mode 100644 index 1a6a9bdf56572..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0048_compound_assignment.rs +++ /dev/null @@ -1,17 +0,0 @@ -// https://github.com/rust-lang/rust-analyzer/pull/983 - -fn compound_assignment() { - let mut a = 0; - a += 1; - a -= 2; - a *= 3; - a %= 4; - a /= 5; - a |= 6; - a &= 7; - a ^= 8; - a <= 9; - a >= 10; - a >>= 11; - a <<= 12; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0049_async_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0049_async_block.rast deleted file mode 100644 index f376821e285a3..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0049_async_block.rast +++ /dev/null @@ -1,36 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - BLOCK_EXPR - ASYNC_KW "async" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BLOCK_EXPR - ASYNC_KW "async" - WHITESPACE " " - MOVE_KW "move" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0049_async_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0049_async_block.rs deleted file mode 100644 index 4781b32254982..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0049_async_block.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn foo() { - async {}; - async move {}; -} - diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0050_async_block_as_argument.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0050_async_block_as_argument.rast deleted file mode 100644 index 53ddf35ccb4db..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0050_async_block_as_argument.rast +++ /dev/null @@ -1,92 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "x" - COLON ":" - WHITESPACE " " - IMPL_TRAIT_TYPE - IMPL_KW "impl" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "std" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "future" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Future" - GENERIC_ARG_LIST - L_ANGLE "<" - ASSOC_TYPE_ARG - NAME_REF - IDENT "Output" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_ANGLE ">" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - ARG_LIST - L_PAREN "(" - BLOCK_EXPR - ASYNC_KW "async" - WHITESPACE " " - MOVE_KW "move" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - WHITESPACE " " - LITERAL - INT_NUMBER "12" - WHITESPACE " " - R_CURLY "}" - R_PAREN ")" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0050_async_block_as_argument.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0050_async_block_as_argument.rs deleted file mode 100644 index ec4612cff2782..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0050_async_block_as_argument.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn foo(x: impl std::future::Future) {} - -fn main() { - foo(async move { 12 }) -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast deleted file mode 100644 index f8b11e7782c91..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast +++ /dev/null @@ -1,548 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "g1" - PARAM_LIST - L_PAREN "(" - PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr1" - R_BRACK "]" - WHITESPACE " " - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr2" - R_BRACK "]" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "pat" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Type" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "g2" - PARAM_LIST - L_PAREN "(" - PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr1" - R_BRACK "]" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "x" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n" - EXTERN_BLOCK - ABI - EXTERN_KW "extern" - WHITESPACE " " - STRING "\"C\"" - WHITESPACE " " - EXTERN_ITEM_LIST - L_CURLY "{" - WHITESPACE " " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "printf" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "format" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - CONST_KW "const" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i8" - COMMA "," - WHITESPACE " " - PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - DOT3 "..." - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "F" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "FnMut" - PARAM_LIST - L_PAREN "(" - PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - REF_TYPE - AMP "&" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - R_PAREN ")" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n" - TRAIT - TRAIT_KW "trait" - WHITESPACE " " - NAME - IDENT "Foo" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "bar" - PARAM_LIST - L_PAREN "(" - PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u64" - COMMA "," - WHITESPACE " " - PARAM - ATTR - POUND "#" - WHITESPACE " " - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - IDENT_PAT - MUT_KW "mut" - WHITESPACE " " - NAME - IDENT "x" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "must_use" - R_BRACK "]" - WHITESPACE " " - NAME - SELF_KW "self" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "g1" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - NAME - SELF_KW "self" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "g2" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - AMP "&" - NAME - SELF_KW "self" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "g3" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - AMP "&" - MUT_KW "mut" - WHITESPACE " " - NAME - SELF_KW "self" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "g4" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - NAME - SELF_KW "self" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "g5" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - MUT_KW "mut" - WHITESPACE " " - NAME - SELF_KW "self" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "c" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - NAME - SELF_KW "self" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - SELF_TYPE_KW "Self" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "d" - PARAM_LIST - L_PAREN "(" - SELF_PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - NAME - SELF_KW "self" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Rc" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - SELF_TYPE_KW "Self" - R_ANGLE ">" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs deleted file mode 100644 index de350d8587ac0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs +++ /dev/null @@ -1,21 +0,0 @@ -fn g1(#[attr1] #[attr2] pat: Type) {} -fn g2(#[attr1] x: u8) {} - -extern "C" { fn printf(format: *const i8, #[attr] ...) -> i32; } - -fn foo)>(){} - -trait Foo { - fn bar(#[attr] _: u64, # [attr] mut x: i32); -} - -impl S { - fn f(#[must_use] self) {} - fn g1(#[attr] self) {} - fn g2(#[attr] &self) {} - fn g3<'a>(#[attr] &mut self) {} - fn g4<'a>(#[attr] &'a self) {} - fn g5<'a>(#[attr] &'a mut self) {} - fn c(#[attr] self: Self) {} - fn d(#[attr] self: Rc) {} -} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0052_for_range_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0052_for_range_block.rast deleted file mode 100644 index 0c9dd432fb460..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0052_for_range_block.rast +++ /dev/null @@ -1,81 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - FOR_EXPR - FOR_KW "for" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "_x" - WHITESPACE " " - IN_KW "in" - WHITESPACE " " - RANGE_EXPR - LITERAL - INT_NUMBER "0" - WHITESPACE " " - DOT2 ".." - WHITESPACE " " - METHOD_CALL_EXPR - PAREN_EXPR - L_PAREN "(" - RANGE_EXPR - LITERAL - INT_NUMBER "0" - WHITESPACE " " - DOT2 ".." - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LITERAL - INT_NUMBER "2" - R_CURLY "}" - R_PAREN ")" - DOT "." - NAME_REF - IDENT "sum" - GENERIC_ARG_LIST - COLON2 "::" - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - R_ANGLE ">" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - BREAK_EXPR - BREAK_KW "break" - SEMICOLON ";" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0052_for_range_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0052_for_range_block.rs deleted file mode 100644 index b51b1963008ce..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0052_for_range_block.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn foo() { - for _x in 0 .. (0 .. {1 + 2}).sum::() { - break; - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast deleted file mode 100644 index b94d43beb3c28..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast +++ /dev/null @@ -1,37 +0,0 @@ -SOURCE_FILE - MACRO_RULES - COMMENT "/// Some docs" - WHITESPACE "\n" - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "macro_export" - R_BRACK "]" - WHITESPACE "\n" - MACRO_RULES_KW "macro_rules" - BANG "!" - WHITESPACE " " - NAME - IDENT "foo" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - WHITESPACE "\n " - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - EQ "=" - R_ANGLE ">" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rs deleted file mode 100644 index b59c23c56a926..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Some docs -#[macro_export] -macro_rules! foo { - () => {}; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast deleted file mode 100644 index 4e1e31f376760..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast +++ /dev/null @@ -1,126 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "a" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "bar" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Baz" - R_ANGLE ">" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "b" - PARAM_LIST - L_PAREN "(" - PARAM - WILDCARD_PAT - UNDERSCORE "_" - COLON ":" - WHITESPACE " " - IMPL_TRAIT_TYPE - IMPL_KW "impl" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "FnMut" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Y" - R_PAREN ")" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "c" - PARAM_LIST - L_PAREN "(" - PARAM - WILDCARD_PAT - UNDERSCORE "_" - COLON ":" - WHITESPACE " " - IMPL_TRAIT_TYPE - IMPL_KW "impl" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "FnMut" - PARAM_LIST - L_PAREN "(" - PARAM - REF_TYPE - AMP "&" - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Y" - R_PAREN ")" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rs deleted file mode 100644 index 0d3f5722a5a3b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn a() -> Foo {} - -fn b(_: impl FnMut(x::Y)) {} - -fn c(_: impl FnMut(&x::Y)) {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rast deleted file mode 100644 index 684f499df5c56..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rast +++ /dev/null @@ -1,50 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "X" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_PAT - L_PAREN "(" - R_PAREN ")" - COLON ":" - PATH_TYPE - PATH - PATH_SEGMENT - COLON2 "::" - NAME_REF - IDENT "X" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rs deleted file mode 100644 index cd204f65ed9d0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rs +++ /dev/null @@ -1,5 +0,0 @@ -type X = (); - -fn main() { - let ():::X = (); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0056_neq_in_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0056_neq_in_type.rast deleted file mode 100644 index 55ce31275fba6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0056_neq_in_type.rast +++ /dev/null @@ -1,65 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - IF_EXPR - IF_KW "if" - WHITESPACE " " - BIN_EXPR - CAST_EXPR - METHOD_CALL_EXPR - LITERAL - FLOAT_NUMBER "1.0f32" - DOT "." - NAME_REF - IDENT "floor" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i64" - WHITESPACE " " - NEQ "!=" - WHITESPACE " " - CAST_EXPR - METHOD_CALL_EXPR - LITERAL - FLOAT_NUMBER "1.0f32" - DOT "." - NAME_REF - IDENT "floor" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i64" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0056_neq_in_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0056_neq_in_type.rs deleted file mode 100644 index 6210683cea36c..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0056_neq_in_type.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - if 1.0f32.floor() as i64 != 1.0f32.floor() as i64 {} -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0057_loop_in_call.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0057_loop_in_call.rast deleted file mode 100644 index 67837e4750cba..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0057_loop_in_call.rast +++ /dev/null @@ -1,59 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "x" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - ARG_LIST - L_PAREN "(" - LOOP_EXPR - LOOP_KW "loop" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0057_loop_in_call.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0057_loop_in_call.rs deleted file mode 100644 index 31c12522ffca8..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0057_loop_in_call.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn foo(x: i32) {} - -fn main() { - foo(loop {}); -} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0058_unary_expr_precedence.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0058_unary_expr_precedence.rast deleted file mode 100644 index 683d5070aee76..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0058_unary_expr_precedence.rast +++ /dev/null @@ -1,97 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - PREFIX_EXPR - STAR "*" - REF_EXPR - AMP "&" - LITERAL - INT_NUMBER "2" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LITERAL - INT_NUMBER "3" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CAST_EXPR - PREFIX_EXPR - STAR "*" - REF_EXPR - AMP "&" - LITERAL - INT_NUMBER "1" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u64" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - PREFIX_EXPR - STAR "*" - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - ARG_LIST - L_PAREN "(" - LITERAL - INT_NUMBER "1" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - REF_EXPR - AMP "&" - INDEX_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "x" - L_BRACK "[" - LITERAL - INT_NUMBER "1" - R_BRACK "]" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - RANGE_EXPR - PREFIX_EXPR - MINUS "-" - LITERAL - INT_NUMBER "1" - DOT2 ".." - LITERAL - INT_NUMBER "2" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0058_unary_expr_precedence.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0058_unary_expr_precedence.rs deleted file mode 100644 index 100fccc641cbd..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0058_unary_expr_precedence.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn foo() { - 1 + *&2 + 3; - *&1 as u64; - *x(1); - &x[1]; - -1..2; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0059_loops_in_parens.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0059_loops_in_parens.rast deleted file mode 100644 index 79bc7f971d187..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0059_loops_in_parens.rast +++ /dev/null @@ -1,100 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - ARG_LIST - L_PAREN "(" - FOR_EXPR - FOR_KW "for" - WHITESPACE " " - WILDCARD_PAT - UNDERSCORE "_" - WHITESPACE " " - IN_KW "in" - WHITESPACE " " - METHOD_CALL_EXPR - ARRAY_EXPR - L_BRACK "[" - LITERAL - INT_NUMBER "1" - R_BRACK "]" - DOT "." - NAME_REF - IDENT "into_iter" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - ARG_LIST - L_PAREN "(" - LOOP_EXPR - LOOP_KW "loop" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE " " - EXPR_STMT - BREAK_EXPR - BREAK_KW "break" - SEMICOLON ";" - WHITESPACE " " - R_CURLY "}" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - ARG_LIST - L_PAREN "(" - WHILE_EXPR - WHILE_KW "while" - WHITESPACE " " - LITERAL - TRUE_KW "true" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0059_loops_in_parens.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0059_loops_in_parens.rs deleted file mode 100644 index 6e8b718aaf9a0..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0059_loops_in_parens.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - Some(for _ in [1].into_iter() {}); - Some(loop { break; }); - Some(while true {}); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0060_as_range.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0060_as_range.rast deleted file mode 100644 index 81fc02b6f4ad1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0060_as_range.rast +++ /dev/null @@ -1,56 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - RANGE_EXPR - CAST_EXPR - LITERAL - INT_NUMBER "0" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "usize" - WHITESPACE " " - DOT2 ".." - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - RANGE_EXPR - BIN_EXPR - LITERAL - INT_NUMBER "1" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - CAST_EXPR - LITERAL - INT_NUMBER "2" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "usize" - WHITESPACE " " - DOT2 ".." - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0060_as_range.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0060_as_range.rs deleted file mode 100644 index f063ffadb3db6..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0060_as_range.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - 0 as usize ..; - 1 + 2 as usize ..; -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0061_match_full_range.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0061_match_full_range.rast deleted file mode 100644 index 2f56e9041ea0f..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0061_match_full_range.rast +++ /dev/null @@ -1,27 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - WHITESPACE " " - MATCH_ARM_LIST - L_CURLY "{" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0061_match_full_range.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0061_match_full_range.rs deleted file mode 100644 index 2c4ed11e1e5dd..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0061_match_full_range.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - match .. { - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rast deleted file mode 100644 index 3915ed7506436..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rast +++ /dev/null @@ -1,177 +0,0 @@ -SOURCE_FILE - MACRO_DEF - MACRO_KW "macro" - WHITESPACE " " - NAME - IDENT "parse_use_trees" - TOKEN_TREE - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - IDENT "s" - COLON ":" - IDENT "expr" - R_PAREN ")" - COMMA "," - STAR "*" - WHITESPACE " " - DOLLAR "$" - TOKEN_TREE - L_PAREN "(" - COMMA "," - R_PAREN ")" - STAR "*" - R_PAREN ")" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - WHITESPACE "\n " - IDENT "vec" - BANG "!" - TOKEN_TREE - L_BRACK "[" - WHITESPACE "\n " - DOLLAR "$" - TOKEN_TREE - L_PAREN "(" - IDENT "parse_use_tree" - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - IDENT "s" - R_PAREN ")" - COMMA "," - R_PAREN ")" - STAR "*" - WHITESPACE "\n " - R_BRACK "]" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - FN - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "test" - R_BRACK "]" - WHITESPACE "\n" - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "test_use_tree_merge" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - MACRO_DEF - MACRO_KW "macro" - WHITESPACE " " - NAME - IDENT "test_merge" - TOKEN_TREE - TOKEN_TREE - L_PAREN "(" - TOKEN_TREE - L_BRACK "[" - DOLLAR "$" - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - IDENT "input" - COLON ":" - IDENT "expr" - R_PAREN ")" - COMMA "," - STAR "*" - WHITESPACE " " - DOLLAR "$" - TOKEN_TREE - L_PAREN "(" - COMMA "," - R_PAREN ")" - STAR "*" - R_BRACK "]" - COMMA "," - WHITESPACE " " - TOKEN_TREE - L_BRACK "[" - DOLLAR "$" - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - IDENT "output" - COLON ":" - IDENT "expr" - R_PAREN ")" - COMMA "," - STAR "*" - WHITESPACE " " - DOLLAR "$" - TOKEN_TREE - L_PAREN "(" - COMMA "," - R_PAREN ")" - STAR "*" - R_BRACK "]" - R_PAREN ")" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - WHITESPACE "\n " - IDENT "assert_eq" - BANG "!" - TOKEN_TREE - L_PAREN "(" - WHITESPACE "\n " - IDENT "merge_use_trees" - TOKEN_TREE - L_PAREN "(" - IDENT "parse_use_trees" - BANG "!" - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - IDENT "input" - COMMA "," - R_PAREN ")" - STAR "*" - R_PAREN ")" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - IDENT "parse_use_trees" - BANG "!" - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - IDENT "output" - COMMA "," - R_PAREN ")" - STAR "*" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rs deleted file mode 100644 index 781047ba19a98..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rs +++ /dev/null @@ -1,15 +0,0 @@ -macro parse_use_trees($($s:expr),* $(,)*) { - vec![ - $(parse_use_tree($s),)* - ] -} - -#[test] -fn test_use_tree_merge() { - macro test_merge([$($input:expr),* $(,)*], [$($output:expr),* $(,)*]) { - assert_eq!( - merge_use_trees(parse_use_trees!($($input,)*)), - parse_use_trees!($($output,)*), - ); - } -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_trait_fn_patterns.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_trait_fn_patterns.rast deleted file mode 100644 index a86b21d27cdf7..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_trait_fn_patterns.rast +++ /dev/null @@ -1,198 +0,0 @@ -SOURCE_FILE - TRAIT - TRAIT_KW "trait" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f1" - PARAM_LIST - L_PAREN "(" - PARAM - TUPLE_PAT - L_PAREN "(" - IDENT_PAT - NAME - IDENT "a" - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "b" - R_PAREN ")" - COLON ":" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "usize" - COMMA "," - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "usize" - R_PAREN ")" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f2" - PARAM_LIST - L_PAREN "(" - PARAM - RECORD_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_PAT_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_PAT_FIELD - IDENT_PAT - NAME - IDENT "a" - COMMA "," - WHITESPACE " " - RECORD_PAT_FIELD - IDENT_PAT - NAME - IDENT "b" - WHITESPACE " " - R_CURLY "}" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f3" - PARAM_LIST - L_PAREN "(" - PARAM - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "NewType" - L_PAREN "(" - IDENT_PAT - NAME - IDENT "a" - R_PAREN ")" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "NewType" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f4" - PARAM_LIST - L_PAREN "(" - PARAM - REF_PAT - AMP "&" - REF_PAT - AMP "&" - IDENT_PAT - NAME - IDENT "a" - COLON ":" - WHITESPACE " " - REF_TYPE - AMP "&" - REF_TYPE - AMP "&" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "usize" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "bar" - PARAM_LIST - L_PAREN "(" - PARAM - WILDCARD_PAT - UNDERSCORE "_" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u64" - COMMA "," - WHITESPACE " " - PARAM - IDENT_PAT - MUT_KW "mut" - WHITESPACE " " - NAME - IDENT "x" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_trait_fn_patterns.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_trait_fn_patterns.rs deleted file mode 100644 index 3b666af8eed3b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_trait_fn_patterns.rs +++ /dev/null @@ -1,7 +0,0 @@ -trait T { - fn f1((a, b): (usize, usize)) {} - fn f2(S { a, b }: S) {} - fn f3(NewType(a): NewType) {} - fn f4(&&a: &&usize) {} - fn bar(_: u64, mut x: i32); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_variadic_fun.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_variadic_fun.rast deleted file mode 100644 index e36399123bcc1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_variadic_fun.rast +++ /dev/null @@ -1,134 +0,0 @@ -SOURCE_FILE - EXTERN_BLOCK - ABI - EXTERN_KW "extern" - WHITESPACE " " - STRING "\"C\"" - WHITESPACE " " - EXTERN_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "a" - PARAM_LIST - L_PAREN "(" - PARAM - WILDCARD_PAT - UNDERSCORE "_" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - COMMA "," - WHITESPACE " " - PARAM - DOT3 "..." - COMMA "," - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "b" - PARAM_LIST - L_PAREN "(" - PARAM - WILDCARD_PAT - UNDERSCORE "_" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - COMMA "," - WHITESPACE " " - PARAM - WILDCARD_PAT - UNDERSCORE "_" - COLON ":" - WHITESPACE " " - DOT3 "..." - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "c" - PARAM_LIST - L_PAREN "(" - PARAM - WILDCARD_PAT - UNDERSCORE "_" - COLON ":" - WHITESPACE " " - PTR_TYPE - STAR "*" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - COMMA "," - WHITESPACE " " - PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "cfg" - TOKEN_TREE - L_PAREN "(" - IDENT "never" - R_PAREN ")" - R_BRACK "]" - WHITESPACE " " - SLICE_PAT - L_BRACK "[" - IDENT_PAT - NAME - IDENT "w" - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "t" - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "f" - R_BRACK "]" - COLON ":" - WHITESPACE " " - DOT3 "..." - COMMA "," - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_variadic_fun.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_variadic_fun.rs deleted file mode 100644 index a16afbaf386d5..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_variadic_fun.rs +++ /dev/null @@ -1,5 +0,0 @@ -extern "C" { - fn a(_: *mut u8, ...,); - fn b(_: *mut u8, _: ...); - fn c(_: *mut u8, #[cfg(never)] [w, t, f]: ...,); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0064_impl_fn_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0064_impl_fn_params.rast deleted file mode 100644 index 18cecc8108dd5..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0064_impl_fn_params.rast +++ /dev/null @@ -1,166 +0,0 @@ -SOURCE_FILE - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "U" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f1" - PARAM_LIST - L_PAREN "(" - PARAM - TUPLE_PAT - L_PAREN "(" - IDENT_PAT - NAME - IDENT "a" - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "b" - R_PAREN ")" - COLON ":" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "usize" - COMMA "," - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "usize" - R_PAREN ")" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f2" - PARAM_LIST - L_PAREN "(" - PARAM - RECORD_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_PAT_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_PAT_FIELD - IDENT_PAT - NAME - IDENT "a" - COMMA "," - WHITESPACE " " - RECORD_PAT_FIELD - IDENT_PAT - NAME - IDENT "b" - WHITESPACE " " - R_CURLY "}" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f3" - PARAM_LIST - L_PAREN "(" - PARAM - TUPLE_STRUCT_PAT - PATH - PATH_SEGMENT - NAME_REF - IDENT "NewType" - L_PAREN "(" - IDENT_PAT - NAME - IDENT "a" - R_PAREN ")" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "NewType" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f4" - PARAM_LIST - L_PAREN "(" - PARAM - REF_PAT - AMP "&" - REF_PAT - AMP "&" - IDENT_PAT - NAME - IDENT "a" - COLON ":" - WHITESPACE " " - REF_TYPE - AMP "&" - REF_TYPE - AMP "&" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "usize" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0064_impl_fn_params.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0064_impl_fn_params.rs deleted file mode 100644 index b49e872d79da2..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0064_impl_fn_params.rs +++ /dev/null @@ -1,6 +0,0 @@ -impl U { - fn f1((a, b): (usize, usize)) {} - fn f2(S { a, b }: S) {} - fn f3(NewType(a): NewType) {} - fn f4(&&a: &&usize) {} -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_comment_newline.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_comment_newline.rast deleted file mode 100644 index 3ffcb48f5e424..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_comment_newline.rast +++ /dev/null @@ -1,17 +0,0 @@ -SOURCE_FILE - FN - COMMENT "/// Example" - WHITESPACE "\n\n" - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "test" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_comment_newline.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_comment_newline.rs deleted file mode 100644 index 1fafe216b6e7a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_comment_newline.rs +++ /dev/null @@ -1,3 +0,0 @@ -/// Example - -fn test() {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast deleted file mode 100644 index ba7b6042a9e3b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast +++ /dev/null @@ -1,61 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE " " - WHERE_PRED - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Send" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rs deleted file mode 100644 index 29f3655e013c5..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rs +++ /dev/null @@ -1 +0,0 @@ -fn f() where T: Fn() -> u8 + Send {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0066_default_modifier.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0066_default_modifier.rast deleted file mode 100644 index a4303098a282b..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0066_default_modifier.rast +++ /dev/null @@ -1,222 +0,0 @@ -SOURCE_FILE - TRAIT - TRAIT_KW "trait" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - TYPE_ALIAS - DEFAULT_KW "default" - WHITESPACE " " - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Bar" - SEMICOLON ";" - WHITESPACE "\n " - CONST - DEFAULT_KW "default" - WHITESPACE " " - CONST_KW "const" - WHITESPACE " " - NAME - IDENT "f" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - SEMICOLON ";" - WHITESPACE "\n " - FN - DEFAULT_KW "default" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - DEFAULT_KW "default" - WHITESPACE " " - UNSAFE_KW "unsafe" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "bar" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - IMPL - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - WHITESPACE " " - FOR_KW "for" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - WHITESPACE "\n " - TYPE_ALIAS - DEFAULT_KW "default" - WHITESPACE " " - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Bar" - SEMICOLON ";" - WHITESPACE "\n " - CONST - DEFAULT_KW "default" - WHITESPACE " " - CONST_KW "const" - WHITESPACE " " - NAME - IDENT "f" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "u8" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - SEMICOLON ";" - WHITESPACE "\n " - FN - DEFAULT_KW "default" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n " - FN - DEFAULT_KW "default" - WHITESPACE " " - UNSAFE_KW "unsafe" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "bar" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n\n" - IMPL - DEFAULT_KW "default" - WHITESPACE " " - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - WHITESPACE " " - FOR_KW "for" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - IMPL - DEFAULT_KW "default" - WHITESPACE " " - UNSAFE_KW "unsafe" - WHITESPACE " " - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - WHITESPACE " " - FOR_KW "for" - WHITESPACE " " - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0066_default_modifier.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0066_default_modifier.rs deleted file mode 100644 index e443e3495e3af..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0066_default_modifier.rs +++ /dev/null @@ -1,16 +0,0 @@ -trait T { - default type T = Bar; - default const f: u8 = 0; - default fn foo() {} - default unsafe fn bar() {} -} - -impl T for Foo { - default type T = Bar; - default const f: u8 = 0; - default fn foo() {} - default unsafe fn bar() {} -} - -default impl T for () {} -default unsafe impl T for () {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast deleted file mode 100644 index 136fce93d7ec1..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast +++ /dev/null @@ -1,413 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "for_trait" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "F" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n" - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE "\n " - WHERE_PRED - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "F" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "str" - R_PAREN ")" - COMMA "," - WHITESPACE "\n" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "for_ref" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "F" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n" - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE "\n " - WHERE_PRED - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "F" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Debug" - COMMA "," - WHITESPACE "\n" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "for_parens" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "F" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n" - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE "\n " - WHERE_PRED - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - PAREN_TYPE - L_PAREN "(" - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "F" - R_PAREN ")" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "str" - R_PAREN ")" - COMMA "," - WHITESPACE "\n" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "for_slice" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "F" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n" - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE "\n " - WHERE_PRED - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - SLICE_TYPE - L_BRACK "[" - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "F" - R_BRACK "]" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Eq" - COMMA "," - WHITESPACE "\n" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "for_qpath" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "_t" - COLON ":" - WHITESPACE " " - REF_TYPE - AMP "&" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - R_PAREN ")" - WHITESPACE "\n" - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE "\n " - WHERE_PRED - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - PATH_TYPE - PATH - PATH - PATH_SEGMENT - L_ANGLE "<" - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Baz" - R_ANGLE ">" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Foo" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Iterator" - COMMA "," - WHITESPACE "\n" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "for_for_fn" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n" - WHERE_CLAUSE - WHERE_KW "where" - WHITESPACE "\n " - WHERE_PRED - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - FOR_TYPE - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'b" - R_ANGLE ">" - WHITESPACE " " - FN_PTR_TYPE - FN_KW "fn" - PARAM_LIST - L_PAREN "(" - PARAM - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - COMMA "," - WHITESPACE " " - PARAM - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'b" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - R_PAREN ")" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Copy" - COMMA "," - WHITESPACE "\n" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rs deleted file mode 100644 index 9058c46190c4d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rs +++ /dev/null @@ -1,30 +0,0 @@ -fn for_trait() -where - for<'a> F: Fn(&'a str), -{ -} -fn for_ref() -where - for<'a> &'a F: Debug, -{ -} -fn for_parens() -where - for<'a> (&'a F): Fn(&'a str), -{ -} -fn for_slice() -where - for<'a> [&'a F]: Eq, -{ -} -fn for_qpath(_t: &T) -where - for<'a> <&'a T as Baz>::Foo: Iterator, -{ -} -fn for_for_fn() -where - for<'a> for<'b> fn(&'a T, &'b T): Copy, -{ -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rast deleted file mode 100644 index 41fc5691ad771..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rast +++ /dev/null @@ -1,238 +0,0 @@ -SOURCE_FILE - FN - ASYNC_KW "async" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - ABI - EXTERN_KW "extern" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - CONST_KW "const" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - CONST_KW "const" - WHITESPACE " " - UNSAFE_KW "unsafe" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - UNSAFE_KW "unsafe" - WHITESPACE " " - ABI - EXTERN_KW "extern" - WHITESPACE " " - STRING "\"C\"" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - UNSAFE_KW "unsafe" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - ASYNC_KW "async" - WHITESPACE " " - UNSAFE_KW "unsafe" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - FN - CONST_KW "const" - WHITESPACE " " - UNSAFE_KW "unsafe" - WHITESPACE " " - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "bar" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n" - TRAIT - UNSAFE_KW "unsafe" - WHITESPACE " " - TRAIT_KW "trait" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - TRAIT - AUTO_KW "auto" - WHITESPACE " " - TRAIT_KW "trait" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - TRAIT - UNSAFE_KW "unsafe" - WHITESPACE " " - AUTO_KW "auto" - WHITESPACE " " - TRAIT_KW "trait" - WHITESPACE " " - NAME - IDENT "T" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n" - IMPL - UNSAFE_KW "unsafe" - WHITESPACE " " - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - IMPL - DEFAULT_KW "default" - WHITESPACE " " - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" - IMPL - UNSAFE_KW "unsafe" - WHITESPACE " " - DEFAULT_KW "default" - WHITESPACE " " - IMPL_KW "impl" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - WHITESPACE " " - ASSOC_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n" - EXTERN_BLOCK - UNSAFE_KW "unsafe" - WHITESPACE " " - ABI - EXTERN_KW "extern" - WHITESPACE " " - STRING "\"C++\"" - WHITESPACE " " - EXTERN_ITEM_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rs deleted file mode 100644 index 6d27a082cb367..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rs +++ /dev/null @@ -1,18 +0,0 @@ -async fn foo() {} -extern fn foo() {} -const fn foo() {} -const unsafe fn foo() {} -unsafe extern "C" fn foo() {} -unsafe fn foo() {} -async unsafe fn foo() {} -const unsafe fn bar() {} - -unsafe trait T {} -auto trait T {} -unsafe auto trait T {} - -unsafe impl Foo {} -default impl Foo {} -unsafe default impl Foo {} - -unsafe extern "C++" {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0069_multi_trait_object.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0069_multi_trait_object.rast deleted file mode 100644 index 9e8f4e197408a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0069_multi_trait_object.rast +++ /dev/null @@ -1,204 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "Foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - EQ "=" - WHITESPACE " " - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PAREN_TYPE - L_PAREN "(" - DYN_TRAIT_TYPE - DYN_KW "dyn" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Send" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Sync" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "Foo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PTR_TYPE - STAR "*" - CONST_KW "const" - WHITESPACE " " - PAREN_TYPE - L_PAREN "(" - DYN_TRAIT_TYPE - DYN_KW "dyn" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Send" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Sync" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "Foo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FN_PTR_TYPE - FN_KW "fn" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PAREN_TYPE - L_PAREN "(" - DYN_TRAIT_TYPE - DYN_KW "dyn" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Send" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - LIFETIME - LIFETIME_IDENT "'static" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "main" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "b" - WHITESPACE " " - EQ "=" - WHITESPACE " " - CAST_EXPR - PAREN_EXPR - L_PAREN "(" - REF_EXPR - AMP "&" - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - R_PAREN ")" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - REF_TYPE - AMP "&" - PAREN_TYPE - L_PAREN "(" - DYN_TRAIT_TYPE - DYN_KW "dyn" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Add" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Other" - COMMA "," - WHITESPACE " " - ASSOC_TYPE_ARG - NAME_REF - IDENT "Output" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Addable" - R_ANGLE ">" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Other" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0069_multi_trait_object.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0069_multi_trait_object.rs deleted file mode 100644 index 97eb79c486f1d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0069_multi_trait_object.rs +++ /dev/null @@ -1,6 +0,0 @@ -type Foo<'a> = &'a (dyn Send + Sync); -type Foo = *const (dyn Send + Sync); -type Foo = fn() -> (dyn Send + 'static); -fn main() { - let b = (&a) as &(dyn Add + Other); -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0070_expr_attr_placement.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0070_expr_attr_placement.rast deleted file mode 100644 index 3d00b27ab8d3d..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0070_expr_attr_placement.rast +++ /dev/null @@ -1,59 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "f" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - PAREN_EXPR - L_PAREN "(" - BIN_EXPR - TRY_EXPR - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - R_BRACK "]" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "lhs" - QUESTION "?" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - AWAIT_EXPR - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "b" - R_BRACK "]" - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "rhs" - DOT "." - AWAIT_KW "await" - R_PAREN ")" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0070_expr_attr_placement.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0070_expr_attr_placement.rs deleted file mode 100644 index d8b7a3832a953..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0070_expr_attr_placement.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn f() { - (#[a] lhs? + #[b] rhs.await) -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0071_stmt_attr_placement.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0071_stmt_attr_placement.rast deleted file mode 100644 index 1cafc775cdf7a..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0071_stmt_attr_placement.rast +++ /dev/null @@ -1,72 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - EXPR_STMT - BLOCK_EXPR - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "A" - R_BRACK "]" - WHITESPACE " " - STMT_LIST - L_CURLY "{" - WHITESPACE " " - TRY_EXPR - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "B" - R_BRACK "]" - WHITESPACE " " - MACRO_EXPR - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "bar" - BANG "!" - TOKEN_TREE - L_PAREN "(" - R_PAREN ")" - QUESTION "?" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n " - REF_EXPR - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "C" - R_BRACK "]" - WHITESPACE " " - AMP "&" - TUPLE_EXPR - L_PAREN "(" - R_PAREN ")" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0071_stmt_attr_placement.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0071_stmt_attr_placement.rs deleted file mode 100644 index b4d5204bc0d43..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0071_stmt_attr_placement.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn foo() { - #[A] { #[B] bar!()? } - #[C] &() -} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rast deleted file mode 100644 index e8b836dfbd09e..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rast +++ /dev/null @@ -1,352 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_PAT - L_PAREN "(" - IDENT_PAT - MUT_KW "mut" - WHITESPACE " " - NAME - IDENT "a" - COMMA "," - WHITESPACE " " - IDENT_PAT - MUT_KW "mut" - WHITESPACE " " - NAME - IDENT "b" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - LITERAL - INT_NUMBER "0" - COMMA "," - WHITESPACE " " - LITERAL - INT_NUMBER "1" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - TUPLE_EXPR - L_PAREN "(" - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "b" - COMMA "," - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - COMMA "," - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - COMMA "," - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "b" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - PAREN_EXPR - L_PAREN "(" - UNDERSCORE_EXPR - UNDERSCORE "_" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - SEMICOLON ";" - WHITESPACE "\n " - STRUCT - STRUCT_KW "struct" - WHITESPACE " " - NAME - IDENT "S" - WHITESPACE " " - RECORD_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - RECORD_FIELD - NAME - IDENT "a" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - WHITESPACE " " - R_CURLY "}" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_EXPR_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - DOT2 ".." - WHITESPACE " " - R_CURLY "}" - WHITESPACE " " - EQ "=" - WHITESPACE " " - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_EXPR_FIELD_LIST - L_CURLY "{" - WHITESPACE " " - DOT2 ".." - CALL_EXPR - PATH_EXPR - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "default" - ARG_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - BIN_EXPR - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - ARG_LIST - L_PAREN "(" - RANGE_EXPR - DOT2 ".." - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - METHOD_CALL_EXPR - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - ARG_LIST - L_PAREN "(" - LITERAL - INT_NUMBER "0" - R_PAREN ")" - DOT "." - WHITESPACE "\n " - NAME_REF - IDENT "Ok" - ARG_LIST - L_PAREN "(" - UNDERSCORE_EXPR - UNDERSCORE "_" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "0" - SEMICOLON ";" - WHITESPACE "\n " - LET_STMT - LET_KW "let" - WHITESPACE " " - TUPLE_PAT - L_PAREN "(" - IDENT_PAT - NAME - IDENT "a" - COMMA "," - WHITESPACE " " - IDENT_PAT - NAME - IDENT "b" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - ARRAY_EXPR - L_BRACK "[" - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - COMMA "," - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - COMMA "," - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "b" - R_BRACK "]" - WHITESPACE " " - EQ "=" - WHITESPACE " " - ARRAY_EXPR - L_BRACK "[" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - RANGE_EXPR - DOT2 ".." - COMMA "," - WHITESPACE " " - LITERAL - INT_NUMBER "2" - R_BRACK "]" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - TUPLE_EXPR - L_PAREN "(" - UNDERSCORE_EXPR - UNDERSCORE "_" - COMMA "," - WHITESPACE " " - UNDERSCORE_EXPR - UNDERSCORE "_" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - COMMA "," - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "b" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - PAREN_EXPR - L_PAREN "(" - UNDERSCORE_EXPR - UNDERSCORE "_" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - COMMA "," - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "b" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - EXPR_STMT - BIN_EXPR - UNDERSCORE_EXPR - UNDERSCORE "_" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "a" - COMMA "," - WHITESPACE " " - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "b" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rs deleted file mode 100644 index 9d3e86603f881..0000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rs +++ /dev/null @@ -1,14 +0,0 @@ -fn foo() { - let (mut a, mut b) = (0, 1); - (b, a, ..) = (a, b); - (_) = ..; - struct S { a: i32 } - S { .. } = S { ..S::default() }; - Some(..) = Some(0). - Ok(_) = 0; - let (a, b); - [a, .., b] = [1, .., 2]; - (_, _) = (a, b); - (_) = (a, b); - _ = (a, b); -} diff --git a/src/tools/rust-analyzer/crates/paths/Cargo.toml b/src/tools/rust-analyzer/crates/paths/Cargo.toml deleted file mode 100644 index 5e83de7d994e0..0000000000000 --- a/src/tools/rust-analyzer/crates/paths/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "paths" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -# Adding this dep sadly puts a lot of rust-analyzer crates after the -# serde-derive crate. Even though we don't activate the derive feature here, -# someone else in the crate graph certainly does! -# serde = "1" diff --git a/src/tools/rust-analyzer/crates/paths/src/lib.rs b/src/tools/rust-analyzer/crates/paths/src/lib.rs deleted file mode 100644 index 025093f4a94ab..0000000000000 --- a/src/tools/rust-analyzer/crates/paths/src/lib.rs +++ /dev/null @@ -1,299 +0,0 @@ -//! Thin wrappers around `std::path`, distinguishing between absolute and -//! relative paths. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -use std::{ - borrow::Borrow, - ffi::OsStr, - ops, - path::{Component, Path, PathBuf}, -}; - -/// Wrapper around an absolute [`PathBuf`]. -#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct AbsPathBuf(PathBuf); - -impl From for PathBuf { - fn from(AbsPathBuf(path_buf): AbsPathBuf) -> PathBuf { - path_buf - } -} - -impl ops::Deref for AbsPathBuf { - type Target = AbsPath; - fn deref(&self) -> &AbsPath { - self.as_path() - } -} - -impl AsRef for AbsPathBuf { - fn as_ref(&self) -> &Path { - self.0.as_path() - } -} - -impl AsRef for AbsPathBuf { - fn as_ref(&self) -> &AbsPath { - self.as_path() - } -} - -impl Borrow for AbsPathBuf { - fn borrow(&self) -> &AbsPath { - self.as_path() - } -} - -impl TryFrom for AbsPathBuf { - type Error = PathBuf; - fn try_from(path_buf: PathBuf) -> Result { - if !path_buf.is_absolute() { - return Err(path_buf); - } - Ok(AbsPathBuf(path_buf)) - } -} - -impl TryFrom<&str> for AbsPathBuf { - type Error = PathBuf; - fn try_from(path: &str) -> Result { - AbsPathBuf::try_from(PathBuf::from(path)) - } -} - -impl PartialEq for AbsPathBuf { - fn eq(&self, other: &AbsPath) -> bool { - self.as_path() == other - } -} - -impl AbsPathBuf { - /// Wrap the given absolute path in `AbsPathBuf` - /// - /// # Panics - /// - /// Panics if `path` is not absolute. - pub fn assert(path: PathBuf) -> AbsPathBuf { - AbsPathBuf::try_from(path) - .unwrap_or_else(|path| panic!("expected absolute path, got {}", path.display())) - } - - /// Coerces to an `AbsPath` slice. - /// - /// Equivalent of [`PathBuf::as_path`] for `AbsPathBuf`. - pub fn as_path(&self) -> &AbsPath { - AbsPath::assert(self.0.as_path()) - } - - /// Equivalent of [`PathBuf::pop`] for `AbsPathBuf`. - /// - /// Note that this won't remove the root component, so `self` will still be - /// absolute. - pub fn pop(&mut self) -> bool { - self.0.pop() - } -} - -/// Wrapper around an absolute [`Path`]. -#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -#[repr(transparent)] -pub struct AbsPath(Path); - -impl AsRef for AbsPath { - fn as_ref(&self) -> &Path { - &self.0 - } -} - -impl<'a> TryFrom<&'a Path> for &'a AbsPath { - type Error = &'a Path; - fn try_from(path: &'a Path) -> Result<&'a AbsPath, &'a Path> { - if !path.is_absolute() { - return Err(path); - } - Ok(AbsPath::assert(path)) - } -} - -impl AbsPath { - /// Wrap the given absolute path in `AbsPath` - /// - /// # Panics - /// - /// Panics if `path` is not absolute. - pub fn assert(path: &Path) -> &AbsPath { - assert!(path.is_absolute()); - unsafe { &*(path as *const Path as *const AbsPath) } - } - - /// Equivalent of [`Path::parent`] for `AbsPath`. - pub fn parent(&self) -> Option<&AbsPath> { - self.0.parent().map(AbsPath::assert) - } - - /// Equivalent of [`Path::join`] for `AbsPath`. - pub fn join(&self, path: impl AsRef) -> AbsPathBuf { - self.as_ref().join(path).try_into().unwrap() - } - - /// Normalize the given path: - /// - Removes repeated separators: `/a//b` becomes `/a/b` - /// - Removes occurrences of `.` and resolves `..`. - /// - Removes trailing slashes: `/a/b/` becomes `/a/b`. - /// - /// # Example - /// ``` - /// # use paths::AbsPathBuf; - /// let abs_path_buf = AbsPathBuf::assert("/a/../../b/.//c//".into()); - /// let normalized = abs_path_buf.normalize(); - /// assert_eq!(normalized, AbsPathBuf::assert("/b/c".into())); - /// ``` - pub fn normalize(&self) -> AbsPathBuf { - AbsPathBuf(normalize_path(&self.0)) - } - - /// Equivalent of [`Path::to_path_buf`] for `AbsPath`. - pub fn to_path_buf(&self) -> AbsPathBuf { - AbsPathBuf::try_from(self.0.to_path_buf()).unwrap() - } - - /// Equivalent of [`Path::strip_prefix`] for `AbsPath`. - /// - /// Returns a relative path. - pub fn strip_prefix(&self, base: &AbsPath) -> Option<&RelPath> { - self.0.strip_prefix(base).ok().map(RelPath::new_unchecked) - } - pub fn starts_with(&self, base: &AbsPath) -> bool { - self.0.starts_with(&base.0) - } - pub fn ends_with(&self, suffix: &RelPath) -> bool { - self.0.ends_with(&suffix.0) - } - - // region:delegate-methods - - // Note that we deliberately don't implement `Deref` here. - // - // The problem with `Path` is that it directly exposes convenience IO-ing - // methods. For example, `Path::exists` delegates to `fs::metadata`. - // - // For `AbsPath`, we want to make sure that this is a POD type, and that all - // IO goes via `fs`. That way, it becomes easier to mock IO when we need it. - - pub fn file_name(&self) -> Option<&OsStr> { - self.0.file_name() - } - pub fn extension(&self) -> Option<&OsStr> { - self.0.extension() - } - pub fn file_stem(&self) -> Option<&OsStr> { - self.0.file_stem() - } - pub fn as_os_str(&self) -> &OsStr { - self.0.as_os_str() - } - pub fn display(&self) -> std::path::Display<'_> { - self.0.display() - } - #[deprecated(note = "use std::fs::metadata().is_ok() instead")] - pub fn exists(&self) -> bool { - self.0.exists() - } - // endregion:delegate-methods -} - -/// Wrapper around a relative [`PathBuf`]. -#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct RelPathBuf(PathBuf); - -impl From for PathBuf { - fn from(RelPathBuf(path_buf): RelPathBuf) -> PathBuf { - path_buf - } -} - -impl ops::Deref for RelPathBuf { - type Target = RelPath; - fn deref(&self) -> &RelPath { - self.as_path() - } -} - -impl AsRef for RelPathBuf { - fn as_ref(&self) -> &Path { - self.0.as_path() - } -} - -impl TryFrom for RelPathBuf { - type Error = PathBuf; - fn try_from(path_buf: PathBuf) -> Result { - if !path_buf.is_relative() { - return Err(path_buf); - } - Ok(RelPathBuf(path_buf)) - } -} - -impl TryFrom<&str> for RelPathBuf { - type Error = PathBuf; - fn try_from(path: &str) -> Result { - RelPathBuf::try_from(PathBuf::from(path)) - } -} - -impl RelPathBuf { - /// Coerces to a `RelPath` slice. - /// - /// Equivalent of [`PathBuf::as_path`] for `RelPathBuf`. - pub fn as_path(&self) -> &RelPath { - RelPath::new_unchecked(self.0.as_path()) - } -} - -/// Wrapper around a relative [`Path`]. -#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -#[repr(transparent)] -pub struct RelPath(Path); - -impl AsRef for RelPath { - fn as_ref(&self) -> &Path { - &self.0 - } -} - -impl RelPath { - /// Creates a new `RelPath` from `path`, without checking if it is relative. - pub fn new_unchecked(path: &Path) -> &RelPath { - unsafe { &*(path as *const Path as *const RelPath) } - } -} - -/// Taken from -fn normalize_path(path: &Path) -> PathBuf { - let mut components = path.components().peekable(); - let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().copied() { - components.next(); - PathBuf::from(c.as_os_str()) - } else { - PathBuf::new() - }; - - for component in components { - match component { - Component::Prefix(..) => unreachable!(), - Component::RootDir => { - ret.push(component.as_os_str()); - } - Component::CurDir => {} - Component::ParentDir => { - ret.pop(); - } - Component::Normal(c) => { - ret.push(c); - } - } - } - ret -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml deleted file mode 100644 index 85a1c13fe7d44..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "proc-macro-api" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -object = { version = "0.29.0", default-features = false, features = [ - "std", - "read_core", - "elf", - "macho", - "pe", -] } -serde = { version = "1.0.137", features = ["derive"] } -serde_json = { version = "1.0.81", features = ["unbounded_depth"] } -tracing = "0.1.35" -memmap2 = "0.5.4" -snap = "1.0.5" - -paths = { path = "../paths", version = "0.0.0" } -tt = { path = "../tt", version = "0.0.0" } -stdx = { path = "../stdx", version = "0.0.0" } -profile = { path = "../profile", version = "0.0.0" } -# Intentionally *not* depend on anything salsa-related -# base-db = { path = "../base-db", version = "0.0.0" } diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs deleted file mode 100644 index d7010e825aa9f..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs +++ /dev/null @@ -1,181 +0,0 @@ -//! Client-side Proc-Macro crate -//! -//! We separate proc-macro expanding logic to an extern program to allow -//! different implementations (e.g. wasm or dylib loading). And this crate -//! is used to provide basic infrastructure for communication between two -//! processes: Client (RA itself), Server (the external program) - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -pub mod msg; -mod process; -mod version; - -use paths::AbsPathBuf; -use std::{ - ffi::OsStr, - fmt, io, - sync::{Arc, Mutex}, -}; - -use serde::{Deserialize, Serialize}; -use tt::Subtree; - -use crate::{ - msg::{ExpandMacro, FlatTree, PanicMessage}, - process::ProcMacroProcessSrv, -}; - -pub use version::{read_dylib_info, read_version, RustCInfo}; - -#[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] -pub enum ProcMacroKind { - CustomDerive, - FuncLike, - Attr, -} - -/// A handle to an external process which load dylibs with macros (.so or .dll) -/// and runs actual macro expansion functions. -#[derive(Debug)] -pub struct ProcMacroServer { - /// Currently, the proc macro process expands all procedural macros sequentially. - /// - /// That means that concurrent salsa requests may block each other when expanding proc macros, - /// which is unfortunate, but simple and good enough for the time being. - /// - /// Therefore, we just wrap the `ProcMacroProcessSrv` in a mutex here. - process: Arc>, -} - -pub struct MacroDylib { - path: AbsPathBuf, -} - -impl MacroDylib { - // FIXME: this is buggy due to TOCTOU, we should check the version in the - // macro process instead. - pub fn new(path: AbsPathBuf) -> io::Result { - let _p = profile::span("MacroDylib::new"); - - let info = version::read_dylib_info(&path)?; - if info.version.0 < 1 || info.version.1 < 47 { - let msg = format!("proc-macro {} built by {:#?} is not supported by Rust Analyzer, please update your rust version.", path.display(), info); - return Err(io::Error::new(io::ErrorKind::InvalidData, msg)); - } - - Ok(MacroDylib { path }) - } -} - -/// A handle to a specific macro (a `#[proc_macro]` annotated function). -/// -/// It exists withing a context of a specific [`ProcMacroProcess`] -- currently -/// we share a single expander process for all macros. -#[derive(Debug, Clone)] -pub struct ProcMacro { - process: Arc>, - dylib_path: AbsPathBuf, - name: String, - kind: ProcMacroKind, -} - -impl Eq for ProcMacro {} -impl PartialEq for ProcMacro { - fn eq(&self, other: &Self) -> bool { - self.name == other.name - && self.kind == other.kind - && self.dylib_path == other.dylib_path - && Arc::ptr_eq(&self.process, &other.process) - } -} - -pub struct ServerError { - pub message: String, - pub io: Option, -} - -impl fmt::Display for ServerError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.message.fmt(f)?; - if let Some(io) = &self.io { - f.write_str(": ")?; - io.fmt(f)?; - } - Ok(()) - } -} - -pub struct MacroPanic { - pub message: String, -} - -impl ProcMacroServer { - /// Spawns an external process as the proc macro server and returns a client connected to it. - pub fn spawn( - process_path: AbsPathBuf, - args: impl IntoIterator>, - ) -> io::Result { - let process = ProcMacroProcessSrv::run(process_path, args)?; - Ok(ProcMacroServer { process: Arc::new(Mutex::new(process)) }) - } - - pub fn load_dylib(&self, dylib: MacroDylib) -> Result, ServerError> { - let _p = profile::span("ProcMacroClient::by_dylib_path"); - let macros = - self.process.lock().unwrap_or_else(|e| e.into_inner()).find_proc_macros(&dylib.path)?; - - match macros { - Ok(macros) => Ok(macros - .into_iter() - .map(|(name, kind)| ProcMacro { - process: self.process.clone(), - name, - kind, - dylib_path: dylib.path.clone(), - }) - .collect()), - Err(message) => Err(ServerError { message, io: None }), - } - } -} - -impl ProcMacro { - pub fn name(&self) -> &str { - &self.name - } - - pub fn kind(&self) -> ProcMacroKind { - self.kind - } - - pub fn expand( - &self, - subtree: &Subtree, - attr: Option<&Subtree>, - env: Vec<(String, String)>, - ) -> Result, ServerError> { - let current_dir = env - .iter() - .find(|(name, _)| name == "CARGO_MANIFEST_DIR") - .map(|(_, value)| value.clone()); - - let task = ExpandMacro { - macro_body: FlatTree::new(subtree), - macro_name: self.name.to_string(), - attributes: attr.map(FlatTree::new), - lib: self.dylib_path.to_path_buf().into(), - env, - current_dir, - }; - - let request = msg::Request::ExpandMacro(task); - let response = self.process.lock().unwrap_or_else(|e| e.into_inner()).send_task(request)?; - match response { - msg::Response::ExpandMacro(it) => Ok(it.map(FlatTree::to_subtree)), - msg::Response::ListMacros { .. } => { - Err(ServerError { message: "unexpected response".to_string(), io: None }) - } - } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs deleted file mode 100644 index f9c2b9fda3aee..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs +++ /dev/null @@ -1,154 +0,0 @@ -//! Defines messages for cross-process message passing based on `ndjson` wire protocol -pub(crate) mod flat; - -use std::{ - io::{self, BufRead, Write}, - path::PathBuf, -}; - -use serde::{de::DeserializeOwned, Deserialize, Serialize}; - -use crate::ProcMacroKind; - -pub use crate::msg::flat::FlatTree; - -#[derive(Debug, Serialize, Deserialize)] -pub enum Request { - ListMacros { dylib_path: PathBuf }, - ExpandMacro(ExpandMacro), -} - -#[derive(Debug, Serialize, Deserialize)] -pub enum Response { - ListMacros(Result, String>), - ExpandMacro(Result), -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct PanicMessage(pub String); - -#[derive(Debug, Serialize, Deserialize)] -pub struct ExpandMacro { - /// Argument of macro call. - /// - /// In custom derive this will be a struct or enum; in attribute-like macro - underlying - /// item; in function-like macro - the macro body. - pub macro_body: FlatTree, - - /// Name of macro to expand. - /// - /// In custom derive this is the name of the derived trait (`Serialize`, `Getters`, etc.). - /// In attribute-like and function-like macros - single name of macro itself (`show_streams`). - pub macro_name: String, - - /// Possible attributes for the attribute-like macros. - pub attributes: Option, - - pub lib: PathBuf, - - /// Environment variables to set during macro expansion. - pub env: Vec<(String, String)>, - - pub current_dir: Option, -} - -pub trait Message: Serialize + DeserializeOwned { - fn read(inp: &mut impl BufRead, buf: &mut String) -> io::Result> { - Ok(match read_json(inp, buf)? { - None => None, - Some(text) => { - let mut deserializer = serde_json::Deserializer::from_str(text); - // Note that some proc-macro generate very deep syntax tree - // We have to disable the current limit of serde here - deserializer.disable_recursion_limit(); - Some(Self::deserialize(&mut deserializer)?) - } - }) - } - fn write(self, out: &mut impl Write) -> io::Result<()> { - let text = serde_json::to_string(&self)?; - write_json(out, &text) - } -} - -impl Message for Request {} -impl Message for Response {} - -fn read_json<'a>(inp: &mut impl BufRead, buf: &'a mut String) -> io::Result> { - loop { - buf.clear(); - - inp.read_line(buf)?; - buf.pop(); // Remove trailing '\n' - - if buf.is_empty() { - return Ok(None); - } - - // Some ill behaved macro try to use stdout for debugging - // We ignore it here - if !buf.starts_with('{') { - tracing::error!("proc-macro tried to print : {}", buf); - continue; - } - - return Ok(Some(buf)); - } -} - -fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> { - tracing::debug!("> {}", msg); - out.write_all(msg.as_bytes())?; - out.write_all(b"\n")?; - out.flush()?; - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - use tt::*; - - fn fixture_token_tree() -> Subtree { - let mut subtree = Subtree::default(); - subtree - .token_trees - .push(TokenTree::Leaf(Ident { text: "struct".into(), id: TokenId(0) }.into())); - subtree - .token_trees - .push(TokenTree::Leaf(Ident { text: "Foo".into(), id: TokenId(1) }.into())); - subtree.token_trees.push(TokenTree::Leaf(Leaf::Literal(Literal { - text: "Foo".into(), - id: TokenId::unspecified(), - }))); - subtree.token_trees.push(TokenTree::Leaf(Leaf::Punct(Punct { - char: '@', - id: TokenId::unspecified(), - spacing: Spacing::Joint, - }))); - subtree.token_trees.push(TokenTree::Subtree(Subtree { - delimiter: Some(Delimiter { id: TokenId(2), kind: DelimiterKind::Brace }), - token_trees: vec![], - })); - subtree - } - - #[test] - fn test_proc_macro_rpc_works() { - let tt = fixture_token_tree(); - let task = ExpandMacro { - macro_body: FlatTree::new(&tt), - macro_name: Default::default(), - attributes: None, - lib: std::env::current_dir().unwrap(), - env: Default::default(), - current_dir: Default::default(), - }; - - let json = serde_json::to_string(&task).unwrap(); - // println!("{}", json); - let back: ExpandMacro = serde_json::from_str(&json).unwrap(); - - assert_eq!(tt, back.macro_body.to_subtree()); - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs deleted file mode 100644 index 8437444e183a0..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs +++ /dev/null @@ -1,328 +0,0 @@ -//! Serialization-friendly representation of `tt::Subtree`. -//! -//! It is possible to serialize `Subtree` as is, as a tree, but using -//! arbitrary-nested trees in JSON is problematic, as they can cause the JSON -//! parser to overflow the stack. -//! -//! Additionally, such implementation would be pretty verbose, and we do care -//! about performance here a bit. -//! -//! So what this module does is dumping a `tt::Subtree` into a bunch of flat -//! array of numbers. See the test in the parent module to get an example -//! output. -//! -//! ```json -//! { -//! // Array of subtrees, each subtree is represented by 4 numbers: -//! // id of delimiter, delimiter kind, index of first child in `token_tree`, -//! // index of last child in `token_tree` -//! "subtree":[4294967295,0,0,5,2,2,5,5], -//! // 2 ints per literal: [token id, index into `text`] -//! "literal":[4294967295,1], -//! // 3 ints per punct: [token id, char, spacing] -//! "punct":[4294967295,64,1], -//! // 2 ints per ident: [token id, index into `text`] -//! "ident": [0,0,1,1], -//! // children of all subtrees, concatenated. Each child is represented as `index << 2 | tag` -//! // where tag denotes one of subtree, literal, punct or ident. -//! "token_tree":[3,7,1,4], -//! // Strings shared by idents and literals -//! "text": ["struct","Foo"] -//! } -//! ``` -//! -//! We probably should replace most of the code here with bincode someday, but, -//! as we don't have bincode in Cargo.toml yet, lets stick with serde_json for -//! the time being. - -use std::{ - collections::{HashMap, VecDeque}, - convert::TryInto, -}; - -use serde::{Deserialize, Serialize}; -use tt::TokenId; - -#[derive(Serialize, Deserialize, Debug)] -pub struct FlatTree { - subtree: Vec, - literal: Vec, - punct: Vec, - ident: Vec, - token_tree: Vec, - text: Vec, -} - -struct SubtreeRepr { - id: tt::TokenId, - kind: Option, - tt: [u32; 2], -} - -struct LiteralRepr { - id: tt::TokenId, - text: u32, -} - -struct PunctRepr { - id: tt::TokenId, - char: char, - spacing: tt::Spacing, -} - -struct IdentRepr { - id: tt::TokenId, - text: u32, -} - -impl FlatTree { - pub fn new(subtree: &tt::Subtree) -> FlatTree { - let mut w = Writer { - string_table: HashMap::new(), - work: VecDeque::new(), - - subtree: Vec::new(), - literal: Vec::new(), - punct: Vec::new(), - ident: Vec::new(), - token_tree: Vec::new(), - text: Vec::new(), - }; - w.write(subtree); - - return FlatTree { - subtree: write_vec(w.subtree, SubtreeRepr::write), - literal: write_vec(w.literal, LiteralRepr::write), - punct: write_vec(w.punct, PunctRepr::write), - ident: write_vec(w.ident, IdentRepr::write), - token_tree: w.token_tree, - text: w.text, - }; - - fn write_vec [u32; N], const N: usize>(xs: Vec, f: F) -> Vec { - xs.into_iter().flat_map(f).collect() - } - } - - pub fn to_subtree(self) -> tt::Subtree { - return Reader { - subtree: read_vec(self.subtree, SubtreeRepr::read), - literal: read_vec(self.literal, LiteralRepr::read), - punct: read_vec(self.punct, PunctRepr::read), - ident: read_vec(self.ident, IdentRepr::read), - token_tree: self.token_tree, - text: self.text, - } - .read(); - - fn read_vec T, const N: usize>(xs: Vec, f: F) -> Vec { - let mut chunks = xs.chunks_exact(N); - let res = chunks.by_ref().map(|chunk| f(chunk.try_into().unwrap())).collect(); - assert!(chunks.remainder().is_empty()); - res - } - } -} - -impl SubtreeRepr { - fn write(self) -> [u32; 4] { - let kind = match self.kind { - None => 0, - Some(tt::DelimiterKind::Parenthesis) => 1, - Some(tt::DelimiterKind::Brace) => 2, - Some(tt::DelimiterKind::Bracket) => 3, - }; - [self.id.0, kind, self.tt[0], self.tt[1]] - } - fn read([id, kind, lo, len]: [u32; 4]) -> SubtreeRepr { - let kind = match kind { - 0 => None, - 1 => Some(tt::DelimiterKind::Parenthesis), - 2 => Some(tt::DelimiterKind::Brace), - 3 => Some(tt::DelimiterKind::Bracket), - other => panic!("bad kind {}", other), - }; - SubtreeRepr { id: TokenId(id), kind, tt: [lo, len] } - } -} - -impl LiteralRepr { - fn write(self) -> [u32; 2] { - [self.id.0, self.text] - } - fn read([id, text]: [u32; 2]) -> LiteralRepr { - LiteralRepr { id: TokenId(id), text } - } -} - -impl PunctRepr { - fn write(self) -> [u32; 3] { - let spacing = match self.spacing { - tt::Spacing::Alone => 0, - tt::Spacing::Joint => 1, - }; - [self.id.0, self.char as u32, spacing] - } - fn read([id, char, spacing]: [u32; 3]) -> PunctRepr { - let spacing = match spacing { - 0 => tt::Spacing::Alone, - 1 => tt::Spacing::Joint, - other => panic!("bad spacing {}", other), - }; - PunctRepr { id: TokenId(id), char: char.try_into().unwrap(), spacing } - } -} - -impl IdentRepr { - fn write(self) -> [u32; 2] { - [self.id.0, self.text] - } - fn read(data: [u32; 2]) -> IdentRepr { - IdentRepr { id: TokenId(data[0]), text: data[1] } - } -} - -struct Writer<'a> { - work: VecDeque<(usize, &'a tt::Subtree)>, - string_table: HashMap<&'a str, u32>, - - subtree: Vec, - literal: Vec, - punct: Vec, - ident: Vec, - token_tree: Vec, - text: Vec, -} - -impl<'a> Writer<'a> { - fn write(&mut self, root: &'a tt::Subtree) { - self.enqueue(root); - while let Some((idx, subtree)) = self.work.pop_front() { - self.subtree(idx, subtree); - } - } - - fn subtree(&mut self, idx: usize, subtree: &'a tt::Subtree) { - let mut first_tt = self.token_tree.len(); - let n_tt = subtree.token_trees.len(); - self.token_tree.resize(first_tt + n_tt, !0); - - self.subtree[idx].tt = [first_tt as u32, (first_tt + n_tt) as u32]; - - for child in &subtree.token_trees { - let idx_tag = match child { - tt::TokenTree::Subtree(it) => { - let idx = self.enqueue(it); - idx << 2 | 0b00 - } - tt::TokenTree::Leaf(leaf) => match leaf { - tt::Leaf::Literal(lit) => { - let idx = self.literal.len() as u32; - let text = self.intern(&lit.text); - self.literal.push(LiteralRepr { id: lit.id, text }); - idx << 2 | 0b01 - } - tt::Leaf::Punct(punct) => { - let idx = self.punct.len() as u32; - self.punct.push(PunctRepr { - char: punct.char, - spacing: punct.spacing, - id: punct.id, - }); - idx << 2 | 0b10 - } - tt::Leaf::Ident(ident) => { - let idx = self.ident.len() as u32; - let text = self.intern(&ident.text); - self.ident.push(IdentRepr { id: ident.id, text }); - idx << 2 | 0b11 - } - }, - }; - self.token_tree[first_tt] = idx_tag; - first_tt += 1; - } - } - - fn enqueue(&mut self, subtree: &'a tt::Subtree) -> u32 { - let idx = self.subtree.len(); - let delimiter_id = subtree.delimiter.map_or(TokenId::unspecified(), |it| it.id); - let delimiter_kind = subtree.delimiter.map(|it| it.kind); - self.subtree.push(SubtreeRepr { id: delimiter_id, kind: delimiter_kind, tt: [!0, !0] }); - self.work.push_back((idx, subtree)); - idx as u32 - } - - pub(crate) fn intern(&mut self, text: &'a str) -> u32 { - let table = &mut self.text; - *self.string_table.entry(text).or_insert_with(|| { - let idx = table.len(); - table.push(text.to_string()); - idx as u32 - }) - } -} - -struct Reader { - subtree: Vec, - literal: Vec, - punct: Vec, - ident: Vec, - token_tree: Vec, - text: Vec, -} - -impl Reader { - pub(crate) fn read(self) -> tt::Subtree { - let mut res: Vec> = vec![None; self.subtree.len()]; - for i in (0..self.subtree.len()).rev() { - let repr = &self.subtree[i]; - let token_trees = &self.token_tree[repr.tt[0] as usize..repr.tt[1] as usize]; - let s = tt::Subtree { - delimiter: repr.kind.map(|kind| tt::Delimiter { id: repr.id, kind }), - token_trees: token_trees - .iter() - .copied() - .map(|idx_tag| { - let tag = idx_tag & 0b11; - let idx = (idx_tag >> 2) as usize; - match tag { - // XXX: we iterate subtrees in reverse to guarantee - // that this unwrap doesn't fire. - 0b00 => res[idx].take().unwrap().into(), - 0b01 => { - let repr = &self.literal[idx]; - tt::Leaf::Literal(tt::Literal { - text: self.text[repr.text as usize].as_str().into(), - id: repr.id, - }) - .into() - } - 0b10 => { - let repr = &self.punct[idx]; - tt::Leaf::Punct(tt::Punct { - char: repr.char, - spacing: repr.spacing, - id: repr.id, - }) - .into() - } - 0b11 => { - let repr = &self.ident[idx]; - tt::Leaf::Ident(tt::Ident { - text: self.text[repr.text as usize].as_str().into(), - id: repr.id, - }) - .into() - } - other => panic!("bad tag: {}", other), - } - }) - .collect(), - }; - res[i] = Some(s); - } - - res[0].take().unwrap() - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs deleted file mode 100644 index c4018d3b39e77..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs +++ /dev/null @@ -1,107 +0,0 @@ -//! Handle process life-time and message passing for proc-macro client - -use std::{ - ffi::{OsStr, OsString}, - io::{self, BufRead, BufReader, Write}, - process::{Child, ChildStdin, ChildStdout, Command, Stdio}, -}; - -use paths::{AbsPath, AbsPathBuf}; -use stdx::JodChild; - -use crate::{ - msg::{Message, Request, Response}, - ProcMacroKind, ServerError, -}; - -#[derive(Debug)] -pub(crate) struct ProcMacroProcessSrv { - _process: Process, - stdin: ChildStdin, - stdout: BufReader, -} - -impl ProcMacroProcessSrv { - pub(crate) fn run( - process_path: AbsPathBuf, - args: impl IntoIterator>, - ) -> io::Result { - let mut process = Process::run(process_path, args)?; - let (stdin, stdout) = process.stdio().expect("couldn't access child stdio"); - - let srv = ProcMacroProcessSrv { _process: process, stdin, stdout }; - - Ok(srv) - } - - pub(crate) fn find_proc_macros( - &mut self, - dylib_path: &AbsPath, - ) -> Result, String>, ServerError> { - let request = Request::ListMacros { dylib_path: dylib_path.to_path_buf().into() }; - - let response = self.send_task(request)?; - - match response { - Response::ListMacros(it) => Ok(it), - Response::ExpandMacro { .. } => { - Err(ServerError { message: "unexpected response".to_string(), io: None }) - } - } - } - - pub(crate) fn send_task(&mut self, req: Request) -> Result { - let mut buf = String::new(); - send_request(&mut self.stdin, &mut self.stdout, req, &mut buf) - } -} - -#[derive(Debug)] -struct Process { - child: JodChild, -} - -impl Process { - fn run( - path: AbsPathBuf, - args: impl IntoIterator>, - ) -> io::Result { - let args: Vec = args.into_iter().map(|s| s.as_ref().into()).collect(); - let child = JodChild(mk_child(&path, &args)?); - Ok(Process { child }) - } - - fn stdio(&mut self) -> Option<(ChildStdin, BufReader)> { - let stdin = self.child.stdin.take()?; - let stdout = self.child.stdout.take()?; - let read = BufReader::new(stdout); - - Some((stdin, read)) - } -} - -fn mk_child( - path: &AbsPath, - args: impl IntoIterator>, -) -> io::Result { - Command::new(path.as_os_str()) - .args(args) - .env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::inherit()) - .spawn() -} - -fn send_request( - mut writer: &mut impl Write, - mut reader: &mut impl BufRead, - req: Request, - buf: &mut String, -) -> Result { - req.write(&mut writer) - .map_err(|err| ServerError { message: "failed to write request".into(), io: Some(err) })?; - let res = Response::read(&mut reader, buf) - .map_err(|err| ServerError { message: "failed to read response".into(), io: Some(err) })?; - res.ok_or_else(|| ServerError { message: "server exited".into(), io: None }) -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs deleted file mode 100644 index 030531b80d7bb..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs +++ /dev/null @@ -1,151 +0,0 @@ -//! Reading proc-macro rustc version information from binary data - -use std::{ - fs::File, - io::{self, Read}, -}; - -use memmap2::Mmap; -use object::read::{File as BinaryFile, Object, ObjectSection}; -use paths::AbsPath; -use snap::read::FrameDecoder as SnapDecoder; - -#[derive(Debug)] -pub struct RustCInfo { - pub version: (usize, usize, usize), - pub channel: String, - pub commit: Option, - pub date: Option, - // something like "rustc 1.58.1 (db9d1b20b 2022-01-20)" - pub version_string: String, -} - -/// Read rustc dylib information -pub fn read_dylib_info(dylib_path: &AbsPath) -> io::Result { - macro_rules! err { - ($e:literal) => { - io::Error::new(io::ErrorKind::InvalidData, $e) - }; - } - - let ver_str = read_version(dylib_path)?; - let mut items = ver_str.split_whitespace(); - let tag = items.next().ok_or_else(|| err!("version format error"))?; - if tag != "rustc" { - return Err(err!("version format error (No rustc tag)")); - } - - let version_part = items.next().ok_or_else(|| err!("no version string"))?; - let mut version_parts = version_part.split('-'); - let version = version_parts.next().ok_or_else(|| err!("no version"))?; - let channel = version_parts.next().unwrap_or_default().to_string(); - - let commit = match items.next() { - Some(commit) => { - match commit.len() { - 0 => None, - _ => Some(commit[1..].to_string() /* remove ( */), - } - } - None => None, - }; - let date = match items.next() { - Some(date) => { - match date.len() { - 0 => None, - _ => Some(date[0..date.len() - 2].to_string() /* remove ) */), - } - } - None => None, - }; - - let version_numbers = version - .split('.') - .map(|it| it.parse::()) - .collect::, _>>() - .map_err(|_| err!("version number error"))?; - - if version_numbers.len() != 3 { - return Err(err!("version number format error")); - } - let version = (version_numbers[0], version_numbers[1], version_numbers[2]); - - Ok(RustCInfo { version, channel, commit, date, version_string: ver_str }) -} - -/// This is used inside read_version() to locate the ".rustc" section -/// from a proc macro crate's binary file. -fn read_section<'a>(dylib_binary: &'a [u8], section_name: &str) -> io::Result<&'a [u8]> { - BinaryFile::parse(dylib_binary) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))? - .section_by_name(section_name) - .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "section read error"))? - .data() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) -} - -/// Check the version of rustc that was used to compile a proc macro crate's -/// -/// binary file. -/// A proc macro crate binary's ".rustc" section has following byte layout: -/// * [b'r',b'u',b's',b't',0,0,0,5] is the first 8 bytes -/// * ff060000 734e6150 is followed, it's the snappy format magic bytes, -/// means bytes from here(including this sequence) are compressed in -/// snappy compression format. Version info is inside here, so decompress -/// this. -/// The bytes you get after decompressing the snappy format portion has -/// following layout: -/// * [b'r',b'u',b's',b't',0,0,0,5] is the first 8 bytes(again) -/// * [crate root bytes] next 4 bytes is to store crate root position, -/// according to rustc's source code comment -/// * [length byte] next 1 byte tells us how many bytes we should read next -/// for the version string's utf8 bytes -/// * [version string bytes encoded in utf8] <- GET THIS BOI -/// * [some more bytes that we don't really care but about still there] :-) -/// Check this issue for more about the bytes layout: -/// -pub fn read_version(dylib_path: &AbsPath) -> io::Result { - let dylib_file = File::open(dylib_path)?; - let dylib_mmaped = unsafe { Mmap::map(&dylib_file) }?; - - let dot_rustc = read_section(&dylib_mmaped, ".rustc")?; - - // check if magic is valid - if &dot_rustc[0..4] != b"rust" { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - format!("unknown metadata magic, expected `rust`, found `{:?}`", &dot_rustc[0..4]), - )); - } - let version = u32::from_be_bytes([dot_rustc[4], dot_rustc[5], dot_rustc[6], dot_rustc[7]]); - // Last supported version is: - // https://github.com/rust-lang/rust/commit/0696e79f2740ad89309269b460579e548a5cd632 - match version { - 5 | 6 => {} - _ => { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - format!("unsupported metadata version {}", version), - )); - } - } - - let snappy_portion = &dot_rustc[8..]; - - let mut snappy_decoder = SnapDecoder::new(snappy_portion); - - // the bytes before version string bytes, so this basically is: - // 8 bytes for [b'r',b'u',b's',b't',0,0,0,5] - // 4 bytes for [crate root bytes] - // 1 byte for length of version string - // so 13 bytes in total, and we should check the 13th byte - // to know the length - let mut bytes_before_version = [0u8; 13]; - snappy_decoder.read_exact(&mut bytes_before_version)?; - let length = bytes_before_version[12]; - - let mut version_string_utf8 = vec![0u8; length as usize]; - snappy_decoder.read_exact(&mut version_string_utf8)?; - let version_string = String::from_utf8(version_string_utf8); - version_string.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml deleted file mode 100644 index 9d0da5dee9c10..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "proc-macro-srv-cli" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[dependencies] -proc-macro-srv = { version = "0.0.0", path = "../proc-macro-srv" } - -[features] -sysroot-abi = ["proc-macro-srv/sysroot-abi"] - -[[bin]] -name = "rust-analyzer-proc-macro-srv" -path = "src/main.rs" diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs deleted file mode 100644 index ac9fa9f5a4ce5..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! A standalone binary for `proc-macro-srv`. - -use proc_macro_srv::cli; - -fn main() -> std::io::Result<()> { - let v = std::env::var("RUST_ANALYZER_INTERNALS_DO_NOT_USE"); - match v.as_deref() { - Ok("this is unstable") => { - // very well, if you must - } - _ => { - eprintln!("If you're rust-analyzer, you can use this tool by exporting RUST_ANALYZER_INTERNALS_DO_NOT_USE='this is unstable'."); - eprintln!("If not, you probably shouldn't use this tool. But do what you want: I'm an error message, not a cop."); - std::process::exit(122); - } - } - - cli::run() -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml deleted file mode 100644 index 5746eac0b3790..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -name = "proc-macro-srv" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -object = { version = "0.29.0", default-features = false, features = [ - "std", - "read_core", - "elf", - "macho", - "pe", -] } -libloading = "0.7.3" -memmap2 = "0.5.4" - -tt = { path = "../tt", version = "0.0.0" } -mbe = { path = "../mbe", version = "0.0.0" } -paths = { path = "../paths", version = "0.0.0" } -proc-macro-api = { path = "../proc-macro-api", version = "0.0.0" } -crossbeam = "0.8.1" - -[dev-dependencies] -expect-test = "1.4.0" - -# used as proc macro test targets -proc-macro-test = { path = "../proc-macro-test" } - -[features] -sysroot-abi = [] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/build.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/build.rs deleted file mode 100644 index a8c732f31541d..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/build.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Determine rustc version `proc-macro-srv` (and thus the sysroot ABI) is -//! build with and make it accessible at runtime for ABI selection. - -use std::{env, fs::File, io::Write, path::PathBuf, process::Command}; - -fn main() { - let mut path = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - path.push("rustc_version.rs"); - let mut f = File::create(&path).unwrap(); - - let rustc = env::var("RUSTC").expect("proc-macro-srv's build script expects RUSTC to be set"); - let output = Command::new(rustc).arg("--version").output().expect("rustc --version must run"); - let version_string = std::str::from_utf8(&output.stdout[..]) - .expect("rustc --version output must be UTF-8") - .trim(); - - write!( - f, - " - #[allow(dead_code)] - pub(crate) const RUSTC_VERSION_STRING: &str = {version_string:?}; - " - ) - .unwrap(); -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/mod.rs deleted file mode 100644 index 1c91ac0fa1b8f..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/mod.rs +++ /dev/null @@ -1,104 +0,0 @@ -//! Macro ABI for version 1.58 of rustc - -#[allow(dead_code)] -#[doc(hidden)] -mod proc_macro; - -#[allow(dead_code)] -#[doc(hidden)] -mod ra_server; - -use libloading::Library; -use proc_macro_api::ProcMacroKind; - -use super::PanicMessage; - -pub(crate) struct Abi { - exported_macros: Vec, -} - -impl From for PanicMessage { - fn from(p: proc_macro::bridge::PanicMessage) -> Self { - Self { message: p.as_str().map(|s| s.to_string()) } - } -} - -impl Abi { - pub unsafe fn from_lib(lib: &Library, symbol_name: String) -> Result { - let macros: libloading::Symbol<'_, &&[proc_macro::bridge::client::ProcMacro]> = - lib.get(symbol_name.as_bytes())?; - Ok(Self { exported_macros: macros.to_vec() }) - } - - pub fn expand( - &self, - macro_name: &str, - macro_body: &tt::Subtree, - attributes: Option<&tt::Subtree>, - ) -> Result { - let parsed_body = ra_server::TokenStream::with_subtree(macro_body.clone()); - - let parsed_attributes = attributes.map_or(ra_server::TokenStream::new(), |attr| { - ra_server::TokenStream::with_subtree(attr.clone()) - }); - - for proc_macro in &self.exported_macros { - match proc_macro { - proc_macro::bridge::client::ProcMacro::CustomDerive { - trait_name, client, .. - } if *trait_name == macro_name => { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - proc_macro::bridge::client::ProcMacro::Bang { name, client } - if *name == macro_name => - { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - proc_macro::bridge::client::ProcMacro::Attr { name, client } - if *name == macro_name => - { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_attributes, - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - _ => continue, - } - } - - Err(proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()).into()) - } - - pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { - self.exported_macros - .iter() - .map(|proc_macro| match proc_macro { - proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { - (trait_name.to_string(), ProcMacroKind::CustomDerive) - } - proc_macro::bridge::client::ProcMacro::Bang { name, .. } => { - (name.to_string(), ProcMacroKind::FuncLike) - } - proc_macro::bridge::client::ProcMacro::Attr { name, .. } => { - (name.to_string(), ProcMacroKind::Attr) - } - }) - .collect() - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/buffer.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/buffer.rs deleted file mode 100644 index d82669d3e2336..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/buffer.rs +++ /dev/null @@ -1,143 +0,0 @@ -//! Buffer management for same-process client<->server communication. - -use std::io::{self, Write}; -use std::mem; -use std::ops::{Deref, DerefMut}; -use std::slice; - -#[repr(C)] -pub struct Buffer { - data: *mut T, - len: usize, - capacity: usize, - reserve: extern "C" fn(Buffer, usize) -> Buffer, - drop: extern "C" fn(Buffer), -} - -unsafe impl Sync for Buffer {} -unsafe impl Send for Buffer {} - -impl Default for Buffer { - fn default() -> Self { - Self::from(vec![]) - } -} - -impl Deref for Buffer { - type Target = [T]; - fn deref(&self) -> &[T] { - unsafe { slice::from_raw_parts(self.data as *const T, self.len) } - } -} - -impl DerefMut for Buffer { - fn deref_mut(&mut self) -> &mut [T] { - unsafe { slice::from_raw_parts_mut(self.data, self.len) } - } -} - -impl Buffer { - pub(super) fn new() -> Self { - Self::default() - } - - pub(super) fn clear(&mut self) { - self.len = 0; - } - - pub(super) fn take(&mut self) -> Self { - mem::take(self) - } - - // We have the array method separate from extending from a slice. This is - // because in the case of small arrays, codegen can be more efficient - // (avoiding a memmove call). With extend_from_slice, LLVM at least - // currently is not able to make that optimization. - pub(super) fn extend_from_array(&mut self, xs: &[T; N]) { - if xs.len() > (self.capacity - self.len) { - let b = self.take(); - *self = (b.reserve)(b, xs.len()); - } - unsafe { - xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len()); - self.len += xs.len(); - } - } - - pub(super) fn extend_from_slice(&mut self, xs: &[T]) { - if xs.len() > (self.capacity - self.len) { - let b = self.take(); - *self = (b.reserve)(b, xs.len()); - } - unsafe { - xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len()); - self.len += xs.len(); - } - } - - pub(super) fn push(&mut self, v: T) { - // The code here is taken from Vec::push, and we know that reserve() - // will panic if we're exceeding isize::MAX bytes and so there's no need - // to check for overflow. - if self.len == self.capacity { - let b = self.take(); - *self = (b.reserve)(b, 1); - } - unsafe { - *self.data.add(self.len) = v; - self.len += 1; - } - } -} - -impl Write for Buffer { - fn write(&mut self, xs: &[u8]) -> io::Result { - self.extend_from_slice(xs); - Ok(xs.len()) - } - - fn write_all(&mut self, xs: &[u8]) -> io::Result<()> { - self.extend_from_slice(xs); - Ok(()) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Drop for Buffer { - fn drop(&mut self) { - let b = self.take(); - (b.drop)(b); - } -} - -impl From> for Buffer { - fn from(mut v: Vec) -> Self { - let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity()); - mem::forget(v); - - // This utility function is nested in here because it can *only* - // be safely called on `Buffer`s created by *this* `proc_macro`. - fn to_vec(b: Buffer) -> Vec { - unsafe { - let Buffer { data, len, capacity, .. } = b; - mem::forget(b); - Vec::from_raw_parts(data, len, capacity) - } - } - - extern "C" fn reserve(b: Buffer, additional: usize) -> Buffer { - let mut v = to_vec(b); - v.reserve(additional); - Buffer::from(v) - } - - extern "C" fn drop(b: Buffer) { - mem::drop(to_vec(b)); - } - - Buffer { data, len, capacity, reserve, drop } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/client.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/client.rs deleted file mode 100644 index ed0e91da36178..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/client.rs +++ /dev/null @@ -1,485 +0,0 @@ -//! Client-side types. - -use super::*; - -macro_rules! define_handles { - ( - 'owned: $($oty:ident,)* - 'interned: $($ity:ident,)* - ) => { - #[repr(C)] - #[allow(non_snake_case)] - pub struct HandleCounters { - $($oty: AtomicUsize,)* - $($ity: AtomicUsize,)* - } - - impl HandleCounters { - // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of - // a wrapper `fn` pointer, once `const fn` can reference `static`s. - extern "C" fn get() -> &'static Self { - static COUNTERS: HandleCounters = HandleCounters { - $($oty: AtomicUsize::new(1),)* - $($ity: AtomicUsize::new(1),)* - }; - &COUNTERS - } - } - - // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. - #[repr(C)] - #[allow(non_snake_case)] - pub(super) struct HandleStore { - $($oty: handle::OwnedStore,)* - $($ity: handle::InternedStore,)* - } - - impl HandleStore { - pub(super) fn new(handle_counters: &'static HandleCounters) -> Self { - HandleStore { - $($oty: handle::OwnedStore::new(&handle_counters.$oty),)* - $($ity: handle::InternedStore::new(&handle_counters.$ity),)* - } - } - } - - $( - #[repr(C)] - pub(crate) struct $oty(handle::Handle); - - // Forward `Drop::drop` to the inherent `drop` method. - impl Drop for $oty { - fn drop(&mut self) { - $oty(self.0).drop(); - } - } - - impl Encode for $oty { - fn encode(self, w: &mut Writer, s: &mut S) { - let handle = self.0; - mem::forget(self); - handle.encode(w, s); - } - } - - impl DecodeMut<'_, '_, HandleStore>> - for Marked - { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { - s.$oty.take(handle::Handle::decode(r, &mut ())) - } - } - - impl Encode for &$oty { - fn encode(self, w: &mut Writer, s: &mut S) { - self.0.encode(w, s); - } - } - - impl<'s, S: server::Types> Decode<'_, 's, HandleStore>> - for &'s Marked - { - fn decode(r: &mut Reader<'_>, s: &'s HandleStore>) -> Self { - &s.$oty[handle::Handle::decode(r, &mut ())] - } - } - - impl Encode for &mut $oty { - fn encode(self, w: &mut Writer, s: &mut S) { - self.0.encode(w, s); - } - } - - impl<'s, S: server::Types> DecodeMut<'_, 's, HandleStore>> - for &'s mut Marked - { - fn decode( - r: &mut Reader<'_>, - s: &'s mut HandleStore> - ) -> Self { - &mut s.$oty[handle::Handle::decode(r, &mut ())] - } - } - - impl Encode>> - for Marked - { - fn encode(self, w: &mut Writer, s: &mut HandleStore>) { - s.$oty.alloc(self).encode(w, s); - } - } - - impl DecodeMut<'_, '_, S> for $oty { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - $oty(handle::Handle::decode(r, s)) - } - } - )* - - $( - #[repr(C)] - #[derive(Copy, Clone, PartialEq, Eq, Hash)] - pub(crate) struct $ity(handle::Handle); - - impl Encode for $ity { - fn encode(self, w: &mut Writer, s: &mut S) { - self.0.encode(w, s); - } - } - - impl DecodeMut<'_, '_, HandleStore>> - for Marked - { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { - s.$ity.copy(handle::Handle::decode(r, &mut ())) - } - } - - impl Encode>> - for Marked - { - fn encode(self, w: &mut Writer, s: &mut HandleStore>) { - s.$ity.alloc(self).encode(w, s); - } - } - - impl DecodeMut<'_, '_, S> for $ity { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - $ity(handle::Handle::decode(r, s)) - } - } - )* - } -} -define_handles! { - 'owned: - FreeFunctions, - TokenStream, - TokenStreamBuilder, - TokenStreamIter, - Group, - Literal, - SourceFile, - MultiSpan, - Diagnostic, - - 'interned: - Punct, - Ident, - Span, -} - -// FIXME(eddyb) generate these impls by pattern-matching on the -// names of methods - also could use the presence of `fn drop` -// to distinguish between 'owned and 'interned, above. -// Alternatively, special 'modes" could be listed of types in with_api -// instead of pattern matching on methods, here and in server decl. - -impl Clone for TokenStream { - fn clone(&self) -> Self { - self.clone() - } -} - -impl Clone for TokenStreamIter { - fn clone(&self) -> Self { - self.clone() - } -} - -impl Clone for Group { - fn clone(&self) -> Self { - self.clone() - } -} - -impl Clone for Literal { - fn clone(&self) -> Self { - self.clone() - } -} - -impl fmt::Debug for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Literal") - // format the kind without quotes, as in `kind: Float` - .field("kind", &format_args!("{}", &self.debug_kind())) - .field("symbol", &self.symbol()) - // format `Some("...")` on one line even in {:#?} mode - .field("suffix", &format_args!("{:?}", &self.suffix())) - .field("span", &self.span()) - .finish() - } -} - -impl Clone for SourceFile { - fn clone(&self) -> Self { - self.clone() - } -} - -impl fmt::Debug for Span { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.debug()) - } -} - -macro_rules! define_client_side { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }),* $(,)?) => { - $(impl $name { - $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* { - Bridge::with(|bridge| { - let mut b = bridge.cached_buffer.take(); - - b.clear(); - api_tags::Method::$name(api_tags::$name::$method).encode(&mut b, &mut ()); - reverse_encode!(b; $($arg),*); - - b = bridge.dispatch.call(b); - - let r = Result::<_, PanicMessage>::decode(&mut &b[..], &mut ()); - - bridge.cached_buffer = b; - - r.unwrap_or_else(|e| panic::resume_unwind(e.into())) - }) - })* - })* - } -} -with_api!(self, self, define_client_side); - -enum BridgeState<'a> { - /// No server is currently connected to this client. - NotConnected, - - /// A server is connected and available for requests. - Connected(Bridge<'a>), - - /// Access to the bridge is being exclusively acquired - /// (e.g., during `BridgeState::with`). - InUse, -} - -enum BridgeStateL {} - -impl<'a> scoped_cell::ApplyL<'a> for BridgeStateL { - type Out = BridgeState<'a>; -} - -thread_local! { - static BRIDGE_STATE: scoped_cell::ScopedCell = - scoped_cell::ScopedCell::new(BridgeState::NotConnected); -} - -impl BridgeState<'_> { - /// Take exclusive control of the thread-local - /// `BridgeState`, and pass it to `f`, mutably. - /// The state will be restored after `f` exits, even - /// by panic, including modifications made to it by `f`. - /// - /// N.B., while `f` is running, the thread-local state - /// is `BridgeState::InUse`. - fn with(f: impl FnOnce(&mut BridgeState<'_>) -> R) -> R { - BRIDGE_STATE.with(|state| { - state.replace(BridgeState::InUse, |mut state| { - // FIXME(#52812) pass `f` directly to `replace` when `RefMutL` is gone - f(&mut *state) - }) - }) - } -} - -impl Bridge<'_> { - pub(crate) fn is_available() -> bool { - BridgeState::with(|state| match state { - BridgeState::Connected(_) | BridgeState::InUse => true, - BridgeState::NotConnected => false, - }) - } - - fn enter(self, f: impl FnOnce() -> R) -> R { - let force_show_panics = self.force_show_panics; - // Hide the default panic output within `proc_macro` expansions. - // NB. the server can't do this because it may use a different libstd. - static HIDE_PANICS_DURING_EXPANSION: Once = Once::new(); - HIDE_PANICS_DURING_EXPANSION.call_once(|| { - let prev = panic::take_hook(); - panic::set_hook(Box::new(move |info| { - let show = BridgeState::with(|state| match state { - BridgeState::NotConnected => true, - BridgeState::Connected(_) | BridgeState::InUse => force_show_panics, - }); - if show { - prev(info) - } - })); - }); - - BRIDGE_STATE.with(|state| state.set(BridgeState::Connected(self), f)) - } - - fn with(f: impl FnOnce(&mut Bridge<'_>) -> R) -> R { - BridgeState::with(|state| match state { - BridgeState::NotConnected => { - panic!("procedural macro API is used outside of a procedural macro"); - } - BridgeState::InUse => { - panic!("procedural macro API is used while it's already in use"); - } - BridgeState::Connected(bridge) => f(bridge), - }) - } -} - -/// A client-side "global object" (usually a function pointer), -/// which may be using a different `proc_macro` from the one -/// used by the server, but can be interacted with compatibly. -/// -/// N.B., `F` must have FFI-friendly memory layout (e.g., a pointer). -/// The call ABI of function pointers used for `F` doesn't -/// need to match between server and client, since it's only -/// passed between them and (eventually) called by the client. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct Client { - // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of - // a wrapper `fn` pointer, once `const fn` can reference `static`s. - pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters, - pub(super) run: extern "C" fn(Bridge<'_>, F) -> Buffer, - pub(super) f: F, -} - -/// Client-side helper for handling client panics, entering the bridge, -/// deserializing input and serializing output. -// FIXME(eddyb) maybe replace `Bridge::enter` with this? -fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( - mut bridge: Bridge<'_>, - f: impl FnOnce(A) -> R, -) -> Buffer { - // The initial `cached_buffer` contains the input. - let mut b = bridge.cached_buffer.take(); - - panic::catch_unwind(panic::AssertUnwindSafe(|| { - bridge.enter(|| { - let reader = &mut &b[..]; - let input = A::decode(reader, &mut ()); - - // Put the `cached_buffer` back in the `Bridge`, for requests. - Bridge::with(|bridge| bridge.cached_buffer = b.take()); - - let output = f(input); - - // Take the `cached_buffer` back out, for the output value. - b = Bridge::with(|bridge| bridge.cached_buffer.take()); - - // HACK(eddyb) Separate encoding a success value (`Ok(output)`) - // from encoding a panic (`Err(e: PanicMessage)`) to avoid - // having handles outside the `bridge.enter(|| ...)` scope, and - // to catch panics that could happen while encoding the success. - // - // Note that panics should be impossible beyond this point, but - // this is defensively trying to avoid any accidental panicking - // reaching the `extern "C"` (which should `abort` but might not - // at the moment, so this is also potentially preventing UB). - b.clear(); - Ok::<_, ()>(output).encode(&mut b, &mut ()); - }) - })) - .map_err(PanicMessage::from) - .unwrap_or_else(|e| { - b.clear(); - Err::<(), _>(e).encode(&mut b, &mut ()); - }); - b -} - -impl Client super::super::TokenStream> { - pub fn expand1(f: fn(super::super::TokenStream) -> super::super::TokenStream) -> Self { - extern "C" fn run( - bridge: Bridge<'_>, - f: impl FnOnce(super::super::TokenStream) -> super::super::TokenStream, - ) -> Buffer { - run_client(bridge, |input| f(super::super::TokenStream(input)).0) - } - Client { get_handle_counters: HandleCounters::get, run, f } - } -} - -impl Client super::super::TokenStream> { - pub fn expand2( - f: fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream, - ) -> Self { - extern "C" fn run( - bridge: Bridge<'_>, - f: impl FnOnce( - super::super::TokenStream, - super::super::TokenStream, - ) -> super::super::TokenStream, - ) -> Buffer { - run_client(bridge, |(input, input2)| { - f(super::super::TokenStream(input), super::super::TokenStream(input2)).0 - }) - } - Client { get_handle_counters: HandleCounters::get, run, f } - } -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum ProcMacro { - CustomDerive { - trait_name: &'static str, - attributes: &'static [&'static str], - client: Client super::super::TokenStream>, - }, - - Attr { - name: &'static str, - client: Client< - fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream, - >, - }, - - Bang { - name: &'static str, - client: Client super::super::TokenStream>, - }, -} - -impl ProcMacro { - pub fn name(&self) -> &'static str { - match self { - ProcMacro::CustomDerive { trait_name, .. } => trait_name, - ProcMacro::Attr { name, .. } => name, - ProcMacro::Bang { name, .. } => name, - } - } - - pub fn custom_derive( - trait_name: &'static str, - attributes: &'static [&'static str], - expand: fn(super::super::TokenStream) -> super::super::TokenStream, - ) -> Self { - ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) } - } - - pub fn attr( - name: &'static str, - expand: fn( - super::super::TokenStream, - super::super::TokenStream, - ) -> super::super::TokenStream, - ) -> Self { - ProcMacro::Attr { name, client: Client::expand2(expand) } - } - - pub fn bang( - name: &'static str, - expand: fn(super::super::TokenStream) -> super::super::TokenStream, - ) -> Self { - ProcMacro::Bang { name, client: Client::expand1(expand) } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/closure.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/closure.rs deleted file mode 100644 index 5be71cc3d7013..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/closure.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! Closure type (equivalent to `&mut dyn FnMut(A) -> R`) that's `repr(C)`. - -#[repr(C)] -pub struct Closure<'a, A, R> { - call: unsafe extern "C" fn(&mut Env, A) -> R, - env: &'a mut Env, -} - -struct Env; - -impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> { - fn from(f: &'a mut F) -> Self { - unsafe extern "C" fn call R>(env: &mut Env, arg: A) -> R { - (*(env as *mut _ as *mut F))(arg) - } - Closure { call: call::, env: unsafe { &mut *(f as *mut _ as *mut Env) } } - } -} - -impl<'a, A, R> Closure<'a, A, R> { - pub fn call(&mut self, arg: A) -> R { - unsafe { (self.call)(self.env, arg) } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/handle.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/handle.rs deleted file mode 100644 index bcbb86812470a..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/handle.rs +++ /dev/null @@ -1,70 +0,0 @@ -//! Server-side handles and storage for per-handle data. - -use std::collections::{BTreeMap, HashMap}; -use std::hash::Hash; -use std::num::NonZeroU32; -use std::ops::{Index, IndexMut}; -use std::sync::atomic::{AtomicUsize, Ordering}; - -pub(super) type Handle = NonZeroU32; - -pub(super) struct OwnedStore { - counter: &'static AtomicUsize, - data: BTreeMap, -} - -impl OwnedStore { - pub(super) fn new(counter: &'static AtomicUsize) -> Self { - // Ensure the handle counter isn't 0, which would panic later, - // when `NonZeroU32::new` (aka `Handle::new`) is called in `alloc`. - assert_ne!(counter.load(Ordering::SeqCst), 0); - - OwnedStore { counter, data: BTreeMap::new() } - } -} - -impl OwnedStore { - pub(super) fn alloc(&mut self, x: T) -> Handle { - let counter = self.counter.fetch_add(1, Ordering::SeqCst); - let handle = Handle::new(counter as u32).expect("`proc_macro` handle counter overflowed"); - assert!(self.data.insert(handle, x).is_none()); - handle - } - - pub(super) fn take(&mut self, h: Handle) -> T { - self.data.remove(&h).expect("use-after-free in `proc_macro` handle") - } -} - -impl Index for OwnedStore { - type Output = T; - fn index(&self, h: Handle) -> &T { - self.data.get(&h).expect("use-after-free in `proc_macro` handle") - } -} - -impl IndexMut for OwnedStore { - fn index_mut(&mut self, h: Handle) -> &mut T { - self.data.get_mut(&h).expect("use-after-free in `proc_macro` handle") - } -} - -pub(super) struct InternedStore { - owned: OwnedStore, - interner: HashMap, -} - -impl InternedStore { - pub(super) fn new(counter: &'static AtomicUsize) -> Self { - InternedStore { owned: OwnedStore::new(counter), interner: HashMap::new() } - } - - pub(super) fn alloc(&mut self, x: T) -> Handle { - let owned = &mut self.owned; - *self.interner.entry(x).or_insert_with(|| owned.alloc(x)) - } - - pub(super) fn copy(&mut self, h: Handle) -> T { - self.owned[h] - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/mod.rs deleted file mode 100644 index b7968c529c30f..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/mod.rs +++ /dev/null @@ -1,429 +0,0 @@ -//! Internal interface for communicating between a `proc_macro` client -//! (a proc macro crate) and a `proc_macro` server (a compiler front-end). -//! -//! Serialization (with C ABI buffers) and unique integer handles are employed -//! to allow safely interfacing between two copies of `proc_macro` built -//! (from the same source) by different compilers with potentially mismatching -//! Rust ABIs (e.g., stage0/bin/rustc vs stage1/bin/rustc during bootstrap). - -#![deny(unsafe_code)] - -pub use super::{Delimiter, Level, LineColumn, Spacing}; -use std::fmt; -use std::hash::Hash; -use std::marker; -use std::mem; -use std::ops::Bound; -use std::panic; -use std::sync::atomic::AtomicUsize; -use std::sync::Once; -use std::thread; - -/// Higher-order macro describing the server RPC API, allowing automatic -/// generation of type-safe Rust APIs, both client-side and server-side. -/// -/// `with_api!(MySelf, my_self, my_macro)` expands to: -/// ```rust,ignore (pseudo-code) -/// my_macro! { -/// // ... -/// Literal { -/// // ... -/// fn character(ch: char) -> MySelf::Literal; -/// // ... -/// fn span(my_self: &MySelf::Literal) -> MySelf::Span; -/// fn set_span(my_self: &mut MySelf::Literal, span: MySelf::Span); -/// }, -/// // ... -/// } -/// ``` -/// -/// The first two arguments serve to customize the arguments names -/// and argument/return types, to enable several different usecases: -/// -/// If `my_self` is just `self`, then each `fn` signature can be used -/// as-is for a method. If it's anything else (`self_` in practice), -/// then the signatures don't have a special `self` argument, and -/// can, therefore, have a different one introduced. -/// -/// If `MySelf` is just `Self`, then the types are only valid inside -/// a trait or a trait impl, where the trait has associated types -/// for each of the API types. If non-associated types are desired, -/// a module name (`self` in practice) can be used instead of `Self`. -macro_rules! with_api { - ($S:ident, $self:ident, $m:ident) => { - $m! { - FreeFunctions { - fn drop($self: $S::FreeFunctions); - fn track_env_var(var: &str, value: Option<&str>); - fn track_path(path: &str); - }, - TokenStream { - fn drop($self: $S::TokenStream); - fn clone($self: &$S::TokenStream) -> $S::TokenStream; - fn new() -> $S::TokenStream; - fn is_empty($self: &$S::TokenStream) -> bool; - fn expand_expr($self: &$S::TokenStream) -> Result<$S::TokenStream, ()>; - fn from_str(src: &str) -> $S::TokenStream; - fn to_string($self: &$S::TokenStream) -> String; - fn from_token_tree( - tree: TokenTree<$S::Group, $S::Punct, $S::Ident, $S::Literal>, - ) -> $S::TokenStream; - fn into_iter($self: $S::TokenStream) -> $S::TokenStreamIter; - }, - TokenStreamBuilder { - fn drop($self: $S::TokenStreamBuilder); - fn new() -> $S::TokenStreamBuilder; - fn push($self: &mut $S::TokenStreamBuilder, stream: $S::TokenStream); - fn build($self: $S::TokenStreamBuilder) -> $S::TokenStream; - }, - TokenStreamIter { - fn drop($self: $S::TokenStreamIter); - fn clone($self: &$S::TokenStreamIter) -> $S::TokenStreamIter; - fn next( - $self: &mut $S::TokenStreamIter, - ) -> Option>; - }, - Group { - fn drop($self: $S::Group); - fn clone($self: &$S::Group) -> $S::Group; - fn new(delimiter: Delimiter, stream: $S::TokenStream) -> $S::Group; - fn delimiter($self: &$S::Group) -> Delimiter; - fn stream($self: &$S::Group) -> $S::TokenStream; - fn span($self: &$S::Group) -> $S::Span; - fn span_open($self: &$S::Group) -> $S::Span; - fn span_close($self: &$S::Group) -> $S::Span; - fn set_span($self: &mut $S::Group, span: $S::Span); - }, - Punct { - fn new(ch: char, spacing: Spacing) -> $S::Punct; - fn as_char($self: $S::Punct) -> char; - fn spacing($self: $S::Punct) -> Spacing; - fn span($self: $S::Punct) -> $S::Span; - fn with_span($self: $S::Punct, span: $S::Span) -> $S::Punct; - }, - Ident { - fn new(string: &str, span: $S::Span, is_raw: bool) -> $S::Ident; - fn span($self: $S::Ident) -> $S::Span; - fn with_span($self: $S::Ident, span: $S::Span) -> $S::Ident; - }, - Literal { - fn drop($self: $S::Literal); - fn clone($self: &$S::Literal) -> $S::Literal; - fn from_str(s: &str) -> Result<$S::Literal, ()>; - fn to_string($self: &$S::Literal) -> String; - fn debug_kind($self: &$S::Literal) -> String; - fn symbol($self: &$S::Literal) -> String; - fn suffix($self: &$S::Literal) -> Option; - fn integer(n: &str) -> $S::Literal; - fn typed_integer(n: &str, kind: &str) -> $S::Literal; - fn float(n: &str) -> $S::Literal; - fn f32(n: &str) -> $S::Literal; - fn f64(n: &str) -> $S::Literal; - fn string(string: &str) -> $S::Literal; - fn character(ch: char) -> $S::Literal; - fn byte_string(bytes: &[u8]) -> $S::Literal; - fn span($self: &$S::Literal) -> $S::Span; - fn set_span($self: &mut $S::Literal, span: $S::Span); - fn subspan( - $self: &$S::Literal, - start: Bound, - end: Bound, - ) -> Option<$S::Span>; - }, - SourceFile { - fn drop($self: $S::SourceFile); - fn clone($self: &$S::SourceFile) -> $S::SourceFile; - fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool; - fn path($self: &$S::SourceFile) -> String; - fn is_real($self: &$S::SourceFile) -> bool; - }, - MultiSpan { - fn drop($self: $S::MultiSpan); - fn new() -> $S::MultiSpan; - fn push($self: &mut $S::MultiSpan, span: $S::Span); - }, - Diagnostic { - fn drop($self: $S::Diagnostic); - fn new(level: Level, msg: &str, span: $S::MultiSpan) -> $S::Diagnostic; - fn sub( - $self: &mut $S::Diagnostic, - level: Level, - msg: &str, - span: $S::MultiSpan, - ); - fn emit($self: $S::Diagnostic); - }, - Span { - fn debug($self: $S::Span) -> String; - fn def_site() -> $S::Span; - fn call_site() -> $S::Span; - fn mixed_site() -> $S::Span; - fn source_file($self: $S::Span) -> $S::SourceFile; - fn parent($self: $S::Span) -> Option<$S::Span>; - fn source($self: $S::Span) -> $S::Span; - fn start($self: $S::Span) -> LineColumn; - fn end($self: $S::Span) -> LineColumn; - fn before($self: $S::Span) -> $S::Span; - fn after($self: $S::Span) -> $S::Span; - fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; - fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span; - fn source_text($self: $S::Span) -> Option; - fn save_span($self: $S::Span) -> usize; - fn recover_proc_macro_span(id: usize) -> $S::Span; - }, - } - }; -} - -// FIXME(eddyb) this calls `encode` for each argument, but in reverse, -// to avoid borrow conflicts from borrows started by `&mut` arguments. -macro_rules! reverse_encode { - ($writer:ident;) => {}; - ($writer:ident; $first:ident $(, $rest:ident)*) => { - reverse_encode!($writer; $($rest),*); - $first.encode(&mut $writer, &mut ()); - } -} - -// FIXME(eddyb) this calls `decode` for each argument, but in reverse, -// to avoid borrow conflicts from borrows started by `&mut` arguments. -macro_rules! reverse_decode { - ($reader:ident, $s:ident;) => {}; - ($reader:ident, $s:ident; $first:ident: $first_ty:ty $(, $rest:ident: $rest_ty:ty)*) => { - reverse_decode!($reader, $s; $($rest: $rest_ty),*); - let $first = <$first_ty>::decode(&mut $reader, $s); - } -} - -#[allow(unsafe_code)] -mod buffer; -#[forbid(unsafe_code)] -pub mod client; -#[allow(unsafe_code)] -mod closure; -#[forbid(unsafe_code)] -mod handle; -#[macro_use] -#[forbid(unsafe_code)] -mod rpc; -#[allow(unsafe_code)] -mod scoped_cell; -#[forbid(unsafe_code)] -pub mod server; - -use buffer::Buffer; -pub use rpc::PanicMessage; -use rpc::{Decode, DecodeMut, Encode, Reader, Writer}; - -/// An active connection between a server and a client. -/// The server creates the bridge (`Bridge::run_server` in `server.rs`), -/// then passes it to the client through the function pointer in the `run` -/// field of `client::Client`. The client holds its copy of the `Bridge` -/// in TLS during its execution (`Bridge::{enter, with}` in `client.rs`). -#[repr(C)] -pub struct Bridge<'a> { - /// Reusable buffer (only `clear`-ed, never shrunk), primarily - /// used for making requests, but also for passing input to client. - cached_buffer: Buffer, - - /// Server-side function that the client uses to make requests. - dispatch: closure::Closure<'a, Buffer, Buffer>, - - /// If 'true', always invoke the default panic hook - force_show_panics: bool, -} - -#[forbid(unsafe_code)] -#[allow(non_camel_case_types)] -mod api_tags { - use super::rpc::{DecodeMut, Encode, Reader, Writer}; - - macro_rules! declare_tags { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }),* $(,)?) => { - $( - pub(super) enum $name { - $($method),* - } - rpc_encode_decode!(enum $name { $($method),* }); - )* - - - pub(super) enum Method { - $($name($name)),* - } - rpc_encode_decode!(enum Method { $($name(m)),* }); - } - } - with_api!(self, self, declare_tags); -} - -/// Helper to wrap associated types to allow trait impl dispatch. -/// That is, normally a pair of impls for `T::Foo` and `T::Bar` -/// can overlap, but if the impls are, instead, on types like -/// `Marked` and `Marked`, they can't. -trait Mark { - type Unmarked; - fn mark(unmarked: Self::Unmarked) -> Self; -} - -/// Unwrap types wrapped by `Mark::mark` (see `Mark` for details). -trait Unmark { - type Unmarked; - fn unmark(self) -> Self::Unmarked; -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -struct Marked { - value: T, - _marker: marker::PhantomData, -} - -impl Mark for Marked { - type Unmarked = T; - fn mark(unmarked: Self::Unmarked) -> Self { - Marked { value: unmarked, _marker: marker::PhantomData } - } -} -impl Unmark for Marked { - type Unmarked = T; - fn unmark(self) -> Self::Unmarked { - self.value - } -} -impl<'a, T, M> Unmark for &'a Marked { - type Unmarked = &'a T; - fn unmark(self) -> Self::Unmarked { - &self.value - } -} -impl<'a, T, M> Unmark for &'a mut Marked { - type Unmarked = &'a mut T; - fn unmark(self) -> Self::Unmarked { - &mut self.value - } -} - -impl Mark for Option { - type Unmarked = Option; - fn mark(unmarked: Self::Unmarked) -> Self { - unmarked.map(T::mark) - } -} -impl Unmark for Option { - type Unmarked = Option; - fn unmark(self) -> Self::Unmarked { - self.map(T::unmark) - } -} - -impl Mark for Result { - type Unmarked = Result; - fn mark(unmarked: Self::Unmarked) -> Self { - unmarked.map(T::mark).map_err(E::mark) - } -} -impl Unmark for Result { - type Unmarked = Result; - fn unmark(self) -> Self::Unmarked { - self.map(T::unmark).map_err(E::unmark) - } -} - -macro_rules! mark_noop { - ($($ty:ty),* $(,)?) => { - $( - impl Mark for $ty { - type Unmarked = Self; - fn mark(unmarked: Self::Unmarked) -> Self { - unmarked - } - } - impl Unmark for $ty { - type Unmarked = Self; - fn unmark(self) -> Self::Unmarked { - self - } - } - )* - } -} -mark_noop! { - (), - bool, - char, - &'_ [u8], - &'_ str, - String, - usize, - Delimiter, - Level, - LineColumn, - Spacing, - Bound, -} - -rpc_encode_decode!( - enum Delimiter { - Parenthesis, - Brace, - Bracket, - None, - } -); -rpc_encode_decode!( - enum Level { - Error, - Warning, - Note, - Help, - } -); -rpc_encode_decode!(struct LineColumn { line, column }); -rpc_encode_decode!( - enum Spacing { - Alone, - Joint, - } -); - -#[derive(Clone)] -pub enum TokenTree { - Group(G), - Punct(P), - Ident(I), - Literal(L), -} - -impl Mark for TokenTree { - type Unmarked = TokenTree; - fn mark(unmarked: Self::Unmarked) -> Self { - match unmarked { - TokenTree::Group(tt) => TokenTree::Group(G::mark(tt)), - TokenTree::Punct(tt) => TokenTree::Punct(P::mark(tt)), - TokenTree::Ident(tt) => TokenTree::Ident(I::mark(tt)), - TokenTree::Literal(tt) => TokenTree::Literal(L::mark(tt)), - } - } -} -impl Unmark for TokenTree { - type Unmarked = TokenTree; - fn unmark(self) -> Self::Unmarked { - match self { - TokenTree::Group(tt) => TokenTree::Group(tt.unmark()), - TokenTree::Punct(tt) => TokenTree::Punct(tt.unmark()), - TokenTree::Ident(tt) => TokenTree::Ident(tt.unmark()), - TokenTree::Literal(tt) => TokenTree::Literal(tt.unmark()), - } - } -} - -rpc_encode_decode!( - enum TokenTree { - Group(tt), - Punct(tt), - Ident(tt), - Literal(tt), - } -); diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/rpc.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/rpc.rs deleted file mode 100644 index d50564d01a5d2..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/rpc.rs +++ /dev/null @@ -1,305 +0,0 @@ -//! Serialization for client-server communication. - -use std::any::Any; -use std::char; -use std::io::Write; -use std::num::NonZeroU32; -use std::ops::Bound; -use std::str; - -pub(super) type Writer = super::buffer::Buffer; - -pub(super) trait Encode: Sized { - fn encode(self, w: &mut Writer, s: &mut S); -} - -pub(super) type Reader<'a> = &'a [u8]; - -pub(super) trait Decode<'a, 's, S>: Sized { - fn decode(r: &mut Reader<'a>, s: &'s S) -> Self; -} - -pub(super) trait DecodeMut<'a, 's, S>: Sized { - fn decode(r: &mut Reader<'a>, s: &'s mut S) -> Self; -} - -macro_rules! rpc_encode_decode { - (le $ty:ty) => { - impl Encode for $ty { - fn encode(self, w: &mut Writer, _: &mut S) { - w.extend_from_array(&self.to_le_bytes()); - } - } - - impl DecodeMut<'_, '_, S> for $ty { - fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { - const N: usize = ::std::mem::size_of::<$ty>(); - - let mut bytes = [0; N]; - bytes.copy_from_slice(&r[..N]); - *r = &r[N..]; - - Self::from_le_bytes(bytes) - } - } - }; - (struct $name:ident { $($field:ident),* $(,)? }) => { - impl Encode for $name { - fn encode(self, w: &mut Writer, s: &mut S) { - $(self.$field.encode(w, s);)* - } - } - - impl DecodeMut<'_, '_, S> for $name { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - $name { - $($field: DecodeMut::decode(r, s)),* - } - } - } - }; - (enum $name:ident $(<$($T:ident),+>)? { $($variant:ident $(($field:ident))*),* $(,)? }) => { - impl),+)?> Encode for $name $(<$($T),+>)? { - fn encode(self, w: &mut Writer, s: &mut S) { - // HACK(eddyb): `Tag` enum duplicated between the - // two impls as there's no other place to stash it. - #[allow(non_upper_case_globals)] - mod tag { - #[repr(u8)] enum Tag { $($variant),* } - - $(pub const $variant: u8 = Tag::$variant as u8;)* - } - - match self { - $($name::$variant $(($field))* => { - tag::$variant.encode(w, s); - $($field.encode(w, s);)* - })* - } - } - } - - impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S> - for $name $(<$($T),+>)? - { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - // HACK(eddyb): `Tag` enum duplicated between the - // two impls as there's no other place to stash it. - #[allow(non_upper_case_globals)] - mod tag { - #[repr(u8)] enum Tag { $($variant),* } - - $(pub const $variant: u8 = Tag::$variant as u8;)* - } - - match u8::decode(r, s) { - $(tag::$variant => { - $(let $field = DecodeMut::decode(r, s);)* - $name::$variant $(($field))* - })* - _ => unreachable!(), - } - } - } - } -} - -impl Encode for () { - fn encode(self, _: &mut Writer, _: &mut S) {} -} - -impl DecodeMut<'_, '_, S> for () { - fn decode(_: &mut Reader<'_>, _: &mut S) -> Self {} -} - -impl Encode for u8 { - fn encode(self, w: &mut Writer, _: &mut S) { - w.push(self); - } -} - -impl DecodeMut<'_, '_, S> for u8 { - fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { - let x = r[0]; - *r = &r[1..]; - x - } -} - -rpc_encode_decode!(le u32); -rpc_encode_decode!(le usize); - -impl Encode for bool { - fn encode(self, w: &mut Writer, s: &mut S) { - (self as u8).encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for bool { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - match u8::decode(r, s) { - 0 => false, - 1 => true, - _ => unreachable!(), - } - } -} - -impl Encode for char { - fn encode(self, w: &mut Writer, s: &mut S) { - (self as u32).encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for char { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - char::from_u32(u32::decode(r, s)).unwrap() - } -} - -impl Encode for NonZeroU32 { - fn encode(self, w: &mut Writer, s: &mut S) { - self.get().encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for NonZeroU32 { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - Self::new(u32::decode(r, s)).unwrap() - } -} - -impl, B: Encode> Encode for (A, B) { - fn encode(self, w: &mut Writer, s: &mut S) { - self.0.encode(w, s); - self.1.encode(w, s); - } -} - -impl<'a, S, A: for<'s> DecodeMut<'a, 's, S>, B: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S> - for (A, B) -{ - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - (DecodeMut::decode(r, s), DecodeMut::decode(r, s)) - } -} - -rpc_encode_decode!( - enum Bound { - Included(x), - Excluded(x), - Unbounded, - } -); - -rpc_encode_decode!( - enum Option { - None, - Some(x), - } -); - -rpc_encode_decode!( - enum Result { - Ok(x), - Err(e), - } -); - -impl Encode for &[u8] { - fn encode(self, w: &mut Writer, s: &mut S) { - self.len().encode(w, s); - w.write_all(self).unwrap(); - } -} - -impl<'a, S> DecodeMut<'a, '_, S> for &'a [u8] { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - let len = usize::decode(r, s); - let xs = &r[..len]; - *r = &r[len..]; - xs - } -} - -impl Encode for &str { - fn encode(self, w: &mut Writer, s: &mut S) { - self.as_bytes().encode(w, s); - } -} - -impl<'a, S> DecodeMut<'a, '_, S> for &'a str { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - str::from_utf8(<&[u8]>::decode(r, s)).unwrap() - } -} - -impl Encode for String { - fn encode(self, w: &mut Writer, s: &mut S) { - self[..].encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for String { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - <&str>::decode(r, s).to_string() - } -} - -/// Simplified version of panic payloads, ignoring -/// types other than `&'static str` and `String`. -pub enum PanicMessage { - StaticStr(&'static str), - String(String), - Unknown, -} - -impl From> for PanicMessage { - fn from(payload: Box) -> Self { - if let Some(s) = payload.downcast_ref::<&'static str>() { - return PanicMessage::StaticStr(s); - } - if let Ok(s) = payload.downcast::() { - return PanicMessage::String(*s); - } - PanicMessage::Unknown - } -} - -impl Into> for PanicMessage { - fn into(self) -> Box { - match self { - PanicMessage::StaticStr(s) => Box::new(s), - PanicMessage::String(s) => Box::new(s), - PanicMessage::Unknown => { - struct UnknownPanicMessage; - Box::new(UnknownPanicMessage) - } - } - } -} - -impl PanicMessage { - pub fn as_str(&self) -> Option<&str> { - match self { - PanicMessage::StaticStr(s) => Some(s), - PanicMessage::String(s) => Some(s), - PanicMessage::Unknown => None, - } - } -} - -impl Encode for PanicMessage { - fn encode(self, w: &mut Writer, s: &mut S) { - self.as_str().encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for PanicMessage { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - match Option::::decode(r, s) { - Some(s) => PanicMessage::String(s), - None => PanicMessage::Unknown, - } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/scoped_cell.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/scoped_cell.rs deleted file mode 100644 index b0c2e5b9c26b1..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/scoped_cell.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! `Cell` variant for (scoped) existential lifetimes. - -use std::cell::Cell; -use std::mem; -use std::ops::{Deref, DerefMut}; - -/// Type lambda application, with a lifetime. -#[allow(unused_lifetimes)] -pub trait ApplyL<'a> { - type Out; -} - -/// Type lambda taking a lifetime, i.e., `Lifetime -> Type`. -pub trait LambdaL: for<'a> ApplyL<'a> {} - -impl ApplyL<'a>> LambdaL for T {} - -// HACK(eddyb) work around projection limitations with a newtype -// FIXME(#52812) replace with `&'a mut >::Out` -pub struct RefMutL<'a, 'b, T: LambdaL>(&'a mut >::Out); - -impl<'a, 'b, T: LambdaL> Deref for RefMutL<'a, 'b, T> { - type Target = >::Out; - fn deref(&self) -> &Self::Target { - self.0 - } -} - -impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.0 - } -} - -pub struct ScopedCell(Cell<>::Out>); - -impl ScopedCell { - pub fn new(value: >::Out) -> Self { - ScopedCell(Cell::new(value)) - } - - /// Sets the value in `self` to `replacement` while - /// running `f`, which gets the old value, mutably. - /// The old value will be restored after `f` exits, even - /// by panic, including modifications made to it by `f`. - pub fn replace<'a, R>( - &self, - replacement: >::Out, - f: impl for<'b, 'c> FnOnce(RefMutL<'b, 'c, T>) -> R, - ) -> R { - /// Wrapper that ensures that the cell always gets filled - /// (with the original state, optionally changed by `f`), - /// even if `f` had panicked. - struct PutBackOnDrop<'a, T: LambdaL> { - cell: &'a ScopedCell, - value: Option<>::Out>, - } - - impl<'a, T: LambdaL> Drop for PutBackOnDrop<'a, T> { - fn drop(&mut self) { - self.cell.0.set(self.value.take().unwrap()); - } - } - - let mut put_back_on_drop = PutBackOnDrop { - cell: self, - value: Some(self.0.replace(unsafe { - let erased = mem::transmute_copy(&replacement); - mem::forget(replacement); - erased - })), - }; - - f(RefMutL(put_back_on_drop.value.as_mut().unwrap())) - } - - /// Sets the value in `self` to `value` while running `f`. - pub fn set(&self, value: >::Out, f: impl FnOnce() -> R) -> R { - self.replace(value, |_| f()) - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/server.rs deleted file mode 100644 index 06a19791351a4..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/server.rs +++ /dev/null @@ -1,352 +0,0 @@ -//! Server-side traits. - -use super::*; - -// FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. -use super::client::HandleStore; - -/// Declare an associated item of one of the traits below, optionally -/// adjusting it (i.e., adding bounds to types and default bodies to methods). -macro_rules! associated_item { - (type FreeFunctions) => - (type FreeFunctions: 'static;); - (type TokenStream) => - (type TokenStream: 'static + Clone;); - (type TokenStreamBuilder) => - (type TokenStreamBuilder: 'static;); - (type TokenStreamIter) => - (type TokenStreamIter: 'static + Clone;); - (type Group) => - (type Group: 'static + Clone;); - (type Punct) => - (type Punct: 'static + Copy + Eq + Hash;); - (type Ident) => - (type Ident: 'static + Copy + Eq + Hash;); - (type Literal) => - (type Literal: 'static + Clone;); - (type SourceFile) => - (type SourceFile: 'static + Clone;); - (type MultiSpan) => - (type MultiSpan: 'static;); - (type Diagnostic) => - (type Diagnostic: 'static;); - (type Span) => - (type Span: 'static + Copy + Eq + Hash;); - (fn drop(&mut self, $arg:ident: $arg_ty:ty)) => - (fn drop(&mut self, $arg: $arg_ty) { mem::drop($arg) }); - (fn clone(&mut self, $arg:ident: $arg_ty:ty) -> $ret_ty:ty) => - (fn clone(&mut self, $arg: $arg_ty) -> $ret_ty { $arg.clone() }); - ($($item:tt)*) => ($($item)*;) -} - -macro_rules! declare_server_traits { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - pub trait Types { - $(associated_item!(type $name);)* - } - - $(pub trait $name: Types { - $(associated_item!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* - })* - - pub trait Server: Types $(+ $name)* {} - impl Server for S {} - } -} -with_api!(Self, self_, declare_server_traits); - -pub(super) struct MarkedTypes(S); - -macro_rules! define_mark_types_impls { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - impl Types for MarkedTypes { - $(type $name = Marked;)* - } - - $(impl $name for MarkedTypes { - $(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)? { - <_>::mark($name::$method(&mut self.0, $($arg.unmark()),*)) - })* - })* - } -} -with_api!(Self, self_, define_mark_types_impls); - -struct Dispatcher { - handle_store: HandleStore, - server: S, -} - -macro_rules! define_dispatcher_impl { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - // FIXME(eddyb) `pub` only for `ExecutionStrategy` below. - pub trait DispatcherTrait { - // HACK(eddyb) these are here to allow `Self::$name` to work below. - $(type $name;)* - fn dispatch(&mut self, b: Buffer) -> Buffer; - } - - impl DispatcherTrait for Dispatcher> { - $(type $name = as Types>::$name;)* - fn dispatch(&mut self, mut b: Buffer) -> Buffer { - let Dispatcher { handle_store, server } = self; - - let mut reader = &b[..]; - match api_tags::Method::decode(&mut reader, &mut ()) { - $(api_tags::Method::$name(m) => match m { - $(api_tags::$name::$method => { - let mut call_method = || { - reverse_decode!(reader, handle_store; $($arg: $arg_ty),*); - $name::$method(server, $($arg),*) - }; - // HACK(eddyb) don't use `panic::catch_unwind` in a panic. - // If client and server happen to use the same `libstd`, - // `catch_unwind` asserts that the panic counter was 0, - // even when the closure passed to it didn't panic. - let r = if thread::panicking() { - Ok(call_method()) - } else { - panic::catch_unwind(panic::AssertUnwindSafe(call_method)) - .map_err(PanicMessage::from) - }; - - b.clear(); - r.encode(&mut b, handle_store); - })* - }),* - } - b - } - } - } -} -with_api!(Self, self_, define_dispatcher_impl); - -pub trait ExecutionStrategy { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, - client_data: D, - force_show_panics: bool, - ) -> Buffer; -} - -pub struct SameThread; - -impl ExecutionStrategy for SameThread { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, - client_data: D, - force_show_panics: bool, - ) -> Buffer { - let mut dispatch = |b| dispatcher.dispatch(b); - - run_client( - Bridge { cached_buffer: input, dispatch: (&mut dispatch).into(), force_show_panics }, - client_data, - ) - } -} - -// NOTE(eddyb) Two implementations are provided, the second one is a bit -// faster but neither is anywhere near as fast as same-thread execution. - -pub struct CrossThread1; - -impl ExecutionStrategy for CrossThread1 { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, - client_data: D, - force_show_panics: bool, - ) -> Buffer { - use std::sync::mpsc::channel; - - let (req_tx, req_rx) = channel(); - let (res_tx, res_rx) = channel(); - - let join_handle = thread::spawn(move || { - let mut dispatch = |b| { - req_tx.send(b).unwrap(); - res_rx.recv().unwrap() - }; - - run_client( - Bridge { - cached_buffer: input, - dispatch: (&mut dispatch).into(), - force_show_panics, - }, - client_data, - ) - }); - - for b in req_rx { - res_tx.send(dispatcher.dispatch(b)).unwrap(); - } - - join_handle.join().unwrap() - } -} - -pub struct CrossThread2; - -impl ExecutionStrategy for CrossThread2 { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, - client_data: D, - force_show_panics: bool, - ) -> Buffer { - use std::sync::{Arc, Mutex}; - - enum State { - Req(T), - Res(T), - } - - let mut state = Arc::new(Mutex::new(State::Res(Buffer::new()))); - - let server_thread = thread::current(); - let state2 = state.clone(); - let join_handle = thread::spawn(move || { - let mut dispatch = |b| { - *state2.lock().unwrap() = State::Req(b); - server_thread.unpark(); - loop { - thread::park(); - if let State::Res(b) = &mut *state2.lock().unwrap() { - break b.take(); - } - } - }; - - let r = run_client( - Bridge { - cached_buffer: input, - dispatch: (&mut dispatch).into(), - force_show_panics, - }, - client_data, - ); - - // Wake up the server so it can exit the dispatch loop. - drop(state2); - server_thread.unpark(); - - r - }); - - // Check whether `state2` was dropped, to know when to stop. - while Arc::get_mut(&mut state).is_none() { - thread::park(); - let mut b = match &mut *state.lock().unwrap() { - State::Req(b) => b.take(), - _ => continue, - }; - b = dispatcher.dispatch(b.take()); - *state.lock().unwrap() = State::Res(b); - join_handle.thread().unpark(); - } - - join_handle.join().unwrap() - } -} - -fn run_server< - S: Server, - I: Encode>>, - O: for<'a, 's> DecodeMut<'a, 's, HandleStore>>, - D: Copy + Send + 'static, ->( - strategy: &impl ExecutionStrategy, - handle_counters: &'static client::HandleCounters, - server: S, - input: I, - run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, - client_data: D, - force_show_panics: bool, -) -> Result { - let mut dispatcher = - Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) }; - - let mut b = Buffer::new(); - input.encode(&mut b, &mut dispatcher.handle_store); - - b = strategy.run_bridge_and_client( - &mut dispatcher, - b, - run_client, - client_data, - force_show_panics, - ); - - Result::decode(&mut &b[..], &mut dispatcher.handle_store) -} - -impl client::Client super::super::TokenStream> { - pub fn run( - &self, - strategy: &impl ExecutionStrategy, - server: S, - input: S::TokenStream, - force_show_panics: bool, - ) -> Result { - let client::Client { get_handle_counters, run, f } = *self; - run_server( - strategy, - get_handle_counters(), - server, - as Types>::TokenStream::mark(input), - run, - f, - force_show_panics, - ) - .map( as Types>::TokenStream::unmark) - } -} - -impl - client::Client< - fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream, - > -{ - pub fn run( - &self, - strategy: &impl ExecutionStrategy, - server: S, - input: S::TokenStream, - input2: S::TokenStream, - force_show_panics: bool, - ) -> Result { - let client::Client { get_handle_counters, run, f } = *self; - run_server( - strategy, - get_handle_counters(), - server, - ( - as Types>::TokenStream::mark(input), - as Types>::TokenStream::mark(input2), - ), - run, - f, - force_show_panics, - ) - .map( as Types>::TokenStream::unmark) - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/diagnostic.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/diagnostic.rs deleted file mode 100644 index cda239f878500..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/diagnostic.rs +++ /dev/null @@ -1,166 +0,0 @@ -//! lib-proc-macro diagnostic -//! -//! Copy from -//! augmented with removing unstable features - -use super::Span; - -/// An enum representing a diagnostic level. -#[derive(Copy, Clone, Debug)] -#[non_exhaustive] -pub enum Level { - /// An error. - Error, - /// A warning. - Warning, - /// A note. - Note, - /// A help message. - Help, -} - -/// Trait implemented by types that can be converted into a set of `Span`s. -pub trait MultiSpan { - /// Converts `self` into a `Vec`. - fn into_spans(self) -> Vec; -} - -impl MultiSpan for Span { - fn into_spans(self) -> Vec { - vec![self] - } -} - -impl MultiSpan for Vec { - fn into_spans(self) -> Vec { - self - } -} - -impl<'a> MultiSpan for &'a [Span] { - fn into_spans(self) -> Vec { - self.to_vec() - } -} - -/// A structure representing a diagnostic message and associated children -/// messages. -#[derive(Clone, Debug)] -pub struct Diagnostic { - level: Level, - message: String, - spans: Vec, - children: Vec, -} - -macro_rules! diagnostic_child_methods { - ($spanned:ident, $regular:ident, $level:expr) => { - #[doc = concat!("Adds a new child diagnostics message to `self` with the [`", - stringify!($level), "`] level, and the given `spans` and `message`.")] - pub fn $spanned(mut self, spans: S, message: T) -> Diagnostic - where - S: MultiSpan, - T: Into, - { - self.children.push(Diagnostic::spanned(spans, $level, message)); - self - } - - #[doc = concat!("Adds a new child diagnostic message to `self` with the [`", - stringify!($level), "`] level, and the given `message`.")] - pub fn $regular>(mut self, message: T) -> Diagnostic { - self.children.push(Diagnostic::new($level, message)); - self - } - }; -} - -/// Iterator over the children diagnostics of a `Diagnostic`. -#[derive(Debug, Clone)] -pub struct Children<'a>(std::slice::Iter<'a, Diagnostic>); - -impl<'a> Iterator for Children<'a> { - type Item = &'a Diagnostic; - - fn next(&mut self) -> Option { - self.0.next() - } -} - -impl Diagnostic { - /// Creates a new diagnostic with the given `level` and `message`. - pub fn new>(level: Level, message: T) -> Diagnostic { - Diagnostic { level, message: message.into(), spans: vec![], children: vec![] } - } - - /// Creates a new diagnostic with the given `level` and `message` pointing to - /// the given set of `spans`. - pub fn spanned(spans: S, level: Level, message: T) -> Diagnostic - where - S: MultiSpan, - T: Into, - { - Diagnostic { level, message: message.into(), spans: spans.into_spans(), children: vec![] } - } - - diagnostic_child_methods!(span_error, error, Level::Error); - diagnostic_child_methods!(span_warning, warning, Level::Warning); - diagnostic_child_methods!(span_note, note, Level::Note); - diagnostic_child_methods!(span_help, help, Level::Help); - - /// Returns the diagnostic `level` for `self`. - pub fn level(&self) -> Level { - self.level - } - - /// Sets the level in `self` to `level`. - pub fn set_level(&mut self, level: Level) { - self.level = level; - } - - /// Returns the message in `self`. - pub fn message(&self) -> &str { - &self.message - } - - /// Sets the message in `self` to `message`. - pub fn set_message>(&mut self, message: T) { - self.message = message.into(); - } - - /// Returns the `Span`s in `self`. - pub fn spans(&self) -> &[Span] { - &self.spans - } - - /// Sets the `Span`s in `self` to `spans`. - pub fn set_spans(&mut self, spans: S) { - self.spans = spans.into_spans(); - } - - /// Returns an iterator over the children diagnostics of `self`. - pub fn children(&self) -> Children<'_> { - Children(self.children.iter()) - } - - /// Emit the diagnostic. - pub fn emit(self) { - fn to_internal(spans: Vec) -> super::bridge::client::MultiSpan { - let mut multi_span = super::bridge::client::MultiSpan::new(); - for span in spans { - multi_span.push(span.0); - } - multi_span - } - - let mut diag = super::bridge::client::Diagnostic::new( - self.level, - &self.message[..], - to_internal(self.spans), - ); - for c in self.children { - diag.sub(c.level, &c.message[..], to_internal(c.spans)); - } - diag.emit(); - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/mod.rs deleted file mode 100644 index 4a07f22779e66..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/mod.rs +++ /dev/null @@ -1,1056 +0,0 @@ -//! A support library for macro authors when defining new macros. -//! -//! This library, provided by the standard distribution, provides the types -//! consumed in the interfaces of procedurally defined macro definitions such as -//! function-like macros `#[proc_macro]`, macro attributes `#[proc_macro_attribute]` and -//! custom derive attributes`#[proc_macro_derive]`. -//! -//! See [the book] for more. -//! -//! [the book]: ../book/ch19-06-macros.html#procedural-macros-for-generating-code-from-attributes - -#[doc(hidden)] -pub mod bridge; - -mod diagnostic; - -pub use diagnostic::{Diagnostic, Level, MultiSpan}; - -use std::cmp::Ordering; -use std::ops::RangeBounds; -use std::path::PathBuf; -use std::str::FromStr; -use std::{error, fmt, iter, mem}; - -/// Determines whether proc_macro has been made accessible to the currently -/// running program. -/// -/// The proc_macro crate is only intended for use inside the implementation of -/// procedural macros. All the functions in this crate panic if invoked from -/// outside of a procedural macro, such as from a build script or unit test or -/// ordinary Rust binary. -/// -/// With consideration for Rust libraries that are designed to support both -/// macro and non-macro use cases, `proc_macro::is_available()` provides a -/// non-panicking way to detect whether the infrastructure required to use the -/// API of proc_macro is presently available. Returns true if invoked from -/// inside of a procedural macro, false if invoked from any other binary. -pub fn is_available() -> bool { - bridge::Bridge::is_available() -} - -/// The main type provided by this crate, representing an abstract stream of -/// tokens, or, more specifically, a sequence of token trees. -/// The type provide interfaces for iterating over those token trees and, conversely, -/// collecting a number of token trees into one stream. -/// -/// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]` -/// and `#[proc_macro_derive]` definitions. -#[derive(Clone)] -pub struct TokenStream(bridge::client::TokenStream); - -/// Error returned from `TokenStream::from_str`. -#[non_exhaustive] -#[derive(Debug)] -pub struct LexError; - -impl fmt::Display for LexError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("cannot parse string into token stream") - } -} - -impl error::Error for LexError {} - -/// Error returned from `TokenStream::expand_expr`. -#[non_exhaustive] -#[derive(Debug)] -pub struct ExpandError; - -impl fmt::Display for ExpandError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("macro expansion failed") - } -} - -impl error::Error for ExpandError {} - -impl TokenStream { - /// Returns an empty `TokenStream` containing no token trees. - pub fn new() -> TokenStream { - TokenStream(bridge::client::TokenStream::new()) - } - - /// Checks if this `TokenStream` is empty. - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - /// Parses this `TokenStream` as an expression and attempts to expand any - /// macros within it. Returns the expanded `TokenStream`. - /// - /// Currently only expressions expanding to literals will succeed, although - /// this may be relaxed in the future. - /// - /// NOTE: In error conditions, `expand_expr` may leave macros unexpanded, - /// report an error, failing compilation, and/or return an `Err(..)`. The - /// specific behavior for any error condition, and what conditions are - /// considered errors, is unspecified and may change in the future. - pub fn expand_expr(&self) -> Result { - match bridge::client::TokenStream::expand_expr(&self.0) { - Ok(stream) => Ok(TokenStream(stream)), - Err(_) => Err(ExpandError), - } - } -} - -/// Attempts to break the string into tokens and parse those tokens into a token stream. -/// May fail for a number of reasons, for example, if the string contains unbalanced delimiters -/// or characters not existing in the language. -/// All tokens in the parsed stream get `Span::call_site()` spans. -/// -/// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to -/// change these errors into `LexError`s later. -impl FromStr for TokenStream { - type Err = LexError; - - fn from_str(src: &str) -> Result { - Ok(TokenStream(bridge::client::TokenStream::from_str(src))) - } -} - -/// Prints the token stream as a string that is supposed to be losslessly convertible back -/// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters and negative numeric literals. -impl fmt::Display for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -/// Prints token in a form convenient for debugging. -impl fmt::Debug for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("TokenStream ")?; - f.debug_list().entries(self.clone()).finish() - } -} - -impl Default for TokenStream { - fn default() -> Self { - TokenStream::new() - } -} - -pub use quote::{quote, quote_span}; - -/// Creates a token stream containing a single token tree. -impl From for TokenStream { - fn from(tree: TokenTree) -> TokenStream { - TokenStream(bridge::client::TokenStream::from_token_tree(match tree { - TokenTree::Group(tt) => bridge::TokenTree::Group(tt.0), - TokenTree::Punct(tt) => bridge::TokenTree::Punct(tt.0), - TokenTree::Ident(tt) => bridge::TokenTree::Ident(tt.0), - TokenTree::Literal(tt) => bridge::TokenTree::Literal(tt.0), - })) - } -} - -/// Collects a number of token trees into a single stream. -impl iter::FromIterator for TokenStream { - fn from_iter>(trees: I) -> Self { - trees.into_iter().map(TokenStream::from).collect() - } -} - -/// A "flattening" operation on token streams, collects token trees -/// from multiple token streams into a single stream. -impl iter::FromIterator for TokenStream { - fn from_iter>(streams: I) -> Self { - let mut builder = bridge::client::TokenStreamBuilder::new(); - streams.into_iter().for_each(|stream| builder.push(stream.0)); - TokenStream(builder.build()) - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, trees: I) { - self.extend(trees.into_iter().map(TokenStream::from)); - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, streams: I) { - // FIXME(eddyb) Use an optimized implementation if/when possible. - *self = iter::once(mem::replace(self, Self::new())).chain(streams).collect(); - } -} - -/// Public implementation details for the `TokenStream` type, such as iterators. -pub mod token_stream { - use super::{bridge, Group, Ident, Literal, Punct, TokenStream, TokenTree}; - - /// An iterator over `TokenStream`'s `TokenTree`s. - /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, - /// and returns whole groups as token trees. - #[derive(Clone)] - pub struct IntoIter(bridge::client::TokenStreamIter); - - impl Iterator for IntoIter { - type Item = TokenTree; - - fn next(&mut self) -> Option { - self.0.next().map(|tree| match tree { - bridge::TokenTree::Group(tt) => TokenTree::Group(Group(tt)), - bridge::TokenTree::Punct(tt) => TokenTree::Punct(Punct(tt)), - bridge::TokenTree::Ident(tt) => TokenTree::Ident(Ident(tt)), - bridge::TokenTree::Literal(tt) => TokenTree::Literal(Literal(tt)), - }) - } - } - - impl IntoIterator for TokenStream { - type Item = TokenTree; - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - IntoIter(self.0.into_iter()) - } - } -} - -/// `quote!(..)` accepts arbitrary tokens and expands into a `TokenStream` describing the input. -/// For example, `quote!(a + b)` will produce an expression, that, when evaluated, constructs -/// the `TokenStream` `[Ident("a"), Punct('+', Alone), Ident("b")]`. -/// -/// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term. -/// To quote `$` itself, use `$$`. -//pub macro quote($($t:tt)*) { -//[> compiler built-in <] -//} - -#[doc(hidden)] -mod quote; - -/// A region of source code, along with macro expansion information. -#[derive(Copy, Clone)] -pub struct Span(bridge::client::Span); - -macro_rules! diagnostic_method { - ($name:ident, $level:expr) => { - /// Creates a new `Diagnostic` with the given `message` at the span - /// `self`. - pub fn $name>(self, message: T) -> Diagnostic { - Diagnostic::spanned(self, $level, message) - } - }; -} - -impl Span { - /// A span that resolves at the macro definition site. - pub fn def_site() -> Span { - Span(bridge::client::Span::def_site()) - } - - /// The span of the invocation of the current procedural macro. - /// Identifiers created with this span will be resolved as if they were written - /// directly at the macro call location (call-site hygiene) and other code - /// at the macro call site will be able to refer to them as well. - pub fn call_site() -> Span { - Span(bridge::client::Span::call_site()) - } - - /// A span that represents `macro_rules` hygiene, and sometimes resolves at the macro - /// definition site (local variables, labels, `$crate`) and sometimes at the macro - /// call site (everything else). - /// The span location is taken from the call-site. - pub fn mixed_site() -> Span { - Span(bridge::client::Span::mixed_site()) - } - - /// The original source file into which this span points. - pub fn source_file(&self) -> SourceFile { - SourceFile(self.0.source_file()) - } - - /// The `Span` for the tokens in the previous macro expansion from which - /// `self` was generated from, if any. - pub fn parent(&self) -> Option { - self.0.parent().map(Span) - } - - /// The span for the origin source code that `self` was generated from. If - /// this `Span` wasn't generated from other macro expansions then the return - /// value is the same as `*self`. - pub fn source(&self) -> Span { - Span(self.0.source()) - } - - /// Gets the starting line/column in the source file for this span. - pub fn start(&self) -> LineColumn { - self.0.start().add_1_to_column() - } - - /// Gets the ending line/column in the source file for this span. - pub fn end(&self) -> LineColumn { - self.0.end().add_1_to_column() - } - - /// Creates an empty span pointing to directly before this span. - pub fn before(&self) -> Span { - Span(self.0.before()) - } - - /// Creates an empty span pointing to directly after this span. - pub fn after(&self) -> Span { - Span(self.0.after()) - } - - /// Creates a new span encompassing `self` and `other`. - /// - /// Returns `None` if `self` and `other` are from different files. - pub fn join(&self, other: Span) -> Option { - self.0.join(other.0).map(Span) - } - - /// Creates a new span with the same line/column information as `self` but - /// that resolves symbols as though it were at `other`. - pub fn resolved_at(&self, other: Span) -> Span { - Span(self.0.resolved_at(other.0)) - } - - /// Creates a new span with the same name resolution behavior as `self` but - /// with the line/column information of `other`. - pub fn located_at(&self, other: Span) -> Span { - other.resolved_at(*self) - } - - /// Compares to spans to see if they're equal. - pub fn eq(&self, other: &Span) -> bool { - self.0 == other.0 - } - - /// Returns the source text behind a span. This preserves the original source - /// code, including spaces and comments. It only returns a result if the span - /// corresponds to real source code. - /// - /// Note: The observable result of a macro should only rely on the tokens and - /// not on this source text. The result of this function is a best effort to - /// be used for diagnostics only. - pub fn source_text(&self) -> Option { - self.0.source_text() - } - - // Used by the implementation of `Span::quote` - #[doc(hidden)] - pub fn save_span(&self) -> usize { - self.0.save_span() - } - - // Used by the implementation of `Span::quote` - #[doc(hidden)] - pub fn recover_proc_macro_span(id: usize) -> Span { - Span(bridge::client::Span::recover_proc_macro_span(id)) - } - - diagnostic_method!(error, Level::Error); - diagnostic_method!(warning, Level::Warning); - diagnostic_method!(note, Level::Note); - diagnostic_method!(help, Level::Help); -} - -/// Prints a span in a form convenient for debugging. -impl fmt::Debug for Span { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// A line-column pair representing the start or end of a `Span`. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct LineColumn { - /// The 1-indexed line in the source file on which the span starts or ends (inclusive). - pub line: usize, - /// The 1-indexed column (number of bytes in UTF-8 encoding) in the source - /// file on which the span starts or ends (inclusive). - pub column: usize, -} - -impl LineColumn { - fn add_1_to_column(self) -> Self { - LineColumn { line: self.line, column: self.column + 1 } - } -} - -impl Ord for LineColumn { - fn cmp(&self, other: &Self) -> Ordering { - self.line.cmp(&other.line).then(self.column.cmp(&other.column)) - } -} - -impl PartialOrd for LineColumn { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -/// The source file of a given `Span`. -#[derive(Clone)] -pub struct SourceFile(bridge::client::SourceFile); - -impl SourceFile { - /// Gets the path to this source file. - /// - /// ### Note - /// If the code span associated with this `SourceFile` was generated by an external macro, this - /// macro, this might not be an actual path on the filesystem. Use [`is_real`] to check. - /// - /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on - /// the command line, the path as given might not actually be valid. - /// - /// [`is_real`]: Self::is_real - pub fn path(&self) -> PathBuf { - PathBuf::from(self.0.path()) - } - - /// Returns `true` if this source file is a real source file, and not generated by an external - /// macro's expansion. - pub fn is_real(&self) -> bool { - // This is a hack until intercrate spans are implemented and we can have real source files - // for spans generated in external macros. - // https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368 - self.0.is_real() - } -} - -impl fmt::Debug for SourceFile { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SourceFile") - .field("path", &self.path()) - .field("is_real", &self.is_real()) - .finish() - } -} - -impl PartialEq for SourceFile { - fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) - } -} - -impl Eq for SourceFile {} - -/// A single token or a delimited sequence of token trees (e.g., `[1, (), ..]`). -#[derive(Clone)] -pub enum TokenTree { - /// A token stream surrounded by bracket delimiters. - Group(Group), - /// An identifier. - Ident(Ident), - /// A single punctuation character (`+`, `,`, `$`, etc.). - Punct(Punct), - /// A literal character (`'a'`), string (`"hello"`), number (`2.3`), etc. - Literal(Literal), -} - -impl TokenTree { - /// Returns the span of this tree, delegating to the `span` method of - /// the contained token or a delimited stream. - pub fn span(&self) -> Span { - match *self { - TokenTree::Group(ref t) => t.span(), - TokenTree::Ident(ref t) => t.span(), - TokenTree::Punct(ref t) => t.span(), - TokenTree::Literal(ref t) => t.span(), - } - } - - /// Configures the span for *only this token*. - /// - /// Note that if this token is a `Group` then this method will not configure - /// the span of each of the internal tokens, this will simply delegate to - /// the `set_span` method of each variant. - pub fn set_span(&mut self, span: Span) { - match *self { - TokenTree::Group(ref mut t) => t.set_span(span), - TokenTree::Ident(ref mut t) => t.set_span(span), - TokenTree::Punct(ref mut t) => t.set_span(span), - TokenTree::Literal(ref mut t) => t.set_span(span), - } - } -} - -/// Prints token tree in a form convenient for debugging. -impl fmt::Debug for TokenTree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Each of these has the name in the struct type in the derived debug, - // so don't bother with an extra layer of indirection - match *self { - TokenTree::Group(ref tt) => tt.fmt(f), - TokenTree::Ident(ref tt) => tt.fmt(f), - TokenTree::Punct(ref tt) => tt.fmt(f), - TokenTree::Literal(ref tt) => tt.fmt(f), - } - } -} - -impl From for TokenTree { - fn from(g: Group) -> TokenTree { - TokenTree::Group(g) - } -} - -impl From for TokenTree { - fn from(g: Ident) -> TokenTree { - TokenTree::Ident(g) - } -} - -impl From for TokenTree { - fn from(g: Punct) -> TokenTree { - TokenTree::Punct(g) - } -} - -impl From for TokenTree { - fn from(g: Literal) -> TokenTree { - TokenTree::Literal(g) - } -} - -/// Prints the token tree as a string that is supposed to be losslessly convertible back -/// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters and negative numeric literals. -impl fmt::Display for TokenTree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -/// A delimited token stream. -/// -/// A `Group` internally contains a `TokenStream` which is surrounded by `Delimiter`s. -#[derive(Clone)] -pub struct Group(bridge::client::Group); - -/// Describes how a sequence of token trees is delimited. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Delimiter { - /// `( ... )` - Parenthesis, - /// `{ ... }` - Brace, - /// `[ ... ]` - Bracket, - /// `Ø ... Ø` - /// An implicit delimiter, that may, for example, appear around tokens coming from a - /// "macro variable" `$var`. It is important to preserve operator priorities in cases like - /// `$var * 3` where `$var` is `1 + 2`. - /// Implicit delimiters might not survive roundtrip of a token stream through a string. - None, -} - -impl Group { - /// Creates a new `Group` with the given delimiter and token stream. - /// - /// This constructor will set the span for this group to - /// `Span::call_site()`. To change the span you can use the `set_span` - /// method below. - pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { - Group(bridge::client::Group::new(delimiter, stream.0)) - } - - /// Returns the delimiter of this `Group` - pub fn delimiter(&self) -> Delimiter { - self.0.delimiter() - } - - /// Returns the `TokenStream` of tokens that are delimited in this `Group`. - /// - /// Note that the returned token stream does not include the delimiter - /// returned above. - pub fn stream(&self) -> TokenStream { - TokenStream(self.0.stream()) - } - - /// Returns the span for the delimiters of this token stream, spanning the - /// entire `Group`. - /// - /// ```text - /// pub fn span(&self) -> Span { - /// ^^^^^^^ - /// ``` - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Returns the span pointing to the opening delimiter of this group. - /// - /// ```text - /// pub fn span_open(&self) -> Span { - /// ^ - /// ``` - pub fn span_open(&self) -> Span { - Span(self.0.span_open()) - } - - /// Returns the span pointing to the closing delimiter of this group. - /// - /// ```text - /// pub fn span_close(&self) -> Span { - /// ^ - /// ``` - pub fn span_close(&self) -> Span { - Span(self.0.span_close()) - } - - /// Configures the span for this `Group`'s delimiters, but not its internal - /// tokens. - /// - /// This method will **not** set the span of all the internal tokens spanned - /// by this group, but rather it will only set the span of the delimiter - /// tokens at the level of the `Group`. - pub fn set_span(&mut self, span: Span) { - self.0.set_span(span.0); - } -} - -/// Prints the group as a string that should be losslessly convertible back -/// into the same group (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters. -impl fmt::Display for Group { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Group { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Group") - .field("delimiter", &self.delimiter()) - .field("stream", &self.stream()) - .field("span", &self.span()) - .finish() - } -} - -/// A `Punct` is a single punctuation character such as `+`, `-` or `#`. -/// -/// Multi-character operators like `+=` are represented as two instances of `Punct` with different -/// forms of `Spacing` returned. -#[derive(Clone)] -pub struct Punct(bridge::client::Punct); - -/// Describes whether a `Punct` is followed immediately by another `Punct` ([`Spacing::Joint`]) or -/// by a different token or whitespace ([`Spacing::Alone`]). -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Spacing { - /// A `Punct` is not immediately followed by another `Punct`. - /// E.g. `+` is `Alone` in `+ =`, `+ident` and `+()`. - Alone, - /// A `Punct` is immediately followed by another `Punct`. - /// E.g. `+` is `Joint` in `+=` and `++`. - /// - /// Additionally, single quote `'` can join with identifiers to form lifetimes: `'ident`. - Joint, -} - -impl Punct { - /// Creates a new `Punct` from the given character and spacing. - /// The `ch` argument must be a valid punctuation character permitted by the language, - /// otherwise the function will panic. - /// - /// The returned `Punct` will have the default span of `Span::call_site()` - /// which can be further configured with the `set_span` method below. - pub fn new(ch: char, spacing: Spacing) -> Punct { - Punct(bridge::client::Punct::new(ch, spacing)) - } - - /// Returns the value of this punctuation character as `char`. - pub fn as_char(&self) -> char { - self.0.as_char() - } - - /// Returns the spacing of this punctuation character, indicating whether it's immediately - /// followed by another `Punct` in the token stream, so they can potentially be combined into - /// a multi-character operator (`Joint`), or it's followed by some other token or whitespace - /// (`Alone`) so the operator has certainly ended. - pub fn spacing(&self) -> Spacing { - self.0.spacing() - } - - /// Returns the span for this punctuation character. - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Configure the span for this punctuation character. - pub fn set_span(&mut self, span: Span) { - self.0 = self.0.with_span(span.0); - } -} - -/// Prints the punctuation character as a string that should be losslessly convertible -/// back into the same character. -impl fmt::Display for Punct { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Punct { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Punct") - .field("ch", &self.as_char()) - .field("spacing", &self.spacing()) - .field("span", &self.span()) - .finish() - } -} - -impl PartialEq for Punct { - fn eq(&self, rhs: &char) -> bool { - self.as_char() == *rhs - } -} - -impl PartialEq for char { - fn eq(&self, rhs: &Punct) -> bool { - *self == rhs.as_char() - } -} - -/// An identifier (`ident`). -#[derive(Clone)] -pub struct Ident(bridge::client::Ident); - -impl Ident { - /// Creates a new `Ident` with the given `string` as well as the specified - /// `span`. - /// The `string` argument must be a valid identifier permitted by the - /// language (including keywords, e.g. `self` or `fn`). Otherwise, the function will panic. - /// - /// Note that `span`, currently in rustc, configures the hygiene information - /// for this identifier. - /// - /// As of this time `Span::call_site()` explicitly opts-in to "call-site" hygiene - /// meaning that identifiers created with this span will be resolved as if they were written - /// directly at the location of the macro call, and other code at the macro call site will be - /// able to refer to them as well. - /// - /// Later spans like `Span::def_site()` will allow to opt-in to "definition-site" hygiene - /// meaning that identifiers created with this span will be resolved at the location of the - /// macro definition and other code at the macro call site will not be able to refer to them. - /// - /// Due to the current importance of hygiene this constructor, unlike other - /// tokens, requires a `Span` to be specified at construction. - pub fn new(string: &str, span: Span) -> Ident { - Ident(bridge::client::Ident::new(string, span.0, false)) - } - - /// Same as `Ident::new`, but creates a raw identifier (`r#ident`). - /// The `string` argument be a valid identifier permitted by the language - /// (including keywords, e.g. `fn`). Keywords which are usable in path segments - /// (e.g. `self`, `super`) are not supported, and will cause a panic. - pub fn new_raw(string: &str, span: Span) -> Ident { - Ident(bridge::client::Ident::new(string, span.0, true)) - } - - /// Returns the span of this `Ident`, encompassing the entire string returned - /// by [`to_string`](Self::to_string). - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Configures the span of this `Ident`, possibly changing its hygiene context. - pub fn set_span(&mut self, span: Span) { - self.0 = self.0.with_span(span.0); - } -} - -/// Prints the identifier as a string that should be losslessly convertible -/// back into the same identifier. -impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Ident { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Ident") - .field("ident", &self.to_string()) - .field("span", &self.span()) - .finish() - } -} - -/// A literal string (`"hello"`), byte string (`b"hello"`), -/// character (`'a'`), byte character (`b'a'`), an integer or floating point number -/// with or without a suffix (`1`, `1u8`, `2.3`, `2.3f32`). -/// Boolean literals like `true` and `false` do not belong here, they are `Ident`s. -#[derive(Clone)] -pub struct Literal(bridge::client::Literal); - -macro_rules! suffixed_int_literals { - ($($name:ident => $kind:ident,)*) => ($( - /// Creates a new suffixed integer literal with the specified value. - /// - /// This function will create an integer like `1u32` where the integer - /// value specified is the first part of the token and the integral is - /// also suffixed at the end. - /// Literals created from negative numbers might not survive round-trips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// Literals created through this method have the `Span::call_site()` - /// span by default, which can be configured with the `set_span` method - /// below. - pub fn $name(n: $kind) -> Literal { - Literal(bridge::client::Literal::typed_integer(&n.to_string(), stringify!($kind))) - } - )*) -} - -macro_rules! unsuffixed_int_literals { - ($($name:ident => $kind:ident,)*) => ($( - /// Creates a new unsuffixed integer literal with the specified value. - /// - /// This function will create an integer like `1` where the integer - /// value specified is the first part of the token. No suffix is - /// specified on this token, meaning that invocations like - /// `Literal::i8_unsuffixed(1)` are equivalent to - /// `Literal::u32_unsuffixed(1)`. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// Literals created through this method have the `Span::call_site()` - /// span by default, which can be configured with the `set_span` method - /// below. - pub fn $name(n: $kind) -> Literal { - Literal(bridge::client::Literal::integer(&n.to_string())) - } - )*) -} - -impl Literal { - suffixed_int_literals! { - u8_suffixed => u8, - u16_suffixed => u16, - u32_suffixed => u32, - u64_suffixed => u64, - u128_suffixed => u128, - usize_suffixed => usize, - i8_suffixed => i8, - i16_suffixed => i16, - i32_suffixed => i32, - i64_suffixed => i64, - i128_suffixed => i128, - isize_suffixed => isize, - } - - unsuffixed_int_literals! { - u8_unsuffixed => u8, - u16_unsuffixed => u16, - u32_unsuffixed => u32, - u64_unsuffixed => u64, - u128_unsuffixed => u128, - usize_unsuffixed => usize, - i8_unsuffixed => i8, - i16_unsuffixed => i16, - i32_unsuffixed => i32, - i64_unsuffixed => i64, - i128_unsuffixed => i128, - isize_unsuffixed => isize, - } - - /// Creates a new unsuffixed floating-point literal. - /// - /// This constructor is similar to those like `Literal::i8_unsuffixed` where - /// the float's value is emitted directly into the token but no suffix is - /// used, so it may be inferred to be a `f64` later in the compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f32_unsuffixed(n: f32) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {}", n); - } - let mut repr = n.to_string(); - if !repr.contains('.') { - repr.push_str(".0"); - } - Literal(bridge::client::Literal::float(&repr)) - } - - /// Creates a new suffixed floating-point literal. - /// - /// This constructor will create a literal like `1.0f32` where the value - /// specified is the preceding part of the token and `f32` is the suffix of - /// the token. This token will always be inferred to be an `f32` in the - /// compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f32_suffixed(n: f32) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {}", n); - } - Literal(bridge::client::Literal::f32(&n.to_string())) - } - - /// Creates a new unsuffixed floating-point literal. - /// - /// This constructor is similar to those like `Literal::i8_unsuffixed` where - /// the float's value is emitted directly into the token but no suffix is - /// used, so it may be inferred to be a `f64` later in the compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f64_unsuffixed(n: f64) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {}", n); - } - let mut repr = n.to_string(); - if !repr.contains('.') { - repr.push_str(".0"); - } - Literal(bridge::client::Literal::float(&repr)) - } - - /// Creates a new suffixed floating-point literal. - /// - /// This constructor will create a literal like `1.0f64` where the value - /// specified is the preceding part of the token and `f64` is the suffix of - /// the token. This token will always be inferred to be an `f64` in the - /// compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f64_suffixed(n: f64) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {}", n); - } - Literal(bridge::client::Literal::f64(&n.to_string())) - } - - /// String literal. - pub fn string(string: &str) -> Literal { - Literal(bridge::client::Literal::string(string)) - } - - /// Character literal. - pub fn character(ch: char) -> Literal { - Literal(bridge::client::Literal::character(ch)) - } - - /// Byte string literal. - pub fn byte_string(bytes: &[u8]) -> Literal { - Literal(bridge::client::Literal::byte_string(bytes)) - } - - /// Returns the span encompassing this literal. - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Configures the span associated for this literal. - pub fn set_span(&mut self, span: Span) { - self.0.set_span(span.0); - } - - /// Returns a `Span` that is a subset of `self.span()` containing only the - /// source bytes in range `range`. Returns `None` if the would-be trimmed - /// span is outside the bounds of `self`. - // FIXME(SergioBenitez): check that the byte range starts and ends at a - // UTF-8 boundary of the source. otherwise, it's likely that a panic will - // occur elsewhere when the source text is printed. - // FIXME(SergioBenitez): there is no way for the user to know what - // `self.span()` actually maps to, so this method can currently only be - // called blindly. For example, `to_string()` for the character 'c' returns - // "'\u{63}'"; there is no way for the user to know whether the source text - // was 'c' or whether it was '\u{63}'. - pub fn subspan>(&self, range: R) -> Option { - self.0.subspan(range.start_bound().cloned(), range.end_bound().cloned()).map(Span) - } -} - -/// Parse a single literal from its stringified representation. -/// -/// In order to parse successfully, the input string must not contain anything -/// but the literal token. Specifically, it must not contain whitespace or -/// comments in addition to the literal. -/// -/// The resulting literal token will have a `Span::call_site()` span. -/// -/// NOTE: some errors may cause panics instead of returning `LexError`. We -/// reserve the right to change these errors into `LexError`s later. -impl FromStr for Literal { - type Err = LexError; - - fn from_str(src: &str) -> Result { - match bridge::client::Literal::from_str(src) { - Ok(literal) => Ok(Literal(literal)), - Err(()) => Err(LexError), - } - } -} - -/// Prints the literal as a string that should be losslessly convertible -/// back into the same literal (except for possible rounding for floating point literals). -impl fmt::Display for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// Tracked access to environment variables. -pub mod tracked_env { - use std::env::{self, VarError}; - use std::ffi::OsStr; - - /// Retrieve an environment variable and add it to build dependency info. - /// Build system executing the compiler will know that the variable was accessed during - /// compilation, and will be able to rerun the build when the value of that variable changes. - /// Besides the dependency tracking this function should be equivalent to `env::var` from the - /// standard library, except that the argument must be UTF-8. - pub fn var + AsRef>(key: K) -> Result { - let key: &str = key.as_ref(); - let value = env::var(key); - super::bridge::client::FreeFunctions::track_env_var(key, value.as_deref().ok()); - value - } -} - -/// Tracked access to additional files. -pub mod tracked_path { - - /// Track a file explicitly. - /// - /// Commonly used for tracking asset preprocessing. - pub fn path>(path: P) { - let path: &str = path.as_ref(); - super::bridge::client::FreeFunctions::track_path(path); - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/quote.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/quote.rs deleted file mode 100644 index b539ab9c0c6d6..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/quote.rs +++ /dev/null @@ -1,140 +0,0 @@ -//! # Quasiquoter -//! This file contains the implementation internals of the quasiquoter provided by `quote!`. - -//! This quasiquoter uses macros 2.0 hygiene to reliably access -//! items from `proc_macro`, to build a `proc_macro::TokenStream`. - -use super::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; - -macro_rules! quote_tt { - (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, quote!($($t)*)) }; - ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, quote!($($t)*)) }; - ({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) }; - (,) => { Punct::new(',', Spacing::Alone) }; - (.) => { Punct::new('.', Spacing::Alone) }; - (:) => { Punct::new(':', Spacing::Alone) }; - (;) => { Punct::new(';', Spacing::Alone) }; - (!) => { Punct::new('!', Spacing::Alone) }; - (<) => { Punct::new('<', Spacing::Alone) }; - (>) => { Punct::new('>', Spacing::Alone) }; - (&) => { Punct::new('&', Spacing::Alone) }; - (=) => { Punct::new('=', Spacing::Alone) }; - ($i:ident) => { Ident::new(stringify!($i), Span::def_site()) }; -} - -macro_rules! quote_ts { - ((@ $($t:tt)*)) => { $($t)* }; - (::) => { - [ - TokenTree::from(Punct::new(':', Spacing::Joint)), - TokenTree::from(Punct::new(':', Spacing::Alone)), - ].iter() - .cloned() - .map(|mut x| { - x.set_span(Span::def_site()); - x - }) - .collect::() - }; - ($t:tt) => { TokenTree::from(quote_tt!($t)) }; -} - -/// Simpler version of the real `quote!` macro, implemented solely -/// through `macro_rules`, for bootstrapping the real implementation -/// (see the `quote` function), which does not have access to the -/// real `quote!` macro due to the `proc_macro` crate not being -/// able to depend on itself. -/// -/// Note: supported tokens are a subset of the real `quote!`, but -/// unquoting is different: instead of `$x`, this uses `(@ expr)`. -macro_rules! quote { - () => { TokenStream::new() }; - ($($t:tt)*) => { - [ - $(TokenStream::from(quote_ts!($t)),)* - ].iter().cloned().collect::() - }; -} - -/// Quote a `TokenStream` into a `TokenStream`. -/// This is the actual implementation of the `quote!()` proc macro. -/// -/// It is loaded by the compiler in `register_builtin_macros`. -pub fn quote(stream: TokenStream) -> TokenStream { - if stream.is_empty() { - return quote!(crate::TokenStream::new()); - } - let proc_macro_crate = quote!(crate); - let mut after_dollar = false; - let tokens = stream - .into_iter() - .filter_map(|tree| { - if after_dollar { - after_dollar = false; - match tree { - TokenTree::Ident(_) => { - return Some(quote!(Into::::into( - Clone::clone(&(@ tree))),)); - } - TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} - _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), - } - } else if let TokenTree::Punct(ref tt) = tree { - if tt.as_char() == '$' { - after_dollar = true; - return None; - } - } - - Some(quote!(crate::TokenStream::from((@ match tree { - TokenTree::Punct(tt) => quote!(crate::TokenTree::Punct(crate::Punct::new( - (@ TokenTree::from(Literal::character(tt.as_char()))), - (@ match tt.spacing() { - Spacing::Alone => quote!(crate::Spacing::Alone), - Spacing::Joint => quote!(crate::Spacing::Joint), - }), - ))), - TokenTree::Group(tt) => quote!(crate::TokenTree::Group(crate::Group::new( - (@ match tt.delimiter() { - Delimiter::Parenthesis => quote!(crate::Delimiter::Parenthesis), - Delimiter::Brace => quote!(crate::Delimiter::Brace), - Delimiter::Bracket => quote!(crate::Delimiter::Bracket), - Delimiter::None => quote!(crate::Delimiter::None), - }), - (@ quote(tt.stream())), - ))), - TokenTree::Ident(tt) => quote!(crate::TokenTree::Ident(crate::Ident::new( - (@ TokenTree::from(Literal::string(&tt.to_string()))), - (@ quote_span(proc_macro_crate.clone(), tt.span())), - ))), - TokenTree::Literal(tt) => quote!(crate::TokenTree::Literal({ - let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string()))) - .parse::() - .unwrap() - .into_iter(); - if let (Some(crate::TokenTree::Literal(mut lit)), None) = - (iter.next(), iter.next()) - { - lit.set_span((@ quote_span(proc_macro_crate.clone(), tt.span()))); - lit - } else { - unreachable!() - } - })) - })),)) - }) - .collect::(); - - if after_dollar { - panic!("unexpected trailing `$` in `quote!`"); - } - - quote!([(@ tokens)].iter().cloned().collect::()) -} - -/// Quote a `Span` into a `TokenStream`. -/// This is needed to implement a custom quoter. -pub fn quote_span(proc_macro_crate: TokenStream, span: Span) -> TokenStream { - let id = span.save_span(); - quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id))))) -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/ra_server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/ra_server.rs deleted file mode 100644 index ebdfca00d735d..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/ra_server.rs +++ /dev/null @@ -1,819 +0,0 @@ -//! Rustc proc-macro server implementation with tt -//! -//! Based on idea from -//! The lib-proc-macro server backend is `TokenStream`-agnostic, such that -//! we could provide any TokenStream implementation. -//! The original idea from fedochet is using proc-macro2 as backend, -//! we use tt instead for better integration with RA. -//! -//! FIXME: No span and source file information is implemented yet - -use super::proc_macro::bridge::{self, server}; - -use std::collections::HashMap; -use std::hash::Hash; -use std::iter::FromIterator; -use std::ops::Bound; -use std::{ascii, vec::IntoIter}; - -type Group = tt::Subtree; -type TokenTree = tt::TokenTree; -type Punct = tt::Punct; -type Spacing = tt::Spacing; -type Literal = tt::Literal; -type Span = tt::TokenId; - -#[derive(Debug, Clone)] -pub struct TokenStream { - pub token_trees: Vec, -} - -impl TokenStream { - pub fn new() -> Self { - TokenStream { token_trees: Default::default() } - } - - pub fn with_subtree(subtree: tt::Subtree) -> Self { - if subtree.delimiter.is_some() { - TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] } - } else { - TokenStream { token_trees: subtree.token_trees } - } - } - - pub fn into_subtree(self) -> tt::Subtree { - tt::Subtree { delimiter: None, token_trees: self.token_trees } - } - - pub fn is_empty(&self) -> bool { - self.token_trees.is_empty() - } -} - -/// Creates a token stream containing a single token tree. -impl From for TokenStream { - fn from(tree: TokenTree) -> TokenStream { - TokenStream { token_trees: vec![tree] } - } -} - -/// Collects a number of token trees into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(trees: I) -> Self { - trees.into_iter().map(TokenStream::from).collect() - } -} - -/// A "flattening" operation on token streams, collects token trees -/// from multiple token streams into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(streams: I) -> Self { - let mut builder = TokenStreamBuilder::new(); - streams.into_iter().for_each(|stream| builder.push(stream)); - builder.build() - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, trees: I) { - self.extend(trees.into_iter().map(TokenStream::from)); - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, streams: I) { - for item in streams { - for tkn in item { - match tkn { - tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => { - self.token_trees.extend(subtree.token_trees); - } - _ => { - self.token_trees.push(tkn); - } - } - } - } - } -} - -#[derive(Clone)] -pub struct SourceFile { - // FIXME stub -} - -type Level = super::proc_macro::Level; -type LineColumn = super::proc_macro::LineColumn; - -/// A structure representing a diagnostic message and associated children -/// messages. -#[derive(Clone, Debug)] -pub struct Diagnostic { - level: Level, - message: String, - spans: Vec, - children: Vec, -} - -impl Diagnostic { - /// Creates a new diagnostic with the given `level` and `message`. - pub fn new>(level: Level, message: T) -> Diagnostic { - Diagnostic { level, message: message.into(), spans: vec![], children: vec![] } - } -} - -// Rustc Server Ident has to be `Copyable` -// We use a stub here for bypassing -#[derive(Hash, Eq, PartialEq, Copy, Clone)] -pub struct IdentId(u32); - -#[derive(Clone, Hash, Eq, PartialEq)] -struct IdentData(tt::Ident); - -#[derive(Default)] -struct IdentInterner { - idents: HashMap, - ident_data: Vec, -} - -impl IdentInterner { - fn intern(&mut self, data: &IdentData) -> u32 { - if let Some(index) = self.idents.get(data) { - return *index; - } - - let index = self.idents.len() as u32; - self.ident_data.push(data.clone()); - self.idents.insert(data.clone(), index); - index - } - - fn get(&self, index: u32) -> &IdentData { - &self.ident_data[index as usize] - } - - #[allow(unused)] - fn get_mut(&mut self, index: u32) -> &mut IdentData { - self.ident_data.get_mut(index as usize).expect("Should be consistent") - } -} - -pub struct TokenStreamBuilder { - acc: TokenStream, -} - -/// Public implementation details for the `TokenStream` type, such as iterators. -pub mod token_stream { - use std::str::FromStr; - - use super::{TokenStream, TokenTree}; - - /// An iterator over `TokenStream`'s `TokenTree`s. - /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, - /// and returns whole groups as token trees. - impl IntoIterator for TokenStream { - type Item = TokenTree; - type IntoIter = super::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.token_trees.into_iter() - } - } - - type LexError = String; - - /// Attempts to break the string into tokens and parse those tokens into a token stream. - /// May fail for a number of reasons, for example, if the string contains unbalanced delimiters - /// or characters not existing in the language. - /// All tokens in the parsed stream get `Span::call_site()` spans. - /// - /// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to - /// change these errors into `LexError`s later. - impl FromStr for TokenStream { - type Err = LexError; - - fn from_str(src: &str) -> Result { - let (subtree, _token_map) = - mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?; - - let subtree = subtree_replace_token_ids_with_unspecified(subtree); - Ok(TokenStream::with_subtree(subtree)) - } - } - - impl ToString for TokenStream { - fn to_string(&self) -> String { - tt::pretty(&self.token_trees) - } - } - - fn subtree_replace_token_ids_with_unspecified(subtree: tt::Subtree) -> tt::Subtree { - tt::Subtree { - delimiter: subtree - .delimiter - .map(|d| tt::Delimiter { id: tt::TokenId::unspecified(), ..d }), - token_trees: subtree - .token_trees - .into_iter() - .map(token_tree_replace_token_ids_with_unspecified) - .collect(), - } - } - - fn token_tree_replace_token_ids_with_unspecified(tt: tt::TokenTree) -> tt::TokenTree { - match tt { - tt::TokenTree::Leaf(leaf) => { - tt::TokenTree::Leaf(leaf_replace_token_ids_with_unspecified(leaf)) - } - tt::TokenTree::Subtree(subtree) => { - tt::TokenTree::Subtree(subtree_replace_token_ids_with_unspecified(subtree)) - } - } - } - - fn leaf_replace_token_ids_with_unspecified(leaf: tt::Leaf) -> tt::Leaf { - match leaf { - tt::Leaf::Literal(lit) => { - tt::Leaf::Literal(tt::Literal { id: tt::TokenId::unspecified(), ..lit }) - } - tt::Leaf::Punct(punct) => { - tt::Leaf::Punct(tt::Punct { id: tt::TokenId::unspecified(), ..punct }) - } - tt::Leaf::Ident(ident) => { - tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), ..ident }) - } - } - } -} - -impl TokenStreamBuilder { - fn new() -> TokenStreamBuilder { - TokenStreamBuilder { acc: TokenStream::new() } - } - - fn push(&mut self, stream: TokenStream) { - self.acc.extend(stream.into_iter()) - } - - fn build(self) -> TokenStream { - self.acc - } -} - -pub struct FreeFunctions; - -#[derive(Clone)] -pub struct TokenStreamIter { - trees: IntoIter, -} - -#[derive(Default)] -pub struct RustAnalyzer { - ident_interner: IdentInterner, - // FIXME: store span information here. -} - -impl server::Types for RustAnalyzer { - type FreeFunctions = FreeFunctions; - type TokenStream = TokenStream; - type TokenStreamBuilder = TokenStreamBuilder; - type TokenStreamIter = TokenStreamIter; - type Group = Group; - type Punct = Punct; - type Ident = IdentId; - type Literal = Literal; - type SourceFile = SourceFile; - type Diagnostic = Diagnostic; - type Span = Span; - type MultiSpan = Vec; -} - -impl server::FreeFunctions for RustAnalyzer { - fn track_env_var(&mut self, _var: &str, _value: Option<&str>) { - // FIXME: track env var accesses - // https://github.com/rust-lang/rust/pull/71858 - } - fn track_path(&mut self, _path: &str) {} -} - -impl server::TokenStream for RustAnalyzer { - fn new(&mut self) -> Self::TokenStream { - Self::TokenStream::new() - } - - fn is_empty(&mut self, stream: &Self::TokenStream) -> bool { - stream.is_empty() - } - fn from_str(&mut self, src: &str) -> Self::TokenStream { - use std::str::FromStr; - - Self::TokenStream::from_str(src).expect("cannot parse string") - } - fn to_string(&mut self, stream: &Self::TokenStream) -> String { - stream.to_string() - } - fn from_token_tree( - &mut self, - tree: bridge::TokenTree, - ) -> Self::TokenStream { - match tree { - bridge::TokenTree::Group(group) => { - let tree = TokenTree::from(group); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Ident(IdentId(index)) => { - let IdentData(ident) = self.ident_interner.get(index).clone(); - let ident: tt::Ident = ident; - let leaf = tt::Leaf::from(ident); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Literal(literal) => { - let leaf = tt::Leaf::from(literal); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Punct(p) => { - let leaf = tt::Leaf::from(p); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - } - } - - fn into_iter(&mut self, stream: Self::TokenStream) -> Self::TokenStreamIter { - let trees: Vec = stream.into_iter().collect(); - TokenStreamIter { trees: trees.into_iter() } - } - - fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result { - Ok(self_.clone()) - } -} - -impl server::TokenStreamBuilder for RustAnalyzer { - fn new(&mut self) -> Self::TokenStreamBuilder { - Self::TokenStreamBuilder::new() - } - fn push(&mut self, builder: &mut Self::TokenStreamBuilder, stream: Self::TokenStream) { - builder.push(stream) - } - fn build(&mut self, builder: Self::TokenStreamBuilder) -> Self::TokenStream { - builder.build() - } -} - -impl server::TokenStreamIter for RustAnalyzer { - fn next( - &mut self, - iter: &mut Self::TokenStreamIter, - ) -> Option> { - iter.trees.next().map(|tree| match tree { - TokenTree::Subtree(group) => bridge::TokenTree::Group(group), - TokenTree::Leaf(tt::Leaf::Ident(ident)) => { - bridge::TokenTree::Ident(IdentId(self.ident_interner.intern(&IdentData(ident)))) - } - TokenTree::Leaf(tt::Leaf::Literal(literal)) => bridge::TokenTree::Literal(literal), - TokenTree::Leaf(tt::Leaf::Punct(punct)) => bridge::TokenTree::Punct(punct), - }) - } -} - -fn delim_to_internal(d: bridge::Delimiter) -> Option { - let kind = match d { - bridge::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis, - bridge::Delimiter::Brace => tt::DelimiterKind::Brace, - bridge::Delimiter::Bracket => tt::DelimiterKind::Bracket, - bridge::Delimiter::None => return None, - }; - Some(tt::Delimiter { id: tt::TokenId::unspecified(), kind }) -} - -fn delim_to_external(d: Option) -> bridge::Delimiter { - match d.map(|it| it.kind) { - Some(tt::DelimiterKind::Parenthesis) => bridge::Delimiter::Parenthesis, - Some(tt::DelimiterKind::Brace) => bridge::Delimiter::Brace, - Some(tt::DelimiterKind::Bracket) => bridge::Delimiter::Bracket, - None => bridge::Delimiter::None, - } -} - -fn spacing_to_internal(spacing: bridge::Spacing) -> Spacing { - match spacing { - bridge::Spacing::Alone => Spacing::Alone, - bridge::Spacing::Joint => Spacing::Joint, - } -} - -fn spacing_to_external(spacing: Spacing) -> bridge::Spacing { - match spacing { - Spacing::Alone => bridge::Spacing::Alone, - Spacing::Joint => bridge::Spacing::Joint, - } -} - -impl server::Group for RustAnalyzer { - fn new(&mut self, delimiter: bridge::Delimiter, stream: Self::TokenStream) -> Self::Group { - Self::Group { delimiter: delim_to_internal(delimiter), token_trees: stream.token_trees } - } - fn delimiter(&mut self, group: &Self::Group) -> bridge::Delimiter { - delim_to_external(group.delimiter) - } - - // NOTE: Return value of do not include delimiter - fn stream(&mut self, group: &Self::Group) -> Self::TokenStream { - TokenStream { token_trees: group.token_trees.clone() } - } - - fn span(&mut self, group: &Self::Group) -> Self::Span { - group.delimiter.map(|it| it.id).unwrap_or_else(tt::TokenId::unspecified) - } - - fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) { - if let Some(delim) = &mut group.delimiter { - delim.id = span; - } - } - - fn span_open(&mut self, group: &Self::Group) -> Self::Span { - // FIXME we only store one `TokenId` for the delimiters - group.delimiter.map(|it| it.id).unwrap_or_else(tt::TokenId::unspecified) - } - - fn span_close(&mut self, group: &Self::Group) -> Self::Span { - // FIXME we only store one `TokenId` for the delimiters - group.delimiter.map(|it| it.id).unwrap_or_else(tt::TokenId::unspecified) - } -} - -impl server::Punct for RustAnalyzer { - fn new(&mut self, ch: char, spacing: bridge::Spacing) -> Self::Punct { - tt::Punct { - char: ch, - spacing: spacing_to_internal(spacing), - id: tt::TokenId::unspecified(), - } - } - fn as_char(&mut self, punct: Self::Punct) -> char { - punct.char - } - fn spacing(&mut self, punct: Self::Punct) -> bridge::Spacing { - spacing_to_external(punct.spacing) - } - fn span(&mut self, punct: Self::Punct) -> Self::Span { - punct.id - } - fn with_span(&mut self, punct: Self::Punct, span: Self::Span) -> Self::Punct { - tt::Punct { id: span, ..punct } - } -} - -impl server::Ident for RustAnalyzer { - fn new(&mut self, string: &str, span: Self::Span, _is_raw: bool) -> Self::Ident { - IdentId(self.ident_interner.intern(&IdentData(tt::Ident { text: string.into(), id: span }))) - } - - fn span(&mut self, ident: Self::Ident) -> Self::Span { - self.ident_interner.get(ident.0).0.id - } - fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident { - let data = self.ident_interner.get(ident.0); - let new = IdentData(tt::Ident { id: span, ..data.0.clone() }); - IdentId(self.ident_interner.intern(&new)) - } -} - -impl server::Literal for RustAnalyzer { - fn debug_kind(&mut self, _literal: &Self::Literal) -> String { - // r-a: debug_kind and suffix are unsupported; corresponding client code has been changed to not call these. - // They must still be present to be ABI-compatible and work with upstream proc_macro. - "".to_owned() - } - fn from_str(&mut self, s: &str) -> Result { - Ok(Literal { text: s.into(), id: tt::TokenId::unspecified() }) - } - fn symbol(&mut self, literal: &Self::Literal) -> String { - literal.text.to_string() - } - fn suffix(&mut self, _literal: &Self::Literal) -> Option { - None - } - - fn to_string(&mut self, literal: &Self::Literal) -> String { - literal.to_string() - } - - fn integer(&mut self, n: &str) -> Self::Literal { - let n = match n.parse::() { - Ok(n) => n.to_string(), - Err(_) => n.parse::().unwrap().to_string(), - }; - Literal { text: n.into(), id: tt::TokenId::unspecified() } - } - - fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal { - macro_rules! def_suffixed_integer { - ($kind:ident, $($ty:ty),*) => { - match $kind { - $( - stringify!($ty) => { - let n: $ty = n.parse().unwrap(); - format!(concat!("{}", stringify!($ty)), n) - } - )* - _ => unimplemented!("unknown args for typed_integer: n {}, kind {}", n, $kind), - } - } - } - - let text = def_suffixed_integer! {kind, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize}; - - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn float(&mut self, n: &str) -> Self::Literal { - let n: f64 = n.parse().unwrap(); - let mut text = f64::to_string(&n); - if !text.contains('.') { - text += ".0" - } - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn f32(&mut self, n: &str) -> Self::Literal { - let n: f32 = n.parse().unwrap(); - let text = format!("{}f32", n); - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn f64(&mut self, n: &str) -> Self::Literal { - let n: f64 = n.parse().unwrap(); - let text = format!("{}f64", n); - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn string(&mut self, string: &str) -> Self::Literal { - let mut escaped = String::new(); - for ch in string.chars() { - escaped.extend(ch.escape_debug()); - } - Literal { text: format!("\"{}\"", escaped).into(), id: tt::TokenId::unspecified() } - } - - fn character(&mut self, ch: char) -> Self::Literal { - Literal { text: format!("'{}'", ch).into(), id: tt::TokenId::unspecified() } - } - - fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal { - let string = bytes - .iter() - .cloned() - .flat_map(ascii::escape_default) - .map(Into::::into) - .collect::(); - - Literal { text: format!("b\"{}\"", string).into(), id: tt::TokenId::unspecified() } - } - - fn span(&mut self, literal: &Self::Literal) -> Self::Span { - literal.id - } - - fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) { - literal.id = span; - } - - fn subspan( - &mut self, - _literal: &Self::Literal, - _start: Bound, - _end: Bound, - ) -> Option { - // FIXME handle span - None - } -} - -impl server::SourceFile for RustAnalyzer { - // FIXME these are all stubs - fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool { - true - } - fn path(&mut self, _file: &Self::SourceFile) -> String { - String::new() - } - fn is_real(&mut self, _file: &Self::SourceFile) -> bool { - true - } -} - -impl server::Diagnostic for RustAnalyzer { - fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic { - let mut diag = Diagnostic::new(level, msg); - diag.spans = spans; - diag - } - - fn sub( - &mut self, - _diag: &mut Self::Diagnostic, - _level: Level, - _msg: &str, - _spans: Self::MultiSpan, - ) { - // FIXME handle diagnostic - // - } - - fn emit(&mut self, _diag: Self::Diagnostic) { - // FIXME handle diagnostic - // diag.emit() - } -} - -impl server::Span for RustAnalyzer { - fn debug(&mut self, span: Self::Span) -> String { - format!("{:?}", span.0) - } - fn def_site(&mut self) -> Self::Span { - // MySpan(self.span_interner.intern(&MySpanData(Span::def_site()))) - // FIXME handle span - tt::TokenId::unspecified() - } - fn call_site(&mut self) -> Self::Span { - // MySpan(self.span_interner.intern(&MySpanData(Span::call_site()))) - // FIXME handle span - tt::TokenId::unspecified() - } - fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile { - SourceFile {} - } - fn save_span(&mut self, _span: Self::Span) -> usize { - // FIXME stub - 0 - } - fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span { - // FIXME stub - tt::TokenId::unspecified() - } - /// Recent feature, not yet in the proc_macro - /// - /// See PR: - /// https://github.com/rust-lang/rust/pull/55780 - fn source_text(&mut self, _span: Self::Span) -> Option { - None - } - - fn parent(&mut self, _span: Self::Span) -> Option { - // FIXME handle span - None - } - fn source(&mut self, span: Self::Span) -> Self::Span { - // FIXME handle span - span - } - fn start(&mut self, _span: Self::Span) -> LineColumn { - // FIXME handle span - LineColumn { line: 0, column: 0 } - } - fn end(&mut self, _span: Self::Span) -> LineColumn { - // FIXME handle span - LineColumn { line: 0, column: 0 } - } - fn join(&mut self, first: Self::Span, _second: Self::Span) -> Option { - // Just return the first span again, because some macros will unwrap the result. - Some(first) - } - fn resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span { - // FIXME handle span - tt::TokenId::unspecified() - } - - fn mixed_site(&mut self) -> Self::Span { - // FIXME handle span - tt::TokenId::unspecified() - } - - fn after(&mut self, _self_: Self::Span) -> Self::Span { - tt::TokenId::unspecified() - } - - fn before(&mut self, _self_: Self::Span) -> Self::Span { - tt::TokenId::unspecified() - } -} - -impl server::MultiSpan for RustAnalyzer { - fn new(&mut self) -> Self::MultiSpan { - // FIXME handle span - vec![] - } - - fn push(&mut self, other: &mut Self::MultiSpan, span: Self::Span) { - //TODP - other.push(span) - } -} - -#[cfg(test)] -mod tests { - use super::super::proc_macro::bridge::server::Literal; - use super::*; - - #[test] - fn test_ra_server_literals() { - let mut srv = RustAnalyzer { ident_interner: IdentInterner::default() }; - assert_eq!(srv.integer("1234").text, "1234"); - - assert_eq!(srv.typed_integer("12", "u8").text, "12u8"); - assert_eq!(srv.typed_integer("255", "u16").text, "255u16"); - assert_eq!(srv.typed_integer("1234", "u32").text, "1234u32"); - assert_eq!(srv.typed_integer("15846685", "u64").text, "15846685u64"); - assert_eq!(srv.typed_integer("15846685258", "u128").text, "15846685258u128"); - assert_eq!(srv.typed_integer("156788984", "usize").text, "156788984usize"); - assert_eq!(srv.typed_integer("127", "i8").text, "127i8"); - assert_eq!(srv.typed_integer("255", "i16").text, "255i16"); - assert_eq!(srv.typed_integer("1234", "i32").text, "1234i32"); - assert_eq!(srv.typed_integer("15846685", "i64").text, "15846685i64"); - assert_eq!(srv.typed_integer("15846685258", "i128").text, "15846685258i128"); - assert_eq!(srv.float("0").text, "0.0"); - assert_eq!(srv.float("15684.5867").text, "15684.5867"); - assert_eq!(srv.f32("15684.58").text, "15684.58f32"); - assert_eq!(srv.f64("15684.58").text, "15684.58f64"); - - assert_eq!(srv.string("hello_world").text, "\"hello_world\""); - assert_eq!(srv.character('c').text, "'c'"); - assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\""); - - // u128::max - assert_eq!( - srv.integer("340282366920938463463374607431768211455").text, - "340282366920938463463374607431768211455" - ); - // i128::min - assert_eq!( - srv.integer("-170141183460469231731687303715884105728").text, - "-170141183460469231731687303715884105728" - ); - } - - #[test] - fn test_ra_server_to_string() { - let s = TokenStream { - token_trees: vec![ - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "struct".into(), - id: tt::TokenId::unspecified(), - })), - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "T".into(), - id: tt::TokenId::unspecified(), - })), - tt::TokenTree::Subtree(tt::Subtree { - delimiter: Some(tt::Delimiter { - id: tt::TokenId::unspecified(), - kind: tt::DelimiterKind::Brace, - }), - token_trees: vec![], - }), - ], - }; - - assert_eq!(s.to_string(), "struct T {}"); - } - - #[test] - fn test_ra_server_from_str() { - use std::str::FromStr; - let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree { - delimiter: Some(tt::Delimiter { - id: tt::TokenId::unspecified(), - kind: tt::DelimiterKind::Parenthesis, - }), - token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "a".into(), - id: tt::TokenId::unspecified(), - }))], - }); - - let t1 = TokenStream::from_str("(a)").unwrap(); - assert_eq!(t1.token_trees.len(), 1); - assert_eq!(t1.token_trees[0], subtree_paren_a); - - let t2 = TokenStream::from_str("(a);").unwrap(); - assert_eq!(t2.token_trees.len(), 2); - assert_eq!(t2.token_trees[0], subtree_paren_a); - - let underscore = TokenStream::from_str("_").unwrap(); - assert_eq!( - underscore.token_trees[0], - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "_".into(), - id: tt::TokenId::unspecified(), - })) - ); - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/mod.rs deleted file mode 100644 index 76e89e3191a67..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/mod.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! Macro ABI for version 1.63 of rustc - -#[allow(dead_code)] -#[doc(hidden)] -mod proc_macro; - -#[allow(dead_code)] -#[doc(hidden)] -mod ra_server; - -use libloading::Library; -use proc_macro_api::ProcMacroKind; - -use super::PanicMessage; - -pub use ra_server::TokenStream; - -pub(crate) struct Abi { - exported_macros: Vec, -} - -impl From for PanicMessage { - fn from(p: proc_macro::bridge::PanicMessage) -> Self { - Self { message: p.as_str().map(|s| s.to_string()) } - } -} - -impl Abi { - pub unsafe fn from_lib(lib: &Library, symbol_name: String) -> Result { - let macros: libloading::Symbol<'_, &&[proc_macro::bridge::client::ProcMacro]> = - lib.get(symbol_name.as_bytes())?; - Ok(Self { exported_macros: macros.to_vec() }) - } - - pub fn expand( - &self, - macro_name: &str, - macro_body: &tt::Subtree, - attributes: Option<&tt::Subtree>, - ) -> Result { - let parsed_body = TokenStream::with_subtree(macro_body.clone()); - - let parsed_attributes = - attributes.map_or(TokenStream::new(), |attr| TokenStream::with_subtree(attr.clone())); - - for proc_macro in &self.exported_macros { - match proc_macro { - proc_macro::bridge::client::ProcMacro::CustomDerive { - trait_name, client, .. - } if *trait_name == macro_name => { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - proc_macro::bridge::client::ProcMacro::Bang { name, client } - if *name == macro_name => - { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - proc_macro::bridge::client::ProcMacro::Attr { name, client } - if *name == macro_name => - { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_attributes, - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - _ => continue, - } - } - - Err(proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()).into()) - } - - pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { - self.exported_macros - .iter() - .map(|proc_macro| match proc_macro { - proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { - (trait_name.to_string(), ProcMacroKind::CustomDerive) - } - proc_macro::bridge::client::ProcMacro::Bang { name, .. } => { - (name.to_string(), ProcMacroKind::FuncLike) - } - proc_macro::bridge::client::ProcMacro::Attr { name, .. } => { - (name.to_string(), ProcMacroKind::Attr) - } - }) - .collect() - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/buffer.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/buffer.rs deleted file mode 100644 index 48030f8d82dca..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/buffer.rs +++ /dev/null @@ -1,156 +0,0 @@ -//! Buffer management for same-process client<->server communication. - -use std::io::{self, Write}; -use std::mem; -use std::ops::{Deref, DerefMut}; -use std::slice; - -#[repr(C)] -pub struct Buffer { - data: *mut u8, - len: usize, - capacity: usize, - reserve: extern "C" fn(Buffer, usize) -> Buffer, - drop: extern "C" fn(Buffer), -} - -unsafe impl Sync for Buffer {} -unsafe impl Send for Buffer {} - -impl Default for Buffer { - #[inline] - fn default() -> Self { - Self::from(vec![]) - } -} - -impl Deref for Buffer { - type Target = [u8]; - #[inline] - fn deref(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.data as *const u8, self.len) } - } -} - -impl DerefMut for Buffer { - #[inline] - fn deref_mut(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.data, self.len) } - } -} - -impl Buffer { - #[inline] - pub(super) fn new() -> Self { - Self::default() - } - - #[inline] - pub(super) fn clear(&mut self) { - self.len = 0; - } - - #[inline] - pub(super) fn take(&mut self) -> Self { - mem::take(self) - } - - // We have the array method separate from extending from a slice. This is - // because in the case of small arrays, codegen can be more efficient - // (avoiding a memmove call). With extend_from_slice, LLVM at least - // currently is not able to make that optimization. - #[inline] - pub(super) fn extend_from_array(&mut self, xs: &[u8; N]) { - if xs.len() > (self.capacity - self.len) { - let b = self.take(); - *self = (b.reserve)(b, xs.len()); - } - unsafe { - xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len()); - self.len += xs.len(); - } - } - - #[inline] - pub(super) fn extend_from_slice(&mut self, xs: &[u8]) { - if xs.len() > (self.capacity - self.len) { - let b = self.take(); - *self = (b.reserve)(b, xs.len()); - } - unsafe { - xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len()); - self.len += xs.len(); - } - } - - #[inline] - pub(super) fn push(&mut self, v: u8) { - // The code here is taken from Vec::push, and we know that reserve() - // will panic if we're exceeding isize::MAX bytes and so there's no need - // to check for overflow. - if self.len == self.capacity { - let b = self.take(); - *self = (b.reserve)(b, 1); - } - unsafe { - *self.data.add(self.len) = v; - self.len += 1; - } - } -} - -impl Write for Buffer { - #[inline] - fn write(&mut self, xs: &[u8]) -> io::Result { - self.extend_from_slice(xs); - Ok(xs.len()) - } - - #[inline] - fn write_all(&mut self, xs: &[u8]) -> io::Result<()> { - self.extend_from_slice(xs); - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Drop for Buffer { - #[inline] - fn drop(&mut self) { - let b = self.take(); - (b.drop)(b); - } -} - -impl From> for Buffer { - fn from(mut v: Vec) -> Self { - let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity()); - mem::forget(v); - - // This utility function is nested in here because it can *only* - // be safely called on `Buffer`s created by *this* `proc_macro`. - fn to_vec(b: Buffer) -> Vec { - unsafe { - let Buffer { data, len, capacity, .. } = b; - mem::forget(b); - Vec::from_raw_parts(data, len, capacity) - } - } - - extern "C" fn reserve(b: Buffer, additional: usize) -> Buffer { - let mut v = to_vec(b); - v.reserve(additional); - Buffer::from(v) - } - - extern "C" fn drop(b: Buffer) { - mem::drop(to_vec(b)); - } - - Buffer { data, len, capacity, reserve, drop } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/client.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/client.rs deleted file mode 100644 index 102027d14a984..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/client.rs +++ /dev/null @@ -1,510 +0,0 @@ -//! Client-side types. - -use super::*; - -use std::marker::PhantomData; - -macro_rules! define_handles { - ( - 'owned: $($oty:ident,)* - 'interned: $($ity:ident,)* - ) => { - #[repr(C)] - #[allow(non_snake_case)] - pub struct HandleCounters { - $($oty: AtomicUsize,)* - $($ity: AtomicUsize,)* - } - - impl HandleCounters { - // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of - // a wrapper `fn` pointer, once `const fn` can reference `static`s. - extern "C" fn get() -> &'static Self { - static COUNTERS: HandleCounters = HandleCounters { - $($oty: AtomicUsize::new(1),)* - $($ity: AtomicUsize::new(1),)* - }; - &COUNTERS - } - } - - // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. - #[repr(C)] - #[allow(non_snake_case)] - pub(super) struct HandleStore { - $($oty: handle::OwnedStore,)* - $($ity: handle::InternedStore,)* - } - - impl HandleStore { - pub(super) fn new(handle_counters: &'static HandleCounters) -> Self { - HandleStore { - $($oty: handle::OwnedStore::new(&handle_counters.$oty),)* - $($ity: handle::InternedStore::new(&handle_counters.$ity),)* - } - } - } - - $( - #[repr(C)] - pub(crate) struct $oty { - handle: handle::Handle, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual - // way of doing this, but that requires unstable features. - // rust-analyzer uses this code and avoids unstable features. - _marker: PhantomData<*mut ()>, - } - - // Forward `Drop::drop` to the inherent `drop` method. - impl Drop for $oty { - fn drop(&mut self) { - $oty { - handle: self.handle, - _marker: PhantomData, - }.drop(); - } - } - - impl Encode for $oty { - fn encode(self, w: &mut Writer, s: &mut S) { - let handle = self.handle; - mem::forget(self); - handle.encode(w, s); - } - } - - impl DecodeMut<'_, '_, HandleStore>> - for Marked - { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { - s.$oty.take(handle::Handle::decode(r, &mut ())) - } - } - - impl Encode for &$oty { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl<'s, S: server::Types> Decode<'_, 's, HandleStore>> - for &'s Marked - { - fn decode(r: &mut Reader<'_>, s: &'s HandleStore>) -> Self { - &s.$oty[handle::Handle::decode(r, &mut ())] - } - } - - impl Encode for &mut $oty { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl<'s, S: server::Types> DecodeMut<'_, 's, HandleStore>> - for &'s mut Marked - { - fn decode( - r: &mut Reader<'_>, - s: &'s mut HandleStore> - ) -> Self { - &mut s.$oty[handle::Handle::decode(r, &mut ())] - } - } - - impl Encode>> - for Marked - { - fn encode(self, w: &mut Writer, s: &mut HandleStore>) { - s.$oty.alloc(self).encode(w, s); - } - } - - impl DecodeMut<'_, '_, S> for $oty { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - $oty { - handle: handle::Handle::decode(r, s), - _marker: PhantomData, - } - } - } - )* - - $( - #[repr(C)] - #[derive(Copy, Clone, PartialEq, Eq, Hash)] - pub(crate) struct $ity { - handle: handle::Handle, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual - // way of doing this, but that requires unstable features. - // rust-analyzer uses this code and avoids unstable features. - _marker: PhantomData<*mut ()>, - } - - impl Encode for $ity { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl DecodeMut<'_, '_, HandleStore>> - for Marked - { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { - s.$ity.copy(handle::Handle::decode(r, &mut ())) - } - } - - impl Encode>> - for Marked - { - fn encode(self, w: &mut Writer, s: &mut HandleStore>) { - s.$ity.alloc(self).encode(w, s); - } - } - - impl DecodeMut<'_, '_, S> for $ity { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - $ity { - handle: handle::Handle::decode(r, s), - _marker: PhantomData, - } - } - } - )* - } -} -define_handles! { - 'owned: - FreeFunctions, - TokenStream, - Group, - Literal, - SourceFile, - MultiSpan, - Diagnostic, - - 'interned: - Punct, - Ident, - Span, -} - -// FIXME(eddyb) generate these impls by pattern-matching on the -// names of methods - also could use the presence of `fn drop` -// to distinguish between 'owned and 'interned, above. -// Alternatively, special "modes" could be listed of types in with_api -// instead of pattern matching on methods, here and in server decl. - -impl Clone for TokenStream { - fn clone(&self) -> Self { - self.clone() - } -} - -impl Clone for Group { - fn clone(&self) -> Self { - self.clone() - } -} - -impl Clone for Literal { - fn clone(&self) -> Self { - self.clone() - } -} - -impl fmt::Debug for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Literal") - // format the kind without quotes, as in `kind: Float` - .field("kind", &format_args!("{}", &self.debug_kind())) - .field("symbol", &self.symbol()) - // format `Some("...")` on one line even in {:#?} mode - .field("suffix", &format_args!("{:?}", &self.suffix())) - .field("span", &self.span()) - .finish() - } -} - -impl Clone for SourceFile { - fn clone(&self) -> Self { - self.clone() - } -} - -impl fmt::Debug for Span { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.debug()) - } -} - -macro_rules! define_client_side { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }),* $(,)?) => { - $(impl $name { - $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* { - Bridge::with(|bridge| { - let mut buf = bridge.cached_buffer.take(); - - buf.clear(); - api_tags::Method::$name(api_tags::$name::$method).encode(&mut buf, &mut ()); - reverse_encode!(buf; $($arg),*); - - buf = bridge.dispatch.call(buf); - - let r = Result::<_, PanicMessage>::decode(&mut &buf[..], &mut ()); - - bridge.cached_buffer = buf; - - r.unwrap_or_else(|e| panic::resume_unwind(e.into())) - }) - })* - })* - } -} -with_api!(self, self, define_client_side); - -enum BridgeState<'a> { - /// No server is currently connected to this client. - NotConnected, - - /// A server is connected and available for requests. - Connected(Bridge<'a>), - - /// Access to the bridge is being exclusively acquired - /// (e.g., during `BridgeState::with`). - InUse, -} - -enum BridgeStateL {} - -impl<'a> scoped_cell::ApplyL<'a> for BridgeStateL { - type Out = BridgeState<'a>; -} - -thread_local! { - static BRIDGE_STATE: scoped_cell::ScopedCell = - scoped_cell::ScopedCell::new(BridgeState::NotConnected); -} - -impl BridgeState<'_> { - /// Take exclusive control of the thread-local - /// `BridgeState`, and pass it to `f`, mutably. - /// The state will be restored after `f` exits, even - /// by panic, including modifications made to it by `f`. - /// - /// N.B., while `f` is running, the thread-local state - /// is `BridgeState::InUse`. - fn with(f: impl FnOnce(&mut BridgeState<'_>) -> R) -> R { - BRIDGE_STATE.with(|state| { - state.replace(BridgeState::InUse, |mut state| { - // FIXME(#52812) pass `f` directly to `replace` when `RefMutL` is gone - f(&mut *state) - }) - }) - } -} - -impl Bridge<'_> { - pub(crate) fn is_available() -> bool { - BridgeState::with(|state| match state { - BridgeState::Connected(_) | BridgeState::InUse => true, - BridgeState::NotConnected => false, - }) - } - - fn enter(self, f: impl FnOnce() -> R) -> R { - let force_show_panics = self.force_show_panics; - // Hide the default panic output within `proc_macro` expansions. - // NB. the server can't do this because it may use a different libstd. - static HIDE_PANICS_DURING_EXPANSION: Once = Once::new(); - HIDE_PANICS_DURING_EXPANSION.call_once(|| { - let prev = panic::take_hook(); - panic::set_hook(Box::new(move |info| { - let show = BridgeState::with(|state| match state { - BridgeState::NotConnected => true, - BridgeState::Connected(_) | BridgeState::InUse => force_show_panics, - }); - if show { - prev(info) - } - })); - }); - - BRIDGE_STATE.with(|state| state.set(BridgeState::Connected(self), f)) - } - - fn with(f: impl FnOnce(&mut Bridge<'_>) -> R) -> R { - BridgeState::with(|state| match state { - BridgeState::NotConnected => { - panic!("procedural macro API is used outside of a procedural macro"); - } - BridgeState::InUse => { - panic!("procedural macro API is used while it's already in use"); - } - BridgeState::Connected(bridge) => f(bridge), - }) - } -} - -/// A client-side RPC entry-point, which may be using a different `proc_macro` -/// from the one used by the server, but can be invoked compatibly. -/// -/// Note that the (phantom) `I` ("input") and `O` ("output") type parameters -/// decorate the `Client` with the RPC "interface" of the entry-point, but -/// do not themselves participate in ABI, at all, only facilitate type-checking. -/// -/// E.g. `Client` is the common proc macro interface, -/// used for `#[proc_macro] fn foo(input: TokenStream) -> TokenStream`, -/// indicating that the RPC input and output will be serialized token streams, -/// and forcing the use of APIs that take/return `S::TokenStream`, server-side. -#[repr(C)] -pub struct Client { - // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of - // a wrapper `fn` pointer, once `const fn` can reference `static`s. - pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters, - - pub(super) run: extern "C" fn(Bridge<'_>) -> Buffer, - - pub(super) _marker: PhantomData O>, -} - -impl Copy for Client {} -impl Clone for Client { - fn clone(&self) -> Self { - *self - } -} - -/// Client-side helper for handling client panics, entering the bridge, -/// deserializing input and serializing output. -// FIXME(eddyb) maybe replace `Bridge::enter` with this? -fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( - mut bridge: Bridge<'_>, - f: impl FnOnce(A) -> R, -) -> Buffer { - // The initial `cached_buffer` contains the input. - let mut buf = bridge.cached_buffer.take(); - - panic::catch_unwind(panic::AssertUnwindSafe(|| { - bridge.enter(|| { - let reader = &mut &buf[..]; - let input = A::decode(reader, &mut ()); - - // Put the `cached_buffer` back in the `Bridge`, for requests. - Bridge::with(|bridge| bridge.cached_buffer = buf.take()); - - let output = f(input); - - // Take the `cached_buffer` back out, for the output value. - buf = Bridge::with(|bridge| bridge.cached_buffer.take()); - - // HACK(eddyb) Separate encoding a success value (`Ok(output)`) - // from encoding a panic (`Err(e: PanicMessage)`) to avoid - // having handles outside the `bridge.enter(|| ...)` scope, and - // to catch panics that could happen while encoding the success. - // - // Note that panics should be impossible beyond this point, but - // this is defensively trying to avoid any accidental panicking - // reaching the `extern "C"` (which should `abort` but might not - // at the moment, so this is also potentially preventing UB). - buf.clear(); - Ok::<_, ()>(output).encode(&mut buf, &mut ()); - }) - })) - .map_err(PanicMessage::from) - .unwrap_or_else(|e| { - buf.clear(); - Err::<(), _>(e).encode(&mut buf, &mut ()); - }); - buf -} - -impl Client { - pub const fn expand1( - f: impl Fn(super::super::TokenStream) -> super::super::TokenStream + Copy, - ) -> Self { - Client { - get_handle_counters: HandleCounters::get, - run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| { - run_client(bridge, |input| f(super::super::TokenStream(input)).0) - }), - _marker: PhantomData, - } - } -} - -impl Client<(super::super::TokenStream, super::super::TokenStream), super::super::TokenStream> { - pub const fn expand2( - f: impl Fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream - + Copy, - ) -> Self { - Client { - get_handle_counters: HandleCounters::get, - run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| { - run_client(bridge, |(input, input2)| { - f(super::super::TokenStream(input), super::super::TokenStream(input2)).0 - }) - }), - _marker: PhantomData, - } - } -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum ProcMacro { - CustomDerive { - trait_name: &'static str, - attributes: &'static [&'static str], - client: Client, - }, - - Attr { - name: &'static str, - client: Client< - (super::super::TokenStream, super::super::TokenStream), - super::super::TokenStream, - >, - }, - - Bang { - name: &'static str, - client: Client, - }, -} - -impl ProcMacro { - pub fn name(&self) -> &'static str { - match self { - ProcMacro::CustomDerive { trait_name, .. } => trait_name, - ProcMacro::Attr { name, .. } => name, - ProcMacro::Bang { name, .. } => name, - } - } - - pub const fn custom_derive( - trait_name: &'static str, - attributes: &'static [&'static str], - expand: impl Fn(super::super::TokenStream) -> super::super::TokenStream + Copy, - ) -> Self { - ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) } - } - - pub const fn attr( - name: &'static str, - expand: impl Fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream - + Copy, - ) -> Self { - ProcMacro::Attr { name, client: Client::expand2(expand) } - } - - pub const fn bang( - name: &'static str, - expand: impl Fn(super::super::TokenStream) -> super::super::TokenStream + Copy, - ) -> Self { - ProcMacro::Bang { name, client: Client::expand1(expand) } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/closure.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/closure.rs deleted file mode 100644 index d371ae3cea098..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/closure.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Closure type (equivalent to `&mut dyn FnMut(A) -> R`) that's `repr(C)`. - -use std::marker::PhantomData; - -#[repr(C)] -pub struct Closure<'a, A, R> { - call: unsafe extern "C" fn(*mut Env, A) -> R, - env: *mut Env, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing - // this, but that requires unstable features. rust-analyzer uses this code - // and avoids unstable features. - // - // The `'a` lifetime parameter represents the lifetime of `Env`. - _marker: PhantomData<*mut &'a mut ()>, -} - -struct Env; - -impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> { - fn from(f: &'a mut F) -> Self { - unsafe extern "C" fn call R>(env: *mut Env, arg: A) -> R { - (*(env as *mut _ as *mut F))(arg) - } - Closure { call: call::, env: f as *mut _ as *mut Env, _marker: PhantomData } - } -} - -impl<'a, A, R> Closure<'a, A, R> { - pub fn call(&mut self, arg: A) -> R { - unsafe { (self.call)(self.env, arg) } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/handle.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/handle.rs deleted file mode 100644 index c219a9465d39f..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/handle.rs +++ /dev/null @@ -1,89 +0,0 @@ -//! Server-side handles and storage for per-handle data. - -use std::collections::{BTreeMap, HashMap}; -use std::hash::{BuildHasher, Hash}; -use std::num::NonZeroU32; -use std::ops::{Index, IndexMut}; -use std::sync::atomic::{AtomicUsize, Ordering}; - -pub(super) type Handle = NonZeroU32; - -/// A store that associates values of type `T` with numeric handles. A value can -/// be looked up using its handle. -pub(super) struct OwnedStore { - counter: &'static AtomicUsize, - data: BTreeMap, -} - -impl OwnedStore { - pub(super) fn new(counter: &'static AtomicUsize) -> Self { - // Ensure the handle counter isn't 0, which would panic later, - // when `NonZeroU32::new` (aka `Handle::new`) is called in `alloc`. - assert_ne!(counter.load(Ordering::SeqCst), 0); - - OwnedStore { counter, data: BTreeMap::new() } - } -} - -impl OwnedStore { - pub(super) fn alloc(&mut self, x: T) -> Handle { - let counter = self.counter.fetch_add(1, Ordering::SeqCst); - let handle = Handle::new(counter as u32).expect("`proc_macro` handle counter overflowed"); - assert!(self.data.insert(handle, x).is_none()); - handle - } - - pub(super) fn take(&mut self, h: Handle) -> T { - self.data.remove(&h).expect("use-after-free in `proc_macro` handle") - } -} - -impl Index for OwnedStore { - type Output = T; - fn index(&self, h: Handle) -> &T { - self.data.get(&h).expect("use-after-free in `proc_macro` handle") - } -} - -impl IndexMut for OwnedStore { - fn index_mut(&mut self, h: Handle) -> &mut T { - self.data.get_mut(&h).expect("use-after-free in `proc_macro` handle") - } -} - -// HACK(eddyb) deterministic `std::collections::hash_map::RandomState` replacement -// that doesn't require adding any dependencies to `proc_macro` (like `rustc-hash`). -#[derive(Clone)] -struct NonRandomState; - -impl BuildHasher for NonRandomState { - type Hasher = std::collections::hash_map::DefaultHasher; - #[inline] - fn build_hasher(&self) -> Self::Hasher { - Self::Hasher::new() - } -} - -/// Like `OwnedStore`, but avoids storing any value more than once. -pub(super) struct InternedStore { - owned: OwnedStore, - interner: HashMap, -} - -impl InternedStore { - pub(super) fn new(counter: &'static AtomicUsize) -> Self { - InternedStore { - owned: OwnedStore::new(counter), - interner: HashMap::with_hasher(NonRandomState), - } - } - - pub(super) fn alloc(&mut self, x: T) -> Handle { - let owned = &mut self.owned; - *self.interner.entry(x).or_insert_with(|| owned.alloc(x)) - } - - pub(super) fn copy(&mut self, h: Handle) -> T { - self.owned[h] - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/mod.rs deleted file mode 100644 index 4967da4931a28..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/mod.rs +++ /dev/null @@ -1,451 +0,0 @@ -//! Internal interface for communicating between a `proc_macro` client -//! (a proc macro crate) and a `proc_macro` server (a compiler front-end). -//! -//! Serialization (with C ABI buffers) and unique integer handles are employed -//! to allow safely interfacing between two copies of `proc_macro` built -//! (from the same source) by different compilers with potentially mismatching -//! Rust ABIs (e.g., stage0/bin/rustc vs stage1/bin/rustc during bootstrap). - -#![deny(unsafe_code)] - -pub use super::{Delimiter, Level, LineColumn, Spacing}; -use std::fmt; -use std::hash::Hash; -use std::marker; -use std::mem; -use std::ops::Bound; -use std::panic; -use std::sync::atomic::AtomicUsize; -use std::sync::Once; -use std::thread; - -/// Higher-order macro describing the server RPC API, allowing automatic -/// generation of type-safe Rust APIs, both client-side and server-side. -/// -/// `with_api!(MySelf, my_self, my_macro)` expands to: -/// ```rust,ignore (pseudo-code) -/// my_macro! { -/// // ... -/// Literal { -/// // ... -/// fn character(ch: char) -> MySelf::Literal; -/// // ... -/// fn span(my_self: &MySelf::Literal) -> MySelf::Span; -/// fn set_span(my_self: &mut MySelf::Literal, span: MySelf::Span); -/// }, -/// // ... -/// } -/// ``` -/// -/// The first two arguments serve to customize the arguments names -/// and argument/return types, to enable several different usecases: -/// -/// If `my_self` is just `self`, then each `fn` signature can be used -/// as-is for a method. If it's anything else (`self_` in practice), -/// then the signatures don't have a special `self` argument, and -/// can, therefore, have a different one introduced. -/// -/// If `MySelf` is just `Self`, then the types are only valid inside -/// a trait or a trait impl, where the trait has associated types -/// for each of the API types. If non-associated types are desired, -/// a module name (`self` in practice) can be used instead of `Self`. -macro_rules! with_api { - ($S:ident, $self:ident, $m:ident) => { - $m! { - FreeFunctions { - fn drop($self: $S::FreeFunctions); - fn track_env_var(var: &str, value: Option<&str>); - fn track_path(path: &str); - }, - TokenStream { - fn drop($self: $S::TokenStream); - fn clone($self: &$S::TokenStream) -> $S::TokenStream; - fn is_empty($self: &$S::TokenStream) -> bool; - fn expand_expr($self: &$S::TokenStream) -> Result<$S::TokenStream, ()>; - fn from_str(src: &str) -> $S::TokenStream; - fn to_string($self: &$S::TokenStream) -> String; - fn from_token_tree( - tree: TokenTree<$S::Group, $S::Punct, $S::Ident, $S::Literal>, - ) -> $S::TokenStream; - fn concat_trees( - base: Option<$S::TokenStream>, - trees: Vec>, - ) -> $S::TokenStream; - fn concat_streams( - base: Option<$S::TokenStream>, - streams: Vec<$S::TokenStream>, - ) -> $S::TokenStream; - fn into_trees( - $self: $S::TokenStream - ) -> Vec>; - }, - Group { - fn drop($self: $S::Group); - fn clone($self: &$S::Group) -> $S::Group; - fn new(delimiter: Delimiter, stream: Option<$S::TokenStream>) -> $S::Group; - fn delimiter($self: &$S::Group) -> Delimiter; - fn stream($self: &$S::Group) -> $S::TokenStream; - fn span($self: &$S::Group) -> $S::Span; - fn span_open($self: &$S::Group) -> $S::Span; - fn span_close($self: &$S::Group) -> $S::Span; - fn set_span($self: &mut $S::Group, span: $S::Span); - }, - Punct { - fn new(ch: char, spacing: Spacing) -> $S::Punct; - fn as_char($self: $S::Punct) -> char; - fn spacing($self: $S::Punct) -> Spacing; - fn span($self: $S::Punct) -> $S::Span; - fn with_span($self: $S::Punct, span: $S::Span) -> $S::Punct; - }, - Ident { - fn new(string: &str, span: $S::Span, is_raw: bool) -> $S::Ident; - fn span($self: $S::Ident) -> $S::Span; - fn with_span($self: $S::Ident, span: $S::Span) -> $S::Ident; - }, - Literal { - fn drop($self: $S::Literal); - fn clone($self: &$S::Literal) -> $S::Literal; - fn from_str(s: &str) -> Result<$S::Literal, ()>; - fn to_string($self: &$S::Literal) -> String; - fn debug_kind($self: &$S::Literal) -> String; - fn symbol($self: &$S::Literal) -> String; - fn suffix($self: &$S::Literal) -> Option; - fn integer(n: &str) -> $S::Literal; - fn typed_integer(n: &str, kind: &str) -> $S::Literal; - fn float(n: &str) -> $S::Literal; - fn f32(n: &str) -> $S::Literal; - fn f64(n: &str) -> $S::Literal; - fn string(string: &str) -> $S::Literal; - fn character(ch: char) -> $S::Literal; - fn byte_string(bytes: &[u8]) -> $S::Literal; - fn span($self: &$S::Literal) -> $S::Span; - fn set_span($self: &mut $S::Literal, span: $S::Span); - fn subspan( - $self: &$S::Literal, - start: Bound, - end: Bound, - ) -> Option<$S::Span>; - }, - SourceFile { - fn drop($self: $S::SourceFile); - fn clone($self: &$S::SourceFile) -> $S::SourceFile; - fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool; - fn path($self: &$S::SourceFile) -> String; - fn is_real($self: &$S::SourceFile) -> bool; - }, - MultiSpan { - fn drop($self: $S::MultiSpan); - fn new() -> $S::MultiSpan; - fn push($self: &mut $S::MultiSpan, span: $S::Span); - }, - Diagnostic { - fn drop($self: $S::Diagnostic); - fn new(level: Level, msg: &str, span: $S::MultiSpan) -> $S::Diagnostic; - fn sub( - $self: &mut $S::Diagnostic, - level: Level, - msg: &str, - span: $S::MultiSpan, - ); - fn emit($self: $S::Diagnostic); - }, - Span { - fn debug($self: $S::Span) -> String; - fn def_site() -> $S::Span; - fn call_site() -> $S::Span; - fn mixed_site() -> $S::Span; - fn source_file($self: $S::Span) -> $S::SourceFile; - fn parent($self: $S::Span) -> Option<$S::Span>; - fn source($self: $S::Span) -> $S::Span; - fn start($self: $S::Span) -> LineColumn; - fn end($self: $S::Span) -> LineColumn; - fn before($self: $S::Span) -> $S::Span; - fn after($self: $S::Span) -> $S::Span; - fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; - fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span; - fn source_text($self: $S::Span) -> Option; - fn save_span($self: $S::Span) -> usize; - fn recover_proc_macro_span(id: usize) -> $S::Span; - }, - } - }; -} - -// FIXME(eddyb) this calls `encode` for each argument, but in reverse, -// to match the ordering in `reverse_decode`. -macro_rules! reverse_encode { - ($writer:ident;) => {}; - ($writer:ident; $first:ident $(, $rest:ident)*) => { - reverse_encode!($writer; $($rest),*); - $first.encode(&mut $writer, &mut ()); - } -} - -// FIXME(eddyb) this calls `decode` for each argument, but in reverse, -// to avoid borrow conflicts from borrows started by `&mut` arguments. -macro_rules! reverse_decode { - ($reader:ident, $s:ident;) => {}; - ($reader:ident, $s:ident; $first:ident: $first_ty:ty $(, $rest:ident: $rest_ty:ty)*) => { - reverse_decode!($reader, $s; $($rest: $rest_ty),*); - let $first = <$first_ty>::decode(&mut $reader, $s); - } -} - -#[allow(unsafe_code)] -mod buffer; -#[forbid(unsafe_code)] -pub mod client; -#[allow(unsafe_code)] -mod closure; -#[forbid(unsafe_code)] -mod handle; -#[macro_use] -#[forbid(unsafe_code)] -mod rpc; -#[allow(unsafe_code)] -mod scoped_cell; -#[allow(unsafe_code)] -mod selfless_reify; -#[forbid(unsafe_code)] -pub mod server; - -use buffer::Buffer; -pub use rpc::PanicMessage; -use rpc::{Decode, DecodeMut, Encode, Reader, Writer}; - -/// An active connection between a server and a client. -/// The server creates the bridge (`Bridge::run_server` in `server.rs`), -/// then passes it to the client through the function pointer in the `run` -/// field of `client::Client`. The client holds its copy of the `Bridge` -/// in TLS during its execution (`Bridge::{enter, with}` in `client.rs`). -#[repr(C)] -pub struct Bridge<'a> { - /// Reusable buffer (only `clear`-ed, never shrunk), primarily - /// used for making requests, but also for passing input to client. - cached_buffer: Buffer, - - /// Server-side function that the client uses to make requests. - dispatch: closure::Closure<'a, Buffer, Buffer>, - - /// If 'true', always invoke the default panic hook - force_show_panics: bool, - - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing - // this, but that requires unstable features. rust-analyzer uses this code - // and avoids unstable features. - _marker: marker::PhantomData<*mut ()>, -} - -#[forbid(unsafe_code)] -#[allow(non_camel_case_types)] -mod api_tags { - use super::rpc::{DecodeMut, Encode, Reader, Writer}; - - macro_rules! declare_tags { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }),* $(,)?) => { - $( - pub(super) enum $name { - $($method),* - } - rpc_encode_decode!(enum $name { $($method),* }); - )* - - pub(super) enum Method { - $($name($name)),* - } - rpc_encode_decode!(enum Method { $($name(m)),* }); - } - } - with_api!(self, self, declare_tags); -} - -/// Helper to wrap associated types to allow trait impl dispatch. -/// That is, normally a pair of impls for `T::Foo` and `T::Bar` -/// can overlap, but if the impls are, instead, on types like -/// `Marked` and `Marked`, they can't. -trait Mark { - type Unmarked; - fn mark(unmarked: Self::Unmarked) -> Self; -} - -/// Unwrap types wrapped by `Mark::mark` (see `Mark` for details). -trait Unmark { - type Unmarked; - fn unmark(self) -> Self::Unmarked; -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -struct Marked { - value: T, - _marker: marker::PhantomData, -} - -impl Mark for Marked { - type Unmarked = T; - fn mark(unmarked: Self::Unmarked) -> Self { - Marked { value: unmarked, _marker: marker::PhantomData } - } -} -impl Unmark for Marked { - type Unmarked = T; - fn unmark(self) -> Self::Unmarked { - self.value - } -} -impl<'a, T, M> Unmark for &'a Marked { - type Unmarked = &'a T; - fn unmark(self) -> Self::Unmarked { - &self.value - } -} -impl<'a, T, M> Unmark for &'a mut Marked { - type Unmarked = &'a mut T; - fn unmark(self) -> Self::Unmarked { - &mut self.value - } -} - -impl Mark for Vec { - type Unmarked = Vec; - fn mark(unmarked: Self::Unmarked) -> Self { - // Should be a no-op due to std's in-place collect optimizations. - unmarked.into_iter().map(T::mark).collect() - } -} -impl Unmark for Vec { - type Unmarked = Vec; - fn unmark(self) -> Self::Unmarked { - // Should be a no-op due to std's in-place collect optimizations. - self.into_iter().map(T::unmark).collect() - } -} - -macro_rules! mark_noop { - ($($ty:ty),* $(,)?) => { - $( - impl Mark for $ty { - type Unmarked = Self; - fn mark(unmarked: Self::Unmarked) -> Self { - unmarked - } - } - impl Unmark for $ty { - type Unmarked = Self; - fn unmark(self) -> Self::Unmarked { - self - } - } - )* - } -} -mark_noop! { - (), - bool, - char, - &'_ [u8], - &'_ str, - String, - usize, - Delimiter, - Level, - LineColumn, - Spacing, -} - -rpc_encode_decode!( - enum Delimiter { - Parenthesis, - Brace, - Bracket, - None, - } -); -rpc_encode_decode!( - enum Level { - Error, - Warning, - Note, - Help, - } -); -rpc_encode_decode!(struct LineColumn { line, column }); -rpc_encode_decode!( - enum Spacing { - Alone, - Joint, - } -); - -macro_rules! mark_compound { - (enum $name:ident <$($T:ident),+> { $($variant:ident $(($field:ident))?),* $(,)? }) => { - impl<$($T: Mark),+> Mark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; - fn mark(unmarked: Self::Unmarked) -> Self { - match unmarked { - $($name::$variant $(($field))? => { - $name::$variant $((Mark::mark($field)))? - })* - } - } - } - - impl<$($T: Unmark),+> Unmark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; - fn unmark(self) -> Self::Unmarked { - match self { - $($name::$variant $(($field))? => { - $name::$variant $((Unmark::unmark($field)))? - })* - } - } - } - } -} - -macro_rules! compound_traits { - ($($t:tt)*) => { - rpc_encode_decode!($($t)*); - mark_compound!($($t)*); - }; -} - -compound_traits!( - enum Bound { - Included(x), - Excluded(x), - Unbounded, - } -); - -compound_traits!( - enum Option { - Some(t), - None, - } -); - -compound_traits!( - enum Result { - Ok(t), - Err(e), - } -); - -#[derive(Clone)] -pub enum TokenTree { - Group(G), - Punct(P), - Ident(I), - Literal(L), -} - -compound_traits!( - enum TokenTree { - Group(tt), - Punct(tt), - Ident(tt), - Literal(tt), - } -); diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/rpc.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/rpc.rs deleted file mode 100644 index e9d7a46c06f6d..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/rpc.rs +++ /dev/null @@ -1,304 +0,0 @@ -//! Serialization for client-server communication. - -use std::any::Any; -use std::char; -use std::io::Write; -use std::num::NonZeroU32; -use std::str; - -pub(super) type Writer = super::buffer::Buffer; - -pub(super) trait Encode: Sized { - fn encode(self, w: &mut Writer, s: &mut S); -} - -pub(super) type Reader<'a> = &'a [u8]; - -pub(super) trait Decode<'a, 's, S>: Sized { - fn decode(r: &mut Reader<'a>, s: &'s S) -> Self; -} - -pub(super) trait DecodeMut<'a, 's, S>: Sized { - fn decode(r: &mut Reader<'a>, s: &'s mut S) -> Self; -} - -macro_rules! rpc_encode_decode { - (le $ty:ty) => { - impl Encode for $ty { - fn encode(self, w: &mut Writer, _: &mut S) { - w.extend_from_array(&self.to_le_bytes()); - } - } - - impl DecodeMut<'_, '_, S> for $ty { - fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { - const N: usize = ::std::mem::size_of::<$ty>(); - - let mut bytes = [0; N]; - bytes.copy_from_slice(&r[..N]); - *r = &r[N..]; - - Self::from_le_bytes(bytes) - } - } - }; - (struct $name:ident $(<$($T:ident),+>)? { $($field:ident),* $(,)? }) => { - impl),+)?> Encode for $name $(<$($T),+>)? { - fn encode(self, w: &mut Writer, s: &mut S) { - $(self.$field.encode(w, s);)* - } - } - - impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S> - for $name $(<$($T),+>)? - { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - $name { - $($field: DecodeMut::decode(r, s)),* - } - } - } - }; - (enum $name:ident $(<$($T:ident),+>)? { $($variant:ident $(($field:ident))*),* $(,)? }) => { - impl),+)?> Encode for $name $(<$($T),+>)? { - fn encode(self, w: &mut Writer, s: &mut S) { - // HACK(eddyb): `Tag` enum duplicated between the - // two impls as there's no other place to stash it. - #[allow(non_upper_case_globals)] - mod tag { - #[repr(u8)] enum Tag { $($variant),* } - - $(pub const $variant: u8 = Tag::$variant as u8;)* - } - - match self { - $($name::$variant $(($field))* => { - tag::$variant.encode(w, s); - $($field.encode(w, s);)* - })* - } - } - } - - impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S> - for $name $(<$($T),+>)? - { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - // HACK(eddyb): `Tag` enum duplicated between the - // two impls as there's no other place to stash it. - #[allow(non_upper_case_globals)] - mod tag { - #[repr(u8)] enum Tag { $($variant),* } - - $(pub const $variant: u8 = Tag::$variant as u8;)* - } - - match u8::decode(r, s) { - $(tag::$variant => { - $(let $field = DecodeMut::decode(r, s);)* - $name::$variant $(($field))* - })* - _ => unreachable!(), - } - } - } - } -} - -impl Encode for () { - fn encode(self, _: &mut Writer, _: &mut S) {} -} - -impl DecodeMut<'_, '_, S> for () { - fn decode(_: &mut Reader<'_>, _: &mut S) -> Self {} -} - -impl Encode for u8 { - fn encode(self, w: &mut Writer, _: &mut S) { - w.push(self); - } -} - -impl DecodeMut<'_, '_, S> for u8 { - fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { - let x = r[0]; - *r = &r[1..]; - x - } -} - -rpc_encode_decode!(le u32); -rpc_encode_decode!(le usize); - -impl Encode for bool { - fn encode(self, w: &mut Writer, s: &mut S) { - (self as u8).encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for bool { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - match u8::decode(r, s) { - 0 => false, - 1 => true, - _ => unreachable!(), - } - } -} - -impl Encode for char { - fn encode(self, w: &mut Writer, s: &mut S) { - (self as u32).encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for char { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - char::from_u32(u32::decode(r, s)).unwrap() - } -} - -impl Encode for NonZeroU32 { - fn encode(self, w: &mut Writer, s: &mut S) { - self.get().encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for NonZeroU32 { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - Self::new(u32::decode(r, s)).unwrap() - } -} - -impl, B: Encode> Encode for (A, B) { - fn encode(self, w: &mut Writer, s: &mut S) { - self.0.encode(w, s); - self.1.encode(w, s); - } -} - -impl<'a, S, A: for<'s> DecodeMut<'a, 's, S>, B: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S> - for (A, B) -{ - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - (DecodeMut::decode(r, s), DecodeMut::decode(r, s)) - } -} - -impl Encode for &[u8] { - fn encode(self, w: &mut Writer, s: &mut S) { - self.len().encode(w, s); - w.write_all(self).unwrap(); - } -} - -impl<'a, S> DecodeMut<'a, '_, S> for &'a [u8] { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - let len = usize::decode(r, s); - let xs = &r[..len]; - *r = &r[len..]; - xs - } -} - -impl Encode for &str { - fn encode(self, w: &mut Writer, s: &mut S) { - self.as_bytes().encode(w, s); - } -} - -impl<'a, S> DecodeMut<'a, '_, S> for &'a str { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - str::from_utf8(<&[u8]>::decode(r, s)).unwrap() - } -} - -impl Encode for String { - fn encode(self, w: &mut Writer, s: &mut S) { - self[..].encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for String { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - <&str>::decode(r, s).to_string() - } -} - -impl> Encode for Vec { - fn encode(self, w: &mut Writer, s: &mut S) { - self.len().encode(w, s); - for x in self { - x.encode(w, s); - } - } -} - -impl<'a, S, T: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S> for Vec { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - let len = usize::decode(r, s); - let mut vec = Vec::with_capacity(len); - for _ in 0..len { - vec.push(T::decode(r, s)); - } - vec - } -} - -/// Simplified version of panic payloads, ignoring -/// types other than `&'static str` and `String`. -pub enum PanicMessage { - StaticStr(&'static str), - String(String), - Unknown, -} - -impl From> for PanicMessage { - fn from(payload: Box) -> Self { - if let Some(s) = payload.downcast_ref::<&'static str>() { - return PanicMessage::StaticStr(s); - } - if let Ok(s) = payload.downcast::() { - return PanicMessage::String(*s); - } - PanicMessage::Unknown - } -} - -impl Into> for PanicMessage { - fn into(self) -> Box { - match self { - PanicMessage::StaticStr(s) => Box::new(s), - PanicMessage::String(s) => Box::new(s), - PanicMessage::Unknown => { - struct UnknownPanicMessage; - Box::new(UnknownPanicMessage) - } - } - } -} - -impl PanicMessage { - pub fn as_str(&self) -> Option<&str> { - match self { - PanicMessage::StaticStr(s) => Some(s), - PanicMessage::String(s) => Some(s), - PanicMessage::Unknown => None, - } - } -} - -impl Encode for PanicMessage { - fn encode(self, w: &mut Writer, s: &mut S) { - self.as_str().encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for PanicMessage { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - match Option::::decode(r, s) { - Some(s) => PanicMessage::String(s), - None => PanicMessage::Unknown, - } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/scoped_cell.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/scoped_cell.rs deleted file mode 100644 index 2cde1f65adf9c..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/scoped_cell.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! `Cell` variant for (scoped) existential lifetimes. - -use std::cell::Cell; -use std::mem; -use std::ops::{Deref, DerefMut}; - -/// Type lambda application, with a lifetime. -#[allow(unused_lifetimes)] -pub trait ApplyL<'a> { - type Out; -} - -/// Type lambda taking a lifetime, i.e., `Lifetime -> Type`. -pub trait LambdaL: for<'a> ApplyL<'a> {} - -impl ApplyL<'a>> LambdaL for T {} - -// HACK(eddyb) work around projection limitations with a newtype -// FIXME(#52812) replace with `&'a mut >::Out` -pub struct RefMutL<'a, 'b, T: LambdaL>(&'a mut >::Out); - -impl<'a, 'b, T: LambdaL> Deref for RefMutL<'a, 'b, T> { - type Target = >::Out; - fn deref(&self) -> &Self::Target { - self.0 - } -} - -impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.0 - } -} - -pub struct ScopedCell(Cell<>::Out>); - -impl ScopedCell { - pub const fn new(value: >::Out) -> Self { - ScopedCell(Cell::new(value)) - } - - /// Sets the value in `self` to `replacement` while - /// running `f`, which gets the old value, mutably. - /// The old value will be restored after `f` exits, even - /// by panic, including modifications made to it by `f`. - pub fn replace<'a, R>( - &self, - replacement: >::Out, - f: impl for<'b, 'c> FnOnce(RefMutL<'b, 'c, T>) -> R, - ) -> R { - /// Wrapper that ensures that the cell always gets filled - /// (with the original state, optionally changed by `f`), - /// even if `f` had panicked. - struct PutBackOnDrop<'a, T: LambdaL> { - cell: &'a ScopedCell, - value: Option<>::Out>, - } - - impl<'a, T: LambdaL> Drop for PutBackOnDrop<'a, T> { - fn drop(&mut self) { - self.cell.0.set(self.value.take().unwrap()); - } - } - - let mut put_back_on_drop = PutBackOnDrop { - cell: self, - value: Some(self.0.replace(unsafe { - let erased = mem::transmute_copy(&replacement); - mem::forget(replacement); - erased - })), - }; - - f(RefMutL(put_back_on_drop.value.as_mut().unwrap())) - } - - /// Sets the value in `self` to `value` while running `f`. - pub fn set(&self, value: >::Out, f: impl FnOnce() -> R) -> R { - self.replace(value, |_| f()) - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/selfless_reify.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/selfless_reify.rs deleted file mode 100644 index 4ee4bb87c2bbd..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/selfless_reify.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! Abstraction for creating `fn` pointers from any callable that *effectively* -//! has the equivalent of implementing `Default`, even if the compiler neither -//! provides `Default` nor allows reifying closures (i.e. creating `fn` pointers) -//! other than those with absolutely no captures. -//! -//! More specifically, for a closure-like type to be "effectively `Default`": -//! * it must be a ZST (zero-sized type): no information contained within, so -//! that `Default`'s return value (if it were implemented) is unambiguous -//! * it must be `Copy`: no captured "unique ZST tokens" or any other similar -//! types that would make duplicating values at will unsound -//! * combined with the ZST requirement, this confers a kind of "telecopy" -//! ability: similar to `Copy`, but without keeping the value around, and -//! instead "reconstructing" it (a noop given it's a ZST) when needed -//! * it must be *provably* inhabited: no captured uninhabited types or any -//! other types that cannot be constructed by the user of this abstraction -//! * the proof is a value of the closure-like type itself, in a sense the -//! "seed" for the "telecopy" process made possible by ZST + `Copy` -//! * this requirement is the only reason an abstraction limited to a specific -//! usecase is required: ZST + `Copy` can be checked with *at worst* a panic -//! at the "attempted `::default()` call" time, but that doesn't guarantee -//! that the value can be soundly created, and attempting to use the typical -//! "proof ZST token" approach leads yet again to having a ZST + `Copy` type -//! that is not proof of anything without a value (i.e. isomorphic to a -//! newtype of the type it's trying to prove the inhabitation of) -//! -//! A more flexible (and safer) solution to the general problem could exist once -//! `const`-generic parameters can have type parameters in their types: -//! -//! ```rust,ignore (needs future const-generics) -//! extern "C" fn ffi_wrapper< -//! A, R, -//! F: Fn(A) -> R, -//! const f: F, // <-- this `const`-generic is not yet allowed -//! >(arg: A) -> R { -//! f(arg) -//! } -//! ``` - -use std::mem; - -// FIXME(eddyb) this could be `trait` impls except for the `const fn` requirement. -macro_rules! define_reify_functions { - ($( - fn $name:ident $(<$($param:ident),*>)? - for $(extern $abi:tt)? fn($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty; - )+) => { - $(pub const fn $name< - $($($param,)*)? - F: Fn($($arg_ty),*) -> $ret_ty + Copy - >(f: F) -> $(extern $abi)? fn($($arg_ty),*) -> $ret_ty { - // FIXME(eddyb) describe the `F` type (e.g. via `type_name::`) once panic - // formatting becomes possible in `const fn`. - assert!(mem::size_of::() == 0, "selfless_reify: closure must be zero-sized"); - - $(extern $abi)? fn wrapper< - $($($param,)*)? - F: Fn($($arg_ty),*) -> $ret_ty + Copy - >($($arg: $arg_ty),*) -> $ret_ty { - let f = unsafe { - // SAFETY: `F` satisfies all criteria for "out of thin air" - // reconstructability (see module-level doc comment). - mem::MaybeUninit::::uninit().assume_init() - }; - f($($arg),*) - } - let _f_proof = f; - wrapper::< - $($($param,)*)? - F - > - })+ - } -} - -define_reify_functions! { - fn _reify_to_extern_c_fn_unary for extern "C" fn(arg: A) -> R; - - // HACK(eddyb) this abstraction is used with `for<'a> fn(Bridge<'a>) -> T` - // but that doesn't work with just `reify_to_extern_c_fn_unary` because of - // the `fn` pointer type being "higher-ranked" (i.e. the `for<'a>` binder). - // FIXME(eddyb) try to remove the lifetime from `Bridge`, that'd help. - fn reify_to_extern_c_fn_hrt_bridge for extern "C" fn(bridge: super::Bridge<'_>) -> R; -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/server.rs deleted file mode 100644 index 0fb3c69858947..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/server.rs +++ /dev/null @@ -1,332 +0,0 @@ -//! Server-side traits. - -use super::*; - -// FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. -use super::client::HandleStore; - -pub trait Types { - type FreeFunctions: 'static; - type TokenStream: 'static + Clone; - type Group: 'static + Clone; - type Punct: 'static + Copy + Eq + Hash; - type Ident: 'static + Copy + Eq + Hash; - type Literal: 'static + Clone; - type SourceFile: 'static + Clone; - type MultiSpan: 'static; - type Diagnostic: 'static; - type Span: 'static + Copy + Eq + Hash; -} - -/// Declare an associated fn of one of the traits below, adding necessary -/// default bodies. -macro_rules! associated_fn { - (fn drop(&mut self, $arg:ident: $arg_ty:ty)) => - (fn drop(&mut self, $arg: $arg_ty) { mem::drop($arg) }); - - (fn clone(&mut self, $arg:ident: $arg_ty:ty) -> $ret_ty:ty) => - (fn clone(&mut self, $arg: $arg_ty) -> $ret_ty { $arg.clone() }); - - ($($item:tt)*) => ($($item)*;) -} - -macro_rules! declare_server_traits { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - $(pub trait $name: Types { - $(associated_fn!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* - })* - - pub trait Server: Types $(+ $name)* {} - impl Server for S {} - } -} -with_api!(Self, self_, declare_server_traits); - -pub(super) struct MarkedTypes(S); - -macro_rules! define_mark_types_impls { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - impl Types for MarkedTypes { - $(type $name = Marked;)* - } - - $(impl $name for MarkedTypes { - $(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)? { - <_>::mark($name::$method(&mut self.0, $($arg.unmark()),*)) - })* - })* - } -} -with_api!(Self, self_, define_mark_types_impls); - -struct Dispatcher { - handle_store: HandleStore, - server: S, -} - -macro_rules! define_dispatcher_impl { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - // FIXME(eddyb) `pub` only for `ExecutionStrategy` below. - pub trait DispatcherTrait { - // HACK(eddyb) these are here to allow `Self::$name` to work below. - $(type $name;)* - fn dispatch(&mut self, buf: Buffer) -> Buffer; - } - - impl DispatcherTrait for Dispatcher> { - $(type $name = as Types>::$name;)* - fn dispatch(&mut self, mut buf: Buffer) -> Buffer { - let Dispatcher { handle_store, server } = self; - - let mut reader = &buf[..]; - match api_tags::Method::decode(&mut reader, &mut ()) { - $(api_tags::Method::$name(m) => match m { - $(api_tags::$name::$method => { - let mut call_method = || { - reverse_decode!(reader, handle_store; $($arg: $arg_ty),*); - $name::$method(server, $($arg),*) - }; - // HACK(eddyb) don't use `panic::catch_unwind` in a panic. - // If client and server happen to use the same `libstd`, - // `catch_unwind` asserts that the panic counter was 0, - // even when the closure passed to it didn't panic. - let r = if thread::panicking() { - Ok(call_method()) - } else { - panic::catch_unwind(panic::AssertUnwindSafe(call_method)) - .map_err(PanicMessage::from) - }; - - buf.clear(); - r.encode(&mut buf, handle_store); - })* - }),* - } - buf - } - } - } -} -with_api!(Self, self_, define_dispatcher_impl); - -pub trait ExecutionStrategy { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(Bridge<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer; -} - -pub struct SameThread; - -impl ExecutionStrategy for SameThread { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(Bridge<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - let mut dispatch = |buf| dispatcher.dispatch(buf); - - run_client(Bridge { - cached_buffer: input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }) - } -} - -// NOTE(eddyb) Two implementations are provided, the second one is a bit -// faster but neither is anywhere near as fast as same-thread execution. - -pub struct CrossThread1; - -impl ExecutionStrategy for CrossThread1 { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(Bridge<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - use std::sync::mpsc::channel; - - let (req_tx, req_rx) = channel(); - let (res_tx, res_rx) = channel(); - - let join_handle = thread::spawn(move || { - let mut dispatch = |buf| { - req_tx.send(buf).unwrap(); - res_rx.recv().unwrap() - }; - - run_client(Bridge { - cached_buffer: input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }) - }); - - for b in req_rx { - res_tx.send(dispatcher.dispatch(b)).unwrap(); - } - - join_handle.join().unwrap() - } -} - -pub struct CrossThread2; - -impl ExecutionStrategy for CrossThread2 { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(Bridge<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - use std::sync::{Arc, Mutex}; - - enum State { - Req(T), - Res(T), - } - - let mut state = Arc::new(Mutex::new(State::Res(Buffer::new()))); - - let server_thread = thread::current(); - let state2 = state.clone(); - let join_handle = thread::spawn(move || { - let mut dispatch = |b| { - *state2.lock().unwrap() = State::Req(b); - server_thread.unpark(); - loop { - thread::park(); - if let State::Res(b) = &mut *state2.lock().unwrap() { - break b.take(); - } - } - }; - - let r = run_client(Bridge { - cached_buffer: input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }); - - // Wake up the server so it can exit the dispatch loop. - drop(state2); - server_thread.unpark(); - - r - }); - - // Check whether `state2` was dropped, to know when to stop. - while Arc::get_mut(&mut state).is_none() { - thread::park(); - let mut b = match &mut *state.lock().unwrap() { - State::Req(b) => b.take(), - _ => continue, - }; - b = dispatcher.dispatch(b.take()); - *state.lock().unwrap() = State::Res(b); - join_handle.thread().unpark(); - } - - join_handle.join().unwrap() - } -} - -fn run_server< - S: Server, - I: Encode>>, - O: for<'a, 's> DecodeMut<'a, 's, HandleStore>>, ->( - strategy: &impl ExecutionStrategy, - handle_counters: &'static client::HandleCounters, - server: S, - input: I, - run_client: extern "C" fn(Bridge<'_>) -> Buffer, - force_show_panics: bool, -) -> Result { - let mut dispatcher = - Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) }; - - let mut buf = Buffer::new(); - input.encode(&mut buf, &mut dispatcher.handle_store); - - buf = strategy.run_bridge_and_client(&mut dispatcher, buf, run_client, force_show_panics); - - Result::decode(&mut &buf[..], &mut dispatcher.handle_store) -} - -impl client::Client { - pub fn run( - &self, - strategy: &impl ExecutionStrategy, - server: S, - input: S::TokenStream, - force_show_panics: bool, - ) -> Result - where - S: Server, - S::TokenStream: Default, - { - let client::Client { get_handle_counters, run, _marker } = *self; - run_server( - strategy, - get_handle_counters(), - server, - as Types>::TokenStream::mark(input), - run, - force_show_panics, - ) - .map(|s| as Types>::TokenStream>>::unmark(s).unwrap_or_default()) - } -} - -impl - client::Client< - (super::super::TokenStream, super::super::TokenStream), - super::super::TokenStream, - > -{ - pub fn run( - &self, - strategy: &impl ExecutionStrategy, - server: S, - input: S::TokenStream, - input2: S::TokenStream, - force_show_panics: bool, - ) -> Result - where - S: Server, - S::TokenStream: Default, - { - let client::Client { get_handle_counters, run, _marker } = *self; - run_server( - strategy, - get_handle_counters(), - server, - ( - as Types>::TokenStream::mark(input), - as Types>::TokenStream::mark(input2), - ), - run, - force_show_panics, - ) - .map(|s| as Types>::TokenStream>>::unmark(s).unwrap_or_default()) - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/diagnostic.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/diagnostic.rs deleted file mode 100644 index 3fade2dc4f9cc..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/diagnostic.rs +++ /dev/null @@ -1,166 +0,0 @@ -//! lib-proc-macro diagnostic -//! -//! Copy from -//! augmented with removing unstable features - -use super::Span; - -/// An enum representing a diagnostic level. -#[derive(Copy, Clone, Debug)] -#[non_exhaustive] -pub enum Level { - /// An error. - Error, - /// A warning. - Warning, - /// A note. - Note, - /// A help message. - Help, -} - -/// Trait implemented by types that can be converted into a set of `Span`s. -pub trait MultiSpan { - /// Converts `self` into a `Vec`. - fn into_spans(self) -> Vec; -} - -impl MultiSpan for Span { - fn into_spans(self) -> Vec { - vec![self] - } -} - -impl MultiSpan for Vec { - fn into_spans(self) -> Vec { - self - } -} - -impl<'a> MultiSpan for &'a [Span] { - fn into_spans(self) -> Vec { - self.to_vec() - } -} - -/// A structure representing a diagnostic message and associated children -/// messages. -#[derive(Clone, Debug)] -pub struct Diagnostic { - level: Level, - message: String, - spans: Vec, - children: Vec, -} - -macro_rules! diagnostic_child_methods { - ($spanned:ident, $regular:ident, $level:expr) => { - #[doc = concat!("Adds a new child diagnostics message to `self` with the [`", - stringify!($level), "`] level, and the given `spans` and `message`.")] - pub fn $spanned(mut self, spans: S, message: T) -> Diagnostic - where - S: MultiSpan, - T: Into, - { - self.children.push(Diagnostic::spanned(spans, $level, message)); - self - } - - #[doc = concat!("Adds a new child diagnostic message to `self` with the [`", - stringify!($level), "`] level, and the given `message`.")] - pub fn $regular>(mut self, message: T) -> Diagnostic { - self.children.push(Diagnostic::new($level, message)); - self - } - }; -} - -/// Iterator over the children diagnostics of a `Diagnostic`. -#[derive(Debug, Clone)] -pub struct Children<'a>(std::slice::Iter<'a, Diagnostic>); - -impl<'a> Iterator for Children<'a> { - type Item = &'a Diagnostic; - - fn next(&mut self) -> Option { - self.0.next() - } -} - -impl Diagnostic { - /// Creates a new diagnostic with the given `level` and `message`. - pub fn new>(level: Level, message: T) -> Diagnostic { - Diagnostic { level, message: message.into(), spans: vec![], children: vec![] } - } - - /// Creates a new diagnostic with the given `level` and `message` pointing to - /// the given set of `spans`. - pub fn spanned(spans: S, level: Level, message: T) -> Diagnostic - where - S: MultiSpan, - T: Into, - { - Diagnostic { level, message: message.into(), spans: spans.into_spans(), children: vec![] } - } - - diagnostic_child_methods!(span_error, error, Level::Error); - diagnostic_child_methods!(span_warning, warning, Level::Warning); - diagnostic_child_methods!(span_note, note, Level::Note); - diagnostic_child_methods!(span_help, help, Level::Help); - - /// Returns the diagnostic `level` for `self`. - pub fn level(&self) -> Level { - self.level - } - - /// Sets the level in `self` to `level`. - pub fn set_level(&mut self, level: Level) { - self.level = level; - } - - /// Returns the message in `self`. - pub fn message(&self) -> &str { - &self.message - } - - /// Sets the message in `self` to `message`. - pub fn set_message>(&mut self, message: T) { - self.message = message.into(); - } - - /// Returns the `Span`s in `self`. - pub fn spans(&self) -> &[Span] { - &self.spans - } - - /// Sets the `Span`s in `self` to `spans`. - pub fn set_spans(&mut self, spans: S) { - self.spans = spans.into_spans(); - } - - /// Returns an iterator over the children diagnostics of `self`. - pub fn children(&self) -> Children<'_> { - Children(self.children.iter()) - } - - /// Emit the diagnostic. - pub fn emit(self) { - fn to_internal(spans: Vec) -> super::bridge::client::MultiSpan { - let mut multi_span = super::bridge::client::MultiSpan::new(); - for span in spans { - multi_span.push(span.0); - } - multi_span - } - - let mut diag = super::bridge::client::Diagnostic::new( - self.level, - &self.message[..], - to_internal(self.spans), - ); - for c in self.children { - diag.sub(c.level, &c.message[..], to_internal(c.spans)); - } - diag.emit(); - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs deleted file mode 100644 index c50a16bf4d1d8..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs +++ /dev/null @@ -1,1106 +0,0 @@ -//! A support library for macro authors when defining new macros. -//! -//! This library, provided by the standard distribution, provides the types -//! consumed in the interfaces of procedurally defined macro definitions such as -//! function-like macros `#[proc_macro]`, macro attributes `#[proc_macro_attribute]` and -//! custom derive attributes`#[proc_macro_derive]`. -//! -//! See [the book] for more. -//! -//! [the book]: ../book/ch19-06-macros.html#procedural-macros-for-generating-code-from-attributes - -#[doc(hidden)] -pub mod bridge; - -mod diagnostic; - -pub use diagnostic::{Diagnostic, Level, MultiSpan}; - -use std::cmp::Ordering; -use std::ops::RangeBounds; -use std::path::PathBuf; -use std::str::FromStr; -use std::{error, fmt, iter, mem}; - -/// Determines whether proc_macro has been made accessible to the currently -/// running program. -/// -/// The proc_macro crate is only intended for use inside the implementation of -/// procedural macros. All the functions in this crate panic if invoked from -/// outside of a procedural macro, such as from a build script or unit test or -/// ordinary Rust binary. -/// -/// With consideration for Rust libraries that are designed to support both -/// macro and non-macro use cases, `proc_macro::is_available()` provides a -/// non-panicking way to detect whether the infrastructure required to use the -/// API of proc_macro is presently available. Returns true if invoked from -/// inside of a procedural macro, false if invoked from any other binary. -pub fn is_available() -> bool { - bridge::Bridge::is_available() -} - -/// The main type provided by this crate, representing an abstract stream of -/// tokens, or, more specifically, a sequence of token trees. -/// The type provide interfaces for iterating over those token trees and, conversely, -/// collecting a number of token trees into one stream. -/// -/// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]` -/// and `#[proc_macro_derive]` definitions. -#[derive(Clone)] -pub struct TokenStream(Option); - -/// Error returned from `TokenStream::from_str`. -#[non_exhaustive] -#[derive(Debug)] -pub struct LexError; - -impl fmt::Display for LexError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("cannot parse string into token stream") - } -} - -impl error::Error for LexError {} - -/// Error returned from `TokenStream::expand_expr`. -#[non_exhaustive] -#[derive(Debug)] -pub struct ExpandError; - -impl fmt::Display for ExpandError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("macro expansion failed") - } -} - -impl error::Error for ExpandError {} - -impl TokenStream { - /// Returns an empty `TokenStream` containing no token trees. - pub fn new() -> TokenStream { - TokenStream(None) - } - - /// Checks if this `TokenStream` is empty. - pub fn is_empty(&self) -> bool { - self.0.as_ref().map(|h| h.is_empty()).unwrap_or(true) - } - - /// Parses this `TokenStream` as an expression and attempts to expand any - /// macros within it. Returns the expanded `TokenStream`. - /// - /// Currently only expressions expanding to literals will succeed, although - /// this may be relaxed in the future. - /// - /// NOTE: In error conditions, `expand_expr` may leave macros unexpanded, - /// report an error, failing compilation, and/or return an `Err(..)`. The - /// specific behavior for any error condition, and what conditions are - /// considered errors, is unspecified and may change in the future. - pub fn expand_expr(&self) -> Result { - let stream = self.0.as_ref().ok_or(ExpandError)?; - match bridge::client::TokenStream::expand_expr(stream) { - Ok(stream) => Ok(TokenStream(Some(stream))), - Err(_) => Err(ExpandError), - } - } -} - -/// Attempts to break the string into tokens and parse those tokens into a token stream. -/// May fail for a number of reasons, for example, if the string contains unbalanced delimiters -/// or characters not existing in the language. -/// All tokens in the parsed stream get `Span::call_site()` spans. -/// -/// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to -/// change these errors into `LexError`s later. -impl FromStr for TokenStream { - type Err = LexError; - - fn from_str(src: &str) -> Result { - Ok(TokenStream(Some(bridge::client::TokenStream::from_str(src)))) - } -} - -/// Prints the token stream as a string that is supposed to be losslessly convertible back -/// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters and negative numeric literals. -impl fmt::Display for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -/// Prints token in a form convenient for debugging. -impl fmt::Debug for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("TokenStream ")?; - f.debug_list().entries(self.clone()).finish() - } -} - -impl Default for TokenStream { - fn default() -> Self { - TokenStream::new() - } -} - -pub use quote::{quote, quote_span}; - -fn tree_to_bridge_tree( - tree: TokenTree, -) -> bridge::TokenTree< - bridge::client::Group, - bridge::client::Punct, - bridge::client::Ident, - bridge::client::Literal, -> { - match tree { - TokenTree::Group(tt) => bridge::TokenTree::Group(tt.0), - TokenTree::Punct(tt) => bridge::TokenTree::Punct(tt.0), - TokenTree::Ident(tt) => bridge::TokenTree::Ident(tt.0), - TokenTree::Literal(tt) => bridge::TokenTree::Literal(tt.0), - } -} - -/// Creates a token stream containing a single token tree. -impl From for TokenStream { - fn from(tree: TokenTree) -> TokenStream { - TokenStream(Some(bridge::client::TokenStream::from_token_tree(tree_to_bridge_tree(tree)))) - } -} - -/// Non-generic helper for implementing `FromIterator` and -/// `Extend` with less monomorphization in calling crates. -struct ConcatStreamsHelper { - streams: Vec, -} - -impl ConcatStreamsHelper { - fn new(capacity: usize) -> Self { - ConcatStreamsHelper { streams: Vec::with_capacity(capacity) } - } - - fn push(&mut self, stream: TokenStream) { - if let Some(stream) = stream.0 { - self.streams.push(stream); - } - } - - fn build(mut self) -> TokenStream { - if self.streams.len() <= 1 { - TokenStream(self.streams.pop()) - } else { - TokenStream(Some(bridge::client::TokenStream::concat_streams(None, self.streams))) - } - } - - fn append_to(mut self, stream: &mut TokenStream) { - if self.streams.is_empty() { - return; - } - let base = stream.0.take(); - if base.is_none() && self.streams.len() == 1 { - stream.0 = self.streams.pop(); - } else { - stream.0 = Some(bridge::client::TokenStream::concat_streams(base, self.streams)); - } - } -} - -/// Collects a number of token trees into a single stream. -impl iter::FromIterator for TokenStream { - fn from_iter>(trees: I) -> Self { - trees.into_iter().map(TokenStream::from).collect() - } -} - -/// A "flattening" operation on token streams, collects token trees -/// from multiple token streams into a single stream. -impl iter::FromIterator for TokenStream { - fn from_iter>(streams: I) -> Self { - let iter = streams.into_iter(); - let mut builder = ConcatStreamsHelper::new(iter.size_hint().0); - iter.for_each(|stream| builder.push(stream)); - builder.build() - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, trees: I) { - self.extend(trees.into_iter().map(TokenStream::from)); - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, streams: I) { - // FIXME(eddyb) Use an optimized implementation if/when possible. - *self = iter::once(mem::replace(self, Self::new())).chain(streams).collect(); - } -} - -/// Public implementation details for the `TokenStream` type, such as iterators. -pub mod token_stream { - use super::{bridge, Group, Ident, Literal, Punct, TokenStream, TokenTree}; - - /// An iterator over `TokenStream`'s `TokenTree`s. - /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, - /// and returns whole groups as token trees. - #[derive(Clone)] - pub struct IntoIter( - std::vec::IntoIter< - bridge::TokenTree< - bridge::client::Group, - bridge::client::Punct, - bridge::client::Ident, - bridge::client::Literal, - >, - >, - ); - - impl Iterator for IntoIter { - type Item = TokenTree; - - fn next(&mut self) -> Option { - self.0.next().map(|tree| match tree { - bridge::TokenTree::Group(tt) => TokenTree::Group(Group(tt)), - bridge::TokenTree::Punct(tt) => TokenTree::Punct(Punct(tt)), - bridge::TokenTree::Ident(tt) => TokenTree::Ident(Ident(tt)), - bridge::TokenTree::Literal(tt) => TokenTree::Literal(Literal(tt)), - }) - } - } - - impl IntoIterator for TokenStream { - type Item = TokenTree; - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - IntoIter(self.0.map(|v| v.into_trees()).unwrap_or_default().into_iter()) - } - } -} - -#[doc(hidden)] -mod quote; - -/// A region of source code, along with macro expansion information. -#[derive(Copy, Clone)] -pub struct Span(bridge::client::Span); - -macro_rules! diagnostic_method { - ($name:ident, $level:expr) => { - /// Creates a new `Diagnostic` with the given `message` at the span - /// `self`. - pub fn $name>(self, message: T) -> Diagnostic { - Diagnostic::spanned(self, $level, message) - } - }; -} - -impl Span { - /// A span that resolves at the macro definition site. - pub fn def_site() -> Span { - Span(bridge::client::Span::def_site()) - } - - /// The span of the invocation of the current procedural macro. - /// Identifiers created with this span will be resolved as if they were written - /// directly at the macro call location (call-site hygiene) and other code - /// at the macro call site will be able to refer to them as well. - pub fn call_site() -> Span { - Span(bridge::client::Span::call_site()) - } - - /// A span that represents `macro_rules` hygiene, and sometimes resolves at the macro - /// definition site (local variables, labels, `$crate`) and sometimes at the macro - /// call site (everything else). - /// The span location is taken from the call-site. - pub fn mixed_site() -> Span { - Span(bridge::client::Span::mixed_site()) - } - - /// The original source file into which this span points. - pub fn source_file(&self) -> SourceFile { - SourceFile(self.0.source_file()) - } - - /// The `Span` for the tokens in the previous macro expansion from which - /// `self` was generated from, if any. - pub fn parent(&self) -> Option { - self.0.parent().map(Span) - } - - /// The span for the origin source code that `self` was generated from. If - /// this `Span` wasn't generated from other macro expansions then the return - /// value is the same as `*self`. - pub fn source(&self) -> Span { - Span(self.0.source()) - } - - /// Gets the starting line/column in the source file for this span. - pub fn start(&self) -> LineColumn { - self.0.start().add_1_to_column() - } - - /// Gets the ending line/column in the source file for this span. - pub fn end(&self) -> LineColumn { - self.0.end().add_1_to_column() - } - - /// Creates an empty span pointing to directly before this span. - pub fn before(&self) -> Span { - Span(self.0.before()) - } - - /// Creates an empty span pointing to directly after this span. - pub fn after(&self) -> Span { - Span(self.0.after()) - } - - /// Creates a new span encompassing `self` and `other`. - /// - /// Returns `None` if `self` and `other` are from different files. - pub fn join(&self, other: Span) -> Option { - self.0.join(other.0).map(Span) - } - - /// Creates a new span with the same line/column information as `self` but - /// that resolves symbols as though it were at `other`. - pub fn resolved_at(&self, other: Span) -> Span { - Span(self.0.resolved_at(other.0)) - } - - /// Creates a new span with the same name resolution behavior as `self` but - /// with the line/column information of `other`. - pub fn located_at(&self, other: Span) -> Span { - other.resolved_at(*self) - } - - /// Compares to spans to see if they're equal. - pub fn eq(&self, other: &Span) -> bool { - self.0 == other.0 - } - - /// Returns the source text behind a span. This preserves the original source - /// code, including spaces and comments. It only returns a result if the span - /// corresponds to real source code. - /// - /// Note: The observable result of a macro should only rely on the tokens and - /// not on this source text. The result of this function is a best effort to - /// be used for diagnostics only. - pub fn source_text(&self) -> Option { - self.0.source_text() - } - - // Used by the implementation of `Span::quote` - #[doc(hidden)] - pub fn save_span(&self) -> usize { - self.0.save_span() - } - - // Used by the implementation of `Span::quote` - #[doc(hidden)] - pub fn recover_proc_macro_span(id: usize) -> Span { - Span(bridge::client::Span::recover_proc_macro_span(id)) - } - - diagnostic_method!(error, Level::Error); - diagnostic_method!(warning, Level::Warning); - diagnostic_method!(note, Level::Note); - diagnostic_method!(help, Level::Help); -} - -/// Prints a span in a form convenient for debugging. -impl fmt::Debug for Span { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// A line-column pair representing the start or end of a `Span`. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct LineColumn { - /// The 1-indexed line in the source file on which the span starts or ends (inclusive). - pub line: usize, - /// The 1-indexed column (number of bytes in UTF-8 encoding) in the source - /// file on which the span starts or ends (inclusive). - pub column: usize, -} - -impl LineColumn { - fn add_1_to_column(self) -> Self { - LineColumn { line: self.line, column: self.column + 1 } - } -} - -impl Ord for LineColumn { - fn cmp(&self, other: &Self) -> Ordering { - self.line.cmp(&other.line).then(self.column.cmp(&other.column)) - } -} - -impl PartialOrd for LineColumn { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -/// The source file of a given `Span`. -#[derive(Clone)] -pub struct SourceFile(bridge::client::SourceFile); - -impl SourceFile { - /// Gets the path to this source file. - /// - /// ### Note - /// If the code span associated with this `SourceFile` was generated by an external macro, this - /// macro, this might not be an actual path on the filesystem. Use [`is_real`] to check. - /// - /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on - /// the command line, the path as given might not actually be valid. - /// - /// [`is_real`]: Self::is_real - pub fn path(&self) -> PathBuf { - PathBuf::from(self.0.path()) - } - - /// Returns `true` if this source file is a real source file, and not generated by an external - /// macro's expansion. - pub fn is_real(&self) -> bool { - // This is a hack until intercrate spans are implemented and we can have real source files - // for spans generated in external macros. - // https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368 - self.0.is_real() - } -} - -impl fmt::Debug for SourceFile { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SourceFile") - .field("path", &self.path()) - .field("is_real", &self.is_real()) - .finish() - } -} - -impl PartialEq for SourceFile { - fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) - } -} - -impl Eq for SourceFile {} - -/// A single token or a delimited sequence of token trees (e.g., `[1, (), ..]`). -#[derive(Clone)] -pub enum TokenTree { - /// A token stream surrounded by bracket delimiters. - Group(Group), - /// An identifier. - Ident(Ident), - /// A single punctuation character (`+`, `,`, `$`, etc.). - Punct(Punct), - /// A literal character (`'a'`), string (`"hello"`), number (`2.3`), etc. - Literal(Literal), -} - -impl TokenTree { - /// Returns the span of this tree, delegating to the `span` method of - /// the contained token or a delimited stream. - pub fn span(&self) -> Span { - match *self { - TokenTree::Group(ref t) => t.span(), - TokenTree::Ident(ref t) => t.span(), - TokenTree::Punct(ref t) => t.span(), - TokenTree::Literal(ref t) => t.span(), - } - } - - /// Configures the span for *only this token*. - /// - /// Note that if this token is a `Group` then this method will not configure - /// the span of each of the internal tokens, this will simply delegate to - /// the `set_span` method of each variant. - pub fn set_span(&mut self, span: Span) { - match *self { - TokenTree::Group(ref mut t) => t.set_span(span), - TokenTree::Ident(ref mut t) => t.set_span(span), - TokenTree::Punct(ref mut t) => t.set_span(span), - TokenTree::Literal(ref mut t) => t.set_span(span), - } - } -} - -/// Prints token tree in a form convenient for debugging. -impl fmt::Debug for TokenTree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Each of these has the name in the struct type in the derived debug, - // so don't bother with an extra layer of indirection - match *self { - TokenTree::Group(ref tt) => tt.fmt(f), - TokenTree::Ident(ref tt) => tt.fmt(f), - TokenTree::Punct(ref tt) => tt.fmt(f), - TokenTree::Literal(ref tt) => tt.fmt(f), - } - } -} - -impl From for TokenTree { - fn from(g: Group) -> TokenTree { - TokenTree::Group(g) - } -} - -impl From for TokenTree { - fn from(g: Ident) -> TokenTree { - TokenTree::Ident(g) - } -} - -impl From for TokenTree { - fn from(g: Punct) -> TokenTree { - TokenTree::Punct(g) - } -} - -impl From for TokenTree { - fn from(g: Literal) -> TokenTree { - TokenTree::Literal(g) - } -} - -/// Prints the token tree as a string that is supposed to be losslessly convertible back -/// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters and negative numeric literals. -impl fmt::Display for TokenTree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -/// A delimited token stream. -/// -/// A `Group` internally contains a `TokenStream` which is surrounded by `Delimiter`s. -#[derive(Clone)] -pub struct Group(bridge::client::Group); - -/// Describes how a sequence of token trees is delimited. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Delimiter { - /// `( ... )` - Parenthesis, - /// `{ ... }` - Brace, - /// `[ ... ]` - Bracket, - /// `Ø ... Ø` - /// An invisible delimiter, that may, for example, appear around tokens coming from a - /// "macro variable" `$var`. It is important to preserve operator priorities in cases like - /// `$var * 3` where `$var` is `1 + 2`. - /// Invisible delimiters might not survive roundtrip of a token stream through a string. - None, -} - -impl Group { - /// Creates a new `Group` with the given delimiter and token stream. - /// - /// This constructor will set the span for this group to - /// `Span::call_site()`. To change the span you can use the `set_span` - /// method below. - pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { - Group(bridge::client::Group::new(delimiter, stream.0)) - } - - /// Returns the delimiter of this `Group` - pub fn delimiter(&self) -> Delimiter { - self.0.delimiter() - } - - /// Returns the `TokenStream` of tokens that are delimited in this `Group`. - /// - /// Note that the returned token stream does not include the delimiter - /// returned above. - pub fn stream(&self) -> TokenStream { - TokenStream(Some(self.0.stream())) - } - - /// Returns the span for the delimiters of this token stream, spanning the - /// entire `Group`. - /// - /// ```text - /// pub fn span(&self) -> Span { - /// ^^^^^^^ - /// ``` - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Returns the span pointing to the opening delimiter of this group. - /// - /// ```text - /// pub fn span_open(&self) -> Span { - /// ^ - /// ``` - pub fn span_open(&self) -> Span { - Span(self.0.span_open()) - } - - /// Returns the span pointing to the closing delimiter of this group. - /// - /// ```text - /// pub fn span_close(&self) -> Span { - /// ^ - /// ``` - pub fn span_close(&self) -> Span { - Span(self.0.span_close()) - } - - /// Configures the span for this `Group`'s delimiters, but not its internal - /// tokens. - /// - /// This method will **not** set the span of all the internal tokens spanned - /// by this group, but rather it will only set the span of the delimiter - /// tokens at the level of the `Group`. - pub fn set_span(&mut self, span: Span) { - self.0.set_span(span.0); - } -} - -/// Prints the group as a string that should be losslessly convertible back -/// into the same group (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters. -impl fmt::Display for Group { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Group { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Group") - .field("delimiter", &self.delimiter()) - .field("stream", &self.stream()) - .field("span", &self.span()) - .finish() - } -} - -/// A `Punct` is a single punctuation character such as `+`, `-` or `#`. -/// -/// Multi-character operators like `+=` are represented as two instances of `Punct` with different -/// forms of `Spacing` returned. -#[derive(Clone)] -pub struct Punct(bridge::client::Punct); - -/// Describes whether a `Punct` is followed immediately by another `Punct` ([`Spacing::Joint`]) or -/// by a different token or whitespace ([`Spacing::Alone`]). -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Spacing { - /// A `Punct` is not immediately followed by another `Punct`. - /// E.g. `+` is `Alone` in `+ =`, `+ident` and `+()`. - Alone, - /// A `Punct` is immediately followed by another `Punct`. - /// E.g. `+` is `Joint` in `+=` and `++`. - /// - /// Additionally, single quote `'` can join with identifiers to form lifetimes: `'ident`. - Joint, -} - -impl Punct { - /// Creates a new `Punct` from the given character and spacing. - /// The `ch` argument must be a valid punctuation character permitted by the language, - /// otherwise the function will panic. - /// - /// The returned `Punct` will have the default span of `Span::call_site()` - /// which can be further configured with the `set_span` method below. - pub fn new(ch: char, spacing: Spacing) -> Punct { - Punct(bridge::client::Punct::new(ch, spacing)) - } - - /// Returns the value of this punctuation character as `char`. - pub fn as_char(&self) -> char { - self.0.as_char() - } - - /// Returns the spacing of this punctuation character, indicating whether it's immediately - /// followed by another `Punct` in the token stream, so they can potentially be combined into - /// a multi-character operator (`Joint`), or it's followed by some other token or whitespace - /// (`Alone`) so the operator has certainly ended. - pub fn spacing(&self) -> Spacing { - self.0.spacing() - } - - /// Returns the span for this punctuation character. - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Configure the span for this punctuation character. - pub fn set_span(&mut self, span: Span) { - self.0 = self.0.with_span(span.0); - } -} - -/// Prints the punctuation character as a string that should be losslessly convertible -/// back into the same character. -impl fmt::Display for Punct { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Punct { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Punct") - .field("ch", &self.as_char()) - .field("spacing", &self.spacing()) - .field("span", &self.span()) - .finish() - } -} - -impl PartialEq for Punct { - fn eq(&self, rhs: &char) -> bool { - self.as_char() == *rhs - } -} - -impl PartialEq for char { - fn eq(&self, rhs: &Punct) -> bool { - *self == rhs.as_char() - } -} - -/// An identifier (`ident`). -#[derive(Clone)] -pub struct Ident(bridge::client::Ident); - -impl Ident { - /// Creates a new `Ident` with the given `string` as well as the specified - /// `span`. - /// The `string` argument must be a valid identifier permitted by the - /// language (including keywords, e.g. `self` or `fn`). Otherwise, the function will panic. - /// - /// Note that `span`, currently in rustc, configures the hygiene information - /// for this identifier. - /// - /// As of this time `Span::call_site()` explicitly opts-in to "call-site" hygiene - /// meaning that identifiers created with this span will be resolved as if they were written - /// directly at the location of the macro call, and other code at the macro call site will be - /// able to refer to them as well. - /// - /// Later spans like `Span::def_site()` will allow to opt-in to "definition-site" hygiene - /// meaning that identifiers created with this span will be resolved at the location of the - /// macro definition and other code at the macro call site will not be able to refer to them. - /// - /// Due to the current importance of hygiene this constructor, unlike other - /// tokens, requires a `Span` to be specified at construction. - pub fn new(string: &str, span: Span) -> Ident { - Ident(bridge::client::Ident::new(string, span.0, false)) - } - - /// Same as `Ident::new`, but creates a raw identifier (`r#ident`). - /// The `string` argument be a valid identifier permitted by the language - /// (including keywords, e.g. `fn`). Keywords which are usable in path segments - /// (e.g. `self`, `super`) are not supported, and will cause a panic. - pub fn new_raw(string: &str, span: Span) -> Ident { - Ident(bridge::client::Ident::new(string, span.0, true)) - } - - /// Returns the span of this `Ident`, encompassing the entire string returned - /// by [`to_string`](Self::to_string). - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Configures the span of this `Ident`, possibly changing its hygiene context. - pub fn set_span(&mut self, span: Span) { - self.0 = self.0.with_span(span.0); - } -} - -/// Prints the identifier as a string that should be losslessly convertible -/// back into the same identifier. -impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Ident { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Ident") - .field("ident", &self.to_string()) - .field("span", &self.span()) - .finish() - } -} - -/// A literal string (`"hello"`), byte string (`b"hello"`), -/// character (`'a'`), byte character (`b'a'`), an integer or floating point number -/// with or without a suffix (`1`, `1u8`, `2.3`, `2.3f32`). -/// Boolean literals like `true` and `false` do not belong here, they are `Ident`s. -#[derive(Clone)] -pub struct Literal(bridge::client::Literal); - -macro_rules! suffixed_int_literals { - ($($name:ident => $kind:ident,)*) => ($( - /// Creates a new suffixed integer literal with the specified value. - /// - /// This function will create an integer like `1u32` where the integer - /// value specified is the first part of the token and the integral is - /// also suffixed at the end. - /// Literals created from negative numbers might not survive round-trips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// Literals created through this method have the `Span::call_site()` - /// span by default, which can be configured with the `set_span` method - /// below. - pub fn $name(n: $kind) -> Literal { - Literal(bridge::client::Literal::typed_integer(&n.to_string(), stringify!($kind))) - } - )*) -} - -macro_rules! unsuffixed_int_literals { - ($($name:ident => $kind:ident,)*) => ($( - /// Creates a new unsuffixed integer literal with the specified value. - /// - /// This function will create an integer like `1` where the integer - /// value specified is the first part of the token. No suffix is - /// specified on this token, meaning that invocations like - /// `Literal::i8_unsuffixed(1)` are equivalent to - /// `Literal::u32_unsuffixed(1)`. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// Literals created through this method have the `Span::call_site()` - /// span by default, which can be configured with the `set_span` method - /// below. - pub fn $name(n: $kind) -> Literal { - Literal(bridge::client::Literal::integer(&n.to_string())) - } - )*) -} - -impl Literal { - suffixed_int_literals! { - u8_suffixed => u8, - u16_suffixed => u16, - u32_suffixed => u32, - u64_suffixed => u64, - u128_suffixed => u128, - usize_suffixed => usize, - i8_suffixed => i8, - i16_suffixed => i16, - i32_suffixed => i32, - i64_suffixed => i64, - i128_suffixed => i128, - isize_suffixed => isize, - } - - unsuffixed_int_literals! { - u8_unsuffixed => u8, - u16_unsuffixed => u16, - u32_unsuffixed => u32, - u64_unsuffixed => u64, - u128_unsuffixed => u128, - usize_unsuffixed => usize, - i8_unsuffixed => i8, - i16_unsuffixed => i16, - i32_unsuffixed => i32, - i64_unsuffixed => i64, - i128_unsuffixed => i128, - isize_unsuffixed => isize, - } - - /// Creates a new unsuffixed floating-point literal. - /// - /// This constructor is similar to those like `Literal::i8_unsuffixed` where - /// the float's value is emitted directly into the token but no suffix is - /// used, so it may be inferred to be a `f64` later in the compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f32_unsuffixed(n: f32) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - let mut repr = n.to_string(); - if !repr.contains('.') { - repr.push_str(".0"); - } - Literal(bridge::client::Literal::float(&repr)) - } - - /// Creates a new suffixed floating-point literal. - /// - /// This constructor will create a literal like `1.0f32` where the value - /// specified is the preceding part of the token and `f32` is the suffix of - /// the token. This token will always be inferred to be an `f32` in the - /// compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f32_suffixed(n: f32) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - Literal(bridge::client::Literal::f32(&n.to_string())) - } - - /// Creates a new unsuffixed floating-point literal. - /// - /// This constructor is similar to those like `Literal::i8_unsuffixed` where - /// the float's value is emitted directly into the token but no suffix is - /// used, so it may be inferred to be a `f64` later in the compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f64_unsuffixed(n: f64) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - let mut repr = n.to_string(); - if !repr.contains('.') { - repr.push_str(".0"); - } - Literal(bridge::client::Literal::float(&repr)) - } - - /// Creates a new suffixed floating-point literal. - /// - /// This constructor will create a literal like `1.0f64` where the value - /// specified is the preceding part of the token and `f64` is the suffix of - /// the token. This token will always be inferred to be an `f64` in the - /// compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f64_suffixed(n: f64) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - Literal(bridge::client::Literal::f64(&n.to_string())) - } - - /// String literal. - pub fn string(string: &str) -> Literal { - Literal(bridge::client::Literal::string(string)) - } - - /// Character literal. - pub fn character(ch: char) -> Literal { - Literal(bridge::client::Literal::character(ch)) - } - - /// Byte string literal. - pub fn byte_string(bytes: &[u8]) -> Literal { - Literal(bridge::client::Literal::byte_string(bytes)) - } - - /// Returns the span encompassing this literal. - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Configures the span associated for this literal. - pub fn set_span(&mut self, span: Span) { - self.0.set_span(span.0); - } - - /// Returns a `Span` that is a subset of `self.span()` containing only the - /// source bytes in range `range`. Returns `None` if the would-be trimmed - /// span is outside the bounds of `self`. - // FIXME(SergioBenitez): check that the byte range starts and ends at a - // UTF-8 boundary of the source. otherwise, it's likely that a panic will - // occur elsewhere when the source text is printed. - // FIXME(SergioBenitez): there is no way for the user to know what - // `self.span()` actually maps to, so this method can currently only be - // called blindly. For example, `to_string()` for the character 'c' returns - // "'\u{63}'"; there is no way for the user to know whether the source text - // was 'c' or whether it was '\u{63}'. - pub fn subspan>(&self, range: R) -> Option { - self.0.subspan(range.start_bound().cloned(), range.end_bound().cloned()).map(Span) - } -} - -/// Parse a single literal from its stringified representation. -/// -/// In order to parse successfully, the input string must not contain anything -/// but the literal token. Specifically, it must not contain whitespace or -/// comments in addition to the literal. -/// -/// The resulting literal token will have a `Span::call_site()` span. -/// -/// NOTE: some errors may cause panics instead of returning `LexError`. We -/// reserve the right to change these errors into `LexError`s later. -impl FromStr for Literal { - type Err = LexError; - - fn from_str(src: &str) -> Result { - match bridge::client::Literal::from_str(src) { - Ok(literal) => Ok(Literal(literal)), - Err(()) => Err(LexError), - } - } -} - -/// Prints the literal as a string that should be losslessly convertible -/// back into the same literal (except for possible rounding for floating point literals). -impl fmt::Display for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// Tracked access to environment variables. -pub mod tracked_env { - use std::env::{self, VarError}; - use std::ffi::OsStr; - - /// Retrieve an environment variable and add it to build dependency info. - /// Build system executing the compiler will know that the variable was accessed during - /// compilation, and will be able to rerun the build when the value of that variable changes. - /// Besides the dependency tracking this function should be equivalent to `env::var` from the - /// standard library, except that the argument must be UTF-8. - pub fn var + AsRef>(key: K) -> Result { - let key: &str = key.as_ref(); - let value = env::var(key); - super::bridge::client::FreeFunctions::track_env_var(key, value.as_deref().ok()); - value - } -} - -/// Tracked access to additional files. -pub mod tracked_path { - - /// Track a file explicitly. - /// - /// Commonly used for tracking asset preprocessing. - pub fn path>(path: P) { - let path: &str = path.as_ref(); - super::bridge::client::FreeFunctions::track_path(path); - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/quote.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/quote.rs deleted file mode 100644 index 39309faa41213..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/quote.rs +++ /dev/null @@ -1,139 +0,0 @@ -//! # Quasiquoter -//! This file contains the implementation internals of the quasiquoter provided by `quote!`. - -//! This quasiquoter uses macros 2.0 hygiene to reliably access -//! items from `proc_macro`, to build a `proc_macro::TokenStream`. - -use super::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; - -macro_rules! quote_tt { - (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, quote!($($t)*)) }; - ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, quote!($($t)*)) }; - ({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) }; - (,) => { Punct::new(',', Spacing::Alone) }; - (.) => { Punct::new('.', Spacing::Alone) }; - (;) => { Punct::new(';', Spacing::Alone) }; - (!) => { Punct::new('!', Spacing::Alone) }; - (<) => { Punct::new('<', Spacing::Alone) }; - (>) => { Punct::new('>', Spacing::Alone) }; - (&) => { Punct::new('&', Spacing::Alone) }; - (=) => { Punct::new('=', Spacing::Alone) }; - ($i:ident) => { Ident::new(stringify!($i), Span::def_site()) }; -} - -macro_rules! quote_ts { - ((@ $($t:tt)*)) => { $($t)* }; - (::) => { - [ - TokenTree::from(Punct::new(':', Spacing::Joint)), - TokenTree::from(Punct::new(':', Spacing::Alone)), - ].iter() - .cloned() - .map(|mut x| { - x.set_span(Span::def_site()); - x - }) - .collect::() - }; - ($t:tt) => { TokenTree::from(quote_tt!($t)) }; -} - -/// Simpler version of the real `quote!` macro, implemented solely -/// through `macro_rules`, for bootstrapping the real implementation -/// (see the `quote` function), which does not have access to the -/// real `quote!` macro due to the `proc_macro` crate not being -/// able to depend on itself. -/// -/// Note: supported tokens are a subset of the real `quote!`, but -/// unquoting is different: instead of `$x`, this uses `(@ expr)`. -macro_rules! quote { - () => { TokenStream::new() }; - ($($t:tt)*) => { - [ - $(TokenStream::from(quote_ts!($t)),)* - ].iter().cloned().collect::() - }; -} - -/// Quote a `TokenStream` into a `TokenStream`. -/// This is the actual implementation of the `quote!()` proc macro. -/// -/// It is loaded by the compiler in `register_builtin_macros`. -pub fn quote(stream: TokenStream) -> TokenStream { - if stream.is_empty() { - return quote!(super::TokenStream::new()); - } - let proc_macro_crate = quote!(crate); - let mut after_dollar = false; - let tokens = stream - .into_iter() - .filter_map(|tree| { - if after_dollar { - after_dollar = false; - match tree { - TokenTree::Ident(_) => { - return Some(quote!(Into::::into( - Clone::clone(&(@ tree))),)); - } - TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} - _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), - } - } else if let TokenTree::Punct(ref tt) = tree { - if tt.as_char() == '$' { - after_dollar = true; - return None; - } - } - - Some(quote!(super::TokenStream::from((@ match tree { - TokenTree::Punct(tt) => quote!(super::TokenTree::Punct(super::Punct::new( - (@ TokenTree::from(Literal::character(tt.as_char()))), - (@ match tt.spacing() { - Spacing::Alone => quote!(super::Spacing::Alone), - Spacing::Joint => quote!(super::Spacing::Joint), - }), - ))), - TokenTree::Group(tt) => quote!(super::TokenTree::Group(super::Group::new( - (@ match tt.delimiter() { - Delimiter::Parenthesis => quote!(super::Delimiter::Parenthesis), - Delimiter::Brace => quote!(super::Delimiter::Brace), - Delimiter::Bracket => quote!(super::Delimiter::Bracket), - Delimiter::None => quote!(super::Delimiter::None), - }), - (@ quote(tt.stream())), - ))), - TokenTree::Ident(tt) => quote!(super::TokenTree::Ident(super::Ident::new( - (@ TokenTree::from(Literal::string(&tt.to_string()))), - (@ quote_span(proc_macro_crate.clone(), tt.span())), - ))), - TokenTree::Literal(tt) => quote!(super::TokenTree::Literal({ - let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string()))) - .parse::() - .unwrap() - .into_iter(); - if let (Some(super::TokenTree::Literal(mut lit)), None) = - (iter.next(), iter.next()) - { - lit.set_span((@ quote_span(proc_macro_crate.clone(), tt.span()))); - lit - } else { - unreachable!() - } - })) - })),)) - }) - .collect::(); - - if after_dollar { - panic!("unexpected trailing `$` in `quote!`"); - } - - quote!([(@ tokens)].iter().cloned().collect::()) -} - -/// Quote a `Span` into a `TokenStream`. -/// This is needed to implement a custom quoter. -pub fn quote_span(proc_macro_crate: TokenStream, span: Span) -> TokenStream { - let id = span.save_span(); - quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id))))) -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs deleted file mode 100644 index 05a565fbf343e..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs +++ /dev/null @@ -1,834 +0,0 @@ -//! Rustc proc-macro server implementation with tt -//! -//! Based on idea from -//! The lib-proc-macro server backend is `TokenStream`-agnostic, such that -//! we could provide any TokenStream implementation. -//! The original idea from fedochet is using proc-macro2 as backend, -//! we use tt instead for better integration with RA. -//! -//! FIXME: No span and source file information is implemented yet - -use super::proc_macro::bridge::{self, server}; - -use std::collections::HashMap; -use std::hash::Hash; -use std::iter::FromIterator; -use std::ops::Bound; -use std::{ascii, vec::IntoIter}; - -type Group = tt::Subtree; -type TokenTree = tt::TokenTree; -type Punct = tt::Punct; -type Spacing = tt::Spacing; -type Literal = tt::Literal; -type Span = tt::TokenId; - -#[derive(Debug, Default, Clone)] -pub struct TokenStream { - pub token_trees: Vec, -} - -impl TokenStream { - pub fn new() -> Self { - TokenStream::default() - } - - pub fn with_subtree(subtree: tt::Subtree) -> Self { - if subtree.delimiter.is_some() { - TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] } - } else { - TokenStream { token_trees: subtree.token_trees } - } - } - - pub fn into_subtree(self) -> tt::Subtree { - tt::Subtree { delimiter: None, token_trees: self.token_trees } - } - - pub fn is_empty(&self) -> bool { - self.token_trees.is_empty() - } -} - -/// Creates a token stream containing a single token tree. -impl From for TokenStream { - fn from(tree: TokenTree) -> TokenStream { - TokenStream { token_trees: vec![tree] } - } -} - -/// Collects a number of token trees into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(trees: I) -> Self { - trees.into_iter().map(TokenStream::from).collect() - } -} - -/// A "flattening" operation on token streams, collects token trees -/// from multiple token streams into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(streams: I) -> Self { - let mut builder = TokenStreamBuilder::new(); - streams.into_iter().for_each(|stream| builder.push(stream)); - builder.build() - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, trees: I) { - self.extend(trees.into_iter().map(TokenStream::from)); - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, streams: I) { - for item in streams { - for tkn in item { - match tkn { - tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => { - self.token_trees.extend(subtree.token_trees); - } - _ => { - self.token_trees.push(tkn); - } - } - } - } - } -} - -#[derive(Clone)] -pub struct SourceFile { - // FIXME stub -} - -type Level = super::proc_macro::Level; -type LineColumn = super::proc_macro::LineColumn; - -/// A structure representing a diagnostic message and associated children -/// messages. -#[derive(Clone, Debug)] -pub struct Diagnostic { - level: Level, - message: String, - spans: Vec, - children: Vec, -} - -impl Diagnostic { - /// Creates a new diagnostic with the given `level` and `message`. - pub fn new>(level: Level, message: T) -> Diagnostic { - Diagnostic { level, message: message.into(), spans: vec![], children: vec![] } - } -} - -// Rustc Server Ident has to be `Copyable` -// We use a stub here for bypassing -#[derive(Hash, Eq, PartialEq, Copy, Clone)] -pub struct IdentId(u32); - -#[derive(Clone, Hash, Eq, PartialEq)] -struct IdentData(tt::Ident); - -#[derive(Default)] -struct IdentInterner { - idents: HashMap, - ident_data: Vec, -} - -impl IdentInterner { - fn intern(&mut self, data: &IdentData) -> u32 { - if let Some(index) = self.idents.get(data) { - return *index; - } - - let index = self.idents.len() as u32; - self.ident_data.push(data.clone()); - self.idents.insert(data.clone(), index); - index - } - - fn get(&self, index: u32) -> &IdentData { - &self.ident_data[index as usize] - } - - #[allow(unused)] - fn get_mut(&mut self, index: u32) -> &mut IdentData { - self.ident_data.get_mut(index as usize).expect("Should be consistent") - } -} - -pub struct TokenStreamBuilder { - acc: TokenStream, -} - -/// Public implementation details for the `TokenStream` type, such as iterators. -pub mod token_stream { - use std::str::FromStr; - - use super::{TokenStream, TokenTree}; - - /// An iterator over `TokenStream`'s `TokenTree`s. - /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, - /// and returns whole groups as token trees. - impl IntoIterator for TokenStream { - type Item = TokenTree; - type IntoIter = super::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.token_trees.into_iter() - } - } - - type LexError = String; - - /// Attempts to break the string into tokens and parse those tokens into a token stream. - /// May fail for a number of reasons, for example, if the string contains unbalanced delimiters - /// or characters not existing in the language. - /// All tokens in the parsed stream get `Span::call_site()` spans. - /// - /// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to - /// change these errors into `LexError`s later. - impl FromStr for TokenStream { - type Err = LexError; - - fn from_str(src: &str) -> Result { - let (subtree, _token_map) = - mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?; - - let subtree = subtree_replace_token_ids_with_unspecified(subtree); - Ok(TokenStream::with_subtree(subtree)) - } - } - - impl ToString for TokenStream { - fn to_string(&self) -> String { - tt::pretty(&self.token_trees) - } - } - - fn subtree_replace_token_ids_with_unspecified(subtree: tt::Subtree) -> tt::Subtree { - tt::Subtree { - delimiter: subtree - .delimiter - .map(|d| tt::Delimiter { id: tt::TokenId::unspecified(), ..d }), - token_trees: subtree - .token_trees - .into_iter() - .map(token_tree_replace_token_ids_with_unspecified) - .collect(), - } - } - - fn token_tree_replace_token_ids_with_unspecified(tt: tt::TokenTree) -> tt::TokenTree { - match tt { - tt::TokenTree::Leaf(leaf) => { - tt::TokenTree::Leaf(leaf_replace_token_ids_with_unspecified(leaf)) - } - tt::TokenTree::Subtree(subtree) => { - tt::TokenTree::Subtree(subtree_replace_token_ids_with_unspecified(subtree)) - } - } - } - - fn leaf_replace_token_ids_with_unspecified(leaf: tt::Leaf) -> tt::Leaf { - match leaf { - tt::Leaf::Literal(lit) => { - tt::Leaf::Literal(tt::Literal { id: tt::TokenId::unspecified(), ..lit }) - } - tt::Leaf::Punct(punct) => { - tt::Leaf::Punct(tt::Punct { id: tt::TokenId::unspecified(), ..punct }) - } - tt::Leaf::Ident(ident) => { - tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), ..ident }) - } - } - } -} - -impl TokenStreamBuilder { - fn new() -> TokenStreamBuilder { - TokenStreamBuilder { acc: TokenStream::new() } - } - - fn push(&mut self, stream: TokenStream) { - self.acc.extend(stream.into_iter()) - } - - fn build(self) -> TokenStream { - self.acc - } -} - -pub struct FreeFunctions; - -#[derive(Clone)] -pub struct TokenStreamIter { - trees: IntoIter, -} - -#[derive(Default)] -pub struct RustAnalyzer { - ident_interner: IdentInterner, - // FIXME: store span information here. -} - -impl server::Types for RustAnalyzer { - type FreeFunctions = FreeFunctions; - type TokenStream = TokenStream; - type Group = Group; - type Punct = Punct; - type Ident = IdentId; - type Literal = Literal; - type SourceFile = SourceFile; - type Diagnostic = Diagnostic; - type Span = Span; - type MultiSpan = Vec; -} - -impl server::FreeFunctions for RustAnalyzer { - fn track_env_var(&mut self, _var: &str, _value: Option<&str>) { - // FIXME: track env var accesses - // https://github.com/rust-lang/rust/pull/71858 - } - fn track_path(&mut self, _path: &str) {} -} - -impl server::TokenStream for RustAnalyzer { - fn is_empty(&mut self, stream: &Self::TokenStream) -> bool { - stream.is_empty() - } - fn from_str(&mut self, src: &str) -> Self::TokenStream { - use std::str::FromStr; - - Self::TokenStream::from_str(src).expect("cannot parse string") - } - fn to_string(&mut self, stream: &Self::TokenStream) -> String { - stream.to_string() - } - fn from_token_tree( - &mut self, - tree: bridge::TokenTree, - ) -> Self::TokenStream { - match tree { - bridge::TokenTree::Group(group) => { - let tree = TokenTree::from(group); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Ident(IdentId(index)) => { - let IdentData(ident) = self.ident_interner.get(index).clone(); - let ident: tt::Ident = ident; - let leaf = tt::Leaf::from(ident); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Literal(literal) => { - let leaf = tt::Leaf::from(literal); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Punct(p) => { - let leaf = tt::Leaf::from(p); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - } - } - - fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result { - Ok(self_.clone()) - } - - fn concat_trees( - &mut self, - base: Option, - trees: Vec>, - ) -> Self::TokenStream { - let mut builder = TokenStreamBuilder::new(); - if let Some(base) = base { - builder.push(base); - } - for tree in trees { - builder.push(self.from_token_tree(tree)); - } - builder.build() - } - - fn concat_streams( - &mut self, - base: Option, - streams: Vec, - ) -> Self::TokenStream { - let mut builder = TokenStreamBuilder::new(); - if let Some(base) = base { - builder.push(base); - } - for stream in streams { - builder.push(stream); - } - builder.build() - } - - fn into_trees( - &mut self, - stream: Self::TokenStream, - ) -> Vec> { - stream - .into_iter() - .map(|tree| match tree { - tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { - bridge::TokenTree::Ident(IdentId(self.ident_interner.intern(&IdentData(ident)))) - } - tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => bridge::TokenTree::Literal(lit), - tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => bridge::TokenTree::Punct(punct), - tt::TokenTree::Subtree(subtree) => bridge::TokenTree::Group(subtree), - }) - .collect() - } -} - -fn delim_to_internal(d: bridge::Delimiter) -> Option { - let kind = match d { - bridge::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis, - bridge::Delimiter::Brace => tt::DelimiterKind::Brace, - bridge::Delimiter::Bracket => tt::DelimiterKind::Bracket, - bridge::Delimiter::None => return None, - }; - Some(tt::Delimiter { id: tt::TokenId::unspecified(), kind }) -} - -fn delim_to_external(d: Option) -> bridge::Delimiter { - match d.map(|it| it.kind) { - Some(tt::DelimiterKind::Parenthesis) => bridge::Delimiter::Parenthesis, - Some(tt::DelimiterKind::Brace) => bridge::Delimiter::Brace, - Some(tt::DelimiterKind::Bracket) => bridge::Delimiter::Bracket, - None => bridge::Delimiter::None, - } -} - -fn spacing_to_internal(spacing: bridge::Spacing) -> Spacing { - match spacing { - bridge::Spacing::Alone => Spacing::Alone, - bridge::Spacing::Joint => Spacing::Joint, - } -} - -fn spacing_to_external(spacing: Spacing) -> bridge::Spacing { - match spacing { - Spacing::Alone => bridge::Spacing::Alone, - Spacing::Joint => bridge::Spacing::Joint, - } -} - -impl server::Group for RustAnalyzer { - fn new( - &mut self, - delimiter: bridge::Delimiter, - stream: Option, - ) -> Self::Group { - Self::Group { - delimiter: delim_to_internal(delimiter), - token_trees: stream.unwrap_or_default().token_trees, - } - } - fn delimiter(&mut self, group: &Self::Group) -> bridge::Delimiter { - delim_to_external(group.delimiter) - } - - // NOTE: Return value of do not include delimiter - fn stream(&mut self, group: &Self::Group) -> Self::TokenStream { - TokenStream { token_trees: group.token_trees.clone() } - } - - fn span(&mut self, group: &Self::Group) -> Self::Span { - group.delimiter.map(|it| it.id).unwrap_or_else(tt::TokenId::unspecified) - } - - fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) { - if let Some(delim) = &mut group.delimiter { - delim.id = span; - } - } - - fn span_open(&mut self, group: &Self::Group) -> Self::Span { - // FIXME we only store one `TokenId` for the delimiters - group.delimiter.map(|it| it.id).unwrap_or_else(tt::TokenId::unspecified) - } - - fn span_close(&mut self, group: &Self::Group) -> Self::Span { - // FIXME we only store one `TokenId` for the delimiters - group.delimiter.map(|it| it.id).unwrap_or_else(tt::TokenId::unspecified) - } -} - -impl server::Punct for RustAnalyzer { - fn new(&mut self, ch: char, spacing: bridge::Spacing) -> Self::Punct { - tt::Punct { - char: ch, - spacing: spacing_to_internal(spacing), - id: tt::TokenId::unspecified(), - } - } - fn as_char(&mut self, punct: Self::Punct) -> char { - punct.char - } - fn spacing(&mut self, punct: Self::Punct) -> bridge::Spacing { - spacing_to_external(punct.spacing) - } - fn span(&mut self, punct: Self::Punct) -> Self::Span { - punct.id - } - fn with_span(&mut self, punct: Self::Punct, span: Self::Span) -> Self::Punct { - tt::Punct { id: span, ..punct } - } -} - -impl server::Ident for RustAnalyzer { - fn new(&mut self, string: &str, span: Self::Span, _is_raw: bool) -> Self::Ident { - IdentId(self.ident_interner.intern(&IdentData(tt::Ident { text: string.into(), id: span }))) - } - - fn span(&mut self, ident: Self::Ident) -> Self::Span { - self.ident_interner.get(ident.0).0.id - } - fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident { - let data = self.ident_interner.get(ident.0); - let new = IdentData(tt::Ident { id: span, ..data.0.clone() }); - IdentId(self.ident_interner.intern(&new)) - } -} - -impl server::Literal for RustAnalyzer { - fn debug_kind(&mut self, _literal: &Self::Literal) -> String { - // r-a: debug_kind and suffix are unsupported; corresponding client code has been changed to not call these. - // They must still be present to be ABI-compatible and work with upstream proc_macro. - "".to_owned() - } - fn from_str(&mut self, s: &str) -> Result { - Ok(Literal { text: s.into(), id: tt::TokenId::unspecified() }) - } - fn symbol(&mut self, literal: &Self::Literal) -> String { - literal.text.to_string() - } - fn suffix(&mut self, _literal: &Self::Literal) -> Option { - None - } - - fn to_string(&mut self, literal: &Self::Literal) -> String { - literal.to_string() - } - - fn integer(&mut self, n: &str) -> Self::Literal { - let n = match n.parse::() { - Ok(n) => n.to_string(), - Err(_) => n.parse::().unwrap().to_string(), - }; - Literal { text: n.into(), id: tt::TokenId::unspecified() } - } - - fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal { - macro_rules! def_suffixed_integer { - ($kind:ident, $($ty:ty),*) => { - match $kind { - $( - stringify!($ty) => { - let n: $ty = n.parse().unwrap(); - format!(concat!("{}", stringify!($ty)), n) - } - )* - _ => unimplemented!("unknown args for typed_integer: n {}, kind {}", n, $kind), - } - } - } - - let text = def_suffixed_integer! {kind, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize}; - - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn float(&mut self, n: &str) -> Self::Literal { - let n: f64 = n.parse().unwrap(); - let mut text = f64::to_string(&n); - if !text.contains('.') { - text += ".0" - } - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn f32(&mut self, n: &str) -> Self::Literal { - let n: f32 = n.parse().unwrap(); - let text = format!("{}f32", n); - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn f64(&mut self, n: &str) -> Self::Literal { - let n: f64 = n.parse().unwrap(); - let text = format!("{}f64", n); - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn string(&mut self, string: &str) -> Self::Literal { - let mut escaped = String::new(); - for ch in string.chars() { - escaped.extend(ch.escape_debug()); - } - Literal { text: format!("\"{}\"", escaped).into(), id: tt::TokenId::unspecified() } - } - - fn character(&mut self, ch: char) -> Self::Literal { - Literal { text: format!("'{}'", ch).into(), id: tt::TokenId::unspecified() } - } - - fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal { - let string = bytes - .iter() - .cloned() - .flat_map(ascii::escape_default) - .map(Into::::into) - .collect::(); - - Literal { text: format!("b\"{}\"", string).into(), id: tt::TokenId::unspecified() } - } - - fn span(&mut self, literal: &Self::Literal) -> Self::Span { - literal.id - } - - fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) { - literal.id = span; - } - - fn subspan( - &mut self, - _literal: &Self::Literal, - _start: Bound, - _end: Bound, - ) -> Option { - // FIXME handle span - None - } -} - -impl server::SourceFile for RustAnalyzer { - // FIXME these are all stubs - fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool { - true - } - fn path(&mut self, _file: &Self::SourceFile) -> String { - String::new() - } - fn is_real(&mut self, _file: &Self::SourceFile) -> bool { - true - } -} - -impl server::Diagnostic for RustAnalyzer { - fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic { - let mut diag = Diagnostic::new(level, msg); - diag.spans = spans; - diag - } - - fn sub( - &mut self, - _diag: &mut Self::Diagnostic, - _level: Level, - _msg: &str, - _spans: Self::MultiSpan, - ) { - // FIXME handle diagnostic - // - } - - fn emit(&mut self, _diag: Self::Diagnostic) { - // FIXME handle diagnostic - // diag.emit() - } -} - -impl server::Span for RustAnalyzer { - fn debug(&mut self, span: Self::Span) -> String { - format!("{:?}", span.0) - } - fn def_site(&mut self) -> Self::Span { - // MySpan(self.span_interner.intern(&MySpanData(Span::def_site()))) - // FIXME handle span - tt::TokenId::unspecified() - } - fn call_site(&mut self) -> Self::Span { - // MySpan(self.span_interner.intern(&MySpanData(Span::call_site()))) - // FIXME handle span - tt::TokenId::unspecified() - } - fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile { - SourceFile {} - } - fn save_span(&mut self, _span: Self::Span) -> usize { - // FIXME stub - 0 - } - fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span { - // FIXME stub - tt::TokenId::unspecified() - } - /// Recent feature, not yet in the proc_macro - /// - /// See PR: - /// https://github.com/rust-lang/rust/pull/55780 - fn source_text(&mut self, _span: Self::Span) -> Option { - None - } - - fn parent(&mut self, _span: Self::Span) -> Option { - // FIXME handle span - None - } - fn source(&mut self, span: Self::Span) -> Self::Span { - // FIXME handle span - span - } - fn start(&mut self, _span: Self::Span) -> LineColumn { - // FIXME handle span - LineColumn { line: 0, column: 0 } - } - fn end(&mut self, _span: Self::Span) -> LineColumn { - // FIXME handle span - LineColumn { line: 0, column: 0 } - } - fn join(&mut self, first: Self::Span, _second: Self::Span) -> Option { - // Just return the first span again, because some macros will unwrap the result. - Some(first) - } - fn resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span { - // FIXME handle span - tt::TokenId::unspecified() - } - - fn mixed_site(&mut self) -> Self::Span { - // FIXME handle span - tt::TokenId::unspecified() - } - - fn after(&mut self, _self_: Self::Span) -> Self::Span { - tt::TokenId::unspecified() - } - - fn before(&mut self, _self_: Self::Span) -> Self::Span { - tt::TokenId::unspecified() - } -} - -impl server::MultiSpan for RustAnalyzer { - fn new(&mut self) -> Self::MultiSpan { - // FIXME handle span - vec![] - } - - fn push(&mut self, other: &mut Self::MultiSpan, span: Self::Span) { - //TODP - other.push(span) - } -} - -#[cfg(test)] -mod tests { - use super::super::proc_macro::bridge::server::Literal; - use super::*; - - #[test] - fn test_ra_server_literals() { - let mut srv = RustAnalyzer { ident_interner: IdentInterner::default() }; - assert_eq!(srv.integer("1234").text, "1234"); - - assert_eq!(srv.typed_integer("12", "u8").text, "12u8"); - assert_eq!(srv.typed_integer("255", "u16").text, "255u16"); - assert_eq!(srv.typed_integer("1234", "u32").text, "1234u32"); - assert_eq!(srv.typed_integer("15846685", "u64").text, "15846685u64"); - assert_eq!(srv.typed_integer("15846685258", "u128").text, "15846685258u128"); - assert_eq!(srv.typed_integer("156788984", "usize").text, "156788984usize"); - assert_eq!(srv.typed_integer("127", "i8").text, "127i8"); - assert_eq!(srv.typed_integer("255", "i16").text, "255i16"); - assert_eq!(srv.typed_integer("1234", "i32").text, "1234i32"); - assert_eq!(srv.typed_integer("15846685", "i64").text, "15846685i64"); - assert_eq!(srv.typed_integer("15846685258", "i128").text, "15846685258i128"); - assert_eq!(srv.float("0").text, "0.0"); - assert_eq!(srv.float("15684.5867").text, "15684.5867"); - assert_eq!(srv.f32("15684.58").text, "15684.58f32"); - assert_eq!(srv.f64("15684.58").text, "15684.58f64"); - - assert_eq!(srv.string("hello_world").text, "\"hello_world\""); - assert_eq!(srv.character('c').text, "'c'"); - assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\""); - - // u128::max - assert_eq!( - srv.integer("340282366920938463463374607431768211455").text, - "340282366920938463463374607431768211455" - ); - // i128::min - assert_eq!( - srv.integer("-170141183460469231731687303715884105728").text, - "-170141183460469231731687303715884105728" - ); - } - - #[test] - fn test_ra_server_to_string() { - let s = TokenStream { - token_trees: vec![ - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "struct".into(), - id: tt::TokenId::unspecified(), - })), - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "T".into(), - id: tt::TokenId::unspecified(), - })), - tt::TokenTree::Subtree(tt::Subtree { - delimiter: Some(tt::Delimiter { - id: tt::TokenId::unspecified(), - kind: tt::DelimiterKind::Brace, - }), - token_trees: vec![], - }), - ], - }; - - assert_eq!(s.to_string(), "struct T {}"); - } - - #[test] - fn test_ra_server_from_str() { - use std::str::FromStr; - let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree { - delimiter: Some(tt::Delimiter { - id: tt::TokenId::unspecified(), - kind: tt::DelimiterKind::Parenthesis, - }), - token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "a".into(), - id: tt::TokenId::unspecified(), - }))], - }); - - let t1 = TokenStream::from_str("(a)").unwrap(); - assert_eq!(t1.token_trees.len(), 1); - assert_eq!(t1.token_trees[0], subtree_paren_a); - - let t2 = TokenStream::from_str("(a);").unwrap(); - assert_eq!(t2.token_trees.len(), 2); - assert_eq!(t2.token_trees[0], subtree_paren_a); - - let underscore = TokenStream::from_str("_").unwrap(); - assert_eq!( - underscore.token_trees[0], - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "_".into(), - id: tt::TokenId::unspecified(), - })) - ); - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/mod.rs deleted file mode 100644 index 9d56f0eaf888f..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/mod.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! Proc macro ABI. - -#[allow(dead_code)] -#[doc(hidden)] -mod proc_macro; - -#[allow(dead_code)] -#[doc(hidden)] -mod ra_server; - -use libloading::Library; -use proc_macro_api::ProcMacroKind; - -use super::PanicMessage; - -pub use ra_server::TokenStream; - -pub(crate) struct Abi { - exported_macros: Vec, -} - -impl From for PanicMessage { - fn from(p: proc_macro::bridge::PanicMessage) -> Self { - Self { message: p.as_str().map(|s| s.to_string()) } - } -} - -impl Abi { - pub unsafe fn from_lib(lib: &Library, symbol_name: String) -> Result { - let macros: libloading::Symbol<'_, &&[proc_macro::bridge::client::ProcMacro]> = - lib.get(symbol_name.as_bytes())?; - Ok(Self { exported_macros: macros.to_vec() }) - } - - pub fn expand( - &self, - macro_name: &str, - macro_body: &tt::Subtree, - attributes: Option<&tt::Subtree>, - ) -> Result { - let parsed_body = TokenStream::with_subtree(macro_body.clone()); - - let parsed_attributes = - attributes.map_or(TokenStream::new(), |attr| TokenStream::with_subtree(attr.clone())); - - for proc_macro in &self.exported_macros { - match proc_macro { - proc_macro::bridge::client::ProcMacro::CustomDerive { - trait_name, client, .. - } if *trait_name == macro_name => { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - proc_macro::bridge::client::ProcMacro::Bang { name, client } - if *name == macro_name => - { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - proc_macro::bridge::client::ProcMacro::Attr { name, client } - if *name == macro_name => - { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_attributes, - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - _ => continue, - } - } - - Err(proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()).into()) - } - - pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { - self.exported_macros - .iter() - .map(|proc_macro| match proc_macro { - proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { - (trait_name.to_string(), ProcMacroKind::CustomDerive) - } - proc_macro::bridge::client::ProcMacro::Bang { name, .. } => { - (name.to_string(), ProcMacroKind::FuncLike) - } - proc_macro::bridge::client::ProcMacro::Attr { name, .. } => { - (name.to_string(), ProcMacroKind::Attr) - } - }) - .collect() - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/buffer.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/buffer.rs deleted file mode 100644 index 48030f8d82dca..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/buffer.rs +++ /dev/null @@ -1,156 +0,0 @@ -//! Buffer management for same-process client<->server communication. - -use std::io::{self, Write}; -use std::mem; -use std::ops::{Deref, DerefMut}; -use std::slice; - -#[repr(C)] -pub struct Buffer { - data: *mut u8, - len: usize, - capacity: usize, - reserve: extern "C" fn(Buffer, usize) -> Buffer, - drop: extern "C" fn(Buffer), -} - -unsafe impl Sync for Buffer {} -unsafe impl Send for Buffer {} - -impl Default for Buffer { - #[inline] - fn default() -> Self { - Self::from(vec![]) - } -} - -impl Deref for Buffer { - type Target = [u8]; - #[inline] - fn deref(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.data as *const u8, self.len) } - } -} - -impl DerefMut for Buffer { - #[inline] - fn deref_mut(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.data, self.len) } - } -} - -impl Buffer { - #[inline] - pub(super) fn new() -> Self { - Self::default() - } - - #[inline] - pub(super) fn clear(&mut self) { - self.len = 0; - } - - #[inline] - pub(super) fn take(&mut self) -> Self { - mem::take(self) - } - - // We have the array method separate from extending from a slice. This is - // because in the case of small arrays, codegen can be more efficient - // (avoiding a memmove call). With extend_from_slice, LLVM at least - // currently is not able to make that optimization. - #[inline] - pub(super) fn extend_from_array(&mut self, xs: &[u8; N]) { - if xs.len() > (self.capacity - self.len) { - let b = self.take(); - *self = (b.reserve)(b, xs.len()); - } - unsafe { - xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len()); - self.len += xs.len(); - } - } - - #[inline] - pub(super) fn extend_from_slice(&mut self, xs: &[u8]) { - if xs.len() > (self.capacity - self.len) { - let b = self.take(); - *self = (b.reserve)(b, xs.len()); - } - unsafe { - xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len()); - self.len += xs.len(); - } - } - - #[inline] - pub(super) fn push(&mut self, v: u8) { - // The code here is taken from Vec::push, and we know that reserve() - // will panic if we're exceeding isize::MAX bytes and so there's no need - // to check for overflow. - if self.len == self.capacity { - let b = self.take(); - *self = (b.reserve)(b, 1); - } - unsafe { - *self.data.add(self.len) = v; - self.len += 1; - } - } -} - -impl Write for Buffer { - #[inline] - fn write(&mut self, xs: &[u8]) -> io::Result { - self.extend_from_slice(xs); - Ok(xs.len()) - } - - #[inline] - fn write_all(&mut self, xs: &[u8]) -> io::Result<()> { - self.extend_from_slice(xs); - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Drop for Buffer { - #[inline] - fn drop(&mut self) { - let b = self.take(); - (b.drop)(b); - } -} - -impl From> for Buffer { - fn from(mut v: Vec) -> Self { - let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity()); - mem::forget(v); - - // This utility function is nested in here because it can *only* - // be safely called on `Buffer`s created by *this* `proc_macro`. - fn to_vec(b: Buffer) -> Vec { - unsafe { - let Buffer { data, len, capacity, .. } = b; - mem::forget(b); - Vec::from_raw_parts(data, len, capacity) - } - } - - extern "C" fn reserve(b: Buffer, additional: usize) -> Buffer { - let mut v = to_vec(b); - v.reserve(additional); - Buffer::from(v) - } - - extern "C" fn drop(b: Buffer) { - mem::drop(to_vec(b)); - } - - Buffer { data, len, capacity, reserve, drop } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/client.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/client.rs deleted file mode 100644 index 22bda8ba5a7cf..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/client.rs +++ /dev/null @@ -1,529 +0,0 @@ -//! Client-side types. - -use super::*; - -use std::marker::PhantomData; - -macro_rules! define_handles { - ( - 'owned: $($oty:ident,)* - 'interned: $($ity:ident,)* - ) => { - #[repr(C)] - #[allow(non_snake_case)] - pub struct HandleCounters { - $($oty: AtomicUsize,)* - $($ity: AtomicUsize,)* - } - - impl HandleCounters { - // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of - // a wrapper `fn` pointer, once `const fn` can reference `static`s. - extern "C" fn get() -> &'static Self { - static COUNTERS: HandleCounters = HandleCounters { - $($oty: AtomicUsize::new(1),)* - $($ity: AtomicUsize::new(1),)* - }; - &COUNTERS - } - } - - // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. - #[repr(C)] - #[allow(non_snake_case)] - pub(super) struct HandleStore { - $($oty: handle::OwnedStore,)* - $($ity: handle::InternedStore,)* - } - - impl HandleStore { - pub(super) fn new(handle_counters: &'static HandleCounters) -> Self { - HandleStore { - $($oty: handle::OwnedStore::new(&handle_counters.$oty),)* - $($ity: handle::InternedStore::new(&handle_counters.$ity),)* - } - } - } - - $( - #[repr(C)] - pub(crate) struct $oty { - handle: handle::Handle, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual - // way of doing this, but that requires unstable features. - // rust-analyzer uses this code and avoids unstable features. - _marker: PhantomData<*mut ()>, - } - - // Forward `Drop::drop` to the inherent `drop` method. - impl Drop for $oty { - fn drop(&mut self) { - $oty { - handle: self.handle, - _marker: PhantomData, - }.drop(); - } - } - - impl Encode for $oty { - fn encode(self, w: &mut Writer, s: &mut S) { - let handle = self.handle; - mem::forget(self); - handle.encode(w, s); - } - } - - impl DecodeMut<'_, '_, HandleStore>> - for Marked - { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { - s.$oty.take(handle::Handle::decode(r, &mut ())) - } - } - - impl Encode for &$oty { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl<'s, S: server::Types> Decode<'_, 's, HandleStore>> - for &'s Marked - { - fn decode(r: &mut Reader<'_>, s: &'s HandleStore>) -> Self { - &s.$oty[handle::Handle::decode(r, &mut ())] - } - } - - impl Encode for &mut $oty { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl<'s, S: server::Types> DecodeMut<'_, 's, HandleStore>> - for &'s mut Marked - { - fn decode( - r: &mut Reader<'_>, - s: &'s mut HandleStore> - ) -> Self { - &mut s.$oty[handle::Handle::decode(r, &mut ())] - } - } - - impl Encode>> - for Marked - { - fn encode(self, w: &mut Writer, s: &mut HandleStore>) { - s.$oty.alloc(self).encode(w, s); - } - } - - impl DecodeMut<'_, '_, S> for $oty { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - $oty { - handle: handle::Handle::decode(r, s), - _marker: PhantomData, - } - } - } - )* - - $( - #[repr(C)] - #[derive(Copy, Clone, PartialEq, Eq, Hash)] - pub(crate) struct $ity { - handle: handle::Handle, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual - // way of doing this, but that requires unstable features. - // rust-analyzer uses this code and avoids unstable features. - _marker: PhantomData<*mut ()>, - } - - impl Encode for $ity { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl DecodeMut<'_, '_, HandleStore>> - for Marked - { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { - s.$ity.copy(handle::Handle::decode(r, &mut ())) - } - } - - impl Encode>> - for Marked - { - fn encode(self, w: &mut Writer, s: &mut HandleStore>) { - s.$ity.alloc(self).encode(w, s); - } - } - - impl DecodeMut<'_, '_, S> for $ity { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - $ity { - handle: handle::Handle::decode(r, s), - _marker: PhantomData, - } - } - } - )* - } -} -define_handles! { - 'owned: - FreeFunctions, - TokenStream, - Literal, - SourceFile, - MultiSpan, - Diagnostic, - - 'interned: - Ident, - Span, -} - -// FIXME(eddyb) generate these impls by pattern-matching on the -// names of methods - also could use the presence of `fn drop` -// to distinguish between 'owned and 'interned, above. -// Alternatively, special "modes" could be listed of types in with_api -// instead of pattern matching on methods, here and in server decl. - -impl Clone for TokenStream { - fn clone(&self) -> Self { - self.clone() - } -} - -impl Clone for Literal { - fn clone(&self) -> Self { - self.clone() - } -} - -impl fmt::Debug for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Literal") - // format the kind without quotes, as in `kind: Float` - .field("kind", &format_args!("{}", &self.debug_kind())) - .field("symbol", &self.symbol()) - // format `Some("...")` on one line even in {:#?} mode - .field("suffix", &format_args!("{:?}", &self.suffix())) - .field("span", &self.span()) - .finish() - } -} - -impl Clone for SourceFile { - fn clone(&self) -> Self { - self.clone() - } -} - -impl Span { - pub(crate) fn def_site() -> Span { - Bridge::with(|bridge| bridge.globals.def_site) - } - - pub(crate) fn call_site() -> Span { - Bridge::with(|bridge| bridge.globals.call_site) - } - - pub(crate) fn mixed_site() -> Span { - Bridge::with(|bridge| bridge.globals.mixed_site) - } -} - -impl fmt::Debug for Span { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.debug()) - } -} - -macro_rules! define_client_side { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }),* $(,)?) => { - $(impl $name { - $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* { - Bridge::with(|bridge| { - let mut buf = bridge.cached_buffer.take(); - - buf.clear(); - api_tags::Method::$name(api_tags::$name::$method).encode(&mut buf, &mut ()); - reverse_encode!(buf; $($arg),*); - - buf = bridge.dispatch.call(buf); - - let r = Result::<_, PanicMessage>::decode(&mut &buf[..], &mut ()); - - bridge.cached_buffer = buf; - - r.unwrap_or_else(|e| panic::resume_unwind(e.into())) - }) - })* - })* - } -} -with_api!(self, self, define_client_side); - -struct Bridge<'a> { - /// Reusable buffer (only `clear`-ed, never shrunk), primarily - /// used for making requests. - cached_buffer: Buffer, - - /// Server-side function that the client uses to make requests. - dispatch: closure::Closure<'a, Buffer, Buffer>, - - /// Provided globals for this macro expansion. - globals: ExpnGlobals, -} - -enum BridgeState<'a> { - /// No server is currently connected to this client. - NotConnected, - - /// A server is connected and available for requests. - Connected(Bridge<'a>), - - /// Access to the bridge is being exclusively acquired - /// (e.g., during `BridgeState::with`). - InUse, -} - -enum BridgeStateL {} - -impl<'a> scoped_cell::ApplyL<'a> for BridgeStateL { - type Out = BridgeState<'a>; -} - -thread_local! { - static BRIDGE_STATE: scoped_cell::ScopedCell = - scoped_cell::ScopedCell::new(BridgeState::NotConnected); -} - -impl BridgeState<'_> { - /// Take exclusive control of the thread-local - /// `BridgeState`, and pass it to `f`, mutably. - /// The state will be restored after `f` exits, even - /// by panic, including modifications made to it by `f`. - /// - /// N.B., while `f` is running, the thread-local state - /// is `BridgeState::InUse`. - fn with(f: impl FnOnce(&mut BridgeState<'_>) -> R) -> R { - BRIDGE_STATE.with(|state| { - state.replace(BridgeState::InUse, |mut state| { - // FIXME(#52812) pass `f` directly to `replace` when `RefMutL` is gone - f(&mut *state) - }) - }) - } -} - -impl Bridge<'_> { - fn with(f: impl FnOnce(&mut Bridge<'_>) -> R) -> R { - BridgeState::with(|state| match state { - BridgeState::NotConnected => { - panic!("procedural macro API is used outside of a procedural macro"); - } - BridgeState::InUse => { - panic!("procedural macro API is used while it's already in use"); - } - BridgeState::Connected(bridge) => f(bridge), - }) - } -} - -pub(crate) fn is_available() -> bool { - BridgeState::with(|state| match state { - BridgeState::Connected(_) | BridgeState::InUse => true, - BridgeState::NotConnected => false, - }) -} - -/// A client-side RPC entry-point, which may be using a different `proc_macro` -/// from the one used by the server, but can be invoked compatibly. -/// -/// Note that the (phantom) `I` ("input") and `O` ("output") type parameters -/// decorate the `Client` with the RPC "interface" of the entry-point, but -/// do not themselves participate in ABI, at all, only facilitate type-checking. -/// -/// E.g. `Client` is the common proc macro interface, -/// used for `#[proc_macro] fn foo(input: TokenStream) -> TokenStream`, -/// indicating that the RPC input and output will be serialized token streams, -/// and forcing the use of APIs that take/return `S::TokenStream`, server-side. -#[repr(C)] -pub struct Client { - // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of - // a wrapper `fn` pointer, once `const fn` can reference `static`s. - pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters, - - pub(super) run: extern "C" fn(BridgeConfig<'_>) -> Buffer, - - pub(super) _marker: PhantomData O>, -} - -impl Copy for Client {} -impl Clone for Client { - fn clone(&self) -> Self { - *self - } -} - -fn maybe_install_panic_hook(force_show_panics: bool) { - // Hide the default panic output within `proc_macro` expansions. - // NB. the server can't do this because it may use a different libstd. - static HIDE_PANICS_DURING_EXPANSION: Once = Once::new(); - HIDE_PANICS_DURING_EXPANSION.call_once(|| { - let prev = panic::take_hook(); - panic::set_hook(Box::new(move |info| { - let show = BridgeState::with(|state| match state { - BridgeState::NotConnected => true, - BridgeState::Connected(_) | BridgeState::InUse => force_show_panics, - }); - if show { - prev(info) - } - })); - }); -} - -/// Client-side helper for handling client panics, entering the bridge, -/// deserializing input and serializing output. -// FIXME(eddyb) maybe replace `Bridge::enter` with this? -fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( - config: BridgeConfig<'_>, - f: impl FnOnce(A) -> R, -) -> Buffer { - let BridgeConfig { input: mut buf, dispatch, force_show_panics, .. } = config; - - panic::catch_unwind(panic::AssertUnwindSafe(|| { - maybe_install_panic_hook(force_show_panics); - - let reader = &mut &buf[..]; - let (globals, input) = <(ExpnGlobals, A)>::decode(reader, &mut ()); - - // Put the buffer we used for input back in the `Bridge` for requests. - let new_state = - BridgeState::Connected(Bridge { cached_buffer: buf.take(), dispatch, globals }); - - BRIDGE_STATE.with(|state| { - state.set(new_state, || { - let output = f(input); - - // Take the `cached_buffer` back out, for the output value. - buf = Bridge::with(|bridge| bridge.cached_buffer.take()); - - // HACK(eddyb) Separate encoding a success value (`Ok(output)`) - // from encoding a panic (`Err(e: PanicMessage)`) to avoid - // having handles outside the `bridge.enter(|| ...)` scope, and - // to catch panics that could happen while encoding the success. - // - // Note that panics should be impossible beyond this point, but - // this is defensively trying to avoid any accidental panicking - // reaching the `extern "C"` (which should `abort` but might not - // at the moment, so this is also potentially preventing UB). - buf.clear(); - Ok::<_, ()>(output).encode(&mut buf, &mut ()); - }) - }) - })) - .map_err(PanicMessage::from) - .unwrap_or_else(|e| { - buf.clear(); - Err::<(), _>(e).encode(&mut buf, &mut ()); - }); - buf -} - -impl Client { - pub const fn expand1( - f: impl Fn(super::super::TokenStream) -> super::super::TokenStream + Copy, - ) -> Self { - Client { - get_handle_counters: HandleCounters::get, - run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| { - run_client(bridge, |input| f(super::super::TokenStream(input)).0) - }), - _marker: PhantomData, - } - } -} - -impl Client<(super::super::TokenStream, super::super::TokenStream), super::super::TokenStream> { - pub const fn expand2( - f: impl Fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream - + Copy, - ) -> Self { - Client { - get_handle_counters: HandleCounters::get, - run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| { - run_client(bridge, |(input, input2)| { - f(super::super::TokenStream(input), super::super::TokenStream(input2)).0 - }) - }), - _marker: PhantomData, - } - } -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum ProcMacro { - CustomDerive { - trait_name: &'static str, - attributes: &'static [&'static str], - client: Client, - }, - - Attr { - name: &'static str, - client: Client< - (super::super::TokenStream, super::super::TokenStream), - super::super::TokenStream, - >, - }, - - Bang { - name: &'static str, - client: Client, - }, -} - -impl ProcMacro { - pub fn name(&self) -> &'static str { - match self { - ProcMacro::CustomDerive { trait_name, .. } => trait_name, - ProcMacro::Attr { name, .. } => name, - ProcMacro::Bang { name, .. } => name, - } - } - - pub const fn custom_derive( - trait_name: &'static str, - attributes: &'static [&'static str], - expand: impl Fn(super::super::TokenStream) -> super::super::TokenStream + Copy, - ) -> Self { - ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) } - } - - pub const fn attr( - name: &'static str, - expand: impl Fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream - + Copy, - ) -> Self { - ProcMacro::Attr { name, client: Client::expand2(expand) } - } - - pub const fn bang( - name: &'static str, - expand: impl Fn(super::super::TokenStream) -> super::super::TokenStream + Copy, - ) -> Self { - ProcMacro::Bang { name, client: Client::expand1(expand) } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/closure.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/closure.rs deleted file mode 100644 index d371ae3cea098..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/closure.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Closure type (equivalent to `&mut dyn FnMut(A) -> R`) that's `repr(C)`. - -use std::marker::PhantomData; - -#[repr(C)] -pub struct Closure<'a, A, R> { - call: unsafe extern "C" fn(*mut Env, A) -> R, - env: *mut Env, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing - // this, but that requires unstable features. rust-analyzer uses this code - // and avoids unstable features. - // - // The `'a` lifetime parameter represents the lifetime of `Env`. - _marker: PhantomData<*mut &'a mut ()>, -} - -struct Env; - -impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> { - fn from(f: &'a mut F) -> Self { - unsafe extern "C" fn call R>(env: *mut Env, arg: A) -> R { - (*(env as *mut _ as *mut F))(arg) - } - Closure { call: call::, env: f as *mut _ as *mut Env, _marker: PhantomData } - } -} - -impl<'a, A, R> Closure<'a, A, R> { - pub fn call(&mut self, arg: A) -> R { - unsafe { (self.call)(self.env, arg) } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/handle.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/handle.rs deleted file mode 100644 index c219a9465d39f..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/handle.rs +++ /dev/null @@ -1,89 +0,0 @@ -//! Server-side handles and storage for per-handle data. - -use std::collections::{BTreeMap, HashMap}; -use std::hash::{BuildHasher, Hash}; -use std::num::NonZeroU32; -use std::ops::{Index, IndexMut}; -use std::sync::atomic::{AtomicUsize, Ordering}; - -pub(super) type Handle = NonZeroU32; - -/// A store that associates values of type `T` with numeric handles. A value can -/// be looked up using its handle. -pub(super) struct OwnedStore { - counter: &'static AtomicUsize, - data: BTreeMap, -} - -impl OwnedStore { - pub(super) fn new(counter: &'static AtomicUsize) -> Self { - // Ensure the handle counter isn't 0, which would panic later, - // when `NonZeroU32::new` (aka `Handle::new`) is called in `alloc`. - assert_ne!(counter.load(Ordering::SeqCst), 0); - - OwnedStore { counter, data: BTreeMap::new() } - } -} - -impl OwnedStore { - pub(super) fn alloc(&mut self, x: T) -> Handle { - let counter = self.counter.fetch_add(1, Ordering::SeqCst); - let handle = Handle::new(counter as u32).expect("`proc_macro` handle counter overflowed"); - assert!(self.data.insert(handle, x).is_none()); - handle - } - - pub(super) fn take(&mut self, h: Handle) -> T { - self.data.remove(&h).expect("use-after-free in `proc_macro` handle") - } -} - -impl Index for OwnedStore { - type Output = T; - fn index(&self, h: Handle) -> &T { - self.data.get(&h).expect("use-after-free in `proc_macro` handle") - } -} - -impl IndexMut for OwnedStore { - fn index_mut(&mut self, h: Handle) -> &mut T { - self.data.get_mut(&h).expect("use-after-free in `proc_macro` handle") - } -} - -// HACK(eddyb) deterministic `std::collections::hash_map::RandomState` replacement -// that doesn't require adding any dependencies to `proc_macro` (like `rustc-hash`). -#[derive(Clone)] -struct NonRandomState; - -impl BuildHasher for NonRandomState { - type Hasher = std::collections::hash_map::DefaultHasher; - #[inline] - fn build_hasher(&self) -> Self::Hasher { - Self::Hasher::new() - } -} - -/// Like `OwnedStore`, but avoids storing any value more than once. -pub(super) struct InternedStore { - owned: OwnedStore, - interner: HashMap, -} - -impl InternedStore { - pub(super) fn new(counter: &'static AtomicUsize) -> Self { - InternedStore { - owned: OwnedStore::new(counter), - interner: HashMap::with_hasher(NonRandomState), - } - } - - pub(super) fn alloc(&mut self, x: T) -> Handle { - let owned = &mut self.owned; - *self.interner.entry(x).or_insert_with(|| owned.alloc(x)) - } - - pub(super) fn copy(&mut self, h: Handle) -> T { - self.owned[h] - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/mod.rs deleted file mode 100644 index ffd440793231c..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/mod.rs +++ /dev/null @@ -1,493 +0,0 @@ -//! Internal interface for communicating between a `proc_macro` client -//! (a proc macro crate) and a `proc_macro` server (a compiler front-end). -//! -//! Serialization (with C ABI buffers) and unique integer handles are employed -//! to allow safely interfacing between two copies of `proc_macro` built -//! (from the same source) by different compilers with potentially mismatching -//! Rust ABIs (e.g., stage0/bin/rustc vs stage1/bin/rustc during bootstrap). - -#![deny(unsafe_code)] - -pub use super::{Delimiter, Level, LineColumn, Spacing}; -use std::fmt; -use std::hash::Hash; -use std::marker; -use std::mem; -use std::ops::Bound; -use std::panic; -use std::sync::atomic::AtomicUsize; -use std::sync::Once; -use std::thread; - -/// Higher-order macro describing the server RPC API, allowing automatic -/// generation of type-safe Rust APIs, both client-side and server-side. -/// -/// `with_api!(MySelf, my_self, my_macro)` expands to: -/// ```rust,ignore (pseudo-code) -/// my_macro! { -/// // ... -/// Literal { -/// // ... -/// fn character(ch: char) -> MySelf::Literal; -/// // ... -/// fn span(my_self: &MySelf::Literal) -> MySelf::Span; -/// fn set_span(my_self: &mut MySelf::Literal, span: MySelf::Span); -/// }, -/// // ... -/// } -/// ``` -/// -/// The first two arguments serve to customize the arguments names -/// and argument/return types, to enable several different usecases: -/// -/// If `my_self` is just `self`, then each `fn` signature can be used -/// as-is for a method. If it's anything else (`self_` in practice), -/// then the signatures don't have a special `self` argument, and -/// can, therefore, have a different one introduced. -/// -/// If `MySelf` is just `Self`, then the types are only valid inside -/// a trait or a trait impl, where the trait has associated types -/// for each of the API types. If non-associated types are desired, -/// a module name (`self` in practice) can be used instead of `Self`. -macro_rules! with_api { - ($S:ident, $self:ident, $m:ident) => { - $m! { - FreeFunctions { - fn drop($self: $S::FreeFunctions); - fn track_env_var(var: &str, value: Option<&str>); - fn track_path(path: &str); - }, - TokenStream { - fn drop($self: $S::TokenStream); - fn clone($self: &$S::TokenStream) -> $S::TokenStream; - fn is_empty($self: &$S::TokenStream) -> bool; - fn expand_expr($self: &$S::TokenStream) -> Result<$S::TokenStream, ()>; - fn from_str(src: &str) -> $S::TokenStream; - fn to_string($self: &$S::TokenStream) -> String; - fn from_token_tree( - tree: TokenTree<$S::TokenStream, $S::Span, $S::Ident, $S::Literal>, - ) -> $S::TokenStream; - fn concat_trees( - base: Option<$S::TokenStream>, - trees: Vec>, - ) -> $S::TokenStream; - fn concat_streams( - base: Option<$S::TokenStream>, - streams: Vec<$S::TokenStream>, - ) -> $S::TokenStream; - fn into_trees( - $self: $S::TokenStream - ) -> Vec>; - }, - Ident { - fn new(string: &str, span: $S::Span, is_raw: bool) -> $S::Ident; - fn span($self: $S::Ident) -> $S::Span; - fn with_span($self: $S::Ident, span: $S::Span) -> $S::Ident; - }, - Literal { - fn drop($self: $S::Literal); - fn clone($self: &$S::Literal) -> $S::Literal; - fn from_str(s: &str) -> Result<$S::Literal, ()>; - fn to_string($self: &$S::Literal) -> String; - fn debug_kind($self: &$S::Literal) -> String; - fn symbol($self: &$S::Literal) -> String; - fn suffix($self: &$S::Literal) -> Option; - fn integer(n: &str) -> $S::Literal; - fn typed_integer(n: &str, kind: &str) -> $S::Literal; - fn float(n: &str) -> $S::Literal; - fn f32(n: &str) -> $S::Literal; - fn f64(n: &str) -> $S::Literal; - fn string(string: &str) -> $S::Literal; - fn character(ch: char) -> $S::Literal; - fn byte_string(bytes: &[u8]) -> $S::Literal; - fn span($self: &$S::Literal) -> $S::Span; - fn set_span($self: &mut $S::Literal, span: $S::Span); - fn subspan( - $self: &$S::Literal, - start: Bound, - end: Bound, - ) -> Option<$S::Span>; - }, - SourceFile { - fn drop($self: $S::SourceFile); - fn clone($self: &$S::SourceFile) -> $S::SourceFile; - fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool; - fn path($self: &$S::SourceFile) -> String; - fn is_real($self: &$S::SourceFile) -> bool; - }, - MultiSpan { - fn drop($self: $S::MultiSpan); - fn new() -> $S::MultiSpan; - fn push($self: &mut $S::MultiSpan, span: $S::Span); - }, - Diagnostic { - fn drop($self: $S::Diagnostic); - fn new(level: Level, msg: &str, span: $S::MultiSpan) -> $S::Diagnostic; - fn sub( - $self: &mut $S::Diagnostic, - level: Level, - msg: &str, - span: $S::MultiSpan, - ); - fn emit($self: $S::Diagnostic); - }, - Span { - fn debug($self: $S::Span) -> String; - fn source_file($self: $S::Span) -> $S::SourceFile; - fn parent($self: $S::Span) -> Option<$S::Span>; - fn source($self: $S::Span) -> $S::Span; - fn start($self: $S::Span) -> LineColumn; - fn end($self: $S::Span) -> LineColumn; - fn before($self: $S::Span) -> $S::Span; - fn after($self: $S::Span) -> $S::Span; - fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; - fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span; - fn source_text($self: $S::Span) -> Option; - fn save_span($self: $S::Span) -> usize; - fn recover_proc_macro_span(id: usize) -> $S::Span; - }, - } - }; -} - -// FIXME(eddyb) this calls `encode` for each argument, but in reverse, -// to match the ordering in `reverse_decode`. -macro_rules! reverse_encode { - ($writer:ident;) => {}; - ($writer:ident; $first:ident $(, $rest:ident)*) => { - reverse_encode!($writer; $($rest),*); - $first.encode(&mut $writer, &mut ()); - } -} - -// FIXME(eddyb) this calls `decode` for each argument, but in reverse, -// to avoid borrow conflicts from borrows started by `&mut` arguments. -macro_rules! reverse_decode { - ($reader:ident, $s:ident;) => {}; - ($reader:ident, $s:ident; $first:ident: $first_ty:ty $(, $rest:ident: $rest_ty:ty)*) => { - reverse_decode!($reader, $s; $($rest: $rest_ty),*); - let $first = <$first_ty>::decode(&mut $reader, $s); - } -} - -#[allow(unsafe_code)] -mod buffer; -#[forbid(unsafe_code)] -pub mod client; -#[allow(unsafe_code)] -mod closure; -#[forbid(unsafe_code)] -mod handle; -#[macro_use] -#[forbid(unsafe_code)] -mod rpc; -#[allow(unsafe_code)] -mod scoped_cell; -#[allow(unsafe_code)] -mod selfless_reify; -#[forbid(unsafe_code)] -pub mod server; - -use buffer::Buffer; -pub use rpc::PanicMessage; -use rpc::{Decode, DecodeMut, Encode, Reader, Writer}; - -/// Configuration for establishing an active connection between a server and a -/// client. The server creates the bridge config (`run_server` in `server.rs`), -/// then passes it to the client through the function pointer in the `run` field -/// of `client::Client`. The client constructs a local `Bridge` from the config -/// in TLS during its execution (`Bridge::{enter, with}` in `client.rs`). -#[repr(C)] -pub struct BridgeConfig<'a> { - /// Buffer used to pass initial input to the client. - input: Buffer, - - /// Server-side function that the client uses to make requests. - dispatch: closure::Closure<'a, Buffer, Buffer>, - - /// If 'true', always invoke the default panic hook - force_show_panics: bool, - - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing - // this, but that requires unstable features. rust-analyzer uses this code - // and avoids unstable features. - _marker: marker::PhantomData<*mut ()>, -} - -#[forbid(unsafe_code)] -#[allow(non_camel_case_types)] -mod api_tags { - use super::rpc::{DecodeMut, Encode, Reader, Writer}; - - macro_rules! declare_tags { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }),* $(,)?) => { - $( - pub(super) enum $name { - $($method),* - } - rpc_encode_decode!(enum $name { $($method),* }); - )* - - pub(super) enum Method { - $($name($name)),* - } - rpc_encode_decode!(enum Method { $($name(m)),* }); - } - } - with_api!(self, self, declare_tags); -} - -/// Helper to wrap associated types to allow trait impl dispatch. -/// That is, normally a pair of impls for `T::Foo` and `T::Bar` -/// can overlap, but if the impls are, instead, on types like -/// `Marked` and `Marked`, they can't. -trait Mark { - type Unmarked; - fn mark(unmarked: Self::Unmarked) -> Self; -} - -/// Unwrap types wrapped by `Mark::mark` (see `Mark` for details). -trait Unmark { - type Unmarked; - fn unmark(self) -> Self::Unmarked; -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -struct Marked { - value: T, - _marker: marker::PhantomData, -} - -impl Mark for Marked { - type Unmarked = T; - fn mark(unmarked: Self::Unmarked) -> Self { - Marked { value: unmarked, _marker: marker::PhantomData } - } -} -impl Unmark for Marked { - type Unmarked = T; - fn unmark(self) -> Self::Unmarked { - self.value - } -} -impl<'a, T, M> Unmark for &'a Marked { - type Unmarked = &'a T; - fn unmark(self) -> Self::Unmarked { - &self.value - } -} -impl<'a, T, M> Unmark for &'a mut Marked { - type Unmarked = &'a mut T; - fn unmark(self) -> Self::Unmarked { - &mut self.value - } -} - -impl Mark for Vec { - type Unmarked = Vec; - fn mark(unmarked: Self::Unmarked) -> Self { - // Should be a no-op due to std's in-place collect optimizations. - unmarked.into_iter().map(T::mark).collect() - } -} -impl Unmark for Vec { - type Unmarked = Vec; - fn unmark(self) -> Self::Unmarked { - // Should be a no-op due to std's in-place collect optimizations. - self.into_iter().map(T::unmark).collect() - } -} - -macro_rules! mark_noop { - ($($ty:ty),* $(,)?) => { - $( - impl Mark for $ty { - type Unmarked = Self; - fn mark(unmarked: Self::Unmarked) -> Self { - unmarked - } - } - impl Unmark for $ty { - type Unmarked = Self; - fn unmark(self) -> Self::Unmarked { - self - } - } - )* - } -} -mark_noop! { - (), - bool, - char, - &'_ [u8], - &'_ str, - String, - u8, - usize, - Delimiter, - Level, - LineColumn, - Spacing, -} - -rpc_encode_decode!( - enum Delimiter { - Parenthesis, - Brace, - Bracket, - None, - } -); -rpc_encode_decode!( - enum Level { - Error, - Warning, - Note, - Help, - } -); -rpc_encode_decode!(struct LineColumn { line, column }); -rpc_encode_decode!( - enum Spacing { - Alone, - Joint, - } -); - -macro_rules! mark_compound { - (struct $name:ident <$($T:ident),+> { $($field:ident),* $(,)? }) => { - impl<$($T: Mark),+> Mark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; - fn mark(unmarked: Self::Unmarked) -> Self { - $name { - $($field: Mark::mark(unmarked.$field)),* - } - } - } - impl<$($T: Unmark),+> Unmark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; - fn unmark(self) -> Self::Unmarked { - $name { - $($field: Unmark::unmark(self.$field)),* - } - } - } - }; - (enum $name:ident <$($T:ident),+> { $($variant:ident $(($field:ident))?),* $(,)? }) => { - impl<$($T: Mark),+> Mark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; - fn mark(unmarked: Self::Unmarked) -> Self { - match unmarked { - $($name::$variant $(($field))? => { - $name::$variant $((Mark::mark($field)))? - })* - } - } - } - impl<$($T: Unmark),+> Unmark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; - fn unmark(self) -> Self::Unmarked { - match self { - $($name::$variant $(($field))? => { - $name::$variant $((Unmark::unmark($field)))? - })* - } - } - } - } -} - -macro_rules! compound_traits { - ($($t:tt)*) => { - rpc_encode_decode!($($t)*); - mark_compound!($($t)*); - }; -} - -compound_traits!( - enum Bound { - Included(x), - Excluded(x), - Unbounded, - } -); - -compound_traits!( - enum Option { - Some(t), - None, - } -); - -compound_traits!( - enum Result { - Ok(t), - Err(e), - } -); - -#[derive(Copy, Clone)] -pub struct DelimSpan { - pub open: Span, - pub close: Span, - pub entire: Span, -} - -impl DelimSpan { - pub fn from_single(span: Span) -> Self { - DelimSpan { open: span, close: span, entire: span } - } -} - -compound_traits!(struct DelimSpan { open, close, entire }); - -#[derive(Clone)] -pub struct Group { - pub delimiter: Delimiter, - pub stream: Option, - pub span: DelimSpan, -} - -compound_traits!(struct Group { delimiter, stream, span }); - -#[derive(Clone)] -pub struct Punct { - pub ch: u8, - pub joint: bool, - pub span: Span, -} - -compound_traits!(struct Punct { ch, joint, span }); - -#[derive(Clone)] -pub enum TokenTree { - Group(Group), - Punct(Punct), - Ident(Ident), - Literal(Literal), -} - -compound_traits!( - enum TokenTree { - Group(tt), - Punct(tt), - Ident(tt), - Literal(tt), - } -); - -/// Globals provided alongside the initial inputs for a macro expansion. -/// Provides values such as spans which are used frequently to avoid RPC. -#[derive(Clone)] -pub struct ExpnGlobals { - pub def_site: Span, - pub call_site: Span, - pub mixed_site: Span, -} - -compound_traits!( - struct ExpnGlobals { def_site, call_site, mixed_site } -); diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/rpc.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/rpc.rs deleted file mode 100644 index e9d7a46c06f6d..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/rpc.rs +++ /dev/null @@ -1,304 +0,0 @@ -//! Serialization for client-server communication. - -use std::any::Any; -use std::char; -use std::io::Write; -use std::num::NonZeroU32; -use std::str; - -pub(super) type Writer = super::buffer::Buffer; - -pub(super) trait Encode: Sized { - fn encode(self, w: &mut Writer, s: &mut S); -} - -pub(super) type Reader<'a> = &'a [u8]; - -pub(super) trait Decode<'a, 's, S>: Sized { - fn decode(r: &mut Reader<'a>, s: &'s S) -> Self; -} - -pub(super) trait DecodeMut<'a, 's, S>: Sized { - fn decode(r: &mut Reader<'a>, s: &'s mut S) -> Self; -} - -macro_rules! rpc_encode_decode { - (le $ty:ty) => { - impl Encode for $ty { - fn encode(self, w: &mut Writer, _: &mut S) { - w.extend_from_array(&self.to_le_bytes()); - } - } - - impl DecodeMut<'_, '_, S> for $ty { - fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { - const N: usize = ::std::mem::size_of::<$ty>(); - - let mut bytes = [0; N]; - bytes.copy_from_slice(&r[..N]); - *r = &r[N..]; - - Self::from_le_bytes(bytes) - } - } - }; - (struct $name:ident $(<$($T:ident),+>)? { $($field:ident),* $(,)? }) => { - impl),+)?> Encode for $name $(<$($T),+>)? { - fn encode(self, w: &mut Writer, s: &mut S) { - $(self.$field.encode(w, s);)* - } - } - - impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S> - for $name $(<$($T),+>)? - { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - $name { - $($field: DecodeMut::decode(r, s)),* - } - } - } - }; - (enum $name:ident $(<$($T:ident),+>)? { $($variant:ident $(($field:ident))*),* $(,)? }) => { - impl),+)?> Encode for $name $(<$($T),+>)? { - fn encode(self, w: &mut Writer, s: &mut S) { - // HACK(eddyb): `Tag` enum duplicated between the - // two impls as there's no other place to stash it. - #[allow(non_upper_case_globals)] - mod tag { - #[repr(u8)] enum Tag { $($variant),* } - - $(pub const $variant: u8 = Tag::$variant as u8;)* - } - - match self { - $($name::$variant $(($field))* => { - tag::$variant.encode(w, s); - $($field.encode(w, s);)* - })* - } - } - } - - impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S> - for $name $(<$($T),+>)? - { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - // HACK(eddyb): `Tag` enum duplicated between the - // two impls as there's no other place to stash it. - #[allow(non_upper_case_globals)] - mod tag { - #[repr(u8)] enum Tag { $($variant),* } - - $(pub const $variant: u8 = Tag::$variant as u8;)* - } - - match u8::decode(r, s) { - $(tag::$variant => { - $(let $field = DecodeMut::decode(r, s);)* - $name::$variant $(($field))* - })* - _ => unreachable!(), - } - } - } - } -} - -impl Encode for () { - fn encode(self, _: &mut Writer, _: &mut S) {} -} - -impl DecodeMut<'_, '_, S> for () { - fn decode(_: &mut Reader<'_>, _: &mut S) -> Self {} -} - -impl Encode for u8 { - fn encode(self, w: &mut Writer, _: &mut S) { - w.push(self); - } -} - -impl DecodeMut<'_, '_, S> for u8 { - fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { - let x = r[0]; - *r = &r[1..]; - x - } -} - -rpc_encode_decode!(le u32); -rpc_encode_decode!(le usize); - -impl Encode for bool { - fn encode(self, w: &mut Writer, s: &mut S) { - (self as u8).encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for bool { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - match u8::decode(r, s) { - 0 => false, - 1 => true, - _ => unreachable!(), - } - } -} - -impl Encode for char { - fn encode(self, w: &mut Writer, s: &mut S) { - (self as u32).encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for char { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - char::from_u32(u32::decode(r, s)).unwrap() - } -} - -impl Encode for NonZeroU32 { - fn encode(self, w: &mut Writer, s: &mut S) { - self.get().encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for NonZeroU32 { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - Self::new(u32::decode(r, s)).unwrap() - } -} - -impl, B: Encode> Encode for (A, B) { - fn encode(self, w: &mut Writer, s: &mut S) { - self.0.encode(w, s); - self.1.encode(w, s); - } -} - -impl<'a, S, A: for<'s> DecodeMut<'a, 's, S>, B: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S> - for (A, B) -{ - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - (DecodeMut::decode(r, s), DecodeMut::decode(r, s)) - } -} - -impl Encode for &[u8] { - fn encode(self, w: &mut Writer, s: &mut S) { - self.len().encode(w, s); - w.write_all(self).unwrap(); - } -} - -impl<'a, S> DecodeMut<'a, '_, S> for &'a [u8] { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - let len = usize::decode(r, s); - let xs = &r[..len]; - *r = &r[len..]; - xs - } -} - -impl Encode for &str { - fn encode(self, w: &mut Writer, s: &mut S) { - self.as_bytes().encode(w, s); - } -} - -impl<'a, S> DecodeMut<'a, '_, S> for &'a str { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - str::from_utf8(<&[u8]>::decode(r, s)).unwrap() - } -} - -impl Encode for String { - fn encode(self, w: &mut Writer, s: &mut S) { - self[..].encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for String { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - <&str>::decode(r, s).to_string() - } -} - -impl> Encode for Vec { - fn encode(self, w: &mut Writer, s: &mut S) { - self.len().encode(w, s); - for x in self { - x.encode(w, s); - } - } -} - -impl<'a, S, T: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S> for Vec { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - let len = usize::decode(r, s); - let mut vec = Vec::with_capacity(len); - for _ in 0..len { - vec.push(T::decode(r, s)); - } - vec - } -} - -/// Simplified version of panic payloads, ignoring -/// types other than `&'static str` and `String`. -pub enum PanicMessage { - StaticStr(&'static str), - String(String), - Unknown, -} - -impl From> for PanicMessage { - fn from(payload: Box) -> Self { - if let Some(s) = payload.downcast_ref::<&'static str>() { - return PanicMessage::StaticStr(s); - } - if let Ok(s) = payload.downcast::() { - return PanicMessage::String(*s); - } - PanicMessage::Unknown - } -} - -impl Into> for PanicMessage { - fn into(self) -> Box { - match self { - PanicMessage::StaticStr(s) => Box::new(s), - PanicMessage::String(s) => Box::new(s), - PanicMessage::Unknown => { - struct UnknownPanicMessage; - Box::new(UnknownPanicMessage) - } - } - } -} - -impl PanicMessage { - pub fn as_str(&self) -> Option<&str> { - match self { - PanicMessage::StaticStr(s) => Some(s), - PanicMessage::String(s) => Some(s), - PanicMessage::Unknown => None, - } - } -} - -impl Encode for PanicMessage { - fn encode(self, w: &mut Writer, s: &mut S) { - self.as_str().encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for PanicMessage { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - match Option::::decode(r, s) { - Some(s) => PanicMessage::String(s), - None => PanicMessage::Unknown, - } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/scoped_cell.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/scoped_cell.rs deleted file mode 100644 index 2cde1f65adf9c..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/scoped_cell.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! `Cell` variant for (scoped) existential lifetimes. - -use std::cell::Cell; -use std::mem; -use std::ops::{Deref, DerefMut}; - -/// Type lambda application, with a lifetime. -#[allow(unused_lifetimes)] -pub trait ApplyL<'a> { - type Out; -} - -/// Type lambda taking a lifetime, i.e., `Lifetime -> Type`. -pub trait LambdaL: for<'a> ApplyL<'a> {} - -impl ApplyL<'a>> LambdaL for T {} - -// HACK(eddyb) work around projection limitations with a newtype -// FIXME(#52812) replace with `&'a mut >::Out` -pub struct RefMutL<'a, 'b, T: LambdaL>(&'a mut >::Out); - -impl<'a, 'b, T: LambdaL> Deref for RefMutL<'a, 'b, T> { - type Target = >::Out; - fn deref(&self) -> &Self::Target { - self.0 - } -} - -impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.0 - } -} - -pub struct ScopedCell(Cell<>::Out>); - -impl ScopedCell { - pub const fn new(value: >::Out) -> Self { - ScopedCell(Cell::new(value)) - } - - /// Sets the value in `self` to `replacement` while - /// running `f`, which gets the old value, mutably. - /// The old value will be restored after `f` exits, even - /// by panic, including modifications made to it by `f`. - pub fn replace<'a, R>( - &self, - replacement: >::Out, - f: impl for<'b, 'c> FnOnce(RefMutL<'b, 'c, T>) -> R, - ) -> R { - /// Wrapper that ensures that the cell always gets filled - /// (with the original state, optionally changed by `f`), - /// even if `f` had panicked. - struct PutBackOnDrop<'a, T: LambdaL> { - cell: &'a ScopedCell, - value: Option<>::Out>, - } - - impl<'a, T: LambdaL> Drop for PutBackOnDrop<'a, T> { - fn drop(&mut self) { - self.cell.0.set(self.value.take().unwrap()); - } - } - - let mut put_back_on_drop = PutBackOnDrop { - cell: self, - value: Some(self.0.replace(unsafe { - let erased = mem::transmute_copy(&replacement); - mem::forget(replacement); - erased - })), - }; - - f(RefMutL(put_back_on_drop.value.as_mut().unwrap())) - } - - /// Sets the value in `self` to `value` while running `f`. - pub fn set(&self, value: >::Out, f: impl FnOnce() -> R) -> R { - self.replace(value, |_| f()) - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/selfless_reify.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/selfless_reify.rs deleted file mode 100644 index 907ad256e4b43..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/selfless_reify.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! Abstraction for creating `fn` pointers from any callable that *effectively* -//! has the equivalent of implementing `Default`, even if the compiler neither -//! provides `Default` nor allows reifying closures (i.e. creating `fn` pointers) -//! other than those with absolutely no captures. -//! -//! More specifically, for a closure-like type to be "effectively `Default`": -//! * it must be a ZST (zero-sized type): no information contained within, so -//! that `Default`'s return value (if it were implemented) is unambiguous -//! * it must be `Copy`: no captured "unique ZST tokens" or any other similar -//! types that would make duplicating values at will unsound -//! * combined with the ZST requirement, this confers a kind of "telecopy" -//! ability: similar to `Copy`, but without keeping the value around, and -//! instead "reconstructing" it (a noop given it's a ZST) when needed -//! * it must be *provably* inhabited: no captured uninhabited types or any -//! other types that cannot be constructed by the user of this abstraction -//! * the proof is a value of the closure-like type itself, in a sense the -//! "seed" for the "telecopy" process made possible by ZST + `Copy` -//! * this requirement is the only reason an abstraction limited to a specific -//! usecase is required: ZST + `Copy` can be checked with *at worst* a panic -//! at the "attempted `::default()` call" time, but that doesn't guarantee -//! that the value can be soundly created, and attempting to use the typical -//! "proof ZST token" approach leads yet again to having a ZST + `Copy` type -//! that is not proof of anything without a value (i.e. isomorphic to a -//! newtype of the type it's trying to prove the inhabitation of) -//! -//! A more flexible (and safer) solution to the general problem could exist once -//! `const`-generic parameters can have type parameters in their types: -//! -//! ```rust,ignore (needs future const-generics) -//! extern "C" fn ffi_wrapper< -//! A, R, -//! F: Fn(A) -> R, -//! const f: F, // <-- this `const`-generic is not yet allowed -//! >(arg: A) -> R { -//! f(arg) -//! } -//! ``` - -use std::mem; - -// FIXME(eddyb) this could be `trait` impls except for the `const fn` requirement. -macro_rules! define_reify_functions { - ($( - fn $name:ident $(<$($param:ident),*>)? - for $(extern $abi:tt)? fn($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty; - )+) => { - $(pub const fn $name< - $($($param,)*)? - F: Fn($($arg_ty),*) -> $ret_ty + Copy - >(f: F) -> $(extern $abi)? fn($($arg_ty),*) -> $ret_ty { - // FIXME(eddyb) describe the `F` type (e.g. via `type_name::`) once panic - // formatting becomes possible in `const fn`. - assert!(mem::size_of::() == 0, "selfless_reify: closure must be zero-sized"); - - $(extern $abi)? fn wrapper< - $($($param,)*)? - F: Fn($($arg_ty),*) -> $ret_ty + Copy - >($($arg: $arg_ty),*) -> $ret_ty { - let f = unsafe { - // SAFETY: `F` satisfies all criteria for "out of thin air" - // reconstructability (see module-level doc comment). - mem::MaybeUninit::::uninit().assume_init() - }; - f($($arg),*) - } - let _f_proof = f; - wrapper::< - $($($param,)*)? - F - > - })+ - } -} - -define_reify_functions! { - fn _reify_to_extern_c_fn_unary for extern "C" fn(arg: A) -> R; - - // HACK(eddyb) this abstraction is used with `for<'a> fn(BridgeConfig<'a>) - // -> T` but that doesn't work with just `reify_to_extern_c_fn_unary` - // because of the `fn` pointer type being "higher-ranked" (i.e. the - // `for<'a>` binder). - // FIXME(eddyb) try to remove the lifetime from `BridgeConfig`, that'd help. - fn reify_to_extern_c_fn_hrt_bridge for extern "C" fn(bridge: super::BridgeConfig<'_>) -> R; -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/server.rs deleted file mode 100644 index 6e7a8d8c10df1..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/server.rs +++ /dev/null @@ -1,339 +0,0 @@ -//! Server-side traits. - -use super::*; - -// FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. -use super::client::HandleStore; - -pub trait Types { - type FreeFunctions: 'static; - type TokenStream: 'static + Clone; - type Ident: 'static + Copy + Eq + Hash; - type Literal: 'static + Clone; - type SourceFile: 'static + Clone; - type MultiSpan: 'static; - type Diagnostic: 'static; - type Span: 'static + Copy + Eq + Hash; -} - -/// Declare an associated fn of one of the traits below, adding necessary -/// default bodies. -macro_rules! associated_fn { - (fn drop(&mut self, $arg:ident: $arg_ty:ty)) => - (fn drop(&mut self, $arg: $arg_ty) { mem::drop($arg) }); - - (fn clone(&mut self, $arg:ident: $arg_ty:ty) -> $ret_ty:ty) => - (fn clone(&mut self, $arg: $arg_ty) -> $ret_ty { $arg.clone() }); - - ($($item:tt)*) => ($($item)*;) -} - -macro_rules! declare_server_traits { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - $(pub trait $name: Types { - $(associated_fn!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* - })* - - pub trait Server: Types $(+ $name)* { - fn globals(&mut self) -> ExpnGlobals; - } - } -} -with_api!(Self, self_, declare_server_traits); - -pub(super) struct MarkedTypes(S); - -impl Server for MarkedTypes { - fn globals(&mut self) -> ExpnGlobals { - <_>::mark(Server::globals(&mut self.0)) - } -} - -macro_rules! define_mark_types_impls { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - impl Types for MarkedTypes { - $(type $name = Marked;)* - } - - $(impl $name for MarkedTypes { - $(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)? { - <_>::mark($name::$method(&mut self.0, $($arg.unmark()),*)) - })* - })* - } -} -with_api!(Self, self_, define_mark_types_impls); - -struct Dispatcher { - handle_store: HandleStore, - server: S, -} - -macro_rules! define_dispatcher_impl { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - // FIXME(eddyb) `pub` only for `ExecutionStrategy` below. - pub trait DispatcherTrait { - // HACK(eddyb) these are here to allow `Self::$name` to work below. - $(type $name;)* - fn dispatch(&mut self, buf: Buffer) -> Buffer; - } - - impl DispatcherTrait for Dispatcher> { - $(type $name = as Types>::$name;)* - fn dispatch(&mut self, mut buf: Buffer) -> Buffer { - let Dispatcher { handle_store, server } = self; - - let mut reader = &buf[..]; - match api_tags::Method::decode(&mut reader, &mut ()) { - $(api_tags::Method::$name(m) => match m { - $(api_tags::$name::$method => { - let mut call_method = || { - reverse_decode!(reader, handle_store; $($arg: $arg_ty),*); - $name::$method(server, $($arg),*) - }; - // HACK(eddyb) don't use `panic::catch_unwind` in a panic. - // If client and server happen to use the same `libstd`, - // `catch_unwind` asserts that the panic counter was 0, - // even when the closure passed to it didn't panic. - let r = if thread::panicking() { - Ok(call_method()) - } else { - panic::catch_unwind(panic::AssertUnwindSafe(call_method)) - .map_err(PanicMessage::from) - }; - - buf.clear(); - r.encode(&mut buf, handle_store); - })* - }),* - } - buf - } - } - } -} -with_api!(Self, self_, define_dispatcher_impl); - -pub trait ExecutionStrategy { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer; -} - -pub struct SameThread; - -impl ExecutionStrategy for SameThread { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - let mut dispatch = |buf| dispatcher.dispatch(buf); - - run_client(BridgeConfig { - input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }) - } -} - -// NOTE(eddyb) Two implementations are provided, the second one is a bit -// faster but neither is anywhere near as fast as same-thread execution. - -pub struct CrossThread1; - -impl ExecutionStrategy for CrossThread1 { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - use std::sync::mpsc::channel; - - let (req_tx, req_rx) = channel(); - let (res_tx, res_rx) = channel(); - - let join_handle = thread::spawn(move || { - let mut dispatch = |buf| { - req_tx.send(buf).unwrap(); - res_rx.recv().unwrap() - }; - - run_client(BridgeConfig { - input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }) - }); - - for b in req_rx { - res_tx.send(dispatcher.dispatch(b)).unwrap(); - } - - join_handle.join().unwrap() - } -} - -pub struct CrossThread2; - -impl ExecutionStrategy for CrossThread2 { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - use std::sync::{Arc, Mutex}; - - enum State { - Req(T), - Res(T), - } - - let mut state = Arc::new(Mutex::new(State::Res(Buffer::new()))); - - let server_thread = thread::current(); - let state2 = state.clone(); - let join_handle = thread::spawn(move || { - let mut dispatch = |b| { - *state2.lock().unwrap() = State::Req(b); - server_thread.unpark(); - loop { - thread::park(); - if let State::Res(b) = &mut *state2.lock().unwrap() { - break b.take(); - } - } - }; - - let r = run_client(BridgeConfig { - input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }); - - // Wake up the server so it can exit the dispatch loop. - drop(state2); - server_thread.unpark(); - - r - }); - - // Check whether `state2` was dropped, to know when to stop. - while Arc::get_mut(&mut state).is_none() { - thread::park(); - let mut b = match &mut *state.lock().unwrap() { - State::Req(b) => b.take(), - _ => continue, - }; - b = dispatcher.dispatch(b.take()); - *state.lock().unwrap() = State::Res(b); - join_handle.thread().unpark(); - } - - join_handle.join().unwrap() - } -} - -fn run_server< - S: Server, - I: Encode>>, - O: for<'a, 's> DecodeMut<'a, 's, HandleStore>>, ->( - strategy: &impl ExecutionStrategy, - handle_counters: &'static client::HandleCounters, - server: S, - input: I, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, -) -> Result { - let mut dispatcher = - Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) }; - - let globals = dispatcher.server.globals(); - - let mut buf = Buffer::new(); - (globals, input).encode(&mut buf, &mut dispatcher.handle_store); - - buf = strategy.run_bridge_and_client(&mut dispatcher, buf, run_client, force_show_panics); - - Result::decode(&mut &buf[..], &mut dispatcher.handle_store) -} - -impl client::Client { - pub fn run( - &self, - strategy: &impl ExecutionStrategy, - server: S, - input: S::TokenStream, - force_show_panics: bool, - ) -> Result - where - S: Server, - S::TokenStream: Default, - { - let client::Client { get_handle_counters, run, _marker } = *self; - run_server( - strategy, - get_handle_counters(), - server, - as Types>::TokenStream::mark(input), - run, - force_show_panics, - ) - .map(|s| as Types>::TokenStream>>::unmark(s).unwrap_or_default()) - } -} - -impl - client::Client< - (super::super::TokenStream, super::super::TokenStream), - super::super::TokenStream, - > -{ - pub fn run( - &self, - strategy: &impl ExecutionStrategy, - server: S, - input: S::TokenStream, - input2: S::TokenStream, - force_show_panics: bool, - ) -> Result - where - S: Server, - S::TokenStream: Default, - { - let client::Client { get_handle_counters, run, _marker } = *self; - run_server( - strategy, - get_handle_counters(), - server, - ( - as Types>::TokenStream::mark(input), - as Types>::TokenStream::mark(input2), - ), - run, - force_show_panics, - ) - .map(|s| as Types>::TokenStream>>::unmark(s).unwrap_or_default()) - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/diagnostic.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/diagnostic.rs deleted file mode 100644 index 3fade2dc4f9cc..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/diagnostic.rs +++ /dev/null @@ -1,166 +0,0 @@ -//! lib-proc-macro diagnostic -//! -//! Copy from -//! augmented with removing unstable features - -use super::Span; - -/// An enum representing a diagnostic level. -#[derive(Copy, Clone, Debug)] -#[non_exhaustive] -pub enum Level { - /// An error. - Error, - /// A warning. - Warning, - /// A note. - Note, - /// A help message. - Help, -} - -/// Trait implemented by types that can be converted into a set of `Span`s. -pub trait MultiSpan { - /// Converts `self` into a `Vec`. - fn into_spans(self) -> Vec; -} - -impl MultiSpan for Span { - fn into_spans(self) -> Vec { - vec![self] - } -} - -impl MultiSpan for Vec { - fn into_spans(self) -> Vec { - self - } -} - -impl<'a> MultiSpan for &'a [Span] { - fn into_spans(self) -> Vec { - self.to_vec() - } -} - -/// A structure representing a diagnostic message and associated children -/// messages. -#[derive(Clone, Debug)] -pub struct Diagnostic { - level: Level, - message: String, - spans: Vec, - children: Vec, -} - -macro_rules! diagnostic_child_methods { - ($spanned:ident, $regular:ident, $level:expr) => { - #[doc = concat!("Adds a new child diagnostics message to `self` with the [`", - stringify!($level), "`] level, and the given `spans` and `message`.")] - pub fn $spanned(mut self, spans: S, message: T) -> Diagnostic - where - S: MultiSpan, - T: Into, - { - self.children.push(Diagnostic::spanned(spans, $level, message)); - self - } - - #[doc = concat!("Adds a new child diagnostic message to `self` with the [`", - stringify!($level), "`] level, and the given `message`.")] - pub fn $regular>(mut self, message: T) -> Diagnostic { - self.children.push(Diagnostic::new($level, message)); - self - } - }; -} - -/// Iterator over the children diagnostics of a `Diagnostic`. -#[derive(Debug, Clone)] -pub struct Children<'a>(std::slice::Iter<'a, Diagnostic>); - -impl<'a> Iterator for Children<'a> { - type Item = &'a Diagnostic; - - fn next(&mut self) -> Option { - self.0.next() - } -} - -impl Diagnostic { - /// Creates a new diagnostic with the given `level` and `message`. - pub fn new>(level: Level, message: T) -> Diagnostic { - Diagnostic { level, message: message.into(), spans: vec![], children: vec![] } - } - - /// Creates a new diagnostic with the given `level` and `message` pointing to - /// the given set of `spans`. - pub fn spanned(spans: S, level: Level, message: T) -> Diagnostic - where - S: MultiSpan, - T: Into, - { - Diagnostic { level, message: message.into(), spans: spans.into_spans(), children: vec![] } - } - - diagnostic_child_methods!(span_error, error, Level::Error); - diagnostic_child_methods!(span_warning, warning, Level::Warning); - diagnostic_child_methods!(span_note, note, Level::Note); - diagnostic_child_methods!(span_help, help, Level::Help); - - /// Returns the diagnostic `level` for `self`. - pub fn level(&self) -> Level { - self.level - } - - /// Sets the level in `self` to `level`. - pub fn set_level(&mut self, level: Level) { - self.level = level; - } - - /// Returns the message in `self`. - pub fn message(&self) -> &str { - &self.message - } - - /// Sets the message in `self` to `message`. - pub fn set_message>(&mut self, message: T) { - self.message = message.into(); - } - - /// Returns the `Span`s in `self`. - pub fn spans(&self) -> &[Span] { - &self.spans - } - - /// Sets the `Span`s in `self` to `spans`. - pub fn set_spans(&mut self, spans: S) { - self.spans = spans.into_spans(); - } - - /// Returns an iterator over the children diagnostics of `self`. - pub fn children(&self) -> Children<'_> { - Children(self.children.iter()) - } - - /// Emit the diagnostic. - pub fn emit(self) { - fn to_internal(spans: Vec) -> super::bridge::client::MultiSpan { - let mut multi_span = super::bridge::client::MultiSpan::new(); - for span in spans { - multi_span.push(span.0); - } - multi_span - } - - let mut diag = super::bridge::client::Diagnostic::new( - self.level, - &self.message[..], - to_internal(self.spans), - ); - for c in self.children { - diag.sub(c.level, &c.message[..], to_internal(c.spans)); - } - diag.emit(); - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/mod.rs deleted file mode 100644 index be62c73ef32b9..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/mod.rs +++ /dev/null @@ -1,1125 +0,0 @@ -//! A support library for macro authors when defining new macros. -//! -//! This library, provided by the standard distribution, provides the types -//! consumed in the interfaces of procedurally defined macro definitions such as -//! function-like macros `#[proc_macro]`, macro attributes `#[proc_macro_attribute]` and -//! custom derive attributes`#[proc_macro_derive]`. -//! -//! See [the book] for more. -//! -//! [the book]: ../book/ch19-06-macros.html#procedural-macros-for-generating-code-from-attributes - -#[doc(hidden)] -pub mod bridge; - -mod diagnostic; - -pub use diagnostic::{Diagnostic, Level, MultiSpan}; - -use std::cmp::Ordering; -use std::ops::RangeBounds; -use std::path::PathBuf; -use std::str::FromStr; -use std::{error, fmt, iter, mem}; - -/// Determines whether proc_macro has been made accessible to the currently -/// running program. -/// -/// The proc_macro crate is only intended for use inside the implementation of -/// procedural macros. All the functions in this crate panic if invoked from -/// outside of a procedural macro, such as from a build script or unit test or -/// ordinary Rust binary. -/// -/// With consideration for Rust libraries that are designed to support both -/// macro and non-macro use cases, `proc_macro::is_available()` provides a -/// non-panicking way to detect whether the infrastructure required to use the -/// API of proc_macro is presently available. Returns true if invoked from -/// inside of a procedural macro, false if invoked from any other binary. -pub fn is_available() -> bool { - bridge::client::is_available() -} - -/// The main type provided by this crate, representing an abstract stream of -/// tokens, or, more specifically, a sequence of token trees. -/// The type provide interfaces for iterating over those token trees and, conversely, -/// collecting a number of token trees into one stream. -/// -/// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]` -/// and `#[proc_macro_derive]` definitions. -#[derive(Clone)] -pub struct TokenStream(Option); - -/// Error returned from `TokenStream::from_str`. -#[non_exhaustive] -#[derive(Debug)] -pub struct LexError; - -impl fmt::Display for LexError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("cannot parse string into token stream") - } -} - -impl error::Error for LexError {} - -/// Error returned from `TokenStream::expand_expr`. -#[non_exhaustive] -#[derive(Debug)] -pub struct ExpandError; - -impl fmt::Display for ExpandError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("macro expansion failed") - } -} - -impl error::Error for ExpandError {} - -impl TokenStream { - /// Returns an empty `TokenStream` containing no token trees. - pub fn new() -> TokenStream { - TokenStream(None) - } - - /// Checks if this `TokenStream` is empty. - pub fn is_empty(&self) -> bool { - self.0.as_ref().map(|h| h.is_empty()).unwrap_or(true) - } - - /// Parses this `TokenStream` as an expression and attempts to expand any - /// macros within it. Returns the expanded `TokenStream`. - /// - /// Currently only expressions expanding to literals will succeed, although - /// this may be relaxed in the future. - /// - /// NOTE: In error conditions, `expand_expr` may leave macros unexpanded, - /// report an error, failing compilation, and/or return an `Err(..)`. The - /// specific behavior for any error condition, and what conditions are - /// considered errors, is unspecified and may change in the future. - pub fn expand_expr(&self) -> Result { - let stream = self.0.as_ref().ok_or(ExpandError)?; - match bridge::client::TokenStream::expand_expr(stream) { - Ok(stream) => Ok(TokenStream(Some(stream))), - Err(_) => Err(ExpandError), - } - } -} - -/// Attempts to break the string into tokens and parse those tokens into a token stream. -/// May fail for a number of reasons, for example, if the string contains unbalanced delimiters -/// or characters not existing in the language. -/// All tokens in the parsed stream get `Span::call_site()` spans. -/// -/// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to -/// change these errors into `LexError`s later. -impl FromStr for TokenStream { - type Err = LexError; - - fn from_str(src: &str) -> Result { - Ok(TokenStream(Some(bridge::client::TokenStream::from_str(src)))) - } -} - -/// Prints the token stream as a string that is supposed to be losslessly convertible back -/// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters and negative numeric literals. -impl fmt::Display for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -/// Prints token in a form convenient for debugging. -impl fmt::Debug for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("TokenStream ")?; - f.debug_list().entries(self.clone()).finish() - } -} - -impl Default for TokenStream { - fn default() -> Self { - TokenStream::new() - } -} - -pub use quote::{quote, quote_span}; - -fn tree_to_bridge_tree( - tree: TokenTree, -) -> bridge::TokenTree< - bridge::client::TokenStream, - bridge::client::Span, - bridge::client::Ident, - bridge::client::Literal, -> { - match tree { - TokenTree::Group(tt) => bridge::TokenTree::Group(tt.0), - TokenTree::Punct(tt) => bridge::TokenTree::Punct(tt.0), - TokenTree::Ident(tt) => bridge::TokenTree::Ident(tt.0), - TokenTree::Literal(tt) => bridge::TokenTree::Literal(tt.0), - } -} - -/// Creates a token stream containing a single token tree. -impl From for TokenStream { - fn from(tree: TokenTree) -> TokenStream { - TokenStream(Some(bridge::client::TokenStream::from_token_tree(tree_to_bridge_tree(tree)))) - } -} - -/// Non-generic helper for implementing `FromIterator` and -/// `Extend` with less monomorphization in calling crates. -struct ConcatStreamsHelper { - streams: Vec, -} - -impl ConcatStreamsHelper { - fn new(capacity: usize) -> Self { - ConcatStreamsHelper { streams: Vec::with_capacity(capacity) } - } - - fn push(&mut self, stream: TokenStream) { - if let Some(stream) = stream.0 { - self.streams.push(stream); - } - } - - fn build(mut self) -> TokenStream { - if self.streams.len() <= 1 { - TokenStream(self.streams.pop()) - } else { - TokenStream(Some(bridge::client::TokenStream::concat_streams(None, self.streams))) - } - } - - fn append_to(mut self, stream: &mut TokenStream) { - if self.streams.is_empty() { - return; - } - let base = stream.0.take(); - if base.is_none() && self.streams.len() == 1 { - stream.0 = self.streams.pop(); - } else { - stream.0 = Some(bridge::client::TokenStream::concat_streams(base, self.streams)); - } - } -} - -/// Collects a number of token trees into a single stream. -impl iter::FromIterator for TokenStream { - fn from_iter>(trees: I) -> Self { - trees.into_iter().map(TokenStream::from).collect() - } -} - -/// A "flattening" operation on token streams, collects token trees -/// from multiple token streams into a single stream. -impl iter::FromIterator for TokenStream { - fn from_iter>(streams: I) -> Self { - let iter = streams.into_iter(); - let mut builder = ConcatStreamsHelper::new(iter.size_hint().0); - iter.for_each(|stream| builder.push(stream)); - builder.build() - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, trees: I) { - self.extend(trees.into_iter().map(TokenStream::from)); - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, streams: I) { - // FIXME(eddyb) Use an optimized implementation if/when possible. - *self = iter::once(mem::replace(self, Self::new())).chain(streams).collect(); - } -} - -/// Public implementation details for the `TokenStream` type, such as iterators. -pub mod token_stream { - use super::{bridge, Group, Ident, Literal, Punct, TokenStream, TokenTree}; - - /// An iterator over `TokenStream`'s `TokenTree`s. - /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, - /// and returns whole groups as token trees. - #[derive(Clone)] - pub struct IntoIter( - std::vec::IntoIter< - bridge::TokenTree< - bridge::client::TokenStream, - bridge::client::Span, - bridge::client::Ident, - bridge::client::Literal, - >, - >, - ); - - impl Iterator for IntoIter { - type Item = TokenTree; - - fn next(&mut self) -> Option { - self.0.next().map(|tree| match tree { - bridge::TokenTree::Group(tt) => TokenTree::Group(Group(tt)), - bridge::TokenTree::Punct(tt) => TokenTree::Punct(Punct(tt)), - bridge::TokenTree::Ident(tt) => TokenTree::Ident(Ident(tt)), - bridge::TokenTree::Literal(tt) => TokenTree::Literal(Literal(tt)), - }) - } - } - - impl IntoIterator for TokenStream { - type Item = TokenTree; - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - IntoIter(self.0.map(|v| v.into_trees()).unwrap_or_default().into_iter()) - } - } -} - -#[doc(hidden)] -mod quote; - -/// A region of source code, along with macro expansion information. -#[derive(Copy, Clone)] -pub struct Span(bridge::client::Span); - -macro_rules! diagnostic_method { - ($name:ident, $level:expr) => { - /// Creates a new `Diagnostic` with the given `message` at the span - /// `self`. - pub fn $name>(self, message: T) -> Diagnostic { - Diagnostic::spanned(self, $level, message) - } - }; -} - -impl Span { - /// A span that resolves at the macro definition site. - pub fn def_site() -> Span { - Span(bridge::client::Span::def_site()) - } - - /// The span of the invocation of the current procedural macro. - /// Identifiers created with this span will be resolved as if they were written - /// directly at the macro call location (call-site hygiene) and other code - /// at the macro call site will be able to refer to them as well. - pub fn call_site() -> Span { - Span(bridge::client::Span::call_site()) - } - - /// A span that represents `macro_rules` hygiene, and sometimes resolves at the macro - /// definition site (local variables, labels, `$crate`) and sometimes at the macro - /// call site (everything else). - /// The span location is taken from the call-site. - pub fn mixed_site() -> Span { - Span(bridge::client::Span::mixed_site()) - } - - /// The original source file into which this span points. - pub fn source_file(&self) -> SourceFile { - SourceFile(self.0.source_file()) - } - - /// The `Span` for the tokens in the previous macro expansion from which - /// `self` was generated from, if any. - pub fn parent(&self) -> Option { - self.0.parent().map(Span) - } - - /// The span for the origin source code that `self` was generated from. If - /// this `Span` wasn't generated from other macro expansions then the return - /// value is the same as `*self`. - pub fn source(&self) -> Span { - Span(self.0.source()) - } - - /// Gets the starting line/column in the source file for this span. - pub fn start(&self) -> LineColumn { - self.0.start().add_1_to_column() - } - - /// Gets the ending line/column in the source file for this span. - pub fn end(&self) -> LineColumn { - self.0.end().add_1_to_column() - } - - /// Creates an empty span pointing to directly before this span. - pub fn before(&self) -> Span { - Span(self.0.before()) - } - - /// Creates an empty span pointing to directly after this span. - pub fn after(&self) -> Span { - Span(self.0.after()) - } - - /// Creates a new span encompassing `self` and `other`. - /// - /// Returns `None` if `self` and `other` are from different files. - pub fn join(&self, other: Span) -> Option { - self.0.join(other.0).map(Span) - } - - /// Creates a new span with the same line/column information as `self` but - /// that resolves symbols as though it were at `other`. - pub fn resolved_at(&self, other: Span) -> Span { - Span(self.0.resolved_at(other.0)) - } - - /// Creates a new span with the same name resolution behavior as `self` but - /// with the line/column information of `other`. - pub fn located_at(&self, other: Span) -> Span { - other.resolved_at(*self) - } - - /// Compares to spans to see if they're equal. - pub fn eq(&self, other: &Span) -> bool { - self.0 == other.0 - } - - /// Returns the source text behind a span. This preserves the original source - /// code, including spaces and comments. It only returns a result if the span - /// corresponds to real source code. - /// - /// Note: The observable result of a macro should only rely on the tokens and - /// not on this source text. The result of this function is a best effort to - /// be used for diagnostics only. - pub fn source_text(&self) -> Option { - self.0.source_text() - } - - // Used by the implementation of `Span::quote` - #[doc(hidden)] - pub fn save_span(&self) -> usize { - self.0.save_span() - } - - // Used by the implementation of `Span::quote` - #[doc(hidden)] - pub fn recover_proc_macro_span(id: usize) -> Span { - Span(bridge::client::Span::recover_proc_macro_span(id)) - } - - diagnostic_method!(error, Level::Error); - diagnostic_method!(warning, Level::Warning); - diagnostic_method!(note, Level::Note); - diagnostic_method!(help, Level::Help); -} - -/// Prints a span in a form convenient for debugging. -impl fmt::Debug for Span { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// A line-column pair representing the start or end of a `Span`. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct LineColumn { - /// The 1-indexed line in the source file on which the span starts or ends (inclusive). - pub line: usize, - /// The 1-indexed column (number of bytes in UTF-8 encoding) in the source - /// file on which the span starts or ends (inclusive). - pub column: usize, -} - -impl LineColumn { - fn add_1_to_column(self) -> Self { - LineColumn { line: self.line, column: self.column + 1 } - } -} - -impl Ord for LineColumn { - fn cmp(&self, other: &Self) -> Ordering { - self.line.cmp(&other.line).then(self.column.cmp(&other.column)) - } -} - -impl PartialOrd for LineColumn { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -/// The source file of a given `Span`. -#[derive(Clone)] -pub struct SourceFile(bridge::client::SourceFile); - -impl SourceFile { - /// Gets the path to this source file. - /// - /// ### Note - /// If the code span associated with this `SourceFile` was generated by an external macro, this - /// macro, this might not be an actual path on the filesystem. Use [`is_real`] to check. - /// - /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on - /// the command line, the path as given might not actually be valid. - /// - /// [`is_real`]: Self::is_real - pub fn path(&self) -> PathBuf { - PathBuf::from(self.0.path()) - } - - /// Returns `true` if this source file is a real source file, and not generated by an external - /// macro's expansion. - pub fn is_real(&self) -> bool { - // This is a hack until intercrate spans are implemented and we can have real source files - // for spans generated in external macros. - // https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368 - self.0.is_real() - } -} - -impl fmt::Debug for SourceFile { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SourceFile") - .field("path", &self.path()) - .field("is_real", &self.is_real()) - .finish() - } -} - -impl PartialEq for SourceFile { - fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) - } -} - -impl Eq for SourceFile {} - -/// A single token or a delimited sequence of token trees (e.g., `[1, (), ..]`). -#[derive(Clone)] -pub enum TokenTree { - /// A token stream surrounded by bracket delimiters. - Group(Group), - /// An identifier. - Ident(Ident), - /// A single punctuation character (`+`, `,`, `$`, etc.). - Punct(Punct), - /// A literal character (`'a'`), string (`"hello"`), number (`2.3`), etc. - Literal(Literal), -} - -impl TokenTree { - /// Returns the span of this tree, delegating to the `span` method of - /// the contained token or a delimited stream. - pub fn span(&self) -> Span { - match *self { - TokenTree::Group(ref t) => t.span(), - TokenTree::Ident(ref t) => t.span(), - TokenTree::Punct(ref t) => t.span(), - TokenTree::Literal(ref t) => t.span(), - } - } - - /// Configures the span for *only this token*. - /// - /// Note that if this token is a `Group` then this method will not configure - /// the span of each of the internal tokens, this will simply delegate to - /// the `set_span` method of each variant. - pub fn set_span(&mut self, span: Span) { - match *self { - TokenTree::Group(ref mut t) => t.set_span(span), - TokenTree::Ident(ref mut t) => t.set_span(span), - TokenTree::Punct(ref mut t) => t.set_span(span), - TokenTree::Literal(ref mut t) => t.set_span(span), - } - } -} - -/// Prints token tree in a form convenient for debugging. -impl fmt::Debug for TokenTree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Each of these has the name in the struct type in the derived debug, - // so don't bother with an extra layer of indirection - match *self { - TokenTree::Group(ref tt) => tt.fmt(f), - TokenTree::Ident(ref tt) => tt.fmt(f), - TokenTree::Punct(ref tt) => tt.fmt(f), - TokenTree::Literal(ref tt) => tt.fmt(f), - } - } -} - -impl From for TokenTree { - fn from(g: Group) -> TokenTree { - TokenTree::Group(g) - } -} - -impl From for TokenTree { - fn from(g: Ident) -> TokenTree { - TokenTree::Ident(g) - } -} - -impl From for TokenTree { - fn from(g: Punct) -> TokenTree { - TokenTree::Punct(g) - } -} - -impl From for TokenTree { - fn from(g: Literal) -> TokenTree { - TokenTree::Literal(g) - } -} - -/// Prints the token tree as a string that is supposed to be losslessly convertible back -/// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters and negative numeric literals. -impl fmt::Display for TokenTree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -/// A delimited token stream. -/// -/// A `Group` internally contains a `TokenStream` which is surrounded by `Delimiter`s. -#[derive(Clone)] -pub struct Group(bridge::Group); - -/// Describes how a sequence of token trees is delimited. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Delimiter { - /// `( ... )` - Parenthesis, - /// `{ ... }` - Brace, - /// `[ ... ]` - Bracket, - /// `Ø ... Ø` - /// An invisible delimiter, that may, for example, appear around tokens coming from a - /// "macro variable" `$var`. It is important to preserve operator priorities in cases like - /// `$var * 3` where `$var` is `1 + 2`. - /// Invisible delimiters might not survive roundtrip of a token stream through a string. - None, -} - -impl Group { - /// Creates a new `Group` with the given delimiter and token stream. - /// - /// This constructor will set the span for this group to - /// `Span::call_site()`. To change the span you can use the `set_span` - /// method below. - pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { - Group(bridge::Group { - delimiter, - stream: stream.0, - span: bridge::DelimSpan::from_single(Span::call_site().0), - }) - } - - /// Returns the delimiter of this `Group` - pub fn delimiter(&self) -> Delimiter { - self.0.delimiter - } - - /// Returns the `TokenStream` of tokens that are delimited in this `Group`. - /// - /// Note that the returned token stream does not include the delimiter - /// returned above. - pub fn stream(&self) -> TokenStream { - TokenStream(self.0.stream.clone()) - } - - /// Returns the span for the delimiters of this token stream, spanning the - /// entire `Group`. - /// - /// ```text - /// pub fn span(&self) -> Span { - /// ^^^^^^^ - /// ``` - pub fn span(&self) -> Span { - Span(self.0.span.entire) - } - - /// Returns the span pointing to the opening delimiter of this group. - /// - /// ```text - /// pub fn span_open(&self) -> Span { - /// ^ - /// ``` - pub fn span_open(&self) -> Span { - Span(self.0.span.open) - } - - /// Returns the span pointing to the closing delimiter of this group. - /// - /// ```text - /// pub fn span_close(&self) -> Span { - /// ^ - /// ``` - pub fn span_close(&self) -> Span { - Span(self.0.span.close) - } - - /// Configures the span for this `Group`'s delimiters, but not its internal - /// tokens. - /// - /// This method will **not** set the span of all the internal tokens spanned - /// by this group, but rather it will only set the span of the delimiter - /// tokens at the level of the `Group`. - pub fn set_span(&mut self, span: Span) { - self.0.span = bridge::DelimSpan::from_single(span.0); - } -} - -/// Prints the group as a string that should be losslessly convertible back -/// into the same group (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters. -impl fmt::Display for Group { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Group { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Group") - .field("delimiter", &self.delimiter()) - .field("stream", &self.stream()) - .field("span", &self.span()) - .finish() - } -} - -/// A `Punct` is a single punctuation character such as `+`, `-` or `#`. -/// -/// Multi-character operators like `+=` are represented as two instances of `Punct` with different -/// forms of `Spacing` returned. -#[derive(Clone)] -pub struct Punct(bridge::Punct); - -/// Describes whether a `Punct` is followed immediately by another `Punct` ([`Spacing::Joint`]) or -/// by a different token or whitespace ([`Spacing::Alone`]). -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Spacing { - /// A `Punct` is not immediately followed by another `Punct`. - /// E.g. `+` is `Alone` in `+ =`, `+ident` and `+()`. - Alone, - /// A `Punct` is immediately followed by another `Punct`. - /// E.g. `+` is `Joint` in `+=` and `++`. - /// - /// Additionally, single quote `'` can join with identifiers to form lifetimes: `'ident`. - Joint, -} - -impl Punct { - /// Creates a new `Punct` from the given character and spacing. - /// The `ch` argument must be a valid punctuation character permitted by the language, - /// otherwise the function will panic. - /// - /// The returned `Punct` will have the default span of `Span::call_site()` - /// which can be further configured with the `set_span` method below. - pub fn new(ch: char, spacing: Spacing) -> Punct { - const LEGAL_CHARS: &[char] = &[ - '=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^', '&', '|', '@', '.', ',', ';', - ':', '#', '$', '?', '\'', - ]; - if !LEGAL_CHARS.contains(&ch) { - panic!("unsupported character `{:?}`", ch); - } - Punct(bridge::Punct { - ch: ch as u8, - joint: spacing == Spacing::Joint, - span: Span::call_site().0, - }) - } - - /// Returns the value of this punctuation character as `char`. - pub fn as_char(&self) -> char { - self.0.ch as char - } - - /// Returns the spacing of this punctuation character, indicating whether it's immediately - /// followed by another `Punct` in the token stream, so they can potentially be combined into - /// a multi-character operator (`Joint`), or it's followed by some other token or whitespace - /// (`Alone`) so the operator has certainly ended. - pub fn spacing(&self) -> Spacing { - if self.0.joint { - Spacing::Joint - } else { - Spacing::Alone - } - } - - /// Returns the span for this punctuation character. - pub fn span(&self) -> Span { - Span(self.0.span) - } - - /// Configure the span for this punctuation character. - pub fn set_span(&mut self, span: Span) { - self.0.span = span.0; - } -} - -/// Prints the punctuation character as a string that should be losslessly convertible -/// back into the same character. -impl fmt::Display for Punct { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Punct { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Punct") - .field("ch", &self.as_char()) - .field("spacing", &self.spacing()) - .field("span", &self.span()) - .finish() - } -} - -impl PartialEq for Punct { - fn eq(&self, rhs: &char) -> bool { - self.as_char() == *rhs - } -} - -impl PartialEq for char { - fn eq(&self, rhs: &Punct) -> bool { - *self == rhs.as_char() - } -} - -/// An identifier (`ident`). -#[derive(Clone)] -pub struct Ident(bridge::client::Ident); - -impl Ident { - /// Creates a new `Ident` with the given `string` as well as the specified - /// `span`. - /// The `string` argument must be a valid identifier permitted by the - /// language (including keywords, e.g. `self` or `fn`). Otherwise, the function will panic. - /// - /// Note that `span`, currently in rustc, configures the hygiene information - /// for this identifier. - /// - /// As of this time `Span::call_site()` explicitly opts-in to "call-site" hygiene - /// meaning that identifiers created with this span will be resolved as if they were written - /// directly at the location of the macro call, and other code at the macro call site will be - /// able to refer to them as well. - /// - /// Later spans like `Span::def_site()` will allow to opt-in to "definition-site" hygiene - /// meaning that identifiers created with this span will be resolved at the location of the - /// macro definition and other code at the macro call site will not be able to refer to them. - /// - /// Due to the current importance of hygiene this constructor, unlike other - /// tokens, requires a `Span` to be specified at construction. - pub fn new(string: &str, span: Span) -> Ident { - Ident(bridge::client::Ident::new(string, span.0, false)) - } - - /// Same as `Ident::new`, but creates a raw identifier (`r#ident`). - /// The `string` argument be a valid identifier permitted by the language - /// (including keywords, e.g. `fn`). Keywords which are usable in path segments - /// (e.g. `self`, `super`) are not supported, and will cause a panic. - pub fn new_raw(string: &str, span: Span) -> Ident { - Ident(bridge::client::Ident::new(string, span.0, true)) - } - - /// Returns the span of this `Ident`, encompassing the entire string returned - /// by [`to_string`](Self::to_string). - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Configures the span of this `Ident`, possibly changing its hygiene context. - pub fn set_span(&mut self, span: Span) { - self.0 = self.0.with_span(span.0); - } -} - -/// Prints the identifier as a string that should be losslessly convertible -/// back into the same identifier. -impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Ident { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Ident") - .field("ident", &self.to_string()) - .field("span", &self.span()) - .finish() - } -} - -/// A literal string (`"hello"`), byte string (`b"hello"`), -/// character (`'a'`), byte character (`b'a'`), an integer or floating point number -/// with or without a suffix (`1`, `1u8`, `2.3`, `2.3f32`). -/// Boolean literals like `true` and `false` do not belong here, they are `Ident`s. -#[derive(Clone)] -pub struct Literal(bridge::client::Literal); - -macro_rules! suffixed_int_literals { - ($($name:ident => $kind:ident,)*) => ($( - /// Creates a new suffixed integer literal with the specified value. - /// - /// This function will create an integer like `1u32` where the integer - /// value specified is the first part of the token and the integral is - /// also suffixed at the end. - /// Literals created from negative numbers might not survive round-trips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// Literals created through this method have the `Span::call_site()` - /// span by default, which can be configured with the `set_span` method - /// below. - pub fn $name(n: $kind) -> Literal { - Literal(bridge::client::Literal::typed_integer(&n.to_string(), stringify!($kind))) - } - )*) -} - -macro_rules! unsuffixed_int_literals { - ($($name:ident => $kind:ident,)*) => ($( - /// Creates a new unsuffixed integer literal with the specified value. - /// - /// This function will create an integer like `1` where the integer - /// value specified is the first part of the token. No suffix is - /// specified on this token, meaning that invocations like - /// `Literal::i8_unsuffixed(1)` are equivalent to - /// `Literal::u32_unsuffixed(1)`. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// Literals created through this method have the `Span::call_site()` - /// span by default, which can be configured with the `set_span` method - /// below. - pub fn $name(n: $kind) -> Literal { - Literal(bridge::client::Literal::integer(&n.to_string())) - } - )*) -} - -impl Literal { - suffixed_int_literals! { - u8_suffixed => u8, - u16_suffixed => u16, - u32_suffixed => u32, - u64_suffixed => u64, - u128_suffixed => u128, - usize_suffixed => usize, - i8_suffixed => i8, - i16_suffixed => i16, - i32_suffixed => i32, - i64_suffixed => i64, - i128_suffixed => i128, - isize_suffixed => isize, - } - - unsuffixed_int_literals! { - u8_unsuffixed => u8, - u16_unsuffixed => u16, - u32_unsuffixed => u32, - u64_unsuffixed => u64, - u128_unsuffixed => u128, - usize_unsuffixed => usize, - i8_unsuffixed => i8, - i16_unsuffixed => i16, - i32_unsuffixed => i32, - i64_unsuffixed => i64, - i128_unsuffixed => i128, - isize_unsuffixed => isize, - } - - /// Creates a new unsuffixed floating-point literal. - /// - /// This constructor is similar to those like `Literal::i8_unsuffixed` where - /// the float's value is emitted directly into the token but no suffix is - /// used, so it may be inferred to be a `f64` later in the compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f32_unsuffixed(n: f32) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - let mut repr = n.to_string(); - if !repr.contains('.') { - repr.push_str(".0"); - } - Literal(bridge::client::Literal::float(&repr)) - } - - /// Creates a new suffixed floating-point literal. - /// - /// This constructor will create a literal like `1.0f32` where the value - /// specified is the preceding part of the token and `f32` is the suffix of - /// the token. This token will always be inferred to be an `f32` in the - /// compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f32_suffixed(n: f32) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - Literal(bridge::client::Literal::f32(&n.to_string())) - } - - /// Creates a new unsuffixed floating-point literal. - /// - /// This constructor is similar to those like `Literal::i8_unsuffixed` where - /// the float's value is emitted directly into the token but no suffix is - /// used, so it may be inferred to be a `f64` later in the compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f64_unsuffixed(n: f64) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - let mut repr = n.to_string(); - if !repr.contains('.') { - repr.push_str(".0"); - } - Literal(bridge::client::Literal::float(&repr)) - } - - /// Creates a new suffixed floating-point literal. - /// - /// This constructor will create a literal like `1.0f64` where the value - /// specified is the preceding part of the token and `f64` is the suffix of - /// the token. This token will always be inferred to be an `f64` in the - /// compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f64_suffixed(n: f64) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - Literal(bridge::client::Literal::f64(&n.to_string())) - } - - /// String literal. - pub fn string(string: &str) -> Literal { - Literal(bridge::client::Literal::string(string)) - } - - /// Character literal. - pub fn character(ch: char) -> Literal { - Literal(bridge::client::Literal::character(ch)) - } - - /// Byte string literal. - pub fn byte_string(bytes: &[u8]) -> Literal { - Literal(bridge::client::Literal::byte_string(bytes)) - } - - /// Returns the span encompassing this literal. - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Configures the span associated for this literal. - pub fn set_span(&mut self, span: Span) { - self.0.set_span(span.0); - } - - /// Returns a `Span` that is a subset of `self.span()` containing only the - /// source bytes in range `range`. Returns `None` if the would-be trimmed - /// span is outside the bounds of `self`. - // FIXME(SergioBenitez): check that the byte range starts and ends at a - // UTF-8 boundary of the source. otherwise, it's likely that a panic will - // occur elsewhere when the source text is printed. - // FIXME(SergioBenitez): there is no way for the user to know what - // `self.span()` actually maps to, so this method can currently only be - // called blindly. For example, `to_string()` for the character 'c' returns - // "'\u{63}'"; there is no way for the user to know whether the source text - // was 'c' or whether it was '\u{63}'. - pub fn subspan>(&self, range: R) -> Option { - self.0.subspan(range.start_bound().cloned(), range.end_bound().cloned()).map(Span) - } -} - -/// Parse a single literal from its stringified representation. -/// -/// In order to parse successfully, the input string must not contain anything -/// but the literal token. Specifically, it must not contain whitespace or -/// comments in addition to the literal. -/// -/// The resulting literal token will have a `Span::call_site()` span. -/// -/// NOTE: some errors may cause panics instead of returning `LexError`. We -/// reserve the right to change these errors into `LexError`s later. -impl FromStr for Literal { - type Err = LexError; - - fn from_str(src: &str) -> Result { - match bridge::client::Literal::from_str(src) { - Ok(literal) => Ok(Literal(literal)), - Err(()) => Err(LexError), - } - } -} - -/// Prints the literal as a string that should be losslessly convertible -/// back into the same literal (except for possible rounding for floating point literals). -impl fmt::Display for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// Tracked access to environment variables. -pub mod tracked_env { - use std::env::{self, VarError}; - use std::ffi::OsStr; - - /// Retrieve an environment variable and add it to build dependency info. - /// Build system executing the compiler will know that the variable was accessed during - /// compilation, and will be able to rerun the build when the value of that variable changes. - /// Besides the dependency tracking this function should be equivalent to `env::var` from the - /// standard library, except that the argument must be UTF-8. - pub fn var + AsRef>(key: K) -> Result { - let key: &str = key.as_ref(); - let value = env::var(key); - super::bridge::client::FreeFunctions::track_env_var(key, value.as_deref().ok()); - value - } -} - -/// Tracked access to additional files. -pub mod tracked_path { - - /// Track a file explicitly. - /// - /// Commonly used for tracking asset preprocessing. - pub fn path>(path: P) { - let path: &str = path.as_ref(); - super::bridge::client::FreeFunctions::track_path(path); - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/quote.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/quote.rs deleted file mode 100644 index 39309faa41213..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/quote.rs +++ /dev/null @@ -1,139 +0,0 @@ -//! # Quasiquoter -//! This file contains the implementation internals of the quasiquoter provided by `quote!`. - -//! This quasiquoter uses macros 2.0 hygiene to reliably access -//! items from `proc_macro`, to build a `proc_macro::TokenStream`. - -use super::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; - -macro_rules! quote_tt { - (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, quote!($($t)*)) }; - ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, quote!($($t)*)) }; - ({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) }; - (,) => { Punct::new(',', Spacing::Alone) }; - (.) => { Punct::new('.', Spacing::Alone) }; - (;) => { Punct::new(';', Spacing::Alone) }; - (!) => { Punct::new('!', Spacing::Alone) }; - (<) => { Punct::new('<', Spacing::Alone) }; - (>) => { Punct::new('>', Spacing::Alone) }; - (&) => { Punct::new('&', Spacing::Alone) }; - (=) => { Punct::new('=', Spacing::Alone) }; - ($i:ident) => { Ident::new(stringify!($i), Span::def_site()) }; -} - -macro_rules! quote_ts { - ((@ $($t:tt)*)) => { $($t)* }; - (::) => { - [ - TokenTree::from(Punct::new(':', Spacing::Joint)), - TokenTree::from(Punct::new(':', Spacing::Alone)), - ].iter() - .cloned() - .map(|mut x| { - x.set_span(Span::def_site()); - x - }) - .collect::() - }; - ($t:tt) => { TokenTree::from(quote_tt!($t)) }; -} - -/// Simpler version of the real `quote!` macro, implemented solely -/// through `macro_rules`, for bootstrapping the real implementation -/// (see the `quote` function), which does not have access to the -/// real `quote!` macro due to the `proc_macro` crate not being -/// able to depend on itself. -/// -/// Note: supported tokens are a subset of the real `quote!`, but -/// unquoting is different: instead of `$x`, this uses `(@ expr)`. -macro_rules! quote { - () => { TokenStream::new() }; - ($($t:tt)*) => { - [ - $(TokenStream::from(quote_ts!($t)),)* - ].iter().cloned().collect::() - }; -} - -/// Quote a `TokenStream` into a `TokenStream`. -/// This is the actual implementation of the `quote!()` proc macro. -/// -/// It is loaded by the compiler in `register_builtin_macros`. -pub fn quote(stream: TokenStream) -> TokenStream { - if stream.is_empty() { - return quote!(super::TokenStream::new()); - } - let proc_macro_crate = quote!(crate); - let mut after_dollar = false; - let tokens = stream - .into_iter() - .filter_map(|tree| { - if after_dollar { - after_dollar = false; - match tree { - TokenTree::Ident(_) => { - return Some(quote!(Into::::into( - Clone::clone(&(@ tree))),)); - } - TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} - _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), - } - } else if let TokenTree::Punct(ref tt) = tree { - if tt.as_char() == '$' { - after_dollar = true; - return None; - } - } - - Some(quote!(super::TokenStream::from((@ match tree { - TokenTree::Punct(tt) => quote!(super::TokenTree::Punct(super::Punct::new( - (@ TokenTree::from(Literal::character(tt.as_char()))), - (@ match tt.spacing() { - Spacing::Alone => quote!(super::Spacing::Alone), - Spacing::Joint => quote!(super::Spacing::Joint), - }), - ))), - TokenTree::Group(tt) => quote!(super::TokenTree::Group(super::Group::new( - (@ match tt.delimiter() { - Delimiter::Parenthesis => quote!(super::Delimiter::Parenthesis), - Delimiter::Brace => quote!(super::Delimiter::Brace), - Delimiter::Bracket => quote!(super::Delimiter::Bracket), - Delimiter::None => quote!(super::Delimiter::None), - }), - (@ quote(tt.stream())), - ))), - TokenTree::Ident(tt) => quote!(super::TokenTree::Ident(super::Ident::new( - (@ TokenTree::from(Literal::string(&tt.to_string()))), - (@ quote_span(proc_macro_crate.clone(), tt.span())), - ))), - TokenTree::Literal(tt) => quote!(super::TokenTree::Literal({ - let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string()))) - .parse::() - .unwrap() - .into_iter(); - if let (Some(super::TokenTree::Literal(mut lit)), None) = - (iter.next(), iter.next()) - { - lit.set_span((@ quote_span(proc_macro_crate.clone(), tt.span()))); - lit - } else { - unreachable!() - } - })) - })),)) - }) - .collect::(); - - if after_dollar { - panic!("unexpected trailing `$` in `quote!`"); - } - - quote!([(@ tokens)].iter().cloned().collect::()) -} - -/// Quote a `Span` into a `TokenStream`. -/// This is needed to implement a custom quoter. -pub fn quote_span(proc_macro_crate: TokenStream, span: Span) -> TokenStream { - let id = span.save_span(); - quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id))))) -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/ra_server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/ra_server.rs deleted file mode 100644 index 7e8e67856e9fd..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/ra_server.rs +++ /dev/null @@ -1,792 +0,0 @@ -//! Rustc proc-macro server implementation with tt -//! -//! Based on idea from -//! The lib-proc-macro server backend is `TokenStream`-agnostic, such that -//! we could provide any TokenStream implementation. -//! The original idea from fedochet is using proc-macro2 as backend, -//! we use tt instead for better integration with RA. -//! -//! FIXME: No span and source file information is implemented yet - -use super::proc_macro::bridge::{self, server}; - -use std::collections::HashMap; -use std::hash::Hash; -use std::iter::FromIterator; -use std::ops::Bound; -use std::{ascii, vec::IntoIter}; - -type Group = tt::Subtree; -type TokenTree = tt::TokenTree; -type Punct = tt::Punct; -type Spacing = tt::Spacing; -type Literal = tt::Literal; -type Span = tt::TokenId; - -#[derive(Debug, Default, Clone)] -pub struct TokenStream { - pub token_trees: Vec, -} - -impl TokenStream { - pub fn new() -> Self { - TokenStream::default() - } - - pub fn with_subtree(subtree: tt::Subtree) -> Self { - if subtree.delimiter.is_some() { - TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] } - } else { - TokenStream { token_trees: subtree.token_trees } - } - } - - pub fn into_subtree(self) -> tt::Subtree { - tt::Subtree { delimiter: None, token_trees: self.token_trees } - } - - pub fn is_empty(&self) -> bool { - self.token_trees.is_empty() - } -} - -/// Creates a token stream containing a single token tree. -impl From for TokenStream { - fn from(tree: TokenTree) -> TokenStream { - TokenStream { token_trees: vec![tree] } - } -} - -/// Collects a number of token trees into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(trees: I) -> Self { - trees.into_iter().map(TokenStream::from).collect() - } -} - -/// A "flattening" operation on token streams, collects token trees -/// from multiple token streams into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(streams: I) -> Self { - let mut builder = TokenStreamBuilder::new(); - streams.into_iter().for_each(|stream| builder.push(stream)); - builder.build() - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, trees: I) { - self.extend(trees.into_iter().map(TokenStream::from)); - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, streams: I) { - for item in streams { - for tkn in item { - match tkn { - tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => { - self.token_trees.extend(subtree.token_trees); - } - _ => { - self.token_trees.push(tkn); - } - } - } - } - } -} - -#[derive(Clone)] -pub struct SourceFile { - // FIXME stub -} - -type Level = super::proc_macro::Level; -type LineColumn = super::proc_macro::LineColumn; - -/// A structure representing a diagnostic message and associated children -/// messages. -#[derive(Clone, Debug)] -pub struct Diagnostic { - level: Level, - message: String, - spans: Vec, - children: Vec, -} - -impl Diagnostic { - /// Creates a new diagnostic with the given `level` and `message`. - pub fn new>(level: Level, message: T) -> Diagnostic { - Diagnostic { level, message: message.into(), spans: vec![], children: vec![] } - } -} - -// Rustc Server Ident has to be `Copyable` -// We use a stub here for bypassing -#[derive(Hash, Eq, PartialEq, Copy, Clone)] -pub struct IdentId(u32); - -#[derive(Clone, Hash, Eq, PartialEq)] -struct IdentData(tt::Ident); - -#[derive(Default)] -struct IdentInterner { - idents: HashMap, - ident_data: Vec, -} - -impl IdentInterner { - fn intern(&mut self, data: &IdentData) -> u32 { - if let Some(index) = self.idents.get(data) { - return *index; - } - - let index = self.idents.len() as u32; - self.ident_data.push(data.clone()); - self.idents.insert(data.clone(), index); - index - } - - fn get(&self, index: u32) -> &IdentData { - &self.ident_data[index as usize] - } - - #[allow(unused)] - fn get_mut(&mut self, index: u32) -> &mut IdentData { - self.ident_data.get_mut(index as usize).expect("Should be consistent") - } -} - -pub struct TokenStreamBuilder { - acc: TokenStream, -} - -/// Public implementation details for the `TokenStream` type, such as iterators. -pub mod token_stream { - use std::str::FromStr; - - use super::{TokenStream, TokenTree}; - - /// An iterator over `TokenStream`'s `TokenTree`s. - /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, - /// and returns whole groups as token trees. - impl IntoIterator for TokenStream { - type Item = TokenTree; - type IntoIter = super::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.token_trees.into_iter() - } - } - - type LexError = String; - - /// Attempts to break the string into tokens and parse those tokens into a token stream. - /// May fail for a number of reasons, for example, if the string contains unbalanced delimiters - /// or characters not existing in the language. - /// All tokens in the parsed stream get `Span::call_site()` spans. - /// - /// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to - /// change these errors into `LexError`s later. - impl FromStr for TokenStream { - type Err = LexError; - - fn from_str(src: &str) -> Result { - let (subtree, _token_map) = - mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?; - - let subtree = subtree_replace_token_ids_with_unspecified(subtree); - Ok(TokenStream::with_subtree(subtree)) - } - } - - impl ToString for TokenStream { - fn to_string(&self) -> String { - tt::pretty(&self.token_trees) - } - } - - fn subtree_replace_token_ids_with_unspecified(subtree: tt::Subtree) -> tt::Subtree { - tt::Subtree { - delimiter: subtree - .delimiter - .map(|d| tt::Delimiter { id: tt::TokenId::unspecified(), ..d }), - token_trees: subtree - .token_trees - .into_iter() - .map(token_tree_replace_token_ids_with_unspecified) - .collect(), - } - } - - fn token_tree_replace_token_ids_with_unspecified(tt: tt::TokenTree) -> tt::TokenTree { - match tt { - tt::TokenTree::Leaf(leaf) => { - tt::TokenTree::Leaf(leaf_replace_token_ids_with_unspecified(leaf)) - } - tt::TokenTree::Subtree(subtree) => { - tt::TokenTree::Subtree(subtree_replace_token_ids_with_unspecified(subtree)) - } - } - } - - fn leaf_replace_token_ids_with_unspecified(leaf: tt::Leaf) -> tt::Leaf { - match leaf { - tt::Leaf::Literal(lit) => { - tt::Leaf::Literal(tt::Literal { id: tt::TokenId::unspecified(), ..lit }) - } - tt::Leaf::Punct(punct) => { - tt::Leaf::Punct(tt::Punct { id: tt::TokenId::unspecified(), ..punct }) - } - tt::Leaf::Ident(ident) => { - tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), ..ident }) - } - } - } -} - -impl TokenStreamBuilder { - fn new() -> TokenStreamBuilder { - TokenStreamBuilder { acc: TokenStream::new() } - } - - fn push(&mut self, stream: TokenStream) { - self.acc.extend(stream.into_iter()) - } - - fn build(self) -> TokenStream { - self.acc - } -} - -pub struct FreeFunctions; - -#[derive(Clone)] -pub struct TokenStreamIter { - trees: IntoIter, -} - -#[derive(Default)] -pub struct RustAnalyzer { - ident_interner: IdentInterner, - // FIXME: store span information here. -} - -impl server::Types for RustAnalyzer { - type FreeFunctions = FreeFunctions; - type TokenStream = TokenStream; - type Ident = IdentId; - type Literal = Literal; - type SourceFile = SourceFile; - type Diagnostic = Diagnostic; - type Span = Span; - type MultiSpan = Vec; -} - -impl server::FreeFunctions for RustAnalyzer { - fn track_env_var(&mut self, _var: &str, _value: Option<&str>) { - // FIXME: track env var accesses - // https://github.com/rust-lang/rust/pull/71858 - } - fn track_path(&mut self, _path: &str) {} -} - -impl server::TokenStream for RustAnalyzer { - fn is_empty(&mut self, stream: &Self::TokenStream) -> bool { - stream.is_empty() - } - fn from_str(&mut self, src: &str) -> Self::TokenStream { - use std::str::FromStr; - - Self::TokenStream::from_str(src).expect("cannot parse string") - } - fn to_string(&mut self, stream: &Self::TokenStream) -> String { - stream.to_string() - } - fn from_token_tree( - &mut self, - tree: bridge::TokenTree, - ) -> Self::TokenStream { - match tree { - bridge::TokenTree::Group(group) => { - let group = Group { - delimiter: delim_to_internal(group.delimiter), - token_trees: match group.stream { - Some(stream) => stream.into_iter().collect(), - None => Vec::new(), - }, - }; - let tree = TokenTree::from(group); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Ident(IdentId(index)) => { - let IdentData(ident) = self.ident_interner.get(index).clone(); - let ident: tt::Ident = ident; - let leaf = tt::Leaf::from(ident); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Literal(literal) => { - let leaf = tt::Leaf::from(literal); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Punct(p) => { - let punct = tt::Punct { - char: p.ch as char, - spacing: if p.joint { Spacing::Joint } else { Spacing::Alone }, - id: p.span, - }; - let leaf = tt::Leaf::from(punct); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - } - } - - fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result { - Ok(self_.clone()) - } - - fn concat_trees( - &mut self, - base: Option, - trees: Vec>, - ) -> Self::TokenStream { - let mut builder = TokenStreamBuilder::new(); - if let Some(base) = base { - builder.push(base); - } - for tree in trees { - builder.push(self.from_token_tree(tree)); - } - builder.build() - } - - fn concat_streams( - &mut self, - base: Option, - streams: Vec, - ) -> Self::TokenStream { - let mut builder = TokenStreamBuilder::new(); - if let Some(base) = base { - builder.push(base); - } - for stream in streams { - builder.push(stream); - } - builder.build() - } - - fn into_trees( - &mut self, - stream: Self::TokenStream, - ) -> Vec> { - stream - .into_iter() - .map(|tree| match tree { - tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { - bridge::TokenTree::Ident(IdentId(self.ident_interner.intern(&IdentData(ident)))) - } - tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => bridge::TokenTree::Literal(lit), - tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => { - bridge::TokenTree::Punct(bridge::Punct { - ch: punct.char as u8, - joint: punct.spacing == Spacing::Joint, - span: punct.id, - }) - } - tt::TokenTree::Subtree(subtree) => bridge::TokenTree::Group(bridge::Group { - delimiter: delim_to_external(subtree.delimiter), - stream: if subtree.token_trees.is_empty() { - None - } else { - Some(subtree.token_trees.into_iter().collect()) - }, - span: bridge::DelimSpan::from_single( - subtree.delimiter.map_or(Span::unspecified(), |del| del.id), - ), - }), - }) - .collect() - } -} - -fn delim_to_internal(d: bridge::Delimiter) -> Option { - let kind = match d { - bridge::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis, - bridge::Delimiter::Brace => tt::DelimiterKind::Brace, - bridge::Delimiter::Bracket => tt::DelimiterKind::Bracket, - bridge::Delimiter::None => return None, - }; - Some(tt::Delimiter { id: tt::TokenId::unspecified(), kind }) -} - -fn delim_to_external(d: Option) -> bridge::Delimiter { - match d.map(|it| it.kind) { - Some(tt::DelimiterKind::Parenthesis) => bridge::Delimiter::Parenthesis, - Some(tt::DelimiterKind::Brace) => bridge::Delimiter::Brace, - Some(tt::DelimiterKind::Bracket) => bridge::Delimiter::Bracket, - None => bridge::Delimiter::None, - } -} - -fn spacing_to_internal(spacing: bridge::Spacing) -> Spacing { - match spacing { - bridge::Spacing::Alone => Spacing::Alone, - bridge::Spacing::Joint => Spacing::Joint, - } -} - -fn spacing_to_external(spacing: Spacing) -> bridge::Spacing { - match spacing { - Spacing::Alone => bridge::Spacing::Alone, - Spacing::Joint => bridge::Spacing::Joint, - } -} - -impl server::Ident for RustAnalyzer { - fn new(&mut self, string: &str, span: Self::Span, _is_raw: bool) -> Self::Ident { - IdentId(self.ident_interner.intern(&IdentData(tt::Ident { text: string.into(), id: span }))) - } - - fn span(&mut self, ident: Self::Ident) -> Self::Span { - self.ident_interner.get(ident.0).0.id - } - fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident { - let data = self.ident_interner.get(ident.0); - let new = IdentData(tt::Ident { id: span, ..data.0.clone() }); - IdentId(self.ident_interner.intern(&new)) - } -} - -impl server::Literal for RustAnalyzer { - fn debug_kind(&mut self, _literal: &Self::Literal) -> String { - // r-a: debug_kind and suffix are unsupported; corresponding client code has been changed to not call these. - // They must still be present to be ABI-compatible and work with upstream proc_macro. - "".to_owned() - } - fn from_str(&mut self, s: &str) -> Result { - Ok(Literal { text: s.into(), id: tt::TokenId::unspecified() }) - } - fn symbol(&mut self, literal: &Self::Literal) -> String { - literal.text.to_string() - } - fn suffix(&mut self, _literal: &Self::Literal) -> Option { - None - } - - fn to_string(&mut self, literal: &Self::Literal) -> String { - literal.to_string() - } - - fn integer(&mut self, n: &str) -> Self::Literal { - let n = match n.parse::() { - Ok(n) => n.to_string(), - Err(_) => n.parse::().unwrap().to_string(), - }; - Literal { text: n.into(), id: tt::TokenId::unspecified() } - } - - fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal { - macro_rules! def_suffixed_integer { - ($kind:ident, $($ty:ty),*) => { - match $kind { - $( - stringify!($ty) => { - let n: $ty = n.parse().unwrap(); - format!(concat!("{}", stringify!($ty)), n) - } - )* - _ => unimplemented!("unknown args for typed_integer: n {}, kind {}", n, $kind), - } - } - } - - let text = def_suffixed_integer! {kind, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize}; - - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn float(&mut self, n: &str) -> Self::Literal { - let n: f64 = n.parse().unwrap(); - let mut text = f64::to_string(&n); - if !text.contains('.') { - text += ".0" - } - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn f32(&mut self, n: &str) -> Self::Literal { - let n: f32 = n.parse().unwrap(); - let text = format!("{}f32", n); - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn f64(&mut self, n: &str) -> Self::Literal { - let n: f64 = n.parse().unwrap(); - let text = format!("{}f64", n); - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn string(&mut self, string: &str) -> Self::Literal { - let mut escaped = String::new(); - for ch in string.chars() { - escaped.extend(ch.escape_debug()); - } - Literal { text: format!("\"{}\"", escaped).into(), id: tt::TokenId::unspecified() } - } - - fn character(&mut self, ch: char) -> Self::Literal { - Literal { text: format!("'{}'", ch).into(), id: tt::TokenId::unspecified() } - } - - fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal { - let string = bytes - .iter() - .cloned() - .flat_map(ascii::escape_default) - .map(Into::::into) - .collect::(); - - Literal { text: format!("b\"{}\"", string).into(), id: tt::TokenId::unspecified() } - } - - fn span(&mut self, literal: &Self::Literal) -> Self::Span { - literal.id - } - - fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) { - literal.id = span; - } - - fn subspan( - &mut self, - _literal: &Self::Literal, - _start: Bound, - _end: Bound, - ) -> Option { - // FIXME handle span - None - } -} - -impl server::SourceFile for RustAnalyzer { - // FIXME these are all stubs - fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool { - true - } - fn path(&mut self, _file: &Self::SourceFile) -> String { - String::new() - } - fn is_real(&mut self, _file: &Self::SourceFile) -> bool { - true - } -} - -impl server::Diagnostic for RustAnalyzer { - fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic { - let mut diag = Diagnostic::new(level, msg); - diag.spans = spans; - diag - } - - fn sub( - &mut self, - _diag: &mut Self::Diagnostic, - _level: Level, - _msg: &str, - _spans: Self::MultiSpan, - ) { - // FIXME handle diagnostic - // - } - - fn emit(&mut self, _diag: Self::Diagnostic) { - // FIXME handle diagnostic - // diag.emit() - } -} - -impl server::Span for RustAnalyzer { - fn debug(&mut self, span: Self::Span) -> String { - format!("{:?}", span.0) - } - fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile { - SourceFile {} - } - fn save_span(&mut self, _span: Self::Span) -> usize { - // FIXME stub - 0 - } - fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span { - // FIXME stub - tt::TokenId::unspecified() - } - /// Recent feature, not yet in the proc_macro - /// - /// See PR: - /// https://github.com/rust-lang/rust/pull/55780 - fn source_text(&mut self, _span: Self::Span) -> Option { - None - } - - fn parent(&mut self, _span: Self::Span) -> Option { - // FIXME handle span - None - } - fn source(&mut self, span: Self::Span) -> Self::Span { - // FIXME handle span - span - } - fn start(&mut self, _span: Self::Span) -> LineColumn { - // FIXME handle span - LineColumn { line: 0, column: 0 } - } - fn end(&mut self, _span: Self::Span) -> LineColumn { - // FIXME handle span - LineColumn { line: 0, column: 0 } - } - fn join(&mut self, first: Self::Span, _second: Self::Span) -> Option { - // Just return the first span again, because some macros will unwrap the result. - Some(first) - } - fn resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span { - // FIXME handle span - tt::TokenId::unspecified() - } - - fn after(&mut self, _self_: Self::Span) -> Self::Span { - tt::TokenId::unspecified() - } - - fn before(&mut self, _self_: Self::Span) -> Self::Span { - tt::TokenId::unspecified() - } -} - -impl server::MultiSpan for RustAnalyzer { - fn new(&mut self) -> Self::MultiSpan { - // FIXME handle span - vec![] - } - - fn push(&mut self, other: &mut Self::MultiSpan, span: Self::Span) { - //TODP - other.push(span) - } -} - -impl server::Server for RustAnalyzer { - fn globals(&mut self) -> bridge::ExpnGlobals { - bridge::ExpnGlobals { - def_site: Span::unspecified(), - call_site: Span::unspecified(), - mixed_site: Span::unspecified(), - } - } -} - -#[cfg(test)] -mod tests { - use super::super::proc_macro::bridge::server::Literal; - use super::*; - - #[test] - fn test_ra_server_literals() { - let mut srv = RustAnalyzer { ident_interner: IdentInterner::default() }; - assert_eq!(srv.integer("1234").text, "1234"); - - assert_eq!(srv.typed_integer("12", "u8").text, "12u8"); - assert_eq!(srv.typed_integer("255", "u16").text, "255u16"); - assert_eq!(srv.typed_integer("1234", "u32").text, "1234u32"); - assert_eq!(srv.typed_integer("15846685", "u64").text, "15846685u64"); - assert_eq!(srv.typed_integer("15846685258", "u128").text, "15846685258u128"); - assert_eq!(srv.typed_integer("156788984", "usize").text, "156788984usize"); - assert_eq!(srv.typed_integer("127", "i8").text, "127i8"); - assert_eq!(srv.typed_integer("255", "i16").text, "255i16"); - assert_eq!(srv.typed_integer("1234", "i32").text, "1234i32"); - assert_eq!(srv.typed_integer("15846685", "i64").text, "15846685i64"); - assert_eq!(srv.typed_integer("15846685258", "i128").text, "15846685258i128"); - assert_eq!(srv.float("0").text, "0.0"); - assert_eq!(srv.float("15684.5867").text, "15684.5867"); - assert_eq!(srv.f32("15684.58").text, "15684.58f32"); - assert_eq!(srv.f64("15684.58").text, "15684.58f64"); - - assert_eq!(srv.string("hello_world").text, "\"hello_world\""); - assert_eq!(srv.character('c').text, "'c'"); - assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\""); - - // u128::max - assert_eq!( - srv.integer("340282366920938463463374607431768211455").text, - "340282366920938463463374607431768211455" - ); - // i128::min - assert_eq!( - srv.integer("-170141183460469231731687303715884105728").text, - "-170141183460469231731687303715884105728" - ); - } - - #[test] - fn test_ra_server_to_string() { - let s = TokenStream { - token_trees: vec![ - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "struct".into(), - id: tt::TokenId::unspecified(), - })), - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "T".into(), - id: tt::TokenId::unspecified(), - })), - tt::TokenTree::Subtree(tt::Subtree { - delimiter: Some(tt::Delimiter { - id: tt::TokenId::unspecified(), - kind: tt::DelimiterKind::Brace, - }), - token_trees: vec![], - }), - ], - }; - - assert_eq!(s.to_string(), "struct T {}"); - } - - #[test] - fn test_ra_server_from_str() { - use std::str::FromStr; - let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree { - delimiter: Some(tt::Delimiter { - id: tt::TokenId::unspecified(), - kind: tt::DelimiterKind::Parenthesis, - }), - token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "a".into(), - id: tt::TokenId::unspecified(), - }))], - }); - - let t1 = TokenStream::from_str("(a)").unwrap(); - assert_eq!(t1.token_trees.len(), 1); - assert_eq!(t1.token_trees[0], subtree_paren_a); - - let t2 = TokenStream::from_str("(a);").unwrap(); - assert_eq!(t2.token_trees.len(), 2); - assert_eq!(t2.token_trees[0], subtree_paren_a); - - let underscore = TokenStream::from_str("_").unwrap(); - assert_eq!( - underscore.token_trees[0], - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "_".into(), - id: tt::TokenId::unspecified(), - })) - ); - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/mod.rs deleted file mode 100644 index 44712f419191b..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/mod.rs +++ /dev/null @@ -1,102 +0,0 @@ -//! Proc macro ABI - -extern crate proc_macro; - -#[allow(dead_code)] -#[doc(hidden)] -mod ra_server; - -use libloading::Library; -use proc_macro_api::ProcMacroKind; - -use super::PanicMessage; - -pub(crate) struct Abi { - exported_macros: Vec, -} - -impl From for PanicMessage { - fn from(p: proc_macro::bridge::PanicMessage) -> Self { - Self { message: p.as_str().map(|s| s.to_string()) } - } -} - -impl Abi { - pub unsafe fn from_lib(lib: &Library, symbol_name: String) -> Result { - let macros: libloading::Symbol<'_, &&[proc_macro::bridge::client::ProcMacro]> = - lib.get(symbol_name.as_bytes())?; - Ok(Self { exported_macros: macros.to_vec() }) - } - - pub fn expand( - &self, - macro_name: &str, - macro_body: &tt::Subtree, - attributes: Option<&tt::Subtree>, - ) -> Result { - let parsed_body = ra_server::TokenStream::with_subtree(macro_body.clone()); - - let parsed_attributes = attributes.map_or(ra_server::TokenStream::new(), |attr| { - ra_server::TokenStream::with_subtree(attr.clone()) - }); - - for proc_macro in &self.exported_macros { - match proc_macro { - proc_macro::bridge::client::ProcMacro::CustomDerive { - trait_name, client, .. - } if *trait_name == macro_name => { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - proc_macro::bridge::client::ProcMacro::Bang { name, client } - if *name == macro_name => - { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - proc_macro::bridge::client::ProcMacro::Attr { name, client } - if *name == macro_name => - { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_attributes, - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - _ => continue, - } - } - - Err(proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()).into()) - } - - pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { - self.exported_macros - .iter() - .map(|proc_macro| match proc_macro { - proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { - (trait_name.to_string(), ProcMacroKind::CustomDerive) - } - proc_macro::bridge::client::ProcMacro::Bang { name, .. } => { - (name.to_string(), ProcMacroKind::FuncLike) - } - proc_macro::bridge::client::ProcMacro::Attr { name, .. } => { - (name.to_string(), ProcMacroKind::Attr) - } - }) - .collect() - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs deleted file mode 100644 index 46882845a8079..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs +++ /dev/null @@ -1,518 +0,0 @@ -//! proc-macro server implementation -//! -//! Based on idea from -//! The lib-proc-macro server backend is `TokenStream`-agnostic, such that -//! we could provide any TokenStream implementation. -//! The original idea from fedochet is using proc-macro2 as backend, -//! we use tt instead for better integration with RA. -//! -//! FIXME: No span and source file information is implemented yet - -use super::proc_macro::{ - self, - bridge::{self, server}, -}; - -mod token_stream; -pub use token_stream::TokenStream; -use token_stream::TokenStreamBuilder; - -mod symbol; -pub use symbol::*; - -use std::{iter::FromIterator, ops::Bound}; - -type Group = tt::Subtree; -type TokenTree = tt::TokenTree; -type Punct = tt::Punct; -type Spacing = tt::Spacing; -type Literal = tt::Literal; -type Span = tt::TokenId; - -#[derive(Clone)] -pub struct SourceFile { - // FIXME stub -} - -type Level = super::proc_macro::Level; -type LineColumn = super::proc_macro::LineColumn; - -/// A structure representing a diagnostic message and associated children -/// messages. -#[derive(Clone, Debug)] -pub struct Diagnostic { - level: Level, - message: String, - spans: Vec, - children: Vec, -} - -impl Diagnostic { - /// Creates a new diagnostic with the given `level` and `message`. - pub fn new>(level: Level, message: T) -> Diagnostic { - Diagnostic { level, message: message.into(), spans: vec![], children: vec![] } - } -} - -pub struct FreeFunctions; - -#[derive(Default)] -pub struct RustAnalyzer { - // FIXME: store span information here. -} - -impl server::Types for RustAnalyzer { - type FreeFunctions = FreeFunctions; - type TokenStream = TokenStream; - type SourceFile = SourceFile; - type MultiSpan = Vec; - type Diagnostic = Diagnostic; - type Span = Span; - type Symbol = Symbol; -} - -impl server::FreeFunctions for RustAnalyzer { - fn track_env_var(&mut self, _var: &str, _value: Option<&str>) { - // FIXME: track env var accesses - // https://github.com/rust-lang/rust/pull/71858 - } - fn track_path(&mut self, _path: &str) {} - - fn literal_from_str( - &mut self, - s: &str, - ) -> Result, ()> { - // FIXME: keep track of LitKind and Suffix - Ok(bridge::Literal { - kind: bridge::LitKind::Err, - symbol: Symbol::intern(s), - suffix: None, - span: tt::TokenId::unspecified(), - }) - } -} - -impl server::TokenStream for RustAnalyzer { - fn is_empty(&mut self, stream: &Self::TokenStream) -> bool { - stream.is_empty() - } - fn from_str(&mut self, src: &str) -> Self::TokenStream { - use std::str::FromStr; - - Self::TokenStream::from_str(src).expect("cannot parse string") - } - fn to_string(&mut self, stream: &Self::TokenStream) -> String { - stream.to_string() - } - fn from_token_tree( - &mut self, - tree: bridge::TokenTree, - ) -> Self::TokenStream { - match tree { - bridge::TokenTree::Group(group) => { - let group = Group { - delimiter: delim_to_internal(group.delimiter), - token_trees: match group.stream { - Some(stream) => stream.into_iter().collect(), - None => Vec::new(), - }, - }; - let tree = TokenTree::from(group); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Ident(ident) => { - // FIXME: handle raw idents - let text = ident.sym.text(); - let ident: tt::Ident = tt::Ident { text, id: ident.span }; - let leaf = tt::Leaf::from(ident); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Literal(literal) => { - let literal = LiteralFormatter(literal); - let text = literal - .with_stringify_parts(|parts| tt::SmolStr::from_iter(parts.iter().copied())); - - let literal = tt::Literal { text, id: literal.0.span }; - let leaf = tt::Leaf::from(literal); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Punct(p) => { - let punct = tt::Punct { - char: p.ch as char, - spacing: if p.joint { Spacing::Joint } else { Spacing::Alone }, - id: p.span, - }; - let leaf = tt::Leaf::from(punct); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - } - } - - fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result { - Ok(self_.clone()) - } - - fn concat_trees( - &mut self, - base: Option, - trees: Vec>, - ) -> Self::TokenStream { - let mut builder = TokenStreamBuilder::new(); - if let Some(base) = base { - builder.push(base); - } - for tree in trees { - builder.push(self.from_token_tree(tree)); - } - builder.build() - } - - fn concat_streams( - &mut self, - base: Option, - streams: Vec, - ) -> Self::TokenStream { - let mut builder = TokenStreamBuilder::new(); - if let Some(base) = base { - builder.push(base); - } - for stream in streams { - builder.push(stream); - } - builder.build() - } - - fn into_trees( - &mut self, - stream: Self::TokenStream, - ) -> Vec> { - stream - .into_iter() - .map(|tree| match tree { - tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { - bridge::TokenTree::Ident(bridge::Ident { - sym: Symbol::intern(&ident.text), - // FIXME: handle raw idents - is_raw: false, - span: ident.id, - }) - } - tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => { - bridge::TokenTree::Literal(bridge::Literal { - // FIXME: handle literal kinds - kind: bridge::LitKind::Err, - symbol: Symbol::intern(&lit.text), - // FIXME: handle suffixes - suffix: None, - span: lit.id, - }) - } - tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => { - bridge::TokenTree::Punct(bridge::Punct { - ch: punct.char as u8, - joint: punct.spacing == Spacing::Joint, - span: punct.id, - }) - } - tt::TokenTree::Subtree(subtree) => bridge::TokenTree::Group(bridge::Group { - delimiter: delim_to_external(subtree.delimiter), - stream: if subtree.token_trees.is_empty() { - None - } else { - Some(subtree.token_trees.into_iter().collect()) - }, - span: bridge::DelimSpan::from_single( - subtree.delimiter.map_or(Span::unspecified(), |del| del.id), - ), - }), - }) - .collect() - } -} - -fn delim_to_internal(d: proc_macro::Delimiter) -> Option { - let kind = match d { - proc_macro::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis, - proc_macro::Delimiter::Brace => tt::DelimiterKind::Brace, - proc_macro::Delimiter::Bracket => tt::DelimiterKind::Bracket, - proc_macro::Delimiter::None => return None, - }; - Some(tt::Delimiter { id: tt::TokenId::unspecified(), kind }) -} - -fn delim_to_external(d: Option) -> proc_macro::Delimiter { - match d.map(|it| it.kind) { - Some(tt::DelimiterKind::Parenthesis) => proc_macro::Delimiter::Parenthesis, - Some(tt::DelimiterKind::Brace) => proc_macro::Delimiter::Brace, - Some(tt::DelimiterKind::Bracket) => proc_macro::Delimiter::Bracket, - None => proc_macro::Delimiter::None, - } -} - -fn spacing_to_internal(spacing: proc_macro::Spacing) -> Spacing { - match spacing { - proc_macro::Spacing::Alone => Spacing::Alone, - proc_macro::Spacing::Joint => Spacing::Joint, - } -} - -fn spacing_to_external(spacing: Spacing) -> proc_macro::Spacing { - match spacing { - Spacing::Alone => proc_macro::Spacing::Alone, - Spacing::Joint => proc_macro::Spacing::Joint, - } -} - -impl server::SourceFile for RustAnalyzer { - // FIXME these are all stubs - fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool { - true - } - fn path(&mut self, _file: &Self::SourceFile) -> String { - String::new() - } - fn is_real(&mut self, _file: &Self::SourceFile) -> bool { - true - } -} - -impl server::Diagnostic for RustAnalyzer { - fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic { - let mut diag = Diagnostic::new(level, msg); - diag.spans = spans; - diag - } - - fn sub( - &mut self, - _diag: &mut Self::Diagnostic, - _level: Level, - _msg: &str, - _spans: Self::MultiSpan, - ) { - // FIXME handle diagnostic - // - } - - fn emit(&mut self, _diag: Self::Diagnostic) { - // FIXME handle diagnostic - // diag.emit() - } -} - -impl server::Span for RustAnalyzer { - fn debug(&mut self, span: Self::Span) -> String { - format!("{:?}", span.0) - } - fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile { - SourceFile {} - } - fn save_span(&mut self, _span: Self::Span) -> usize { - // FIXME stub - 0 - } - fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span { - // FIXME stub - tt::TokenId::unspecified() - } - /// Recent feature, not yet in the proc_macro - /// - /// See PR: - /// https://github.com/rust-lang/rust/pull/55780 - fn source_text(&mut self, _span: Self::Span) -> Option { - None - } - - fn parent(&mut self, _span: Self::Span) -> Option { - // FIXME handle span - None - } - fn source(&mut self, span: Self::Span) -> Self::Span { - // FIXME handle span - span - } - fn start(&mut self, _span: Self::Span) -> LineColumn { - // FIXME handle span - LineColumn { line: 0, column: 0 } - } - fn end(&mut self, _span: Self::Span) -> LineColumn { - // FIXME handle span - LineColumn { line: 0, column: 0 } - } - fn join(&mut self, first: Self::Span, _second: Self::Span) -> Option { - // Just return the first span again, because some macros will unwrap the result. - Some(first) - } - fn subspan( - &mut self, - span: Self::Span, - _start: Bound, - _end: Bound, - ) -> Option { - // Just return the span again, because some macros will unwrap the result. - Some(span) - } - fn resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span { - // FIXME handle span - tt::TokenId::unspecified() - } - - fn after(&mut self, _self_: Self::Span) -> Self::Span { - tt::TokenId::unspecified() - } - - fn before(&mut self, _self_: Self::Span) -> Self::Span { - tt::TokenId::unspecified() - } -} - -impl server::MultiSpan for RustAnalyzer { - fn new(&mut self) -> Self::MultiSpan { - // FIXME handle span - vec![] - } - - fn push(&mut self, other: &mut Self::MultiSpan, span: Self::Span) { - //TODP - other.push(span) - } -} - -impl server::Symbol for RustAnalyzer { - fn normalize_and_validate_ident(&mut self, string: &str) -> Result { - // FIXME: nfc-normalize and validate idents - Ok(::intern_symbol(string)) - } -} - -impl server::Server for RustAnalyzer { - fn globals(&mut self) -> bridge::ExpnGlobals { - bridge::ExpnGlobals { - def_site: Span::unspecified(), - call_site: Span::unspecified(), - mixed_site: Span::unspecified(), - } - } - - fn intern_symbol(ident: &str) -> Self::Symbol { - Symbol::intern(&tt::SmolStr::from(ident)) - } - - fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) { - f(symbol.text().as_str()) - } -} - -struct LiteralFormatter(bridge::Literal); - -impl LiteralFormatter { - /// Invokes the callback with a `&[&str]` consisting of each part of the - /// literal's representation. This is done to allow the `ToString` and - /// `Display` implementations to borrow references to symbol values, and - /// both be optimized to reduce overhead. - fn with_stringify_parts(&self, f: impl FnOnce(&[&str]) -> R) -> R { - /// Returns a string containing exactly `num` '#' characters. - /// Uses a 256-character source string literal which is always safe to - /// index with a `u8` index. - fn get_hashes_str(num: u8) -> &'static str { - const HASHES: &str = "\ - ################################################################\ - ################################################################\ - ################################################################\ - ################################################################\ - "; - const _: () = assert!(HASHES.len() == 256); - &HASHES[..num as usize] - } - - self.with_symbol_and_suffix(|symbol, suffix| match self.0.kind { - bridge::LitKind::Byte => f(&["b'", symbol, "'", suffix]), - bridge::LitKind::Char => f(&["'", symbol, "'", suffix]), - bridge::LitKind::Str => f(&["\"", symbol, "\"", suffix]), - bridge::LitKind::StrRaw(n) => { - let hashes = get_hashes_str(n); - f(&["r", hashes, "\"", symbol, "\"", hashes, suffix]) - } - bridge::LitKind::ByteStr => f(&["b\"", symbol, "\"", suffix]), - bridge::LitKind::ByteStrRaw(n) => { - let hashes = get_hashes_str(n); - f(&["br", hashes, "\"", symbol, "\"", hashes, suffix]) - } - _ => f(&[symbol, suffix]), - }) - } - - fn with_symbol_and_suffix(&self, f: impl FnOnce(&str, &str) -> R) -> R { - let symbol = self.0.symbol.text(); - let suffix = self.0.suffix.map(|s| s.text()).unwrap_or_default(); - f(symbol.as_str(), suffix.as_str()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_ra_server_to_string() { - let s = TokenStream { - token_trees: vec![ - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "struct".into(), - id: tt::TokenId::unspecified(), - })), - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "T".into(), - id: tt::TokenId::unspecified(), - })), - tt::TokenTree::Subtree(tt::Subtree { - delimiter: Some(tt::Delimiter { - id: tt::TokenId::unspecified(), - kind: tt::DelimiterKind::Brace, - }), - token_trees: vec![], - }), - ], - }; - - assert_eq!(s.to_string(), "struct T {}"); - } - - #[test] - fn test_ra_server_from_str() { - use std::str::FromStr; - let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree { - delimiter: Some(tt::Delimiter { - id: tt::TokenId::unspecified(), - kind: tt::DelimiterKind::Parenthesis, - }), - token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "a".into(), - id: tt::TokenId::unspecified(), - }))], - }); - - let t1 = TokenStream::from_str("(a)").unwrap(); - assert_eq!(t1.token_trees.len(), 1); - assert_eq!(t1.token_trees[0], subtree_paren_a); - - let t2 = TokenStream::from_str("(a);").unwrap(); - assert_eq!(t2.token_trees.len(), 2); - assert_eq!(t2.token_trees[0], subtree_paren_a); - - let underscore = TokenStream::from_str("_").unwrap(); - assert_eq!( - underscore.token_trees[0], - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "_".into(), - id: tt::TokenId::unspecified(), - })) - ); - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server/symbol.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server/symbol.rs deleted file mode 100644 index 51dfba2ea9fb4..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server/symbol.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! Symbol interner for proc-macro-srv - -use std::{cell::RefCell, collections::HashMap}; -use tt::SmolStr; - -thread_local! { - static SYMBOL_INTERNER: RefCell = Default::default(); -} - -// ID for an interned symbol. -#[derive(Hash, Eq, PartialEq, Copy, Clone)] -pub struct Symbol(u32); - -impl Symbol { - pub fn intern(data: &str) -> Symbol { - SYMBOL_INTERNER.with(|i| i.borrow_mut().intern(data)) - } - - pub fn text(&self) -> SmolStr { - SYMBOL_INTERNER.with(|i| i.borrow().get(self).clone()) - } -} - -#[derive(Default)] -struct SymbolInterner { - idents: HashMap, - ident_data: Vec, -} - -impl SymbolInterner { - fn intern(&mut self, data: &str) -> Symbol { - if let Some(index) = self.idents.get(data) { - return Symbol(*index); - } - - let index = self.idents.len() as u32; - let data = SmolStr::from(data); - self.ident_data.push(data.clone()); - self.idents.insert(data, index); - Symbol(index) - } - - fn get(&self, sym: &Symbol) -> &SmolStr { - &self.ident_data[sym.0 as usize] - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server/token_stream.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server/token_stream.rs deleted file mode 100644 index 113bb52c1af53..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server/token_stream.rs +++ /dev/null @@ -1,179 +0,0 @@ -//! TokenStream implementation used by sysroot ABI - -use tt::TokenTree; - -#[derive(Debug, Default, Clone)] -pub struct TokenStream { - pub token_trees: Vec, -} - -impl TokenStream { - pub fn new() -> Self { - TokenStream::default() - } - - pub fn with_subtree(subtree: tt::Subtree) -> Self { - if subtree.delimiter.is_some() { - TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] } - } else { - TokenStream { token_trees: subtree.token_trees } - } - } - - pub fn into_subtree(self) -> tt::Subtree { - tt::Subtree { delimiter: None, token_trees: self.token_trees } - } - - pub fn is_empty(&self) -> bool { - self.token_trees.is_empty() - } -} - -/// Creates a token stream containing a single token tree. -impl From for TokenStream { - fn from(tree: TokenTree) -> TokenStream { - TokenStream { token_trees: vec![tree] } - } -} - -/// Collects a number of token trees into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(trees: I) -> Self { - trees.into_iter().map(TokenStream::from).collect() - } -} - -/// A "flattening" operation on token streams, collects token trees -/// from multiple token streams into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(streams: I) -> Self { - let mut builder = TokenStreamBuilder::new(); - streams.into_iter().for_each(|stream| builder.push(stream)); - builder.build() - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, trees: I) { - self.extend(trees.into_iter().map(TokenStream::from)); - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, streams: I) { - for item in streams { - for tkn in item { - match tkn { - tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => { - self.token_trees.extend(subtree.token_trees); - } - _ => { - self.token_trees.push(tkn); - } - } - } - } - } -} - -pub struct TokenStreamBuilder { - acc: TokenStream, -} - -/// Public implementation details for the `TokenStream` type, such as iterators. -pub mod token_stream { - use std::str::FromStr; - - use super::{TokenStream, TokenTree}; - - /// An iterator over `TokenStream`'s `TokenTree`s. - /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, - /// and returns whole groups as token trees. - impl IntoIterator for TokenStream { - type Item = TokenTree; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.token_trees.into_iter() - } - } - - type LexError = String; - - /// Attempts to break the string into tokens and parse those tokens into a token stream. - /// May fail for a number of reasons, for example, if the string contains unbalanced delimiters - /// or characters not existing in the language. - /// All tokens in the parsed stream get `Span::call_site()` spans. - /// - /// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to - /// change these errors into `LexError`s later. - impl FromStr for TokenStream { - type Err = LexError; - - fn from_str(src: &str) -> Result { - let (subtree, _token_map) = - mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?; - - let subtree = subtree_replace_token_ids_with_unspecified(subtree); - Ok(TokenStream::with_subtree(subtree)) - } - } - - impl ToString for TokenStream { - fn to_string(&self) -> String { - tt::pretty(&self.token_trees) - } - } - - fn subtree_replace_token_ids_with_unspecified(subtree: tt::Subtree) -> tt::Subtree { - tt::Subtree { - delimiter: subtree - .delimiter - .map(|d| tt::Delimiter { id: tt::TokenId::unspecified(), ..d }), - token_trees: subtree - .token_trees - .into_iter() - .map(token_tree_replace_token_ids_with_unspecified) - .collect(), - } - } - - fn token_tree_replace_token_ids_with_unspecified(tt: tt::TokenTree) -> tt::TokenTree { - match tt { - tt::TokenTree::Leaf(leaf) => { - tt::TokenTree::Leaf(leaf_replace_token_ids_with_unspecified(leaf)) - } - tt::TokenTree::Subtree(subtree) => { - tt::TokenTree::Subtree(subtree_replace_token_ids_with_unspecified(subtree)) - } - } - } - - fn leaf_replace_token_ids_with_unspecified(leaf: tt::Leaf) -> tt::Leaf { - match leaf { - tt::Leaf::Literal(lit) => { - tt::Leaf::Literal(tt::Literal { id: tt::TokenId::unspecified(), ..lit }) - } - tt::Leaf::Punct(punct) => { - tt::Leaf::Punct(tt::Punct { id: tt::TokenId::unspecified(), ..punct }) - } - tt::Leaf::Ident(ident) => { - tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), ..ident }) - } - } - } -} - -impl TokenStreamBuilder { - pub(super) fn new() -> TokenStreamBuilder { - TokenStreamBuilder { acc: TokenStream::new() } - } - - pub(super) fn push(&mut self, stream: TokenStream) { - self.acc.extend(stream.into_iter()) - } - - pub(super) fn build(self) -> TokenStream { - self.acc - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/mod.rs deleted file mode 100644 index bcf3f1184cf65..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/mod.rs +++ /dev/null @@ -1,155 +0,0 @@ -//! Procedural macros are implemented by compiling the macro providing crate -//! to a dynamic library with a particular ABI which the compiler uses to expand -//! macros. Unfortunately this ABI is not specified and can change from version -//! to version of the compiler. To support this we copy the ABI from the rust -//! compiler into submodules of this module (e.g proc_macro_srv::abis::abi_1_47). -//! -//! All of these ABIs are subsumed in the `Abi` enum, which exposes a simple -//! interface the rest of rust analyzer can use to talk to the macro -//! provider. -//! -//! # Adding a new ABI -//! -//! To add a new ABI you'll need to copy the source of the target proc_macro -//! crate from the source tree of the Rust compiler into this directory tree. -//! Then you'll need to modify it -//! - Remove any feature! or other things which won't compile on stable -//! - change any absolute imports to relative imports within the ABI tree -//! -//! Then you'll need to add a branch to the `Abi` enum and an implementation of -//! `Abi::expand`, `Abi::list_macros` and `Abi::from_lib` for the new ABI. See -//! `proc_macro_srv/src/abis/abi_1_47/mod.rs` for an example. Finally you'll -//! need to update the conditionals in `Abi::from_lib` to return your new ABI -//! for the relevant versions of the rust compiler -//! - -mod abi_1_58; -mod abi_1_63; -mod abi_1_64; -#[cfg(feature = "sysroot-abi")] -mod abi_sysroot; - -// see `build.rs` -include!(concat!(env!("OUT_DIR"), "/rustc_version.rs")); - -// Used by `test/utils.rs` -#[cfg(test)] -pub(crate) use abi_1_64::TokenStream as TestTokenStream; - -use super::dylib::LoadProcMacroDylibError; -pub(crate) use abi_1_58::Abi as Abi_1_58; -pub(crate) use abi_1_63::Abi as Abi_1_63; -pub(crate) use abi_1_64::Abi as Abi_1_64; -#[cfg(feature = "sysroot-abi")] -pub(crate) use abi_sysroot::Abi as Abi_Sysroot; -use libloading::Library; -use proc_macro_api::{ProcMacroKind, RustCInfo}; - -pub struct PanicMessage { - message: Option, -} - -impl PanicMessage { - pub fn as_str(&self) -> Option { - self.message.clone() - } -} - -pub(crate) enum Abi { - Abi1_58(Abi_1_58), - Abi1_63(Abi_1_63), - Abi1_64(Abi_1_64), - #[cfg(feature = "sysroot-abi")] - AbiSysroot(Abi_Sysroot), -} - -impl Abi { - /// Load a new ABI. - /// - /// # Arguments - /// - /// *`lib` - The dynamic library containing the macro implementations - /// *`symbol_name` - The symbol name the macros can be found attributes - /// *`info` - RustCInfo about the compiler that was used to compile the - /// macro crate. This is the information we use to figure out - /// which ABI to return - pub fn from_lib( - lib: &Library, - symbol_name: String, - info: RustCInfo, - ) -> Result { - // the sysroot ABI relies on `extern proc_macro` with unstable features, - // instead of a snapshot of the proc macro bridge's source code. it's only - // enabled if we have an exact version match. - #[cfg(feature = "sysroot-abi")] - { - if info.version_string == RUSTC_VERSION_STRING { - let inner = unsafe { Abi_Sysroot::from_lib(lib, symbol_name) }?; - return Ok(Abi::AbiSysroot(inner)); - } - - // if we reached this point, versions didn't match. in testing, we - // want that to panic - this could mean that the format of `rustc - // --version` no longer matches the format of the version string - // stored in the `.rustc` section, and we want to catch that in-tree - // with `x.py test` - #[cfg(test)] - { - let allow_mismatch = std::env::var("PROC_MACRO_SRV_ALLOW_SYSROOT_MISMATCH"); - if let Ok("1") = allow_mismatch.as_deref() { - // only used by rust-analyzer developers, when working on the - // sysroot ABI from the rust-analyzer repository - which should - // only happen pre-subtree. this can be removed later. - } else { - panic!( - "sysroot ABI mismatch: dylib rustc version (read from .rustc section): {:?} != proc-macro-srv version (read from 'rustc --version'): {:?}", - info.version_string, RUSTC_VERSION_STRING - ); - } - } - } - - // FIXME: this should use exclusive ranges when they're stable - // https://github.com/rust-lang/rust/issues/37854 - match (info.version.0, info.version.1) { - (1, 58..=62) => { - let inner = unsafe { Abi_1_58::from_lib(lib, symbol_name) }?; - Ok(Abi::Abi1_58(inner)) - } - (1, 63) => { - let inner = unsafe { Abi_1_63::from_lib(lib, symbol_name) }?; - Ok(Abi::Abi1_63(inner)) - } - (1, 64..) => { - let inner = unsafe { Abi_1_64::from_lib(lib, symbol_name) }?; - Ok(Abi::Abi1_64(inner)) - } - _ => Err(LoadProcMacroDylibError::UnsupportedABI), - } - } - - pub fn expand( - &self, - macro_name: &str, - macro_body: &tt::Subtree, - attributes: Option<&tt::Subtree>, - ) -> Result { - match self { - Self::Abi1_58(abi) => abi.expand(macro_name, macro_body, attributes), - Self::Abi1_63(abi) => abi.expand(macro_name, macro_body, attributes), - Self::Abi1_64(abi) => abi.expand(macro_name, macro_body, attributes), - #[cfg(feature = "sysroot-abi")] - Self::AbiSysroot(abi) => abi.expand(macro_name, macro_body, attributes), - } - } - - pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { - match self { - Self::Abi1_58(abi) => abi.list_macros(), - Self::Abi1_63(abi) => abi.list_macros(), - Self::Abi1_64(abi) => abi.list_macros(), - #[cfg(feature = "sysroot-abi")] - Self::AbiSysroot(abi) => abi.list_macros(), - } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/cli.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/cli.rs deleted file mode 100644 index f1e131c135d83..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/cli.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Driver for proc macro server -use std::io; - -use proc_macro_api::msg::{self, Message}; - -use crate::ProcMacroSrv; - -pub fn run() -> io::Result<()> { - let mut srv = ProcMacroSrv::default(); - let mut buf = String::new(); - - while let Some(req) = read_request(&mut buf)? { - let res = match req { - msg::Request::ListMacros { dylib_path } => { - msg::Response::ListMacros(srv.list_macros(&dylib_path)) - } - msg::Request::ExpandMacro(task) => msg::Response::ExpandMacro(srv.expand(task)), - }; - write_response(res)? - } - - Ok(()) -} - -fn read_request(buf: &mut String) -> io::Result> { - msg::Request::read(&mut io::stdin().lock(), buf) -} - -fn write_response(msg: msg::Response) -> io::Result<()> { - msg.write(&mut io::stdout().lock()) -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs deleted file mode 100644 index 2b6c070fece3f..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs +++ /dev/null @@ -1,199 +0,0 @@ -//! Handles dynamic library loading for proc macro - -use std::{ - convert::TryInto, - fmt, - fs::File, - io, - path::{Path, PathBuf}, -}; - -use libloading::Library; -use memmap2::Mmap; -use object::Object; -use paths::AbsPath; -use proc_macro_api::{read_dylib_info, ProcMacroKind}; - -use super::abis::Abi; - -const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_"; - -fn invalid_data_err(e: impl Into>) -> io::Error { - io::Error::new(io::ErrorKind::InvalidData, e) -} - -fn is_derive_registrar_symbol(symbol: &str) -> bool { - symbol.contains(NEW_REGISTRAR_SYMBOL) -} - -fn find_registrar_symbol(file: &Path) -> io::Result> { - let file = File::open(file)?; - let buffer = unsafe { Mmap::map(&file)? }; - - Ok(object::File::parse(&*buffer) - .map_err(invalid_data_err)? - .exports() - .map_err(invalid_data_err)? - .into_iter() - .map(|export| export.name()) - .filter_map(|sym| String::from_utf8(sym.into()).ok()) - .find(|sym| is_derive_registrar_symbol(sym)) - .map(|sym| { - // From MacOS docs: - // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlsym.3.html - // Unlike other dyld API's, the symbol name passed to dlsym() must NOT be - // prepended with an underscore. - if cfg!(target_os = "macos") && sym.starts_with('_') { - sym[1..].to_owned() - } else { - sym - } - })) -} - -/// Loads dynamic library in platform dependent manner. -/// -/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described -/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample) -/// and [here](https://github.com/rust-lang/rust/issues/60593). -/// -/// Usage of RTLD_DEEPBIND -/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1) -/// -/// It seems that on Windows that behaviour is default, so we do nothing in that case. -#[cfg(windows)] -fn load_library(file: &Path) -> Result { - unsafe { Library::new(file) } -} - -#[cfg(unix)] -fn load_library(file: &Path) -> Result { - use libloading::os::unix::Library as UnixLibrary; - use std::os::raw::c_int; - - const RTLD_NOW: c_int = 0x00002; - const RTLD_DEEPBIND: c_int = 0x00008; - - unsafe { UnixLibrary::open(Some(file), RTLD_NOW | RTLD_DEEPBIND).map(|lib| lib.into()) } -} - -#[derive(Debug)] -pub enum LoadProcMacroDylibError { - Io(io::Error), - LibLoading(libloading::Error), - UnsupportedABI, -} - -impl fmt::Display for LoadProcMacroDylibError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Io(e) => e.fmt(f), - Self::UnsupportedABI => write!(f, "unsupported ABI version"), - Self::LibLoading(e) => e.fmt(f), - } - } -} - -impl From for LoadProcMacroDylibError { - fn from(e: io::Error) -> Self { - LoadProcMacroDylibError::Io(e) - } -} - -impl From for LoadProcMacroDylibError { - fn from(e: libloading::Error) -> Self { - LoadProcMacroDylibError::LibLoading(e) - } -} - -struct ProcMacroLibraryLibloading { - // Hold on to the library so it doesn't unload - _lib: Library, - abi: Abi, -} - -impl ProcMacroLibraryLibloading { - fn open(file: &Path) -> Result { - let symbol_name = find_registrar_symbol(file)?.ok_or_else(|| { - invalid_data_err(format!("Cannot find registrar symbol in file {}", file.display())) - })?; - - let abs_file: &AbsPath = file.try_into().map_err(|_| { - invalid_data_err(format!("expected an absolute path, got {}", file.display())) - })?; - let version_info = read_dylib_info(abs_file)?; - - let lib = load_library(file).map_err(invalid_data_err)?; - let abi = Abi::from_lib(&lib, symbol_name, version_info)?; - Ok(ProcMacroLibraryLibloading { _lib: lib, abi }) - } -} - -pub struct Expander { - inner: ProcMacroLibraryLibloading, -} - -impl Expander { - pub fn new(lib: &Path) -> Result { - // Some libraries for dynamic loading require canonicalized path even when it is - // already absolute - let lib = lib.canonicalize()?; - - let lib = ensure_file_with_lock_free_access(&lib)?; - - let library = ProcMacroLibraryLibloading::open(lib.as_ref())?; - - Ok(Expander { inner: library }) - } - - pub fn expand( - &self, - macro_name: &str, - macro_body: &tt::Subtree, - attributes: Option<&tt::Subtree>, - ) -> Result { - let result = self.inner.abi.expand(macro_name, macro_body, attributes); - result.map_err(|e| e.as_str().unwrap_or_else(|| "".to_string())) - } - - pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { - self.inner.abi.list_macros() - } -} - -/// Copy the dylib to temp directory to prevent locking in Windows -#[cfg(windows)] -fn ensure_file_with_lock_free_access(path: &Path) -> io::Result { - use std::collections::hash_map::RandomState; - use std::ffi::OsString; - use std::hash::{BuildHasher, Hasher}; - - if std::env::var("RA_DONT_COPY_PROC_MACRO_DLL").is_ok() { - return Ok(path.to_path_buf()); - } - - let mut to = std::env::temp_dir(); - - let file_name = path.file_name().ok_or_else(|| { - io::Error::new( - io::ErrorKind::InvalidInput, - format!("File path is invalid: {}", path.display()), - ) - })?; - - // Generate a unique number by abusing `HashMap`'s hasher. - // Maybe this will also "inspire" a libs team member to finally put `rand` in libstd. - let t = RandomState::new().build_hasher().finish(); - - let mut unique_name = OsString::from(t.to_string()); - unique_name.push(file_name); - - to.push(unique_name); - std::fs::copy(path, &to).unwrap(); - Ok(to) -} - -#[cfg(unix)] -fn ensure_file_with_lock_free_access(path: &Path) -> io::Result { - Ok(path.to_path_buf()) -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs deleted file mode 100644 index 4b1858b8ed89e..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ /dev/null @@ -1,153 +0,0 @@ -//! RA Proc Macro Server -//! -//! This library is able to call compiled Rust custom derive dynamic libraries on arbitrary code. -//! The general idea here is based on . -//! -//! But we adapt it to better fit RA needs: -//! -//! * We use `tt` for proc-macro `TokenStream` server, it is easier to manipulate and interact with -//! RA than `proc-macro2` token stream. -//! * By **copying** the whole rustc `lib_proc_macro` code, we are able to build this with `stable` -//! rustc rather than `unstable`. (Although in general ABI compatibility is still an issue)… - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] -#![cfg_attr( - feature = "sysroot-abi", - feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span) -)] -#![allow(unreachable_pub)] - -mod dylib; -mod abis; - -use std::{ - collections::{hash_map::Entry, HashMap}, - env, - ffi::OsString, - fs, - path::{Path, PathBuf}, - time::SystemTime, -}; - -use proc_macro_api::{ - msg::{ExpandMacro, FlatTree, PanicMessage}, - ProcMacroKind, -}; - -#[derive(Default)] -pub(crate) struct ProcMacroSrv { - expanders: HashMap<(PathBuf, SystemTime), dylib::Expander>, -} - -impl ProcMacroSrv { - pub fn expand(&mut self, task: ExpandMacro) -> Result { - let expander = self.expander(task.lib.as_ref()).map_err(|err| { - debug_assert!(false, "should list macros before asking to expand"); - PanicMessage(format!("failed to load macro: {}", err)) - })?; - - let prev_env = EnvSnapshot::new(); - for (k, v) in &task.env { - env::set_var(k, v); - } - let prev_working_dir = match task.current_dir { - Some(dir) => { - let prev_working_dir = std::env::current_dir().ok(); - if let Err(err) = std::env::set_current_dir(&dir) { - eprintln!("Failed to set the current working dir to {}. Error: {:?}", dir, err) - } - prev_working_dir - } - None => None, - }; - - let macro_body = task.macro_body.to_subtree(); - let attributes = task.attributes.map(|it| it.to_subtree()); - // FIXME: replace this with std's scoped threads once they stabilize - // (then remove dependency on crossbeam) - let result = crossbeam::scope(|s| { - let res = s - .spawn(|_| { - expander - .expand(&task.macro_name, ¯o_body, attributes.as_ref()) - .map(|it| FlatTree::new(&it)) - }) - .join(); - - match res { - Ok(res) => res, - Err(e) => std::panic::resume_unwind(e), - } - }); - let result = match result { - Ok(result) => result, - Err(e) => std::panic::resume_unwind(e), - }; - - prev_env.rollback(); - - if let Some(dir) = prev_working_dir { - if let Err(err) = std::env::set_current_dir(&dir) { - eprintln!( - "Failed to set the current working dir to {}. Error: {:?}", - dir.display(), - err - ) - } - } - - result.map_err(PanicMessage) - } - - pub(crate) fn list_macros( - &mut self, - dylib_path: &Path, - ) -> Result, String> { - let expander = self.expander(dylib_path)?; - Ok(expander.list_macros()) - } - - fn expander(&mut self, path: &Path) -> Result<&dylib::Expander, String> { - let time = fs::metadata(path).and_then(|it| it.modified()).map_err(|err| { - format!("Failed to get file metadata for {}: {:?}", path.display(), err) - })?; - - Ok(match self.expanders.entry((path.to_path_buf(), time)) { - Entry::Vacant(v) => v.insert(dylib::Expander::new(path).map_err(|err| { - format!("Cannot create expander for {}: {:?}", path.display(), err) - })?), - Entry::Occupied(e) => e.into_mut(), - }) - } -} - -struct EnvSnapshot { - vars: HashMap, -} - -impl EnvSnapshot { - fn new() -> EnvSnapshot { - EnvSnapshot { vars: env::vars_os().collect() } - } - - fn rollback(self) { - let mut old_vars = self.vars; - for (name, value) in env::vars_os() { - let old_value = old_vars.remove(&name); - if old_value != Some(value) { - match old_value { - None => env::remove_var(name), - Some(old_value) => env::set_var(name, old_value), - } - } - } - for (name, old_value) in old_vars { - env::set_var(name, old_value) - } - } -} - -pub mod cli; - -#[cfg(test)] -mod tests; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs deleted file mode 100644 index 07222907f0880..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs +++ /dev/null @@ -1,166 +0,0 @@ -//! proc-macro tests - -#[macro_use] -mod utils; -use expect_test::expect; -use paths::AbsPathBuf; -use utils::*; - -#[test] -fn test_derive_empty() { - assert_expand("DeriveEmpty", r#"struct S;"#, expect![[r#"SUBTREE $"#]]); -} - -#[test] -fn test_derive_error() { - assert_expand( - "DeriveError", - r#"struct S;"#, - expect![[r##" - SUBTREE $ - IDENT compile_error 4294967295 - PUNCH ! [alone] 4294967295 - SUBTREE () 4294967295 - LITERAL "#[derive(DeriveError)] struct S ;" 4294967295 - PUNCH ; [alone] 4294967295"##]], - ); -} - -#[test] -fn test_fn_like_macro_noop() { - assert_expand( - "fn_like_noop", - r#"ident, 0, 1, []"#, - expect![[r#" - SUBTREE $ - IDENT ident 4294967295 - PUNCH , [alone] 4294967295 - LITERAL 0 4294967295 - PUNCH , [alone] 4294967295 - LITERAL 1 4294967295 - PUNCH , [alone] 4294967295 - SUBTREE [] 4294967295"#]], - ); -} - -#[test] -fn test_fn_like_macro_clone_ident_subtree() { - assert_expand( - "fn_like_clone_tokens", - r#"ident, []"#, - expect![[r#" - SUBTREE $ - IDENT ident 4294967295 - PUNCH , [alone] 4294967295 - SUBTREE [] 4294967295"#]], - ); -} - -#[test] -fn test_fn_like_macro_clone_raw_ident() { - assert_expand( - "fn_like_clone_tokens", - "r#async", - expect![[r#" - SUBTREE $ - IDENT async 4294967295"#]], - ); -} - -#[test] -fn test_fn_like_mk_literals() { - assert_expand( - "fn_like_mk_literals", - r#""#, - expect![[r#" - SUBTREE $ - LITERAL b"byte_string" 4294967295 - LITERAL 'c' 4294967295 - LITERAL "string" 4294967295 - LITERAL 3.14f64 4294967295 - LITERAL 3.14 4294967295 - LITERAL 123i64 4294967295 - LITERAL 123 4294967295"#]], - ); -} - -#[test] -fn test_fn_like_mk_idents() { - // FIXME: this test is wrong: raw should be 'r#raw' but ABIs 1.64 and below - // simply ignore `is_raw` when implementing the `Ident` interface. - assert_expand( - "fn_like_mk_idents", - r#""#, - expect![[r#" - SUBTREE $ - IDENT standard 4294967295 - IDENT raw 4294967295"#]], - ); -} - -#[test] -fn test_fn_like_macro_clone_literals() { - assert_expand( - "fn_like_clone_tokens", - r#"1u16, 2_u32, -4i64, 3.14f32, "hello bridge""#, - expect![[r#" - SUBTREE $ - LITERAL 1u16 4294967295 - PUNCH , [alone] 4294967295 - LITERAL 2_u32 4294967295 - PUNCH , [alone] 4294967295 - PUNCH - [alone] 4294967295 - LITERAL 4i64 4294967295 - PUNCH , [alone] 4294967295 - LITERAL 3.14f32 4294967295 - PUNCH , [alone] 4294967295 - LITERAL "hello bridge" 4294967295"#]], - ); -} - -#[test] -fn test_attr_macro() { - // Corresponds to - // #[proc_macro_test::attr_error(some arguments)] - // mod m {} - assert_expand_attr( - "attr_error", - r#"mod m {}"#, - r#"some arguments"#, - expect![[r##" - SUBTREE $ - IDENT compile_error 4294967295 - PUNCH ! [alone] 4294967295 - SUBTREE () 4294967295 - LITERAL "#[attr_error(some arguments)] mod m {}" 4294967295 - PUNCH ; [alone] 4294967295"##]], - ); -} - -/// Tests that we find and classify all proc macros correctly. -#[test] -fn list_test_macros() { - let res = list().join("\n"); - - expect![[r#" - fn_like_noop [FuncLike] - fn_like_panic [FuncLike] - fn_like_error [FuncLike] - fn_like_clone_tokens [FuncLike] - fn_like_mk_literals [FuncLike] - fn_like_mk_idents [FuncLike] - attr_noop [Attr] - attr_panic [Attr] - attr_error [Attr] - DeriveEmpty [CustomDerive] - DerivePanic [CustomDerive] - DeriveError [CustomDerive]"#]] - .assert_eq(&res); -} - -#[test] -fn test_version_check() { - let path = AbsPathBuf::assert(fixtures::proc_macro_test_dylib_path()); - let info = proc_macro_api::read_dylib_info(&path).unwrap(); - assert!(info.version.1 >= 50); -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs deleted file mode 100644 index f881fe86847d6..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! utils used in proc-macro tests - -use crate::dylib; -use crate::ProcMacroSrv; -use expect_test::Expect; -use std::str::FromStr; - -pub mod fixtures { - pub fn proc_macro_test_dylib_path() -> std::path::PathBuf { - proc_macro_test::PROC_MACRO_TEST_LOCATION.into() - } -} - -fn parse_string(code: &str) -> Option { - // This is a bit strange. We need to parse a string into a token stream into - // order to create a tt::SubTree from it in fixtures. `into_subtree` is - // implemented by all the ABIs we have so we arbitrarily choose one ABI to - // write a `parse_string` function for and use that. The tests don't really - // care which ABI we're using as the `into_subtree` function isn't part of - // the ABI and shouldn't change between ABI versions. - crate::abis::TestTokenStream::from_str(code).ok() -} - -pub fn assert_expand(macro_name: &str, ra_fixture: &str, expect: Expect) { - assert_expand_impl(macro_name, ra_fixture, None, expect); -} - -pub fn assert_expand_attr(macro_name: &str, ra_fixture: &str, attr_args: &str, expect: Expect) { - assert_expand_impl(macro_name, ra_fixture, Some(attr_args), expect); -} - -fn assert_expand_impl(macro_name: &str, input: &str, attr: Option<&str>, expect: Expect) { - let path = fixtures::proc_macro_test_dylib_path(); - let expander = dylib::Expander::new(&path).unwrap(); - let fixture = parse_string(input).unwrap(); - let attr = attr.map(|attr| parse_string(attr).unwrap().into_subtree()); - - let res = expander.expand(macro_name, &fixture.into_subtree(), attr.as_ref()).unwrap(); - expect.assert_eq(&format!("{:?}", res)); -} - -pub(crate) fn list() -> Vec { - let dylib_path = fixtures::proc_macro_test_dylib_path(); - let mut srv = ProcMacroSrv::default(); - let res = srv.list_macros(&dylib_path).unwrap(); - res.into_iter().map(|(name, kind)| format!("{} [{:?}]", name, kind)).collect() -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-test/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-test/Cargo.toml deleted file mode 100644 index 684477191b276..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-test/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "proc-macro-test" -version = "0.0.0" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" -publish = false - -[lib] -doctest = false - -[build-dependencies] -proc-macro-test-impl = { path = "imp", version = "0.0.0" } -toolchain = { path = "../toolchain", version = "0.0.0" } -cargo_metadata = "0.15.0" diff --git a/src/tools/rust-analyzer/crates/proc-macro-test/build.rs b/src/tools/rust-analyzer/crates/proc-macro-test/build.rs deleted file mode 100644 index a80c962617bb3..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-test/build.rs +++ /dev/null @@ -1,106 +0,0 @@ -//! This will build the proc macro in `imp`, and copy the resulting dylib artifact into the -//! `OUT_DIR`. -//! -//! `proc-macro-test` itself contains only a path to that artifact. -//! -//! The `PROC_MACRO_TEST_TOOLCHAIN` environment variable can be exported to use -//! a specific rustup toolchain: this allows testing against older ABIs (e.g. -//! 1.58) and future ABIs (stage1, nightly) - -use std::{ - env, fs, - path::{Path, PathBuf}, - process::Command, -}; - -use cargo_metadata::Message; - -fn main() { - println!("cargo:rerun-if-changed=imp"); - println!("cargo:rerun-if-env-changed=PROC_MACRO_TEST_TOOLCHAIN"); - - let out_dir = env::var_os("OUT_DIR").unwrap(); - let out_dir = Path::new(&out_dir); - - let name = "proc-macro-test-impl"; - let version = "0.0.0"; - - let imp_dir = std::env::current_dir().unwrap().join("imp"); - - let staging_dir = out_dir.join("proc-macro-test-imp-staging"); - // this'll error out if the staging dir didn't previously exist. using - // `std::fs::exists` would suffer from TOCTOU so just do our best to - // wipe it and ignore errors. - let _ = std::fs::remove_dir_all(&staging_dir); - - println!("Creating {}", staging_dir.display()); - std::fs::create_dir_all(&staging_dir).unwrap(); - - let src_dir = staging_dir.join("src"); - println!("Creating {}", src_dir.display()); - std::fs::create_dir_all(src_dir).unwrap(); - - for item_els in [&["Cargo.toml"][..], &["src", "lib.rs"]] { - let mut src = imp_dir.clone(); - let mut dst = staging_dir.clone(); - for el in item_els { - src.push(el); - dst.push(el); - } - println!("Copying {} to {}", src.display(), dst.display()); - std::fs::copy(src, dst).unwrap(); - } - - let target_dir = out_dir.join("target"); - - let mut cmd = if let Ok(toolchain) = std::env::var("PROC_MACRO_TEST_TOOLCHAIN") { - // leverage rustup to find user-specific toolchain - let mut cmd = Command::new("cargo"); - cmd.arg(format!("+{toolchain}")); - cmd - } else { - Command::new(toolchain::cargo()) - }; - - cmd.current_dir(&staging_dir) - .args(&["build", "-p", "proc-macro-test-impl", "--message-format", "json"]) - // Explicit override the target directory to avoid using the same one which the parent - // cargo is using, or we'll deadlock. - // This can happen when `CARGO_TARGET_DIR` is set or global config forces all cargo - // instance to use the same target directory. - .arg("--target-dir") - .arg(&target_dir); - - println!("Running {:?}", cmd); - - let output = cmd.output().unwrap(); - if !output.status.success() { - println!("proc-macro-test-impl failed to build"); - println!("============ stdout ============"); - println!("{}", String::from_utf8_lossy(&output.stdout)); - println!("============ stderr ============"); - println!("{}", String::from_utf8_lossy(&output.stderr)); - panic!("proc-macro-test-impl failed to build"); - } - - let mut artifact_path = None; - for message in Message::parse_stream(output.stdout.as_slice()) { - match message.unwrap() { - Message::CompilerArtifact(artifact) => { - if artifact.target.kind.contains(&"proc-macro".to_string()) { - let repr = format!("{} {}", name, version); - if artifact.package_id.repr.starts_with(&repr) { - artifact_path = Some(PathBuf::from(&artifact.filenames[0])); - } - } - } - _ => (), // Unknown message - } - } - - // This file is under `target_dir` and is already under `OUT_DIR`. - let artifact_path = artifact_path.expect("no dylib for proc-macro-test-impl found"); - - let info_path = out_dir.join("proc_macro_test_location.txt"); - fs::write(info_path, artifact_path.to_str().unwrap()).unwrap(); -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-test/imp/.gitignore b/src/tools/rust-analyzer/crates/proc-macro-test/imp/.gitignore deleted file mode 100644 index 2c96eb1b6517f..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-test/imp/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target/ -Cargo.lock diff --git a/src/tools/rust-analyzer/crates/proc-macro-test/imp/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-test/imp/Cargo.toml deleted file mode 100644 index 2d1fc3c5c7a3b..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-test/imp/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "proc-macro-test-impl" -version = "0.0.0" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" -publish = false - -[lib] -doctest = false -proc-macro = true - -[workspace] - -[dependencies] -# this crate should not have any dependencies, since it uses its own workspace, -# and its own `Cargo.lock` diff --git a/src/tools/rust-analyzer/crates/proc-macro-test/imp/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-test/imp/src/lib.rs deleted file mode 100644 index feeacdb6407af..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-test/imp/src/lib.rs +++ /dev/null @@ -1,114 +0,0 @@ -//! Exports a few trivial procedural macros for testing. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree}; - -#[proc_macro] -pub fn fn_like_noop(args: TokenStream) -> TokenStream { - args -} - -#[proc_macro] -pub fn fn_like_panic(args: TokenStream) -> TokenStream { - panic!("fn_like_panic!({})", args); -} - -#[proc_macro] -pub fn fn_like_error(args: TokenStream) -> TokenStream { - format!("compile_error!(\"fn_like_error!({})\");", args).parse().unwrap() -} - -#[proc_macro] -pub fn fn_like_clone_tokens(args: TokenStream) -> TokenStream { - clone_stream(args) -} - -#[proc_macro] -pub fn fn_like_mk_literals(_args: TokenStream) -> TokenStream { - let trees: Vec = vec![ - TokenTree::from(Literal::byte_string(b"byte_string")), - TokenTree::from(Literal::character('c')), - TokenTree::from(Literal::string("string")), - // as of 2022-07-21, there's no method on `Literal` to build a raw - // string or a raw byte string - TokenTree::from(Literal::f64_suffixed(3.14)), - TokenTree::from(Literal::f64_unsuffixed(3.14)), - TokenTree::from(Literal::i64_suffixed(123)), - TokenTree::from(Literal::i64_unsuffixed(123)), - ]; - TokenStream::from_iter(trees) -} - -#[proc_macro] -pub fn fn_like_mk_idents(_args: TokenStream) -> TokenStream { - let trees: Vec = vec![ - TokenTree::from(Ident::new("standard", Span::call_site())), - TokenTree::from(Ident::new_raw("raw", Span::call_site())), - ]; - TokenStream::from_iter(trees) -} - -#[proc_macro_attribute] -pub fn attr_noop(_args: TokenStream, item: TokenStream) -> TokenStream { - item -} - -#[proc_macro_attribute] -pub fn attr_panic(args: TokenStream, item: TokenStream) -> TokenStream { - panic!("#[attr_panic {}] {}", args, item); -} - -#[proc_macro_attribute] -pub fn attr_error(args: TokenStream, item: TokenStream) -> TokenStream { - format!("compile_error!(\"#[attr_error({})] {}\");", args, item).parse().unwrap() -} - -#[proc_macro_derive(DeriveEmpty)] -pub fn derive_empty(_item: TokenStream) -> TokenStream { - TokenStream::new() -} - -#[proc_macro_derive(DerivePanic)] -pub fn derive_panic(item: TokenStream) -> TokenStream { - panic!("#[derive(DerivePanic)] {}", item); -} - -#[proc_macro_derive(DeriveError)] -pub fn derive_error(item: TokenStream) -> TokenStream { - format!("compile_error!(\"#[derive(DeriveError)] {}\");", item).parse().unwrap() -} - -fn clone_stream(ts: TokenStream) -> TokenStream { - ts.into_iter().map(clone_tree).collect() -} - -fn clone_tree(t: TokenTree) -> TokenTree { - match t { - TokenTree::Group(orig) => { - let mut new = Group::new(orig.delimiter(), clone_stream(orig.stream())); - new.set_span(orig.span()); - TokenTree::Group(new) - } - TokenTree::Ident(orig) => { - let s = orig.to_string(); - if let Some(rest) = s.strip_prefix("r#") { - TokenTree::Ident(Ident::new_raw(rest, orig.span())) - } else { - TokenTree::Ident(Ident::new(&s, orig.span())) - } - } - TokenTree::Punct(orig) => { - let mut new = Punct::new(orig.as_char(), orig.spacing()); - new.set_span(orig.span()); - TokenTree::Punct(new) - } - TokenTree::Literal(orig) => { - // this goes through `literal_from_str` as of 2022-07-18, cf. - // https://github.com/rust-lang/rust/commit/b34c79f8f1ef4d0149ad4bf77e1759c07a9a01a8 - let mut new: Literal = orig.to_string().parse().unwrap(); - new.set_span(orig.span()); - TokenTree::Literal(new) - } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-test/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-test/src/lib.rs deleted file mode 100644 index 6d57bc81e0e33..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-test/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! Exports a few trivial procedural macros for testing. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -pub static PROC_MACRO_TEST_LOCATION: &str = - include_str!(concat!(env!("OUT_DIR"), "/proc_macro_test_location.txt")); diff --git a/src/tools/rust-analyzer/crates/profile/Cargo.toml b/src/tools/rust-analyzer/crates/profile/Cargo.toml deleted file mode 100644 index 0b78a45a24b33..0000000000000 --- a/src/tools/rust-analyzer/crates/profile/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "profile" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -once_cell = "1.12.0" -cfg-if = "1.0.0" -libc = "0.2.126" -la-arena = { version = "0.3.0", path = "../../lib/la-arena" } -countme = { version = "3.0.1", features = ["enable"] } -jemalloc-ctl = { version = "0.5.0", package = "tikv-jemalloc-ctl", optional = true } - -[target.'cfg(target_os = "linux")'.dependencies] -perf-event = "0.4.7" - -[target.'cfg(windows)'.dependencies] -winapi = { version = "0.3.9", features = ["processthreadsapi", "psapi"] } - -[features] -cpu_profiler = [] -jemalloc = ["jemalloc-ctl"] - -# Uncomment to enable for the whole crate graph -# default = [ "cpu_profiler" ] diff --git a/src/tools/rust-analyzer/crates/profile/src/google_cpu_profiler.rs b/src/tools/rust-analyzer/crates/profile/src/google_cpu_profiler.rs deleted file mode 100644 index cae6caeaa669c..0000000000000 --- a/src/tools/rust-analyzer/crates/profile/src/google_cpu_profiler.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! https://github.com/gperftools/gperftools - -use std::{ - ffi::CString, - os::raw::c_char, - path::Path, - sync::atomic::{AtomicUsize, Ordering}, -}; - -#[link(name = "profiler")] -#[allow(non_snake_case)] -extern "C" { - fn ProfilerStart(fname: *const c_char) -> i32; - fn ProfilerStop(); -} - -const OFF: usize = 0; -const ON: usize = 1; -const PENDING: usize = 2; - -fn transition(current: usize, new: usize) -> bool { - static STATE: AtomicUsize = AtomicUsize::new(OFF); - - STATE.compare_exchange(current, new, Ordering::SeqCst, Ordering::SeqCst).is_ok() -} - -pub(crate) fn start(path: &Path) { - if !transition(OFF, PENDING) { - panic!("profiler already started"); - } - let path = CString::new(path.display().to_string()).unwrap(); - if unsafe { ProfilerStart(path.as_ptr()) } == 0 { - panic!("profiler failed to start") - } - assert!(transition(PENDING, ON)); -} - -pub(crate) fn stop() { - if !transition(ON, PENDING) { - panic!("profiler is not started") - } - unsafe { ProfilerStop() }; - assert!(transition(PENDING, OFF)); -} diff --git a/src/tools/rust-analyzer/crates/profile/src/hprof.rs b/src/tools/rust-analyzer/crates/profile/src/hprof.rs deleted file mode 100644 index b562c193e7137..0000000000000 --- a/src/tools/rust-analyzer/crates/profile/src/hprof.rs +++ /dev/null @@ -1,326 +0,0 @@ -//! Simple hierarchical profiler -use std::{ - cell::RefCell, - collections::{BTreeMap, HashSet}, - env, fmt, - io::{stderr, Write}, - sync::{ - atomic::{AtomicBool, Ordering}, - RwLock, - }, - time::{Duration, Instant}, -}; - -use once_cell::sync::Lazy; - -use crate::tree::{Idx, Tree}; - -/// Filtering syntax -/// env RA_PROFILE=* // dump everything -/// env RA_PROFILE=foo|bar|baz // enabled only selected entries -/// env RA_PROFILE=*@3>10 // dump everything, up to depth 3, if it takes more than 10 ms -pub fn init() { - countme::enable(env::var("RA_COUNT").is_ok()); - let spec = env::var("RA_PROFILE").unwrap_or_default(); - init_from(&spec); -} - -pub fn init_from(spec: &str) { - let filter = if spec.is_empty() { Filter::disabled() } else { Filter::from_spec(spec) }; - filter.install(); -} - -type Label = &'static str; - -/// This function starts a profiling scope in the current execution stack with a given description. -/// It returns a `Profile` struct that measures elapsed time between this method invocation and `Profile` struct drop. -/// It supports nested profiling scopes in case when this function is invoked multiple times at the execution stack. -/// In this case the profiling information will be nested at the output. -/// Profiling information is being printed in the stderr. -/// -/// # Example -/// ``` -/// profile::init_from("profile1|profile2@2"); -/// profiling_function1(); -/// -/// fn profiling_function1() { -/// let _p = profile::span("profile1"); -/// profiling_function2(); -/// } -/// -/// fn profiling_function2() { -/// let _p = profile::span("profile2"); -/// } -/// ``` -/// This will print in the stderr the following: -/// ```text -/// 0ms - profile -/// 0ms - profile2 -/// ``` -#[inline] -pub fn span(label: Label) -> ProfileSpan { - debug_assert!(!label.is_empty()); - - let enabled = PROFILING_ENABLED.load(Ordering::Relaxed); - if enabled && with_profile_stack(|stack| stack.push(label)) { - ProfileSpan(Some(ProfilerImpl { label, detail: None })) - } else { - ProfileSpan(None) - } -} - -#[inline] -pub fn heartbeat_span() -> HeartbeatSpan { - let enabled = PROFILING_ENABLED.load(Ordering::Relaxed); - HeartbeatSpan::new(enabled) -} - -#[inline] -pub fn heartbeat() { - let enabled = PROFILING_ENABLED.load(Ordering::Relaxed); - if enabled { - with_profile_stack(|it| it.heartbeat(1)); - } -} - -pub struct ProfileSpan(Option); - -struct ProfilerImpl { - label: Label, - detail: Option, -} - -impl ProfileSpan { - pub fn detail(mut self, detail: impl FnOnce() -> String) -> ProfileSpan { - if let Some(profiler) = &mut self.0 { - profiler.detail = Some(detail()); - } - self - } -} - -impl Drop for ProfilerImpl { - #[inline] - fn drop(&mut self) { - with_profile_stack(|it| it.pop(self.label, self.detail.take())); - } -} - -pub struct HeartbeatSpan { - enabled: bool, -} - -impl HeartbeatSpan { - #[inline] - pub fn new(enabled: bool) -> Self { - if enabled { - with_profile_stack(|it| it.heartbeats(true)); - } - Self { enabled } - } -} - -impl Drop for HeartbeatSpan { - fn drop(&mut self) { - if self.enabled { - with_profile_stack(|it| it.heartbeats(false)); - } - } -} - -static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false); -static FILTER: Lazy> = Lazy::new(Default::default); - -fn with_profile_stack(f: impl FnOnce(&mut ProfileStack) -> T) -> T { - thread_local!(static STACK: RefCell = RefCell::new(ProfileStack::new())); - STACK.with(|it| f(&mut *it.borrow_mut())) -} - -#[derive(Default, Clone, Debug)] -struct Filter { - depth: usize, - allowed: HashSet, - longer_than: Duration, - heartbeat_longer_than: Duration, - version: usize, -} - -impl Filter { - fn disabled() -> Filter { - Filter::default() - } - - fn from_spec(mut spec: &str) -> Filter { - let longer_than = if let Some(idx) = spec.rfind('>') { - let longer_than = spec[idx + 1..].parse().expect("invalid profile longer_than"); - spec = &spec[..idx]; - Duration::from_millis(longer_than) - } else { - Duration::new(0, 0) - }; - let heartbeat_longer_than = longer_than; - - let depth = if let Some(idx) = spec.rfind('@') { - let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth"); - spec = &spec[..idx]; - depth - } else { - 999 - }; - let allowed = - if spec == "*" { HashSet::new() } else { spec.split('|').map(String::from).collect() }; - Filter { depth, allowed, longer_than, heartbeat_longer_than, version: 0 } - } - - fn install(mut self) { - PROFILING_ENABLED.store(self.depth > 0, Ordering::SeqCst); - let mut old = FILTER.write().unwrap(); - self.version = old.version + 1; - *old = self; - } -} - -struct ProfileStack { - frames: Vec, - filter: Filter, - messages: Tree, - heartbeats: bool, -} - -struct Frame { - t: Instant, - heartbeats: u32, -} - -#[derive(Default)] -struct Message { - duration: Duration, - label: Label, - detail: Option, -} - -impl ProfileStack { - fn new() -> ProfileStack { - ProfileStack { - frames: Vec::new(), - messages: Tree::default(), - filter: Default::default(), - heartbeats: false, - } - } - - fn push(&mut self, label: Label) -> bool { - if self.frames.is_empty() { - if let Ok(f) = FILTER.try_read() { - if f.version > self.filter.version { - self.filter = f.clone(); - } - }; - } - if self.frames.len() > self.filter.depth { - return false; - } - let allowed = &self.filter.allowed; - if self.frames.is_empty() && !allowed.is_empty() && !allowed.contains(label) { - return false; - } - - self.frames.push(Frame { t: Instant::now(), heartbeats: 0 }); - self.messages.start(); - true - } - - fn pop(&mut self, label: Label, detail: Option) { - let frame = self.frames.pop().unwrap(); - let duration = frame.t.elapsed(); - - if self.heartbeats { - self.heartbeat(frame.heartbeats); - let avg_span = duration / (frame.heartbeats + 1); - if avg_span > self.filter.heartbeat_longer_than { - eprintln!("Too few heartbeats {} ({}/{:?})?", label, frame.heartbeats, duration); - } - } - - self.messages.finish(Message { duration, label, detail }); - if self.frames.is_empty() { - let longer_than = self.filter.longer_than; - // Convert to millis for comparison to avoid problems with rounding - // (otherwise we could print `0ms` despite user's `>0` filter when - // `duration` is just a few nanos). - if duration.as_millis() > longer_than.as_millis() { - if let Some(root) = self.messages.root() { - print(&self.messages, root, 0, longer_than, &mut stderr().lock()); - } - } - self.messages.clear(); - } - } - - fn heartbeats(&mut self, yes: bool) { - self.heartbeats = yes; - } - fn heartbeat(&mut self, n: u32) { - if let Some(frame) = self.frames.last_mut() { - frame.heartbeats += n; - } - } -} - -fn print( - tree: &Tree, - curr: Idx, - level: u32, - longer_than: Duration, - out: &mut impl Write, -) { - let current_indent = " ".repeat(level as usize); - let detail = tree[curr].detail.as_ref().map(|it| format!(" @ {}", it)).unwrap_or_default(); - writeln!( - out, - "{}{} - {}{}", - current_indent, - ms(tree[curr].duration), - tree[curr].label, - detail, - ) - .expect("printing profiling info"); - - let mut accounted_for = Duration::default(); - let mut short_children = BTreeMap::new(); // Use `BTreeMap` to get deterministic output. - for child in tree.children(curr) { - accounted_for += tree[child].duration; - - if tree[child].duration.as_millis() > longer_than.as_millis() { - print(tree, child, level + 1, longer_than, out); - } else { - let (total_duration, cnt) = - short_children.entry(tree[child].label).or_insert((Duration::default(), 0)); - *total_duration += tree[child].duration; - *cnt += 1; - } - } - - for (child_msg, (duration, count)) in &short_children { - writeln!(out, " {}{} - {} ({} calls)", current_indent, ms(*duration), child_msg, count) - .expect("printing profiling info"); - } - - let unaccounted = tree[curr].duration - accounted_for; - if tree.children(curr).next().is_some() && unaccounted > longer_than { - writeln!(out, " {}{} - ???", current_indent, ms(unaccounted)) - .expect("printing profiling info"); - } -} - -#[allow(non_camel_case_types)] -struct ms(Duration); - -impl fmt::Display for ms { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0.as_millis() { - 0 => f.write_str(" 0 "), - n => write!(f, "{:5}ms", n), - } - } -} diff --git a/src/tools/rust-analyzer/crates/profile/src/lib.rs b/src/tools/rust-analyzer/crates/profile/src/lib.rs deleted file mode 100644 index 00f7952e80725..0000000000000 --- a/src/tools/rust-analyzer/crates/profile/src/lib.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! A collection of tools for profiling rust-analyzer. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -mod stop_watch; -mod memory_usage; -#[cfg(feature = "cpu_profiler")] -mod google_cpu_profiler; -mod hprof; -mod tree; - -use std::cell::RefCell; - -pub use crate::{ - hprof::{heartbeat, heartbeat_span, init, init_from, span}, - memory_usage::{Bytes, MemoryUsage}, - stop_watch::{StopWatch, StopWatchSpan}, -}; - -pub use countme; -/// Include `_c: Count` field in important structs to count them. -/// -/// To view the counts, run with `RA_COUNT=1`. The overhead of disabled count is -/// almost zero. -pub use countme::Count; - -thread_local!(static IN_SCOPE: RefCell = RefCell::new(false)); - -/// Allows to check if the current code is withing some dynamic scope, can be -/// useful during debugging to figure out why a function is called. -pub struct Scope { - prev: bool, -} - -impl Scope { - #[must_use] - pub fn enter() -> Scope { - let prev = IN_SCOPE.with(|slot| std::mem::replace(&mut *slot.borrow_mut(), true)); - Scope { prev } - } - pub fn is_active() -> bool { - IN_SCOPE.with(|slot| *slot.borrow()) - } -} - -impl Drop for Scope { - fn drop(&mut self) { - IN_SCOPE.with(|slot| *slot.borrow_mut() = self.prev); - } -} - -/// A wrapper around google_cpu_profiler. -/// -/// Usage: -/// 1. Install gpref_tools (), probably packaged with your Linux distro. -/// 2. Build with `cpu_profiler` feature. -/// 3. Run the code, the *raw* output would be in the `./out.profile` file. -/// 4. Install pprof for visualization (). -/// 5. Bump sampling frequency to once per ms: `export CPUPROFILE_FREQUENCY=1000` -/// 6. Use something like `pprof -svg target/release/rust-analyzer ./out.profile` to see the results. -/// -/// For example, here's how I run profiling on NixOS: -/// -/// ```bash -/// $ bat -p shell.nix -/// with import {}; -/// mkShell { -/// buildInputs = [ gperftools ]; -/// shellHook = '' -/// export LD_LIBRARY_PATH="${gperftools}/lib:" -/// ''; -/// } -/// $ set -x CPUPROFILE_FREQUENCY 1000 -/// $ nix-shell --run 'cargo test --release --package rust-analyzer --lib -- benchmarks::benchmark_integrated_highlighting --exact --nocapture' -/// $ pprof -svg target/release/deps/rust_analyzer-8739592dc93d63cb crates/rust-analyzer/out.profile > profile.svg -/// ``` -/// -/// See this diff for how to profile completions: -/// -/// -#[derive(Debug)] -pub struct CpuSpan { - _private: (), -} - -#[must_use] -pub fn cpu_span() -> CpuSpan { - #[cfg(feature = "cpu_profiler")] - { - google_cpu_profiler::start("./out.profile".as_ref()) - } - - #[cfg(not(feature = "cpu_profiler"))] - { - eprintln!( - r#"cpu profiling is disabled, uncomment `default = [ "cpu_profiler" ]` in Cargo.toml to enable."# - ); - } - - CpuSpan { _private: () } -} - -impl Drop for CpuSpan { - fn drop(&mut self) { - #[cfg(feature = "cpu_profiler")] - { - google_cpu_profiler::stop(); - let profile_data = std::env::current_dir().unwrap().join("out.profile"); - eprintln!("Profile data saved to:\n\n {}\n", profile_data.display()); - let mut cmd = std::process::Command::new("pprof"); - cmd.arg("-svg").arg(std::env::current_exe().unwrap()).arg(&profile_data); - let out = cmd.output(); - - match out { - Ok(out) if out.status.success() => { - let svg = profile_data.with_extension("svg"); - std::fs::write(&svg, &out.stdout).unwrap(); - eprintln!("Profile rendered to:\n\n {}\n", svg.display()); - } - _ => { - eprintln!("Failed to run:\n\n {:?}\n", cmd); - } - } - } - } -} - -pub fn memory_usage() -> MemoryUsage { - MemoryUsage::now() -} diff --git a/src/tools/rust-analyzer/crates/profile/src/memory_usage.rs b/src/tools/rust-analyzer/crates/profile/src/memory_usage.rs deleted file mode 100644 index ee882b4cb4c68..0000000000000 --- a/src/tools/rust-analyzer/crates/profile/src/memory_usage.rs +++ /dev/null @@ -1,127 +0,0 @@ -//! Like [`std::time::Instant`], but for memory. -//! -//! Measures the total size of all currently allocated objects. -use std::fmt; - -use cfg_if::cfg_if; - -#[derive(Copy, Clone)] -pub struct MemoryUsage { - pub allocated: Bytes, -} - -impl fmt::Display for MemoryUsage { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.allocated.fmt(f) - } -} - -impl std::ops::Sub for MemoryUsage { - type Output = MemoryUsage; - fn sub(self, rhs: MemoryUsage) -> MemoryUsage { - MemoryUsage { allocated: self.allocated - rhs.allocated } - } -} - -impl MemoryUsage { - pub fn now() -> MemoryUsage { - cfg_if! { - if #[cfg(all(feature = "jemalloc", not(target_env = "msvc")))] { - jemalloc_ctl::epoch::advance().unwrap(); - MemoryUsage { - allocated: Bytes(jemalloc_ctl::stats::allocated::read().unwrap() as isize), - } - } else if #[cfg(all(target_os = "linux", target_env = "gnu"))] { - memusage_linux() - } else if #[cfg(windows)] { - // There doesn't seem to be an API for determining heap usage, so we try to - // approximate that by using the Commit Charge value. - - use winapi::um::processthreadsapi::*; - use winapi::um::psapi::*; - use std::mem::{MaybeUninit, size_of}; - - let proc = unsafe { GetCurrentProcess() }; - let mut mem_counters = MaybeUninit::uninit(); - let cb = size_of::(); - let ret = unsafe { GetProcessMemoryInfo(proc, mem_counters.as_mut_ptr(), cb as u32) }; - assert!(ret != 0); - - let usage = unsafe { mem_counters.assume_init().PagefileUsage }; - MemoryUsage { allocated: Bytes(usage as isize) } - } else { - MemoryUsage { allocated: Bytes(0) } - } - } - } -} - -#[cfg(all(target_os = "linux", target_env = "gnu", not(feature = "jemalloc")))] -fn memusage_linux() -> MemoryUsage { - // Linux/glibc has 2 APIs for allocator introspection that we can use: mallinfo and mallinfo2. - // mallinfo uses `int` fields and cannot handle memory usage exceeding 2 GB. - // mallinfo2 is very recent, so its presence needs to be detected at runtime. - // Both are abysmally slow. - - use std::ffi::CStr; - use std::sync::atomic::{AtomicUsize, Ordering}; - - static MALLINFO2: AtomicUsize = AtomicUsize::new(1); - - let mut mallinfo2 = MALLINFO2.load(Ordering::Relaxed); - if mallinfo2 == 1 { - let cstr = CStr::from_bytes_with_nul(b"mallinfo2\0").unwrap(); - mallinfo2 = unsafe { libc::dlsym(libc::RTLD_DEFAULT, cstr.as_ptr()) } as usize; - // NB: races don't matter here, since they'll always store the same value - MALLINFO2.store(mallinfo2, Ordering::Relaxed); - } - - if mallinfo2 == 0 { - // mallinfo2 does not exist, use mallinfo. - let alloc = unsafe { libc::mallinfo() }.uordblks as isize; - MemoryUsage { allocated: Bytes(alloc) } - } else { - let mallinfo2: fn() -> libc::mallinfo2 = unsafe { std::mem::transmute(mallinfo2) }; - let alloc = mallinfo2().uordblks as isize; - MemoryUsage { allocated: Bytes(alloc) } - } -} - -#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] -pub struct Bytes(isize); - -impl Bytes { - pub fn megabytes(self) -> isize { - self.0 / 1024 / 1024 - } -} - -impl fmt::Display for Bytes { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let bytes = self.0; - let mut value = bytes; - let mut suffix = "b"; - if value.abs() > 4096 { - value /= 1024; - suffix = "kb"; - if value.abs() > 4096 { - value /= 1024; - suffix = "mb"; - } - } - f.pad(&format!("{}{}", value, suffix)) - } -} - -impl std::ops::AddAssign for Bytes { - fn add_assign(&mut self, x: usize) { - self.0 += x as isize; - } -} - -impl std::ops::Sub for Bytes { - type Output = Bytes; - fn sub(self, rhs: Bytes) -> Bytes { - Bytes(self.0 - rhs.0) - } -} diff --git a/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs b/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs deleted file mode 100644 index 6258328482962..0000000000000 --- a/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Like `std::time::Instant`, but also measures memory & CPU cycles. -use std::{ - fmt, - time::{Duration, Instant}, -}; - -use crate::MemoryUsage; - -pub struct StopWatch { - time: Instant, - #[cfg(target_os = "linux")] - counter: Option, - memory: Option, -} - -pub struct StopWatchSpan { - pub time: Duration, - pub instructions: Option, - pub memory: Option, -} - -impl StopWatch { - pub fn start() -> StopWatch { - #[cfg(target_os = "linux")] - let counter = { - // When debugging rust-analyzer using rr, the perf-related syscalls cause it to abort. - // We allow disabling perf by setting the env var `RA_DISABLE_PERF`. - - use once_cell::sync::Lazy; - static PERF_ENABLED: Lazy = - Lazy::new(|| std::env::var_os("RA_DISABLE_PERF").is_none()); - - if *PERF_ENABLED { - let mut counter = perf_event::Builder::new() - .build() - .map_err(|err| eprintln!("Failed to create perf counter: {}", err)) - .ok(); - if let Some(counter) = &mut counter { - if let Err(err) = counter.enable() { - eprintln!("Failed to start perf counter: {}", err) - } - } - counter - } else { - None - } - }; - let time = Instant::now(); - StopWatch { - time, - #[cfg(target_os = "linux")] - counter, - memory: None, - } - } - pub fn memory(mut self, yes: bool) -> StopWatch { - if yes { - self.memory = Some(MemoryUsage::now()); - } - self - } - pub fn elapsed(&mut self) -> StopWatchSpan { - let time = self.time.elapsed(); - - #[cfg(target_os = "linux")] - let instructions = self.counter.as_mut().and_then(|it| { - it.read().map_err(|err| eprintln!("Failed to read perf counter: {}", err)).ok() - }); - #[cfg(not(target_os = "linux"))] - let instructions = None; - - let memory = self.memory.map(|it| MemoryUsage::now() - it); - StopWatchSpan { time, instructions, memory } - } -} - -impl fmt::Display for StopWatchSpan { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:.2?}", self.time)?; - if let Some(mut instructions) = self.instructions { - let mut prefix = ""; - if instructions > 10000 { - instructions /= 1000; - prefix = "k"; - } - if instructions > 10000 { - instructions /= 1000; - prefix = "m"; - } - if instructions > 10000 { - instructions /= 1000; - prefix = "g"; - } - write!(f, ", {}{}instr", instructions, prefix)?; - } - if let Some(memory) = self.memory { - write!(f, ", {}", memory)?; - } - Ok(()) - } -} diff --git a/src/tools/rust-analyzer/crates/profile/src/tree.rs b/src/tools/rust-analyzer/crates/profile/src/tree.rs deleted file mode 100644 index 62f0c30b52939..0000000000000 --- a/src/tools/rust-analyzer/crates/profile/src/tree.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! A simple tree implementation which tries to not allocate all over the place. -use std::ops; - -use la_arena::Arena; - -#[derive(Default)] -pub(crate) struct Tree { - nodes: Arena>, - current_path: Vec<(Idx, Option>)>, -} - -pub(crate) type Idx = la_arena::Idx>; - -impl Tree { - pub(crate) fn start(&mut self) - where - T: Default, - { - let me = self.nodes.alloc(Node::new(T::default())); - if let Some((parent, last_child)) = self.current_path.last_mut() { - let slot = match *last_child { - Some(last_child) => &mut self.nodes[last_child].next_sibling, - None => &mut self.nodes[*parent].first_child, - }; - let prev = slot.replace(me); - assert!(prev.is_none()); - *last_child = Some(me); - } - - self.current_path.push((me, None)); - } - - pub(crate) fn finish(&mut self, data: T) { - let (me, _last_child) = self.current_path.pop().unwrap(); - self.nodes[me].data = data; - } - - pub(crate) fn root(&self) -> Option> { - self.nodes.iter().next().map(|(idx, _)| idx) - } - - pub(crate) fn children(&self, idx: Idx) -> impl Iterator> + '_ { - NodeIter { nodes: &self.nodes, next: self.nodes[idx].first_child } - } - pub(crate) fn clear(&mut self) { - self.nodes.clear(); - self.current_path.clear(); - } -} - -impl ops::Index> for Tree { - type Output = T; - fn index(&self, index: Idx) -> &T { - &self.nodes[index].data - } -} - -pub(crate) struct Node { - data: T, - first_child: Option>, - next_sibling: Option>, -} - -impl Node { - fn new(data: T) -> Node { - Node { data, first_child: None, next_sibling: None } - } -} - -struct NodeIter<'a, T> { - nodes: &'a Arena>, - next: Option>, -} - -impl<'a, T> Iterator for NodeIter<'a, T> { - type Item = Idx; - - fn next(&mut self) -> Option> { - self.next.map(|next| { - self.next = self.nodes[next].next_sibling; - next - }) - } -} diff --git a/src/tools/rust-analyzer/crates/project-model/Cargo.toml b/src/tools/rust-analyzer/crates/project-model/Cargo.toml deleted file mode 100644 index bc75d6faa383f..0000000000000 --- a/src/tools/rust-analyzer/crates/project-model/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "project-model" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -tracing = "0.1.35" -rustc-hash = "1.1.0" -cargo_metadata = "0.15.0" -semver = "1.0.10" -serde = { version = "1.0.137", features = ["derive"] } -serde_json = "1.0.81" -anyhow = "1.0.57" -expect-test = "1.4.0" -la-arena = { version = "0.3.0", path = "../../lib/la-arena" } - -cfg = { path = "../cfg", version = "0.0.0" } -base-db = { path = "../base-db", version = "0.0.0" } -toolchain = { path = "../toolchain", version = "0.0.0" } -paths = { path = "../paths", version = "0.0.0" } -stdx = { path = "../stdx", version = "0.0.0" } -profile = { path = "../profile", version = "0.0.0" } diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs deleted file mode 100644 index ee7f8339a76a1..0000000000000 --- a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs +++ /dev/null @@ -1,238 +0,0 @@ -//! Workspace information we get from cargo consists of two pieces. The first is -//! the output of `cargo metadata`. The second is the output of running -//! `build.rs` files (`OUT_DIR` env var, extra cfg flags) and compiling proc -//! macro. -//! -//! This module implements this second part. We use "build script" terminology -//! here, but it covers procedural macros as well. - -use std::{cell::RefCell, io, path::PathBuf, process::Command}; - -use cargo_metadata::{camino::Utf8Path, Message}; -use la_arena::ArenaMap; -use paths::AbsPathBuf; -use rustc_hash::FxHashMap; -use serde::Deserialize; - -use crate::{cfg_flag::CfgFlag, CargoConfig, CargoWorkspace, Package}; - -#[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct WorkspaceBuildScripts { - outputs: ArenaMap>, - error: Option, -} - -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub(crate) struct BuildScriptOutput { - /// List of config flags defined by this package's build script. - pub(crate) cfgs: Vec, - /// List of cargo-related environment variables with their value. - /// - /// If the package has a build script which defines environment variables, - /// they can also be found here. - pub(crate) envs: Vec<(String, String)>, - /// Directory where a build script might place its output. - pub(crate) out_dir: Option, - /// Path to the proc-macro library file if this package exposes proc-macros. - pub(crate) proc_macro_dylib_path: Option, -} - -impl WorkspaceBuildScripts { - fn build_command(config: &CargoConfig) -> Command { - if let Some([program, args @ ..]) = config.run_build_script_command.as_deref() { - let mut cmd = Command::new(program); - cmd.args(args); - return cmd; - } - - let mut cmd = Command::new(toolchain::cargo()); - - cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]); - - // --all-targets includes tests, benches and examples in addition to the - // default lib and bins. This is an independent concept from the --targets - // flag below. - cmd.arg("--all-targets"); - - if let Some(target) = &config.target { - cmd.args(&["--target", target]); - } - - if config.all_features { - cmd.arg("--all-features"); - } else { - if config.no_default_features { - cmd.arg("--no-default-features"); - } - if !config.features.is_empty() { - cmd.arg("--features"); - cmd.arg(config.features.join(" ")); - } - } - - cmd - } - - pub(crate) fn run( - config: &CargoConfig, - workspace: &CargoWorkspace, - progress: &dyn Fn(String), - ) -> io::Result { - let mut cmd = Self::build_command(config); - - if config.wrap_rustc_in_build_scripts { - // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use - // that to compile only proc macros and build scripts during the initial - // `cargo check`. - let myself = std::env::current_exe()?; - cmd.env("RUSTC_WRAPPER", myself); - cmd.env("RA_RUSTC_WRAPPER", "1"); - } - - cmd.current_dir(workspace.workspace_root()); - - let mut res = WorkspaceBuildScripts::default(); - let outputs = &mut res.outputs; - // NB: Cargo.toml could have been modified between `cargo metadata` and - // `cargo check`. We shouldn't assume that package ids we see here are - // exactly those from `config`. - let mut by_id: FxHashMap = FxHashMap::default(); - for package in workspace.packages() { - outputs.insert(package, None); - by_id.insert(workspace[package].id.clone(), package); - } - - let errors = RefCell::new(String::new()); - let push_err = |err: &str| { - let mut e = errors.borrow_mut(); - e.push_str(err); - e.push('\n'); - }; - - tracing::info!("Running build scripts: {:?}", cmd); - let output = stdx::process::spawn_with_streaming_output( - cmd, - &mut |line| { - // Copy-pasted from existing cargo_metadata. It seems like we - // should be using serde_stacker here? - let mut deserializer = serde_json::Deserializer::from_str(line); - deserializer.disable_recursion_limit(); - let message = Message::deserialize(&mut deserializer) - .unwrap_or_else(|_| Message::TextLine(line.to_string())); - - match message { - Message::BuildScriptExecuted(message) => { - let package = match by_id.get(&message.package_id.repr) { - Some(&it) => it, - None => return, - }; - let cfgs = { - let mut acc = Vec::new(); - for cfg in message.cfgs { - match cfg.parse::() { - Ok(it) => acc.push(it), - Err(err) => { - push_err(&format!( - "invalid cfg from cargo-metadata: {}", - err - )); - return; - } - }; - } - acc - }; - // cargo_metadata crate returns default (empty) path for - // older cargos, which is not absolute, so work around that. - let out_dir = message.out_dir.into_os_string(); - if !out_dir.is_empty() { - let data = outputs[package].get_or_insert_with(Default::default); - data.out_dir = Some(AbsPathBuf::assert(PathBuf::from(out_dir))); - data.cfgs = cfgs; - } - if !message.env.is_empty() { - outputs[package].get_or_insert_with(Default::default).envs = - message.env; - } - } - Message::CompilerArtifact(message) => { - let package = match by_id.get(&message.package_id.repr) { - Some(it) => *it, - None => return, - }; - - progress(format!("metadata {}", message.target.name)); - - if message.target.kind.iter().any(|k| k == "proc-macro") { - // Skip rmeta file - if let Some(filename) = - message.filenames.iter().find(|name| is_dylib(name)) - { - let filename = AbsPathBuf::assert(PathBuf::from(&filename)); - outputs[package] - .get_or_insert_with(Default::default) - .proc_macro_dylib_path = Some(filename); - } - } - } - Message::CompilerMessage(message) => { - progress(message.target.name); - - if let Some(diag) = message.message.rendered.as_deref() { - push_err(diag); - } - } - Message::BuildFinished(_) => {} - Message::TextLine(_) => {} - _ => {} - } - }, - &mut |line| { - push_err(line); - }, - )?; - - for package in workspace.packages() { - if let Some(package_build_data) = &mut outputs[package] { - tracing::info!( - "{}: {:?}", - workspace[package].manifest.parent().display(), - package_build_data, - ); - // inject_cargo_env(package, package_build_data); - if let Some(out_dir) = &package_build_data.out_dir { - // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!() - if let Some(out_dir) = out_dir.as_os_str().to_str().map(|s| s.to_owned()) { - package_build_data.envs.push(("OUT_DIR".to_string(), out_dir)); - } - } - } - } - - let mut errors = errors.into_inner(); - if !output.status.success() { - if errors.is_empty() { - errors = "cargo check failed".to_string(); - } - res.error = Some(errors); - } - - Ok(res) - } - - pub fn error(&self) -> Option<&str> { - self.error.as_deref() - } - - pub(crate) fn get_output(&self, idx: Package) -> Option<&BuildScriptOutput> { - self.outputs.get(idx)?.as_ref() - } -} - -// FIXME: File a better way to know if it is a dylib. -fn is_dylib(path: &Utf8Path) -> bool { - match path.extension().map(|e| e.to_string().to_lowercase()) { - None => false, - Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"), - } -} diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs deleted file mode 100644 index 597880c2ca214..0000000000000 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ /dev/null @@ -1,504 +0,0 @@ -//! See [`CargoWorkspace`]. - -use std::iter; -use std::path::PathBuf; -use std::{ops, process::Command}; - -use anyhow::{Context, Result}; -use base_db::Edition; -use cargo_metadata::{CargoOpt, MetadataCommand}; -use la_arena::{Arena, Idx}; -use paths::{AbsPath, AbsPathBuf}; -use rustc_hash::FxHashMap; -use serde::Deserialize; -use serde_json::from_value; - -use crate::CfgOverrides; -use crate::{utf8_stdout, ManifestPath}; - -/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo -/// workspace. It pretty closely mirrors `cargo metadata` output. -/// -/// Note that internally, rust analyzer uses a different structure: -/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, -/// while this knows about `Packages` & `Targets`: purely cargo-related -/// concepts. -/// -/// We use absolute paths here, `cargo metadata` guarantees to always produce -/// abs paths. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct CargoWorkspace { - packages: Arena, - targets: Arena, - workspace_root: AbsPathBuf, -} - -impl ops::Index for CargoWorkspace { - type Output = PackageData; - fn index(&self, index: Package) -> &PackageData { - &self.packages[index] - } -} - -impl ops::Index for CargoWorkspace { - type Output = TargetData; - fn index(&self, index: Target) -> &TargetData { - &self.targets[index] - } -} - -/// Describes how to set the rustc source directory. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum RustcSource { - /// Explicit path for the rustc source directory. - Path(AbsPathBuf), - /// Try to automatically detect where the rustc source directory is. - Discover, -} - -/// Crates to disable `#[cfg(test)]` on. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum UnsetTestCrates { - None, - Only(Vec), - All, -} - -impl Default for UnsetTestCrates { - fn default() -> Self { - Self::None - } -} - -#[derive(Default, Clone, Debug, PartialEq, Eq)] -pub struct CargoConfig { - /// Do not activate the `default` feature. - pub no_default_features: bool, - - /// Activate all available features - pub all_features: bool, - - /// List of features to activate. - /// This will be ignored if `cargo_all_features` is true. - pub features: Vec, - - /// rustc target - pub target: Option, - - /// Don't load sysroot crates (`std`, `core` & friends). Might be useful - /// when debugging isolated issues. - pub no_sysroot: bool, - - /// rustc private crate source - pub rustc_source: Option, - - /// crates to disable `#[cfg(test)]` on - pub unset_test_crates: UnsetTestCrates, - - pub wrap_rustc_in_build_scripts: bool, - - pub run_build_script_command: Option>, -} - -impl CargoConfig { - pub fn cfg_overrides(&self) -> CfgOverrides { - match &self.unset_test_crates { - UnsetTestCrates::None => CfgOverrides::Selective(iter::empty().collect()), - UnsetTestCrates::Only(unset_test_crates) => CfgOverrides::Selective( - unset_test_crates - .iter() - .cloned() - .zip(iter::repeat_with(|| { - cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())]) - .unwrap() - })) - .collect(), - ), - UnsetTestCrates::All => CfgOverrides::Wildcard( - cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())]).unwrap(), - ), - } - } -} - -pub type Package = Idx; - -pub type Target = Idx; - -/// Information associated with a cargo crate -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct PackageData { - /// Version given in the `Cargo.toml` - pub version: semver::Version, - /// Name as given in the `Cargo.toml` - pub name: String, - /// Repository as given in the `Cargo.toml` - pub repository: Option, - /// Path containing the `Cargo.toml` - pub manifest: ManifestPath, - /// Targets provided by the crate (lib, bin, example, test, ...) - pub targets: Vec, - /// Does this package come from the local filesystem (and is editable)? - pub is_local: bool, - // Whether this package is a member of the workspace - pub is_member: bool, - /// List of packages this package depends on - pub dependencies: Vec, - /// Rust edition for this package - pub edition: Edition, - /// Features provided by the crate, mapped to the features required by that feature. - pub features: FxHashMap>, - /// List of features enabled on this package - pub active_features: Vec, - /// String representation of package id - pub id: String, - /// The contents of [package.metadata.rust-analyzer] - pub metadata: RustAnalyzerPackageMetaData, -} - -#[derive(Deserialize, Default, Debug, Clone, Eq, PartialEq)] -pub struct RustAnalyzerPackageMetaData { - pub rustc_private: bool, -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct PackageDependency { - pub pkg: Package, - pub name: String, - pub kind: DepKind, -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] -pub enum DepKind { - /// Available to the library, binary, and dev targets in the package (but not the build script). - Normal, - /// Available only to test and bench targets (and the library target, when built with `cfg(test)`). - Dev, - /// Available only to the build script target. - Build, -} - -impl DepKind { - fn iter(list: &[cargo_metadata::DepKindInfo]) -> impl Iterator + '_ { - let mut dep_kinds = Vec::new(); - if list.is_empty() { - dep_kinds.push(Self::Normal); - } - for info in list { - let kind = match info.kind { - cargo_metadata::DependencyKind::Normal => Self::Normal, - cargo_metadata::DependencyKind::Development => Self::Dev, - cargo_metadata::DependencyKind::Build => Self::Build, - cargo_metadata::DependencyKind::Unknown => continue, - }; - dep_kinds.push(kind); - } - dep_kinds.sort_unstable(); - dep_kinds.dedup(); - dep_kinds.into_iter() - } -} - -/// Information associated with a package's target -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct TargetData { - /// Package that provided this target - pub package: Package, - /// Name as given in the `Cargo.toml` or generated from the file name - pub name: String, - /// Path to the main source file of the target - pub root: AbsPathBuf, - /// Kind of target - pub kind: TargetKind, - /// Is this target a proc-macro - pub is_proc_macro: bool, - /// Required features of the target without which it won't build - pub required_features: Vec, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum TargetKind { - Bin, - /// Any kind of Cargo lib crate-type (dylib, rlib, proc-macro, ...). - Lib, - Example, - Test, - Bench, - BuildScript, - Other, -} - -impl TargetKind { - fn new(kinds: &[String]) -> TargetKind { - for kind in kinds { - return match kind.as_str() { - "bin" => TargetKind::Bin, - "test" => TargetKind::Test, - "bench" => TargetKind::Bench, - "example" => TargetKind::Example, - "custom-build" => TargetKind::BuildScript, - "proc-macro" => TargetKind::Lib, - _ if kind.contains("lib") => TargetKind::Lib, - _ => continue, - }; - } - TargetKind::Other - } -} - -#[derive(Deserialize, Default)] -// Deserialise helper for the cargo metadata -struct PackageMetadata { - #[serde(rename = "rust-analyzer")] - rust_analyzer: Option, -} - -impl CargoWorkspace { - pub fn fetch_metadata( - cargo_toml: &ManifestPath, - current_dir: &AbsPath, - config: &CargoConfig, - progress: &dyn Fn(String), - ) -> Result { - let target = config - .target - .clone() - .or_else(|| cargo_config_build_target(cargo_toml)) - .or_else(|| rustc_discover_host_triple(cargo_toml)); - - let mut meta = MetadataCommand::new(); - meta.cargo_path(toolchain::cargo()); - meta.manifest_path(cargo_toml.to_path_buf()); - if config.all_features { - meta.features(CargoOpt::AllFeatures); - } else { - if config.no_default_features { - // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` - // https://github.com/oli-obk/cargo_metadata/issues/79 - meta.features(CargoOpt::NoDefaultFeatures); - } - if !config.features.is_empty() { - meta.features(CargoOpt::SomeFeatures(config.features.clone())); - } - } - meta.current_dir(current_dir.as_os_str()); - - if let Some(target) = target { - meta.other_options(vec![String::from("--filter-platform"), target]); - } - - // FIXME: Fetching metadata is a slow process, as it might require - // calling crates.io. We should be reporting progress here, but it's - // unclear whether cargo itself supports it. - progress("metadata".to_string()); - - let meta = - meta.exec().with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))?; - - Ok(meta) - } - - pub fn new(mut meta: cargo_metadata::Metadata) -> CargoWorkspace { - let mut pkg_by_id = FxHashMap::default(); - let mut packages = Arena::default(); - let mut targets = Arena::default(); - - let ws_members = &meta.workspace_members; - - meta.packages.sort_by(|a, b| a.id.cmp(&b.id)); - for meta_pkg in &meta.packages { - let cargo_metadata::Package { - id, - edition, - name, - manifest_path, - version, - metadata, - repository, - .. - } = meta_pkg; - let meta = from_value::(metadata.clone()).unwrap_or_default(); - let edition = match edition { - cargo_metadata::Edition::E2015 => Edition::Edition2015, - cargo_metadata::Edition::E2018 => Edition::Edition2018, - cargo_metadata::Edition::E2021 => Edition::Edition2021, - _ => { - tracing::error!("Unsupported edition `{:?}`", edition); - Edition::CURRENT - } - }; - // We treat packages without source as "local" packages. That includes all members of - // the current workspace, as well as any path dependency outside the workspace. - let is_local = meta_pkg.source.is_none(); - let is_member = ws_members.contains(id); - - let pkg = packages.alloc(PackageData { - id: id.repr.clone(), - name: name.clone(), - version: version.clone(), - manifest: AbsPathBuf::assert(PathBuf::from(&manifest_path)).try_into().unwrap(), - targets: Vec::new(), - is_local, - is_member, - edition, - repository: repository.clone(), - dependencies: Vec::new(), - features: meta_pkg.features.clone().into_iter().collect(), - active_features: Vec::new(), - metadata: meta.rust_analyzer.unwrap_or_default(), - }); - let pkg_data = &mut packages[pkg]; - pkg_by_id.insert(id, pkg); - for meta_tgt in &meta_pkg.targets { - let is_proc_macro = meta_tgt.kind.as_slice() == ["proc-macro"]; - let tgt = targets.alloc(TargetData { - package: pkg, - name: meta_tgt.name.clone(), - root: AbsPathBuf::assert(PathBuf::from(&meta_tgt.src_path)), - kind: TargetKind::new(meta_tgt.kind.as_slice()), - is_proc_macro, - required_features: meta_tgt.required_features.clone(), - }); - pkg_data.targets.push(tgt); - } - } - let resolve = meta.resolve.expect("metadata executed with deps"); - for mut node in resolve.nodes { - let source = match pkg_by_id.get(&node.id) { - Some(&src) => src, - // FIXME: replace this and a similar branch below with `.unwrap`, once - // https://github.com/rust-lang/cargo/issues/7841 - // is fixed and hits stable (around 1.43-is probably?). - None => { - tracing::error!("Node id do not match in cargo metadata, ignoring {}", node.id); - continue; - } - }; - node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg)); - for (dep_node, kind) in node - .deps - .iter() - .flat_map(|dep| DepKind::iter(&dep.dep_kinds).map(move |kind| (dep, kind))) - { - let pkg = match pkg_by_id.get(&dep_node.pkg) { - Some(&pkg) => pkg, - None => { - tracing::error!( - "Dep node id do not match in cargo metadata, ignoring {}", - dep_node.pkg - ); - continue; - } - }; - let dep = PackageDependency { name: dep_node.name.clone(), pkg, kind }; - packages[source].dependencies.push(dep); - } - packages[source].active_features.extend(node.features); - } - - let workspace_root = - AbsPathBuf::assert(PathBuf::from(meta.workspace_root.into_os_string())); - - CargoWorkspace { packages, targets, workspace_root } - } - - pub fn packages<'a>(&'a self) -> impl Iterator + ExactSizeIterator + 'a { - self.packages.iter().map(|(id, _pkg)| id) - } - - pub fn target_by_root(&self, root: &AbsPath) -> Option { - self.packages() - .filter(|&pkg| self[pkg].is_member) - .find_map(|pkg| self[pkg].targets.iter().find(|&&it| &self[it].root == root)) - .copied() - } - - pub fn workspace_root(&self) -> &AbsPath { - &self.workspace_root - } - - pub fn package_flag(&self, package: &PackageData) -> String { - if self.is_unique(&*package.name) { - package.name.clone() - } else { - format!("{}:{}", package.name, package.version) - } - } - - pub fn parent_manifests(&self, manifest_path: &ManifestPath) -> Option> { - let mut found = false; - let parent_manifests = self - .packages() - .filter_map(|pkg| { - if !found && &self[pkg].manifest == manifest_path { - found = true - } - self[pkg].dependencies.iter().find_map(|dep| { - if &self[dep.pkg].manifest == manifest_path { - return Some(self[pkg].manifest.clone()); - } - None - }) - }) - .collect::>(); - - // some packages has this pkg as dep. return their manifests - if parent_manifests.len() > 0 { - return Some(parent_manifests); - } - - // this pkg is inside this cargo workspace, fallback to workspace root - if found { - return Some(vec![ - ManifestPath::try_from(self.workspace_root().join("Cargo.toml")).ok()? - ]); - } - - // not in this workspace - None - } - - fn is_unique(&self, name: &str) -> bool { - self.packages.iter().filter(|(_, v)| v.name == name).count() == 1 - } -} - -fn rustc_discover_host_triple(cargo_toml: &ManifestPath) -> Option { - let mut rustc = Command::new(toolchain::rustc()); - rustc.current_dir(cargo_toml.parent()).arg("-vV"); - tracing::debug!("Discovering host platform by {:?}", rustc); - match utf8_stdout(rustc) { - Ok(stdout) => { - let field = "host: "; - let target = stdout.lines().find_map(|l| l.strip_prefix(field)); - if let Some(target) = target { - Some(target.to_string()) - } else { - // If we fail to resolve the host platform, it's not the end of the world. - tracing::info!("rustc -vV did not report host platform, got:\n{}", stdout); - None - } - } - Err(e) => { - tracing::warn!("Failed to discover host platform: {}", e); - None - } - } -} - -fn cargo_config_build_target(cargo_toml: &ManifestPath) -> Option { - let mut cargo_config = Command::new(toolchain::cargo()); - cargo_config - .current_dir(cargo_toml.parent()) - .args(&["-Z", "unstable-options", "config", "get", "build.target"]) - .env("RUSTC_BOOTSTRAP", "1"); - // if successful we receive `build.target = "target-triple"` - tracing::debug!("Discovering cargo config target by {:?}", cargo_config); - match utf8_stdout(cargo_config) { - Ok(stdout) => stdout - .strip_prefix("build.target = \"") - .and_then(|stdout| stdout.strip_suffix('"')) - .map(ToOwned::to_owned), - Err(_) => None, - } -} diff --git a/src/tools/rust-analyzer/crates/project-model/src/cfg_flag.rs b/src/tools/rust-analyzer/crates/project-model/src/cfg_flag.rs deleted file mode 100644 index f3dd8f51333be..0000000000000 --- a/src/tools/rust-analyzer/crates/project-model/src/cfg_flag.rs +++ /dev/null @@ -1,63 +0,0 @@ -//! Parsing of CfgFlags as command line arguments, as in -//! -//! rustc main.rs --cfg foo --cfg 'feature="bar"' -use std::{fmt, str::FromStr}; - -use cfg::CfgOptions; - -#[derive(Clone, Eq, PartialEq, Debug)] -pub enum CfgFlag { - Atom(String), - KeyValue { key: String, value: String }, -} - -impl FromStr for CfgFlag { - type Err = String; - fn from_str(s: &str) -> Result { - let res = match s.split_once('=') { - Some((key, value)) => { - if !(value.starts_with('"') && value.ends_with('"')) { - return Err(format!("Invalid cfg ({:?}), value should be in quotes", s)); - } - let key = key.to_string(); - let value = value[1..value.len() - 1].to_string(); - CfgFlag::KeyValue { key, value } - } - None => CfgFlag::Atom(s.into()), - }; - Ok(res) - } -} - -impl<'de> serde::Deserialize<'de> for CfgFlag { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - String::deserialize(deserializer)?.parse().map_err(serde::de::Error::custom) - } -} - -impl Extend for CfgOptions { - fn extend>(&mut self, iter: T) { - for cfg_flag in iter { - match cfg_flag { - CfgFlag::Atom(it) => self.insert_atom(it.into()), - CfgFlag::KeyValue { key, value } => self.insert_key_value(key.into(), value.into()), - } - } - } -} - -impl fmt::Display for CfgFlag { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - CfgFlag::Atom(atom) => f.write_str(atom), - CfgFlag::KeyValue { key, value } => { - f.write_str(key)?; - f.write_str("=")?; - f.write_str(value) - } - } - } -} diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs deleted file mode 100644 index e3f83084ac8ac..0000000000000 --- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs +++ /dev/null @@ -1,159 +0,0 @@ -//! In rust-analyzer, we maintain a strict separation between pure abstract -//! semantic project model and a concrete model of a particular build system. -//! -//! Pure model is represented by the [`base_db::CrateGraph`] from another crate. -//! -//! In this crate, we are conserned with "real world" project models. -//! -//! Specifically, here we have a representation for a Cargo project -//! ([`CargoWorkspace`]) and for manually specified layout ([`ProjectJson`]). -//! -//! Roughly, the things we do here are: -//! -//! * Project discovery (where's the relevant Cargo.toml for the current dir). -//! * Custom build steps (`build.rs` code generation and compilation of -//! procedural macros). -//! * Lowering of concrete model to a [`base_db::CrateGraph`] - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -mod manifest_path; -mod cargo_workspace; -mod cfg_flag; -mod project_json; -mod sysroot; -mod workspace; -mod rustc_cfg; -mod build_scripts; - -#[cfg(test)] -mod tests; - -use std::{ - fs::{self, read_dir, ReadDir}, - io, - process::Command, -}; - -use anyhow::{bail, format_err, Context, Result}; -use paths::{AbsPath, AbsPathBuf}; -use rustc_hash::FxHashSet; - -pub use crate::{ - build_scripts::WorkspaceBuildScripts, - cargo_workspace::{ - CargoConfig, CargoWorkspace, Package, PackageData, PackageDependency, RustcSource, Target, - TargetData, TargetKind, UnsetTestCrates, - }, - manifest_path::ManifestPath, - project_json::{ProjectJson, ProjectJsonData}, - sysroot::Sysroot, - workspace::{CfgOverrides, PackageRoot, ProjectWorkspace}, -}; - -#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] -pub enum ProjectManifest { - ProjectJson(ManifestPath), - CargoToml(ManifestPath), -} - -impl ProjectManifest { - pub fn from_manifest_file(path: AbsPathBuf) -> Result { - let path = ManifestPath::try_from(path) - .map_err(|path| format_err!("bad manifest path: {}", path.display()))?; - if path.file_name().unwrap_or_default() == "rust-project.json" { - return Ok(ProjectManifest::ProjectJson(path)); - } - if path.file_name().unwrap_or_default() == "Cargo.toml" { - return Ok(ProjectManifest::CargoToml(path)); - } - bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display()) - } - - pub fn discover_single(path: &AbsPath) -> Result { - let mut candidates = ProjectManifest::discover(path)?; - let res = match candidates.pop() { - None => bail!("no projects"), - Some(it) => it, - }; - - if !candidates.is_empty() { - bail!("more than one project") - } - Ok(res) - } - - pub fn discover(path: &AbsPath) -> io::Result> { - if let Some(project_json) = find_in_parent_dirs(path, "rust-project.json") { - return Ok(vec![ProjectManifest::ProjectJson(project_json)]); - } - return find_cargo_toml(path) - .map(|paths| paths.into_iter().map(ProjectManifest::CargoToml).collect()); - - fn find_cargo_toml(path: &AbsPath) -> io::Result> { - match find_in_parent_dirs(path, "Cargo.toml") { - Some(it) => Ok(vec![it]), - None => Ok(find_cargo_toml_in_child_dir(read_dir(path)?)), - } - } - - fn find_in_parent_dirs(path: &AbsPath, target_file_name: &str) -> Option { - if path.file_name().unwrap_or_default() == target_file_name { - if let Ok(manifest) = ManifestPath::try_from(path.to_path_buf()) { - return Some(manifest); - } - } - - let mut curr = Some(path); - - while let Some(path) = curr { - let candidate = path.join(target_file_name); - if fs::metadata(&candidate).is_ok() { - if let Ok(manifest) = ManifestPath::try_from(candidate) { - return Some(manifest); - } - } - curr = path.parent(); - } - - None - } - - fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec { - // Only one level down to avoid cycles the easy way and stop a runaway scan with large projects - entities - .filter_map(Result::ok) - .map(|it| it.path().join("Cargo.toml")) - .filter(|it| it.exists()) - .map(AbsPathBuf::assert) - .filter_map(|it| it.try_into().ok()) - .collect() - } - } - - pub fn discover_all(paths: &[AbsPathBuf]) -> Vec { - let mut res = paths - .iter() - .filter_map(|it| ProjectManifest::discover(it.as_ref()).ok()) - .flatten() - .collect::>() - .into_iter() - .collect::>(); - res.sort(); - res - } -} - -fn utf8_stdout(mut cmd: Command) -> Result { - let output = cmd.output().with_context(|| format!("{:?} failed", cmd))?; - if !output.status.success() { - match String::from_utf8(output.stderr) { - Ok(stderr) if !stderr.is_empty() => { - bail!("{:?} failed, {}\nstderr:\n{}", cmd, output.status, stderr) - } - _ => bail!("{:?} failed, {}", cmd, output.status), - } - } - let stdout = String::from_utf8(output.stdout)?; - Ok(stdout.trim().to_string()) -} diff --git a/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs b/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs deleted file mode 100644 index 4910fd3d11ccc..0000000000000 --- a/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs +++ /dev/null @@ -1,51 +0,0 @@ -//! See [`ManifestPath`]. -use std::{ops, path::Path}; - -use paths::{AbsPath, AbsPathBuf}; - -/// More or less [`AbsPathBuf`] with non-None parent. -/// -/// We use it to store path to Cargo.toml, as we frequently use the parent dir -/// as a working directory to spawn various commands, and its nice to not have -/// to `.unwrap()` everywhere. -/// -/// This could have been named `AbsNonRootPathBuf`, as we don't enforce that -/// this stores manifest files in particular, but we only use this for manifests -/// at the moment in practice. -#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] -pub struct ManifestPath { - file: AbsPathBuf, -} - -impl TryFrom for ManifestPath { - type Error = AbsPathBuf; - - fn try_from(file: AbsPathBuf) -> Result { - if file.parent().is_none() { - Err(file) - } else { - Ok(ManifestPath { file }) - } - } -} - -impl ManifestPath { - // Shadow `parent` from `Deref`. - pub fn parent(&self) -> &AbsPath { - self.file.parent().unwrap() - } -} - -impl ops::Deref for ManifestPath { - type Target = AbsPath; - - fn deref(&self) -> &Self::Target { - &*self.file - } -} - -impl AsRef for ManifestPath { - fn as_ref(&self) -> &Path { - self.file.as_ref() - } -} diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs deleted file mode 100644 index 63d1d0ace96b9..0000000000000 --- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs +++ /dev/null @@ -1,198 +0,0 @@ -//! `rust-project.json` file format. -//! -//! This format is spiritually a serialization of [`base_db::CrateGraph`]. The -//! idea here is that people who do not use Cargo, can instead teach their build -//! system to generate `rust-project.json` which can be ingested by -//! rust-analyzer. - -use std::path::PathBuf; - -use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, Edition}; -use paths::{AbsPath, AbsPathBuf}; -use rustc_hash::FxHashMap; -use serde::{de, Deserialize}; - -use crate::cfg_flag::CfgFlag; - -/// Roots and crates that compose this Rust project. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ProjectJson { - /// e.g. `path/to/sysroot` - pub(crate) sysroot: Option, - /// e.g. `path/to/sysroot/lib/rustlib/src/rust` - pub(crate) sysroot_src: Option, - project_root: AbsPathBuf, - crates: Vec, -} - -/// A crate points to the root module of a crate and lists the dependencies of the crate. This is -/// useful in creating the crate graph. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Crate { - pub(crate) display_name: Option, - pub(crate) root_module: AbsPathBuf, - pub(crate) edition: Edition, - pub(crate) version: Option, - pub(crate) deps: Vec, - pub(crate) cfg: Vec, - pub(crate) target: Option, - pub(crate) env: FxHashMap, - pub(crate) proc_macro_dylib_path: Option, - pub(crate) is_workspace_member: bool, - pub(crate) include: Vec, - pub(crate) exclude: Vec, - pub(crate) is_proc_macro: bool, - pub(crate) repository: Option, -} - -impl ProjectJson { - /// Create a new ProjectJson instance. - /// - /// # Arguments - /// - /// * `base` - The path to the workspace root (i.e. the folder containing `rust-project.json`) - /// * `data` - The parsed contents of `rust-project.json`, or project json that's passed via - /// configuration. - pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson { - ProjectJson { - sysroot: data.sysroot.map(|it| base.join(it)), - sysroot_src: data.sysroot_src.map(|it| base.join(it)), - project_root: base.to_path_buf(), - crates: data - .crates - .into_iter() - .map(|crate_data| { - let is_workspace_member = crate_data.is_workspace_member.unwrap_or_else(|| { - crate_data.root_module.is_relative() - && !crate_data.root_module.starts_with("..") - || crate_data.root_module.starts_with(base) - }); - let root_module = base.join(crate_data.root_module).normalize(); - let (include, exclude) = match crate_data.source { - Some(src) => { - let absolutize = |dirs: Vec| { - dirs.into_iter() - .map(|it| base.join(it).normalize()) - .collect::>() - }; - (absolutize(src.include_dirs), absolutize(src.exclude_dirs)) - } - None => (vec![root_module.parent().unwrap().to_path_buf()], Vec::new()), - }; - - Crate { - display_name: crate_data - .display_name - .map(CrateDisplayName::from_canonical_name), - root_module, - edition: crate_data.edition.into(), - version: crate_data.version.as_ref().map(ToString::to_string), - deps: crate_data - .deps - .into_iter() - .map(|dep_data| { - Dependency::new(dep_data.name, CrateId(dep_data.krate as u32)) - }) - .collect::>(), - cfg: crate_data.cfg, - target: crate_data.target, - env: crate_data.env, - proc_macro_dylib_path: crate_data - .proc_macro_dylib_path - .map(|it| base.join(it)), - is_workspace_member, - include, - exclude, - is_proc_macro: crate_data.is_proc_macro, - repository: crate_data.repository, - } - }) - .collect::>(), - } - } - /// Returns the number of crates in the project. - pub fn n_crates(&self) -> usize { - self.crates.len() - } - /// Returns an iterator over the crates in the project. - pub fn crates(&self) -> impl Iterator + '_ { - self.crates.iter().enumerate().map(|(idx, krate)| (CrateId(idx as u32), krate)) - } - /// Returns the path to the project's root folder. - pub fn path(&self) -> &AbsPath { - &self.project_root - } -} - -#[derive(Deserialize, Debug, Clone)] -pub struct ProjectJsonData { - sysroot: Option, - sysroot_src: Option, - crates: Vec, -} - -#[derive(Deserialize, Debug, Clone)] -struct CrateData { - display_name: Option, - root_module: PathBuf, - edition: EditionData, - #[serde(default)] - version: Option, - deps: Vec, - #[serde(default)] - cfg: Vec, - target: Option, - #[serde(default)] - env: FxHashMap, - proc_macro_dylib_path: Option, - is_workspace_member: Option, - source: Option, - #[serde(default)] - is_proc_macro: bool, - #[serde(default)] - repository: Option, -} - -#[derive(Deserialize, Debug, Clone)] -#[serde(rename = "edition")] -enum EditionData { - #[serde(rename = "2015")] - Edition2015, - #[serde(rename = "2018")] - Edition2018, - #[serde(rename = "2021")] - Edition2021, -} - -impl From for Edition { - fn from(data: EditionData) -> Self { - match data { - EditionData::Edition2015 => Edition::Edition2015, - EditionData::Edition2018 => Edition::Edition2018, - EditionData::Edition2021 => Edition::Edition2021, - } - } -} - -#[derive(Deserialize, Debug, Clone)] -struct DepData { - /// Identifies a crate by position in the crates array. - #[serde(rename = "crate")] - krate: usize, - #[serde(deserialize_with = "deserialize_crate_name")] - name: CrateName, -} - -#[derive(Deserialize, Debug, Clone)] -struct CrateSource { - include_dirs: Vec, - exclude_dirs: Vec, -} - -fn deserialize_crate_name<'de, D>(de: D) -> Result -where - D: de::Deserializer<'de>, -{ - let name = String::deserialize(de)?; - CrateName::new(&name).map_err(|err| de::Error::custom(format!("invalid crate name: {:?}", err))) -} diff --git a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs deleted file mode 100644 index 17e244d0649ed..0000000000000 --- a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! Runs `rustc --print cfg` to get built-in cfg flags. - -use std::process::Command; - -use anyhow::Result; - -use crate::{cfg_flag::CfgFlag, utf8_stdout, ManifestPath}; - -pub(crate) fn get(cargo_toml: Option<&ManifestPath>, target: Option<&str>) -> Vec { - let _p = profile::span("rustc_cfg::get"); - let mut res = Vec::with_capacity(6 * 2 + 1); - - // Some nightly-only cfgs, which are required for stdlib - res.push(CfgFlag::Atom("target_thread_local".into())); - for ty in ["8", "16", "32", "64", "cas", "ptr"] { - for key in ["target_has_atomic", "target_has_atomic_load_store"] { - res.push(CfgFlag::KeyValue { key: key.to_string(), value: ty.into() }); - } - } - - match get_rust_cfgs(cargo_toml, target) { - Ok(rustc_cfgs) => { - tracing::debug!( - "rustc cfgs found: {:?}", - rustc_cfgs - .lines() - .map(|it| it.parse::().map(|it| it.to_string())) - .collect::>() - ); - res.extend(rustc_cfgs.lines().filter_map(|it| it.parse().ok())); - } - Err(e) => tracing::error!("failed to get rustc cfgs: {e:?}"), - } - - res -} - -fn get_rust_cfgs(cargo_toml: Option<&ManifestPath>, target: Option<&str>) -> Result { - if let Some(cargo_toml) = cargo_toml { - let mut cargo_config = Command::new(toolchain::cargo()); - cargo_config - .current_dir(cargo_toml.parent()) - .args(&["-Z", "unstable-options", "rustc", "--print", "cfg"]) - .env("RUSTC_BOOTSTRAP", "1"); - if let Some(target) = target { - cargo_config.args(&["--target", target]); - } - match utf8_stdout(cargo_config) { - Ok(it) => return Ok(it), - Err(e) => tracing::debug!("{e:?}: falling back to querying rustc for cfgs"), - } - } - // using unstable cargo features failed, fall back to using plain rustc - let mut cmd = Command::new(toolchain::rustc()); - cmd.args(&["--print", "cfg", "-O"]); - if let Some(target) = target { - cmd.args(&["--target", target]); - } - utf8_stdout(cmd) -} diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs deleted file mode 100644 index 362bb0f5e79cd..0000000000000 --- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs +++ /dev/null @@ -1,232 +0,0 @@ -//! Loads "sysroot" crate. -//! -//! One confusing point here is that normally sysroot is a bunch of `.rlib`s, -//! but we can't process `.rlib` and need source code instead. The source code -//! is typically installed with `rustup component add rust-src` command. - -use std::{env, fs, iter, ops, path::PathBuf, process::Command}; - -use anyhow::{format_err, Result}; -use la_arena::{Arena, Idx}; -use paths::{AbsPath, AbsPathBuf}; - -use crate::{utf8_stdout, ManifestPath}; - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Sysroot { - root: AbsPathBuf, - src_root: AbsPathBuf, - crates: Arena, -} - -pub(crate) type SysrootCrate = Idx; - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct SysrootCrateData { - pub name: String, - pub root: ManifestPath, - pub deps: Vec, -} - -impl ops::Index for Sysroot { - type Output = SysrootCrateData; - fn index(&self, index: SysrootCrate) -> &SysrootCrateData { - &self.crates[index] - } -} - -impl Sysroot { - /// Returns sysroot "root" directory, where `bin/`, `etc/`, `lib/`, `libexec/` - /// subfolder live, like: - /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu` - pub fn root(&self) -> &AbsPath { - &self.root - } - - /// Returns the sysroot "source" directory, where stdlib sources are located, like: - /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library` - pub fn src_root(&self) -> &AbsPath { - &self.src_root - } - - pub fn public_deps(&self) -> impl Iterator + '_ { - // core is added as a dependency before std in order to - // mimic rustcs dependency order - ["core", "alloc", "std"] - .into_iter() - .zip(iter::repeat(true)) - .chain(iter::once(("test", false))) - .filter_map(move |(name, prelude)| Some((name, self.by_name(name)?, prelude))) - } - - pub fn proc_macro(&self) -> Option { - self.by_name("proc_macro") - } - - pub fn crates<'a>(&'a self) -> impl Iterator + ExactSizeIterator + 'a { - self.crates.iter().map(|(id, _data)| id) - } - - pub fn discover(dir: &AbsPath) -> Result { - tracing::debug!("Discovering sysroot for {}", dir.display()); - let sysroot_dir = discover_sysroot_dir(dir)?; - let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, dir)?; - let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?; - Ok(res) - } - - pub fn discover_rustc(cargo_toml: &ManifestPath) -> Option { - tracing::debug!("Discovering rustc source for {}", cargo_toml.display()); - let current_dir = cargo_toml.parent(); - discover_sysroot_dir(current_dir).ok().and_then(|sysroot_dir| get_rustc_src(&sysroot_dir)) - } - - pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Result { - let mut sysroot = - Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() }; - - for path in SYSROOT_CRATES.trim().lines() { - let name = path.split('/').last().unwrap(); - let root = [format!("{}/src/lib.rs", path), format!("lib{}/lib.rs", path)] - .into_iter() - .map(|it| sysroot.src_root.join(it)) - .filter_map(|it| ManifestPath::try_from(it).ok()) - .find(|it| fs::metadata(it).is_ok()); - - if let Some(root) = root { - sysroot.crates.alloc(SysrootCrateData { - name: name.into(), - root, - deps: Vec::new(), - }); - } - } - - if let Some(std) = sysroot.by_name("std") { - for dep in STD_DEPS.trim().lines() { - if let Some(dep) = sysroot.by_name(dep) { - sysroot.crates[std].deps.push(dep) - } - } - } - - if let Some(alloc) = sysroot.by_name("alloc") { - if let Some(core) = sysroot.by_name("core") { - sysroot.crates[alloc].deps.push(core); - } - } - - if let Some(proc_macro) = sysroot.by_name("proc_macro") { - if let Some(std) = sysroot.by_name("std") { - sysroot.crates[proc_macro].deps.push(std); - } - } - - if sysroot.by_name("core").is_none() { - let var_note = if env::var_os("RUST_SRC_PATH").is_some() { - " (`RUST_SRC_PATH` might be incorrect, try unsetting it)" - } else { - "" - }; - anyhow::bail!( - "could not find libcore in sysroot path `{}`{}", - sysroot.src_root.as_path().display(), - var_note, - ); - } - - Ok(sysroot) - } - - fn by_name(&self, name: &str) -> Option { - let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?; - Some(id) - } -} - -fn discover_sysroot_dir(current_dir: &AbsPath) -> Result { - let mut rustc = Command::new(toolchain::rustc()); - rustc.current_dir(current_dir).args(&["--print", "sysroot"]); - tracing::debug!("Discovering sysroot by {:?}", rustc); - let stdout = utf8_stdout(rustc)?; - Ok(AbsPathBuf::assert(PathBuf::from(stdout))) -} - -fn discover_sysroot_src_dir( - sysroot_path: &AbsPathBuf, - current_dir: &AbsPath, -) -> Result { - if let Ok(path) = env::var("RUST_SRC_PATH") { - let path = AbsPathBuf::try_from(path.as_str()) - .map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?; - let core = path.join("core"); - if fs::metadata(&core).is_ok() { - tracing::debug!("Discovered sysroot by RUST_SRC_PATH: {}", path.display()); - return Ok(path); - } - tracing::debug!("RUST_SRC_PATH is set, but is invalid (no core: {:?}), ignoring", core); - } - - get_rust_src(sysroot_path) - .or_else(|| { - let mut rustup = Command::new(toolchain::rustup()); - rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]); - utf8_stdout(rustup).ok()?; - get_rust_src(sysroot_path) - }) - .ok_or_else(|| { - format_err!( - "\ -can't load standard library from sysroot -{} -(discovered via `rustc --print sysroot`) -try installing the Rust source the same way you installed rustc", - sysroot_path.display(), - ) - }) -} - -fn get_rustc_src(sysroot_path: &AbsPath) -> Option { - let rustc_src = sysroot_path.join("lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml"); - let rustc_src = ManifestPath::try_from(rustc_src).ok()?; - tracing::debug!("Checking for rustc source code: {}", rustc_src.display()); - if fs::metadata(&rustc_src).is_ok() { - Some(rustc_src) - } else { - None - } -} - -fn get_rust_src(sysroot_path: &AbsPath) -> Option { - let rust_src = sysroot_path.join("lib/rustlib/src/rust/library"); - tracing::debug!("Checking sysroot: {}", rust_src.display()); - if fs::metadata(&rust_src).is_ok() { - Some(rust_src) - } else { - None - } -} - -const SYSROOT_CRATES: &str = " -alloc -core -panic_abort -panic_unwind -proc_macro -profiler_builtins -std -stdarch/crates/std_detect -term -test -unwind"; - -const STD_DEPS: &str = " -alloc -core -panic_abort -panic_unwind -profiler_builtins -std_detect -term -test -unwind"; diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs deleted file mode 100644 index e304a59c0180b..0000000000000 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ /dev/null @@ -1,1820 +0,0 @@ -use std::{ - ops::Deref, - path::{Path, PathBuf}, -}; - -use base_db::{CrateGraph, FileId}; -use cfg::{CfgAtom, CfgDiff}; -use expect_test::{expect, Expect}; -use paths::{AbsPath, AbsPathBuf}; -use serde::de::DeserializeOwned; - -use crate::{ - CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace, Sysroot, - WorkspaceBuildScripts, -}; - -fn load_cargo(file: &str) -> CrateGraph { - load_cargo_with_overrides(file, CfgOverrides::default()) -} - -fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGraph { - let meta = get_test_json_file(file); - let cargo_workspace = CargoWorkspace::new(meta); - let project_workspace = ProjectWorkspace::Cargo { - cargo: cargo_workspace, - build_scripts: WorkspaceBuildScripts::default(), - sysroot: None, - rustc: None, - rustc_cfg: Vec::new(), - cfg_overrides, - }; - to_crate_graph(project_workspace) -} - -fn load_rust_project(file: &str) -> CrateGraph { - let data = get_test_json_file(file); - let project = rooted_project_json(data); - let sysroot = Some(get_fake_sysroot()); - let project_workspace = ProjectWorkspace::Json { project, sysroot, rustc_cfg: Vec::new() }; - to_crate_graph(project_workspace) -} - -fn get_test_json_file(file: &str) -> T { - let file = get_test_path(file); - let data = std::fs::read_to_string(file).unwrap(); - let mut json = data.parse::().unwrap(); - fixup_paths(&mut json); - return serde_json::from_value(json).unwrap(); - - fn fixup_paths(val: &mut serde_json::Value) { - match val { - serde_json::Value::String(s) => replace_root(s, true), - serde_json::Value::Array(vals) => vals.iter_mut().for_each(fixup_paths), - serde_json::Value::Object(kvals) => kvals.values_mut().for_each(fixup_paths), - serde_json::Value::Null | serde_json::Value::Bool(_) | serde_json::Value::Number(_) => { - } - } - } -} - -fn replace_root(s: &mut String, direction: bool) { - if direction { - let root = if cfg!(windows) { r#"C:\\ROOT\"# } else { "/ROOT/" }; - *s = s.replace("$ROOT$", root) - } else { - let root = if cfg!(windows) { r#"C:\\\\ROOT\\"# } else { "/ROOT/" }; - *s = s.replace(root, "$ROOT$") - } -} - -fn get_test_path(file: &str) -> PathBuf { - let base = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - base.join("test_data").join(file) -} - -fn get_fake_sysroot() -> Sysroot { - let sysroot_path = get_test_path("fake-sysroot"); - // there's no `libexec/` directory with a `proc-macro-srv` binary in that - // fake sysroot, so we give them both the same path: - let sysroot_dir = AbsPathBuf::assert(sysroot_path); - let sysroot_src_dir = sysroot_dir.clone(); - Sysroot::load(sysroot_dir, sysroot_src_dir).unwrap() -} - -fn rooted_project_json(data: ProjectJsonData) -> ProjectJson { - let mut root = "$ROOT$".to_string(); - replace_root(&mut root, true); - let path = Path::new(&root); - let base = AbsPath::assert(path); - ProjectJson::new(base, data) -} - -fn to_crate_graph(project_workspace: ProjectWorkspace) -> CrateGraph { - project_workspace.to_crate_graph(&mut |_, _| Ok(Vec::new()), &mut { - let mut counter = 0; - move |_path| { - counter += 1; - Some(FileId(counter)) - } - }) -} - -fn check_crate_graph(crate_graph: CrateGraph, expect: Expect) { - let mut crate_graph = format!("{:#?}", crate_graph); - replace_root(&mut crate_graph, false); - expect.assert_eq(&crate_graph); -} - -#[test] -fn cargo_hello_world_project_model_with_wildcard_overrides() { - let cfg_overrides = CfgOverrides::Wildcard( - CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(), - ); - let crate_graph = load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides); - check_crate_graph( - crate_graph, - expect![[r#" - CrateGraph { - arena: { - CrateId( - 0, - ): CrateData { - root_file_id: FileId( - 1, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello-world", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - }, - is_proc_macro: false, - }, - CrateId( - 2, - ): CrateData { - root_file_id: FileId( - 3, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "an_example", - ), - canonical_name: "an-example", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - }, - is_proc_macro: false, - }, - CrateId( - 4, - ): CrateData { - root_file_id: FileId( - 5, - ), - edition: Edition2015, - version: Some( - "0.2.98", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "libc", - ), - canonical_name: "libc", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "feature=default", - "feature=std", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "feature=align", - "feature=const-extern-fn", - "feature=default", - "feature=extra_traits", - "feature=rustc-dep-of-std", - "feature=std", - "feature=use_std", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", - "CARGO_PKG_VERSION": "0.2.98", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "libc", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "libc", - "CARGO_PKG_VERSION_PATCH": "98", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "2", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: Some( - "https://github.com/rust-lang/libc", - ), - }, - is_proc_macro: false, - }, - CrateId( - 1, - ): CrateData { - root_file_id: FileId( - 2, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello-world", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - }, - is_proc_macro: false, - }, - CrateId( - 3, - ): CrateData { - root_file_id: FileId( - 4, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "it", - ), - canonical_name: "it", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - }, - is_proc_macro: false, - }, - }, - }"#]], - ) -} - -#[test] -fn cargo_hello_world_project_model_with_selective_overrides() { - let cfg_overrides = { - CfgOverrides::Selective( - std::iter::once(( - "libc".to_owned(), - CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(), - )) - .collect(), - ) - }; - let crate_graph = load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides); - check_crate_graph( - crate_graph, - expect![[r#" - CrateGraph { - arena: { - CrateId( - 0, - ): CrateData { - root_file_id: FileId( - 1, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello-world", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - }, - is_proc_macro: false, - }, - CrateId( - 2, - ): CrateData { - root_file_id: FileId( - 3, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "an_example", - ), - canonical_name: "an-example", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - }, - is_proc_macro: false, - }, - CrateId( - 4, - ): CrateData { - root_file_id: FileId( - 5, - ), - edition: Edition2015, - version: Some( - "0.2.98", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "libc", - ), - canonical_name: "libc", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "feature=default", - "feature=std", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "feature=align", - "feature=const-extern-fn", - "feature=default", - "feature=extra_traits", - "feature=rustc-dep-of-std", - "feature=std", - "feature=use_std", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", - "CARGO_PKG_VERSION": "0.2.98", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "libc", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "libc", - "CARGO_PKG_VERSION_PATCH": "98", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "2", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: Some( - "https://github.com/rust-lang/libc", - ), - }, - is_proc_macro: false, - }, - CrateId( - 1, - ): CrateData { - root_file_id: FileId( - 2, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello-world", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - }, - is_proc_macro: false, - }, - CrateId( - 3, - ): CrateData { - root_file_id: FileId( - 4, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "it", - ), - canonical_name: "it", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - }, - is_proc_macro: false, - }, - }, - }"#]], - ) -} - -#[test] -fn cargo_hello_world_project_model() { - let crate_graph = load_cargo("hello-world-metadata.json"); - check_crate_graph( - crate_graph, - expect![[r#" - CrateGraph { - arena: { - CrateId( - 0, - ): CrateData { - root_file_id: FileId( - 1, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello-world", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - }, - is_proc_macro: false, - }, - CrateId( - 2, - ): CrateData { - root_file_id: FileId( - 3, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "an_example", - ), - canonical_name: "an-example", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - }, - is_proc_macro: false, - }, - CrateId( - 4, - ): CrateData { - root_file_id: FileId( - 5, - ), - edition: Edition2015, - version: Some( - "0.2.98", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "libc", - ), - canonical_name: "libc", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "feature=default", - "feature=std", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "feature=align", - "feature=const-extern-fn", - "feature=default", - "feature=extra_traits", - "feature=rustc-dep-of-std", - "feature=std", - "feature=use_std", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", - "CARGO_PKG_VERSION": "0.2.98", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "libc", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "libc", - "CARGO_PKG_VERSION_PATCH": "98", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "2", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: Some( - "https://github.com/rust-lang/libc", - ), - }, - is_proc_macro: false, - }, - CrateId( - 1, - ): CrateData { - root_file_id: FileId( - 2, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello-world", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - }, - is_proc_macro: false, - }, - CrateId( - 3, - ): CrateData { - root_file_id: FileId( - 4, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "it", - ), - canonical_name: "it", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - }, - is_proc_macro: false, - }, - }, - }"#]], - ) -} - -#[test] -fn rust_project_hello_world_project_model() { - let crate_graph = load_rust_project("hello-world-project.json"); - check_crate_graph( - crate_graph, - expect![[r#" - CrateGraph { - arena: { - CrateId( - 0, - ): CrateData { - root_file_id: FileId( - 1, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "alloc", - ), - canonical_name: "alloc", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - env: Env { - entries: {}, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 1, - ), - name: CrateName( - "core", - ), - prelude: true, - }, - ], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Alloc, - ), - is_proc_macro: false, - }, - CrateId( - 10, - ): CrateData { - root_file_id: FileId( - 11, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "unwind", - ), - canonical_name: "unwind", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), - is_proc_macro: false, - }, - CrateId( - 7, - ): CrateData { - root_file_id: FileId( - 8, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "std_detect", - ), - canonical_name: "std_detect", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), - is_proc_macro: false, - }, - CrateId( - 4, - ): CrateData { - root_file_id: FileId( - 5, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "proc_macro", - ), - canonical_name: "proc_macro", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - env: Env { - entries: {}, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 6, - ), - name: CrateName( - "std", - ), - prelude: true, - }, - ], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), - is_proc_macro: false, - }, - CrateId( - 1, - ): CrateData { - root_file_id: FileId( - 2, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "core", - ), - canonical_name: "core", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Core, - ), - is_proc_macro: false, - }, - CrateId( - 11, - ): CrateData { - root_file_id: FileId( - 12, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello_world", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - env: Env { - entries: {}, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 1, - ), - name: CrateName( - "core", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "alloc", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 6, - ), - name: CrateName( - "std", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 9, - ), - name: CrateName( - "test", - ), - prelude: false, - }, - ], - proc_macro: Err( - "no proc macro dylib present", - ), - origin: CratesIo { - repo: None, - }, - is_proc_macro: false, - }, - CrateId( - 8, - ): CrateData { - root_file_id: FileId( - 9, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "term", - ), - canonical_name: "term", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), - is_proc_macro: false, - }, - CrateId( - 5, - ): CrateData { - root_file_id: FileId( - 6, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "profiler_builtins", - ), - canonical_name: "profiler_builtins", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), - is_proc_macro: false, - }, - CrateId( - 2, - ): CrateData { - root_file_id: FileId( - 3, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "panic_abort", - ), - canonical_name: "panic_abort", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), - is_proc_macro: false, - }, - CrateId( - 9, - ): CrateData { - root_file_id: FileId( - 10, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "test", - ), - canonical_name: "test", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Test, - ), - is_proc_macro: false, - }, - CrateId( - 6, - ): CrateData { - root_file_id: FileId( - 7, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "std", - ), - canonical_name: "std", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - env: Env { - entries: {}, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "alloc", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 1, - ), - name: CrateName( - "core", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 2, - ), - name: CrateName( - "panic_abort", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 3, - ), - name: CrateName( - "panic_unwind", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 5, - ), - name: CrateName( - "profiler_builtins", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 7, - ), - name: CrateName( - "std_detect", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 8, - ), - name: CrateName( - "term", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 9, - ), - name: CrateName( - "test", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 10, - ), - name: CrateName( - "unwind", - ), - prelude: true, - }, - ], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Std, - ), - is_proc_macro: false, - }, - CrateId( - 3, - ): CrateData { - root_file_id: FileId( - 4, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "panic_unwind", - ), - canonical_name: "panic_unwind", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), - is_proc_macro: false, - }, - }, - }"#]], - ); -} - -#[test] -fn rust_project_is_proc_macro_has_proc_macro_dep() { - let crate_graph = load_rust_project("is-proc-macro-project.json"); - // Since the project only defines one crate (outside the sysroot crates), - // it should be the one with the biggest Id. - let crate_id = crate_graph.iter().max().unwrap(); - let crate_data = &crate_graph[crate_id]; - // Assert that the project crate with `is_proc_macro` has a dependency - // on the proc_macro sysroot crate. - crate_data.dependencies.iter().find(|&dep| dep.name.deref() == "proc_macro").unwrap(); -} diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs deleted file mode 100644 index b144006b44e03..0000000000000 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ /dev/null @@ -1,1032 +0,0 @@ -//! Handles lowering of build-system specific workspace information (`cargo -//! metadata` or `rust-project.json`) into representation stored in the salsa -//! database -- `CrateGraph`. - -use std::{collections::VecDeque, fmt, fs, process::Command}; - -use anyhow::{format_err, Context, Result}; -use base_db::{ - CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, - FileId, LangCrateOrigin, ProcMacroLoadResult, -}; -use cfg::{CfgDiff, CfgOptions}; -use paths::{AbsPath, AbsPathBuf}; -use rustc_hash::{FxHashMap, FxHashSet}; -use stdx::always; - -use crate::{ - build_scripts::BuildScriptOutput, - cargo_workspace::{DepKind, PackageData, RustcSource}, - cfg_flag::CfgFlag, - rustc_cfg, - sysroot::SysrootCrate, - utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath, ProjectJson, ProjectManifest, Sysroot, - TargetKind, WorkspaceBuildScripts, -}; - -/// A set of cfg-overrides per crate. -/// -/// `Wildcard(..)` is useful e.g. disabling `#[cfg(test)]` on all crates, -/// without having to first obtain a list of all crates. -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum CfgOverrides { - /// A single global set of overrides matching all crates. - Wildcard(CfgDiff), - /// A set of overrides matching specific crates. - Selective(FxHashMap), -} - -impl Default for CfgOverrides { - fn default() -> Self { - Self::Selective(FxHashMap::default()) - } -} - -impl CfgOverrides { - pub fn len(&self) -> usize { - match self { - CfgOverrides::Wildcard(_) => 1, - CfgOverrides::Selective(hash_map) => hash_map.len(), - } - } -} - -/// `PackageRoot` describes a package root folder. -/// Which may be an external dependency, or a member of -/// the current workspace. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct PackageRoot { - /// Is from the local filesystem and may be edited - pub is_local: bool, - pub include: Vec, - pub exclude: Vec, -} - -#[derive(Clone, Eq, PartialEq)] -pub enum ProjectWorkspace { - /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. - Cargo { - cargo: CargoWorkspace, - build_scripts: WorkspaceBuildScripts, - sysroot: Option, - rustc: Option, - /// Holds cfg flags for the current target. We get those by running - /// `rustc --print cfg`. - /// - /// FIXME: make this a per-crate map, as, eg, build.rs might have a - /// different target. - rustc_cfg: Vec, - cfg_overrides: CfgOverrides, - }, - /// Project workspace was manually specified using a `rust-project.json` file. - Json { project: ProjectJson, sysroot: Option, rustc_cfg: Vec }, - - // FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning. - // That's not the end user experience we should strive for. - // Ideally, you should be able to just open a random detached file in existing cargo projects, and get the basic features working. - // That needs some changes on the salsa-level though. - // In particular, we should split the unified CrateGraph (which currently has maximal durability) into proper crate graph, and a set of ad hoc roots (with minimal durability). - // Then, we need to hide the graph behind the queries such that most queries look only at the proper crate graph, and fall back to ad hoc roots only if there's no results. - // After this, we should be able to tweak the logic in reload.rs to add newly opened files, which don't belong to any existing crates, to the set of the detached files. - // // - /// Project with a set of disjoint files, not belonging to any particular workspace. - /// Backed by basic sysroot crates for basic completion and highlighting. - DetachedFiles { files: Vec, sysroot: Sysroot, rustc_cfg: Vec }, -} - -impl fmt::Debug for ProjectWorkspace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Make sure this isn't too verbose. - match self { - ProjectWorkspace::Cargo { - cargo, - build_scripts: _, - sysroot, - rustc, - rustc_cfg, - cfg_overrides, - } => f - .debug_struct("Cargo") - .field("root", &cargo.workspace_root().file_name()) - .field("n_packages", &cargo.packages().len()) - .field("sysroot", &sysroot.is_some()) - .field( - "n_rustc_compiler_crates", - &rustc.as_ref().map_or(0, |rc| rc.packages().len()), - ) - .field("n_rustc_cfg", &rustc_cfg.len()) - .field("n_cfg_overrides", &cfg_overrides.len()) - .finish(), - ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { - let mut debug_struct = f.debug_struct("Json"); - debug_struct.field("n_crates", &project.n_crates()); - if let Some(sysroot) = sysroot { - debug_struct.field("n_sysroot_crates", &sysroot.crates().len()); - } - debug_struct.field("n_rustc_cfg", &rustc_cfg.len()); - debug_struct.finish() - } - ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => f - .debug_struct("DetachedFiles") - .field("n_files", &files.len()) - .field("n_sysroot_crates", &sysroot.crates().len()) - .field("n_rustc_cfg", &rustc_cfg.len()) - .finish(), - } - } -} - -impl ProjectWorkspace { - pub fn load( - manifest: ProjectManifest, - config: &CargoConfig, - progress: &dyn Fn(String), - ) -> Result { - let res = match manifest { - ProjectManifest::ProjectJson(project_json) => { - let file = fs::read_to_string(&project_json).with_context(|| { - format!("Failed to read json file {}", project_json.display()) - })?; - let data = serde_json::from_str(&file).with_context(|| { - format!("Failed to deserialize json file {}", project_json.display()) - })?; - let project_location = project_json.parent().to_path_buf(); - let project_json = ProjectJson::new(&project_location, data); - ProjectWorkspace::load_inline(project_json, config.target.as_deref())? - } - ProjectManifest::CargoToml(cargo_toml) => { - let cargo_version = utf8_stdout({ - let mut cmd = Command::new(toolchain::cargo()); - cmd.arg("--version"); - cmd - })?; - - let meta = CargoWorkspace::fetch_metadata( - &cargo_toml, - cargo_toml.parent(), - config, - progress, - ) - .with_context(|| { - format!( - "Failed to read Cargo metadata from Cargo.toml file {}, {}", - cargo_toml.display(), - cargo_version - ) - })?; - let cargo = CargoWorkspace::new(meta); - - let sysroot = if config.no_sysroot { - None - } else { - Some(Sysroot::discover(cargo_toml.parent()).with_context(|| { - format!( - "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?", - cargo_toml.display() - ) - })?) - }; - - let rustc_dir = match &config.rustc_source { - Some(RustcSource::Path(path)) => ManifestPath::try_from(path.clone()).ok(), - Some(RustcSource::Discover) => Sysroot::discover_rustc(&cargo_toml), - None => None, - }; - - let rustc = match rustc_dir { - Some(rustc_dir) => Some({ - let meta = CargoWorkspace::fetch_metadata( - &rustc_dir, - cargo_toml.parent(), - config, - progress, - ) - .with_context(|| { - "Failed to read Cargo metadata for Rust sources".to_string() - })?; - CargoWorkspace::new(meta) - }), - None => None, - }; - - let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref()); - - let cfg_overrides = config.cfg_overrides(); - ProjectWorkspace::Cargo { - cargo, - build_scripts: WorkspaceBuildScripts::default(), - sysroot, - rustc, - rustc_cfg, - cfg_overrides, - } - } - }; - - Ok(res) - } - - pub fn load_inline( - project_json: ProjectJson, - target: Option<&str>, - ) -> Result { - let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) { - (Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)?), - (Some(sysroot), None) => { - // assume sysroot is structured like rustup's and guess `sysroot_src` - let sysroot_src = - sysroot.join("lib").join("rustlib").join("src").join("rust").join("library"); - - Some(Sysroot::load(sysroot, sysroot_src)?) - } - (None, Some(sysroot_src)) => { - // assume sysroot is structured like rustup's and guess `sysroot` - let mut sysroot = sysroot_src.clone(); - for _ in 0..5 { - sysroot.pop(); - } - Some(Sysroot::load(sysroot, sysroot_src)?) - } - (None, None) => None, - }; - - let rustc_cfg = rustc_cfg::get(None, target); - Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }) - } - - pub fn load_detached_files(detached_files: Vec) -> Result { - let sysroot = Sysroot::discover( - detached_files - .first() - .and_then(|it| it.parent()) - .ok_or_else(|| format_err!("No detached files to load"))?, - )?; - let rustc_cfg = rustc_cfg::get(None, None); - Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg }) - } - - pub fn run_build_scripts( - &self, - config: &CargoConfig, - progress: &dyn Fn(String), - ) -> Result { - match self { - ProjectWorkspace::Cargo { cargo, .. } => { - WorkspaceBuildScripts::run(config, cargo, progress).with_context(|| { - format!("Failed to run build scripts for {}", &cargo.workspace_root().display()) - }) - } - ProjectWorkspace::Json { .. } | ProjectWorkspace::DetachedFiles { .. } => { - Ok(WorkspaceBuildScripts::default()) - } - } - } - - pub fn set_build_scripts(&mut self, bs: WorkspaceBuildScripts) { - match self { - ProjectWorkspace::Cargo { build_scripts, .. } => *build_scripts = bs, - _ => { - always!(bs == WorkspaceBuildScripts::default()); - } - } - } - - /// Returns the roots for the current `ProjectWorkspace` - /// The return type contains the path and whether or not - /// the root is a member of the current workspace - pub fn to_roots(&self) -> Vec { - match self { - ProjectWorkspace::Json { project, sysroot, rustc_cfg: _ } => project - .crates() - .map(|(_, krate)| PackageRoot { - is_local: krate.is_workspace_member, - include: krate.include.clone(), - exclude: krate.exclude.clone(), - }) - .collect::>() - .into_iter() - .chain(sysroot.as_ref().into_iter().flat_map(|sysroot| { - sysroot.crates().map(move |krate| PackageRoot { - is_local: false, - include: vec![sysroot[krate].root.parent().to_path_buf()], - exclude: Vec::new(), - }) - })) - .collect::>(), - ProjectWorkspace::Cargo { - cargo, - sysroot, - rustc, - rustc_cfg: _, - cfg_overrides: _, - build_scripts, - } => { - cargo - .packages() - .map(|pkg| { - let is_local = cargo[pkg].is_local; - let pkg_root = cargo[pkg].manifest.parent().to_path_buf(); - - let mut include = vec![pkg_root.clone()]; - let out_dir = - build_scripts.get_output(pkg).and_then(|it| it.out_dir.clone()); - include.extend(out_dir); - - // In case target's path is manually set in Cargo.toml to be - // outside the package root, add its parent as an extra include. - // An example of this situation would look like this: - // - // ```toml - // [lib] - // path = "../../src/lib.rs" - // ``` - let extra_targets = cargo[pkg] - .targets - .iter() - .filter(|&&tgt| cargo[tgt].kind == TargetKind::Lib) - .filter_map(|&tgt| cargo[tgt].root.parent()) - .map(|tgt| tgt.normalize().to_path_buf()) - .filter(|path| !path.starts_with(&pkg_root)); - include.extend(extra_targets); - - let mut exclude = vec![pkg_root.join(".git")]; - if is_local { - exclude.push(pkg_root.join("target")); - } else { - exclude.push(pkg_root.join("tests")); - exclude.push(pkg_root.join("examples")); - exclude.push(pkg_root.join("benches")); - } - PackageRoot { is_local, include, exclude } - }) - .chain(sysroot.iter().map(|sysroot| PackageRoot { - is_local: false, - include: vec![sysroot.src_root().to_path_buf()], - exclude: Vec::new(), - })) - .chain(rustc.iter().flat_map(|rustc| { - rustc.packages().map(move |krate| PackageRoot { - is_local: false, - include: vec![rustc[krate].manifest.parent().to_path_buf()], - exclude: Vec::new(), - }) - })) - .collect() - } - ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files - .iter() - .map(|detached_file| PackageRoot { - is_local: true, - include: vec![detached_file.clone()], - exclude: Vec::new(), - }) - .chain(sysroot.crates().map(|krate| PackageRoot { - is_local: false, - include: vec![sysroot[krate].root.parent().to_path_buf()], - exclude: Vec::new(), - })) - .collect(), - } - } - - pub fn n_packages(&self) -> usize { - match self { - ProjectWorkspace::Json { project, .. } => project.n_crates(), - ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => { - let rustc_package_len = rustc.as_ref().map_or(0, |it| it.packages().len()); - let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len()); - cargo.packages().len() + sysroot_package_len + rustc_package_len - } - ProjectWorkspace::DetachedFiles { sysroot, files, .. } => { - sysroot.crates().len() + files.len() - } - } - } - - pub fn to_crate_graph( - &self, - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, - load: &mut dyn FnMut(&AbsPath) -> Option, - ) -> CrateGraph { - let _p = profile::span("ProjectWorkspace::to_crate_graph"); - - let mut crate_graph = match self { - ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph( - rustc_cfg.clone(), - load_proc_macro, - load, - project, - sysroot, - ), - ProjectWorkspace::Cargo { - cargo, - sysroot, - rustc, - rustc_cfg, - cfg_overrides, - build_scripts, - } => cargo_to_crate_graph( - rustc_cfg.clone(), - cfg_overrides, - load_proc_macro, - load, - cargo, - build_scripts, - sysroot.as_ref(), - rustc, - ), - ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { - detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot) - } - }; - if crate_graph.patch_cfg_if() { - tracing::debug!("Patched std to depend on cfg-if") - } else { - tracing::debug!("Did not patch std to depend on cfg-if") - } - crate_graph - } -} - -fn project_json_to_crate_graph( - rustc_cfg: Vec, - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, - load: &mut dyn FnMut(&AbsPath) -> Option, - project: &ProjectJson, - sysroot: &Option, -) -> CrateGraph { - let mut crate_graph = CrateGraph::default(); - let sysroot_deps = sysroot - .as_ref() - .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load)); - - let mut cfg_cache: FxHashMap<&str, Vec> = FxHashMap::default(); - let crates: FxHashMap = project - .crates() - .filter_map(|(crate_id, krate)| { - let file_path = &krate.root_module; - let file_id = load(file_path)?; - Some((crate_id, krate, file_id)) - }) - .map(|(crate_id, krate, file_id)| { - let env = krate.env.clone().into_iter().collect(); - let proc_macro = match krate.proc_macro_dylib_path.clone() { - Some(it) => load_proc_macro( - krate.display_name.as_ref().map(|it| it.canonical_name()).unwrap_or(""), - &it, - ), - None => Err("no proc macro dylib present".into()), - }; - - let target_cfgs = match krate.target.as_deref() { - Some(target) => { - cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(None, Some(target))) - } - None => &rustc_cfg, - }; - - let mut cfg_options = CfgOptions::default(); - cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned()); - ( - crate_id, - crate_graph.add_crate_root( - file_id, - krate.edition, - krate.display_name.clone(), - krate.version.clone(), - cfg_options.clone(), - cfg_options, - env, - proc_macro, - krate.is_proc_macro, - if krate.display_name.is_some() { - CrateOrigin::CratesIo { repo: krate.repository.clone() } - } else { - CrateOrigin::CratesIo { repo: None } - }, - ), - ) - }) - .collect(); - - for (from, krate) in project.crates() { - if let Some(&from) = crates.get(&from) { - if let Some((public_deps, libproc_macro)) = &sysroot_deps { - public_deps.add(from, &mut crate_graph); - if krate.is_proc_macro { - if let Some(proc_macro) = libproc_macro { - add_dep( - &mut crate_graph, - from, - CrateName::new("proc_macro").unwrap(), - *proc_macro, - ); - } - } - } - - for dep in &krate.deps { - if let Some(&to) = crates.get(&dep.crate_id) { - add_dep(&mut crate_graph, from, dep.name.clone(), to) - } - } - } - } - crate_graph -} - -fn cargo_to_crate_graph( - rustc_cfg: Vec, - override_cfg: &CfgOverrides, - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, - load: &mut dyn FnMut(&AbsPath) -> Option, - cargo: &CargoWorkspace, - build_scripts: &WorkspaceBuildScripts, - sysroot: Option<&Sysroot>, - rustc: &Option, -) -> CrateGraph { - let _p = profile::span("cargo_to_crate_graph"); - let mut crate_graph = CrateGraph::default(); - let (public_deps, libproc_macro) = match sysroot { - Some(sysroot) => sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load), - None => (SysrootPublicDeps::default(), None), - }; - - let mut cfg_options = CfgOptions::default(); - cfg_options.extend(rustc_cfg); - - let mut pkg_to_lib_crate = FxHashMap::default(); - - cfg_options.insert_atom("debug_assertions".into()); - - let mut pkg_crates = FxHashMap::default(); - // Does any crate signal to rust-analyzer that they need the rustc_private crates? - let mut has_private = false; - // Next, create crates for each package, target pair - for pkg in cargo.packages() { - let mut cfg_options = cfg_options.clone(); - - let overrides = match override_cfg { - CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff), - CfgOverrides::Selective(cfg_overrides) => cfg_overrides.get(&cargo[pkg].name), - }; - - // Add test cfg for local crates - if cargo[pkg].is_local { - cfg_options.insert_atom("test".into()); - } - - if let Some(overrides) = overrides { - // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen - // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while - // working on rust-lang/rust as that's the only time it appears outside sysroot). - // - // A more ideal solution might be to reanalyze crates based on where the cursor is and - // figure out the set of cfgs that would have to apply to make it active. - - cfg_options.apply_diff(overrides.clone()); - }; - - has_private |= cargo[pkg].metadata.rustc_private; - let mut lib_tgt = None; - for &tgt in cargo[pkg].targets.iter() { - if cargo[tgt].kind != TargetKind::Lib && !cargo[pkg].is_member { - // For non-workspace-members, Cargo does not resolve dev-dependencies, so we don't - // add any targets except the library target, since those will not work correctly if - // they use dev-dependencies. - // In fact, they can break quite badly if multiple client workspaces get merged: - // https://github.com/rust-lang/rust-analyzer/issues/11300 - continue; - } - - if let Some(file_id) = load(&cargo[tgt].root) { - let crate_id = add_target_crate_root( - &mut crate_graph, - &cargo[pkg], - build_scripts.get_output(pkg), - cfg_options.clone(), - &mut |path| load_proc_macro(&cargo[tgt].name, path), - file_id, - &cargo[tgt].name, - cargo[tgt].is_proc_macro, - ); - if cargo[tgt].kind == TargetKind::Lib { - lib_tgt = Some((crate_id, cargo[tgt].name.clone())); - pkg_to_lib_crate.insert(pkg, crate_id); - } - if let Some(proc_macro) = libproc_macro { - add_dep_with_prelude( - &mut crate_graph, - crate_id, - CrateName::new("proc_macro").unwrap(), - proc_macro, - cargo[tgt].is_proc_macro, - ); - } - - pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, cargo[tgt].kind)); - } - } - - // Set deps to the core, std and to the lib target of the current package - for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() { - // Add sysroot deps first so that a lib target named `core` etc. can overwrite them. - public_deps.add(*from, &mut crate_graph); - - if let Some((to, name)) = lib_tgt.clone() { - if to != *from && *kind != TargetKind::BuildScript { - // (build script can not depend on its library target) - - // For root projects with dashes in their name, - // cargo metadata does not do any normalization, - // so we do it ourselves currently - let name = CrateName::normalize_dashes(&name); - add_dep(&mut crate_graph, *from, name, to); - } - } - } - } - - // Now add a dep edge from all targets of upstream to the lib - // target of downstream. - for pkg in cargo.packages() { - for dep in cargo[pkg].dependencies.iter() { - let name = CrateName::new(&dep.name).unwrap(); - if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { - for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() { - if dep.kind == DepKind::Build && *kind != TargetKind::BuildScript { - // Only build scripts may depend on build dependencies. - continue; - } - if dep.kind != DepKind::Build && *kind == TargetKind::BuildScript { - // Build scripts may only depend on build dependencies. - continue; - } - - add_dep(&mut crate_graph, *from, name.clone(), to) - } - } - } - } - - if has_private { - // If the user provided a path to rustc sources, we add all the rustc_private crates - // and create dependencies on them for the crates which opt-in to that - if let Some(rustc_workspace) = rustc { - handle_rustc_crates( - rustc_workspace, - load, - &mut crate_graph, - &cfg_options, - override_cfg, - load_proc_macro, - &mut pkg_to_lib_crate, - &public_deps, - cargo, - &pkg_crates, - build_scripts, - ); - } - } - crate_graph -} - -fn detached_files_to_crate_graph( - rustc_cfg: Vec, - load: &mut dyn FnMut(&AbsPath) -> Option, - detached_files: &[AbsPathBuf], - sysroot: &Sysroot, -) -> CrateGraph { - let _p = profile::span("detached_files_to_crate_graph"); - let mut crate_graph = CrateGraph::default(); - let (public_deps, _libproc_macro) = - sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load); - - let mut cfg_options = CfgOptions::default(); - cfg_options.extend(rustc_cfg); - - for detached_file in detached_files { - let file_id = match load(detached_file) { - Some(file_id) => file_id, - None => { - tracing::error!("Failed to load detached file {:?}", detached_file); - continue; - } - }; - let display_name = detached_file - .file_stem() - .and_then(|os_str| os_str.to_str()) - .map(|file_stem| CrateDisplayName::from_canonical_name(file_stem.to_string())); - let detached_file_crate = crate_graph.add_crate_root( - file_id, - Edition::CURRENT, - display_name, - None, - cfg_options.clone(), - cfg_options.clone(), - Env::default(), - Ok(Vec::new()), - false, - CrateOrigin::CratesIo { repo: None }, - ); - - public_deps.add(detached_file_crate, &mut crate_graph); - } - crate_graph -} - -fn handle_rustc_crates( - rustc_workspace: &CargoWorkspace, - load: &mut dyn FnMut(&AbsPath) -> Option, - crate_graph: &mut CrateGraph, - cfg_options: &CfgOptions, - override_cfg: &CfgOverrides, - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, - pkg_to_lib_crate: &mut FxHashMap, CrateId>, - public_deps: &SysrootPublicDeps, - cargo: &CargoWorkspace, - pkg_crates: &FxHashMap, Vec<(CrateId, TargetKind)>>, - build_scripts: &WorkspaceBuildScripts, -) { - let mut rustc_pkg_crates = FxHashMap::default(); - // The root package of the rustc-dev component is rustc_driver, so we match that - let root_pkg = - rustc_workspace.packages().find(|package| rustc_workspace[*package].name == "rustc_driver"); - // The rustc workspace might be incomplete (such as if rustc-dev is not - // installed for the current toolchain) and `rustc_source` is set to discover. - if let Some(root_pkg) = root_pkg { - // Iterate through every crate in the dependency subtree of rustc_driver using BFS - let mut queue = VecDeque::new(); - queue.push_back(root_pkg); - while let Some(pkg) = queue.pop_front() { - // Don't duplicate packages if they are dependended on a diamond pattern - // N.B. if this line is ommitted, we try to analyse over 4_800_000 crates - // which is not ideal - if rustc_pkg_crates.contains_key(&pkg) { - continue; - } - for dep in &rustc_workspace[pkg].dependencies { - queue.push_back(dep.pkg); - } - - let mut cfg_options = cfg_options.clone(); - - let overrides = match override_cfg { - CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff), - CfgOverrides::Selective(cfg_overrides) => { - cfg_overrides.get(&rustc_workspace[pkg].name) - } - }; - - if let Some(overrides) = overrides { - // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen - // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while - // working on rust-lang/rust as that's the only time it appears outside sysroot). - // - // A more ideal solution might be to reanalyze crates based on where the cursor is and - // figure out the set of cfgs that would have to apply to make it active. - - cfg_options.apply_diff(overrides.clone()); - }; - - for &tgt in rustc_workspace[pkg].targets.iter() { - if rustc_workspace[tgt].kind != TargetKind::Lib { - continue; - } - if let Some(file_id) = load(&rustc_workspace[tgt].root) { - let crate_id = add_target_crate_root( - crate_graph, - &rustc_workspace[pkg], - build_scripts.get_output(pkg), - cfg_options.clone(), - &mut |path| load_proc_macro(&rustc_workspace[tgt].name, path), - file_id, - &rustc_workspace[tgt].name, - rustc_workspace[tgt].is_proc_macro, - ); - pkg_to_lib_crate.insert(pkg, crate_id); - // Add dependencies on core / std / alloc for this crate - public_deps.add(crate_id, crate_graph); - rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); - } - } - } - } - // Now add a dep edge from all targets of upstream to the lib - // target of downstream. - for pkg in rustc_pkg_crates.keys().copied() { - for dep in rustc_workspace[pkg].dependencies.iter() { - let name = CrateName::new(&dep.name).unwrap(); - if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { - for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() { - add_dep(crate_graph, from, name.clone(), to); - } - } - } - } - // Add a dependency on the rustc_private crates for all targets of each package - // which opts in - for dep in rustc_workspace.packages() { - let name = CrateName::normalize_dashes(&rustc_workspace[dep].name); - - if let Some(&to) = pkg_to_lib_crate.get(&dep) { - for pkg in cargo.packages() { - let package = &cargo[pkg]; - if !package.metadata.rustc_private { - continue; - } - for (from, _) in pkg_crates.get(&pkg).into_iter().flatten() { - // Avoid creating duplicate dependencies - // This avoids the situation where `from` depends on e.g. `arrayvec`, but - // `rust_analyzer` thinks that it should use the one from the `rustc_source` - // instead of the one from `crates.io` - if !crate_graph[*from].dependencies.iter().any(|d| d.name == name) { - add_dep(crate_graph, *from, name.clone(), to); - } - } - } - } - } -} - -fn add_target_crate_root( - crate_graph: &mut CrateGraph, - pkg: &PackageData, - build_data: Option<&BuildScriptOutput>, - cfg_options: CfgOptions, - load_proc_macro: &mut dyn FnMut(&AbsPath) -> ProcMacroLoadResult, - file_id: FileId, - cargo_name: &str, - is_proc_macro: bool, -) -> CrateId { - let edition = pkg.edition; - let mut potential_cfg_options = cfg_options.clone(); - potential_cfg_options.extend( - pkg.features - .iter() - .map(|feat| CfgFlag::KeyValue { key: "feature".into(), value: feat.0.into() }), - ); - let cfg_options = { - let mut opts = cfg_options; - for feature in pkg.active_features.iter() { - opts.insert_key_value("feature".into(), feature.into()); - } - if let Some(cfgs) = build_data.as_ref().map(|it| &it.cfgs) { - opts.extend(cfgs.iter().cloned()); - } - opts - }; - - let mut env = Env::default(); - inject_cargo_env(pkg, &mut env); - - if let Some(envs) = build_data.map(|it| &it.envs) { - for (k, v) in envs { - env.set(k, v.clone()); - } - } - - let proc_macro = match build_data.as_ref().map(|it| it.proc_macro_dylib_path.as_ref()) { - Some(Some(it)) => load_proc_macro(it), - Some(None) => Err("no proc macro dylib present".into()), - None => Err("crate has not (yet) been built".into()), - }; - - let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string()); - crate_graph.add_crate_root( - file_id, - edition, - Some(display_name), - Some(pkg.version.to_string()), - cfg_options, - potential_cfg_options, - env, - proc_macro, - is_proc_macro, - CrateOrigin::CratesIo { repo: pkg.repository.clone() }, - ) -} - -#[derive(Default)] -struct SysrootPublicDeps { - deps: Vec<(CrateName, CrateId, bool)>, -} - -impl SysrootPublicDeps { - /// Makes `from` depend on the public sysroot crates. - fn add(&self, from: CrateId, crate_graph: &mut CrateGraph) { - for (name, krate, prelude) in &self.deps { - add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude); - } - } -} - -fn sysroot_to_crate_graph( - crate_graph: &mut CrateGraph, - sysroot: &Sysroot, - rustc_cfg: Vec, - load: &mut dyn FnMut(&AbsPath) -> Option, -) -> (SysrootPublicDeps, Option) { - let _p = profile::span("sysroot_to_crate_graph"); - let mut cfg_options = CfgOptions::default(); - cfg_options.extend(rustc_cfg); - let sysroot_crates: FxHashMap = sysroot - .crates() - .filter_map(|krate| { - let file_id = load(&sysroot[krate].root)?; - - let env = Env::default(); - let display_name = CrateDisplayName::from_canonical_name(sysroot[krate].name.clone()); - let crate_id = crate_graph.add_crate_root( - file_id, - Edition::CURRENT, - Some(display_name), - None, - cfg_options.clone(), - cfg_options.clone(), - env, - Err("no proc macro loaded for sysroot crate".into()), - false, - CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)), - ); - Some((krate, crate_id)) - }) - .collect(); - - for from in sysroot.crates() { - for &to in sysroot[from].deps.iter() { - let name = CrateName::new(&sysroot[to].name).unwrap(); - if let (Some(&from), Some(&to)) = (sysroot_crates.get(&from), sysroot_crates.get(&to)) { - add_dep(crate_graph, from, name, to); - } - } - } - - let public_deps = SysrootPublicDeps { - deps: sysroot - .public_deps() - .map(|(name, idx, prelude)| { - (CrateName::new(name).unwrap(), sysroot_crates[&idx], prelude) - }) - .collect::>(), - }; - - let libproc_macro = sysroot.proc_macro().and_then(|it| sysroot_crates.get(&it).copied()); - (public_deps, libproc_macro) -} - -fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) { - add_dep_inner(graph, from, Dependency::new(name, to)) -} - -fn add_dep_with_prelude( - graph: &mut CrateGraph, - from: CrateId, - name: CrateName, - to: CrateId, - prelude: bool, -) { - add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude)) -} - -fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) { - if let Err(err) = graph.add_dep(from, dep) { - tracing::error!("{}", err) - } -} - -/// Recreates the compile-time environment variables that Cargo sets. -/// -/// Should be synced with -/// -/// -/// FIXME: ask Cargo to provide this data instead of re-deriving. -fn inject_cargo_env(package: &PackageData, env: &mut Env) { - // FIXME: Missing variables: - // CARGO_BIN_NAME, CARGO_BIN_EXE_ - - let manifest_dir = package.manifest.parent(); - env.set("CARGO_MANIFEST_DIR", manifest_dir.as_os_str().to_string_lossy().into_owned()); - - // Not always right, but works for common cases. - env.set("CARGO", "cargo".into()); - - env.set("CARGO_PKG_VERSION", package.version.to_string()); - env.set("CARGO_PKG_VERSION_MAJOR", package.version.major.to_string()); - env.set("CARGO_PKG_VERSION_MINOR", package.version.minor.to_string()); - env.set("CARGO_PKG_VERSION_PATCH", package.version.patch.to_string()); - env.set("CARGO_PKG_VERSION_PRE", package.version.pre.to_string()); - - env.set("CARGO_PKG_AUTHORS", String::new()); - - env.set("CARGO_PKG_NAME", package.name.clone()); - // FIXME: This isn't really correct (a package can have many crates with different names), but - // it's better than leaving the variable unset. - env.set("CARGO_CRATE_NAME", CrateName::normalize_dashes(&package.name).to_string()); - env.set("CARGO_PKG_DESCRIPTION", String::new()); - env.set("CARGO_PKG_HOMEPAGE", String::new()); - env.set("CARGO_PKG_REPOSITORY", String::new()); - env.set("CARGO_PKG_LICENSE", String::new()); - - env.set("CARGO_PKG_LICENSE_FILE", String::new()); -} diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/alloc/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/alloc/src/lib.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/core/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/core/src/lib.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/panic_abort/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/panic_abort/src/lib.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/panic_unwind/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/panic_unwind/src/lib.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/proc_macro/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/proc_macro/src/lib.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/profiler_builtins/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/profiler_builtins/src/lib.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/std/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/std/src/lib.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/stdarch/crates/std_detect/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/stdarch/crates/std_detect/src/lib.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/term/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/term/src/lib.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/test/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/test/src/lib.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/unwind/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/test_data/fake-sysroot/unwind/src/lib.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/hello-world-metadata.json b/src/tools/rust-analyzer/crates/project-model/test_data/hello-world-metadata.json deleted file mode 100644 index b6142eeaf2f60..0000000000000 --- a/src/tools/rust-analyzer/crates/project-model/test_data/hello-world-metadata.json +++ /dev/null @@ -1,245 +0,0 @@ -{ - "packages": [ - { - "name": "hello-world", - "version": "0.1.0", - "id": "hello-world 0.1.0 (path+file://$ROOT$hello-world)", - "license": null, - "license_file": null, - "description": null, - "source": null, - "dependencies": [ - { - "name": "libc", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^0.2", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "hello-world", - "src_path": "$ROOT$hello-world/src/lib.rs", - "edition": "2018", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "bin" - ], - "crate_types": [ - "bin" - ], - "name": "hello-world", - "src_path": "$ROOT$hello-world/src/main.rs", - "edition": "2018", - "doc": true, - "doctest": false, - "test": true - }, - { - "kind": [ - "example" - ], - "crate_types": [ - "bin" - ], - "name": "an-example", - "src_path": "$ROOT$hello-world/examples/an-example.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": false - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "it", - "src_path": "$ROOT$hello-world/tests/it.rs", - "edition": "2018", - "doc": false, - "doctest": false, - "test": true - } - ], - "features": {}, - "manifest_path": "$ROOT$hello-world/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [], - "categories": [], - "keywords": [], - "readme": null, - "repository": null, - "homepage": null, - "documentation": null, - "edition": "2018", - "links": null - }, - { - "name": "libc", - "version": "0.2.98", - "id": "libc 0.2.98 (registry+https://github.com/rust-lang/crates.io-index)", - "license": "MIT OR Apache-2.0", - "license_file": null, - "description": "Raw FFI bindings to platform libraries like libc.\n", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "dependencies": [ - { - "name": "rustc-std-workspace-core", - "source": "registry+https://github.com/rust-lang/crates.io-index", - "req": "^1.0.0", - "kind": null, - "rename": null, - "optional": true, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "libc", - "src_path": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98/src/lib.rs", - "edition": "2015", - "doc": true, - "doctest": true, - "test": true - }, - { - "kind": [ - "test" - ], - "crate_types": [ - "bin" - ], - "name": "const_fn", - "src_path": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98/tests/const_fn.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": true - }, - { - "kind": [ - "custom-build" - ], - "crate_types": [ - "bin" - ], - "name": "build-script-build", - "src_path": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98/build.rs", - "edition": "2015", - "doc": false, - "doctest": false, - "test": false - } - ], - "features": { - "align": [], - "const-extern-fn": [], - "default": [ - "std" - ], - "extra_traits": [], - "rustc-dep-of-std": [ - "align", - "rustc-std-workspace-core" - ], - "std": [], - "use_std": [ - "std" - ] - }, - "manifest_path": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [ - "The Rust Project Developers" - ], - "categories": [ - "external-ffi-bindings", - "no-std", - "os" - ], - "keywords": [ - "libc", - "ffi", - "bindings", - "operating", - "system" - ], - "readme": "README.md", - "repository": "https://github.com/rust-lang/libc", - "homepage": "https://github.com/rust-lang/libc", - "documentation": "https://docs.rs/libc/", - "edition": "2015", - "links": null - } - ], - "workspace_members": [ - "hello-world 0.1.0 (path+file://$ROOT$hello-world)" - ], - "resolve": { - "nodes": [ - { - "id": "hello-world 0.1.0 (path+file://$ROOT$hello-world)", - "dependencies": [ - "libc 0.2.98 (registry+https://github.com/rust-lang/crates.io-index)" - ], - "deps": [ - { - "name": "libc", - "pkg": "libc 0.2.98 (registry+https://github.com/rust-lang/crates.io-index)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [] - }, - { - "id": "libc 0.2.98 (registry+https://github.com/rust-lang/crates.io-index)", - "dependencies": [], - "deps": [], - "features": [ - "default", - "std" - ] - } - ], - "root": "hello-world 0.1.0 (path+file://$ROOT$hello-world)" - }, - "target_directory": "$ROOT$hello-world/target", - "version": 1, - "workspace_root": "$ROOT$hello-world", - "metadata": null -} diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/hello-world-project.json b/src/tools/rust-analyzer/crates/project-model/test_data/hello-world-project.json deleted file mode 100644 index b27ab1f42b577..0000000000000 --- a/src/tools/rust-analyzer/crates/project-model/test_data/hello-world-project.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "sysroot_src": null, - "crates": [ - { - "display_name": "hello_world", - "root_module": "$ROOT$src/lib.rs", - "edition": "2018", - "deps": [], - "is_workspace_member": true - } - ] -} diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/is-proc-macro-project.json b/src/tools/rust-analyzer/crates/project-model/test_data/is-proc-macro-project.json deleted file mode 100644 index 5d500a4729f57..0000000000000 --- a/src/tools/rust-analyzer/crates/project-model/test_data/is-proc-macro-project.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "sysroot_src": null, - "crates": [ - { - "display_name": "is_proc_macro", - "root_module": "$ROOT$src/lib.rs", - "edition": "2018", - "deps": [], - "is_workspace_member": true, - "is_proc_macro": true - } - ] -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml deleted file mode 100644 index 07771d1b392ce..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml +++ /dev/null @@ -1,92 +0,0 @@ -[package] -name = "rust-analyzer" -version = "0.0.0" -authors = ["rust-analyzer Team"] -homepage = "https://github.com/rust-analyzer/rust-analyzer" -description = "A language server for the Rust programming language" -documentation = "https://rust-analyzer.github.io/manual.html" -license = "MIT OR Apache-2.0" -autobins = false -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[[bin]] -name = "rust-analyzer" -path = "src/bin/main.rs" - -[dependencies] -anyhow = "1.0.57" -crossbeam-channel = "0.5.5" -dissimilar = "1.0.4" -itertools = "0.10.3" -lsp-types = { version = "0.93.0", features = ["proposed"] } -parking_lot = "0.12.1" -xflags = "0.2.4" -oorandom = "11.1.3" -rustc-hash = "1.1.0" -serde = { version = "1.0.137", features = ["derive"] } -serde_json = { version = "1.0.81", features = ["preserve_order"] } -threadpool = "1.8.1" -rayon = "1.5.3" -num_cpus = "1.13.1" -mimalloc = { version = "0.1.29", default-features = false, optional = true } -lsp-server = { version = "0.6.0", path = "../../lib/lsp-server" } -tracing = "0.1.35" -tracing-subscriber = { version = "0.3.14", default-features = false, features = [ - "env-filter", - "registry", - "fmt", - "tracing-log", -] } -tracing-log = "0.1.3" -tracing-tree = "0.2.1" -always-assert = "0.1.2" - -stdx = { path = "../stdx", version = "0.0.0" } -flycheck = { path = "../flycheck", version = "0.0.0" } -ide = { path = "../ide", version = "0.0.0" } -ide-db = { path = "../ide-db", version = "0.0.0" } -profile = { path = "../profile", version = "0.0.0" } -project-model = { path = "../project-model", version = "0.0.0" } -syntax = { path = "../syntax", version = "0.0.0" } -vfs = { path = "../vfs", version = "0.0.0" } -vfs-notify = { path = "../vfs-notify", version = "0.0.0" } -cfg = { path = "../cfg", version = "0.0.0" } -toolchain = { path = "../toolchain", version = "0.0.0" } -tt = { path = "../tt", version = "0.0.0" } -proc-macro-api = { path = "../proc-macro-api", version = "0.0.0" } - -# This should only be used in CLI -ide-ssr = { path = "../ide-ssr", version = "0.0.0" } -hir = { path = "../hir", version = "0.0.0" } -hir-def = { path = "../hir-def", version = "0.0.0" } -hir-ty = { path = "../hir-ty", version = "0.0.0" } -proc-macro-srv = { path = "../proc-macro-srv", version = "0.0.0" } - -[target.'cfg(windows)'.dependencies] -winapi = "0.3.9" - -[target.'cfg(not(target_env = "msvc"))'.dependencies] -jemallocator = { version = "0.5.0", package = "tikv-jemallocator", optional = true } - -[dev-dependencies] -expect-test = "1.4.0" -jod-thread = "0.1.2" -xshell = "0.2.2" - -test-utils = { path = "../test-utils" } -sourcegen = { path = "../sourcegen" } -mbe = { path = "../mbe" } - -[features] -jemalloc = ["jemallocator", "profile/jemalloc"] -force-always-assert = ["always-assert/force"] -in-rust-tree = [ - "proc-macro-srv/sysroot-abi", - "sourcegen/in-rust-tree", - "ide/in-rust-tree", - "syntax/in-rust-tree" -] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/build.rs b/src/tools/rust-analyzer/crates/rust-analyzer/build.rs deleted file mode 100644 index 15935e2da8d00..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/build.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! Construct version in the `commit-hash date channel` format - -use std::{env, path::PathBuf, process::Command}; - -fn main() { - set_rerun(); - set_commit_info(); - if option_env!("CFG_RELEASE").is_none() { - println!("cargo:rustc-env=POKE_RA_DEVS=1"); - } -} - -fn set_rerun() { - println!("cargo:rerun-if-env-changed=CFG_RELEASE"); - - let mut manifest_dir = PathBuf::from( - env::var("CARGO_MANIFEST_DIR").expect("`CARGO_MANIFEST_DIR` is always set by cargo."), - ); - - while manifest_dir.parent().is_some() { - let head_ref = manifest_dir.join(".git/HEAD"); - if head_ref.exists() { - println!("cargo:rerun-if-changed={}", head_ref.display()); - return; - } - - manifest_dir.pop(); - } - - println!("cargo:warning=Could not find `.git/HEAD` from manifest dir!"); -} - -fn set_commit_info() { - let output = match Command::new("git") - .arg("log") - .arg("-1") - .arg("--date=short") - .arg("--format=%H %h %cd") - .output() - { - Ok(output) if output.status.success() => output, - _ => return, - }; - let stdout = String::from_utf8(output.stdout).unwrap(); - let mut parts = stdout.split_whitespace(); - let mut next = || parts.next().unwrap(); - println!("cargo:rustc-env=RA_COMMIT_HASH={}", next()); - println!("cargo:rustc-env=RA_COMMIT_SHORT_HASH={}", next()); - println!("cargo:rustc-env=RA_COMMIT_DATE={}", next()) -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/logger.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/logger.rs deleted file mode 100644 index 0b69f75bc0db0..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/logger.rs +++ /dev/null @@ -1,155 +0,0 @@ -//! Simple logger that logs either to stderr or to a file, using `tracing_subscriber` -//! filter syntax and `tracing_appender` for non blocking output. - -use std::{ - fmt, - fs::File, - io::{self, Stderr}, - sync::Arc, -}; - -use rust_analyzer::Result; -use tracing::{level_filters::LevelFilter, Event, Subscriber}; -use tracing_log::NormalizeEvent; -use tracing_subscriber::{ - fmt::{ - format::Writer, writer::BoxMakeWriter, FmtContext, FormatEvent, FormatFields, - FormattedFields, MakeWriter, - }, - layer::SubscriberExt, - registry::LookupSpan, - util::SubscriberInitExt, - EnvFilter, Registry, -}; -use tracing_tree::HierarchicalLayer; - -pub(crate) struct Logger { - filter: EnvFilter, - file: Option, -} - -struct MakeWriterStderr; - -impl<'a> MakeWriter<'a> for MakeWriterStderr { - type Writer = Stderr; - - fn make_writer(&'a self) -> Self::Writer { - io::stderr() - } -} - -impl Logger { - pub(crate) fn new(file: Option, filter: Option<&str>) -> Logger { - let filter = filter.map_or(EnvFilter::default(), EnvFilter::new); - - Logger { filter, file } - } - - pub(crate) fn install(self) -> Result<()> { - // The meaning of CHALK_DEBUG I suspected is to tell chalk crates - // (i.e. chalk-solve, chalk-ir, chalk-recursive) how to filter tracing - // logs. But now we can only have just one filter, which means we have to - // merge chalk filter to our main filter (from RA_LOG env). - // - // The acceptable syntax of CHALK_DEBUG is `target[span{field=value}]=level`. - // As the value should only affect chalk crates, we'd better mannually - // specify the target. And for simplicity, CHALK_DEBUG only accept the value - // that specify level. - let chalk_level_dir = std::env::var("CHALK_DEBUG") - .map(|val| { - val.parse::().expect( - "invalid CHALK_DEBUG value, expect right log level (like debug or trace)", - ) - }) - .ok(); - - let chalk_layer = HierarchicalLayer::default() - .with_indent_lines(true) - .with_ansi(false) - .with_indent_amount(2) - .with_writer(io::stderr); - - let writer = match self.file { - Some(file) => BoxMakeWriter::new(Arc::new(file)), - None => BoxMakeWriter::new(io::stderr), - }; - let ra_fmt_layer = - tracing_subscriber::fmt::layer().event_format(LoggerFormatter).with_writer(writer); - - match chalk_level_dir { - Some(val) => { - Registry::default() - .with( - self.filter - .add_directive(format!("chalk_solve={}", val).parse()?) - .add_directive(format!("chalk_ir={}", val).parse()?) - .add_directive(format!("chalk_recursive={}", val).parse()?), - ) - .with(ra_fmt_layer) - .with(chalk_layer) - .init(); - } - None => { - Registry::default().with(self.filter).with(ra_fmt_layer).init(); - } - }; - - Ok(()) - } -} - -#[derive(Debug)] -struct LoggerFormatter; - -impl FormatEvent for LoggerFormatter -where - S: Subscriber + for<'a> LookupSpan<'a>, - N: for<'a> FormatFields<'a> + 'static, -{ - fn format_event( - &self, - ctx: &FmtContext<'_, S, N>, - mut writer: Writer<'_>, - event: &Event<'_>, - ) -> fmt::Result { - // Write level and target - let level = *event.metadata().level(); - - // If this event is issued from `log` crate, then the value of target is - // always "log". `tracing-log` has hard coded it for some reason, so we - // need to extract it using `normalized_metadata` method which is part of - // `tracing_log::NormalizeEvent`. - let target = match event.normalized_metadata() { - // This event is issued from `log` crate - Some(log) => log.target(), - None => event.metadata().target(), - }; - write!(writer, "[{} {}] ", level, target)?; - - // Write spans and fields of each span - ctx.visit_spans(|span| { - write!(writer, "{}", span.name())?; - - let ext = span.extensions(); - - // `FormattedFields` is a a formatted representation of the span's - // fields, which is stored in its extensions by the `fmt` layer's - // `new_span` method. The fields will have been formatted - // by the same field formatter that's provided to the event - // formatter in the `FmtContext`. - let fields = &ext.get::>().expect("will never be `None`"); - - if !fields.is_empty() { - write!(writer, "{{{}}}", fields)?; - } - write!(writer, ": ")?; - - Ok(()) - })?; - - // Write fields on the event - ctx.field_format().format_fields(writer.by_ref(), event)?; - - writeln!(writer) - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs deleted file mode 100644 index e9de23cb395d1..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ /dev/null @@ -1,239 +0,0 @@ -//! Driver for rust-analyzer. -//! -//! Based on cli flags, either spawns an LSP server, or runs a batch analysis - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -mod logger; -mod rustc_wrapper; - -use std::{env, fs, path::Path, process}; - -use lsp_server::Connection; -use project_model::ProjectManifest; -use rust_analyzer::{cli::flags, config::Config, from_json, lsp_ext::supports_utf8, Result}; -use vfs::AbsPathBuf; - -#[cfg(all(feature = "mimalloc"))] -#[global_allocator] -static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; - -#[cfg(all(feature = "jemalloc", not(target_env = "msvc")))] -#[global_allocator] -static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; - -fn main() { - if std::env::var("RA_RUSTC_WRAPPER").is_ok() { - let mut args = std::env::args_os(); - let _me = args.next().unwrap(); - let rustc = args.next().unwrap(); - let code = match rustc_wrapper::run_rustc_skipping_cargo_checking(rustc, args.collect()) { - Ok(rustc_wrapper::ExitCode(code)) => code.unwrap_or(102), - Err(err) => { - eprintln!("{}", err); - 101 - } - }; - process::exit(code); - } - - if let Err(err) = try_main() { - tracing::error!("Unexpected error: {}", err); - eprintln!("{}", err); - process::exit(101); - } -} - -fn try_main() -> Result<()> { - let flags = flags::RustAnalyzer::from_env()?; - - #[cfg(debug_assertions)] - if flags.wait_dbg || env::var("RA_WAIT_DBG").is_ok() { - #[allow(unused_mut)] - let mut d = 4; - while d == 4 { - d = 4; - } - } - - let mut log_file = flags.log_file.as_deref(); - - let env_log_file = env::var("RA_LOG_FILE").ok(); - if let Some(env_log_file) = env_log_file.as_deref() { - log_file = Some(Path::new(env_log_file)); - } - - setup_logging(log_file)?; - let verbosity = flags.verbosity(); - - match flags.subcommand { - flags::RustAnalyzerCmd::LspServer(cmd) => { - if cmd.print_config_schema { - println!("{:#}", Config::json_schema()); - return Ok(()); - } - if cmd.version { - println!("rust-analyzer {}", rust_analyzer::version()); - return Ok(()); - } - if cmd.help { - println!("{}", flags::RustAnalyzer::HELP); - return Ok(()); - } - with_extra_thread("LspServer", run_server)?; - } - flags::RustAnalyzerCmd::ProcMacro(flags::ProcMacro) => { - with_extra_thread("MacroExpander", || proc_macro_srv::cli::run().map_err(Into::into))?; - } - flags::RustAnalyzerCmd::Parse(cmd) => cmd.run()?, - flags::RustAnalyzerCmd::Symbols(cmd) => cmd.run()?, - flags::RustAnalyzerCmd::Highlight(cmd) => cmd.run()?, - flags::RustAnalyzerCmd::AnalysisStats(cmd) => cmd.run(verbosity)?, - flags::RustAnalyzerCmd::Diagnostics(cmd) => cmd.run()?, - flags::RustAnalyzerCmd::Ssr(cmd) => cmd.run()?, - flags::RustAnalyzerCmd::Search(cmd) => cmd.run()?, - flags::RustAnalyzerCmd::Lsif(cmd) => cmd.run()?, - } - Ok(()) -} - -fn setup_logging(log_file: Option<&Path>) -> Result<()> { - if cfg!(windows) { - // This is required so that windows finds our pdb that is placed right beside the exe. - // By default it doesn't look at the folder the exe resides in, only in the current working - // directory which we set to the project workspace. - // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/general-environment-variables - // https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-syminitialize - if let Ok(path) = env::current_exe() { - if let Some(path) = path.parent() { - env::set_var("_NT_SYMBOL_PATH", path); - } - } - } - if env::var("RUST_BACKTRACE").is_err() { - env::set_var("RUST_BACKTRACE", "short"); - } - - let log_file = match log_file { - Some(path) => { - if let Some(parent) = path.parent() { - let _ = fs::create_dir_all(parent); - } - Some(fs::File::create(path)?) - } - None => None, - }; - let filter = env::var("RA_LOG").ok(); - // deliberately enable all `error` logs if the user has not set RA_LOG, as there is usually useful - // information in there for debugging - logger::Logger::new(log_file, filter.as_deref().or(Some("error"))).install()?; - - profile::init(); - - Ok(()) -} - -const STACK_SIZE: usize = 1024 * 1024 * 8; - -/// Parts of rust-analyzer can use a lot of stack space, and some operating systems only give us -/// 1 MB by default (eg. Windows), so this spawns a new thread with hopefully sufficient stack -/// space. -fn with_extra_thread( - thread_name: impl Into, - f: impl FnOnce() -> Result<()> + Send + 'static, -) -> Result<()> { - let handle = - std::thread::Builder::new().name(thread_name.into()).stack_size(STACK_SIZE).spawn(f)?; - match handle.join() { - Ok(res) => res, - Err(panic) => std::panic::resume_unwind(panic), - } -} - -fn run_server() -> Result<()> { - tracing::info!("server version {} will start", rust_analyzer::version()); - - let (connection, io_threads) = Connection::stdio(); - - let (initialize_id, initialize_params) = connection.initialize_start()?; - tracing::info!("InitializeParams: {}", initialize_params); - let initialize_params = - from_json::("InitializeParams", &initialize_params)?; - - let root_path = match initialize_params - .root_uri - .and_then(|it| it.to_file_path().ok()) - .and_then(|it| AbsPathBuf::try_from(it).ok()) - { - Some(it) => it, - None => { - let cwd = env::current_dir()?; - AbsPathBuf::assert(cwd) - } - }; - - let mut config = Config::new(root_path, initialize_params.capabilities); - if let Some(json) = initialize_params.initialization_options { - if let Err(e) = config.update(json) { - use lsp_types::{ - notification::{Notification, ShowMessage}, - MessageType, ShowMessageParams, - }; - let not = lsp_server::Notification::new( - ShowMessage::METHOD.to_string(), - ShowMessageParams { typ: MessageType::WARNING, message: e.to_string() }, - ); - connection.sender.send(lsp_server::Message::Notification(not)).unwrap(); - } - } - - let server_capabilities = rust_analyzer::server_capabilities(&config); - - let initialize_result = lsp_types::InitializeResult { - capabilities: server_capabilities, - server_info: Some(lsp_types::ServerInfo { - name: String::from("rust-analyzer"), - version: Some(rust_analyzer::version().to_string()), - }), - offset_encoding: if supports_utf8(config.caps()) { - Some("utf-8".to_string()) - } else { - None - }, - }; - - let initialize_result = serde_json::to_value(initialize_result).unwrap(); - - connection.initialize_finish(initialize_id, initialize_result)?; - - if let Some(client_info) = initialize_params.client_info { - tracing::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); - } - - if config.linked_projects().is_empty() && config.detached_files().is_empty() { - let workspace_roots = initialize_params - .workspace_folders - .map(|workspaces| { - workspaces - .into_iter() - .filter_map(|it| it.uri.to_file_path().ok()) - .filter_map(|it| AbsPathBuf::try_from(it).ok()) - .collect::>() - }) - .filter(|workspaces| !workspaces.is_empty()) - .unwrap_or_else(|| vec![config.root_path().clone()]); - - let discovered = ProjectManifest::discover_all(&workspace_roots); - tracing::info!("discovered projects: {:?}", discovered); - if discovered.is_empty() { - tracing::error!("failed to find any projects in {:?}", workspace_roots); - } - config.discovered_projects = Some(discovered); - } - - rust_analyzer::main_loop(config, connection)?; - - io_threads.join()?; - tracing::info!("server did shut down"); - Ok(()) -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/rustc_wrapper.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/rustc_wrapper.rs deleted file mode 100644 index 2f6d4706d879e..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/rustc_wrapper.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! We setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself during the -//! initial `cargo check`. That way, we avoid checking the actual project, and -//! only build proc macros and build.rs. -//! -//! Code taken from IntelliJ :0) -//! https://github.com/intellij-rust/intellij-rust/blob/master/native-helper/src/main.rs -use std::{ - ffi::OsString, - io, - process::{Command, Stdio}, -}; - -/// ExitCode/ExitStatus are impossible to create :(. -pub(crate) struct ExitCode(pub(crate) Option); - -pub(crate) fn run_rustc_skipping_cargo_checking( - rustc_executable: OsString, - args: Vec, -) -> io::Result { - let is_cargo_check = args.iter().any(|arg| { - let arg = arg.to_string_lossy(); - // `cargo check` invokes `rustc` with `--emit=metadata` argument. - // - // https://doc.rust-lang.org/rustc/command-line-arguments.html#--emit-specifies-the-types-of-output-files-to-generate - // link — Generates the crates specified by --crate-type. The default - // output filenames depend on the crate type and platform. This - // is the default if --emit is not specified. - // metadata — Generates a file containing metadata about the crate. - // The default output filename is CRATE_NAME.rmeta. - arg.starts_with("--emit=") && arg.contains("metadata") && !arg.contains("link") - }); - if is_cargo_check { - return Ok(ExitCode(Some(0))); - } - run_rustc(rustc_executable, args) -} - -fn run_rustc(rustc_executable: OsString, args: Vec) -> io::Result { - let mut child = Command::new(rustc_executable) - .args(args) - .stdin(Stdio::inherit()) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()) - .spawn()?; - Ok(ExitCode(child.wait()?.code())) -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs deleted file mode 100644 index cda95cd8626c9..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs +++ /dev/null @@ -1,210 +0,0 @@ -//! Advertises the capabilities of the LSP Server. -use lsp_types::{ - CallHierarchyServerCapability, ClientCapabilities, CodeActionKind, CodeActionOptions, - CodeActionProviderCapability, CodeLensOptions, CompletionOptions, - CompletionOptionsCompletionItem, DeclarationCapability, DocumentOnTypeFormattingOptions, - FileOperationFilter, FileOperationPattern, FileOperationPatternKind, - FileOperationRegistrationOptions, FoldingRangeProviderCapability, HoverProviderCapability, - ImplementationProviderCapability, InlayHintOptions, InlayHintServerCapabilities, OneOf, - RenameOptions, SaveOptions, SelectionRangeProviderCapability, SemanticTokensFullOptions, - SemanticTokensLegend, SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, - TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions, - TypeDefinitionProviderCapability, WorkDoneProgressOptions, - WorkspaceFileOperationsServerCapabilities, WorkspaceServerCapabilities, -}; -use serde_json::json; - -use crate::config::{Config, RustfmtConfig}; -use crate::semantic_tokens; - -pub fn server_capabilities(config: &Config) -> ServerCapabilities { - ServerCapabilities { - text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions { - open_close: Some(true), - change: Some(TextDocumentSyncKind::INCREMENTAL), - will_save: None, - will_save_wait_until: None, - save: Some(SaveOptions::default().into()), - })), - hover_provider: Some(HoverProviderCapability::Simple(true)), - completion_provider: Some(CompletionOptions { - resolve_provider: completions_resolve_provider(config.caps()), - trigger_characters: Some(vec![ - ":".to_string(), - ".".to_string(), - "'".to_string(), - "(".to_string(), - ]), - all_commit_characters: None, - completion_item: completion_item(&config), - work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, - }), - signature_help_provider: Some(SignatureHelpOptions { - trigger_characters: Some(vec!["(".to_string(), ",".to_string(), "<".to_string()]), - retrigger_characters: None, - work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, - }), - declaration_provider: Some(DeclarationCapability::Simple(true)), - definition_provider: Some(OneOf::Left(true)), - type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)), - implementation_provider: Some(ImplementationProviderCapability::Simple(true)), - references_provider: Some(OneOf::Left(true)), - document_highlight_provider: Some(OneOf::Left(true)), - document_symbol_provider: Some(OneOf::Left(true)), - workspace_symbol_provider: Some(OneOf::Left(true)), - code_action_provider: Some(code_action_capabilities(config.caps())), - code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }), - document_formatting_provider: Some(OneOf::Left(true)), - document_range_formatting_provider: match config.rustfmt() { - RustfmtConfig::Rustfmt { enable_range_formatting: true, .. } => Some(OneOf::Left(true)), - _ => Some(OneOf::Left(false)), - }, - document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { - first_trigger_character: "=".to_string(), - more_trigger_character: Some(more_trigger_character(&config)), - }), - selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)), - folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), - rename_provider: Some(OneOf::Right(RenameOptions { - prepare_provider: Some(true), - work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, - })), - linked_editing_range_provider: None, - document_link_provider: None, - color_provider: None, - execute_command_provider: None, - workspace: Some(WorkspaceServerCapabilities { - workspace_folders: None, - file_operations: Some(WorkspaceFileOperationsServerCapabilities { - did_create: None, - will_create: None, - did_rename: None, - will_rename: Some(FileOperationRegistrationOptions { - filters: vec![ - FileOperationFilter { - scheme: Some(String::from("file")), - pattern: FileOperationPattern { - glob: String::from("**/*.rs"), - matches: Some(FileOperationPatternKind::File), - options: None, - }, - }, - FileOperationFilter { - scheme: Some(String::from("file")), - pattern: FileOperationPattern { - glob: String::from("**"), - matches: Some(FileOperationPatternKind::Folder), - options: None, - }, - }, - ], - }), - did_delete: None, - will_delete: None, - }), - }), - call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)), - semantic_tokens_provider: Some( - SemanticTokensOptions { - legend: SemanticTokensLegend { - token_types: semantic_tokens::SUPPORTED_TYPES.to_vec(), - token_modifiers: semantic_tokens::SUPPORTED_MODIFIERS.to_vec(), - }, - - full: Some(SemanticTokensFullOptions::Delta { delta: Some(true) }), - range: Some(true), - work_done_progress_options: Default::default(), - } - .into(), - ), - moniker_provider: None, - inlay_hint_provider: Some(OneOf::Right(InlayHintServerCapabilities::Options( - InlayHintOptions { - work_done_progress_options: Default::default(), - resolve_provider: Some(true), - }, - ))), - experimental: Some(json!({ - "externalDocs": true, - "hoverRange": true, - "joinLines": true, - "matchingBrace": true, - "moveItem": true, - "onEnter": true, - "openCargoToml": true, - "parentModule": true, - "runnables": { - "kinds": [ "cargo" ], - }, - "ssr": true, - "workspaceSymbolScopeKindFiltering": true, - })), - } -} - -fn completions_resolve_provider(client_caps: &ClientCapabilities) -> Option { - if completion_item_edit_resolve(client_caps) { - Some(true) - } else { - tracing::info!("No `additionalTextEdits` completion resolve capability was found in the client capabilities, autoimport completion is disabled"); - None - } -} - -/// Parses client capabilities and returns all completion resolve capabilities rust-analyzer supports. -pub(crate) fn completion_item_edit_resolve(caps: &ClientCapabilities) -> bool { - (|| { - Some( - caps.text_document - .as_ref()? - .completion - .as_ref()? - .completion_item - .as_ref()? - .resolve_support - .as_ref()? - .properties - .iter() - .any(|cap_string| cap_string.as_str() == "additionalTextEdits"), - ) - })() == Some(true) -} - -fn completion_item(config: &Config) -> Option { - Some(CompletionOptionsCompletionItem { - label_details_support: Some(config.completion_label_details_support()), - }) -} - -fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProviderCapability { - client_caps - .text_document - .as_ref() - .and_then(|it| it.code_action.as_ref()) - .and_then(|it| it.code_action_literal_support.as_ref()) - .map_or(CodeActionProviderCapability::Simple(true), |_| { - CodeActionProviderCapability::Options(CodeActionOptions { - // Advertise support for all built-in CodeActionKinds. - // Ideally we would base this off of the client capabilities - // but the client is supposed to fall back gracefully for unknown values. - code_action_kinds: Some(vec![ - CodeActionKind::EMPTY, - CodeActionKind::QUICKFIX, - CodeActionKind::REFACTOR, - CodeActionKind::REFACTOR_EXTRACT, - CodeActionKind::REFACTOR_INLINE, - CodeActionKind::REFACTOR_REWRITE, - ]), - resolve_provider: Some(true), - work_done_progress_options: Default::default(), - }) - }) -} - -fn more_trigger_character(config: &Config) -> Vec { - let mut res = vec![".".to_string(), ">".to_string(), "{".to_string()]; - if config.snippet_cap() { - res.push("<".to_string()); - } - res -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs deleted file mode 100644 index 1c39e9391af24..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs +++ /dev/null @@ -1,228 +0,0 @@ -//! See `CargoTargetSpec` - -use std::mem; - -use cfg::{CfgAtom, CfgExpr}; -use ide::{FileId, RunnableKind, TestId}; -use project_model::{self, ManifestPath, TargetKind}; -use vfs::AbsPathBuf; - -use crate::{global_state::GlobalStateSnapshot, Result}; - -/// Abstract representation of Cargo target. -/// -/// We use it to cook up the set of cli args we need to pass to Cargo to -/// build/test/run the target. -#[derive(Clone)] -pub(crate) struct CargoTargetSpec { - pub(crate) workspace_root: AbsPathBuf, - pub(crate) cargo_toml: ManifestPath, - pub(crate) package: String, - pub(crate) target: String, - pub(crate) target_kind: TargetKind, - pub(crate) required_features: Vec, -} - -impl CargoTargetSpec { - pub(crate) fn runnable_args( - snap: &GlobalStateSnapshot, - spec: Option, - kind: &RunnableKind, - cfg: &Option, - ) -> Result<(Vec, Vec)> { - let mut args = Vec::new(); - let mut extra_args = Vec::new(); - - match kind { - RunnableKind::Test { test_id, attr } => { - args.push("test".to_string()); - extra_args.push(test_id.to_string()); - if let TestId::Path(_) = test_id { - extra_args.push("--exact".to_string()); - } - extra_args.push("--nocapture".to_string()); - if attr.ignore { - extra_args.push("--ignored".to_string()); - } - } - RunnableKind::TestMod { path } => { - args.push("test".to_string()); - extra_args.push(path.to_string()); - extra_args.push("--nocapture".to_string()); - } - RunnableKind::Bench { test_id } => { - args.push("bench".to_string()); - extra_args.push(test_id.to_string()); - if let TestId::Path(_) = test_id { - extra_args.push("--exact".to_string()); - } - extra_args.push("--nocapture".to_string()); - } - RunnableKind::DocTest { test_id } => { - args.push("test".to_string()); - args.push("--doc".to_string()); - extra_args.push(test_id.to_string()); - extra_args.push("--nocapture".to_string()); - } - RunnableKind::Bin => { - let subcommand = match spec { - Some(CargoTargetSpec { target_kind: TargetKind::Test, .. }) => "test", - _ => "run", - }; - args.push(subcommand.to_string()); - } - } - - let target_required_features = if let Some(mut spec) = spec { - let required_features = mem::take(&mut spec.required_features); - spec.push_to(&mut args, kind); - required_features - } else { - Vec::new() - }; - - let cargo_config = snap.config.cargo(); - if cargo_config.all_features { - args.push("--all-features".to_string()); - - for feature in target_required_features { - args.push("--features".to_string()); - args.push(feature); - } - } else { - let mut features = Vec::new(); - if let Some(cfg) = cfg.as_ref() { - required_features(cfg, &mut features); - } - - features.extend(cargo_config.features); - features.extend(target_required_features); - - features.dedup(); - for feature in features { - args.push("--features".to_string()); - args.push(feature); - } - } - - Ok((args, extra_args)) - } - - pub(crate) fn for_file( - global_state_snapshot: &GlobalStateSnapshot, - file_id: FileId, - ) -> Result> { - let crate_id = match &*global_state_snapshot.analysis.crate_for(file_id)? { - &[crate_id, ..] => crate_id, - _ => return Ok(None), - }; - let (cargo_ws, target) = match global_state_snapshot.cargo_target_for_crate_root(crate_id) { - Some(it) => it, - None => return Ok(None), - }; - - let target_data = &cargo_ws[target]; - let package_data = &cargo_ws[target_data.package]; - let res = CargoTargetSpec { - workspace_root: cargo_ws.workspace_root().to_path_buf(), - cargo_toml: package_data.manifest.clone(), - package: cargo_ws.package_flag(package_data), - target: target_data.name.clone(), - target_kind: target_data.kind, - required_features: target_data.required_features.clone(), - }; - - Ok(Some(res)) - } - - pub(crate) fn push_to(self, buf: &mut Vec, kind: &RunnableKind) { - buf.push("--package".to_string()); - buf.push(self.package); - - // Can't mix --doc with other target flags - if let RunnableKind::DocTest { .. } = kind { - return; - } - match self.target_kind { - TargetKind::Bin => { - buf.push("--bin".to_string()); - buf.push(self.target); - } - TargetKind::Test => { - buf.push("--test".to_string()); - buf.push(self.target); - } - TargetKind::Bench => { - buf.push("--bench".to_string()); - buf.push(self.target); - } - TargetKind::Example => { - buf.push("--example".to_string()); - buf.push(self.target); - } - TargetKind::Lib => { - buf.push("--lib".to_string()); - } - TargetKind::Other | TargetKind::BuildScript => (), - } - } -} - -/// Fill minimal features needed -fn required_features(cfg_expr: &CfgExpr, features: &mut Vec) { - match cfg_expr { - CfgExpr::Atom(CfgAtom::KeyValue { key, value }) if key == "feature" => { - features.push(value.to_string()) - } - CfgExpr::All(preds) => { - preds.iter().for_each(|cfg| required_features(cfg, features)); - } - CfgExpr::Any(preds) => { - for cfg in preds { - let len_features = features.len(); - required_features(cfg, features); - if len_features != features.len() { - break; - } - } - } - _ => {} - } -} - -#[cfg(test)] -mod tests { - use super::*; - - use cfg::CfgExpr; - use mbe::syntax_node_to_token_tree; - use syntax::{ - ast::{self, AstNode}, - SmolStr, - }; - - fn check(cfg: &str, expected_features: &[&str]) { - let cfg_expr = { - let source_file = ast::SourceFile::parse(cfg).ok().unwrap(); - let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - let (tt, _) = syntax_node_to_token_tree(tt.syntax()); - CfgExpr::parse(&tt) - }; - - let mut features = vec![]; - required_features(&cfg_expr, &mut features); - - let expected_features = - expected_features.iter().map(|&it| SmolStr::new(it)).collect::>(); - - assert_eq!(features, expected_features); - } - - #[test] - fn test_cfg_expr_minimal_features_needed() { - check(r#"#![cfg(feature = "baz")]"#, &["baz"]); - check(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#, &["baz", "foo"]); - check(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#, &["baz"]); - check(r#"#![cfg(foo)]"#, &[]); - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs deleted file mode 100644 index 6ccdaa86dd628..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs +++ /dev/null @@ -1,69 +0,0 @@ -//! Various batch processing tasks, intended primarily for debugging. - -pub mod flags; -pub mod load_cargo; -mod parse; -mod symbols; -mod highlight; -mod analysis_stats; -mod diagnostics; -mod ssr; -mod lsif; - -mod progress_report; - -use std::io::Read; - -use anyhow::Result; -use ide::AnalysisHost; -use vfs::Vfs; - -#[derive(Clone, Copy)] -pub enum Verbosity { - Spammy, - Verbose, - Normal, - Quiet, -} - -impl Verbosity { - pub fn is_verbose(self) -> bool { - matches!(self, Verbosity::Verbose | Verbosity::Spammy) - } - pub fn is_spammy(self) -> bool { - matches!(self, Verbosity::Spammy) - } -} - -fn read_stdin() -> Result { - let mut buff = String::new(); - std::io::stdin().read_to_string(&mut buff)?; - Ok(buff) -} - -fn report_metric(metric: &str, value: u64, unit: &str) { - if std::env::var("RA_METRICS").is_err() { - return; - } - println!("METRIC:{}:{}:{}", metric, value, unit) -} - -fn print_memory_usage(mut host: AnalysisHost, vfs: Vfs) { - let mut mem = host.per_query_memory_usage(); - - let before = profile::memory_usage(); - drop(vfs); - let vfs = before.allocated - profile::memory_usage().allocated; - mem.push(("VFS".into(), vfs)); - - let before = profile::memory_usage(); - drop(host); - mem.push(("Unaccounted".into(), before.allocated - profile::memory_usage().allocated)); - - mem.push(("Remaining".into(), profile::memory_usage().allocated)); - - for (name, bytes) in mem { - // NOTE: Not a debug print, so avoid going through the `eprintln` defined above. - eprintln!("{:>8} {}", bytes, name); - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs deleted file mode 100644 index f52e1e7512788..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ /dev/null @@ -1,447 +0,0 @@ -//! Fully type-check project and print various stats, like the number of type -//! errors. - -use std::{ - env, - time::{SystemTime, UNIX_EPOCH}, -}; - -use hir::{ - db::{AstDatabase, DefDatabase, HirDatabase}, - AssocItem, Crate, Function, HasSource, HirDisplay, ModuleDef, -}; -use hir_def::{ - body::{BodySourceMap, SyntheticSyntax}, - expr::ExprId, - FunctionId, -}; -use hir_ty::{TyExt, TypeWalk}; -use ide::{Analysis, AnalysisHost, LineCol, RootDatabase}; -use ide_db::base_db::{ - salsa::{self, debug::DebugQueryTable, ParallelDatabase}, - SourceDatabase, SourceDatabaseExt, -}; -use itertools::Itertools; -use oorandom::Rand32; -use profile::{Bytes, StopWatch}; -use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace}; -use rayon::prelude::*; -use rustc_hash::FxHashSet; -use stdx::format_to; -use syntax::{AstNode, SyntaxNode}; -use vfs::{AbsPathBuf, Vfs, VfsPath}; - -use crate::cli::{ - flags::{self, OutputFormat}, - load_cargo::{load_workspace, LoadCargoConfig}, - print_memory_usage, - progress_report::ProgressReport, - report_metric, Result, Verbosity, -}; - -/// Need to wrap Snapshot to provide `Clone` impl for `map_with` -struct Snap(DB); -impl Clone for Snap> { - fn clone(&self) -> Snap> { - Snap(self.0.snapshot()) - } -} - -impl flags::AnalysisStats { - pub fn run(self, verbosity: Verbosity) -> Result<()> { - let mut rng = { - let seed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() as u64; - Rand32::new(seed) - }; - - let mut cargo_config = CargoConfig::default(); - cargo_config.no_sysroot = self.no_sysroot; - let load_cargo_config = LoadCargoConfig { - load_out_dirs_from_check: !self.disable_build_scripts, - with_proc_macro: !self.disable_proc_macros, - prefill_caches: false, - }; - let no_progress = &|_| (); - - let mut db_load_sw = self.stop_watch(); - - let path = AbsPathBuf::assert(env::current_dir()?.join(&self.path)); - let manifest = ProjectManifest::discover_single(&path)?; - - let mut workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?; - let metadata_time = db_load_sw.elapsed(); - - let build_scripts_time = if self.disable_build_scripts { - None - } else { - let mut build_scripts_sw = self.stop_watch(); - let bs = workspace.run_build_scripts(&cargo_config, no_progress)?; - workspace.set_build_scripts(bs); - Some(build_scripts_sw.elapsed()) - }; - - let (host, vfs, _proc_macro) = load_workspace(workspace, &load_cargo_config)?; - let db = host.raw_database(); - eprint!("{:<20} {}", "Database loaded:", db_load_sw.elapsed()); - eprint!(" (metadata {}", metadata_time); - if let Some(build_scripts_time) = build_scripts_time { - eprint!("; build {}", build_scripts_time); - } - eprintln!(")"); - - let mut analysis_sw = self.stop_watch(); - let mut num_crates = 0; - let mut visited_modules = FxHashSet::default(); - let mut visit_queue = Vec::new(); - - let mut krates = Crate::all(db); - if self.randomize { - shuffle(&mut rng, &mut krates); - } - for krate in krates { - let module = krate.root_module(db); - let file_id = module.definition_source(db).file_id; - let file_id = file_id.original_file(db); - let source_root = db.file_source_root(file_id); - let source_root = db.source_root(source_root); - if !source_root.is_library || self.with_deps { - num_crates += 1; - visit_queue.push(module); - } - } - - if self.randomize { - shuffle(&mut rng, &mut visit_queue); - } - - eprint!(" crates: {}", num_crates); - let mut num_decls = 0; - let mut funcs = Vec::new(); - while let Some(module) = visit_queue.pop() { - if visited_modules.insert(module) { - visit_queue.extend(module.children(db)); - - for decl in module.declarations(db) { - num_decls += 1; - if let ModuleDef::Function(f) = decl { - funcs.push(f); - } - } - - for impl_def in module.impl_defs(db) { - for item in impl_def.items(db) { - num_decls += 1; - if let AssocItem::Function(f) = item { - funcs.push(f); - } - } - } - } - } - eprintln!(", mods: {}, decls: {}, fns: {}", visited_modules.len(), num_decls, funcs.len()); - eprintln!("{:<20} {}", "Item Collection:", analysis_sw.elapsed()); - - if self.randomize { - shuffle(&mut rng, &mut funcs); - } - - if !self.skip_inference { - self.run_inference(&host, db, &vfs, &funcs, verbosity); - } - - let total_span = analysis_sw.elapsed(); - eprintln!("{:<20} {}", "Total:", total_span); - report_metric("total time", total_span.time.as_millis() as u64, "ms"); - if let Some(instructions) = total_span.instructions { - report_metric("total instructions", instructions, "#instr"); - } - if let Some(memory) = total_span.memory { - report_metric("total memory", memory.allocated.megabytes() as u64, "MB"); - } - - if env::var("RA_COUNT").is_ok() { - eprintln!("{}", profile::countme::get_all()); - } - - if self.source_stats { - let mut total_file_size = Bytes::default(); - for e in ide_db::base_db::ParseQuery.in_db(db).entries::>() { - total_file_size += syntax_len(db.parse(e.key).syntax_node()) - } - - let mut total_macro_file_size = Bytes::default(); - for e in hir::db::ParseMacroExpansionQuery.in_db(db).entries::>() { - if let Some((val, _)) = db.parse_macro_expansion(e.key).value { - total_macro_file_size += syntax_len(val.syntax_node()) - } - } - eprintln!("source files: {}, macro files: {}", total_file_size, total_macro_file_size); - } - - if self.memory_usage && verbosity.is_verbose() { - print_memory_usage(host, vfs); - } - - Ok(()) - } - - fn run_inference( - &self, - host: &AnalysisHost, - db: &RootDatabase, - vfs: &Vfs, - funcs: &[Function], - verbosity: Verbosity, - ) { - let mut bar = match verbosity { - Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), - _ if self.parallel || self.output.is_some() => ProgressReport::hidden(), - _ => ProgressReport::new(funcs.len() as u64), - }; - - if self.parallel { - let mut inference_sw = self.stop_watch(); - let snap = Snap(db.snapshot()); - funcs - .par_iter() - .map_with(snap, |snap, &f| { - let f_id = FunctionId::from(f); - snap.0.body(f_id.into()); - snap.0.infer(f_id.into()); - }) - .count(); - eprintln!("{:<20} {}", "Parallel Inference:", inference_sw.elapsed()); - } - - let mut inference_sw = self.stop_watch(); - bar.tick(); - let mut num_exprs = 0; - let mut num_exprs_unknown = 0; - let mut num_exprs_partially_unknown = 0; - let mut num_type_mismatches = 0; - let analysis = host.analysis(); - for f in funcs.iter().copied() { - let name = f.name(db); - let full_name = f - .module(db) - .path_to_root(db) - .into_iter() - .rev() - .filter_map(|it| it.name(db)) - .chain(Some(f.name(db))) - .join("::"); - if let Some(only_name) = self.only.as_deref() { - if name.to_string() != only_name && full_name != only_name { - continue; - } - } - let mut msg = format!("processing: {}", full_name); - if verbosity.is_verbose() { - if let Some(src) = f.source(db) { - let original_file = src.file_id.original_file(db); - let path = vfs.file_path(original_file); - let syntax_range = src.value.syntax().text_range(); - format_to!(msg, " ({} {:?})", path, syntax_range); - } - } - if verbosity.is_spammy() { - bar.println(msg.to_string()); - } - bar.set_message(&msg); - let f_id = FunctionId::from(f); - let (body, sm) = db.body_with_source_map(f_id.into()); - let inference_result = db.infer(f_id.into()); - let (previous_exprs, previous_unknown, previous_partially_unknown) = - (num_exprs, num_exprs_unknown, num_exprs_partially_unknown); - for (expr_id, _) in body.exprs.iter() { - let ty = &inference_result[expr_id]; - num_exprs += 1; - let unknown_or_partial = if ty.is_unknown() { - num_exprs_unknown += 1; - if verbosity.is_spammy() { - if let Some((path, start, end)) = - expr_syntax_range(db, &analysis, vfs, &sm, expr_id) - { - bar.println(format!( - "{} {}:{}-{}:{}: Unknown type", - path, - start.line + 1, - start.col, - end.line + 1, - end.col, - )); - } else { - bar.println(format!("{}: Unknown type", name,)); - } - } - true - } else { - let mut is_partially_unknown = false; - ty.walk(&mut |ty| { - if ty.is_unknown() { - is_partially_unknown = true; - } - }); - if is_partially_unknown { - num_exprs_partially_unknown += 1; - } - is_partially_unknown - }; - if self.only.is_some() && verbosity.is_spammy() { - // in super-verbose mode for just one function, we print every single expression - if let Some((_, start, end)) = - expr_syntax_range(db, &analysis, vfs, &sm, expr_id) - { - bar.println(format!( - "{}:{}-{}:{}: {}", - start.line + 1, - start.col, - end.line + 1, - end.col, - ty.display(db) - )); - } else { - bar.println(format!("unknown location: {}", ty.display(db))); - } - } - if unknown_or_partial && self.output == Some(OutputFormat::Csv) { - println!( - r#"{},type,"{}""#, - location_csv(db, &analysis, vfs, &sm, expr_id), - ty.display(db) - ); - } - if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) { - num_type_mismatches += 1; - if verbosity.is_verbose() { - if let Some((path, start, end)) = - expr_syntax_range(db, &analysis, vfs, &sm, expr_id) - { - bar.println(format!( - "{} {}:{}-{}:{}: Expected {}, got {}", - path, - start.line + 1, - start.col, - end.line + 1, - end.col, - mismatch.expected.display(db), - mismatch.actual.display(db) - )); - } else { - bar.println(format!( - "{}: Expected {}, got {}", - name, - mismatch.expected.display(db), - mismatch.actual.display(db) - )); - } - } - if self.output == Some(OutputFormat::Csv) { - println!( - r#"{},mismatch,"{}","{}""#, - location_csv(db, &analysis, vfs, &sm, expr_id), - mismatch.expected.display(db), - mismatch.actual.display(db) - ); - } - } - } - if verbosity.is_spammy() { - bar.println(format!( - "In {}: {} exprs, {} unknown, {} partial", - full_name, - num_exprs - previous_exprs, - num_exprs_unknown - previous_unknown, - num_exprs_partially_unknown - previous_partially_unknown - )); - } - bar.inc(1); - } - - bar.finish_and_clear(); - eprintln!( - " exprs: {}, ??ty: {} ({}%), ?ty: {} ({}%), !ty: {}", - num_exprs, - num_exprs_unknown, - percentage(num_exprs_unknown, num_exprs), - num_exprs_partially_unknown, - percentage(num_exprs_partially_unknown, num_exprs), - num_type_mismatches - ); - report_metric("unknown type", num_exprs_unknown, "#"); - report_metric("type mismatches", num_type_mismatches, "#"); - - eprintln!("{:<20} {}", "Inference:", inference_sw.elapsed()); - } - - fn stop_watch(&self) -> StopWatch { - StopWatch::start().memory(self.memory_usage) - } -} - -fn location_csv( - db: &RootDatabase, - analysis: &Analysis, - vfs: &Vfs, - sm: &BodySourceMap, - expr_id: ExprId, -) -> String { - let src = match sm.expr_syntax(expr_id) { - Ok(s) => s, - Err(SyntheticSyntax) => return "synthetic,,".to_string(), - }; - let root = db.parse_or_expand(src.file_id).unwrap(); - let node = src.map(|e| e.to_node(&root).syntax().clone()); - let original_range = node.as_ref().original_file_range(db); - let path = vfs.file_path(original_range.file_id); - let line_index = analysis.file_line_index(original_range.file_id).unwrap(); - let text_range = original_range.range; - let (start, end) = - (line_index.line_col(text_range.start()), line_index.line_col(text_range.end())); - format!("{},{}:{},{}:{}", path, start.line + 1, start.col, end.line + 1, end.col) -} - -fn expr_syntax_range( - db: &RootDatabase, - analysis: &Analysis, - vfs: &Vfs, - sm: &BodySourceMap, - expr_id: ExprId, -) -> Option<(VfsPath, LineCol, LineCol)> { - let src = sm.expr_syntax(expr_id); - if let Ok(src) = src { - let root = db.parse_or_expand(src.file_id).unwrap(); - let node = src.map(|e| e.to_node(&root).syntax().clone()); - let original_range = node.as_ref().original_file_range(db); - let path = vfs.file_path(original_range.file_id); - let line_index = analysis.file_line_index(original_range.file_id).unwrap(); - let text_range = original_range.range; - let (start, end) = - (line_index.line_col(text_range.start()), line_index.line_col(text_range.end())); - Some((path, start, end)) - } else { - None - } -} - -fn shuffle(rng: &mut Rand32, slice: &mut [T]) { - for i in 0..slice.len() { - randomize_first(rng, &mut slice[i..]); - } - - fn randomize_first(rng: &mut Rand32, slice: &mut [T]) { - assert!(!slice.is_empty()); - let idx = rng.rand_range(0..slice.len() as u32) as usize; - slice.swap(0, idx); - } -} - -fn percentage(n: u64, total: u64) -> u64 { - (n * 100).checked_div(total).unwrap_or(100) -} - -fn syntax_len(node: SyntaxNode) -> usize { - // Macro expanded code doesn't contain whitespace, so erase *all* whitespace - // to make macro and non-macro code comparable. - node.to_string().replace(|it: char| it.is_ascii_whitespace(), "").len() -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs deleted file mode 100644 index 52511ceb5805d..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! Analyze all modules in a project for diagnostics. Exits with a non-zero -//! status code if any errors are found. - -use rustc_hash::FxHashSet; - -use hir::{db::HirDatabase, Crate, Module}; -use ide::{AssistResolveStrategy, DiagnosticsConfig, Severity}; -use ide_db::base_db::SourceDatabaseExt; - -use crate::cli::{ - flags, - load_cargo::{load_workspace_at, LoadCargoConfig}, -}; - -impl flags::Diagnostics { - pub fn run(self) -> anyhow::Result<()> { - let cargo_config = Default::default(); - let load_cargo_config = LoadCargoConfig { - load_out_dirs_from_check: !self.disable_build_scripts, - with_proc_macro: !self.disable_proc_macros, - prefill_caches: false, - }; - let (host, _vfs, _proc_macro) = - load_workspace_at(&self.path, &cargo_config, &load_cargo_config, &|_| {})?; - let db = host.raw_database(); - let analysis = host.analysis(); - - let mut found_error = false; - let mut visited_files = FxHashSet::default(); - - let work = all_modules(db).into_iter().filter(|module| { - let file_id = module.definition_source(db).file_id.original_file(db); - let source_root = db.file_source_root(file_id); - let source_root = db.source_root(source_root); - !source_root.is_library - }); - - for module in work { - let file_id = module.definition_source(db).file_id.original_file(db); - if !visited_files.contains(&file_id) { - let crate_name = - module.krate().display_name(db).as_deref().unwrap_or("unknown").to_string(); - println!("processing crate: {}, module: {}", crate_name, _vfs.file_path(file_id)); - for diagnostic in analysis - .diagnostics( - &DiagnosticsConfig::default(), - AssistResolveStrategy::None, - file_id, - ) - .unwrap() - { - if matches!(diagnostic.severity, Severity::Error) { - found_error = true; - } - - println!("{:?}", diagnostic); - } - - visited_files.insert(file_id); - } - } - - println!(); - println!("diagnostic scan complete"); - - if found_error { - println!(); - anyhow::bail!("diagnostic error detected") - } - - Ok(()) - } -} - -fn all_modules(db: &dyn HirDatabase) -> Vec { - let mut worklist: Vec<_> = - Crate::all(db).into_iter().map(|krate| krate.root_module(db)).collect(); - let mut modules = Vec::new(); - - while let Some(module) = worklist.pop() { - modules.push(module); - worklist.extend(module.children(db)); - } - - modules -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs deleted file mode 100644 index 19907ebddb6ad..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs +++ /dev/null @@ -1,248 +0,0 @@ -//! Grammar for the command-line arguments. -#![allow(unreachable_pub)] -use std::{path::PathBuf, str::FromStr}; - -use ide_ssr::{SsrPattern, SsrRule}; - -use crate::cli::Verbosity; - -xflags::xflags! { - src "./src/cli/flags.rs" - - /// LSP server for the Rust programming language. - cmd rust-analyzer { - /// Verbosity level, can be repeated multiple times. - repeated -v, --verbose - /// Verbosity level. - optional -q, --quiet - - /// Log to the specified file instead of stderr. - optional --log-file path: PathBuf - /// Flush log records to the file immediately. - optional --no-log-buffering - - /// Wait until a debugger is attached to (requires debug build). - optional --wait-dbg - - default cmd lsp-server { - /// Print version. - optional --version - /// Print help. - optional -h, --help - - /// Dump a LSP config JSON schema. - optional --print-config-schema - } - - /// Parse stdin. - cmd parse { - /// Suppress printing. - optional --no-dump - } - - /// Parse stdin and print the list of symbols. - cmd symbols {} - - /// Highlight stdin as html. - cmd highlight { - /// Enable rainbow highlighting of identifiers. - optional --rainbow - } - - /// Batch typecheck project and print summary statistics - cmd analysis-stats - /// Directory with Cargo.toml. - required path: PathBuf - { - optional --output format: OutputFormat - - /// Randomize order in which crates, modules, and items are processed. - optional --randomize - /// Run type inference in parallel. - optional --parallel - /// Collect memory usage statistics. - optional --memory-usage - /// Print the total length of all source and macro files (whitespace is not counted). - optional --source-stats - - /// Only analyze items matching this path. - optional -o, --only path: String - /// Also analyze all dependencies. - optional --with-deps - /// Don't load sysroot crates (`std`, `core` & friends). - optional --no-sysroot - - /// Don't run build scripts or load `OUT_DIR` values by running `cargo check` before analysis. - optional --disable-build-scripts - /// Don't use expand proc macros. - optional --disable-proc-macros - /// Only resolve names, don't run type inference. - optional --skip-inference - } - - cmd diagnostics - /// Directory with Cargo.toml. - required path: PathBuf - { - /// Don't run build scripts or load `OUT_DIR` values by running `cargo check` before analysis. - optional --disable-build-scripts - /// Don't use expand proc macros. - optional --disable-proc-macros - } - - cmd ssr - /// A structured search replace rule (`$a.foo($b) ==> bar($a, $b)`) - repeated rule: SsrRule - {} - - cmd search - /// A structured search replace pattern (`$a.foo($b)`) - repeated pattern: SsrPattern - { - /// Prints debug information for any nodes with source exactly equal to snippet. - optional --debug snippet: String - } - - cmd proc-macro {} - - cmd lsif - required path: PathBuf - {} - } -} - -// generated start -// The following code is generated by `xflags` macro. -// Run `env UPDATE_XFLAGS=1 cargo build` to regenerate. -#[derive(Debug)] -pub struct RustAnalyzer { - pub verbose: u32, - pub quiet: bool, - pub log_file: Option, - pub no_log_buffering: bool, - pub wait_dbg: bool, - pub subcommand: RustAnalyzerCmd, -} - -#[derive(Debug)] -pub enum RustAnalyzerCmd { - LspServer(LspServer), - Parse(Parse), - Symbols(Symbols), - Highlight(Highlight), - AnalysisStats(AnalysisStats), - Diagnostics(Diagnostics), - Ssr(Ssr), - Search(Search), - ProcMacro(ProcMacro), - Lsif(Lsif), -} - -#[derive(Debug)] -pub struct LspServer { - pub version: bool, - pub help: bool, - pub print_config_schema: bool, -} - -#[derive(Debug)] -pub struct Parse { - pub no_dump: bool, -} - -#[derive(Debug)] -pub struct Symbols; - -#[derive(Debug)] -pub struct Highlight { - pub rainbow: bool, -} - -#[derive(Debug)] -pub struct AnalysisStats { - pub path: PathBuf, - - pub output: Option, - pub randomize: bool, - pub parallel: bool, - pub memory_usage: bool, - pub source_stats: bool, - pub only: Option, - pub with_deps: bool, - pub no_sysroot: bool, - pub disable_build_scripts: bool, - pub disable_proc_macros: bool, - pub skip_inference: bool, -} - -#[derive(Debug)] -pub struct Diagnostics { - pub path: PathBuf, - - pub disable_build_scripts: bool, - pub disable_proc_macros: bool, -} - -#[derive(Debug)] -pub struct Ssr { - pub rule: Vec, -} - -#[derive(Debug)] -pub struct Search { - pub pattern: Vec, - - pub debug: Option, -} - -#[derive(Debug)] -pub struct ProcMacro; - -#[derive(Debug)] -pub struct Lsif { - pub path: PathBuf, -} - -impl RustAnalyzer { - pub const HELP: &'static str = Self::HELP_; - - #[allow(dead_code)] - pub fn from_env() -> xflags::Result { - Self::from_env_() - } - - #[allow(dead_code)] - pub fn from_vec(args: Vec) -> xflags::Result { - Self::from_vec_(args) - } -} -// generated end - -#[derive(Debug, PartialEq, Eq)] -pub enum OutputFormat { - Csv, -} - -impl RustAnalyzer { - pub fn verbosity(&self) -> Verbosity { - if self.quiet { - return Verbosity::Quiet; - } - match self.verbose { - 0 => Verbosity::Normal, - 1 => Verbosity::Verbose, - _ => Verbosity::Spammy, - } - } -} - -impl FromStr for OutputFormat { - type Err = String; - - fn from_str(s: &str) -> Result { - match s { - "csv" => Ok(Self::Csv), - _ => Err(format!("unknown output format `{}`", s)), - } - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/highlight.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/highlight.rs deleted file mode 100644 index 4f9b362f1bec4..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/highlight.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! Read Rust code on stdin, print HTML highlighted version to stdout. - -use ide::Analysis; - -use crate::cli::{flags, read_stdin}; - -impl flags::Highlight { - pub fn run(self) -> anyhow::Result<()> { - let (analysis, file_id) = Analysis::from_single_file(read_stdin()?); - let html = analysis.highlight_as_html(file_id, self.rainbow).unwrap(); - println!("{}", html); - Ok(()) - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/load_cargo.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/load_cargo.rs deleted file mode 100644 index 0ada4b73e842d..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/load_cargo.rs +++ /dev/null @@ -1,162 +0,0 @@ -//! Loads a Cargo project into a static instance of analysis, without support -//! for incorporating changes. -use std::{path::Path, sync::Arc}; - -use anyhow::Result; -use crossbeam_channel::{unbounded, Receiver}; -use hir::db::DefDatabase; -use ide::{AnalysisHost, Change}; -use ide_db::base_db::CrateGraph; -use proc_macro_api::ProcMacroServer; -use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace}; -use vfs::{loader::Handle, AbsPath, AbsPathBuf}; - -use crate::reload::{load_proc_macro, ProjectFolders, SourceRootConfig}; - -// Note: Since this type is used by external tools that use rust-analyzer as a library -// what otherwise would be `pub(crate)` has to be `pub` here instead. -pub struct LoadCargoConfig { - pub load_out_dirs_from_check: bool, - pub with_proc_macro: bool, - pub prefill_caches: bool, -} - -// Note: Since this function is used by external tools that use rust-analyzer as a library -// what otherwise would be `pub(crate)` has to be `pub` here instead. -pub fn load_workspace_at( - root: &Path, - cargo_config: &CargoConfig, - load_config: &LoadCargoConfig, - progress: &dyn Fn(String), -) -> Result<(AnalysisHost, vfs::Vfs, Option)> { - let root = AbsPathBuf::assert(std::env::current_dir()?.join(root)); - let root = ProjectManifest::discover_single(&root)?; - let mut workspace = ProjectWorkspace::load(root, cargo_config, progress)?; - - if load_config.load_out_dirs_from_check { - let build_scripts = workspace.run_build_scripts(cargo_config, progress)?; - workspace.set_build_scripts(build_scripts) - } - - load_workspace(workspace, load_config) -} - -// Note: Since this function is used by external tools that use rust-analyzer as a library -// what otherwise would be `pub(crate)` has to be `pub` here instead. -// -// The reason both, `load_workspace_at` and `load_workspace` are `pub` is that some of -// these tools need access to `ProjectWorkspace`, too, which `load_workspace_at` hides. -pub fn load_workspace( - ws: ProjectWorkspace, - load_config: &LoadCargoConfig, -) -> Result<(AnalysisHost, vfs::Vfs, Option)> { - let (sender, receiver) = unbounded(); - let mut vfs = vfs::Vfs::default(); - let mut loader = { - let loader = - vfs_notify::NotifyHandle::spawn(Box::new(move |msg| sender.send(msg).unwrap())); - Box::new(loader) - }; - - let proc_macro_client = if load_config.with_proc_macro { - let path = AbsPathBuf::assert(std::env::current_exe()?); - Ok(ProcMacroServer::spawn(path, &["proc-macro"]).unwrap()) - } else { - Err("proc macro server not started".to_owned()) - }; - - let crate_graph = ws.to_crate_graph( - &mut |_, path: &AbsPath| load_proc_macro(proc_macro_client.as_ref(), path, &[]), - &mut |path: &AbsPath| { - let contents = loader.load_sync(path); - let path = vfs::VfsPath::from(path.to_path_buf()); - vfs.set_file_contents(path.clone(), contents); - vfs.file_id(&path) - }, - ); - - let project_folders = ProjectFolders::new(&[ws], &[]); - loader.set_config(vfs::loader::Config { - load: project_folders.load, - watch: vec![], - version: 0, - }); - - tracing::debug!("crate graph: {:?}", crate_graph); - let host = - load_crate_graph(crate_graph, project_folders.source_root_config, &mut vfs, &receiver); - - if load_config.prefill_caches { - host.analysis().parallel_prime_caches(1, |_| {})?; - } - Ok((host, vfs, proc_macro_client.ok())) -} - -fn load_crate_graph( - crate_graph: CrateGraph, - source_root_config: SourceRootConfig, - vfs: &mut vfs::Vfs, - receiver: &Receiver, -) -> AnalysisHost { - let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::().ok()); - let mut host = AnalysisHost::new(lru_cap); - let mut analysis_change = Change::new(); - - host.raw_database_mut().set_enable_proc_attr_macros(true); - - // wait until Vfs has loaded all roots - for task in receiver { - match task { - vfs::loader::Message::Progress { n_done, n_total, config_version: _ } => { - if n_done == n_total { - break; - } - } - vfs::loader::Message::Loaded { files } => { - for (path, contents) in files { - vfs.set_file_contents(path.into(), contents); - } - } - } - } - let changes = vfs.take_changes(); - for file in changes { - if file.exists() { - let contents = vfs.file_contents(file.file_id).to_vec(); - if let Ok(text) = String::from_utf8(contents) { - analysis_change.change_file(file.file_id, Some(Arc::new(text))) - } - } - } - let source_roots = source_root_config.partition(vfs); - analysis_change.set_roots(source_roots); - - analysis_change.set_crate_graph(crate_graph); - - host.apply_change(analysis_change); - host -} - -#[cfg(test)] -mod tests { - use super::*; - - use hir::Crate; - - #[test] - fn test_loading_rust_analyzer() { - let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap(); - let cargo_config = CargoConfig::default(); - let load_cargo_config = LoadCargoConfig { - load_out_dirs_from_check: false, - with_proc_macro: false, - prefill_caches: false, - }; - let (host, _vfs, _proc_macro) = - load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {}).unwrap(); - - let n_crates = Crate::all(host.raw_database()).len(); - // RA has quite a few crates, but the exact count doesn't matter - assert!(n_crates > 20); - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs deleted file mode 100644 index 491c55a04f8c0..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs +++ /dev/null @@ -1,328 +0,0 @@ -//! LSIF (language server index format) generator - -use std::collections::HashMap; -use std::env; -use std::time::Instant; - -use ide::{ - Analysis, FileId, FileRange, MonikerKind, PackageInformation, RootDatabase, StaticIndex, - StaticIndexedFile, TokenId, TokenStaticData, -}; -use ide_db::LineIndexDatabase; - -use ide_db::base_db::salsa::{self, ParallelDatabase}; -use lsp_types::{self, lsif}; -use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace}; -use vfs::{AbsPathBuf, Vfs}; - -use crate::cli::{ - flags, - load_cargo::{load_workspace, LoadCargoConfig}, - Result, -}; -use crate::line_index::{LineEndings, LineIndex, OffsetEncoding}; -use crate::to_proto; -use crate::version::version; - -/// Need to wrap Snapshot to provide `Clone` impl for `map_with` -struct Snap(DB); -impl Clone for Snap> { - fn clone(&self) -> Snap> { - Snap(self.0.snapshot()) - } -} - -struct LsifManager<'a> { - count: i32, - token_map: HashMap, - range_map: HashMap, - file_map: HashMap, - package_map: HashMap, - analysis: &'a Analysis, - db: &'a RootDatabase, - vfs: &'a Vfs, -} - -#[derive(Clone, Copy)] -struct Id(i32); - -impl From for lsp_types::NumberOrString { - fn from(Id(x): Id) -> Self { - lsp_types::NumberOrString::Number(x) - } -} - -impl LsifManager<'_> { - fn new<'a>(analysis: &'a Analysis, db: &'a RootDatabase, vfs: &'a Vfs) -> LsifManager<'a> { - LsifManager { - count: 0, - token_map: HashMap::default(), - range_map: HashMap::default(), - file_map: HashMap::default(), - package_map: HashMap::default(), - analysis, - db, - vfs, - } - } - - fn add(&mut self, data: lsif::Element) -> Id { - let id = Id(self.count); - self.emit(&serde_json::to_string(&lsif::Entry { id: id.into(), data }).unwrap()); - self.count += 1; - id - } - - fn add_vertex(&mut self, vertex: lsif::Vertex) -> Id { - self.add(lsif::Element::Vertex(vertex)) - } - - fn add_edge(&mut self, edge: lsif::Edge) -> Id { - self.add(lsif::Element::Edge(edge)) - } - - // FIXME: support file in addition to stdout here - fn emit(&self, data: &str) { - println!("{}", data); - } - - fn get_token_id(&mut self, id: TokenId) -> Id { - if let Some(x) = self.token_map.get(&id) { - return *x; - } - let result_set_id = self.add_vertex(lsif::Vertex::ResultSet(lsif::ResultSet { key: None })); - self.token_map.insert(id, result_set_id); - result_set_id - } - - fn get_package_id(&mut self, package_information: PackageInformation) -> Id { - if let Some(x) = self.package_map.get(&package_information) { - return *x; - } - let pi = package_information.clone(); - let result_set_id = - self.add_vertex(lsif::Vertex::PackageInformation(lsif::PackageInformation { - name: pi.name, - manager: "cargo".to_string(), - uri: None, - content: None, - repository: Some(lsif::Repository { - url: pi.repo, - r#type: "git".to_string(), - commit_id: None, - }), - version: Some(pi.version), - })); - self.package_map.insert(package_information, result_set_id); - result_set_id - } - - fn get_range_id(&mut self, id: FileRange) -> Id { - if let Some(x) = self.range_map.get(&id) { - return *x; - } - let file_id = id.file_id; - let doc_id = self.get_file_id(file_id); - let line_index = self.db.line_index(file_id); - let line_index = LineIndex { - index: line_index, - encoding: OffsetEncoding::Utf16, - endings: LineEndings::Unix, - }; - let range_id = self.add_vertex(lsif::Vertex::Range { - range: to_proto::range(&line_index, id.range), - tag: None, - }); - self.add_edge(lsif::Edge::Contains(lsif::EdgeDataMultiIn { - in_vs: vec![range_id.into()], - out_v: doc_id.into(), - })); - range_id - } - - fn get_file_id(&mut self, id: FileId) -> Id { - if let Some(x) = self.file_map.get(&id) { - return *x; - } - let path = self.vfs.file_path(id); - let path = path.as_path().unwrap(); - let doc_id = self.add_vertex(lsif::Vertex::Document(lsif::Document { - language_id: "rust".to_string(), - uri: lsp_types::Url::from_file_path(path).unwrap(), - })); - self.file_map.insert(id, doc_id); - doc_id - } - - fn add_token(&mut self, id: TokenId, token: TokenStaticData) { - let result_set_id = self.get_token_id(id); - if let Some(hover) = token.hover { - let hover_id = self.add_vertex(lsif::Vertex::HoverResult { - result: lsp_types::Hover { - contents: lsp_types::HoverContents::Markup(to_proto::markup_content( - hover.markup, - ide::HoverDocFormat::Markdown, - )), - range: None, - }, - }); - self.add_edge(lsif::Edge::Hover(lsif::EdgeData { - in_v: hover_id.into(), - out_v: result_set_id.into(), - })); - } - if let Some(moniker) = token.moniker { - let package_id = self.get_package_id(moniker.package_information); - let moniker_id = self.add_vertex(lsif::Vertex::Moniker(lsp_types::Moniker { - scheme: "rust-analyzer".to_string(), - identifier: moniker.identifier.to_string(), - unique: lsp_types::UniquenessLevel::Scheme, - kind: Some(match moniker.kind { - MonikerKind::Import => lsp_types::MonikerKind::Import, - MonikerKind::Export => lsp_types::MonikerKind::Export, - }), - })); - self.add_edge(lsif::Edge::PackageInformation(lsif::EdgeData { - in_v: package_id.into(), - out_v: moniker_id.into(), - })); - self.add_edge(lsif::Edge::Moniker(lsif::EdgeData { - in_v: moniker_id.into(), - out_v: result_set_id.into(), - })); - } - if let Some(def) = token.definition { - let result_id = self.add_vertex(lsif::Vertex::DefinitionResult); - let def_vertex = self.get_range_id(def); - self.add_edge(lsif::Edge::Item(lsif::Item { - document: (*self.file_map.get(&def.file_id).unwrap()).into(), - property: None, - edge_data: lsif::EdgeDataMultiIn { - in_vs: vec![def_vertex.into()], - out_v: result_id.into(), - }, - })); - self.add_edge(lsif::Edge::Definition(lsif::EdgeData { - in_v: result_id.into(), - out_v: result_set_id.into(), - })); - } - if !token.references.is_empty() { - let result_id = self.add_vertex(lsif::Vertex::ReferenceResult); - self.add_edge(lsif::Edge::References(lsif::EdgeData { - in_v: result_id.into(), - out_v: result_set_id.into(), - })); - let mut edges = token.references.iter().fold( - HashMap::<_, Vec>::new(), - |mut edges, x| { - let entry = - edges.entry((x.range.file_id, x.is_definition)).or_insert_with(Vec::new); - entry.push((*self.range_map.get(&x.range).unwrap()).into()); - edges - }, - ); - for x in token.references { - if let Some(vertices) = edges.remove(&(x.range.file_id, x.is_definition)) { - self.add_edge(lsif::Edge::Item(lsif::Item { - document: (*self.file_map.get(&x.range.file_id).unwrap()).into(), - property: Some(if x.is_definition { - lsif::ItemKind::Definitions - } else { - lsif::ItemKind::References - }), - edge_data: lsif::EdgeDataMultiIn { - in_vs: vertices, - out_v: result_id.into(), - }, - })); - } - } - } - } - - fn add_file(&mut self, file: StaticIndexedFile) { - let StaticIndexedFile { file_id, tokens, folds, .. } = file; - let doc_id = self.get_file_id(file_id); - let text = self.analysis.file_text(file_id).unwrap(); - let line_index = self.db.line_index(file_id); - let line_index = LineIndex { - index: line_index, - encoding: OffsetEncoding::Utf16, - endings: LineEndings::Unix, - }; - let result = folds - .into_iter() - .map(|it| to_proto::folding_range(&*text, &line_index, false, it)) - .collect(); - let folding_id = self.add_vertex(lsif::Vertex::FoldingRangeResult { result }); - self.add_edge(lsif::Edge::FoldingRange(lsif::EdgeData { - in_v: folding_id.into(), - out_v: doc_id.into(), - })); - let tokens_id = tokens - .into_iter() - .map(|(range, id)| { - let range_id = self.add_vertex(lsif::Vertex::Range { - range: to_proto::range(&line_index, range), - tag: None, - }); - self.range_map.insert(FileRange { file_id, range }, range_id); - let result_set_id = self.get_token_id(id); - self.add_edge(lsif::Edge::Next(lsif::EdgeData { - in_v: result_set_id.into(), - out_v: range_id.into(), - })); - range_id.into() - }) - .collect(); - self.add_edge(lsif::Edge::Contains(lsif::EdgeDataMultiIn { - in_vs: tokens_id, - out_v: doc_id.into(), - })); - } -} - -impl flags::Lsif { - pub fn run(self) -> Result<()> { - eprintln!("Generating LSIF started..."); - let now = Instant::now(); - let cargo_config = CargoConfig::default(); - let no_progress = &|_| (); - let load_cargo_config = LoadCargoConfig { - load_out_dirs_from_check: true, - with_proc_macro: true, - prefill_caches: false, - }; - let path = AbsPathBuf::assert(env::current_dir()?.join(&self.path)); - let manifest = ProjectManifest::discover_single(&path)?; - - let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?; - - let (host, vfs, _proc_macro) = load_workspace(workspace, &load_cargo_config)?; - let db = host.raw_database(); - let analysis = host.analysis(); - - let si = StaticIndex::compute(&analysis); - - let mut lsif = LsifManager::new(&analysis, db, &vfs); - lsif.add_vertex(lsif::Vertex::MetaData(lsif::MetaData { - version: String::from("0.5.0"), - project_root: lsp_types::Url::from_file_path(path).unwrap(), - position_encoding: lsif::Encoding::Utf16, - tool_info: Some(lsp_types::lsif::ToolInfo { - name: "rust-analyzer".to_string(), - args: vec![], - version: Some(version().to_string()), - }), - })); - for file in si.files { - lsif.add_file(file); - } - for (id, token) in si.tokens.iter() { - lsif.add_token(id, token); - } - eprintln!("Generating LSIF finished in {:?}", now.elapsed()); - Ok(()) - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs deleted file mode 100644 index 5ef8cdff4cf25..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Read Rust code on stdin, print syntax tree on stdout. -use syntax::{AstNode, SourceFile}; - -use crate::cli::{flags, read_stdin}; - -impl flags::Parse { - pub fn run(self) -> anyhow::Result<()> { - let _p = profile::span("parsing"); - let text = read_stdin()?; - let file = SourceFile::parse(&text).tree(); - if !self.no_dump { - println!("{:#?}", file.syntax()); - } - std::mem::forget(file); - Ok(()) - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs deleted file mode 100644 index 5a2dc39d52b39..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs +++ /dev/null @@ -1,122 +0,0 @@ -//! A simple progress bar -//! -//! A single thread non-optimized progress bar -use std::io::{self, Write}; - -/// A Simple ASCII Progress Bar -pub(crate) struct ProgressReport { - curr: f32, - text: String, - hidden: bool, - - len: u64, - pos: u64, - msg: String, -} - -impl ProgressReport { - pub(crate) fn new(len: u64) -> ProgressReport { - ProgressReport { - curr: 0.0, - text: String::new(), - hidden: false, - len, - pos: 0, - msg: String::new(), - } - } - - pub(crate) fn hidden() -> ProgressReport { - ProgressReport { - curr: 0.0, - text: String::new(), - hidden: true, - len: 0, - pos: 0, - msg: String::new(), - } - } - - pub(crate) fn set_message(&mut self, msg: &str) { - self.msg = msg.to_string(); - self.tick(); - } - - pub(crate) fn println>(&mut self, msg: I) { - self.clear(); - println!("{}", msg.into()); - self.tick(); - } - - pub(crate) fn inc(&mut self, delta: u64) { - self.pos += delta; - if self.len == 0 { - self.set_value(0.0) - } else { - self.set_value((self.pos as f32) / (self.len as f32)) - } - self.tick(); - } - - pub(crate) fn finish_and_clear(&mut self) { - self.clear(); - } - - pub(crate) fn tick(&mut self) { - if self.hidden { - return; - } - let percent = (self.curr * 100.0) as u32; - let text = format!("{}/{} {:3>}% {}", self.pos, self.len, percent, self.msg); - self.update_text(&text); - } - - fn update_text(&mut self, text: &str) { - // Get length of common portion - let mut common_prefix_length = 0; - let common_length = usize::min(self.text.len(), text.len()); - - while common_prefix_length < common_length - && text.chars().nth(common_prefix_length).unwrap() - == self.text.chars().nth(common_prefix_length).unwrap() - { - common_prefix_length += 1; - } - - // Backtrack to the first differing character - let mut output = String::new(); - output += &'\x08'.to_string().repeat(self.text.len() - common_prefix_length); - // Output new suffix - output += &text[common_prefix_length..text.len()]; - - // If the new text is shorter than the old one: delete overlapping characters - if let Some(overlap_count) = self.text.len().checked_sub(text.len()) { - if overlap_count > 0 { - output += &" ".repeat(overlap_count); - output += &"\x08".repeat(overlap_count); - } - } - - let _ = io::stdout().write(output.as_bytes()); - let _ = io::stdout().flush(); - self.text = text.to_string(); - } - - fn set_value(&mut self, value: f32) { - self.curr = f32::max(0.0, f32::min(1.0, value)); - } - - fn clear(&mut self) { - if self.hidden { - return; - } - - // Fill all last text to space and return the cursor - let spaces = " ".repeat(self.text.len()); - let backspaces = "\x08".repeat(self.text.len()); - print!("{}{}{}", backspaces, spaces, backspaces); - let _ = io::stdout().flush(); - - self.text = String::new(); - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs deleted file mode 100644 index e8291782b7ac1..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! Applies structured search replace rules from the command line. - -use ide_ssr::MatchFinder; -use project_model::CargoConfig; - -use crate::cli::{ - flags, - load_cargo::{load_workspace_at, LoadCargoConfig}, - Result, -}; - -impl flags::Ssr { - pub fn run(self) -> Result<()> { - use ide_db::base_db::SourceDatabaseExt; - let cargo_config = CargoConfig::default(); - let load_cargo_config = LoadCargoConfig { - load_out_dirs_from_check: true, - with_proc_macro: true, - prefill_caches: false, - }; - let (host, vfs, _proc_macro) = load_workspace_at( - &std::env::current_dir()?, - &cargo_config, - &load_cargo_config, - &|_| {}, - )?; - let db = host.raw_database(); - let mut match_finder = MatchFinder::at_first_file(db)?; - for rule in self.rule { - match_finder.add_rule(rule)?; - } - let edits = match_finder.edits(); - for (file_id, edit) in edits { - if let Some(path) = vfs.file_path(file_id).as_path() { - let mut contents = db.file_text(file_id).to_string(); - edit.apply(&mut contents); - std::fs::write(path, contents)?; - } - } - Ok(()) - } -} - -impl flags::Search { - /// Searches for `patterns`, printing debug information for any nodes whose text exactly matches - /// `debug_snippet`. This is intended for debugging and probably isn't in it's current form useful - /// for much else. - pub fn run(self) -> Result<()> { - use ide_db::base_db::SourceDatabaseExt; - use ide_db::symbol_index::SymbolsDatabase; - let cargo_config = CargoConfig::default(); - let load_cargo_config = LoadCargoConfig { - load_out_dirs_from_check: true, - with_proc_macro: true, - prefill_caches: false, - }; - let (host, _vfs, _proc_macro) = load_workspace_at( - &std::env::current_dir()?, - &cargo_config, - &load_cargo_config, - &|_| {}, - )?; - let db = host.raw_database(); - let mut match_finder = MatchFinder::at_first_file(db)?; - for pattern in self.pattern { - match_finder.add_search_pattern(pattern)?; - } - if let Some(debug_snippet) = &self.debug { - for &root in db.local_roots().iter() { - let sr = db.source_root(root); - for file_id in sr.iter() { - for debug_info in match_finder.debug_where_text_equal(file_id, debug_snippet) { - println!("{:#?}", debug_info); - } - } - } - } else { - for m in match_finder.matches().flattened().matches { - // We could possibly at some point do something more useful than just printing - // the matched text. For now though, that's the easiest thing to do. - println!("{}", m.matched_text()); - } - } - Ok(()) - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/symbols.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/symbols.rs deleted file mode 100644 index 84659b5ea9cd5..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/symbols.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Read Rust code on stdin, print syntax tree on stdout. -use ide::Analysis; - -use crate::cli::{flags, read_stdin}; - -impl flags::Symbols { - pub fn run(self) -> anyhow::Result<()> { - let text = read_stdin()?; - let (analysis, file_id) = Analysis::from_single_file(text); - let structure = analysis.file_structure(file_id).unwrap(); - for s in structure { - println!("{:?}", s); - } - Ok(()) - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs deleted file mode 100644 index ac0fdf85a774e..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ /dev/null @@ -1,1985 +0,0 @@ -//! Config used by the language server. -//! -//! We currently get this config from `initialize` LSP request, which is not the -//! best way to do it, but was the simplest thing we could implement. -//! -//! Of particular interest is the `feature_flags` hash map: while other fields -//! configure the server itself, feature flags are passed into analysis, and -//! tweak things like automatic insertion of `()` in completions. - -use std::{ffi::OsString, fmt, iter, path::PathBuf}; - -use flycheck::FlycheckConfig; -use ide::{ - AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode, - HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig, JoinLinesConfig, - Snippet, SnippetScope, -}; -use ide_db::{ - imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, - SnippetCap, -}; -use itertools::Itertools; -use lsp_types::{ClientCapabilities, MarkupKind}; -use project_model::{ - CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest, RustcSource, UnsetTestCrates, -}; -use rustc_hash::{FxHashMap, FxHashSet}; -use serde::{de::DeserializeOwned, Deserialize}; -use vfs::AbsPathBuf; - -use crate::{ - caps::completion_item_edit_resolve, - diagnostics::DiagnosticsMapConfig, - line_index::OffsetEncoding, - lsp_ext::{self, supports_utf8, WorkspaceSymbolSearchKind, WorkspaceSymbolSearchScope}, -}; - -mod patch_old_style; - -// Conventions for configuration keys to preserve maximal extendability without breakage: -// - Toggles (be it binary true/false or with more options in-between) should almost always suffix as `_enable` -// This has the benefit of namespaces being extensible, and if the suffix doesn't fit later it can be changed without breakage. -// - In general be wary of using the namespace of something verbatim, it prevents us from adding subkeys in the future -// - Don't use abbreviations unless really necessary -// - foo_command = overrides the subcommand, foo_overrideCommand allows full overwriting, extra args only applies for foo_command - -// Defines the server-side configuration of the rust-analyzer. We generate -// *parts* of VS Code's `package.json` config from this. -// -// However, editor specific config, which the server doesn't know about, should -// be specified directly in `package.json`. -// -// To deprecate an option by replacing it with another name use `new_name | `old_name` so that we keep -// parsing the old name. -config_data! { - struct ConfigData { - /// Placeholder expression to use for missing expressions in assists. - assist_expressionFillDefault: ExprFillDefaultDef = "\"todo\"", - - /// Warm up caches on project load. - cachePriming_enable: bool = "true", - /// How many worker threads to handle priming caches. The default `0` means to pick automatically. - cachePriming_numThreads: ParallelCachePrimingNumThreads = "0", - - /// Automatically refresh project info via `cargo metadata` on - /// `Cargo.toml` or `.cargo/config.toml` changes. - cargo_autoreload: bool = "true", - /// Run build scripts (`build.rs`) for more precise code analysis. - cargo_buildScripts_enable: bool = "true", - /// Override the command rust-analyzer uses to run build scripts and - /// build procedural macros. The command is required to output json - /// and should therefore include `--message-format=json` or a similar - /// option. - /// - /// By default, a cargo invocation will be constructed for the configured - /// targets and features, with the following base command line: - /// - /// ```bash - /// cargo check --quiet --workspace --message-format=json --all-targets - /// ``` - /// . - cargo_buildScripts_overrideCommand: Option> = "null", - /// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to - /// avoid checking unnecessary things. - cargo_buildScripts_useRustcWrapper: bool = "true", - /// List of features to activate. - /// - /// Set this to `"all"` to pass `--all-features` to cargo. - cargo_features: CargoFeatures = "[]", - /// Whether to pass `--no-default-features` to cargo. - cargo_noDefaultFeatures: bool = "false", - /// Internal config for debugging, disables loading of sysroot crates. - cargo_noSysroot: bool = "false", - /// Compilation target override (target triple). - cargo_target: Option = "null", - /// Unsets `#[cfg(test)]` for the specified crates. - cargo_unsetTest: Vec = "[\"core\"]", - - /// Check all targets and tests (`--all-targets`). - checkOnSave_allTargets: bool = "true", - /// Cargo command to use for `cargo check`. - checkOnSave_command: String = "\"check\"", - /// Run specified `cargo check` command for diagnostics on save. - checkOnSave_enable: bool = "true", - /// Extra arguments for `cargo check`. - checkOnSave_extraArgs: Vec = "[]", - /// List of features to activate. Defaults to - /// `#rust-analyzer.cargo.features#`. - /// - /// Set to `"all"` to pass `--all-features` to Cargo. - checkOnSave_features: Option = "null", - /// Whether to pass `--no-default-features` to Cargo. Defaults to - /// `#rust-analyzer.cargo.noDefaultFeatures#`. - checkOnSave_noDefaultFeatures: Option = "null", - /// Override the command rust-analyzer uses instead of `cargo check` for - /// diagnostics on save. The command is required to output json and - /// should therefor include `--message-format=json` or a similar option. - /// - /// If you're changing this because you're using some tool wrapping - /// Cargo, you might also want to change - /// `#rust-analyzer.cargo.buildScripts.overrideCommand#`. - /// - /// An example command would be: - /// - /// ```bash - /// cargo check --workspace --message-format=json --all-targets - /// ``` - /// . - checkOnSave_overrideCommand: Option> = "null", - /// Check for a specific target. Defaults to - /// `#rust-analyzer.cargo.target#`. - checkOnSave_target: Option = "null", - - /// Toggles the additional completions that automatically add imports when completed. - /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. - completion_autoimport_enable: bool = "true", - /// Toggles the additional completions that automatically show method calls and field accesses - /// with `self` prefixed to them when inside a method. - completion_autoself_enable: bool = "true", - /// Whether to add parenthesis and argument snippets when completing function. - completion_callable_snippets: CallableCompletionDef = "\"fill_arguments\"", - /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc. - completion_postfix_enable: bool = "true", - /// Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position. - completion_privateEditable_enable: bool = "false", - /// Custom completion snippets. - // NOTE: Keep this list in sync with the feature docs of user snippets. - completion_snippets_custom: FxHashMap = r#"{ - "Arc::new": { - "postfix": "arc", - "body": "Arc::new(${receiver})", - "requires": "std::sync::Arc", - "description": "Put the expression into an `Arc`", - "scope": "expr" - }, - "Rc::new": { - "postfix": "rc", - "body": "Rc::new(${receiver})", - "requires": "std::rc::Rc", - "description": "Put the expression into an `Rc`", - "scope": "expr" - }, - "Box::pin": { - "postfix": "pinbox", - "body": "Box::pin(${receiver})", - "requires": "std::boxed::Box", - "description": "Put the expression into a pinned `Box`", - "scope": "expr" - }, - "Ok": { - "postfix": "ok", - "body": "Ok(${receiver})", - "description": "Wrap the expression in a `Result::Ok`", - "scope": "expr" - }, - "Err": { - "postfix": "err", - "body": "Err(${receiver})", - "description": "Wrap the expression in a `Result::Err`", - "scope": "expr" - }, - "Some": { - "postfix": "some", - "body": "Some(${receiver})", - "description": "Wrap the expression in an `Option::Some`", - "scope": "expr" - } - }"#, - - /// List of rust-analyzer diagnostics to disable. - diagnostics_disabled: FxHashSet = "[]", - /// Whether to show native rust-analyzer diagnostics. - diagnostics_enable: bool = "true", - /// Whether to show experimental rust-analyzer diagnostics that might - /// have more false positives than usual. - diagnostics_experimental_enable: bool = "false", - /// Map of prefixes to be substituted when parsing diagnostic file paths. - /// This should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`. - diagnostics_remapPrefix: FxHashMap = "{}", - /// List of warnings that should be displayed with hint severity. - /// - /// The warnings will be indicated by faded text or three dots in code - /// and will not show up in the `Problems Panel`. - diagnostics_warningsAsHint: Vec = "[]", - /// List of warnings that should be displayed with info severity. - /// - /// The warnings will be indicated by a blue squiggly underline in code - /// and a blue icon in the `Problems Panel`. - diagnostics_warningsAsInfo: Vec = "[]", - - /// These directories will be ignored by rust-analyzer. They are - /// relative to the workspace root, and globs are not supported. You may - /// also need to add the folders to Code's `files.watcherExclude`. - files_excludeDirs: Vec = "[]", - /// Controls file watching implementation. - files_watcher: FilesWatcherDef = "\"client\"", - - /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords. - highlightRelated_breakPoints_enable: bool = "true", - /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`). - highlightRelated_exitPoints_enable: bool = "true", - /// Enables highlighting of related references while the cursor is on any identifier. - highlightRelated_references_enable: bool = "true", - /// Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords. - highlightRelated_yieldPoints_enable: bool = "true", - - /// Whether to show `Debug` action. Only applies when - /// `#rust-analyzer.hover.actions.enable#` is set. - hover_actions_debug_enable: bool = "true", - /// Whether to show HoverActions in Rust files. - hover_actions_enable: bool = "true", - /// Whether to show `Go to Type Definition` action. Only applies when - /// `#rust-analyzer.hover.actions.enable#` is set. - hover_actions_gotoTypeDef_enable: bool = "true", - /// Whether to show `Implementations` action. Only applies when - /// `#rust-analyzer.hover.actions.enable#` is set. - hover_actions_implementations_enable: bool = "true", - /// Whether to show `References` action. Only applies when - /// `#rust-analyzer.hover.actions.enable#` is set. - hover_actions_references_enable: bool = "false", - /// Whether to show `Run` action. Only applies when - /// `#rust-analyzer.hover.actions.enable#` is set. - hover_actions_run_enable: bool = "true", - - /// Whether to show documentation on hover. - hover_documentation_enable: bool = "true", - /// Use markdown syntax for links in hover. - hover_links_enable: bool = "true", - - /// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file. - imports_granularity_enforce: bool = "false", - /// How imports should be grouped into use statements. - imports_granularity_group: ImportGranularityDef = "\"crate\"", - /// Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-import[following order]. Groups are separated by newlines. - imports_group_enable: bool = "true", - /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`. - imports_merge_glob: bool = "true", - /// The path structure for newly inserted paths to use. - imports_prefix: ImportPrefixDef = "\"plain\"", - - /// Whether to show inlay type hints for binding modes. - inlayHints_bindingModeHints_enable: bool = "false", - /// Whether to show inlay type hints for method chains. - inlayHints_chainingHints_enable: bool = "true", - /// Whether to show inlay hints after a closing `}` to indicate what item it belongs to. - inlayHints_closingBraceHints_enable: bool = "true", - /// Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1 - /// to always show them). - inlayHints_closingBraceHints_minLines: usize = "25", - /// Whether to show inlay type hints for return types of closures. - inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef = "\"never\"", - /// Whether to show inlay type hints for elided lifetimes in function signatures. - inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = "\"never\"", - /// Whether to prefer using parameter names as the name for elided lifetime hints if possible. - inlayHints_lifetimeElisionHints_useParameterNames: bool = "false", - /// Maximum length for inlay hints. Set to null to have an unlimited length. - inlayHints_maxLength: Option = "25", - /// Whether to show function parameter name inlay hints at the call - /// site. - inlayHints_parameterHints_enable: bool = "true", - /// Whether to show inlay type hints for compiler inserted reborrows. - inlayHints_reborrowHints_enable: ReborrowHintsDef = "\"never\"", - /// Whether to render leading colons for type hints, and trailing colons for parameter hints. - inlayHints_renderColons: bool = "true", - /// Whether to show inlay type hints for variables. - inlayHints_typeHints_enable: bool = "true", - /// Whether to hide inlay type hints for `let` statements that initialize to a closure. - /// Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`. - inlayHints_typeHints_hideClosureInitialization: bool = "false", - /// Whether to hide inlay type hints for constructors. - inlayHints_typeHints_hideNamedConstructor: bool = "false", - - /// Join lines merges consecutive declaration and initialization of an assignment. - joinLines_joinAssignments: bool = "true", - /// Join lines inserts else between consecutive ifs. - joinLines_joinElseIf: bool = "true", - /// Join lines removes trailing commas. - joinLines_removeTrailingComma: bool = "true", - /// Join lines unwraps trivial blocks. - joinLines_unwrapTrivialBlock: bool = "true", - - /// Whether to show `Debug` lens. Only applies when - /// `#rust-analyzer.lens.enable#` is set. - lens_debug_enable: bool = "true", - /// Whether to show CodeLens in Rust files. - lens_enable: bool = "true", - /// Internal config: use custom client-side commands even when the - /// client doesn't set the corresponding capability. - lens_forceCustomCommands: bool = "true", - /// Whether to show `Implementations` lens. Only applies when - /// `#rust-analyzer.lens.enable#` is set. - lens_implementations_enable: bool = "true", - /// Whether to show `References` lens for Struct, Enum, and Union. - /// Only applies when `#rust-analyzer.lens.enable#` is set. - lens_references_adt_enable: bool = "false", - /// Whether to show `References` lens for Enum Variants. - /// Only applies when `#rust-analyzer.lens.enable#` is set. - lens_references_enumVariant_enable: bool = "false", - /// Whether to show `Method References` lens. Only applies when - /// `#rust-analyzer.lens.enable#` is set. - lens_references_method_enable: bool = "false", - /// Whether to show `References` lens for Trait. - /// Only applies when `#rust-analyzer.lens.enable#` is set. - lens_references_trait_enable: bool = "false", - /// Whether to show `Run` lens. Only applies when - /// `#rust-analyzer.lens.enable#` is set. - lens_run_enable: bool = "true", - - /// Disable project auto-discovery in favor of explicitly specified set - /// of projects. - /// - /// Elements must be paths pointing to `Cargo.toml`, - /// `rust-project.json`, or JSON objects in `rust-project.json` format. - linkedProjects: Vec = "[]", - - /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. - lru_capacity: Option = "null", - - /// Whether to show `can't find Cargo.toml` error message. - notifications_cargoTomlNotFound: bool = "true", - - /// Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set. - procMacro_attributes_enable: bool = "true", - /// Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`. - procMacro_enable: bool = "true", - /// These proc-macros will be ignored when trying to expand them. - /// - /// This config takes a map of crate names with the exported proc-macro names to ignore as values. - procMacro_ignored: FxHashMap, Box<[Box]>> = "{}", - /// Internal config, path to proc-macro server executable (typically, - /// this is rust-analyzer itself, but we override this in tests). - procMacro_server: Option = "null", - - /// Command to be executed instead of 'cargo' for runnables. - runnables_command: Option = "null", - /// Additional arguments to be passed to cargo for runnables such as - /// tests or binaries. For example, it may be `--release`. - runnables_extraArgs: Vec = "[]", - - /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private - /// projects, or "discover" to try to automatically find it if the `rustc-dev` component - /// is installed. - /// - /// Any project which uses rust-analyzer with the rustcPrivate - /// crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it. - /// - /// This option does not take effect until rust-analyzer is restarted. - rustc_source: Option = "null", - - /// Additional arguments to `rustfmt`. - rustfmt_extraArgs: Vec = "[]", - /// Advanced option, fully override the command rust-analyzer uses for - /// formatting. - rustfmt_overrideCommand: Option> = "null", - /// Enables the use of rustfmt's unstable range formatting command for the - /// `textDocument/rangeFormatting` request. The rustfmt option is unstable and only - /// available on a nightly build. - rustfmt_rangeFormatting_enable: bool = "false", - - /// Use semantic tokens for strings. - /// - /// In some editors (e.g. vscode) semantic tokens override other highlighting grammars. - /// By disabling semantic tokens for strings, other grammars can be used to highlight - /// their contents. - semanticHighlighting_strings_enable: bool = "true", - - /// Show full signature of the callable. Only shows parameters if disabled. - signatureInfo_detail: SignatureDetail = "\"full\"", - /// Show documentation. - signatureInfo_documentation_enable: bool = "true", - - /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. - typing_autoClosingAngleBrackets_enable: bool = "false", - - /// Workspace symbol search kind. - workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = "\"only_types\"", - /// Limits the number of items returned from a workspace symbol search (Defaults to 128). - /// Some clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search. - /// Other clients requires all results upfront and might require a higher limit. - workspace_symbol_search_limit: usize = "128", - /// Workspace symbol search scope. - workspace_symbol_search_scope: WorkspaceSymbolSearchScopeDef = "\"workspace\"", - } -} - -impl Default for ConfigData { - fn default() -> Self { - ConfigData::from_json(serde_json::Value::Null, &mut Vec::new()) - } -} - -#[derive(Debug, Clone)] -pub struct Config { - pub discovered_projects: Option>, - caps: lsp_types::ClientCapabilities, - root_path: AbsPathBuf, - data: ConfigData, - detached_files: Vec, - snippets: Vec, -} - -type ParallelCachePrimingNumThreads = u8; - -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum LinkedProject { - ProjectManifest(ProjectManifest), - InlineJsonProject(ProjectJson), -} - -impl From for LinkedProject { - fn from(v: ProjectManifest) -> Self { - LinkedProject::ProjectManifest(v) - } -} - -impl From for LinkedProject { - fn from(v: ProjectJson) -> Self { - LinkedProject::InlineJsonProject(v) - } -} - -pub struct CallInfoConfig { - pub params_only: bool, - pub docs: bool, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct LensConfig { - // runnables - pub run: bool, - pub debug: bool, - - // implementations - pub implementations: bool, - - // references - pub method_refs: bool, - pub refs_adt: bool, // for Struct, Enum, Union and Trait - pub refs_trait: bool, // for Struct, Enum, Union and Trait - pub enum_variant_refs: bool, -} - -impl LensConfig { - pub fn any(&self) -> bool { - self.run - || self.debug - || self.implementations - || self.method_refs - || self.refs_adt - || self.refs_trait - || self.enum_variant_refs - } - - pub fn none(&self) -> bool { - !self.any() - } - - pub fn runnable(&self) -> bool { - self.run || self.debug - } - - pub fn references(&self) -> bool { - self.method_refs || self.refs_adt || self.refs_trait || self.enum_variant_refs - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct HoverActionsConfig { - pub implementations: bool, - pub references: bool, - pub run: bool, - pub debug: bool, - pub goto_type_def: bool, -} - -impl HoverActionsConfig { - pub const NO_ACTIONS: Self = Self { - implementations: false, - references: false, - run: false, - debug: false, - goto_type_def: false, - }; - - pub fn any(&self) -> bool { - self.implementations || self.references || self.runnable() || self.goto_type_def - } - - pub fn none(&self) -> bool { - !self.any() - } - - pub fn runnable(&self) -> bool { - self.run || self.debug - } -} - -#[derive(Debug, Clone)] -pub struct FilesConfig { - pub watcher: FilesWatcher, - pub exclude: Vec, -} - -#[derive(Debug, Clone)] -pub enum FilesWatcher { - Client, - Server, -} - -#[derive(Debug, Clone)] -pub struct NotificationsConfig { - pub cargo_toml_not_found: bool, -} - -#[derive(Debug, Clone)] -pub enum RustfmtConfig { - Rustfmt { extra_args: Vec, enable_range_formatting: bool }, - CustomCommand { command: String, args: Vec }, -} - -/// Configuration for runnable items, such as `main` function or tests. -#[derive(Debug, Clone)] -pub struct RunnablesConfig { - /// Custom command to be executed instead of `cargo` for runnables. - pub override_cargo: Option, - /// Additional arguments for the `cargo`, e.g. `--release`. - pub cargo_extra_args: Vec, -} - -/// Configuration for workspace symbol search requests. -#[derive(Debug, Clone)] -pub struct WorkspaceSymbolConfig { - /// In what scope should the symbol be searched in. - pub search_scope: WorkspaceSymbolSearchScope, - /// What kind of symbol is being searched for. - pub search_kind: WorkspaceSymbolSearchKind, - /// How many items are returned at most. - pub search_limit: usize, -} - -pub struct ClientCommandsConfig { - pub run_single: bool, - pub debug_single: bool, - pub show_reference: bool, - pub goto_location: bool, - pub trigger_parameter_hints: bool, -} - -#[derive(Debug)] -pub struct ConfigUpdateError { - errors: Vec<(String, serde_json::Error)>, -} - -impl fmt::Display for ConfigUpdateError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let errors = self.errors.iter().format_with("\n", |(key, e), f| { - f(key)?; - f(&": ")?; - f(e) - }); - write!( - f, - "rust-analyzer found {} invalid config value{}:\n{}", - self.errors.len(), - if self.errors.len() == 1 { "" } else { "s" }, - errors - ) - } -} - -impl Config { - pub fn new(root_path: AbsPathBuf, caps: ClientCapabilities) -> Self { - Config { - caps, - data: ConfigData::default(), - detached_files: Vec::new(), - discovered_projects: None, - root_path, - snippets: Default::default(), - } - } - - pub fn update(&mut self, mut json: serde_json::Value) -> Result<(), ConfigUpdateError> { - tracing::info!("updating config from JSON: {:#}", json); - if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { - return Ok(()); - } - let mut errors = Vec::new(); - self.detached_files = - get_field::>(&mut json, &mut errors, "detachedFiles", None, "[]") - .into_iter() - .map(AbsPathBuf::assert) - .collect(); - patch_old_style::patch_json_for_outdated_configs(&mut json); - self.data = ConfigData::from_json(json, &mut errors); - tracing::debug!("deserialized config data: {:#?}", self.data); - self.snippets.clear(); - for (name, def) in self.data.completion_snippets_custom.iter() { - if def.prefix.is_empty() && def.postfix.is_empty() { - continue; - } - let scope = match def.scope { - SnippetScopeDef::Expr => SnippetScope::Expr, - SnippetScopeDef::Type => SnippetScope::Type, - SnippetScopeDef::Item => SnippetScope::Item, - }; - match Snippet::new( - &def.prefix, - &def.postfix, - &def.body, - def.description.as_ref().unwrap_or(name), - &def.requires, - scope, - ) { - Some(snippet) => self.snippets.push(snippet), - None => errors.push(( - format!("snippet {name} is invalid"), - ::custom( - "snippet path is invalid or triggers are missing", - ), - )), - } - } - - self.validate(&mut errors); - - if errors.is_empty() { - Ok(()) - } else { - Err(ConfigUpdateError { errors }) - } - } - - fn validate(&self, error_sink: &mut Vec<(String, serde_json::Error)>) { - use serde::de::Error; - if self.data.checkOnSave_command.is_empty() { - error_sink.push(( - "/checkOnSave/command".to_string(), - serde_json::Error::custom("expected a non-empty string"), - )); - } - } - - pub fn json_schema() -> serde_json::Value { - ConfigData::json_schema() - } - - pub fn root_path(&self) -> &AbsPathBuf { - &self.root_path - } - - pub fn caps(&self) -> &lsp_types::ClientCapabilities { - &self.caps - } - - pub fn detached_files(&self) -> &[AbsPathBuf] { - &self.detached_files - } -} - -macro_rules! try_ { - ($expr:expr) => { - || -> _ { Some($expr) }() - }; -} -macro_rules! try_or { - ($expr:expr, $or:expr) => { - try_!($expr).unwrap_or($or) - }; -} - -macro_rules! try_or_def { - ($expr:expr) => { - try_!($expr).unwrap_or_default() - }; -} - -impl Config { - pub fn linked_projects(&self) -> Vec { - match self.data.linkedProjects.as_slice() { - [] => match self.discovered_projects.as_ref() { - Some(discovered_projects) => { - let exclude_dirs: Vec<_> = self - .data - .files_excludeDirs - .iter() - .map(|p| self.root_path.join(p)) - .collect(); - discovered_projects - .iter() - .filter(|p| { - let (ProjectManifest::ProjectJson(path) - | ProjectManifest::CargoToml(path)) = p; - !exclude_dirs.iter().any(|p| path.starts_with(p)) - }) - .cloned() - .map(LinkedProject::from) - .collect() - } - None => Vec::new(), - }, - linked_projects => linked_projects - .iter() - .filter_map(|linked_project| match linked_project { - ManifestOrProjectJson::Manifest(it) => { - let path = self.root_path.join(it); - ProjectManifest::from_manifest_file(path) - .map_err(|e| tracing::error!("failed to load linked project: {}", e)) - .ok() - .map(Into::into) - } - ManifestOrProjectJson::ProjectJson(it) => { - Some(ProjectJson::new(&self.root_path, it.clone()).into()) - } - }) - .collect(), - } - } - - pub fn did_save_text_document_dynamic_registration(&self) -> bool { - let caps = try_or_def!(self.caps.text_document.as_ref()?.synchronization.clone()?); - caps.did_save == Some(true) && caps.dynamic_registration == Some(true) - } - - pub fn did_change_watched_files_dynamic_registration(&self) -> bool { - try_or_def!( - self.caps.workspace.as_ref()?.did_change_watched_files.as_ref()?.dynamic_registration? - ) - } - - pub fn prefill_caches(&self) -> bool { - self.data.cachePriming_enable - } - - pub fn location_link(&self) -> bool { - try_or_def!(self.caps.text_document.as_ref()?.definition?.link_support?) - } - - pub fn line_folding_only(&self) -> bool { - try_or_def!(self.caps.text_document.as_ref()?.folding_range.as_ref()?.line_folding_only?) - } - - pub fn hierarchical_symbols(&self) -> bool { - try_or_def!( - self.caps - .text_document - .as_ref()? - .document_symbol - .as_ref()? - .hierarchical_document_symbol_support? - ) - } - - pub fn code_action_literals(&self) -> bool { - try_!(self - .caps - .text_document - .as_ref()? - .code_action - .as_ref()? - .code_action_literal_support - .as_ref()?) - .is_some() - } - - pub fn work_done_progress(&self) -> bool { - try_or_def!(self.caps.window.as_ref()?.work_done_progress?) - } - - pub fn will_rename(&self) -> bool { - try_or_def!(self.caps.workspace.as_ref()?.file_operations.as_ref()?.will_rename?) - } - - pub fn change_annotation_support(&self) -> bool { - try_!(self - .caps - .workspace - .as_ref()? - .workspace_edit - .as_ref()? - .change_annotation_support - .as_ref()?) - .is_some() - } - - pub fn code_action_resolve(&self) -> bool { - try_or_def!(self - .caps - .text_document - .as_ref()? - .code_action - .as_ref()? - .resolve_support - .as_ref()? - .properties - .as_slice()) - .iter() - .any(|it| it == "edit") - } - - pub fn signature_help_label_offsets(&self) -> bool { - try_or_def!( - self.caps - .text_document - .as_ref()? - .signature_help - .as_ref()? - .signature_information - .as_ref()? - .parameter_information - .as_ref()? - .label_offset_support? - ) - } - - pub fn completion_label_details_support(&self) -> bool { - try_!(self - .caps - .text_document - .as_ref()? - .completion - .as_ref()? - .completion_item - .as_ref()? - .label_details_support - .as_ref()?) - .is_some() - } - - pub fn offset_encoding(&self) -> OffsetEncoding { - if supports_utf8(&self.caps) { - OffsetEncoding::Utf8 - } else { - OffsetEncoding::Utf16 - } - } - - fn experimental(&self, index: &'static str) -> bool { - try_or_def!(self.caps.experimental.as_ref()?.get(index)?.as_bool()?) - } - - pub fn code_action_group(&self) -> bool { - self.experimental("codeActionGroup") - } - - pub fn server_status_notification(&self) -> bool { - self.experimental("serverStatusNotification") - } - - pub fn publish_diagnostics(&self) -> bool { - self.data.diagnostics_enable - } - - pub fn diagnostics(&self) -> DiagnosticsConfig { - DiagnosticsConfig { - proc_attr_macros_enabled: self.expand_proc_attr_macros(), - proc_macros_enabled: self.data.procMacro_enable, - disable_experimental: !self.data.diagnostics_experimental_enable, - disabled: self.data.diagnostics_disabled.clone(), - expr_fill_default: match self.data.assist_expressionFillDefault { - ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo, - ExprFillDefaultDef::Default => ExprFillDefaultMode::Default, - }, - } - } - - pub fn diagnostics_map(&self) -> DiagnosticsMapConfig { - DiagnosticsMapConfig { - remap_prefix: self.data.diagnostics_remapPrefix.clone(), - warnings_as_info: self.data.diagnostics_warningsAsInfo.clone(), - warnings_as_hint: self.data.diagnostics_warningsAsHint.clone(), - } - } - - pub fn lru_capacity(&self) -> Option { - self.data.lru_capacity - } - - pub fn proc_macro_srv(&self) -> Option<(AbsPathBuf, Vec)> { - if !self.data.procMacro_enable { - return None; - } - let path = match &self.data.procMacro_server { - Some(it) => self.root_path.join(it), - None => AbsPathBuf::assert(std::env::current_exe().ok()?), - }; - Some((path, vec!["proc-macro".into()])) - } - - pub fn dummy_replacements(&self) -> &FxHashMap, Box<[Box]>> { - &self.data.procMacro_ignored - } - - pub fn expand_proc_attr_macros(&self) -> bool { - self.data.procMacro_enable && self.data.procMacro_attributes_enable - } - - pub fn files(&self) -> FilesConfig { - FilesConfig { - watcher: match self.data.files_watcher { - FilesWatcherDef::Client if self.did_change_watched_files_dynamic_registration() => { - FilesWatcher::Client - } - _ => FilesWatcher::Server, - }, - exclude: self.data.files_excludeDirs.iter().map(|it| self.root_path.join(it)).collect(), - } - } - - pub fn notifications(&self) -> NotificationsConfig { - NotificationsConfig { cargo_toml_not_found: self.data.notifications_cargoTomlNotFound } - } - - pub fn cargo_autoreload(&self) -> bool { - self.data.cargo_autoreload - } - - pub fn run_build_scripts(&self) -> bool { - self.data.cargo_buildScripts_enable || self.data.procMacro_enable - } - - pub fn cargo(&self) -> CargoConfig { - let rustc_source = self.data.rustc_source.as_ref().map(|rustc_src| { - if rustc_src == "discover" { - RustcSource::Discover - } else { - RustcSource::Path(self.root_path.join(rustc_src)) - } - }); - - CargoConfig { - no_default_features: self.data.cargo_noDefaultFeatures, - all_features: matches!(self.data.cargo_features, CargoFeatures::All), - features: match &self.data.cargo_features { - CargoFeatures::All => vec![], - CargoFeatures::Listed(it) => it.clone(), - }, - target: self.data.cargo_target.clone(), - no_sysroot: self.data.cargo_noSysroot, - rustc_source, - unset_test_crates: UnsetTestCrates::Only(self.data.cargo_unsetTest.clone()), - wrap_rustc_in_build_scripts: self.data.cargo_buildScripts_useRustcWrapper, - run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(), - } - } - - pub fn rustfmt(&self) -> RustfmtConfig { - match &self.data.rustfmt_overrideCommand { - Some(args) if !args.is_empty() => { - let mut args = args.clone(); - let command = args.remove(0); - RustfmtConfig::CustomCommand { command, args } - } - Some(_) | None => RustfmtConfig::Rustfmt { - extra_args: self.data.rustfmt_extraArgs.clone(), - enable_range_formatting: self.data.rustfmt_rangeFormatting_enable, - }, - } - } - - pub fn flycheck(&self) -> Option { - if !self.data.checkOnSave_enable { - return None; - } - let flycheck_config = match &self.data.checkOnSave_overrideCommand { - Some(args) if !args.is_empty() => { - let mut args = args.clone(); - let command = args.remove(0); - FlycheckConfig::CustomCommand { command, args } - } - Some(_) | None => FlycheckConfig::CargoCommand { - command: self.data.checkOnSave_command.clone(), - target_triple: self - .data - .checkOnSave_target - .clone() - .or_else(|| self.data.cargo_target.clone()), - all_targets: self.data.checkOnSave_allTargets, - no_default_features: self - .data - .checkOnSave_noDefaultFeatures - .unwrap_or(self.data.cargo_noDefaultFeatures), - all_features: matches!( - self.data.checkOnSave_features.as_ref().unwrap_or(&self.data.cargo_features), - CargoFeatures::All - ), - features: match self - .data - .checkOnSave_features - .clone() - .unwrap_or_else(|| self.data.cargo_features.clone()) - { - CargoFeatures::All => vec![], - CargoFeatures::Listed(it) => it, - }, - extra_args: self.data.checkOnSave_extraArgs.clone(), - }, - }; - Some(flycheck_config) - } - - pub fn runnables(&self) -> RunnablesConfig { - RunnablesConfig { - override_cargo: self.data.runnables_command.clone(), - cargo_extra_args: self.data.runnables_extraArgs.clone(), - } - } - - pub fn inlay_hints(&self) -> InlayHintsConfig { - InlayHintsConfig { - render_colons: self.data.inlayHints_renderColons, - type_hints: self.data.inlayHints_typeHints_enable, - parameter_hints: self.data.inlayHints_parameterHints_enable, - chaining_hints: self.data.inlayHints_chainingHints_enable, - closure_return_type_hints: match self.data.inlayHints_closureReturnTypeHints_enable { - ClosureReturnTypeHintsDef::Always => ide::ClosureReturnTypeHints::Always, - ClosureReturnTypeHintsDef::Never => ide::ClosureReturnTypeHints::Never, - ClosureReturnTypeHintsDef::WithBlock => ide::ClosureReturnTypeHints::WithBlock, - }, - lifetime_elision_hints: match self.data.inlayHints_lifetimeElisionHints_enable { - LifetimeElisionDef::Always => ide::LifetimeElisionHints::Always, - LifetimeElisionDef::Never => ide::LifetimeElisionHints::Never, - LifetimeElisionDef::SkipTrivial => ide::LifetimeElisionHints::SkipTrivial, - }, - hide_named_constructor_hints: self.data.inlayHints_typeHints_hideNamedConstructor, - hide_closure_initialization_hints: self - .data - .inlayHints_typeHints_hideClosureInitialization, - reborrow_hints: match self.data.inlayHints_reborrowHints_enable { - ReborrowHintsDef::Always => ide::ReborrowHints::Always, - ReborrowHintsDef::Never => ide::ReborrowHints::Never, - ReborrowHintsDef::Mutable => ide::ReborrowHints::MutableOnly, - }, - binding_mode_hints: self.data.inlayHints_bindingModeHints_enable, - param_names_for_lifetime_elision_hints: self - .data - .inlayHints_lifetimeElisionHints_useParameterNames, - max_length: self.data.inlayHints_maxLength, - closing_brace_hints_min_lines: if self.data.inlayHints_closingBraceHints_enable { - Some(self.data.inlayHints_closingBraceHints_minLines) - } else { - None - }, - } - } - - fn insert_use_config(&self) -> InsertUseConfig { - InsertUseConfig { - granularity: match self.data.imports_granularity_group { - ImportGranularityDef::Preserve => ImportGranularity::Preserve, - ImportGranularityDef::Item => ImportGranularity::Item, - ImportGranularityDef::Crate => ImportGranularity::Crate, - ImportGranularityDef::Module => ImportGranularity::Module, - }, - enforce_granularity: self.data.imports_granularity_enforce, - prefix_kind: match self.data.imports_prefix { - ImportPrefixDef::Plain => PrefixKind::Plain, - ImportPrefixDef::ByCrate => PrefixKind::ByCrate, - ImportPrefixDef::BySelf => PrefixKind::BySelf, - }, - group: self.data.imports_group_enable, - skip_glob_imports: !self.data.imports_merge_glob, - } - } - - pub fn completion(&self) -> CompletionConfig { - CompletionConfig { - enable_postfix_completions: self.data.completion_postfix_enable, - enable_imports_on_the_fly: self.data.completion_autoimport_enable - && completion_item_edit_resolve(&self.caps), - enable_self_on_the_fly: self.data.completion_autoself_enable, - enable_private_editable: self.data.completion_privateEditable_enable, - callable: match self.data.completion_callable_snippets { - CallableCompletionDef::FillArguments => Some(CallableSnippets::FillArguments), - CallableCompletionDef::AddParentheses => Some(CallableSnippets::AddParentheses), - CallableCompletionDef::None => None, - }, - insert_use: self.insert_use_config(), - snippet_cap: SnippetCap::new(try_or_def!( - self.caps - .text_document - .as_ref()? - .completion - .as_ref()? - .completion_item - .as_ref()? - .snippet_support? - )), - snippets: self.snippets.clone(), - } - } - - pub fn snippet_cap(&self) -> bool { - self.experimental("snippetTextEdit") - } - - pub fn assist(&self) -> AssistConfig { - AssistConfig { - snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")), - allowed: None, - insert_use: self.insert_use_config(), - } - } - - pub fn join_lines(&self) -> JoinLinesConfig { - JoinLinesConfig { - join_else_if: self.data.joinLines_joinElseIf, - remove_trailing_comma: self.data.joinLines_removeTrailingComma, - unwrap_trivial_blocks: self.data.joinLines_unwrapTrivialBlock, - join_assignments: self.data.joinLines_joinAssignments, - } - } - - pub fn call_info(&self) -> CallInfoConfig { - CallInfoConfig { - params_only: matches!(self.data.signatureInfo_detail, SignatureDetail::Parameters), - docs: self.data.signatureInfo_documentation_enable, - } - } - - pub fn lens(&self) -> LensConfig { - LensConfig { - run: self.data.lens_enable && self.data.lens_run_enable, - debug: self.data.lens_enable && self.data.lens_debug_enable, - implementations: self.data.lens_enable && self.data.lens_implementations_enable, - method_refs: self.data.lens_enable && self.data.lens_references_method_enable, - refs_adt: self.data.lens_enable && self.data.lens_references_adt_enable, - refs_trait: self.data.lens_enable && self.data.lens_references_trait_enable, - enum_variant_refs: self.data.lens_enable - && self.data.lens_references_enumVariant_enable, - } - } - - pub fn hover_actions(&self) -> HoverActionsConfig { - let enable = self.experimental("hoverActions") && self.data.hover_actions_enable; - HoverActionsConfig { - implementations: enable && self.data.hover_actions_implementations_enable, - references: enable && self.data.hover_actions_references_enable, - run: enable && self.data.hover_actions_run_enable, - debug: enable && self.data.hover_actions_debug_enable, - goto_type_def: enable && self.data.hover_actions_gotoTypeDef_enable, - } - } - - pub fn highlighting_strings(&self) -> bool { - self.data.semanticHighlighting_strings_enable - } - - pub fn hover(&self) -> HoverConfig { - HoverConfig { - links_in_hover: self.data.hover_links_enable, - documentation: self.data.hover_documentation_enable.then(|| { - let is_markdown = try_or_def!(self - .caps - .text_document - .as_ref()? - .hover - .as_ref()? - .content_format - .as_ref()? - .as_slice()) - .contains(&MarkupKind::Markdown); - if is_markdown { - HoverDocFormat::Markdown - } else { - HoverDocFormat::PlainText - } - }), - } - } - - pub fn workspace_symbol(&self) -> WorkspaceSymbolConfig { - WorkspaceSymbolConfig { - search_scope: match self.data.workspace_symbol_search_scope { - WorkspaceSymbolSearchScopeDef::Workspace => WorkspaceSymbolSearchScope::Workspace, - WorkspaceSymbolSearchScopeDef::WorkspaceAndDependencies => { - WorkspaceSymbolSearchScope::WorkspaceAndDependencies - } - }, - search_kind: match self.data.workspace_symbol_search_kind { - WorkspaceSymbolSearchKindDef::OnlyTypes => WorkspaceSymbolSearchKind::OnlyTypes, - WorkspaceSymbolSearchKindDef::AllSymbols => WorkspaceSymbolSearchKind::AllSymbols, - }, - search_limit: self.data.workspace_symbol_search_limit, - } - } - - pub fn semantic_tokens_refresh(&self) -> bool { - try_or_def!(self.caps.workspace.as_ref()?.semantic_tokens.as_ref()?.refresh_support?) - } - - pub fn code_lens_refresh(&self) -> bool { - try_or_def!(self.caps.workspace.as_ref()?.code_lens.as_ref()?.refresh_support?) - } - - pub fn insert_replace_support(&self) -> bool { - try_or_def!( - self.caps - .text_document - .as_ref()? - .completion - .as_ref()? - .completion_item - .as_ref()? - .insert_replace_support? - ) - } - - pub fn client_commands(&self) -> ClientCommandsConfig { - let commands = - try_or!(self.caps.experimental.as_ref()?.get("commands")?, &serde_json::Value::Null); - let commands: Option = - serde_json::from_value(commands.clone()).ok(); - let force = commands.is_none() && self.data.lens_forceCustomCommands; - let commands = commands.map(|it| it.commands).unwrap_or_default(); - - let get = |name: &str| commands.iter().any(|it| it == name) || force; - - ClientCommandsConfig { - run_single: get("rust-analyzer.runSingle"), - debug_single: get("rust-analyzer.debugSingle"), - show_reference: get("rust-analyzer.showReferences"), - goto_location: get("rust-analyzer.gotoLocation"), - trigger_parameter_hints: get("editor.action.triggerParameterHints"), - } - } - - pub fn highlight_related(&self) -> HighlightRelatedConfig { - HighlightRelatedConfig { - references: self.data.highlightRelated_references_enable, - break_points: self.data.highlightRelated_breakPoints_enable, - exit_points: self.data.highlightRelated_exitPoints_enable, - yield_points: self.data.highlightRelated_yieldPoints_enable, - } - } - - pub fn prime_caches_num_threads(&self) -> u8 { - match self.data.cachePriming_numThreads { - 0 => num_cpus::get_physical().try_into().unwrap_or(u8::MAX), - n => n, - } - } - - pub fn typing_autoclose_angle(&self) -> bool { - self.data.typing_autoClosingAngleBrackets_enable - } -} -// Deserialization definitions - -macro_rules! create_bool_or_string_de { - ($ident:ident<$bool:literal, $string:literal>) => { - fn $ident<'de, D>(d: D) -> Result<(), D::Error> - where - D: serde::Deserializer<'de>, - { - struct V; - impl<'de> serde::de::Visitor<'de> for V { - type Value = (); - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str(concat!( - stringify!($bool), - " or \"", - stringify!($string), - "\"" - )) - } - - fn visit_bool(self, v: bool) -> Result - where - E: serde::de::Error, - { - match v { - $bool => Ok(()), - _ => Err(serde::de::Error::invalid_value( - serde::de::Unexpected::Bool(v), - &self, - )), - } - } - - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - match v { - $string => Ok(()), - _ => Err(serde::de::Error::invalid_value( - serde::de::Unexpected::Str(v), - &self, - )), - } - } - - fn visit_enum(self, a: A) -> Result - where - A: serde::de::EnumAccess<'de>, - { - use serde::de::VariantAccess; - let (variant, va) = a.variant::<&'de str>()?; - va.unit_variant()?; - match variant { - $string => Ok(()), - _ => Err(serde::de::Error::invalid_value( - serde::de::Unexpected::Str(variant), - &self, - )), - } - } - } - d.deserialize_any(V) - } - }; -} -create_bool_or_string_de!(true_or_always); -create_bool_or_string_de!(false_or_never); - -macro_rules! named_unit_variant { - ($variant:ident) => { - pub(super) fn $variant<'de, D>(deserializer: D) -> Result<(), D::Error> - where - D: serde::Deserializer<'de>, - { - struct V; - impl<'de> serde::de::Visitor<'de> for V { - type Value = (); - fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(concat!("\"", stringify!($variant), "\"")) - } - fn visit_str(self, value: &str) -> Result { - if value == stringify!($variant) { - Ok(()) - } else { - Err(E::invalid_value(serde::de::Unexpected::Str(value), &self)) - } - } - } - deserializer.deserialize_str(V) - } - }; -} - -mod de_unit_v { - named_unit_variant!(all); - named_unit_variant!(skip_trivial); - named_unit_variant!(mutable); - named_unit_variant!(with_block); -} - -#[derive(Deserialize, Debug, Clone, Copy)] -#[serde(rename_all = "snake_case")] -enum SnippetScopeDef { - Expr, - Item, - Type, -} - -impl Default for SnippetScopeDef { - fn default() -> Self { - SnippetScopeDef::Expr - } -} - -#[derive(Deserialize, Debug, Clone, Default)] -#[serde(default)] -struct SnippetDef { - #[serde(deserialize_with = "single_or_array")] - prefix: Vec, - #[serde(deserialize_with = "single_or_array")] - postfix: Vec, - description: Option, - #[serde(deserialize_with = "single_or_array")] - body: Vec, - #[serde(deserialize_with = "single_or_array")] - requires: Vec, - scope: SnippetScopeDef, -} - -fn single_or_array<'de, D>(deserializer: D) -> Result, D::Error> -where - D: serde::Deserializer<'de>, -{ - struct SingleOrVec; - - impl<'de> serde::de::Visitor<'de> for SingleOrVec { - type Value = Vec; - - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("string or array of strings") - } - - fn visit_str(self, value: &str) -> Result - where - E: serde::de::Error, - { - Ok(vec![value.to_owned()]) - } - - fn visit_seq(self, seq: A) -> Result - where - A: serde::de::SeqAccess<'de>, - { - Deserialize::deserialize(serde::de::value::SeqAccessDeserializer::new(seq)) - } - } - - deserializer.deserialize_any(SingleOrVec) -} - -#[derive(Deserialize, Debug, Clone)] -#[serde(untagged)] -enum ManifestOrProjectJson { - Manifest(PathBuf), - ProjectJson(ProjectJsonData), -} - -#[derive(Deserialize, Debug, Clone)] -#[serde(rename_all = "snake_case")] -enum ExprFillDefaultDef { - Todo, - Default, -} - -#[derive(Deserialize, Debug, Clone)] -#[serde(rename_all = "snake_case")] -enum ImportGranularityDef { - Preserve, - Item, - Crate, - Module, -} - -#[derive(Deserialize, Debug, Copy, Clone)] -#[serde(rename_all = "snake_case")] -enum CallableCompletionDef { - FillArguments, - AddParentheses, - None, -} - -#[derive(Deserialize, Debug, Clone)] -#[serde(untagged)] -enum CargoFeatures { - #[serde(deserialize_with = "de_unit_v::all")] - All, - Listed(Vec), -} - -#[derive(Deserialize, Debug, Clone)] -#[serde(untagged)] -enum LifetimeElisionDef { - #[serde(deserialize_with = "true_or_always")] - Always, - #[serde(deserialize_with = "false_or_never")] - Never, - #[serde(deserialize_with = "de_unit_v::skip_trivial")] - SkipTrivial, -} - -#[derive(Deserialize, Debug, Clone)] -#[serde(untagged)] -enum ClosureReturnTypeHintsDef { - #[serde(deserialize_with = "true_or_always")] - Always, - #[serde(deserialize_with = "false_or_never")] - Never, - #[serde(deserialize_with = "de_unit_v::with_block")] - WithBlock, -} - -#[derive(Deserialize, Debug, Clone)] -#[serde(untagged)] -enum ReborrowHintsDef { - #[serde(deserialize_with = "true_or_always")] - Always, - #[serde(deserialize_with = "false_or_never")] - Never, - #[serde(deserialize_with = "de_unit_v::mutable")] - Mutable, -} - -#[derive(Deserialize, Debug, Clone)] -#[serde(rename_all = "snake_case")] -enum FilesWatcherDef { - Client, - Notify, - Server, -} - -#[derive(Deserialize, Debug, Clone)] -#[serde(rename_all = "snake_case")] -enum ImportPrefixDef { - Plain, - #[serde(alias = "self")] - BySelf, - #[serde(alias = "crate")] - ByCrate, -} - -#[derive(Deserialize, Debug, Clone)] -#[serde(rename_all = "snake_case")] -enum WorkspaceSymbolSearchScopeDef { - Workspace, - WorkspaceAndDependencies, -} - -#[derive(Deserialize, Debug, Clone)] -#[serde(rename_all = "snake_case")] -enum SignatureDetail { - Full, - Parameters, -} - -#[derive(Deserialize, Debug, Clone)] -#[serde(rename_all = "snake_case")] -enum WorkspaceSymbolSearchKindDef { - OnlyTypes, - AllSymbols, -} - -macro_rules! _config_data { - (struct $name:ident { - $( - $(#[doc=$doc:literal])* - $field:ident $(| $alias:ident)*: $ty:ty = $default:expr, - )* - }) => { - #[allow(non_snake_case)] - #[derive(Debug, Clone)] - struct $name { $($field: $ty,)* } - impl $name { - fn from_json(mut json: serde_json::Value, error_sink: &mut Vec<(String, serde_json::Error)>) -> $name { - $name {$( - $field: get_field( - &mut json, - error_sink, - stringify!($field), - None$(.or(Some(stringify!($alias))))*, - $default, - ), - )*} - } - - fn json_schema() -> serde_json::Value { - schema(&[ - $({ - let field = stringify!($field); - let ty = stringify!($ty); - - (field, ty, &[$($doc),*], $default) - },)* - ]) - } - - #[cfg(test)] - fn manual() -> String { - manual(&[ - $({ - let field = stringify!($field); - let ty = stringify!($ty); - - (field, ty, &[$($doc),*], $default) - },)* - ]) - } - } - - #[test] - fn fields_are_sorted() { - [$(stringify!($field)),*].windows(2).for_each(|w| assert!(w[0] <= w[1], "{} <= {} does not hold", w[0], w[1])); - } - }; -} -use _config_data as config_data; - -fn get_field( - json: &mut serde_json::Value, - error_sink: &mut Vec<(String, serde_json::Error)>, - field: &'static str, - alias: Option<&'static str>, - default: &str, -) -> T { - let default = serde_json::from_str(default).unwrap(); - // XXX: check alias first, to work-around the VS Code where it pre-fills the - // defaults instead of sending an empty object. - alias - .into_iter() - .chain(iter::once(field)) - .find_map(move |field| { - let mut pointer = field.replace('_', "/"); - pointer.insert(0, '/'); - json.pointer_mut(&pointer).and_then(|it| match serde_json::from_value(it.take()) { - Ok(it) => Some(it), - Err(e) => { - tracing::warn!("Failed to deserialize config field at {}: {:?}", pointer, e); - error_sink.push((pointer, e)); - None - } - }) - }) - .unwrap_or(default) -} - -fn schema(fields: &[(&'static str, &'static str, &[&str], &str)]) -> serde_json::Value { - for ((f1, ..), (f2, ..)) in fields.iter().zip(&fields[1..]) { - fn key(f: &str) -> &str { - f.splitn(2, '_').next().unwrap() - } - assert!(key(f1) <= key(f2), "wrong field order: {:?} {:?}", f1, f2); - } - - let map = fields - .iter() - .map(|(field, ty, doc, default)| { - let name = field.replace('_', "."); - let name = format!("rust-analyzer.{}", name); - let props = field_props(field, ty, doc, default); - (name, props) - }) - .collect::>(); - map.into() -} - -fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json::Value { - let doc = doc_comment_to_string(doc); - let doc = doc.trim_end_matches('\n'); - assert!( - doc.ends_with('.') && doc.starts_with(char::is_uppercase), - "bad docs for {}: {:?}", - field, - doc - ); - let default = default.parse::().unwrap(); - - let mut map = serde_json::Map::default(); - macro_rules! set { - ($($key:literal: $value:tt),*$(,)?) => {{$( - map.insert($key.into(), serde_json::json!($value)); - )*}}; - } - set!("markdownDescription": doc); - set!("default": default); - - match ty { - "bool" => set!("type": "boolean"), - "usize" => set!("type": "integer", "minimum": 0), - "String" => set!("type": "string"), - "Vec" => set! { - "type": "array", - "items": { "type": "string" }, - }, - "Vec" => set! { - "type": "array", - "items": { "type": "string" }, - }, - "FxHashSet" => set! { - "type": "array", - "items": { "type": "string" }, - "uniqueItems": true, - }, - "FxHashMap, Box<[Box]>>" => set! { - "type": "object", - }, - "FxHashMap" => set! { - "type": "object", - }, - "FxHashMap" => set! { - "type": "object", - }, - "Option" => set! { - "type": ["null", "integer"], - "minimum": 0, - }, - "Option" => set! { - "type": ["null", "string"], - }, - "Option" => set! { - "type": ["null", "string"], - }, - "Option" => set! { - "type": ["null", "boolean"], - }, - "Option>" => set! { - "type": ["null", "array"], - "items": { "type": "string" }, - }, - "MergeBehaviorDef" => set! { - "type": "string", - "enum": ["none", "crate", "module"], - "enumDescriptions": [ - "Do not merge imports at all.", - "Merge imports from the same crate into a single `use` statement.", - "Merge imports from the same module into a single `use` statement." - ], - }, - "ExprFillDefaultDef" => set! { - "type": "string", - "enum": ["todo", "default"], - "enumDescriptions": [ - "Fill missing expressions with the `todo` macro", - "Fill missing expressions with reasonable defaults, `new` or `default` constructors." - ], - }, - "ImportGranularityDef" => set! { - "type": "string", - "enum": ["preserve", "crate", "module", "item"], - "enumDescriptions": [ - "Do not change the granularity of any imports and preserve the original structure written by the developer.", - "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.", - "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.", - "Flatten imports so that each has its own use statement." - ], - }, - "ImportPrefixDef" => set! { - "type": "string", - "enum": [ - "plain", - "self", - "crate" - ], - "enumDescriptions": [ - "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", - "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item. Prefixes `self` in front of the path if it starts with a module.", - "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from." - ], - }, - "Vec" => set! { - "type": "array", - "items": { "type": ["string", "object"] }, - }, - "WorkspaceSymbolSearchScopeDef" => set! { - "type": "string", - "enum": ["workspace", "workspace_and_dependencies"], - "enumDescriptions": [ - "Search in current workspace only.", - "Search in current workspace and dependencies." - ], - }, - "WorkspaceSymbolSearchKindDef" => set! { - "type": "string", - "enum": ["only_types", "all_symbols"], - "enumDescriptions": [ - "Search for types only.", - "Search for all symbols kinds." - ], - }, - "ParallelCachePrimingNumThreads" => set! { - "type": "number", - "minimum": 0, - "maximum": 255 - }, - "LifetimeElisionDef" => set! { - "type": "string", - "enum": [ - "always", - "never", - "skip_trivial" - ], - "enumDescriptions": [ - "Always show lifetime elision hints.", - "Never show lifetime elision hints.", - "Only show lifetime elision hints if a return type is involved." - ] - }, - "ClosureReturnTypeHintsDef" => set! { - "type": "string", - "enum": [ - "always", - "never", - "with_block" - ], - "enumDescriptions": [ - "Always show type hints for return types of closures.", - "Never show type hints for return types of closures.", - "Only show type hints for return types of closures with blocks." - ] - }, - "ReborrowHintsDef" => set! { - "type": "string", - "enum": [ - "always", - "never", - "mutable" - ], - "enumDescriptions": [ - "Always show reborrow hints.", - "Never show reborrow hints.", - "Only show mutable reborrow hints." - ] - }, - "CargoFeatures" => set! { - "anyOf": [ - { - "type": "string", - "enum": [ - "all" - ], - "enumDescriptions": [ - "Pass `--all-features` to cargo", - ] - }, - { - "type": "array", - "items": { "type": "string" } - } - ], - }, - "Option" => set! { - "anyOf": [ - { - "type": "string", - "enum": [ - "all" - ], - "enumDescriptions": [ - "Pass `--all-features` to cargo", - ] - }, - { - "type": "array", - "items": { "type": "string" } - }, - { "type": "null" } - ], - }, - "CallableCompletionDef" => set! { - "type": "string", - "enum": [ - "fill_arguments", - "add_parentheses", - "none", - ], - "enumDescriptions": [ - "Add call parentheses and pre-fill arguments.", - "Add call parentheses.", - "Do no snippet completions for callables." - ] - }, - "SignatureDetail" => set! { - "type": "string", - "enum": ["full", "parameters"], - "enumDescriptions": [ - "Show the entire signature.", - "Show only the parameters." - ], - }, - "FilesWatcherDef" => set! { - "type": "string", - "enum": ["client", "server"], - "enumDescriptions": [ - "Use the client (editor) to watch files for changes", - "Use server-side file watching", - ], - }, - _ => panic!("missing entry for {}: {}", ty, default), - } - - map.into() -} - -#[cfg(test)] -fn manual(fields: &[(&'static str, &'static str, &[&str], &str)]) -> String { - fields - .iter() - .map(|(field, _ty, doc, default)| { - let name = format!("rust-analyzer.{}", field.replace('_', ".")); - let doc = doc_comment_to_string(*doc); - if default.contains('\n') { - format!( - r#"[[{}]]{}:: -+ --- -Default: ----- -{} ----- -{} --- -"#, - name, name, default, doc - ) - } else { - format!("[[{}]]{} (default: `{}`)::\n+\n--\n{}--\n", name, name, default, doc) - } - }) - .collect::() -} - -fn doc_comment_to_string(doc: &[&str]) -> String { - doc.iter().map(|it| it.strip_prefix(' ').unwrap_or(it)).map(|it| format!("{}\n", it)).collect() -} - -#[cfg(test)] -mod tests { - use std::fs; - - use test_utils::{ensure_file_contents, project_root}; - - use super::*; - - #[test] - fn generate_package_json_config() { - let s = Config::json_schema(); - let schema = format!("{:#}", s); - let mut schema = schema - .trim_start_matches('{') - .trim_end_matches('}') - .replace(" ", " ") - .replace('\n', "\n ") - .trim_start_matches('\n') - .trim_end() - .to_string(); - schema.push_str(",\n"); - - // Transform the asciidoc form link to markdown style. - // - // https://link[text] => [text](https://link) - let url_matches = schema.match_indices("https://"); - let mut url_offsets = url_matches.map(|(idx, _)| idx).collect::>(); - url_offsets.reverse(); - for idx in url_offsets { - let link = &schema[idx..]; - // matching on whitespace to ignore normal links - if let Some(link_end) = link.find(|c| c == ' ' || c == '[') { - if link.chars().nth(link_end) == Some('[') { - if let Some(link_text_end) = link.find(']') { - let link_text = link[link_end..(link_text_end + 1)].to_string(); - - schema.replace_range((idx + link_end)..(idx + link_text_end + 1), ""); - schema.insert(idx, '('); - schema.insert(idx + link_end + 1, ')'); - schema.insert_str(idx, &link_text); - } - } - } - } - - let package_json_path = project_root().join("editors/code/package.json"); - let mut package_json = fs::read_to_string(&package_json_path).unwrap(); - - let start_marker = " \"$generated-start\": {},\n"; - let end_marker = " \"$generated-end\": {}\n"; - - let start = package_json.find(start_marker).unwrap() + start_marker.len(); - let end = package_json.find(end_marker).unwrap(); - - let p = remove_ws(&package_json[start..end]); - let s = remove_ws(&schema); - if !p.contains(&s) { - package_json.replace_range(start..end, &schema); - ensure_file_contents(&package_json_path, &package_json) - } - } - - #[test] - fn generate_config_documentation() { - let docs_path = project_root().join("docs/user/generated_config.adoc"); - let expected = ConfigData::manual(); - ensure_file_contents(&docs_path, &expected); - } - - fn remove_ws(text: &str) -> String { - text.replace(char::is_whitespace, "") - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config/patch_old_style.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config/patch_old_style.rs deleted file mode 100644 index 472e2e0eeeabf..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config/patch_old_style.rs +++ /dev/null @@ -1,135 +0,0 @@ -//! See [`patch_json_for_outdated_configs`] -use serde_json::{json, Value}; - -/// This function patches the json config to the new expected keys. -/// That is we try to load old known config keys here and convert them to the new ones. -/// See https://github.com/rust-lang/rust-analyzer/pull/12010 -pub(super) fn patch_json_for_outdated_configs(json: &mut Value) { - let copy = json.clone(); - - macro_rules! patch { - ($( - $($src:ident).+ -> $($dst:ident).+ ; - )+) => { $( - match copy.pointer(concat!($("/", stringify!($src)),+)).cloned() { - Some(Value::Object(_)) | None => (), - Some(it) => { - let mut last = it; - for segment in [$(stringify!($dst)),+].into_iter().rev() { - last = Value::Object(serde_json::Map::from_iter(std::iter::once((segment.to_string(), last)))); - } - - merge(json, last); - }, - } - )+ }; - } - - patch! { - assist.allowMergingIntoGlobImports -> imports.merge.glob; - assist.exprFillDefault -> assist.expressionFillDefault; - assist.importEnforceGranularity -> imports.granularity.enforce; - assist.importGranularity -> imports.granularity.group; - assist.importMergeBehavior -> imports.granularity.group; - assist.importMergeBehaviour -> imports.granularity.group; - assist.importGroup -> imports.group.enable; - assist.importPrefix -> imports.prefix; - primeCaches.enable -> cachePriming.enable; - cache.warmup -> cachePriming.enable; - cargo.loadOutDirsFromCheck -> cargo.buildScripts.enable; - cargo.runBuildScripts -> cargo.buildScripts.enable; - cargo.runBuildScriptsCommand -> cargo.buildScripts.overrideCommand; - cargo.useRustcWrapperForBuildScripts -> cargo.buildScripts.useRustcWrapper; - diagnostics.enableExperimental -> diagnostics.experimental.enable; - experimental.procAttrMacros -> procMacro.attributes.enable; - highlighting.strings -> semanticHighlighting.strings.enable; - highlightRelated.breakPoints -> semanticHighlighting.breakPoints.enable; - highlightRelated.exitPoints -> semanticHighlighting.exitPoints.enable; - highlightRelated.yieldPoints -> semanticHighlighting.yieldPoints.enable; - highlightRelated.references -> semanticHighlighting.references.enable; - hover.documentation -> hover.documentation.enable; - hover.linksInHover -> hover.links.enable; - hoverActions.linksInHover -> hover.links.enable; - hoverActions.debug -> hover.actions.debug.enable; - hoverActions.enable -> hover.actions.enable; - hoverActions.gotoTypeDef -> hover.actions.gotoTypeDef.enable; - hoverActions.implementations -> hover.actions.implementations.enable; - hoverActions.references -> hover.actions.references.enable; - hoverActions.run -> hover.actions.run.enable; - inlayHints.chainingHints -> inlayHints.chainingHints.enable; - inlayHints.closureReturnTypeHints -> inlayHints.closureReturnTypeHints.enable; - inlayHints.hideNamedConstructorHints -> inlayHints.typeHints.hideNamedConstructorHints; - inlayHints.parameterHints -> inlayHints.parameterHints.enable; - inlayHints.reborrowHints -> inlayHints.reborrowHints.enable; - inlayHints.typeHints -> inlayHints.typeHints.enable; - lruCapacity -> lru.capacity; - runnables.cargoExtraArgs -> runnables.extraArgs ; - runnables.overrideCargo -> runnables.command ; - rustcSource -> rustc.source; - rustfmt.enableRangeFormatting -> rustfmt.rangeFormatting.enable; - } - - // completion.snippets -> completion.snippets.custom; - if let Some(Value::Object(obj)) = copy.pointer("/completion/snippets").cloned() { - if obj.len() != 1 || obj.get("custom").is_none() { - merge( - json, - json! {{ - "completion": { - "snippets": { - "custom": obj - }, - }, - }}, - ); - } - } - - // callInfo_full -> signatureInfo_detail, signatureInfo_documentation_enable - if let Some(Value::Bool(b)) = copy.pointer("/callInfo/full") { - let sig_info = match b { - true => json!({ "signatureInfo": { - "documentation": {"enable": true}}, - "detail": "full" - }), - false => json!({ "signatureInfo": { - "documentation": {"enable": false}}, - "detail": "parameters" - }), - }; - merge(json, sig_info); - } - - // cargo_allFeatures, cargo_features -> cargo_features - if let Some(Value::Bool(true)) = copy.pointer("/cargo/allFeatures") { - merge(json, json!({ "cargo": { "features": "all" } })); - } - - // checkOnSave_allFeatures, checkOnSave_features -> checkOnSave_features - if let Some(Value::Bool(true)) = copy.pointer("/checkOnSave/allFeatures") { - merge(json, json!({ "checkOnSave": { "features": "all" } })); - } - - // completion_addCallArgumentSnippets completion_addCallParenthesis -> completion_callable_snippets - let res = match ( - copy.pointer("/completion/addCallArgumentSnippets"), - copy.pointer("/completion/addCallParenthesis"), - ) { - (Some(Value::Bool(true)), Some(Value::Bool(true))) => json!("fill_arguments"), - (Some(Value::Bool(true)), _) => json!("add_parentheses"), - (Some(Value::Bool(false)), Some(Value::Bool(false))) => json!("none"), - (_, _) => return, - }; - merge(json, json!({ "completion": { "callable": {"snippets": res }} })); -} - -fn merge(dst: &mut Value, src: Value) { - match (dst, src) { - (Value::Object(dst), Value::Object(src)) => { - for (k, v) in src { - merge(dst.entry(k).or_insert(v.clone()), v) - } - } - (dst, src) => *dst = src, - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs deleted file mode 100644 index 202a01adf7108..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs +++ /dev/null @@ -1,109 +0,0 @@ -//! Book keeping for keeping diagnostics easily in sync with the client. -pub(crate) mod to_proto; - -use std::{mem, sync::Arc}; - -use ide::FileId; -use rustc_hash::{FxHashMap, FxHashSet}; - -use crate::lsp_ext; - -pub(crate) type CheckFixes = Arc>>; - -#[derive(Debug, Default, Clone)] -pub struct DiagnosticsMapConfig { - pub remap_prefix: FxHashMap, - pub warnings_as_info: Vec, - pub warnings_as_hint: Vec, -} - -#[derive(Debug, Default, Clone)] -pub(crate) struct DiagnosticCollection { - // FIXME: should be FxHashMap> - pub(crate) native: FxHashMap>, - // FIXME: should be Vec - pub(crate) check: FxHashMap>, - pub(crate) check_fixes: CheckFixes, - changes: FxHashSet, -} - -#[derive(Debug, Clone)] -pub(crate) struct Fix { - // Fixes may be triggerable from multiple ranges. - pub(crate) ranges: Vec, - pub(crate) action: lsp_ext::CodeAction, -} - -impl DiagnosticCollection { - pub(crate) fn clear_check(&mut self) { - Arc::make_mut(&mut self.check_fixes).clear(); - self.changes.extend(self.check.drain().map(|(key, _value)| key)) - } - - pub(crate) fn clear_native_for(&mut self, file_id: FileId) { - self.native.remove(&file_id); - self.changes.insert(file_id); - } - - pub(crate) fn add_check_diagnostic( - &mut self, - file_id: FileId, - diagnostic: lsp_types::Diagnostic, - fix: Option, - ) { - let diagnostics = self.check.entry(file_id).or_default(); - for existing_diagnostic in diagnostics.iter() { - if are_diagnostics_equal(existing_diagnostic, &diagnostic) { - return; - } - } - - let check_fixes = Arc::make_mut(&mut self.check_fixes); - check_fixes.entry(file_id).or_default().extend(fix); - diagnostics.push(diagnostic); - self.changes.insert(file_id); - } - - pub(crate) fn set_native_diagnostics( - &mut self, - file_id: FileId, - diagnostics: Vec, - ) { - if let Some(existing_diagnostics) = self.native.get(&file_id) { - if existing_diagnostics.len() == diagnostics.len() - && diagnostics - .iter() - .zip(existing_diagnostics) - .all(|(new, existing)| are_diagnostics_equal(new, existing)) - { - return; - } - } - - self.native.insert(file_id, diagnostics); - self.changes.insert(file_id); - } - - pub(crate) fn diagnostics_for( - &self, - file_id: FileId, - ) -> impl Iterator { - let native = self.native.get(&file_id).into_iter().flatten(); - let check = self.check.get(&file_id).into_iter().flatten(); - native.chain(check) - } - - pub(crate) fn take_changes(&mut self) -> Option> { - if self.changes.is_empty() { - return None; - } - Some(mem::take(&mut self.changes)) - } -} - -fn are_diagnostics_equal(left: &lsp_types::Diagnostic, right: &lsp_types::Diagnostic) -> bool { - left.source == right.source - && left.severity == right.severity - && left.range == right.range - && left.message == right.message -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt deleted file mode 100644 index c3b540e31f77f..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt +++ /dev/null @@ -1,301 +0,0 @@ -[ - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/compiler/mir/tagset.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 41, - character: 23, - }, - end: Position { - line: 41, - character: 28, - }, - }, - severity: Some( - Warning, - ), - code: Some( - String( - "trivially_copy_pass_by_ref", - ), - ), - code_description: Some( - CodeDescription { - href: Url { - scheme: "https", - cannot_be_a_base: false, - username: "", - password: None, - host: Some( - Domain( - "rust-lang.github.io", - ), - ), - port: None, - path: "/rust-clippy/master/index.html", - query: None, - fragment: Some( - "trivially_copy_pass_by_ref", - ), - }, - }, - ), - source: Some( - "clippy", - ), - message: "this argument is passed by reference, but would be more efficient if passed by value\n#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]\nfor further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/compiler/lib.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 0, - character: 8, - }, - end: Position { - line: 0, - character: 19, - }, - }, - }, - message: "lint level defined here", - }, - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/compiler/mir/tagset.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 41, - character: 23, - }, - end: Position { - line: 41, - character: 28, - }, - }, - }, - message: "consider passing by value instead: `self`", - }, - ], - ), - tags: None, - data: None, - }, - fix: None, - }, - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/compiler/lib.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 0, - character: 8, - }, - end: Position { - line: 0, - character: 19, - }, - }, - severity: Some( - Hint, - ), - code: Some( - String( - "trivially_copy_pass_by_ref", - ), - ), - code_description: Some( - CodeDescription { - href: Url { - scheme: "https", - cannot_be_a_base: false, - username: "", - password: None, - host: Some( - Domain( - "rust-lang.github.io", - ), - ), - port: None, - path: "/rust-clippy/master/index.html", - query: None, - fragment: Some( - "trivially_copy_pass_by_ref", - ), - }, - }, - ), - source: Some( - "clippy", - ), - message: "lint level defined here", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/compiler/mir/tagset.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 41, - character: 23, - }, - end: Position { - line: 41, - character: 28, - }, - }, - }, - message: "original diagnostic", - }, - ], - ), - tags: None, - data: None, - }, - fix: None, - }, - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/compiler/mir/tagset.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 41, - character: 23, - }, - end: Position { - line: 41, - character: 28, - }, - }, - severity: Some( - Hint, - ), - code: Some( - String( - "trivially_copy_pass_by_ref", - ), - ), - code_description: Some( - CodeDescription { - href: Url { - scheme: "https", - cannot_be_a_base: false, - username: "", - password: None, - host: Some( - Domain( - "rust-lang.github.io", - ), - ), - port: None, - path: "/rust-clippy/master/index.html", - query: None, - fragment: Some( - "trivially_copy_pass_by_ref", - ), - }, - }, - ), - source: Some( - "clippy", - ), - message: "consider passing by value instead: `self`", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/compiler/mir/tagset.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 41, - character: 23, - }, - end: Position { - line: 41, - character: 28, - }, - }, - }, - message: "original diagnostic", - }, - ], - ), - tags: None, - data: None, - }, - fix: None, - }, -] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt deleted file mode 100644 index 989e5cf66d86a..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt +++ /dev/null @@ -1,64 +0,0 @@ -[ - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/src/main.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 1, - character: 4, - }, - end: Position { - line: 1, - character: 26, - }, - }, - severity: Some( - Error, - ), - code: Some( - String( - "E0277", - ), - ), - code_description: Some( - CodeDescription { - href: Url { - scheme: "https", - cannot_be_a_base: false, - username: "", - password: None, - host: Some( - Domain( - "doc.rust-lang.org", - ), - ), - port: None, - path: "/error-index.html", - query: None, - fragment: Some( - "E0277", - ), - }, - }, - ), - source: Some( - "rustc", - ), - message: "can't compare `{integer}` with `&str`\nthe trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`", - related_information: None, - tags: None, - data: None, - }, - fix: None, - }, -] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt deleted file mode 100644 index fe5cf9b3bea7b..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt +++ /dev/null @@ -1,229 +0,0 @@ -[ - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/crates/hir_def/src/path.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 271, - character: 8, - }, - end: Position { - line: 271, - character: 50, - }, - }, - severity: Some( - Hint, - ), - code: None, - code_description: None, - source: Some( - "rustc", - ), - message: "Please register your known path in the path module", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/crates/hir_def/src/path.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 264, - character: 8, - }, - end: Position { - line: 264, - character: 76, - }, - }, - }, - message: "Exact error occurred here", - }, - ], - ), - tags: None, - data: None, - }, - fix: None, - }, - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/crates/hir_def/src/data.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 79, - character: 15, - }, - end: Position { - line: 79, - character: 41, - }, - }, - severity: Some( - Hint, - ), - code: None, - code_description: None, - source: Some( - "rustc", - ), - message: "Please register your known path in the path module", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/crates/hir_def/src/path.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 264, - character: 8, - }, - end: Position { - line: 264, - character: 76, - }, - }, - }, - message: "Exact error occurred here", - }, - ], - ), - tags: None, - data: None, - }, - fix: None, - }, - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/crates/hir_def/src/path.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 264, - character: 8, - }, - end: Position { - line: 264, - character: 76, - }, - }, - severity: Some( - Error, - ), - code: None, - code_description: None, - source: Some( - "rustc", - ), - message: "Please register your known path in the path module", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/crates/hir_def/src/path.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 271, - character: 8, - }, - end: Position { - line: 271, - character: 50, - }, - }, - }, - message: "Error originated from macro call here", - }, - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/crates/hir_def/src/data.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 79, - character: 15, - }, - end: Position { - line: 79, - character: 41, - }, - }, - }, - message: "Error originated from macro call here", - }, - ], - ), - tags: None, - data: None, - }, - fix: None, - }, -] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/reasonable_line_numbers_from_empty_file.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/reasonable_line_numbers_from_empty_file.txt deleted file mode 100644 index df00b330b6e99..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/reasonable_line_numbers_from_empty_file.txt +++ /dev/null @@ -1,64 +0,0 @@ -[ - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/src/bin/current.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 0, - character: 0, - }, - end: Position { - line: 0, - character: 0, - }, - }, - severity: Some( - Error, - ), - code: Some( - String( - "E0601", - ), - ), - code_description: Some( - CodeDescription { - href: Url { - scheme: "https", - cannot_be_a_base: false, - username: "", - password: None, - host: Some( - Domain( - "doc.rust-lang.org", - ), - ), - port: None, - path: "/error-index.html", - query: None, - fragment: Some( - "E0601", - ), - }, - }, - ), - source: Some( - "rustc", - ), - message: "`main` function not found in crate `current`\nconsider adding a `main` function to `src/bin/current.rs`", - related_information: None, - tags: None, - data: None, - }, - fix: None, - }, -] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt deleted file mode 100644 index dc36aa761c066..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt +++ /dev/null @@ -1,64 +0,0 @@ -[ - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/compiler/ty/list_iter.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 51, - character: 4, - }, - end: Position { - line: 51, - character: 47, - }, - }, - severity: Some( - Error, - ), - code: Some( - String( - "E0053", - ), - ), - code_description: Some( - CodeDescription { - href: Url { - scheme: "https", - cannot_be_a_base: false, - username: "", - password: None, - host: Some( - Domain( - "doc.rust-lang.org", - ), - ), - port: None, - path: "/error-index.html", - query: None, - fragment: Some( - "E0053", - ), - }, - }, - ), - source: Some( - "rustc", - ), - message: "method `next` has an incompatible type for trait\nexpected type `fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref>`\n found type `fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref>`", - related_information: None, - tags: None, - data: None, - }, - fix: None, - }, -] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt deleted file mode 100644 index d557196c2bd24..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt +++ /dev/null @@ -1,64 +0,0 @@ -[ - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/runtime/compiler_support.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 47, - character: 64, - }, - end: Position { - line: 47, - character: 69, - }, - }, - severity: Some( - Error, - ), - code: Some( - String( - "E0308", - ), - ), - code_description: Some( - CodeDescription { - href: Url { - scheme: "https", - cannot_be_a_base: false, - username: "", - password: None, - host: Some( - Domain( - "doc.rust-lang.org", - ), - ), - port: None, - path: "/error-index.html", - query: None, - fragment: Some( - "E0308", - ), - }, - }, - ), - source: Some( - "rustc", - ), - message: "mismatched types\nexpected usize, found u32", - related_information: None, - tags: None, - data: None, - }, - fix: None, - }, -] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_range_map_lsp_position.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_range_map_lsp_position.txt deleted file mode 100644 index a100fa07ffdd5..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_range_map_lsp_position.txt +++ /dev/null @@ -1,184 +0,0 @@ -[ - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/crates/test_diagnostics/src/main.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 3, - character: 17, - }, - end: Position { - line: 3, - character: 27, - }, - }, - severity: Some( - Error, - ), - code: Some( - String( - "E0308", - ), - ), - code_description: Some( - CodeDescription { - href: Url { - scheme: "https", - cannot_be_a_base: false, - username: "", - password: None, - host: Some( - Domain( - "doc.rust-lang.org", - ), - ), - port: None, - path: "/error-index.html", - query: None, - fragment: Some( - "E0308", - ), - }, - }, - ), - source: Some( - "rustc", - ), - message: "mismatched types\nexpected `u32`, found `&str`", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/crates/test_diagnostics/src/main.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 3, - character: 11, - }, - end: Position { - line: 3, - character: 14, - }, - }, - }, - message: "expected due to this", - }, - ], - ), - tags: None, - data: None, - }, - fix: None, - }, - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/crates/test_diagnostics/src/main.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 3, - character: 11, - }, - end: Position { - line: 3, - character: 14, - }, - }, - severity: Some( - Hint, - ), - code: Some( - String( - "E0308", - ), - ), - code_description: Some( - CodeDescription { - href: Url { - scheme: "https", - cannot_be_a_base: false, - username: "", - password: None, - host: Some( - Domain( - "doc.rust-lang.org", - ), - ), - port: None, - path: "/error-index.html", - query: None, - fragment: Some( - "E0308", - ), - }, - }, - ), - source: Some( - "rustc", - ), - message: "expected due to this", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/crates/test_diagnostics/src/main.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 3, - character: 17, - }, - end: Position { - line: 3, - character: 27, - }, - }, - }, - message: "original diagnostic", - }, - ], - ), - tags: None, - data: None, - }, - fix: None, - }, -] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt deleted file mode 100644 index 1c5c33622349b..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt +++ /dev/null @@ -1,212 +0,0 @@ -[ - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/driver/subcommand/repl.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - severity: Some( - Warning, - ), - code: Some( - String( - "unused_variables", - ), - ), - code_description: None, - source: Some( - "rustc", - ), - message: "unused variable: `foo`\n#[warn(unused_variables)] on by default", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/driver/subcommand/repl.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - }, - message: "consider prefixing with an underscore: `_foo`", - }, - ], - ), - tags: Some( - [ - Unnecessary, - ], - ), - data: None, - }, - fix: None, - }, - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/driver/subcommand/repl.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - severity: Some( - Hint, - ), - code: Some( - String( - "unused_variables", - ), - ), - code_description: None, - source: Some( - "rustc", - ), - message: "consider prefixing with an underscore: `_foo`", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/driver/subcommand/repl.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - }, - message: "original diagnostic", - }, - ], - ), - tags: None, - data: None, - }, - fix: Some( - Fix { - ranges: [ - Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - ], - action: CodeAction { - title: "consider prefixing with an underscore: `_foo`", - group: None, - kind: Some( - CodeActionKind( - "quickfix", - ), - ), - command: None, - edit: Some( - SnippetWorkspaceEdit { - changes: Some( - { - Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/driver/subcommand/repl.rs", - query: None, - fragment: None, - }: [ - TextEdit { - range: Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - new_text: "_foo", - }, - ], - }, - ), - document_changes: None, - change_annotations: None, - }, - ), - is_preferred: Some( - true, - ), - data: None, - }, - }, - ), - }, -] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt deleted file mode 100644 index 3ab3412d971b9..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt +++ /dev/null @@ -1,212 +0,0 @@ -[ - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/driver/subcommand/repl.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - severity: Some( - Hint, - ), - code: Some( - String( - "unused_variables", - ), - ), - code_description: None, - source: Some( - "rustc", - ), - message: "unused variable: `foo`\n#[warn(unused_variables)] on by default", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/driver/subcommand/repl.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - }, - message: "consider prefixing with an underscore: `_foo`", - }, - ], - ), - tags: Some( - [ - Unnecessary, - ], - ), - data: None, - }, - fix: None, - }, - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/driver/subcommand/repl.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - severity: Some( - Hint, - ), - code: Some( - String( - "unused_variables", - ), - ), - code_description: None, - source: Some( - "rustc", - ), - message: "consider prefixing with an underscore: `_foo`", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/driver/subcommand/repl.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - }, - message: "original diagnostic", - }, - ], - ), - tags: None, - data: None, - }, - fix: Some( - Fix { - ranges: [ - Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - ], - action: CodeAction { - title: "consider prefixing with an underscore: `_foo`", - group: None, - kind: Some( - CodeActionKind( - "quickfix", - ), - ), - command: None, - edit: Some( - SnippetWorkspaceEdit { - changes: Some( - { - Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/driver/subcommand/repl.rs", - query: None, - fragment: None, - }: [ - TextEdit { - range: Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - new_text: "_foo", - }, - ], - }, - ), - document_changes: None, - change_annotations: None, - }, - ), - is_preferred: Some( - true, - ), - data: None, - }, - }, - ), - }, -] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt deleted file mode 100644 index 0702420aa5f96..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt +++ /dev/null @@ -1,212 +0,0 @@ -[ - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/driver/subcommand/repl.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - severity: Some( - Information, - ), - code: Some( - String( - "unused_variables", - ), - ), - code_description: None, - source: Some( - "rustc", - ), - message: "unused variable: `foo`\n#[warn(unused_variables)] on by default", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/driver/subcommand/repl.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - }, - message: "consider prefixing with an underscore: `_foo`", - }, - ], - ), - tags: Some( - [ - Unnecessary, - ], - ), - data: None, - }, - fix: None, - }, - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/driver/subcommand/repl.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - severity: Some( - Hint, - ), - code: Some( - String( - "unused_variables", - ), - ), - code_description: None, - source: Some( - "rustc", - ), - message: "consider prefixing with an underscore: `_foo`", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/driver/subcommand/repl.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - }, - message: "original diagnostic", - }, - ], - ), - tags: None, - data: None, - }, - fix: Some( - Fix { - ranges: [ - Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - ], - action: CodeAction { - title: "consider prefixing with an underscore: `_foo`", - group: None, - kind: Some( - CodeActionKind( - "quickfix", - ), - ), - command: None, - edit: Some( - SnippetWorkspaceEdit { - changes: Some( - { - Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/driver/subcommand/repl.rs", - query: None, - fragment: None, - }: [ - TextEdit { - range: Range { - start: Position { - line: 290, - character: 8, - }, - end: Position { - line: 290, - character: 11, - }, - }, - new_text: "_foo", - }, - ], - }, - ), - document_changes: None, - change_annotations: None, - }, - ), - is_preferred: Some( - true, - ), - data: None, - }, - }, - ), - }, -] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt deleted file mode 100644 index 8ec92888ce115..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt +++ /dev/null @@ -1,184 +0,0 @@ -[ - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/compiler/ty/select.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 103, - character: 17, - }, - end: Position { - line: 103, - character: 29, - }, - }, - severity: Some( - Error, - ), - code: Some( - String( - "E0061", - ), - ), - code_description: Some( - CodeDescription { - href: Url { - scheme: "https", - cannot_be_a_base: false, - username: "", - password: None, - host: Some( - Domain( - "doc.rust-lang.org", - ), - ), - port: None, - path: "/error-index.html", - query: None, - fragment: Some( - "E0061", - ), - }, - }, - ), - source: Some( - "rustc", - ), - message: "this function takes 2 parameters but 3 parameters were supplied\nexpected 2 parameters", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/compiler/ty/select.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 218, - character: 4, - }, - end: Position { - line: 230, - character: 5, - }, - }, - }, - message: "defined here", - }, - ], - ), - tags: None, - data: None, - }, - fix: None, - }, - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/compiler/ty/select.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 218, - character: 4, - }, - end: Position { - line: 230, - character: 5, - }, - }, - severity: Some( - Hint, - ), - code: Some( - String( - "E0061", - ), - ), - code_description: Some( - CodeDescription { - href: Url { - scheme: "https", - cannot_be_a_base: false, - username: "", - password: None, - host: Some( - Domain( - "doc.rust-lang.org", - ), - ), - port: None, - path: "/error-index.html", - query: None, - fragment: Some( - "E0061", - ), - }, - }, - ), - source: Some( - "rustc", - ), - message: "defined here", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/compiler/ty/select.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 103, - character: 17, - }, - end: Position { - line: 103, - character: 29, - }, - }, - }, - message: "original diagnostic", - }, - ], - ), - tags: None, - data: None, - }, - fix: None, - }, -] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt deleted file mode 100644 index 4365e450df1f5..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt +++ /dev/null @@ -1,388 +0,0 @@ -[ - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/src/main.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 3, - character: 4, - }, - end: Position { - line: 3, - character: 5, - }, - }, - severity: Some( - Warning, - ), - code: Some( - String( - "let_and_return", - ), - ), - code_description: Some( - CodeDescription { - href: Url { - scheme: "https", - cannot_be_a_base: false, - username: "", - password: None, - host: Some( - Domain( - "rust-lang.github.io", - ), - ), - port: None, - path: "/rust-clippy/master/index.html", - query: None, - fragment: Some( - "let_and_return", - ), - }, - }, - ), - source: Some( - "clippy", - ), - message: "returning the result of a let binding from a block\n`#[warn(clippy::let_and_return)]` on by default\nfor further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/src/main.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 2, - character: 4, - }, - end: Position { - line: 2, - character: 30, - }, - }, - }, - message: "unnecessary let binding", - }, - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/src/main.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 2, - character: 4, - }, - end: Position { - line: 2, - character: 30, - }, - }, - }, - message: "return the expression directly: `(0..10).collect()`", - }, - ], - ), - tags: None, - data: None, - }, - fix: None, - }, - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/src/main.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 2, - character: 4, - }, - end: Position { - line: 2, - character: 30, - }, - }, - severity: Some( - Hint, - ), - code: Some( - String( - "let_and_return", - ), - ), - code_description: Some( - CodeDescription { - href: Url { - scheme: "https", - cannot_be_a_base: false, - username: "", - password: None, - host: Some( - Domain( - "rust-lang.github.io", - ), - ), - port: None, - path: "/rust-clippy/master/index.html", - query: None, - fragment: Some( - "let_and_return", - ), - }, - }, - ), - source: Some( - "clippy", - ), - message: "unnecessary let binding", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/src/main.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 3, - character: 4, - }, - end: Position { - line: 3, - character: 5, - }, - }, - }, - message: "original diagnostic", - }, - ], - ), - tags: None, - data: None, - }, - fix: None, - }, - MappedRustDiagnostic { - url: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/src/main.rs", - query: None, - fragment: None, - }, - diagnostic: Diagnostic { - range: Range { - start: Position { - line: 2, - character: 4, - }, - end: Position { - line: 2, - character: 30, - }, - }, - severity: Some( - Hint, - ), - code: Some( - String( - "let_and_return", - ), - ), - code_description: Some( - CodeDescription { - href: Url { - scheme: "https", - cannot_be_a_base: false, - username: "", - password: None, - host: Some( - Domain( - "rust-lang.github.io", - ), - ), - port: None, - path: "/rust-clippy/master/index.html", - query: None, - fragment: Some( - "let_and_return", - ), - }, - }, - ), - source: Some( - "clippy", - ), - message: "return the expression directly: `(0..10).collect()`", - related_information: Some( - [ - DiagnosticRelatedInformation { - location: Location { - uri: Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/src/main.rs", - query: None, - fragment: None, - }, - range: Range { - start: Position { - line: 3, - character: 4, - }, - end: Position { - line: 3, - character: 5, - }, - }, - }, - message: "original diagnostic", - }, - ], - ), - tags: None, - data: None, - }, - fix: Some( - Fix { - ranges: [ - Range { - start: Position { - line: 2, - character: 4, - }, - end: Position { - line: 2, - character: 30, - }, - }, - Range { - start: Position { - line: 3, - character: 4, - }, - end: Position { - line: 3, - character: 5, - }, - }, - ], - action: CodeAction { - title: "return the expression directly: `(0..10).collect()`", - group: None, - kind: Some( - CodeActionKind( - "quickfix", - ), - ), - command: None, - edit: Some( - SnippetWorkspaceEdit { - changes: Some( - { - Url { - scheme: "file", - cannot_be_a_base: false, - username: "", - password: None, - host: None, - port: None, - path: "/test/src/main.rs", - query: None, - fragment: None, - }: [ - TextEdit { - range: Range { - start: Position { - line: 2, - character: 4, - }, - end: Position { - line: 2, - character: 30, - }, - }, - new_text: "", - }, - TextEdit { - range: Range { - start: Position { - line: 3, - character: 4, - }, - end: Position { - line: 3, - character: 5, - }, - }, - new_text: "(0..10).collect()", - }, - ], - }, - ), - document_changes: None, - change_annotations: None, - }, - ), - is_preferred: Some( - true, - ), - data: None, - }, - }, - ), - }, -] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs deleted file mode 100644 index cff4bd7f66acd..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ /dev/null @@ -1,1843 +0,0 @@ -//! This module provides the functionality needed to convert diagnostics from -//! `cargo check` json format to the LSP diagnostic format. -use std::collections::HashMap; - -use flycheck::{Applicability, DiagnosticLevel, DiagnosticSpan}; -use itertools::Itertools; -use stdx::format_to; -use vfs::{AbsPath, AbsPathBuf}; - -use crate::{ - global_state::GlobalStateSnapshot, line_index::OffsetEncoding, lsp_ext, - to_proto::url_from_abs_path, -}; - -use super::{DiagnosticsMapConfig, Fix}; - -/// Determines the LSP severity from a diagnostic -fn diagnostic_severity( - config: &DiagnosticsMapConfig, - level: flycheck::DiagnosticLevel, - code: Option, -) -> Option { - let res = match level { - DiagnosticLevel::Ice => lsp_types::DiagnosticSeverity::ERROR, - DiagnosticLevel::Error => lsp_types::DiagnosticSeverity::ERROR, - DiagnosticLevel::Warning => match &code { - // HACK: special case for `warnings` rustc lint. - Some(code) - if config.warnings_as_hint.iter().any(|lint| { - lint == "warnings" || ide_db::helpers::lint_eq_or_in_group(&code.code, lint) - }) => - { - lsp_types::DiagnosticSeverity::HINT - } - // HACK: special case for `warnings` rustc lint. - Some(code) - if config.warnings_as_info.iter().any(|lint| { - lint == "warnings" || ide_db::helpers::lint_eq_or_in_group(&code.code, lint) - }) => - { - lsp_types::DiagnosticSeverity::INFORMATION - } - _ => lsp_types::DiagnosticSeverity::WARNING, - }, - DiagnosticLevel::Note => lsp_types::DiagnosticSeverity::INFORMATION, - DiagnosticLevel::Help => lsp_types::DiagnosticSeverity::HINT, - _ => return None, - }; - Some(res) -} - -/// Checks whether a file name is from macro invocation and does not refer to an actual file. -fn is_dummy_macro_file(file_name: &str) -> bool { - // FIXME: current rustc does not seem to emit `` files anymore? - file_name.starts_with('<') && file_name.ends_with('>') -} - -/// Converts a Rust span to a LSP location -fn location( - config: &DiagnosticsMapConfig, - workspace_root: &AbsPath, - span: &DiagnosticSpan, - snap: &GlobalStateSnapshot, -) -> lsp_types::Location { - let file_name = resolve_path(config, workspace_root, &span.file_name); - let uri = url_from_abs_path(&file_name); - - let range = { - let offset_encoding = snap.config.offset_encoding(); - lsp_types::Range::new( - position(&offset_encoding, span, span.line_start, span.column_start), - position(&offset_encoding, span, span.line_end, span.column_end), - ) - }; - lsp_types::Location::new(uri, range) -} - -fn position( - offset_encoding: &OffsetEncoding, - span: &DiagnosticSpan, - line_offset: usize, - column_offset: usize, -) -> lsp_types::Position { - let line_index = line_offset - span.line_start; - - let mut true_column_offset = column_offset; - if let Some(line) = span.text.get(line_index) { - if line.text.chars().count() == line.text.len() { - // all one byte utf-8 char - return lsp_types::Position { - line: (line_offset as u32).saturating_sub(1), - character: (column_offset as u32).saturating_sub(1), - }; - } - let mut char_offset = 0; - let len_func = match offset_encoding { - OffsetEncoding::Utf8 => char::len_utf8, - OffsetEncoding::Utf16 => char::len_utf16, - }; - for c in line.text.chars() { - char_offset += 1; - if char_offset > column_offset { - break; - } - true_column_offset += len_func(c) - 1; - } - } - - lsp_types::Position { - line: (line_offset as u32).saturating_sub(1), - character: (true_column_offset as u32).saturating_sub(1), - } -} - -/// Extracts a suitable "primary" location from a rustc diagnostic. -/// -/// This takes locations pointing into the standard library, or generally outside the current -/// workspace into account and tries to avoid those, in case macros are involved. -fn primary_location( - config: &DiagnosticsMapConfig, - workspace_root: &AbsPath, - span: &DiagnosticSpan, - snap: &GlobalStateSnapshot, -) -> lsp_types::Location { - let span_stack = std::iter::successors(Some(span), |span| Some(&span.expansion.as_ref()?.span)); - for span in span_stack.clone() { - let abs_path = resolve_path(config, workspace_root, &span.file_name); - if !is_dummy_macro_file(&span.file_name) && abs_path.starts_with(workspace_root) { - return location(config, workspace_root, span, snap); - } - } - - // Fall back to the outermost macro invocation if no suitable span comes up. - let last_span = span_stack.last().unwrap(); - location(config, workspace_root, last_span, snap) -} - -/// Converts a secondary Rust span to a LSP related information -/// -/// If the span is unlabelled this will return `None`. -fn diagnostic_related_information( - config: &DiagnosticsMapConfig, - workspace_root: &AbsPath, - span: &DiagnosticSpan, - snap: &GlobalStateSnapshot, -) -> Option { - let message = span.label.clone()?; - let location = location(config, workspace_root, span, snap); - Some(lsp_types::DiagnosticRelatedInformation { location, message }) -} - -/// Resolves paths applying any matching path prefix remappings, and then -/// joining the path to the workspace root. -fn resolve_path( - config: &DiagnosticsMapConfig, - workspace_root: &AbsPath, - file_name: &str, -) -> AbsPathBuf { - match config - .remap_prefix - .iter() - .find_map(|(from, to)| file_name.strip_prefix(from).map(|file_name| (to, file_name))) - { - Some((to, file_name)) => workspace_root.join(format!("{}{}", to, file_name)), - None => workspace_root.join(file_name), - } -} - -struct SubDiagnostic { - related: lsp_types::DiagnosticRelatedInformation, - suggested_fix: Option, -} - -enum MappedRustChildDiagnostic { - SubDiagnostic(SubDiagnostic), - MessageLine(String), -} - -fn map_rust_child_diagnostic( - config: &DiagnosticsMapConfig, - workspace_root: &AbsPath, - rd: &flycheck::Diagnostic, - snap: &GlobalStateSnapshot, -) -> MappedRustChildDiagnostic { - let spans: Vec<&DiagnosticSpan> = rd.spans.iter().filter(|s| s.is_primary).collect(); - if spans.is_empty() { - // `rustc` uses these spanless children as a way to print multi-line - // messages - return MappedRustChildDiagnostic::MessageLine(rd.message.clone()); - } - - let mut edit_map: HashMap> = HashMap::new(); - let mut suggested_replacements = Vec::new(); - for &span in &spans { - if let Some(suggested_replacement) = &span.suggested_replacement { - if !suggested_replacement.is_empty() { - suggested_replacements.push(suggested_replacement); - } - let location = location(config, workspace_root, span, snap); - let edit = lsp_types::TextEdit::new(location.range, suggested_replacement.clone()); - - // Only actually emit a quickfix if the suggestion is "valid enough". - // We accept both "MaybeIncorrect" and "MachineApplicable". "MaybeIncorrect" means that - // the suggestion is *complete* (contains no placeholders where code needs to be - // inserted), but might not be what the user wants, or might need minor adjustments. - if matches!( - span.suggestion_applicability, - None | Some(Applicability::MaybeIncorrect | Applicability::MachineApplicable) - ) { - edit_map.entry(location.uri).or_default().push(edit); - } - } - } - - // rustc renders suggestion diagnostics by appending the suggested replacement, so do the same - // here, otherwise the diagnostic text is missing useful information. - let mut message = rd.message.clone(); - if !suggested_replacements.is_empty() { - message.push_str(": "); - let suggestions = - suggested_replacements.iter().map(|suggestion| format!("`{}`", suggestion)).join(", "); - message.push_str(&suggestions); - } - - if edit_map.is_empty() { - MappedRustChildDiagnostic::SubDiagnostic(SubDiagnostic { - related: lsp_types::DiagnosticRelatedInformation { - location: location(config, workspace_root, spans[0], snap), - message, - }, - suggested_fix: None, - }) - } else { - MappedRustChildDiagnostic::SubDiagnostic(SubDiagnostic { - related: lsp_types::DiagnosticRelatedInformation { - location: location(config, workspace_root, spans[0], snap), - message: message.clone(), - }, - suggested_fix: Some(Fix { - ranges: spans - .iter() - .map(|&span| location(config, workspace_root, span, snap).range) - .collect(), - action: lsp_ext::CodeAction { - title: message, - group: None, - kind: Some(lsp_types::CodeActionKind::QUICKFIX), - edit: Some(lsp_ext::SnippetWorkspaceEdit { - // FIXME: there's no good reason to use edit_map here.... - changes: Some(edit_map), - document_changes: None, - change_annotations: None, - }), - is_preferred: Some(true), - data: None, - command: None, - }, - }), - }) - } -} - -#[derive(Debug)] -pub(crate) struct MappedRustDiagnostic { - pub(crate) url: lsp_types::Url, - pub(crate) diagnostic: lsp_types::Diagnostic, - pub(crate) fix: Option, -} - -/// Converts a Rust root diagnostic to LSP form -/// -/// This flattens the Rust diagnostic by: -/// -/// 1. Creating a LSP diagnostic with the root message and primary span. -/// 2. Adding any labelled secondary spans to `relatedInformation` -/// 3. Categorising child diagnostics as either `SuggestedFix`es, -/// `relatedInformation` or additional message lines. -/// -/// If the diagnostic has no primary span this will return `None` -pub(crate) fn map_rust_diagnostic_to_lsp( - config: &DiagnosticsMapConfig, - rd: &flycheck::Diagnostic, - workspace_root: &AbsPath, - snap: &GlobalStateSnapshot, -) -> Vec { - let primary_spans: Vec<&DiagnosticSpan> = rd.spans.iter().filter(|s| s.is_primary).collect(); - if primary_spans.is_empty() { - return Vec::new(); - } - - let severity = diagnostic_severity(config, rd.level, rd.code.clone()); - - let mut source = String::from("rustc"); - let mut code = rd.code.as_ref().map(|c| c.code.clone()); - if let Some(code_val) = &code { - // See if this is an RFC #2103 scoped lint (e.g. from Clippy) - let scoped_code: Vec<&str> = code_val.split("::").collect(); - if scoped_code.len() == 2 { - source = String::from(scoped_code[0]); - code = Some(String::from(scoped_code[1])); - } - } - - let mut needs_primary_span_label = true; - let mut subdiagnostics = Vec::new(); - let mut tags = Vec::new(); - - for secondary_span in rd.spans.iter().filter(|s| !s.is_primary) { - let related = diagnostic_related_information(config, workspace_root, secondary_span, snap); - if let Some(related) = related { - subdiagnostics.push(SubDiagnostic { related, suggested_fix: None }); - } - } - - let mut message = rd.message.clone(); - for child in &rd.children { - let child = map_rust_child_diagnostic(config, workspace_root, child, snap); - match child { - MappedRustChildDiagnostic::SubDiagnostic(sub) => { - subdiagnostics.push(sub); - } - MappedRustChildDiagnostic::MessageLine(message_line) => { - format_to!(message, "\n{}", message_line); - - // These secondary messages usually duplicate the content of the - // primary span label. - needs_primary_span_label = false; - } - } - } - - if let Some(code) = &rd.code { - let code = code.code.as_str(); - if matches!( - code, - "dead_code" - | "unknown_lints" - | "unreachable_code" - | "unused_attributes" - | "unused_imports" - | "unused_macros" - | "unused_variables" - ) { - tags.push(lsp_types::DiagnosticTag::UNNECESSARY); - } - - if matches!(code, "deprecated") { - tags.push(lsp_types::DiagnosticTag::DEPRECATED); - } - } - - let code_description = match source.as_str() { - "rustc" => rustc_code_description(code.as_deref()), - "clippy" => clippy_code_description(code.as_deref()), - _ => None, - }; - - primary_spans - .iter() - .flat_map(|primary_span| { - let primary_location = primary_location(config, workspace_root, primary_span, snap); - - let mut message = message.clone(); - if needs_primary_span_label { - if let Some(primary_span_label) = &primary_span.label { - format_to!(message, "\n{}", primary_span_label); - } - } - - // Each primary diagnostic span may result in multiple LSP diagnostics. - let mut diagnostics = Vec::new(); - - let mut related_info_macro_calls = vec![]; - - // If error occurs from macro expansion, add related info pointing to - // where the error originated - // Also, we would generate an additional diagnostic, so that exact place of macro - // will be highlighted in the error origin place. - let span_stack = std::iter::successors(Some(*primary_span), |span| { - Some(&span.expansion.as_ref()?.span) - }); - for (i, span) in span_stack.enumerate() { - if is_dummy_macro_file(&span.file_name) { - continue; - } - - // First span is the original diagnostic, others are macro call locations that - // generated that code. - let is_in_macro_call = i != 0; - - let secondary_location = location(config, workspace_root, span, snap); - if secondary_location == primary_location { - continue; - } - related_info_macro_calls.push(lsp_types::DiagnosticRelatedInformation { - location: secondary_location.clone(), - message: if is_in_macro_call { - "Error originated from macro call here".to_string() - } else { - "Actual error occurred here".to_string() - }, - }); - // For the additional in-macro diagnostic we add the inverse message pointing to the error location in code. - let information_for_additional_diagnostic = - vec![lsp_types::DiagnosticRelatedInformation { - location: primary_location.clone(), - message: "Exact error occurred here".to_string(), - }]; - - let diagnostic = lsp_types::Diagnostic { - range: secondary_location.range, - // downgrade to hint if we're pointing at the macro - severity: Some(lsp_types::DiagnosticSeverity::HINT), - code: code.clone().map(lsp_types::NumberOrString::String), - code_description: code_description.clone(), - source: Some(source.clone()), - message: message.clone(), - related_information: Some(information_for_additional_diagnostic), - tags: if tags.is_empty() { None } else { Some(tags.clone()) }, - data: None, - }; - diagnostics.push(MappedRustDiagnostic { - url: secondary_location.uri, - diagnostic, - fix: None, - }); - } - - // Emit the primary diagnostic. - diagnostics.push(MappedRustDiagnostic { - url: primary_location.uri.clone(), - diagnostic: lsp_types::Diagnostic { - range: primary_location.range, - severity, - code: code.clone().map(lsp_types::NumberOrString::String), - code_description: code_description.clone(), - source: Some(source.clone()), - message, - related_information: { - let info = related_info_macro_calls - .iter() - .cloned() - .chain(subdiagnostics.iter().map(|sub| sub.related.clone())) - .collect::>(); - if info.is_empty() { - None - } else { - Some(info) - } - }, - tags: if tags.is_empty() { None } else { Some(tags.clone()) }, - data: None, - }, - fix: None, - }); - - // Emit hint-level diagnostics for all `related_information` entries such as "help"s. - // This is useful because they will show up in the user's editor, unlike - // `related_information`, which just produces hard-to-read links, at least in VS Code. - let back_ref = lsp_types::DiagnosticRelatedInformation { - location: primary_location, - message: "original diagnostic".to_string(), - }; - for sub in &subdiagnostics { - diagnostics.push(MappedRustDiagnostic { - url: sub.related.location.uri.clone(), - fix: sub.suggested_fix.clone(), - diagnostic: lsp_types::Diagnostic { - range: sub.related.location.range, - severity: Some(lsp_types::DiagnosticSeverity::HINT), - code: code.clone().map(lsp_types::NumberOrString::String), - code_description: code_description.clone(), - source: Some(source.clone()), - message: sub.related.message.clone(), - related_information: Some(vec![back_ref.clone()]), - tags: None, // don't apply modifiers again - data: None, - }, - }); - } - - diagnostics - }) - .collect() -} - -fn rustc_code_description(code: Option<&str>) -> Option { - code.filter(|code| { - let mut chars = code.chars(); - chars.next().map_or(false, |c| c == 'E') - && chars.by_ref().take(4).all(|c| c.is_ascii_digit()) - && chars.next().is_none() - }) - .and_then(|code| { - lsp_types::Url::parse(&format!("https://doc.rust-lang.org/error-index.html#{}", code)) - .ok() - .map(|href| lsp_types::CodeDescription { href }) - }) -} - -fn clippy_code_description(code: Option<&str>) -> Option { - code.and_then(|code| { - lsp_types::Url::parse(&format!( - "https://rust-lang.github.io/rust-clippy/master/index.html#{}", - code - )) - .ok() - .map(|href| lsp_types::CodeDescription { href }) - }) -} - -#[cfg(test)] -#[cfg(not(windows))] -mod tests { - use std::{convert::TryInto, path::Path}; - - use crate::{config::Config, global_state::GlobalState}; - - use super::*; - - use expect_test::{expect_file, ExpectFile}; - use lsp_types::ClientCapabilities; - - fn check(diagnostics_json: &str, expect: ExpectFile) { - check_with_config(DiagnosticsMapConfig::default(), diagnostics_json, expect) - } - - fn check_with_config(config: DiagnosticsMapConfig, diagnostics_json: &str, expect: ExpectFile) { - let diagnostic: flycheck::Diagnostic = serde_json::from_str(diagnostics_json).unwrap(); - let workspace_root: &AbsPath = Path::new("/test/").try_into().unwrap(); - let (sender, _) = crossbeam_channel::unbounded(); - let state = GlobalState::new( - sender, - Config::new(workspace_root.to_path_buf(), ClientCapabilities::default()), - ); - let snap = state.snapshot(); - let actual = map_rust_diagnostic_to_lsp(&config, &diagnostic, workspace_root, &snap); - expect.assert_debug_eq(&actual) - } - - #[test] - fn rustc_incompatible_type_for_trait() { - check( - r##"{ - "message": "method `next` has an incompatible type for trait", - "code": { - "code": "E0053", - "explanation": "\nThe parameters of any trait method must match between a trait implementation\nand the trait definition.\n\nHere are a couple examples of this error:\n\n```compile_fail,E0053\ntrait Foo {\n fn foo(x: u16);\n fn bar(&self);\n}\n\nstruct Bar;\n\nimpl Foo for Bar {\n // error, expected u16, found i16\n fn foo(x: i16) { }\n\n // error, types differ in mutability\n fn bar(&mut self) { }\n}\n```\n" - }, - "level": "error", - "spans": [ - { - "file_name": "compiler/ty/list_iter.rs", - "byte_start": 1307, - "byte_end": 1350, - "line_start": 52, - "line_end": 52, - "column_start": 5, - "column_end": 48, - "is_primary": true, - "text": [ - { - "text": " fn next(&self) -> Option<&'list ty::Ref> {", - "highlight_start": 5, - "highlight_end": 48 - } - ], - "label": "types differ in mutability", - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "expected type `fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref>`\n found type `fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref>`", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - } - ], - "rendered": "error[E0053]: method `next` has an incompatible type for trait\n --> compiler/ty/list_iter.rs:52:5\n |\n52 | fn next(&self) -> Option<&'list ty::Ref> {\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability\n |\n = note: expected type `fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref>`\n found type `fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref>`\n\n" - } - "##, - expect_file!["./test_data/rustc_incompatible_type_for_trait.txt"], - ); - } - - #[test] - fn rustc_unused_variable() { - check( - r##"{ - "message": "unused variable: `foo`", - "code": { - "code": "unused_variables", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "driver/subcommand/repl.rs", - "byte_start": 9228, - "byte_end": 9231, - "line_start": 291, - "line_end": 291, - "column_start": 9, - "column_end": 12, - "is_primary": true, - "text": [ - { - "text": " let foo = 42;", - "highlight_start": 9, - "highlight_end": 12 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "#[warn(unused_variables)] on by default", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - }, - { - "message": "consider prefixing with an underscore", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "driver/subcommand/repl.rs", - "byte_start": 9228, - "byte_end": 9231, - "line_start": 291, - "line_end": 291, - "column_start": 9, - "column_end": 12, - "is_primary": true, - "text": [ - { - "text": " let foo = 42;", - "highlight_start": 9, - "highlight_end": 12 - } - ], - "label": null, - "suggested_replacement": "_foo", - "suggestion_applicability": "MachineApplicable", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n" - }"##, - expect_file!["./test_data/rustc_unused_variable.txt"], - ); - } - - #[test] - #[cfg(not(windows))] - fn rustc_unused_variable_as_info() { - check_with_config( - DiagnosticsMapConfig { - warnings_as_info: vec!["unused_variables".to_string()], - ..DiagnosticsMapConfig::default() - }, - r##"{ - "message": "unused variable: `foo`", - "code": { - "code": "unused_variables", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "driver/subcommand/repl.rs", - "byte_start": 9228, - "byte_end": 9231, - "line_start": 291, - "line_end": 291, - "column_start": 9, - "column_end": 12, - "is_primary": true, - "text": [ - { - "text": " let foo = 42;", - "highlight_start": 9, - "highlight_end": 12 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "#[warn(unused_variables)] on by default", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - }, - { - "message": "consider prefixing with an underscore", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "driver/subcommand/repl.rs", - "byte_start": 9228, - "byte_end": 9231, - "line_start": 291, - "line_end": 291, - "column_start": 9, - "column_end": 12, - "is_primary": true, - "text": [ - { - "text": " let foo = 42;", - "highlight_start": 9, - "highlight_end": 12 - } - ], - "label": null, - "suggested_replacement": "_foo", - "suggestion_applicability": "MachineApplicable", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n" - }"##, - expect_file!["./test_data/rustc_unused_variable_as_info.txt"], - ); - } - - #[test] - #[cfg(not(windows))] - fn rustc_unused_variable_as_hint() { - check_with_config( - DiagnosticsMapConfig { - warnings_as_hint: vec!["unused_variables".to_string()], - ..DiagnosticsMapConfig::default() - }, - r##"{ - "message": "unused variable: `foo`", - "code": { - "code": "unused_variables", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "driver/subcommand/repl.rs", - "byte_start": 9228, - "byte_end": 9231, - "line_start": 291, - "line_end": 291, - "column_start": 9, - "column_end": 12, - "is_primary": true, - "text": [ - { - "text": " let foo = 42;", - "highlight_start": 9, - "highlight_end": 12 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "#[warn(unused_variables)] on by default", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - }, - { - "message": "consider prefixing with an underscore", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "driver/subcommand/repl.rs", - "byte_start": 9228, - "byte_end": 9231, - "line_start": 291, - "line_end": 291, - "column_start": 9, - "column_end": 12, - "is_primary": true, - "text": [ - { - "text": " let foo = 42;", - "highlight_start": 9, - "highlight_end": 12 - } - ], - "label": null, - "suggested_replacement": "_foo", - "suggestion_applicability": "MachineApplicable", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n" - }"##, - expect_file!["./test_data/rustc_unused_variable_as_hint.txt"], - ); - } - - #[test] - fn rustc_wrong_number_of_parameters() { - check( - r##"{ - "message": "this function takes 2 parameters but 3 parameters were supplied", - "code": { - "code": "E0061", - "explanation": "\nThe number of arguments passed to a function must match the number of arguments\nspecified in the function signature.\n\nFor example, a function like:\n\n```\nfn f(a: u16, b: &str) {}\n```\n\nMust always be called with exactly two arguments, e.g., `f(2, \"test\")`.\n\nNote that Rust does not have a notion of optional function arguments or\nvariadic functions (except for its C-FFI).\n" - }, - "level": "error", - "spans": [ - { - "file_name": "compiler/ty/select.rs", - "byte_start": 8787, - "byte_end": 9241, - "line_start": 219, - "line_end": 231, - "column_start": 5, - "column_end": 6, - "is_primary": false, - "text": [ - { - "text": " pub fn add_evidence(", - "highlight_start": 5, - "highlight_end": 25 - }, - { - "text": " &mut self,", - "highlight_start": 1, - "highlight_end": 19 - }, - { - "text": " target_poly: &ty::Ref,", - "highlight_start": 1, - "highlight_end": 41 - }, - { - "text": " evidence_poly: &ty::Ref,", - "highlight_start": 1, - "highlight_end": 43 - }, - { - "text": " ) {", - "highlight_start": 1, - "highlight_end": 8 - }, - { - "text": " match target_poly {", - "highlight_start": 1, - "highlight_end": 28 - }, - { - "text": " ty::Ref::Var(tvar, _) => self.add_var_evidence(tvar, evidence_poly),", - "highlight_start": 1, - "highlight_end": 81 - }, - { - "text": " ty::Ref::Fixed(target_ty) => {", - "highlight_start": 1, - "highlight_end": 43 - }, - { - "text": " let evidence_ty = evidence_poly.resolve_to_ty();", - "highlight_start": 1, - "highlight_end": 65 - }, - { - "text": " self.add_evidence_ty(target_ty, evidence_poly, evidence_ty)", - "highlight_start": 1, - "highlight_end": 76 - }, - { - "text": " }", - "highlight_start": 1, - "highlight_end": 14 - }, - { - "text": " }", - "highlight_start": 1, - "highlight_end": 10 - }, - { - "text": " }", - "highlight_start": 1, - "highlight_end": 6 - } - ], - "label": "defined here", - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - }, - { - "file_name": "compiler/ty/select.rs", - "byte_start": 4045, - "byte_end": 4057, - "line_start": 104, - "line_end": 104, - "column_start": 18, - "column_end": 30, - "is_primary": true, - "text": [ - { - "text": " self.add_evidence(target_fixed, evidence_fixed, false);", - "highlight_start": 18, - "highlight_end": 30 - } - ], - "label": "expected 2 parameters", - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [], - "rendered": "error[E0061]: this function takes 2 parameters but 3 parameters were supplied\n --> compiler/ty/select.rs:104:18\n |\n104 | self.add_evidence(target_fixed, evidence_fixed, false);\n | ^^^^^^^^^^^^ expected 2 parameters\n...\n219 | / pub fn add_evidence(\n220 | | &mut self,\n221 | | target_poly: &ty::Ref,\n222 | | evidence_poly: &ty::Ref,\n... |\n230 | | }\n231 | | }\n | |_____- defined here\n\n" - }"##, - expect_file!["./test_data/rustc_wrong_number_of_parameters.txt"], - ); - } - - #[test] - fn clippy_pass_by_ref() { - check( - r##"{ - "message": "this argument is passed by reference, but would be more efficient if passed by value", - "code": { - "code": "clippy::trivially_copy_pass_by_ref", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "compiler/mir/tagset.rs", - "byte_start": 941, - "byte_end": 946, - "line_start": 42, - "line_end": 42, - "column_start": 24, - "column_end": 29, - "is_primary": true, - "text": [ - { - "text": " pub fn is_disjoint(&self, other: Self) -> bool {", - "highlight_start": 24, - "highlight_end": 29 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "lint level defined here", - "code": null, - "level": "note", - "spans": [ - { - "file_name": "compiler/lib.rs", - "byte_start": 8, - "byte_end": 19, - "line_start": 1, - "line_end": 1, - "column_start": 9, - "column_end": 20, - "is_primary": true, - "text": [ - { - "text": "#![warn(clippy::all)]", - "highlight_start": 9, - "highlight_end": 20 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [], - "rendered": null - }, - { - "message": "#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - }, - { - "message": "for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref", - "code": null, - "level": "help", - "spans": [], - "children": [], - "rendered": null - }, - { - "message": "consider passing by value instead", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "compiler/mir/tagset.rs", - "byte_start": 941, - "byte_end": 946, - "line_start": 42, - "line_end": 42, - "column_start": 24, - "column_end": 29, - "is_primary": true, - "text": [ - { - "text": " pub fn is_disjoint(&self, other: Self) -> bool {", - "highlight_start": 24, - "highlight_end": 29 - } - ], - "label": null, - "suggested_replacement": "self", - "suggestion_applicability": "Unspecified", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: this argument is passed by reference, but would be more efficient if passed by value\n --> compiler/mir/tagset.rs:42:24\n |\n42 | pub fn is_disjoint(&self, other: Self) -> bool {\n | ^^^^^ help: consider passing by value instead: `self`\n |\nnote: lint level defined here\n --> compiler/lib.rs:1:9\n |\n1 | #![warn(clippy::all)]\n | ^^^^^^^^^^^\n = note: #[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]\n = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref\n\n" - }"##, - expect_file!["./test_data/clippy_pass_by_ref.txt"], - ); - } - - #[test] - fn rustc_range_map_lsp_position() { - check( - r##"{ - "message": "mismatched types", - "code": { - "code": "E0308", - "explanation": "Expected type did not match the received type.\n\nErroneous code examples:\n\n```compile_fail,E0308\nfn plus_one(x: i32) -> i32 {\n x + 1\n}\n\nplus_one(\"Not a number\");\n// ^^^^^^^^^^^^^^ expected `i32`, found `&str`\n\nif \"Not a bool\" {\n// ^^^^^^^^^^^^ expected `bool`, found `&str`\n}\n\nlet x: f32 = \"Not a float\";\n// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`\n// |\n// expected due to this\n```\n\nThis error occurs when an expression was used in a place where the compiler\nexpected an expression of a different type. It can occur in several cases, the\nmost common being when calling a function and passing an argument which has a\ndifferent type than the matching type in the function declaration.\n" - }, - "level": "error", - "spans": [ - { - "file_name": "crates/test_diagnostics/src/main.rs", - "byte_start": 87, - "byte_end": 105, - "line_start": 4, - "line_end": 4, - "column_start": 18, - "column_end": 24, - "is_primary": true, - "text": [ - { - "text": " let x: u32 = \"𐐀𐐀𐐀𐐀\"; // 17-23", - "highlight_start": 18, - "highlight_end": 24 - } - ], - "label": "expected `u32`, found `&str`", - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - }, - { - "file_name": "crates/test_diagnostics/src/main.rs", - "byte_start": 81, - "byte_end": 84, - "line_start": 4, - "line_end": 4, - "column_start": 12, - "column_end": 15, - "is_primary": false, - "text": [ - { - "text": " let x: u32 = \"𐐀𐐀𐐀𐐀\"; // 17-23", - "highlight_start": 12, - "highlight_end": 15 - } - ], - "label": "expected due to this", - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [], - "rendered": "error[E0308]: mismatched types\n --> crates/test_diagnostics/src/main.rs:4:18\n |\n4 | let x: u32 = \"𐐀𐐀𐐀𐐀\"; // 17-23\n | --- ^^^^^^ expected `u32`, found `&str`\n | |\n | expected due to this\n\n" - }"##, - expect_file!("./test_data/rustc_range_map_lsp_position.txt"), - ) - } - - #[test] - fn rustc_mismatched_type() { - check( - r##"{ - "message": "mismatched types", - "code": { - "code": "E0308", - "explanation": "\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n" - }, - "level": "error", - "spans": [ - { - "file_name": "runtime/compiler_support.rs", - "byte_start": 1589, - "byte_end": 1594, - "line_start": 48, - "line_end": 48, - "column_start": 65, - "column_end": 70, - "is_primary": true, - "text": [ - { - "text": " let layout = alloc::Layout::from_size_align_unchecked(size, align);", - "highlight_start": 65, - "highlight_end": 70 - } - ], - "label": "expected usize, found u32", - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [], - "rendered": "error[E0308]: mismatched types\n --> runtime/compiler_support.rs:48:65\n |\n48 | let layout = alloc::Layout::from_size_align_unchecked(size, align);\n | ^^^^^ expected usize, found u32\n\n" - }"##, - expect_file!["./test_data/rustc_mismatched_type.txt"], - ); - } - - #[test] - fn handles_macro_location() { - check( - r##"{ - "rendered": "error[E0277]: can't compare `{integer}` with `&str`\n --> src/main.rs:2:5\n |\n2 | assert_eq!(1, \"love\");\n | ^^^^^^^^^^^^^^^^^^^^^^ no implementation for `{integer} == &str`\n |\n = help: the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`\n = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)\n\n", - "children": [ - { - "children": [], - "code": null, - "level": "help", - "message": "the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`", - "rendered": null, - "spans": [] - } - ], - "code": { - "code": "E0277", - "explanation": "\nYou tried to use a type which doesn't implement some trait in a place which\nexpected that trait. Erroneous code example:\n\n```compile_fail,E0277\n// here we declare the Foo trait with a bar method\ntrait Foo {\n fn bar(&self);\n}\n\n// we now declare a function which takes an object implementing the Foo trait\nfn some_func(foo: T) {\n foo.bar();\n}\n\nfn main() {\n // we now call the method with the i32 type, which doesn't implement\n // the Foo trait\n some_func(5i32); // error: the trait bound `i32 : Foo` is not satisfied\n}\n```\n\nIn order to fix this error, verify that the type you're using does implement\nthe trait. Example:\n\n```\ntrait Foo {\n fn bar(&self);\n}\n\nfn some_func(foo: T) {\n foo.bar(); // we can now use this method since i32 implements the\n // Foo trait\n}\n\n// we implement the trait on the i32 type\nimpl Foo for i32 {\n fn bar(&self) {}\n}\n\nfn main() {\n some_func(5i32); // ok!\n}\n```\n\nOr in a generic context, an erroneous code example would look like:\n\n```compile_fail,E0277\nfn some_func(foo: T) {\n println!(\"{:?}\", foo); // error: the trait `core::fmt::Debug` is not\n // implemented for the type `T`\n}\n\nfn main() {\n // We now call the method with the i32 type,\n // which *does* implement the Debug trait.\n some_func(5i32);\n}\n```\n\nNote that the error here is in the definition of the generic function: Although\nwe only call it with a parameter that does implement `Debug`, the compiler\nstill rejects the function: It must work with all possible input types. In\norder to make this example compile, we need to restrict the generic type we're\naccepting:\n\n```\nuse std::fmt;\n\n// Restrict the input type to types that implement Debug.\nfn some_func(foo: T) {\n println!(\"{:?}\", foo);\n}\n\nfn main() {\n // Calling the method is still fine, as i32 implements Debug.\n some_func(5i32);\n\n // This would fail to compile now:\n // struct WithoutDebug;\n // some_func(WithoutDebug);\n}\n```\n\nRust only looks at the signature of the called function, as such it must\nalready specify all requirements that will be used for every type parameter.\n" - }, - "level": "error", - "message": "can't compare `{integer}` with `&str`", - "spans": [ - { - "byte_end": 155, - "byte_start": 153, - "column_end": 33, - "column_start": 31, - "expansion": { - "def_site_span": { - "byte_end": 940, - "byte_start": 0, - "column_end": 6, - "column_start": 1, - "expansion": null, - "file_name": "<::core::macros::assert_eq macros>", - "is_primary": false, - "label": null, - "line_end": 36, - "line_start": 1, - "suggested_replacement": null, - "suggestion_applicability": null, - "text": [ - { - "highlight_end": 35, - "highlight_start": 1, - "text": "($ left : expr, $ right : expr) =>" - }, - { - "highlight_end": 3, - "highlight_start": 1, - "text": "({" - }, - { - "highlight_end": 33, - "highlight_start": 1, - "text": " match (& $ left, & $ right)" - }, - { - "highlight_end": 7, - "highlight_start": 1, - "text": " {" - }, - { - "highlight_end": 34, - "highlight_start": 1, - "text": " (left_val, right_val) =>" - }, - { - "highlight_end": 11, - "highlight_start": 1, - "text": " {" - }, - { - "highlight_end": 46, - "highlight_start": 1, - "text": " if ! (* left_val == * right_val)" - }, - { - "highlight_end": 15, - "highlight_start": 1, - "text": " {" - }, - { - "highlight_end": 25, - "highlight_start": 1, - "text": " panic !" - }, - { - "highlight_end": 57, - "highlight_start": 1, - "text": " (r#\"assertion failed: `(left == right)`" - }, - { - "highlight_end": 16, - "highlight_start": 1, - "text": " left: `{:?}`," - }, - { - "highlight_end": 18, - "highlight_start": 1, - "text": " right: `{:?}`\"#," - }, - { - "highlight_end": 47, - "highlight_start": 1, - "text": " & * left_val, & * right_val)" - }, - { - "highlight_end": 15, - "highlight_start": 1, - "text": " }" - }, - { - "highlight_end": 11, - "highlight_start": 1, - "text": " }" - }, - { - "highlight_end": 7, - "highlight_start": 1, - "text": " }" - }, - { - "highlight_end": 42, - "highlight_start": 1, - "text": " }) ; ($ left : expr, $ right : expr,) =>" - }, - { - "highlight_end": 49, - "highlight_start": 1, - "text": "({ $ crate :: assert_eq ! ($ left, $ right) }) ;" - }, - { - "highlight_end": 53, - "highlight_start": 1, - "text": "($ left : expr, $ right : expr, $ ($ arg : tt) +) =>" - }, - { - "highlight_end": 3, - "highlight_start": 1, - "text": "({" - }, - { - "highlight_end": 37, - "highlight_start": 1, - "text": " match (& ($ left), & ($ right))" - }, - { - "highlight_end": 7, - "highlight_start": 1, - "text": " {" - }, - { - "highlight_end": 34, - "highlight_start": 1, - "text": " (left_val, right_val) =>" - }, - { - "highlight_end": 11, - "highlight_start": 1, - "text": " {" - }, - { - "highlight_end": 46, - "highlight_start": 1, - "text": " if ! (* left_val == * right_val)" - }, - { - "highlight_end": 15, - "highlight_start": 1, - "text": " {" - }, - { - "highlight_end": 25, - "highlight_start": 1, - "text": " panic !" - }, - { - "highlight_end": 57, - "highlight_start": 1, - "text": " (r#\"assertion failed: `(left == right)`" - }, - { - "highlight_end": 16, - "highlight_start": 1, - "text": " left: `{:?}`," - }, - { - "highlight_end": 22, - "highlight_start": 1, - "text": " right: `{:?}`: {}\"#," - }, - { - "highlight_end": 72, - "highlight_start": 1, - "text": " & * left_val, & * right_val, $ crate :: format_args !" - }, - { - "highlight_end": 33, - "highlight_start": 1, - "text": " ($ ($ arg) +))" - }, - { - "highlight_end": 15, - "highlight_start": 1, - "text": " }" - }, - { - "highlight_end": 11, - "highlight_start": 1, - "text": " }" - }, - { - "highlight_end": 7, - "highlight_start": 1, - "text": " }" - }, - { - "highlight_end": 6, - "highlight_start": 1, - "text": " }) ;" - } - ] - }, - "macro_decl_name": "assert_eq!", - "span": { - "byte_end": 38, - "byte_start": 16, - "column_end": 27, - "column_start": 5, - "expansion": null, - "file_name": "src/main.rs", - "is_primary": false, - "label": null, - "line_end": 2, - "line_start": 2, - "suggested_replacement": null, - "suggestion_applicability": null, - "text": [ - { - "highlight_end": 27, - "highlight_start": 5, - "text": " assert_eq!(1, \"love\");" - } - ] - } - }, - "file_name": "<::core::macros::assert_eq macros>", - "is_primary": true, - "label": "no implementation for `{integer} == &str`", - "line_end": 7, - "line_start": 7, - "suggested_replacement": null, - "suggestion_applicability": null, - "text": [ - { - "highlight_end": 33, - "highlight_start": 31, - "text": " if ! (* left_val == * right_val)" - } - ] - } - ] - }"##, - expect_file!["./test_data/handles_macro_location.txt"], - ); - } - - #[test] - fn macro_compiler_error() { - check( - r##"{ - "rendered": "error: Please register your known path in the path module\n --> crates/hir_def/src/path.rs:265:9\n |\n265 | compile_error!(\"Please register your known path in the path module\")\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n | \n ::: crates/hir_def/src/data.rs:80:16\n |\n80 | let path = path![std::future::Future];\n | -------------------------- in this macro invocation\n\n", - "children": [], - "code": null, - "level": "error", - "message": "Please register your known path in the path module", - "spans": [ - { - "byte_end": 8285, - "byte_start": 8217, - "column_end": 77, - "column_start": 9, - "expansion": { - "def_site_span": { - "byte_end": 8294, - "byte_start": 7858, - "column_end": 2, - "column_start": 1, - "expansion": null, - "file_name": "crates/hir_def/src/path.rs", - "is_primary": false, - "label": null, - "line_end": 267, - "line_start": 254, - "suggested_replacement": null, - "suggestion_applicability": null, - "text": [ - { - "highlight_end": 28, - "highlight_start": 1, - "text": "macro_rules! __known_path {" - }, - { - "highlight_end": 37, - "highlight_start": 1, - "text": " (std::iter::IntoIterator) => {};" - }, - { - "highlight_end": 33, - "highlight_start": 1, - "text": " (std::result::Result) => {};" - }, - { - "highlight_end": 29, - "highlight_start": 1, - "text": " (std::ops::Range) => {};" - }, - { - "highlight_end": 33, - "highlight_start": 1, - "text": " (std::ops::RangeFrom) => {};" - }, - { - "highlight_end": 33, - "highlight_start": 1, - "text": " (std::ops::RangeFull) => {};" - }, - { - "highlight_end": 31, - "highlight_start": 1, - "text": " (std::ops::RangeTo) => {};" - }, - { - "highlight_end": 40, - "highlight_start": 1, - "text": " (std::ops::RangeToInclusive) => {};" - }, - { - "highlight_end": 38, - "highlight_start": 1, - "text": " (std::ops::RangeInclusive) => {};" - }, - { - "highlight_end": 27, - "highlight_start": 1, - "text": " (std::ops::Try) => {};" - }, - { - "highlight_end": 22, - "highlight_start": 1, - "text": " ($path:path) => {" - }, - { - "highlight_end": 77, - "highlight_start": 1, - "text": " compile_error!(\"Please register your known path in the path module\")" - }, - { - "highlight_end": 7, - "highlight_start": 1, - "text": " };" - }, - { - "highlight_end": 2, - "highlight_start": 1, - "text": "}" - } - ] - }, - "macro_decl_name": "$crate::__known_path!", - "span": { - "byte_end": 8427, - "byte_start": 8385, - "column_end": 51, - "column_start": 9, - "expansion": { - "def_site_span": { - "byte_end": 8611, - "byte_start": 8312, - "column_end": 2, - "column_start": 1, - "expansion": null, - "file_name": "crates/hir_def/src/path.rs", - "is_primary": false, - "label": null, - "line_end": 277, - "line_start": 270, - "suggested_replacement": null, - "suggestion_applicability": null, - "text": [ - { - "highlight_end": 22, - "highlight_start": 1, - "text": "macro_rules! __path {" - }, - { - "highlight_end": 43, - "highlight_start": 1, - "text": " ($start:ident $(:: $seg:ident)*) => ({" - }, - { - "highlight_end": 51, - "highlight_start": 1, - "text": " $crate::__known_path!($start $(:: $seg)*);" - }, - { - "highlight_end": 87, - "highlight_start": 1, - "text": " $crate::path::ModPath::from_simple_segments($crate::path::PathKind::Abs, vec![" - }, - { - "highlight_end": 76, - "highlight_start": 1, - "text": " $crate::path::__name![$start], $($crate::path::__name![$seg],)*" - }, - { - "highlight_end": 11, - "highlight_start": 1, - "text": " ])" - }, - { - "highlight_end": 8, - "highlight_start": 1, - "text": " });" - }, - { - "highlight_end": 2, - "highlight_start": 1, - "text": "}" - } - ] - }, - "macro_decl_name": "path!", - "span": { - "byte_end": 2966, - "byte_start": 2940, - "column_end": 42, - "column_start": 16, - "expansion": null, - "file_name": "crates/hir_def/src/data.rs", - "is_primary": false, - "label": null, - "line_end": 80, - "line_start": 80, - "suggested_replacement": null, - "suggestion_applicability": null, - "text": [ - { - "highlight_end": 42, - "highlight_start": 16, - "text": " let path = path![std::future::Future];" - } - ] - } - }, - "file_name": "crates/hir_def/src/path.rs", - "is_primary": false, - "label": null, - "line_end": 272, - "line_start": 272, - "suggested_replacement": null, - "suggestion_applicability": null, - "text": [ - { - "highlight_end": 51, - "highlight_start": 9, - "text": " $crate::__known_path!($start $(:: $seg)*);" - } - ] - } - }, - "file_name": "crates/hir_def/src/path.rs", - "is_primary": true, - "label": null, - "line_end": 265, - "line_start": 265, - "suggested_replacement": null, - "suggestion_applicability": null, - "text": [ - { - "highlight_end": 77, - "highlight_start": 9, - "text": " compile_error!(\"Please register your known path in the path module\")" - } - ] - } - ] - } - "##, - expect_file!["./test_data/macro_compiler_error.txt"], - ); - } - - #[test] - fn snap_multi_line_fix() { - check( - r##"{ - "rendered": "warning: returning the result of a let binding from a block\n --> src/main.rs:4:5\n |\n3 | let a = (0..10).collect();\n | -------------------------- unnecessary let binding\n4 | a\n | ^\n |\n = note: `#[warn(clippy::let_and_return)]` on by default\n = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return\nhelp: return the expression directly\n |\n3 | \n4 | (0..10).collect()\n |\n\n", - "children": [ - { - "children": [], - "code": null, - "level": "note", - "message": "`#[warn(clippy::let_and_return)]` on by default", - "rendered": null, - "spans": [] - }, - { - "children": [], - "code": null, - "level": "help", - "message": "for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return", - "rendered": null, - "spans": [] - }, - { - "children": [], - "code": null, - "level": "help", - "message": "return the expression directly", - "rendered": null, - "spans": [ - { - "byte_end": 55, - "byte_start": 29, - "column_end": 31, - "column_start": 5, - "expansion": null, - "file_name": "src/main.rs", - "is_primary": true, - "label": null, - "line_end": 3, - "line_start": 3, - "suggested_replacement": "", - "suggestion_applicability": "MachineApplicable", - "text": [ - { - "highlight_end": 31, - "highlight_start": 5, - "text": " let a = (0..10).collect();" - } - ] - }, - { - "byte_end": 61, - "byte_start": 60, - "column_end": 6, - "column_start": 5, - "expansion": null, - "file_name": "src/main.rs", - "is_primary": true, - "label": null, - "line_end": 4, - "line_start": 4, - "suggested_replacement": "(0..10).collect()", - "suggestion_applicability": "MachineApplicable", - "text": [ - { - "highlight_end": 6, - "highlight_start": 5, - "text": " a" - } - ] - } - ] - } - ], - "code": { - "code": "clippy::let_and_return", - "explanation": null - }, - "level": "warning", - "message": "returning the result of a let binding from a block", - "spans": [ - { - "byte_end": 55, - "byte_start": 29, - "column_end": 31, - "column_start": 5, - "expansion": null, - "file_name": "src/main.rs", - "is_primary": false, - "label": "unnecessary let binding", - "line_end": 3, - "line_start": 3, - "suggested_replacement": null, - "suggestion_applicability": null, - "text": [ - { - "highlight_end": 31, - "highlight_start": 5, - "text": " let a = (0..10).collect();" - } - ] - }, - { - "byte_end": 61, - "byte_start": 60, - "column_end": 6, - "column_start": 5, - "expansion": null, - "file_name": "src/main.rs", - "is_primary": true, - "label": null, - "line_end": 4, - "line_start": 4, - "suggested_replacement": null, - "suggestion_applicability": null, - "text": [ - { - "highlight_end": 6, - "highlight_start": 5, - "text": " a" - } - ] - } - ] - } - "##, - expect_file!["./test_data/snap_multi_line_fix.txt"], - ); - } - - #[test] - fn reasonable_line_numbers_from_empty_file() { - check( - r##"{ - "message": "`main` function not found in crate `current`", - "code": { - "code": "E0601", - "explanation": "No `main` function was found in a binary crate.\n\nTo fix this error, add a `main` function:\n\n```\nfn main() {\n // Your program will start here.\n println!(\"Hello world!\");\n}\n```\n\nIf you don't know the basics of Rust, you can look at the\n[Rust Book][rust-book] to get started.\n\n[rust-book]: https://doc.rust-lang.org/book/\n" - }, - "level": "error", - "spans": [ - { - "file_name": "src/bin/current.rs", - "byte_start": 0, - "byte_end": 0, - "line_start": 0, - "line_end": 0, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "consider adding a `main` function to `src/bin/current.rs`", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - } - ], - "rendered": "error[E0601]: `main` function not found in crate `current`\n |\n = note: consider adding a `main` function to `src/bin/current.rs`\n\n" - }"##, - expect_file!["./test_data/reasonable_line_numbers_from_empty_file.txt"], - ); - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diff.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diff.rs deleted file mode 100644 index 3fcfb4a1b08aa..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diff.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! Generate minimal `TextEdit`s from different text versions -use dissimilar::Chunk; -use ide::{TextEdit, TextRange, TextSize}; - -pub(crate) fn diff(left: &str, right: &str) -> TextEdit { - let chunks = dissimilar::diff(left, right); - textedit_from_chunks(chunks) -} - -fn textedit_from_chunks(chunks: Vec>) -> TextEdit { - let mut builder = TextEdit::builder(); - let mut pos = TextSize::default(); - - let mut chunks = chunks.into_iter().peekable(); - while let Some(chunk) = chunks.next() { - if let (Chunk::Delete(deleted), Some(&Chunk::Insert(inserted))) = (chunk, chunks.peek()) { - chunks.next().unwrap(); - let deleted_len = TextSize::of(deleted); - builder.replace(TextRange::at(pos, deleted_len), inserted.into()); - pos += deleted_len; - continue; - } - - match chunk { - Chunk::Equal(text) => { - pos += TextSize::of(text); - } - Chunk::Delete(deleted) => { - let deleted_len = TextSize::of(deleted); - builder.delete(TextRange::at(pos, deleted_len)); - pos += deleted_len; - } - Chunk::Insert(inserted) => { - builder.insert(pos, inserted.into()); - } - } - } - builder.finish() -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn diff_applies() { - let mut original = String::from("fn foo(a:u32){\n}"); - let result = "fn foo(a: u32) {}"; - let edit = diff(&original, result); - edit.apply(&mut original); - assert_eq!(original, result); - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs deleted file mode 100644 index f16559148e651..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs +++ /dev/null @@ -1,266 +0,0 @@ -//! See [RequestDispatcher]. -use std::{fmt, panic, thread}; - -use ide::Cancelled; -use lsp_server::ExtractError; -use serde::{de::DeserializeOwned, Serialize}; - -use crate::{ - global_state::{GlobalState, GlobalStateSnapshot}, - main_loop::Task, - version::version, - LspError, Result, -}; - -/// A visitor for routing a raw JSON request to an appropriate handler function. -/// -/// Most requests are read-only and async and are handled on the threadpool -/// (`on` method). -/// -/// Some read-only requests are latency sensitive, and are immediately handled -/// on the main loop thread (`on_sync`). These are typically typing-related -/// requests. -/// -/// Some requests modify the state, and are run on the main thread to get -/// `&mut` (`on_sync_mut`). -/// -/// Read-only requests are wrapped into `catch_unwind` -- they don't modify the -/// state, so it's OK to recover from their failures. -pub(crate) struct RequestDispatcher<'a> { - pub(crate) req: Option, - pub(crate) global_state: &'a mut GlobalState, -} - -impl<'a> RequestDispatcher<'a> { - /// Dispatches the request onto the current thread, given full access to - /// mutable global state. Unlike all other methods here, this one isn't - /// guarded by `catch_unwind`, so, please, don't make bugs :-) - pub(crate) fn on_sync_mut( - &mut self, - f: fn(&mut GlobalState, R::Params) -> Result, - ) -> &mut Self - where - R: lsp_types::request::Request, - R::Params: DeserializeOwned + panic::UnwindSafe + fmt::Debug, - R::Result: Serialize, - { - let (req, params, panic_context) = match self.parse::() { - Some(it) => it, - None => return self, - }; - let result = { - let _pctx = stdx::panic_context::enter(panic_context); - f(self.global_state, params) - }; - if let Ok(response) = result_to_response::(req.id.clone(), result) { - self.global_state.respond(response); - } - - self - } - - /// Dispatches the request onto the current thread. - pub(crate) fn on_sync( - &mut self, - f: fn(GlobalStateSnapshot, R::Params) -> Result, - ) -> &mut Self - where - R: lsp_types::request::Request, - R::Params: DeserializeOwned + panic::UnwindSafe + fmt::Debug, - R::Result: Serialize, - { - let (req, params, panic_context) = match self.parse::() { - Some(it) => it, - None => return self, - }; - let global_state_snapshot = self.global_state.snapshot(); - - let result = panic::catch_unwind(move || { - let _pctx = stdx::panic_context::enter(panic_context); - f(global_state_snapshot, params) - }); - - if let Ok(response) = thread_result_to_response::(req.id.clone(), result) { - self.global_state.respond(response); - } - - self - } - - /// Dispatches the request onto thread pool - pub(crate) fn on( - &mut self, - f: fn(GlobalStateSnapshot, R::Params) -> Result, - ) -> &mut Self - where - R: lsp_types::request::Request + 'static, - R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug, - R::Result: Serialize, - { - let (req, params, panic_context) = match self.parse::() { - Some(it) => it, - None => return self, - }; - - self.global_state.task_pool.handle.spawn({ - let world = self.global_state.snapshot(); - move || { - let result = panic::catch_unwind(move || { - let _pctx = stdx::panic_context::enter(panic_context); - f(world, params) - }); - match thread_result_to_response::(req.id.clone(), result) { - Ok(response) => Task::Response(response), - Err(_) => Task::Retry(req), - } - } - }); - - self - } - - pub(crate) fn finish(&mut self) { - if let Some(req) = self.req.take() { - tracing::error!("unknown request: {:?}", req); - let response = lsp_server::Response::new_err( - req.id, - lsp_server::ErrorCode::MethodNotFound as i32, - "unknown request".to_string(), - ); - self.global_state.respond(response); - } - } - - fn parse(&mut self) -> Option<(lsp_server::Request, R::Params, String)> - where - R: lsp_types::request::Request, - R::Params: DeserializeOwned + fmt::Debug, - { - let req = match &self.req { - Some(req) if req.method == R::METHOD => self.req.take()?, - _ => return None, - }; - - let res = crate::from_json(R::METHOD, &req.params); - match res { - Ok(params) => { - let panic_context = - format!("\nversion: {}\nrequest: {} {:#?}", version(), R::METHOD, params); - Some((req, params, panic_context)) - } - Err(err) => { - let response = lsp_server::Response::new_err( - req.id, - lsp_server::ErrorCode::InvalidParams as i32, - err.to_string(), - ); - self.global_state.respond(response); - None - } - } - } -} - -fn thread_result_to_response( - id: lsp_server::RequestId, - result: thread::Result>, -) -> Result -where - R: lsp_types::request::Request, - R::Params: DeserializeOwned, - R::Result: Serialize, -{ - match result { - Ok(result) => result_to_response::(id, result), - Err(panic) => { - let panic_message = panic - .downcast_ref::() - .map(String::as_str) - .or_else(|| panic.downcast_ref::<&str>().copied()); - - let mut message = "request handler panicked".to_string(); - if let Some(panic_message) = panic_message { - message.push_str(": "); - message.push_str(panic_message) - }; - - Ok(lsp_server::Response::new_err( - id, - lsp_server::ErrorCode::InternalError as i32, - message, - )) - } - } -} - -fn result_to_response( - id: lsp_server::RequestId, - result: Result, -) -> Result -where - R: lsp_types::request::Request, - R::Params: DeserializeOwned, - R::Result: Serialize, -{ - let res = match result { - Ok(resp) => lsp_server::Response::new_ok(id, &resp), - Err(e) => match e.downcast::() { - Ok(lsp_error) => lsp_server::Response::new_err(id, lsp_error.code, lsp_error.message), - Err(e) => match e.downcast::() { - Ok(cancelled) => return Err(*cancelled), - Err(e) => lsp_server::Response::new_err( - id, - lsp_server::ErrorCode::InternalError as i32, - e.to_string(), - ), - }, - }, - }; - Ok(res) -} - -pub(crate) struct NotificationDispatcher<'a> { - pub(crate) not: Option, - pub(crate) global_state: &'a mut GlobalState, -} - -impl<'a> NotificationDispatcher<'a> { - pub(crate) fn on( - &mut self, - f: fn(&mut GlobalState, N::Params) -> Result<()>, - ) -> Result<&mut Self> - where - N: lsp_types::notification::Notification, - N::Params: DeserializeOwned + Send, - { - let not = match self.not.take() { - Some(it) => it, - None => return Ok(self), - }; - let params = match not.extract::(N::METHOD) { - Ok(it) => it, - Err(ExtractError::JsonError { method, error }) => { - panic!("Invalid request\nMethod: {method}\n error: {error}",) - } - Err(ExtractError::MethodMismatch(not)) => { - self.not = Some(not); - return Ok(self); - } - }; - let _pctx = stdx::panic_context::enter(format!( - "\nversion: {}\nnotification: {}", - version(), - N::METHOD - )); - f(self.global_state, params)?; - Ok(self) - } - - pub(crate) fn finish(&mut self) { - if let Some(not) = &self.not { - if !not.method.starts_with("$/") { - tracing::error!("unhandled notification: {:?}", not); - } - } - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/from_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/from_proto.rs deleted file mode 100644 index 7bdd34d1f093a..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/from_proto.rs +++ /dev/null @@ -1,117 +0,0 @@ -//! Conversion lsp_types types to rust-analyzer specific ones. -use anyhow::format_err; -use ide::{Annotation, AnnotationKind, AssistKind, LineCol, LineColUtf16}; -use ide_db::base_db::{FileId, FilePosition, FileRange}; -use syntax::{TextRange, TextSize}; -use vfs::AbsPathBuf; - -use crate::{ - from_json, - global_state::GlobalStateSnapshot, - line_index::{LineIndex, OffsetEncoding}, - lsp_ext, - lsp_utils::invalid_params_error, - Result, -}; - -pub(crate) fn abs_path(url: &lsp_types::Url) -> Result { - let path = url.to_file_path().map_err(|()| "url is not a file")?; - Ok(AbsPathBuf::try_from(path).unwrap()) -} - -pub(crate) fn vfs_path(url: &lsp_types::Url) -> Result { - abs_path(url).map(vfs::VfsPath::from) -} - -pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> Result { - let line_col = match line_index.encoding { - OffsetEncoding::Utf8 => { - LineCol { line: position.line as u32, col: position.character as u32 } - } - OffsetEncoding::Utf16 => { - let line_col = - LineColUtf16 { line: position.line as u32, col: position.character as u32 }; - line_index.index.to_utf8(line_col) - } - }; - let text_size = - line_index.index.offset(line_col).ok_or_else(|| format_err!("Invalid offset"))?; - Ok(text_size) -} - -pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> Result { - let start = offset(line_index, range.start)?; - let end = offset(line_index, range.end)?; - let text_range = TextRange::new(start, end); - Ok(text_range) -} - -pub(crate) fn file_id(snap: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result { - snap.url_to_file_id(url) -} - -pub(crate) fn file_position( - snap: &GlobalStateSnapshot, - tdpp: lsp_types::TextDocumentPositionParams, -) -> Result { - let file_id = file_id(snap, &tdpp.text_document.uri)?; - let line_index = snap.file_line_index(file_id)?; - let offset = offset(&line_index, tdpp.position)?; - Ok(FilePosition { file_id, offset }) -} - -pub(crate) fn file_range( - snap: &GlobalStateSnapshot, - text_document_identifier: lsp_types::TextDocumentIdentifier, - range: lsp_types::Range, -) -> Result { - let file_id = file_id(snap, &text_document_identifier.uri)?; - let line_index = snap.file_line_index(file_id)?; - let range = text_range(&line_index, range)?; - Ok(FileRange { file_id, range }) -} - -pub(crate) fn assist_kind(kind: lsp_types::CodeActionKind) -> Option { - let assist_kind = match &kind { - k if k == &lsp_types::CodeActionKind::EMPTY => AssistKind::None, - k if k == &lsp_types::CodeActionKind::QUICKFIX => AssistKind::QuickFix, - k if k == &lsp_types::CodeActionKind::REFACTOR => AssistKind::Refactor, - k if k == &lsp_types::CodeActionKind::REFACTOR_EXTRACT => AssistKind::RefactorExtract, - k if k == &lsp_types::CodeActionKind::REFACTOR_INLINE => AssistKind::RefactorInline, - k if k == &lsp_types::CodeActionKind::REFACTOR_REWRITE => AssistKind::RefactorRewrite, - _ => return None, - }; - - Some(assist_kind) -} - -pub(crate) fn annotation( - snap: &GlobalStateSnapshot, - code_lens: lsp_types::CodeLens, -) -> Result { - let data = - code_lens.data.ok_or_else(|| invalid_params_error("code lens without data".to_string()))?; - let resolve = from_json::("CodeLensResolveData", &data)?; - - match resolve { - lsp_ext::CodeLensResolveData::Impls(params) => { - let file_id = - snap.url_to_file_id(¶ms.text_document_position_params.text_document.uri)?; - let line_index = snap.file_line_index(file_id)?; - - Ok(Annotation { - range: text_range(&line_index, code_lens.range)?, - kind: AnnotationKind::HasImpls { file_id, data: None }, - }) - } - lsp_ext::CodeLensResolveData::References(params) => { - let file_id = snap.url_to_file_id(¶ms.text_document.uri)?; - let line_index = snap.file_line_index(file_id)?; - - Ok(Annotation { - range: text_range(&line_index, code_lens.range)?, - kind: AnnotationKind::HasReferences { file_id, data: None }, - }) - } - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs deleted file mode 100644 index 8f881cba4dbd7..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ /dev/null @@ -1,375 +0,0 @@ -//! The context or environment in which the language server functions. In our -//! server implementation this is know as the `WorldState`. -//! -//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`. - -use std::{sync::Arc, time::Instant}; - -use crossbeam_channel::{unbounded, Receiver, Sender}; -use flycheck::FlycheckHandle; -use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId}; -use ide_db::base_db::{CrateId, FileLoader, SourceDatabase}; -use lsp_types::{SemanticTokens, Url}; -use parking_lot::{Mutex, RwLock}; -use proc_macro_api::ProcMacroServer; -use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts}; -use rustc_hash::FxHashMap; -use vfs::AnchoredPathBuf; - -use crate::{ - config::Config, - diagnostics::{CheckFixes, DiagnosticCollection}, - from_proto, - line_index::{LineEndings, LineIndex}, - lsp_ext, - main_loop::Task, - mem_docs::MemDocs, - op_queue::OpQueue, - reload::{self, SourceRootConfig}, - task_pool::TaskPool, - to_proto::url_from_abs_path, - Result, -}; - -// Enforces drop order -pub(crate) struct Handle { - pub(crate) handle: H, - pub(crate) receiver: C, -} - -pub(crate) type ReqHandler = fn(&mut GlobalState, lsp_server::Response); -pub(crate) type ReqQueue = lsp_server::ReqQueue<(String, Instant), ReqHandler>; - -/// `GlobalState` is the primary mutable state of the language server -/// -/// The most interesting components are `vfs`, which stores a consistent -/// snapshot of the file systems, and `analysis_host`, which stores our -/// incremental salsa database. -/// -/// Note that this struct has more than one impl in various modules! -pub(crate) struct GlobalState { - sender: Sender, - req_queue: ReqQueue, - pub(crate) task_pool: Handle, Receiver>, - pub(crate) loader: Handle, Receiver>, - pub(crate) config: Arc, - pub(crate) analysis_host: AnalysisHost, - pub(crate) diagnostics: DiagnosticCollection, - pub(crate) mem_docs: MemDocs, - pub(crate) semantic_tokens_cache: Arc>>, - pub(crate) shutdown_requested: bool, - pub(crate) proc_macro_changed: bool, - pub(crate) last_reported_status: Option, - pub(crate) source_root_config: SourceRootConfig, - pub(crate) proc_macro_clients: Vec>, - - pub(crate) flycheck: Vec, - pub(crate) flycheck_sender: Sender, - pub(crate) flycheck_receiver: Receiver, - - pub(crate) vfs: Arc)>>, - pub(crate) vfs_config_version: u32, - pub(crate) vfs_progress_config_version: u32, - pub(crate) vfs_progress_n_total: usize, - pub(crate) vfs_progress_n_done: usize, - - /// `workspaces` field stores the data we actually use, while the `OpQueue` - /// stores the result of the last fetch. - /// - /// If the fetch (partially) fails, we do not update the current value. - /// - /// The handling of build data is subtle. We fetch workspace in two phases: - /// - /// *First*, we run `cargo metadata`, which gives us fast results for - /// initial analysis. - /// - /// *Second*, we run `cargo check` which runs build scripts and compiles - /// proc macros. - /// - /// We need both for the precise analysis, but we want rust-analyzer to be - /// at least partially available just after the first phase. That's because - /// first phase is much faster, and is much less likely to fail. - /// - /// This creates a complication -- by the time the second phase completes, - /// the results of the fist phase could be invalid. That is, while we run - /// `cargo check`, the user edits `Cargo.toml`, we notice this, and the new - /// `cargo metadata` completes before `cargo check`. - /// - /// An additional complication is that we want to avoid needless work. When - /// the user just adds comments or whitespace to Cargo.toml, we do not want - /// to invalidate any salsa caches. - pub(crate) workspaces: Arc>, - pub(crate) fetch_workspaces_queue: OpQueue>>, - pub(crate) fetch_build_data_queue: - OpQueue<(Arc>, Vec>)>, - - pub(crate) prime_caches_queue: OpQueue<()>, -} - -/// An immutable snapshot of the world's state at a point in time. -pub(crate) struct GlobalStateSnapshot { - pub(crate) config: Arc, - pub(crate) analysis: Analysis, - pub(crate) check_fixes: CheckFixes, - mem_docs: MemDocs, - pub(crate) semantic_tokens_cache: Arc>>, - vfs: Arc)>>, - pub(crate) workspaces: Arc>, -} - -impl std::panic::UnwindSafe for GlobalStateSnapshot {} - -impl GlobalState { - pub(crate) fn new(sender: Sender, config: Config) -> GlobalState { - let loader = { - let (sender, receiver) = unbounded::(); - let handle: vfs_notify::NotifyHandle = - vfs::loader::Handle::spawn(Box::new(move |msg| sender.send(msg).unwrap())); - let handle = Box::new(handle) as Box; - Handle { handle, receiver } - }; - - let task_pool = { - let (sender, receiver) = unbounded(); - let handle = TaskPool::new(sender); - Handle { handle, receiver } - }; - - let analysis_host = AnalysisHost::new(config.lru_capacity()); - let (flycheck_sender, flycheck_receiver) = unbounded(); - let mut this = GlobalState { - sender, - req_queue: ReqQueue::default(), - task_pool, - loader, - config: Arc::new(config.clone()), - analysis_host, - diagnostics: Default::default(), - mem_docs: MemDocs::default(), - semantic_tokens_cache: Arc::new(Default::default()), - shutdown_requested: false, - proc_macro_changed: false, - last_reported_status: None, - source_root_config: SourceRootConfig::default(), - proc_macro_clients: vec![], - - flycheck: Vec::new(), - flycheck_sender, - flycheck_receiver, - - vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), - vfs_config_version: 0, - vfs_progress_config_version: 0, - vfs_progress_n_total: 0, - vfs_progress_n_done: 0, - - workspaces: Arc::new(Vec::new()), - fetch_workspaces_queue: OpQueue::default(), - prime_caches_queue: OpQueue::default(), - - fetch_build_data_queue: OpQueue::default(), - }; - // Apply any required database inputs from the config. - this.update_configuration(config); - this - } - - pub(crate) fn process_changes(&mut self) -> bool { - let _p = profile::span("GlobalState::process_changes"); - let mut fs_changes = Vec::new(); - // A file was added or deleted - let mut has_structure_changes = false; - - let (change, changed_files) = { - let mut change = Change::new(); - let (vfs, line_endings_map) = &mut *self.vfs.write(); - let changed_files = vfs.take_changes(); - if changed_files.is_empty() { - return false; - } - - for file in &changed_files { - if let Some(path) = vfs.file_path(file.file_id).as_path() { - let path = path.to_path_buf(); - if reload::should_refresh_for_change(&path, file.change_kind) { - self.fetch_workspaces_queue - .request_op(format!("vfs file change: {}", path.display())); - } - fs_changes.push((path, file.change_kind)); - if file.is_created_or_deleted() { - has_structure_changes = true; - } - } - - if !file.exists() { - self.diagnostics.clear_native_for(file.file_id); - } - - let text = if file.exists() { - let bytes = vfs.file_contents(file.file_id).to_vec(); - String::from_utf8(bytes).ok().and_then(|text| { - let (text, line_endings) = LineEndings::normalize(text); - line_endings_map.insert(file.file_id, line_endings); - Some(Arc::new(text)) - }) - } else { - None - }; - change.change_file(file.file_id, text); - } - if has_structure_changes { - let roots = self.source_root_config.partition(vfs); - change.set_roots(roots); - } - (change, changed_files) - }; - - self.analysis_host.apply_change(change); - - let raw_database = &self.analysis_host.raw_database(); - self.proc_macro_changed = - changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| { - let crates = raw_database.relevant_crates(file.file_id); - let crate_graph = raw_database.crate_graph(); - - crates.iter().any(|&krate| crate_graph[krate].is_proc_macro) - }); - true - } - - pub(crate) fn snapshot(&self) -> GlobalStateSnapshot { - GlobalStateSnapshot { - config: Arc::clone(&self.config), - workspaces: Arc::clone(&self.workspaces), - analysis: self.analysis_host.analysis(), - vfs: Arc::clone(&self.vfs), - check_fixes: Arc::clone(&self.diagnostics.check_fixes), - mem_docs: self.mem_docs.clone(), - semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache), - } - } - - pub(crate) fn send_request( - &mut self, - params: R::Params, - handler: ReqHandler, - ) { - let request = self.req_queue.outgoing.register(R::METHOD.to_string(), params, handler); - self.send(request.into()); - } - - pub(crate) fn complete_request(&mut self, response: lsp_server::Response) { - let handler = self - .req_queue - .outgoing - .complete(response.id.clone()) - .expect("received response for unknown request"); - handler(self, response) - } - - pub(crate) fn send_notification( - &mut self, - params: N::Params, - ) { - let not = lsp_server::Notification::new(N::METHOD.to_string(), params); - self.send(not.into()); - } - - pub(crate) fn register_request( - &mut self, - request: &lsp_server::Request, - request_received: Instant, - ) { - self.req_queue - .incoming - .register(request.id.clone(), (request.method.clone(), request_received)); - } - - pub(crate) fn respond(&mut self, response: lsp_server::Response) { - if let Some((method, start)) = self.req_queue.incoming.complete(response.id.clone()) { - if let Some(err) = &response.error { - if err.message.starts_with("server panicked") { - self.poke_rust_analyzer_developer(format!("{}, check the log", err.message)) - } - } - - let duration = start.elapsed(); - tracing::debug!("handled {} - ({}) in {:0.2?}", method, response.id, duration); - self.send(response.into()); - } - } - - pub(crate) fn cancel(&mut self, request_id: lsp_server::RequestId) { - if let Some(response) = self.req_queue.incoming.cancel(request_id) { - self.send(response.into()); - } - } - - fn send(&mut self, message: lsp_server::Message) { - self.sender.send(message).unwrap() - } -} - -impl Drop for GlobalState { - fn drop(&mut self) { - self.analysis_host.request_cancellation(); - } -} - -impl GlobalStateSnapshot { - pub(crate) fn url_to_file_id(&self, url: &Url) -> Result { - url_to_file_id(&self.vfs.read().0, url) - } - - pub(crate) fn file_id_to_url(&self, id: FileId) -> Url { - file_id_to_url(&self.vfs.read().0, id) - } - - pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancellable { - let endings = self.vfs.read().1[&file_id]; - let index = self.analysis.file_line_index(file_id)?; - let res = LineIndex { index, endings, encoding: self.config.offset_encoding() }; - Ok(res) - } - - pub(crate) fn url_file_version(&self, url: &Url) -> Option { - let path = from_proto::vfs_path(url).ok()?; - Some(self.mem_docs.get(&path)?.version) - } - - pub(crate) fn anchored_path(&self, path: &AnchoredPathBuf) -> Url { - let mut base = self.vfs.read().0.file_path(path.anchor); - base.pop(); - let path = base.join(&path.path).unwrap(); - let path = path.as_path().unwrap(); - url_from_abs_path(path) - } - - pub(crate) fn cargo_target_for_crate_root( - &self, - crate_id: CrateId, - ) -> Option<(&CargoWorkspace, Target)> { - let file_id = self.analysis.crate_root(crate_id).ok()?; - let path = self.vfs.read().0.file_path(file_id); - let path = path.as_path()?; - self.workspaces.iter().find_map(|ws| match ws { - ProjectWorkspace::Cargo { cargo, .. } => { - cargo.target_by_root(path).map(|it| (cargo, it)) - } - ProjectWorkspace::Json { .. } => None, - ProjectWorkspace::DetachedFiles { .. } => None, - }) - } -} - -pub(crate) fn file_id_to_url(vfs: &vfs::Vfs, id: FileId) -> Url { - let path = vfs.file_path(id); - let path = path.as_path().unwrap(); - url_from_abs_path(path) -} - -pub(crate) fn url_to_file_id(vfs: &vfs::Vfs, url: &Url) -> Result { - let path = from_proto::vfs_path(url)?; - let res = vfs.file_id(&path).ok_or_else(|| format!("file not found: {}", path))?; - Ok(res) -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs deleted file mode 100644 index deb777c952fdf..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs +++ /dev/null @@ -1,1892 +0,0 @@ -//! This module is responsible for implementing handlers for Language Server -//! Protocol. The majority of requests are fulfilled by calling into the -//! `ide` crate. - -use std::{ - io::Write as _, - process::{self, Stdio}, -}; - -use anyhow::Context; -use ide::{ - AnnotationConfig, AssistKind, AssistResolveStrategy, FileId, FilePosition, FileRange, - HoverAction, HoverGotoTypeData, Query, RangeInfo, Runnable, RunnableKind, SingleResolve, - SourceChange, TextEdit, -}; -use ide_db::SymbolKind; -use lsp_server::ErrorCode; -use lsp_types::{ - CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, - CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, - CodeLens, CompletionItem, Diagnostic, DiagnosticTag, DocumentFormattingParams, FoldingRange, - FoldingRangeParams, HoverContents, InlayHint, InlayHintParams, Location, LocationLink, - NumberOrString, Position, PrepareRenameResponse, Range, RenameParams, - SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams, - SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, - SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit, -}; -use project_model::{ManifestPath, ProjectWorkspace, TargetKind}; -use serde_json::json; -use stdx::{format_to, never}; -use syntax::{algo, ast, AstNode, TextRange, TextSize, T}; -use vfs::AbsPathBuf; - -use crate::{ - cargo_target_spec::CargoTargetSpec, - config::{RustfmtConfig, WorkspaceSymbolConfig}, - diff::diff, - from_proto, - global_state::{GlobalState, GlobalStateSnapshot}, - line_index::LineEndings, - lsp_ext::{self, PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams}, - lsp_utils::{all_edits_are_disjoint, invalid_params_error}, - to_proto, LspError, Result, -}; - -pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result<()> { - state.proc_macro_clients.clear(); - state.proc_macro_changed = false; - state.fetch_workspaces_queue.request_op("reload workspace request".to_string()); - state.fetch_build_data_queue.request_op("reload workspace request".to_string()); - Ok(()) -} - -pub(crate) fn handle_analyzer_status( - snap: GlobalStateSnapshot, - params: lsp_ext::AnalyzerStatusParams, -) -> Result { - let _p = profile::span("handle_analyzer_status"); - - let mut buf = String::new(); - - let mut file_id = None; - if let Some(tdi) = params.text_document { - match from_proto::file_id(&snap, &tdi.uri) { - Ok(it) => file_id = Some(it), - Err(_) => format_to!(buf, "file {} not found in vfs", tdi.uri), - } - } - - if snap.workspaces.is_empty() { - buf.push_str("No workspaces\n") - } else { - buf.push_str("Workspaces:\n"); - format_to!( - buf, - "Loaded {:?} packages across {} workspace{}.\n", - snap.workspaces.iter().map(|w| w.n_packages()).sum::(), - snap.workspaces.len(), - if snap.workspaces.len() == 1 { "" } else { "s" } - ); - } - buf.push_str("\nAnalysis:\n"); - buf.push_str( - &snap - .analysis - .status(file_id) - .unwrap_or_else(|_| "Analysis retrieval was cancelled".to_owned()), - ); - Ok(buf) -} - -pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> Result { - let _p = profile::span("handle_memory_usage"); - let mut mem = state.analysis_host.per_query_memory_usage(); - mem.push(("Remaining".into(), profile::memory_usage().allocated)); - - let mut out = String::new(); - for (name, bytes) in mem { - format_to!(out, "{:>8} {}\n", bytes, name); - } - Ok(out) -} - -pub(crate) fn handle_shuffle_crate_graph(state: &mut GlobalState, _: ()) -> Result<()> { - state.analysis_host.shuffle_crate_graph(); - Ok(()) -} - -pub(crate) fn handle_syntax_tree( - snap: GlobalStateSnapshot, - params: lsp_ext::SyntaxTreeParams, -) -> Result { - let _p = profile::span("handle_syntax_tree"); - let id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.file_line_index(id)?; - let text_range = params.range.and_then(|r| from_proto::text_range(&line_index, r).ok()); - let res = snap.analysis.syntax_tree(id, text_range)?; - Ok(res) -} - -pub(crate) fn handle_view_hir( - snap: GlobalStateSnapshot, - params: lsp_types::TextDocumentPositionParams, -) -> Result { - let _p = profile::span("handle_view_hir"); - let position = from_proto::file_position(&snap, params)?; - let res = snap.analysis.view_hir(position)?; - Ok(res) -} - -pub(crate) fn handle_view_file_text( - snap: GlobalStateSnapshot, - params: lsp_types::TextDocumentIdentifier, -) -> Result { - let file_id = from_proto::file_id(&snap, ¶ms.uri)?; - Ok(snap.analysis.file_text(file_id)?.to_string()) -} - -pub(crate) fn handle_view_item_tree( - snap: GlobalStateSnapshot, - params: lsp_ext::ViewItemTreeParams, -) -> Result { - let _p = profile::span("handle_view_item_tree"); - let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let res = snap.analysis.view_item_tree(file_id)?; - Ok(res) -} - -pub(crate) fn handle_view_crate_graph( - snap: GlobalStateSnapshot, - params: ViewCrateGraphParams, -) -> Result { - let _p = profile::span("handle_view_crate_graph"); - let dot = snap.analysis.view_crate_graph(params.full)??; - Ok(dot) -} - -pub(crate) fn handle_expand_macro( - snap: GlobalStateSnapshot, - params: lsp_ext::ExpandMacroParams, -) -> Result> { - let _p = profile::span("handle_expand_macro"); - let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.file_line_index(file_id)?; - let offset = from_proto::offset(&line_index, params.position)?; - - let res = snap.analysis.expand_macro(FilePosition { file_id, offset })?; - Ok(res.map(|it| lsp_ext::ExpandedMacro { name: it.name, expansion: it.expansion })) -} - -pub(crate) fn handle_selection_range( - snap: GlobalStateSnapshot, - params: lsp_types::SelectionRangeParams, -) -> Result>> { - let _p = profile::span("handle_selection_range"); - let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.file_line_index(file_id)?; - let res: Result> = params - .positions - .into_iter() - .map(|position| { - let offset = from_proto::offset(&line_index, position)?; - let mut ranges = Vec::new(); - { - let mut range = TextRange::new(offset, offset); - loop { - ranges.push(range); - let frange = FileRange { file_id, range }; - let next = snap.analysis.extend_selection(frange)?; - if next == range { - break; - } else { - range = next - } - } - } - let mut range = lsp_types::SelectionRange { - range: to_proto::range(&line_index, *ranges.last().unwrap()), - parent: None, - }; - for &r in ranges.iter().rev().skip(1) { - range = lsp_types::SelectionRange { - range: to_proto::range(&line_index, r), - parent: Some(Box::new(range)), - } - } - Ok(range) - }) - .collect(); - - Ok(Some(res?)) -} - -pub(crate) fn handle_matching_brace( - snap: GlobalStateSnapshot, - params: lsp_ext::MatchingBraceParams, -) -> Result> { - let _p = profile::span("handle_matching_brace"); - let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.file_line_index(file_id)?; - params - .positions - .into_iter() - .map(|position| { - let offset = from_proto::offset(&line_index, position); - offset.map(|offset| { - let offset = match snap.analysis.matching_brace(FilePosition { file_id, offset }) { - Ok(Some(matching_brace_offset)) => matching_brace_offset, - Err(_) | Ok(None) => offset, - }; - to_proto::position(&line_index, offset) - }) - }) - .collect() -} - -pub(crate) fn handle_join_lines( - snap: GlobalStateSnapshot, - params: lsp_ext::JoinLinesParams, -) -> Result> { - let _p = profile::span("handle_join_lines"); - - let config = snap.config.join_lines(); - let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.file_line_index(file_id)?; - - let mut res = TextEdit::default(); - for range in params.ranges { - let range = from_proto::text_range(&line_index, range)?; - let edit = snap.analysis.join_lines(&config, FileRange { file_id, range })?; - match res.union(edit) { - Ok(()) => (), - Err(_edit) => { - // just ignore overlapping edits - } - } - } - - Ok(to_proto::text_edit_vec(&line_index, res)) -} - -pub(crate) fn handle_on_enter( - snap: GlobalStateSnapshot, - params: lsp_types::TextDocumentPositionParams, -) -> Result>> { - let _p = profile::span("handle_on_enter"); - let position = from_proto::file_position(&snap, params)?; - let edit = match snap.analysis.on_enter(position)? { - None => return Ok(None), - Some(it) => it, - }; - let line_index = snap.file_line_index(position.file_id)?; - let edit = to_proto::snippet_text_edit_vec(&line_index, true, edit); - Ok(Some(edit)) -} - -pub(crate) fn handle_on_type_formatting( - snap: GlobalStateSnapshot, - params: lsp_types::DocumentOnTypeFormattingParams, -) -> Result>> { - let _p = profile::span("handle_on_type_formatting"); - let mut position = from_proto::file_position(&snap, params.text_document_position)?; - let line_index = snap.file_line_index(position.file_id)?; - - // in `ide`, the `on_type` invariant is that - // `text.char_at(position) == typed_char`. - position.offset -= TextSize::of('.'); - let char_typed = params.ch.chars().next().unwrap_or('\0'); - - let text = snap.analysis.file_text(position.file_id)?; - if stdx::never!(!text[usize::from(position.offset)..].starts_with(char_typed)) { - return Ok(None); - } - - // We have an assist that inserts ` ` after typing `->` in `fn foo() ->{`, - // but it requires precise cursor positioning to work, and one can't - // position the cursor with on_type formatting. So, let's just toggle this - // feature off here, hoping that we'll enable it one day, 😿. - if char_typed == '>' { - return Ok(None); - } - - let edit = - snap.analysis.on_char_typed(position, char_typed, snap.config.typing_autoclose_angle())?; - let edit = match edit { - Some(it) => it, - None => return Ok(None), - }; - - // This should be a single-file edit - let (_, text_edit) = edit.source_file_edits.into_iter().next().unwrap(); - - let change = to_proto::snippet_text_edit_vec(&line_index, edit.is_snippet, text_edit); - Ok(Some(change)) -} - -pub(crate) fn handle_document_symbol( - snap: GlobalStateSnapshot, - params: lsp_types::DocumentSymbolParams, -) -> Result> { - let _p = profile::span("handle_document_symbol"); - let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.file_line_index(file_id)?; - - let mut parents: Vec<(lsp_types::DocumentSymbol, Option)> = Vec::new(); - - for symbol in snap.analysis.file_structure(file_id)? { - let mut tags = Vec::new(); - if symbol.deprecated { - tags.push(SymbolTag::DEPRECATED) - }; - - #[allow(deprecated)] - let doc_symbol = lsp_types::DocumentSymbol { - name: symbol.label, - detail: symbol.detail, - kind: to_proto::structure_node_kind(symbol.kind), - tags: Some(tags), - deprecated: Some(symbol.deprecated), - range: to_proto::range(&line_index, symbol.node_range), - selection_range: to_proto::range(&line_index, symbol.navigation_range), - children: None, - }; - parents.push((doc_symbol, symbol.parent)); - } - - // Builds hierarchy from a flat list, in reverse order (so that indices - // makes sense) - let document_symbols = { - let mut acc = Vec::new(); - while let Some((mut node, parent_idx)) = parents.pop() { - if let Some(children) = &mut node.children { - children.reverse(); - } - let parent = match parent_idx { - None => &mut acc, - Some(i) => parents[i].0.children.get_or_insert_with(Vec::new), - }; - parent.push(node); - } - acc.reverse(); - acc - }; - - let res = if snap.config.hierarchical_symbols() { - document_symbols.into() - } else { - let url = to_proto::url(&snap, file_id); - let mut symbol_information = Vec::::new(); - for symbol in document_symbols { - flatten_document_symbol(&symbol, None, &url, &mut symbol_information); - } - symbol_information.into() - }; - return Ok(Some(res)); - - fn flatten_document_symbol( - symbol: &lsp_types::DocumentSymbol, - container_name: Option, - url: &Url, - res: &mut Vec, - ) { - let mut tags = Vec::new(); - - #[allow(deprecated)] - if let Some(true) = symbol.deprecated { - tags.push(SymbolTag::DEPRECATED) - } - - #[allow(deprecated)] - res.push(SymbolInformation { - name: symbol.name.clone(), - kind: symbol.kind, - tags: Some(tags), - deprecated: symbol.deprecated, - location: Location::new(url.clone(), symbol.range), - container_name, - }); - - for child in symbol.children.iter().flatten() { - flatten_document_symbol(child, Some(symbol.name.clone()), url, res); - } - } -} - -pub(crate) fn handle_workspace_symbol( - snap: GlobalStateSnapshot, - params: WorkspaceSymbolParams, -) -> Result>> { - let _p = profile::span("handle_workspace_symbol"); - - let config = snap.config.workspace_symbol(); - let (all_symbols, libs) = decide_search_scope_and_kind(¶ms, &config); - let limit = config.search_limit; - - let query = { - let query: String = params.query.chars().filter(|&c| c != '#' && c != '*').collect(); - let mut q = Query::new(query); - if !all_symbols { - q.only_types(); - } - if libs { - q.libs(); - } - q.limit(limit); - q - }; - let mut res = exec_query(&snap, query)?; - if res.is_empty() && !all_symbols { - let mut query = Query::new(params.query); - query.limit(limit); - res = exec_query(&snap, query)?; - } - - return Ok(Some(res)); - - fn decide_search_scope_and_kind( - params: &WorkspaceSymbolParams, - config: &WorkspaceSymbolConfig, - ) -> (bool, bool) { - // Support old-style parsing of markers in the query. - let mut all_symbols = params.query.contains('#'); - let mut libs = params.query.contains('*'); - - // If no explicit marker was set, check request params. If that's also empty - // use global config. - if !all_symbols { - let search_kind = match params.search_kind { - Some(ref search_kind) => search_kind, - None => &config.search_kind, - }; - all_symbols = match search_kind { - lsp_ext::WorkspaceSymbolSearchKind::OnlyTypes => false, - lsp_ext::WorkspaceSymbolSearchKind::AllSymbols => true, - } - } - - if !libs { - let search_scope = match params.search_scope { - Some(ref search_scope) => search_scope, - None => &config.search_scope, - }; - libs = match search_scope { - lsp_ext::WorkspaceSymbolSearchScope::Workspace => false, - lsp_ext::WorkspaceSymbolSearchScope::WorkspaceAndDependencies => true, - } - } - - (all_symbols, libs) - } - - fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result> { - let mut res = Vec::new(); - for nav in snap.analysis.symbol_search(query)? { - let container_name = nav.container_name.as_ref().map(|v| v.to_string()); - - #[allow(deprecated)] - let info = SymbolInformation { - name: nav.name.to_string(), - kind: nav - .kind - .map(to_proto::symbol_kind) - .unwrap_or(lsp_types::SymbolKind::VARIABLE), - tags: None, - location: to_proto::location_from_nav(snap, nav)?, - container_name, - deprecated: None, - }; - res.push(info); - } - Ok(res) - } -} - -pub(crate) fn handle_will_rename_files( - snap: GlobalStateSnapshot, - params: lsp_types::RenameFilesParams, -) -> Result> { - let _p = profile::span("handle_will_rename_files"); - - let source_changes: Vec = params - .files - .into_iter() - .filter_map(|file_rename| { - let from = Url::parse(&file_rename.old_uri).ok()?; - let to = Url::parse(&file_rename.new_uri).ok()?; - - let from_path = from.to_file_path().ok()?; - let to_path = to.to_file_path().ok()?; - - // Limit to single-level moves for now. - match (from_path.parent(), to_path.parent()) { - (Some(p1), Some(p2)) if p1 == p2 => { - if from_path.is_dir() { - // add '/' to end of url -- from `file://path/to/folder` to `file://path/to/folder/` - let mut old_folder_name = from_path.file_stem()?.to_str()?.to_string(); - old_folder_name.push('/'); - let from_with_trailing_slash = from.join(&old_folder_name).ok()?; - - let imitate_from_url = from_with_trailing_slash.join("mod.rs").ok()?; - let new_file_name = to_path.file_name()?.to_str()?; - Some(( - snap.url_to_file_id(&imitate_from_url).ok()?, - new_file_name.to_string(), - )) - } else { - let old_name = from_path.file_stem()?.to_str()?; - let new_name = to_path.file_stem()?.to_str()?; - match (old_name, new_name) { - ("mod", _) => None, - (_, "mod") => None, - _ => Some((snap.url_to_file_id(&from).ok()?, new_name.to_string())), - } - } - } - _ => None, - } - }) - .filter_map(|(file_id, new_name)| { - snap.analysis.will_rename_file(file_id, &new_name).ok()? - }) - .collect(); - - // Drop file system edits since we're just renaming things on the same level - let mut source_changes = source_changes.into_iter(); - let mut source_change = source_changes.next().unwrap_or_default(); - source_change.file_system_edits.clear(); - // no collect here because we want to merge text edits on same file ids - source_change.extend(source_changes.flat_map(|it| it.source_file_edits)); - if source_change.source_file_edits.is_empty() { - Ok(None) - } else { - to_proto::workspace_edit(&snap, source_change).map(Some) - } -} - -pub(crate) fn handle_goto_definition( - snap: GlobalStateSnapshot, - params: lsp_types::GotoDefinitionParams, -) -> Result> { - let _p = profile::span("handle_goto_definition"); - let position = from_proto::file_position(&snap, params.text_document_position_params)?; - let nav_info = match snap.analysis.goto_definition(position)? { - None => return Ok(None), - Some(it) => it, - }; - let src = FileRange { file_id: position.file_id, range: nav_info.range }; - let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?; - Ok(Some(res)) -} - -pub(crate) fn handle_goto_declaration( - snap: GlobalStateSnapshot, - params: lsp_types::request::GotoDeclarationParams, -) -> Result> { - let _p = profile::span("handle_goto_declaration"); - let position = from_proto::file_position(&snap, params.text_document_position_params.clone())?; - let nav_info = match snap.analysis.goto_declaration(position)? { - None => return handle_goto_definition(snap, params), - Some(it) => it, - }; - let src = FileRange { file_id: position.file_id, range: nav_info.range }; - let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?; - Ok(Some(res)) -} - -pub(crate) fn handle_goto_implementation( - snap: GlobalStateSnapshot, - params: lsp_types::request::GotoImplementationParams, -) -> Result> { - let _p = profile::span("handle_goto_implementation"); - let position = from_proto::file_position(&snap, params.text_document_position_params)?; - let nav_info = match snap.analysis.goto_implementation(position)? { - None => return Ok(None), - Some(it) => it, - }; - let src = FileRange { file_id: position.file_id, range: nav_info.range }; - let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?; - Ok(Some(res)) -} - -pub(crate) fn handle_goto_type_definition( - snap: GlobalStateSnapshot, - params: lsp_types::request::GotoTypeDefinitionParams, -) -> Result> { - let _p = profile::span("handle_goto_type_definition"); - let position = from_proto::file_position(&snap, params.text_document_position_params)?; - let nav_info = match snap.analysis.goto_type_definition(position)? { - None => return Ok(None), - Some(it) => it, - }; - let src = FileRange { file_id: position.file_id, range: nav_info.range }; - let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?; - Ok(Some(res)) -} - -pub(crate) fn handle_parent_module( - snap: GlobalStateSnapshot, - params: lsp_types::TextDocumentPositionParams, -) -> Result> { - let _p = profile::span("handle_parent_module"); - if let Ok(file_path) = ¶ms.text_document.uri.to_file_path() { - if file_path.file_name().unwrap_or_default() == "Cargo.toml" { - // search workspaces for parent packages or fallback to workspace root - let abs_path_buf = match AbsPathBuf::try_from(file_path.to_path_buf()).ok() { - Some(abs_path_buf) => abs_path_buf, - None => return Ok(None), - }; - - let manifest_path = match ManifestPath::try_from(abs_path_buf).ok() { - Some(manifest_path) => manifest_path, - None => return Ok(None), - }; - - let links: Vec = snap - .workspaces - .iter() - .filter_map(|ws| match ws { - ProjectWorkspace::Cargo { cargo, .. } => cargo.parent_manifests(&manifest_path), - _ => None, - }) - .flatten() - .map(|parent_manifest_path| LocationLink { - origin_selection_range: None, - target_uri: to_proto::url_from_abs_path(&parent_manifest_path), - target_range: Range::default(), - target_selection_range: Range::default(), - }) - .collect::<_>(); - return Ok(Some(links.into())); - } - - // check if invoked at the crate root - let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let crate_id = match snap.analysis.crate_for(file_id)?.first() { - Some(&crate_id) => crate_id, - None => return Ok(None), - }; - let cargo_spec = match CargoTargetSpec::for_file(&snap, file_id)? { - Some(it) => it, - None => return Ok(None), - }; - - if snap.analysis.crate_root(crate_id)? == file_id { - let cargo_toml_url = to_proto::url_from_abs_path(&cargo_spec.cargo_toml); - let res = vec![LocationLink { - origin_selection_range: None, - target_uri: cargo_toml_url, - target_range: Range::default(), - target_selection_range: Range::default(), - }] - .into(); - return Ok(Some(res)); - } - } - - // locate parent module by semantics - let position = from_proto::file_position(&snap, params)?; - let navs = snap.analysis.parent_module(position)?; - let res = to_proto::goto_definition_response(&snap, None, navs)?; - Ok(Some(res)) -} - -pub(crate) fn handle_runnables( - snap: GlobalStateSnapshot, - params: lsp_ext::RunnablesParams, -) -> Result> { - let _p = profile::span("handle_runnables"); - let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.file_line_index(file_id)?; - let offset = params.position.and_then(|it| from_proto::offset(&line_index, it).ok()); - let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?; - - let expect_test = match offset { - Some(offset) => { - let source_file = snap.analysis.parse(file_id)?; - algo::find_node_at_offset::(source_file.syntax(), offset) - .and_then(|it| it.path()?.segment()?.name_ref()) - .map_or(false, |it| it.text() == "expect" || it.text() == "expect_file") - } - None => false, - }; - - let mut res = Vec::new(); - for runnable in snap.analysis.runnables(file_id)? { - if let Some(offset) = offset { - if !runnable.nav.full_range.contains_inclusive(offset) { - continue; - } - } - if should_skip_target(&runnable, cargo_spec.as_ref()) { - continue; - } - let mut runnable = to_proto::runnable(&snap, runnable)?; - if expect_test { - runnable.label = format!("{} + expect", runnable.label); - runnable.args.expect_test = Some(true); - } - res.push(runnable); - } - - // Add `cargo check` and `cargo test` for all targets of the whole package - let config = snap.config.runnables(); - match cargo_spec { - Some(spec) => { - for cmd in ["check", "test"] { - res.push(lsp_ext::Runnable { - label: format!("cargo {} -p {} --all-targets", cmd, spec.package), - location: None, - kind: lsp_ext::RunnableKind::Cargo, - args: lsp_ext::CargoRunnable { - workspace_root: Some(spec.workspace_root.clone().into()), - override_cargo: config.override_cargo.clone(), - cargo_args: vec![ - cmd.to_string(), - "--package".to_string(), - spec.package.clone(), - "--all-targets".to_string(), - ], - cargo_extra_args: config.cargo_extra_args.clone(), - executable_args: Vec::new(), - expect_test: None, - }, - }) - } - } - None => { - if !snap.config.linked_projects().is_empty() - || !snap - .config - .discovered_projects - .as_ref() - .map(|projects| projects.is_empty()) - .unwrap_or(true) - { - res.push(lsp_ext::Runnable { - label: "cargo check --workspace".to_string(), - location: None, - kind: lsp_ext::RunnableKind::Cargo, - args: lsp_ext::CargoRunnable { - workspace_root: None, - override_cargo: config.override_cargo, - cargo_args: vec!["check".to_string(), "--workspace".to_string()], - cargo_extra_args: config.cargo_extra_args, - executable_args: Vec::new(), - expect_test: None, - }, - }); - } - } - } - Ok(res) -} - -pub(crate) fn handle_related_tests( - snap: GlobalStateSnapshot, - params: lsp_types::TextDocumentPositionParams, -) -> Result> { - let _p = profile::span("handle_related_tests"); - let position = from_proto::file_position(&snap, params)?; - - let tests = snap.analysis.related_tests(position, None)?; - let mut res = Vec::new(); - for it in tests { - if let Ok(runnable) = to_proto::runnable(&snap, it) { - res.push(lsp_ext::TestInfo { runnable }) - } - } - - Ok(res) -} - -pub(crate) fn handle_completion( - snap: GlobalStateSnapshot, - params: lsp_types::CompletionParams, -) -> Result> { - let _p = profile::span("handle_completion"); - let text_document_position = params.text_document_position.clone(); - let position = from_proto::file_position(&snap, params.text_document_position)?; - let completion_trigger_character = - params.context.and_then(|ctx| ctx.trigger_character).and_then(|s| s.chars().next()); - - if Some(':') == completion_trigger_character { - let source_file = snap.analysis.parse(position.file_id)?; - let left_token = source_file.syntax().token_at_offset(position.offset).left_biased(); - let completion_triggered_after_single_colon = match left_token { - Some(left_token) => left_token.kind() == T![:], - None => true, - }; - if completion_triggered_after_single_colon { - return Ok(None); - } - } - - let completion_config = &snap.config.completion(); - let items = match snap.analysis.completions( - completion_config, - position, - completion_trigger_character, - )? { - None => return Ok(None), - Some(items) => items, - }; - let line_index = snap.file_line_index(position.file_id)?; - - let items = - to_proto::completion_items(&snap.config, &line_index, text_document_position, items); - - let completion_list = lsp_types::CompletionList { is_incomplete: true, items }; - Ok(Some(completion_list.into())) -} - -pub(crate) fn handle_completion_resolve( - snap: GlobalStateSnapshot, - mut original_completion: CompletionItem, -) -> Result { - let _p = profile::span("handle_completion_resolve"); - - if !all_edits_are_disjoint(&original_completion, &[]) { - return Err(invalid_params_error( - "Received a completion with overlapping edits, this is not LSP-compliant".to_string(), - ) - .into()); - } - - let data = match original_completion.data.take() { - Some(it) => it, - None => return Ok(original_completion), - }; - - let resolve_data: lsp_ext::CompletionResolveData = serde_json::from_value(data)?; - - let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?; - let line_index = snap.file_line_index(file_id)?; - let offset = from_proto::offset(&line_index, resolve_data.position.position)?; - - let additional_edits = snap - .analysis - .resolve_completion_edits( - &snap.config.completion(), - FilePosition { file_id, offset }, - resolve_data - .imports - .into_iter() - .map(|import| (import.full_import_path, import.imported_name)), - )? - .into_iter() - .flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel))) - .collect::>(); - - if !all_edits_are_disjoint(&original_completion, &additional_edits) { - return Err(LspError::new( - ErrorCode::InternalError as i32, - "Import edit overlaps with the original completion edits, this is not LSP-compliant" - .into(), - ) - .into()); - } - - if let Some(original_additional_edits) = original_completion.additional_text_edits.as_mut() { - original_additional_edits.extend(additional_edits.into_iter()) - } else { - original_completion.additional_text_edits = Some(additional_edits); - } - - Ok(original_completion) -} - -pub(crate) fn handle_folding_range( - snap: GlobalStateSnapshot, - params: FoldingRangeParams, -) -> Result>> { - let _p = profile::span("handle_folding_range"); - let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let folds = snap.analysis.folding_ranges(file_id)?; - let text = snap.analysis.file_text(file_id)?; - let line_index = snap.file_line_index(file_id)?; - let line_folding_only = snap.config.line_folding_only(); - let res = folds - .into_iter() - .map(|it| to_proto::folding_range(&*text, &line_index, line_folding_only, it)) - .collect(); - Ok(Some(res)) -} - -pub(crate) fn handle_signature_help( - snap: GlobalStateSnapshot, - params: lsp_types::SignatureHelpParams, -) -> Result> { - let _p = profile::span("handle_signature_help"); - let position = from_proto::file_position(&snap, params.text_document_position_params)?; - let help = match snap.analysis.signature_help(position)? { - Some(it) => it, - None => return Ok(None), - }; - let config = snap.config.call_info(); - let res = to_proto::signature_help(help, config, snap.config.signature_help_label_offsets()); - Ok(Some(res)) -} - -pub(crate) fn handle_hover( - snap: GlobalStateSnapshot, - params: lsp_ext::HoverParams, -) -> Result> { - let _p = profile::span("handle_hover"); - let range = match params.position { - PositionOrRange::Position(position) => Range::new(position, position), - PositionOrRange::Range(range) => range, - }; - - let file_range = from_proto::file_range(&snap, params.text_document, range)?; - let info = match snap.analysis.hover(&snap.config.hover(), file_range)? { - None => return Ok(None), - Some(info) => info, - }; - - let line_index = snap.file_line_index(file_range.file_id)?; - let range = to_proto::range(&line_index, info.range); - let markup_kind = - snap.config.hover().documentation.map_or(ide::HoverDocFormat::Markdown, |kind| kind); - let hover = lsp_ext::Hover { - hover: lsp_types::Hover { - contents: HoverContents::Markup(to_proto::markup_content( - info.info.markup, - markup_kind, - )), - range: Some(range), - }, - actions: if snap.config.hover_actions().none() { - Vec::new() - } else { - prepare_hover_actions(&snap, &info.info.actions) - }, - }; - - Ok(Some(hover)) -} - -pub(crate) fn handle_prepare_rename( - snap: GlobalStateSnapshot, - params: lsp_types::TextDocumentPositionParams, -) -> Result> { - let _p = profile::span("handle_prepare_rename"); - let position = from_proto::file_position(&snap, params)?; - - let change = snap.analysis.prepare_rename(position)?.map_err(to_proto::rename_error)?; - - let line_index = snap.file_line_index(position.file_id)?; - let range = to_proto::range(&line_index, change.range); - Ok(Some(PrepareRenameResponse::Range(range))) -} - -pub(crate) fn handle_rename( - snap: GlobalStateSnapshot, - params: RenameParams, -) -> Result> { - let _p = profile::span("handle_rename"); - let position = from_proto::file_position(&snap, params.text_document_position)?; - - let mut change = - snap.analysis.rename(position, &*params.new_name)?.map_err(to_proto::rename_error)?; - - // this is kind of a hack to prevent double edits from happening when moving files - // When a module gets renamed by renaming the mod declaration this causes the file to move - // which in turn will trigger a WillRenameFiles request to the server for which we reply with a - // a second identical set of renames, the client will then apply both edits causing incorrect edits - // with this we only emit source_file_edits in the WillRenameFiles response which will do the rename instead - // See https://github.com/microsoft/vscode-languageserver-node/issues/752 for more info - if !change.file_system_edits.is_empty() && snap.config.will_rename() { - change.source_file_edits.clear(); - } - let workspace_edit = to_proto::workspace_edit(&snap, change)?; - Ok(Some(workspace_edit)) -} - -pub(crate) fn handle_references( - snap: GlobalStateSnapshot, - params: lsp_types::ReferenceParams, -) -> Result>> { - let _p = profile::span("handle_references"); - let position = from_proto::file_position(&snap, params.text_document_position)?; - - let refs = match snap.analysis.find_all_refs(position, None)? { - None => return Ok(None), - Some(refs) => refs, - }; - - let include_declaration = params.context.include_declaration; - let locations = refs - .into_iter() - .flat_map(|refs| { - let decl = if include_declaration { - refs.declaration.map(|decl| FileRange { - file_id: decl.nav.file_id, - range: decl.nav.focus_or_full_range(), - }) - } else { - None - }; - refs.references - .into_iter() - .flat_map(|(file_id, refs)| { - refs.into_iter().map(move |(range, _)| FileRange { file_id, range }) - }) - .chain(decl) - }) - .filter_map(|frange| to_proto::location(&snap, frange).ok()) - .collect(); - - Ok(Some(locations)) -} - -pub(crate) fn handle_formatting( - snap: GlobalStateSnapshot, - params: DocumentFormattingParams, -) -> Result>> { - let _p = profile::span("handle_formatting"); - - run_rustfmt(&snap, params.text_document, None) -} - -pub(crate) fn handle_range_formatting( - snap: GlobalStateSnapshot, - params: lsp_types::DocumentRangeFormattingParams, -) -> Result>> { - let _p = profile::span("handle_range_formatting"); - - run_rustfmt(&snap, params.text_document, Some(params.range)) -} - -pub(crate) fn handle_code_action( - snap: GlobalStateSnapshot, - params: lsp_types::CodeActionParams, -) -> Result>> { - let _p = profile::span("handle_code_action"); - - if !snap.config.code_action_literals() { - // We intentionally don't support command-based actions, as those either - // require either custom client-code or server-initiated edits. Server - // initiated edits break causality, so we avoid those. - return Ok(None); - } - - let line_index = - snap.file_line_index(from_proto::file_id(&snap, ¶ms.text_document.uri)?)?; - let frange = from_proto::file_range(&snap, params.text_document.clone(), params.range)?; - - let mut assists_config = snap.config.assist(); - assists_config.allowed = params - .context - .only - .clone() - .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); - - let mut res: Vec = Vec::new(); - - let code_action_resolve_cap = snap.config.code_action_resolve(); - let resolve = if code_action_resolve_cap { - AssistResolveStrategy::None - } else { - AssistResolveStrategy::All - }; - let assists = snap.analysis.assists_with_fixes( - &assists_config, - &snap.config.diagnostics(), - resolve, - frange, - )?; - for (index, assist) in assists.into_iter().enumerate() { - let resolve_data = - if code_action_resolve_cap { Some((index, params.clone())) } else { None }; - let code_action = to_proto::code_action(&snap, assist, resolve_data)?; - res.push(code_action) - } - - // Fixes from `cargo check`. - for fix in snap.check_fixes.get(&frange.file_id).into_iter().flatten() { - // FIXME: this mapping is awkward and shouldn't exist. Refactor - // `snap.check_fixes` to not convert to LSP prematurely. - let intersect_fix_range = fix - .ranges - .iter() - .copied() - .filter_map(|range| from_proto::text_range(&line_index, range).ok()) - .any(|fix_range| fix_range.intersect(frange.range).is_some()); - if intersect_fix_range { - res.push(fix.action.clone()); - } - } - - Ok(Some(res)) -} - -pub(crate) fn handle_code_action_resolve( - snap: GlobalStateSnapshot, - mut code_action: lsp_ext::CodeAction, -) -> Result { - let _p = profile::span("handle_code_action_resolve"); - let params = match code_action.data.take() { - Some(it) => it, - None => return Err(invalid_params_error("code action without data".to_string()).into()), - }; - - let file_id = from_proto::file_id(&snap, ¶ms.code_action_params.text_document.uri)?; - let line_index = snap.file_line_index(file_id)?; - let range = from_proto::text_range(&line_index, params.code_action_params.range)?; - let frange = FileRange { file_id, range }; - - let mut assists_config = snap.config.assist(); - assists_config.allowed = params - .code_action_params - .context - .only - .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); - - let (assist_index, assist_resolve) = match parse_action_id(¶ms.id) { - Ok(parsed_data) => parsed_data, - Err(e) => { - return Err(invalid_params_error(format!( - "Failed to parse action id string '{}': {}", - params.id, e - )) - .into()) - } - }; - - let expected_assist_id = assist_resolve.assist_id.clone(); - let expected_kind = assist_resolve.assist_kind; - - let assists = snap.analysis.assists_with_fixes( - &assists_config, - &snap.config.diagnostics(), - AssistResolveStrategy::Single(assist_resolve), - frange, - )?; - - let assist = match assists.get(assist_index) { - Some(assist) => assist, - None => return Err(invalid_params_error(format!( - "Failed to find the assist for index {} provided by the resolve request. Resolve request assist id: {}", - assist_index, params.id, - )) - .into()) - }; - if assist.id.0 != expected_assist_id || assist.id.1 != expected_kind { - return Err(invalid_params_error(format!( - "Mismatching assist at index {} for the resolve parameters given. Resolve request assist id: {}, actual id: {:?}.", - assist_index, params.id, assist.id - )) - .into()); - } - let ca = to_proto::code_action(&snap, assist.clone(), None)?; - code_action.edit = ca.edit; - code_action.command = ca.command; - Ok(code_action) -} - -fn parse_action_id(action_id: &str) -> Result<(usize, SingleResolve), String> { - let id_parts = action_id.split(':').collect::>(); - match id_parts.as_slice() { - [assist_id_string, assist_kind_string, index_string] => { - let assist_kind: AssistKind = assist_kind_string.parse()?; - let index: usize = match index_string.parse() { - Ok(index) => index, - Err(e) => return Err(format!("Incorrect index string: {}", e)), - }; - Ok((index, SingleResolve { assist_id: assist_id_string.to_string(), assist_kind })) - } - _ => Err("Action id contains incorrect number of segments".to_string()), - } -} - -pub(crate) fn handle_code_lens( - snap: GlobalStateSnapshot, - params: lsp_types::CodeLensParams, -) -> Result>> { - let _p = profile::span("handle_code_lens"); - - let lens_config = snap.config.lens(); - if lens_config.none() { - // early return before any db query! - return Ok(Some(Vec::default())); - } - - let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let cargo_target_spec = CargoTargetSpec::for_file(&snap, file_id)?; - - let annotations = snap.analysis.annotations( - &AnnotationConfig { - binary_target: cargo_target_spec - .map(|spec| { - matches!( - spec.target_kind, - TargetKind::Bin | TargetKind::Example | TargetKind::Test - ) - }) - .unwrap_or(false), - annotate_runnables: lens_config.runnable(), - annotate_impls: lens_config.implementations, - annotate_references: lens_config.refs_adt, - annotate_method_references: lens_config.method_refs, - annotate_enum_variant_references: lens_config.enum_variant_refs, - }, - file_id, - )?; - - let mut res = Vec::new(); - for a in annotations { - to_proto::code_lens(&mut res, &snap, a)?; - } - - Ok(Some(res)) -} - -pub(crate) fn handle_code_lens_resolve( - snap: GlobalStateSnapshot, - code_lens: CodeLens, -) -> Result { - let annotation = from_proto::annotation(&snap, code_lens.clone())?; - let annotation = snap.analysis.resolve_annotation(annotation)?; - - let mut acc = Vec::new(); - to_proto::code_lens(&mut acc, &snap, annotation)?; - - let res = match acc.pop() { - Some(it) if acc.is_empty() => it, - _ => { - never!(); - code_lens - } - }; - - Ok(res) -} - -pub(crate) fn handle_document_highlight( - snap: GlobalStateSnapshot, - params: lsp_types::DocumentHighlightParams, -) -> Result>> { - let _p = profile::span("handle_document_highlight"); - let position = from_proto::file_position(&snap, params.text_document_position_params)?; - let line_index = snap.file_line_index(position.file_id)?; - - let refs = match snap.analysis.highlight_related(snap.config.highlight_related(), position)? { - None => return Ok(None), - Some(refs) => refs, - }; - let res = refs - .into_iter() - .map(|ide::HighlightedRange { range, category }| lsp_types::DocumentHighlight { - range: to_proto::range(&line_index, range), - kind: category.map(to_proto::document_highlight_kind), - }) - .collect(); - Ok(Some(res)) -} - -pub(crate) fn handle_ssr( - snap: GlobalStateSnapshot, - params: lsp_ext::SsrParams, -) -> Result { - let _p = profile::span("handle_ssr"); - let selections = params - .selections - .iter() - .map(|range| from_proto::file_range(&snap, params.position.text_document.clone(), *range)) - .collect::, _>>()?; - let position = from_proto::file_position(&snap, params.position)?; - let source_change = snap.analysis.structural_search_replace( - ¶ms.query, - params.parse_only, - position, - selections, - )??; - to_proto::workspace_edit(&snap, source_change) -} - -pub(crate) fn publish_diagnostics( - snap: &GlobalStateSnapshot, - file_id: FileId, -) -> Result> { - let _p = profile::span("publish_diagnostics"); - let line_index = snap.file_line_index(file_id)?; - - let diagnostics: Vec = snap - .analysis - .diagnostics(&snap.config.diagnostics(), AssistResolveStrategy::None, file_id)? - .into_iter() - .map(|d| Diagnostic { - range: to_proto::range(&line_index, d.range), - severity: Some(to_proto::diagnostic_severity(d.severity)), - code: Some(NumberOrString::String(d.code.as_str().to_string())), - code_description: Some(lsp_types::CodeDescription { - href: lsp_types::Url::parse(&format!( - "https://rust-analyzer.github.io/manual.html#{}", - d.code.as_str() - )) - .unwrap(), - }), - source: Some("rust-analyzer".to_string()), - // https://github.com/rust-lang/rust-analyzer/issues/11404 - message: if !d.message.is_empty() { d.message } else { " ".to_string() }, - related_information: None, - tags: if d.unused { Some(vec![DiagnosticTag::UNNECESSARY]) } else { None }, - data: None, - }) - .collect(); - Ok(diagnostics) -} - -pub(crate) fn handle_inlay_hints( - snap: GlobalStateSnapshot, - params: InlayHintParams, -) -> Result>> { - let _p = profile::span("handle_inlay_hints"); - let document_uri = ¶ms.text_document.uri; - let file_id = from_proto::file_id(&snap, document_uri)?; - let line_index = snap.file_line_index(file_id)?; - let range = from_proto::file_range( - &snap, - TextDocumentIdentifier::new(document_uri.to_owned()), - params.range, - )?; - let inlay_hints_config = snap.config.inlay_hints(); - Ok(Some( - snap.analysis - .inlay_hints(&inlay_hints_config, file_id, Some(range))? - .into_iter() - .map(|it| { - to_proto::inlay_hint(&snap, &line_index, inlay_hints_config.render_colons, it) - }) - .collect(), - )) -} - -pub(crate) fn handle_inlay_hints_resolve( - snap: GlobalStateSnapshot, - mut hint: InlayHint, -) -> Result { - let _p = profile::span("handle_inlay_hints_resolve"); - let data = match hint.data.take() { - Some(it) => it, - None => return Ok(hint), - }; - - let resolve_data: lsp_ext::InlayHintResolveData = serde_json::from_value(data)?; - - let file_range = from_proto::file_range( - &snap, - resolve_data.text_document, - match resolve_data.position { - PositionOrRange::Position(pos) => Range::new(pos, pos), - PositionOrRange::Range(range) => range, - }, - )?; - let info = match snap.analysis.hover(&snap.config.hover(), file_range)? { - None => return Ok(hint), - Some(info) => info, - }; - - let markup_kind = - snap.config.hover().documentation.map_or(ide::HoverDocFormat::Markdown, |kind| kind); - - // FIXME: hover actions? - hint.tooltip = Some(lsp_types::InlayHintTooltip::MarkupContent(to_proto::markup_content( - info.info.markup, - markup_kind, - ))); - Ok(hint) -} - -pub(crate) fn handle_call_hierarchy_prepare( - snap: GlobalStateSnapshot, - params: CallHierarchyPrepareParams, -) -> Result>> { - let _p = profile::span("handle_call_hierarchy_prepare"); - let position = from_proto::file_position(&snap, params.text_document_position_params)?; - - let nav_info = match snap.analysis.call_hierarchy(position)? { - None => return Ok(None), - Some(it) => it, - }; - - let RangeInfo { range: _, info: navs } = nav_info; - let res = navs - .into_iter() - .filter(|it| it.kind == Some(SymbolKind::Function)) - .map(|it| to_proto::call_hierarchy_item(&snap, it)) - .collect::>>()?; - - Ok(Some(res)) -} - -pub(crate) fn handle_call_hierarchy_incoming( - snap: GlobalStateSnapshot, - params: CallHierarchyIncomingCallsParams, -) -> Result>> { - let _p = profile::span("handle_call_hierarchy_incoming"); - let item = params.item; - - let doc = TextDocumentIdentifier::new(item.uri); - let frange = from_proto::file_range(&snap, doc, item.selection_range)?; - let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; - - let call_items = match snap.analysis.incoming_calls(fpos)? { - None => return Ok(None), - Some(it) => it, - }; - - let mut res = vec![]; - - for call_item in call_items.into_iter() { - let file_id = call_item.target.file_id; - let line_index = snap.file_line_index(file_id)?; - let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; - res.push(CallHierarchyIncomingCall { - from: item, - from_ranges: call_item - .ranges - .into_iter() - .map(|it| to_proto::range(&line_index, it)) - .collect(), - }); - } - - Ok(Some(res)) -} - -pub(crate) fn handle_call_hierarchy_outgoing( - snap: GlobalStateSnapshot, - params: CallHierarchyOutgoingCallsParams, -) -> Result>> { - let _p = profile::span("handle_call_hierarchy_outgoing"); - let item = params.item; - - let doc = TextDocumentIdentifier::new(item.uri); - let frange = from_proto::file_range(&snap, doc, item.selection_range)?; - let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; - - let call_items = match snap.analysis.outgoing_calls(fpos)? { - None => return Ok(None), - Some(it) => it, - }; - - let mut res = vec![]; - - for call_item in call_items.into_iter() { - let file_id = call_item.target.file_id; - let line_index = snap.file_line_index(file_id)?; - let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; - res.push(CallHierarchyOutgoingCall { - to: item, - from_ranges: call_item - .ranges - .into_iter() - .map(|it| to_proto::range(&line_index, it)) - .collect(), - }); - } - - Ok(Some(res)) -} - -pub(crate) fn handle_semantic_tokens_full( - snap: GlobalStateSnapshot, - params: SemanticTokensParams, -) -> Result> { - let _p = profile::span("handle_semantic_tokens_full"); - - let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let text = snap.analysis.file_text(file_id)?; - let line_index = snap.file_line_index(file_id)?; - - let highlights = snap.analysis.highlight(file_id)?; - let highlight_strings = snap.config.highlighting_strings(); - let semantic_tokens = - to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings); - - // Unconditionally cache the tokens - snap.semantic_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens.clone()); - - Ok(Some(semantic_tokens.into())) -} - -pub(crate) fn handle_semantic_tokens_full_delta( - snap: GlobalStateSnapshot, - params: SemanticTokensDeltaParams, -) -> Result> { - let _p = profile::span("handle_semantic_tokens_full_delta"); - - let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let text = snap.analysis.file_text(file_id)?; - let line_index = snap.file_line_index(file_id)?; - - let highlights = snap.analysis.highlight(file_id)?; - let highlight_strings = snap.config.highlighting_strings(); - let semantic_tokens = - to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings); - - let mut cache = snap.semantic_tokens_cache.lock(); - let cached_tokens = cache.entry(params.text_document.uri).or_default(); - - if let Some(prev_id) = &cached_tokens.result_id { - if *prev_id == params.previous_result_id { - let delta = to_proto::semantic_token_delta(cached_tokens, &semantic_tokens); - *cached_tokens = semantic_tokens; - return Ok(Some(delta.into())); - } - } - - *cached_tokens = semantic_tokens.clone(); - - Ok(Some(semantic_tokens.into())) -} - -pub(crate) fn handle_semantic_tokens_range( - snap: GlobalStateSnapshot, - params: SemanticTokensRangeParams, -) -> Result> { - let _p = profile::span("handle_semantic_tokens_range"); - - let frange = from_proto::file_range(&snap, params.text_document, params.range)?; - let text = snap.analysis.file_text(frange.file_id)?; - let line_index = snap.file_line_index(frange.file_id)?; - - let highlights = snap.analysis.highlight_range(frange)?; - let highlight_strings = snap.config.highlighting_strings(); - let semantic_tokens = - to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings); - Ok(Some(semantic_tokens.into())) -} - -pub(crate) fn handle_open_docs( - snap: GlobalStateSnapshot, - params: lsp_types::TextDocumentPositionParams, -) -> Result> { - let _p = profile::span("handle_open_docs"); - let position = from_proto::file_position(&snap, params)?; - - let remote = snap.analysis.external_docs(position)?; - - Ok(remote.and_then(|remote| Url::parse(&remote).ok())) -} - -pub(crate) fn handle_open_cargo_toml( - snap: GlobalStateSnapshot, - params: lsp_ext::OpenCargoTomlParams, -) -> Result> { - let _p = profile::span("handle_open_cargo_toml"); - let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - - let cargo_spec = match CargoTargetSpec::for_file(&snap, file_id)? { - Some(it) => it, - None => return Ok(None), - }; - - let cargo_toml_url = to_proto::url_from_abs_path(&cargo_spec.cargo_toml); - let res: lsp_types::GotoDefinitionResponse = - Location::new(cargo_toml_url, Range::default()).into(); - Ok(Some(res)) -} - -pub(crate) fn handle_move_item( - snap: GlobalStateSnapshot, - params: lsp_ext::MoveItemParams, -) -> Result> { - let _p = profile::span("handle_move_item"); - let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let range = from_proto::file_range(&snap, params.text_document, params.range)?; - - let direction = match params.direction { - lsp_ext::MoveItemDirection::Up => ide::Direction::Up, - lsp_ext::MoveItemDirection::Down => ide::Direction::Down, - }; - - match snap.analysis.move_item(range, direction)? { - Some(text_edit) => { - let line_index = snap.file_line_index(file_id)?; - Ok(to_proto::snippet_text_edit_vec(&line_index, true, text_edit)) - } - None => Ok(vec![]), - } -} - -fn to_command_link(command: lsp_types::Command, tooltip: String) -> lsp_ext::CommandLink { - lsp_ext::CommandLink { tooltip: Some(tooltip), command } -} - -fn show_impl_command_link( - snap: &GlobalStateSnapshot, - position: &FilePosition, -) -> Option { - if snap.config.hover_actions().implementations && snap.config.client_commands().show_reference { - if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) { - let uri = to_proto::url(snap, position.file_id); - let line_index = snap.file_line_index(position.file_id).ok()?; - let position = to_proto::position(&line_index, position.offset); - let locations: Vec<_> = nav_data - .info - .into_iter() - .filter_map(|nav| to_proto::location_from_nav(snap, nav).ok()) - .collect(); - let title = to_proto::implementation_title(locations.len()); - let command = to_proto::command::show_references(title, &uri, position, locations); - - return Some(lsp_ext::CommandLinkGroup { - commands: vec![to_command_link(command, "Go to implementations".into())], - ..Default::default() - }); - } - } - None -} - -fn show_ref_command_link( - snap: &GlobalStateSnapshot, - position: &FilePosition, -) -> Option { - if snap.config.hover_actions().references && snap.config.client_commands().show_reference { - if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) { - let uri = to_proto::url(snap, position.file_id); - let line_index = snap.file_line_index(position.file_id).ok()?; - let position = to_proto::position(&line_index, position.offset); - let locations: Vec<_> = ref_search_res - .into_iter() - .flat_map(|res| res.references) - .flat_map(|(file_id, ranges)| { - ranges.into_iter().filter_map(move |(range, _)| { - to_proto::location(snap, FileRange { file_id, range }).ok() - }) - }) - .collect(); - let title = to_proto::reference_title(locations.len()); - let command = to_proto::command::show_references(title, &uri, position, locations); - - return Some(lsp_ext::CommandLinkGroup { - commands: vec![to_command_link(command, "Go to references".into())], - ..Default::default() - }); - } - } - None -} - -fn runnable_action_links( - snap: &GlobalStateSnapshot, - runnable: Runnable, -) -> Option { - let hover_actions_config = snap.config.hover_actions(); - if !hover_actions_config.runnable() { - return None; - } - - let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?; - if should_skip_target(&runnable, cargo_spec.as_ref()) { - return None; - } - - let client_commands_config = snap.config.client_commands(); - if !(client_commands_config.run_single || client_commands_config.debug_single) { - return None; - } - - let title = runnable.title(); - let r = to_proto::runnable(snap, runnable).ok()?; - - let mut group = lsp_ext::CommandLinkGroup::default(); - - if hover_actions_config.run && client_commands_config.run_single { - let run_command = to_proto::command::run_single(&r, &title); - group.commands.push(to_command_link(run_command, r.label.clone())); - } - - if hover_actions_config.debug && client_commands_config.debug_single { - let dbg_command = to_proto::command::debug_single(&r); - group.commands.push(to_command_link(dbg_command, r.label)); - } - - Some(group) -} - -fn goto_type_action_links( - snap: &GlobalStateSnapshot, - nav_targets: &[HoverGotoTypeData], -) -> Option { - if !snap.config.hover_actions().goto_type_def - || nav_targets.is_empty() - || !snap.config.client_commands().goto_location - { - return None; - } - - Some(lsp_ext::CommandLinkGroup { - title: Some("Go to ".into()), - commands: nav_targets - .iter() - .filter_map(|it| { - to_proto::command::goto_location(snap, &it.nav) - .map(|cmd| to_command_link(cmd, it.mod_path.clone())) - }) - .collect(), - }) -} - -fn prepare_hover_actions( - snap: &GlobalStateSnapshot, - actions: &[HoverAction], -) -> Vec { - actions - .iter() - .filter_map(|it| match it { - HoverAction::Implementation(position) => show_impl_command_link(snap, position), - HoverAction::Reference(position) => show_ref_command_link(snap, position), - HoverAction::Runnable(r) => runnable_action_links(snap, r.clone()), - HoverAction::GoToType(targets) => goto_type_action_links(snap, targets), - }) - .collect() -} - -fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>) -> bool { - match runnable.kind { - RunnableKind::Bin => { - // Do not suggest binary run on other target than binary - match &cargo_spec { - Some(spec) => !matches!( - spec.target_kind, - TargetKind::Bin | TargetKind::Example | TargetKind::Test - ), - None => true, - } - } - _ => false, - } -} - -fn run_rustfmt( - snap: &GlobalStateSnapshot, - text_document: TextDocumentIdentifier, - range: Option, -) -> Result>> { - let file_id = from_proto::file_id(snap, &text_document.uri)?; - let file = snap.analysis.file_text(file_id)?; - let crate_ids = snap.analysis.crate_for(file_id)?; - - let line_index = snap.file_line_index(file_id)?; - - let mut rustfmt = match snap.config.rustfmt() { - RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => { - let mut cmd = process::Command::new(toolchain::rustfmt()); - cmd.args(extra_args); - // try to chdir to the file so we can respect `rustfmt.toml` - // FIXME: use `rustfmt --config-path` once - // https://github.com/rust-lang/rustfmt/issues/4660 gets fixed - match text_document.uri.to_file_path() { - Ok(mut path) => { - // pop off file name - if path.pop() && path.is_dir() { - cmd.current_dir(path); - } - } - Err(_) => { - tracing::error!( - "Unable to get file path for {}, rustfmt.toml might be ignored", - text_document.uri - ); - } - } - if let Some(&crate_id) = crate_ids.first() { - // Assume all crates are in the same edition - let edition = snap.analysis.crate_edition(crate_id)?; - cmd.arg("--edition"); - cmd.arg(edition.to_string()); - } - - if let Some(range) = range { - if !enable_range_formatting { - return Err(LspError::new( - ErrorCode::InvalidRequest as i32, - String::from( - "rustfmt range formatting is unstable. \ - Opt-in by using a nightly build of rustfmt and setting \ - `rustfmt.rangeFormatting.enable` to true in your LSP configuration", - ), - ) - .into()); - } - - let frange = from_proto::file_range(snap, text_document, range)?; - let start_line = line_index.index.line_col(frange.range.start()).line; - let end_line = line_index.index.line_col(frange.range.end()).line; - - cmd.arg("--unstable-features"); - cmd.arg("--file-lines"); - cmd.arg( - json!([{ - "file": "stdin", - "range": [start_line, end_line] - }]) - .to_string(), - ); - } - - cmd - } - RustfmtConfig::CustomCommand { command, args } => { - let mut cmd = process::Command::new(command); - cmd.args(args); - cmd - } - }; - - let mut rustfmt = rustfmt - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .context(format!("Failed to spawn {:?}", rustfmt))?; - - rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?; - - let output = rustfmt.wait_with_output()?; - let captured_stdout = String::from_utf8(output.stdout)?; - let captured_stderr = String::from_utf8(output.stderr).unwrap_or_default(); - - if !output.status.success() { - let rustfmt_not_installed = - captured_stderr.contains("not installed") || captured_stderr.contains("not available"); - - return match output.status.code() { - Some(1) if !rustfmt_not_installed => { - // While `rustfmt` doesn't have a specific exit code for parse errors this is the - // likely cause exiting with 1. Most Language Servers swallow parse errors on - // formatting because otherwise an error is surfaced to the user on top of the - // syntax error diagnostics they're already receiving. This is especially jarring - // if they have format on save enabled. - tracing::info!("rustfmt exited with status 1, assuming parse error and ignoring"); - Ok(None) - } - _ => { - // Something else happened - e.g. `rustfmt` is missing or caught a signal - Err(LspError::new( - -32900, - format!( - r#"rustfmt exited with: - Status: {} - stdout: {} - stderr: {}"#, - output.status, captured_stdout, captured_stderr, - ), - ) - .into()) - } - }; - } - - let (new_text, new_line_endings) = LineEndings::normalize(captured_stdout); - - if line_index.endings != new_line_endings { - // If line endings are different, send the entire file. - // Diffing would not work here, as the line endings might be the only - // difference. - Ok(Some(to_proto::text_edit_vec( - &line_index, - TextEdit::replace(TextRange::up_to(TextSize::of(&*file)), new_text), - ))) - } else if *file == new_text { - // The document is already formatted correctly -- no edits needed. - Ok(None) - } else { - Ok(Some(to_proto::text_edit_vec(&line_index, diff(&file, &new_text)))) - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs deleted file mode 100644 index 47cdd8dfc75d8..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs +++ /dev/null @@ -1,196 +0,0 @@ -//! Fully integrated benchmarks for rust-analyzer, which load real cargo -//! projects. -//! -//! The benchmark here is used to debug specific performance regressions. If you -//! notice that, eg, completion is slow in some specific case, you can modify -//! code here exercise this specific completion, and thus have a fast -//! edit/compile/test cycle. -//! -//! Note that "Rust Analyzer: Run" action does not allow running a single test -//! in release mode in VS Code. There's however "Rust Analyzer: Copy Run Command Line" -//! which you can use to paste the command in terminal and add `--release` manually. - -use std::sync::Arc; - -use ide::{CallableSnippets, Change, CompletionConfig, FilePosition, TextSize}; -use ide_db::{ - imports::insert_use::{ImportGranularity, InsertUseConfig}, - SnippetCap, -}; -use project_model::CargoConfig; -use test_utils::project_root; -use vfs::{AbsPathBuf, VfsPath}; - -use crate::cli::load_cargo::{load_workspace_at, LoadCargoConfig}; - -#[test] -fn integrated_highlighting_benchmark() { - if std::env::var("RUN_SLOW_BENCHES").is_err() { - return; - } - - // Load rust-analyzer itself. - let workspace_to_load = project_root(); - let file = "./crates/ide-db/src/apply_change.rs"; - - let cargo_config = CargoConfig::default(); - let load_cargo_config = LoadCargoConfig { - load_out_dirs_from_check: true, - with_proc_macro: false, - prefill_caches: false, - }; - - let (mut host, vfs, _proc_macro) = { - let _it = stdx::timeit("workspace loading"); - load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap() - }; - - let file_id = { - let file = workspace_to_load.join(file); - let path = VfsPath::from(AbsPathBuf::assert(file)); - vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {}", path)) - }; - - { - let _it = stdx::timeit("initial"); - let analysis = host.analysis(); - analysis.highlight_as_html(file_id, false).unwrap(); - } - - profile::init_from("*>100"); - // let _s = profile::heartbeat_span(); - - { - let _it = stdx::timeit("change"); - let mut text = host.analysis().file_text(file_id).unwrap().to_string(); - text.push_str("\npub fn _dummy() {}\n"); - let mut change = Change::new(); - change.change_file(file_id, Some(Arc::new(text))); - host.apply_change(change); - } - - { - let _it = stdx::timeit("after change"); - let _span = profile::cpu_span(); - let analysis = host.analysis(); - analysis.highlight_as_html(file_id, false).unwrap(); - } -} - -#[test] -fn integrated_completion_benchmark() { - if std::env::var("RUN_SLOW_BENCHES").is_err() { - return; - } - - // Load rust-analyzer itself. - let workspace_to_load = project_root(); - let file = "./crates/hir/src/lib.rs"; - - let cargo_config = CargoConfig::default(); - let load_cargo_config = LoadCargoConfig { - load_out_dirs_from_check: true, - with_proc_macro: false, - prefill_caches: true, - }; - - let (mut host, vfs, _proc_macro) = { - let _it = stdx::timeit("workspace loading"); - load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap() - }; - - let file_id = { - let file = workspace_to_load.join(file); - let path = VfsPath::from(AbsPathBuf::assert(file)); - vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {}", path)) - }; - - { - let _it = stdx::timeit("initial"); - let analysis = host.analysis(); - analysis.highlight_as_html(file_id, false).unwrap(); - } - - profile::init_from("*>5"); - // let _s = profile::heartbeat_span(); - - let completion_offset = { - let _it = stdx::timeit("change"); - let mut text = host.analysis().file_text(file_id).unwrap().to_string(); - let completion_offset = - patch(&mut text, "db.struct_data(self.id)", "sel;\ndb.struct_data(self.id)") - + "sel".len(); - let mut change = Change::new(); - change.change_file(file_id, Some(Arc::new(text))); - host.apply_change(change); - completion_offset - }; - - { - let _p = profile::span("unqualified path completion"); - let _span = profile::cpu_span(); - let analysis = host.analysis(); - let config = CompletionConfig { - enable_postfix_completions: true, - enable_imports_on_the_fly: true, - enable_self_on_the_fly: true, - enable_private_editable: true, - callable: Some(CallableSnippets::FillArguments), - snippet_cap: SnippetCap::new(true), - insert_use: InsertUseConfig { - granularity: ImportGranularity::Crate, - prefix_kind: hir::PrefixKind::ByCrate, - enforce_granularity: true, - group: true, - skip_glob_imports: true, - }, - snippets: Vec::new(), - }; - let position = - FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() }; - analysis.completions(&config, position, None).unwrap(); - } - - let completion_offset = { - let _it = stdx::timeit("change"); - let mut text = host.analysis().file_text(file_id).unwrap().to_string(); - let completion_offset = - patch(&mut text, "sel;\ndb.struct_data(self.id)", "self.;\ndb.struct_data(self.id)") - + "self.".len(); - let mut change = Change::new(); - change.change_file(file_id, Some(Arc::new(text))); - host.apply_change(change); - completion_offset - }; - - { - let _p = profile::span("dot completion"); - let _span = profile::cpu_span(); - let analysis = host.analysis(); - let config = CompletionConfig { - enable_postfix_completions: true, - enable_imports_on_the_fly: true, - enable_self_on_the_fly: true, - enable_private_editable: true, - callable: Some(CallableSnippets::FillArguments), - snippet_cap: SnippetCap::new(true), - insert_use: InsertUseConfig { - granularity: ImportGranularity::Crate, - prefix_kind: hir::PrefixKind::ByCrate, - enforce_granularity: true, - group: true, - skip_glob_imports: true, - }, - snippets: Vec::new(), - }; - let position = - FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() }; - analysis.completions(&config, position, None).unwrap(); - } -} - -fn patch(what: &mut String, from: &str, to: &str) -> usize { - let idx = what.find(from).unwrap(); - *what = what.replacen(from, to, 1); - idx -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs deleted file mode 100644 index 552379752fa64..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! Implementation of the LSP for rust-analyzer. -//! -//! This crate takes Rust-specific analysis results from ide and translates -//! into LSP types. -//! -//! It also is the root of all state. `world` module defines the bulk of the -//! state, and `main_loop` module defines the rules for modifying it. -//! -//! The `cli` submodule implements some batch-processing analysis, primarily as -//! a debugging aid. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -pub mod cli; - -#[allow(unused)] -macro_rules! eprintln { - ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; -} - -mod caps; -mod cargo_target_spec; -mod diagnostics; -mod diff; -mod dispatch; -mod from_proto; -mod global_state; -mod handlers; -mod line_index; -mod lsp_utils; -mod main_loop; -mod markdown; -mod mem_docs; -mod op_queue; -mod reload; -mod semantic_tokens; -mod task_pool; -mod to_proto; -mod version; - -pub mod config; -pub mod lsp_ext; - -#[cfg(test)] -mod integrated_benchmarks; - -use std::fmt; - -use serde::de::DeserializeOwned; - -pub use crate::{caps::server_capabilities, main_loop::main_loop, version::version}; - -pub type Error = Box; -pub type Result = std::result::Result; - -pub fn from_json(what: &'static str, json: &serde_json::Value) -> Result { - let res = serde_json::from_value(json.clone()) - .map_err(|e| format!("Failed to deserialize {}: {}; {}", what, e, json))?; - Ok(res) -} - -#[derive(Debug)] -struct LspError { - code: i32, - message: String, -} - -impl LspError { - fn new(code: i32, message: String) -> LspError { - LspError { code, message } - } -} - -impl fmt::Display for LspError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Language Server request failed with {}. ({})", self.code, self.message) - } -} - -impl std::error::Error for LspError {} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/line_index.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/line_index.rs deleted file mode 100644 index c116414da01df..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/line_index.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Enhances `ide::LineIndex` with additional info required to convert offsets -//! into lsp positions. -//! -//! We maintain invariant that all internal strings use `\n` as line separator. -//! This module does line ending conversion and detection (so that we can -//! convert back to `\r\n` on the way out). - -use std::sync::Arc; - -pub enum OffsetEncoding { - Utf8, - Utf16, -} - -pub(crate) struct LineIndex { - pub(crate) index: Arc, - pub(crate) endings: LineEndings, - pub(crate) encoding: OffsetEncoding, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) enum LineEndings { - Unix, - Dos, -} - -impl LineEndings { - /// Replaces `\r\n` with `\n` in-place in `src`. - pub(crate) fn normalize(src: String) -> (String, LineEndings) { - if !src.as_bytes().contains(&b'\r') { - return (src, LineEndings::Unix); - } - - // We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding. - // While we *can* call `as_mut_vec` and do surgery on the live string - // directly, let's rather steal the contents of `src`. This makes the code - // safe even if a panic occurs. - - let mut buf = src.into_bytes(); - let mut gap_len = 0; - let mut tail = buf.as_mut_slice(); - loop { - let idx = match find_crlf(&tail[gap_len..]) { - None => tail.len(), - Some(idx) => idx + gap_len, - }; - tail.copy_within(gap_len..idx, 0); - tail = &mut tail[idx - gap_len..]; - if tail.len() == gap_len { - break; - } - gap_len += 1; - } - - // Account for removed `\r`. - // After `set_len`, `buf` is guaranteed to contain utf-8 again. - let new_len = buf.len() - gap_len; - let src = unsafe { - buf.set_len(new_len); - String::from_utf8_unchecked(buf) - }; - return (src, LineEndings::Dos); - - fn find_crlf(src: &[u8]) -> Option { - src.windows(2).position(|it| it == b"\r\n") - } - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_ext.rs deleted file mode 100644 index 5f0e108624b2e..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_ext.rs +++ /dev/null @@ -1,549 +0,0 @@ -//! rust-analyzer extensions to the LSP. - -use std::{collections::HashMap, path::PathBuf}; - -use lsp_types::request::Request; -use lsp_types::{ - notification::Notification, CodeActionKind, DocumentOnTypeFormattingParams, - PartialResultParams, Position, Range, TextDocumentIdentifier, WorkDoneProgressParams, -}; -use serde::{Deserialize, Serialize}; - -pub enum AnalyzerStatus {} - -impl Request for AnalyzerStatus { - type Params = AnalyzerStatusParams; - type Result = String; - const METHOD: &'static str = "rust-analyzer/analyzerStatus"; -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct AnalyzerStatusParams { - pub text_document: Option, -} - -pub enum MemoryUsage {} - -impl Request for MemoryUsage { - type Params = (); - type Result = String; - const METHOD: &'static str = "rust-analyzer/memoryUsage"; -} - -pub enum ShuffleCrateGraph {} - -impl Request for ShuffleCrateGraph { - type Params = (); - type Result = (); - const METHOD: &'static str = "rust-analyzer/shuffleCrateGraph"; -} - -pub enum ReloadWorkspace {} - -impl Request for ReloadWorkspace { - type Params = (); - type Result = (); - const METHOD: &'static str = "rust-analyzer/reloadWorkspace"; -} - -pub enum SyntaxTree {} - -impl Request for SyntaxTree { - type Params = SyntaxTreeParams; - type Result = String; - const METHOD: &'static str = "rust-analyzer/syntaxTree"; -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct SyntaxTreeParams { - pub text_document: TextDocumentIdentifier, - pub range: Option, -} - -pub enum ViewHir {} - -impl Request for ViewHir { - type Params = lsp_types::TextDocumentPositionParams; - type Result = String; - const METHOD: &'static str = "rust-analyzer/viewHir"; -} - -pub enum ViewFileText {} - -impl Request for ViewFileText { - type Params = lsp_types::TextDocumentIdentifier; - type Result = String; - const METHOD: &'static str = "rust-analyzer/viewFileText"; -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct ViewCrateGraphParams { - /// Include *all* crates, not just crates in the workspace. - pub full: bool, -} - -pub enum ViewCrateGraph {} - -impl Request for ViewCrateGraph { - type Params = ViewCrateGraphParams; - type Result = String; - const METHOD: &'static str = "rust-analyzer/viewCrateGraph"; -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct ViewItemTreeParams { - pub text_document: TextDocumentIdentifier, -} - -pub enum ViewItemTree {} - -impl Request for ViewItemTree { - type Params = ViewItemTreeParams; - type Result = String; - const METHOD: &'static str = "rust-analyzer/viewItemTree"; -} - -pub enum ExpandMacro {} - -impl Request for ExpandMacro { - type Params = ExpandMacroParams; - type Result = Option; - const METHOD: &'static str = "rust-analyzer/expandMacro"; -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct ExpandMacroParams { - pub text_document: TextDocumentIdentifier, - pub position: Position, -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct ExpandedMacro { - pub name: String, - pub expansion: String, -} - -pub enum MatchingBrace {} - -impl Request for MatchingBrace { - type Params = MatchingBraceParams; - type Result = Vec; - const METHOD: &'static str = "experimental/matchingBrace"; -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct MatchingBraceParams { - pub text_document: TextDocumentIdentifier, - pub positions: Vec, -} - -pub enum ParentModule {} - -impl Request for ParentModule { - type Params = lsp_types::TextDocumentPositionParams; - type Result = Option; - const METHOD: &'static str = "experimental/parentModule"; -} - -pub enum JoinLines {} - -impl Request for JoinLines { - type Params = JoinLinesParams; - type Result = Vec; - const METHOD: &'static str = "experimental/joinLines"; -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct JoinLinesParams { - pub text_document: TextDocumentIdentifier, - pub ranges: Vec, -} - -pub enum OnEnter {} - -impl Request for OnEnter { - type Params = lsp_types::TextDocumentPositionParams; - type Result = Option>; - const METHOD: &'static str = "experimental/onEnter"; -} - -pub enum Runnables {} - -impl Request for Runnables { - type Params = RunnablesParams; - type Result = Vec; - const METHOD: &'static str = "experimental/runnables"; -} - -#[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct RunnablesParams { - pub text_document: TextDocumentIdentifier, - pub position: Option, -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct Runnable { - pub label: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub location: Option, - pub kind: RunnableKind, - pub args: CargoRunnable, -} - -#[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "lowercase")] -pub enum RunnableKind { - Cargo, -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct CargoRunnable { - // command to be executed instead of cargo - pub override_cargo: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace_root: Option, - // command, --package and --lib stuff - pub cargo_args: Vec, - // user-specified additional cargo args, like `--release`. - pub cargo_extra_args: Vec, - // stuff after -- - pub executable_args: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - pub expect_test: Option, -} - -pub enum RelatedTests {} - -impl Request for RelatedTests { - type Params = lsp_types::TextDocumentPositionParams; - type Result = Vec; - const METHOD: &'static str = "rust-analyzer/relatedTests"; -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct TestInfo { - pub runnable: Runnable, -} - -#[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct InlayHintsParams { - pub text_document: TextDocumentIdentifier, - pub range: Option, -} - -pub enum Ssr {} - -impl Request for Ssr { - type Params = SsrParams; - type Result = lsp_types::WorkspaceEdit; - const METHOD: &'static str = "experimental/ssr"; -} - -#[derive(Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SsrParams { - pub query: String, - pub parse_only: bool, - - /// File position where SSR was invoked. Paths in `query` will be resolved relative to this - /// position. - #[serde(flatten)] - pub position: lsp_types::TextDocumentPositionParams, - - /// Current selections. Search/replace will be restricted to these if non-empty. - pub selections: Vec, -} - -pub enum ServerStatusNotification {} - -impl Notification for ServerStatusNotification { - type Params = ServerStatusParams; - const METHOD: &'static str = "experimental/serverStatus"; -} - -#[derive(Deserialize, Serialize, PartialEq, Eq, Clone)] -pub struct ServerStatusParams { - pub health: Health, - pub quiescent: bool, - pub message: Option, -} - -#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] -#[serde(rename_all = "camelCase")] -pub enum Health { - Ok, - Warning, - Error, -} - -pub enum CodeActionRequest {} - -impl Request for CodeActionRequest { - type Params = lsp_types::CodeActionParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/codeAction"; -} - -pub enum CodeActionResolveRequest {} -impl Request for CodeActionResolveRequest { - type Params = CodeAction; - type Result = CodeAction; - const METHOD: &'static str = "codeAction/resolve"; -} - -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeAction { - pub title: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub group: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub kind: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub command: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub edit: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub is_preferred: Option, - - #[serde(skip_serializing_if = "Option::is_none")] - pub data: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeActionData { - pub code_action_params: lsp_types::CodeActionParams, - pub id: String, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SnippetWorkspaceEdit { - #[serde(skip_serializing_if = "Option::is_none")] - pub changes: Option>>, - #[serde(skip_serializing_if = "Option::is_none")] - pub document_changes: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - pub change_annotations: - Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged, rename_all = "lowercase")] -pub enum SnippetDocumentChangeOperation { - Op(lsp_types::ResourceOp), - Edit(SnippetTextDocumentEdit), -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SnippetTextDocumentEdit { - pub text_document: lsp_types::OptionalVersionedTextDocumentIdentifier, - pub edits: Vec, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SnippetTextEdit { - pub range: Range, - pub new_text: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub insert_text_format: Option, - /// The annotation id if this is an annotated - #[serde(skip_serializing_if = "Option::is_none")] - pub annotation_id: Option, -} - -pub enum HoverRequest {} - -impl Request for HoverRequest { - type Params = HoverParams; - type Result = Option; - const METHOD: &'static str = "textDocument/hover"; -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct HoverParams { - pub text_document: TextDocumentIdentifier, - pub position: PositionOrRange, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum PositionOrRange { - Position(lsp_types::Position), - Range(lsp_types::Range), -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -pub struct Hover { - #[serde(flatten)] - pub hover: lsp_types::Hover, - #[serde(skip_serializing_if = "Vec::is_empty")] - pub actions: Vec, -} - -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct CommandLinkGroup { - #[serde(skip_serializing_if = "Option::is_none")] - pub title: Option, - pub commands: Vec, -} - -// LSP v3.15 Command does not have a `tooltip` field, vscode supports one. -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct CommandLink { - #[serde(flatten)] - pub command: lsp_types::Command, - #[serde(skip_serializing_if = "Option::is_none")] - pub tooltip: Option, -} - -pub enum ExternalDocs {} - -impl Request for ExternalDocs { - type Params = lsp_types::TextDocumentPositionParams; - type Result = Option; - const METHOD: &'static str = "experimental/externalDocs"; -} - -pub enum OpenCargoToml {} - -impl Request for OpenCargoToml { - type Params = OpenCargoTomlParams; - type Result = Option; - const METHOD: &'static str = "experimental/openCargoToml"; -} - -#[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct OpenCargoTomlParams { - pub text_document: TextDocumentIdentifier, -} - -/// Information about CodeLens, that is to be resolved. -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) enum CodeLensResolveData { - Impls(lsp_types::request::GotoImplementationParams), - References(lsp_types::TextDocumentPositionParams), -} - -pub fn supports_utf8(caps: &lsp_types::ClientCapabilities) -> bool { - caps.offset_encoding.as_deref().unwrap_or_default().iter().any(|it| it == "utf-8") -} - -pub enum MoveItem {} - -impl Request for MoveItem { - type Params = MoveItemParams; - type Result = Vec; - const METHOD: &'static str = "experimental/moveItem"; -} - -#[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct MoveItemParams { - pub direction: MoveItemDirection, - pub text_document: TextDocumentIdentifier, - pub range: Range, -} - -#[derive(Serialize, Deserialize, Debug)] -pub enum MoveItemDirection { - Up, - Down, -} - -#[derive(Debug)] -pub enum WorkspaceSymbol {} - -impl Request for WorkspaceSymbol { - type Params = WorkspaceSymbolParams; - type Result = Option>; - const METHOD: &'static str = "workspace/symbol"; -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceSymbolParams { - #[serde(flatten)] - pub partial_result_params: PartialResultParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - /// A non-empty query string - pub query: String, - - pub search_scope: Option, - - pub search_kind: Option, -} - -#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] -#[serde(rename_all = "camelCase")] -pub enum WorkspaceSymbolSearchScope { - Workspace, - WorkspaceAndDependencies, -} - -#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] -#[serde(rename_all = "camelCase")] -pub enum WorkspaceSymbolSearchKind { - OnlyTypes, - AllSymbols, -} - -/// The document on type formatting request is sent from the client to -/// the server to format parts of the document during typing. This is -/// almost same as lsp_types::request::OnTypeFormatting, but the -/// result has SnippetTextEdit in it instead of TextEdit. -#[derive(Debug)] -pub enum OnTypeFormatting {} - -impl Request for OnTypeFormatting { - type Params = DocumentOnTypeFormattingParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/onTypeFormatting"; -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct CompletionResolveData { - pub position: lsp_types::TextDocumentPositionParams, - pub imports: Vec, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct InlayHintResolveData { - pub text_document: TextDocumentIdentifier, - pub position: PositionOrRange, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct CompletionImport { - pub full_import_path: String, - pub imported_name: String, -} - -#[derive(Debug, Deserialize, Default)] -pub struct ClientCommandOptions { - pub commands: Vec, -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs deleted file mode 100644 index 5a37cbe2e334b..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs +++ /dev/null @@ -1,407 +0,0 @@ -//! Utilities for LSP-related boilerplate code. -use std::{ops::Range, sync::Arc}; - -use lsp_server::Notification; - -use crate::{ - from_proto, - global_state::GlobalState, - line_index::{LineEndings, LineIndex, OffsetEncoding}, - LspError, -}; - -pub(crate) fn invalid_params_error(message: String) -> LspError { - LspError { code: lsp_server::ErrorCode::InvalidParams as i32, message } -} - -pub(crate) fn notification_is( - notification: &Notification, -) -> bool { - notification.method == N::METHOD -} - -#[derive(Debug, Eq, PartialEq)] -pub(crate) enum Progress { - Begin, - Report, - End, -} - -impl Progress { - pub(crate) fn fraction(done: usize, total: usize) -> f64 { - assert!(done <= total); - done as f64 / total.max(1) as f64 - } -} - -impl GlobalState { - pub(crate) fn show_message(&mut self, typ: lsp_types::MessageType, message: String) { - let message = message; - self.send_notification::( - lsp_types::ShowMessageParams { typ, message }, - ) - } - - /// Sends a notification to the client containing the error `message`. - /// If `additional_info` is [`Some`], appends a note to the notification telling to check the logs. - /// This will always log `message` + `additional_info` to the server's error log. - pub(crate) fn show_and_log_error(&mut self, message: String, additional_info: Option) { - let mut message = message; - match additional_info { - Some(additional_info) => { - tracing::error!("{}\n\n{}", &message, &additional_info); - if tracing::enabled!(tracing::Level::ERROR) { - message.push_str("\n\nCheck the server logs for additional info."); - } - } - None => tracing::error!("{}", &message), - } - - self.send_notification::( - lsp_types::ShowMessageParams { typ: lsp_types::MessageType::ERROR, message }, - ) - } - - /// rust-analyzer is resilient -- if it fails, this doesn't usually affect - /// the user experience. Part of that is that we deliberately hide panics - /// from the user. - /// - /// We do however want to pester rust-analyzer developers with panics and - /// other "you really gotta fix that" messages. The current strategy is to - /// be noisy for "from source" builds or when profiling is enabled. - /// - /// It's unclear if making from source `cargo xtask install` builds more - /// panicky is a good idea, let's see if we can keep our awesome bleeding - /// edge users from being upset! - pub(crate) fn poke_rust_analyzer_developer(&mut self, message: String) { - let from_source_build = option_env!("POKE_RA_DEVS").is_some(); - let profiling_enabled = std::env::var("RA_PROFILE").is_ok(); - if from_source_build || profiling_enabled { - self.show_message(lsp_types::MessageType::ERROR, message) - } - } - - pub(crate) fn report_progress( - &mut self, - title: &str, - state: Progress, - message: Option, - fraction: Option, - ) { - if !self.config.work_done_progress() { - return; - } - let percentage = fraction.map(|f| { - assert!((0.0..=1.0).contains(&f)); - (f * 100.0) as u32 - }); - let token = lsp_types::ProgressToken::String(format!("rustAnalyzer/{}", title)); - let work_done_progress = match state { - Progress::Begin => { - self.send_request::( - lsp_types::WorkDoneProgressCreateParams { token: token.clone() }, - |_, _| (), - ); - - lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin { - title: title.into(), - cancellable: None, - message, - percentage, - }) - } - Progress::Report => { - lsp_types::WorkDoneProgress::Report(lsp_types::WorkDoneProgressReport { - cancellable: None, - message, - percentage, - }) - } - Progress::End => { - lsp_types::WorkDoneProgress::End(lsp_types::WorkDoneProgressEnd { message }) - } - }; - self.send_notification::(lsp_types::ProgressParams { - token, - value: lsp_types::ProgressParamsValue::WorkDone(work_done_progress), - }); - } -} - -pub(crate) fn apply_document_changes( - old_text: &mut String, - content_changes: Vec, -) { - let mut line_index = LineIndex { - index: Arc::new(ide::LineIndex::new(old_text)), - // We don't care about line endings or offset encoding here. - endings: LineEndings::Unix, - encoding: OffsetEncoding::Utf16, - }; - - // The changes we got must be applied sequentially, but can cross lines so we - // have to keep our line index updated. - // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we - // remember the last valid line in the index and only rebuild it if needed. - // The VFS will normalize the end of lines to `\n`. - enum IndexValid { - All, - UpToLineExclusive(u32), - } - - impl IndexValid { - fn covers(&self, line: u32) -> bool { - match *self { - IndexValid::UpToLineExclusive(to) => to > line, - _ => true, - } - } - } - - let mut index_valid = IndexValid::All; - for change in content_changes { - match change.range { - Some(range) => { - if !index_valid.covers(range.end.line) { - line_index.index = Arc::new(ide::LineIndex::new(old_text)); - } - index_valid = IndexValid::UpToLineExclusive(range.start.line); - if let Ok(range) = from_proto::text_range(&line_index, range) { - old_text.replace_range(Range::::from(range), &change.text); - } - } - None => { - *old_text = change.text; - index_valid = IndexValid::UpToLineExclusive(0); - } - } - } -} - -/// Checks that the edits inside the completion and the additional edits do not overlap. -/// LSP explicitly forbids the additional edits to overlap both with the main edit and themselves. -pub(crate) fn all_edits_are_disjoint( - completion: &lsp_types::CompletionItem, - additional_edits: &[lsp_types::TextEdit], -) -> bool { - let mut edit_ranges = Vec::new(); - match completion.text_edit.as_ref() { - Some(lsp_types::CompletionTextEdit::Edit(edit)) => { - edit_ranges.push(edit.range); - } - Some(lsp_types::CompletionTextEdit::InsertAndReplace(edit)) => { - let replace = edit.replace; - let insert = edit.insert; - if replace.start != insert.start - || insert.start > insert.end - || insert.end > replace.end - { - // insert has to be a prefix of replace but it is not - return false; - } - edit_ranges.push(replace); - } - None => {} - } - if let Some(additional_changes) = completion.additional_text_edits.as_ref() { - edit_ranges.extend(additional_changes.iter().map(|edit| edit.range)); - }; - edit_ranges.extend(additional_edits.iter().map(|edit| edit.range)); - edit_ranges.sort_by_key(|range| (range.start, range.end)); - edit_ranges - .iter() - .zip(edit_ranges.iter().skip(1)) - .all(|(previous, next)| previous.end <= next.start) -} - -#[cfg(test)] -mod tests { - use lsp_types::{ - CompletionItem, CompletionTextEdit, InsertReplaceEdit, Position, Range, - TextDocumentContentChangeEvent, - }; - - use super::*; - - #[test] - fn test_apply_document_changes() { - macro_rules! c { - [$($sl:expr, $sc:expr; $el:expr, $ec:expr => $text:expr),+] => { - vec![$(TextDocumentContentChangeEvent { - range: Some(Range { - start: Position { line: $sl, character: $sc }, - end: Position { line: $el, character: $ec }, - }), - range_length: None, - text: String::from($text), - }),+] - }; - } - - let mut text = String::new(); - apply_document_changes(&mut text, vec![]); - assert_eq!(text, ""); - apply_document_changes( - &mut text, - vec![TextDocumentContentChangeEvent { - range: None, - range_length: None, - text: String::from("the"), - }], - ); - assert_eq!(text, "the"); - apply_document_changes(&mut text, c![0, 3; 0, 3 => " quick"]); - assert_eq!(text, "the quick"); - apply_document_changes(&mut text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]); - assert_eq!(text, "quick foxes"); - apply_document_changes(&mut text, c![0, 11; 0, 11 => "\ndream"]); - assert_eq!(text, "quick foxes\ndream"); - apply_document_changes(&mut text, c![1, 0; 1, 0 => "have "]); - assert_eq!(text, "quick foxes\nhave dream"); - apply_document_changes( - &mut text, - c![0, 0; 0, 0 => "the ", 1, 4; 1, 4 => " quiet", 1, 16; 1, 16 => "s\n"], - ); - assert_eq!(text, "the quick foxes\nhave quiet dreams\n"); - apply_document_changes(&mut text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]); - assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n"); - apply_document_changes( - &mut text, - c![1, 0; 1, 0 => "DREAM", 2, 0; 2, 0 => "they ", 3, 0; 3, 0 => "DON'T THEY?"], - ); - assert_eq!(text, "the quick foxes\nDREAM\nthey have quiet dreams\nDON'T THEY?\n"); - apply_document_changes(&mut text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]); - assert_eq!(text, "the quick \nthey have quiet dreams\n"); - - text = String::from("❤️"); - apply_document_changes(&mut text, c![0, 0; 0, 0 => "a"]); - assert_eq!(text, "a❤️"); - - text = String::from("a\nb"); - apply_document_changes(&mut text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]); - assert_eq!(text, "adcb"); - - text = String::from("a\nb"); - apply_document_changes(&mut text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]); - assert_eq!(text, "ațc\ncb"); - } - - #[test] - fn empty_completion_disjoint_tests() { - let empty_completion = - CompletionItem::new_simple("label".to_string(), "detail".to_string()); - - let disjoint_edit_1 = lsp_types::TextEdit::new( - Range::new(Position::new(2, 2), Position::new(3, 3)), - "new_text".to_string(), - ); - let disjoint_edit_2 = lsp_types::TextEdit::new( - Range::new(Position::new(3, 3), Position::new(4, 4)), - "new_text".to_string(), - ); - - let joint_edit = lsp_types::TextEdit::new( - Range::new(Position::new(1, 1), Position::new(5, 5)), - "new_text".to_string(), - ); - - assert!( - all_edits_are_disjoint(&empty_completion, &[]), - "Empty completion has all its edits disjoint" - ); - assert!( - all_edits_are_disjoint( - &empty_completion, - &[disjoint_edit_1.clone(), disjoint_edit_2.clone()] - ), - "Empty completion is disjoint to whatever disjoint extra edits added" - ); - - assert!( - !all_edits_are_disjoint( - &empty_completion, - &[disjoint_edit_1, disjoint_edit_2, joint_edit] - ), - "Empty completion does not prevent joint extra edits from failing the validation" - ); - } - - #[test] - fn completion_with_joint_edits_disjoint_tests() { - let disjoint_edit = lsp_types::TextEdit::new( - Range::new(Position::new(1, 1), Position::new(2, 2)), - "new_text".to_string(), - ); - let disjoint_edit_2 = lsp_types::TextEdit::new( - Range::new(Position::new(2, 2), Position::new(3, 3)), - "new_text".to_string(), - ); - let joint_edit = lsp_types::TextEdit::new( - Range::new(Position::new(1, 1), Position::new(5, 5)), - "new_text".to_string(), - ); - - let mut completion_with_joint_edits = - CompletionItem::new_simple("label".to_string(), "detail".to_string()); - completion_with_joint_edits.additional_text_edits = - Some(vec![disjoint_edit.clone(), joint_edit.clone()]); - assert!( - !all_edits_are_disjoint(&completion_with_joint_edits, &[]), - "Completion with disjoint edits fails the validation even with empty extra edits" - ); - - completion_with_joint_edits.text_edit = - Some(CompletionTextEdit::Edit(disjoint_edit.clone())); - completion_with_joint_edits.additional_text_edits = Some(vec![joint_edit.clone()]); - assert!( - !all_edits_are_disjoint(&completion_with_joint_edits, &[]), - "Completion with disjoint edits fails the validation even with empty extra edits" - ); - - completion_with_joint_edits.text_edit = - Some(CompletionTextEdit::InsertAndReplace(InsertReplaceEdit { - new_text: "new_text".to_string(), - insert: disjoint_edit.range, - replace: disjoint_edit_2.range, - })); - completion_with_joint_edits.additional_text_edits = Some(vec![joint_edit]); - assert!( - !all_edits_are_disjoint(&completion_with_joint_edits, &[]), - "Completion with disjoint edits fails the validation even with empty extra edits" - ); - } - - #[test] - fn completion_with_disjoint_edits_disjoint_tests() { - let disjoint_edit = lsp_types::TextEdit::new( - Range::new(Position::new(1, 1), Position::new(2, 2)), - "new_text".to_string(), - ); - let disjoint_edit_2 = lsp_types::TextEdit::new( - Range::new(Position::new(2, 2), Position::new(3, 3)), - "new_text".to_string(), - ); - let joint_edit = lsp_types::TextEdit::new( - Range::new(Position::new(1, 1), Position::new(5, 5)), - "new_text".to_string(), - ); - - let mut completion_with_disjoint_edits = - CompletionItem::new_simple("label".to_string(), "detail".to_string()); - completion_with_disjoint_edits.text_edit = Some(CompletionTextEdit::Edit(disjoint_edit)); - let completion_with_disjoint_edits = completion_with_disjoint_edits; - - assert!( - all_edits_are_disjoint(&completion_with_disjoint_edits, &[]), - "Completion with disjoint edits is valid" - ); - assert!( - !all_edits_are_disjoint(&completion_with_disjoint_edits, &[joint_edit]), - "Completion with disjoint edits and joint extra edit is invalid" - ); - assert!( - all_edits_are_disjoint(&completion_with_disjoint_edits, &[disjoint_edit_2]), - "Completion with disjoint edits and joint extra edit is valid" - ); - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs deleted file mode 100644 index 5845cf712c899..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ /dev/null @@ -1,823 +0,0 @@ -//! The main loop of `rust-analyzer` responsible for dispatching LSP -//! requests/replies and notifications back to the client. -use std::{ - fmt, - sync::Arc, - time::{Duration, Instant}, -}; - -use always_assert::always; -use crossbeam_channel::{select, Receiver}; -use ide_db::base_db::{SourceDatabaseExt, VfsPath}; -use lsp_server::{Connection, Notification, Request}; -use lsp_types::notification::Notification as _; -use vfs::{ChangeKind, FileId}; - -use crate::{ - config::Config, - dispatch::{NotificationDispatcher, RequestDispatcher}, - from_proto, - global_state::{file_id_to_url, url_to_file_id, GlobalState}, - handlers, lsp_ext, - lsp_utils::{apply_document_changes, notification_is, Progress}, - mem_docs::DocumentData, - reload::{self, BuildDataProgress, ProjectWorkspaceProgress}, - Result, -}; - -pub fn main_loop(config: Config, connection: Connection) -> Result<()> { - tracing::info!("initial config: {:#?}", config); - - // Windows scheduler implements priority boosts: if thread waits for an - // event (like a condvar), and event fires, priority of the thread is - // temporary bumped. This optimization backfires in our case: each time the - // `main_loop` schedules a task to run on a threadpool, the worker threads - // gets a higher priority, and (on a machine with fewer cores) displaces the - // main loop! We work-around this by marking the main loop as a - // higher-priority thread. - // - // https://docs.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities - // https://docs.microsoft.com/en-us/windows/win32/procthread/priority-boosts - // https://github.com/rust-lang/rust-analyzer/issues/2835 - #[cfg(windows)] - unsafe { - use winapi::um::processthreadsapi::*; - let thread = GetCurrentThread(); - let thread_priority_above_normal = 1; - SetThreadPriority(thread, thread_priority_above_normal); - } - - GlobalState::new(connection.sender, config).run(connection.receiver) -} - -enum Event { - Lsp(lsp_server::Message), - Task(Task), - Vfs(vfs::loader::Message), - Flycheck(flycheck::Message), -} - -#[derive(Debug)] -pub(crate) enum Task { - Response(lsp_server::Response), - Retry(lsp_server::Request), - Diagnostics(Vec<(FileId, Vec)>), - PrimeCaches(PrimeCachesProgress), - FetchWorkspace(ProjectWorkspaceProgress), - FetchBuildData(BuildDataProgress), -} - -#[derive(Debug)] -pub(crate) enum PrimeCachesProgress { - Begin, - Report(ide::ParallelPrimeCachesProgress), - End { cancelled: bool }, -} - -impl fmt::Debug for Event { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let debug_verbose_not = |not: &Notification, f: &mut fmt::Formatter<'_>| { - f.debug_struct("Notification").field("method", ¬.method).finish() - }; - - match self { - Event::Lsp(lsp_server::Message::Notification(not)) => { - if notification_is::(not) - || notification_is::(not) - { - return debug_verbose_not(not, f); - } - } - Event::Task(Task::Response(resp)) => { - return f - .debug_struct("Response") - .field("id", &resp.id) - .field("error", &resp.error) - .finish(); - } - _ => (), - } - match self { - Event::Lsp(it) => fmt::Debug::fmt(it, f), - Event::Task(it) => fmt::Debug::fmt(it, f), - Event::Vfs(it) => fmt::Debug::fmt(it, f), - Event::Flycheck(it) => fmt::Debug::fmt(it, f), - } - } -} - -impl GlobalState { - fn run(mut self, inbox: Receiver) -> Result<()> { - if self.config.linked_projects().is_empty() - && self.config.detached_files().is_empty() - && self.config.notifications().cargo_toml_not_found - { - self.show_and_log_error("rust-analyzer failed to discover workspace".to_string(), None); - }; - - if self.config.did_save_text_document_dynamic_registration() { - let save_registration_options = lsp_types::TextDocumentSaveRegistrationOptions { - include_text: Some(false), - text_document_registration_options: lsp_types::TextDocumentRegistrationOptions { - document_selector: Some(vec![ - lsp_types::DocumentFilter { - language: None, - scheme: None, - pattern: Some("**/*.rs".into()), - }, - lsp_types::DocumentFilter { - language: None, - scheme: None, - pattern: Some("**/Cargo.toml".into()), - }, - lsp_types::DocumentFilter { - language: None, - scheme: None, - pattern: Some("**/Cargo.lock".into()), - }, - ]), - }, - }; - - let registration = lsp_types::Registration { - id: "textDocument/didSave".to_string(), - method: "textDocument/didSave".to_string(), - register_options: Some(serde_json::to_value(save_registration_options).unwrap()), - }; - self.send_request::( - lsp_types::RegistrationParams { registrations: vec![registration] }, - |_, _| (), - ); - } - - self.fetch_workspaces_queue.request_op("startup".to_string()); - if let Some(cause) = self.fetch_workspaces_queue.should_start_op() { - self.fetch_workspaces(cause); - } - - while let Some(event) = self.next_event(&inbox) { - if let Event::Lsp(lsp_server::Message::Notification(not)) = &event { - if not.method == lsp_types::notification::Exit::METHOD { - return Ok(()); - } - } - self.handle_event(event)? - } - - Err("client exited without proper shutdown sequence".into()) - } - - fn next_event(&self, inbox: &Receiver) -> Option { - select! { - recv(inbox) -> msg => - msg.ok().map(Event::Lsp), - - recv(self.task_pool.receiver) -> task => - Some(Event::Task(task.unwrap())), - - recv(self.loader.receiver) -> task => - Some(Event::Vfs(task.unwrap())), - - recv(self.flycheck_receiver) -> task => - Some(Event::Flycheck(task.unwrap())), - } - } - - fn handle_event(&mut self, event: Event) -> Result<()> { - let loop_start = Instant::now(); - // NOTE: don't count blocking select! call as a loop-turn time - let _p = profile::span("GlobalState::handle_event"); - - tracing::debug!("handle_event({:?})", event); - let task_queue_len = self.task_pool.handle.len(); - if task_queue_len > 0 { - tracing::info!("task queue len: {}", task_queue_len); - } - - let was_quiescent = self.is_quiescent(); - match event { - Event::Lsp(msg) => match msg { - lsp_server::Message::Request(req) => self.on_new_request(loop_start, req), - lsp_server::Message::Notification(not) => { - self.on_notification(not)?; - } - lsp_server::Message::Response(resp) => self.complete_request(resp), - }, - Event::Task(mut task) => { - let _p = profile::span("GlobalState::handle_event/task"); - let mut prime_caches_progress = Vec::new(); - loop { - match task { - Task::Response(response) => self.respond(response), - Task::Retry(req) => self.on_request(req), - Task::Diagnostics(diagnostics_per_file) => { - for (file_id, diagnostics) in diagnostics_per_file { - self.diagnostics.set_native_diagnostics(file_id, diagnostics) - } - } - Task::PrimeCaches(progress) => match progress { - PrimeCachesProgress::Begin => prime_caches_progress.push(progress), - PrimeCachesProgress::Report(_) => { - match prime_caches_progress.last_mut() { - Some(last @ PrimeCachesProgress::Report(_)) => { - // Coalesce subsequent update events. - *last = progress; - } - _ => prime_caches_progress.push(progress), - } - } - PrimeCachesProgress::End { .. } => prime_caches_progress.push(progress), - }, - Task::FetchWorkspace(progress) => { - let (state, msg) = match progress { - ProjectWorkspaceProgress::Begin => (Progress::Begin, None), - ProjectWorkspaceProgress::Report(msg) => { - (Progress::Report, Some(msg)) - } - ProjectWorkspaceProgress::End(workspaces) => { - self.fetch_workspaces_queue.op_completed(workspaces); - - let old = Arc::clone(&self.workspaces); - self.switch_workspaces("fetched workspace".to_string()); - let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces); - - if self.config.run_build_scripts() && workspaces_updated { - self.fetch_build_data_queue - .request_op(format!("workspace updated")); - } - - (Progress::End, None) - } - }; - - self.report_progress("Fetching", state, msg, None); - } - Task::FetchBuildData(progress) => { - let (state, msg) = match progress { - BuildDataProgress::Begin => (Some(Progress::Begin), None), - BuildDataProgress::Report(msg) => { - (Some(Progress::Report), Some(msg)) - } - BuildDataProgress::End(build_data_result) => { - self.fetch_build_data_queue.op_completed(build_data_result); - - self.switch_workspaces("fetched build data".to_string()); - - (Some(Progress::End), None) - } - }; - - if let Some(state) = state { - self.report_progress("Loading", state, msg, None); - } - } - } - - // Coalesce multiple task events into one loop turn - task = match self.task_pool.receiver.try_recv() { - Ok(task) => task, - Err(_) => break, - }; - } - - for progress in prime_caches_progress { - let (state, message, fraction); - match progress { - PrimeCachesProgress::Begin => { - state = Progress::Begin; - message = None; - fraction = 0.0; - } - PrimeCachesProgress::Report(report) => { - state = Progress::Report; - - message = match &report.crates_currently_indexing[..] { - [crate_name] => Some(format!( - "{}/{} ({})", - report.crates_done, report.crates_total, crate_name - )), - [crate_name, rest @ ..] => Some(format!( - "{}/{} ({} + {} more)", - report.crates_done, - report.crates_total, - crate_name, - rest.len() - )), - _ => None, - }; - - fraction = Progress::fraction(report.crates_done, report.crates_total); - } - PrimeCachesProgress::End { cancelled } => { - state = Progress::End; - message = None; - fraction = 1.0; - - self.prime_caches_queue.op_completed(()); - if cancelled { - self.prime_caches_queue - .request_op("restart after cancellation".to_string()); - } - } - }; - - self.report_progress("Indexing", state, message, Some(fraction)); - } - } - Event::Vfs(mut task) => { - let _p = profile::span("GlobalState::handle_event/vfs"); - loop { - match task { - vfs::loader::Message::Loaded { files } => { - let vfs = &mut self.vfs.write().0; - for (path, contents) in files { - let path = VfsPath::from(path); - if !self.mem_docs.contains(&path) { - vfs.set_file_contents(path, contents); - } - } - } - vfs::loader::Message::Progress { n_total, n_done, config_version } => { - always!(config_version <= self.vfs_config_version); - - self.vfs_progress_config_version = config_version; - self.vfs_progress_n_total = n_total; - self.vfs_progress_n_done = n_done; - - let state = if n_done == 0 { - Progress::Begin - } else if n_done < n_total { - Progress::Report - } else { - assert_eq!(n_done, n_total); - Progress::End - }; - self.report_progress( - "Roots Scanned", - state, - Some(format!("{}/{}", n_done, n_total)), - Some(Progress::fraction(n_done, n_total)), - ) - } - } - // Coalesce many VFS event into a single loop turn - task = match self.loader.receiver.try_recv() { - Ok(task) => task, - Err(_) => break, - } - } - } - Event::Flycheck(mut task) => { - let _p = profile::span("GlobalState::handle_event/flycheck"); - loop { - match task { - flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => { - let snap = self.snapshot(); - let diagnostics = - crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( - &self.config.diagnostics_map(), - &diagnostic, - &workspace_root, - &snap, - ); - for diag in diagnostics { - match url_to_file_id(&self.vfs.read().0, &diag.url) { - Ok(file_id) => self.diagnostics.add_check_diagnostic( - file_id, - diag.diagnostic, - diag.fix, - ), - Err(err) => { - tracing::error!( - "File with cargo diagnostic not found in VFS: {}", - err - ); - } - }; - } - } - - flycheck::Message::Progress { id, progress } => { - let (state, message) = match progress { - flycheck::Progress::DidStart => { - self.diagnostics.clear_check(); - (Progress::Begin, None) - } - flycheck::Progress::DidCheckCrate(target) => { - (Progress::Report, Some(target)) - } - flycheck::Progress::DidCancel => (Progress::End, None), - flycheck::Progress::DidFinish(result) => { - if let Err(err) = result { - self.show_and_log_error( - "cargo check failed".to_string(), - Some(err.to_string()), - ); - } - (Progress::End, None) - } - }; - - // When we're running multiple flychecks, we have to include a disambiguator in - // the title, or the editor complains. Note that this is a user-facing string. - let title = if self.flycheck.len() == 1 { - match self.config.flycheck() { - Some(config) => format!("{}", config), - None => "cargo check".to_string(), - } - } else { - format!("cargo check (#{})", id + 1) - }; - self.report_progress(&title, state, message, None); - } - } - // Coalesce many flycheck updates into a single loop turn - task = match self.flycheck_receiver.try_recv() { - Ok(task) => task, - Err(_) => break, - } - } - } - } - - let state_changed = self.process_changes(); - let memdocs_added_or_removed = self.mem_docs.take_changes(); - - if self.is_quiescent() { - if !was_quiescent { - for flycheck in &self.flycheck { - flycheck.update(); - } - if self.config.prefill_caches() { - self.prime_caches_queue.request_op("became quiescent".to_string()); - } - } - - if !was_quiescent || state_changed { - // Refresh semantic tokens if the client supports it. - if self.config.semantic_tokens_refresh() { - self.semantic_tokens_cache.lock().clear(); - self.send_request::((), |_, _| ()); - } - - // Refresh code lens if the client supports it. - if self.config.code_lens_refresh() { - self.send_request::((), |_, _| ()); - } - } - - if !was_quiescent || state_changed || memdocs_added_or_removed { - if self.config.publish_diagnostics() { - self.update_diagnostics() - } - } - } - - if let Some(diagnostic_changes) = self.diagnostics.take_changes() { - for file_id in diagnostic_changes { - let db = self.analysis_host.raw_database(); - let source_root = db.file_source_root(file_id); - if db.source_root(source_root).is_library { - // Only publish diagnostics for files in the workspace, not from crates.io deps - // or the sysroot. - // While theoretically these should never have errors, we have quite a few false - // positives particularly in the stdlib, and those diagnostics would stay around - // forever if we emitted them here. - continue; - } - - let url = file_id_to_url(&self.vfs.read().0, file_id); - let mut diagnostics = - self.diagnostics.diagnostics_for(file_id).cloned().collect::>(); - // https://github.com/rust-lang/rust-analyzer/issues/11404 - for d in &mut diagnostics { - if d.message.is_empty() { - d.message = " ".to_string(); - } - if let Some(rds) = d.related_information.as_mut() { - for rd in rds { - if rd.message.is_empty() { - rd.message = " ".to_string(); - } - } - } - } - let version = from_proto::vfs_path(&url) - .map(|path| self.mem_docs.get(&path).map(|it| it.version)) - .unwrap_or_default(); - - self.send_notification::( - lsp_types::PublishDiagnosticsParams { uri: url, diagnostics, version }, - ); - } - } - - if self.config.cargo_autoreload() { - if let Some(cause) = self.fetch_workspaces_queue.should_start_op() { - self.fetch_workspaces(cause); - } - } - - if !self.fetch_workspaces_queue.op_in_progress() { - if let Some(cause) = self.fetch_build_data_queue.should_start_op() { - self.fetch_build_data(cause); - } - } - - if let Some(cause) = self.prime_caches_queue.should_start_op() { - tracing::debug!(%cause, "will prime caches"); - let num_worker_threads = self.config.prime_caches_num_threads(); - - self.task_pool.handle.spawn_with_sender({ - let analysis = self.snapshot().analysis; - move |sender| { - sender.send(Task::PrimeCaches(PrimeCachesProgress::Begin)).unwrap(); - let res = analysis.parallel_prime_caches(num_worker_threads, |progress| { - let report = PrimeCachesProgress::Report(progress); - sender.send(Task::PrimeCaches(report)).unwrap(); - }); - sender - .send(Task::PrimeCaches(PrimeCachesProgress::End { - cancelled: res.is_err(), - })) - .unwrap(); - } - }); - } - - let status = self.current_status(); - if self.last_reported_status.as_ref() != Some(&status) { - self.last_reported_status = Some(status.clone()); - - if let (lsp_ext::Health::Error, Some(message)) = (status.health, &status.message) { - self.show_message(lsp_types::MessageType::ERROR, message.clone()); - } - - if self.config.server_status_notification() { - self.send_notification::(status); - } - } - - let loop_duration = loop_start.elapsed(); - if loop_duration > Duration::from_millis(100) && was_quiescent { - tracing::warn!("overly long loop turn: {:?}", loop_duration); - self.poke_rust_analyzer_developer(format!( - "overly long loop turn: {:?}", - loop_duration - )); - } - Ok(()) - } - - fn on_new_request(&mut self, request_received: Instant, req: Request) { - self.register_request(&req, request_received); - self.on_request(req); - } - - fn on_request(&mut self, req: Request) { - if self.shutdown_requested { - self.respond(lsp_server::Response::new_err( - req.id, - lsp_server::ErrorCode::InvalidRequest as i32, - "Shutdown already requested.".to_owned(), - )); - return; - } - - // Avoid flashing a bunch of unresolved references during initial load. - if self.workspaces.is_empty() && !self.is_quiescent() { - self.respond(lsp_server::Response::new_err( - req.id, - lsp_server::ErrorCode::ContentModified as i32, - "waiting for cargo metadata or cargo check".to_owned(), - )); - return; - } - - RequestDispatcher { req: Some(req), global_state: self } - .on_sync_mut::(|s, ()| { - s.shutdown_requested = true; - Ok(()) - }) - .on_sync_mut::(handlers::handle_workspace_reload) - .on_sync_mut::(handlers::handle_memory_usage) - .on_sync_mut::(handlers::handle_shuffle_crate_graph) - .on_sync::(handlers::handle_join_lines) - .on_sync::(handlers::handle_on_enter) - .on_sync::(handlers::handle_selection_range) - .on_sync::(handlers::handle_matching_brace) - .on::(handlers::handle_analyzer_status) - .on::(handlers::handle_syntax_tree) - .on::(handlers::handle_view_hir) - .on::(handlers::handle_view_file_text) - .on::(handlers::handle_view_crate_graph) - .on::(handlers::handle_view_item_tree) - .on::(handlers::handle_expand_macro) - .on::(handlers::handle_parent_module) - .on::(handlers::handle_runnables) - .on::(handlers::handle_related_tests) - .on::(handlers::handle_code_action) - .on::(handlers::handle_code_action_resolve) - .on::(handlers::handle_hover) - .on::(handlers::handle_open_docs) - .on::(handlers::handle_open_cargo_toml) - .on::(handlers::handle_move_item) - .on::(handlers::handle_workspace_symbol) - .on::(handlers::handle_on_type_formatting) - .on::(handlers::handle_document_symbol) - .on::(handlers::handle_goto_definition) - .on::(handlers::handle_goto_declaration) - .on::(handlers::handle_goto_implementation) - .on::(handlers::handle_goto_type_definition) - .on::(handlers::handle_inlay_hints) - .on::(handlers::handle_inlay_hints_resolve) - .on::(handlers::handle_completion) - .on::(handlers::handle_completion_resolve) - .on::(handlers::handle_code_lens) - .on::(handlers::handle_code_lens_resolve) - .on::(handlers::handle_folding_range) - .on::(handlers::handle_signature_help) - .on::(handlers::handle_prepare_rename) - .on::(handlers::handle_rename) - .on::(handlers::handle_references) - .on::(handlers::handle_formatting) - .on::(handlers::handle_range_formatting) - .on::(handlers::handle_document_highlight) - .on::(handlers::handle_call_hierarchy_prepare) - .on::( - handlers::handle_call_hierarchy_incoming, - ) - .on::( - handlers::handle_call_hierarchy_outgoing, - ) - .on::( - handlers::handle_semantic_tokens_full, - ) - .on::( - handlers::handle_semantic_tokens_full_delta, - ) - .on::( - handlers::handle_semantic_tokens_range, - ) - .on::(handlers::handle_will_rename_files) - .on::(handlers::handle_ssr) - .finish(); - } - - fn on_notification(&mut self, not: Notification) -> Result<()> { - NotificationDispatcher { not: Some(not), global_state: self } - .on::(|this, params| { - let id: lsp_server::RequestId = match params.id { - lsp_types::NumberOrString::Number(id) => id.into(), - lsp_types::NumberOrString::String(id) => id.into(), - }; - this.cancel(id); - Ok(()) - })? - .on::(|_this, _params| { - // Just ignore this. It is OK to continue sending progress - // notifications for this token, as the client can't know when - // we accepted notification. - Ok(()) - })? - .on::(|this, params| { - if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { - let already_exists = this - .mem_docs - .insert(path.clone(), DocumentData::new(params.text_document.version)) - .is_err(); - if already_exists { - tracing::error!("duplicate DidOpenTextDocument: {}", path) - } - this.vfs - .write() - .0 - .set_file_contents(path, Some(params.text_document.text.into_bytes())); - } - Ok(()) - })? - .on::(|this, params| { - if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { - match this.mem_docs.get_mut(&path) { - Some(doc) => { - // The version passed in DidChangeTextDocument is the version after all edits are applied - // so we should apply it before the vfs is notified. - doc.version = params.text_document.version; - } - None => { - tracing::error!("unexpected DidChangeTextDocument: {}", path); - return Ok(()); - } - }; - - let vfs = &mut this.vfs.write().0; - let file_id = vfs.file_id(&path).unwrap(); - let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap(); - apply_document_changes(&mut text, params.content_changes); - - vfs.set_file_contents(path, Some(text.into_bytes())); - } - Ok(()) - })? - .on::(|this, params| { - if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { - if this.mem_docs.remove(&path).is_err() { - tracing::error!("orphan DidCloseTextDocument: {}", path); - } - - this.semantic_tokens_cache.lock().remove(¶ms.text_document.uri); - - if let Some(path) = path.as_path() { - this.loader.handle.invalidate(path.to_path_buf()); - } - } - Ok(()) - })? - .on::(|this, params| { - for flycheck in &this.flycheck { - flycheck.update(); - } - if let Ok(abs_path) = from_proto::abs_path(¶ms.text_document.uri) { - if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) { - this.fetch_workspaces_queue - .request_op(format!("DidSaveTextDocument {}", abs_path.display())); - } - } - Ok(()) - })? - .on::(|this, _params| { - // As stated in https://github.com/microsoft/language-server-protocol/issues/676, - // this notification's parameters should be ignored and the actual config queried separately. - this.send_request::( - lsp_types::ConfigurationParams { - items: vec![lsp_types::ConfigurationItem { - scope_uri: None, - section: Some("rust-analyzer".to_string()), - }], - }, - |this, resp| { - tracing::debug!("config update response: '{:?}", resp); - let lsp_server::Response { error, result, .. } = resp; - - match (error, result) { - (Some(err), _) => { - tracing::error!("failed to fetch the server settings: {:?}", err) - } - (None, Some(mut configs)) => { - if let Some(json) = configs.get_mut(0) { - // Note that json can be null according to the spec if the client can't - // provide a configuration. This is handled in Config::update below. - let mut config = Config::clone(&*this.config); - if let Err(error) = config.update(json.take()) { - this.show_message( - lsp_types::MessageType::WARNING, - error.to_string(), - ); - } - this.update_configuration(config); - } - } - (None, None) => tracing::error!( - "received empty server settings response from the client" - ), - } - }, - ); - - Ok(()) - })? - .on::(|this, params| { - for change in params.changes { - if let Ok(path) = from_proto::abs_path(&change.uri) { - this.loader.handle.invalidate(path); - } - } - Ok(()) - })? - .finish(); - Ok(()) - } - - fn update_diagnostics(&mut self) { - let subscriptions = self - .mem_docs - .iter() - .map(|path| self.vfs.read().0.file_id(path).unwrap()) - .collect::>(); - - tracing::trace!("updating notifications for {:?}", subscriptions); - - let snapshot = self.snapshot(); - self.task_pool.handle.spawn(move || { - let diagnostics = subscriptions - .into_iter() - .filter_map(|file_id| { - handlers::publish_diagnostics(&snapshot, file_id) - .ok() - .map(|diags| (file_id, diags)) - }) - .collect::>(); - Task::Diagnostics(diagnostics) - }) - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/markdown.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/markdown.rs deleted file mode 100644 index 912ed1e764275..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/markdown.rs +++ /dev/null @@ -1,157 +0,0 @@ -//! Transforms markdown -use ide_db::rust_doc::is_rust_fence; - -const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"]; - -pub(crate) fn format_docs(src: &str) -> String { - let mut processed_lines = Vec::new(); - let mut in_code_block = false; - let mut is_rust = false; - - for mut line in src.lines() { - if in_code_block && is_rust && code_line_ignored_by_rustdoc(line) { - continue; - } - - if let Some(header) = RUSTDOC_FENCES.into_iter().find_map(|fence| line.strip_prefix(fence)) - { - in_code_block ^= true; - - if in_code_block { - is_rust = is_rust_fence(header); - - if is_rust { - line = "```rust"; - } - } - } - - if in_code_block { - let trimmed = line.trim_start(); - if trimmed.starts_with("##") { - line = &trimmed[1..]; - } - } - - processed_lines.push(line); - } - processed_lines.join("\n") -} - -fn code_line_ignored_by_rustdoc(line: &str) -> bool { - let trimmed = line.trim(); - trimmed == "#" || trimmed.starts_with("# ") || trimmed.starts_with("#\t") -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_format_docs_adds_rust() { - let comment = "```\nfn some_rust() {}\n```"; - assert_eq!(format_docs(comment), "```rust\nfn some_rust() {}\n```"); - } - - #[test] - fn test_format_docs_handles_plain_text() { - let comment = "```text\nthis is plain text\n```"; - assert_eq!(format_docs(comment), "```text\nthis is plain text\n```"); - } - - #[test] - fn test_format_docs_handles_non_rust() { - let comment = "```sh\nsupposedly shell code\n```"; - assert_eq!(format_docs(comment), "```sh\nsupposedly shell code\n```"); - } - - #[test] - fn test_format_docs_handles_rust_alias() { - let comment = "```ignore\nlet z = 55;\n```"; - assert_eq!(format_docs(comment), "```rust\nlet z = 55;\n```"); - } - - #[test] - fn test_format_docs_handles_complex_code_block_attrs() { - let comment = "```rust,no_run\nlet z = 55;\n```"; - assert_eq!(format_docs(comment), "```rust\nlet z = 55;\n```"); - } - - #[test] - fn test_format_docs_handles_error_codes() { - let comment = "```compile_fail,E0641\nlet b = 0 as *const _;\n```"; - assert_eq!(format_docs(comment), "```rust\nlet b = 0 as *const _;\n```"); - } - - #[test] - fn test_format_docs_skips_comments_in_rust_block() { - let comment = - "```rust\n # skip1\n# skip2\n#stay1\nstay2\n#\n #\n # \n #\tskip3\n\t#\t\n```"; - assert_eq!(format_docs(comment), "```rust\n#stay1\nstay2\n```"); - } - - #[test] - fn test_format_docs_does_not_skip_lines_if_plain_text() { - let comment = - "```text\n # stay1\n# stay2\n#stay3\nstay4\n#\n #\n # \n #\tstay5\n\t#\t\n```"; - assert_eq!( - format_docs(comment), - "```text\n # stay1\n# stay2\n#stay3\nstay4\n#\n #\n # \n #\tstay5\n\t#\t\n```", - ); - } - - #[test] - fn test_format_docs_keeps_comments_outside_of_rust_block() { - let comment = " # stay1\n# stay2\n#stay3\nstay4\n#\n #\n # \n #\tstay5\n\t#\t"; - assert_eq!(format_docs(comment), comment); - } - - #[test] - fn test_format_docs_preserves_newlines() { - let comment = "this\nis\nmultiline"; - assert_eq!(format_docs(comment), comment); - } - - #[test] - fn test_code_blocks_in_comments_marked_as_rust() { - let comment = r#"```rust -fn main(){} -``` -Some comment. -``` -let a = 1; -```"#; - - assert_eq!( - format_docs(comment), - "```rust\nfn main(){}\n```\nSome comment.\n```rust\nlet a = 1;\n```" - ); - } - - #[test] - fn test_code_blocks_in_comments_marked_as_text() { - let comment = r#"```text -filler -text -``` -Some comment. -``` -let a = 1; -```"#; - - assert_eq!( - format_docs(comment), - "```text\nfiller\ntext\n```\nSome comment.\n```rust\nlet a = 1;\n```" - ); - } - - #[test] - fn test_format_docs_handles_escape_double_hashes() { - let comment = r#"```rust -let s = "foo -## bar # baz"; -```"#; - - assert_eq!(format_docs(comment), "```rust\nlet s = \"foo\n# bar # baz\";\n```"); - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/mem_docs.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/mem_docs.rs deleted file mode 100644 index f86a0f66ad8d6..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/mem_docs.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! In-memory document information. - -use std::mem; - -use rustc_hash::FxHashMap; -use vfs::VfsPath; - -/// Holds the set of in-memory documents. -/// -/// For these document, there true contents is maintained by the client. It -/// might be different from what's on disk. -#[derive(Default, Clone)] -pub(crate) struct MemDocs { - mem_docs: FxHashMap, - added_or_removed: bool, -} - -impl MemDocs { - pub(crate) fn contains(&self, path: &VfsPath) -> bool { - self.mem_docs.contains_key(path) - } - pub(crate) fn insert(&mut self, path: VfsPath, data: DocumentData) -> Result<(), ()> { - self.added_or_removed = true; - match self.mem_docs.insert(path, data) { - Some(_) => Err(()), - None => Ok(()), - } - } - pub(crate) fn remove(&mut self, path: &VfsPath) -> Result<(), ()> { - self.added_or_removed = true; - match self.mem_docs.remove(path) { - Some(_) => Ok(()), - None => Err(()), - } - } - pub(crate) fn get(&self, path: &VfsPath) -> Option<&DocumentData> { - self.mem_docs.get(path) - } - pub(crate) fn get_mut(&mut self, path: &VfsPath) -> Option<&mut DocumentData> { - // NB: don't set `self.added_or_removed` here, as that purposefully only - // tracks changes to the key set. - self.mem_docs.get_mut(path) - } - pub(crate) fn iter(&self) -> impl Iterator { - self.mem_docs.keys() - } - pub(crate) fn take_changes(&mut self) -> bool { - mem::replace(&mut self.added_or_removed, false) - } -} - -/// Information about a document that the Language Client -/// knows about. -/// Its lifetime is driven by the textDocument/didOpen and textDocument/didClose -/// client notifications. -#[derive(Debug, Clone)] -pub(crate) struct DocumentData { - pub(crate) version: i32, -} - -impl DocumentData { - pub(crate) fn new(version: i32) -> Self { - DocumentData { version } - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs deleted file mode 100644 index 97aca0161873e..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! Bookkeeping to make sure only one long-running operation is being executed -//! at a time. - -pub(crate) type Cause = String; - -pub(crate) struct OpQueue { - op_requested: Option, - op_in_progress: bool, - last_op_result: Output, -} - -impl Default for OpQueue { - fn default() -> Self { - Self { op_requested: None, op_in_progress: false, last_op_result: Default::default() } - } -} - -impl OpQueue { - pub(crate) fn request_op(&mut self, reason: Cause) { - self.op_requested = Some(reason); - } - pub(crate) fn should_start_op(&mut self) -> Option { - if self.op_in_progress { - return None; - } - self.op_in_progress = self.op_requested.is_some(); - self.op_requested.take() - } - pub(crate) fn op_completed(&mut self, result: Output) { - assert!(self.op_in_progress); - self.op_in_progress = false; - self.last_op_result = result; - } - - pub(crate) fn last_op_result(&self) -> &Output { - &self.last_op_result - } - pub(crate) fn op_in_progress(&self) -> bool { - self.op_in_progress - } - pub(crate) fn op_requested(&self) -> bool { - self.op_requested.is_some() - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs deleted file mode 100644 index 9ae361b034e28..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ /dev/null @@ -1,701 +0,0 @@ -//! Project loading & configuration updates. -//! -//! This is quite tricky. The main problem is time and changes -- there's no -//! fixed "project" rust-analyzer is working with, "current project" is itself -//! mutable state. For example, when the user edits `Cargo.toml` by adding a new -//! dependency, project model changes. What's more, switching project model is -//! not instantaneous -- it takes time to run `cargo metadata` and (for proc -//! macros) `cargo check`. -//! -//! The main guiding principle here is, as elsewhere in rust-analyzer, -//! robustness. We try not to assume that the project model exists or is -//! correct. Instead, we try to provide a best-effort service. Even if the -//! project is currently loading and we don't have a full project model, we -//! still want to respond to various requests. -use std::{mem, sync::Arc}; - -use flycheck::{FlycheckConfig, FlycheckHandle}; -use hir::db::DefDatabase; -use ide::Change; -use ide_db::base_db::{ - CrateGraph, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, - ProcMacroLoadResult, SourceRoot, VfsPath, -}; -use proc_macro_api::{MacroDylib, ProcMacroServer}; -use project_model::{ProjectWorkspace, WorkspaceBuildScripts}; -use syntax::SmolStr; -use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind}; - -use crate::{ - config::{Config, FilesWatcher, LinkedProject}, - global_state::GlobalState, - lsp_ext, - main_loop::Task, - op_queue::Cause, -}; - -#[derive(Debug)] -pub(crate) enum ProjectWorkspaceProgress { - Begin, - Report(String), - End(Vec>), -} - -#[derive(Debug)] -pub(crate) enum BuildDataProgress { - Begin, - Report(String), - End((Arc>, Vec>)), -} - -impl GlobalState { - pub(crate) fn is_quiescent(&self) -> bool { - !(self.fetch_workspaces_queue.op_in_progress() - || self.fetch_build_data_queue.op_in_progress() - || self.vfs_progress_config_version < self.vfs_config_version - || self.vfs_progress_n_done < self.vfs_progress_n_total) - } - - pub(crate) fn update_configuration(&mut self, config: Config) { - let _p = profile::span("GlobalState::update_configuration"); - let old_config = mem::replace(&mut self.config, Arc::new(config)); - if self.config.lru_capacity() != old_config.lru_capacity() { - self.analysis_host.update_lru_capacity(self.config.lru_capacity()); - } - if self.config.linked_projects() != old_config.linked_projects() { - self.fetch_workspaces_queue.request_op("linked projects changed".to_string()) - } else if self.config.flycheck() != old_config.flycheck() { - self.reload_flycheck(); - } - - if self.analysis_host.raw_database().enable_proc_attr_macros() - != self.config.expand_proc_attr_macros() - { - self.analysis_host - .raw_database_mut() - .set_enable_proc_attr_macros(self.config.expand_proc_attr_macros()); - } - } - - pub(crate) fn current_status(&self) -> lsp_ext::ServerStatusParams { - let mut status = lsp_ext::ServerStatusParams { - health: lsp_ext::Health::Ok, - quiescent: self.is_quiescent(), - message: None, - }; - - if self.proc_macro_changed { - status.health = lsp_ext::Health::Warning; - status.message = - Some("Reload required due to source changes of a procedural macro.".into()) - } - if let Err(_) = self.fetch_build_data_error() { - status.health = lsp_ext::Health::Warning; - status.message = - Some("Failed to run build scripts of some packages, check the logs.".to_string()); - } - if !self.config.cargo_autoreload() - && self.is_quiescent() - && self.fetch_workspaces_queue.op_requested() - { - status.health = lsp_ext::Health::Warning; - status.message = Some("Workspace reload required".to_string()) - } - - if let Err(error) = self.fetch_workspace_error() { - status.health = lsp_ext::Health::Error; - status.message = Some(error) - } - status - } - - pub(crate) fn fetch_workspaces(&mut self, cause: Cause) { - tracing::info!(%cause, "will fetch workspaces"); - - self.task_pool.handle.spawn_with_sender({ - let linked_projects = self.config.linked_projects(); - let detached_files = self.config.detached_files().to_vec(); - let cargo_config = self.config.cargo(); - - move |sender| { - let progress = { - let sender = sender.clone(); - move |msg| { - sender - .send(Task::FetchWorkspace(ProjectWorkspaceProgress::Report(msg))) - .unwrap() - } - }; - - sender.send(Task::FetchWorkspace(ProjectWorkspaceProgress::Begin)).unwrap(); - - let mut workspaces = linked_projects - .iter() - .map(|project| match project { - LinkedProject::ProjectManifest(manifest) => { - project_model::ProjectWorkspace::load( - manifest.clone(), - &cargo_config, - &progress, - ) - } - LinkedProject::InlineJsonProject(it) => { - project_model::ProjectWorkspace::load_inline( - it.clone(), - cargo_config.target.as_deref(), - ) - } - }) - .collect::>(); - - if !detached_files.is_empty() { - workspaces - .push(project_model::ProjectWorkspace::load_detached_files(detached_files)); - } - - tracing::info!("did fetch workspaces {:?}", workspaces); - sender - .send(Task::FetchWorkspace(ProjectWorkspaceProgress::End(workspaces))) - .unwrap(); - } - }); - } - - pub(crate) fn fetch_build_data(&mut self, cause: Cause) { - tracing::info!(%cause, "will fetch build data"); - let workspaces = Arc::clone(&self.workspaces); - let config = self.config.cargo(); - self.task_pool.handle.spawn_with_sender(move |sender| { - sender.send(Task::FetchBuildData(BuildDataProgress::Begin)).unwrap(); - - let progress = { - let sender = sender.clone(); - move |msg| { - sender.send(Task::FetchBuildData(BuildDataProgress::Report(msg))).unwrap() - } - }; - let mut res = Vec::new(); - for ws in workspaces.iter() { - res.push(ws.run_build_scripts(&config, &progress)); - } - sender.send(Task::FetchBuildData(BuildDataProgress::End((workspaces, res)))).unwrap(); - }); - } - - pub(crate) fn switch_workspaces(&mut self, cause: Cause) { - let _p = profile::span("GlobalState::switch_workspaces"); - tracing::info!(%cause, "will switch workspaces"); - - if let Err(error_message) = self.fetch_workspace_error() { - self.show_and_log_error(error_message, None); - if !self.workspaces.is_empty() { - // It only makes sense to switch to a partially broken workspace - // if we don't have any workspace at all yet. - return; - } - } - - if let Err(error) = self.fetch_build_data_error() { - self.show_and_log_error( - "rust-analyzer failed to run build scripts".to_string(), - Some(error), - ); - } - - let workspaces = self - .fetch_workspaces_queue - .last_op_result() - .iter() - .filter_map(|res| res.as_ref().ok().cloned()) - .collect::>(); - - fn eq_ignore_build_data<'a>( - left: &'a ProjectWorkspace, - right: &'a ProjectWorkspace, - ) -> bool { - let key = |p: &'a ProjectWorkspace| match p { - ProjectWorkspace::Cargo { - cargo, - sysroot, - rustc, - rustc_cfg, - cfg_overrides, - - build_scripts: _, - } => Some((cargo, sysroot, rustc, rustc_cfg, cfg_overrides)), - _ => None, - }; - match (key(left), key(right)) { - (Some(lk), Some(rk)) => lk == rk, - _ => left == right, - } - } - - let same_workspaces = workspaces.len() == self.workspaces.len() - && workspaces - .iter() - .zip(self.workspaces.iter()) - .all(|(l, r)| eq_ignore_build_data(l, r)); - - if same_workspaces { - let (workspaces, build_scripts) = self.fetch_build_data_queue.last_op_result(); - if Arc::ptr_eq(workspaces, &self.workspaces) { - tracing::debug!("set build scripts to workspaces"); - - let workspaces = workspaces - .iter() - .cloned() - .zip(build_scripts) - .map(|(mut ws, bs)| { - ws.set_build_scripts(bs.as_ref().ok().cloned().unwrap_or_default()); - ws - }) - .collect::>(); - - // Workspaces are the same, but we've updated build data. - self.workspaces = Arc::new(workspaces); - } else { - tracing::info!("build scripts do not match the version of the active workspace"); - // Current build scripts do not match the version of the active - // workspace, so there's nothing for us to update. - return; - } - } else { - tracing::debug!("abandon build scripts for workspaces"); - - // Here, we completely changed the workspace (Cargo.toml edit), so - // we don't care about build-script results, they are stale. - self.workspaces = Arc::new(workspaces) - } - - if let FilesWatcher::Client = self.config.files().watcher { - let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions { - watchers: self - .workspaces - .iter() - .flat_map(|ws| ws.to_roots()) - .filter(|it| it.is_local) - .flat_map(|root| { - root.include.into_iter().flat_map(|it| { - [ - format!("{}/**/*.rs", it.display()), - format!("{}/**/Cargo.toml", it.display()), - format!("{}/**/Cargo.lock", it.display()), - ] - }) - }) - .map(|glob_pattern| lsp_types::FileSystemWatcher { glob_pattern, kind: None }) - .collect(), - }; - let registration = lsp_types::Registration { - id: "workspace/didChangeWatchedFiles".to_string(), - method: "workspace/didChangeWatchedFiles".to_string(), - register_options: Some(serde_json::to_value(registration_options).unwrap()), - }; - self.send_request::( - lsp_types::RegistrationParams { registrations: vec![registration] }, - |_, _| (), - ); - } - - let mut change = Change::new(); - - let files_config = self.config.files(); - let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude); - - if self.proc_macro_clients.is_empty() { - if let Some((path, args)) = self.config.proc_macro_srv() { - self.proc_macro_clients = self - .workspaces - .iter() - .map(|ws| { - let mut args = args.clone(); - let mut path = path.clone(); - - if let ProjectWorkspace::Cargo { sysroot, .. } = ws { - tracing::info!("Found a cargo workspace..."); - if let Some(sysroot) = sysroot.as_ref() { - tracing::info!("Found a cargo workspace with a sysroot..."); - let server_path = sysroot - .root() - .join("libexec") - .join("rust-analyzer-proc-macro-srv"); - if std::fs::metadata(&server_path).is_ok() { - tracing::info!( - "And the server exists at {}", - server_path.display() - ); - path = server_path; - args = vec![]; - } else { - tracing::info!( - "And the server does not exist at {}", - server_path.display() - ); - } - } - } - - tracing::info!( - "Using proc-macro server at {} with args {:?}", - path.display(), - args - ); - ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| { - let error = format!( - "Failed to run proc_macro_srv from path {}, error: {:?}", - path.display(), - err - ); - tracing::error!(error); - error - }) - }) - .collect(); - } - } - - let watch = match files_config.watcher { - FilesWatcher::Client => vec![], - FilesWatcher::Server => project_folders.watch, - }; - self.vfs_config_version += 1; - self.loader.handle.set_config(vfs::loader::Config { - load: project_folders.load, - watch, - version: self.vfs_config_version, - }); - - // Create crate graph from all the workspaces - let crate_graph = { - let dummy_replacements = self.config.dummy_replacements(); - - let vfs = &mut self.vfs.write().0; - let loader = &mut self.loader; - let mem_docs = &self.mem_docs; - let mut load = move |path: &AbsPath| { - let _p = profile::span("GlobalState::load"); - let vfs_path = vfs::VfsPath::from(path.to_path_buf()); - if !mem_docs.contains(&vfs_path) { - let contents = loader.handle.load_sync(path); - vfs.set_file_contents(vfs_path.clone(), contents); - } - let res = vfs.file_id(&vfs_path); - if res.is_none() { - tracing::warn!("failed to load {}", path.display()) - } - res - }; - - let mut crate_graph = CrateGraph::default(); - for (idx, ws) in self.workspaces.iter().enumerate() { - let proc_macro_client = self.proc_macro_clients[idx].as_ref(); - let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| { - load_proc_macro( - proc_macro_client, - path, - dummy_replacements.get(crate_name).map(|v| &**v).unwrap_or_default(), - ) - }; - crate_graph.extend(ws.to_crate_graph(&mut load_proc_macro, &mut load)); - } - crate_graph - }; - change.set_crate_graph(crate_graph); - - self.source_root_config = project_folders.source_root_config; - - self.analysis_host.apply_change(change); - self.process_changes(); - self.reload_flycheck(); - tracing::info!("did switch workspaces"); - } - - fn fetch_workspace_error(&self) -> Result<(), String> { - let mut buf = String::new(); - - for ws in self.fetch_workspaces_queue.last_op_result() { - if let Err(err) = ws { - stdx::format_to!(buf, "rust-analyzer failed to load workspace: {:#}\n", err); - } - } - - if buf.is_empty() { - return Ok(()); - } - - Err(buf) - } - - fn fetch_build_data_error(&self) -> Result<(), String> { - let mut buf = String::new(); - - for ws in &self.fetch_build_data_queue.last_op_result().1 { - match ws { - Ok(data) => match data.error() { - Some(stderr) => stdx::format_to!(buf, "{:#}\n", stderr), - _ => (), - }, - // io errors - Err(err) => stdx::format_to!(buf, "{:#}\n", err), - } - } - - if buf.is_empty() { - Ok(()) - } else { - Err(buf) - } - } - - fn reload_flycheck(&mut self) { - let _p = profile::span("GlobalState::reload_flycheck"); - let config = match self.config.flycheck() { - Some(it) => it, - None => { - self.flycheck = Vec::new(); - self.diagnostics.clear_check(); - return; - } - }; - - let sender = self.flycheck_sender.clone(); - self.flycheck = self - .workspaces - .iter() - .enumerate() - .filter_map(|(id, w)| match w { - ProjectWorkspace::Cargo { cargo, .. } => Some((id, cargo.workspace_root())), - ProjectWorkspace::Json { project, .. } => { - // Enable flychecks for json projects if a custom flycheck command was supplied - // in the workspace configuration. - match config { - FlycheckConfig::CustomCommand { .. } => Some((id, project.path())), - _ => None, - } - } - ProjectWorkspace::DetachedFiles { .. } => None, - }) - .map(|(id, root)| { - let sender = sender.clone(); - FlycheckHandle::spawn( - id, - Box::new(move |msg| sender.send(msg).unwrap()), - config.clone(), - root.to_path_buf(), - ) - }) - .collect(); - } -} - -#[derive(Default)] -pub(crate) struct ProjectFolders { - pub(crate) load: Vec, - pub(crate) watch: Vec, - pub(crate) source_root_config: SourceRootConfig, -} - -impl ProjectFolders { - pub(crate) fn new( - workspaces: &[ProjectWorkspace], - global_excludes: &[AbsPathBuf], - ) -> ProjectFolders { - let mut res = ProjectFolders::default(); - let mut fsc = FileSetConfig::builder(); - let mut local_filesets = vec![]; - - for root in workspaces.iter().flat_map(|ws| ws.to_roots()) { - let file_set_roots: Vec = - root.include.iter().cloned().map(VfsPath::from).collect(); - - let entry = { - let mut dirs = vfs::loader::Directories::default(); - dirs.extensions.push("rs".into()); - dirs.include.extend(root.include); - dirs.exclude.extend(root.exclude); - for excl in global_excludes { - if dirs - .include - .iter() - .any(|incl| incl.starts_with(excl) || excl.starts_with(incl)) - { - dirs.exclude.push(excl.clone()); - } - } - - vfs::loader::Entry::Directories(dirs) - }; - - if root.is_local { - res.watch.push(res.load.len()); - } - res.load.push(entry); - - if root.is_local { - local_filesets.push(fsc.len()); - } - fsc.add_file_set(file_set_roots) - } - - let fsc = fsc.build(); - res.source_root_config = SourceRootConfig { fsc, local_filesets }; - - res - } -} - -#[derive(Default, Debug)] -pub(crate) struct SourceRootConfig { - pub(crate) fsc: FileSetConfig, - pub(crate) local_filesets: Vec, -} - -impl SourceRootConfig { - pub(crate) fn partition(&self, vfs: &vfs::Vfs) -> Vec { - let _p = profile::span("SourceRootConfig::partition"); - self.fsc - .partition(vfs) - .into_iter() - .enumerate() - .map(|(idx, file_set)| { - let is_local = self.local_filesets.contains(&idx); - if is_local { - SourceRoot::new_local(file_set) - } else { - SourceRoot::new_library(file_set) - } - }) - .collect() - } -} - -/// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace` -/// with an identity dummy expander. -pub(crate) fn load_proc_macro( - server: Result<&ProcMacroServer, &String>, - path: &AbsPath, - dummy_replace: &[Box], -) -> ProcMacroLoadResult { - let res: Result, String> = (|| { - let dylib = MacroDylib::new(path.to_path_buf()) - .map_err(|io| format!("Proc-macro dylib loading failed: {io}"))?; - let server = server.map_err(ToOwned::to_owned)?; - let vec = server.load_dylib(dylib).map_err(|e| format!("{e}"))?; - if vec.is_empty() { - return Err("proc macro library returned no proc macros".to_string()); - } - Ok(vec - .into_iter() - .map(|expander| expander_to_proc_macro(expander, dummy_replace)) - .collect()) - })(); - return match res { - Ok(proc_macros) => { - tracing::info!( - "Loaded proc-macros for {}: {:?}", - path.display(), - proc_macros.iter().map(|it| it.name.clone()).collect::>() - ); - Ok(proc_macros) - } - Err(e) => { - tracing::warn!("proc-macro loading for {} failed: {e}", path.display()); - Err(e) - } - }; - - fn expander_to_proc_macro( - expander: proc_macro_api::ProcMacro, - dummy_replace: &[Box], - ) -> ProcMacro { - let name = SmolStr::from(expander.name()); - let kind = match expander.kind() { - proc_macro_api::ProcMacroKind::CustomDerive => ProcMacroKind::CustomDerive, - proc_macro_api::ProcMacroKind::FuncLike => ProcMacroKind::FuncLike, - proc_macro_api::ProcMacroKind::Attr => ProcMacroKind::Attr, - }; - let expander: Arc = - if dummy_replace.iter().any(|replace| &**replace == name) { - Arc::new(DummyExpander) - } else { - Arc::new(Expander(expander)) - }; - ProcMacro { name, kind, expander } - } - - #[derive(Debug)] - struct Expander(proc_macro_api::ProcMacro); - - impl ProcMacroExpander for Expander { - fn expand( - &self, - subtree: &tt::Subtree, - attrs: Option<&tt::Subtree>, - env: &Env, - ) -> Result { - let env = env.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect(); - match self.0.expand(subtree, attrs, env) { - Ok(Ok(subtree)) => Ok(subtree), - Ok(Err(err)) => Err(ProcMacroExpansionError::Panic(err.0)), - Err(err) => Err(ProcMacroExpansionError::System(err.to_string())), - } - } - } - - /// Dummy identity expander, used for proc-macros that are deliberately ignored by the user. - #[derive(Debug)] - struct DummyExpander; - - impl ProcMacroExpander for DummyExpander { - fn expand( - &self, - subtree: &tt::Subtree, - _: Option<&tt::Subtree>, - _: &Env, - ) -> Result { - Ok(subtree.clone()) - } - } -} - -pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool { - const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"]; - const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"]; - let file_name = path.file_name().unwrap_or_default(); - - if file_name == "Cargo.toml" || file_name == "Cargo.lock" { - return true; - } - if change_kind == ChangeKind::Modify { - return false; - } - if path.extension().unwrap_or_default() != "rs" { - if (file_name == "config.toml" || file_name == "config") - && path.parent().map(|parent| parent.as_ref().ends_with(".cargo")) == Some(true) - { - return true; - } - return false; - } - if IMPLICIT_TARGET_FILES.iter().any(|it| path.as_ref().ends_with(it)) { - return true; - } - let parent = match path.parent() { - Some(it) => it, - None => return false, - }; - if IMPLICIT_TARGET_DIRS.iter().any(|it| parent.as_ref().ends_with(it)) { - return true; - } - if file_name == "main.rs" { - let grand_parent = match parent.parent() { - Some(it) => it, - None => return false, - }; - if IMPLICIT_TARGET_DIRS.iter().any(|it| grand_parent.as_ref().ends_with(it)) { - return true; - } - } - false -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/semantic_tokens.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/semantic_tokens.rs deleted file mode 100644 index 6c78b5df1a705..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/semantic_tokens.rs +++ /dev/null @@ -1,301 +0,0 @@ -//! Semantic Tokens helpers - -use std::ops; - -use lsp_types::{ - Range, SemanticToken, SemanticTokenModifier, SemanticTokenType, SemanticTokens, - SemanticTokensEdit, -}; - -macro_rules! define_semantic_token_types { - ($(($ident:ident, $string:literal)),*$(,)?) => { - $(pub(crate) const $ident: SemanticTokenType = SemanticTokenType::new($string);)* - - pub(crate) const SUPPORTED_TYPES: &[SemanticTokenType] = &[ - SemanticTokenType::COMMENT, - SemanticTokenType::KEYWORD, - SemanticTokenType::STRING, - SemanticTokenType::NUMBER, - SemanticTokenType::REGEXP, - SemanticTokenType::OPERATOR, - SemanticTokenType::NAMESPACE, - SemanticTokenType::TYPE, - SemanticTokenType::STRUCT, - SemanticTokenType::CLASS, - SemanticTokenType::INTERFACE, - SemanticTokenType::ENUM, - SemanticTokenType::ENUM_MEMBER, - SemanticTokenType::TYPE_PARAMETER, - SemanticTokenType::FUNCTION, - SemanticTokenType::METHOD, - SemanticTokenType::PROPERTY, - SemanticTokenType::MACRO, - SemanticTokenType::VARIABLE, - SemanticTokenType::PARAMETER, - $($ident),* - ]; - }; -} - -define_semantic_token_types![ - (ANGLE, "angle"), - (ARITHMETIC, "arithmetic"), - (ATTRIBUTE, "attribute"), - (ATTRIBUTE_BRACKET, "attributeBracket"), - (BITWISE, "bitwise"), - (BOOLEAN, "boolean"), - (BRACE, "brace"), - (BRACKET, "bracket"), - (BUILTIN_ATTRIBUTE, "builtinAttribute"), - (BUILTIN_TYPE, "builtinType"), - (CHAR, "character"), - (COLON, "colon"), - (COMMA, "comma"), - (COMPARISON, "comparison"), - (CONST_PARAMETER, "constParameter"), - (DERIVE, "derive"), - (DERIVE_HELPER, "deriveHelper"), - (DOT, "dot"), - (ESCAPE_SEQUENCE, "escapeSequence"), - (FORMAT_SPECIFIER, "formatSpecifier"), - (GENERIC, "generic"), - (LABEL, "label"), - (LIFETIME, "lifetime"), - (LOGICAL, "logical"), - (MACRO_BANG, "macroBang"), - (OPERATOR, "operator"), - (PARENTHESIS, "parenthesis"), - (PUNCTUATION, "punctuation"), - (SELF_KEYWORD, "selfKeyword"), - (SELF_TYPE_KEYWORD, "selfTypeKeyword"), - (SEMICOLON, "semicolon"), - (TYPE_ALIAS, "typeAlias"), - (TOOL_MODULE, "toolModule"), - (UNION, "union"), - (UNRESOLVED_REFERENCE, "unresolvedReference"), -]; - -macro_rules! define_semantic_token_modifiers { - ($(($ident:ident, $string:literal)),*$(,)?) => { - $(pub(crate) const $ident: SemanticTokenModifier = SemanticTokenModifier::new($string);)* - - pub(crate) const SUPPORTED_MODIFIERS: &[SemanticTokenModifier] = &[ - SemanticTokenModifier::DOCUMENTATION, - SemanticTokenModifier::DECLARATION, - SemanticTokenModifier::DEFINITION, - SemanticTokenModifier::STATIC, - SemanticTokenModifier::ABSTRACT, - SemanticTokenModifier::DEPRECATED, - SemanticTokenModifier::READONLY, - SemanticTokenModifier::DEFAULT_LIBRARY, - $($ident),* - ]; - }; -} - -define_semantic_token_modifiers![ - (ASYNC, "async"), - (ATTRIBUTE_MODIFIER, "attribute"), - (CALLABLE, "callable"), - (CONSTANT, "constant"), - (CONSUMING, "consuming"), - (CONTROL_FLOW, "controlFlow"), - (CRATE_ROOT, "crateRoot"), - (INJECTED, "injected"), - (INTRA_DOC_LINK, "intraDocLink"), - (LIBRARY, "library"), - (MUTABLE, "mutable"), - (PUBLIC, "public"), - (REFERENCE, "reference"), - (TRAIT_MODIFIER, "trait"), - (UNSAFE, "unsafe"), -]; - -#[derive(Default)] -pub(crate) struct ModifierSet(pub(crate) u32); - -impl ops::BitOrAssign for ModifierSet { - fn bitor_assign(&mut self, rhs: SemanticTokenModifier) { - let idx = SUPPORTED_MODIFIERS.iter().position(|it| it == &rhs).unwrap(); - self.0 |= 1 << idx; - } -} - -/// Tokens are encoded relative to each other. -/// -/// This is a direct port of -pub(crate) struct SemanticTokensBuilder { - id: String, - prev_line: u32, - prev_char: u32, - data: Vec, -} - -impl SemanticTokensBuilder { - pub(crate) fn new(id: String) -> Self { - SemanticTokensBuilder { id, prev_line: 0, prev_char: 0, data: Default::default() } - } - - /// Push a new token onto the builder - pub(crate) fn push(&mut self, range: Range, token_index: u32, modifier_bitset: u32) { - let mut push_line = range.start.line as u32; - let mut push_char = range.start.character as u32; - - if !self.data.is_empty() { - push_line -= self.prev_line; - if push_line == 0 { - push_char -= self.prev_char; - } - } - - // A token cannot be multiline - let token_len = range.end.character - range.start.character; - - let token = SemanticToken { - delta_line: push_line, - delta_start: push_char, - length: token_len as u32, - token_type: token_index, - token_modifiers_bitset: modifier_bitset, - }; - - self.data.push(token); - - self.prev_line = range.start.line as u32; - self.prev_char = range.start.character as u32; - } - - pub(crate) fn build(self) -> SemanticTokens { - SemanticTokens { result_id: Some(self.id), data: self.data } - } -} - -pub(crate) fn diff_tokens(old: &[SemanticToken], new: &[SemanticToken]) -> Vec { - let offset = new.iter().zip(old.iter()).take_while(|&(n, p)| n == p).count(); - - let (_, old) = old.split_at(offset); - let (_, new) = new.split_at(offset); - - let offset_from_end = - new.iter().rev().zip(old.iter().rev()).take_while(|&(n, p)| n == p).count(); - - let (old, _) = old.split_at(old.len() - offset_from_end); - let (new, _) = new.split_at(new.len() - offset_from_end); - - if old.is_empty() && new.is_empty() { - vec![] - } else { - // The lsp data field is actually a byte-diff but we - // travel in tokens so `start` and `delete_count` are in multiples of the - // serialized size of `SemanticToken`. - vec![SemanticTokensEdit { - start: 5 * offset as u32, - delete_count: 5 * old.len() as u32, - data: Some(new.into()), - }] - } -} - -pub(crate) fn type_index(ty: SemanticTokenType) -> u32 { - SUPPORTED_TYPES.iter().position(|it| *it == ty).unwrap() as u32 -} - -#[cfg(test)] -mod tests { - use super::*; - - fn from(t: (u32, u32, u32, u32, u32)) -> SemanticToken { - SemanticToken { - delta_line: t.0, - delta_start: t.1, - length: t.2, - token_type: t.3, - token_modifiers_bitset: t.4, - } - } - - #[test] - fn test_diff_insert_at_end() { - let before = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))]; - let after = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10)), from((11, 12, 13, 14, 15))]; - - let edits = diff_tokens(&before, &after); - assert_eq!( - edits[0], - SemanticTokensEdit { - start: 10, - delete_count: 0, - data: Some(vec![from((11, 12, 13, 14, 15))]) - } - ); - } - - #[test] - fn test_diff_insert_at_beginning() { - let before = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))]; - let after = [from((11, 12, 13, 14, 15)), from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))]; - - let edits = diff_tokens(&before, &after); - assert_eq!( - edits[0], - SemanticTokensEdit { - start: 0, - delete_count: 0, - data: Some(vec![from((11, 12, 13, 14, 15))]) - } - ); - } - - #[test] - fn test_diff_insert_in_middle() { - let before = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))]; - let after = [ - from((1, 2, 3, 4, 5)), - from((10, 20, 30, 40, 50)), - from((60, 70, 80, 90, 100)), - from((6, 7, 8, 9, 10)), - ]; - - let edits = diff_tokens(&before, &after); - assert_eq!( - edits[0], - SemanticTokensEdit { - start: 5, - delete_count: 0, - data: Some(vec![from((10, 20, 30, 40, 50)), from((60, 70, 80, 90, 100))]) - } - ); - } - - #[test] - fn test_diff_remove_from_end() { - let before = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10)), from((11, 12, 13, 14, 15))]; - let after = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))]; - - let edits = diff_tokens(&before, &after); - assert_eq!(edits[0], SemanticTokensEdit { start: 10, delete_count: 5, data: Some(vec![]) }); - } - - #[test] - fn test_diff_remove_from_beginning() { - let before = [from((11, 12, 13, 14, 15)), from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))]; - let after = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))]; - - let edits = diff_tokens(&before, &after); - assert_eq!(edits[0], SemanticTokensEdit { start: 0, delete_count: 5, data: Some(vec![]) }); - } - - #[test] - fn test_diff_remove_from_middle() { - let before = [ - from((1, 2, 3, 4, 5)), - from((10, 20, 30, 40, 50)), - from((60, 70, 80, 90, 100)), - from((6, 7, 8, 9, 10)), - ]; - let after = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))]; - - let edits = diff_tokens(&before, &after); - assert_eq!(edits[0], SemanticTokensEdit { start: 5, delete_count: 10, data: Some(vec![]) }); - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs deleted file mode 100644 index aeeb3b7c582b1..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! A thin wrapper around `ThreadPool` to make sure that we join all things -//! properly. -use crossbeam_channel::Sender; - -pub(crate) struct TaskPool { - sender: Sender, - inner: threadpool::ThreadPool, -} - -impl TaskPool { - pub(crate) fn new(sender: Sender) -> TaskPool { - const STACK_SIZE: usize = 8 * 1024 * 1024; - - let inner = threadpool::Builder::new() - .thread_name("Worker".into()) - .thread_stack_size(STACK_SIZE) - .build(); - TaskPool { sender, inner } - } - - pub(crate) fn spawn(&mut self, task: F) - where - F: FnOnce() -> T + Send + 'static, - T: Send + 'static, - { - self.inner.execute({ - let sender = self.sender.clone(); - move || sender.send(task()).unwrap() - }) - } - - pub(crate) fn spawn_with_sender(&mut self, task: F) - where - F: FnOnce(Sender) + Send + 'static, - T: Send + 'static, - { - self.inner.execute({ - let sender = self.sender.clone(); - move || task(sender) - }) - } - - pub(crate) fn len(&self) -> usize { - self.inner.queued_count() - } -} - -impl Drop for TaskPool { - fn drop(&mut self) { - self.inner.join() - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs deleted file mode 100644 index 7f4fa57fa1e09..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs +++ /dev/null @@ -1,1397 +0,0 @@ -//! Conversion of rust-analyzer specific types to lsp_types equivalents. -use std::{ - iter::once, - path, - sync::atomic::{AtomicU32, Ordering}, -}; - -use ide::{ - Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem, - CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit, - Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint, - InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, - SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize, -}; -use itertools::Itertools; -use serde_json::to_value; -use vfs::AbsPath; - -use crate::{ - cargo_target_spec::CargoTargetSpec, - config::{CallInfoConfig, Config}, - global_state::GlobalStateSnapshot, - line_index::{LineEndings, LineIndex, OffsetEncoding}, - lsp_ext, - lsp_utils::invalid_params_error, - semantic_tokens, Result, -}; - -pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { - let line_col = line_index.index.line_col(offset); - match line_index.encoding { - OffsetEncoding::Utf8 => lsp_types::Position::new(line_col.line, line_col.col), - OffsetEncoding::Utf16 => { - let line_col = line_index.index.to_utf16(line_col); - lsp_types::Position::new(line_col.line, line_col.col) - } - } -} - -pub(crate) fn range(line_index: &LineIndex, range: TextRange) -> lsp_types::Range { - let start = position(line_index, range.start()); - let end = position(line_index, range.end()); - lsp_types::Range::new(start, end) -} - -pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind { - match symbol_kind { - SymbolKind::Function => lsp_types::SymbolKind::FUNCTION, - SymbolKind::Struct => lsp_types::SymbolKind::STRUCT, - SymbolKind::Enum => lsp_types::SymbolKind::ENUM, - SymbolKind::Variant => lsp_types::SymbolKind::ENUM_MEMBER, - SymbolKind::Trait => lsp_types::SymbolKind::INTERFACE, - SymbolKind::Macro - | SymbolKind::BuiltinAttr - | SymbolKind::Attribute - | SymbolKind::Derive - | SymbolKind::DeriveHelper => lsp_types::SymbolKind::FUNCTION, - SymbolKind::Module | SymbolKind::ToolModule => lsp_types::SymbolKind::MODULE, - SymbolKind::TypeAlias | SymbolKind::TypeParam | SymbolKind::SelfType => { - lsp_types::SymbolKind::TYPE_PARAMETER - } - SymbolKind::Field => lsp_types::SymbolKind::FIELD, - SymbolKind::Static => lsp_types::SymbolKind::CONSTANT, - SymbolKind::Const => lsp_types::SymbolKind::CONSTANT, - SymbolKind::ConstParam => lsp_types::SymbolKind::CONSTANT, - SymbolKind::Impl => lsp_types::SymbolKind::OBJECT, - SymbolKind::Local - | SymbolKind::SelfParam - | SymbolKind::LifetimeParam - | SymbolKind::ValueParam - | SymbolKind::Label => lsp_types::SymbolKind::VARIABLE, - SymbolKind::Union => lsp_types::SymbolKind::STRUCT, - } -} - -pub(crate) fn structure_node_kind(kind: StructureNodeKind) -> lsp_types::SymbolKind { - match kind { - StructureNodeKind::SymbolKind(symbol) => symbol_kind(symbol), - StructureNodeKind::Region => lsp_types::SymbolKind::NAMESPACE, - } -} - -pub(crate) fn document_highlight_kind( - category: ReferenceCategory, -) -> lsp_types::DocumentHighlightKind { - match category { - ReferenceCategory::Read => lsp_types::DocumentHighlightKind::READ, - ReferenceCategory::Write => lsp_types::DocumentHighlightKind::WRITE, - } -} - -pub(crate) fn diagnostic_severity(severity: Severity) -> lsp_types::DiagnosticSeverity { - match severity { - Severity::Error => lsp_types::DiagnosticSeverity::ERROR, - Severity::WeakWarning => lsp_types::DiagnosticSeverity::HINT, - } -} - -pub(crate) fn documentation(documentation: Documentation) -> lsp_types::Documentation { - let value = crate::markdown::format_docs(documentation.as_str()); - let markup_content = lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, value }; - lsp_types::Documentation::MarkupContent(markup_content) -} - -pub(crate) fn completion_item_kind( - completion_item_kind: CompletionItemKind, -) -> lsp_types::CompletionItemKind { - match completion_item_kind { - CompletionItemKind::Binding => lsp_types::CompletionItemKind::VARIABLE, - CompletionItemKind::BuiltinType => lsp_types::CompletionItemKind::STRUCT, - CompletionItemKind::InferredType => lsp_types::CompletionItemKind::SNIPPET, - CompletionItemKind::Keyword => lsp_types::CompletionItemKind::KEYWORD, - CompletionItemKind::Method => lsp_types::CompletionItemKind::METHOD, - CompletionItemKind::Snippet => lsp_types::CompletionItemKind::SNIPPET, - CompletionItemKind::UnresolvedReference => lsp_types::CompletionItemKind::REFERENCE, - CompletionItemKind::SymbolKind(symbol) => match symbol { - SymbolKind::Attribute => lsp_types::CompletionItemKind::FUNCTION, - SymbolKind::Const => lsp_types::CompletionItemKind::CONSTANT, - SymbolKind::ConstParam => lsp_types::CompletionItemKind::TYPE_PARAMETER, - SymbolKind::Derive => lsp_types::CompletionItemKind::FUNCTION, - SymbolKind::DeriveHelper => lsp_types::CompletionItemKind::FUNCTION, - SymbolKind::Enum => lsp_types::CompletionItemKind::ENUM, - SymbolKind::Field => lsp_types::CompletionItemKind::FIELD, - SymbolKind::Function => lsp_types::CompletionItemKind::FUNCTION, - SymbolKind::Impl => lsp_types::CompletionItemKind::TEXT, - SymbolKind::Label => lsp_types::CompletionItemKind::VARIABLE, - SymbolKind::LifetimeParam => lsp_types::CompletionItemKind::TYPE_PARAMETER, - SymbolKind::Local => lsp_types::CompletionItemKind::VARIABLE, - SymbolKind::Macro => lsp_types::CompletionItemKind::FUNCTION, - SymbolKind::Module => lsp_types::CompletionItemKind::MODULE, - SymbolKind::SelfParam => lsp_types::CompletionItemKind::VALUE, - SymbolKind::SelfType => lsp_types::CompletionItemKind::TYPE_PARAMETER, - SymbolKind::Static => lsp_types::CompletionItemKind::VALUE, - SymbolKind::Struct => lsp_types::CompletionItemKind::STRUCT, - SymbolKind::Trait => lsp_types::CompletionItemKind::INTERFACE, - SymbolKind::TypeAlias => lsp_types::CompletionItemKind::STRUCT, - SymbolKind::TypeParam => lsp_types::CompletionItemKind::TYPE_PARAMETER, - SymbolKind::Union => lsp_types::CompletionItemKind::STRUCT, - SymbolKind::ValueParam => lsp_types::CompletionItemKind::VALUE, - SymbolKind::Variant => lsp_types::CompletionItemKind::ENUM_MEMBER, - SymbolKind::BuiltinAttr => lsp_types::CompletionItemKind::FUNCTION, - SymbolKind::ToolModule => lsp_types::CompletionItemKind::MODULE, - }, - } -} - -pub(crate) fn text_edit(line_index: &LineIndex, indel: Indel) -> lsp_types::TextEdit { - let range = range(line_index, indel.delete); - let new_text = match line_index.endings { - LineEndings::Unix => indel.insert, - LineEndings::Dos => indel.insert.replace('\n', "\r\n"), - }; - lsp_types::TextEdit { range, new_text } -} - -pub(crate) fn completion_text_edit( - line_index: &LineIndex, - insert_replace_support: Option, - indel: Indel, -) -> lsp_types::CompletionTextEdit { - let text_edit = text_edit(line_index, indel); - match insert_replace_support { - Some(cursor_pos) => lsp_types::InsertReplaceEdit { - new_text: text_edit.new_text, - insert: lsp_types::Range { start: text_edit.range.start, end: cursor_pos }, - replace: text_edit.range, - } - .into(), - None => text_edit.into(), - } -} - -pub(crate) fn snippet_text_edit( - line_index: &LineIndex, - is_snippet: bool, - indel: Indel, -) -> lsp_ext::SnippetTextEdit { - let text_edit = text_edit(line_index, indel); - let insert_text_format = - if is_snippet { Some(lsp_types::InsertTextFormat::SNIPPET) } else { None }; - lsp_ext::SnippetTextEdit { - range: text_edit.range, - new_text: text_edit.new_text, - insert_text_format, - annotation_id: None, - } -} - -pub(crate) fn text_edit_vec( - line_index: &LineIndex, - text_edit: TextEdit, -) -> Vec { - text_edit.into_iter().map(|indel| self::text_edit(line_index, indel)).collect() -} - -pub(crate) fn snippet_text_edit_vec( - line_index: &LineIndex, - is_snippet: bool, - text_edit: TextEdit, -) -> Vec { - text_edit - .into_iter() - .map(|indel| self::snippet_text_edit(line_index, is_snippet, indel)) - .collect() -} - -pub(crate) fn completion_items( - config: &Config, - line_index: &LineIndex, - tdpp: lsp_types::TextDocumentPositionParams, - items: Vec, -) -> Vec { - let max_relevance = items.iter().map(|it| it.relevance().score()).max().unwrap_or_default(); - let mut res = Vec::with_capacity(items.len()); - for item in items { - completion_item(&mut res, config, line_index, &tdpp, max_relevance, item) - } - res -} - -fn completion_item( - acc: &mut Vec, - config: &Config, - line_index: &LineIndex, - tdpp: &lsp_types::TextDocumentPositionParams, - max_relevance: u32, - item: CompletionItem, -) { - let insert_replace_support = config.insert_replace_support().then(|| tdpp.position); - let mut additional_text_edits = Vec::new(); - - // LSP does not allow arbitrary edits in completion, so we have to do a - // non-trivial mapping here. - let text_edit = { - let mut text_edit = None; - let source_range = item.source_range(); - for indel in item.text_edit().iter() { - if indel.delete.contains_range(source_range) { - text_edit = Some(if indel.delete == source_range { - self::completion_text_edit(line_index, insert_replace_support, indel.clone()) - } else { - assert!(source_range.end() == indel.delete.end()); - let range1 = TextRange::new(indel.delete.start(), source_range.start()); - let range2 = source_range; - let indel1 = Indel::replace(range1, String::new()); - let indel2 = Indel::replace(range2, indel.insert.clone()); - additional_text_edits.push(self::text_edit(line_index, indel1)); - self::completion_text_edit(line_index, insert_replace_support, indel2) - }) - } else { - assert!(source_range.intersect(indel.delete).is_none()); - let text_edit = self::text_edit(line_index, indel.clone()); - additional_text_edits.push(text_edit); - } - } - text_edit.unwrap() - }; - - let insert_text_format = item.is_snippet().then(|| lsp_types::InsertTextFormat::SNIPPET); - let tags = item.deprecated().then(|| vec![lsp_types::CompletionItemTag::DEPRECATED]); - let command = if item.trigger_call_info() && config.client_commands().trigger_parameter_hints { - Some(command::trigger_parameter_hints()) - } else { - None - }; - - let mut lsp_item = lsp_types::CompletionItem { - label: item.label().to_string(), - detail: item.detail().map(|it| it.to_string()), - filter_text: Some(item.lookup().to_string()), - kind: Some(completion_item_kind(item.kind())), - text_edit: Some(text_edit), - additional_text_edits: Some(additional_text_edits), - documentation: item.documentation().map(documentation), - deprecated: Some(item.deprecated()), - tags, - command, - insert_text_format, - ..Default::default() - }; - - if config.completion_label_details_support() { - lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails { - detail: None, - description: lsp_item.detail.clone(), - }); - } - - set_score(&mut lsp_item, max_relevance, item.relevance()); - - if config.completion().enable_imports_on_the_fly { - if let imports @ [_, ..] = item.imports_to_add() { - let imports: Vec<_> = imports - .iter() - .filter_map(|import_edit| { - let import_path = &import_edit.import_path; - let import_name = import_path.segments().last()?; - Some(lsp_ext::CompletionImport { - full_import_path: import_path.to_string(), - imported_name: import_name.to_string(), - }) - }) - .collect(); - if !imports.is_empty() { - let data = lsp_ext::CompletionResolveData { position: tdpp.clone(), imports }; - lsp_item.data = Some(to_value(data).unwrap()); - } - } - } - - if let Some((mutability, offset, relevance)) = item.ref_match() { - let mut lsp_item_with_ref = lsp_item.clone(); - set_score(&mut lsp_item_with_ref, max_relevance, relevance); - lsp_item_with_ref.label = - format!("&{}{}", mutability.as_keyword_for_ref(), lsp_item_with_ref.label); - lsp_item_with_ref.additional_text_edits.get_or_insert_with(Default::default).push( - self::text_edit( - line_index, - Indel::insert(offset, format!("&{}", mutability.as_keyword_for_ref())), - ), - ); - - acc.push(lsp_item_with_ref); - }; - - acc.push(lsp_item); - - fn set_score( - res: &mut lsp_types::CompletionItem, - max_relevance: u32, - relevance: CompletionRelevance, - ) { - if relevance.is_relevant() && relevance.score() == max_relevance { - res.preselect = Some(true); - } - // The relevance needs to be inverted to come up with a sort score - // because the client will sort ascending. - let sort_score = relevance.score() ^ 0xFF_FF_FF_FF; - // Zero pad the string to ensure values can be properly sorted - // by the client. Hex format is used because it is easier to - // visually compare very large values, which the sort text - // tends to be since it is the opposite of the score. - res.sort_text = Some(format!("{:08x}", sort_score)); - } -} - -pub(crate) fn signature_help( - call_info: SignatureHelp, - config: CallInfoConfig, - label_offsets: bool, -) -> lsp_types::SignatureHelp { - let (label, parameters) = match (config.params_only, label_offsets) { - (concise, false) => { - let params = call_info - .parameter_labels() - .map(|label| lsp_types::ParameterInformation { - label: lsp_types::ParameterLabel::Simple(label.to_string()), - documentation: None, - }) - .collect::>(); - let label = - if concise { call_info.parameter_labels().join(", ") } else { call_info.signature }; - (label, params) - } - (false, true) => { - let params = call_info - .parameter_ranges() - .iter() - .map(|it| { - let start = call_info.signature[..it.start().into()].chars().count() as u32; - let end = call_info.signature[..it.end().into()].chars().count() as u32; - [start, end] - }) - .map(|label_offsets| lsp_types::ParameterInformation { - label: lsp_types::ParameterLabel::LabelOffsets(label_offsets), - documentation: None, - }) - .collect::>(); - (call_info.signature, params) - } - (true, true) => { - let mut params = Vec::new(); - let mut label = String::new(); - let mut first = true; - for param in call_info.parameter_labels() { - if !first { - label.push_str(", "); - } - first = false; - let start = label.chars().count() as u32; - label.push_str(param); - let end = label.chars().count() as u32; - params.push(lsp_types::ParameterInformation { - label: lsp_types::ParameterLabel::LabelOffsets([start, end]), - documentation: None, - }); - } - - (label, params) - } - }; - - let documentation = call_info.doc.filter(|_| config.docs).map(|doc| { - lsp_types::Documentation::MarkupContent(lsp_types::MarkupContent { - kind: lsp_types::MarkupKind::Markdown, - value: doc, - }) - }); - - let active_parameter = call_info.active_parameter.map(|it| it as u32); - - let signature = lsp_types::SignatureInformation { - label, - documentation, - parameters: Some(parameters), - active_parameter, - }; - lsp_types::SignatureHelp { - signatures: vec![signature], - active_signature: Some(0), - active_parameter, - } -} - -pub(crate) fn inlay_hint( - snap: &GlobalStateSnapshot, - line_index: &LineIndex, - render_colons: bool, - inlay_hint: InlayHint, -) -> lsp_types::InlayHint { - lsp_types::InlayHint { - position: match inlay_hint.kind { - // before annotated thing - InlayKind::ParameterHint - | InlayKind::ImplicitReborrowHint - | InlayKind::BindingModeHint => position(line_index, inlay_hint.range.start()), - // after annotated thing - InlayKind::ClosureReturnTypeHint - | InlayKind::TypeHint - | InlayKind::ChainingHint - | InlayKind::GenericParamListHint - | InlayKind::LifetimeHint - | InlayKind::ClosingBraceHint => position(line_index, inlay_hint.range.end()), - }, - padding_left: Some(match inlay_hint.kind { - InlayKind::TypeHint => !render_colons, - InlayKind::ChainingHint | InlayKind::ClosingBraceHint => true, - InlayKind::BindingModeHint - | InlayKind::ClosureReturnTypeHint - | InlayKind::GenericParamListHint - | InlayKind::ImplicitReborrowHint - | InlayKind::LifetimeHint - | InlayKind::ParameterHint => false, - }), - padding_right: Some(match inlay_hint.kind { - InlayKind::ChainingHint - | InlayKind::ClosureReturnTypeHint - | InlayKind::GenericParamListHint - | InlayKind::ImplicitReborrowHint - | InlayKind::TypeHint - | InlayKind::ClosingBraceHint => false, - InlayKind::BindingModeHint => inlay_hint.label != "&", - InlayKind::ParameterHint | InlayKind::LifetimeHint => true, - }), - label: lsp_types::InlayHintLabel::String(match inlay_hint.kind { - InlayKind::ParameterHint if render_colons => format!("{}:", inlay_hint.label), - InlayKind::TypeHint if render_colons => format!(": {}", inlay_hint.label), - InlayKind::ClosureReturnTypeHint => format!(" -> {}", inlay_hint.label), - _ => inlay_hint.label.clone(), - }), - kind: match inlay_hint.kind { - InlayKind::ParameterHint => Some(lsp_types::InlayHintKind::PARAMETER), - InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => { - Some(lsp_types::InlayHintKind::TYPE) - } - InlayKind::BindingModeHint - | InlayKind::GenericParamListHint - | InlayKind::LifetimeHint - | InlayKind::ImplicitReborrowHint - | InlayKind::ClosingBraceHint => None, - }, - text_edits: None, - data: (|| match inlay_hint.tooltip { - Some(ide::InlayTooltip::HoverOffset(file_id, offset)) => { - let uri = url(snap, file_id); - let line_index = snap.file_line_index(file_id).ok()?; - - let text_document = lsp_types::TextDocumentIdentifier { uri }; - to_value(lsp_ext::InlayHintResolveData { - text_document, - position: lsp_ext::PositionOrRange::Position(position(&line_index, offset)), - }) - .ok() - } - Some(ide::InlayTooltip::HoverRanged(file_id, text_range)) => { - let uri = url(snap, file_id); - let text_document = lsp_types::TextDocumentIdentifier { uri }; - let line_index = snap.file_line_index(file_id).ok()?; - to_value(lsp_ext::InlayHintResolveData { - text_document, - position: lsp_ext::PositionOrRange::Range(range(&line_index, text_range)), - }) - .ok() - } - _ => None, - })(), - tooltip: Some(match inlay_hint.tooltip { - Some(ide::InlayTooltip::String(s)) => lsp_types::InlayHintTooltip::String(s), - _ => lsp_types::InlayHintTooltip::String(inlay_hint.label), - }), - } -} - -static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1); - -pub(crate) fn semantic_tokens( - text: &str, - line_index: &LineIndex, - highlights: Vec, - highlight_strings: bool, -) -> lsp_types::SemanticTokens { - let id = TOKEN_RESULT_COUNTER.fetch_add(1, Ordering::SeqCst).to_string(); - let mut builder = semantic_tokens::SemanticTokensBuilder::new(id); - - for highlight_range in highlights { - if highlight_range.highlight.is_empty() { - continue; - } - let (ty, mods) = semantic_token_type_and_modifiers(highlight_range.highlight); - if !highlight_strings && ty == lsp_types::SemanticTokenType::STRING { - continue; - } - let token_index = semantic_tokens::type_index(ty); - let modifier_bitset = mods.0; - - for mut text_range in line_index.index.lines(highlight_range.range) { - if text[text_range].ends_with('\n') { - text_range = - TextRange::new(text_range.start(), text_range.end() - TextSize::of('\n')); - } - let range = range(line_index, text_range); - builder.push(range, token_index, modifier_bitset); - } - } - - builder.build() -} - -pub(crate) fn semantic_token_delta( - previous: &lsp_types::SemanticTokens, - current: &lsp_types::SemanticTokens, -) -> lsp_types::SemanticTokensDelta { - let result_id = current.result_id.clone(); - let edits = semantic_tokens::diff_tokens(&previous.data, ¤t.data); - lsp_types::SemanticTokensDelta { result_id, edits } -} - -fn semantic_token_type_and_modifiers( - highlight: Highlight, -) -> (lsp_types::SemanticTokenType, semantic_tokens::ModifierSet) { - let mut mods = semantic_tokens::ModifierSet::default(); - let type_ = match highlight.tag { - HlTag::Symbol(symbol) => match symbol { - SymbolKind::Attribute => semantic_tokens::ATTRIBUTE, - SymbolKind::Derive => semantic_tokens::DERIVE, - SymbolKind::DeriveHelper => semantic_tokens::DERIVE_HELPER, - SymbolKind::Module => lsp_types::SemanticTokenType::NAMESPACE, - SymbolKind::Impl => semantic_tokens::TYPE_ALIAS, - SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY, - SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER, - SymbolKind::ConstParam => semantic_tokens::CONST_PARAMETER, - SymbolKind::LifetimeParam => semantic_tokens::LIFETIME, - SymbolKind::Label => semantic_tokens::LABEL, - SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER, - SymbolKind::SelfParam => semantic_tokens::SELF_KEYWORD, - SymbolKind::SelfType => semantic_tokens::SELF_TYPE_KEYWORD, - SymbolKind::Local => lsp_types::SemanticTokenType::VARIABLE, - SymbolKind::Function => { - if highlight.mods.contains(HlMod::Associated) { - lsp_types::SemanticTokenType::METHOD - } else { - lsp_types::SemanticTokenType::FUNCTION - } - } - SymbolKind::Const => { - mods |= semantic_tokens::CONSTANT; - mods |= lsp_types::SemanticTokenModifier::STATIC; - lsp_types::SemanticTokenType::VARIABLE - } - SymbolKind::Static => { - mods |= lsp_types::SemanticTokenModifier::STATIC; - lsp_types::SemanticTokenType::VARIABLE - } - SymbolKind::Struct => lsp_types::SemanticTokenType::STRUCT, - SymbolKind::Enum => lsp_types::SemanticTokenType::ENUM, - SymbolKind::Variant => lsp_types::SemanticTokenType::ENUM_MEMBER, - SymbolKind::Union => semantic_tokens::UNION, - SymbolKind::TypeAlias => semantic_tokens::TYPE_ALIAS, - SymbolKind::Trait => lsp_types::SemanticTokenType::INTERFACE, - SymbolKind::Macro => lsp_types::SemanticTokenType::MACRO, - SymbolKind::BuiltinAttr => semantic_tokens::BUILTIN_ATTRIBUTE, - SymbolKind::ToolModule => semantic_tokens::TOOL_MODULE, - }, - HlTag::AttributeBracket => semantic_tokens::ATTRIBUTE_BRACKET, - HlTag::BoolLiteral => semantic_tokens::BOOLEAN, - HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE, - HlTag::ByteLiteral | HlTag::NumericLiteral => lsp_types::SemanticTokenType::NUMBER, - HlTag::CharLiteral => semantic_tokens::CHAR, - HlTag::Comment => lsp_types::SemanticTokenType::COMMENT, - HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE, - HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, - HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD, - HlTag::None => semantic_tokens::GENERIC, - HlTag::Operator(op) => match op { - HlOperator::Bitwise => semantic_tokens::BITWISE, - HlOperator::Arithmetic => semantic_tokens::ARITHMETIC, - HlOperator::Logical => semantic_tokens::LOGICAL, - HlOperator::Comparison => semantic_tokens::COMPARISON, - HlOperator::Other => semantic_tokens::OPERATOR, - }, - HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING, - HlTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE, - HlTag::Punctuation(punct) => match punct { - HlPunct::Bracket => semantic_tokens::BRACKET, - HlPunct::Brace => semantic_tokens::BRACE, - HlPunct::Parenthesis => semantic_tokens::PARENTHESIS, - HlPunct::Angle => semantic_tokens::ANGLE, - HlPunct::Comma => semantic_tokens::COMMA, - HlPunct::Dot => semantic_tokens::DOT, - HlPunct::Colon => semantic_tokens::COLON, - HlPunct::Semi => semantic_tokens::SEMICOLON, - HlPunct::Other => semantic_tokens::PUNCTUATION, - HlPunct::MacroBang => semantic_tokens::MACRO_BANG, - }, - }; - - for modifier in highlight.mods.iter() { - let modifier = match modifier { - HlMod::Associated => continue, - HlMod::Async => semantic_tokens::ASYNC, - HlMod::Attribute => semantic_tokens::ATTRIBUTE_MODIFIER, - HlMod::Callable => semantic_tokens::CALLABLE, - HlMod::Consuming => semantic_tokens::CONSUMING, - HlMod::ControlFlow => semantic_tokens::CONTROL_FLOW, - HlMod::CrateRoot => semantic_tokens::CRATE_ROOT, - HlMod::DefaultLibrary => lsp_types::SemanticTokenModifier::DEFAULT_LIBRARY, - HlMod::Definition => lsp_types::SemanticTokenModifier::DECLARATION, - HlMod::Documentation => lsp_types::SemanticTokenModifier::DOCUMENTATION, - HlMod::Injected => semantic_tokens::INJECTED, - HlMod::IntraDocLink => semantic_tokens::INTRA_DOC_LINK, - HlMod::Library => semantic_tokens::LIBRARY, - HlMod::Mutable => semantic_tokens::MUTABLE, - HlMod::Public => semantic_tokens::PUBLIC, - HlMod::Reference => semantic_tokens::REFERENCE, - HlMod::Static => lsp_types::SemanticTokenModifier::STATIC, - HlMod::Trait => semantic_tokens::TRAIT_MODIFIER, - HlMod::Unsafe => semantic_tokens::UNSAFE, - }; - mods |= modifier; - } - - (type_, mods) -} - -pub(crate) fn folding_range( - text: &str, - line_index: &LineIndex, - line_folding_only: bool, - fold: Fold, -) -> lsp_types::FoldingRange { - let kind = match fold.kind { - FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment), - FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports), - FoldKind::Region => Some(lsp_types::FoldingRangeKind::Region), - FoldKind::Mods - | FoldKind::Block - | FoldKind::ArgList - | FoldKind::Consts - | FoldKind::Statics - | FoldKind::WhereClause - | FoldKind::ReturnType - | FoldKind::Array - | FoldKind::MatchArm => None, - }; - - let range = range(line_index, fold.range); - - if line_folding_only { - // Clients with line_folding_only == true (such as VSCode) will fold the whole end line - // even if it contains text not in the folding range. To prevent that we exclude - // range.end.line from the folding region if there is more text after range.end - // on the same line. - let has_more_text_on_end_line = text[TextRange::new(fold.range.end(), TextSize::of(text))] - .chars() - .take_while(|it| *it != '\n') - .any(|it| !it.is_whitespace()); - - let end_line = if has_more_text_on_end_line { - range.end.line.saturating_sub(1) - } else { - range.end.line - }; - - lsp_types::FoldingRange { - start_line: range.start.line, - start_character: None, - end_line, - end_character: None, - kind, - } - } else { - lsp_types::FoldingRange { - start_line: range.start.line, - start_character: Some(range.start.character), - end_line: range.end.line, - end_character: Some(range.end.character), - kind, - } - } -} - -pub(crate) fn url(snap: &GlobalStateSnapshot, file_id: FileId) -> lsp_types::Url { - snap.file_id_to_url(file_id) -} - -/// Returns a `Url` object from a given path, will lowercase drive letters if present. -/// This will only happen when processing windows paths. -/// -/// When processing non-windows path, this is essentially the same as `Url::from_file_path`. -pub(crate) fn url_from_abs_path(path: &AbsPath) -> lsp_types::Url { - let url = lsp_types::Url::from_file_path(path).unwrap(); - match path.as_ref().components().next() { - Some(path::Component::Prefix(prefix)) - if matches!(prefix.kind(), path::Prefix::Disk(_) | path::Prefix::VerbatimDisk(_)) => - { - // Need to lowercase driver letter - } - _ => return url, - } - - let driver_letter_range = { - let (scheme, drive_letter, _rest) = match url.as_str().splitn(3, ':').collect_tuple() { - Some(it) => it, - None => return url, - }; - let start = scheme.len() + ':'.len_utf8(); - start..(start + drive_letter.len()) - }; - - // Note: lowercasing the `path` itself doesn't help, the `Url::parse` - // machinery *also* canonicalizes the drive letter. So, just massage the - // string in place. - let mut url: String = url.into(); - url[driver_letter_range].make_ascii_lowercase(); - lsp_types::Url::parse(&url).unwrap() -} - -pub(crate) fn optional_versioned_text_document_identifier( - snap: &GlobalStateSnapshot, - file_id: FileId, -) -> lsp_types::OptionalVersionedTextDocumentIdentifier { - let url = url(snap, file_id); - let version = snap.url_file_version(&url); - lsp_types::OptionalVersionedTextDocumentIdentifier { uri: url, version } -} - -pub(crate) fn location( - snap: &GlobalStateSnapshot, - frange: FileRange, -) -> Result { - let url = url(snap, frange.file_id); - let line_index = snap.file_line_index(frange.file_id)?; - let range = range(&line_index, frange.range); - let loc = lsp_types::Location::new(url, range); - Ok(loc) -} - -/// Prefer using `location_link`, if the client has the cap. -pub(crate) fn location_from_nav( - snap: &GlobalStateSnapshot, - nav: NavigationTarget, -) -> Result { - let url = url(snap, nav.file_id); - let line_index = snap.file_line_index(nav.file_id)?; - let range = range(&line_index, nav.full_range); - let loc = lsp_types::Location::new(url, range); - Ok(loc) -} - -pub(crate) fn location_link( - snap: &GlobalStateSnapshot, - src: Option, - target: NavigationTarget, -) -> Result { - let origin_selection_range = match src { - Some(src) => { - let line_index = snap.file_line_index(src.file_id)?; - let range = range(&line_index, src.range); - Some(range) - } - None => None, - }; - let (target_uri, target_range, target_selection_range) = location_info(snap, target)?; - let res = lsp_types::LocationLink { - origin_selection_range, - target_uri, - target_range, - target_selection_range, - }; - Ok(res) -} - -fn location_info( - snap: &GlobalStateSnapshot, - target: NavigationTarget, -) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { - let line_index = snap.file_line_index(target.file_id)?; - - let target_uri = url(snap, target.file_id); - let target_range = range(&line_index, target.full_range); - let target_selection_range = - target.focus_range.map(|it| range(&line_index, it)).unwrap_or(target_range); - Ok((target_uri, target_range, target_selection_range)) -} - -pub(crate) fn goto_definition_response( - snap: &GlobalStateSnapshot, - src: Option, - targets: Vec, -) -> Result { - if snap.config.location_link() { - let links = targets - .into_iter() - .map(|nav| location_link(snap, src, nav)) - .collect::>>()?; - Ok(links.into()) - } else { - let locations = targets - .into_iter() - .map(|nav| { - location(snap, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) - }) - .collect::>>()?; - Ok(locations.into()) - } -} - -fn outside_workspace_annotation_id() -> String { - String::from("OutsideWorkspace") -} - -pub(crate) fn snippet_text_document_edit( - snap: &GlobalStateSnapshot, - is_snippet: bool, - file_id: FileId, - edit: TextEdit, -) -> Result { - let text_document = optional_versioned_text_document_identifier(snap, file_id); - let line_index = snap.file_line_index(file_id)?; - let mut edits: Vec<_> = - edit.into_iter().map(|it| snippet_text_edit(&line_index, is_snippet, it)).collect(); - - if snap.analysis.is_library_file(file_id)? && snap.config.change_annotation_support() { - for edit in &mut edits { - edit.annotation_id = Some(outside_workspace_annotation_id()) - } - } - Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) -} - -pub(crate) fn snippet_text_document_ops( - snap: &GlobalStateSnapshot, - file_system_edit: FileSystemEdit, -) -> Cancellable> { - let mut ops = Vec::new(); - match file_system_edit { - FileSystemEdit::CreateFile { dst, initial_contents } => { - let uri = snap.anchored_path(&dst); - let create_file = lsp_types::ResourceOp::Create(lsp_types::CreateFile { - uri: uri.clone(), - options: None, - annotation_id: None, - }); - ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(create_file)); - if !initial_contents.is_empty() { - let text_document = - lsp_types::OptionalVersionedTextDocumentIdentifier { uri, version: None }; - let text_edit = lsp_ext::SnippetTextEdit { - range: lsp_types::Range::default(), - new_text: initial_contents, - insert_text_format: Some(lsp_types::InsertTextFormat::PLAIN_TEXT), - annotation_id: None, - }; - let edit_file = - lsp_ext::SnippetTextDocumentEdit { text_document, edits: vec![text_edit] }; - ops.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit_file)); - } - } - FileSystemEdit::MoveFile { src, dst } => { - let old_uri = snap.file_id_to_url(src); - let new_uri = snap.anchored_path(&dst); - let mut rename_file = - lsp_types::RenameFile { old_uri, new_uri, options: None, annotation_id: None }; - if snap.analysis.is_library_file(src).ok() == Some(true) - && snap.config.change_annotation_support() - { - rename_file.annotation_id = Some(outside_workspace_annotation_id()) - } - ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(lsp_types::ResourceOp::Rename( - rename_file, - ))) - } - FileSystemEdit::MoveDir { src, src_id, dst } => { - let old_uri = snap.anchored_path(&src); - let new_uri = snap.anchored_path(&dst); - let mut rename_file = - lsp_types::RenameFile { old_uri, new_uri, options: None, annotation_id: None }; - if snap.analysis.is_library_file(src_id).ok() == Some(true) - && snap.config.change_annotation_support() - { - rename_file.annotation_id = Some(outside_workspace_annotation_id()) - } - ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(lsp_types::ResourceOp::Rename( - rename_file, - ))) - } - } - Ok(ops) -} - -pub(crate) fn snippet_workspace_edit( - snap: &GlobalStateSnapshot, - source_change: SourceChange, -) -> Result { - let mut document_changes: Vec = Vec::new(); - - for op in source_change.file_system_edits { - let ops = snippet_text_document_ops(snap, op)?; - document_changes.extend_from_slice(&ops); - } - for (file_id, edit) in source_change.source_file_edits { - let edit = snippet_text_document_edit(snap, source_change.is_snippet, file_id, edit)?; - document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit)); - } - let mut workspace_edit = lsp_ext::SnippetWorkspaceEdit { - changes: None, - document_changes: Some(document_changes), - change_annotations: None, - }; - if snap.config.change_annotation_support() { - workspace_edit.change_annotations = Some( - once(( - outside_workspace_annotation_id(), - lsp_types::ChangeAnnotation { - label: String::from("Edit outside of the workspace"), - needs_confirmation: Some(true), - description: Some(String::from( - "This edit lies outside of the workspace and may affect dependencies", - )), - }, - )) - .collect(), - ) - } - Ok(workspace_edit) -} - -pub(crate) fn workspace_edit( - snap: &GlobalStateSnapshot, - source_change: SourceChange, -) -> Result { - assert!(!source_change.is_snippet); - snippet_workspace_edit(snap, source_change).map(|it| it.into()) -} - -impl From for lsp_types::WorkspaceEdit { - fn from(snippet_workspace_edit: lsp_ext::SnippetWorkspaceEdit) -> lsp_types::WorkspaceEdit { - lsp_types::WorkspaceEdit { - changes: None, - document_changes: snippet_workspace_edit.document_changes.map(|changes| { - lsp_types::DocumentChanges::Operations( - changes - .into_iter() - .map(|change| match change { - lsp_ext::SnippetDocumentChangeOperation::Op(op) => { - lsp_types::DocumentChangeOperation::Op(op) - } - lsp_ext::SnippetDocumentChangeOperation::Edit(edit) => { - lsp_types::DocumentChangeOperation::Edit( - lsp_types::TextDocumentEdit { - text_document: edit.text_document, - edits: edit.edits.into_iter().map(From::from).collect(), - }, - ) - } - }) - .collect(), - ) - }), - change_annotations: snippet_workspace_edit.change_annotations, - } - } -} - -impl From - for lsp_types::OneOf -{ - fn from( - lsp_ext::SnippetTextEdit { annotation_id, insert_text_format:_, new_text, range }: lsp_ext::SnippetTextEdit, - ) -> Self { - match annotation_id { - Some(annotation_id) => lsp_types::OneOf::Right(lsp_types::AnnotatedTextEdit { - text_edit: lsp_types::TextEdit { range, new_text }, - annotation_id, - }), - None => lsp_types::OneOf::Left(lsp_types::TextEdit { range, new_text }), - } - } -} - -pub(crate) fn call_hierarchy_item( - snap: &GlobalStateSnapshot, - target: NavigationTarget, -) -> Result { - let name = target.name.to_string(); - let detail = target.description.clone(); - let kind = target.kind.map(symbol_kind).unwrap_or(lsp_types::SymbolKind::FUNCTION); - let (uri, range, selection_range) = location_info(snap, target)?; - Ok(lsp_types::CallHierarchyItem { - name, - kind, - tags: None, - detail, - uri, - range, - selection_range, - data: None, - }) -} - -pub(crate) fn code_action_kind(kind: AssistKind) -> lsp_types::CodeActionKind { - match kind { - AssistKind::None | AssistKind::Generate => lsp_types::CodeActionKind::EMPTY, - AssistKind::QuickFix => lsp_types::CodeActionKind::QUICKFIX, - AssistKind::Refactor => lsp_types::CodeActionKind::REFACTOR, - AssistKind::RefactorExtract => lsp_types::CodeActionKind::REFACTOR_EXTRACT, - AssistKind::RefactorInline => lsp_types::CodeActionKind::REFACTOR_INLINE, - AssistKind::RefactorRewrite => lsp_types::CodeActionKind::REFACTOR_REWRITE, - } -} - -pub(crate) fn code_action( - snap: &GlobalStateSnapshot, - assist: Assist, - resolve_data: Option<(usize, lsp_types::CodeActionParams)>, -) -> Result { - let mut res = lsp_ext::CodeAction { - title: assist.label.to_string(), - group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0), - kind: Some(code_action_kind(assist.id.1)), - edit: None, - is_preferred: None, - data: None, - command: None, - }; - - if assist.trigger_signature_help && snap.config.client_commands().trigger_parameter_hints { - res.command = Some(command::trigger_parameter_hints()); - } - - match (assist.source_change, resolve_data) { - (Some(it), _) => res.edit = Some(snippet_workspace_edit(snap, it)?), - (None, Some((index, code_action_params))) => { - res.data = Some(lsp_ext::CodeActionData { - id: format!("{}:{}:{}", assist.id.0, assist.id.1.name(), index), - code_action_params, - }); - } - (None, None) => { - stdx::never!("assist should always be resolved if client can't do lazy resolving") - } - }; - Ok(res) -} - -pub(crate) fn runnable( - snap: &GlobalStateSnapshot, - runnable: Runnable, -) -> Result { - let config = snap.config.runnables(); - let spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id)?; - let workspace_root = spec.as_ref().map(|it| it.workspace_root.clone()); - let target = spec.as_ref().map(|s| s.target.clone()); - let (cargo_args, executable_args) = - CargoTargetSpec::runnable_args(snap, spec, &runnable.kind, &runnable.cfg)?; - let label = runnable.label(target); - let location = location_link(snap, None, runnable.nav)?; - - Ok(lsp_ext::Runnable { - label, - location: Some(location), - kind: lsp_ext::RunnableKind::Cargo, - args: lsp_ext::CargoRunnable { - workspace_root: workspace_root.map(|it| it.into()), - override_cargo: config.override_cargo, - cargo_args, - cargo_extra_args: config.cargo_extra_args, - executable_args, - expect_test: None, - }, - }) -} - -pub(crate) fn code_lens( - acc: &mut Vec, - snap: &GlobalStateSnapshot, - annotation: Annotation, -) -> Result<()> { - let client_commands_config = snap.config.client_commands(); - match annotation.kind { - AnnotationKind::Runnable(run) => { - let line_index = snap.file_line_index(run.nav.file_id)?; - let annotation_range = range(&line_index, annotation.range); - - let title = run.title(); - let can_debug = match run.kind { - ide::RunnableKind::DocTest { .. } => false, - ide::RunnableKind::TestMod { .. } - | ide::RunnableKind::Test { .. } - | ide::RunnableKind::Bench { .. } - | ide::RunnableKind::Bin => true, - }; - let r = runnable(snap, run)?; - - let lens_config = snap.config.lens(); - if lens_config.run && client_commands_config.run_single { - let command = command::run_single(&r, &title); - acc.push(lsp_types::CodeLens { - range: annotation_range, - command: Some(command), - data: None, - }) - } - if lens_config.debug && can_debug && client_commands_config.debug_single { - let command = command::debug_single(&r); - acc.push(lsp_types::CodeLens { - range: annotation_range, - command: Some(command), - data: None, - }) - } - } - AnnotationKind::HasImpls { file_id, data } => { - if !client_commands_config.show_reference { - return Ok(()); - } - let line_index = snap.file_line_index(file_id)?; - let annotation_range = range(&line_index, annotation.range); - let url = url(snap, file_id); - - let id = lsp_types::TextDocumentIdentifier { uri: url.clone() }; - - let doc_pos = lsp_types::TextDocumentPositionParams::new(id, annotation_range.start); - - let goto_params = lsp_types::request::GotoImplementationParams { - text_document_position_params: doc_pos, - work_done_progress_params: Default::default(), - partial_result_params: Default::default(), - }; - - let command = data.map(|ranges| { - let locations: Vec = ranges - .into_iter() - .filter_map(|target| { - location( - snap, - FileRange { file_id: target.file_id, range: target.full_range }, - ) - .ok() - }) - .collect(); - - command::show_references( - implementation_title(locations.len()), - &url, - annotation_range.start, - locations, - ) - }); - - acc.push(lsp_types::CodeLens { - range: annotation_range, - command, - data: Some(to_value(lsp_ext::CodeLensResolveData::Impls(goto_params)).unwrap()), - }) - } - AnnotationKind::HasReferences { file_id, data } => { - if !client_commands_config.show_reference { - return Ok(()); - } - let line_index = snap.file_line_index(file_id)?; - let annotation_range = range(&line_index, annotation.range); - let url = url(snap, file_id); - - let id = lsp_types::TextDocumentIdentifier { uri: url.clone() }; - - let doc_pos = lsp_types::TextDocumentPositionParams::new(id, annotation_range.start); - - let command = data.map(|ranges| { - let locations: Vec = - ranges.into_iter().filter_map(|range| location(snap, range).ok()).collect(); - - command::show_references( - reference_title(locations.len()), - &url, - annotation_range.start, - locations, - ) - }); - - acc.push(lsp_types::CodeLens { - range: annotation_range, - command, - data: Some(to_value(lsp_ext::CodeLensResolveData::References(doc_pos)).unwrap()), - }) - } - } - Ok(()) -} - -pub(crate) mod command { - use ide::{FileRange, NavigationTarget}; - use serde_json::to_value; - - use crate::{ - global_state::GlobalStateSnapshot, - lsp_ext, - to_proto::{location, location_link}, - }; - - pub(crate) fn show_references( - title: String, - uri: &lsp_types::Url, - position: lsp_types::Position, - locations: Vec, - ) -> lsp_types::Command { - // We cannot use the 'editor.action.showReferences' command directly - // because that command requires vscode types which we convert in the handler - // on the client side. - - lsp_types::Command { - title, - command: "rust-analyzer.showReferences".into(), - arguments: Some(vec![ - to_value(uri).unwrap(), - to_value(position).unwrap(), - to_value(locations).unwrap(), - ]), - } - } - - pub(crate) fn run_single(runnable: &lsp_ext::Runnable, title: &str) -> lsp_types::Command { - lsp_types::Command { - title: title.to_string(), - command: "rust-analyzer.runSingle".into(), - arguments: Some(vec![to_value(runnable).unwrap()]), - } - } - - pub(crate) fn debug_single(runnable: &lsp_ext::Runnable) -> lsp_types::Command { - lsp_types::Command { - title: "Debug".into(), - command: "rust-analyzer.debugSingle".into(), - arguments: Some(vec![to_value(runnable).unwrap()]), - } - } - - pub(crate) fn goto_location( - snap: &GlobalStateSnapshot, - nav: &NavigationTarget, - ) -> Option { - let value = if snap.config.location_link() { - let link = location_link(snap, None, nav.clone()).ok()?; - to_value(link).ok()? - } else { - let range = FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }; - let location = location(snap, range).ok()?; - to_value(location).ok()? - }; - - Some(lsp_types::Command { - title: nav.name.to_string(), - command: "rust-analyzer.gotoLocation".into(), - arguments: Some(vec![value]), - }) - } - - pub(crate) fn trigger_parameter_hints() -> lsp_types::Command { - lsp_types::Command { - title: "triggerParameterHints".into(), - command: "editor.action.triggerParameterHints".into(), - arguments: None, - } - } -} - -pub(crate) fn implementation_title(count: usize) -> String { - if count == 1 { - "1 implementation".into() - } else { - format!("{} implementations", count) - } -} - -pub(crate) fn reference_title(count: usize) -> String { - if count == 1 { - "1 reference".into() - } else { - format!("{} references", count) - } -} - -pub(crate) fn markup_content( - markup: Markup, - kind: ide::HoverDocFormat, -) -> lsp_types::MarkupContent { - let kind = match kind { - ide::HoverDocFormat::Markdown => lsp_types::MarkupKind::Markdown, - ide::HoverDocFormat::PlainText => lsp_types::MarkupKind::PlainText, - }; - let value = crate::markdown::format_docs(markup.as_str()); - lsp_types::MarkupContent { kind, value } -} - -pub(crate) fn rename_error(err: RenameError) -> crate::LspError { - // This is wrong, but we don't have a better alternative I suppose? - // https://github.com/microsoft/language-server-protocol/issues/1341 - invalid_params_error(err.to_string()) -} - -#[cfg(test)] -mod tests { - use std::sync::Arc; - - use ide::Analysis; - - use super::*; - - #[test] - fn conv_fold_line_folding_only_fixup() { - let text = r#"mod a; -mod b; -mod c; - -fn main() { - if cond { - a::do_a(); - } else { - b::do_b(); - } -}"#; - - let (analysis, file_id) = Analysis::from_single_file(text.to_string()); - let folds = analysis.folding_ranges(file_id).unwrap(); - assert_eq!(folds.len(), 4); - - let line_index = LineIndex { - index: Arc::new(ide::LineIndex::new(text)), - endings: LineEndings::Unix, - encoding: OffsetEncoding::Utf16, - }; - let converted: Vec = - folds.into_iter().map(|it| folding_range(text, &line_index, true, it)).collect(); - - let expected_lines = [(0, 2), (4, 10), (5, 6), (7, 9)]; - assert_eq!(converted.len(), expected_lines.len()); - for (folding_range, (start_line, end_line)) in converted.iter().zip(expected_lines.iter()) { - assert_eq!(folding_range.start_line, *start_line); - assert_eq!(folding_range.start_character, None); - assert_eq!(folding_range.end_line, *end_line); - assert_eq!(folding_range.end_character, None); - } - } - - // `Url` is not able to parse windows paths on unix machines. - #[test] - #[cfg(target_os = "windows")] - fn test_lowercase_drive_letter() { - use std::{convert::TryInto, path::Path}; - - let url = url_from_abs_path(Path::new("C:\\Test").try_into().unwrap()); - assert_eq!(url.to_string(), "file:///c:/Test"); - - let url = url_from_abs_path(Path::new(r#"\\localhost\C$\my_dir"#).try_into().unwrap()); - assert_eq!(url.to_string(), "file://localhost/C$/my_dir"); - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/version.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/version.rs deleted file mode 100644 index 1e829299e6f3c..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/version.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! Code for representing rust-analyzer's release version number. - -use std::fmt; - -/// Information about the git repository where rust-analyzer was built from. -pub struct CommitInfo { - pub short_commit_hash: &'static str, - pub commit_hash: &'static str, - pub commit_date: &'static str, -} - -/// Cargo's version. -pub struct VersionInfo { - /// rust-analyzer's version, such as "1.57.0", "1.58.0-beta.1", "1.59.0-nightly", etc. - pub version: &'static str, - /// The release channel we were built for (stable/beta/nightly/dev). - /// - /// `None` if not built via rustbuild. - pub release_channel: Option<&'static str>, - /// Information about the Git repository we may have been built from. - /// - /// `None` if not built from a git repo. - pub commit_info: Option, -} - -impl fmt::Display for VersionInfo { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.version)?; - - if let Some(ci) = &self.commit_info { - write!(f, " ({} {})", ci.short_commit_hash, ci.commit_date)?; - }; - Ok(()) - } -} - -/// Returns information about cargo's version. -pub const fn version() -> VersionInfo { - let version = match option_env!("CFG_RELEASE") { - Some(x) => x, - None => "0.0.0", - }; - - let release_channel = option_env!("CFG_RELEASE_CHANNEL"); - let commit_info = match ( - option_env!("RA_COMMIT_SHORT_HASH"), - option_env!("RA_COMMIT_HASH"), - option_env!("RA_COMMIT_DATE"), - ) { - (Some(short_commit_hash), Some(commit_hash), Some(commit_date)) => { - Some(CommitInfo { short_commit_hash, commit_hash, commit_date }) - } - _ => None, - }; - - VersionInfo { version, release_channel, commit_info } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs deleted file mode 100644 index 4cc46af1b17c5..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ /dev/null @@ -1,1099 +0,0 @@ -//! The most high-level integrated tests for rust-analyzer. -//! -//! This tests run a full LSP event loop, spawn cargo and process stdlib from -//! sysroot. For this reason, the tests here are very slow, and should be -//! avoided unless absolutely necessary. -//! -//! In particular, it's fine *not* to test that client & server agree on -//! specific JSON shapes here -- there's little value in such tests, as we can't -//! be sure without a real client anyway. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -#[cfg(not(feature = "in-rust-tree"))] -mod sourcegen; -mod support; -mod testdir; -mod tidy; - -use std::{collections::HashMap, path::PathBuf, time::Instant}; - -use expect_test::expect; -use lsp_types::{ - notification::DidOpenTextDocument, - request::{ - CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest, - WillRenameFiles, WorkspaceSymbol, - }, - CodeActionContext, CodeActionParams, CompletionParams, DidOpenTextDocumentParams, - DocumentFormattingParams, FileRename, FormattingOptions, GotoDefinitionParams, HoverParams, - PartialResultParams, Position, Range, RenameFilesParams, TextDocumentItem, - TextDocumentPositionParams, WorkDoneProgressParams, -}; -use rust_analyzer::lsp_ext::{OnEnter, Runnables, RunnablesParams}; -use serde_json::json; -use test_utils::skip_slow_tests; - -use crate::{ - support::{project, Project}, - testdir::TestDir, -}; - -const PROFILE: &str = ""; -// const PROFILE: &'static str = "*@3>100"; - -#[test] -fn completes_items_from_standard_library() { - if skip_slow_tests() { - return; - } - - let server = Project::with_fixture( - r#" -//- /Cargo.toml -[package] -name = "foo" -version = "0.0.0" - -//- /src/lib.rs -use std::collections::Spam; -"#, - ) - .with_config(serde_json::json!({ - "cargo": { "noSysroot": false } - })) - .server() - .wait_until_workspace_is_loaded(); - - let res = server.send_request::(CompletionParams { - text_document_position: TextDocumentPositionParams::new( - server.doc_id("src/lib.rs"), - Position::new(0, 23), - ), - context: None, - partial_result_params: PartialResultParams::default(), - work_done_progress_params: WorkDoneProgressParams::default(), - }); - assert!(res.to_string().contains("HashMap")); -} - -#[test] -fn test_runnables_project() { - if skip_slow_tests() { - return; - } - - let server = Project::with_fixture( - r#" -//- /foo/Cargo.toml -[package] -name = "foo" -version = "0.0.0" - -//- /foo/src/lib.rs -pub fn foo() {} - -//- /foo/tests/spam.rs -#[test] -fn test_eggs() {} - -//- /bar/Cargo.toml -[package] -name = "bar" -version = "0.0.0" - -//- /bar/src/main.rs -fn main() {} -"#, - ) - .root("foo") - .root("bar") - .server() - .wait_until_workspace_is_loaded(); - - server.request::( - RunnablesParams { text_document: server.doc_id("foo/tests/spam.rs"), position: None }, - json!([ - { - "args": { - "cargoArgs": ["test", "--package", "foo", "--test", "spam"], - "executableArgs": ["test_eggs", "--exact", "--nocapture"], - "cargoExtraArgs": [], - "overrideCargo": null, - "workspaceRoot": server.path().join("foo") - }, - "kind": "cargo", - "label": "test test_eggs", - "location": { - "targetRange": { - "end": { "character": 17, "line": 1 }, - "start": { "character": 0, "line": 0 } - }, - "targetSelectionRange": { - "end": { "character": 12, "line": 1 }, - "start": { "character": 3, "line": 1 } - }, - "targetUri": "file:///[..]/tests/spam.rs" - } - }, - { - "args": { - "overrideCargo": null, - "workspaceRoot": server.path().join("foo"), - "cargoArgs": [ - "test", - "--package", - "foo", - "--test", - "spam" - ], - "cargoExtraArgs": [], - "executableArgs": [ - "", - "--nocapture" - ] - }, - "kind": "cargo", - "label": "test-mod ", - "location": { - "targetUri": "file:///[..]/tests/spam.rs", - "targetRange": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "targetSelectionRange": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - } - }, - }, - { - "args": { - "cargoArgs": ["check", "--package", "foo", "--all-targets"], - "executableArgs": [], - "cargoExtraArgs": [], - "overrideCargo": null, - "workspaceRoot": server.path().join("foo") - }, - "kind": "cargo", - "label": "cargo check -p foo --all-targets" - }, - { - "args": { - "cargoArgs": ["test", "--package", "foo", "--all-targets"], - "executableArgs": [], - "cargoExtraArgs": [], - "overrideCargo": null, - "workspaceRoot": server.path().join("foo") - }, - "kind": "cargo", - "label": "cargo test -p foo --all-targets" - } - ]), - ); -} - -// Each package in these workspaces should be run from its own root -#[test] -fn test_path_dependency_runnables() { - if skip_slow_tests() { - return; - } - - let server = Project::with_fixture( - r#" -//- /consumer/Cargo.toml -[package] -name = "consumer" -version = "0.1.0" -[dependencies] -dependency = { path = "../dependency" } - -//- /consumer/src/lib.rs -#[cfg(test)] -mod tests { - #[test] - fn consumer() {} -} - -//- /dependency/Cargo.toml -[package] -name = "dependency" -version = "0.1.0" -[dev-dependencies] -devdependency = { path = "../devdependency" } - -//- /dependency/src/lib.rs -#[cfg(test)] -mod tests { - #[test] - fn dependency() {} -} - -//- /devdependency/Cargo.toml -[package] -name = "devdependency" -version = "0.1.0" - -//- /devdependency/src/lib.rs -#[cfg(test)] -mod tests { - #[test] - fn devdependency() {} -} - "#, - ) - .root("consumer") - .root("dependency") - .root("devdependency") - .server() - .wait_until_workspace_is_loaded(); - - for runnable in ["consumer", "dependency", "devdependency"] { - server.request::( - RunnablesParams { - text_document: server.doc_id(&format!("{}/src/lib.rs", runnable)), - position: None, - }, - json!([ - "{...}", - { - "label": "cargo test -p [..] --all-targets", - "kind": "cargo", - "args": { - "overrideCargo": null, - "workspaceRoot": server.path().join(runnable), - "cargoArgs": [ - "test", - "--package", - runnable, - "--all-targets" - ], - "cargoExtraArgs": [], - "executableArgs": [] - }, - }, - "{...}", - "{...}" - ]), - ); - } -} - -#[test] -fn test_format_document() { - if skip_slow_tests() { - return; - } - - let server = project( - r#" -//- /Cargo.toml -[package] -name = "foo" -version = "0.0.0" - -//- /src/lib.rs -mod bar; - -fn main() { -} - -pub use std::collections::HashMap; -"#, - ) - .wait_until_workspace_is_loaded(); - - server.request::( - DocumentFormattingParams { - text_document: server.doc_id("src/lib.rs"), - options: FormattingOptions { - tab_size: 4, - insert_spaces: false, - insert_final_newline: None, - trim_final_newlines: None, - trim_trailing_whitespace: None, - properties: HashMap::new(), - }, - work_done_progress_params: WorkDoneProgressParams::default(), - }, - json!([ - { - "newText": "", - "range": { - "end": { "character": 0, "line": 3 }, - "start": { "character": 11, "line": 2 } - } - } - ]), - ); -} - -#[test] -fn test_format_document_2018() { - if skip_slow_tests() { - return; - } - - let server = project( - r#" -//- /Cargo.toml -[package] -name = "foo" -version = "0.0.0" -edition = "2018" - -//- /src/lib.rs -mod bar; - -async fn test() { -} - -fn main() { -} - -pub use std::collections::HashMap; -"#, - ) - .wait_until_workspace_is_loaded(); - - server.request::( - DocumentFormattingParams { - text_document: server.doc_id("src/lib.rs"), - options: FormattingOptions { - tab_size: 4, - insert_spaces: false, - properties: HashMap::new(), - insert_final_newline: None, - trim_final_newlines: None, - trim_trailing_whitespace: None, - }, - work_done_progress_params: WorkDoneProgressParams::default(), - }, - json!([ - { - "newText": "", - "range": { - "end": { "character": 0, "line": 3 }, - "start": { "character": 17, "line": 2 } - } - }, - { - "newText": "", - "range": { - "end": { "character": 0, "line": 6 }, - "start": { "character": 11, "line": 5 } - } - } - ]), - ); -} - -#[test] -fn test_format_document_unchanged() { - if skip_slow_tests() { - return; - } - - let server = project( - r#" -//- /Cargo.toml -[package] -name = "foo" -version = "0.0.0" - -//- /src/lib.rs -fn main() {} -"#, - ) - .wait_until_workspace_is_loaded(); - - server.request::( - DocumentFormattingParams { - text_document: server.doc_id("src/lib.rs"), - options: FormattingOptions { - tab_size: 4, - insert_spaces: false, - insert_final_newline: None, - trim_final_newlines: None, - trim_trailing_whitespace: None, - properties: HashMap::new(), - }, - work_done_progress_params: WorkDoneProgressParams::default(), - }, - json!(null), - ); -} - -#[test] -fn test_missing_module_code_action() { - if skip_slow_tests() { - return; - } - - let server = project( - r#" -//- /Cargo.toml -[package] -name = "foo" -version = "0.0.0" - -//- /src/lib.rs -mod bar; - -fn main() {} -"#, - ) - .wait_until_workspace_is_loaded(); - - server.request::( - CodeActionParams { - text_document: server.doc_id("src/lib.rs"), - range: Range::new(Position::new(0, 4), Position::new(0, 7)), - context: CodeActionContext::default(), - partial_result_params: PartialResultParams::default(), - work_done_progress_params: WorkDoneProgressParams::default(), - }, - json!([ - { - "title": "Create module at `bar.rs`", - "kind": "quickfix", - "edit": { - "documentChanges": [ - { - "kind": "create", - "uri": "file://[..]/src/bar.rs" - } - ] - } - }, - { - "title": "Create module at `bar/mod.rs`", - "kind": "quickfix", - "edit": { - "documentChanges": [ - { - "kind": "create", - "uri": "file://[..]src/bar/mod.rs" - } - ] - } - } - ]), - ); - - server.request::( - CodeActionParams { - text_document: server.doc_id("src/lib.rs"), - range: Range::new(Position::new(2, 8), Position::new(2, 8)), - context: CodeActionContext::default(), - partial_result_params: PartialResultParams::default(), - work_done_progress_params: WorkDoneProgressParams::default(), - }, - json!([]), - ); -} - -#[test] -fn test_missing_module_code_action_in_json_project() { - if skip_slow_tests() { - // return; - } - - let tmp_dir = TestDir::new(); - - let path = tmp_dir.path(); - - let project = json!({ - "roots": [path], - "crates": [ { - "root_module": path.join("src/lib.rs"), - "deps": [], - "edition": "2015", - "cfg": [ "cfg_atom_1", "feature=\"cfg_1\""], - } ] - }); - - let code = format!( - r#" -//- /rust-project.json -{PROJECT} - -//- /src/lib.rs -mod bar; - -fn main() {{}} -"#, - PROJECT = project, - ); - - let server = - Project::with_fixture(&code).tmp_dir(tmp_dir).server().wait_until_workspace_is_loaded(); - - server.request::( - CodeActionParams { - text_document: server.doc_id("src/lib.rs"), - range: Range::new(Position::new(0, 4), Position::new(0, 7)), - context: CodeActionContext::default(), - partial_result_params: PartialResultParams::default(), - work_done_progress_params: WorkDoneProgressParams::default(), - }, - json!([ - { - "title": "Create module at `bar.rs`", - "kind": "quickfix", - "edit": { - "documentChanges": [ - { - "kind": "create", - "uri": "file://[..]/src/bar.rs" - } - ] - } - }, - { - "title": "Create module at `bar/mod.rs`", - "kind": "quickfix", - "edit": { - "documentChanges": [ - { - "kind": "create", - "uri": "file://[..]src/bar/mod.rs" - } - ] - } - } - ]), - ); - - server.request::( - CodeActionParams { - text_document: server.doc_id("src/lib.rs"), - range: Range::new(Position::new(2, 8), Position::new(2, 8)), - context: CodeActionContext::default(), - partial_result_params: PartialResultParams::default(), - work_done_progress_params: WorkDoneProgressParams::default(), - }, - json!([]), - ); -} - -#[test] -fn diagnostics_dont_block_typing() { - if skip_slow_tests() { - return; - } - - let librs: String = (0..10).map(|i| format!("mod m{};", i)).collect(); - let libs: String = (0..10).map(|i| format!("//- /src/m{}.rs\nfn foo() {{}}\n\n", i)).collect(); - let server = Project::with_fixture(&format!( - r#" -//- /Cargo.toml -[package] -name = "foo" -version = "0.0.0" - -//- /src/lib.rs -{} - -{} - -fn main() {{}} -"#, - librs, libs - )) - .with_config(serde_json::json!({ - "cargo": { "noSysroot": false } - })) - .server() - .wait_until_workspace_is_loaded(); - - for i in 0..10 { - server.notification::(DidOpenTextDocumentParams { - text_document: TextDocumentItem { - uri: server.doc_id(&format!("src/m{}.rs", i)).uri, - language_id: "rust".to_string(), - version: 0, - text: "/// Docs\nfn foo() {}".to_string(), - }, - }); - } - let start = Instant::now(); - server.request::( - TextDocumentPositionParams { - text_document: server.doc_id("src/m0.rs"), - position: Position { line: 0, character: 5 }, - }, - json!([{ - "insertTextFormat": 2, - "newText": "\n/// $0", - "range": { - "end": { "character": 5, "line": 0 }, - "start": { "character": 5, "line": 0 } - } - }]), - ); - let elapsed = start.elapsed(); - assert!(elapsed.as_millis() < 2000, "typing enter took {:?}", elapsed); -} - -#[test] -fn preserves_dos_line_endings() { - if skip_slow_tests() { - return; - } - - let server = Project::with_fixture( - " -//- /Cargo.toml -[package] -name = \"foo\" -version = \"0.0.0\" - -//- /src/main.rs -/// Some Docs\r\nfn main() {} -", - ) - .server() - .wait_until_workspace_is_loaded(); - - server.request::( - TextDocumentPositionParams { - text_document: server.doc_id("src/main.rs"), - position: Position { line: 0, character: 8 }, - }, - json!([{ - "insertTextFormat": 2, - "newText": "\r\n/// $0", - "range": { - "end": { "line": 0, "character": 8 }, - "start": { "line": 0, "character": 8 } - } - }]), - ); -} - -#[test] -fn out_dirs_check() { - if skip_slow_tests() { - // return; - } - - let server = Project::with_fixture( - r###" -//- /Cargo.toml -[package] -name = "foo" -version = "0.0.0" - -//- /build.rs -use std::{env, fs, path::Path}; - -fn main() { - let out_dir = env::var_os("OUT_DIR").unwrap(); - let dest_path = Path::new(&out_dir).join("hello.rs"); - fs::write( - &dest_path, - r#"pub fn message() -> &'static str { "Hello, World!" }"#, - ) - .unwrap(); - println!("cargo:rustc-cfg=atom_cfg"); - println!("cargo:rustc-cfg=featlike=\"set\""); - println!("cargo:rerun-if-changed=build.rs"); -} -//- /src/main.rs -#[rustc_builtin_macro] macro_rules! include {} -#[rustc_builtin_macro] macro_rules! include_str {} -#[rustc_builtin_macro] macro_rules! concat {} -#[rustc_builtin_macro] macro_rules! env {} - -include!(concat!(env!("OUT_DIR"), "/hello.rs")); - -#[cfg(atom_cfg)] -struct A; -#[cfg(bad_atom_cfg)] -struct A; -#[cfg(featlike = "set")] -struct B; -#[cfg(featlike = "not_set")] -struct B; - -fn main() { - let va = A; - let vb = B; - let should_be_str = message(); - let another_str = include_str!("main.rs"); -} -"###, - ) - .with_config(serde_json::json!({ - "cargo": { - "buildScripts": { - "enable": true - }, - "noSysroot": true, - } - })) - .server() - .wait_until_workspace_is_loaded(); - - let res = server.send_request::(HoverParams { - text_document_position_params: TextDocumentPositionParams::new( - server.doc_id("src/main.rs"), - Position::new(19, 10), - ), - work_done_progress_params: Default::default(), - }); - assert!(res.to_string().contains("&str")); - - let res = server.send_request::(HoverParams { - text_document_position_params: TextDocumentPositionParams::new( - server.doc_id("src/main.rs"), - Position::new(20, 10), - ), - work_done_progress_params: Default::default(), - }); - assert!(res.to_string().contains("&str")); - - server.request::( - GotoDefinitionParams { - text_document_position_params: TextDocumentPositionParams::new( - server.doc_id("src/main.rs"), - Position::new(17, 9), - ), - work_done_progress_params: Default::default(), - partial_result_params: Default::default(), - }, - json!([{ - "originSelectionRange": { - "end": { "character": 10, "line": 17 }, - "start": { "character": 8, "line": 17 } - }, - "targetRange": { - "end": { "character": 9, "line": 8 }, - "start": { "character": 0, "line": 7 } - }, - "targetSelectionRange": { - "end": { "character": 8, "line": 8 }, - "start": { "character": 7, "line": 8 } - }, - "targetUri": "file:///[..]src/main.rs" - }]), - ); - - server.request::( - GotoDefinitionParams { - text_document_position_params: TextDocumentPositionParams::new( - server.doc_id("src/main.rs"), - Position::new(18, 9), - ), - work_done_progress_params: Default::default(), - partial_result_params: Default::default(), - }, - json!([{ - "originSelectionRange": { - "end": { "character": 10, "line": 18 }, - "start": { "character": 8, "line": 18 } - }, - "targetRange": { - "end": { "character": 9, "line": 12 }, - "start": { "character": 0, "line":11 } - }, - "targetSelectionRange": { - "end": { "character": 8, "line": 12 }, - "start": { "character": 7, "line": 12 } - }, - "targetUri": "file:///[..]src/main.rs" - }]), - ); -} - -#[test] -fn resolve_proc_macro() { - if skip_slow_tests() { - return; - } - - let server = Project::with_fixture( - r###" -//- /foo/Cargo.toml -[package] -name = "foo" -version = "0.0.0" -edition = "2021" -[dependencies] -bar = {path = "../bar"} - -//- /foo/src/main.rs -use bar::Bar; - -#[rustc_builtin_macro] -macro derive($item:item) {} -trait Bar { - fn bar(); -} -#[derive(Bar)] -struct Foo {} -fn main() { - Foo::bar(); -} - -//- /bar/Cargo.toml -[package] -name = "bar" -version = "0.0.0" -edition = "2021" - -[lib] -proc-macro = true - -//- /bar/src/lib.rs -extern crate proc_macro; -use proc_macro::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; -macro_rules! t { - ($n:literal) => { - TokenTree::from(Ident::new($n, Span::call_site())) - }; - ({}) => { - TokenTree::from(Group::new(Delimiter::Brace, TokenStream::new())) - }; - (()) => { - TokenTree::from(Group::new(Delimiter::Parenthesis, TokenStream::new())) - }; -} -#[proc_macro_derive(Bar)] -pub fn foo(_input: TokenStream) -> TokenStream { - // We hard code the output here for preventing to use any deps - let mut res = TokenStream::new(); - - // ill behaved proc-macro will use the stdout - // we should ignore it - println!("I am bad guy"); - - // impl Bar for Foo { fn bar() {} } - let mut tokens = vec![t!("impl"), t!("Bar"), t!("for"), t!("Foo")]; - let mut fn_stream = TokenStream::new(); - fn_stream.extend(vec![t!("fn"), t!("bar"), t!(()), t!({})]); - tokens.push(Group::new(Delimiter::Brace, fn_stream).into()); - res.extend(tokens); - res -} - -"###, - ) - .with_config(serde_json::json!({ - "cargo": { - "buildScripts": { - "enable": true - }, - "noSysroot": true, - }, - "procMacro": { - "enable": true, - "server": PathBuf::from(env!("CARGO_BIN_EXE_rust-analyzer")), - } - })) - .root("foo") - .root("bar") - .server() - .wait_until_workspace_is_loaded(); - - let res = server.send_request::(HoverParams { - text_document_position_params: TextDocumentPositionParams::new( - server.doc_id("foo/src/main.rs"), - Position::new(10, 9), - ), - work_done_progress_params: Default::default(), - }); - let value = res.get("contents").unwrap().get("value").unwrap().as_str().unwrap(); - - expect![[r#" - - ```rust - foo::Foo - ``` - - ```rust - fn bar() - ```"#]] - .assert_eq(value); -} - -#[test] -fn test_will_rename_files_same_level() { - if skip_slow_tests() { - return; - } - - let tmp_dir = TestDir::new(); - let tmp_dir_path = tmp_dir.path().to_owned(); - let tmp_dir_str = tmp_dir_path.to_str().unwrap(); - let base_path = PathBuf::from(format!("file://{}", tmp_dir_str)); - - let code = r#" -//- /Cargo.toml -[package] -name = "foo" -version = "0.0.0" - -//- /src/lib.rs -mod old_file; -mod from_mod; -mod to_mod; -mod old_folder; -fn main() {} - -//- /src/old_file.rs - -//- /src/old_folder/mod.rs - -//- /src/from_mod/mod.rs - -//- /src/to_mod/foo.rs - -"#; - let server = - Project::with_fixture(code).tmp_dir(tmp_dir).server().wait_until_workspace_is_loaded(); - - //rename same level file - server.request::( - RenameFilesParams { - files: vec![FileRename { - old_uri: base_path.join("src/old_file.rs").to_str().unwrap().to_string(), - new_uri: base_path.join("src/new_file.rs").to_str().unwrap().to_string(), - }], - }, - json!({ - "documentChanges": [ - { - "textDocument": { - "uri": format!("file://{}", tmp_dir_path.join("src").join("lib.rs").to_str().unwrap().to_string().replace("C:\\", "/c:/").replace('\\', "/")), - "version": null - }, - "edits": [ - { - "range": { - "start": { - "line": 0, - "character": 4 - }, - "end": { - "line": 0, - "character": 12 - } - }, - "newText": "new_file" - } - ] - } - ] - }), - ); - - //rename file from mod.rs to foo.rs - server.request::( - RenameFilesParams { - files: vec![FileRename { - old_uri: base_path.join("src/from_mod/mod.rs").to_str().unwrap().to_string(), - new_uri: base_path.join("src/from_mod/foo.rs").to_str().unwrap().to_string(), - }], - }, - json!(null), - ); - - //rename file from foo.rs to mod.rs - server.request::( - RenameFilesParams { - files: vec![FileRename { - old_uri: base_path.join("src/to_mod/foo.rs").to_str().unwrap().to_string(), - new_uri: base_path.join("src/to_mod/mod.rs").to_str().unwrap().to_string(), - }], - }, - json!(null), - ); - - //rename same level file - server.request::( - RenameFilesParams { - files: vec![FileRename { - old_uri: base_path.join("src/old_folder").to_str().unwrap().to_string(), - new_uri: base_path.join("src/new_folder").to_str().unwrap().to_string(), - }], - }, - json!({ - "documentChanges": [ - { - "textDocument": { - "uri": format!("file://{}", tmp_dir_path.join("src").join("lib.rs").to_str().unwrap().to_string().replace("C:\\", "/c:/").replace('\\', "/")), - "version": null - }, - "edits": [ - { - "range": { - "start": { - "line": 3, - "character": 4 - }, - "end": { - "line": 3, - "character": 14 - } - }, - "newText": "new_folder" - } - ] - } - ] - }), - ); -} - -#[test] -fn test_exclude_config_works() { - if skip_slow_tests() { - return; - } - - let server = Project::with_fixture( - r#" -//- /foo/Cargo.toml -[package] -name = "foo" -version = "0.0.0" - -//- /foo/src/lib.rs -pub fn foo() {} - -//- /bar/Cargo.toml -[package] -name = "bar" -version = "0.0.0" - -//- /bar/src/lib.rs -pub fn bar() {} -"#, - ) - .root("foo") - .root("bar") - .with_config(json!({ - "files": { - "excludeDirs": ["foo", "bar"] - } - })) - .server() - .wait_until_workspace_is_loaded(); - - server.request::(Default::default(), json!([])); -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/sourcegen.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/sourcegen.rs deleted file mode 100644 index e6ac018a05fea..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/sourcegen.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! Generates `assists.md` documentation. - -use std::{fmt, fs, io, path::PathBuf}; - -#[test] -fn sourcegen_feature_docs() { - let features = Feature::collect().unwrap(); - let contents = features.into_iter().map(|it| it.to_string()).collect::>().join("\n\n"); - let contents = format!( - " -// Generated file, do not edit by hand, see `sourcegen_feature_docs`. -{} -", - contents.trim() - ); - let dst = sourcegen::project_root().join("docs/user/generated_features.adoc"); - fs::write(&dst, &contents).unwrap(); -} - -#[derive(Debug)] -struct Feature { - id: String, - location: sourcegen::Location, - doc: String, -} - -impl Feature { - fn collect() -> io::Result> { - let crates_dir = sourcegen::project_root().join("crates"); - - let mut res = Vec::new(); - for path in sourcegen::list_rust_files(&crates_dir) { - collect_file(&mut res, path)?; - } - res.sort_by(|lhs, rhs| lhs.id.cmp(&rhs.id)); - return Ok(res); - - fn collect_file(acc: &mut Vec, path: PathBuf) -> io::Result<()> { - let text = std::fs::read_to_string(&path)?; - let comment_blocks = sourcegen::CommentBlock::extract("Feature", &text); - - for block in comment_blocks { - let id = block.id; - if let Err(msg) = is_valid_feature_name(&id) { - panic!("invalid feature name: {:?}:\n {}", id, msg) - } - let doc = block.contents.join("\n"); - let location = sourcegen::Location { file: path.clone(), line: block.line }; - acc.push(Feature { id, location, doc }) - } - - Ok(()) - } - } -} - -fn is_valid_feature_name(feature: &str) -> Result<(), String> { - 'word: for word in feature.split_whitespace() { - for short in ["to", "and"] { - if word == short { - continue 'word; - } - } - for short in ["To", "And"] { - if word == short { - return Err(format!("Don't capitalize {:?}", word)); - } - } - if !word.starts_with(char::is_uppercase) { - return Err(format!("Capitalize {:?}", word)); - } - } - Ok(()) -} - -impl fmt::Display for Feature { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "=== {}\n**Source:** {}\n{}", self.id, self.location, self.doc) - } -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs deleted file mode 100644 index 4fa88c3c6da11..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs +++ /dev/null @@ -1,406 +0,0 @@ -use std::{ - cell::{Cell, RefCell}, - fs, - path::{Path, PathBuf}, - sync::Once, - time::Duration, -}; - -use crossbeam_channel::{after, select, Receiver}; -use lsp_server::{Connection, Message, Notification, Request}; -use lsp_types::{notification::Exit, request::Shutdown, TextDocumentIdentifier, Url}; -use project_model::ProjectManifest; -use rust_analyzer::{config::Config, lsp_ext, main_loop}; -use serde::Serialize; -use serde_json::{json, to_string_pretty, Value}; -use test_utils::Fixture; -use vfs::AbsPathBuf; - -use crate::testdir::TestDir; - -pub(crate) struct Project<'a> { - fixture: &'a str, - tmp_dir: Option, - roots: Vec, - config: serde_json::Value, -} - -impl<'a> Project<'a> { - pub(crate) fn with_fixture(fixture: &str) -> Project<'_> { - Project { - fixture, - tmp_dir: None, - roots: vec![], - config: serde_json::json!({ - "cargo": { - // Loading standard library is costly, let's ignore it by default - "noSysroot": true, - // Can't use test binary as rustc wrapper. - "buildScripts": { - "useRustcWrapper": false - }, - } - }), - } - } - - pub(crate) fn tmp_dir(mut self, tmp_dir: TestDir) -> Project<'a> { - self.tmp_dir = Some(tmp_dir); - self - } - - pub(crate) fn root(mut self, path: &str) -> Project<'a> { - self.roots.push(path.into()); - self - } - - pub(crate) fn with_config(mut self, config: serde_json::Value) -> Project<'a> { - fn merge(dst: &mut serde_json::Value, src: serde_json::Value) { - match (dst, src) { - (Value::Object(dst), Value::Object(src)) => { - for (k, v) in src { - merge(dst.entry(k).or_insert(v.clone()), v) - } - } - (dst, src) => *dst = src, - } - } - merge(&mut self.config, config); - self - } - - pub(crate) fn server(self) -> Server { - let tmp_dir = self.tmp_dir.unwrap_or_else(TestDir::new); - static INIT: Once = Once::new(); - INIT.call_once(|| { - tracing_subscriber::fmt() - .with_test_writer() - .with_env_filter(tracing_subscriber::EnvFilter::from_env("RA_LOG")) - .init(); - profile::init_from(crate::PROFILE); - }); - - let (mini_core, proc_macros, fixtures) = Fixture::parse(self.fixture); - assert!(proc_macros.is_empty()); - assert!(mini_core.is_none()); - for entry in fixtures { - let path = tmp_dir.path().join(&entry.path['/'.len_utf8()..]); - fs::create_dir_all(path.parent().unwrap()).unwrap(); - fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); - } - - let tmp_dir_path = AbsPathBuf::assert(tmp_dir.path().to_path_buf()); - let mut roots = - self.roots.into_iter().map(|root| tmp_dir_path.join(root)).collect::>(); - if roots.is_empty() { - roots.push(tmp_dir_path.clone()); - } - let discovered_projects = roots - .into_iter() - .map(|it| ProjectManifest::discover_single(&it).unwrap()) - .collect::>(); - - let mut config = Config::new( - tmp_dir_path, - lsp_types::ClientCapabilities { - workspace: Some(lsp_types::WorkspaceClientCapabilities { - did_change_watched_files: Some( - lsp_types::DidChangeWatchedFilesClientCapabilities { - dynamic_registration: Some(true), - }, - ), - ..Default::default() - }), - text_document: Some(lsp_types::TextDocumentClientCapabilities { - definition: Some(lsp_types::GotoCapability { - link_support: Some(true), - ..Default::default() - }), - code_action: Some(lsp_types::CodeActionClientCapabilities { - code_action_literal_support: Some( - lsp_types::CodeActionLiteralSupport::default(), - ), - ..Default::default() - }), - hover: Some(lsp_types::HoverClientCapabilities { - content_format: Some(vec![lsp_types::MarkupKind::Markdown]), - ..Default::default() - }), - ..Default::default() - }), - window: Some(lsp_types::WindowClientCapabilities { - work_done_progress: Some(false), - ..Default::default() - }), - experimental: Some(json!({ - "serverStatusNotification": true, - })), - ..Default::default() - }, - ); - config.discovered_projects = Some(discovered_projects); - config.update(self.config).expect("invalid config"); - - Server::new(tmp_dir, config) - } -} - -pub(crate) fn project(fixture: &str) -> Server { - Project::with_fixture(fixture).server() -} - -pub(crate) struct Server { - req_id: Cell, - messages: RefCell>, - _thread: jod_thread::JoinHandle<()>, - client: Connection, - /// XXX: remove the tempdir last - dir: TestDir, -} - -impl Server { - fn new(dir: TestDir, config: Config) -> Server { - let (connection, client) = Connection::memory(); - - let _thread = jod_thread::Builder::new() - .name("test server".to_string()) - .spawn(move || main_loop(config, connection).unwrap()) - .expect("failed to spawn a thread"); - - Server { req_id: Cell::new(1), dir, messages: Default::default(), client, _thread } - } - - pub(crate) fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier { - let path = self.dir.path().join(rel_path); - TextDocumentIdentifier { uri: Url::from_file_path(path).unwrap() } - } - - pub(crate) fn notification(&self, params: N::Params) - where - N: lsp_types::notification::Notification, - N::Params: Serialize, - { - let r = Notification::new(N::METHOD.to_string(), params); - self.send_notification(r) - } - - #[track_caller] - pub(crate) fn request(&self, params: R::Params, expected_resp: Value) - where - R: lsp_types::request::Request, - R::Params: Serialize, - { - let actual = self.send_request::(params); - if let Some((expected_part, actual_part)) = find_mismatch(&expected_resp, &actual) { - panic!( - "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n", - to_string_pretty(&expected_resp).unwrap(), - to_string_pretty(&actual).unwrap(), - to_string_pretty(expected_part).unwrap(), - to_string_pretty(actual_part).unwrap(), - ); - } - } - - pub(crate) fn send_request(&self, params: R::Params) -> Value - where - R: lsp_types::request::Request, - R::Params: Serialize, - { - let id = self.req_id.get(); - self.req_id.set(id.wrapping_add(1)); - - let r = Request::new(id.into(), R::METHOD.to_string(), params); - self.send_request_(r) - } - fn send_request_(&self, r: Request) -> Value { - let id = r.id.clone(); - self.client.sender.send(r.clone().into()).unwrap(); - while let Some(msg) = self.recv().unwrap_or_else(|Timeout| panic!("timeout: {:?}", r)) { - match msg { - Message::Request(req) => { - if req.method == "client/registerCapability" { - let params = req.params.to_string(); - if ["workspace/didChangeWatchedFiles", "textDocument/didSave"] - .into_iter() - .any(|it| params.contains(it)) - { - continue; - } - } - panic!("unexpected request: {:?}", req) - } - Message::Notification(_) => (), - Message::Response(res) => { - assert_eq!(res.id, id); - if let Some(err) = res.error { - panic!("error response: {:#?}", err); - } - return res.result.unwrap(); - } - } - } - panic!("no response for {:?}", r); - } - pub(crate) fn wait_until_workspace_is_loaded(self) -> Server { - self.wait_for_message_cond(1, &|msg: &Message| match msg { - Message::Notification(n) if n.method == "experimental/serverStatus" => { - let status = n - .clone() - .extract::("experimental/serverStatus") - .unwrap(); - status.quiescent - } - _ => false, - }) - .unwrap_or_else(|Timeout| panic!("timeout while waiting for ws to load")); - self - } - fn wait_for_message_cond( - &self, - n: usize, - cond: &dyn Fn(&Message) -> bool, - ) -> Result<(), Timeout> { - let mut total = 0; - for msg in self.messages.borrow().iter() { - if cond(msg) { - total += 1 - } - } - while total < n { - let msg = self.recv()?.expect("no response"); - if cond(&msg) { - total += 1; - } - } - Ok(()) - } - fn recv(&self) -> Result, Timeout> { - let msg = recv_timeout(&self.client.receiver)?; - let msg = msg.map(|msg| { - self.messages.borrow_mut().push(msg.clone()); - msg - }); - Ok(msg) - } - fn send_notification(&self, not: Notification) { - self.client.sender.send(Message::Notification(not)).unwrap(); - } - - pub(crate) fn path(&self) -> &Path { - self.dir.path() - } -} - -impl Drop for Server { - fn drop(&mut self) { - self.request::((), Value::Null); - self.notification::(()); - } -} - -struct Timeout; - -fn recv_timeout(receiver: &Receiver) -> Result, Timeout> { - let timeout = - if cfg!(target_os = "macos") { Duration::from_secs(300) } else { Duration::from_secs(120) }; - select! { - recv(receiver) -> msg => Ok(msg.ok()), - recv(after(timeout)) -> _ => Err(Timeout), - } -} - -// Comparison functionality borrowed from cargo: - -/// Compares JSON object for approximate equality. -/// You can use `[..]` wildcard in strings (useful for OS dependent things such -/// as paths). You can use a `"{...}"` string literal as a wildcard for -/// arbitrary nested JSON. Arrays are sorted before comparison. -fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a Value, &'a Value)> { - match (expected, actual) { - (Value::Number(l), Value::Number(r)) if l == r => None, - (Value::Bool(l), Value::Bool(r)) if l == r => None, - (Value::String(l), Value::String(r)) if lines_match(l, r) => None, - (Value::Array(l), Value::Array(r)) => { - if l.len() != r.len() { - return Some((expected, actual)); - } - - let mut l = l.iter().collect::>(); - let mut r = r.iter().collect::>(); - - l.retain(|l| match r.iter().position(|r| find_mismatch(l, r).is_none()) { - Some(i) => { - r.remove(i); - false - } - None => true, - }); - - if !l.is_empty() { - assert!(!r.is_empty()); - Some((l[0], r[0])) - } else { - assert_eq!(r.len(), 0); - None - } - } - (Value::Object(l), Value::Object(r)) => { - fn sorted_values(obj: &serde_json::Map) -> Vec<&Value> { - let mut entries = obj.iter().collect::>(); - entries.sort_by_key(|it| it.0); - entries.into_iter().map(|(_k, v)| v).collect::>() - } - - let same_keys = l.len() == r.len() && l.keys().all(|k| r.contains_key(k)); - if !same_keys { - return Some((expected, actual)); - } - - let l = sorted_values(l); - let r = sorted_values(r); - - l.into_iter().zip(r).find_map(|(l, r)| find_mismatch(l, r)) - } - (Value::Null, Value::Null) => None, - // magic string literal "{...}" acts as wildcard for any sub-JSON - (Value::String(l), _) if l == "{...}" => None, - _ => Some((expected, actual)), - } -} - -/// Compare a line with an expected pattern. -/// - Use `[..]` as a wildcard to match 0 or more characters on the same line -/// (similar to `.*` in a regex). -fn lines_match(expected: &str, actual: &str) -> bool { - // Let's not deal with / vs \ (windows...) - // First replace backslash-escaped backslashes with forward slashes - // which can occur in, for example, JSON output - let expected = expected.replace(r"\\", "/").replace('\\', "/"); - let mut actual: &str = &actual.replace(r"\\", "/").replace('\\', "/"); - for (i, part) in expected.split("[..]").enumerate() { - match actual.find(part) { - Some(j) => { - if i == 0 && j != 0 { - return false; - } - actual = &actual[j + part.len()..]; - } - None => return false, - } - } - actual.is_empty() || expected.ends_with("[..]") -} - -#[test] -fn lines_match_works() { - assert!(lines_match("a b", "a b")); - assert!(lines_match("a[..]b", "a b")); - assert!(lines_match("a[..]", "a b")); - assert!(lines_match("[..]", "a b")); - assert!(lines_match("[..]b", "a b")); - - assert!(!lines_match("[..]b", "c")); - assert!(!lines_match("b", "c")); - assert!(!lines_match("b", "cb")); -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs deleted file mode 100644 index 3bec23a911750..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs +++ /dev/null @@ -1,75 +0,0 @@ -use std::{ - fs, io, - path::{Path, PathBuf}, - sync::atomic::{AtomicUsize, Ordering}, -}; - -pub(crate) struct TestDir { - path: PathBuf, - keep: bool, -} - -impl TestDir { - pub(crate) fn new() -> TestDir { - let temp_dir = std::env::temp_dir(); - // On MacOS builders on GitHub actions, the temp dir is a symlink, and - // that causes problems down the line. Specifically: - // * Cargo may emit different PackageId depending on the working directory - // * rust-analyzer may fail to map LSP URIs to correct paths. - // - // Work-around this by canonicalizing. Note that we don't want to do this - // on *every* OS, as on windows `canonicalize` itself creates problems. - #[cfg(target_os = "macos")] - let temp_dir = temp_dir.canonicalize().unwrap(); - - let base = temp_dir.join("testdir"); - let pid = std::process::id(); - - static CNT: AtomicUsize = AtomicUsize::new(0); - for _ in 0..100 { - let cnt = CNT.fetch_add(1, Ordering::Relaxed); - let path = base.join(format!("{}_{}", pid, cnt)); - if path.is_dir() { - continue; - } - fs::create_dir_all(&path).unwrap(); - return TestDir { path, keep: false }; - } - panic!("Failed to create a temporary directory") - } - #[allow(unused)] - pub(crate) fn keep(mut self) -> TestDir { - self.keep = true; - self - } - pub(crate) fn path(&self) -> &Path { - &self.path - } -} - -impl Drop for TestDir { - fn drop(&mut self) { - if self.keep { - return; - } - remove_dir_all(&self.path).unwrap_or_else(|err| { - panic!("failed to remove temporary directory {}: {}", self.path.display(), err) - }) - } -} - -#[cfg(not(windows))] -fn remove_dir_all(path: &Path) -> io::Result<()> { - fs::remove_dir_all(path) -} - -#[cfg(windows)] -fn remove_dir_all(path: &Path) -> io::Result<()> { - for _ in 0..99 { - if fs::remove_dir_all(path).is_ok() { - return Ok(()); - } - std::thread::sleep(std::time::Duration::from_millis(10)) - } - fs::remove_dir_all(path) -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs deleted file mode 100644 index 18f95925d9a49..0000000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs +++ /dev/null @@ -1,473 +0,0 @@ -use std::{ - collections::HashSet, - path::{Path, PathBuf}, -}; - -use xshell::Shell; - -#[cfg(not(feature = "in-rust-tree"))] -use xshell::cmd; - -#[cfg(not(feature = "in-rust-tree"))] -#[test] -fn check_code_formatting() { - let sh = &Shell::new().unwrap(); - sh.change_dir(sourcegen::project_root()); - sh.set_var("RUSTUP_TOOLCHAIN", "stable"); - - let out = cmd!(sh, "rustfmt --version").read().unwrap(); - if !out.contains("stable") { - panic!( - "Failed to run rustfmt from toolchain 'stable'. \ - Please run `rustup component add rustfmt --toolchain stable` to install it.", - ) - } - - let res = cmd!(sh, "cargo fmt -- --check").run(); - if res.is_err() { - let _ = cmd!(sh, "cargo fmt").run(); - } - res.unwrap() -} - -#[test] -fn check_lsp_extensions_docs() { - let sh = &Shell::new().unwrap(); - - let expected_hash = { - let lsp_ext_rs = sh - .read_file(sourcegen::project_root().join("crates/rust-analyzer/src/lsp_ext.rs")) - .unwrap(); - stable_hash(lsp_ext_rs.as_str()) - }; - - let actual_hash = { - let lsp_extensions_md = - sh.read_file(sourcegen::project_root().join("docs/dev/lsp-extensions.md")).unwrap(); - let text = lsp_extensions_md - .lines() - .find_map(|line| line.strip_prefix("lsp_ext.rs hash:")) - .unwrap() - .trim(); - u64::from_str_radix(text, 16).unwrap() - }; - - if actual_hash != expected_hash { - panic!( - " -lsp_ext.rs was changed without touching lsp-extensions.md. - -Expected hash: {:x} -Actual hash: {:x} - -Please adjust docs/dev/lsp-extensions.md. -", - expected_hash, actual_hash - ) - } -} - -#[test] -fn files_are_tidy() { - let sh = &Shell::new().unwrap(); - - let files = sourcegen::list_files(&sourcegen::project_root().join("crates")); - - let mut tidy_docs = TidyDocs::default(); - let mut tidy_marks = TidyMarks::default(); - for path in files { - let extension = path.extension().unwrap_or_default().to_str().unwrap_or_default(); - match extension { - "rs" => { - let text = sh.read_file(&path).unwrap(); - check_todo(&path, &text); - check_dbg(&path, &text); - check_test_attrs(&path, &text); - check_trailing_ws(&path, &text); - deny_clippy(&path, &text); - tidy_docs.visit(&path, &text); - tidy_marks.visit(&path, &text); - } - "toml" => { - let text = sh.read_file(&path).unwrap(); - check_cargo_toml(&path, text); - } - _ => (), - } - } - - tidy_docs.finish(); - tidy_marks.finish(); -} - -fn check_cargo_toml(path: &Path, text: String) { - let mut section = None; - for (line_no, text) in text.lines().enumerate() { - let text = text.trim(); - if text.starts_with('[') { - if !text.ends_with(']') { - panic!( - "\nplease don't add comments or trailing whitespace in section lines.\n\ - {}:{}\n", - path.display(), - line_no + 1 - ) - } - section = Some(text); - continue; - } - let text: String = text.split_whitespace().collect(); - if !text.contains("path=") { - continue; - } - match section { - Some(s) if s.contains("dev-dependencies") => { - if text.contains("version") { - panic!( - "\ncargo internal dev-dependencies should not have a version.\n\ - {}:{}\n", - path.display(), - line_no + 1 - ); - } - } - Some(s) if s.contains("dependencies") => { - if !text.contains("version") { - panic!( - "\ncargo internal dependencies should have a version.\n\ - {}:{}\n", - path.display(), - line_no + 1 - ); - } - } - _ => {} - } - } -} - -fn deny_clippy(path: &Path, text: &str) { - let ignore = &[ - // The documentation in string literals may contain anything for its own purposes - "ide-db/src/generated/lints.rs", - // The tests test clippy lint hovers - "ide/src/hover/tests.rs", - // The tests test clippy lint completions - "ide-completion/src/tests/attribute.rs", - ]; - if ignore.iter().any(|p| path.ends_with(p)) { - return; - } - - if text.contains("\u{61}llow(clippy") { - panic!( - "\n\nallowing lints is forbidden: {}. -rust-analyzer intentionally doesn't check clippy on CI. -You can allow lint globally via `xtask clippy`. -See https://github.com/rust-lang/rust-clippy/issues/5537 for discussion. - -", - path.display() - ) - } -} - -#[cfg(not(feature = "in-rust-tree"))] -#[test] -fn check_licenses() { - let sh = &Shell::new().unwrap(); - - let expected = " -0BSD OR MIT OR Apache-2.0 -Apache-2.0 -Apache-2.0 OR BSL-1.0 -Apache-2.0 OR MIT -Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT -Apache-2.0/MIT -BSD-3-Clause -BlueOak-1.0.0 OR MIT OR Apache-2.0 -CC0-1.0 OR Artistic-2.0 -ISC -MIT -MIT / Apache-2.0 -MIT OR Apache-2.0 -MIT OR Apache-2.0 OR Zlib -MIT OR Zlib OR Apache-2.0 -MIT/Apache-2.0 -Unlicense/MIT -Zlib OR Apache-2.0 OR MIT -" - .lines() - .filter(|it| !it.is_empty()) - .collect::>(); - - let meta = cmd!(sh, "cargo metadata --format-version 1").read().unwrap(); - let mut licenses = meta - .split(|c| c == ',' || c == '{' || c == '}') - .filter(|it| it.contains(r#""license""#)) - .map(|it| it.trim()) - .map(|it| it[r#""license":"#.len()..].trim_matches('"')) - .collect::>(); - licenses.sort_unstable(); - licenses.dedup(); - if licenses != expected { - let mut diff = String::new(); - - diff.push_str("New Licenses:\n"); - for &l in licenses.iter() { - if !expected.contains(&l) { - diff += &format!(" {}\n", l) - } - } - - diff.push_str("\nMissing Licenses:\n"); - for &l in expected.iter() { - if !licenses.contains(&l) { - diff += &format!(" {}\n", l) - } - } - - panic!("different set of licenses!\n{}", diff); - } - assert_eq!(licenses, expected); -} - -fn check_todo(path: &Path, text: &str) { - let need_todo = &[ - // This file itself obviously needs to use todo (<- like this!). - "tests/tidy.rs", - // Some of our assists generate `todo!()`. - "handlers/add_turbo_fish.rs", - "handlers/generate_function.rs", - "handlers/add_missing_match_arms.rs", - "handlers/replace_derive_with_manual_impl.rs", - // To support generating `todo!()` in assists, we have `expr_todo()` in - // `ast::make`. - "ast/make.rs", - // The documentation in string literals may contain anything for its own purposes - "ide-db/src/generated/lints.rs", - "ide-assists/src/utils/gen_trait_fn_body.rs", - "ide-assists/src/tests/generated.rs", - // The tests for missing fields - "ide-diagnostics/src/handlers/missing_fields.rs", - ]; - if need_todo.iter().any(|p| path.ends_with(p)) { - return; - } - if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") { - // Generated by an assist - if text.contains("${0:todo!()}") { - return; - } - - panic!( - "\nTODO markers or todo! macros should not be committed to the master branch,\n\ - use FIXME instead\n\ - {}\n", - path.display(), - ) - } -} - -fn check_dbg(path: &Path, text: &str) { - let need_dbg = &[ - // This file itself obviously needs to use dbg. - "slow-tests/tidy.rs", - // Assists to remove `dbg!()` - "handlers/remove_dbg.rs", - // We have .dbg postfix - "ide-completion/src/completions/postfix.rs", - "ide-completion/src/completions/keyword.rs", - "ide-completion/src/tests/proc_macros.rs", - // The documentation in string literals may contain anything for its own purposes - "ide-completion/src/lib.rs", - "ide-db/src/generated/lints.rs", - // test for doc test for remove_dbg - "src/tests/generated.rs", - ]; - if need_dbg.iter().any(|p| path.ends_with(p)) { - return; - } - if text.contains("dbg!") { - panic!( - "\ndbg! macros should not be committed to the master branch,\n\ - {}\n", - path.display(), - ) - } -} - -fn check_test_attrs(path: &Path, text: &str) { - let ignore_rule = - "https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/style.md#ignore"; - let need_ignore: &[&str] = &[ - // This file. - "slow-tests/tidy.rs", - // Special case to run `#[ignore]` tests. - "ide/src/runnables.rs", - // A legit test which needs to be ignored, as it takes too long to run - // :( - "hir-def/src/nameres/collector.rs", - // Long sourcegen test to generate lint completions. - "ide-db/src/tests/sourcegen_lints.rs", - // Obviously needs ignore. - "ide-assists/src/handlers/toggle_ignore.rs", - // See above. - "ide-assists/src/tests/generated.rs", - ]; - if text.contains("#[ignore") && !need_ignore.iter().any(|p| path.ends_with(p)) { - panic!("\ndon't `#[ignore]` tests, see:\n\n {}\n\n {}\n", ignore_rule, path.display(),) - } - - let panic_rule = - "https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/style.md#should_panic"; - let need_panic: &[&str] = &[ - // This file. - "slow-tests/tidy.rs", - "test-utils/src/fixture.rs", - ]; - if text.contains("#[should_panic") && !need_panic.iter().any(|p| path.ends_with(p)) { - panic!( - "\ndon't add `#[should_panic]` tests, see:\n\n {}\n\n {}\n", - panic_rule, - path.display(), - ) - } -} - -fn check_trailing_ws(path: &Path, text: &str) { - if is_exclude_dir(path, &["test_data"]) { - return; - } - for (line_number, line) in text.lines().enumerate() { - if line.chars().last().map(char::is_whitespace) == Some(true) { - panic!("Trailing whitespace in {} at line {}", path.display(), line_number + 1) - } - } -} - -#[derive(Default)] -struct TidyDocs { - missing_docs: Vec, - contains_fixme: Vec, -} - -impl TidyDocs { - fn visit(&mut self, path: &Path, text: &str) { - // Tests and diagnostic fixes don't need module level comments. - if is_exclude_dir(path, &["tests", "test_data", "fixes", "grammar"]) { - return; - } - - if is_exclude_file(path) { - return; - } - - let first_line = match text.lines().next() { - Some(it) => it, - None => return, - }; - - if first_line.starts_with("//!") { - if first_line.contains("FIXME") { - self.contains_fixme.push(path.to_path_buf()); - } - } else { - if text.contains("// Feature:") - || text.contains("// Assist:") - || text.contains("// Diagnostic:") - { - return; - } - self.missing_docs.push(path.display().to_string()); - } - - fn is_exclude_file(d: &Path) -> bool { - let file_names = ["tests.rs", "famous_defs_fixture.rs"]; - - d.file_name() - .unwrap_or_default() - .to_str() - .map(|f_n| file_names.iter().any(|name| *name == f_n)) - .unwrap_or(false) - } - } - - fn finish(self) { - if !self.missing_docs.is_empty() { - panic!( - "\nMissing docs strings\n\n\ - modules:\n{}\n\n", - self.missing_docs.join("\n") - ) - } - - for path in self.contains_fixme { - panic!("FIXME doc in a fully-documented crate: {}", path.display()) - } - } -} - -fn is_exclude_dir(p: &Path, dirs_to_exclude: &[&str]) -> bool { - p.strip_prefix(sourcegen::project_root()) - .unwrap() - .components() - .rev() - .skip(1) - .filter_map(|it| it.as_os_str().to_str()) - .any(|it| dirs_to_exclude.contains(&it)) -} - -#[derive(Default)] -struct TidyMarks { - hits: HashSet, - checks: HashSet, -} - -impl TidyMarks { - fn visit(&mut self, _path: &Path, text: &str) { - find_marks(&mut self.hits, text, "hit"); - find_marks(&mut self.checks, text, "check"); - find_marks(&mut self.checks, text, "check_count"); - } - - fn finish(self) { - assert!(!self.hits.is_empty()); - - let diff: Vec<_> = - self.hits.symmetric_difference(&self.checks).map(|it| it.as_str()).collect(); - - if !diff.is_empty() { - panic!("unpaired marks: {:?}", diff) - } - } -} - -#[allow(deprecated)] -fn stable_hash(text: &str) -> u64 { - use std::hash::{Hash, Hasher, SipHasher}; - - let text = text.replace('\r', ""); - let mut hasher = SipHasher::default(); - text.hash(&mut hasher); - hasher.finish() -} - -fn find_marks(set: &mut HashSet, text: &str, mark: &str) { - let mut text = text; - let mut prev_text = ""; - while text != prev_text { - prev_text = text; - if let Some(idx) = text.find(mark) { - text = &text[idx + mark.len()..]; - if let Some(stripped_text) = text.strip_prefix("!(") { - text = stripped_text.trim_start(); - if let Some(idx2) = text.find(|c: char| !(c.is_alphanumeric() || c == '_')) { - let mark_text = &text[..idx2]; - set.insert(mark_text.to_string()); - text = &text[idx2..]; - } - } - } - } -} diff --git a/src/tools/rust-analyzer/crates/sourcegen/Cargo.toml b/src/tools/rust-analyzer/crates/sourcegen/Cargo.toml deleted file mode 100644 index a84110d940bc7..0000000000000 --- a/src/tools/rust-analyzer/crates/sourcegen/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "sourcegen" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -xshell = "0.2.2" - -[features] -in-rust-tree = [] diff --git a/src/tools/rust-analyzer/crates/sourcegen/src/lib.rs b/src/tools/rust-analyzer/crates/sourcegen/src/lib.rs deleted file mode 100644 index ce0224ec744d9..0000000000000 --- a/src/tools/rust-analyzer/crates/sourcegen/src/lib.rs +++ /dev/null @@ -1,203 +0,0 @@ -//! rust-analyzer relies heavily on source code generation. -//! -//! Things like feature documentation or assist tests are implemented by -//! processing rust-analyzer's own source code and generating the appropriate -//! output. See `sourcegen_` tests in various crates. -//! -//! This crate contains utilities to make this kind of source-gen easy. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -use std::{ - fmt, fs, mem, - path::{Path, PathBuf}, -}; - -use xshell::{cmd, Shell}; - -pub fn list_rust_files(dir: &Path) -> Vec { - let mut res = list_files(dir); - res.retain(|it| { - it.file_name().unwrap_or_default().to_str().unwrap_or_default().ends_with(".rs") - }); - res -} - -pub fn list_files(dir: &Path) -> Vec { - let mut res = Vec::new(); - let mut work = vec![dir.to_path_buf()]; - while let Some(dir) = work.pop() { - for entry in dir.read_dir().unwrap() { - let entry = entry.unwrap(); - let file_type = entry.file_type().unwrap(); - let path = entry.path(); - let is_hidden = - path.file_name().unwrap_or_default().to_str().unwrap_or_default().starts_with('.'); - if !is_hidden { - if file_type.is_dir() { - work.push(path); - } else if file_type.is_file() { - res.push(path); - } - } - } - } - res -} - -#[derive(Clone)] -pub struct CommentBlock { - pub id: String, - pub line: usize, - pub contents: Vec, - is_doc: bool, -} - -impl CommentBlock { - pub fn extract(tag: &str, text: &str) -> Vec { - assert!(tag.starts_with(char::is_uppercase)); - - let tag = format!("{}:", tag); - // Would be nice if we had `.retain_mut` here! - CommentBlock::extract_untagged(text) - .into_iter() - .filter_map(|mut block| { - let first = block.contents.remove(0); - first.strip_prefix(&tag).map(|id| { - if block.is_doc { - panic!( - "Use plain (non-doc) comments with tags like {}:\n {}", - tag, first - ); - } - - block.id = id.trim().to_string(); - block - }) - }) - .collect() - } - - pub fn extract_untagged(text: &str) -> Vec { - let mut res = Vec::new(); - - let lines = text.lines().map(str::trim_start); - - let dummy_block = - CommentBlock { id: String::new(), line: 0, contents: Vec::new(), is_doc: false }; - let mut block = dummy_block.clone(); - for (line_num, line) in lines.enumerate() { - match line.strip_prefix("//") { - Some(mut contents) => { - if let Some('/' | '!') = contents.chars().next() { - contents = &contents[1..]; - block.is_doc = true; - } - if let Some(' ') = contents.chars().next() { - contents = &contents[1..]; - } - block.contents.push(contents.to_string()); - } - None => { - if !block.contents.is_empty() { - let block = mem::replace(&mut block, dummy_block.clone()); - res.push(block); - } - block.line = line_num + 2; - } - } - } - if !block.contents.is_empty() { - res.push(block); - } - res - } -} - -#[derive(Debug)] -pub struct Location { - pub file: PathBuf, - pub line: usize, -} - -impl fmt::Display for Location { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let path = self.file.strip_prefix(&project_root()).unwrap().display().to_string(); - let path = path.replace('\\', "/"); - let name = self.file.file_name().unwrap(); - write!( - f, - "https://github.com/rust-lang/rust-analyzer/blob/master/{}#L{}[{}]", - path, - self.line, - name.to_str().unwrap() - ) - } -} - -fn ensure_rustfmt(sh: &Shell) { - let version = cmd!(sh, "rustfmt --version").read().unwrap_or_default(); - if !version.contains("stable") { - panic!( - "Failed to run rustfmt from toolchain 'stable'. \ - Please run `rustup component add rustfmt --toolchain stable` to install it.", - ); - } -} - -pub fn reformat(text: String) -> String { - let sh = Shell::new().unwrap(); - sh.set_var("RUSTUP_TOOLCHAIN", "stable"); - ensure_rustfmt(&sh); - let rustfmt_toml = project_root().join("rustfmt.toml"); - let mut stdout = cmd!(sh, "rustfmt --config-path {rustfmt_toml} --config fn_single_line=true") - .stdin(text) - .read() - .unwrap(); - if !stdout.ends_with('\n') { - stdout.push('\n'); - } - stdout -} - -pub fn add_preamble(generator: &'static str, mut text: String) -> String { - let preamble = format!("//! Generated by `{}`, do not edit by hand.\n\n", generator); - text.insert_str(0, &preamble); - text -} - -/// Checks that the `file` has the specified `contents`. If that is not the -/// case, updates the file and then fails the test. -pub fn ensure_file_contents(file: &Path, contents: &str) { - if let Ok(old_contents) = fs::read_to_string(file) { - if normalize_newlines(&old_contents) == normalize_newlines(contents) { - // File is already up to date. - return; - } - } - - let display_path = file.strip_prefix(&project_root()).unwrap_or(file); - eprintln!( - "\n\x1b[31;1merror\x1b[0m: {} was not up-to-date, updating\n", - display_path.display() - ); - if std::env::var("CI").is_ok() { - eprintln!(" NOTE: run `cargo test` locally and commit the updated files\n"); - } - if let Some(parent) = file.parent() { - let _ = fs::create_dir_all(parent); - } - fs::write(file, contents).unwrap(); - panic!("some file was not up to date and has been updated, simply re-run the tests"); -} - -fn normalize_newlines(s: &str) -> String { - s.replace("\r\n", "\n") -} - -pub fn project_root() -> PathBuf { - let dir = env!("CARGO_MANIFEST_DIR"); - let res = PathBuf::from(dir).parent().unwrap().parent().unwrap().to_owned(); - assert!(res.join("triagebot.toml").exists()); - res -} diff --git a/src/tools/rust-analyzer/crates/stdx/Cargo.toml b/src/tools/rust-analyzer/crates/stdx/Cargo.toml deleted file mode 100644 index 092b99ae5152d..0000000000000 --- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "stdx" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -libc = "0.2.126" -backtrace = { version = "0.3.65", optional = true } -always-assert = { version = "0.1.2", features = ["log"] } -# Think twice before adding anything here - -[target.'cfg(windows)'.dependencies] -miow = "0.4.0" -winapi = { version = "0.3.9", features = ["winerror"] } - -[features] -# Uncomment to enable for the whole crate graph -# default = [ "backtrace" ] diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs deleted file mode 100644 index b4d45206c44ea..0000000000000 --- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs +++ /dev/null @@ -1,247 +0,0 @@ -//! Missing batteries for standard libraries. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -use std::process::Command; -use std::{cmp::Ordering, ops, time::Instant}; -use std::{io as sio, iter}; - -mod macros; -pub mod process; -pub mod panic_context; -pub mod non_empty_vec; - -pub use always_assert::{always, never}; - -#[inline(always)] -pub fn is_ci() -> bool { - option_env!("CI").is_some() -} - -#[must_use] -pub fn timeit(label: &'static str) -> impl Drop { - let start = Instant::now(); - defer(move || eprintln!("{}: {:.2?}", label, start.elapsed())) -} - -/// Prints backtrace to stderr, useful for debugging. -pub fn print_backtrace() { - #[cfg(feature = "backtrace")] - eprintln!("{:?}", backtrace::Backtrace::new()); - - #[cfg(not(feature = "backtrace"))] - eprintln!( - r#"Enable the backtrace feature. -Uncomment `default = [ "backtrace" ]` in `crates/stdx/Cargo.toml`. -"# - ); -} - -pub fn to_lower_snake_case(s: &str) -> String { - to_snake_case(s, char::to_ascii_lowercase) -} -pub fn to_upper_snake_case(s: &str) -> String { - to_snake_case(s, char::to_ascii_uppercase) -} - -// Code partially taken from rust/compiler/rustc_lint/src/nonstandard_style.rs -// commit: 9626f2b -fn to_snake_case char>(mut s: &str, change_case: F) -> String { - let mut words = vec![]; - - // Preserve leading underscores - s = s.trim_start_matches(|c: char| { - if c == '_' { - words.push(String::new()); - true - } else { - false - } - }); - - for s in s.split('_') { - let mut last_upper = false; - let mut buf = String::new(); - - if s.is_empty() { - continue; - } - - for ch in s.chars() { - if !buf.is_empty() && buf != "'" && ch.is_uppercase() && !last_upper { - words.push(buf); - buf = String::new(); - } - - last_upper = ch.is_uppercase(); - buf.extend(iter::once(change_case(&ch))); - } - - words.push(buf); - } - - words.join("_") -} - -pub fn replace(buf: &mut String, from: char, to: &str) { - if !buf.contains(from) { - return; - } - // FIXME: do this in place. - *buf = buf.replace(from, to); -} - -pub fn trim_indent(mut text: &str) -> String { - if text.starts_with('\n') { - text = &text[1..]; - } - let indent = text - .lines() - .filter(|it| !it.trim().is_empty()) - .map(|it| it.len() - it.trim_start().len()) - .min() - .unwrap_or(0); - text.split_inclusive('\n') - .map( - |line| { - if line.len() <= indent { - line.trim_start_matches(' ') - } else { - &line[indent..] - } - }, - ) - .collect() -} - -pub fn equal_range_by(slice: &[T], mut key: F) -> ops::Range -where - F: FnMut(&T) -> Ordering, -{ - let start = slice.partition_point(|it| key(it) == Ordering::Less); - let len = slice[start..].partition_point(|it| key(it) == Ordering::Equal); - start..start + len -} - -#[must_use] -pub fn defer(f: F) -> impl Drop { - struct D(Option); - impl Drop for D { - fn drop(&mut self) { - if let Some(f) = self.0.take() { - f(); - } - } - } - D(Some(f)) -} - -/// A [`std::process::Child`] wrapper that will kill the child on drop. -#[cfg_attr(not(target_arch = "wasm32"), repr(transparent))] -#[derive(Debug)] -pub struct JodChild(pub std::process::Child); - -impl ops::Deref for JodChild { - type Target = std::process::Child; - fn deref(&self) -> &std::process::Child { - &self.0 - } -} - -impl ops::DerefMut for JodChild { - fn deref_mut(&mut self) -> &mut std::process::Child { - &mut self.0 - } -} - -impl Drop for JodChild { - fn drop(&mut self) { - let _ = self.0.kill(); - let _ = self.0.wait(); - } -} - -impl JodChild { - pub fn spawn(mut command: Command) -> sio::Result { - command.spawn().map(Self) - } - - pub fn into_inner(self) -> std::process::Child { - if cfg!(target_arch = "wasm32") { - panic!("no processes on wasm"); - } - // SAFETY: repr transparent, except on WASM - unsafe { std::mem::transmute::(self) } - } -} - -// feature: iter_order_by -// Iterator::eq_by -pub fn iter_eq_by(this: I2, other: I, mut eq: F) -> bool -where - I: IntoIterator, - I2: IntoIterator, - F: FnMut(I2::Item, I::Item) -> bool, -{ - let mut other = other.into_iter(); - let mut this = this.into_iter(); - - loop { - let x = match this.next() { - None => return other.next().is_none(), - Some(val) => val, - }; - - let y = match other.next() { - None => return false, - Some(val) => val, - }; - - if !eq(x, y) { - return false; - } - } -} - -/// Returns all final segments of the argument, longest first. -pub fn slice_tails(this: &[T]) -> impl Iterator { - (0..this.len()).map(|i| &this[i..]) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_trim_indent() { - assert_eq!(trim_indent(""), ""); - assert_eq!( - trim_indent( - " - hello - world -" - ), - "hello\nworld\n" - ); - assert_eq!( - trim_indent( - " - hello - world" - ), - "hello\nworld" - ); - assert_eq!(trim_indent(" hello\n world\n"), "hello\nworld\n"); - assert_eq!( - trim_indent( - " - fn main() { - return 92; - } - " - ), - "fn main() {\n return 92;\n}\n" - ); - } -} diff --git a/src/tools/rust-analyzer/crates/stdx/src/macros.rs b/src/tools/rust-analyzer/crates/stdx/src/macros.rs deleted file mode 100644 index d91fc690cb517..0000000000000 --- a/src/tools/rust-analyzer/crates/stdx/src/macros.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Convenience macros. - -#[macro_export] -macro_rules! eprintln { - ($($tt:tt)*) => {{ - if $crate::is_ci() { - panic!("Forgot to remove debug-print?") - } - std::eprintln!($($tt)*) - }} -} - -/// Appends formatted string to a `String`. -#[macro_export] -macro_rules! format_to { - ($buf:expr) => (); - ($buf:expr, $lit:literal $($arg:tt)*) => { - { use ::std::fmt::Write as _; let _ = ::std::write!($buf, $lit $($arg)*); } - }; -} - -/// Generates `From` impls for `Enum E { Foo(Foo), Bar(Bar) }` enums -/// -/// # Example -/// -/// ```rust -/// impl_from!(Struct, Union, Enum for Adt); -/// ``` -#[macro_export] -macro_rules! impl_from { - ($($variant:ident $(($($sub_variant:ident),*))?),* for $enum:ident) => { - $( - impl From<$variant> for $enum { - fn from(it: $variant) -> $enum { - $enum::$variant(it) - } - } - $($( - impl From<$sub_variant> for $enum { - fn from(it: $sub_variant) -> $enum { - $enum::$variant($variant::$sub_variant(it)) - } - } - )*)? - )* - } -} diff --git a/src/tools/rust-analyzer/crates/stdx/src/non_empty_vec.rs b/src/tools/rust-analyzer/crates/stdx/src/non_empty_vec.rs deleted file mode 100644 index 342194c7838c6..0000000000000 --- a/src/tools/rust-analyzer/crates/stdx/src/non_empty_vec.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! See [`NonEmptyVec`]. - -/// A [`Vec`] that is guaranteed to at least contain one element. -pub struct NonEmptyVec { - first: T, - rest: Vec, -} - -impl NonEmptyVec { - #[inline] - pub fn new(first: T) -> Self { - NonEmptyVec { first, rest: Vec::new() } - } - - #[inline] - pub fn last_mut(&mut self) -> &mut T { - self.rest.last_mut().unwrap_or(&mut self.first) - } - - #[inline] - pub fn pop(&mut self) -> Option { - self.rest.pop() - } - - #[inline] - pub fn push(&mut self, value: T) { - self.rest.push(value) - } - - #[inline] - pub fn len(&self) -> usize { - 1 + self.rest.len() - } - - #[inline] - pub fn into_last(mut self) -> T { - self.rest.pop().unwrap_or(self.first) - } -} diff --git a/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs b/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs deleted file mode 100644 index f8fafc5a67724..0000000000000 --- a/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs +++ /dev/null @@ -1,49 +0,0 @@ -//! A micro-crate to enhance panic messages with context info. -//! -//! FIXME: upstream to ? - -use std::{cell::RefCell, panic, sync::Once}; - -pub fn enter(context: String) -> PanicContext { - static ONCE: Once = Once::new(); - ONCE.call_once(PanicContext::init); - - with_ctx(|ctx| ctx.push(context)); - PanicContext { _priv: () } -} - -#[must_use] -pub struct PanicContext { - _priv: (), -} - -impl PanicContext { - fn init() { - let default_hook = panic::take_hook(); - let hook = move |panic_info: &panic::PanicInfo<'_>| { - with_ctx(|ctx| { - if !ctx.is_empty() { - eprintln!("Panic context:"); - for frame in ctx.iter() { - eprintln!("> {}\n", frame); - } - } - default_hook(panic_info); - }); - }; - panic::set_hook(Box::new(hook)); - } -} - -impl Drop for PanicContext { - fn drop(&mut self) { - with_ctx(|ctx| assert!(ctx.pop().is_some())); - } -} - -fn with_ctx(f: impl FnOnce(&mut Vec)) { - thread_local! { - static CTX: RefCell> = RefCell::new(Vec::new()); - } - CTX.with(|ctx| f(&mut *ctx.borrow_mut())); -} diff --git a/src/tools/rust-analyzer/crates/stdx/src/process.rs b/src/tools/rust-analyzer/crates/stdx/src/process.rs deleted file mode 100644 index e5aa343651876..0000000000000 --- a/src/tools/rust-analyzer/crates/stdx/src/process.rs +++ /dev/null @@ -1,267 +0,0 @@ -//! Read both stdout and stderr of child without deadlocks. -//! -//! -//! - -use std::{ - io, - process::{ChildStderr, ChildStdout, Command, Output, Stdio}, -}; - -use crate::JodChild; - -pub fn streaming_output( - out: ChildStdout, - err: ChildStderr, - on_stdout_line: &mut dyn FnMut(&str), - on_stderr_line: &mut dyn FnMut(&str), -) -> io::Result<(Vec, Vec)> { - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - - imp::read2(out, err, &mut |is_out, data, eof| { - let idx = if eof { - data.len() - } else { - match data.iter().rposition(|b| *b == b'\n') { - Some(i) => i + 1, - None => return, - } - }; - { - // scope for new_lines - let new_lines = { - let dst = if is_out { &mut stdout } else { &mut stderr }; - let start = dst.len(); - let data = data.drain(..idx); - dst.extend(data); - &dst[start..] - }; - for line in String::from_utf8_lossy(new_lines).lines() { - if is_out { - on_stdout_line(line); - } else { - on_stderr_line(line); - } - } - } - })?; - - Ok((stdout, stderr)) -} - -pub fn spawn_with_streaming_output( - mut cmd: Command, - on_stdout_line: &mut dyn FnMut(&str), - on_stderr_line: &mut dyn FnMut(&str), -) -> io::Result { - let cmd = cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null()); - - let mut child = JodChild(cmd.spawn()?); - let (stdout, stderr) = streaming_output( - child.stdout.take().unwrap(), - child.stderr.take().unwrap(), - on_stdout_line, - on_stderr_line, - )?; - let status = child.wait()?; - Ok(Output { status, stdout, stderr }) -} - -#[cfg(unix)] -mod imp { - use std::{ - io::{self, prelude::*}, - mem, - os::unix::prelude::*, - process::{ChildStderr, ChildStdout}, - }; - - pub(crate) fn read2( - mut out_pipe: ChildStdout, - mut err_pipe: ChildStderr, - data: &mut dyn FnMut(bool, &mut Vec, bool), - ) -> io::Result<()> { - unsafe { - libc::fcntl(out_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK); - libc::fcntl(err_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK); - } - - let mut out_done = false; - let mut err_done = false; - let mut out = Vec::new(); - let mut err = Vec::new(); - - let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; - fds[0].fd = out_pipe.as_raw_fd(); - fds[0].events = libc::POLLIN; - fds[1].fd = err_pipe.as_raw_fd(); - fds[1].events = libc::POLLIN; - let mut nfds = 2; - let mut errfd = 1; - - while nfds > 0 { - // wait for either pipe to become readable using `select` - let r = unsafe { libc::poll(fds.as_mut_ptr(), nfds, -1) }; - if r == -1 { - let err = io::Error::last_os_error(); - if err.kind() == io::ErrorKind::Interrupted { - continue; - } - return Err(err); - } - - // Read as much as we can from each pipe, ignoring EWOULDBLOCK or - // EAGAIN. If we hit EOF, then this will happen because the underlying - // reader will return Ok(0), in which case we'll see `Ok` ourselves. In - // this case we flip the other fd back into blocking mode and read - // whatever's leftover on that file descriptor. - let handle = |res: io::Result<_>| match res { - Ok(_) => Ok(true), - Err(e) => { - if e.kind() == io::ErrorKind::WouldBlock { - Ok(false) - } else { - Err(e) - } - } - }; - if !err_done && fds[errfd].revents != 0 && handle(err_pipe.read_to_end(&mut err))? { - err_done = true; - nfds -= 1; - } - data(false, &mut err, err_done); - if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? { - out_done = true; - fds[0].fd = err_pipe.as_raw_fd(); - errfd = 0; - nfds -= 1; - } - data(true, &mut out, out_done); - } - Ok(()) - } -} - -#[cfg(windows)] -mod imp { - use std::{ - io, - os::windows::prelude::*, - process::{ChildStderr, ChildStdout}, - slice, - }; - - use miow::{ - iocp::{CompletionPort, CompletionStatus}, - pipe::NamedPipe, - Overlapped, - }; - use winapi::shared::winerror::ERROR_BROKEN_PIPE; - - struct Pipe<'a> { - dst: &'a mut Vec, - overlapped: Overlapped, - pipe: NamedPipe, - done: bool, - } - - pub(crate) fn read2( - out_pipe: ChildStdout, - err_pipe: ChildStderr, - data: &mut dyn FnMut(bool, &mut Vec, bool), - ) -> io::Result<()> { - let mut out = Vec::new(); - let mut err = Vec::new(); - - let port = CompletionPort::new(1)?; - port.add_handle(0, &out_pipe)?; - port.add_handle(1, &err_pipe)?; - - unsafe { - let mut out_pipe = Pipe::new(out_pipe, &mut out); - let mut err_pipe = Pipe::new(err_pipe, &mut err); - - out_pipe.read()?; - err_pipe.read()?; - - let mut status = [CompletionStatus::zero(), CompletionStatus::zero()]; - - while !out_pipe.done || !err_pipe.done { - for status in port.get_many(&mut status, None)? { - if status.token() == 0 { - out_pipe.complete(status); - data(true, out_pipe.dst, out_pipe.done); - out_pipe.read()?; - } else { - err_pipe.complete(status); - data(false, err_pipe.dst, err_pipe.done); - err_pipe.read()?; - } - } - } - - Ok(()) - } - } - - impl<'a> Pipe<'a> { - unsafe fn new(p: P, dst: &'a mut Vec) -> Pipe<'a> { - Pipe { - dst, - pipe: NamedPipe::from_raw_handle(p.into_raw_handle()), - overlapped: Overlapped::zero(), - done: false, - } - } - - unsafe fn read(&mut self) -> io::Result<()> { - let dst = slice_to_end(self.dst); - match self.pipe.read_overlapped(dst, self.overlapped.raw()) { - Ok(_) => Ok(()), - Err(e) => { - if e.raw_os_error() == Some(ERROR_BROKEN_PIPE as i32) { - self.done = true; - Ok(()) - } else { - Err(e) - } - } - } - } - - unsafe fn complete(&mut self, status: &CompletionStatus) { - let prev = self.dst.len(); - self.dst.set_len(prev + status.bytes_transferred() as usize); - if status.bytes_transferred() == 0 { - self.done = true; - } - } - } - - unsafe fn slice_to_end(v: &mut Vec) -> &mut [u8] { - if v.capacity() == 0 { - v.reserve(16); - } - if v.capacity() == v.len() { - v.reserve(1); - } - slice::from_raw_parts_mut(v.as_mut_ptr().add(v.len()), v.capacity() - v.len()) - } -} - -#[cfg(target_arch = "wasm32")] -mod imp { - use std::{ - io, - process::{ChildStderr, ChildStdout}, - }; - - pub(crate) fn read2( - _out_pipe: ChildStdout, - _err_pipe: ChildStderr, - _data: &mut dyn FnMut(bool, &mut Vec, bool), - ) -> io::Result<()> { - panic!("no processes on wasm") - } -} diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml deleted file mode 100644 index 0e2dec386ff77..0000000000000 --- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -name = "syntax" -version = "0.0.0" -description = "Comment and whitespace preserving parser for the Rust language" -license = "MIT OR Apache-2.0" -repository = "https://github.com/rust-lang/rust-analyzer" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -cov-mark = "2.0.0-pre.1" -itertools = "0.10.3" -rowan = "0.15.8" -rustc_lexer = { version = "725.0.0", package = "rustc-ap-rustc_lexer" } -rustc-hash = "1.1.0" -once_cell = "1.12.0" -indexmap = "1.9.1" -smol_str = "0.1.23" - -stdx = { path = "../stdx", version = "0.0.0" } -text-edit = { path = "../text-edit", version = "0.0.0" } -parser = { path = "../parser", version = "0.0.0" } -profile = { path = "../profile", version = "0.0.0" } - -[dev-dependencies] -rayon = "1.5.3" -expect-test = "1.4.0" -proc-macro2 = "1.0.39" -quote = "1.0.20" -ungrammar = "1.16.1" - -test-utils = { path = "../test-utils" } -sourcegen = { path = "../sourcegen" } - -[features] -in-rust-tree = [] diff --git a/src/tools/rust-analyzer/crates/syntax/fuzz/.gitignore b/src/tools/rust-analyzer/crates/syntax/fuzz/.gitignore deleted file mode 100644 index f734abd499ca9..0000000000000 --- a/src/tools/rust-analyzer/crates/syntax/fuzz/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -Cargo.lock -target -corpus -artifacts diff --git a/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml deleted file mode 100644 index ba2f515b0bc1b..0000000000000 --- a/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ - -[package] -name = "syntax-fuzz" -version = "0.0.1" -publish = false -edition = "2021" -rust-version = "1.57" - -[package.metadata] -cargo-fuzz = true - -[dependencies] -syntax = { path = "..", version = "0.0.0" } -text_edit = { path = "../../text_edit", version = "0.0.0" } -libfuzzer-sys = { git = "https://github.com/rust-fuzz/libfuzzer-sys.git" } - -# Prevent this from interfering with workspaces -[workspace] -members = ["."] - -[[bin]] -name = "parser" -path = "fuzz_targets/parser.rs" - -[[bin]] -name = "reparse" -path = "fuzz_targets/reparse.rs" diff --git a/src/tools/rust-analyzer/crates/syntax/fuzz/fuzz_targets/parser.rs b/src/tools/rust-analyzer/crates/syntax/fuzz/fuzz_targets/parser.rs deleted file mode 100644 index f80e130021d46..0000000000000 --- a/src/tools/rust-analyzer/crates/syntax/fuzz/fuzz_targets/parser.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Fuzzing for from-scratch parsing. - -#![no_main] -use libfuzzer_sys::fuzz_target; -use syntax::fuzz::check_parser; - -fuzz_target!(|data: &[u8]| { - if let Ok(text) = std::str::from_utf8(data) { - check_parser(text) - } -}); diff --git a/src/tools/rust-analyzer/crates/syntax/fuzz/fuzz_targets/reparse.rs b/src/tools/rust-analyzer/crates/syntax/fuzz/fuzz_targets/reparse.rs deleted file mode 100644 index f865ce8d67abf..0000000000000 --- a/src/tools/rust-analyzer/crates/syntax/fuzz/fuzz_targets/reparse.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Fuzzing for incremental parsing. - -#![no_main] -use libfuzzer_sys::fuzz_target; -use syntax::fuzz::CheckReparse; - -fuzz_target!(|data: &[u8]| { - if let Some(check) = CheckReparse::from_data(data) { - check.run(); - } -}); diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram deleted file mode 100644 index 62aa47839942a..0000000000000 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ /dev/null @@ -1,667 +0,0 @@ -// Rust Un-Grammar. -// -// This grammar specifies the structure of Rust's concrete syntax tree. -// It does not specify parsing rules (ambiguities, precedence, etc are out of scope). -// Tokens are processed -- contextual keywords are recognised, compound operators glued. -// -// Legend: -// -// // -- comment -// Name = -- non-terminal definition -// 'ident' -- token (terminal) -// A B -- sequence -// A | B -- alternation -// A* -- zero or more repetition -// A? -- zero or one repetition -// (A) -- same as A -// label:A -- suggested name for field of AST node - -//*************************// -// Names, Paths and Macros // -//*************************// - -Name = - 'ident' | 'self' - -NameRef = - 'ident' | 'int_number' | 'self' | 'super' | 'crate' | 'Self' - -Lifetime = - 'lifetime_ident' - -Path = - (qualifier:Path '::')? segment:PathSegment - -PathSegment = - '::'? NameRef -| NameRef GenericArgList? -| NameRef ParamList RetType? -| '<' PathType ('as' PathType)? '>' - -GenericArgList = - '::'? '<' (GenericArg (',' GenericArg)* ','?)? '>' - -GenericArg = - TypeArg -| AssocTypeArg -| LifetimeArg -| ConstArg - -TypeArg = - Type - -AssocTypeArg = - NameRef GenericParamList? (':' TypeBoundList | ('=' Type | ConstArg)) - -LifetimeArg = - Lifetime - -ConstArg = - Expr - -MacroCall = - Attr* Path '!' TokenTree ';'? - -TokenTree = - '(' ')' -| '{' '}' -| '[' ']' - -MacroItems = - Item* - -MacroStmts = - statements:Stmt* - Expr? - -//*************************// -// Items // -//*************************// - -SourceFile = - 'shebang'? - Attr* - Item* - -Item = - Const -| Enum -| ExternBlock -| ExternCrate -| Fn -| Impl -| MacroCall -| MacroRules -| MacroDef -| Module -| Static -| Struct -| Trait -| TypeAlias -| Union -| Use - -MacroRules = - Attr* Visibility? - 'macro_rules' '!' Name - TokenTree - -MacroDef = - Attr* Visibility? - 'macro' Name args:TokenTree? - body:TokenTree - -Module = - Attr* Visibility? - 'mod' Name - (ItemList | ';') - -ItemList = - '{' Attr* Item* '}' - -ExternCrate = - Attr* Visibility? - 'extern' 'crate' NameRef Rename? ';' - -Rename = - 'as' (Name | '_') - -Use = - Attr* Visibility? - 'use' UseTree ';' - -UseTree = - (Path? '::')? ('*' | UseTreeList) -| Path Rename? - -UseTreeList = - '{' (UseTree (',' UseTree)* ','?)? '}' - -Fn = - Attr* Visibility? - 'default'? 'const'? 'async'? 'unsafe'? Abi? - 'fn' Name GenericParamList? ParamList RetType? WhereClause? - (body:BlockExpr | ';') - -Abi = - 'extern' 'string'? - -ParamList = - '('( - SelfParam - | (SelfParam ',')? (Param (',' Param)* ','?)? - )')' -| '|' (Param (',' Param)* ','?)? '|' - -SelfParam = - Attr* ( - ('&' Lifetime?)? 'mut'? Name - | 'mut'? Name ':' Type - ) - -Param = - Attr* ( - Pat (':' Type)? - | Type - | '...' - ) - -RetType = - '->' Type - -TypeAlias = - Attr* Visibility? - 'default'? - 'type' Name GenericParamList? (':' TypeBoundList?)? WhereClause? - ('=' Type)? ';' - -Struct = - Attr* Visibility? - 'struct' Name GenericParamList? ( - WhereClause? (RecordFieldList | ';') - | TupleFieldList WhereClause? ';' - ) - -RecordFieldList = - '{' fields:(RecordField (',' RecordField)* ','?)? '}' - -RecordField = - Attr* Visibility? - Name ':' Type - -TupleFieldList = - '(' fields:(TupleField (',' TupleField)* ','?)? ')' - -TupleField = - Attr* Visibility? - Type - -FieldList = - RecordFieldList -| TupleFieldList - -Enum = - Attr* Visibility? - 'enum' Name GenericParamList? WhereClause? - VariantList - -VariantList = - '{' (Variant (',' Variant)* ','?)? '}' - -Variant = - Attr* Visibility? - Name FieldList? ('=' Expr)? - -Union = - Attr* Visibility? - 'union' Name GenericParamList? WhereClause? - RecordFieldList - -// A Data Type. -// -// Not used directly in the grammar, but handy to have anyway. -Adt = - Enum -| Struct -| Union - -Const = - Attr* Visibility? - 'default'? - 'const' (Name | '_') ':' Type - ('=' body:Expr)? ';' - -Static = - Attr* Visibility? - 'static' 'mut'? Name ':' Type - ('=' body:Expr)? ';' - -Trait = - Attr* Visibility? - 'unsafe'? 'auto'? - 'trait' Name GenericParamList? (':' TypeBoundList?)? WhereClause? - AssocItemList - -AssocItemList = - '{' Attr* AssocItem* '}' - -AssocItem = - Const -| Fn -| MacroCall -| TypeAlias - -Impl = - Attr* Visibility? - 'default'? 'unsafe'? - 'impl' GenericParamList? ('const'? '!'? trait:Type 'for')? self_ty:Type WhereClause? - AssocItemList - -ExternBlock = - Attr* 'unsafe'? Abi ExternItemList - -ExternItemList = - '{' Attr* ExternItem* '}' - -ExternItem = - Fn -| MacroCall -| Static -| TypeAlias - -GenericParamList = - '<' (GenericParam (',' GenericParam)* ','?)? '>' - -GenericParam = - ConstParam -| LifetimeParam -| TypeParam - -TypeParam = - Attr* Name (':' TypeBoundList?)? - ('=' default_type:Type)? - -ConstParam = - Attr* 'const' Name ':' Type - ('=' default_val:Expr)? - -LifetimeParam = - Attr* Lifetime (':' TypeBoundList?)? - -WhereClause = - 'where' predicates:(WherePred (',' WherePred)* ','?) - -WherePred = - ('for' GenericParamList)? (Lifetime | Type) ':' TypeBoundList? - -Visibility = - 'pub' ('(' 'in'? Path ')')? - -Attr = - '#' '!'? '[' Meta ']' - -Meta = - Path ('=' Expr | TokenTree)? - -//****************************// -// Statements and Expressions // -//****************************// - -Stmt = - ';' -| ExprStmt -| Item -| LetStmt - -LetStmt = - Attr* 'let' Pat (':' Type)? - '=' initializer:Expr - LetElse? - ';' - -LetElse = - 'else' BlockExpr - -ExprStmt = - Expr ';'? - -Expr = - ArrayExpr -| AwaitExpr -| BinExpr -| BlockExpr -| BoxExpr -| BreakExpr -| CallExpr -| CastExpr -| ClosureExpr -| ContinueExpr -| FieldExpr -| ForExpr -| IfExpr -| IndexExpr -| Literal -| LoopExpr -| MacroExpr -| MacroStmts -| MatchExpr -| MethodCallExpr -| ParenExpr -| PathExpr -| PrefixExpr -| RangeExpr -| RecordExpr -| RefExpr -| ReturnExpr -| TryExpr -| TupleExpr -| WhileExpr -| YieldExpr -| LetExpr -| UnderscoreExpr - -MacroExpr = - MacroCall - -Literal = - Attr* value:( - 'int_number' | 'float_number' - | 'string' | 'raw_string' - | 'byte_string' | 'raw_byte_string' - | 'true' | 'false' - | 'char' | 'byte' - ) - -PathExpr = - Attr* Path - -StmtList = - '{' - Attr* - statements:Stmt* - tail_expr:Expr? - '}' - -RefExpr = - Attr* '&' ('raw' | 'mut' | 'const') Expr - -TryExpr = - Attr* Expr '?' - -BlockExpr = - Attr* Label? ('try' | 'unsafe' | 'async' | 'const') StmtList - -PrefixExpr = - Attr* op:('-' | '!' | '*') Expr - -BinExpr = - Attr* - lhs:Expr - op:( - '||' | '&&' - | '==' | '!=' | '<=' | '>=' | '<' | '>' - | '+' | '*' | '-' | '/' | '%' | '<<' | '>>' | '^' | '|' | '&' - | '=' | '+=' | '/=' | '*=' | '%=' | '>>=' | '<<=' | '-=' | '|=' | '&=' | '^=' - ) - rhs:Expr - -CastExpr = - Attr* Expr 'as' Type - -ParenExpr = - Attr* '(' Attr* Expr ')' - -ArrayExpr = - Attr* '[' Attr* ( - (Expr (',' Expr)* ','?)? - | Expr ';' Expr - ) ']' - -IndexExpr = - Attr* base:Expr '[' index:Expr ']' - -TupleExpr = - Attr* '(' Attr* fields:(Expr (',' Expr)* ','?)? ')' - -RecordExpr = - Path RecordExprFieldList - -RecordExprFieldList = - '{' - Attr* - fields:(RecordExprField (',' RecordExprField)* ','?)? - ('..' spread:Expr?)? - '}' - -RecordExprField = - Attr* (NameRef ':')? Expr - -CallExpr = - Attr* Expr ArgList - -ArgList = - '(' args:(Expr (',' Expr)* ','?)? ')' - -MethodCallExpr = - Attr* receiver:Expr '.' NameRef GenericArgList? ArgList - -FieldExpr = - Attr* Expr '.' NameRef - -ClosureExpr = - Attr* ('for' GenericParamList)? 'static'? 'async'? 'move'? ParamList RetType? - body:Expr - -IfExpr = - Attr* 'if' condition:Expr then_branch:BlockExpr - ('else' else_branch:(IfExpr | BlockExpr))? - -LoopExpr = - Attr* Label? 'loop' - loop_body:BlockExpr - -ForExpr = - Attr* Label? 'for' Pat 'in' iterable:Expr - loop_body:BlockExpr - -WhileExpr = - Attr* Label? 'while' condition:Expr - loop_body:BlockExpr - -Label = - Lifetime ':' - -BreakExpr = - Attr* 'break' Lifetime? Expr? - -ContinueExpr = - Attr* 'continue' Lifetime? - -RangeExpr = - Attr* start:Expr? op:('..' | '..=') end:Expr? - -MatchExpr = - Attr* 'match' Expr MatchArmList - -MatchArmList = - '{' - Attr* - arms:MatchArm* - '}' - -MatchArm = - Attr* Pat guard:MatchGuard? '=>' Expr ','? - -MatchGuard = - 'if' condition:Expr - -ReturnExpr = - Attr* 'return' Expr? - -YieldExpr = - Attr* 'yield' Expr? - -LetExpr = - Attr* 'let' Pat '=' Expr - -UnderscoreExpr = - Attr* '_' - -AwaitExpr = - Attr* Expr '.' 'await' - -BoxExpr = - Attr* 'box' Expr - -//*************************// -// Types // -//*************************// - -Type = - ArrayType -| DynTraitType -| FnPtrType -| ForType -| ImplTraitType -| InferType -| MacroType -| NeverType -| ParenType -| PathType -| PtrType -| RefType -| SliceType -| TupleType - -ParenType = - '(' Type ')' - -NeverType = - '!' - -MacroType = - MacroCall - -PathType = - Path - -TupleType = - '(' fields:(Type (',' Type)* ','?)? ')' - -PtrType = - '*' ('const' | 'mut') Type - -RefType = - '&' Lifetime? 'mut'? Type - -ArrayType = - '[' Type ';' Expr ']' - -SliceType = - '[' Type ']' - -InferType = - '_' - -FnPtrType = - 'const'? 'async'? 'unsafe'? Abi? 'fn' ParamList RetType? - -ForType = - 'for' GenericParamList Type - -ImplTraitType = - 'impl' TypeBoundList - -DynTraitType = - 'dyn' TypeBoundList - -TypeBoundList = - bounds:(TypeBound ('+' TypeBound)* '+'?) - -TypeBound = - Lifetime -| ('?' | '~' 'const')? Type - -//************************// -// Patterns // -//************************// - -Pat = - IdentPat -| BoxPat -| RestPat -| LiteralPat -| MacroPat -| OrPat -| ParenPat -| PathPat -| WildcardPat -| RangePat -| RecordPat -| RefPat -| SlicePat -| TuplePat -| TupleStructPat -| ConstBlockPat - -LiteralPat = - Literal - -IdentPat = - Attr* 'ref'? 'mut'? Name ('@' Pat)? - -WildcardPat = - '_' - -RangePat = - // 1.. - start:Pat op:('..' | '..=') - // 1..2 - | start:Pat op:('..' | '..=') end:Pat - // ..2 - | op:('..' | '..=') end:Pat - -RefPat = - '&' 'mut'? Pat - -RecordPat = - Path RecordPatFieldList - -RecordPatFieldList = - '{' - fields:(RecordPatField (',' RecordPatField)* ','?)? - RestPat? - '}' - -RecordPatField = - Attr* (NameRef ':')? Pat - -TupleStructPat = - Path '(' fields:(Pat (',' Pat)* ','?)? ')' - -TuplePat = - '(' fields:(Pat (',' Pat)* ','?)? ')' - -ParenPat = - '(' Pat ')' - -SlicePat = - '[' (Pat (',' Pat)* ','?)? ']' - -PathPat = - Path - -OrPat = - (Pat ('|' Pat)* '|'?) - -BoxPat = - 'box' Pat - -RestPat = - Attr* '..' - -MacroPat = - MacroCall - -ConstBlockPat = - 'const' BlockExpr diff --git a/src/tools/rust-analyzer/crates/syntax/src/algo.rs b/src/tools/rust-analyzer/crates/syntax/src/algo.rs deleted file mode 100644 index 8b14789dd917d..0000000000000 --- a/src/tools/rust-analyzer/crates/syntax/src/algo.rs +++ /dev/null @@ -1,660 +0,0 @@ -//! Collection of assorted algorithms for syntax trees. - -use std::hash::BuildHasherDefault; - -use indexmap::IndexMap; -use itertools::Itertools; -use rustc_hash::FxHashMap; -use text_edit::TextEditBuilder; - -use crate::{ - AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, - TextSize, -}; - -/// Returns ancestors of the node at the offset, sorted by length. This should -/// do the right thing at an edge, e.g. when searching for expressions at `{ -/// $0foo }` we will get the name reference instead of the whole block, which -/// we would get if we just did `find_token_at_offset(...).flat_map(|t| -/// t.parent().ancestors())`. -pub fn ancestors_at_offset( - node: &SyntaxNode, - offset: TextSize, -) -> impl Iterator { - node.token_at_offset(offset) - .map(|token| token.parent_ancestors()) - .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) -} - -/// Finds a node of specific Ast type at offset. Note that this is slightly -/// imprecise: if the cursor is strictly between two nodes of the desired type, -/// as in -/// -/// ```no_run -/// struct Foo {}|struct Bar; -/// ``` -/// -/// then the shorter node will be silently preferred. -pub fn find_node_at_offset(syntax: &SyntaxNode, offset: TextSize) -> Option { - ancestors_at_offset(syntax, offset).find_map(N::cast) -} - -pub fn find_node_at_range(syntax: &SyntaxNode, range: TextRange) -> Option { - syntax.covering_element(range).ancestors().find_map(N::cast) -} - -/// Skip to next non `trivia` token -pub fn skip_trivia_token(mut token: SyntaxToken, direction: Direction) -> Option { - while token.kind().is_trivia() { - token = match direction { - Direction::Next => token.next_token()?, - Direction::Prev => token.prev_token()?, - } - } - Some(token) -} -/// Skip to next non `whitespace` token -pub fn skip_whitespace_token(mut token: SyntaxToken, direction: Direction) -> Option { - while token.kind() == SyntaxKind::WHITESPACE { - token = match direction { - Direction::Next => token.next_token()?, - Direction::Prev => token.prev_token()?, - } - } - Some(token) -} - -/// Finds the first sibling in the given direction which is not `trivia` -pub fn non_trivia_sibling(element: SyntaxElement, direction: Direction) -> Option { - return match element { - NodeOrToken::Node(node) => node.siblings_with_tokens(direction).skip(1).find(not_trivia), - NodeOrToken::Token(token) => token.siblings_with_tokens(direction).skip(1).find(not_trivia), - }; - - fn not_trivia(element: &SyntaxElement) -> bool { - match element { - NodeOrToken::Node(_) => true, - NodeOrToken::Token(token) => !token.kind().is_trivia(), - } - } -} - -pub fn least_common_ancestor(u: &SyntaxNode, v: &SyntaxNode) -> Option { - if u == v { - return Some(u.clone()); - } - - let u_depth = u.ancestors().count(); - let v_depth = v.ancestors().count(); - let keep = u_depth.min(v_depth); - - let u_candidates = u.ancestors().skip(u_depth - keep); - let v_candidates = v.ancestors().skip(v_depth - keep); - let (res, _) = u_candidates.zip(v_candidates).find(|(x, y)| x == y)?; - Some(res) -} - -pub fn neighbor(me: &T, direction: Direction) -> Option { - me.syntax().siblings(direction).skip(1).find_map(T::cast) -} - -pub fn has_errors(node: &SyntaxNode) -> bool { - node.children().any(|it| it.kind() == SyntaxKind::ERROR) -} - -type FxIndexMap = IndexMap>; - -#[derive(Debug, Hash, PartialEq, Eq)] -enum TreeDiffInsertPos { - After(SyntaxElement), - AsFirstChild(SyntaxElement), -} - -#[derive(Debug)] -pub struct TreeDiff { - replacements: FxHashMap, - deletions: Vec, - // the vec as well as the indexmap are both here to preserve order - insertions: FxIndexMap>, -} - -impl TreeDiff { - pub fn into_text_edit(&self, builder: &mut TextEditBuilder) { - let _p = profile::span("into_text_edit"); - - for (anchor, to) in &self.insertions { - let offset = match anchor { - TreeDiffInsertPos::After(it) => it.text_range().end(), - TreeDiffInsertPos::AsFirstChild(it) => it.text_range().start(), - }; - to.iter().for_each(|to| builder.insert(offset, to.to_string())); - } - for (from, to) in &self.replacements { - builder.replace(from.text_range(), to.to_string()); - } - for text_range in self.deletions.iter().map(SyntaxElement::text_range) { - builder.delete(text_range); - } - } - - pub fn is_empty(&self) -> bool { - self.replacements.is_empty() && self.deletions.is_empty() && self.insertions.is_empty() - } -} - -/// Finds a (potentially minimal) diff, which, applied to `from`, will result in `to`. -/// -/// Specifically, returns a structure that consists of a replacements, insertions and deletions -/// such that applying this map on `from` will result in `to`. -/// -/// This function tries to find a fine-grained diff. -pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff { - let _p = profile::span("diff"); - - let mut diff = TreeDiff { - replacements: FxHashMap::default(), - insertions: FxIndexMap::default(), - deletions: Vec::new(), - }; - let (from, to) = (from.clone().into(), to.clone().into()); - - if !syntax_element_eq(&from, &to) { - go(&mut diff, from, to); - } - return diff; - - fn syntax_element_eq(lhs: &SyntaxElement, rhs: &SyntaxElement) -> bool { - lhs.kind() == rhs.kind() - && lhs.text_range().len() == rhs.text_range().len() - && match (&lhs, &rhs) { - (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => { - lhs == rhs || lhs.text() == rhs.text() - } - (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => lhs.text() == rhs.text(), - _ => false, - } - } - - // FIXME: this is horribly inefficient. I bet there's a cool algorithm to diff trees properly. - fn go(diff: &mut TreeDiff, lhs: SyntaxElement, rhs: SyntaxElement) { - let (lhs, rhs) = match lhs.as_node().zip(rhs.as_node()) { - Some((lhs, rhs)) => (lhs, rhs), - _ => { - cov_mark::hit!(diff_node_token_replace); - diff.replacements.insert(lhs, rhs); - return; - } - }; - - let mut look_ahead_scratch = Vec::default(); - - let mut rhs_children = rhs.children_with_tokens(); - let mut lhs_children = lhs.children_with_tokens(); - let mut last_lhs = None; - loop { - let lhs_child = lhs_children.next(); - match (lhs_child.clone(), rhs_children.next()) { - (None, None) => break, - (None, Some(element)) => { - let insert_pos = match last_lhs.clone() { - Some(prev) => { - cov_mark::hit!(diff_insert); - TreeDiffInsertPos::After(prev) - } - // first iteration, insert into out parent as the first child - None => { - cov_mark::hit!(diff_insert_as_first_child); - TreeDiffInsertPos::AsFirstChild(lhs.clone().into()) - } - }; - diff.insertions.entry(insert_pos).or_insert_with(Vec::new).push(element); - } - (Some(element), None) => { - cov_mark::hit!(diff_delete); - diff.deletions.push(element); - } - (Some(ref lhs_ele), Some(ref rhs_ele)) if syntax_element_eq(lhs_ele, rhs_ele) => {} - (Some(lhs_ele), Some(rhs_ele)) => { - // nodes differ, look for lhs_ele in rhs, if its found we can mark everything up - // until that element as insertions. This is important to keep the diff minimal - // in regards to insertions that have been actually done, this is important for - // use insertions as we do not want to replace the entire module node. - look_ahead_scratch.push(rhs_ele.clone()); - let mut rhs_children_clone = rhs_children.clone(); - let mut insert = false; - for rhs_child in &mut rhs_children_clone { - if syntax_element_eq(&lhs_ele, &rhs_child) { - cov_mark::hit!(diff_insertions); - insert = true; - break; - } - look_ahead_scratch.push(rhs_child); - } - let drain = look_ahead_scratch.drain(..); - if insert { - let insert_pos = if let Some(prev) = last_lhs.clone().filter(|_| insert) { - TreeDiffInsertPos::After(prev) - } else { - cov_mark::hit!(insert_first_child); - TreeDiffInsertPos::AsFirstChild(lhs.clone().into()) - }; - - diff.insertions.entry(insert_pos).or_insert_with(Vec::new).extend(drain); - rhs_children = rhs_children_clone; - } else { - go(diff, lhs_ele, rhs_ele); - } - } - } - last_lhs = lhs_child.or(last_lhs); - } - } -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - use itertools::Itertools; - use parser::SyntaxKind; - use text_edit::TextEdit; - - use crate::{AstNode, SyntaxElement}; - - #[test] - fn replace_node_token() { - cov_mark::check!(diff_node_token_replace); - check_diff( - r#"use node;"#, - r#"ident"#, - expect![[r#" - insertions: - - - - replacements: - - Line 0: Token(USE_KW@0..3 "use") -> ident - - deletions: - - Line 1: " " - Line 1: node - Line 1: ; - "#]], - ); - } - - #[test] - fn replace_parent() { - cov_mark::check!(diff_insert_as_first_child); - check_diff( - r#""#, - r#"use foo::bar;"#, - expect![[r#" - insertions: - - Line 0: AsFirstChild(Node(SOURCE_FILE@0..0)) - -> use foo::bar; - - replacements: - - - - deletions: - - - "#]], - ); - } - - #[test] - fn insert_last() { - cov_mark::check!(diff_insert); - check_diff( - r#" -use foo; -use bar;"#, - r#" -use foo; -use bar; -use baz;"#, - expect![[r#" - insertions: - - Line 2: After(Node(USE@10..18)) - -> "\n" - -> use baz; - - replacements: - - - - deletions: - - - "#]], - ); - } - - #[test] - fn insert_middle() { - check_diff( - r#" -use foo; -use baz;"#, - r#" -use foo; -use bar; -use baz;"#, - expect![[r#" - insertions: - - Line 2: After(Token(WHITESPACE@9..10 "\n")) - -> use bar; - -> "\n" - - replacements: - - - - deletions: - - - "#]], - ) - } - - #[test] - fn insert_first() { - check_diff( - r#" -use bar; -use baz;"#, - r#" -use foo; -use bar; -use baz;"#, - expect![[r#" - insertions: - - Line 0: After(Token(WHITESPACE@0..1 "\n")) - -> use foo; - -> "\n" - - replacements: - - - - deletions: - - - "#]], - ) - } - - #[test] - fn first_child_insertion() { - cov_mark::check!(insert_first_child); - check_diff( - r#"fn main() { - stdi - }"#, - r#"use foo::bar; - - fn main() { - stdi - }"#, - expect![[r#" - insertions: - - Line 0: AsFirstChild(Node(SOURCE_FILE@0..30)) - -> use foo::bar; - -> "\n\n " - - replacements: - - - - deletions: - - - "#]], - ); - } - - #[test] - fn delete_last() { - cov_mark::check!(diff_delete); - check_diff( - r#"use foo; - use bar;"#, - r#"use foo;"#, - expect![[r#" - insertions: - - - - replacements: - - - - deletions: - - Line 1: "\n " - Line 2: use bar; - "#]], - ); - } - - #[test] - fn delete_middle() { - cov_mark::check!(diff_insertions); - check_diff( - r#" -use expect_test::{expect, Expect}; -use text_edit::TextEdit; - -use crate::AstNode; -"#, - r#" -use expect_test::{expect, Expect}; - -use crate::AstNode; -"#, - expect![[r#" - insertions: - - Line 1: After(Node(USE@1..35)) - -> "\n\n" - -> use crate::AstNode; - - replacements: - - - - deletions: - - Line 2: use text_edit::TextEdit; - Line 3: "\n\n" - Line 4: use crate::AstNode; - Line 5: "\n" - "#]], - ) - } - - #[test] - fn delete_first() { - check_diff( - r#" -use text_edit::TextEdit; - -use crate::AstNode; -"#, - r#" -use crate::AstNode; -"#, - expect![[r#" - insertions: - - - - replacements: - - Line 2: Token(IDENT@5..14 "text_edit") -> crate - Line 2: Token(IDENT@16..24 "TextEdit") -> AstNode - Line 2: Token(WHITESPACE@25..27 "\n\n") -> "\n" - - deletions: - - Line 3: use crate::AstNode; - Line 4: "\n" - "#]], - ) - } - - #[test] - fn merge_use() { - check_diff( - r#" -use std::{ - fmt, - hash::BuildHasherDefault, - ops::{self, RangeInclusive}, -}; -"#, - r#" -use std::fmt; -use std::hash::BuildHasherDefault; -use std::ops::{self, RangeInclusive}; -"#, - expect![[r#" - insertions: - - Line 2: After(Node(PATH_SEGMENT@5..8)) - -> :: - -> fmt - Line 6: After(Token(WHITESPACE@86..87 "\n")) - -> use std::hash::BuildHasherDefault; - -> "\n" - -> use std::ops::{self, RangeInclusive}; - -> "\n" - - replacements: - - Line 2: Token(IDENT@5..8 "std") -> std - - deletions: - - Line 2: :: - Line 2: { - fmt, - hash::BuildHasherDefault, - ops::{self, RangeInclusive}, - } - "#]], - ) - } - - #[test] - fn early_return_assist() { - check_diff( - r#" -fn main() { - if let Ok(x) = Err(92) { - foo(x); - } -} - "#, - r#" -fn main() { - let x = match Err(92) { - Ok(it) => it, - _ => return, - }; - foo(x); -} - "#, - expect![[r#" - insertions: - - Line 3: After(Node(BLOCK_EXPR@40..63)) - -> " " - -> match Err(92) { - Ok(it) => it, - _ => return, - } - -> ; - Line 3: After(Node(IF_EXPR@17..63)) - -> "\n " - -> foo(x); - - replacements: - - Line 3: Token(IF_KW@17..19 "if") -> let - Line 3: Token(LET_KW@20..23 "let") -> x - Line 3: Node(BLOCK_EXPR@40..63) -> = - - deletions: - - Line 3: " " - Line 3: Ok(x) - Line 3: " " - Line 3: = - Line 3: " " - Line 3: Err(92) - "#]], - ) - } - - fn check_diff(from: &str, to: &str, expected_diff: Expect) { - let from_node = crate::SourceFile::parse(from).tree().syntax().clone(); - let to_node = crate::SourceFile::parse(to).tree().syntax().clone(); - let diff = super::diff(&from_node, &to_node); - - let line_number = - |syn: &SyntaxElement| from[..syn.text_range().start().into()].lines().count(); - - let fmt_syntax = |syn: &SyntaxElement| match syn.kind() { - SyntaxKind::WHITESPACE => format!("{:?}", syn.to_string()), - _ => format!("{}", syn), - }; - - let insertions = - diff.insertions.iter().format_with("\n", |(k, v), f| -> Result<(), std::fmt::Error> { - f(&format!( - "Line {}: {:?}\n-> {}", - line_number(match k { - super::TreeDiffInsertPos::After(syn) => syn, - super::TreeDiffInsertPos::AsFirstChild(syn) => syn, - }), - k, - v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v))) - )) - }); - - let replacements = diff - .replacements - .iter() - .sorted_by_key(|(syntax, _)| syntax.text_range().start()) - .format_with("\n", |(k, v), f| { - f(&format!("Line {}: {:?} -> {}", line_number(k), k, fmt_syntax(v))) - }); - - let deletions = diff - .deletions - .iter() - .format_with("\n", |v, f| f(&format!("Line {}: {}", line_number(v), &fmt_syntax(v)))); - - let actual = format!( - "insertions:\n\n{}\n\nreplacements:\n\n{}\n\ndeletions:\n\n{}\n", - insertions, replacements, deletions - ); - expected_diff.assert_eq(&actual); - - let mut from = from.to_owned(); - let mut text_edit = TextEdit::builder(); - diff.into_text_edit(&mut text_edit); - text_edit.finish().apply(&mut from); - assert_eq!(&*from, to, "diff did not turn `from` to `to`"); - } -} diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast.rs b/src/tools/rust-analyzer/crates/syntax/src/ast.rs deleted file mode 100644 index 4aa64d0d6e8a6..0000000000000 --- a/src/tools/rust-analyzer/crates/syntax/src/ast.rs +++ /dev/null @@ -1,367 +0,0 @@ -//! Abstract Syntax Tree, layered on top of untyped `SyntaxNode`s - -mod generated; -mod traits; -mod token_ext; -mod node_ext; -mod expr_ext; -mod operators; -pub mod edit; -pub mod edit_in_place; -pub mod make; - -use std::marker::PhantomData; - -use crate::{ - syntax_node::{SyntaxNode, SyntaxNodeChildren, SyntaxToken}, - SyntaxKind, -}; - -pub use self::{ - expr_ext::{ArrayExprKind, BlockModifier, CallableExpr, ElseBranch, LiteralKind}, - generated::{nodes::*, tokens::*}, - node_ext::{ - AttrKind, FieldKind, Macro, NameLike, NameOrNameRef, PathSegmentKind, SelfParamKind, - SlicePatComponents, StructKind, TypeBoundKind, TypeOrConstParam, VisibilityKind, - }, - operators::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp}, - token_ext::{CommentKind, CommentPlacement, CommentShape, IsString, QuoteOffsets, Radix}, - traits::{ - AttrDocCommentIter, DocCommentIter, HasArgList, HasAttrs, HasDocComments, HasGenericParams, - HasLoopBody, HasModuleItem, HasName, HasTypeBounds, HasVisibility, - }, -}; - -/// The main trait to go from untyped `SyntaxNode` to a typed ast. The -/// conversion itself has zero runtime cost: ast and syntax nodes have exactly -/// the same representation: a pointer to the tree root and a pointer to the -/// node itself. -pub trait AstNode { - fn can_cast(kind: SyntaxKind) -> bool - where - Self: Sized; - - fn cast(syntax: SyntaxNode) -> Option - where - Self: Sized; - - fn syntax(&self) -> &SyntaxNode; - fn clone_for_update(&self) -> Self - where - Self: Sized, - { - Self::cast(self.syntax().clone_for_update()).unwrap() - } - fn clone_subtree(&self) -> Self - where - Self: Sized, - { - Self::cast(self.syntax().clone_subtree()).unwrap() - } -} - -/// Like `AstNode`, but wraps tokens rather than interior nodes. -pub trait AstToken { - fn can_cast(token: SyntaxKind) -> bool - where - Self: Sized; - - fn cast(syntax: SyntaxToken) -> Option - where - Self: Sized; - - fn syntax(&self) -> &SyntaxToken; - - fn text(&self) -> &str { - self.syntax().text() - } -} - -/// An iterator over `SyntaxNode` children of a particular AST type. -#[derive(Debug, Clone)] -pub struct AstChildren { - inner: SyntaxNodeChildren, - ph: PhantomData, -} - -impl AstChildren { - fn new(parent: &SyntaxNode) -> Self { - AstChildren { inner: parent.children(), ph: PhantomData } - } -} - -impl Iterator for AstChildren { - type Item = N; - fn next(&mut self) -> Option { - self.inner.find_map(N::cast) - } -} - -mod support { - use super::{AstChildren, AstNode, SyntaxKind, SyntaxNode, SyntaxToken}; - - pub(super) fn child(parent: &SyntaxNode) -> Option { - parent.children().find_map(N::cast) - } - - pub(super) fn children(parent: &SyntaxNode) -> AstChildren { - AstChildren::new(parent) - } - - pub(super) fn token(parent: &SyntaxNode, kind: SyntaxKind) -> Option { - parent.children_with_tokens().filter_map(|it| it.into_token()).find(|it| it.kind() == kind) - } -} - -#[test] -fn assert_ast_is_object_safe() { - fn _f(_: &dyn AstNode, _: &dyn HasName) {} -} - -#[test] -fn test_doc_comment_none() { - let file = SourceFile::parse( - r#" - // non-doc - mod foo {} - "#, - ) - .ok() - .unwrap(); - let module = file.syntax().descendants().find_map(Module::cast).unwrap(); - assert!(module.doc_comments().doc_comment_text().is_none()); -} - -#[test] -fn test_outer_doc_comment_of_items() { - let file = SourceFile::parse( - r#" - /// doc - // non-doc - mod foo {} - "#, - ) - .ok() - .unwrap(); - let module = file.syntax().descendants().find_map(Module::cast).unwrap(); - assert_eq!(" doc", module.doc_comments().doc_comment_text().unwrap()); -} - -#[test] -fn test_inner_doc_comment_of_items() { - let file = SourceFile::parse( - r#" - //! doc - // non-doc - mod foo {} - "#, - ) - .ok() - .unwrap(); - let module = file.syntax().descendants().find_map(Module::cast).unwrap(); - assert!(module.doc_comments().doc_comment_text().is_none()); -} - -#[test] -fn test_doc_comment_of_statics() { - let file = SourceFile::parse( - r#" - /// Number of levels - static LEVELS: i32 = 0; - "#, - ) - .ok() - .unwrap(); - let st = file.syntax().descendants().find_map(Static::cast).unwrap(); - assert_eq!(" Number of levels", st.doc_comments().doc_comment_text().unwrap()); -} - -#[test] -fn test_doc_comment_preserves_indents() { - let file = SourceFile::parse( - r#" - /// doc1 - /// ``` - /// fn foo() { - /// // ... - /// } - /// ``` - mod foo {} - "#, - ) - .ok() - .unwrap(); - let module = file.syntax().descendants().find_map(Module::cast).unwrap(); - assert_eq!( - " doc1\n ```\n fn foo() {\n // ...\n }\n ```", - module.doc_comments().doc_comment_text().unwrap() - ); -} - -#[test] -fn test_doc_comment_preserves_newlines() { - let file = SourceFile::parse( - r#" - /// this - /// is - /// mod - /// foo - mod foo {} - "#, - ) - .ok() - .unwrap(); - let module = file.syntax().descendants().find_map(Module::cast).unwrap(); - assert_eq!(" this\n is\n mod\n foo", module.doc_comments().doc_comment_text().unwrap()); -} - -#[test] -fn test_doc_comment_single_line_block_strips_suffix() { - let file = SourceFile::parse( - r#" - /** this is mod foo*/ - mod foo {} - "#, - ) - .ok() - .unwrap(); - let module = file.syntax().descendants().find_map(Module::cast).unwrap(); - assert_eq!(" this is mod foo", module.doc_comments().doc_comment_text().unwrap()); -} - -#[test] -fn test_doc_comment_single_line_block_strips_suffix_whitespace() { - let file = SourceFile::parse( - r#" - /** this is mod foo */ - mod foo {} - "#, - ) - .ok() - .unwrap(); - let module = file.syntax().descendants().find_map(Module::cast).unwrap(); - assert_eq!(" this is mod foo ", module.doc_comments().doc_comment_text().unwrap()); -} - -#[test] -fn test_doc_comment_multi_line_block_strips_suffix() { - let file = SourceFile::parse( - r#" - /** - this - is - mod foo - */ - mod foo {} - "#, - ) - .ok() - .unwrap(); - let module = file.syntax().descendants().find_map(Module::cast).unwrap(); - assert_eq!( - "\n this\n is\n mod foo\n ", - module.doc_comments().doc_comment_text().unwrap() - ); -} - -#[test] -fn test_comments_preserve_trailing_whitespace() { - let file = SourceFile::parse( - "\n/// Representation of a Realm. \n/// In the specification these are called Realm Records.\nstruct Realm {}", - ) - .ok() - .unwrap(); - let def = file.syntax().descendants().find_map(Struct::cast).unwrap(); - assert_eq!( - " Representation of a Realm. \n In the specification these are called Realm Records.", - def.doc_comments().doc_comment_text().unwrap() - ); -} - -#[test] -fn test_four_slash_line_comment() { - let file = SourceFile::parse( - r#" - //// too many slashes to be a doc comment - /// doc comment - mod foo {} - "#, - ) - .ok() - .unwrap(); - let module = file.syntax().descendants().find_map(Module::cast).unwrap(); - assert_eq!(" doc comment", module.doc_comments().doc_comment_text().unwrap()); -} - -#[test] -fn test_where_predicates() { - fn assert_bound(text: &str, bound: Option) { - assert_eq!(text, bound.unwrap().syntax().text().to_string()); - } - - let file = SourceFile::parse( - r#" -fn foo() -where - T: Clone + Copy + Debug + 'static, - 'a: 'b + 'c, - Iterator::Item: 'a + Debug, - Iterator::Item: Debug + 'a, - ::Item: Debug + 'a, - for<'a> F: Fn(&'a str) -{} - "#, - ) - .ok() - .unwrap(); - let where_clause = file.syntax().descendants().find_map(WhereClause::cast).unwrap(); - - let mut predicates = where_clause.predicates(); - - let pred = predicates.next().unwrap(); - let mut bounds = pred.type_bound_list().unwrap().bounds(); - - assert!(pred.for_token().is_none()); - assert!(pred.generic_param_list().is_none()); - assert_eq!("T", pred.ty().unwrap().syntax().text().to_string()); - assert_bound("Clone", bounds.next()); - assert_bound("Copy", bounds.next()); - assert_bound("Debug", bounds.next()); - assert_bound("'static", bounds.next()); - - let pred = predicates.next().unwrap(); - let mut bounds = pred.type_bound_list().unwrap().bounds(); - - assert_eq!("'a", pred.lifetime().unwrap().lifetime_ident_token().unwrap().text()); - - assert_bound("'b", bounds.next()); - assert_bound("'c", bounds.next()); - - let pred = predicates.next().unwrap(); - let mut bounds = pred.type_bound_list().unwrap().bounds(); - - assert_eq!("Iterator::Item", pred.ty().unwrap().syntax().text().to_string()); - assert_bound("'a", bounds.next()); - - let pred = predicates.next().unwrap(); - let mut bounds = pred.type_bound_list().unwrap().bounds(); - - assert_eq!("Iterator::Item", pred.ty().unwrap().syntax().text().to_string()); - assert_bound("Debug", bounds.next()); - assert_bound("'a", bounds.next()); - - let pred = predicates.next().unwrap(); - let mut bounds = pred.type_bound_list().unwrap().bounds(); - - assert_eq!("::Item", pred.ty().unwrap().syntax().text().to_string()); - assert_bound("Debug", bounds.next()); - assert_bound("'a", bounds.next()); - - let pred = predicates.next().unwrap(); - let mut bounds = pred.type_bound_list().unwrap().bounds(); - - assert!(pred.for_token().is_some()); - assert_eq!("<'a>", pred.generic_param_list().unwrap().syntax().text().to_string()); - assert_eq!("F", pred.ty().unwrap().syntax().text().to_string()); - assert_bound("Fn(&'a str)", bounds.next()); -} diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs deleted file mode 100644 index 15805dfc8608f..0000000000000 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs +++ /dev/null @@ -1,174 +0,0 @@ -//! This module contains functions for editing syntax trees. As the trees are -//! immutable, all function here return a fresh copy of the tree, instead of -//! doing an in-place modification. -use std::{fmt, iter, ops}; - -use crate::{ - ast::{self, make, AstNode}, - ted, AstToken, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, -}; - -#[derive(Debug, Clone, Copy)] -pub struct IndentLevel(pub u8); - -impl From for IndentLevel { - fn from(level: u8) -> IndentLevel { - IndentLevel(level) - } -} - -impl fmt::Display for IndentLevel { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let spaces = " "; - let buf; - let len = self.0 as usize * 4; - let indent = if len <= spaces.len() { - &spaces[..len] - } else { - buf = " ".repeat(len); - &buf - }; - fmt::Display::fmt(indent, f) - } -} - -impl ops::Add for IndentLevel { - type Output = IndentLevel; - fn add(self, rhs: u8) -> IndentLevel { - IndentLevel(self.0 + rhs) - } -} - -impl IndentLevel { - pub fn single() -> IndentLevel { - IndentLevel(0) - } - pub fn is_zero(&self) -> bool { - self.0 == 0 - } - pub fn from_element(element: &SyntaxElement) -> IndentLevel { - match element { - rowan::NodeOrToken::Node(it) => IndentLevel::from_node(it), - rowan::NodeOrToken::Token(it) => IndentLevel::from_token(it), - } - } - - pub fn from_node(node: &SyntaxNode) -> IndentLevel { - match node.first_token() { - Some(it) => Self::from_token(&it), - None => IndentLevel(0), - } - } - - pub fn from_token(token: &SyntaxToken) -> IndentLevel { - for ws in prev_tokens(token.clone()).filter_map(ast::Whitespace::cast) { - let text = ws.syntax().text(); - if let Some(pos) = text.rfind('\n') { - let level = text[pos + 1..].chars().count() / 4; - return IndentLevel(level as u8); - } - } - IndentLevel(0) - } - - /// XXX: this intentionally doesn't change the indent of the very first token. - /// Ie, in something like - /// ``` - /// fn foo() { - /// 92 - /// } - /// ``` - /// if you indent the block, the `{` token would stay put. - pub(super) fn increase_indent(self, node: &SyntaxNode) { - let tokens = node.preorder_with_tokens().filter_map(|event| match event { - rowan::WalkEvent::Leave(NodeOrToken::Token(it)) => Some(it), - _ => None, - }); - for token in tokens { - if let Some(ws) = ast::Whitespace::cast(token) { - if ws.text().contains('\n') { - let new_ws = make::tokens::whitespace(&format!("{}{}", ws.syntax(), self)); - ted::replace(ws.syntax(), &new_ws); - } - } - } - } - - pub(super) fn decrease_indent(self, node: &SyntaxNode) { - let tokens = node.preorder_with_tokens().filter_map(|event| match event { - rowan::WalkEvent::Leave(NodeOrToken::Token(it)) => Some(it), - _ => None, - }); - for token in tokens { - if let Some(ws) = ast::Whitespace::cast(token) { - if ws.text().contains('\n') { - let new_ws = make::tokens::whitespace( - &ws.syntax().text().replace(&format!("\n{}", self), "\n"), - ); - ted::replace(ws.syntax(), &new_ws); - } - } - } - } -} - -fn prev_tokens(token: SyntaxToken) -> impl Iterator { - iter::successors(Some(token), |token| token.prev_token()) -} - -/// Soft-deprecated in favor of mutable tree editing API `edit_in_place::Ident`. -pub trait AstNodeEdit: AstNode + Clone + Sized { - fn indent_level(&self) -> IndentLevel { - IndentLevel::from_node(self.syntax()) - } - #[must_use] - fn indent(&self, level: IndentLevel) -> Self { - fn indent_inner(node: &SyntaxNode, level: IndentLevel) -> SyntaxNode { - let res = node.clone_subtree().clone_for_update(); - level.increase_indent(&res); - res.clone_subtree() - } - - Self::cast(indent_inner(self.syntax(), level)).unwrap() - } - #[must_use] - fn dedent(&self, level: IndentLevel) -> Self { - fn dedent_inner(node: &SyntaxNode, level: IndentLevel) -> SyntaxNode { - let res = node.clone_subtree().clone_for_update(); - level.decrease_indent(&res); - res.clone_subtree() - } - - Self::cast(dedent_inner(self.syntax(), level)).unwrap() - } - #[must_use] - fn reset_indent(&self) -> Self { - let level = IndentLevel::from_node(self.syntax()); - self.dedent(level) - } -} - -impl AstNodeEdit for N {} - -#[test] -fn test_increase_indent() { - let arm_list = { - let arm = make::match_arm(iter::once(make::wildcard_pat().into()), None, make::expr_unit()); - make::match_arm_list(vec![arm.clone(), arm]) - }; - assert_eq!( - arm_list.syntax().to_string(), - "{ - _ => (), - _ => (), -}" - ); - let indented = arm_list.indent(IndentLevel(2)); - assert_eq!( - indented.syntax().to_string(), - "{ - _ => (), - _ => (), - }" - ); -} diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs deleted file mode 100644 index e3e928aecd4ad..0000000000000 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ /dev/null @@ -1,717 +0,0 @@ -//! Structural editing for ast. - -use std::iter::{empty, successors}; - -use parser::{SyntaxKind, T}; -use rowan::SyntaxElement; - -use crate::{ - algo::{self, neighbor}, - ast::{self, edit::IndentLevel, make, HasGenericParams}, - ted::{self, Position}, - AstNode, AstToken, Direction, - SyntaxKind::{ATTR, COMMENT, WHITESPACE}, - SyntaxNode, -}; - -use super::HasName; - -pub trait GenericParamsOwnerEdit: ast::HasGenericParams { - fn get_or_create_generic_param_list(&self) -> ast::GenericParamList; - fn get_or_create_where_clause(&self) -> ast::WhereClause; -} - -impl GenericParamsOwnerEdit for ast::Fn { - fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { - match self.generic_param_list() { - Some(it) => it, - None => { - let position = if let Some(name) = self.name() { - Position::after(name.syntax) - } else if let Some(fn_token) = self.fn_token() { - Position::after(fn_token) - } else if let Some(param_list) = self.param_list() { - Position::before(param_list.syntax) - } else { - Position::last_child_of(self.syntax()) - }; - create_generic_param_list(position) - } - } - } - - fn get_or_create_where_clause(&self) -> ast::WhereClause { - if self.where_clause().is_none() { - let position = if let Some(ty) = self.ret_type() { - Position::after(ty.syntax()) - } else if let Some(param_list) = self.param_list() { - Position::after(param_list.syntax()) - } else { - Position::last_child_of(self.syntax()) - }; - create_where_clause(position); - } - self.where_clause().unwrap() - } -} - -impl GenericParamsOwnerEdit for ast::Impl { - fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { - match self.generic_param_list() { - Some(it) => it, - None => { - let position = match self.impl_token() { - Some(imp_token) => Position::after(imp_token), - None => Position::last_child_of(self.syntax()), - }; - create_generic_param_list(position) - } - } - } - - fn get_or_create_where_clause(&self) -> ast::WhereClause { - if self.where_clause().is_none() { - let position = match self.assoc_item_list() { - Some(items) => Position::before(items.syntax()), - None => Position::last_child_of(self.syntax()), - }; - create_where_clause(position); - } - self.where_clause().unwrap() - } -} - -impl GenericParamsOwnerEdit for ast::Trait { - fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { - match self.generic_param_list() { - Some(it) => it, - None => { - let position = if let Some(name) = self.name() { - Position::after(name.syntax) - } else if let Some(trait_token) = self.trait_token() { - Position::after(trait_token) - } else { - Position::last_child_of(self.syntax()) - }; - create_generic_param_list(position) - } - } - } - - fn get_or_create_where_clause(&self) -> ast::WhereClause { - if self.where_clause().is_none() { - let position = match self.assoc_item_list() { - Some(items) => Position::before(items.syntax()), - None => Position::last_child_of(self.syntax()), - }; - create_where_clause(position); - } - self.where_clause().unwrap() - } -} - -impl GenericParamsOwnerEdit for ast::Struct { - fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { - match self.generic_param_list() { - Some(it) => it, - None => { - let position = if let Some(name) = self.name() { - Position::after(name.syntax) - } else if let Some(struct_token) = self.struct_token() { - Position::after(struct_token) - } else { - Position::last_child_of(self.syntax()) - }; - create_generic_param_list(position) - } - } - } - - fn get_or_create_where_clause(&self) -> ast::WhereClause { - if self.where_clause().is_none() { - let tfl = self.field_list().and_then(|fl| match fl { - ast::FieldList::RecordFieldList(_) => None, - ast::FieldList::TupleFieldList(it) => Some(it), - }); - let position = if let Some(tfl) = tfl { - Position::after(tfl.syntax()) - } else if let Some(gpl) = self.generic_param_list() { - Position::after(gpl.syntax()) - } else if let Some(name) = self.name() { - Position::after(name.syntax()) - } else { - Position::last_child_of(self.syntax()) - }; - create_where_clause(position); - } - self.where_clause().unwrap() - } -} - -impl GenericParamsOwnerEdit for ast::Enum { - fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { - match self.generic_param_list() { - Some(it) => it, - None => { - let position = if let Some(name) = self.name() { - Position::after(name.syntax) - } else if let Some(enum_token) = self.enum_token() { - Position::after(enum_token) - } else { - Position::last_child_of(self.syntax()) - }; - create_generic_param_list(position) - } - } - } - - fn get_or_create_where_clause(&self) -> ast::WhereClause { - if self.where_clause().is_none() { - let position = if let Some(gpl) = self.generic_param_list() { - Position::after(gpl.syntax()) - } else if let Some(name) = self.name() { - Position::after(name.syntax()) - } else { - Position::last_child_of(self.syntax()) - }; - create_where_clause(position); - } - self.where_clause().unwrap() - } -} - -fn create_where_clause(position: Position) { - let where_clause = make::where_clause(empty()).clone_for_update(); - ted::insert(position, where_clause.syntax()); -} - -fn create_generic_param_list(position: Position) -> ast::GenericParamList { - let gpl = make::generic_param_list(empty()).clone_for_update(); - ted::insert_raw(position, gpl.syntax()); - gpl -} - -pub trait AttrsOwnerEdit: ast::HasAttrs { - fn remove_attrs_and_docs(&self) { - remove_attrs_and_docs(self.syntax()); - - fn remove_attrs_and_docs(node: &SyntaxNode) { - let mut remove_next_ws = false; - for child in node.children_with_tokens() { - match child.kind() { - ATTR | COMMENT => { - remove_next_ws = true; - child.detach(); - continue; - } - WHITESPACE if remove_next_ws => { - child.detach(); - } - _ => (), - } - remove_next_ws = false; - } - } - } -} - -impl AttrsOwnerEdit for T {} - -impl ast::GenericParamList { - pub fn add_generic_param(&self, generic_param: ast::GenericParam) { - match self.generic_params().last() { - Some(last_param) => { - let position = Position::after(last_param.syntax()); - let elements = vec![ - make::token(T![,]).into(), - make::tokens::single_space().into(), - generic_param.syntax().clone().into(), - ]; - ted::insert_all(position, elements); - } - None => { - let after_l_angle = Position::after(self.l_angle_token().unwrap()); - ted::insert(after_l_angle, generic_param.syntax()); - } - } - } -} - -impl ast::WhereClause { - pub fn add_predicate(&self, predicate: ast::WherePred) { - if let Some(pred) = self.predicates().last() { - if !pred.syntax().siblings_with_tokens(Direction::Next).any(|it| it.kind() == T![,]) { - ted::append_child_raw(self.syntax(), make::token(T![,])); - } - } - ted::append_child(self.syntax(), predicate.syntax()); - } -} - -impl ast::TypeBoundList { - pub fn remove(&self) { - match self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:]) { - Some(colon) => ted::remove_all(colon..=self.syntax().clone().into()), - None => ted::remove(self.syntax()), - } - } -} - -impl ast::PathSegment { - pub fn get_or_create_generic_arg_list(&self) -> ast::GenericArgList { - if self.generic_arg_list().is_none() { - let arg_list = make::generic_arg_list().clone_for_update(); - ted::append_child(self.syntax(), arg_list.syntax()); - } - self.generic_arg_list().unwrap() - } -} - -impl ast::UseTree { - pub fn remove(&self) { - for dir in [Direction::Next, Direction::Prev] { - if let Some(next_use_tree) = neighbor(self, dir) { - let separators = self - .syntax() - .siblings_with_tokens(dir) - .skip(1) - .take_while(|it| it.as_node() != Some(next_use_tree.syntax())); - ted::remove_all_iter(separators); - break; - } - } - ted::remove(self.syntax()); - } - - pub fn get_or_create_use_tree_list(&self) -> ast::UseTreeList { - match self.use_tree_list() { - Some(it) => it, - None => { - let position = Position::last_child_of(self.syntax()); - let use_tree_list = make::use_tree_list(empty()).clone_for_update(); - let mut elements = Vec::with_capacity(2); - if self.coloncolon_token().is_none() { - elements.push(make::token(T![::]).into()); - } - elements.push(use_tree_list.syntax().clone().into()); - ted::insert_all_raw(position, elements); - use_tree_list - } - } - } - - /// Splits off the given prefix, making it the path component of the use tree, - /// appending the rest of the path to all UseTreeList items. - /// - /// # Examples - /// - /// `prefix$0::suffix` -> `prefix::{suffix}` - /// - /// `prefix$0` -> `prefix::{self}` - /// - /// `prefix$0::*` -> `prefix::{*}` - pub fn split_prefix(&self, prefix: &ast::Path) { - debug_assert_eq!(self.path(), Some(prefix.top_path())); - let path = self.path().unwrap(); - if &path == prefix && self.use_tree_list().is_none() { - if self.star_token().is_some() { - // path$0::* -> * - self.coloncolon_token().map(ted::remove); - ted::remove(prefix.syntax()); - } else { - // path$0 -> self - let self_suffix = - make::path_unqualified(make::path_segment_self()).clone_for_update(); - ted::replace(path.syntax(), self_suffix.syntax()); - } - } else if split_path_prefix(prefix).is_none() { - return; - } - // At this point, prefix path is detached; _self_ use tree has suffix path. - // Next, transform 'suffix' use tree into 'prefix::{suffix}' - let subtree = self.clone_subtree().clone_for_update(); - ted::remove_all_iter(self.syntax().children_with_tokens()); - ted::insert(Position::first_child_of(self.syntax()), prefix.syntax()); - self.get_or_create_use_tree_list().add_use_tree(subtree); - - fn split_path_prefix(prefix: &ast::Path) -> Option<()> { - let parent = prefix.parent_path()?; - let segment = parent.segment()?; - if algo::has_errors(segment.syntax()) { - return None; - } - for p in successors(parent.parent_path(), |it| it.parent_path()) { - p.segment()?; - } - prefix.parent_path().and_then(|p| p.coloncolon_token()).map(ted::remove); - ted::remove(prefix.syntax()); - Some(()) - } - } -} - -impl ast::UseTreeList { - pub fn add_use_tree(&self, use_tree: ast::UseTree) { - let (position, elements) = match self.use_trees().last() { - Some(last_tree) => ( - Position::after(last_tree.syntax()), - vec![ - make::token(T![,]).into(), - make::tokens::single_space().into(), - use_tree.syntax.into(), - ], - ), - None => { - let position = match self.l_curly_token() { - Some(l_curly) => Position::after(l_curly), - None => Position::last_child_of(self.syntax()), - }; - (position, vec![use_tree.syntax.into()]) - } - }; - ted::insert_all_raw(position, elements); - } -} - -impl ast::Use { - pub fn remove(&self) { - let next_ws = self - .syntax() - .next_sibling_or_token() - .and_then(|it| it.into_token()) - .and_then(ast::Whitespace::cast); - if let Some(next_ws) = next_ws { - let ws_text = next_ws.syntax().text(); - if let Some(rest) = ws_text.strip_prefix('\n') { - if rest.is_empty() { - ted::remove(next_ws.syntax()); - } else { - ted::replace(next_ws.syntax(), make::tokens::whitespace(rest)); - } - } - } - ted::remove(self.syntax()); - } -} - -impl ast::Impl { - pub fn get_or_create_assoc_item_list(&self) -> ast::AssocItemList { - if self.assoc_item_list().is_none() { - let assoc_item_list = make::assoc_item_list().clone_for_update(); - ted::append_child(self.syntax(), assoc_item_list.syntax()); - } - self.assoc_item_list().unwrap() - } -} - -impl ast::AssocItemList { - pub fn add_item(&self, item: ast::AssocItem) { - let (indent, position, whitespace) = match self.assoc_items().last() { - Some(last_item) => ( - IndentLevel::from_node(last_item.syntax()), - Position::after(last_item.syntax()), - "\n\n", - ), - None => match self.l_curly_token() { - Some(l_curly) => { - normalize_ws_between_braces(self.syntax()); - (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly), "\n") - } - None => (IndentLevel::single(), Position::last_child_of(self.syntax()), "\n"), - }, - }; - let elements: Vec> = vec![ - make::tokens::whitespace(&format!("{}{}", whitespace, indent)).into(), - item.syntax().clone().into(), - ]; - ted::insert_all(position, elements); - } -} - -impl ast::Fn { - pub fn get_or_create_body(&self) -> ast::BlockExpr { - if self.body().is_none() { - let body = make::ext::empty_block_expr().clone_for_update(); - match self.semicolon_token() { - Some(semi) => { - ted::replace(semi, body.syntax()); - ted::insert(Position::before(body.syntax), make::tokens::single_space()); - } - None => ted::append_child(self.syntax(), body.syntax()), - } - } - self.body().unwrap() - } -} - -impl ast::MatchArm { - pub fn remove(&self) { - if let Some(sibling) = self.syntax().prev_sibling_or_token() { - if sibling.kind() == SyntaxKind::WHITESPACE { - ted::remove(sibling); - } - } - if let Some(sibling) = self.syntax().next_sibling_or_token() { - if sibling.kind() == T![,] { - ted::remove(sibling); - } - } - ted::remove(self.syntax()); - } -} - -impl ast::MatchArmList { - pub fn add_arm(&self, arm: ast::MatchArm) { - normalize_ws_between_braces(self.syntax()); - let mut elements = Vec::new(); - let position = match self.arms().last() { - Some(last_arm) => { - if needs_comma(&last_arm) { - ted::append_child(last_arm.syntax(), make::token(SyntaxKind::COMMA)); - } - Position::after(last_arm.syntax().clone()) - } - None => match self.l_curly_token() { - Some(it) => Position::after(it), - None => Position::last_child_of(self.syntax()), - }, - }; - let indent = IndentLevel::from_node(self.syntax()) + 1; - elements.push(make::tokens::whitespace(&format!("\n{}", indent)).into()); - elements.push(arm.syntax().clone().into()); - if needs_comma(&arm) { - ted::append_child(arm.syntax(), make::token(SyntaxKind::COMMA)); - } - ted::insert_all(position, elements); - - fn needs_comma(arm: &ast::MatchArm) -> bool { - arm.expr().map_or(false, |e| !e.is_block_like()) && arm.comma_token().is_none() - } - } -} - -impl ast::RecordExprFieldList { - pub fn add_field(&self, field: ast::RecordExprField) { - let is_multiline = self.syntax().text().contains_char('\n'); - let whitespace = if is_multiline { - let indent = IndentLevel::from_node(self.syntax()) + 1; - make::tokens::whitespace(&format!("\n{}", indent)) - } else { - make::tokens::single_space() - }; - - if is_multiline { - normalize_ws_between_braces(self.syntax()); - } - - let position = match self.fields().last() { - Some(last_field) => { - let comma = match last_field - .syntax() - .siblings_with_tokens(Direction::Next) - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == T![,]) - { - Some(it) => it, - None => { - let comma = ast::make::token(T![,]); - ted::insert(Position::after(last_field.syntax()), &comma); - comma - } - }; - Position::after(comma) - } - None => match self.l_curly_token() { - Some(it) => Position::after(it), - None => Position::last_child_of(self.syntax()), - }, - }; - - ted::insert_all(position, vec![whitespace.into(), field.syntax().clone().into()]); - if is_multiline { - ted::insert(Position::after(field.syntax()), ast::make::token(T![,])); - } - } -} - -impl ast::RecordExprField { - /// This will either replace the initializer, or in the case that this is a shorthand convert - /// the initializer into the name ref and insert the expr as the new initializer. - pub fn replace_expr(&self, expr: ast::Expr) { - if self.name_ref().is_some() { - match self.expr() { - Some(prev) => ted::replace(prev.syntax(), expr.syntax()), - None => ted::append_child(self.syntax(), expr.syntax()), - } - return; - } - // this is a shorthand - if let Some(ast::Expr::PathExpr(path_expr)) = self.expr() { - if let Some(path) = path_expr.path() { - if let Some(name_ref) = path.as_single_name_ref() { - path_expr.syntax().detach(); - let children = vec![ - name_ref.syntax().clone().into(), - ast::make::token(T![:]).into(), - ast::make::tokens::single_space().into(), - expr.syntax().clone().into(), - ]; - ted::insert_all_raw(Position::last_child_of(self.syntax()), children); - } - } - } - } -} - -impl ast::RecordPatFieldList { - pub fn add_field(&self, field: ast::RecordPatField) { - let is_multiline = self.syntax().text().contains_char('\n'); - let whitespace = if is_multiline { - let indent = IndentLevel::from_node(self.syntax()) + 1; - make::tokens::whitespace(&format!("\n{}", indent)) - } else { - make::tokens::single_space() - }; - - if is_multiline { - normalize_ws_between_braces(self.syntax()); - } - - let position = match self.fields().last() { - Some(last_field) => { - let comma = match last_field - .syntax() - .siblings_with_tokens(Direction::Next) - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == T![,]) - { - Some(it) => it, - None => { - let comma = ast::make::token(T![,]); - ted::insert(Position::after(last_field.syntax()), &comma); - comma - } - }; - Position::after(comma) - } - None => match self.l_curly_token() { - Some(it) => Position::after(it), - None => Position::last_child_of(self.syntax()), - }, - }; - - ted::insert_all(position, vec![whitespace.into(), field.syntax().clone().into()]); - if is_multiline { - ted::insert(Position::after(field.syntax()), ast::make::token(T![,])); - } - } -} -impl ast::StmtList { - pub fn push_front(&self, statement: ast::Stmt) { - ted::insert(Position::after(self.l_curly_token().unwrap()), statement.syntax()); - } -} - -fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> { - let l = node - .children_with_tokens() - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == T!['{'])?; - let r = node - .children_with_tokens() - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == T!['}'])?; - - let indent = IndentLevel::from_node(node); - - match l.next_sibling_or_token() { - Some(ws) if ws.kind() == SyntaxKind::WHITESPACE => { - if ws.next_sibling_or_token()?.into_token()? == r { - ted::replace(ws, make::tokens::whitespace(&format!("\n{}", indent))); - } - } - Some(ws) if ws.kind() == T!['}'] => { - ted::insert(Position::after(l), make::tokens::whitespace(&format!("\n{}", indent))); - } - _ => (), - } - Some(()) -} - -pub trait Indent: AstNode + Clone + Sized { - fn indent_level(&self) -> IndentLevel { - IndentLevel::from_node(self.syntax()) - } - fn indent(&self, by: IndentLevel) { - by.increase_indent(self.syntax()); - } - fn dedent(&self, by: IndentLevel) { - by.decrease_indent(self.syntax()); - } - fn reindent_to(&self, target_level: IndentLevel) { - let current_level = IndentLevel::from_node(self.syntax()); - self.dedent(current_level); - self.indent(target_level); - } -} - -impl Indent for N {} - -#[cfg(test)] -mod tests { - use std::fmt; - - use crate::SourceFile; - - use super::*; - - fn ast_mut_from_text(text: &str) -> N { - let parse = SourceFile::parse(text); - parse.tree().syntax().descendants().find_map(N::cast).unwrap().clone_for_update() - } - - #[test] - fn test_create_generic_param_list() { - fn check_create_gpl(before: &str, after: &str) { - let gpl_owner = ast_mut_from_text::(before); - gpl_owner.get_or_create_generic_param_list(); - assert_eq!(gpl_owner.to_string(), after); - } - - check_create_gpl::("fn foo", "fn foo<>"); - check_create_gpl::("fn foo() {}", "fn foo<>() {}"); - - check_create_gpl::("impl", "impl<>"); - check_create_gpl::("impl Struct {}", "impl<> Struct {}"); - check_create_gpl::("impl Trait for Struct {}", "impl<> Trait for Struct {}"); - - check_create_gpl::("trait Trait<>", "trait Trait<>"); - check_create_gpl::("trait Trait<> {}", "trait Trait<> {}"); - - check_create_gpl::("struct A", "struct A<>"); - check_create_gpl::("struct A;", "struct A<>;"); - check_create_gpl::("struct A();", "struct A<>();"); - check_create_gpl::("struct A {}", "struct A<> {}"); - - check_create_gpl::("enum E", "enum E<>"); - check_create_gpl::("enum E {", "enum E<> {"); - } - - #[test] - fn test_increase_indent() { - let arm_list = ast_mut_from_text::( - "fn foo() { - ; - ; -}", - ); - arm_list.indent(IndentLevel(2)); - assert_eq!( - arm_list.to_string(), - "fn foo() { - ; - ; - }", - ); - } -} diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs deleted file mode 100644 index db66d08a73b5e..0000000000000 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs +++ /dev/null @@ -1,410 +0,0 @@ -//! Various extension methods to ast Expr Nodes, which are hard to code-generate. -//! -//! These methods should only do simple, shallow tasks related to the syntax of the node itself. - -use crate::{ - ast::{ - self, - operators::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp}, - support, AstChildren, AstNode, - }, - AstToken, - SyntaxKind::*, - SyntaxNode, SyntaxToken, T, -}; - -impl ast::HasAttrs for ast::Expr {} - -impl ast::Expr { - pub fn is_block_like(&self) -> bool { - matches!( - self, - ast::Expr::IfExpr(_) - | ast::Expr::LoopExpr(_) - | ast::Expr::ForExpr(_) - | ast::Expr::WhileExpr(_) - | ast::Expr::BlockExpr(_) - | ast::Expr::MatchExpr(_) - ) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ElseBranch { - Block(ast::BlockExpr), - IfExpr(ast::IfExpr), -} - -impl From for ElseBranch { - fn from(block_expr: ast::BlockExpr) -> Self { - Self::Block(block_expr) - } -} - -impl From for ElseBranch { - fn from(if_expr: ast::IfExpr) -> Self { - Self::IfExpr(if_expr) - } -} - -impl ast::IfExpr { - pub fn then_branch(&self) -> Option { - self.children_after_condition().next() - } - - pub fn else_branch(&self) -> Option { - let res = match self.children_after_condition().nth(1) { - Some(block) => ElseBranch::Block(block), - None => { - let elif = self.children_after_condition().next()?; - ElseBranch::IfExpr(elif) - } - }; - Some(res) - } - - fn children_after_condition(&self) -> impl Iterator { - self.syntax().children().skip(1).filter_map(N::cast) - } -} - -#[test] -fn if_block_condition() { - let parse = ast::SourceFile::parse( - r#" - fn test() { - if { true } { "if" } - else if { false } { "first elif" } - else if true { "second elif" } - else if (true) { "third elif" } - else { "else" } - } - "#, - ); - let if_ = parse.tree().syntax().descendants().find_map(ast::IfExpr::cast).unwrap(); - assert_eq!(if_.then_branch().unwrap().syntax().text(), r#"{ "if" }"#); - let elif = match if_.else_branch().unwrap() { - ElseBranch::IfExpr(elif) => elif, - ElseBranch::Block(_) => panic!("should be `else if`"), - }; - assert_eq!(elif.then_branch().unwrap().syntax().text(), r#"{ "first elif" }"#); - let elif = match elif.else_branch().unwrap() { - ElseBranch::IfExpr(elif) => elif, - ElseBranch::Block(_) => panic!("should be `else if`"), - }; - assert_eq!(elif.then_branch().unwrap().syntax().text(), r#"{ "second elif" }"#); - let elif = match elif.else_branch().unwrap() { - ElseBranch::IfExpr(elif) => elif, - ElseBranch::Block(_) => panic!("should be `else if`"), - }; - assert_eq!(elif.then_branch().unwrap().syntax().text(), r#"{ "third elif" }"#); - let else_ = match elif.else_branch().unwrap() { - ElseBranch::Block(else_) => else_, - ElseBranch::IfExpr(_) => panic!("should be `else`"), - }; - assert_eq!(else_.syntax().text(), r#"{ "else" }"#); -} - -#[test] -fn if_condition_with_if_inside() { - let parse = ast::SourceFile::parse( - r#" - fn test() { - if if true { true } else { false } { "if" } - else { "else" } - } - "#, - ); - let if_ = parse.tree().syntax().descendants().find_map(ast::IfExpr::cast).unwrap(); - assert_eq!(if_.then_branch().unwrap().syntax().text(), r#"{ "if" }"#); - let else_ = match if_.else_branch().unwrap() { - ElseBranch::Block(else_) => else_, - ElseBranch::IfExpr(_) => panic!("should be `else`"), - }; - assert_eq!(else_.syntax().text(), r#"{ "else" }"#); -} - -impl ast::PrefixExpr { - pub fn op_kind(&self) -> Option { - let res = match self.op_token()?.kind() { - T![*] => UnaryOp::Deref, - T![!] => UnaryOp::Not, - T![-] => UnaryOp::Neg, - _ => return None, - }; - Some(res) - } - - pub fn op_token(&self) -> Option { - self.syntax().first_child_or_token()?.into_token() - } -} - -impl ast::BinExpr { - pub fn op_details(&self) -> Option<(SyntaxToken, BinaryOp)> { - self.syntax().children_with_tokens().filter_map(|it| it.into_token()).find_map(|c| { - #[rustfmt::skip] - let bin_op = match c.kind() { - T![||] => BinaryOp::LogicOp(LogicOp::Or), - T![&&] => BinaryOp::LogicOp(LogicOp::And), - - T![==] => BinaryOp::CmpOp(CmpOp::Eq { negated: false }), - T![!=] => BinaryOp::CmpOp(CmpOp::Eq { negated: true }), - T![<=] => BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false }), - T![>=] => BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false }), - T![<] => BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true }), - T![>] => BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true }), - - T![+] => BinaryOp::ArithOp(ArithOp::Add), - T![*] => BinaryOp::ArithOp(ArithOp::Mul), - T![-] => BinaryOp::ArithOp(ArithOp::Sub), - T![/] => BinaryOp::ArithOp(ArithOp::Div), - T![%] => BinaryOp::ArithOp(ArithOp::Rem), - T![<<] => BinaryOp::ArithOp(ArithOp::Shl), - T![>>] => BinaryOp::ArithOp(ArithOp::Shr), - T![^] => BinaryOp::ArithOp(ArithOp::BitXor), - T![|] => BinaryOp::ArithOp(ArithOp::BitOr), - T![&] => BinaryOp::ArithOp(ArithOp::BitAnd), - - T![=] => BinaryOp::Assignment { op: None }, - T![+=] => BinaryOp::Assignment { op: Some(ArithOp::Add) }, - T![*=] => BinaryOp::Assignment { op: Some(ArithOp::Mul) }, - T![-=] => BinaryOp::Assignment { op: Some(ArithOp::Sub) }, - T![/=] => BinaryOp::Assignment { op: Some(ArithOp::Div) }, - T![%=] => BinaryOp::Assignment { op: Some(ArithOp::Rem) }, - T![<<=] => BinaryOp::Assignment { op: Some(ArithOp::Shl) }, - T![>>=] => BinaryOp::Assignment { op: Some(ArithOp::Shr) }, - T![^=] => BinaryOp::Assignment { op: Some(ArithOp::BitXor) }, - T![|=] => BinaryOp::Assignment { op: Some(ArithOp::BitOr) }, - T![&=] => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) }, - - _ => return None, - }; - Some((c, bin_op)) - }) - } - - pub fn op_kind(&self) -> Option { - self.op_details().map(|t| t.1) - } - - pub fn op_token(&self) -> Option { - self.op_details().map(|t| t.0) - } - - pub fn lhs(&self) -> Option { - support::children(self.syntax()).next() - } - - pub fn rhs(&self) -> Option { - support::children(self.syntax()).nth(1) - } - - pub fn sub_exprs(&self) -> (Option, Option) { - let mut children = support::children(self.syntax()); - let first = children.next(); - let second = children.next(); - (first, second) - } -} - -impl ast::RangeExpr { - fn op_details(&self) -> Option<(usize, SyntaxToken, RangeOp)> { - self.syntax().children_with_tokens().enumerate().find_map(|(ix, child)| { - let token = child.into_token()?; - let bin_op = match token.kind() { - T![..] => RangeOp::Exclusive, - T![..=] => RangeOp::Inclusive, - _ => return None, - }; - Some((ix, token, bin_op)) - }) - } - - pub fn op_kind(&self) -> Option { - self.op_details().map(|t| t.2) - } - - pub fn op_token(&self) -> Option { - self.op_details().map(|t| t.1) - } - - pub fn start(&self) -> Option { - let op_ix = self.op_details()?.0; - self.syntax() - .children_with_tokens() - .take(op_ix) - .find_map(|it| ast::Expr::cast(it.into_node()?)) - } - - pub fn end(&self) -> Option { - let op_ix = self.op_details()?.0; - self.syntax() - .children_with_tokens() - .skip(op_ix + 1) - .find_map(|it| ast::Expr::cast(it.into_node()?)) - } -} - -impl ast::IndexExpr { - pub fn base(&self) -> Option { - support::children(self.syntax()).next() - } - pub fn index(&self) -> Option { - support::children(self.syntax()).nth(1) - } -} - -pub enum ArrayExprKind { - Repeat { initializer: Option, repeat: Option }, - ElementList(AstChildren), -} - -impl ast::ArrayExpr { - pub fn kind(&self) -> ArrayExprKind { - if self.is_repeat() { - ArrayExprKind::Repeat { - initializer: support::children(self.syntax()).next(), - repeat: support::children(self.syntax()).nth(1), - } - } else { - ArrayExprKind::ElementList(support::children(self.syntax())) - } - } - - fn is_repeat(&self) -> bool { - self.semicolon_token().is_some() - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum LiteralKind { - String(ast::String), - ByteString(ast::ByteString), - IntNumber(ast::IntNumber), - FloatNumber(ast::FloatNumber), - Char(ast::Char), - Byte(ast::Byte), - Bool(bool), -} - -impl ast::Literal { - pub fn token(&self) -> SyntaxToken { - self.syntax() - .children_with_tokens() - .find(|e| e.kind() != ATTR && !e.kind().is_trivia()) - .and_then(|e| e.into_token()) - .unwrap() - } - - pub fn kind(&self) -> LiteralKind { - let token = self.token(); - - if let Some(t) = ast::IntNumber::cast(token.clone()) { - return LiteralKind::IntNumber(t); - } - if let Some(t) = ast::FloatNumber::cast(token.clone()) { - return LiteralKind::FloatNumber(t); - } - if let Some(t) = ast::String::cast(token.clone()) { - return LiteralKind::String(t); - } - if let Some(t) = ast::ByteString::cast(token.clone()) { - return LiteralKind::ByteString(t); - } - if let Some(t) = ast::Char::cast(token.clone()) { - return LiteralKind::Char(t); - } - if let Some(t) = ast::Byte::cast(token.clone()) { - return LiteralKind::Byte(t); - } - - match token.kind() { - T![true] => LiteralKind::Bool(true), - T![false] => LiteralKind::Bool(false), - _ => unreachable!(), - } - } -} - -pub enum BlockModifier { - Async(SyntaxToken), - Unsafe(SyntaxToken), - Try(SyntaxToken), - Const(SyntaxToken), - Label(ast::Label), -} - -impl ast::BlockExpr { - pub fn modifier(&self) -> Option { - self.async_token() - .map(BlockModifier::Async) - .or_else(|| self.unsafe_token().map(BlockModifier::Unsafe)) - .or_else(|| self.try_token().map(BlockModifier::Try)) - .or_else(|| self.const_token().map(BlockModifier::Const)) - .or_else(|| self.label().map(BlockModifier::Label)) - } - /// false if the block is an intrinsic part of the syntax and can't be - /// replaced with arbitrary expression. - /// - /// ```not_rust - /// fn foo() { not_stand_alone } - /// const FOO: () = { stand_alone }; - /// ``` - pub fn is_standalone(&self) -> bool { - let parent = match self.syntax().parent() { - Some(it) => it, - None => return true, - }; - !matches!(parent.kind(), FN | IF_EXPR | WHILE_EXPR | LOOP_EXPR) - } -} - -#[test] -fn test_literal_with_attr() { - let parse = ast::SourceFile::parse(r#"const _: &str = { #[attr] "Hello" };"#); - let lit = parse.tree().syntax().descendants().find_map(ast::Literal::cast).unwrap(); - assert_eq!(lit.token().text(), r#""Hello""#); -} - -impl ast::RecordExprField { - pub fn parent_record_lit(&self) -> ast::RecordExpr { - self.syntax().ancestors().find_map(ast::RecordExpr::cast).unwrap() - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum CallableExpr { - Call(ast::CallExpr), - MethodCall(ast::MethodCallExpr), -} - -impl ast::HasAttrs for CallableExpr {} -impl ast::HasArgList for CallableExpr {} - -impl AstNode for CallableExpr { - fn can_cast(kind: parser::SyntaxKind) -> bool - where - Self: Sized, - { - ast::CallExpr::can_cast(kind) || ast::MethodCallExpr::can_cast(kind) - } - - fn cast(syntax: SyntaxNode) -> Option - where - Self: Sized, - { - if let Some(it) = ast::CallExpr::cast(syntax.clone()) { - Some(Self::Call(it)) - } else { - ast::MethodCallExpr::cast(syntax).map(Self::MethodCall) - } - } - - fn syntax(&self) -> &SyntaxNode { - match self { - Self::Call(it) => it.syntax(), - Self::MethodCall(it) => it.syntax(), - } - } -} diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated.rs deleted file mode 100644 index 843b43cf0b6ba..0000000000000 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated.rs +++ /dev/null @@ -1,41 +0,0 @@ -//! This file is actually hand-written, but the submodules are indeed generated. -#[rustfmt::skip] -pub(crate) mod nodes; -#[rustfmt::skip] -pub(crate) mod tokens; - -use crate::{ - AstNode, - SyntaxKind::{self, *}, - SyntaxNode, -}; - -pub(crate) use nodes::*; - -// Stmt is the only nested enum, so it's easier to just hand-write it -impl AstNode for Stmt { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - LET_STMT | EXPR_STMT => true, - _ => Item::can_cast(kind), - } - } - fn cast(syntax: SyntaxNode) -> Option { - let res = match syntax.kind() { - LET_STMT => Stmt::LetStmt(LetStmt { syntax }), - EXPR_STMT => Stmt::ExprStmt(ExprStmt { syntax }), - _ => { - let item = Item::cast(syntax)?; - Stmt::Item(item) - } - }; - Some(res) - } - fn syntax(&self) -> &SyntaxNode { - match self { - Stmt::LetStmt(it) => &it.syntax, - Stmt::ExprStmt(it) => &it.syntax, - Stmt::Item(it) => it.syntax(), - } - } -} diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs deleted file mode 100644 index cf90ba64cff1a..0000000000000 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ /dev/null @@ -1,4810 +0,0 @@ -//! Generated by `sourcegen_ast`, do not edit by hand. - -#![allow(non_snake_case)] -use crate::{ - ast::{self, support, AstChildren, AstNode}, - SyntaxKind::{self, *}, - SyntaxNode, SyntaxToken, T, -}; - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Name { - pub(crate) syntax: SyntaxNode, -} -impl Name { - pub fn ident_token(&self) -> Option { support::token(&self.syntax, T![ident]) } - pub fn self_token(&self) -> Option { support::token(&self.syntax, T![self]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct NameRef { - pub(crate) syntax: SyntaxNode, -} -impl NameRef { - pub fn ident_token(&self) -> Option { support::token(&self.syntax, T![ident]) } - pub fn self_token(&self) -> Option { support::token(&self.syntax, T![self]) } - pub fn super_token(&self) -> Option { support::token(&self.syntax, T![super]) } - pub fn crate_token(&self) -> Option { support::token(&self.syntax, T![crate]) } - pub fn Self_token(&self) -> Option { support::token(&self.syntax, T![Self]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Lifetime { - pub(crate) syntax: SyntaxNode, -} -impl Lifetime { - pub fn lifetime_ident_token(&self) -> Option { - support::token(&self.syntax, T![lifetime_ident]) - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Path { - pub(crate) syntax: SyntaxNode, -} -impl Path { - pub fn qualifier(&self) -> Option { support::child(&self.syntax) } - pub fn coloncolon_token(&self) -> Option { support::token(&self.syntax, T![::]) } - pub fn segment(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct PathSegment { - pub(crate) syntax: SyntaxNode, -} -impl PathSegment { - pub fn coloncolon_token(&self) -> Option { support::token(&self.syntax, T![::]) } - pub fn name_ref(&self) -> Option { support::child(&self.syntax) } - pub fn generic_arg_list(&self) -> Option { support::child(&self.syntax) } - pub fn param_list(&self) -> Option { support::child(&self.syntax) } - pub fn ret_type(&self) -> Option { support::child(&self.syntax) } - pub fn l_angle_token(&self) -> Option { support::token(&self.syntax, T![<]) } - pub fn path_type(&self) -> Option { support::child(&self.syntax) } - pub fn as_token(&self) -> Option { support::token(&self.syntax, T![as]) } - pub fn r_angle_token(&self) -> Option { support::token(&self.syntax, T![>]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct GenericArgList { - pub(crate) syntax: SyntaxNode, -} -impl GenericArgList { - pub fn coloncolon_token(&self) -> Option { support::token(&self.syntax, T![::]) } - pub fn l_angle_token(&self) -> Option { support::token(&self.syntax, T![<]) } - pub fn generic_args(&self) -> AstChildren { support::children(&self.syntax) } - pub fn r_angle_token(&self) -> Option { support::token(&self.syntax, T![>]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ParamList { - pub(crate) syntax: SyntaxNode, -} -impl ParamList { - pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } - pub fn self_param(&self) -> Option { support::child(&self.syntax) } - pub fn comma_token(&self) -> Option { support::token(&self.syntax, T![,]) } - pub fn params(&self) -> AstChildren { support::children(&self.syntax) } - pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } - pub fn pipe_token(&self) -> Option { support::token(&self.syntax, T![|]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct RetType { - pub(crate) syntax: SyntaxNode, -} -impl RetType { - pub fn thin_arrow_token(&self) -> Option { support::token(&self.syntax, T![->]) } - pub fn ty(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct PathType { - pub(crate) syntax: SyntaxNode, -} -impl PathType { - pub fn path(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct TypeArg { - pub(crate) syntax: SyntaxNode, -} -impl TypeArg { - pub fn ty(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct AssocTypeArg { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasTypeBounds for AssocTypeArg {} -impl AssocTypeArg { - pub fn name_ref(&self) -> Option { support::child(&self.syntax) } - pub fn generic_param_list(&self) -> Option { support::child(&self.syntax) } - pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } - pub fn ty(&self) -> Option { support::child(&self.syntax) } - pub fn const_arg(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct LifetimeArg { - pub(crate) syntax: SyntaxNode, -} -impl LifetimeArg { - pub fn lifetime(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ConstArg { - pub(crate) syntax: SyntaxNode, -} -impl ConstArg { - pub fn expr(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct GenericParamList { - pub(crate) syntax: SyntaxNode, -} -impl GenericParamList { - pub fn l_angle_token(&self) -> Option { support::token(&self.syntax, T![<]) } - pub fn generic_params(&self) -> AstChildren { support::children(&self.syntax) } - pub fn r_angle_token(&self) -> Option { support::token(&self.syntax, T![>]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct TypeBoundList { - pub(crate) syntax: SyntaxNode, -} -impl TypeBoundList { - pub fn bounds(&self) -> AstChildren { support::children(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct MacroCall { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for MacroCall {} -impl ast::HasDocComments for MacroCall {} -impl MacroCall { - pub fn path(&self) -> Option { support::child(&self.syntax) } - pub fn excl_token(&self) -> Option { support::token(&self.syntax, T![!]) } - pub fn token_tree(&self) -> Option { support::child(&self.syntax) } - pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Attr { - pub(crate) syntax: SyntaxNode, -} -impl Attr { - pub fn pound_token(&self) -> Option { support::token(&self.syntax, T![#]) } - pub fn excl_token(&self) -> Option { support::token(&self.syntax, T![!]) } - pub fn l_brack_token(&self) -> Option { support::token(&self.syntax, T!['[']) } - pub fn meta(&self) -> Option { support::child(&self.syntax) } - pub fn r_brack_token(&self) -> Option { support::token(&self.syntax, T![']']) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct TokenTree { - pub(crate) syntax: SyntaxNode, -} -impl TokenTree { - pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } - pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } - pub fn l_curly_token(&self) -> Option { support::token(&self.syntax, T!['{']) } - pub fn r_curly_token(&self) -> Option { support::token(&self.syntax, T!['}']) } - pub fn l_brack_token(&self) -> Option { support::token(&self.syntax, T!['[']) } - pub fn r_brack_token(&self) -> Option { support::token(&self.syntax, T![']']) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct MacroItems { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasModuleItem for MacroItems {} -impl MacroItems {} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct MacroStmts { - pub(crate) syntax: SyntaxNode, -} -impl MacroStmts { - pub fn statements(&self) -> AstChildren { support::children(&self.syntax) } - pub fn expr(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct SourceFile { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for SourceFile {} -impl ast::HasModuleItem for SourceFile {} -impl ast::HasDocComments for SourceFile {} -impl SourceFile { - pub fn shebang_token(&self) -> Option { support::token(&self.syntax, T![shebang]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Const { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for Const {} -impl ast::HasName for Const {} -impl ast::HasVisibility for Const {} -impl ast::HasDocComments for Const {} -impl Const { - pub fn default_token(&self) -> Option { support::token(&self.syntax, T![default]) } - pub fn const_token(&self) -> Option { support::token(&self.syntax, T![const]) } - pub fn underscore_token(&self) -> Option { support::token(&self.syntax, T![_]) } - pub fn colon_token(&self) -> Option { support::token(&self.syntax, T![:]) } - pub fn ty(&self) -> Option { support::child(&self.syntax) } - pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } - pub fn body(&self) -> Option { support::child(&self.syntax) } - pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Enum { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for Enum {} -impl ast::HasName for Enum {} -impl ast::HasVisibility for Enum {} -impl ast::HasGenericParams for Enum {} -impl ast::HasDocComments for Enum {} -impl Enum { - pub fn enum_token(&self) -> Option { support::token(&self.syntax, T![enum]) } - pub fn variant_list(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ExternBlock { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for ExternBlock {} -impl ast::HasDocComments for ExternBlock {} -impl ExternBlock { - pub fn unsafe_token(&self) -> Option { support::token(&self.syntax, T![unsafe]) } - pub fn abi(&self) -> Option { support::child(&self.syntax) } - pub fn extern_item_list(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ExternCrate { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for ExternCrate {} -impl ast::HasVisibility for ExternCrate {} -impl ast::HasDocComments for ExternCrate {} -impl ExternCrate { - pub fn extern_token(&self) -> Option { support::token(&self.syntax, T![extern]) } - pub fn crate_token(&self) -> Option { support::token(&self.syntax, T![crate]) } - pub fn name_ref(&self) -> Option { support::child(&self.syntax) } - pub fn rename(&self) -> Option { support::child(&self.syntax) } - pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Fn { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for Fn {} -impl ast::HasName for Fn {} -impl ast::HasVisibility for Fn {} -impl ast::HasGenericParams for Fn {} -impl ast::HasDocComments for Fn {} -impl Fn { - pub fn default_token(&self) -> Option { support::token(&self.syntax, T![default]) } - pub fn const_token(&self) -> Option { support::token(&self.syntax, T![const]) } - pub fn async_token(&self) -> Option { support::token(&self.syntax, T![async]) } - pub fn unsafe_token(&self) -> Option { support::token(&self.syntax, T![unsafe]) } - pub fn abi(&self) -> Option { support::child(&self.syntax) } - pub fn fn_token(&self) -> Option { support::token(&self.syntax, T![fn]) } - pub fn param_list(&self) -> Option { support::child(&self.syntax) } - pub fn ret_type(&self) -> Option { support::child(&self.syntax) } - pub fn body(&self) -> Option { support::child(&self.syntax) } - pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Impl { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for Impl {} -impl ast::HasVisibility for Impl {} -impl ast::HasGenericParams for Impl {} -impl ast::HasDocComments for Impl {} -impl Impl { - pub fn default_token(&self) -> Option { support::token(&self.syntax, T![default]) } - pub fn unsafe_token(&self) -> Option { support::token(&self.syntax, T![unsafe]) } - pub fn impl_token(&self) -> Option { support::token(&self.syntax, T![impl]) } - pub fn const_token(&self) -> Option { support::token(&self.syntax, T![const]) } - pub fn excl_token(&self) -> Option { support::token(&self.syntax, T![!]) } - pub fn for_token(&self) -> Option { support::token(&self.syntax, T![for]) } - pub fn assoc_item_list(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct MacroRules { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for MacroRules {} -impl ast::HasName for MacroRules {} -impl ast::HasVisibility for MacroRules {} -impl ast::HasDocComments for MacroRules {} -impl MacroRules { - pub fn macro_rules_token(&self) -> Option { - support::token(&self.syntax, T![macro_rules]) - } - pub fn excl_token(&self) -> Option { support::token(&self.syntax, T![!]) } - pub fn token_tree(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct MacroDef { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for MacroDef {} -impl ast::HasName for MacroDef {} -impl ast::HasVisibility for MacroDef {} -impl ast::HasDocComments for MacroDef {} -impl MacroDef { - pub fn macro_token(&self) -> Option { support::token(&self.syntax, T![macro]) } - pub fn args(&self) -> Option { support::child(&self.syntax) } - pub fn body(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Module { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for Module {} -impl ast::HasName for Module {} -impl ast::HasVisibility for Module {} -impl ast::HasDocComments for Module {} -impl Module { - pub fn mod_token(&self) -> Option { support::token(&self.syntax, T![mod]) } - pub fn item_list(&self) -> Option { support::child(&self.syntax) } - pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Static { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for Static {} -impl ast::HasName for Static {} -impl ast::HasVisibility for Static {} -impl ast::HasDocComments for Static {} -impl Static { - pub fn static_token(&self) -> Option { support::token(&self.syntax, T![static]) } - pub fn mut_token(&self) -> Option { support::token(&self.syntax, T![mut]) } - pub fn colon_token(&self) -> Option { support::token(&self.syntax, T![:]) } - pub fn ty(&self) -> Option { support::child(&self.syntax) } - pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } - pub fn body(&self) -> Option { support::child(&self.syntax) } - pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Struct { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for Struct {} -impl ast::HasName for Struct {} -impl ast::HasVisibility for Struct {} -impl ast::HasGenericParams for Struct {} -impl ast::HasDocComments for Struct {} -impl Struct { - pub fn struct_token(&self) -> Option { support::token(&self.syntax, T![struct]) } - pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } - pub fn field_list(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Trait { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for Trait {} -impl ast::HasName for Trait {} -impl ast::HasVisibility for Trait {} -impl ast::HasGenericParams for Trait {} -impl ast::HasTypeBounds for Trait {} -impl ast::HasDocComments for Trait {} -impl Trait { - pub fn unsafe_token(&self) -> Option { support::token(&self.syntax, T![unsafe]) } - pub fn auto_token(&self) -> Option { support::token(&self.syntax, T![auto]) } - pub fn trait_token(&self) -> Option { support::token(&self.syntax, T![trait]) } - pub fn assoc_item_list(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct TypeAlias { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for TypeAlias {} -impl ast::HasName for TypeAlias {} -impl ast::HasVisibility for TypeAlias {} -impl ast::HasGenericParams for TypeAlias {} -impl ast::HasTypeBounds for TypeAlias {} -impl ast::HasDocComments for TypeAlias {} -impl TypeAlias { - pub fn default_token(&self) -> Option { support::token(&self.syntax, T![default]) } - pub fn type_token(&self) -> Option { support::token(&self.syntax, T![type]) } - pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } - pub fn ty(&self) -> Option { support::child(&self.syntax) } - pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Union { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for Union {} -impl ast::HasName for Union {} -impl ast::HasVisibility for Union {} -impl ast::HasGenericParams for Union {} -impl ast::HasDocComments for Union {} -impl Union { - pub fn union_token(&self) -> Option { support::token(&self.syntax, T![union]) } - pub fn record_field_list(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Use { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for Use {} -impl ast::HasVisibility for Use {} -impl ast::HasDocComments for Use {} -impl Use { - pub fn use_token(&self) -> Option { support::token(&self.syntax, T![use]) } - pub fn use_tree(&self) -> Option { support::child(&self.syntax) } - pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Visibility { - pub(crate) syntax: SyntaxNode, -} -impl Visibility { - pub fn pub_token(&self) -> Option { support::token(&self.syntax, T![pub]) } - pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } - pub fn in_token(&self) -> Option { support::token(&self.syntax, T![in]) } - pub fn path(&self) -> Option { support::child(&self.syntax) } - pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ItemList { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for ItemList {} -impl ast::HasModuleItem for ItemList {} -impl ItemList { - pub fn l_curly_token(&self) -> Option { support::token(&self.syntax, T!['{']) } - pub fn r_curly_token(&self) -> Option { support::token(&self.syntax, T!['}']) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Rename { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasName for Rename {} -impl Rename { - pub fn as_token(&self) -> Option { support::token(&self.syntax, T![as]) } - pub fn underscore_token(&self) -> Option { support::token(&self.syntax, T![_]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct UseTree { - pub(crate) syntax: SyntaxNode, -} -impl UseTree { - pub fn path(&self) -> Option { support::child(&self.syntax) } - pub fn coloncolon_token(&self) -> Option { support::token(&self.syntax, T![::]) } - pub fn star_token(&self) -> Option { support::token(&self.syntax, T![*]) } - pub fn use_tree_list(&self) -> Option { support::child(&self.syntax) } - pub fn rename(&self) -> Option { support::child(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct UseTreeList { - pub(crate) syntax: SyntaxNode, -} -impl UseTreeList { - pub fn l_curly_token(&self) -> Option { support::token(&self.syntax, T!['{']) } - pub fn use_trees(&self) -> AstChildren { support::children(&self.syntax) } - pub fn r_curly_token(&self) -> Option { support::token(&self.syntax, T!['}']) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Abi { - pub(crate) syntax: SyntaxNode, -} -impl Abi { - pub fn extern_token(&self) -> Option { support::token(&self.syntax, T![extern]) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct WhereClause { - pub(crate) syntax: SyntaxNode, -} -impl WhereClause { - pub fn where_token(&self) -> Option { support::token(&self.syntax, T![where]) } - pub fn predicates(&self) -> AstChildren { support::children(&self.syntax) } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct BlockExpr { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for BlockExpr {} -impl BlockExpr { - pub fn label(&self) -> Option

{ - pointer: P, - } -} -// endregion:pin - -// region:future -pub mod future { - use crate::{ - pin::Pin, - task::{Context, Poll}, - }; - - #[lang = "future_trait"] - pub trait Future { - type Output; - #[lang = "poll"] - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; - } -} -pub mod task { - pub enum Poll { - #[lang = "Ready"] - Ready(T), - #[lang = "Pending"] - Pending, - } - - pub struct Context<'a> { - waker: &'a (), - } -} -// endregion:future - -// region:iterator -pub mod iter { - // region:iterators - mod adapters { - pub struct Take { - iter: I, - n: usize, - } - impl Iterator for Take - where - I: Iterator, - { - type Item = ::Item; - - fn next(&mut self) -> Option<::Item> { - loop {} - } - } - - pub struct FilterMap { - iter: I, - f: F, - } - impl Iterator for FilterMap - where - F: FnMut(I::Item) -> Option, - { - type Item = B; - - #[inline] - fn next(&mut self) -> Option { - loop {} - } - } - } - pub use self::adapters::{Take, FilterMap}; - - mod sources { - mod repeat { - pub fn repeat(elt: T) -> Repeat { - loop {} - } - - pub struct Repeat { - element: A, - } - - impl Iterator for Repeat { - type Item = A; - - fn next(&mut self) -> Option { - loop {} - } - } - } - pub use self::repeat::{repeat, Repeat}; - } - pub use self::sources::{repeat, Repeat}; - // endregion:iterators - - mod traits { - mod iterator { - use super::super::Take; - - pub trait Iterator { - type Item; - #[lang = "next"] - fn next(&mut self) -> Option; - fn nth(&mut self, n: usize) -> Option { - loop {} - } - fn by_ref(&mut self) -> &mut Self - where - Self: Sized, - { - self - } - // region:iterators - fn take(self, n: usize) -> crate::iter::Take { - loop {} - } - fn filter_map(self, f: F) -> crate::iter::FilterMap - where - Self: Sized, - F: FnMut(Self::Item) -> Option, - { - loop {} - } - // endregion:iterators - } - impl Iterator for &mut I { - type Item = I::Item; - fn next(&mut self) -> Option { - (**self).next() - } - } - } - pub use self::iterator::Iterator; - - mod collect { - pub trait IntoIterator { - type Item; - type IntoIter: Iterator; - #[lang = "into_iter"] - fn into_iter(self) -> Self::IntoIter; - } - impl IntoIterator for I { - type Item = I::Item; - type IntoIter = I; - fn into_iter(self) -> I { - self - } - } - } - pub use self::collect::IntoIterator; - } - pub use self::traits::{IntoIterator, Iterator}; -} -// endregion:iterator - -// region:derive -mod macros { - pub(crate) mod builtin { - #[rustc_builtin_macro] - pub macro derive($item:item) { - /* compiler built-in */ - } - } -} -// endregion:derive - -// region:bool_impl -#[lang = "bool"] -impl bool { - pub fn then T>(self, f: F) -> Option { - if self { - Some(f()) - } else { - None - } - } -} -// endregion:bool_impl - -pub mod prelude { - pub mod v1 { - pub use crate::{ - clone::Clone, // :clone - cmp::{Eq, PartialEq}, // :eq - cmp::{Ord, PartialOrd}, // :ord - convert::AsRef, // :as_ref - convert::{From, Into}, // :from - default::Default, // :default - iter::{IntoIterator, Iterator}, // :iterator - macros::builtin::derive, // :derive - marker::Copy, // :copy - marker::Sized, // :sized - mem::drop, // :drop - ops::Drop, // :drop - ops::{Fn, FnMut, FnOnce}, // :fn - option::Option::{self, None, Some}, // :option - result::Result::{self, Err, Ok}, // :result - }; - } - - pub mod rust_2015 { - pub use super::v1::*; - } - - pub mod rust_2018 { - pub use super::v1::*; - } - - pub mod rust_2021 { - pub use super::v1::*; - } -} - -#[prelude_import] -#[allow(unused)] -use prelude::v1::*; diff --git a/src/tools/rust-analyzer/crates/text-edit/Cargo.toml b/src/tools/rust-analyzer/crates/text-edit/Cargo.toml deleted file mode 100644 index cf14bbd3c3e06..0000000000000 --- a/src/tools/rust-analyzer/crates/text-edit/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "text-edit" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -itertools = "0.10.3" -text-size = "1.1.0" diff --git a/src/tools/rust-analyzer/crates/text-edit/src/lib.rs b/src/tools/rust-analyzer/crates/text-edit/src/lib.rs deleted file mode 100644 index 9bb4271b65f7f..0000000000000 --- a/src/tools/rust-analyzer/crates/text-edit/src/lib.rs +++ /dev/null @@ -1,264 +0,0 @@ -//! Representation of a `TextEdit`. -//! -//! `rust-analyzer` never mutates text itself and only sends diffs to clients, -//! so `TextEdit` is the ultimate representation of the work done by -//! rust-analyzer. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -use itertools::Itertools; -use std::cmp::max; -pub use text_size::{TextRange, TextSize}; - -/// `InsertDelete` -- a single "atomic" change to text -/// -/// Must not overlap with other `InDel`s -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Indel { - pub insert: String, - /// Refers to offsets in the original text - pub delete: TextRange, -} - -#[derive(Default, Debug, Clone)] -pub struct TextEdit { - /// Invariant: disjoint and sorted by `delete`. - indels: Vec, -} - -#[derive(Debug, Default, Clone)] -pub struct TextEditBuilder { - indels: Vec, -} - -impl Indel { - pub fn insert(offset: TextSize, text: String) -> Indel { - Indel::replace(TextRange::empty(offset), text) - } - pub fn delete(range: TextRange) -> Indel { - Indel::replace(range, String::new()) - } - pub fn replace(range: TextRange, replace_with: String) -> Indel { - Indel { delete: range, insert: replace_with } - } - - pub fn apply(&self, text: &mut String) { - let start: usize = self.delete.start().into(); - let end: usize = self.delete.end().into(); - text.replace_range(start..end, &self.insert); - } -} - -impl TextEdit { - pub fn builder() -> TextEditBuilder { - TextEditBuilder::default() - } - - pub fn insert(offset: TextSize, text: String) -> TextEdit { - let mut builder = TextEdit::builder(); - builder.insert(offset, text); - builder.finish() - } - - pub fn delete(range: TextRange) -> TextEdit { - let mut builder = TextEdit::builder(); - builder.delete(range); - builder.finish() - } - - pub fn replace(range: TextRange, replace_with: String) -> TextEdit { - let mut builder = TextEdit::builder(); - builder.replace(range, replace_with); - builder.finish() - } - - pub fn len(&self) -> usize { - self.indels.len() - } - - pub fn is_empty(&self) -> bool { - self.indels.is_empty() - } - - pub fn iter(&self) -> std::slice::Iter<'_, Indel> { - self.into_iter() - } - - pub fn apply(&self, text: &mut String) { - match self.len() { - 0 => return, - 1 => { - self.indels[0].apply(text); - return; - } - _ => (), - } - - let text_size = TextSize::of(&*text); - let mut total_len = text_size; - let mut max_total_len = text_size; - for indel in &self.indels { - total_len += TextSize::of(&indel.insert); - total_len -= indel.delete.len(); - max_total_len = max(max_total_len, total_len); - } - - if let Some(additional) = max_total_len.checked_sub(text_size) { - text.reserve(additional.into()); - } - - for indel in self.indels.iter().rev() { - indel.apply(text); - } - - assert_eq!(TextSize::of(&*text), total_len); - } - - pub fn union(&mut self, other: TextEdit) -> Result<(), TextEdit> { - let iter_merge = - self.iter().merge_by(other.iter(), |l, r| l.delete.start() <= r.delete.start()); - if !check_disjoint(&mut iter_merge.clone()) { - return Err(other); - } - - // Only dedup deletions and replacements, keep all insertions - self.indels = iter_merge.dedup_by(|a, b| a == b && !a.delete.is_empty()).cloned().collect(); - Ok(()) - } - - pub fn apply_to_offset(&self, offset: TextSize) -> Option { - let mut res = offset; - for indel in &self.indels { - if indel.delete.start() >= offset { - break; - } - if offset < indel.delete.end() { - return None; - } - res += TextSize::of(&indel.insert); - res -= indel.delete.len(); - } - Some(res) - } -} - -impl IntoIterator for TextEdit { - type Item = Indel; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.indels.into_iter() - } -} - -impl<'a> IntoIterator for &'a TextEdit { - type Item = &'a Indel; - type IntoIter = std::slice::Iter<'a, Indel>; - - fn into_iter(self) -> Self::IntoIter { - self.indels.iter() - } -} - -impl TextEditBuilder { - pub fn is_empty(&self) -> bool { - self.indels.is_empty() - } - pub fn replace(&mut self, range: TextRange, replace_with: String) { - self.indel(Indel::replace(range, replace_with)); - } - pub fn delete(&mut self, range: TextRange) { - self.indel(Indel::delete(range)); - } - pub fn insert(&mut self, offset: TextSize, text: String) { - self.indel(Indel::insert(offset, text)); - } - pub fn finish(self) -> TextEdit { - let mut indels = self.indels; - assert_disjoint_or_equal(&mut indels); - TextEdit { indels } - } - pub fn invalidates_offset(&self, offset: TextSize) -> bool { - self.indels.iter().any(|indel| indel.delete.contains_inclusive(offset)) - } - fn indel(&mut self, indel: Indel) { - self.indels.push(indel); - if self.indels.len() <= 16 { - assert_disjoint_or_equal(&mut self.indels); - } - } -} - -fn assert_disjoint_or_equal(indels: &mut [Indel]) { - assert!(check_disjoint_and_sort(indels)); -} - -fn check_disjoint_and_sort(indels: &mut [Indel]) -> bool { - indels.sort_by_key(|indel| (indel.delete.start(), indel.delete.end())); - check_disjoint(&mut indels.iter()) -} - -fn check_disjoint<'a, I>(indels: &mut I) -> bool -where - I: std::iter::Iterator + Clone, -{ - indels.clone().zip(indels.skip(1)).all(|(l, r)| l.delete.end() <= r.delete.start() || l == r) -} - -#[cfg(test)] -mod tests { - use super::{TextEdit, TextEditBuilder, TextRange}; - - fn range(start: u32, end: u32) -> TextRange { - TextRange::new(start.into(), end.into()) - } - - #[test] - fn test_apply() { - let mut text = "_11h1_2222_xx3333_4444_6666".to_string(); - let mut builder = TextEditBuilder::default(); - builder.replace(range(3, 4), "1".to_string()); - builder.delete(range(11, 13)); - builder.insert(22.into(), "_5555".to_string()); - - let text_edit = builder.finish(); - text_edit.apply(&mut text); - - assert_eq!(text, "_1111_2222_3333_4444_5555_6666") - } - - #[test] - fn test_union() { - let mut edit1 = TextEdit::delete(range(7, 11)); - let mut builder = TextEditBuilder::default(); - builder.delete(range(1, 5)); - builder.delete(range(13, 17)); - - let edit2 = builder.finish(); - assert!(edit1.union(edit2).is_ok()); - assert_eq!(edit1.indels.len(), 3); - } - - #[test] - fn test_union_with_duplicates() { - let mut builder1 = TextEditBuilder::default(); - builder1.delete(range(7, 11)); - builder1.delete(range(13, 17)); - - let mut builder2 = TextEditBuilder::default(); - builder2.delete(range(1, 5)); - builder2.delete(range(13, 17)); - - let mut edit1 = builder1.finish(); - let edit2 = builder2.finish(); - assert!(edit1.union(edit2).is_ok()); - assert_eq!(edit1.indels.len(), 3); - } - - #[test] - fn test_union_panics() { - let mut edit1 = TextEdit::delete(range(7, 11)); - let edit2 = TextEdit::delete(range(9, 13)); - assert!(edit1.union(edit2).is_err()); - } -} diff --git a/src/tools/rust-analyzer/crates/toolchain/Cargo.toml b/src/tools/rust-analyzer/crates/toolchain/Cargo.toml deleted file mode 100644 index 7d3b9e09ece77..0000000000000 --- a/src/tools/rust-analyzer/crates/toolchain/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "toolchain" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -home = "0.5.3" diff --git a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs deleted file mode 100644 index b05da769161e6..0000000000000 --- a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs +++ /dev/null @@ -1,69 +0,0 @@ -//! Discovery of `cargo` & `rustc` executables. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -use std::{env, iter, path::PathBuf}; - -pub fn cargo() -> PathBuf { - get_path_for_executable("cargo") -} - -pub fn rustc() -> PathBuf { - get_path_for_executable("rustc") -} - -pub fn rustup() -> PathBuf { - get_path_for_executable("rustup") -} - -pub fn rustfmt() -> PathBuf { - get_path_for_executable("rustfmt") -} - -/// Return a `PathBuf` to use for the given executable. -/// -/// E.g., `get_path_for_executable("cargo")` may return just `cargo` if that -/// gives a valid Cargo executable; or it may return a full path to a valid -/// Cargo. -fn get_path_for_executable(executable_name: &'static str) -> PathBuf { - // The current implementation checks three places for an executable to use: - // 1) Appropriate environment variable (erroring if this is set but not a usable executable) - // example: for cargo, this checks $CARGO environment variable; for rustc, $RUSTC; etc - // 2) `` - // example: for cargo, this tries just `cargo`, which will succeed if `cargo` is on the $PATH - // 3) `~/.cargo/bin/` - // example: for cargo, this tries ~/.cargo/bin/cargo - // It seems that this is a reasonable place to try for cargo, rustc, and rustup - let env_var = executable_name.to_ascii_uppercase(); - if let Some(path) = env::var_os(&env_var) { - return path.into(); - } - - if lookup_in_path(executable_name) { - return executable_name.into(); - } - - if let Some(mut path) = home::home_dir() { - path.push(".cargo"); - path.push("bin"); - path.push(executable_name); - if let Some(path) = probe(path) { - return path; - } - } - - executable_name.into() -} - -fn lookup_in_path(exec: &str) -> bool { - let paths = env::var_os("PATH").unwrap_or_default(); - env::split_paths(&paths).map(|path| path.join(exec)).find_map(probe).is_some() -} - -fn probe(path: PathBuf) -> Option { - let with_extension = match env::consts::EXE_EXTENSION { - "" => None, - it => Some(path.with_extension(it)), - }; - iter::once(path).chain(with_extension).find(|it| it.is_file()) -} diff --git a/src/tools/rust-analyzer/crates/tt/Cargo.toml b/src/tools/rust-analyzer/crates/tt/Cargo.toml deleted file mode 100644 index 52dfb86080418..0000000000000 --- a/src/tools/rust-analyzer/crates/tt/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "tt" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -smol_str = "0.1.23" - -stdx = { path = "../stdx", version = "0.0.0" } diff --git a/src/tools/rust-analyzer/crates/tt/src/buffer.rs b/src/tools/rust-analyzer/crates/tt/src/buffer.rs deleted file mode 100644 index 69226bd4c4805..0000000000000 --- a/src/tools/rust-analyzer/crates/tt/src/buffer.rs +++ /dev/null @@ -1,231 +0,0 @@ -//! Stateful iteration over token trees. -//! -//! We use this as the source of tokens for parser. -use crate::{Leaf, Subtree, TokenTree}; - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -struct EntryId(usize); - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -struct EntryPtr(EntryId, usize); - -/// Internal type which is used instead of `TokenTree` to represent a token tree -/// within a `TokenBuffer`. -#[derive(Debug)] -enum Entry<'t> { - // Mimicking types from proc-macro. - Subtree(Option<&'t TokenTree>, &'t Subtree, EntryId), - Leaf(&'t TokenTree), - // End entries contain a pointer to the entry from the containing - // token tree, or None if this is the outermost level. - End(Option), -} - -/// A token tree buffer -/// The safe version of `syn` [`TokenBuffer`](https://github.com/dtolnay/syn/blob/6533607f91686545cb034d2838beea338d9d0742/src/buffer.rs#L41) -#[derive(Debug)] -pub struct TokenBuffer<'t> { - buffers: Vec]>>, -} - -trait TokenList<'a> { - fn entries(&self) -> (Vec<(usize, (&'a Subtree, Option<&'a TokenTree>))>, Vec>); -} - -impl<'a> TokenList<'a> for &'a [TokenTree] { - fn entries(&self) -> (Vec<(usize, (&'a Subtree, Option<&'a TokenTree>))>, Vec>) { - // Must contain everything in tokens and then the Entry::End - let start_capacity = self.len() + 1; - let mut entries = Vec::with_capacity(start_capacity); - let mut children = vec![]; - for (idx, tt) in self.iter().enumerate() { - match tt { - TokenTree::Leaf(_) => { - entries.push(Entry::Leaf(tt)); - } - TokenTree::Subtree(subtree) => { - entries.push(Entry::End(None)); - children.push((idx, (subtree, Some(tt)))); - } - } - } - (children, entries) - } -} - -impl<'a> TokenList<'a> for &'a Subtree { - fn entries(&self) -> (Vec<(usize, (&'a Subtree, Option<&'a TokenTree>))>, Vec>) { - // Must contain everything in tokens and then the Entry::End - let mut entries = vec![]; - let mut children = vec![]; - entries.push(Entry::End(None)); - children.push((0usize, (*self, None))); - (children, entries) - } -} - -impl<'t> TokenBuffer<'t> { - pub fn from_tokens(tokens: &'t [TokenTree]) -> TokenBuffer<'t> { - Self::new(tokens) - } - - pub fn from_subtree(subtree: &'t Subtree) -> TokenBuffer<'t> { - Self::new(subtree) - } - - fn new>(tokens: T) -> TokenBuffer<'t> { - let mut buffers = vec![]; - let idx = TokenBuffer::new_inner(tokens, &mut buffers, None); - assert_eq!(idx, 0); - TokenBuffer { buffers } - } - - fn new_inner>( - tokens: T, - buffers: &mut Vec]>>, - next: Option, - ) -> usize { - let (children, mut entries) = tokens.entries(); - - entries.push(Entry::End(next)); - let res = buffers.len(); - buffers.push(entries.into_boxed_slice()); - - for (child_idx, (subtree, tt)) in children { - let idx = TokenBuffer::new_inner( - subtree.token_trees.as_slice(), - buffers, - Some(EntryPtr(EntryId(res), child_idx + 1)), - ); - buffers[res].as_mut()[child_idx] = Entry::Subtree(tt, subtree, EntryId(idx)); - } - - res - } - - /// Creates a cursor referencing the first token in the buffer and able to - /// traverse until the end of the buffer. - pub fn begin(&self) -> Cursor<'_> { - Cursor::create(self, EntryPtr(EntryId(0), 0)) - } - - fn entry(&self, ptr: &EntryPtr) -> Option<&Entry<'_>> { - let id = ptr.0; - self.buffers[id.0].get(ptr.1) - } -} - -#[derive(Debug)] -pub enum TokenTreeRef<'a> { - Subtree(&'a Subtree, Option<&'a TokenTree>), - Leaf(&'a Leaf, &'a TokenTree), -} - -impl<'a> TokenTreeRef<'a> { - pub fn cloned(&self) -> TokenTree { - match &self { - TokenTreeRef::Subtree(subtree, tt) => match tt { - Some(it) => (*it).clone(), - None => (*subtree).clone().into(), - }, - TokenTreeRef::Leaf(_, tt) => (*tt).clone(), - } - } -} - -/// A safe version of `Cursor` from `syn` crate -#[derive(Copy, Clone, Debug)] -pub struct Cursor<'a> { - buffer: &'a TokenBuffer<'a>, - ptr: EntryPtr, -} - -impl<'a> PartialEq for Cursor<'a> { - fn eq(&self, other: &Cursor<'_>) -> bool { - self.ptr == other.ptr && std::ptr::eq(self.buffer, other.buffer) - } -} - -impl<'a> Eq for Cursor<'a> {} - -impl<'a> Cursor<'a> { - /// Check whether it is eof - pub fn eof(self) -> bool { - matches!(self.buffer.entry(&self.ptr), None | Some(Entry::End(None))) - } - - /// If the cursor is pointing at the end of a subtree, returns - /// the parent subtree - pub fn end(self) -> Option<&'a Subtree> { - match self.entry() { - Some(Entry::End(Some(ptr))) => { - let idx = ptr.1; - if let Some(Entry::Subtree(_, subtree, _)) = - self.buffer.entry(&EntryPtr(ptr.0, idx - 1)) - { - return Some(subtree); - } - None - } - _ => None, - } - } - - fn entry(self) -> Option<&'a Entry<'a>> { - self.buffer.entry(&self.ptr) - } - - /// If the cursor is pointing at a `Subtree`, returns - /// a cursor into that subtree - pub fn subtree(self) -> Option> { - match self.entry() { - Some(Entry::Subtree(_, _, entry_id)) => { - Some(Cursor::create(self.buffer, EntryPtr(*entry_id, 0))) - } - _ => None, - } - } - - /// If the cursor is pointing at a `TokenTree`, returns it - pub fn token_tree(self) -> Option> { - match self.entry() { - Some(Entry::Leaf(tt)) => match tt { - TokenTree::Leaf(leaf) => Some(TokenTreeRef::Leaf(leaf, *tt)), - TokenTree::Subtree(subtree) => Some(TokenTreeRef::Subtree(subtree, Some(tt))), - }, - Some(Entry::Subtree(tt, subtree, _)) => Some(TokenTreeRef::Subtree(subtree, *tt)), - Some(Entry::End(_)) | None => None, - } - } - - fn create(buffer: &'a TokenBuffer<'_>, ptr: EntryPtr) -> Cursor<'a> { - Cursor { buffer, ptr } - } - - /// Bump the cursor - pub fn bump(self) -> Cursor<'a> { - if let Some(Entry::End(exit)) = self.buffer.entry(&self.ptr) { - match exit { - Some(exit) => Cursor::create(self.buffer, *exit), - None => self, - } - } else { - Cursor::create(self.buffer, EntryPtr(self.ptr.0, self.ptr.1 + 1)) - } - } - - /// Bump the cursor, if it is a subtree, returns - /// a cursor into that subtree - pub fn bump_subtree(self) -> Cursor<'a> { - match self.entry() { - Some(Entry::Subtree(_, _, _)) => self.subtree().unwrap(), - _ => self.bump(), - } - } - - /// Check whether it is a top level - pub fn is_root(&self) -> bool { - let entry_id = self.ptr.0; - entry_id.0 == 0 - } -} diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs deleted file mode 100644 index a54861de9587b..0000000000000 --- a/src/tools/rust-analyzer/crates/tt/src/lib.rs +++ /dev/null @@ -1,322 +0,0 @@ -//! `tt` crate defines a `TokenTree` data structure: this is the interface (both -//! input and output) of macros. It closely mirrors `proc_macro` crate's -//! `TokenTree`. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -use std::fmt; - -use stdx::impl_from; - -pub use smol_str::SmolStr; - -/// Represents identity of the token. -/// -/// For hygiene purposes, we need to track which expanded tokens originated from -/// which source tokens. We do it by assigning an distinct identity to each -/// source token and making sure that identities are preserved during macro -/// expansion. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct TokenId(pub u32); - -impl TokenId { - pub const fn unspecified() -> TokenId { - TokenId(!0) - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum TokenTree { - Leaf(Leaf), - Subtree(Subtree), -} -impl_from!(Leaf, Subtree for TokenTree); - -impl TokenTree { - pub fn empty() -> Self { - TokenTree::Subtree(Subtree::default()) - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum Leaf { - Literal(Literal), - Punct(Punct), - Ident(Ident), -} -impl_from!(Literal, Punct, Ident for Leaf); - -#[derive(Clone, PartialEq, Eq, Hash, Default)] -pub struct Subtree { - pub delimiter: Option, - pub token_trees: Vec, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct Delimiter { - pub id: TokenId, - pub kind: DelimiterKind, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum DelimiterKind { - Parenthesis, - Brace, - Bracket, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Literal { - pub text: SmolStr, - pub id: TokenId, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Punct { - pub char: char, - pub spacing: Spacing, - pub id: TokenId, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum Spacing { - Alone, - Joint, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Ident { - pub text: SmolStr, - pub id: TokenId, -} - -impl Leaf { - pub fn id(&self) -> TokenId { - match self { - Leaf::Literal(l) => l.id, - Leaf::Punct(p) => p.id, - Leaf::Ident(i) => i.id, - } - } -} - -fn print_debug_subtree(f: &mut fmt::Formatter<'_>, subtree: &Subtree, level: usize) -> fmt::Result { - let align = " ".repeat(level); - - let aux = match subtree.delimiter.map(|it| (it.kind, it.id.0)) { - None => "$".to_string(), - Some((DelimiterKind::Parenthesis, id)) => format!("() {}", id), - Some((DelimiterKind::Brace, id)) => format!("{{}} {}", id), - Some((DelimiterKind::Bracket, id)) => format!("[] {}", id), - }; - - if subtree.token_trees.is_empty() { - write!(f, "{}SUBTREE {}", align, aux)?; - } else { - writeln!(f, "{}SUBTREE {}", align, aux)?; - for (idx, child) in subtree.token_trees.iter().enumerate() { - print_debug_token(f, child, level + 1)?; - if idx != subtree.token_trees.len() - 1 { - writeln!(f)?; - } - } - } - - Ok(()) -} - -fn print_debug_token(f: &mut fmt::Formatter<'_>, tkn: &TokenTree, level: usize) -> fmt::Result { - let align = " ".repeat(level); - - match tkn { - TokenTree::Leaf(leaf) => match leaf { - Leaf::Literal(lit) => write!(f, "{}LITERAL {} {}", align, lit.text, lit.id.0)?, - Leaf::Punct(punct) => write!( - f, - "{}PUNCH {} [{}] {}", - align, - punct.char, - if punct.spacing == Spacing::Alone { "alone" } else { "joint" }, - punct.id.0 - )?, - Leaf::Ident(ident) => write!(f, "{}IDENT {} {}", align, ident.text, ident.id.0)?, - }, - TokenTree::Subtree(subtree) => { - print_debug_subtree(f, subtree, level)?; - } - } - - Ok(()) -} - -impl fmt::Debug for Subtree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - print_debug_subtree(f, self, 0) - } -} - -impl fmt::Display for TokenTree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - TokenTree::Leaf(it) => fmt::Display::fmt(it, f), - TokenTree::Subtree(it) => fmt::Display::fmt(it, f), - } - } -} - -impl fmt::Display for Subtree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let (l, r) = match self.delimiter_kind() { - Some(DelimiterKind::Parenthesis) => ("(", ")"), - Some(DelimiterKind::Brace) => ("{", "}"), - Some(DelimiterKind::Bracket) => ("[", "]"), - None => ("", ""), - }; - f.write_str(l)?; - let mut needs_space = false; - for tt in &self.token_trees { - if needs_space { - f.write_str(" ")?; - } - needs_space = true; - match tt { - TokenTree::Leaf(Leaf::Punct(p)) => { - needs_space = p.spacing == Spacing::Alone; - fmt::Display::fmt(p, f)?; - } - tt => fmt::Display::fmt(tt, f)?, - } - } - f.write_str(r)?; - Ok(()) - } -} - -impl fmt::Display for Leaf { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Leaf::Ident(it) => fmt::Display::fmt(it, f), - Leaf::Literal(it) => fmt::Display::fmt(it, f), - Leaf::Punct(it) => fmt::Display::fmt(it, f), - } - } -} - -impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.text, f) - } -} - -impl fmt::Display for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.text, f) - } -} - -impl fmt::Display for Punct { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.char, f) - } -} - -impl Subtree { - /// Count the number of tokens recursively - pub fn count(&self) -> usize { - let children_count = self - .token_trees - .iter() - .map(|c| match c { - TokenTree::Subtree(c) => c.count(), - TokenTree::Leaf(_) => 0, - }) - .sum::(); - - self.token_trees.len() + children_count - } - - pub fn delimiter_kind(&self) -> Option { - self.delimiter.map(|it| it.kind) - } -} - -impl Subtree { - /// A simple line string used for debugging - pub fn as_debug_string(&self) -> String { - let delim = match self.delimiter_kind() { - Some(DelimiterKind::Brace) => ("{", "}"), - Some(DelimiterKind::Bracket) => ("[", "]"), - Some(DelimiterKind::Parenthesis) => ("(", ")"), - None => (" ", " "), - }; - - let mut res = String::new(); - res.push_str(delim.0); - let mut last = None; - for child in &self.token_trees { - let s = match child { - TokenTree::Leaf(it) => { - let s = match it { - Leaf::Literal(it) => it.text.to_string(), - Leaf::Punct(it) => it.char.to_string(), - Leaf::Ident(it) => it.text.to_string(), - }; - match (it, last) { - (Leaf::Ident(_), Some(&TokenTree::Leaf(Leaf::Ident(_)))) => { - " ".to_string() + &s - } - (Leaf::Punct(_), Some(&TokenTree::Leaf(Leaf::Punct(punct)))) => { - if punct.spacing == Spacing::Alone { - " ".to_string() + &s - } else { - s - } - } - _ => s, - } - } - TokenTree::Subtree(it) => it.as_debug_string(), - }; - res.push_str(&s); - last = Some(child); - } - - res.push_str(delim.1); - res - } -} - -pub mod buffer; - -pub fn pretty(tkns: &[TokenTree]) -> String { - fn tokentree_to_text(tkn: &TokenTree) -> String { - match tkn { - TokenTree::Leaf(Leaf::Ident(ident)) => ident.text.clone().into(), - TokenTree::Leaf(Leaf::Literal(literal)) => literal.text.clone().into(), - TokenTree::Leaf(Leaf::Punct(punct)) => format!("{}", punct.char), - TokenTree::Subtree(subtree) => { - let content = pretty(&subtree.token_trees); - let (open, close) = match subtree.delimiter.map(|it| it.kind) { - None => ("", ""), - Some(DelimiterKind::Brace) => ("{", "}"), - Some(DelimiterKind::Parenthesis) => ("(", ")"), - Some(DelimiterKind::Bracket) => ("[", "]"), - }; - format!("{}{}{}", open, content, close) - } - } - } - - tkns.iter() - .fold((String::new(), true), |(last, last_to_joint), tkn| { - let s = [last, tokentree_to_text(tkn)].join(if last_to_joint { "" } else { " " }); - let mut is_joint = false; - if let TokenTree::Leaf(Leaf::Punct(punct)) = tkn { - if punct.spacing == Spacing::Joint { - is_joint = true; - } - } - (s, is_joint) - }) - .0 -} diff --git a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml deleted file mode 100644 index 9ee4415dcada0..0000000000000 --- a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "vfs-notify" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -tracing = "0.1.35" -jod-thread = "0.1.2" -walkdir = "2.3.2" -crossbeam-channel = "0.5.5" -notify = "=5.0.0-pre.15" - -vfs = { path = "../vfs", version = "0.0.0" } -paths = { path = "../paths", version = "0.0.0" } diff --git a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs deleted file mode 100644 index 4d33a9afb9635..0000000000000 --- a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs +++ /dev/null @@ -1,234 +0,0 @@ -//! An implementation of `loader::Handle`, based on `walkdir` and `notify`. -//! -//! The file watching bits here are untested and quite probably buggy. For this -//! reason, by default we don't watch files and rely on editor's file watching -//! capabilities. -//! -//! Hopefully, one day a reliable file watching/walking crate appears on -//! crates.io, and we can reduce this to trivial glue code. - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -use std::fs; - -use crossbeam_channel::{never, select, unbounded, Receiver, Sender}; -use notify::{RecommendedWatcher, RecursiveMode, Watcher}; -use paths::{AbsPath, AbsPathBuf}; -use vfs::loader; -use walkdir::WalkDir; - -#[derive(Debug)] -pub struct NotifyHandle { - // Relative order of fields below is significant. - sender: Sender, - _thread: jod_thread::JoinHandle, -} - -#[derive(Debug)] -enum Message { - Config(loader::Config), - Invalidate(AbsPathBuf), -} - -impl loader::Handle for NotifyHandle { - fn spawn(sender: loader::Sender) -> NotifyHandle { - let actor = NotifyActor::new(sender); - let (sender, receiver) = unbounded::(); - let thread = jod_thread::Builder::new() - .name("VfsLoader".to_owned()) - .spawn(move || actor.run(receiver)) - .expect("failed to spawn thread"); - NotifyHandle { sender, _thread: thread } - } - fn set_config(&mut self, config: loader::Config) { - self.sender.send(Message::Config(config)).unwrap(); - } - fn invalidate(&mut self, path: AbsPathBuf) { - self.sender.send(Message::Invalidate(path)).unwrap(); - } - fn load_sync(&mut self, path: &AbsPath) -> Option> { - read(path) - } -} - -type NotifyEvent = notify::Result; - -struct NotifyActor { - sender: loader::Sender, - watched_entries: Vec, - // Drop order is significant. - watcher: Option<(RecommendedWatcher, Receiver)>, -} - -#[derive(Debug)] -enum Event { - Message(Message), - NotifyEvent(NotifyEvent), -} - -impl NotifyActor { - fn new(sender: loader::Sender) -> NotifyActor { - NotifyActor { sender, watched_entries: Vec::new(), watcher: None } - } - fn next_event(&self, receiver: &Receiver) -> Option { - let watcher_receiver = self.watcher.as_ref().map(|(_, receiver)| receiver); - select! { - recv(receiver) -> it => it.ok().map(Event::Message), - recv(watcher_receiver.unwrap_or(&never())) -> it => Some(Event::NotifyEvent(it.unwrap())), - } - } - fn run(mut self, inbox: Receiver) { - while let Some(event) = self.next_event(&inbox) { - tracing::debug!("vfs-notify event: {:?}", event); - match event { - Event::Message(msg) => match msg { - Message::Config(config) => { - self.watcher = None; - if !config.watch.is_empty() { - let (watcher_sender, watcher_receiver) = unbounded(); - let watcher = log_notify_error(RecommendedWatcher::new(move |event| { - watcher_sender.send(event).unwrap(); - })); - self.watcher = watcher.map(|it| (it, watcher_receiver)); - } - - let config_version = config.version; - - let n_total = config.load.len(); - self.send(loader::Message::Progress { n_total, n_done: 0, config_version }); - - self.watched_entries.clear(); - - for (i, entry) in config.load.into_iter().enumerate() { - let watch = config.watch.contains(&i); - if watch { - self.watched_entries.push(entry.clone()); - } - let files = self.load_entry(entry, watch); - self.send(loader::Message::Loaded { files }); - self.send(loader::Message::Progress { - n_total, - n_done: i + 1, - config_version, - }); - } - } - Message::Invalidate(path) => { - let contents = read(path.as_path()); - let files = vec![(path, contents)]; - self.send(loader::Message::Loaded { files }); - } - }, - Event::NotifyEvent(event) => { - if let Some(event) = log_notify_error(event) { - let files = event - .paths - .into_iter() - .map(|path| AbsPathBuf::try_from(path).unwrap()) - .filter_map(|path| { - let meta = fs::metadata(&path).ok()?; - if meta.file_type().is_dir() - && self - .watched_entries - .iter() - .any(|entry| entry.contains_dir(&path)) - { - self.watch(path); - return None; - } - - if !meta.file_type().is_file() { - return None; - } - if !self - .watched_entries - .iter() - .any(|entry| entry.contains_file(&path)) - { - return None; - } - - let contents = read(&path); - Some((path, contents)) - }) - .collect(); - self.send(loader::Message::Loaded { files }); - } - } - } - } - } - fn load_entry( - &mut self, - entry: loader::Entry, - watch: bool, - ) -> Vec<(AbsPathBuf, Option>)> { - match entry { - loader::Entry::Files(files) => files - .into_iter() - .map(|file| { - if watch { - self.watch(file.clone()); - } - let contents = read(file.as_path()); - (file, contents) - }) - .collect::>(), - loader::Entry::Directories(dirs) => { - let mut res = Vec::new(); - - for root in &dirs.include { - let walkdir = - WalkDir::new(root).follow_links(true).into_iter().filter_entry(|entry| { - if !entry.file_type().is_dir() { - return true; - } - let path = AbsPath::assert(entry.path()); - root == path - || dirs.exclude.iter().chain(&dirs.include).all(|it| it != path) - }); - - let files = walkdir.filter_map(|it| it.ok()).filter_map(|entry| { - let is_dir = entry.file_type().is_dir(); - let is_file = entry.file_type().is_file(); - let abs_path = AbsPathBuf::assert(entry.into_path()); - if is_dir && watch { - self.watch(abs_path.clone()); - } - if !is_file { - return None; - } - let ext = abs_path.extension().unwrap_or_default(); - if dirs.extensions.iter().all(|it| it.as_str() != ext) { - return None; - } - Some(abs_path) - }); - - res.extend(files.map(|file| { - let contents = read(file.as_path()); - (file, contents) - })); - } - res - } - } - } - - fn watch(&mut self, path: AbsPathBuf) { - if let Some((watcher, _)) = &mut self.watcher { - log_notify_error(watcher.watch(path.as_ref(), RecursiveMode::NonRecursive)); - } - } - fn send(&mut self, msg: loader::Message) { - (self.sender)(msg); - } -} - -fn read(path: &AbsPath) -> Option> { - std::fs::read(path).ok() -} - -fn log_notify_error(res: notify::Result) -> Option { - res.map_err(|err| tracing::warn!("notify error: {}", err)).ok() -} diff --git a/src/tools/rust-analyzer/crates/vfs/Cargo.toml b/src/tools/rust-analyzer/crates/vfs/Cargo.toml deleted file mode 100644 index c6377348784a4..0000000000000 --- a/src/tools/rust-analyzer/crates/vfs/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "vfs" -version = "0.0.0" -description = "TBD" -license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.57" - -[lib] -doctest = false - -[dependencies] -rustc-hash = "1.1.0" -fst = "0.4.7" - -paths = { path = "../paths", version = "0.0.0" } -indexmap = "1.9.1" diff --git a/src/tools/rust-analyzer/crates/vfs/src/anchored_path.rs b/src/tools/rust-analyzer/crates/vfs/src/anchored_path.rs deleted file mode 100644 index db15a2a21cd6e..0000000000000 --- a/src/tools/rust-analyzer/crates/vfs/src/anchored_path.rs +++ /dev/null @@ -1,49 +0,0 @@ -//! Analysis-level representation of file-system paths. -//! -//! The primary goal of this is to losslessly represent paths like -//! -//! ``` -//! #[path = "./bar.rs"] -//! mod foo; -//! ``` -//! -//! The first approach one might reach for is to use `PathBuf`. The problem here -//! is that `PathBuf` depends on host target (windows or linux), but -//! rust-analyzer should be capable to process `#[path = r"C:\bar.rs"]` on Unix. -//! -//! The second try is to use a `String`. This also fails, however. Consider a -//! hypothetical scenario, where rust-analyzer operates in a -//! networked/distributed mode. There's one global instance of rust-analyzer, -//! which processes requests from different machines. Now, the semantics of -//! `#[path = "/abs/path.rs"]` actually depends on which file-system we are at! -//! That is, even absolute paths exist relative to a file system! -//! -//! A more realistic scenario here is virtual VFS paths we use for testing. More -//! generally, there can be separate "universes" of VFS paths. -//! -//! That's why we use anchored representation -- each path carries an info about -//! a file this path originates from. We can fetch fs/"universe" information -//! from the anchor than. -use crate::FileId; - -/// Path relative to a file. -/// -/// Owned version of [`AnchoredPath`]. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct AnchoredPathBuf { - /// File that this path is relative to. - pub anchor: FileId, - /// Path relative to `anchor`'s containing directory. - pub path: String, -} - -/// Path relative to a file. -/// -/// Borrowed version of [`AnchoredPathBuf`]. -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct AnchoredPath<'a> { - /// File that this path is relative to. - pub anchor: FileId, - /// Path relative to `anchor`'s containing directory. - pub path: &'a str, -} diff --git a/src/tools/rust-analyzer/crates/vfs/src/file_set.rs b/src/tools/rust-analyzer/crates/vfs/src/file_set.rs deleted file mode 100644 index 6a89263e53988..0000000000000 --- a/src/tools/rust-analyzer/crates/vfs/src/file_set.rs +++ /dev/null @@ -1,218 +0,0 @@ -//! Partitions a list of files into disjoint subsets. -//! -//! Files which do not belong to any explicitly configured `FileSet` belong to -//! the default `FileSet`. -use std::fmt; - -use fst::{IntoStreamer, Streamer}; -use rustc_hash::FxHashMap; - -use crate::{AnchoredPath, FileId, Vfs, VfsPath}; - -/// A set of [`VfsPath`]s identified by [`FileId`]s. -#[derive(Default, Clone, Eq, PartialEq)] -pub struct FileSet { - files: FxHashMap, - paths: FxHashMap, -} - -impl FileSet { - /// Returns the number of stored paths. - pub fn len(&self) -> usize { - self.files.len() - } - - /// Get the id of the file corresponding to `path`. - /// - /// If either `path`'s [`anchor`](AnchoredPath::anchor) or the resolved path is not in - /// the set, returns [`None`]. - pub fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { - let mut base = self.paths[&path.anchor].clone(); - base.pop(); - let path = base.join(path.path)?; - self.files.get(&path).copied() - } - - /// Get the id corresponding to `path` if it exists in the set. - pub fn file_for_path(&self, path: &VfsPath) -> Option<&FileId> { - self.files.get(path) - } - - /// Get the path corresponding to `file` if it exists in the set. - pub fn path_for_file(&self, file: &FileId) -> Option<&VfsPath> { - self.paths.get(file) - } - - /// Insert the `file_id, path` pair into the set. - /// - /// # Note - /// Multiple [`FileId`] can be mapped to the same [`VfsPath`], and vice-versa. - pub fn insert(&mut self, file_id: FileId, path: VfsPath) { - self.files.insert(path.clone(), file_id); - self.paths.insert(file_id, path); - } - - /// Iterate over this set's ids. - pub fn iter(&self) -> impl Iterator + '_ { - self.paths.keys().copied() - } -} - -impl fmt::Debug for FileSet { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("FileSet").field("n_files", &self.files.len()).finish() - } -} - -/// This contains path prefixes to partition a [`Vfs`] into [`FileSet`]s. -/// -/// # Example -/// ```rust -/// # use vfs::{file_set::FileSetConfigBuilder, VfsPath, Vfs}; -/// let mut builder = FileSetConfigBuilder::default(); -/// builder.add_file_set(vec![VfsPath::new_virtual_path("/src".to_string())]); -/// let config = builder.build(); -/// let mut file_system = Vfs::default(); -/// file_system.set_file_contents(VfsPath::new_virtual_path("/src/main.rs".to_string()), Some(vec![])); -/// file_system.set_file_contents(VfsPath::new_virtual_path("/src/lib.rs".to_string()), Some(vec![])); -/// file_system.set_file_contents(VfsPath::new_virtual_path("/build.rs".to_string()), Some(vec![])); -/// // contains the sets : -/// // { "/src/main.rs", "/src/lib.rs" } -/// // { "build.rs" } -/// let sets = config.partition(&file_system); -/// ``` -#[derive(Debug)] -pub struct FileSetConfig { - /// Number of sets that `self` can partition a [`Vfs`] into. - /// - /// This should be the number of sets in `self.map` + 1 for files that don't fit in any - /// defined set. - n_file_sets: usize, - /// Map from encoded paths to the set they belong to. - map: fst::Map>, -} - -impl Default for FileSetConfig { - fn default() -> Self { - FileSetConfig::builder().build() - } -} - -impl FileSetConfig { - /// Returns a builder for `FileSetConfig`. - pub fn builder() -> FileSetConfigBuilder { - FileSetConfigBuilder::default() - } - - /// Partition `vfs` into `FileSet`s. - /// - /// Creates a new [`FileSet`] for every set of prefixes in `self`. - pub fn partition(&self, vfs: &Vfs) -> Vec { - let mut scratch_space = Vec::new(); - let mut res = vec![FileSet::default(); self.len()]; - for (file_id, path) in vfs.iter() { - let root = self.classify(path, &mut scratch_space); - res[root].insert(file_id, path.clone()); - } - res - } - - /// Number of sets that `self` can partition a [`Vfs`] into. - fn len(&self) -> usize { - self.n_file_sets - } - - /// Returns the set index for the given `path`. - /// - /// `scratch_space` is used as a buffer and will be entirely replaced. - fn classify(&self, path: &VfsPath, scratch_space: &mut Vec) -> usize { - scratch_space.clear(); - path.encode(scratch_space); - let automaton = PrefixOf::new(scratch_space.as_slice()); - let mut longest_prefix = self.len() - 1; - let mut stream = self.map.search(automaton).into_stream(); - while let Some((_, v)) = stream.next() { - longest_prefix = v as usize; - } - longest_prefix - } -} - -/// Builder for [`FileSetConfig`]. -pub struct FileSetConfigBuilder { - roots: Vec>, -} - -impl Default for FileSetConfigBuilder { - fn default() -> Self { - FileSetConfigBuilder { roots: Vec::new() } - } -} - -impl FileSetConfigBuilder { - /// Returns the number of sets currently held. - pub fn len(&self) -> usize { - self.roots.len() - } - - /// Add a new set of paths prefixes. - pub fn add_file_set(&mut self, roots: Vec) { - self.roots.push(roots); - } - - /// Build the `FileSetConfig`. - pub fn build(self) -> FileSetConfig { - let n_file_sets = self.roots.len() + 1; - let map = { - let mut entries = Vec::new(); - for (i, paths) in self.roots.into_iter().enumerate() { - for p in paths { - let mut buf = Vec::new(); - p.encode(&mut buf); - entries.push((buf, i as u64)); - } - } - entries.sort(); - entries.dedup_by(|(a, _), (b, _)| a == b); - fst::Map::from_iter(entries).unwrap() - }; - FileSetConfig { n_file_sets, map } - } -} - -/// Implements [`fst::Automaton`] -/// -/// It will match if `prefix_of` is a prefix of the given data. -struct PrefixOf<'a> { - prefix_of: &'a [u8], -} - -impl<'a> PrefixOf<'a> { - /// Creates a new `PrefixOf` from the given slice. - fn new(prefix_of: &'a [u8]) -> Self { - Self { prefix_of } - } -} - -impl fst::Automaton for PrefixOf<'_> { - type State = usize; - fn start(&self) -> usize { - 0 - } - fn is_match(&self, &state: &usize) -> bool { - state != !0 - } - fn can_match(&self, &state: &usize) -> bool { - state != !0 - } - fn accept(&self, &state: &usize, byte: u8) -> usize { - if self.prefix_of.get(state) == Some(&byte) { - state + 1 - } else { - !0 - } - } -} - -#[cfg(test)] -mod tests; diff --git a/src/tools/rust-analyzer/crates/vfs/src/file_set/tests.rs b/src/tools/rust-analyzer/crates/vfs/src/file_set/tests.rs deleted file mode 100644 index 2146df185d3a7..0000000000000 --- a/src/tools/rust-analyzer/crates/vfs/src/file_set/tests.rs +++ /dev/null @@ -1,42 +0,0 @@ -use super::*; - -#[test] -fn path_prefix() { - let mut file_set = FileSetConfig::builder(); - file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo".into())]); - file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo/bar/baz".into())]); - let file_set = file_set.build(); - - let mut vfs = Vfs::default(); - vfs.set_file_contents(VfsPath::new_virtual_path("/foo/src/lib.rs".into()), Some(Vec::new())); - vfs.set_file_contents( - VfsPath::new_virtual_path("/foo/src/bar/baz/lib.rs".into()), - Some(Vec::new()), - ); - vfs.set_file_contents( - VfsPath::new_virtual_path("/foo/bar/baz/lib.rs".into()), - Some(Vec::new()), - ); - vfs.set_file_contents(VfsPath::new_virtual_path("/quux/lib.rs".into()), Some(Vec::new())); - - let partition = file_set.partition(&vfs).into_iter().map(|it| it.len()).collect::>(); - assert_eq!(partition, vec![2, 1, 1]); -} - -#[test] -fn name_prefix() { - let mut file_set = FileSetConfig::builder(); - file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo".into())]); - file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo-things".into())]); - let file_set = file_set.build(); - - let mut vfs = Vfs::default(); - vfs.set_file_contents(VfsPath::new_virtual_path("/foo/src/lib.rs".into()), Some(Vec::new())); - vfs.set_file_contents( - VfsPath::new_virtual_path("/foo-things/src/lib.rs".into()), - Some(Vec::new()), - ); - - let partition = file_set.partition(&vfs).into_iter().map(|it| it.len()).collect::>(); - assert_eq!(partition, vec![1, 1, 0]); -} diff --git a/src/tools/rust-analyzer/crates/vfs/src/lib.rs b/src/tools/rust-analyzer/crates/vfs/src/lib.rs deleted file mode 100644 index 10fae41d081c7..0000000000000 --- a/src/tools/rust-analyzer/crates/vfs/src/lib.rs +++ /dev/null @@ -1,221 +0,0 @@ -//! # Virtual File System -//! -//! VFS stores all files read by rust-analyzer. Reading file contents from VFS -//! always returns the same contents, unless VFS was explicitly modified with -//! [`set_file_contents`]. All changes to VFS are logged, and can be retrieved via -//! [`take_changes`] method. The pack of changes is then pushed to `salsa` and -//! triggers incremental recomputation. -//! -//! Files in VFS are identified with [`FileId`]s -- interned paths. The notion of -//! the path, [`VfsPath`] is somewhat abstract: at the moment, it is represented -//! as an [`std::path::PathBuf`] internally, but this is an implementation detail. -//! -//! VFS doesn't do IO or file watching itself. For that, see the [`loader`] -//! module. [`loader::Handle`] is an object-safe trait which abstracts both file -//! loading and file watching. [`Handle`] is dynamically configured with a set of -//! directory entries which should be scanned and watched. [`Handle`] then -//! asynchronously pushes file changes. Directory entries are configured in -//! free-form via list of globs, it's up to the [`Handle`] to interpret the globs -//! in any specific way. -//! -//! VFS stores a flat list of files. [`file_set::FileSet`] can partition this list -//! of files into disjoint sets of files. Traversal-like operations (including -//! getting the neighbor file by the relative path) are handled by the [`FileSet`]. -//! [`FileSet`]s are also pushed to salsa and cause it to re-check `mod foo;` -//! declarations when files are created or deleted. -//! -//! [`FileSet`] and [`loader::Entry`] play similar, but different roles. -//! Both specify the "set of paths/files", one is geared towards file watching, -//! the other towards salsa changes. In particular, single [`FileSet`] -//! may correspond to several [`loader::Entry`]. For example, a crate from -//! crates.io which uses code generation would have two [`Entries`] -- for sources -//! in `~/.cargo`, and for generated code in `./target/debug/build`. It will -//! have a single [`FileSet`] which unions the two sources. -//! -//! [`set_file_contents`]: Vfs::set_file_contents -//! [`take_changes`]: Vfs::take_changes -//! [`FileSet`]: file_set::FileSet -//! [`Handle`]: loader::Handle -//! [`Entries`]: loader::Entry - -#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] - -mod anchored_path; -pub mod file_set; -pub mod loader; -mod path_interner; -mod vfs_path; - -use std::{fmt, mem}; - -use crate::path_interner::PathInterner; - -pub use crate::{ - anchored_path::{AnchoredPath, AnchoredPathBuf}, - vfs_path::VfsPath, -}; -pub use paths::{AbsPath, AbsPathBuf}; - -/// Handle to a file in [`Vfs`] -/// -/// Most functions in rust-analyzer use this when they need to refer to a file. -#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct FileId(pub u32); - -/// Storage for all files read by rust-analyzer. -/// -/// For more informations see the [crate-level](crate) documentation. -#[derive(Default)] -pub struct Vfs { - interner: PathInterner, - data: Vec>>, - changes: Vec, -} - -/// Changed file in the [`Vfs`]. -pub struct ChangedFile { - /// Id of the changed file - pub file_id: FileId, - /// Kind of change - pub change_kind: ChangeKind, -} - -impl ChangedFile { - /// Returns `true` if the change is not [`Delete`](ChangeKind::Delete). - pub fn exists(&self) -> bool { - self.change_kind != ChangeKind::Delete - } - - /// Returns `true` if the change is [`Create`](ChangeKind::Create) or - /// [`Delete`](ChangeKind::Delete). - pub fn is_created_or_deleted(&self) -> bool { - matches!(self.change_kind, ChangeKind::Create | ChangeKind::Delete) - } -} - -/// Kind of [file change](ChangedFile). -#[derive(Eq, PartialEq, Copy, Clone, Debug)] -pub enum ChangeKind { - /// The file was (re-)created - Create, - /// The file was modified - Modify, - /// The file was deleted - Delete, -} - -impl Vfs { - /// Amount of files currently stored. - /// - /// Note that this includes deleted files. - pub fn len(&self) -> usize { - self.data.len() - } - - /// Id of the given path if it exists in the `Vfs` and is not deleted. - pub fn file_id(&self, path: &VfsPath) -> Option { - self.interner.get(path).filter(|&it| self.get(it).is_some()) - } - - /// File path corresponding to the given `file_id`. - /// - /// # Panics - /// - /// Panics if the id is not present in the `Vfs`. - pub fn file_path(&self, file_id: FileId) -> VfsPath { - self.interner.lookup(file_id).clone() - } - - /// File content corresponding to the given `file_id`. - /// - /// # Panics - /// - /// Panics if the id is not present in the `Vfs`, or if the corresponding file is - /// deleted. - pub fn file_contents(&self, file_id: FileId) -> &[u8] { - self.get(file_id).as_deref().unwrap() - } - - /// Returns an iterator over the stored ids and their corresponding paths. - /// - /// This will skip deleted files. - pub fn iter(&self) -> impl Iterator + '_ { - (0..self.data.len()) - .map(|it| FileId(it as u32)) - .filter(move |&file_id| self.get(file_id).is_some()) - .map(move |file_id| { - let path = self.interner.lookup(file_id); - (file_id, path) - }) - } - - /// Update the `path` with the given `contents`. `None` means the file was deleted. - /// - /// Returns `true` if the file was modified, and saves the [change](ChangedFile). - /// - /// If the path does not currently exists in the `Vfs`, allocates a new - /// [`FileId`] for it. - pub fn set_file_contents(&mut self, path: VfsPath, contents: Option>) -> bool { - let file_id = self.alloc_file_id(path); - let change_kind = match (&self.get(file_id), &contents) { - (None, None) => return false, - (None, Some(_)) => ChangeKind::Create, - (Some(_), None) => ChangeKind::Delete, - (Some(old), Some(new)) if old == new => return false, - (Some(_), Some(_)) => ChangeKind::Modify, - }; - - *self.get_mut(file_id) = contents; - self.changes.push(ChangedFile { file_id, change_kind }); - true - } - - /// Returns `true` if the `Vfs` contains [changes](ChangedFile). - pub fn has_changes(&self) -> bool { - !self.changes.is_empty() - } - - /// Drain and returns all the changes in the `Vfs`. - pub fn take_changes(&mut self) -> Vec { - mem::take(&mut self.changes) - } - - /// Returns the id associated with `path` - /// - /// - If `path` does not exists in the `Vfs`, allocate a new id for it, associated with a - /// deleted file; - /// - Else, returns `path`'s id. - /// - /// Does not record a change. - fn alloc_file_id(&mut self, path: VfsPath) -> FileId { - let file_id = self.interner.intern(path); - let idx = file_id.0 as usize; - let len = self.data.len().max(idx + 1); - self.data.resize_with(len, || None); - file_id - } - - /// Returns the content associated with the given `file_id`. - /// - /// # Panics - /// - /// Panics if no file is associated to that id. - fn get(&self, file_id: FileId) -> &Option> { - &self.data[file_id.0 as usize] - } - - /// Mutably returns the content associated with the given `file_id`. - /// - /// # Panics - /// - /// Panics if no file is associated to that id. - fn get_mut(&mut self, file_id: FileId) -> &mut Option> { - &mut self.data[file_id.0 as usize] - } -} - -impl fmt::Debug for Vfs { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Vfs").field("n_files", &self.data.len()).finish() - } -} diff --git a/src/tools/rust-analyzer/crates/vfs/src/loader.rs b/src/tools/rust-analyzer/crates/vfs/src/loader.rs deleted file mode 100644 index e2d74782ae526..0000000000000 --- a/src/tools/rust-analyzer/crates/vfs/src/loader.rs +++ /dev/null @@ -1,215 +0,0 @@ -//! Object safe interface for file watching and reading. -use std::fmt; - -use paths::{AbsPath, AbsPathBuf}; - -/// A set of files on the file system. -#[derive(Debug, Clone)] -pub enum Entry { - /// The `Entry` is represented by a raw set of files. - Files(Vec), - /// The `Entry` is represented by `Directories`. - Directories(Directories), -} - -/// Specifies a set of files on the file system. -/// -/// A file is included if: -/// * it has included extension -/// * it is under an `include` path -/// * it is not under `exclude` path -/// -/// If many include/exclude paths match, the longest one wins. -/// -/// If a path is in both `include` and `exclude`, the `exclude` one wins. -#[derive(Debug, Clone, Default)] -pub struct Directories { - pub extensions: Vec, - pub include: Vec, - pub exclude: Vec, -} - -/// [`Handle`]'s configuration. -#[derive(Debug)] -pub struct Config { - /// Version number to associate progress updates to the right config - /// version. - pub version: u32, - /// Set of initially loaded files. - pub load: Vec, - /// Index of watched entries in `load`. - /// - /// If a path in a watched entry is modified,the [`Handle`] should notify it. - pub watch: Vec, -} - -/// Message about an action taken by a [`Handle`]. -pub enum Message { - /// Indicate a gradual progress. - /// - /// This is supposed to be the number of loaded files. - Progress { n_total: usize, n_done: usize, config_version: u32 }, - /// The handle loaded the following files' content. - Loaded { files: Vec<(AbsPathBuf, Option>)> }, -} - -/// Type that will receive [`Messages`](Message) from a [`Handle`]. -pub type Sender = Box; - -/// Interface for reading and watching files. -pub trait Handle: fmt::Debug { - /// Spawn a new handle with the given `sender`. - fn spawn(sender: Sender) -> Self - where - Self: Sized; - - /// Set this handle's configuration. - fn set_config(&mut self, config: Config); - - /// The file's content at `path` has been modified, and should be reloaded. - fn invalidate(&mut self, path: AbsPathBuf); - - /// Load the content of the given file, returning [`None`] if it does not - /// exists. - fn load_sync(&mut self, path: &AbsPath) -> Option>; -} - -impl Entry { - /// Returns: - /// ```text - /// Entry::Directories(Directories { - /// extensions: ["rs"], - /// include: [base], - /// exclude: [base/.git], - /// }) - /// ``` - pub fn rs_files_recursively(base: AbsPathBuf) -> Entry { - Entry::Directories(dirs(base, &[".git"])) - } - - /// Returns: - /// ```text - /// Entry::Directories(Directories { - /// extensions: ["rs"], - /// include: [base], - /// exclude: [base/.git, base/target], - /// }) - /// ``` - pub fn local_cargo_package(base: AbsPathBuf) -> Entry { - Entry::Directories(dirs(base, &[".git", "target"])) - } - - /// Returns: - /// ```text - /// Entry::Directories(Directories { - /// extensions: ["rs"], - /// include: [base], - /// exclude: [base/.git, /tests, /examples, /benches], - /// }) - /// ``` - pub fn cargo_package_dependency(base: AbsPathBuf) -> Entry { - Entry::Directories(dirs(base, &[".git", "/tests", "/examples", "/benches"])) - } - - /// Returns `true` if `path` is included in `self`. - /// - /// See [`Directories::contains_file`]. - pub fn contains_file(&self, path: &AbsPath) -> bool { - match self { - Entry::Files(files) => files.iter().any(|it| it == path), - Entry::Directories(dirs) => dirs.contains_file(path), - } - } - - /// Returns `true` if `path` is included in `self`. - /// - /// - If `self` is `Entry::Files`, returns `false` - /// - Else, see [`Directories::contains_dir`]. - pub fn contains_dir(&self, path: &AbsPath) -> bool { - match self { - Entry::Files(_) => false, - Entry::Directories(dirs) => dirs.contains_dir(path), - } - } -} - -impl Directories { - /// Returns `true` if `path` is included in `self`. - pub fn contains_file(&self, path: &AbsPath) -> bool { - // First, check the file extension... - let ext = path.extension().unwrap_or_default(); - if self.extensions.iter().all(|it| it.as_str() != ext) { - return false; - } - - // Then, check for path inclusion... - self.includes_path(path) - } - - /// Returns `true` if `path` is included in `self`. - /// - /// Since `path` is supposed to be a directory, this will not take extension - /// into account. - pub fn contains_dir(&self, path: &AbsPath) -> bool { - self.includes_path(path) - } - - /// Returns `true` if `path` is included in `self`. - /// - /// It is included if - /// - An element in `self.include` is a prefix of `path`. - /// - This path is longer than any element in `self.exclude` that is a prefix - /// of `path`. In case of equality, exclusion wins. - fn includes_path(&self, path: &AbsPath) -> bool { - let mut include: Option<&AbsPathBuf> = None; - for incl in &self.include { - if path.starts_with(incl) { - include = Some(match include { - Some(prev) if prev.starts_with(incl) => prev, - _ => incl, - }); - } - } - - let include = match include { - Some(it) => it, - None => return false, - }; - - !self.exclude.iter().any(|excl| path.starts_with(excl) && excl.starts_with(include)) - } -} - -/// Returns : -/// ```text -/// Directories { -/// extensions: ["rs"], -/// include: [base], -/// exclude: [base/], -/// } -/// ``` -fn dirs(base: AbsPathBuf, exclude: &[&str]) -> Directories { - let exclude = exclude.iter().map(|it| base.join(it)).collect::>(); - Directories { extensions: vec!["rs".to_string()], include: vec![base], exclude } -} - -impl fmt::Debug for Message { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Message::Loaded { files } => { - f.debug_struct("Loaded").field("n_files", &files.len()).finish() - } - Message::Progress { n_total, n_done, config_version } => f - .debug_struct("Progress") - .field("n_total", n_total) - .field("n_done", n_done) - .field("config_version", config_version) - .finish(), - } - } -} - -#[test] -fn handle_is_object_safe() { - fn _assert(_: &dyn Handle) {} -} diff --git a/src/tools/rust-analyzer/crates/vfs/src/path_interner.rs b/src/tools/rust-analyzer/crates/vfs/src/path_interner.rs deleted file mode 100644 index 6e049f0d40f73..0000000000000 --- a/src/tools/rust-analyzer/crates/vfs/src/path_interner.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! Maps paths to compact integer ids. We don't care about clearings paths which -//! no longer exist -- the assumption is total size of paths we ever look at is -//! not too big. -use std::hash::BuildHasherDefault; - -use indexmap::IndexSet; -use rustc_hash::FxHasher; - -use crate::{FileId, VfsPath}; - -/// Structure to map between [`VfsPath`] and [`FileId`]. -pub(crate) struct PathInterner { - map: IndexSet>, -} - -impl Default for PathInterner { - fn default() -> Self { - Self { map: IndexSet::default() } - } -} - -impl PathInterner { - /// Get the id corresponding to `path`. - /// - /// If `path` does not exists in `self`, returns [`None`]. - pub(crate) fn get(&self, path: &VfsPath) -> Option { - self.map.get_index_of(path).map(|i| FileId(i as u32)) - } - - /// Insert `path` in `self`. - /// - /// - If `path` already exists in `self`, returns its associated id; - /// - Else, returns a newly allocated id. - pub(crate) fn intern(&mut self, path: VfsPath) -> FileId { - let (id, _added) = self.map.insert_full(path); - assert!(id < u32::MAX as usize); - FileId(id as u32) - } - - /// Returns the path corresponding to `id`. - /// - /// # Panics - /// - /// Panics if `id` does not exists in `self`. - pub(crate) fn lookup(&self, id: FileId) -> &VfsPath { - self.map.get_index(id.0 as usize).unwrap() - } -} diff --git a/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs b/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs deleted file mode 100644 index 668c7320d4ec2..0000000000000 --- a/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs +++ /dev/null @@ -1,406 +0,0 @@ -//! Abstract-ish representation of paths for VFS. -use std::fmt; - -use paths::{AbsPath, AbsPathBuf}; - -/// Path in [`Vfs`]. -/// -/// Long-term, we want to support files which do not reside in the file-system, -/// so we treat `VfsPath`s as opaque identifiers. -/// -/// [`Vfs`]: crate::Vfs -#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct VfsPath(VfsPathRepr); - -impl VfsPath { - /// Creates an "in-memory" path from `/`-separated string. - /// - /// This is most useful for testing, to avoid windows/linux differences - /// - /// # Panics - /// - /// Panics if `path` does not start with `'/'`. - pub fn new_virtual_path(path: String) -> VfsPath { - assert!(path.starts_with('/')); - VfsPath(VfsPathRepr::VirtualPath(VirtualPath(path))) - } - - /// Create a path from string. Input should be a string representation of - /// an absolute path inside filesystem - pub fn new_real_path(path: String) -> VfsPath { - VfsPath::from(AbsPathBuf::assert(path.into())) - } - - /// Returns the `AbsPath` representation of `self` if `self` is on the file system. - pub fn as_path(&self) -> Option<&AbsPath> { - match &self.0 { - VfsPathRepr::PathBuf(it) => Some(it.as_path()), - VfsPathRepr::VirtualPath(_) => None, - } - } - - /// Creates a new `VfsPath` with `path` adjoined to `self`. - pub fn join(&self, path: &str) -> Option { - match &self.0 { - VfsPathRepr::PathBuf(it) => { - let res = it.join(path).normalize(); - Some(VfsPath(VfsPathRepr::PathBuf(res))) - } - VfsPathRepr::VirtualPath(it) => { - let res = it.join(path)?; - Some(VfsPath(VfsPathRepr::VirtualPath(res))) - } - } - } - - /// Remove the last component of `self` if there is one. - /// - /// If `self` has no component, returns `false`; else returns `true`. - /// - /// # Example - /// - /// ``` - /// # use vfs::{AbsPathBuf, VfsPath}; - /// let mut path = VfsPath::from(AbsPathBuf::assert("/foo/bar".into())); - /// assert!(path.pop()); - /// assert_eq!(path, VfsPath::from(AbsPathBuf::assert("/foo".into()))); - /// assert!(path.pop()); - /// assert_eq!(path, VfsPath::from(AbsPathBuf::assert("/".into()))); - /// assert!(!path.pop()); - /// ``` - pub fn pop(&mut self) -> bool { - match &mut self.0 { - VfsPathRepr::PathBuf(it) => it.pop(), - VfsPathRepr::VirtualPath(it) => it.pop(), - } - } - - /// Returns `true` if `other` is a prefix of `self`. - pub fn starts_with(&self, other: &VfsPath) -> bool { - match (&self.0, &other.0) { - (VfsPathRepr::PathBuf(lhs), VfsPathRepr::PathBuf(rhs)) => lhs.starts_with(rhs), - (VfsPathRepr::VirtualPath(lhs), VfsPathRepr::VirtualPath(rhs)) => lhs.starts_with(rhs), - (VfsPathRepr::PathBuf(_) | VfsPathRepr::VirtualPath(_), _) => false, - } - } - - /// Returns the `VfsPath` without its final component, if there is one. - /// - /// Returns [`None`] if the path is a root or prefix. - pub fn parent(&self) -> Option { - let mut parent = self.clone(); - if parent.pop() { - Some(parent) - } else { - None - } - } - - /// Returns `self`'s base name and file extension. - pub fn name_and_extension(&self) -> Option<(&str, Option<&str>)> { - match &self.0 { - VfsPathRepr::PathBuf(p) => Some(( - p.file_stem()?.to_str()?, - p.extension().and_then(|extension| extension.to_str()), - )), - VfsPathRepr::VirtualPath(p) => p.name_and_extension(), - } - } - - /// **Don't make this `pub`** - /// - /// Encode the path in the given buffer. - /// - /// The encoding will be `0` if [`AbsPathBuf`], `1` if [`VirtualPath`], followed - /// by `self`'s representation. - /// - /// Note that this encoding is dependent on the operating system. - pub(crate) fn encode(&self, buf: &mut Vec) { - let tag = match &self.0 { - VfsPathRepr::PathBuf(_) => 0, - VfsPathRepr::VirtualPath(_) => 1, - }; - buf.push(tag); - match &self.0 { - VfsPathRepr::PathBuf(path) => { - #[cfg(windows)] - { - use windows_paths::Encode; - let path: &std::path::Path = path.as_ref(); - let components = path.components(); - let mut add_sep = false; - for component in components { - if add_sep { - windows_paths::SEP.encode(buf); - } - let len_before = buf.len(); - match component { - std::path::Component::Prefix(prefix) => { - // kind() returns a normalized and comparable path prefix. - prefix.kind().encode(buf); - } - std::path::Component::RootDir => { - if !add_sep { - component.as_os_str().encode(buf); - } - } - _ => component.as_os_str().encode(buf), - } - - // some components may be encoded empty - add_sep = len_before != buf.len(); - } - } - #[cfg(unix)] - { - use std::os::unix::ffi::OsStrExt; - buf.extend(path.as_os_str().as_bytes()); - } - #[cfg(not(any(windows, unix)))] - { - buf.extend(path.as_os_str().to_string_lossy().as_bytes()); - } - } - VfsPathRepr::VirtualPath(VirtualPath(s)) => buf.extend(s.as_bytes()), - } - } -} - -#[cfg(windows)] -mod windows_paths { - pub(crate) trait Encode { - fn encode(&self, buf: &mut Vec); - } - - impl Encode for std::ffi::OsStr { - fn encode(&self, buf: &mut Vec) { - use std::os::windows::ffi::OsStrExt; - for wchar in self.encode_wide() { - buf.extend(wchar.to_le_bytes().iter().copied()); - } - } - } - - impl Encode for u8 { - fn encode(&self, buf: &mut Vec) { - let wide = *self as u16; - buf.extend(wide.to_le_bytes().iter().copied()) - } - } - - impl Encode for &str { - fn encode(&self, buf: &mut Vec) { - debug_assert!(self.is_ascii()); - for b in self.as_bytes() { - b.encode(buf) - } - } - } - - pub(crate) const SEP: &str = "\\"; - const VERBATIM: &str = "\\\\?\\"; - const UNC: &str = "UNC"; - const DEVICE: &str = "\\\\.\\"; - const COLON: &str = ":"; - - impl Encode for std::path::Prefix<'_> { - fn encode(&self, buf: &mut Vec) { - match self { - std::path::Prefix::Verbatim(c) => { - VERBATIM.encode(buf); - c.encode(buf); - } - std::path::Prefix::VerbatimUNC(server, share) => { - VERBATIM.encode(buf); - UNC.encode(buf); - SEP.encode(buf); - server.encode(buf); - SEP.encode(buf); - share.encode(buf); - } - std::path::Prefix::VerbatimDisk(d) => { - VERBATIM.encode(buf); - d.encode(buf); - COLON.encode(buf); - } - std::path::Prefix::DeviceNS(device) => { - DEVICE.encode(buf); - device.encode(buf); - } - std::path::Prefix::UNC(server, share) => { - SEP.encode(buf); - SEP.encode(buf); - server.encode(buf); - SEP.encode(buf); - share.encode(buf); - } - std::path::Prefix::Disk(d) => { - d.encode(buf); - COLON.encode(buf); - } - } - } - } - #[test] - fn paths_encoding() { - // drive letter casing agnostic - test_eq("C:/x.rs", "c:/x.rs"); - // separator agnostic - test_eq("C:/x/y.rs", "C:\\x\\y.rs"); - - fn test_eq(a: &str, b: &str) { - let mut b1 = Vec::new(); - let mut b2 = Vec::new(); - vfs(a).encode(&mut b1); - vfs(b).encode(&mut b2); - assert_eq!(b1, b2); - } - } - - #[test] - fn test_sep_root_dir_encoding() { - let mut buf = Vec::new(); - vfs("C:/x/y").encode(&mut buf); - assert_eq!(&buf, &[0, 67, 0, 58, 0, 92, 0, 120, 0, 92, 0, 121, 0]) - } - - #[cfg(test)] - fn vfs(str: &str) -> super::VfsPath { - use super::{AbsPathBuf, VfsPath}; - VfsPath::from(AbsPathBuf::try_from(str).unwrap()) - } -} - -/// Internal, private representation of [`VfsPath`]. -#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -enum VfsPathRepr { - PathBuf(AbsPathBuf), - VirtualPath(VirtualPath), -} - -impl From for VfsPath { - fn from(v: AbsPathBuf) -> Self { - VfsPath(VfsPathRepr::PathBuf(v.normalize())) - } -} - -impl fmt::Display for VfsPath { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match &self.0 { - VfsPathRepr::PathBuf(it) => fmt::Display::fmt(&it.display(), f), - VfsPathRepr::VirtualPath(VirtualPath(it)) => fmt::Display::fmt(it, f), - } - } -} - -impl fmt::Debug for VfsPath { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.0, f) - } -} - -impl fmt::Debug for VfsPathRepr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self { - VfsPathRepr::PathBuf(it) => fmt::Debug::fmt(&it.display(), f), - VfsPathRepr::VirtualPath(VirtualPath(it)) => fmt::Debug::fmt(&it, f), - } - } -} - -/// `/`-separated virtual path. -/// -/// This is used to describe files that do not reside on the file system. -#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -struct VirtualPath(String); - -impl VirtualPath { - /// Returns `true` if `other` is a prefix of `self` (as strings). - fn starts_with(&self, other: &VirtualPath) -> bool { - self.0.starts_with(&other.0) - } - - /// Remove the last component of `self`. - /// - /// This will find the last `'/'` in `self`, and remove everything after it, - /// including the `'/'`. - /// - /// If `self` contains no `'/'`, returns `false`; else returns `true`. - /// - /// # Example - /// - /// ```rust,ignore - /// let mut path = VirtualPath("/foo/bar".to_string()); - /// path.pop(); - /// assert_eq!(path.0, "/foo"); - /// path.pop(); - /// assert_eq!(path.0, ""); - /// ``` - fn pop(&mut self) -> bool { - let pos = match self.0.rfind('/') { - Some(pos) => pos, - None => return false, - }; - self.0 = self.0[..pos].to_string(); - true - } - - /// Append the given *relative* path `path` to `self`. - /// - /// This will resolve any leading `"../"` in `path` before appending it. - /// - /// Returns [`None`] if `path` has more leading `"../"` than the number of - /// components in `self`. - /// - /// # Notes - /// - /// In practice, appending here means `self/path` as strings. - fn join(&self, mut path: &str) -> Option { - let mut res = self.clone(); - while path.starts_with("../") { - if !res.pop() { - return None; - } - path = &path["../".len()..]; - } - path = path.trim_start_matches("./"); - res.0 = format!("{}/{}", res.0, path); - Some(res) - } - - /// Returns `self`'s base name and file extension. - /// - /// # Returns - /// - `None` if `self` ends with `"//"`. - /// - `Some((name, None))` if `self`'s base contains no `.`, or only one `.` at - /// the start. - /// - `Some((name, Some(extension))` else. - /// - /// # Note - /// The extension will not contains `.`. This means `"/foo/bar.baz.rs"` will - /// return `Some(("bar.baz", Some("rs"))`. - fn name_and_extension(&self) -> Option<(&str, Option<&str>)> { - let file_path = if self.0.ends_with('/') { &self.0[..&self.0.len() - 1] } else { &self.0 }; - let file_name = match file_path.rfind('/') { - Some(position) => &file_path[position + 1..], - None => file_path, - }; - - if file_name.is_empty() { - None - } else { - let mut file_stem_and_extension = file_name.rsplitn(2, '.'); - let extension = file_stem_and_extension.next(); - let file_stem = file_stem_and_extension.next(); - - match (file_stem, extension) { - (None, None) => None, - (None | Some(""), Some(_)) => Some((file_name, None)), - (Some(file_stem), extension) => Some((file_stem, extension)), - } - } - } -} - -#[cfg(test)] -mod tests; diff --git a/src/tools/rust-analyzer/crates/vfs/src/vfs_path/tests.rs b/src/tools/rust-analyzer/crates/vfs/src/vfs_path/tests.rs deleted file mode 100644 index 510e021e89035..0000000000000 --- a/src/tools/rust-analyzer/crates/vfs/src/vfs_path/tests.rs +++ /dev/null @@ -1,30 +0,0 @@ -use super::*; - -#[test] -fn virtual_path_extensions() { - assert_eq!(VirtualPath("/".to_string()).name_and_extension(), None); - assert_eq!( - VirtualPath("/directory".to_string()).name_and_extension(), - Some(("directory", None)) - ); - assert_eq!( - VirtualPath("/directory/".to_string()).name_and_extension(), - Some(("directory", None)) - ); - assert_eq!( - VirtualPath("/directory/file".to_string()).name_and_extension(), - Some(("file", None)) - ); - assert_eq!( - VirtualPath("/directory/.file".to_string()).name_and_extension(), - Some((".file", None)) - ); - assert_eq!( - VirtualPath("/directory/.file.rs".to_string()).name_and_extension(), - Some((".file", Some("rs"))) - ); - assert_eq!( - VirtualPath("/directory/file.rs".to_string()).name_and_extension(), - Some(("file", Some("rs"))) - ); -} diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/dev/README.md deleted file mode 100644 index 468f2b9e981fe..0000000000000 --- a/src/tools/rust-analyzer/docs/dev/README.md +++ /dev/null @@ -1,265 +0,0 @@ -# Contributing Quick Start - -rust-analyzer is an ordinary Rust project, which is organized as a Cargo workspace, builds on stable and doesn't depend on C libraries. -So, just - -``` -$ cargo test -``` - -should be enough to get you started! - -To learn more about how rust-analyzer works, see [./architecture.md](./architecture.md). -It also explains the high-level layout of the source code. -Do skim through that document. - -We also publish rustdoc docs to pages: https://rust-lang.github.io/rust-analyzer/ide/. -Note though, that the internal documentation is very incomplete. - -Various organizational and process issues are discussed in this document. - -# Getting in Touch - -rust-analyzer is a part of the [RLS-2.0 working -group](https://github.com/rust-lang/compiler-team/tree/6a769c13656c0a6959ebc09e7b1f7c09b86fb9c0/working-groups/rls-2.0). -Discussion happens in this Zulip stream: - -https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer - -# Issue Labels - -* [good-first-issue](https://github.com/rust-lang/rust-analyzer/labels/good%20first%20issue) - are good issues to get into the project. -* [E-has-instructions](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-has-instructions) - issues have links to the code in question and tests. -* [Broken Window](https://github.com/rust-lang/rust-analyzer/issues?q=is:issue+is:open+label:%22Broken+Window%22) - are issues which are not necessarily critical by themselves, but which should be fixed ASAP regardless, to avoid accumulation of technical debt. -* [E-easy](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy), - [E-medium](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-medium), - [E-hard](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-hard), - [E-unknown](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-unknown), - labels are *estimates* for how hard would be to write a fix. Each triaged issue should have one of these labels. -* [S-actionable](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AS-actionable) and - [S-unactionable](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AS-unactionable) - specify if there are concrete steps to resolve or advance an issue. Roughly, actionable issues need only work to be fixed, - while unactionable ones are blocked either on user feedback (providing a reproducible example), or on larger architectural - work or decisions. This classification is descriptive, not prescriptive, and might be wrong: Any unactionable issue might have a simple fix that we missed. - Each triaged issue should have one of these labels. -* [fun](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3Afun) - is for cool, but probably hard stuff. -* [Design](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%Design) - is for moderate/large scale architecture discussion. - Also a kind of fun. - These issues should generally include a link to a Zulip discussion thread. - -# Code Style & Review Process - -Do see [./style.md](./style.md). - -# Cookbook - -## CI - -We use GitHub Actions for CI. -Most of the things, including formatting, are checked by `cargo test`. -If `cargo test` passes locally, that's a good sign that CI will be green as well. -The only exception is that some long-running tests are skipped locally by default. -Use `env RUN_SLOW_TESTS=1 cargo test` to run the full suite. - -We use bors to enforce the [not rocket science](https://graydon2.dreamwidth.org/1597.html) rule. - -## Launching rust-analyzer - -Debugging the language server can be tricky. -LSP is rather chatty, so driving it from the command line is not really feasible, driving it via VS Code requires interacting with two processes. - -For this reason, the best way to see how rust-analyzer works is to **find a relevant test and execute it**. -VS Code & Emacs include an action for running a single test. - -Launching a VS Code instance with a locally built language server is also possible. -There's **"Run Extension (Debug Build)"** launch configuration for this in VS Code. - -In general, I use one of the following workflows for fixing bugs and implementing features: - -If the problem concerns only internal parts of rust-analyzer (i.e. I don't need to touch the `rust-analyzer` crate or TypeScript code), there is a unit-test for it. -So, I use **Rust Analyzer: Run** action in VS Code to run this single test, and then just do printf-driven development/debugging. -As a sanity check after I'm done, I use `cargo xtask install --server` and **Reload Window** action in VS Code to verify that the thing works as I expect. - -If the problem concerns only the VS Code extension, I use **Run Installed Extension** launch configuration from `launch.json`. -Notably, this uses the usual `rust-analyzer` binary from `PATH`. -For this, it is important to have the following in your `settings.json` file: -```json -{ - "rust-analyzer.server.path": "rust-analyzer" -} -``` -After I am done with the fix, I use `cargo xtask install --client` to try the new extension for real. - -If I need to fix something in the `rust-analyzer` crate, I feel sad because it's on the boundary between the two processes, and working there is slow. -I usually just `cargo xtask install --server` and poke changes from my live environment. -Note that this uses `--release`, which is usually faster overall, because loading stdlib into debug version of rust-analyzer takes a lot of time. -To speed things up, sometimes I open a temporary hello-world project which has `"rust-analyzer.cargo.noSysroot": true` in `.code/settings.json`. -This flag causes rust-analyzer to skip loading the sysroot, which greatly reduces the amount of things rust-analyzer needs to do, and makes printf's more useful. -Note that you should only use the `eprint!` family of macros for debugging: stdout is used for LSP communication, and `print!` would break it. - -If I need to fix something simultaneously in the server and in the client, I feel even more sad. -I don't have a specific workflow for this case. - -Additionally, I use `cargo run --release -p rust-analyzer -- analysis-stats path/to/some/rust/crate` to run a batch analysis. -This is primarily useful for performance optimizations, or for bug minimization. - -## TypeScript Tests - -If you change files under `editors/code` and would like to run the tests and linter, install npm and run: - -```bash -cd editors/code -npm ci -npm run lint -``` -## How to ... - -* ... add an assist? [#7535](https://github.com/rust-lang/rust-analyzer/pull/7535) -* ... add a new protocol extension? [#4569](https://github.com/rust-lang/rust-analyzer/pull/4569) -* ... add a new configuration option? [#7451](https://github.com/rust-lang/rust-analyzer/pull/7451) -* ... add a new completion? [#6964](https://github.com/rust-lang/rust-analyzer/pull/6964) -* ... allow new syntax in the parser? [#7338](https://github.com/rust-lang/rust-analyzer/pull/7338) - -## Logging - -Logging is done by both rust-analyzer and VS Code, so it might be tricky to figure out where logs go. - -Inside rust-analyzer, we use the [`tracing`](https://docs.rs/tracing/) crate for logging, -and [`tracing-subscriber`](https://docs.rs/tracing-subscriber) for logging frontend. -By default, log goes to stderr, but the stderr itself is processed by VS Code. -`--log-file ` CLI argument allows logging to file. -Setting the `RA_LOG_FILE=` environment variable will also log to file, it will also override `--log-file`. - -To see stderr in the running VS Code instance, go to the "Output" tab of the panel and select `rust-analyzer`. -This shows `eprintln!` as well. -Note that `stdout` is used for the actual protocol, so `println!` will break things. - -To log all communication between the server and the client, there are two choices: - -* You can log on the server side, by running something like - ``` - env RA_LOG=lsp_server=debug code . - ``` -* You can log on the client side, by enabling `"rust-analyzer.trace.server": "verbose"` workspace setting. - These logs are shown in a separate tab in the output and could be used with LSP inspector. - Kudos to [@DJMcNab](https://github.com/DJMcNab) for setting this awesome infra up! - - -There are also several VS Code commands which might be of interest: - -* `Rust Analyzer: Status` shows some memory-usage statistics. - -* `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection. - -* `Rust Analyzer: View Hir` shows the HIR expressions within the function containing the cursor. - - You can hover over syntax nodes in the opened text file to see the appropriate - rust code that it refers to and the rust editor will also highlight the proper - text range. - - If you trigger Go to Definition in the inspected Rust source file, - the syntax tree read-only editor should scroll to and select the - appropriate syntax node token. - - ![demo](https://user-images.githubusercontent.com/36276403/78225773-6636a480-74d3-11ea-9d9f-1c9d42da03b0.png) - -## Profiling - -We have a built-in hierarchical profiler, you can enable it by using `RA_PROFILE` env-var: - -``` -RA_PROFILE=* // dump everything -RA_PROFILE=foo|bar|baz // enabled only selected entries -RA_PROFILE=*@3>10 // dump everything, up to depth 3, if it takes more than 10 ms -``` - -In particular, I have `export RA_PROFILE='*>10'` in my shell profile. - -We also have a "counting" profiler which counts number of instances of popular structs. -It is enabled by `RA_COUNT=1`. - -To measure time for from-scratch analysis, use something like this: - -``` -$ cargo run --release -p rust-analyzer -- analysis-stats ../chalk/ -``` - -For measuring time of incremental analysis, use either of these: - -``` -$ cargo run --release -p rust-analyzer -- analysis-bench ../chalk/ --highlight ../chalk/chalk-engine/src/logic.rs -$ cargo run --release -p rust-analyzer -- analysis-bench ../chalk/ --complete ../chalk/chalk-engine/src/logic.rs:94:0 -``` - -Look for `fn benchmark_xxx` tests for a quick way to reproduce performance problems. - -## Release Process - -Release process is handled by `release`, `dist` and `promote` xtasks, `release` being the main one. - -`release` assumes that you have checkouts of `rust-analyzer`, `rust-analyzer.github.io`, and `rust-lang/rust` in the same directory: - -``` -./rust-analyzer -./rust-analyzer.github.io -./rust-rust-analyzer # Note the name! -``` - -Additionally, it assumes that the remote for `rust-analyzer` is called `upstream` (I use `origin` to point to my fork). - -`release` calls the GitHub API calls to scrape pull request comments and categorize them in the changelog. -This step uses the `curl` and `jq` applications, which need to be available in `PATH`. -Finally, you need to obtain a GitHub personal access token and set the `GITHUB_TOKEN` environment variable. - -Release steps: - -1. Set the `GITHUB_TOKEN` environment variable. -2. Inside rust-analyzer, run `cargo xtask release`. This will: - * checkout the `release` branch - * reset it to `upstream/nightly` - * push it to `upstream`. This triggers GitHub Actions which: - * runs `cargo xtask dist` to package binaries and VS Code extension - * makes a GitHub release - * pushes VS Code extension to the marketplace - * call the GitHub API for PR details - * create a new changelog in `rust-analyzer.github.io` -3. While the release is in progress, fill in the changelog -4. Commit & push the changelog -5. Tweet -6. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's submodule. - Self-approve the PR. - -If the GitHub Actions release fails because of a transient problem like a timeout, you can re-run the job from the Actions console. -If it fails because of something that needs to be fixed, remove the release tag (if needed), fix the problem, then start over. -Make sure to remove the new changelog post created when running `cargo xtask release` a second time. - -We release "nightly" every night automatically and promote the latest nightly to "stable" manually, every week. - -We don't do "patch" releases, unless something truly egregious comes up. -To do a patch release, cherry-pick the fix on top of the current `release` branch and push the branch. -There's no need to write a changelog for a patch release, it's OK to include the notes about the fix into the next weekly one. -Note: we tag releases by dates, releasing a patch release on the same day should work (by overwriting a tag), but I am not 100% sure. - -## Permissions - -There are three sets of people with extra permissions: - -* rust-analyzer GitHub organization [**admins**](https://github.com/orgs/rust-analyzer/people?query=role:owner) (which include current t-compiler leads). - Admins have full access to the org. -* [**review**](https://github.com/orgs/rust-analyzer/teams/review) team in the organization. - Reviewers have `r+` access to all of organization's repositories and publish rights on crates.io. - They also have direct commit access, but all changes should via bors queue. - It's ok to self-approve if you think you know what you are doing! - bors should automatically sync the permissions. - Feel free to request a review or assign any PR to a reviewer with the relevant expertise to bring the work to their attention. - Don't feel pressured to review assigned PRs though. - If you don't feel like reviewing for whatever reason, someone else will pick the review up! -* [**triage**](https://github.com/orgs/rust-analyzer/teams/triage) team in the organization. - This team can label and close issues. - -Note that at the time being you need to be a member of the org yourself to view the links. diff --git a/src/tools/rust-analyzer/docs/dev/architecture.md b/src/tools/rust-analyzer/docs/dev/architecture.md deleted file mode 100644 index ea4035baf114c..0000000000000 --- a/src/tools/rust-analyzer/docs/dev/architecture.md +++ /dev/null @@ -1,497 +0,0 @@ -# Architecture - -This document describes the high-level architecture of rust-analyzer. -If you want to familiarize yourself with the code base, you are just in the right place! - -You might also enjoy ["Explaining Rust Analyzer"](https://www.youtube.com/playlist?list=PLhb66M_x9UmrqXhQuIpWC5VgTdrGxMx3y) series on YouTube. -It goes deeper than what is covered in this document, but will take some time to watch. - -See also these implementation-related blog posts: - -* https://rust-analyzer.github.io/blog/2019/11/13/find-usages.html -* https://rust-analyzer.github.io/blog/2020/07/20/three-architectures-for-responsive-ide.html -* https://rust-analyzer.github.io/blog/2020/09/16/challeging-LR-parsing.html -* https://rust-analyzer.github.io/blog/2020/09/28/how-to-make-a-light-bulb.html -* https://rust-analyzer.github.io/blog/2020/10/24/introducing-ungrammar.html - -For older, by now mostly outdated stuff, see the [guide](./guide.md) and [another playlist](https://www.youtube.com/playlist?list=PL85XCvVPmGQho7MZkdW-wtPtuJcFpzycE). - - -## Bird's Eye View - -![](https://user-images.githubusercontent.com/4789492/107129398-0ab70f00-687a-11eb-9bfc-d4eb023aec06.png) - -On the highest level, rust-analyzer is a thing which accepts input source code from the client and produces a structured semantic model of the code. - -More specifically, input data consists of a set of test files (`(PathBuf, String)` pairs) and information about project structure, captured in the so called `CrateGraph`. -The crate graph specifies which files are crate roots, which cfg flags are specified for each crate and what dependencies exist between the crates. -This is the input (ground) state. -The analyzer keeps all this input data in memory and never does any IO. -Because the input data is source code, which typically measures in tens of megabytes at most, keeping everything in memory is OK. - -A "structured semantic model" is basically an object-oriented representation of modules, functions and types which appear in the source code. -This representation is fully "resolved": all expressions have types, all references are bound to declarations, etc. -This is derived state. - -The client can submit a small delta of input data (typically, a change to a single file) and get a fresh code model which accounts for changes. - -The underlying engine makes sure that model is computed lazily (on-demand) and can be quickly updated for small modifications. - -## Entry Points - -`crates/rust-analyzer/src/bin/main.rs` contains the main function which spawns LSP. -This is *the* entry point, but it front-loads a lot of complexity, so it's fine to just skim through it. - -`crates/rust-analyzer/src/handlers.rs` implements all LSP requests and is a great place to start if you are already familiar with LSP. - -`Analysis` and `AnalysisHost` types define the main API for consumers of IDE services. - -## Code Map - -This section talks briefly about various important directories and data structures. -Pay attention to the **Architecture Invariant** sections. -They often talk about things which are deliberately absent in the source code. - -Note also which crates are **API Boundaries**. -Remember, [rules at the boundary are different](https://www.tedinski.com/2018/02/06/system-boundaries.html). - -### `xtask` - -This is rust-analyzer's "build system". -We use cargo to compile rust code, but there are also various other tasks, like release management or local installation. -They are handled by Rust code in the xtask directory. - -### `editors/code` - -VS Code plugin. - -### `lib/` - -rust-analyzer independent libraries which we publish to crates.io. -It's not heavily utilized at the moment. - -### `crates/parser` - -It is a hand-written recursive descent parser, which produces a sequence of events like "start node X", "finish node Y". -It works similarly to -[kotlin's parser](https://github.com/JetBrains/kotlin/blob/4d951de616b20feca92f3e9cc9679b2de9e65195/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinParsing.java), -which is a good source of inspiration for dealing with syntax errors and incomplete input. -Original [libsyntax parser](https://github.com/rust-lang/rust/blob/6b99adeb11313197f409b4f7c4083c2ceca8a4fe/src/libsyntax/parse/parser.rs) is what we use for the definition of the Rust language. -`TreeSink` and `TokenSource` traits bridge the tree-agnostic parser from `grammar` with `rowan` trees. - -**Architecture Invariant:** the parser is independent of the particular tree structure and particular representation of the tokens. -It transforms one flat stream of events into another flat stream of events. -Token independence allows us to parse out both text-based source code and `tt`-based macro input. -Tree independence allows us to more easily vary the syntax tree implementation. -It should also unlock efficient light-parsing approaches. -For example, you can extract the set of names defined in a file (for typo correction) without building a syntax tree. - -**Architecture Invariant:** parsing never fails, the parser produces `(T, Vec)` rather than `Result`. - -### `crates/syntax` - -Rust syntax tree structure and parser. -See [RFC](https://github.com/rust-lang/rfcs/pull/2256) and [./syntax.md](./syntax.md) for some design notes. - -- [rowan](https://github.com/rust-analyzer/rowan) library is used for constructing syntax trees. -- `ast` provides a type safe API on top of the raw `rowan` tree. -- `ungrammar` description of the grammar, which is used to generate `syntax_kinds` and `ast` modules, using `cargo test -p xtask` command. - -Tests for ra_syntax are mostly data-driven. -`test_data/parser` contains subdirectories with a bunch of `.rs` (test vectors) and `.txt` files with corresponding syntax trees. -During testing, we check `.rs` against `.txt`. -If the `.txt` file is missing, it is created (this is how you update tests). -Additionally, running the xtask test suite with `cargo test -p xtask` will walk the grammar module and collect all `// test test_name` comments into files inside `test_data/parser/inline` directory. - -To update test data, run with `UPDATE_EXPECT` variable: - -```bash -env UPDATE_EXPECT=1 cargo qt -``` - -After adding a new inline test you need to run `cargo test -p xtask` and also update the test data as described above. - -Note [`api_walkthrough`](https://github.com/rust-lang/rust-analyzer/blob/2fb6af89eb794f775de60b82afe56b6f986c2a40/crates/ra_syntax/src/lib.rs#L190-L348) -in particular: it shows off various methods of working with syntax tree. - -See [#93](https://github.com/rust-lang/rust-analyzer/pull/93) for an example PR which fixes a bug in the grammar. - -**Architecture Invariant:** `syntax` crate is completely independent from the rest of rust-analyzer. It knows nothing about salsa or LSP. -This is important because it is possible to make useful tooling using only the syntax tree. -Without semantic information, you don't need to be able to _build_ code, which makes the tooling more robust. -See also https://web.stanford.edu/~mlfbrown/paper.pdf. -You can view the `syntax` crate as an entry point to rust-analyzer. -`syntax` crate is an **API Boundary**. - -**Architecture Invariant:** syntax tree is a value type. -The tree is fully determined by the contents of its syntax nodes, it doesn't need global context (like an interner) and doesn't store semantic info. -Using the tree as a store for semantic info is convenient in traditional compilers, but doesn't work nicely in the IDE. -Specifically, assists and refactors require transforming syntax trees, and that becomes awkward if you need to do something with the semantic info. - -**Architecture Invariant:** syntax tree is built for a single file. -This is to enable parallel parsing of all files. - -**Architecture Invariant:** Syntax trees are by design incomplete and do not enforce well-formedness. -If an AST method returns an `Option`, it *can* be `None` at runtime, even if this is forbidden by the grammar. - -### `crates/base_db` - -We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and on-demand computation. -Roughly, you can think of salsa as a key-value store, but it can also compute derived values using specified functions. -The `base_db` crate provides basic infrastructure for interacting with salsa. -Crucially, it defines most of the "input" queries: facts supplied by the client of the analyzer. -Reading the docs of the `base_db::input` module should be useful: everything else is strictly derived from those inputs. - -**Architecture Invariant:** particularities of the build system are *not* the part of the ground state. -In particular, `base_db` knows nothing about cargo. -For example, `cfg` flags are a part of `base_db`, but `feature`s are not. -A `foo` feature is a Cargo-level concept, which is lowered by Cargo to `--cfg feature=foo` argument on the command line. -The `CrateGraph` structure is used to represent the dependencies between the crates abstractly. - -**Architecture Invariant:** `base_db` doesn't know about file system and file paths. -Files are represented with opaque `FileId`, there's no operation to get an `std::path::Path` out of the `FileId`. - -### `crates/hir_expand`, `crates/hir_def`, `crates/hir_ty` - -These crates are the *brain* of rust-analyzer. -This is the compiler part of the IDE. - -`hir_xxx` crates have a strong [ECS](https://en.wikipedia.org/wiki/Entity_component_system) flavor, in that they work with raw ids and directly query the database. -There's little abstraction here. -These crates integrate deeply with salsa and chalk. - -Name resolution, macro expansion and type inference all happen here. -These crates also define various intermediate representations of the core. - -`ItemTree` condenses a single `SyntaxTree` into a "summary" data structure, which is stable over modifications to function bodies. - -`DefMap` contains the module tree of a crate and stores module scopes. - -`Body` stores information about expressions. - -**Architecture Invariant:** these crates are not, and will never be, an api boundary. - -**Architecture Invariant:** these crates explicitly care about being incremental. -The core invariant we maintain is "typing inside a function's body never invalidates global derived data". -i.e., if you change the body of `foo`, all facts about `bar` should remain intact. - -**Architecture Invariant:** hir exists only in context of particular crate instance with specific CFG flags. -The same syntax may produce several instances of HIR if the crate participates in the crate graph more than once. - -### `crates/hir` - -The top-level `hir` crate is an **API Boundary**. -If you think about "using rust-analyzer as a library", `hir` crate is most likely the façade you'll be talking to. - -It wraps ECS-style internal API into a more OO-flavored API (with an extra `db` argument for each call). - -**Architecture Invariant:** `hir` provides a static, fully resolved view of the code. -While internal `hir_*` crates _compute_ things, `hir`, from the outside, looks like an inert data structure. - -`hir` also handles the delicate task of going from syntax to the corresponding `hir`. -Remember that the mapping here is one-to-many. -See `Semantics` type and `source_to_def` module. - -Note in particular a curious recursive structure in `source_to_def`. -We first resolve the parent _syntax_ node to the parent _hir_ element. -Then we ask the _hir_ parent what _syntax_ children does it have. -Then we look for our node in the set of children. - -This is the heart of many IDE features, like goto definition, which start with figuring out the hir node at the cursor. -This is some kind of (yet unnamed) uber-IDE pattern, as it is present in Roslyn and Kotlin as well. - -### `crates/ide` - -The `ide` crate builds on top of `hir` semantic model to provide high-level IDE features like completion or goto definition. -It is an **API Boundary**. -If you want to use IDE parts of rust-analyzer via LSP, custom flatbuffers-based protocol or just as a library in your text editor, this is the right API. - -**Architecture Invariant:** `ide` crate's API is build out of POD types with public fields. -The API uses editor's terminology, it talks about offsets and string labels rather than in terms of definitions or types. -It is effectively the view in MVC and viewmodel in [MVVM](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel). -All arguments and return types are conceptually serializable. -In particular, syntax trees and hir types are generally absent from the API (but are used heavily in the implementation). -Shout outs to LSP developers for popularizing the idea that "UI" is a good place to draw a boundary at. - -`ide` is also the first crate which has the notion of change over time. -`AnalysisHost` is a state to which you can transactionally `apply_change`. -`Analysis` is an immutable snapshot of the state. - -Internally, `ide` is split across several crates. `ide_assists`, `ide_completion` and `ide_ssr` implement large isolated features. -`ide_db` implements common IDE functionality (notably, reference search is implemented here). -The `ide` contains a public API/façade, as well as implementation for a plethora of smaller features. - -**Architecture Invariant:** `ide` crate strives to provide a _perfect_ API. -Although at the moment it has only one consumer, the LSP server, LSP *does not* influence its API design. -Instead, we keep in mind a hypothetical _ideal_ client -- an IDE tailored specifically for rust, every nook and cranny of which is packed with Rust-specific goodies. - -### `crates/rust-analyzer` - -This crate defines the `rust-analyzer` binary, so it is the **entry point**. -It implements the language server. - -**Architecture Invariant:** `rust-analyzer` is the only crate that knows about LSP and JSON serialization. -If you want to expose a data structure `X` from ide to LSP, don't make it serializable. -Instead, create a serializable counterpart in `rust-analyzer` crate and manually convert between the two. - -`GlobalState` is the state of the server. -The `main_loop` defines the server event loop which accepts requests and sends responses. -Requests that modify the state or might block user's typing are handled on the main thread. -All other requests are processed in background. - -**Architecture Invariant:** the server is stateless, a-la HTTP. -Sometimes state needs to be preserved between requests. -For example, "what is the `edit` for the fifth completion item of the last completion edit?". -For this, the second request should include enough info to re-create the context from scratch. -This generally means including all the parameters of the original request. - -`reload` module contains the code that handles configuration and Cargo.toml changes. -This is a tricky business. - -**Architecture Invariant:** `rust-analyzer` should be partially available even when the build is broken. -Reloading process should not prevent IDE features from working. - -### `crates/toolchain`, `crates/project_model`, `crates/flycheck` - -These crates deal with invoking `cargo` to learn about project structure and get compiler errors for the "check on save" feature. - -They use `crates/path` heavily instead of `std::path`. -A single `rust-analyzer` process can serve many projects, so it is important that server's current directory does not leak. - -### `crates/mbe`, `crates/tt`, `crates/proc_macro_api`, `crates/proc_macro_srv` - -These crates implement macros as token tree -> token tree transforms. -They are independent from the rest of the code. - -`tt` crate defined `TokenTree`, a single token or a delimited sequence of token trees. -`mbe` crate contains tools for transforming between syntax trees and token tree. -And it also handles the actual parsing and expansion of declarative macro (a-la "Macros By Example" or mbe). - -For proc macros, the client-server model are used. -We pass an argument `--proc-macro` to `rust-analyzer` binary to start a separate process (`proc_macro_srv`). -And the client (`proc_macro_api`) provides an interface to talk to that server separately. - -And then token trees are passed from client, and the server will load the corresponding dynamic library (which built by `cargo`). -And due to the fact the api for getting result from proc macro are always unstable in `rustc`, -we maintain our own copy (and paste) of that part of code to allow us to build the whole thing in stable rust. - - **Architecture Invariant:** -Bad proc macros may panic or segfault accidentally. So we run it in another process and recover it from fatal error. -And they may be non-deterministic which conflict how `salsa` works, so special attention is required. - -### `crates/cfg` - -This crate is responsible for parsing, evaluation and general definition of `cfg` attributes. - -### `crates/vfs`, `crates/vfs-notify` - -These crates implement a virtual file system. -They provide consistent snapshots of the underlying file system and insulate messy OS paths. - -**Architecture Invariant:** vfs doesn't assume a single unified file system. -i.e., a single rust-analyzer process can act as a remote server for two different machines, where the same `/tmp/foo.rs` path points to different files. -For this reason, all path APIs generally take some existing path as a "file system witness". - -### `crates/stdx` - -This crate contains various non-rust-analyzer specific utils, which could have been in std, as well -as copies of unstable std items we would like to make use of already, like `std::str::split_once`. - -### `crates/profile` - -This crate contains utilities for CPU and memory profiling. - - -## Cross-Cutting Concerns - -This sections talks about the things which are everywhere and nowhere in particular. - -### Stability Guarantees - -One of the reasons rust-analyzer moves relatively fast is that we don't introduce new stability guarantees. -Instead, as much as possible we leverage existing ones. - -Examples: - -* The `ide` API of rust-analyzer are explicitly unstable, but the LSP interface is stable, and here we just implement a stable API managed by someone else. -* Rust language and Cargo are stable, and they are the primary inputs to rust-analyzer. -* The `rowan` library is published to crates.io, but it is deliberately kept under `1.0` and always makes semver-incompatible upgrades - -Another important example is that rust-analyzer isn't run on CI, so, unlike `rustc` and `clippy`, it is actually ok for us to change runtime behavior. - -At some point we might consider opening up APIs or allowing crates.io libraries to include rust-analyzer specific annotations, but that's going to be a big commitment on our side. - -Exceptions: - -* `rust-project.json` is a de-facto stable format for non-cargo build systems. - It is probably ok enough, but was definitely stabilized implicitly. - Lesson for the future: when designing API which could become a stability boundary, don't wait for the first users until you stabilize it. - By the time you have first users, it is already de-facto stable. - And the users will first use the thing, and *then* inform you that now you have users. - The sad thing is that stuff should be stable before someone uses it for the first time, or it should contain explicit opt-in. -* We ship some LSP extensions, and we try to keep those somewhat stable. - Here, we need to work with a finite set of editor maintainers, so not providing rock-solid guarantees works. - -### Code generation - -Some components in this repository are generated through automatic processes. -Generated code is updated automatically on `cargo test`. -Generated code is generally committed to the git repository. - -In particular, we generate: - -* API for working with syntax trees (`syntax::ast`, the [`ungrammar`](https://github.com/rust-analyzer/ungrammar) crate). -* Various sections of the manual: - - * features - * assists - * config - -* Documentation tests for assists - -See the `sourcegen` crate for details. - -**Architecture Invariant:** we avoid bootstrapping. -For codegen we need to parse Rust code. -Using rust-analyzer for that would work and would be fun, but it would also complicate the build process a lot. -For that reason, we use syn and manual string parsing. - -### Cancellation - -Let's say that the IDE is in the process of computing syntax highlighting, when the user types `foo`. -What should happen? -`rust-analyzer`s answer is that the highlighting process should be cancelled -- its results are now stale, and it also blocks modification of the inputs. - -The salsa database maintains a global revision counter. -When applying a change, salsa bumps this counter and waits until all other threads using salsa finish. -If a thread does salsa-based computation and notices that the counter is incremented, it panics with a special value (see `Canceled::throw`). -That is, rust-analyzer requires unwinding. - -`ide` is the boundary where the panic is caught and transformed into a `Result`. - -### Testing - -Rust Analyzer has three interesting [system boundaries](https://www.tedinski.com/2018/04/10/making-tests-a-positive-influence-on-design.html) to concentrate tests on. - -The outermost boundary is the `rust-analyzer` crate, which defines an LSP interface in terms of stdio. -We do integration testing of this component, by feeding it with a stream of LSP requests and checking responses. -These tests are known as "heavy", because they interact with Cargo and read real files from disk. -For this reason, we try to avoid writing too many tests on this boundary: in a statically typed language, it's hard to make an error in the protocol itself if messages are themselves typed. -Heavy tests are only run when `RUN_SLOW_TESTS` env var is set. - -The middle, and most important, boundary is `ide`. -Unlike `rust-analyzer`, which exposes API, `ide` uses Rust API and is intended for use by various tools. -A typical test creates an `AnalysisHost`, calls some `Analysis` functions and compares the results against expectation. - -The innermost and most elaborate boundary is `hir`. -It has a much richer vocabulary of types than `ide`, but the basic testing setup is the same: we create a database, run some queries, assert result. - -For comparisons, we use the `expect` crate for snapshot testing. - -To test various analysis corner cases and avoid forgetting about old tests, we use so-called marks. -See the `marks` module in the `test_utils` crate for more. - -**Architecture Invariant:** rust-analyzer tests do not use libcore or libstd. -All required library code must be a part of the tests. -This ensures fast test execution. - -**Architecture Invariant:** tests are data driven and do not test the API. -Tests which directly call various API functions are a liability, because they make refactoring the API significantly more complicated. -So most of the tests look like this: - -```rust -#[track_caller] -fn check(input: &str, expect: expect_test::Expect) { - // The single place that actually exercises a particular API -} - -#[test] -fn foo() { - check("foo", expect![["bar"]]); -} - -#[test] -fn spam() { - check("spam", expect![["eggs"]]); -} -// ...and a hundred more tests that don't care about the specific API at all. -``` - -To specify input data, we use a single string literal in a special format, which can describe a set of rust files. -See the `Fixture` its module for fixture examples and documentation. - -**Architecture Invariant:** all code invariants are tested by `#[test]` tests. -There's no additional checks in CI, formatting and tidy tests are run with `cargo test`. - -**Architecture Invariant:** tests do not depend on any kind of external resources, they are perfectly reproducible. - - -### Performance Testing - -TBA, take a look at the `metrics` xtask and `#[test] fn benchmark_xxx()` functions. - -### Error Handling - -**Architecture Invariant:** core parts of rust-analyzer (`ide`/`hir`) don't interact with the outside world and thus can't fail. -Only parts touching LSP are allowed to do IO. - -Internals of rust-analyzer need to deal with broken code, but this is not an error condition. -rust-analyzer is robust: various analysis compute `(T, Vec)` rather than `Result`. - -rust-analyzer is a complex long-running process. -It will always have bugs and panics. -But a panic in an isolated feature should not bring down the whole process. -Each LSP-request is protected by a `catch_unwind`. -We use `always` and `never` macros instead of `assert` to gracefully recover from impossible conditions. - -### Observability - -rust-analyzer is a long-running process, so it is important to understand what's going on inside. -We have several instruments for that. - -The event loop that runs rust-analyzer is very explicit. -Rather than spawning futures or scheduling callbacks (open), the event loop accepts an `enum` of possible events (closed). -It's easy to see all the things that trigger rust-analyzer processing, together with their performance - -rust-analyzer includes a simple hierarchical profiler (`hprof`). -It is enabled with `RA_PROFILE='*>50'` env var (log all (`*`) actions which take more than `50` ms) and produces output like: - -``` -85ms - handle_completion - 68ms - import_on_the_fly - 67ms - import_assets::search_for_relative_paths - 0ms - crate_def_map:wait (804 calls) - 0ms - find_path (16 calls) - 2ms - find_similar_imports (1 calls) - 0ms - generic_params_query (334 calls) - 59ms - trait_solve_query (186 calls) - 0ms - Semantics::analyze_impl (1 calls) - 1ms - render_resolution (8 calls) - 0ms - Semantics::analyze_impl (5 calls) -``` - -This is cheap enough to enable in production. - - -Similarly, we save live object counting (`RA_COUNT=1`). -It is not cheap enough to enable in prod, and this is a bug which should be fixed. - -### Configurability - -rust-analyzer strives to be as configurable as possible while offering reasonable defaults where no configuration exists yet. -There will always be features that some people find more annoying than helpful, so giving the users the ability to tweak or disable these is a big part of offering a good user experience. -Mind the code--architecture gap: at the moment, we are using fewer feature flags than we really should. - -### Serialization - -In Rust, it is easy (often too easy) to add serialization to any type by adding `#[derive(Serialize)]`. -This easiness is misleading -- serializable types impose significant backwards compatability constraints. -If a type is serializable, then it is a part of some IPC boundary. -You often don't control the other side of this boundary, so changing serializable types is hard. - -For this reason, the types in `ide`, `base_db` and below are not serializable by design. -If such types need to cross an IPC boundary, then the client of rust-analyzer needs to provide custom, client-specific serialization format. -This isolates backwards compatibility and migration concerns to a specific client. - -For example, `rust-project.json` is it's own format -- it doesn't include `CrateGraph` as is. -Instead, it creates a `CrateGraph` by calling appropriate constructing functions. diff --git a/src/tools/rust-analyzer/docs/dev/debugging.md b/src/tools/rust-analyzer/docs/dev/debugging.md deleted file mode 100644 index 48caec1d8fa6e..0000000000000 --- a/src/tools/rust-analyzer/docs/dev/debugging.md +++ /dev/null @@ -1,99 +0,0 @@ -# Debugging VSCode plugin and the language server - -## Prerequisites - -- Install [LLDB](https://lldb.llvm.org/) and the [LLDB Extension](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb). -- Open the root folder in VSCode. Here you can access the preconfigured debug setups. - - Debug options view - -- Install all TypeScript dependencies - ```bash - cd editors/code - npm ci - ``` - -## Common knowledge - -* All debug configurations open a new `[Extension Development Host]` VSCode instance -where **only** the `rust-analyzer` extension being debugged is enabled. -* To activate the extension you need to open any Rust project folder in `[Extension Development Host]`. - - -## Debug TypeScript VSCode extension - -- `Run Installed Extension` - runs the extension with the globally installed `rust-analyzer` binary. -- `Run Extension (Debug Build)` - runs extension with the locally built LSP server (`target/debug/rust-analyzer`). - -TypeScript debugging is configured to watch your source edits and recompile. -To apply changes to an already running debug process, press Ctrl+Shift+P and run the following command in your `[Extension Development Host]` - -``` -> Developer: Reload Window -``` - -## Debug Rust LSP server - -- When attaching a debugger to an already running `rust-analyzer` server on Linux you might need to enable `ptrace` for unrelated processes by running: - - ``` - echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope - ``` - - -- By default, the LSP server is built without debug information. To enable it, you'll need to change `Cargo.toml`: - ```toml - [profile.dev] - debug = 2 - ``` - -- Select `Run Extension (Debug Build)` to run your locally built `target/debug/rust-analyzer`. - -- In the original VSCode window once again select the `Attach To Server` debug configuration. - -- A list of running processes should appear. Select the `rust-analyzer` from this repo. - -- Navigate to `crates/rust-analyzer/src/main_loop.rs` and add a breakpoint to the `on_request` function. - -- Go back to the `[Extension Development Host]` instance and hover over a Rust variable and your breakpoint should hit. - -If you need to debug the server from the very beginning, including its initialization code, you can use the `--wait-dbg` command line argument or `RA_WAIT_DBG` environment variable. The server will spin at the beginning of the `try_main` function (see `crates\rust-analyzer\src\bin\main.rs`) -```rust - let mut d = 4; - while d == 4 { // set a breakpoint here and change the value - d = 4; - } -``` - -However for this to work, you will need to enable debug_assertions in your build -```rust -RUSTFLAGS='--cfg debug_assertions' cargo build --release -``` - -## Demo - -- [Debugging TypeScript VScode extension](https://www.youtube.com/watch?v=T-hvpK6s4wM). -- [Debugging Rust LSP server](https://www.youtube.com/watch?v=EaNb5rg4E0M). - -## Troubleshooting - -### Can't find the `rust-analyzer` process - -It could be a case of just jumping the gun. - -The `rust-analyzer` is only started once the `onLanguage:rust` activation. - -Make sure you open a rust file in the `[Extension Development Host]` and try again. - -### Can't connect to `rust-analyzer` - -Make sure you have run `echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope`. - -By default this should reset back to 1 every time you log in. - -### Breakpoints are never being hit - -Check your version of `lldb`. If it's version 6 and lower, use the `classic` adapter type. -It's `lldb.adapterType` in settings file. - -If you're running `lldb` version 7, change the lldb adapter type to `bundled` or `native`. diff --git a/src/tools/rust-analyzer/docs/dev/guide.md b/src/tools/rust-analyzer/docs/dev/guide.md deleted file mode 100644 index 47ae3f3e6a902..0000000000000 --- a/src/tools/rust-analyzer/docs/dev/guide.md +++ /dev/null @@ -1,573 +0,0 @@ -# Guide to rust-analyzer - -## About the guide - -This guide describes the current state of rust-analyzer as of 2019-01-20 (git -tag [guide-2019-01]). Its purpose is to document various problems and -architectural solutions related to the problem of building IDE-first compiler -for Rust. There is a video version of this guide as well: -https://youtu.be/ANKBNiSWyfc. - -[guide-2019-01]: https://github.com/rust-lang/rust-analyzer/tree/guide-2019-01 - -## The big picture - -On the highest possible level, rust-analyzer is a stateful component. A client may -apply changes to the analyzer (new contents of `foo.rs` file is "fn main() {}") -and it may ask semantic questions about the current state (what is the -definition of the identifier with offset 92 in file `bar.rs`?). Two important -properties hold: - -* Analyzer does not do any I/O. It starts in an empty state and all input data is - provided via `apply_change` API. - -* Only queries about the current state are supported. One can, of course, - simulate undo and redo by keeping a log of changes and inverse changes respectively. - -## IDE API - -To see the bigger picture of how the IDE features work, let's take a look at the [`AnalysisHost`] and -[`Analysis`] pair of types. `AnalysisHost` has three methods: - -* `default()` for creating an empty analysis instance -* `apply_change(&mut self)` to make changes (this is how you get from an empty - state to something interesting) -* `analysis(&self)` to get an instance of `Analysis` - -`Analysis` has a ton of methods for IDEs, like `goto_definition`, or -`completions`. Both inputs and outputs of `Analysis`' methods are formulated in -terms of files and offsets, and **not** in terms of Rust concepts like structs, -traits, etc. The "typed" API with Rust specific types is slightly lower in the -stack, we'll talk about it later. - -[`AnalysisHost`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/lib.rs#L265-L284 -[`Analysis`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/lib.rs#L291-L478 - -The reason for this separation of `Analysis` and `AnalysisHost` is that we want to apply -changes "uniquely", but we might also want to fork an `Analysis` and send it to -another thread for background processing. That is, there is only a single -`AnalysisHost`, but there may be several (equivalent) `Analysis`. - -Note that all of the `Analysis` API return `Cancellable`. This is required to -be responsive in an IDE setting. Sometimes a long-running query is being computed -and the user types something in the editor and asks for completion. In this -case, we cancel the long-running computation (so it returns `Err(Cancelled)`), -apply the change and execute request for completion. We never use stale data to -answer requests. Under the cover, `AnalysisHost` "remembers" all outstanding -`Analysis` instances. The `AnalysisHost::apply_change` method cancels all -`Analysis`es, blocks until all of them are `Dropped` and then applies changes -in-place. This may be familiar to Rustaceans who use read-write locks for interior -mutability. - -Next, let's talk about what the inputs to the `Analysis` are, precisely. - -## Inputs - -Rust Analyzer never does any I/O itself, all inputs get passed explicitly via -the `AnalysisHost::apply_change` method, which accepts a single argument, a -`Change`. [`Change`] is a builder for a single change -"transaction", so it suffices to study its methods to understand all of the -input data. - -[`Change`]: https://github.com/rust-lang/rust-analyzer/blob/master/crates/base_db/src/change.rs#L14-L89 - -The `(add|change|remove)_file` methods control the set of the input files, where -each file has an integer id (`FileId`, picked by the client), text (`String`) -and a filesystem path. Paths are tricky; they'll be explained below, in source roots -section, together with the `add_root` method. The `add_library` method allows us to add a -group of files which are assumed to rarely change. It's mostly an optimization -and does not change the fundamental picture. - -The `set_crate_graph` method allows us to control how the input files are partitioned -into compilation units -- crates. It also controls (in theory, not implemented -yet) `cfg` flags. `CrateGraph` is a directed acyclic graph of crates. Each crate -has a root `FileId`, a set of active `cfg` flags and a set of dependencies. Each -dependency is a pair of a crate and a name. It is possible to have two crates -with the same root `FileId` but different `cfg`-flags/dependencies. This model -is lower than Cargo's model of packages: each Cargo package consists of several -targets, each of which is a separate crate (or several crates, if you try -different feature combinations). - -Procedural macros should become inputs as well, but currently they are not -supported. Procedural macro will be a black box `Box TokenStream>` -function, and will be inserted into the crate graph just like dependencies. - -Soon we'll talk how we build an LSP server on top of `Analysis`, but first, -let's deal with that paths issue. - -## Source roots (a.k.a. "Filesystems are horrible") - -This is a non-essential section, feel free to skip. - -The previous section said that the filesystem path is an attribute of a file, -but this is not the whole truth. Making it an absolute `PathBuf` will be bad for -several reasons. First, filesystems are full of (platform-dependent) edge cases: - -* It's hard (requires a syscall) to decide if two paths are equivalent. -* Some filesystems are case-sensitive (e.g. macOS). -* Paths are not necessarily UTF-8. -* Symlinks can form cycles. - -Second, this might hurt the reproducibility and hermeticity of builds. In theory, -moving a project from `/foo/bar/my-project` to `/spam/eggs/my-project` should -not change a bit in the output. However, if the absolute path is a part of the -input, it is at least in theory observable, and *could* affect the output. - -Yet another problem is that we really *really* want to avoid doing I/O, but with -Rust the set of "input" files is not necessarily known up-front. In theory, you -can have `#[path="/dev/random"] mod foo;`. - -To solve (or explicitly refuse to solve) these problems rust-analyzer uses the -concept of a "source root". Roughly speaking, source roots are the contents of a -directory on a file systems, like `/home/matklad/projects/rustraytracer/**.rs`. - -More precisely, all files (`FileId`s) are partitioned into disjoint -`SourceRoot`s. Each file has a relative UTF-8 path within the `SourceRoot`. -`SourceRoot` has an identity (integer ID). Crucially, the root path of the -source root itself is unknown to the analyzer: A client is supposed to maintain a -mapping between `SourceRoot` IDs (which are assigned by the client) and actual -`PathBuf`s. `SourceRoot`s give a sane tree model of the file system to the -analyzer. - -Note that `mod`, `#[path]` and `include!()` can only reference files from the -same source root. It is of course possible to explicitly add extra files to -the source root, even `/dev/random`. - -## Language Server Protocol - -Now let's see how the `Analysis` API is exposed via the JSON RPC based language server protocol. The -hard part here is managing changes (which can come either from the file system -or from the editor) and concurrency (we want to spawn background jobs for things -like syntax highlighting). We use the event loop pattern to manage the zoo, and -the loop is the [`main_loop_inner`] function. The [`main_loop`] does a one-time -initialization and tearing down of the resources. - -[`main_loop`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L51-L110 -[`main_loop_inner`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L156-L258 - - -Let's walk through a typical analyzer session! - -First, we need to figure out what to analyze. To do this, we run `cargo -metadata` to learn about Cargo packages for current workspace and dependencies, -and we run `rustc --print sysroot` and scan the "sysroot" (the directory containing the current Rust toolchain's files) to learn about crates like -`std`. Currently we load this configuration once at the start of the server, but -it should be possible to dynamically reconfigure it later without restart. - -[main_loop.rs#L62-L70](https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L62-L70) - -The [`ProjectModel`] we get after this step is very Cargo and sysroot specific, -it needs to be lowered to get the input in the form of `Change`. This -happens in [`ServerWorldState::new`] method. Specifically - -* Create a `SourceRoot` for each Cargo package and sysroot. -* Schedule a filesystem scan of the roots. -* Create an analyzer's `Crate` for each Cargo **target** and sysroot crate. -* Setup dependencies between the crates. - -[`ProjectModel`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/project_model.rs#L16-L20 -[`ServerWorldState::new`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/server_world.rs#L38-L160 - -The results of the scan (which may take a while) will be processed in the body -of the main loop, just like any other change. Here's where we handle: - -* [File system changes](https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L194) -* [Changes from the editor](https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L377) - -After a single loop's turn, we group the changes into one `Change` and -[apply] it. This always happens on the main thread and blocks the loop. - -[apply]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/server_world.rs#L216 - -To handle requests, like ["goto definition"], we create an instance of the -`Analysis` and [`schedule`] the task (which consumes `Analysis`) on the -threadpool. [The task] calls the corresponding `Analysis` method, while -massaging the types into the LSP representation. Keep in mind that if we are -executing "goto definition" on the threadpool and a new change comes in, the -task will be canceled as soon as the main loop calls `apply_change` on the -`AnalysisHost`. - -["goto definition"]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/server_world.rs#L216 -[`schedule`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L426-L455 -[The task]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop/handlers.rs#L205-L223 - -This concludes the overview of the analyzer's programing *interface*. Next, let's -dig into the implementation! - -## Salsa - -The most straightforward way to implement an "apply change, get analysis, repeat" -API would be to maintain the input state and to compute all possible analysis -information from scratch after every change. This works, but scales poorly with -the size of the project. To make this fast, we need to take advantage of the -fact that most of the changes are small, and that analysis results are unlikely -to change significantly between invocations. - -To do this we use [salsa]: a framework for incremental on-demand computation. -You can skip the rest of the section if you are familiar with `rustc`'s red-green -algorithm (which is used for incremental compilation). - -[salsa]: https://github.com/salsa-rs/salsa - -It's better to refer to salsa's docs to learn about it. Here's a small excerpt: - -The key idea of salsa is that you define your program as a set of queries. Every -query is used like a function `K -> V` that maps from some key of type `K` to a value -of type `V`. Queries come in two basic varieties: - -* **Inputs**: the base inputs to your system. You can change these whenever you - like. - -* **Functions**: pure functions (no side effects) that transform your inputs - into other values. The results of queries are memoized to avoid recomputing - them a lot. When you make changes to the inputs, we'll figure out (fairly - intelligently) when we can re-use these memoized values and when we have to - recompute them. - -For further discussion, its important to understand one bit of "fairly -intelligently". Suppose we have two functions, `f1` and `f2`, and one input, -`z`. We call `f1(X)` which in turn calls `f2(Y)` which inspects `i(Z)`. `i(Z)` -returns some value `V1`, `f2` uses that and returns `R1`, `f1` uses that and -returns `O`. Now, let's change `i` at `Z` to `V2` from `V1` and try to compute -`f1(X)` again. Because `f1(X)` (transitively) depends on `i(Z)`, we can't just -reuse its value as is. However, if `f2(Y)` is *still* equal to `R1` (despite -`i`'s change), we, in fact, *can* reuse `O` as result of `f1(X)`. And that's how -salsa works: it recomputes results in *reverse* order, starting from inputs and -progressing towards outputs, stopping as soon as it sees an intermediate value -that hasn't changed. If this sounds confusing to you, don't worry: it is -confusing. This illustration by @killercup might help: - -step 1 - -step 2 - -step 3 - -step 4 - -## Salsa Input Queries - -All analyzer information is stored in a salsa database. `Analysis` and -`AnalysisHost` types are newtype wrappers for [`RootDatabase`] -- a salsa -database. - -[`RootDatabase`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/db.rs#L88-L134 - -Salsa input queries are defined in [`FilesDatabase`] (which is a part of -`RootDatabase`). They closely mirror the familiar `Change` structure: -indeed, what `apply_change` does is it sets the values of input queries. - -[`FilesDatabase`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/base_db/src/input.rs#L150-L174 - -## From text to semantic model - -The bulk of the rust-analyzer is transforming input text into a semantic model of -Rust code: a web of entities like modules, structs, functions and traits. - -An important fact to realize is that (unlike most other languages like C# or -Java) there is not a one-to-one mapping between the source code and the semantic model. A -single function definition in the source code might result in several semantic -functions: for example, the same source file might get included as a module in -several crates or a single crate might be present in the compilation DAG -several times, with different sets of `cfg`s enabled. The IDE-specific task of -mapping source code into a semantic model is inherently imprecise for -this reason and gets handled by the [`source_binder`]. - -[`source_binder`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/source_binder.rs - -The semantic interface is declared in the [`code_model_api`] module. Each entity is -identified by an integer ID and has a bunch of methods which take a salsa database -as an argument and returns other entities (which are also IDs). Internally, these -methods invoke various queries on the database to build the model on demand. -Here's [the list of queries]. - -[`code_model_api`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/code_model_api.rs -[the list of queries]: https://github.com/rust-lang/rust-analyzer/blob/7e84440e25e19529e4ff8a66e521d1b06349c6ec/crates/hir/src/db.rs#L20-L106 - -The first step of building the model is parsing the source code. - -## Syntax trees - -An important property of the Rust language is that each file can be parsed in -isolation. Unlike, say, `C++`, an `include` can't change the meaning of the -syntax. For this reason, rust-analyzer can build a syntax tree for each "source -file", which could then be reused by several semantic models if this file -happens to be a part of several crates. - -The representation of syntax trees that rust-analyzer uses is similar to that of `Roslyn` -and Swift's new [libsyntax]. Swift's docs give an excellent overview of the -approach, so I skip this part here and instead outline the main characteristics -of the syntax trees: - -* Syntax trees are fully lossless. Converting **any** text to a syntax tree and - back is a total identity function. All whitespace and comments are explicitly - represented in the tree. - -* Syntax nodes have generic `(next|previous)_sibling`, `parent`, - `(first|last)_child` functions. You can get from any one node to any other - node in the file using only these functions. - -* Syntax nodes know their range (start offset and length) in the file. - -* Syntax nodes share the ownership of their syntax tree: if you keep a reference - to a single function, the whole enclosing file is alive. - -* Syntax trees are immutable and the cost of replacing the subtree is - proportional to the depth of the subtree. Read Swift's docs to learn how - immutable + parent pointers + cheap modification is possible. - -* Syntax trees are build on best-effort basis. All accessor methods return - `Option`s. The tree for `fn foo` will contain a function declaration with - `None` for parameter list and body. - -* Syntax trees do not know the file they are built from, they only know about - the text. - -The implementation is based on the generic [rowan] crate on top of which a -[rust-specific] AST is generated. - -[libsyntax]: https://github.com/apple/swift/tree/5e2c815edfd758f9b1309ce07bfc01c4bc20ec23/lib/Syntax -[rowan]: https://github.com/rust-analyzer/rowan/tree/100a36dc820eb393b74abe0d20ddf99077b61f88 -[rust-specific]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_syntax/src/ast/generated.rs - -The next step in constructing the semantic model is ... - -## Building a Module Tree - -The algorithm for building a tree of modules is to start with a crate root -(remember, each `Crate` from a `CrateGraph` has a `FileId`), collect all `mod` -declarations and recursively process child modules. This is handled by the -[`module_tree_query`], with two slight variations. - -[`module_tree_query`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/module_tree.rs#L116-L123 - -First, rust-analyzer builds a module tree for all crates in a source root -simultaneously. The main reason for this is historical (`module_tree` predates -`CrateGraph`), but this approach also enables accounting for files which are not -part of any crate. That is, if you create a file but do not include it as a -submodule anywhere, you still get semantic completion, and you get a warning -about a free-floating module (the actual warning is not implemented yet). - -The second difference is that `module_tree_query` does not *directly* depend on -the "parse" query (which is confusingly called `source_file`). Why would calling -the parse directly be bad? Suppose the user changes the file slightly, by adding -an insignificant whitespace. Adding whitespace changes the parse tree (because -it includes whitespace), and that means recomputing the whole module tree. - -We deal with this problem by introducing an intermediate [`submodules_query`]. -This query processes the syntax tree and extracts a set of declared submodule -names. Now, changing the whitespace results in `submodules_query` being -re-executed for a *single* module, but because the result of this query stays -the same, we don't have to re-execute [`module_tree_query`]. In fact, we only -need to re-execute it when we add/remove new files or when we change mod -declarations. - -[`submodules_query`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/module_tree.rs#L41 - -We store the resulting modules in a `Vec`-based indexed arena. The indices in -the arena becomes module IDs. And this brings us to the next topic: -assigning IDs in the general case. - -## Location Interner pattern - -One way to assign IDs is how we've dealt with modules: Collect all items into a -single array in some specific order and use the index in the array as an ID. The -main drawback of this approach is that these IDs are not stable: Adding a new item can -shift the IDs of all other items. This works for modules, because adding a module is -a comparatively rare operation, but would be less convenient for, for example, -functions. - -Another solution here is positional IDs: We can identify a function as "the -function with name `foo` in a ModuleId(92) module". Such locations are stable: -adding a new function to the module (unless it is also named `foo`) does not -change the location. However, such "ID" types ceases to be a `Copy`able integer and in -general can become pretty large if we account for nesting (for example: "third parameter of -the `foo` function of the `bar` `impl` in the `baz` module"). - -[`LocationInterner`] allows us to combine the benefits of positional and numeric -IDs. It is a bidirectional append-only map between locations and consecutive -integers which can "intern" a location and return an integer ID back. The salsa -database we use includes a couple of [interners]. How to "garbage collect" -unused locations is an open question. - -[`LocationInterner`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/base_db/src/loc2id.rs#L65-L71 -[interners]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/db.rs#L22-L23 - -For example, we use `LocationInterner` to assign IDs to definitions of functions, -structs, enums, etc. The location, [`DefLoc`] contains two bits of information: - -* the ID of the module which contains the definition, -* the ID of the specific item in the modules source code. - -We "could" use a text offset for the location of a particular item, but that would play -badly with salsa: offsets change after edits. So, as a rule of thumb, we avoid -using offsets, text ranges or syntax trees as keys and values for queries. What -we do instead is we store "index" of the item among all of the items of a file -(so, a positional based ID, but localized to a single file). - -[`DefLoc`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/ids.rs#L127-L139 - -One thing we've glossed over for the time being is support for macros. We have -only proof of concept handling of macros at the moment, but they are extremely -interesting from an "assigning IDs" perspective. - -## Macros and recursive locations - -The tricky bit about macros is that they effectively create new source files. -While we can use `FileId`s to refer to original files, we can't just assign them -willy-nilly to the pseudo files of macro expansion. Instead, we use a special -ID, [`HirFileId`] to refer to either a usual file or a macro-generated file: - -```rust -enum HirFileId { - FileId(FileId), - Macro(MacroCallId), -} -``` - -`MacroCallId` is an interned ID that specifies a particular macro invocation. -Its `MacroCallLoc` contains: - -* `ModuleId` of the containing module -* `HirFileId` of the containing file or pseudo file -* an index of this particular macro invocation in this file (positional id - again). - -Note how `HirFileId` is defined in terms of `MacroCallLoc` which is defined in -terms of `HirFileId`! This does not recur infinitely though: any chain of -`HirFileId`s bottoms out in `HirFileId::FileId`, that is, some source file -actually written by the user. - -[`HirFileId`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/ids.rs#L18-L125 - -Now that we understand how to identify a definition, in a source or in a -macro-generated file, we can discuss name resolution a bit. - -## Name resolution - -Name resolution faces the same problem as the module tree: if we look at the -syntax tree directly, we'll have to recompute name resolution after every -modification. The solution to the problem is the same: We [lower] the source code of -each module into a position-independent representation which does not change if -we modify bodies of the items. After that we [loop] resolving all imports until -we've reached a fixed point. - -[lower]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/lower.rs#L113-L117 -[loop]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres.rs#L186-L196 - -And, given all our preparation with IDs and a position-independent representation, -it is satisfying to [test] that typing inside function body does not invalidate -name resolution results. - -[test]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/tests.rs#L376 - -An interesting fact about name resolution is that it "erases" all of the -intermediate paths from the imports: in the end, we know which items are defined -and which items are imported in each module, but, if the import was `use -foo::bar::baz`, we deliberately forget what modules `foo` and `bar` resolve to. - -To serve "goto definition" requests on intermediate segments we need this info -in the IDE, however. Luckily, we need it only for a tiny fraction of imports, so we just ask -the module explicitly, "What does the path `foo::bar` resolve to?". This is a -general pattern: we try to compute the minimal possible amount of information -during analysis while allowing IDE to ask for additional specific bits. - -Name resolution is also a good place to introduce another salsa pattern used -throughout the analyzer: - -## Source Map pattern - -Due to an obscure edge case in completion, IDE needs to know the syntax node of -a use statement which imported the given completion candidate. We can't just -store the syntax node as a part of name resolution: this will break -incrementality, due to the fact that syntax changes after every file -modification. - -We solve this problem during the lowering step of name resolution. The lowering -query actually produces a *pair* of outputs: `LoweredModule` and [`SourceMap`]. -The `LoweredModule` module contains [imports], but in a position-independent form. -The `SourceMap` contains a mapping from position-independent imports to -(position-dependent) syntax nodes. - -The result of this basic lowering query changes after every modification. But -there's an intermediate [projection query] which returns only the first -position-independent part of the lowering. The result of this query is stable. -Naturally, name resolution [uses] this stable projection query. - -[imports]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/lower.rs#L52-L59 -[`SourceMap`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/lower.rs#L52-L59 -[projection query]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/lower.rs#L97-L103 -[uses]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/query_definitions.rs#L49 - -## Type inference - -First of all, implementation of type inference in rust-analyzer was spearheaded -by [@flodiebold]. [#327] was an awesome Christmas present, thank you, Florian! - -Type inference runs on per-function granularity and uses the patterns we've -discussed previously. - -First, we [lower the AST] of a function body into a position-independent -representation. In this representation, each expression is assigned a -[positional ID]. Alongside the lowered expression, [a source map] is produced, -which maps between expression ids and original syntax. This lowering step also -deals with "incomplete" source trees by replacing missing expressions by an -explicit `Missing` expression. - -Given the lowered body of the function, we can now run [type inference] and -construct a mapping from `ExprId`s to types. - -[@flodiebold]: https://github.com/flodiebold -[#327]: https://github.com/rust-lang/rust-analyzer/pull/327 -[lower the AST]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/expr.rs -[positional ID]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/expr.rs#L13-L15 -[a source map]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/expr.rs#L41-L44 -[type inference]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/ty.rs#L1208-L1223 - -## Tying it all together: completion - -To conclude the overview of the rust-analyzer, let's trace the request for -(type-inference powered!) code completion! - -We start by [receiving a message] from the language client. We decode the -message as a request for completion and [schedule it on the threadpool]. This is -the place where we [catch] canceled errors if, immediately after completion, the -client sends some modification. - -In [the handler], we deserialize LSP requests into rust-analyzer specific data -types (by converting a file url into a numeric `FileId`), [ask analysis for -completion] and serialize results into the LSP. - -The [completion implementation] is finally the place where we start doing the actual -work. The first step is to collect the `CompletionContext` -- a struct which -describes the cursor position in terms of Rust syntax and semantics. For -example, `function_syntax: Option<&'a ast::FnDef>` stores a reference to -the enclosing function *syntax*, while `function: Option` is the -`Def` for this function. - -To construct the context, we first do an ["IntelliJ Trick"]: we insert a dummy -identifier at the cursor's position and parse this modified file, to get a -reasonably looking syntax tree. Then we do a bunch of "classification" routines -to figure out the context. For example, we [find an ancestor `fn` node] and we get a -[semantic model] for it (using the lossy `source_binder` infrastructure). - -The second step is to run a [series of independent completion routines]. Let's -take a closer look at [`complete_dot`], which completes fields and methods in -`foo.bar|`. First we extract a semantic function and a syntactic receiver -expression out of the `Context`. Then we run type-inference for this single -function and map our syntactic expression to `ExprId`. Using the ID, we figure -out the type of the receiver expression. Then we add all fields & methods from -the type to completion. - -[receiving a message]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L203 -[schedule it on the threadpool]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L428 -[catch]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L436-L442 -[the handler]: https://salsa.zulipchat.com/#narrow/stream/181542-rfcs.2Fsalsa-query-group/topic/design.20next.20steps -[ask analysis for completion]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/lib.rs#L439-L444 -[completion implementation]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion.rs#L46-L62 -[`CompletionContext`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/completion_context.rs#L14-L37 -["IntelliJ Trick"]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/completion_context.rs#L72-L75 -[find an ancestor `fn` node]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/completion_context.rs#L116-L120 -[semantic model]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/completion_context.rs#L123 -[series of independent completion routines]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion.rs#L52-L59 -[`complete_dot`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/complete_dot.rs#L6-L22 diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md deleted file mode 100644 index 5040643d34a32..0000000000000 --- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md +++ /dev/null @@ -1,761 +0,0 @@ - - -# LSP Extensions - -This document describes LSP extensions used by rust-analyzer. -It's a best effort document, when in doubt, consult the source (and send a PR with clarification ;-) ). -We aim to upstream all non Rust-specific extensions to the protocol, but this is not a top priority. -All capabilities are enabled via the `experimental` field of `ClientCapabilities` or `ServerCapabilities`. -Requests which we hope to upstream live under `experimental/` namespace. -Requests, which are likely to always remain specific to `rust-analyzer` are under `rust-analyzer/` namespace. - -If you want to be notified about the changes to this document, subscribe to [#4604](https://github.com/rust-lang/rust-analyzer/issues/4604). - -## UTF-8 offsets - -rust-analyzer supports clangd's extension for opting into UTF-8 as the coordinate space for offsets (by default, LSP uses UTF-16 offsets). - -https://clangd.llvm.org/extensions.html#utf-8-offsets - -## Configuration in `initializationOptions` - -**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/567 - -The `initializationOptions` field of the `InitializeParams` of the initialization request should contain the `"rust-analyzer"` section of the configuration. - -`rust-analyzer` normally sends a `"workspace/configuration"` request with `{ "items": ["rust-analyzer"] }` payload. -However, the server can't do this during initialization. -At the same time some essential configuration parameters are needed early on, before servicing requests. -For this reason, we ask that `initializationOptions` contains the configuration, as if the server did make a `"workspace/configuration"` request. - -If a language client does not know about `rust-analyzer`'s configuration options it can get sensible defaults by doing any of the following: - * Not sending `initializationOptions` - * Sending `"initializationOptions": null` - * Sending `"initializationOptions": {}` - -## Snippet `TextEdit` - -**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/724 - -**Experimental Client Capability:** `{ "snippetTextEdit": boolean }` - -If this capability is set, `WorkspaceEdit`s returned from `codeAction` requests and `TextEdit`s returned from `textDocument/onTypeFormatting` requests might contain `SnippetTextEdit`s instead of usual `TextEdit`s: - -```typescript -interface SnippetTextEdit extends TextEdit { - insertTextFormat?: InsertTextFormat; - annotationId?: ChangeAnnotationIdentifier; -} -``` - -```typescript -export interface TextDocumentEdit { - textDocument: OptionalVersionedTextDocumentIdentifier; - edits: (TextEdit | SnippetTextEdit)[]; -} -``` - -When applying such code action or text edit, the editor should insert snippet, with tab stops and placeholder. -At the moment, rust-analyzer guarantees that only a single edit will have `InsertTextFormat.Snippet`. - -### Example - -"Add `derive`" code action transforms `struct S;` into `#[derive($0)] struct S;` - -### Unresolved Questions - -* Where exactly are `SnippetTextEdit`s allowed (only in code actions at the moment)? -* Can snippets span multiple files (so far, no)? - -## `CodeAction` Groups - -**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/994 - -**Experimental Client Capability:** `{ "codeActionGroup": boolean }` - -If this capability is set, `CodeAction`s returned from the server contain an additional field, `group`: - -```typescript -interface CodeAction { - title: string; - group?: string; - ... -} -``` - -All code-actions with the same `group` should be grouped under single (extendable) entry in lightbulb menu. -The set of actions `[ { title: "foo" }, { group: "frobnicate", title: "bar" }, { group: "frobnicate", title: "baz" }]` should be rendered as - -``` -💡 - +-------------+ - | foo | - +-------------+-----+ - | frobnicate >| bar | - +-------------+-----+ - | baz | - +-----+ -``` - -Alternatively, selecting `frobnicate` could present a user with an additional menu to choose between `bar` and `baz`. - -### Example - -```rust -fn main() { - let x: Entry/*cursor here*/ = todo!(); -} -``` - -Invoking code action at this position will yield two code actions for importing `Entry` from either `collections::HashMap` or `collection::BTreeMap`, grouped under a single "import" group. - -### Unresolved Questions - -* Is a fixed two-level structure enough? -* Should we devise a general way to encode custom interaction protocols for GUI refactorings? - -## Parent Module - -**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/1002 - -**Experimental Server Capability:** `{ "parentModule": boolean }` - -This request is sent from client to server to handle "Goto Parent Module" editor action. - -**Method:** `experimental/parentModule` - -**Request:** `TextDocumentPositionParams` - -**Response:** `Location | Location[] | LocationLink[] | null` - - -### Example - -```rust -// src/main.rs -mod foo; -// src/foo.rs - -/* cursor here*/ -``` - -`experimental/parentModule` returns a single `Link` to the `mod foo;` declaration. - -### Unresolved Question - -* An alternative would be to use a more general "gotoSuper" request, which would work for super methods, super classes and super modules. - This is the approach IntelliJ Rust is taking. - However, experience shows that super module (which generally has a feeling of navigation between files) should be separate. - If you want super module, but the cursor happens to be inside an overridden function, the behavior with single "gotoSuper" request is surprising. - -## Join Lines - -**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/992 - -**Experimental Server Capability:** `{ "joinLines": boolean }` - -This request is sent from client to server to handle "Join Lines" editor action. - -**Method:** `experimental/joinLines` - -**Request:** - -```typescript -interface JoinLinesParams { - textDocument: TextDocumentIdentifier, - /// Currently active selections/cursor offsets. - /// This is an array to support multiple cursors. - ranges: Range[], -} -``` - -**Response:** `TextEdit[]` - -### Example - -```rust -fn main() { - /*cursor here*/let x = { - 92 - }; -} -``` - -`experimental/joinLines` yields (curly braces are automagically removed) - -```rust -fn main() { - let x = 92; -} -``` - -### Unresolved Question - -* What is the position of the cursor after `joinLines`? - Currently, this is left to editor's discretion, but it might be useful to specify on the server via snippets. - However, it then becomes unclear how it works with multi cursor. - -## On Enter - -**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/1001 - -**Experimental Server Capability:** `{ "onEnter": boolean }` - -This request is sent from client to server to handle the Enter key press. - -**Method:** `experimental/onEnter` - -**Request:**: `TextDocumentPositionParams` - -**Response:** - -```typescript -SnippetTextEdit[] -``` - -### Example - -```rust -fn main() { - // Some /*cursor here*/ docs - let x = 92; -} -``` - -`experimental/onEnter` returns the following snippet - -```rust -fn main() { - // Some - // $0 docs - let x = 92; -} -``` - -The primary goal of `onEnter` is to handle automatic indentation when opening a new line. -This is not yet implemented. -The secondary goal is to handle fixing up syntax, like continuing doc strings and comments, and escaping `\n` in string literals. - -As proper cursor positioning is raison-d'etat for `onEnter`, it uses `SnippetTextEdit`. - -### Unresolved Question - -* How to deal with synchronicity of the request? - One option is to require the client to block until the server returns the response. - Another option is to do a OT-style merging of edits from client and server. - A third option is to do a record-replay: client applies heuristic on enter immediately, then applies all user's keypresses. - When the server is ready with the response, the client rollbacks all the changes and applies the recorded actions on top of the correct response. -* How to deal with multiple carets? -* Should we extend this to arbitrary typed events and not just `onEnter`? - -## Structural Search Replace (SSR) - -**Experimental Server Capability:** `{ "ssr": boolean }` - -This request is sent from client to server to handle structural search replace -- automated syntax tree based transformation of the source. - -**Method:** `experimental/ssr` - -**Request:** - -```typescript -interface SsrParams { - /// Search query. - /// The specific syntax is specified outside of the protocol. - query: string, - /// If true, only check the syntax of the query and don't compute the actual edit. - parseOnly: boolean, - /// The current text document. This and `position` will be used to determine in what scope - /// paths in `query` should be resolved. - textDocument: TextDocumentIdentifier; - /// Position where SSR was invoked. - position: Position; - /// Current selections. Search/replace will be restricted to these if non-empty. - selections: Range[]; -} -``` - -**Response:** - -```typescript -WorkspaceEdit -``` - -### Example - -SSR with query `foo($a, $b) ==>> ($a).foo($b)` will transform, eg `foo(y + 5, z)` into `(y + 5).foo(z)`. - -### Unresolved Question - -* Probably needs search without replace mode -* Needs a way to limit the scope to certain files. - -## Matching Brace - -**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/999 - -**Experimental Server Capability:** `{ "matchingBrace": boolean }` - -This request is sent from client to server to handle "Matching Brace" editor action. - -**Method:** `experimental/matchingBrace` - -**Request:** - -```typescript -interface MatchingBraceParams { - textDocument: TextDocumentIdentifier, - /// Position for each cursor - positions: Position[], -} -``` - -**Response:** - -```typescript -Position[] -``` - -### Example - -```rust -fn main() { - let x: Vec<()>/*cursor here*/ = vec![] -} -``` - -`experimental/matchingBrace` yields the position of `<`. -In many cases, matching braces can be handled by the editor. -However, some cases (like disambiguating between generics and comparison operations) need a real parser. -Moreover, it would be cool if editors didn't need to implement even basic language parsing - -### Unresolved Question - -* Should we return a nested brace structure, to allow paredit-like actions of jump *out* of the current brace pair? - This is how `SelectionRange` request works. -* Alternatively, should we perhaps flag certain `SelectionRange`s as being brace pairs? - -## Runnables - -**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/944 - -**Experimental Server Capability:** `{ "runnables": { "kinds": string[] } }` - -This request is sent from client to server to get the list of things that can be run (tests, binaries, `cargo check -p`). - -**Method:** `experimental/runnables` - -**Request:** - -```typescript -interface RunnablesParams { - textDocument: TextDocumentIdentifier; - /// If null, compute runnables for the whole file. - position?: Position; -} -``` - -**Response:** `Runnable[]` - -```typescript -interface Runnable { - label: string; - /// If this Runnable is associated with a specific function/module, etc, the location of this item - location?: LocationLink; - /// Running things is necessary technology specific, `kind` needs to be advertised via server capabilities, - // the type of `args` is specific to `kind`. The actual running is handled by the client. - kind: string; - args: any; -} -``` - -rust-analyzer supports only one `kind`, `"cargo"`. The `args` for `"cargo"` look like this: - -```typescript -{ - workspaceRoot?: string; - cargoArgs: string[]; - cargoExtraArgs: string[]; - executableArgs: string[]; - expectTest?: boolean; - overrideCargo?: string; -} -``` - -## Open External Documentation - -This request is sent from client to server to get a URL to documentation for the symbol under the cursor, if available. - -**Method** `experimental/externalDocs` - -**Request:**: `TextDocumentPositionParams` - -**Response** `string | null` - - -## Analyzer Status - -**Method:** `rust-analyzer/analyzerStatus` - -**Request:** - -```typescript -interface AnalyzerStatusParams { - /// If specified, show dependencies of the current file. - textDocument?: TextDocumentIdentifier; -} -``` - -**Response:** `string` - -Returns internal status message, mostly for debugging purposes. - -## Reload Workspace - -**Method:** `rust-analyzer/reloadWorkspace` - -**Request:** `null` - -**Response:** `null` - -Reloads project information (that is, re-executes `cargo metadata`). - -## Server Status - -**Experimental Client Capability:** `{ "serverStatusNotification": boolean }` - -**Method:** `experimental/serverStatus` - -**Notification:** - -```typescript -interface ServerStatusParams { - /// `ok` means that the server is completely functional. - /// - /// `warning` means that the server is partially functional. - /// It can answer correctly to most requests, but some results - /// might be wrong due to, for example, some missing dependencies. - /// - /// `error` means that the server is not functional. For example, - /// there's a fatal build configuration problem. The server might - /// still give correct answers to simple requests, but most results - /// will be incomplete or wrong. - health: "ok" | "warning" | "error", - /// Is there any pending background work which might change the status? - /// For example, are dependencies being downloaded? - quiescent: boolean, - /// Explanatory message to show on hover. - message?: string, -} -``` - -This notification is sent from server to client. -The client can use it to display *persistent* status to the user (in modline). -It is similar to the `showMessage`, but is intended for stares rather than point-in-time events. - -Note that this functionality is intended primarily to inform the end user about the state of the server. -In particular, it's valid for the client to completely ignore this extension. -Clients are discouraged from but are allowed to use the `health` status to decide if it's worth sending a request to the server. - -## Syntax Tree - -**Method:** `rust-analyzer/syntaxTree` - -**Request:** - -```typescript -interface SyntaxTreeParams { - textDocument: TextDocumentIdentifier, - range?: Range, -} -``` - -**Response:** `string` - -Returns textual representation of a parse tree for the file/selected region. -Primarily for debugging, but very useful for all people working on rust-analyzer itself. - -## View Hir - -**Method:** `rust-analyzer/viewHir` - -**Request:** `TextDocumentPositionParams` - -**Response:** `string` - -Returns a textual representation of the HIR of the function containing the cursor. -For debugging or when working on rust-analyzer itself. - -## View File Text - -**Method:** `rust-analyzer/viewFileText` - -**Request:** `TextDocumentIdentifier` - -**Response:** `string` - -Returns the text of a file as seen by the server. -This is for debugging file sync problems. - -## View ItemTree - -**Method:** `rust-analyzer/viewItemTree` - -**Request:** - -```typescript -interface ViewItemTreeParams { - textDocument: TextDocumentIdentifier, -} -``` - -**Response:** `string` - -Returns a textual representation of the `ItemTree` of the currently open file, for debugging. - -## View Crate Graph - -**Method:** `rust-analyzer/viewCrateGraph` - -**Request:** - -```typescript -interface ViewCrateGraphParams { - full: boolean, -} -``` - -**Response:** `string` - -Renders rust-analyzer's crate graph as an SVG image. - -If `full` is `true`, the graph includes non-workspace crates (crates.io dependencies as well as sysroot crates). - -## Shuffle Crate Graph - -**Method:** `rust-analyzer/shuffleCrateGraph` - -**Request:** `null` - -Shuffles the crate IDs in the crate graph, for debugging purposes. - -## Expand Macro - -**Method:** `rust-analyzer/expandMacro` - -**Request:** - -```typescript -interface ExpandMacroParams { - textDocument: TextDocumentIdentifier, - position: Position, -} -``` - -**Response:** - -```typescript -interface ExpandedMacro { - name: string, - expansion: string, -} -``` - -Expands macro call at a given position. - -## Hover Actions - -**Experimental Client Capability:** `{ "hoverActions": boolean }` - -If this capability is set, `Hover` request returned from the server might contain an additional field, `actions`: - -```typescript -interface Hover { - ... - actions?: CommandLinkGroup[]; -} - -interface CommandLink extends Command { - /** - * A tooltip for the command, when represented in the UI. - */ - tooltip?: string; -} - -interface CommandLinkGroup { - title?: string; - commands: CommandLink[]; -} -``` - -Such actions on the client side are appended to a hover bottom as command links: -``` - +-----------------------------+ - | Hover content | - | | - +-----------------------------+ - | _Action1_ | _Action2_ | <- first group, no TITLE - +-----------------------------+ - | TITLE _Action1_ | _Action2_ | <- second group - +-----------------------------+ - ... -``` - -## Open Cargo.toml - -**Upstream Issue:** https://github.com/rust-lang/rust-analyzer/issues/6462 - -**Experimental Server Capability:** `{ "openCargoToml": boolean }` - -This request is sent from client to server to open the current project's Cargo.toml - -**Method:** `experimental/openCargoToml` - -**Request:** `OpenCargoTomlParams` - -**Response:** `Location | null` - - -### Example - -```rust -// Cargo.toml -[package] -// src/main.rs - -/* cursor here*/ -``` - -`experimental/openCargoToml` returns a single `Link` to the start of the `[package]` keyword. - -## Related tests - -This request is sent from client to server to get the list of tests for the specified position. - -**Method:** `rust-analyzer/relatedTests` - -**Request:** `TextDocumentPositionParams` - -**Response:** `TestInfo[]` - -```typescript -interface TestInfo { - runnable: Runnable; -} -``` - -## Hover Range - -**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/377 - -**Experimental Server Capability:** { "hoverRange": boolean } - -This extension allows passing a `Range` as a `position` field of `HoverParams`. -The primary use-case is to use the hover request to show the type of the expression currently selected. - -```typescript -interface HoverParams extends WorkDoneProgressParams { - textDocument: TextDocumentIdentifier; - position: Range | Position; -} -``` -Whenever the client sends a `Range`, it is understood as the current selection and any hover included in the range will show the type of the expression if possible. - -### Example - -```rust -fn main() { - let expression = $01 + 2 * 3$0; -} -``` - -Triggering a hover inside the selection above will show a result of `i32`. - -## Move Item - -**Upstream Issue:** https://github.com/rust-lang/rust-analyzer/issues/6823 - -This request is sent from client to server to move item under cursor or selection in some direction. - -**Method:** `experimental/moveItem` - -**Request:** `MoveItemParams` - -**Response:** `SnippetTextEdit[]` - -```typescript -export interface MoveItemParams { - textDocument: TextDocumentIdentifier, - range: Range, - direction: Direction -} - -export const enum Direction { - Up = "Up", - Down = "Down" -} -``` - -## Workspace Symbols Filtering - -**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/941 - -**Experimental Server Capability:** `{ "workspaceSymbolScopeKindFiltering": boolean }` - -Extends the existing `workspace/symbol` request with ability to filter symbols by broad scope and kind of symbol. -If this capability is set, `workspace/symbol` parameter gains two new optional fields: - - -```typescript -interface WorkspaceSymbolParams { - /** - * Return only the symbols defined in the specified scope. - */ - searchScope?: WorkspaceSymbolSearchScope; - /** - * Return only the symbols of specified kinds. - */ - searchKind?: WorkspaceSymbolSearchKind; - ... -} - -const enum WorkspaceSymbolSearchScope { - Workspace = "workspace", - WorkspaceAndDependencies = "workspaceAndDependencies" -} - -const enum WorkspaceSymbolSearchKind { - OnlyTypes = "onlyTypes", - AllSymbols = "allSymbols" -} -``` - -## Client Commands - -**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/642 - -**Experimental Client Capability:** `{ "commands?": ClientCommandOptions }` - -Certain LSP types originating on the server, notably code lenses, embed commands. -Commands can be serviced either by the server or by the client. -However, the server doesn't know which commands are available on the client. - -This extensions allows the client to communicate this info. - - -```typescript -export interface ClientCommandOptions { - /** - * The commands to be executed on the client - */ - commands: string[]; -} -``` diff --git a/src/tools/rust-analyzer/docs/dev/style.md b/src/tools/rust-analyzer/docs/dev/style.md deleted file mode 100644 index a80eebd632961..0000000000000 --- a/src/tools/rust-analyzer/docs/dev/style.md +++ /dev/null @@ -1,1172 +0,0 @@ -Our approach to "clean code" is two-fold: - -* We generally don't block PRs on style changes. -* At the same time, all code in rust-analyzer is constantly refactored. - -It is explicitly OK for a reviewer to flag only some nits in the PR, and then send a follow-up cleanup PR for things which are easier to explain by example, cc-ing the original author. -Sending small cleanup PRs (like renaming a single local variable) is encouraged. - -When reviewing pull requests prefer extending this document to leaving -non-reusable comments on the pull request itself. - -# General - -## Scale of Changes - -Everyone knows that it's better to send small & focused pull requests. -The problem is, sometimes you *have* to, eg, rewrite the whole compiler, and that just doesn't fit into a set of isolated PRs. - -The main things to keep an eye on are the boundaries between various components. -There are three kinds of changes: - -1. Internals of a single component are changed. - Specifically, you don't change any `pub` items. - A good example here would be an addition of a new assist. - -2. API of a component is expanded. - Specifically, you add a new `pub` function which wasn't there before. - A good example here would be expansion of assist API, for example, to implement lazy assists or assists groups. - -3. A new dependency between components is introduced. - Specifically, you add a `pub use` reexport from another crate or you add a new line to the `[dependencies]` section of `Cargo.toml`. - A good example here would be adding reference search capability to the assists crates. - -For the first group, the change is generally merged as long as: - -* it works for the happy case, -* it has tests, -* it doesn't panic for the unhappy case. - -For the second group, the change would be subjected to quite a bit of scrutiny and iteration. -The new API needs to be right (or at least easy to change later). -The actual implementation doesn't matter that much. -It's very important to minimize the amount of changed lines of code for changes of the second kind. -Often, you start doing a change of the first kind, only to realize that you need to elevate to a change of the second kind. -In this case, we'll probably ask you to split API changes into a separate PR. - -Changes of the third group should be pretty rare, so we don't specify any specific process for them. -That said, adding an innocent-looking `pub use` is a very simple way to break encapsulation, keep an eye on it! - -Note: if you enjoyed this abstract hand-waving about boundaries, you might appreciate -https://www.tedinski.com/2018/02/06/system-boundaries.html - -## Crates.io Dependencies - -We try to be very conservative with usage of crates.io dependencies. -Don't use small "helper" crates (exception: `itertools` and `either` are allowed). -If there's some general reusable bit of code you need, consider adding it to the `stdx` crate. -A useful exercise is to read Cargo.lock and see if some *transitive* dependencies do not make sense for rust-analyzer. - -**Rationale:** keep compile times low, create ecosystem pressure for faster compiles, reduce the number of things which might break. - -## Commit Style - -We don't have specific rules around git history hygiene. -Maintaining clean git history is strongly encouraged, but not enforced. -Use rebase workflow, it's OK to rewrite history during PR review process. -After you are happy with the state of the code, please use [interactive rebase](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History) to squash fixup commits. - -Avoid @mentioning people in commit messages and pull request descriptions(they are added to commit message by bors). -Such messages create a lot of duplicate notification traffic during rebases. - -If possible, write Pull Request titles and descriptions from the user's perspective: - -``` -# GOOD -Make goto definition work inside macros - -# BAD -Use original span for FileId -``` - -This makes it easier to prepare a changelog. - -If the change adds a new user-visible functionality, consider recording a GIF with [peek](https://github.com/phw/peek) and pasting it into the PR description. - -To make writing the release notes easier, you can mark a pull request as a feature, fix, internal change, or minor. -Minor changes are excluded from the release notes, while the other types are distributed in their corresponding sections. -There are two ways to mark this: - -* use a `feat: `, `feature: `, `fix: `, `internal: ` or `minor: ` prefix in the PR title -* write `changelog [feature|fix|internal|skip] [description]` in a comment or in the PR description; the description is optional, and will replace the title if included. - -These comments don't have to be added by the PR author. -Editing a comment or the PR description or title is also fine, as long as it happens before the release. - -**Rationale:** clean history is potentially useful, but rarely used. -But many users read changelogs. -Including a description and GIF suitable for the changelog means less work for the maintainers on the release day. - -## Clippy - -We don't enforce Clippy. -A number of default lints have high false positive rate. -Selectively patching false-positives with `allow(clippy)` is considered worse than not using Clippy at all. -There's a `cargo lint` command which runs a subset of low-FPR lints. -Careful tweaking of `lint` is welcome. -Of course, applying Clippy suggestions is welcome as long as they indeed improve the code. - -**Rationale:** see [rust-lang/clippy#5537](https://github.com/rust-lang/rust-clippy/issues/5537). - -# Code - -## Minimal Tests - -Most tests in rust-analyzer start with a snippet of Rust code. -These snippets should be minimal -- if you copy-paste a snippet of real code into the tests, make sure to remove everything which could be removed. - -It also makes sense to format snippets more compactly (for example, by placing enum definitions like `enum E { Foo, Bar }` on a single line), -as long as they are still readable. - -When using multiline fixtures, use unindented raw string literals: - -```rust - #[test] - fn inline_field_shorthand() { - check_assist( - inline_local_variable, - r#" -struct S { foo: i32} -fn main() { - let $0foo = 92; - S { foo } -} -"#, - r#" -struct S { foo: i32} -fn main() { - S { foo: 92 } -} -"#, - ); - } -``` - -**Rationale:** - -There are many benefits to this: - -* less to read or to scroll past -* easier to understand what exactly is tested -* less stuff printed during printf-debugging -* less time to run test - -Formatting ensures that you can use your editor's "number of selected characters" feature to correlate offsets with test's source code. - -## Marked Tests - -Use -[`cov_mark::hit! / cov_mark::check!`](https://github.com/matklad/cov-mark) -when testing specific conditions. -Do not place several marks into a single test or condition. -Do not reuse marks between several tests. - -**Rationale:** marks provide an easy way to find the canonical test for each bit of code. -This makes it much easier to understand. -More than one mark per test / code branch doesn't add significantly to understanding. - -## `#[should_panic]` - -Do not use `#[should_panic]` tests. -Instead, explicitly check for `None`, `Err`, etc. - -**Rationale:** `#[should_panic]` is a tool for library authors to make sure that the API does not fail silently when misused. -`rust-analyzer` is not a library, we don't need to test for API misuse, and we have to handle any user input without panics. -Panic messages in the logs from the `#[should_panic]` tests are confusing. - -## `#[ignore]` - -Do not `#[ignore]` tests. -If the test currently does not work, assert the wrong behavior and add a fixme explaining why it is wrong. - -**Rationale:** noticing when the behavior is fixed, making sure that even the wrong behavior is acceptable (ie, not a panic). - -## Function Preconditions - -Express function preconditions in types and force the caller to provide them (rather than checking in callee): - -```rust -// GOOD -fn frobnicate(walrus: Walrus) { - ... -} - -// BAD -fn frobnicate(walrus: Option) { - let walrus = match walrus { - Some(it) => it, - None => return, - }; - ... -} -``` - -**Rationale:** this makes control flow explicit at the call site. -Call-site has more context, it often happens that the precondition falls out naturally or can be bubbled up higher in the stack. - -Avoid splitting precondition check and precondition use across functions: - -```rust -// GOOD -fn main() { - let s: &str = ...; - if let Some(contents) = string_literal_contents(s) { - - } -} - -fn string_literal_contents(s: &str) -> Option<&str> { - if s.starts_with('"') && s.ends_with('"') { - Some(&s[1..s.len() - 1]) - } else { - None - } -} - -// BAD -fn main() { - let s: &str = ...; - if is_string_literal(s) { - let contents = &s[1..s.len() - 1]; - } -} - -fn is_string_literal(s: &str) -> bool { - s.starts_with('"') && s.ends_with('"') -} -``` - -In the "Not as good" version, the precondition that `1` is a valid char boundary is checked in `is_string_literal` and used in `foo`. -In the "Good" version, the precondition check and usage are checked in the same block, and then encoded in the types. - -**Rationale:** non-local code properties degrade under change. - -When checking a boolean precondition, prefer `if !invariant` to `if negated_invariant`: - -```rust -// GOOD -if !(idx < len) { - return None; -} - -// BAD -if idx >= len { - return None; -} -``` - -**Rationale:** it's useful to see the invariant relied upon by the rest of the function clearly spelled out. - -## Control Flow - -As a special case of the previous rule, do not hide control flow inside functions, push it to the caller: - -```rust -// GOOD -if cond { - f() -} - -// BAD -fn f() { - if !cond { - return; - } - ... -} -``` - -## Assertions - -Assert liberally. -Prefer [`stdx::never!`](https://docs.rs/always-assert/0.1.2/always_assert/macro.never.html) to standard `assert!`. - -**Rationale:** See [cross cutting concern: error handling](https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/architecture.md#error-handling). - -## Getters & Setters - -If a field can have any value without breaking invariants, make the field public. -Conversely, if there is an invariant, document it, enforce it in the "constructor" function, make the field private, and provide a getter. -Never provide setters. - -Getters should return borrowed data: - -```rust -struct Person { - // Invariant: never empty - first_name: String, - middle_name: Option -} - -// GOOD -impl Person { - fn first_name(&self) -> &str { self.first_name.as_str() } - fn middle_name(&self) -> Option<&str> { self.middle_name.as_ref() } -} - -// BAD -impl Person { - fn first_name(&self) -> String { self.first_name.clone() } - fn middle_name(&self) -> &Option { &self.middle_name } -} -``` - -**Rationale:** we don't provide public API, it's cheaper to refactor than to pay getters rent. -Non-local code properties degrade under change, privacy makes invariant local. -Borrowed owned types (`&String`) disclose irrelevant details about internal representation. -Irrelevant (neither right nor wrong) things obscure correctness. - -## Useless Types - -More generally, always prefer types on the left - -```rust -// GOOD BAD -&[T] &Vec -&str &String -Option<&T> &Option -&Path &PathBuf -``` - -**Rationale:** types on the left are strictly more general. -Even when generality is not required, consistency is important. - -## Constructors - -Prefer `Default` to zero-argument `new` function. - -```rust -// GOOD -#[derive(Default)] -struct Foo { - bar: Option -} - -// BAD -struct Foo { - bar: Option -} - -impl Foo { - fn new() -> Foo { - Foo { bar: None } - } -} -``` - -Prefer `Default` even if it has to be implemented manually. - -**Rationale:** less typing in the common case, uniformity. - -Use `Vec::new` rather than `vec![]`. - -**Rationale:** uniformity, strength reduction. - -Avoid using "dummy" states to implement a `Default`. -If a type doesn't have a sensible default, empty value, don't hide it. -Let the caller explicitly decide what the right initial state is. - -## Functions Over Objects - -Avoid creating "doer" objects. -That is, objects which are created only to execute a single action. - -```rust -// GOOD -do_thing(arg1, arg2); - -// BAD -ThingDoer::new(arg1, arg2).do(); -``` - -Note that this concerns only outward API. -When implementing `do_thing`, it might be very useful to create a context object. - -```rust -pub fn do_thing(arg1: Arg1, arg2: Arg2) -> Res { - let mut ctx = Ctx { arg1, arg2 }; - ctx.run() -} - -struct Ctx { - arg1: Arg1, arg2: Arg2 -} - -impl Ctx { - fn run(self) -> Res { - ... - } -} -``` - -The difference is that `Ctx` is an impl detail here. - -Sometimes a middle ground is acceptable if this can save some busywork: - -```rust -ThingDoer::do(arg1, arg2); - -pub struct ThingDoer { - arg1: Arg1, arg2: Arg2, -} - -impl ThingDoer { - pub fn do(arg1: Arg1, arg2: Arg2) -> Res { - ThingDoer { arg1, arg2 }.run() - } - fn run(self) -> Res { - ... - } -} -``` - -**Rationale:** not bothering the caller with irrelevant details, not mixing user API with implementor API. - -## Functions with many parameters - -Avoid creating functions with many optional or boolean parameters. -Introduce a `Config` struct instead. - -```rust -// GOOD -pub struct AnnotationConfig { - pub binary_target: bool, - pub annotate_runnables: bool, - pub annotate_impls: bool, -} - -pub fn annotations( - db: &RootDatabase, - file_id: FileId, - config: AnnotationConfig -) -> Vec { - ... -} - -// BAD -pub fn annotations( - db: &RootDatabase, - file_id: FileId, - binary_target: bool, - annotate_runnables: bool, - annotate_impls: bool, -) -> Vec { - ... -} -``` - -**Rationale:** reducing churn. -If the function has many parameters, they most likely change frequently. -By packing them into a struct we protect all intermediary functions from changes. - -Do not implement `Default` for the `Config` struct, the caller has more context to determine better defaults. -Do not store `Config` as a part of the `state`, pass it explicitly. -This gives more flexibility for the caller. - -If there is variation not only in the input parameters, but in the return type as well, consider introducing a `Command` type. - -```rust -// MAYBE GOOD -pub struct Query { - pub name: String, - pub case_sensitive: bool, -} - -impl Query { - pub fn all(self) -> Vec { ... } - pub fn first(self) -> Option { ... } -} - -// MAYBE BAD -fn query_all(name: String, case_sensitive: bool) -> Vec { ... } -fn query_first(name: String, case_sensitive: bool) -> Option { ... } -``` - -## Prefer Separate Functions Over Parameters - -If a function has a `bool` or an `Option` parameter, and it is always called with `true`, `false`, `Some` and `None` literals, split the function in two. - -```rust -// GOOD -fn caller_a() { - foo() -} - -fn caller_b() { - foo_with_bar(Bar::new()) -} - -fn foo() { ... } -fn foo_with_bar(bar: Bar) { ... } - -// BAD -fn caller_a() { - foo(None) -} - -fn caller_b() { - foo(Some(Bar::new())) -} - -fn foo(bar: Option) { ... } -``` - -**Rationale:** more often than not, such functions display "`false sharing`" -- they have additional `if` branching inside for two different cases. -Splitting the two different control flows into two functions simplifies each path, and remove cross-dependencies between the two paths. -If there's common code between `foo` and `foo_with_bar`, extract *that* into a common helper. - -## Appropriate String Types - -When interfacing with OS APIs, use `OsString`, even if the original source of data is utf-8 encoded. -**Rationale:** cleanly delineates the boundary when the data goes into the OS-land. - -Use `AbsPathBuf` and `AbsPath` over `std::Path`. -**Rationale:** rust-analyzer is a long-lived process which handles several projects at the same time. -It is important not to leak cwd by accident. - -# Premature Pessimization - -## Avoid Allocations - -Avoid writing code which is slower than it needs to be. -Don't allocate a `Vec` where an iterator would do, don't allocate strings needlessly. - -```rust -// GOOD -use itertools::Itertools; - -let (first_word, second_word) = match text.split_ascii_whitespace().collect_tuple() { - Some(it) => it, - None => return, -} - -// BAD -let words = text.split_ascii_whitespace().collect::>(); -if words.len() != 2 { - return -} -``` - -**Rationale:** not allocating is almost always faster. - -## Push Allocations to the Call Site - -If allocation is inevitable, let the caller allocate the resource: - -```rust -// GOOD -fn frobnicate(s: String) { - ... -} - -// BAD -fn frobnicate(s: &str) { - let s = s.to_string(); - ... -} -``` - -**Rationale:** reveals the costs. -It is also more efficient when the caller already owns the allocation. - -## Collection Types - -Prefer `rustc_hash::FxHashMap` and `rustc_hash::FxHashSet` instead of the ones in `std::collections`. - -**Rationale:** they use a hasher that's significantly faster and using them consistently will reduce code size by some small amount. - -## Avoid Intermediate Collections - -When writing a recursive function to compute a sets of things, use an accumulator parameter instead of returning a fresh collection. -Accumulator goes first in the list of arguments. - -```rust -// GOOD -pub fn reachable_nodes(node: Node) -> FxHashSet { - let mut res = FxHashSet::default(); - go(&mut res, node); - res -} -fn go(acc: &mut FxHashSet, node: Node) { - acc.insert(node); - for n in node.neighbors() { - go(acc, n); - } -} - -// BAD -pub fn reachable_nodes(node: Node) -> FxHashSet { - let mut res = FxHashSet::default(); - res.insert(node); - for n in node.neighbors() { - res.extend(reachable_nodes(n)); - } - res -} -``` - -**Rationale:** re-use allocations, accumulator style is more concise for complex cases. - -## Avoid Monomorphization - -Avoid making a lot of code type parametric, *especially* on the boundaries between crates. - -```rust -// GOOD -fn frobnicate(f: impl FnMut()) { - frobnicate_impl(&mut f) -} -fn frobnicate_impl(f: &mut dyn FnMut()) { - // lots of code -} - -// BAD -fn frobnicate(f: impl FnMut()) { - // lots of code -} -``` - -Avoid `AsRef` polymorphism, it pays back only for widely used libraries: - -```rust -// GOOD -fn frobnicate(f: &Path) { -} - -// BAD -fn frobnicate(f: impl AsRef) { -} -``` - -**Rationale:** Rust uses monomorphization to compile generic code, meaning that for each instantiation of a generic functions with concrete types, the function is compiled afresh, *per crate*. -This allows for exceptionally good performance, but leads to increased compile times. -Runtime performance obeys 80%/20% rule -- only a small fraction of code is hot. -Compile time **does not** obey this rule -- all code has to be compiled. - -# Style - -## Order of Imports - -Separate import groups with blank lines. -Use one `use` per crate. - -Module declarations come before the imports. -Order them in "suggested reading order" for a person new to the code base. - -```rust -mod x; -mod y; - -// First std. -use std::{ ... } - -// Second, external crates (both crates.io crates and other rust-analyzer crates). -use crate_foo::{ ... } -use crate_bar::{ ... } - -// Then current crate. -use crate::{} - -// Finally, parent and child modules, but prefer `use crate::`. -use super::{} - -// Re-exports are treated as item definitions rather than imports, so they go -// after imports and modules. Use them sparingly. -pub use crate::x::Z; -``` - -**Rationale:** consistency. -Reading order is important for new contributors. -Grouping by crate allows spotting unwanted dependencies easier. - -## Import Style - -Qualify items from `hir` and `ast`. - -```rust -// GOOD -use syntax::ast; - -fn frobnicate(func: hir::Function, strukt: ast::Struct) {} - -// BAD -use hir::Function; -use syntax::ast::Struct; - -fn frobnicate(func: Function, strukt: Struct) {} -``` - -**Rationale:** avoids name clashes, makes the layer clear at a glance. - -When implementing traits from `std::fmt` or `std::ops`, import the module: - -```rust -// GOOD -use std::fmt; - -impl fmt::Display for RenameError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { .. } -} - -// BAD -impl std::fmt::Display for RenameError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { .. } -} - -// BAD -use std::ops::Deref; - -impl Deref for Widget { - type Target = str; - fn deref(&self) -> &str { .. } -} -``` - -**Rationale:** overall, less typing. -Makes it clear that a trait is implemented, rather than used. - -Avoid local `use MyEnum::*` imports. -**Rationale:** consistency. - -Prefer `use crate::foo::bar` to `use super::bar` or `use self::bar::baz`. -**Rationale:** consistency, this is the style which works in all cases. - -By default, avoid re-exports. -**Rationale:** for non-library code, re-exports introduce two ways to use something and allow for inconsistency. - -## Order of Items - -Optimize for the reader who sees the file for the first time, and wants to get a general idea about what's going on. -People read things from top to bottom, so place most important things first. - -Specifically, if all items except one are private, always put the non-private item on top. - -```rust -// GOOD -pub(crate) fn frobnicate() { - Helper::act() -} - -#[derive(Default)] -struct Helper { stuff: i32 } - -impl Helper { - fn act(&self) { - - } -} - -// BAD -#[derive(Default)] -struct Helper { stuff: i32 } - -pub(crate) fn frobnicate() { - Helper::act() -} - -impl Helper { - fn act(&self) { - - } -} -``` - -If there's a mixture of private and public items, put public items first. - -Put `struct`s and `enum`s first, functions and impls last. Order type declarations in top-down manner. - -```rust -// GOOD -struct Parent { - children: Vec -} - -struct Child; - -impl Parent { -} - -impl Child { -} - -// BAD -struct Child; - -impl Child { -} - -struct Parent { - children: Vec -} - -impl Parent { -} -``` - -**Rationale:** easier to get the sense of the API by visually scanning the file. -If function bodies are folded in the editor, the source code should read as documentation for the public API. - -## Context Parameters - -Some parameters are threaded unchanged through many function calls. -They determine the "context" of the operation. -Pass such parameters first, not last. -If there are several context parameters, consider packing them into a `struct Ctx` and passing it as `&self`. - -```rust -// GOOD -fn dfs(graph: &Graph, v: Vertex) -> usize { - let mut visited = FxHashSet::default(); - return go(graph, &mut visited, v); - - fn go(graph: &Graph, visited: &mut FxHashSet, v: usize) -> usize { - ... - } -} - -// BAD -fn dfs(v: Vertex, graph: &Graph) -> usize { - fn go(v: usize, graph: &Graph, visited: &mut FxHashSet) -> usize { - ... - } - - let mut visited = FxHashSet::default(); - go(v, graph, &mut visited) -} -``` - -**Rationale:** consistency. -Context-first works better when non-context parameter is a lambda. - -## Variable Naming - -Use boring and long names for local variables ([yay code completion](https://github.com/rust-lang/rust-analyzer/pull/4162#discussion_r417130973)). -The default name is a lowercased name of the type: `global_state: GlobalState`. -Avoid ad-hoc acronyms and contractions, but use the ones that exist consistently (`db`, `ctx`, `acc`). -Prefer American spelling (color, behavior). - -Default names: - -* `res` -- "result of the function" local variable -* `it` -- I don't really care about the name -* `n_foos` -- number of foos (prefer this to `foo_count`) -* `foo_idx` -- index of `foo` - -Many names in rust-analyzer conflict with keywords. -We use mangled names instead of `r#ident` syntax: - -``` -crate -> krate -enum -> enum_ -fn -> func -impl -> imp -macro -> mac -mod -> module -struct -> strukt -trait -> trait_ -type -> ty -``` - -**Rationale:** consistency. - -## Early Returns - -Do use early returns - -```rust -// GOOD -fn foo() -> Option { - if !condition() { - return None; - } - - Some(...) -} - -// BAD -fn foo() -> Option { - if condition() { - Some(...) - } else { - None - } -} -``` - -**Rationale:** reduce cognitive stack usage. - -Use `return Err(err)` to throw an error: - -```rust -// GOOD -fn f() -> Result<(), ()> { - if condition { - return Err(()); - } - Ok(()) -} - -// BAD -fn f() -> Result<(), ()> { - if condition { - Err(())?; - } - Ok(()) -} -``` - -**Rationale:** `return` has type `!`, which allows the compiler to flag dead -code (`Err(...)?` is of unconstrained generic type `T`). - -## Comparisons - -When doing multiple comparisons use `<`/`<=`, avoid `>`/`>=`. - -```rust -// GOOD -assert!(lo <= x && x <= hi); -assert!(r1 < l2 || r2 < l1); -assert!(x < y); -assert!(0 < x); - -// BAD -assert!(x >= lo && x <= hi); -assert!(r1 < l2 || l1 > r2); -assert!(y > x); -assert!(x > 0); -``` - -**Rationale:** Less-then comparisons are more intuitive, they correspond spatially to [real line](https://en.wikipedia.org/wiki/Real_line). - -## If-let - -Avoid `if let ... { } else { }` construct, use `match` instead. - -```rust -// GOOD -match ctx.expected_type.as_ref() { - Some(expected_type) => completion_ty == expected_type && !expected_type.is_unit(), - None => false, -} - -// BAD -if let Some(expected_type) = ctx.expected_type.as_ref() { - completion_ty == expected_type && !expected_type.is_unit() -} else { - false -} -``` - -**Rationale:** `match` is almost always more compact. -The `else` branch can get a more precise pattern: `None` or `Err(_)` instead of `_`. - -## Match Ergonomics - -Don't use the `ref` keyword. - -**Rationale:** consistency & simplicity. -`ref` was required before [match ergonomics](https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md). -Today, it is redundant. -Between `ref` and mach ergonomics, the latter is more ergonomic in most cases, and is simpler (does not require a keyword). - -## Empty Match Arms - -Use `=> (),` when a match arm is intentionally empty: - -```rust -// GOOD -match result { - Ok(_) => (), - Err(err) => error!("{}", err), -} - -// BAD -match result { - Ok(_) => {} - Err(err) => error!("{}", err), -} -``` - -**Rationale:** consistency. - -## Functional Combinators - -Use high order monadic combinators like `map`, `then` when they are a natural choice; don't bend the code to fit into some combinator. -If writing a chain of combinators creates friction, replace them with control flow constructs: `for`, `if`, `match`. -Mostly avoid `bool::then` and `Option::filter`. - -```rust -// GOOD -if !x.cond() { - return None; -} -Some(x) - -// BAD -Some(x).filter(|it| it.cond()) -``` - -This rule is more "soft" then others, and boils down mostly to taste. -The guiding principle behind this rule is that code should be dense in computation, and sparse in the number of expressions per line. -The second example contains *less* computation -- the `filter` function is an indirection for `if`, it doesn't do any useful work by itself. -At the same time, it is more crowded -- it takes more time to visually scan it. - -**Rationale:** consistency, playing to language's strengths. -Rust has first-class support for imperative control flow constructs like `for` and `if`, while functions are less first-class due to lack of universal function type, currying, and non-first-class effects (`?`, `.await`). - -## Turbofish - -Prefer type ascription over the turbofish. -When ascribing types, avoid `_` - -```rust -// GOOD -let mutable: Vec = old.into_iter().map(|it| builder.make_mut(it)).collect(); - -// BAD -let mutable: Vec<_> = old.into_iter().map(|it| builder.make_mut(it)).collect(); - -// BAD -let mutable = old.into_iter().map(|it| builder.make_mut(it)).collect::>(); -``` - -**Rationale:** consistency, readability. -If compiler struggles to infer the type, the human would as well. -Having the result type specified up-front helps with understanding what the chain of iterator methods is doing. - -## Helper Functions - -Avoid creating single-use helper functions: - -```rust -// GOOD -let buf = { - let mut buf = get_empty_buf(&mut arena); - buf.add_item(item); - buf -}; - -// BAD -let buf = prepare_buf(&mut arena, item); - -... - -fn prepare_buf(arena: &mut Arena, item: Item) -> ItemBuf { - let mut res = get_empty_buf(&mut arena); - res.add_item(item); - res -} -``` - -Exception: if you want to make use of `return` or `?`. - -**Rationale:** single-use functions change frequently, adding or removing parameters adds churn. -A block serves just as well to delineate a bit of logic, but has access to all the context. -Re-using originally single-purpose function often leads to bad coupling. - -## Local Helper Functions - -Put nested helper functions at the end of the enclosing functions -(this requires using return statement). -Don't nest more than one level deep. - -```rust -// GOOD -fn dfs(graph: &Graph, v: Vertex) -> usize { - let mut visited = FxHashSet::default(); - return go(graph, &mut visited, v); - - fn go(graph: &Graph, visited: &mut FxHashSet, v: usize) -> usize { - ... - } -} - -// BAD -fn dfs(graph: &Graph, v: Vertex) -> usize { - fn go(graph: &Graph, visited: &mut FxHashSet, v: usize) -> usize { - ... - } - - let mut visited = FxHashSet::default(); - go(graph, &mut visited, v) -} -``` - -**Rationale:** consistency, improved top-down readability. - -## Helper Variables - -Introduce helper variables freely, especially for multiline conditions: - -```rust -// GOOD -let rustfmt_not_installed = - captured_stderr.contains("not installed") || captured_stderr.contains("not available"); - -match output.status.code() { - Some(1) if !rustfmt_not_installed => Ok(None), - _ => Err(format_err!("rustfmt failed:\n{}", captured_stderr)), -}; - -// BAD -match output.status.code() { - Some(1) - if !captured_stderr.contains("not installed") - && !captured_stderr.contains("not available") => Ok(None), - _ => Err(format_err!("rustfmt failed:\n{}", captured_stderr)), -}; -``` - -**Rationale:** Like blocks, single-use variables are a cognitively cheap abstraction, as they have access to all the context. -Extra variables help during debugging, they make it easy to print/view important intermediate results. -Giving a name to a condition inside an `if` expression often improves clarity and leads to nicely formatted code. - -## Token names - -Use `T![foo]` instead of `SyntaxKind::FOO_KW`. - -```rust -// GOOD -match p.current() { - T![true] | T![false] => true, - _ => false, -} - -// BAD - -match p.current() { - SyntaxKind::TRUE_KW | SyntaxKind::FALSE_KW => true, - _ => false, -} -``` - -**Rationale:** The macro uses the familiar Rust syntax, avoiding ambiguities like "is this a brace or bracket?". - -## Documentation - -Style inline code comments as proper sentences. -Start with a capital letter, end with a dot. - -```rust -// GOOD - -// Only simple single segment paths are allowed. -MergeBehavior::Last => { - tree.use_tree_list().is_none() && tree.path().map(path_len) <= Some(1) -} - -// BAD - -// only simple single segment paths are allowed -MergeBehavior::Last => { - tree.use_tree_list().is_none() && tree.path().map(path_len) <= Some(1) -} -``` - -**Rationale:** writing a sentence (or maybe even a paragraph) rather just "a comment" creates a more appropriate frame of mind. -It tricks you into writing down more of the context you keep in your head while coding. - -For `.md` and `.adoc` files, prefer a sentence-per-line format, don't wrap lines. -If the line is too long, you want to split the sentence in two :-) - -**Rationale:** much easier to edit the text and read the diff, see [this link](https://asciidoctor.org/docs/asciidoc-recommended-practices/#one-sentence-per-line). diff --git a/src/tools/rust-analyzer/docs/dev/syntax.md b/src/tools/rust-analyzer/docs/dev/syntax.md deleted file mode 100644 index 30e13701383a9..0000000000000 --- a/src/tools/rust-analyzer/docs/dev/syntax.md +++ /dev/null @@ -1,534 +0,0 @@ -# Syntax in rust-analyzer - -## About the guide - -This guide describes the current state of syntax trees and parsing in rust-analyzer as of 2020-01-09 ([link to commit](https://github.com/rust-lang/rust-analyzer/tree/cf5bdf464cad7ceb9a67e07985a3f4d3799ec0b6)). - -## Source Code - -The things described are implemented in three places - -* [rowan](https://github.com/rust-analyzer/rowan/tree/v0.9.0) -- a generic library for rowan syntax trees. -* [ra_syntax](https://github.com/rust-lang/rust-analyzer/tree/cf5bdf464cad7ceb9a67e07985a3f4d3799ec0b6/crates/ra_syntax) crate inside rust-analyzer which wraps `rowan` into rust-analyzer specific API. - Nothing in rust-analyzer except this crate knows about `rowan`. -* [parser](https://github.com/rust-lang/rust-analyzer/tree/cf5bdf464cad7ceb9a67e07985a3f4d3799ec0b6/crates/parser) crate parses input tokens into an `ra_syntax` tree - -## Design Goals - -* Syntax trees are lossless, or full fidelity. All comments and whitespace get preserved. -* Syntax trees are semantic-less. They describe *strictly* the structure of a sequence of characters, they don't have hygiene, name resolution or type information attached. -* Syntax trees are simple value types. It is possible to create trees for a syntax without any external context. -* Syntax trees have intuitive traversal API (parent, children, siblings, etc). -* Parsing is lossless (even if the input is invalid, the tree produced by the parser represents it exactly). -* Parsing is resilient (even if the input is invalid, parser tries to see as much syntax tree fragments in the input as it can). -* Performance is important, it's OK to use `unsafe` if it means better memory/cpu usage. -* Keep the parser and the syntax tree isolated from each other, such that they can vary independently. - -## Trees - -### Overview - -The syntax tree consists of three layers: - -* GreenNodes -* SyntaxNodes (aka RedNode) -* AST - -Of these, only GreenNodes store the actual data, the other two layers are (non-trivial) views into green tree. -Red-green terminology comes from Roslyn ([link](https://ericlippert.com/2012/06/08/red-green-trees/)) and gives the name to the `rowan` library. Green and syntax nodes are defined in rowan, ast is defined in rust-analyzer. - -Syntax trees are a semi-transient data structure. -In general, frontend does not keep syntax trees for all files in memory. -Instead, it *lowers* syntax trees to more compact and rigid representation, which is not full-fidelity, but which can be mapped back to a syntax tree if so desired. - - -### GreenNode - -GreenNode is a purely-functional tree with arbitrary arity. Conceptually, it is equivalent to the following run of the mill struct: - -```rust -#[derive(PartialEq, Eq, Clone, Copy)] -struct SyntaxKind(u16); - -#[derive(PartialEq, Eq, Clone)] -struct Node { - kind: SyntaxKind, - text_len: usize, - children: Vec>>, -} - -#[derive(PartialEq, Eq, Clone)] -struct Token { - kind: SyntaxKind, - text: String, -} -``` - -All the difference between the above sketch and the real implementation are strictly due to optimizations. - -Points of note: -* The tree is untyped. Each node has a "type tag", `SyntaxKind`. -* Interior and leaf nodes are distinguished on the type level. -* Trivia and non-trivia tokens are not distinguished on the type level. -* Each token carries its full text. -* The original text can be recovered by concatenating the texts of all tokens in order. -* Accessing a child of particular type (for example, parameter list of a function) generally involves linearly traversing the children, looking for a specific `kind`. -* Modifying the tree is roughly `O(depth)`. - We don't make special efforts to guarantee that the depth is not linear, but, in practice, syntax trees are branchy and shallow. -* If mandatory (grammar wise) node is missing from the input, it's just missing from the tree. -* If an extra erroneous input is present, it is wrapped into a node with `ERROR` kind, and treated just like any other node. -* Parser errors are not a part of syntax tree. - -An input like `fn f() { 90 + 2 }` might be parsed as - -``` -FN@0..17 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..4 - IDENT@3..4 "f" - PARAM_LIST@4..6 - L_PAREN@4..5 "(" - R_PAREN@5..6 ")" - WHITESPACE@6..7 " " - BLOCK_EXPR@7..17 - L_CURLY@7..8 "{" - WHITESPACE@8..9 " " - BIN_EXPR@9..15 - LITERAL@9..11 - INT_NUMBER@9..11 "90" - WHITESPACE@11..12 " " - PLUS@12..13 "+" - WHITESPACE@13..14 " " - LITERAL@14..15 - INT_NUMBER@14..15 "2" - WHITESPACE@15..16 " " - R_CURLY@16..17 "}" -``` - -#### Optimizations - -(significant amount of implementation work here was done by [CAD97](https://github.com/cad97)). - -To reduce the amount of allocations, the GreenNode is a [DST](https://doc.rust-lang.org/reference/dynamically-sized-types.html), which uses a single allocation for header and children. Thus, it is only usable behind a pointer. - -``` -*-----------+------+----------+------------+--------+--------+-----+--------* -| ref_count | kind | text_len | n_children | child1 | child2 | ... | childn | -*-----------+------+----------+------------+--------+--------+-----+--------* -``` - -To more compactly store the children, we box *both* interior nodes and tokens, and represent -`Either, Arc>` as a single pointer with a tag in the last bit. - -To avoid allocating EVERY SINGLE TOKEN on the heap, syntax trees use interning. -Because the tree is fully immutable, it's valid to structurally share subtrees. -For example, in `1 + 1`, there will be a *single* token for `1` with ref count 2; the same goes for the ` ` whitespace token. -Interior nodes are shared as well (for example in `(1 + 1) * (1 + 1)`). - -Note that, the result of the interning is an `Arc`. -That is, it's not an index into interning table, so you don't have to have the table around to do anything with the tree. -Each tree is fully self-contained (although different trees might share parts). -Currently, the interner is created per-file, but it will be easy to use a per-thread or per-some-contex one. - -We use a `TextSize`, a newtyped `u32`, to store the length of the text. - -We currently use `SmolStr`, a small object optimized string to store text. -This was mostly relevant *before* we implemented tree interning, to avoid allocating common keywords and identifiers. We should switch to storing text data alongside the interned tokens. - -#### Alternative designs - -##### Dealing with trivia - -In the above model, whitespace is not treated specially. -Another alternative (used by swift and roslyn) is to explicitly divide the set of tokens into trivia and non-trivia tokens, and represent non-trivia tokens as - -```rust -struct Token { - kind: NonTriviaTokenKind, - text: String, - leading_trivia: Vec, - trailing_trivia: Vec, -} -``` - -The tree then contains only non-trivia tokens. - -Another approach (from Dart) is to, in addition to a syntax tree, link all the tokens into a bidirectional link list. -That way, the tree again contains only non-trivia tokens. - -Explicit trivia nodes, like in `rowan`, are used by IntelliJ. - -##### Accessing Children - -As noted before, accessing a specific child in the node requires a linear traversal of the children (though we can skip tokens, because the tag is encoded in the pointer itself). -It is possible to recover O(1) access with another representation. -We explicitly store optional and missing (required by the grammar, but not present) nodes. -That is, we use `Option` for children. -We also remove trivia tokens from the tree. -This way, each child kind generally occupies a fixed position in a parent, and we can use index access to fetch it. -The cost is that we now need to allocate space for all not-present optional nodes. -So, `fn foo() {}` will have slots for visibility, unsafeness, attributes, abi and return type. - -IntelliJ uses linear traversal. -Roslyn and Swift do `O(1)` access. - -##### Mutable Trees - -IntelliJ uses mutable trees. -Overall, it creates a lot of additional complexity. -However, the API for *editing* syntax trees is nice. - -For example the assist to move generic bounds to where clause has this code: - -```kotlin - for typeBound in typeBounds { - typeBound.typeParamBounds?.delete() -} -``` - -Modeling this with immutable trees is possible, but annoying. - -### Syntax Nodes - -A function green tree is not super-convenient to use. -The biggest problem is accessing parents (there are no parent pointers!). -But there are also "identify" issues. -Let's say you want to write a code which builds a list of expressions in a file: `fn collect_expressions(file: GreenNode) -> HashSet`. -For the input like - -```rust -fn main() { - let x = 90i8; - let x = x + 2; - let x = 90i64; - let x = x + 2; -} -``` - -both copies of the `x + 2` expression are representing by equal (and, with interning in mind, actually the same) green nodes. -Green trees just can't differentiate between the two. - -`SyntaxNode` adds parent pointers and identify semantics to green nodes. -They can be called cursors or [zippers](https://en.wikipedia.org/wiki/Zipper_(data_structure)) (fun fact: zipper is a derivative (as in ′) of a data structure). - -Conceptually, a `SyntaxNode` looks like this: - -```rust -type SyntaxNode = Arc; - -struct SyntaxData { - offset: usize, - parent: Option, - green: Arc, -} - -impl SyntaxNode { - fn new_root(root: Arc) -> SyntaxNode { - Arc::new(SyntaxData { - offset: 0, - parent: None, - green: root, - }) - } - fn parent(&self) -> Option { - self.parent.clone() - } - fn children(&self) -> impl Iterator { - let mut offset = self.offset; - self.green.children().map(|green_child| { - let child_offset = offset; - offset += green_child.text_len; - Arc::new(SyntaxData { - offset: child_offset, - parent: Some(Arc::clone(self)), - green: Arc::clone(green_child), - }) - }) - } -} - -impl PartialEq for SyntaxNode { - fn eq(&self, other: &SyntaxNode) -> bool { - self.offset == other.offset - && Arc::ptr_eq(&self.green, &other.green) - } -} -``` - -Points of note: - -* SyntaxNode remembers its parent node (and, transitively, the path to the root of the tree) -* SyntaxNode knows its *absolute* text offset in the whole file -* Equality is based on identity. Comparing nodes from different trees does not make sense. - -#### Optimization - -The reality is different though :-) -Traversal of trees is a common operation, and it makes sense to optimize it. -In particular, the above code allocates and does atomic operations during a traversal. - -To get rid of atomics, `rowan` uses non thread-safe `Rc`. -This is OK because trees traversals mostly (always, in case of rust-analyzer) run on a single thread. If you need to send a `SyntaxNode` to another thread, you can send a pair of **root**`GreenNode` (which is thread safe) and a `Range`. -The other thread can restore the `SyntaxNode` by traversing from the root green node and looking for a node with specified range. -You can also use the similar trick to store a `SyntaxNode`. -That is, a data structure that holds a `(GreenNode, Range)` will be `Sync`. -However, rust-analyzer goes even further. -It treats trees as semi-transient and instead of storing a `GreenNode`, it generally stores just the id of the file from which the tree originated: `(FileId, Range)`. -The `SyntaxNode` is the restored by reparsing the file and traversing it from root. -With this trick, rust-analyzer holds only a small amount of trees in memory at the same time, which reduces memory usage. - -Additionally, only the root `SyntaxNode` owns an `Arc` to the (root) `GreenNode`. -All other `SyntaxNode`s point to corresponding `GreenNode`s with a raw pointer. -They also point to the parent (and, consequently, to the root) with an owning `Rc`, so this is sound. -In other words, one needs *one* arc bump when initiating a traversal. - -To get rid of allocations, `rowan` takes advantage of `SyntaxNode: !Sync` and uses a thread-local free list of `SyntaxNode`s. -In a typical traversal, you only directly hold a few `SyntaxNode`s at a time (and their ancestors indirectly), so a free list proportional to the depth of the tree removes all allocations in a typical case. - -So, while traversal is not exactly incrementing a pointer, it's still pretty cheap: TLS + rc bump! - -Traversal also yields (cheap) owned nodes, which improves ergonomics quite a bit. - -#### Alternative Designs - -##### Memoized RedNodes - -C# and Swift follow the design where the red nodes are memoized, which would look roughly like this in Rust: - -```rust -type SyntaxNode = Arc; - -struct SyntaxData { - offset: usize, - parent: Option, - green: Arc, - children: Vec>, -} -``` - -This allows using true pointer equality for comparison of identities of `SyntaxNodes`. -rust-analyzer used to have this design as well, but we've since switched to cursors. -The main problem with memoizing the red nodes is that it more than doubles the memory requirements for fully realized syntax trees. -In contrast, cursors generally retain only a path to the root. -C# combats increased memory usage by using weak references. - -### AST - -`GreenTree`s are untyped and homogeneous, because it makes accommodating error nodes, arbitrary whitespace and comments natural, and because it makes possible to write generic tree traversals. -However, when working with a specific node, like a function definition, one would want a strongly typed API. - -This is what is provided by the AST layer. AST nodes are transparent wrappers over untyped syntax nodes: - -```rust -pub trait AstNode { - fn cast(syntax: SyntaxNode) -> Option - where - Self: Sized; - - fn syntax(&self) -> &SyntaxNode; -} -``` - -Concrete nodes are generated (there are 117 of them), and look roughly like this: - -```rust -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct FnDef { - syntax: SyntaxNode, -} - -impl AstNode for FnDef { - fn cast(syntax: SyntaxNode) -> Option { - match kind { - FN => Some(FnDef { syntax }), - _ => None, - } - } - fn syntax(&self) -> &SyntaxNode { - &self.syntax - } -} - -impl FnDef { - pub fn param_list(&self) -> Option { - self.syntax.children().find_map(ParamList::cast) - } - pub fn ret_type(&self) -> Option { - self.syntax.children().find_map(RetType::cast) - } - pub fn body(&self) -> Option { - self.syntax.children().find_map(BlockExpr::cast) - } - // ... -} -``` - -Variants like expressions, patterns or items are modeled with `enum`s, which also implement `AstNode`: - -```rust -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum AssocItem { - FnDef(FnDef), - TypeAliasDef(TypeAliasDef), - ConstDef(ConstDef), -} - -impl AstNode for AssocItem { - ... -} -``` - -Shared AST substructures are modeled via (object safe) traits: - -```rust -trait HasVisibility: AstNode { - fn visibility(&self) -> Option; -} - -impl HasVisibility for FnDef { - fn visibility(&self) -> Option { - self.syntax.children().find_map(Visibility::cast) - } -} -``` - -Points of note: - -* Like `SyntaxNode`s, AST nodes are cheap to clone pointer-sized owned values. -* All "fields" are optional, to accommodate incomplete and/or erroneous source code. -* It's always possible to go from an ast node to an untyped `SyntaxNode`. -* It's possible to go in the opposite direction with a checked cast. -* `enum`s allow modeling of arbitrary intersecting subsets of AST types. -* Most of rust-analyzer works with the ast layer, with notable exceptions of: - * macro expansion, which needs access to raw tokens and works with `SyntaxNode`s - * some IDE-specific features like syntax highlighting are more conveniently implemented over a homogeneous `SyntaxNode` tree - -#### Alternative Designs - -##### Semantic Full AST - -In IntelliJ the AST layer (dubbed **P**rogram **S**tructure **I**nterface) can have semantics attached, and is usually backed by either syntax tree, indices, or metadata from compiled libraries. -The backend for PSI can change dynamically. - -### Syntax Tree Recap - -At its core, the syntax tree is a purely functional n-ary tree, which stores text at the leaf nodes and node "kinds" at all nodes. -A cursor layer is added on top, which gives owned, cheap to clone nodes with identity semantics, parent links and absolute offsets. -An AST layer is added on top, which reifies each node `Kind` as a separate Rust type with the corresponding API. - -## Parsing - -The (green) tree is constructed by a DFS "traversal" of the desired tree structure: - -```rust -pub struct GreenNodeBuilder { ... } - -impl GreenNodeBuilder { - pub fn new() -> GreenNodeBuilder { ... } - - pub fn token(&mut self, kind: SyntaxKind, text: &str) { ... } - - pub fn start_node(&mut self, kind: SyntaxKind) { ... } - pub fn finish_node(&mut self) { ... } - - pub fn finish(self) -> GreenNode { ... } -} -``` - -The parser, ultimately, needs to invoke the `GreenNodeBuilder`. -There are two principal sources of inputs for the parser: - * source text, which contains trivia tokens (whitespace and comments) - * token trees from macros, which lack trivia - -Additionally, input tokens do not correspond 1-to-1 with output tokens. -For example, two consecutive `>` tokens might be glued, by the parser, into a single `>>`. - -For these reasons, the parser crate defines a callback interfaces for both input tokens and output trees. -The explicit glue layer then bridges various gaps. - -The parser interface looks like this: - -```rust -pub struct Token { - pub kind: SyntaxKind, - pub is_joined_to_next: bool, -} - -pub trait TokenSource { - fn current(&self) -> Token; - fn lookahead_nth(&self, n: usize) -> Token; - fn is_keyword(&self, kw: &str) -> bool; - - fn bump(&mut self); -} - -pub trait TreeSink { - fn token(&mut self, kind: SyntaxKind, n_tokens: u8); - - fn start_node(&mut self, kind: SyntaxKind); - fn finish_node(&mut self); - - fn error(&mut self, error: ParseError); -} - -pub fn parse( - token_source: &mut dyn TokenSource, - tree_sink: &mut dyn TreeSink, -) { ... } -``` - -Points of note: - -* The parser and the syntax tree are independent, they live in different crates neither of which depends on the other. -* The parser doesn't know anything about textual contents of the tokens, with an isolated hack for checking contextual keywords. -* For gluing tokens, the `TreeSink::token` might advance further than one atomic token ahead. - -### Reporting Syntax Errors - -Syntax errors are not stored directly in the tree. -The primary motivation for this is that syntax tree is not necessary produced by the parser, it may also be assembled manually from pieces (which happens all the time in refactorings). -Instead, parser reports errors to an error sink, which stores them in a `Vec`. -If possible, errors are not reported during parsing and are postponed for a separate validation step. -For example, parser accepts visibility modifiers on trait methods, but then a separate tree traversal flags all such visibilities as erroneous. - -### Macros - -The primary difficulty with macros is that individual tokens have identities, which need to be preserved in the syntax tree for hygiene purposes. -This is handled by the `TreeSink` layer. -Specifically, `TreeSink` constructs the tree in lockstep with draining the original token stream. -In the process, it records which tokens of the tree correspond to which tokens of the input, by using text ranges to identify syntax tokens. -The end result is that parsing an expanded code yields a syntax tree and a mapping of text-ranges of the tree to original tokens. - -To deal with precedence in cases like `$expr * 1`, we use special invisible parenthesis, which are explicitly handled by the parser - -### Whitespace & Comments - -Parser does not see whitespace nodes. -Instead, they are attached to the tree in the `TreeSink` layer. - -For example, in - -```rust -// non doc comment -fn foo() {} -``` - -the comment will be (heuristically) made a child of function node. - -### Incremental Reparse - -Green trees are cheap to modify, so incremental reparse works by patching a previous tree, without maintaining any additional state. -The reparse is based on heuristic: we try to contain a change to a single `{}` block, and reparse only this block. -To do this, we maintain the invariant that, even for invalid code, curly braces are always paired correctly. - -In practice, incremental reparsing doesn't actually matter much for IDE use-cases, parsing from scratch seems to be fast enough. - -### Parsing Algorithm - -We use a boring hand-crafted recursive descent + pratt combination, with a special effort of continuing the parsing if an error is detected. - -### Parser Recap - -Parser itself defines traits for token sequence input and syntax tree output. -It doesn't care about where the tokens come from, and how the resulting syntax tree looks like. diff --git a/src/tools/rust-analyzer/docs/user/.gitignore b/src/tools/rust-analyzer/docs/user/.gitignore deleted file mode 100644 index c32b1bcec2eef..0000000000000 --- a/src/tools/rust-analyzer/docs/user/.gitignore +++ /dev/null @@ -1 +0,0 @@ -manual.html diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc deleted file mode 100644 index b0f2f1614dbf8..0000000000000 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ /dev/null @@ -1,620 +0,0 @@ -[[rust-analyzer.assist.expressionFillDefault]]rust-analyzer.assist.expressionFillDefault (default: `"todo"`):: -+ --- -Placeholder expression to use for missing expressions in assists. --- -[[rust-analyzer.cachePriming.enable]]rust-analyzer.cachePriming.enable (default: `true`):: -+ --- -Warm up caches on project load. --- -[[rust-analyzer.cachePriming.numThreads]]rust-analyzer.cachePriming.numThreads (default: `0`):: -+ --- -How many worker threads to handle priming caches. The default `0` means to pick automatically. --- -[[rust-analyzer.cargo.autoreload]]rust-analyzer.cargo.autoreload (default: `true`):: -+ --- -Automatically refresh project info via `cargo metadata` on -`Cargo.toml` or `.cargo/config.toml` changes. --- -[[rust-analyzer.cargo.buildScripts.enable]]rust-analyzer.cargo.buildScripts.enable (default: `true`):: -+ --- -Run build scripts (`build.rs`) for more precise code analysis. --- -[[rust-analyzer.cargo.buildScripts.overrideCommand]]rust-analyzer.cargo.buildScripts.overrideCommand (default: `null`):: -+ --- -Override the command rust-analyzer uses to run build scripts and -build procedural macros. The command is required to output json -and should therefore include `--message-format=json` or a similar -option. - -By default, a cargo invocation will be constructed for the configured -targets and features, with the following base command line: - -```bash -cargo check --quiet --workspace --message-format=json --all-targets -``` -. --- -[[rust-analyzer.cargo.buildScripts.useRustcWrapper]]rust-analyzer.cargo.buildScripts.useRustcWrapper (default: `true`):: -+ --- -Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to -avoid checking unnecessary things. --- -[[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`):: -+ --- -List of features to activate. - -Set this to `"all"` to pass `--all-features` to cargo. --- -[[rust-analyzer.cargo.noDefaultFeatures]]rust-analyzer.cargo.noDefaultFeatures (default: `false`):: -+ --- -Whether to pass `--no-default-features` to cargo. --- -[[rust-analyzer.cargo.noSysroot]]rust-analyzer.cargo.noSysroot (default: `false`):: -+ --- -Internal config for debugging, disables loading of sysroot crates. --- -[[rust-analyzer.cargo.target]]rust-analyzer.cargo.target (default: `null`):: -+ --- -Compilation target override (target triple). --- -[[rust-analyzer.cargo.unsetTest]]rust-analyzer.cargo.unsetTest (default: `["core"]`):: -+ --- -Unsets `#[cfg(test)]` for the specified crates. --- -[[rust-analyzer.checkOnSave.allTargets]]rust-analyzer.checkOnSave.allTargets (default: `true`):: -+ --- -Check all targets and tests (`--all-targets`). --- -[[rust-analyzer.checkOnSave.command]]rust-analyzer.checkOnSave.command (default: `"check"`):: -+ --- -Cargo command to use for `cargo check`. --- -[[rust-analyzer.checkOnSave.enable]]rust-analyzer.checkOnSave.enable (default: `true`):: -+ --- -Run specified `cargo check` command for diagnostics on save. --- -[[rust-analyzer.checkOnSave.extraArgs]]rust-analyzer.checkOnSave.extraArgs (default: `[]`):: -+ --- -Extra arguments for `cargo check`. --- -[[rust-analyzer.checkOnSave.features]]rust-analyzer.checkOnSave.features (default: `null`):: -+ --- -List of features to activate. Defaults to -`#rust-analyzer.cargo.features#`. - -Set to `"all"` to pass `--all-features` to Cargo. --- -[[rust-analyzer.checkOnSave.noDefaultFeatures]]rust-analyzer.checkOnSave.noDefaultFeatures (default: `null`):: -+ --- -Whether to pass `--no-default-features` to Cargo. Defaults to -`#rust-analyzer.cargo.noDefaultFeatures#`. --- -[[rust-analyzer.checkOnSave.overrideCommand]]rust-analyzer.checkOnSave.overrideCommand (default: `null`):: -+ --- -Override the command rust-analyzer uses instead of `cargo check` for -diagnostics on save. The command is required to output json and -should therefor include `--message-format=json` or a similar option. - -If you're changing this because you're using some tool wrapping -Cargo, you might also want to change -`#rust-analyzer.cargo.buildScripts.overrideCommand#`. - -An example command would be: - -```bash -cargo check --workspace --message-format=json --all-targets -``` -. --- -[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `null`):: -+ --- -Check for a specific target. Defaults to -`#rust-analyzer.cargo.target#`. --- -[[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`):: -+ --- -Toggles the additional completions that automatically add imports when completed. -Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. --- -[[rust-analyzer.completion.autoself.enable]]rust-analyzer.completion.autoself.enable (default: `true`):: -+ --- -Toggles the additional completions that automatically show method calls and field accesses -with `self` prefixed to them when inside a method. --- -[[rust-analyzer.completion.callable.snippets]]rust-analyzer.completion.callable.snippets (default: `"fill_arguments"`):: -+ --- -Whether to add parenthesis and argument snippets when completing function. --- -[[rust-analyzer.completion.postfix.enable]]rust-analyzer.completion.postfix.enable (default: `true`):: -+ --- -Whether to show postfix snippets like `dbg`, `if`, `not`, etc. --- -[[rust-analyzer.completion.privateEditable.enable]]rust-analyzer.completion.privateEditable.enable (default: `false`):: -+ --- -Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position. --- -[[rust-analyzer.completion.snippets.custom]]rust-analyzer.completion.snippets.custom:: -+ --- -Default: ----- -{ - "Arc::new": { - "postfix": "arc", - "body": "Arc::new(${receiver})", - "requires": "std::sync::Arc", - "description": "Put the expression into an `Arc`", - "scope": "expr" - }, - "Rc::new": { - "postfix": "rc", - "body": "Rc::new(${receiver})", - "requires": "std::rc::Rc", - "description": "Put the expression into an `Rc`", - "scope": "expr" - }, - "Box::pin": { - "postfix": "pinbox", - "body": "Box::pin(${receiver})", - "requires": "std::boxed::Box", - "description": "Put the expression into a pinned `Box`", - "scope": "expr" - }, - "Ok": { - "postfix": "ok", - "body": "Ok(${receiver})", - "description": "Wrap the expression in a `Result::Ok`", - "scope": "expr" - }, - "Err": { - "postfix": "err", - "body": "Err(${receiver})", - "description": "Wrap the expression in a `Result::Err`", - "scope": "expr" - }, - "Some": { - "postfix": "some", - "body": "Some(${receiver})", - "description": "Wrap the expression in an `Option::Some`", - "scope": "expr" - } - } ----- -Custom completion snippets. - --- -[[rust-analyzer.diagnostics.disabled]]rust-analyzer.diagnostics.disabled (default: `[]`):: -+ --- -List of rust-analyzer diagnostics to disable. --- -[[rust-analyzer.diagnostics.enable]]rust-analyzer.diagnostics.enable (default: `true`):: -+ --- -Whether to show native rust-analyzer diagnostics. --- -[[rust-analyzer.diagnostics.experimental.enable]]rust-analyzer.diagnostics.experimental.enable (default: `false`):: -+ --- -Whether to show experimental rust-analyzer diagnostics that might -have more false positives than usual. --- -[[rust-analyzer.diagnostics.remapPrefix]]rust-analyzer.diagnostics.remapPrefix (default: `{}`):: -+ --- -Map of prefixes to be substituted when parsing diagnostic file paths. -This should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`. --- -[[rust-analyzer.diagnostics.warningsAsHint]]rust-analyzer.diagnostics.warningsAsHint (default: `[]`):: -+ --- -List of warnings that should be displayed with hint severity. - -The warnings will be indicated by faded text or three dots in code -and will not show up in the `Problems Panel`. --- -[[rust-analyzer.diagnostics.warningsAsInfo]]rust-analyzer.diagnostics.warningsAsInfo (default: `[]`):: -+ --- -List of warnings that should be displayed with info severity. - -The warnings will be indicated by a blue squiggly underline in code -and a blue icon in the `Problems Panel`. --- -[[rust-analyzer.files.excludeDirs]]rust-analyzer.files.excludeDirs (default: `[]`):: -+ --- -These directories will be ignored by rust-analyzer. They are -relative to the workspace root, and globs are not supported. You may -also need to add the folders to Code's `files.watcherExclude`. --- -[[rust-analyzer.files.watcher]]rust-analyzer.files.watcher (default: `"client"`):: -+ --- -Controls file watching implementation. --- -[[rust-analyzer.highlightRelated.breakPoints.enable]]rust-analyzer.highlightRelated.breakPoints.enable (default: `true`):: -+ --- -Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords. --- -[[rust-analyzer.highlightRelated.exitPoints.enable]]rust-analyzer.highlightRelated.exitPoints.enable (default: `true`):: -+ --- -Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`). --- -[[rust-analyzer.highlightRelated.references.enable]]rust-analyzer.highlightRelated.references.enable (default: `true`):: -+ --- -Enables highlighting of related references while the cursor is on any identifier. --- -[[rust-analyzer.highlightRelated.yieldPoints.enable]]rust-analyzer.highlightRelated.yieldPoints.enable (default: `true`):: -+ --- -Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords. --- -[[rust-analyzer.hover.actions.debug.enable]]rust-analyzer.hover.actions.debug.enable (default: `true`):: -+ --- -Whether to show `Debug` action. Only applies when -`#rust-analyzer.hover.actions.enable#` is set. --- -[[rust-analyzer.hover.actions.enable]]rust-analyzer.hover.actions.enable (default: `true`):: -+ --- -Whether to show HoverActions in Rust files. --- -[[rust-analyzer.hover.actions.gotoTypeDef.enable]]rust-analyzer.hover.actions.gotoTypeDef.enable (default: `true`):: -+ --- -Whether to show `Go to Type Definition` action. Only applies when -`#rust-analyzer.hover.actions.enable#` is set. --- -[[rust-analyzer.hover.actions.implementations.enable]]rust-analyzer.hover.actions.implementations.enable (default: `true`):: -+ --- -Whether to show `Implementations` action. Only applies when -`#rust-analyzer.hover.actions.enable#` is set. --- -[[rust-analyzer.hover.actions.references.enable]]rust-analyzer.hover.actions.references.enable (default: `false`):: -+ --- -Whether to show `References` action. Only applies when -`#rust-analyzer.hover.actions.enable#` is set. --- -[[rust-analyzer.hover.actions.run.enable]]rust-analyzer.hover.actions.run.enable (default: `true`):: -+ --- -Whether to show `Run` action. Only applies when -`#rust-analyzer.hover.actions.enable#` is set. --- -[[rust-analyzer.hover.documentation.enable]]rust-analyzer.hover.documentation.enable (default: `true`):: -+ --- -Whether to show documentation on hover. --- -[[rust-analyzer.hover.links.enable]]rust-analyzer.hover.links.enable (default: `true`):: -+ --- -Use markdown syntax for links in hover. --- -[[rust-analyzer.imports.granularity.enforce]]rust-analyzer.imports.granularity.enforce (default: `false`):: -+ --- -Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file. --- -[[rust-analyzer.imports.granularity.group]]rust-analyzer.imports.granularity.group (default: `"crate"`):: -+ --- -How imports should be grouped into use statements. --- -[[rust-analyzer.imports.group.enable]]rust-analyzer.imports.group.enable (default: `true`):: -+ --- -Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-import[following order]. Groups are separated by newlines. --- -[[rust-analyzer.imports.merge.glob]]rust-analyzer.imports.merge.glob (default: `true`):: -+ --- -Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`. --- -[[rust-analyzer.imports.prefix]]rust-analyzer.imports.prefix (default: `"plain"`):: -+ --- -The path structure for newly inserted paths to use. --- -[[rust-analyzer.inlayHints.bindingModeHints.enable]]rust-analyzer.inlayHints.bindingModeHints.enable (default: `false`):: -+ --- -Whether to show inlay type hints for binding modes. --- -[[rust-analyzer.inlayHints.chainingHints.enable]]rust-analyzer.inlayHints.chainingHints.enable (default: `true`):: -+ --- -Whether to show inlay type hints for method chains. --- -[[rust-analyzer.inlayHints.closingBraceHints.enable]]rust-analyzer.inlayHints.closingBraceHints.enable (default: `true`):: -+ --- -Whether to show inlay hints after a closing `}` to indicate what item it belongs to. --- -[[rust-analyzer.inlayHints.closingBraceHints.minLines]]rust-analyzer.inlayHints.closingBraceHints.minLines (default: `25`):: -+ --- -Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1 -to always show them). --- -[[rust-analyzer.inlayHints.closureReturnTypeHints.enable]]rust-analyzer.inlayHints.closureReturnTypeHints.enable (default: `"never"`):: -+ --- -Whether to show inlay type hints for return types of closures. --- -[[rust-analyzer.inlayHints.lifetimeElisionHints.enable]]rust-analyzer.inlayHints.lifetimeElisionHints.enable (default: `"never"`):: -+ --- -Whether to show inlay type hints for elided lifetimes in function signatures. --- -[[rust-analyzer.inlayHints.lifetimeElisionHints.useParameterNames]]rust-analyzer.inlayHints.lifetimeElisionHints.useParameterNames (default: `false`):: -+ --- -Whether to prefer using parameter names as the name for elided lifetime hints if possible. --- -[[rust-analyzer.inlayHints.maxLength]]rust-analyzer.inlayHints.maxLength (default: `25`):: -+ --- -Maximum length for inlay hints. Set to null to have an unlimited length. --- -[[rust-analyzer.inlayHints.parameterHints.enable]]rust-analyzer.inlayHints.parameterHints.enable (default: `true`):: -+ --- -Whether to show function parameter name inlay hints at the call -site. --- -[[rust-analyzer.inlayHints.reborrowHints.enable]]rust-analyzer.inlayHints.reborrowHints.enable (default: `"never"`):: -+ --- -Whether to show inlay type hints for compiler inserted reborrows. --- -[[rust-analyzer.inlayHints.renderColons]]rust-analyzer.inlayHints.renderColons (default: `true`):: -+ --- -Whether to render leading colons for type hints, and trailing colons for parameter hints. --- -[[rust-analyzer.inlayHints.typeHints.enable]]rust-analyzer.inlayHints.typeHints.enable (default: `true`):: -+ --- -Whether to show inlay type hints for variables. --- -[[rust-analyzer.inlayHints.typeHints.hideClosureInitialization]]rust-analyzer.inlayHints.typeHints.hideClosureInitialization (default: `false`):: -+ --- -Whether to hide inlay type hints for `let` statements that initialize to a closure. -Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`. --- -[[rust-analyzer.inlayHints.typeHints.hideNamedConstructor]]rust-analyzer.inlayHints.typeHints.hideNamedConstructor (default: `false`):: -+ --- -Whether to hide inlay type hints for constructors. --- -[[rust-analyzer.joinLines.joinAssignments]]rust-analyzer.joinLines.joinAssignments (default: `true`):: -+ --- -Join lines merges consecutive declaration and initialization of an assignment. --- -[[rust-analyzer.joinLines.joinElseIf]]rust-analyzer.joinLines.joinElseIf (default: `true`):: -+ --- -Join lines inserts else between consecutive ifs. --- -[[rust-analyzer.joinLines.removeTrailingComma]]rust-analyzer.joinLines.removeTrailingComma (default: `true`):: -+ --- -Join lines removes trailing commas. --- -[[rust-analyzer.joinLines.unwrapTrivialBlock]]rust-analyzer.joinLines.unwrapTrivialBlock (default: `true`):: -+ --- -Join lines unwraps trivial blocks. --- -[[rust-analyzer.lens.debug.enable]]rust-analyzer.lens.debug.enable (default: `true`):: -+ --- -Whether to show `Debug` lens. Only applies when -`#rust-analyzer.lens.enable#` is set. --- -[[rust-analyzer.lens.enable]]rust-analyzer.lens.enable (default: `true`):: -+ --- -Whether to show CodeLens in Rust files. --- -[[rust-analyzer.lens.forceCustomCommands]]rust-analyzer.lens.forceCustomCommands (default: `true`):: -+ --- -Internal config: use custom client-side commands even when the -client doesn't set the corresponding capability. --- -[[rust-analyzer.lens.implementations.enable]]rust-analyzer.lens.implementations.enable (default: `true`):: -+ --- -Whether to show `Implementations` lens. Only applies when -`#rust-analyzer.lens.enable#` is set. --- -[[rust-analyzer.lens.references.adt.enable]]rust-analyzer.lens.references.adt.enable (default: `false`):: -+ --- -Whether to show `References` lens for Struct, Enum, and Union. -Only applies when `#rust-analyzer.lens.enable#` is set. --- -[[rust-analyzer.lens.references.enumVariant.enable]]rust-analyzer.lens.references.enumVariant.enable (default: `false`):: -+ --- -Whether to show `References` lens for Enum Variants. -Only applies when `#rust-analyzer.lens.enable#` is set. --- -[[rust-analyzer.lens.references.method.enable]]rust-analyzer.lens.references.method.enable (default: `false`):: -+ --- -Whether to show `Method References` lens. Only applies when -`#rust-analyzer.lens.enable#` is set. --- -[[rust-analyzer.lens.references.trait.enable]]rust-analyzer.lens.references.trait.enable (default: `false`):: -+ --- -Whether to show `References` lens for Trait. -Only applies when `#rust-analyzer.lens.enable#` is set. --- -[[rust-analyzer.lens.run.enable]]rust-analyzer.lens.run.enable (default: `true`):: -+ --- -Whether to show `Run` lens. Only applies when -`#rust-analyzer.lens.enable#` is set. --- -[[rust-analyzer.linkedProjects]]rust-analyzer.linkedProjects (default: `[]`):: -+ --- -Disable project auto-discovery in favor of explicitly specified set -of projects. - -Elements must be paths pointing to `Cargo.toml`, -`rust-project.json`, or JSON objects in `rust-project.json` format. --- -[[rust-analyzer.lru.capacity]]rust-analyzer.lru.capacity (default: `null`):: -+ --- -Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. --- -[[rust-analyzer.notifications.cargoTomlNotFound]]rust-analyzer.notifications.cargoTomlNotFound (default: `true`):: -+ --- -Whether to show `can't find Cargo.toml` error message. --- -[[rust-analyzer.procMacro.attributes.enable]]rust-analyzer.procMacro.attributes.enable (default: `true`):: -+ --- -Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set. --- -[[rust-analyzer.procMacro.enable]]rust-analyzer.procMacro.enable (default: `true`):: -+ --- -Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`. --- -[[rust-analyzer.procMacro.ignored]]rust-analyzer.procMacro.ignored (default: `{}`):: -+ --- -These proc-macros will be ignored when trying to expand them. - -This config takes a map of crate names with the exported proc-macro names to ignore as values. --- -[[rust-analyzer.procMacro.server]]rust-analyzer.procMacro.server (default: `null`):: -+ --- -Internal config, path to proc-macro server executable (typically, -this is rust-analyzer itself, but we override this in tests). --- -[[rust-analyzer.runnables.command]]rust-analyzer.runnables.command (default: `null`):: -+ --- -Command to be executed instead of 'cargo' for runnables. --- -[[rust-analyzer.runnables.extraArgs]]rust-analyzer.runnables.extraArgs (default: `[]`):: -+ --- -Additional arguments to be passed to cargo for runnables such as -tests or binaries. For example, it may be `--release`. --- -[[rust-analyzer.rustc.source]]rust-analyzer.rustc.source (default: `null`):: -+ --- -Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private -projects, or "discover" to try to automatically find it if the `rustc-dev` component -is installed. - -Any project which uses rust-analyzer with the rustcPrivate -crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it. - -This option does not take effect until rust-analyzer is restarted. --- -[[rust-analyzer.rustfmt.extraArgs]]rust-analyzer.rustfmt.extraArgs (default: `[]`):: -+ --- -Additional arguments to `rustfmt`. --- -[[rust-analyzer.rustfmt.overrideCommand]]rust-analyzer.rustfmt.overrideCommand (default: `null`):: -+ --- -Advanced option, fully override the command rust-analyzer uses for -formatting. --- -[[rust-analyzer.rustfmt.rangeFormatting.enable]]rust-analyzer.rustfmt.rangeFormatting.enable (default: `false`):: -+ --- -Enables the use of rustfmt's unstable range formatting command for the -`textDocument/rangeFormatting` request. The rustfmt option is unstable and only -available on a nightly build. --- -[[rust-analyzer.semanticHighlighting.strings.enable]]rust-analyzer.semanticHighlighting.strings.enable (default: `true`):: -+ --- -Use semantic tokens for strings. - -In some editors (e.g. vscode) semantic tokens override other highlighting grammars. -By disabling semantic tokens for strings, other grammars can be used to highlight -their contents. --- -[[rust-analyzer.signatureInfo.detail]]rust-analyzer.signatureInfo.detail (default: `"full"`):: -+ --- -Show full signature of the callable. Only shows parameters if disabled. --- -[[rust-analyzer.signatureInfo.documentation.enable]]rust-analyzer.signatureInfo.documentation.enable (default: `true`):: -+ --- -Show documentation. --- -[[rust-analyzer.typing.autoClosingAngleBrackets.enable]]rust-analyzer.typing.autoClosingAngleBrackets.enable (default: `false`):: -+ --- -Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. --- -[[rust-analyzer.workspace.symbol.search.kind]]rust-analyzer.workspace.symbol.search.kind (default: `"only_types"`):: -+ --- -Workspace symbol search kind. --- -[[rust-analyzer.workspace.symbol.search.limit]]rust-analyzer.workspace.symbol.search.limit (default: `128`):: -+ --- -Limits the number of items returned from a workspace symbol search (Defaults to 128). -Some clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search. -Other clients requires all results upfront and might require a higher limit. --- -[[rust-analyzer.workspace.symbol.search.scope]]rust-analyzer.workspace.symbol.search.scope (default: `"workspace"`):: -+ --- -Workspace symbol search scope. --- diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc deleted file mode 100644 index 999a6437ab9ed..0000000000000 --- a/src/tools/rust-analyzer/docs/user/manual.adoc +++ /dev/null @@ -1,863 +0,0 @@ -= User Manual -:toc: preamble -:sectanchors: -:page-layout: post -:icons: font -:source-highlighter: rouge -:experimental: - -//// -IMPORTANT: the master copy of this document lives in the https://github.com/rust-lang/rust-analyzer repository -//// - -At its core, rust-analyzer is a *library* for semantic analysis of Rust code as it changes over time. -This manual focuses on a specific usage of the library -- running it as part of a server that implements the -https://microsoft.github.io/language-server-protocol/[Language Server Protocol] (LSP). -The LSP allows various code editors, like VS Code, Emacs or Vim, to implement semantic features like completion or goto definition by talking to an external language server process. - -[TIP] -==== -[.lead] -To improve this document, send a pull request: + -https://github.com/rust-lang/rust-analyzer/blob/master/docs/user/manual.adoc[https://github.com/rust-analyzer/.../manual.adoc] - -The manual is written in https://asciidoc.org[AsciiDoc] and includes some extra files which are generated from the source code. Run `cargo test` and `cargo test -p xtask` to create these and then `asciidoctor manual.adoc` to create an HTML copy. -==== - -If you have questions about using rust-analyzer, please ask them in the https://users.rust-lang.org/c/ide/14["`IDEs and Editors`"] topic of Rust users forum. - -== Installation - -In theory, one should be able to just install the <> and have it automatically work with any editor. -We are not there yet, so some editor specific setup is required. - -Additionally, rust-analyzer needs the sources of the standard library. -If the source code is not present, rust-analyzer will attempt to install it automatically. - -To add the sources manually, run the following command: - -```bash -$ rustup component add rust-src -``` - -=== Toolchain - -Only the latest stable standard library source is officially supported for use with rust-analyzer. -If you are using an older toolchain or have an override set, rust-analyzer may fail to understand the Rust source. -You will either need to update your toolchain or use an older version of rust-analyzer that is compatible with your toolchain. - -If you are using an override in your project, you can still force rust-analyzer to use the stable toolchain via the environment variable `RUSTUP_TOOLCHAIN`. -For example, with VS Code or coc-rust-analyzer: - -[source,json] ----- -{ "rust-analyzer.server.extraEnv": { "RUSTUP_TOOLCHAIN": "stable" } } ----- - -=== VS Code - -This is the best supported editor at the moment. -The rust-analyzer plugin for VS Code is maintained -https://github.com/rust-lang/rust-analyzer/tree/master/editors/code[in tree]. - -You can install the latest release of the plugin from -https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer[the marketplace]. - -Note that the plugin may cause conflicts with the -https://marketplace.visualstudio.com/items?itemName=rust-lang.rust[official Rust plugin]. -It is recommended to disable the Rust plugin when using the rust-analyzer extension. - -By default, the plugin will prompt you to download the matching version of the server as well: - -image::https://user-images.githubusercontent.com/9021944/75067008-17502500-54ba-11ea-835a-f92aac50e866.png[] - -[NOTE] -==== -To disable this notification put the following to `settings.json` - -[source,json] ----- -{ "rust-analyzer.updates.askBeforeDownload": false } ----- -==== - -The server binary is stored in the extension install directory, which starts with `rust-lang.rust-analyzer-` and is located under: - -* Linux: `~/.vscode/extensions` -* Linux (Remote, such as WSL): `~/.vscode-server/extensions` -* macOS: `~/.vscode/extensions` -* Windows: `%USERPROFILE%\.vscode\extensions` - -As an exception, on NixOS, the extension makes a copy of the server and stores it under `~/.config/Code/User/globalStorage/rust-lang.rust-analyzer`. - -Note that we only support the two most recent versions of VS Code. - -==== Updates - -The extension will be updated automatically as new versions become available. -It will ask your permission to download the matching language server version binary if needed. - -===== Nightly - -We ship nightly releases for VS Code. -To help us out by testing the newest code, you can enable pre-release versions in the Code extension page. - -==== Manual installation - -Alternatively, download a VSIX corresponding to your platform from the -https://github.com/rust-lang/rust-analyzer/releases[releases] page. - -Install the extension with the `Extensions: Install from VSIX` command within VS Code, or from the command line via: -[source] ----- -$ code --install-extension /path/to/rust-analyzer.vsix ----- - -If you are running an unsupported platform, you can install `rust-analyzer-no-server.vsix` and compile or obtain a server binary. -Copy the server anywhere, then add the path to your settings.json, for example: -[source,json] ----- -{ "rust-analyzer.server.path": "~/.local/bin/rust-analyzer-linux" } ----- - -==== Building From Source - -Both the server and the Code plugin can be installed from source: - -[source] ----- -$ git clone https://github.com/rust-lang/rust-analyzer.git && cd rust-analyzer -$ cargo xtask install ----- - -You'll need Cargo, nodejs (matching a supported version of VS Code) and npm for this. - -Note that installing via `xtask install` does not work for VS Code Remote, instead you'll need to install the `.vsix` manually. - -If you're not using Code, you can compile and install only the LSP server: - -[source] ----- -$ cargo xtask install --server ----- - -=== rust-analyzer Language Server Binary - -Other editors generally require the `rust-analyzer` binary to be in `$PATH`. -You can download pre-built binaries from the https://github.com/rust-lang/rust-analyzer/releases[releases] page. -You will need to uncompress and rename the binary for your platform, e.g. from `rust-analyzer-aarch64-apple-darwin.gz` on Mac OS to `rust-analyzer`, make it executable, then move it into a directory in your `$PATH`. - -On Linux to install the `rust-analyzer` binary into `~/.local/bin`, these commands should work: - -[source,bash] ----- -$ mkdir -p ~/.local/bin -$ curl -L https://github.com/rust-lang/rust-analyzer/releases/latest/download/rust-analyzer-x86_64-unknown-linux-gnu.gz | gunzip -c - > ~/.local/bin/rust-analyzer -$ chmod +x ~/.local/bin/rust-analyzer ----- - -Make sure that `~/.local/bin` is listed in the `$PATH` variable and use the appropriate URL if you're not on a `x86-64` system. - -You don't have to use `~/.local/bin`, any other path like `~/.cargo/bin` or `/usr/local/bin` will work just as well. - -Alternatively, you can install it from source using the command below. -You'll need the latest stable version of the Rust toolchain. - -[source,bash] ----- -$ git clone https://github.com/rust-lang/rust-analyzer.git && cd rust-analyzer -$ cargo xtask install --server ----- - -If your editor can't find the binary even though the binary is on your `$PATH`, the likely explanation is that it doesn't see the same `$PATH` as the shell, see https://github.com/rust-lang/rust-analyzer/issues/1811[this issue]. -On Unix, running the editor from a shell or changing the `.desktop` file to set the environment should help. - -==== `rustup` - -`rust-analyzer` is available in `rustup`, but only in the nightly toolchain: - -[source,bash] ----- -$ rustup +nightly component add rust-analyzer-preview ----- - -However, in contrast to `component add clippy` or `component add rustfmt`, this does not actually place a `rust-analyzer` binary in `~/.cargo/bin`, see https://github.com/rust-lang/rustup/issues/2411[this issue]. - -==== Arch Linux - -The `rust-analyzer` binary can be installed from the repos or AUR (Arch User Repository): - -- https://www.archlinux.org/packages/community/x86_64/rust-analyzer/[`rust-analyzer`] (built from latest tagged source) -- https://aur.archlinux.org/packages/rust-analyzer-git[`rust-analyzer-git`] (latest Git version) - -Install it with pacman, for example: - -[source,bash] ----- -$ pacman -S rust-analyzer ----- - -==== Gentoo Linux - -`rust-analyzer` is available in the GURU repository: - -- https://gitweb.gentoo.org/repo/proj/guru.git/tree/dev-util/rust-analyzer?id=9895cea62602cfe599bd48e0fb02127411ca6e81[`dev-util/rust-analyzer`] builds from source -- https://gitweb.gentoo.org/repo/proj/guru.git/tree/dev-util/rust-analyzer-bin?id=9895cea62602cfe599bd48e0fb02127411ca6e81[`dev-util/rust-analyzer-bin`] installs an official binary release - -If not already, GURU must be enabled (e.g. using `app-eselect/eselect-repository`) and sync'd before running `emerge`: - -[source,bash] ----- -$ eselect repository enable guru && emaint sync -r guru -$ emerge rust-analyzer-bin ----- - -==== macOS - -The `rust-analyzer` binary can be installed via https://brew.sh/[Homebrew]. - -[source,bash] ----- -$ brew install rust-analyzer ----- - -=== Emacs - -Note this excellent https://robert.kra.hn/posts/2021-02-07_rust-with-emacs/[guide] from https://github.com/rksm[@rksm]. - -Prerequisites: You have installed the <>. - -Emacs support is maintained as part of the https://github.com/emacs-lsp/lsp-mode[Emacs-LSP] package in https://github.com/emacs-lsp/lsp-mode/blob/master/lsp-rust.el[lsp-rust.el]. - -1. Install the most recent version of `emacs-lsp` package by following the https://github.com/emacs-lsp/lsp-mode[Emacs-LSP instructions]. -2. Set `lsp-rust-server` to `'rust-analyzer`. -3. Run `lsp` in a Rust buffer. -4. (Optionally) bind commands like `lsp-rust-analyzer-join-lines`, `lsp-extend-selection` and `lsp-rust-analyzer-expand-macro` to keys. - -=== Vim/NeoVim - -Prerequisites: You have installed the <>. -Not needed if the extension can install/update it on its own, coc-rust-analyzer is one example. - -There are several LSP client implementations for vim or neovim: - -==== coc-rust-analyzer - -1. Install coc.nvim by following the instructions at - https://github.com/neoclide/coc.nvim[coc.nvim] - (Node.js required) -2. Run `:CocInstall coc-rust-analyzer` to install - https://github.com/fannheyward/coc-rust-analyzer[coc-rust-analyzer], - this extension implements _most_ of the features supported in the VSCode extension: - * automatically install and upgrade stable/nightly releases - * same configurations as VSCode extension, `rust-analyzer.server.path`, `rust-analyzer.cargo.features` etc. - * same commands too, `rust-analyzer.analyzerStatus`, `rust-analyzer.ssr` etc. - * inlay hints for variables and method chaining, _Neovim Only_ - -Note: for code actions, use `coc-codeaction-cursor` and `coc-codeaction-selected`; `coc-codeaction` and `coc-codeaction-line` are unlikely to be useful. - -==== LanguageClient-neovim - -1. Install LanguageClient-neovim by following the instructions - https://github.com/autozimu/LanguageClient-neovim[here] - * The GitHub project wiki has extra tips on configuration - -2. Configure by adding this to your vim/neovim config file (replacing the existing Rust-specific line if it exists): -+ -[source,vim] ----- -let g:LanguageClient_serverCommands = { -\ 'rust': ['rust-analyzer'], -\ } ----- - -==== YouCompleteMe - -Install YouCompleteMe by following the instructions - https://github.com/ycm-core/YouCompleteMe#installation[here]. - -rust-analyzer is the default in ycm, it should work out of the box. - -==== ALE - -To use the LSP server in https://github.com/dense-analysis/ale[ale]: - -[source,vim] ----- -let g:ale_linters = {'rust': ['analyzer']} ----- - -==== nvim-lsp - -NeoVim 0.5 has built-in language server support. -For a quick start configuration of rust-analyzer, use https://github.com/neovim/nvim-lspconfig#rust_analyzer[neovim/nvim-lspconfig]. -Once `neovim/nvim-lspconfig` is installed, use `+lua require'lspconfig'.rust_analyzer.setup({})+` in your `init.vim`. - -You can also pass LSP settings to the server: - -[source,vim] ----- -lua << EOF -local nvim_lsp = require'lspconfig' - -local on_attach = function(client) - require'completion'.on_attach(client) -end - -nvim_lsp.rust_analyzer.setup({ - on_attach=on_attach, - settings = { - ["rust-analyzer"] = { - imports = { - granularity = { - group = "module", - }, - prefix = "self", - }, - cargo = { - buildScripts = { - enable = true, - }, - }, - procMacro = { - enable = true - }, - } - } -}) -EOF ----- - -See https://sharksforarms.dev/posts/neovim-rust/ for more tips on getting started. - -Check out https://github.com/simrat39/rust-tools.nvim for a batteries included rust-analyzer setup for neovim. - -==== vim-lsp - -vim-lsp is installed by following https://github.com/prabirshrestha/vim-lsp[the plugin instructions]. -It can be as simple as adding this line to your `.vimrc`: - -[source,vim] ----- -Plug 'prabirshrestha/vim-lsp' ----- - -Next you need to register the `rust-analyzer` binary. -If it is available in `$PATH`, you may want to add this to your `.vimrc`: - -[source,vim] ----- -if executable('rust-analyzer') - au User lsp_setup call lsp#register_server({ - \ 'name': 'Rust Language Server', - \ 'cmd': {server_info->['rust-analyzer']}, - \ 'whitelist': ['rust'], - \ }) -endif ----- - -There is no dedicated UI for the server configuration, so you would need to send any options as a value of the `initialization_options` field, as described in the <<_configuration,Configuration>> section. -Here is an example of how to enable the proc-macro support: - -[source,vim] ----- -if executable('rust-analyzer') - au User lsp_setup call lsp#register_server({ - \ 'name': 'Rust Language Server', - \ 'cmd': {server_info->['rust-analyzer']}, - \ 'whitelist': ['rust'], - \ 'initialization_options': { - \ 'cargo': { - \ 'buildScripts': { - \ 'enable': v:true, - \ }, - \ }, - \ 'procMacro': { - \ 'enable': v:true, - \ }, - \ }, - \ }) -endif ----- - -=== Sublime Text - -==== Sublime Text 4: -* Follow the instructions in link:https://github.com/sublimelsp/LSP-rust-analyzer[LSP-rust-analyzer]. - -NOTE: Install link:https://packagecontrol.io/packages/LSP-file-watcher-chokidar[LSP-file-watcher-chokidar] to enable file watching (`workspace/didChangeWatchedFiles`). - -==== Sublime Text 3: -* Install the <>. -* Install the link:https://packagecontrol.io/packages/LSP[LSP package]. -* From the command palette, run `LSP: Enable Language Server Globally` and select `rust-analyzer`. - -If it worked, you should see "rust-analyzer, Line X, Column Y" on the left side of the status bar, and after waiting a bit, functionalities like tooltips on hovering over variables should become available. - -If you get an error saying `No such file or directory: 'rust-analyzer'`, see the <> section on installing the language server binary. - -=== GNOME Builder - -GNOME Builder 3.37.1 and newer has native `rust-analyzer` support. -If the LSP binary is not available, GNOME Builder can install it when opening a Rust file. - - -=== Eclipse IDE - -Support for Rust development in the Eclipse IDE is provided by link:https://github.com/eclipse/corrosion[Eclipse Corrosion]. -If available in PATH or in some standard location, `rust-analyzer` is detected and powers editing of Rust files without further configuration. -If `rust-analyzer` is not detected, Corrosion will prompt you for configuration of your Rust toolchain and language server with a link to the __Window > Preferences > Rust__ preference page; from here a button allows to download and configure `rust-analyzer`, but you can also reference another installation. -You'll need to close and reopen all .rs and Cargo files, or to restart the IDE, for this change to take effect. - -=== Kate Text Editor - -Support for the language server protocol is built into Kate through the LSP plugin, which is included by default. -It is preconfigured to use rust-analyzer for Rust sources since Kate 21.12. - -Earlier versions allow you to use rust-analyzer through a simple settings change. -In the LSP Client settings of Kate, copy the content of the third tab "default parameters" to the second tab "server configuration". -Then in the configuration replace: -[source,json] ----- - "rust": { - "command": ["rls"], - "rootIndicationFileNames": ["Cargo.lock", "Cargo.toml"], - "url": "https://github.com/rust-lang/rls", - "highlightingModeRegex": "^Rust$" - }, ----- -With -[source,json] ----- - "rust": { - "command": ["rust-analyzer"], - "rootIndicationFileNames": ["Cargo.lock", "Cargo.toml"], - "url": "https://github.com/rust-lang/rust-analyzer", - "highlightingModeRegex": "^Rust$" - }, ----- -Then click on apply, and restart the LSP server for your rust project. - -=== juCi++ - -https://gitlab.com/cppit/jucipp[juCi++] has built-in support for the language server protocol, and since version 1.7.0 offers installation of both Rust and rust-analyzer when opening a Rust file. - -=== Kakoune - -https://kakoune.org/[Kakoune] supports LSP with the help of https://github.com/kak-lsp/kak-lsp[`kak-lsp`]. -Follow the https://github.com/kak-lsp/kak-lsp#installation[instructions] to install `kak-lsp`. -To configure `kak-lsp`, refer to the https://github.com/kak-lsp/kak-lsp#configuring-kak-lsp[configuration section] which is basically about copying the https://github.com/kak-lsp/kak-lsp/blob/master/kak-lsp.toml[configuration file] in the right place (latest versions should use `rust-analyzer` by default). - -Finally, you need to configure Kakoune to talk to `kak-lsp` (see https://github.com/kak-lsp/kak-lsp#usage[Usage section]). -A basic configuration will only get you LSP but you can also activate inlay diagnostics and auto-formatting on save. -The following might help you get all of this. - -[source,txt] ----- -eval %sh{kak-lsp --kakoune -s $kak_session} # Not needed if you load it with plug.kak. -hook global WinSetOption filetype=rust %{ - # Enable LSP - lsp-enable-window - - # Auto-formatting on save - hook window BufWritePre .* lsp-formatting-sync - - # Configure inlay hints (only on save) - hook window -group rust-inlay-hints BufWritePost .* rust-analyzer-inlay-hints - hook -once -always window WinSetOption filetype=.* %{ - remove-hooks window rust-inlay-hints - } -} ----- - -=== Helix - -https://docs.helix-editor.com/[Helix] supports LSP by default. -However, it won't install `rust-analyzer` automatically. -You can follow instructions for installing <>. - -== Troubleshooting - -Start with looking at the rust-analyzer version. -Try **Rust Analyzer: Show RA Version** in VS Code (using **Command Palette** feature typically activated by Ctrl+Shift+P) or `rust-analyzer --version` in the command line. -If the date is more than a week ago, it's better to update rust-analyzer version. - -The next thing to check would be panic messages in rust-analyzer's log. -Log messages are printed to stderr, in VS Code you can see then in the `Output > Rust Analyzer Language Server` tab of the panel. -To see more logs, set the `RA_LOG=info` environment variable, this can be done either by setting the environment variable manually or by using `rust-analyzer.server.extraEnv`, note that both of these approaches require the server to be restarted. - -To fully capture LSP messages between the editor and the server, set `"rust-analyzer.trace.server": "verbose"` config and check -`Output > Rust Analyzer Language Server Trace`. - -The root cause for many "`nothing works`" problems is that rust-analyzer fails to understand the project structure. -To debug that, first note the `rust-analyzer` section in the status bar. -If it has an error icon and red, that's the problem (hover will have somewhat helpful error message). -**Rust Analyzer: Status** prints dependency information for the current file. -Finally, `RA_LOG=project_model=debug` enables verbose logs during project loading. - -If rust-analyzer outright crashes, try running `rust-analyzer analysis-stats /path/to/project/directory/` on the command line. -This command type checks the whole project in batch mode bypassing LSP machinery. - -When filing issues, it is useful (but not necessary) to try to minimize examples. -An ideal bug reproduction looks like this: - -```bash -$ git clone https://github.com/username/repo.git && cd repo && git switch --detach commit-hash -$ rust-analyzer --version -rust-analyzer dd12184e4 2021-05-08 dev -$ rust-analyzer analysis-stats . -💀 💀 💀 -``` - -It is especially useful when the `repo` doesn't use external crates or the standard library. - -If you want to go as far as to modify the source code to debug the problem, be sure to take a look at the -https://github.com/rust-lang/rust-analyzer/tree/master/docs/dev[dev docs]! - -== Configuration - -**Source:** https://github.com/rust-lang/rust-analyzer/blob/master/crates/rust-analyzer/src/config.rs[config.rs] - -The <<_installation,Installation>> section contains details on configuration for some of the editors. -In general `rust-analyzer` is configured via LSP messages, which means that it's up to the editor to decide on the exact format and location of configuration files. - -Some clients, such as <> or <> provide `rust-analyzer` specific configuration UIs. Others may require you to know a bit more about the interaction with `rust-analyzer`. - -For the later category, it might help to know that the initial configuration is specified as a value of the `initializationOptions` field of the https://microsoft.github.io/language-server-protocol/specifications/specification-current/#initialize[`InitializeParams` message, in the LSP protocol]. -The spec says that the field type is `any?`, but `rust-analyzer` is looking for a JSON object that is constructed using settings from the list below. -Name of the setting, ignoring the `rust-analyzer.` prefix, is used as a path, and value of the setting becomes the JSON property value. - -For example, a very common configuration is to enable proc-macro support, can be achieved by sending this JSON: - -[source,json] ----- -{ - "cargo": { - "buildScripts": { - "enable": true, - }, - }, - "procMacro": { - "enable": true, - } -} ----- - -Please consult your editor's documentation to learn more about how to configure https://microsoft.github.io/language-server-protocol/[LSP servers]. - -To verify which configuration is actually used by `rust-analyzer`, set `RA_LOG` environment variable to `rust_analyzer=info` and look for config-related messages. -Logs should show both the JSON that `rust-analyzer` sees as well as the updated config. - -This is the list of config options `rust-analyzer` supports: - -include::./generated_config.adoc[] - -== Non-Cargo Based Projects - -rust-analyzer does not require Cargo. -However, if you use some other build system, you'll have to describe the structure of your project for rust-analyzer in the `rust-project.json` format: - -[source,TypeScript] ----- -interface JsonProject { - /// Path to the directory with *source code* of - /// sysroot crates. - /// - /// It should point to the directory where std, - /// core, and friends can be found: - /// - /// https://github.com/rust-lang/rust/tree/master/library. - /// - /// If provided, rust-analyzer automatically adds - /// dependencies on sysroot crates. Conversely, - /// if you omit this path, you can specify sysroot - /// dependencies yourself and, for example, have - /// several different "sysroots" in one graph of - /// crates. - sysroot_src?: string; - /// The set of crates comprising the current - /// project. Must include all transitive - /// dependencies as well as sysroot crate (libstd, - /// libcore and such). - crates: Crate[]; -} - -interface Crate { - /// Optional crate name used for display purposes, - /// without affecting semantics. See the `deps` - /// key for semantically-significant crate names. - display_name?: string; - /// Path to the root module of the crate. - root_module: string; - /// Edition of the crate. - edition: "2015" | "2018" | "2021"; - /// Dependencies - deps: Dep[]; - /// Should this crate be treated as a member of - /// current "workspace". - /// - /// By default, inferred from the `root_module` - /// (members are the crates which reside inside - /// the directory opened in the editor). - /// - /// Set this to `false` for things like standard - /// library and 3rd party crates to enable - /// performance optimizations (rust-analyzer - /// assumes that non-member crates don't change). - is_workspace_member?: boolean; - /// Optionally specify the (super)set of `.rs` - /// files comprising this crate. - /// - /// By default, rust-analyzer assumes that only - /// files under `root_module.parent` can belong - /// to a crate. `include_dirs` are included - /// recursively, unless a subdirectory is in - /// `exclude_dirs`. - /// - /// Different crates can share the same `source`. - /// - /// If two crates share an `.rs` file in common, - /// they *must* have the same `source`. - /// rust-analyzer assumes that files from one - /// source can't refer to files in another source. - source?: { - include_dirs: string[], - exclude_dirs: string[], - }, - /// The set of cfgs activated for a given crate, like - /// `["unix", "feature=\"foo\"", "feature=\"bar\""]`. - cfg: string[]; - /// Target triple for this Crate. - /// - /// Used when running `rustc --print cfg` - /// to get target-specific cfgs. - target?: string; - /// Environment variables, used for - /// the `env!` macro - env: { [key: string]: string; }, - - /// Whether the crate is a proc-macro crate. - is_proc_macro: boolean; - /// For proc-macro crates, path to compiled - /// proc-macro (.so file). - proc_macro_dylib_path?: string; -} - -interface Dep { - /// Index of a crate in the `crates` array. - crate: number, - /// Name as should appear in the (implicit) - /// `extern crate name` declaration. - name: string, -} ----- - -This format is provisional and subject to change. -Specifically, the `roots` setup will be different eventually. - -There are three ways to feed `rust-project.json` to rust-analyzer: - -* Place `rust-project.json` file at the root of the project, and rust-analyzer will discover it. -* Specify `"rust-analyzer.linkedProjects": [ "path/to/rust-project.json" ]` in the settings (and make sure that your LSP client sends settings as a part of initialize request). -* Specify `"rust-analyzer.linkedProjects": [ { "roots": [...], "crates": [...] }]` inline. - -Relative paths are interpreted relative to `rust-project.json` file location or (for inline JSON) relative to `rootUri`. - -See https://github.com/rust-analyzer/rust-project.json-example for a small example. - -You can set the `RA_LOG` environment variable to `rust_analyzer=info` to inspect how rust-analyzer handles config and project loading. - -Note that calls to `cargo check` are disabled when using `rust-project.json` by default, so compilation errors and warnings will no longer be sent to your LSP client. To enable these compilation errors you will need to specify explicitly what command rust-analyzer should run to perform the checks using the `checkOnSave.overrideCommand` configuration. As an example, the following configuration explicitly sets `cargo check` as the `checkOnSave` command. - -[source,json] ----- -{ "rust-analyzer.checkOnSave.overrideCommand": ["cargo", "check", "--message-format=json"] } ----- - -The `checkOnSave.overrideCommand` requires the command specified to output json error messages for rust-analyzer to consume. The `--message-format=json` flag does this for `cargo check` so whichever command you use must also output errors in this format. See the <> section for more information. - -== Security - -At the moment, rust-analyzer assumes that all code is trusted. -Here is a **non-exhaustive** list of ways to make rust-analyzer execute arbitrary code: - -* proc macros and build scripts are executed by default -* `.cargo/config` can override `rustc` with an arbitrary executable -* `rust-toolchain.toml` can override `rustc` with an arbitrary executable -* VS Code plugin reads configuration from project directory, and that can be used to override paths to various executables, like `rustfmt` or `rust-analyzer` itself. -* rust-analyzer's syntax trees library uses a lot of `unsafe` and hasn't been properly audited for memory safety. - -== Privacy - -The LSP server performs no network access in itself, but runs `cargo metadata` which will update or download the crate registry and the source code of the project dependencies. -If enabled (the default), build scripts and procedural macros can do anything. - -The Code extension does not access the network. - -Any other editor plugins are not under the control of the `rust-analyzer` developers. For any privacy concerns, you should check with their respective developers. - -For `rust-analyzer` developers, `cargo xtask release` uses the GitHub API to put together the release notes. - -== Features - -include::./generated_features.adoc[] - -== Assists (Code Actions) - -Assists, or code actions, are small local refactorings, available in a particular context. -They are usually triggered by a shortcut or by clicking a light bulb icon in the editor. -Cursor position or selection is signified by `┃` character. - -include::./generated_assists.adoc[] - -== Diagnostics - -While most errors and warnings provided by rust-analyzer come from the `cargo check` integration, there's a growing number of diagnostics implemented using rust-analyzer's own analysis. -Some of these diagnostics don't respect `\#[allow]` or `\#[deny]` attributes yet, but can be turned off using the `rust-analyzer.diagnostics.enable`, `rust-analyzer.diagnostics.experimental.enable` or `rust-analyzer.diagnostics.disabled` settings. - -include::./generated_diagnostic.adoc[] - -== Editor Features -=== VS Code - -==== Color configurations - -It is possible to change the foreground/background color and font family/size of inlay hints. -Just add this to your `settings.json`: - -[source,jsonc] ----- -{ - "editor.inlayHints.fontFamily": "Courier New", - "editor.inlayHints.fontSize": 11, - - "workbench.colorCustomizations": { - // Name of the theme you are currently using - "[Default Dark+]": { - "editorInlayHint.foreground": "#868686f0", - "editorInlayHint.background": "#3d3d3d48", - - // Overrides for specific kinds of inlay hints - "editorInlayHint.typeForeground": "#fdb6fdf0", - "editorInlayHint.parameterForeground": "#fdb6fdf0", - } - } -} ----- - -==== Semantic style customizations - -You can customize the look of different semantic elements in the source code. -For example, mutable bindings are underlined by default and you can override this behavior by adding the following section to your `settings.json`: - -[source,jsonc] ----- -{ - "editor.semanticTokenColorCustomizations": { - "rules": { - "*.mutable": { - "fontStyle": "", // underline is the default - }, - } - }, -} ----- - -Most themes doesn't support styling unsafe operations differently yet. You can fix this by adding overrides for the rules `operator.unsafe`, `function.unsafe`, and `method.unsafe`: - -[source,jsonc] ----- -{ - "editor.semanticTokenColorCustomizations": { - "rules": { - "operator.unsafe": "#ff6600", - "function.unsafe": "#ff6600", - "method.unsafe": "#ff6600" - } - }, -} ----- - -In addition to the top-level rules you can specify overrides for specific themes. For example, if you wanted to use a darker text color on a specific light theme, you might write: - -[source,jsonc] ----- -{ - "editor.semanticTokenColorCustomizations": { - "rules": { - "operator.unsafe": "#ff6600" - }, - "[Ayu Light]": { - "rules": { - "operator.unsafe": "#572300" - } - } - }, -} ----- - -Make sure you include the brackets around the theme name. For example, use `"[Ayu Light]"` to customize the theme Ayu Light. - -==== Special `when` clause context for keybindings. -You may use `inRustProject` context to configure keybindings for rust projects only. -For example: - -[source,json] ----- -{ - "key": "ctrl+alt+d", - "command": "rust-analyzer.openDocs", - "when": "inRustProject" -} ----- -More about `when` clause contexts https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts[here]. - -==== Setting runnable environment variables -You can use "rust-analyzer.runnableEnv" setting to define runnable environment-specific substitution variables. -The simplest way for all runnables in a bunch: -```jsonc -"rust-analyzer.runnableEnv": { - "RUN_SLOW_TESTS": "1" -} -``` - -Or it is possible to specify vars more granularly: -```jsonc -"rust-analyzer.runnableEnv": [ - { - // "mask": null, // null mask means that this rule will be applied for all runnables - env: { - "APP_ID": "1", - "APP_DATA": "asdf" - } - }, - { - "mask": "test_name", - "env": { - "APP_ID": "2", // overwrites only APP_ID - } - } -] -``` - -You can use any valid regular expression as a mask. -Also note that a full runnable name is something like *run bin_or_example_name*, *test some::mod::test_name* or *test-mod some::mod*, so it is possible to distinguish binaries, single tests, and test modules with this masks: `"^run"`, `"^test "` (the trailing space matters!), and `"^test-mod"` respectively. - -==== Compiler feedback from external commands - -Instead of relying on the built-in `cargo check`, you can configure Code to run a command in the background and use the `$rustc-watch` problem matcher to generate inline error markers from its output. - -To do this you need to create a new https://code.visualstudio.com/docs/editor/tasks[VS Code Task] and set `rust-analyzer.checkOnSave.enable: false` in preferences. - -For example, if you want to run https://crates.io/crates/cargo-watch[`cargo watch`] instead, you might add the following to `.vscode/tasks.json`: - -```json -{ - "label": "Watch", - "group": "build", - "type": "shell", - "command": "cargo watch", - "problemMatcher": "$rustc-watch", - "isBackground": true -} -``` diff --git a/src/tools/rust-analyzer/editors/code/.eslintignore b/src/tools/rust-analyzer/editors/code/.eslintignore deleted file mode 100644 index 3a1e8e186f5dc..0000000000000 --- a/src/tools/rust-analyzer/editors/code/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -.eslintrc.js diff --git a/src/tools/rust-analyzer/editors/code/.eslintrc.js b/src/tools/rust-analyzer/editors/code/.eslintrc.js deleted file mode 100644 index 297e9fa1e5c89..0000000000000 --- a/src/tools/rust-analyzer/editors/code/.eslintrc.js +++ /dev/null @@ -1,37 +0,0 @@ -module.exports = { - env: { - es6: true, - node: true, - }, - extends: ["prettier"], - parser: "@typescript-eslint/parser", - parserOptions: { - project: "tsconfig.eslint.json", - tsconfigRootDir: __dirname, - sourceType: "module", - }, - plugins: ["@typescript-eslint"], - rules: { - camelcase: ["error"], - eqeqeq: ["error", "always", { null: "ignore" }], - curly: ["error", "multi-line"], - "no-console": ["error", { allow: ["warn", "error"] }], - "prefer-const": "error", - "@typescript-eslint/member-delimiter-style": [ - "error", - { - multiline: { - delimiter: "semi", - requireLast: true, - }, - singleline: { - delimiter: "semi", - requireLast: false, - }, - }, - ], - "@typescript-eslint/semi": ["error", "always"], - "@typescript-eslint/no-unnecessary-type-assertion": "error", - "@typescript-eslint/no-floating-promises": "error", - }, -}; diff --git a/src/tools/rust-analyzer/editors/code/.gitignore b/src/tools/rust-analyzer/editors/code/.gitignore deleted file mode 100644 index 2c975a947eb35..0000000000000 --- a/src/tools/rust-analyzer/editors/code/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -out -node_modules -server -.vscode-test/ -*.vsix -bundle -vscode.proposed.d.ts diff --git a/src/tools/rust-analyzer/editors/code/.prettierignore b/src/tools/rust-analyzer/editors/code/.prettierignore deleted file mode 100644 index 13baf68d7cc2e..0000000000000 --- a/src/tools/rust-analyzer/editors/code/.prettierignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules -.vscode-test -out diff --git a/src/tools/rust-analyzer/editors/code/.prettierrc.js b/src/tools/rust-analyzer/editors/code/.prettierrc.js deleted file mode 100644 index cafb12f0e6ddf..0000000000000 --- a/src/tools/rust-analyzer/editors/code/.prettierrc.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - // use 100 because it's Rustfmt's default - // https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#max_width - printWidth: 100, -}; diff --git a/src/tools/rust-analyzer/editors/code/.vscodeignore b/src/tools/rust-analyzer/editors/code/.vscodeignore deleted file mode 100644 index 09dc27056b37a..0000000000000 --- a/src/tools/rust-analyzer/editors/code/.vscodeignore +++ /dev/null @@ -1,14 +0,0 @@ -** -!icon.png -!language-configuration.json -!LICENSE -!node_modules/@hpcc-js/wasm/dist/graphvizlib.wasm -!node_modules/@hpcc-js/wasm/dist/index.min.js -!node_modules/d3-graphviz/build/d3-graphviz.min.js -!node_modules/d3/dist/d3.min.js -!out/main.js -!package-lock.json -!package.json -!ra_syntax_tree.tmGrammar.json -!server -!README.md diff --git a/src/tools/rust-analyzer/editors/code/LICENSE b/src/tools/rust-analyzer/editors/code/LICENSE deleted file mode 100644 index d32e7fe8c9189..0000000000000 --- a/src/tools/rust-analyzer/editors/code/LICENSE +++ /dev/null @@ -1,230 +0,0 @@ -This software is licensed under either of the Apache License, Version -2.0, or the MIT License. See below for their text. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -MIT License - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/src/tools/rust-analyzer/editors/code/README.md b/src/tools/rust-analyzer/editors/code/README.md deleted file mode 100644 index 36ab98188220e..0000000000000 --- a/src/tools/rust-analyzer/editors/code/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# rust-analyzer - -This extension provides support for the [Rust programming language](https://www.rust-lang.org/). -It is recommended over and replaces `rust-lang.rust`. - -## Features - -- [code completion] with [imports insertion] -- go to [definition], [implementation], [type definition] -- [find all references], [workspace symbol search], [symbol renaming] -- [types and documentation on hover] -- [inlay hints] for types and parameter names -- [semantic syntax highlighting] -- a lot of [assists (code actions)] -- apply suggestions from errors -- ... and many more, check out the [manual] to see them all - -[code completion]: https://rust-analyzer.github.io/manual.html#magic-completions -[imports insertion]: https://rust-analyzer.github.io/manual.html#completion-with-autoimport -[definition]: https://rust-analyzer.github.io/manual.html#go-to-definition -[implementation]: https://rust-analyzer.github.io/manual.html#go-to-implementation -[type definition]: https://rust-analyzer.github.io/manual.html#go-to-type-definition -[find all references]: https://rust-analyzer.github.io/manual.html#find-all-references -[workspace symbol search]: https://rust-analyzer.github.io/manual.html#workspace-symbol -[symbol renaming]: https://rust-analyzer.github.io/manual.html#rename -[types and documentation on hover]: https://rust-analyzer.github.io/manual.html#hover -[inlay hints]: https://rust-analyzer.github.io/manual.html#inlay-hints -[semantic syntax highlighting]: https://rust-analyzer.github.io/manual.html#semantic-syntax-highlighting -[assists (code actions)]: https://rust-analyzer.github.io/manual.html#assists-code-actions -[manual]: https://rust-analyzer.github.io/manual.html - -## Quick start - -1. Install [rustup]. -2. Install the [rust-analyzer extension]. - -[rustup]: https://rustup.rs -[rust-analyzer extension]: https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer - -## Configuration - -This extension provides configurations through VSCode's configuration settings. All configurations are under `rust-analyzer.*`. - -See [the manual](https://rust-analyzer.github.io/manual.html#vs-code-2) for more information on VSCode specific configurations. - -## Communication - -For usage and troubleshooting requests, please use the ["IDEs and Editors" category of the Rust forum](https://users.rust-lang.org/c/ide/14). - -## Documentation - -See [rust-analyzer.github.io](https://rust-analyzer.github.io/) for more information. diff --git a/src/tools/rust-analyzer/editors/code/icon.png b/src/tools/rust-analyzer/editors/code/icon.png deleted file mode 100644 index 072090c6f4a1f..0000000000000 Binary files a/src/tools/rust-analyzer/editors/code/icon.png and /dev/null differ diff --git a/src/tools/rust-analyzer/editors/code/language-configuration.json b/src/tools/rust-analyzer/editors/code/language-configuration.json deleted file mode 100644 index b1ee0843e3e69..0000000000000 --- a/src/tools/rust-analyzer/editors/code/language-configuration.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "comments": { - "lineComment": "//", - "blockComment": ["/*", "*/"] - }, - "brackets": [ - ["{", "}"], - ["[", "]"], - ["(", ")"] - ], - "colorizedBracketPairs": [ - ["{", "}"], - ["[", "]"], - ["(", ")"] - ], - "autoClosingPairs": [ - { "open": "{", "close": "}" }, - { "open": "[", "close": "]" }, - { "open": "(", "close": ")" }, - { "open": "\"", "close": "\"", "notIn": ["string"] }, - { "open": "/*", "close": " */" } - ], - "autoCloseBefore": ";:.,=}])> \n\t", - "surroundingPairs": [ - ["{", "}"], - ["[", "]"], - ["(", ")"], - ["<", ">"], - ["\"", "\""], - ["'", "'"] - ], - "indentationRules": { - "increaseIndentPattern": "^.*\\{[^}\"']*$|^.*\\([^\\)\"']*$", - "decreaseIndentPattern": "^\\s*(\\s*\\/[*].*[*]\\/\\s*)*[})]" - }, - "folding": { - "markers": { - "start": "^\\s*//\\s*#?region\\b", - "end": "^\\s*//\\s*#?endregion\\b" - } - } -} diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json deleted file mode 100644 index 0436681b1a0a9..0000000000000 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ /dev/null @@ -1,2811 +0,0 @@ -{ - "name": "rust-analyzer", - "version": "0.5.0-dev", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@eslint/eslintrc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", - "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.3.2", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@hpcc-js/wasm": { - "version": "1.12.8", - "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-1.12.8.tgz", - "integrity": "sha512-n4q9ARKco2hpCLsuVaW6Az3cDVaua7B3DSONHkc49WtEzgY/btvcDG5Zr1P6PZDv0sQ7oPnAi9Y+W2DI++MgcQ==", - "requires": { - "yargs": "^17.3.1" - } - }, - "@humanwhocodes/config-array": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", - "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, - "@types/node": { - "version": "16.11.43", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.43.tgz", - "integrity": "sha512-GqWykok+3uocgfAJM8imbozrqLnPyTrpFlrryURQlw1EesPUCx5XxTiucWDSFF9/NUEXDuD4bnvHm8xfVGWTpQ==", - "dev": true - }, - "@types/vscode": { - "version": "1.66.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.66.0.tgz", - "integrity": "sha512-ZfJck4M7nrGasfs4A4YbUoxis3Vu24cETw3DERsNYtDZmYSYtk6ljKexKFKhImO/ZmY6ZMsmegu2FPkXoUFImA==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "5.30.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz", - "integrity": "sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.30.5", - "@typescript-eslint/type-utils": "5.30.5", - "@typescript-eslint/utils": "5.30.5", - "debug": "^4.3.4", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.2.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/parser": { - "version": "5.30.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.5.tgz", - "integrity": "sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.30.5", - "@typescript-eslint/types": "5.30.5", - "@typescript-eslint/typescript-estree": "5.30.5", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.30.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz", - "integrity": "sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.30.5", - "@typescript-eslint/visitor-keys": "5.30.5" - } - }, - "@typescript-eslint/type-utils": { - "version": "5.30.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz", - "integrity": "sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw==", - "dev": true, - "requires": { - "@typescript-eslint/utils": "5.30.5", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/types": { - "version": "5.30.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.5.tgz", - "integrity": "sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.30.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz", - "integrity": "sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.30.5", - "@typescript-eslint/visitor-keys": "5.30.5", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/utils": { - "version": "5.30.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.5.tgz", - "integrity": "sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.30.5", - "@typescript-eslint/types": "5.30.5", - "@typescript-eslint/typescript-estree": "5.30.5", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.30.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz", - "integrity": "sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.30.5", - "eslint-visitor-keys": "^3.3.0" - } - }, - "@vscode/test-electron": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.1.5.tgz", - "integrity": "sha512-O/ioqFpV+RvKbRykX2ItYPnbcZ4Hk5V0rY4uhQjQTLhGL9WZUvS7exzuYQCCI+ilSqJpctvxq2llTfGXf9UnnA==", - "dev": true, - "requires": { - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "rimraf": "^3.0.2", - "unzipper": "^0.10.11" - } - }, - "acorn": { - "version": "8.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", - "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "azure-devops-node-api": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz", - "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==", - "dev": true, - "requires": { - "tunnel": "0.0.6", - "typed-rest-client": "^1.8.4" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, - "big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "dev": true - }, - "binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", - "dev": true, - "requires": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - } - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", - "dev": true - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true - }, - "buffer-indexof-polyfill": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", - "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", - "dev": true - }, - "buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", - "dev": true - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", - "dev": true, - "requires": { - "traverse": ">=0.3.0 <0.4" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", - "dev": true, - "requires": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" - } - }, - "cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.1" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - } - }, - "css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "dev": true - }, - "d3": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/d3/-/d3-7.6.1.tgz", - "integrity": "sha512-txMTdIHFbcpLx+8a0IFhZsbp+PfBBPt8yfbmukZTQFroKuFqIwqswF0qE5JXWefylaAVpSXFoKm3yP+jpNLFLw==", - "requires": { - "d3-array": "3", - "d3-axis": "3", - "d3-brush": "3", - "d3-chord": "3", - "d3-color": "3", - "d3-contour": "4", - "d3-delaunay": "6", - "d3-dispatch": "3", - "d3-drag": "3", - "d3-dsv": "3", - "d3-ease": "3", - "d3-fetch": "3", - "d3-force": "3", - "d3-format": "3", - "d3-geo": "3", - "d3-hierarchy": "3", - "d3-interpolate": "3", - "d3-path": "3", - "d3-polygon": "3", - "d3-quadtree": "3", - "d3-random": "3", - "d3-scale": "4", - "d3-scale-chromatic": "3", - "d3-selection": "3", - "d3-shape": "3", - "d3-time": "3", - "d3-time-format": "4", - "d3-timer": "3", - "d3-transition": "3", - "d3-zoom": "3" - }, - "dependencies": { - "d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" - } - } - }, - "d3-array": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.0.tgz", - "integrity": "sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g==", - "requires": { - "internmap": "1 - 2" - } - }, - "d3-axis": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", - "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==" - }, - "d3-brush": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", - "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", - "requires": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "3", - "d3-transition": "3" - }, - "dependencies": { - "d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" - } - } - }, - "d3-chord": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", - "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", - "requires": { - "d3-path": "1 - 3" - } - }, - "d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==" - }, - "d3-contour": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.0.tgz", - "integrity": "sha512-7aQo0QHUTu/Ko3cP9YK9yUTxtoDEiDGwnBHyLxG5M4vqlBkO/uixMRele3nfsfj6UXOcuReVpVXzAboGraYIJw==", - "requires": { - "d3-array": "^3.2.0" - } - }, - "d3-delaunay": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz", - "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==", - "requires": { - "delaunator": "5" - } - }, - "d3-dispatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==" - }, - "d3-drag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", - "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", - "requires": { - "d3-dispatch": "1 - 3", - "d3-selection": "3" - }, - "dependencies": { - "d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" - } - } - }, - "d3-dsv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", - "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", - "requires": { - "commander": "7", - "iconv-lite": "0.6", - "rw": "1" - } - }, - "d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==" - }, - "d3-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", - "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", - "requires": { - "d3-dsv": "1 - 3" - } - }, - "d3-force": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", - "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", - "requires": { - "d3-dispatch": "1 - 3", - "d3-quadtree": "1 - 3", - "d3-timer": "1 - 3" - } - }, - "d3-format": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", - "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==" - }, - "d3-geo": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.0.1.tgz", - "integrity": "sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==", - "requires": { - "d3-array": "2.5.0 - 3" - } - }, - "d3-graphviz": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/d3-graphviz/-/d3-graphviz-4.1.1.tgz", - "integrity": "sha512-s0IVbKf8rs4eJI2xo5Umr7nXDX/LEZw/x2WtKxmlyQxR0qUY49UiLhBNOX7VDHZywMle43NKEXnU6fn22fpJvQ==", - "requires": { - "@hpcc-js/wasm": "1.12.8", - "d3-dispatch": "^2.0.0", - "d3-format": "^2.0.0", - "d3-interpolate": "^2.0.1", - "d3-path": "^2.0.0", - "d3-timer": "^2.0.0", - "d3-transition": "^2.0.0", - "d3-zoom": "^2.0.0" - }, - "dependencies": { - "d3-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", - "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==" - }, - "d3-dispatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz", - "integrity": "sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA==" - }, - "d3-drag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-2.0.0.tgz", - "integrity": "sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w==", - "requires": { - "d3-dispatch": "1 - 2", - "d3-selection": "2" - } - }, - "d3-ease": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz", - "integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ==" - }, - "d3-format": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz", - "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==" - }, - "d3-interpolate": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", - "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", - "requires": { - "d3-color": "1 - 2" - } - }, - "d3-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz", - "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA==" - }, - "d3-timer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz", - "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==" - }, - "d3-transition": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-2.0.0.tgz", - "integrity": "sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==", - "requires": { - "d3-color": "1 - 2", - "d3-dispatch": "1 - 2", - "d3-ease": "1 - 2", - "d3-interpolate": "1 - 2", - "d3-timer": "1 - 2" - } - }, - "d3-zoom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-2.0.0.tgz", - "integrity": "sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==", - "requires": { - "d3-dispatch": "1 - 2", - "d3-drag": "2", - "d3-interpolate": "1 - 2", - "d3-selection": "2", - "d3-transition": "2" - } - } - } - }, - "d3-hierarchy": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", - "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==" - }, - "d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "requires": { - "d3-color": "1 - 3" - } - }, - "d3-path": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz", - "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==" - }, - "d3-polygon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", - "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==" - }, - "d3-quadtree": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", - "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==" - }, - "d3-random": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", - "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==" - }, - "d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "requires": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" - } - }, - "d3-scale-chromatic": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", - "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", - "requires": { - "d3-color": "1 - 3", - "d3-interpolate": "1 - 3" - } - }, - "d3-selection": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz", - "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA==" - }, - "d3-shape": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.1.0.tgz", - "integrity": "sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==", - "requires": { - "d3-path": "1 - 3" - } - }, - "d3-time": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.0.0.tgz", - "integrity": "sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==", - "requires": { - "d3-array": "2 - 3" - } - }, - "d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "requires": { - "d3-time": "1 - 3" - } - }, - "d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==" - }, - "d3-transition": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", - "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", - "requires": { - "d3-color": "1 - 3", - "d3-dispatch": "1 - 3", - "d3-ease": "1 - 3", - "d3-interpolate": "1 - 3", - "d3-timer": "1 - 3" - } - }, - "d3-zoom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", - "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", - "requires": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "2 - 3", - "d3-transition": "2 - 3" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "requires": { - "mimic-response": "^3.1.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "delaunator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", - "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", - "requires": { - "robust-predicates": "^3.0.0" - } - }, - "detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - } - }, - "domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true - }, - "domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0" - } - }, - "domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", - "dev": true, - "requires": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" - } - }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", - "dev": true, - "requires": { - "readable-stream": "^2.0.2" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "entities": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz", - "integrity": "sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==", - "dev": true - }, - "esbuild": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz", - "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==", - "dev": true, - "requires": { - "esbuild-android-64": "0.14.48", - "esbuild-android-arm64": "0.14.48", - "esbuild-darwin-64": "0.14.48", - "esbuild-darwin-arm64": "0.14.48", - "esbuild-freebsd-64": "0.14.48", - "esbuild-freebsd-arm64": "0.14.48", - "esbuild-linux-32": "0.14.48", - "esbuild-linux-64": "0.14.48", - "esbuild-linux-arm": "0.14.48", - "esbuild-linux-arm64": "0.14.48", - "esbuild-linux-mips64le": "0.14.48", - "esbuild-linux-ppc64le": "0.14.48", - "esbuild-linux-riscv64": "0.14.48", - "esbuild-linux-s390x": "0.14.48", - "esbuild-netbsd-64": "0.14.48", - "esbuild-openbsd-64": "0.14.48", - "esbuild-sunos-64": "0.14.48", - "esbuild-windows-32": "0.14.48", - "esbuild-windows-64": "0.14.48", - "esbuild-windows-arm64": "0.14.48" - } - }, - "esbuild-android-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz", - "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==", - "dev": true, - "optional": true - }, - "esbuild-android-arm64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz", - "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==", - "dev": true, - "optional": true - }, - "esbuild-darwin-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz", - "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==", - "dev": true, - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz", - "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz", - "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz", - "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==", - "dev": true, - "optional": true - }, - "esbuild-linux-32": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz", - "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz", - "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz", - "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz", - "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==", - "dev": true, - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz", - "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==", - "dev": true, - "optional": true - }, - "esbuild-linux-ppc64le": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz", - "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-riscv64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz", - "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==", - "dev": true, - "optional": true - }, - "esbuild-linux-s390x": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz", - "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==", - "dev": true, - "optional": true - }, - "esbuild-netbsd-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz", - "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==", - "dev": true, - "optional": true - }, - "esbuild-openbsd-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz", - "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==", - "dev": true, - "optional": true - }, - "esbuild-sunos-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz", - "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==", - "dev": true, - "optional": true - }, - "esbuild-windows-32": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz", - "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==", - "dev": true, - "optional": true - }, - "esbuild-windows-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz", - "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==", - "dev": true, - "optional": true - }, - "esbuild-windows-arm64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz", - "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==", - "dev": true, - "optional": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz", - "integrity": "sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.9.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.2", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "eslint-config-prettier": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", - "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", - "dev": true - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - }, - "espree": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", - "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", - "dev": true, - "requires": { - "acorn": "^8.7.1", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - } - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "requires": { - "pend": "~1.2.0" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", - "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", - "dev": true - }, - "follow-redirects": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", - "dev": true - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "dev": true - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "13.16.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz", - "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true - }, - "hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "htmlparser2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", - "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "entities": "^4.3.0" - } - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==" - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "keytar": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", - "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", - "dev": true, - "requires": { - "node-addon-api": "^4.3.0", - "prebuild-install": "^7.0.1" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", - "dev": true, - "requires": { - "uc.micro": "^1.0.1" - } - }, - "listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", - "dev": true, - "requires": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "dependencies": { - "entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "dev": true - } - } - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "requires": { - "minimist": "^1.2.6" - } - }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node-abi": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.22.0.tgz", - "integrity": "sha512-u4uAs/4Zzmp/jjsD9cyFYDXeISfUWaAVWshPmDZOFOv4Xl4SbzTXm53I04C2uRueYJ+0t5PEtLH/owbn2Npf/w==", - "dev": true, - "requires": { - "semver": "^7.3.5" - } - }, - "node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", - "dev": true - }, - "nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "requires": { - "boolbase": "^1.0.0" - } - }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "ovsx": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.5.1.tgz", - "integrity": "sha512-3OWq0l7DuVHi2bd2aQe5+QVQlFIqvrcw3/2vGXL404L6Tr+R4QHtzfnYYghv8CCa85xJHjU0RhcaC7pyXkAUbg==", - "dev": true, - "requires": { - "commander": "^6.1.0", - "follow-redirects": "^1.14.6", - "is-ci": "^2.0.0", - "leven": "^3.1.0", - "tmp": "^0.2.1", - "vsce": "^2.6.3" - }, - "dependencies": { - "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true - } - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-semver": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", - "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==", - "dev": true, - "requires": { - "semver": "^5.1.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "parse5": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz", - "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==", - "dev": true, - "requires": { - "entities": "^4.3.0" - } - }, - "parse5-htmlparser2-tree-adapter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", - "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", - "dev": true, - "requires": { - "domhandler": "^5.0.2", - "parse5": "^7.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "prebuild-install": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", - "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", - "dev": true, - "requires": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true - } - } - }, - "read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", - "dev": true, - "requires": { - "mute-stream": "~0.0.4" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "robust-predicates": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz", - "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==" - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true - }, - "simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "dev": true, - "requires": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "requires": { - "rimraf": "^3.0.0" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", - "dev": true - }, - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "typed-rest-client": { - "version": "1.8.9", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz", - "integrity": "sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g==", - "dev": true, - "requires": { - "qs": "^6.9.1", - "tunnel": "0.0.6", - "underscore": "^1.12.1" - } - }, - "typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", - "dev": true - }, - "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true - }, - "underscore": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz", - "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==", - "dev": true - }, - "unzipper": { - "version": "0.10.11", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", - "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", - "dev": true, - "requires": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", - "duplexer2": "~0.1.4", - "fstream": "^1.0.12", - "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "vsce": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.9.2.tgz", - "integrity": "sha512-xyLqL4U82BilUX1t6Ym2opQEa2tLGWYjbgB7+ETeNVXlIJz5sWBJjQJSYJVFOKJSpiOtQclolu88cj7oY6vvPQ==", - "dev": true, - "requires": { - "azure-devops-node-api": "^11.0.1", - "chalk": "^2.4.2", - "cheerio": "^1.0.0-rc.9", - "commander": "^6.1.0", - "glob": "^7.0.6", - "hosted-git-info": "^4.0.2", - "keytar": "^7.7.0", - "leven": "^3.1.0", - "markdown-it": "^12.3.2", - "mime": "^1.3.4", - "minimatch": "^3.0.3", - "parse-semver": "^1.1.1", - "read": "^1.0.7", - "semver": "^5.1.0", - "tmp": "^0.2.1", - "typed-rest-client": "^1.8.4", - "url-join": "^4.0.1", - "xml2js": "^0.4.23", - "yauzl": "^2.3.1", - "yazl": "^2.2.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "vscode-jsonrpc": { - "version": "8.0.0-next.7", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.0-next.7.tgz", - "integrity": "sha512-JX/F31LEsims0dAlOTKFE4E+AJMiJvdRSRViifFJSqSN7EzeYyWlfuDchF7g91oRNPZOIWfibTkDf3/UMsQGzQ==" - }, - "vscode-languageclient": { - "version": "8.0.0-next.14", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.0-next.14.tgz", - "integrity": "sha512-NqjkOuDTMu8uo+PhoMsV72VO9Gd3wBi/ZpOrkRUOrWKQo7yUdiIw183g8wjH8BImgbK9ZP51HM7TI0ZhCnI1Mw==", - "requires": { - "minimatch": "^3.0.4", - "semver": "^7.3.5", - "vscode-languageserver-protocol": "3.17.0-next.16" - } - }, - "vscode-languageserver-protocol": { - "version": "3.17.0-next.16", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.0-next.16.tgz", - "integrity": "sha512-tx4DnXw9u3N7vw+bx6n2NKp6FoxoNwiP/biH83AS30I2AnTGyLd7afSeH6Oewn2E8jvB7K15bs12sMppkKOVeQ==", - "requires": { - "vscode-jsonrpc": "8.0.0-next.7", - "vscode-languageserver-types": "3.17.0-next.9" - } - }, - "vscode-languageserver-types": { - "version": "3.17.0-next.9", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.9.tgz", - "integrity": "sha512-9/PeDNPYduaoXRUzYpqmu4ZV9L01HGo0wH9FUt+sSHR7IXwA7xoXBfNUlv8gB9H0D2WwEmMomSy1NmhjKQyn3A==" - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dev": true, - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - } - }, - "yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==" - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3" - } - } - } -} diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json deleted file mode 100644 index a13798d8b36c9..0000000000000 --- a/src/tools/rust-analyzer/editors/code/package.json +++ /dev/null @@ -1,1613 +0,0 @@ -{ - "name": "rust-analyzer", - "displayName": "rust-analyzer", - "description": "Rust language support for Visual Studio Code", - "private": true, - "icon": "icon.png", - "version": "0.5.0-dev", - "releaseTag": null, - "publisher": "rust-lang", - "repository": { - "url": "https://github.com/rust-lang/rust-analyzer.git", - "type": "git" - }, - "homepage": "https://rust-analyzer.github.io/", - "license": "MIT OR Apache-2.0", - "keywords": [ - "rust" - ], - "categories": [ - "Programming Languages" - ], - "engines": { - "vscode": "^1.66.0" - }, - "enabledApiProposals": [], - "scripts": { - "vscode:prepublish": "npm run build-base -- --minify", - "package": "vsce package -o rust-analyzer.vsix", - "build-base": "esbuild ./src/main.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node --target=node16", - "build": "npm run build-base -- --sourcemap", - "watch": "npm run build-base -- --sourcemap --watch", - "lint": "prettier --check . && eslint -c .eslintrc.js --ext ts ./src ./tests", - "fix": "prettier --write . && eslint -c .eslintrc.js --ext ts ./src ./tests --fix", - "pretest": "tsc && npm run build", - "test": "cross-env TEST_VARIABLE=test node ./out/tests/runTests.js" - }, - "dependencies": { - "d3": "^7.6.1", - "d3-graphviz": "^4.1.1", - "vscode-languageclient": "^8.0.0-next.14" - }, - "devDependencies": { - "@types/node": "~16.11.7", - "@types/vscode": "~1.66.0", - "@typescript-eslint/eslint-plugin": "^5.30.5", - "@typescript-eslint/parser": "^5.30.5", - "@vscode/test-electron": "^2.1.5", - "cross-env": "^7.0.3", - "esbuild": "^0.14.48", - "eslint": "^8.19.0", - "eslint-config-prettier": "^8.5.0", - "ovsx": "^0.5.1", - "prettier": "^2.7.1", - "tslib": "^2.4.0", - "typescript": "^4.7.4", - "vsce": "^2.9.2" - }, - "activationEvents": [ - "onLanguage:rust", - "onCommand:rust-analyzer.analyzerStatus", - "onCommand:rust-analyzer.memoryUsage", - "onCommand:rust-analyzer.reloadWorkspace", - "workspaceContains:*/Cargo.toml", - "workspaceContains:*/rust-project.json" - ], - "main": "./out/main", - "contributes": { - "taskDefinitions": [ - { - "type": "cargo", - "required": [ - "command" - ], - "properties": { - "label": { - "type": "string" - }, - "command": { - "type": "string" - }, - "args": { - "type": "array", - "items": { - "type": "string" - } - }, - "env": { - "type": "object", - "patternProperties": { - ".+": { - "type": "string" - } - } - } - } - } - ], - "commands": [ - { - "command": "rust-analyzer.syntaxTree", - "title": "Show Syntax Tree", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.viewHir", - "title": "View Hir", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.viewFileText", - "title": "View File Text (as seen by the server)", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.viewItemTree", - "title": "Debug ItemTree", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.viewCrateGraph", - "title": "View Crate Graph", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.viewFullCrateGraph", - "title": "View Crate Graph (Full)", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.expandMacro", - "title": "Expand macro recursively", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.matchingBrace", - "title": "Find matching brace", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.parentModule", - "title": "Locate parent module", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.joinLines", - "title": "Join lines", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.run", - "title": "Run", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.copyRunCommandLine", - "title": "Copy Run Command Line", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.debug", - "title": "Debug", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.newDebugConfig", - "title": "Generate launch configuration", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.analyzerStatus", - "title": "Status", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.memoryUsage", - "title": "Memory Usage (Clears Database)", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.shuffleCrateGraph", - "title": "Shuffle Crate Graph", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.reloadWorkspace", - "title": "Reload workspace", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.reload", - "title": "Restart server", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.onEnter", - "title": "Enhanced enter key", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.ssr", - "title": "Structural Search Replace", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.serverVersion", - "title": "Show RA Version", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.toggleInlayHints", - "title": "Toggle inlay hints", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.openDocs", - "title": "Open docs under cursor", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.openCargoToml", - "title": "Open Cargo.toml", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.peekTests", - "title": "Peek related tests", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.moveItemUp", - "title": "Move item up", - "category": "Rust Analyzer" - }, - { - "command": "rust-analyzer.moveItemDown", - "title": "Move item down", - "category": "Rust Analyzer" - } - ], - "keybindings": [ - { - "command": "rust-analyzer.parentModule", - "key": "ctrl+shift+u", - "when": "editorTextFocus && editorLangId == rust" - }, - { - "command": "rust-analyzer.matchingBrace", - "key": "ctrl+shift+m", - "when": "editorTextFocus && editorLangId == rust" - }, - { - "command": "rust-analyzer.joinLines", - "key": "ctrl+shift+j", - "when": "editorTextFocus && editorLangId == rust" - } - ], - "configuration": { - "type": "object", - "title": "Rust Analyzer", - "properties": { - "rust-analyzer.cargoRunner": { - "type": [ - "null", - "string" - ], - "default": null, - "description": "Custom cargo runner extension ID." - }, - "rust-analyzer.runnableEnv": { - "anyOf": [ - { - "type": "null" - }, - { - "type": "array", - "items": { - "type": "object", - "properties": { - "mask": { - "type": "string", - "description": "Runnable name mask" - }, - "env": { - "type": "object", - "description": "Variables in form of { \"key\": \"value\"}" - } - } - } - }, - { - "type": "object", - "description": "Variables in form of { \"key\": \"value\"}" - } - ], - "default": null, - "markdownDescription": "Environment variables passed to the runnable launched using `Test` or `Debug` lens or `rust-analyzer.run` command." - }, - "rust-analyzer.server.path": { - "type": [ - "null", - "string" - ], - "scope": "machine-overridable", - "default": null, - "markdownDescription": "Path to rust-analyzer executable (points to bundled binary by default)." - }, - "rust-analyzer.server.extraEnv": { - "type": [ - "null", - "object" - ], - "additionalProperties": { - "type": [ - "string", - "number" - ] - }, - "default": null, - "markdownDescription": "Extra environment variables that will be passed to the rust-analyzer executable. Useful for passing e.g. `RA_LOG` for debugging." - }, - "rust-analyzer.trace.server": { - "type": "string", - "scope": "window", - "enum": [ - "off", - "messages", - "verbose" - ], - "enumDescriptions": [ - "No traces", - "Error only", - "Full log" - ], - "default": "off", - "description": "Trace requests to the rust-analyzer (this is usually overly verbose and not recommended for regular users)." - }, - "rust-analyzer.trace.extension": { - "description": "Enable logging of VS Code extensions itself.", - "type": "boolean", - "default": false - }, - "rust-analyzer.debug.engine": { - "type": "string", - "enum": [ - "auto", - "vadimcn.vscode-lldb", - "ms-vscode.cpptools" - ], - "default": "auto", - "description": "Preferred debug engine.", - "markdownEnumDescriptions": [ - "First try to use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), if it's not installed try to use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools).", - "Use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)", - "Use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)" - ] - }, - "rust-analyzer.debug.sourceFileMap": { - "type": [ - "object", - "string" - ], - "const": "auto", - "description": "Optional source file mappings passed to the debug engine.", - "default": { - "/rustc/": "${env:USERPROFILE}/.rustup/toolchains//lib/rustlib/src/rust" - } - }, - "rust-analyzer.debug.openDebugPane": { - "markdownDescription": "Whether to open up the `Debug Panel` on debugging start.", - "type": "boolean", - "default": false - }, - "rust-analyzer.debug.engineSettings": { - "type": "object", - "default": {}, - "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`" - }, - "rust-analyzer.restartServerOnConfigChange": { - "markdownDescription": "Whether to restart the server automatically when certain settings that require a restart are changed.", - "default": false, - "type": "boolean" - }, - "$generated-start": {}, - "rust-analyzer.assist.expressionFillDefault": { - "markdownDescription": "Placeholder expression to use for missing expressions in assists.", - "default": "todo", - "type": "string", - "enum": [ - "todo", - "default" - ], - "enumDescriptions": [ - "Fill missing expressions with the `todo` macro", - "Fill missing expressions with reasonable defaults, `new` or `default` constructors." - ] - }, - "rust-analyzer.cachePriming.enable": { - "markdownDescription": "Warm up caches on project load.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.cachePriming.numThreads": { - "markdownDescription": "How many worker threads to handle priming caches. The default `0` means to pick automatically.", - "default": 0, - "type": "number", - "minimum": 0, - "maximum": 255 - }, - "rust-analyzer.cargo.autoreload": { - "markdownDescription": "Automatically refresh project info via `cargo metadata` on\n`Cargo.toml` or `.cargo/config.toml` changes.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.cargo.buildScripts.enable": { - "markdownDescription": "Run build scripts (`build.rs`) for more precise code analysis.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.cargo.buildScripts.overrideCommand": { - "markdownDescription": "Override the command rust-analyzer uses to run build scripts and\nbuild procedural macros. The command is required to output json\nand should therefore include `--message-format=json` or a similar\noption.\n\nBy default, a cargo invocation will be constructed for the configured\ntargets and features, with the following base command line:\n\n```bash\ncargo check --quiet --workspace --message-format=json --all-targets\n```\n.", - "default": null, - "type": [ - "null", - "array" - ], - "items": { - "type": "string" - } - }, - "rust-analyzer.cargo.buildScripts.useRustcWrapper": { - "markdownDescription": "Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to\navoid checking unnecessary things.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.cargo.features": { - "markdownDescription": "List of features to activate.\n\nSet this to `\"all\"` to pass `--all-features` to cargo.", - "default": [], - "anyOf": [ - { - "type": "string", - "enum": [ - "all" - ], - "enumDescriptions": [ - "Pass `--all-features` to cargo" - ] - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - }, - "rust-analyzer.cargo.noDefaultFeatures": { - "markdownDescription": "Whether to pass `--no-default-features` to cargo.", - "default": false, - "type": "boolean" - }, - "rust-analyzer.cargo.noSysroot": { - "markdownDescription": "Internal config for debugging, disables loading of sysroot crates.", - "default": false, - "type": "boolean" - }, - "rust-analyzer.cargo.target": { - "markdownDescription": "Compilation target override (target triple).", - "default": null, - "type": [ - "null", - "string" - ] - }, - "rust-analyzer.cargo.unsetTest": { - "markdownDescription": "Unsets `#[cfg(test)]` for the specified crates.", - "default": [ - "core" - ], - "type": "array", - "items": { - "type": "string" - } - }, - "rust-analyzer.checkOnSave.allTargets": { - "markdownDescription": "Check all targets and tests (`--all-targets`).", - "default": true, - "type": "boolean" - }, - "rust-analyzer.checkOnSave.command": { - "markdownDescription": "Cargo command to use for `cargo check`.", - "default": "check", - "type": "string" - }, - "rust-analyzer.checkOnSave.enable": { - "markdownDescription": "Run specified `cargo check` command for diagnostics on save.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.checkOnSave.extraArgs": { - "markdownDescription": "Extra arguments for `cargo check`.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - }, - "rust-analyzer.checkOnSave.features": { - "markdownDescription": "List of features to activate. Defaults to\n`#rust-analyzer.cargo.features#`.\n\nSet to `\"all\"` to pass `--all-features` to Cargo.", - "default": null, - "anyOf": [ - { - "type": "string", - "enum": [ - "all" - ], - "enumDescriptions": [ - "Pass `--all-features` to cargo" - ] - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "null" - } - ] - }, - "rust-analyzer.checkOnSave.noDefaultFeatures": { - "markdownDescription": "Whether to pass `--no-default-features` to Cargo. Defaults to\n`#rust-analyzer.cargo.noDefaultFeatures#`.", - "default": null, - "type": [ - "null", - "boolean" - ] - }, - "rust-analyzer.checkOnSave.overrideCommand": { - "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefor include `--message-format=json` or a similar option.\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.", - "default": null, - "type": [ - "null", - "array" - ], - "items": { - "type": "string" - } - }, - "rust-analyzer.checkOnSave.target": { - "markdownDescription": "Check for a specific target. Defaults to\n`#rust-analyzer.cargo.target#`.", - "default": null, - "type": [ - "null", - "string" - ] - }, - "rust-analyzer.completion.autoimport.enable": { - "markdownDescription": "Toggles the additional completions that automatically add imports when completed.\nNote that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.completion.autoself.enable": { - "markdownDescription": "Toggles the additional completions that automatically show method calls and field accesses\nwith `self` prefixed to them when inside a method.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.completion.callable.snippets": { - "markdownDescription": "Whether to add parenthesis and argument snippets when completing function.", - "default": "fill_arguments", - "type": "string", - "enum": [ - "fill_arguments", - "add_parentheses", - "none" - ], - "enumDescriptions": [ - "Add call parentheses and pre-fill arguments.", - "Add call parentheses.", - "Do no snippet completions for callables." - ] - }, - "rust-analyzer.completion.postfix.enable": { - "markdownDescription": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.completion.privateEditable.enable": { - "markdownDescription": "Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.", - "default": false, - "type": "boolean" - }, - "rust-analyzer.completion.snippets.custom": { - "markdownDescription": "Custom completion snippets.", - "default": { - "Arc::new": { - "postfix": "arc", - "body": "Arc::new(${receiver})", - "requires": "std::sync::Arc", - "description": "Put the expression into an `Arc`", - "scope": "expr" - }, - "Rc::new": { - "postfix": "rc", - "body": "Rc::new(${receiver})", - "requires": "std::rc::Rc", - "description": "Put the expression into an `Rc`", - "scope": "expr" - }, - "Box::pin": { - "postfix": "pinbox", - "body": "Box::pin(${receiver})", - "requires": "std::boxed::Box", - "description": "Put the expression into a pinned `Box`", - "scope": "expr" - }, - "Ok": { - "postfix": "ok", - "body": "Ok(${receiver})", - "description": "Wrap the expression in a `Result::Ok`", - "scope": "expr" - }, - "Err": { - "postfix": "err", - "body": "Err(${receiver})", - "description": "Wrap the expression in a `Result::Err`", - "scope": "expr" - }, - "Some": { - "postfix": "some", - "body": "Some(${receiver})", - "description": "Wrap the expression in an `Option::Some`", - "scope": "expr" - } - }, - "type": "object" - }, - "rust-analyzer.diagnostics.disabled": { - "markdownDescription": "List of rust-analyzer diagnostics to disable.", - "default": [], - "type": "array", - "items": { - "type": "string" - }, - "uniqueItems": true - }, - "rust-analyzer.diagnostics.enable": { - "markdownDescription": "Whether to show native rust-analyzer diagnostics.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.diagnostics.experimental.enable": { - "markdownDescription": "Whether to show experimental rust-analyzer diagnostics that might\nhave more false positives than usual.", - "default": false, - "type": "boolean" - }, - "rust-analyzer.diagnostics.remapPrefix": { - "markdownDescription": "Map of prefixes to be substituted when parsing diagnostic file paths.\nThis should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`.", - "default": {}, - "type": "object" - }, - "rust-analyzer.diagnostics.warningsAsHint": { - "markdownDescription": "List of warnings that should be displayed with hint severity.\n\nThe warnings will be indicated by faded text or three dots in code\nand will not show up in the `Problems Panel`.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - }, - "rust-analyzer.diagnostics.warningsAsInfo": { - "markdownDescription": "List of warnings that should be displayed with info severity.\n\nThe warnings will be indicated by a blue squiggly underline in code\nand a blue icon in the `Problems Panel`.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - }, - "rust-analyzer.files.excludeDirs": { - "markdownDescription": "These directories will be ignored by rust-analyzer. They are\nrelative to the workspace root, and globs are not supported. You may\nalso need to add the folders to Code's `files.watcherExclude`.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - }, - "rust-analyzer.files.watcher": { - "markdownDescription": "Controls file watching implementation.", - "default": "client", - "type": "string", - "enum": [ - "client", - "server" - ], - "enumDescriptions": [ - "Use the client (editor) to watch files for changes", - "Use server-side file watching" - ] - }, - "rust-analyzer.highlightRelated.breakPoints.enable": { - "markdownDescription": "Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.highlightRelated.exitPoints.enable": { - "markdownDescription": "Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).", - "default": true, - "type": "boolean" - }, - "rust-analyzer.highlightRelated.references.enable": { - "markdownDescription": "Enables highlighting of related references while the cursor is on any identifier.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.highlightRelated.yieldPoints.enable": { - "markdownDescription": "Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.hover.actions.debug.enable": { - "markdownDescription": "Whether to show `Debug` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.hover.actions.enable": { - "markdownDescription": "Whether to show HoverActions in Rust files.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.hover.actions.gotoTypeDef.enable": { - "markdownDescription": "Whether to show `Go to Type Definition` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.hover.actions.implementations.enable": { - "markdownDescription": "Whether to show `Implementations` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.hover.actions.references.enable": { - "markdownDescription": "Whether to show `References` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.", - "default": false, - "type": "boolean" - }, - "rust-analyzer.hover.actions.run.enable": { - "markdownDescription": "Whether to show `Run` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.hover.documentation.enable": { - "markdownDescription": "Whether to show documentation on hover.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.hover.links.enable": { - "markdownDescription": "Use markdown syntax for links in hover.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.imports.granularity.enforce": { - "markdownDescription": "Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.", - "default": false, - "type": "boolean" - }, - "rust-analyzer.imports.granularity.group": { - "markdownDescription": "How imports should be grouped into use statements.", - "default": "crate", - "type": "string", - "enum": [ - "preserve", - "crate", - "module", - "item" - ], - "enumDescriptions": [ - "Do not change the granularity of any imports and preserve the original structure written by the developer.", - "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.", - "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.", - "Flatten imports so that each has its own use statement." - ] - }, - "rust-analyzer.imports.group.enable": { - "markdownDescription": "Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.imports.merge.glob": { - "markdownDescription": "Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.imports.prefix": { - "markdownDescription": "The path structure for newly inserted paths to use.", - "default": "plain", - "type": "string", - "enum": [ - "plain", - "self", - "crate" - ], - "enumDescriptions": [ - "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", - "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item. Prefixes `self` in front of the path if it starts with a module.", - "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from." - ] - }, - "rust-analyzer.inlayHints.bindingModeHints.enable": { - "markdownDescription": "Whether to show inlay type hints for binding modes.", - "default": false, - "type": "boolean" - }, - "rust-analyzer.inlayHints.chainingHints.enable": { - "markdownDescription": "Whether to show inlay type hints for method chains.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.inlayHints.closingBraceHints.enable": { - "markdownDescription": "Whether to show inlay hints after a closing `}` to indicate what item it belongs to.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.inlayHints.closingBraceHints.minLines": { - "markdownDescription": "Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1\nto always show them).", - "default": 25, - "type": "integer", - "minimum": 0 - }, - "rust-analyzer.inlayHints.closureReturnTypeHints.enable": { - "markdownDescription": "Whether to show inlay type hints for return types of closures.", - "default": "never", - "type": "string", - "enum": [ - "always", - "never", - "with_block" - ], - "enumDescriptions": [ - "Always show type hints for return types of closures.", - "Never show type hints for return types of closures.", - "Only show type hints for return types of closures with blocks." - ] - }, - "rust-analyzer.inlayHints.lifetimeElisionHints.enable": { - "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.", - "default": "never", - "type": "string", - "enum": [ - "always", - "never", - "skip_trivial" - ], - "enumDescriptions": [ - "Always show lifetime elision hints.", - "Never show lifetime elision hints.", - "Only show lifetime elision hints if a return type is involved." - ] - }, - "rust-analyzer.inlayHints.lifetimeElisionHints.useParameterNames": { - "markdownDescription": "Whether to prefer using parameter names as the name for elided lifetime hints if possible.", - "default": false, - "type": "boolean" - }, - "rust-analyzer.inlayHints.maxLength": { - "markdownDescription": "Maximum length for inlay hints. Set to null to have an unlimited length.", - "default": 25, - "type": [ - "null", - "integer" - ], - "minimum": 0 - }, - "rust-analyzer.inlayHints.parameterHints.enable": { - "markdownDescription": "Whether to show function parameter name inlay hints at the call\nsite.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.inlayHints.reborrowHints.enable": { - "markdownDescription": "Whether to show inlay type hints for compiler inserted reborrows.", - "default": "never", - "type": "string", - "enum": [ - "always", - "never", - "mutable" - ], - "enumDescriptions": [ - "Always show reborrow hints.", - "Never show reborrow hints.", - "Only show mutable reborrow hints." - ] - }, - "rust-analyzer.inlayHints.renderColons": { - "markdownDescription": "Whether to render leading colons for type hints, and trailing colons for parameter hints.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.inlayHints.typeHints.enable": { - "markdownDescription": "Whether to show inlay type hints for variables.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.inlayHints.typeHints.hideClosureInitialization": { - "markdownDescription": "Whether to hide inlay type hints for `let` statements that initialize to a closure.\nOnly applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.", - "default": false, - "type": "boolean" - }, - "rust-analyzer.inlayHints.typeHints.hideNamedConstructor": { - "markdownDescription": "Whether to hide inlay type hints for constructors.", - "default": false, - "type": "boolean" - }, - "rust-analyzer.joinLines.joinAssignments": { - "markdownDescription": "Join lines merges consecutive declaration and initialization of an assignment.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.joinLines.joinElseIf": { - "markdownDescription": "Join lines inserts else between consecutive ifs.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.joinLines.removeTrailingComma": { - "markdownDescription": "Join lines removes trailing commas.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.joinLines.unwrapTrivialBlock": { - "markdownDescription": "Join lines unwraps trivial blocks.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.lens.debug.enable": { - "markdownDescription": "Whether to show `Debug` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.lens.enable": { - "markdownDescription": "Whether to show CodeLens in Rust files.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.lens.forceCustomCommands": { - "markdownDescription": "Internal config: use custom client-side commands even when the\nclient doesn't set the corresponding capability.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.lens.implementations.enable": { - "markdownDescription": "Whether to show `Implementations` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.lens.references.adt.enable": { - "markdownDescription": "Whether to show `References` lens for Struct, Enum, and Union.\nOnly applies when `#rust-analyzer.lens.enable#` is set.", - "default": false, - "type": "boolean" - }, - "rust-analyzer.lens.references.enumVariant.enable": { - "markdownDescription": "Whether to show `References` lens for Enum Variants.\nOnly applies when `#rust-analyzer.lens.enable#` is set.", - "default": false, - "type": "boolean" - }, - "rust-analyzer.lens.references.method.enable": { - "markdownDescription": "Whether to show `Method References` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.", - "default": false, - "type": "boolean" - }, - "rust-analyzer.lens.references.trait.enable": { - "markdownDescription": "Whether to show `References` lens for Trait.\nOnly applies when `#rust-analyzer.lens.enable#` is set.", - "default": false, - "type": "boolean" - }, - "rust-analyzer.lens.run.enable": { - "markdownDescription": "Whether to show `Run` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.linkedProjects": { - "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set\nof projects.\n\nElements must be paths pointing to `Cargo.toml`,\n`rust-project.json`, or JSON objects in `rust-project.json` format.", - "default": [], - "type": "array", - "items": { - "type": [ - "string", - "object" - ] - } - }, - "rust-analyzer.lru.capacity": { - "markdownDescription": "Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.", - "default": null, - "type": [ - "null", - "integer" - ], - "minimum": 0 - }, - "rust-analyzer.notifications.cargoTomlNotFound": { - "markdownDescription": "Whether to show `can't find Cargo.toml` error message.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.procMacro.attributes.enable": { - "markdownDescription": "Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.procMacro.enable": { - "markdownDescription": "Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.procMacro.ignored": { - "markdownDescription": "These proc-macros will be ignored when trying to expand them.\n\nThis config takes a map of crate names with the exported proc-macro names to ignore as values.", - "default": {}, - "type": "object" - }, - "rust-analyzer.procMacro.server": { - "markdownDescription": "Internal config, path to proc-macro server executable (typically,\nthis is rust-analyzer itself, but we override this in tests).", - "default": null, - "type": [ - "null", - "string" - ] - }, - "rust-analyzer.runnables.command": { - "markdownDescription": "Command to be executed instead of 'cargo' for runnables.", - "default": null, - "type": [ - "null", - "string" - ] - }, - "rust-analyzer.runnables.extraArgs": { - "markdownDescription": "Additional arguments to be passed to cargo for runnables such as\ntests or binaries. For example, it may be `--release`.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - }, - "rust-analyzer.rustc.source": { - "markdownDescription": "Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private\nprojects, or \"discover\" to try to automatically find it if the `rustc-dev` component\nis installed.\n\nAny project which uses rust-analyzer with the rustcPrivate\ncrates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.\n\nThis option does not take effect until rust-analyzer is restarted.", - "default": null, - "type": [ - "null", - "string" - ] - }, - "rust-analyzer.rustfmt.extraArgs": { - "markdownDescription": "Additional arguments to `rustfmt`.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - }, - "rust-analyzer.rustfmt.overrideCommand": { - "markdownDescription": "Advanced option, fully override the command rust-analyzer uses for\nformatting.", - "default": null, - "type": [ - "null", - "array" - ], - "items": { - "type": "string" - } - }, - "rust-analyzer.rustfmt.rangeFormatting.enable": { - "markdownDescription": "Enables the use of rustfmt's unstable range formatting command for the\n`textDocument/rangeFormatting` request. The rustfmt option is unstable and only\navailable on a nightly build.", - "default": false, - "type": "boolean" - }, - "rust-analyzer.semanticHighlighting.strings.enable": { - "markdownDescription": "Use semantic tokens for strings.\n\nIn some editors (e.g. vscode) semantic tokens override other highlighting grammars.\nBy disabling semantic tokens for strings, other grammars can be used to highlight\ntheir contents.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.signatureInfo.detail": { - "markdownDescription": "Show full signature of the callable. Only shows parameters if disabled.", - "default": "full", - "type": "string", - "enum": [ - "full", - "parameters" - ], - "enumDescriptions": [ - "Show the entire signature.", - "Show only the parameters." - ] - }, - "rust-analyzer.signatureInfo.documentation.enable": { - "markdownDescription": "Show documentation.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.typing.autoClosingAngleBrackets.enable": { - "markdownDescription": "Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.", - "default": false, - "type": "boolean" - }, - "rust-analyzer.workspace.symbol.search.kind": { - "markdownDescription": "Workspace symbol search kind.", - "default": "only_types", - "type": "string", - "enum": [ - "only_types", - "all_symbols" - ], - "enumDescriptions": [ - "Search for types only.", - "Search for all symbols kinds." - ] - }, - "rust-analyzer.workspace.symbol.search.limit": { - "markdownDescription": "Limits the number of items returned from a workspace symbol search (Defaults to 128).\nSome clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.\nOther clients requires all results upfront and might require a higher limit.", - "default": 128, - "type": "integer", - "minimum": 0 - }, - "rust-analyzer.workspace.symbol.search.scope": { - "markdownDescription": "Workspace symbol search scope.", - "default": "workspace", - "type": "string", - "enum": [ - "workspace", - "workspace_and_dependencies" - ], - "enumDescriptions": [ - "Search in current workspace only.", - "Search in current workspace and dependencies." - ] - }, - "$generated-end": {} - } - }, - "problemPatterns": [ - { - "name": "rustc", - "patterns": [ - { - "regexp": "^(warning|warn|error)(?:\\[(.*?)\\])?: (.*)$", - "severity": 1, - "code": 2, - "message": 3 - }, - { - "regexp": "^[\\s->=]*(.*?):(\\d*):(\\d*)\\s*$", - "file": 1, - "line": 2, - "column": 3 - } - ] - }, - { - "name": "rustc-json", - "patterns": [ - { - "regexp": "^.*\"message\":{\"message\":\"([^\"]*).*?\"file_name\":\"([^\"]+).*?\"line_start\":(\\d+).*?\"line_end\":(\\d+).*?\"column_start\":(\\d+).*?\"column_end\":(\\d+).*}$", - "message": 1, - "file": 2, - "line": 3, - "endLine": 4, - "column": 5, - "endColumn": 6 - } - ] - } - ], - "languages": [ - { - "id": "ra_syntax_tree", - "extensions": [ - ".rast" - ] - }, - { - "id": "rust", - "extensions": [ - ".rs" - ], - "aliases": [ - "Rust", - "rs" - ], - "configuration": "language-configuration.json" - } - ], - "grammars": [ - { - "language": "ra_syntax_tree", - "scopeName": "source.ra_syntax_tree", - "path": "ra_syntax_tree.tmGrammar.json" - } - ], - "problemMatchers": [ - { - "name": "rustc", - "owner": "rustc", - "source": "rustc", - "fileLocation": [ - "autoDetect", - "${workspaceRoot}" - ], - "pattern": "$rustc" - }, - { - "name": "rustc-json", - "owner": "rustc", - "source": "rustc", - "fileLocation": [ - "autoDetect", - "${workspaceRoot}" - ], - "pattern": "$rustc-json" - }, - { - "name": "rustc-watch", - "owner": "rustc", - "source": "rustc", - "fileLocation": [ - "autoDetect", - "${workspaceRoot}" - ], - "background": { - "beginsPattern": "^\\[Running\\b", - "endsPattern": "^\\[Finished running\\b" - }, - "pattern": "$rustc" - } - ], - "colors": [ - { - "id": "rust_analyzer.syntaxTreeBorder", - "description": "Color of the border displayed in the Rust source code for the selected syntax node (see \"Show Syntax Tree\" command)", - "defaults": { - "dark": "#ffffff", - "light": "#b700ff", - "highContrast": "#b700ff" - } - } - ], - "semanticTokenTypes": [ - { - "id": "angle", - "description": "Style for < or >", - "superType": "punctuation" - }, - { - "id": "arithmetic", - "description": "Style for arithmetic operators", - "superType": "operator" - }, - { - "id": "attribute", - "description": "Style for attributes" - }, - { - "id": "attributeBracket", - "description": "Style for attribute invocation brackets, that is the `#[` and `]` tokens", - "superType": "punctuation" - }, - { - "id": "bitwise", - "description": "Style for bitwise operators", - "superType": "operator" - }, - { - "id": "boolean", - "description": "Style for boolean literals", - "superType": "keyword" - }, - { - "id": "brace", - "description": "Style for { or }", - "superType": "punctuation" - }, - { - "id": "bracket", - "description": "Style for [ or ]", - "superType": "punctuation" - }, - { - "id": "builtinAttribute", - "description": "Style for builtin attributes", - "superType": "attribute" - }, - { - "id": "builtinType", - "description": "Style for builtin types", - "superType": "type" - }, - { - "id": "character", - "description": "Style for character literals", - "superType": "string" - }, - { - "id": "colon", - "description": "Style for :", - "superType": "punctuation" - }, - { - "id": "comma", - "description": "Style for ,", - "superType": "punctuation" - }, - { - "id": "comparison", - "description": "Style for comparison operators", - "superType": "operator" - }, - { - "id": "constParameter", - "description": "Style for const generics" - }, - { - "id": "derive", - "description": "Style for derives", - "superType": "attribute" - }, - { - "id": "dot", - "description": "Style for .", - "superType": "punctuation" - }, - { - "id": "escapeSequence", - "description": "Style for char escapes in strings" - }, - { - "id": "formatSpecifier", - "description": "Style for {} placeholders in format strings" - }, - { - "id": "label", - "description": "Style for labels" - }, - { - "id": "lifetime", - "description": "Style for lifetimes" - }, - { - "id": "logical", - "description": "Style for logic operators", - "superType": "operator" - }, - { - "id": "macroBang", - "description": "Style for the ! token of macro calls", - "superType": "punctuation" - }, - { - "id": "operator", - "description": "Style for operators", - "superType": "punctuation" - }, - { - "id": "parenthesis", - "description": "Style for ( or )", - "superType": "punctuation" - }, - { - "id": "punctuation", - "description": "Style for generic punctuation" - }, - { - "id": "selfKeyword", - "description": "Style for the self keyword", - "superType": "keyword" - }, - { - "id": "selfTypeKeyword", - "description": "Style for the self type keyword", - "superType": "keyword" - }, - { - "id": "semicolon", - "description": "Style for ;", - "superType": "punctuation" - }, - { - "id": "typeAlias", - "description": "Style for type aliases", - "superType": "type" - }, - { - "id": "union", - "description": "Style for C-style untagged unions", - "superType": "type" - }, - { - "id": "unresolvedReference", - "description": "Style for names which can not be resolved due to compilation errors" - } - ], - "semanticTokenModifiers": [ - { - "id": "async", - "description": "Style for async functions and the `async` and `await` keywords" - }, - { - "id": "attribute", - "description": "Style for elements within attributes" - }, - { - "id": "callable", - "description": "Style for locals whose types implements one of the `Fn*` traits" - }, - { - "id": "constant", - "description": "Style for compile-time constants" - }, - { - "id": "consuming", - "description": "Style for locals that are being consumed when use in a function call" - }, - { - "id": "controlFlow", - "description": "Style for control-flow related tokens, this includes the `?` operator" - }, - { - "id": "crateRoot", - "description": "Style for names resolving to a crate root" - }, - { - "id": "injected", - "description": "Style for doc-string injected highlighting like rust source blocks in documentation" - }, - { - "id": "intraDocLink", - "description": "Style for intra doc links in doc-strings" - }, - { - "id": "library", - "description": "Style for items that are defined outside of the current crate" - }, - { - "id": "mutable", - "description": "Style for mutable locals and statics as well as functions taking `&mut self`" - }, - { - "id": "public", - "description": "Style for items that are from the current crate and are `pub`" - }, - { - "id": "reference", - "description": "Style for locals behind a reference and functions taking `self` by reference" - }, - { - "id": "trait", - "description": "Style for associated trait items" - }, - { - "id": "unsafe", - "description": "Style for unsafe operations, like unsafe function calls, as well as the `unsafe` token" - } - ], - "semanticTokenScopes": [ - { - "language": "rust", - "scopes": { - "attribute": [ - "meta.attribute.rust" - ], - "boolean": [ - "constant.language.boolean.rust" - ], - "builtinType": [ - "support.type.primitive.rust" - ], - "constParameter": [ - "constant.other.caps.rust" - ], - "enum": [ - "entity.name.type.enum.rust" - ], - "formatSpecifier": [ - "punctuation.section.embedded.rust" - ], - "function": [ - "entity.name.function.rust" - ], - "interface": [ - "entity.name.type.trait.rust" - ], - "keyword": [ - "keyword.other.rust" - ], - "keyword.controlFlow": [ - "keyword.control.rust" - ], - "lifetime": [ - "storage.modifier.lifetime.rust" - ], - "macroBang": [ - "entity.name.function.macro.rust" - ], - "method": [ - "entity.name.function.rust" - ], - "struct": [ - "entity.name.type.struct.rust" - ], - "typeAlias": [ - "entity.name.type.declaration.rust" - ], - "union": [ - "entity.name.type.union.rust" - ], - "variable": [ - "variable.other.rust" - ], - "variable.constant": [ - "variable.other.constant.rust" - ], - "*.mutable": [ - "markup.underline" - ] - } - } - ], - "menus": { - "commandPalette": [ - { - "command": "rust-analyzer.syntaxTree", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.viewHir", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.viewFileText", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.expandMacro", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.matchingBrace", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.parentModule", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.joinLines", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.run", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.debug", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.newDebugConfig", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.analyzerStatus", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.memoryUsage", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.reloadWorkspace", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.reload", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.onEnter", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.ssr", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.serverVersion", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.toggleInlayHints", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.openDocs", - "when": "inRustProject" - }, - { - "command": "rust-analyzer.openCargoToml", - "when": "inRustProject" - } - ], - "editor/context": [ - { - "command": "rust-analyzer.peekTests", - "when": "inRustProject", - "group": "navigation@1000" - } - ] - } - } -} diff --git a/src/tools/rust-analyzer/editors/code/ra_syntax_tree.tmGrammar.json b/src/tools/rust-analyzer/editors/code/ra_syntax_tree.tmGrammar.json deleted file mode 100644 index 279e7bafa0b68..0000000000000 --- a/src/tools/rust-analyzer/editors/code/ra_syntax_tree.tmGrammar.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", - - "scopeName": "source.ra_syntax_tree", - "patterns": [ - { "include": "#node_type" }, - { "include": "#node_range_index" }, - { "include": "#token_text" } - ], - "repository": { - "node_type": { - "match": "^\\s*([A-Z_][A-Z_0-9]*?)@", - "captures": { - "1": { - "name": "entity.name.class" - } - } - }, - "node_range_index": { - "match": "\\d+", - "name": "constant.numeric" - }, - "token_text": { - "match": "\".+\"", - "name": "string" - } - }, - "fileTypes": ["rast"] -} diff --git a/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts b/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts deleted file mode 100644 index e57fb20e2cf8b..0000000000000 --- a/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts +++ /dev/null @@ -1,215 +0,0 @@ -import * as vscode from "vscode"; - -import { Ctx, Disposable } from "./ctx"; -import { RustEditor, isRustEditor } from "./util"; - -// FIXME: consider implementing this via the Tree View API? -// https://code.visualstudio.com/api/extension-guides/tree-view -export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable { - private readonly astDecorationType = vscode.window.createTextEditorDecorationType({ - borderColor: new vscode.ThemeColor("rust_analyzer.syntaxTreeBorder"), - borderStyle: "solid", - borderWidth: "2px", - }); - private rustEditor: undefined | RustEditor; - - // Lazy rust token range -> syntax tree file range. - private readonly rust2Ast = new Lazy(() => { - const astEditor = this.findAstTextEditor(); - if (!this.rustEditor || !astEditor) return undefined; - - const buf: [vscode.Range, vscode.Range][] = []; - for (let i = 0; i < astEditor.document.lineCount; ++i) { - const astLine = astEditor.document.lineAt(i); - - // Heuristically look for nodes with quoted text (which are token nodes) - const isTokenNode = astLine.text.lastIndexOf('"') >= 0; - if (!isTokenNode) continue; - - const rustRange = this.parseRustTextRange(this.rustEditor.document, astLine.text); - if (!rustRange) continue; - - buf.push([rustRange, this.findAstNodeRange(astLine)]); - } - return buf; - }); - - constructor(ctx: Ctx) { - ctx.pushCleanup(vscode.languages.registerHoverProvider({ scheme: "rust-analyzer" }, this)); - ctx.pushCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this)); - vscode.workspace.onDidCloseTextDocument( - this.onDidCloseTextDocument, - this, - ctx.subscriptions - ); - vscode.workspace.onDidChangeTextDocument( - this.onDidChangeTextDocument, - this, - ctx.subscriptions - ); - vscode.window.onDidChangeVisibleTextEditors( - this.onDidChangeVisibleTextEditors, - this, - ctx.subscriptions - ); - - ctx.pushCleanup(this); - } - dispose() { - this.setRustEditor(undefined); - } - - private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { - if ( - this.rustEditor && - event.document.uri.toString() === this.rustEditor.document.uri.toString() - ) { - this.rust2Ast.reset(); - } - } - - private onDidCloseTextDocument(doc: vscode.TextDocument) { - if (this.rustEditor && doc.uri.toString() === this.rustEditor.document.uri.toString()) { - this.setRustEditor(undefined); - } - } - - private onDidChangeVisibleTextEditors(editors: readonly vscode.TextEditor[]) { - if (!this.findAstTextEditor()) { - this.setRustEditor(undefined); - return; - } - this.setRustEditor(editors.find(isRustEditor)); - } - - private findAstTextEditor(): undefined | vscode.TextEditor { - return vscode.window.visibleTextEditors.find( - (it) => it.document.uri.scheme === "rust-analyzer" - ); - } - - private setRustEditor(newRustEditor: undefined | RustEditor) { - if (this.rustEditor && this.rustEditor !== newRustEditor) { - this.rustEditor.setDecorations(this.astDecorationType, []); - this.rust2Ast.reset(); - } - this.rustEditor = newRustEditor; - } - - // additional positional params are omitted - provideDefinition( - doc: vscode.TextDocument, - pos: vscode.Position - ): vscode.ProviderResult { - if (!this.rustEditor || doc.uri.toString() !== this.rustEditor.document.uri.toString()) { - return; - } - - const astEditor = this.findAstTextEditor(); - if (!astEditor) return; - - const rust2AstRanges = this.rust2Ast - .get() - ?.find(([rustRange, _]) => rustRange.contains(pos)); - if (!rust2AstRanges) return; - - const [rustFileRange, astFileRange] = rust2AstRanges; - - astEditor.revealRange(astFileRange); - astEditor.selection = new vscode.Selection(astFileRange.start, astFileRange.end); - - return [ - { - targetRange: astFileRange, - targetUri: astEditor.document.uri, - originSelectionRange: rustFileRange, - targetSelectionRange: astFileRange, - }, - ]; - } - - // additional positional params are omitted - provideHover( - doc: vscode.TextDocument, - hoverPosition: vscode.Position - ): vscode.ProviderResult { - if (!this.rustEditor) return; - - const astFileLine = doc.lineAt(hoverPosition.line); - - const rustFileRange = this.parseRustTextRange(this.rustEditor.document, astFileLine.text); - if (!rustFileRange) return; - - this.rustEditor.setDecorations(this.astDecorationType, [rustFileRange]); - this.rustEditor.revealRange(rustFileRange); - - const rustSourceCode = this.rustEditor.document.getText(rustFileRange); - const astFileRange = this.findAstNodeRange(astFileLine); - - return new vscode.Hover(["```rust\n" + rustSourceCode + "\n```"], astFileRange); - } - - private findAstNodeRange(astLine: vscode.TextLine): vscode.Range { - const lineOffset = astLine.range.start; - const begin = lineOffset.translate(undefined, astLine.firstNonWhitespaceCharacterIndex); - const end = lineOffset.translate(undefined, astLine.text.trimEnd().length); - return new vscode.Range(begin, end); - } - - private parseRustTextRange( - doc: vscode.TextDocument, - astLine: string - ): undefined | vscode.Range { - const parsedRange = /(\d+)\.\.(\d+)/.exec(astLine); - if (!parsedRange) return; - - const [begin, end] = parsedRange.slice(1).map((off) => this.positionAt(doc, +off)); - - return new vscode.Range(begin, end); - } - - // Memoize the last value, otherwise the CPU is at 100% single core - // with quadratic lookups when we build rust2Ast cache - cache?: { doc: vscode.TextDocument; offset: number; line: number }; - - positionAt(doc: vscode.TextDocument, targetOffset: number): vscode.Position { - if (doc.eol === vscode.EndOfLine.LF) { - return doc.positionAt(targetOffset); - } - - // Dirty workaround for crlf line endings - // We are still in this prehistoric era of carriage returns here... - - let line = 0; - let offset = 0; - - const cache = this.cache; - if (cache?.doc === doc && cache.offset <= targetOffset) { - ({ line, offset } = cache); - } - - while (true) { - const lineLenWithLf = doc.lineAt(line).text.length + 1; - if (offset + lineLenWithLf > targetOffset) { - this.cache = { doc, offset, line }; - return doc.positionAt(targetOffset + line); - } - offset += lineLenWithLf; - line += 1; - } - } -} - -class Lazy { - val: undefined | T; - - constructor(private readonly compute: () => undefined | T) {} - - get() { - return this.val ?? (this.val = this.compute()); - } - - reset() { - this.val = undefined; - } -} diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts deleted file mode 100644 index 8a2dea6b35b76..0000000000000 --- a/src/tools/rust-analyzer/editors/code/src/client.ts +++ /dev/null @@ -1,299 +0,0 @@ -import * as lc from "vscode-languageclient/node"; -import * as vscode from "vscode"; -import * as ra from "../src/lsp_ext"; -import * as Is from "vscode-languageclient/lib/common/utils/is"; -import { assert } from "./util"; -import { WorkspaceEdit } from "vscode"; -import { Workspace } from "./ctx"; -import { updateConfig } from "./config"; -import { substituteVariablesInEnv } from "./config"; -import { outputChannel, traceOutputChannel } from "./main"; -import { randomUUID } from "crypto"; - -export interface Env { - [name: string]: string; -} - -// Command URIs have a form of command:command-name?arguments, where -// arguments is a percent-encoded array of data we want to pass along to -// the command function. For "Show References" this is a list of all file -// URIs with locations of every reference, and it can get quite long. -// -// To work around it we use an intermediary linkToCommand command. When -// we render a command link, a reference to a command with all its arguments -// is stored in a map, and instead a linkToCommand link is rendered -// with the key to that map. -export const LINKED_COMMANDS = new Map(); - -// For now the map is cleaned up periodically (I've set it to every -// 10 minutes). In general case we'll probably need to introduce TTLs or -// flags to denote ephemeral links (like these in hover popups) and -// persistent links and clean those separately. But for now simply keeping -// the last few links in the map should be good enough. Likewise, we could -// add code to remove a target command from the map after the link is -// clicked, but assuming most links in hover sheets won't be clicked anyway -// this code won't change the overall memory use much. -setInterval(function cleanupOlderCommandLinks() { - // keys are returned in insertion order, we'll keep a few - // of recent keys available, and clean the rest - const keys = [...LINKED_COMMANDS.keys()]; - const keysToRemove = keys.slice(0, keys.length - 10); - for (const key of keysToRemove) { - LINKED_COMMANDS.delete(key); - } -}, 10 * 60 * 1000); - -function renderCommand(cmd: ra.CommandLink): string { - const commandId = randomUUID(); - LINKED_COMMANDS.set(commandId, cmd); - return `[${cmd.title}](command:rust-analyzer.linkToCommand?${encodeURIComponent( - JSON.stringify([commandId]) - )} '${cmd.tooltip}')`; -} - -function renderHoverActions(actions: ra.CommandLinkGroup[]): vscode.MarkdownString { - const text = actions - .map( - (group) => - (group.title ? group.title + " " : "") + - group.commands.map(renderCommand).join(" | ") - ) - .join("___"); - - const result = new vscode.MarkdownString(text); - result.isTrusted = true; - return result; -} - -export async function createClient( - serverPath: string, - workspace: Workspace, - extraEnv: Env -): Promise { - // '.' Is the fallback if no folder is open - // TODO?: Workspace folders support Uri's (eg: file://test.txt). - // It might be a good idea to test if the uri points to a file. - - const newEnv = substituteVariablesInEnv(Object.assign({}, process.env, extraEnv)); - const run: lc.Executable = { - command: serverPath, - options: { env: newEnv }, - }; - const serverOptions: lc.ServerOptions = { - run, - debug: run, - }; - - let initializationOptions = vscode.workspace.getConfiguration("rust-analyzer"); - - // Update outdated user configs - await updateConfig(initializationOptions).catch((err) => { - void vscode.window.showErrorMessage(`Failed updating old config keys: ${err.message}`); - }); - - if (workspace.kind === "Detached Files") { - initializationOptions = { - detachedFiles: workspace.files.map((file) => file.uri.fsPath), - ...initializationOptions, - }; - } - - const clientOptions: lc.LanguageClientOptions = { - documentSelector: [{ scheme: "file", language: "rust" }], - initializationOptions, - diagnosticCollectionName: "rustc", - traceOutputChannel: traceOutputChannel(), - outputChannel: outputChannel(), - middleware: { - async provideHover( - document: vscode.TextDocument, - position: vscode.Position, - token: vscode.CancellationToken, - _next: lc.ProvideHoverSignature - ) { - const editor = vscode.window.activeTextEditor; - const positionOrRange = editor?.selection?.contains(position) - ? client.code2ProtocolConverter.asRange(editor.selection) - : client.code2ProtocolConverter.asPosition(position); - return client - .sendRequest( - ra.hover, - { - textDocument: - client.code2ProtocolConverter.asTextDocumentIdentifier(document), - position: positionOrRange, - }, - token - ) - .then( - (result) => { - const hover = client.protocol2CodeConverter.asHover(result); - if (hover) { - const actions = (result).actions; - if (actions) { - hover.contents.push(renderHoverActions(actions)); - } - } - return hover; - }, - (error) => { - client.handleFailedRequest(lc.HoverRequest.type, token, error, null); - return Promise.resolve(null); - } - ); - }, - // Using custom handling of CodeActions to support action groups and snippet edits. - // Note that this means we have to re-implement lazy edit resolving ourselves as well. - async provideCodeActions( - document: vscode.TextDocument, - range: vscode.Range, - context: vscode.CodeActionContext, - token: vscode.CancellationToken, - _next: lc.ProvideCodeActionsSignature - ) { - const params: lc.CodeActionParams = { - textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), - range: client.code2ProtocolConverter.asRange(range), - context: await client.code2ProtocolConverter.asCodeActionContext( - context, - token - ), - }; - return client.sendRequest(lc.CodeActionRequest.type, params, token).then( - async (values) => { - if (values === null) return undefined; - const result: (vscode.CodeAction | vscode.Command)[] = []; - const groups = new Map< - string, - { index: number; items: vscode.CodeAction[] } - >(); - for (const item of values) { - // In our case we expect to get code edits only from diagnostics - if (lc.CodeAction.is(item)) { - assert( - !item.command, - "We don't expect to receive commands in CodeActions" - ); - const action = await client.protocol2CodeConverter.asCodeAction( - item, - token - ); - result.push(action); - continue; - } - assert( - isCodeActionWithoutEditsAndCommands(item), - "We don't expect edits or commands here" - ); - const kind = client.protocol2CodeConverter.asCodeActionKind( - (item as any).kind - ); - const action = new vscode.CodeAction(item.title, kind); - const group = (item as any).group; - action.command = { - command: "rust-analyzer.resolveCodeAction", - title: item.title, - arguments: [item], - }; - - // Set a dummy edit, so that VS Code doesn't try to resolve this. - action.edit = new WorkspaceEdit(); - - if (group) { - let entry = groups.get(group); - if (!entry) { - entry = { index: result.length, items: [] }; - groups.set(group, entry); - result.push(action); - } - entry.items.push(action); - } else { - result.push(action); - } - } - for (const [group, { index, items }] of groups) { - if (items.length === 1) { - result[index] = items[0]; - } else { - const action = new vscode.CodeAction(group); - action.kind = items[0].kind; - action.command = { - command: "rust-analyzer.applyActionGroup", - title: "", - arguments: [ - items.map((item) => { - return { - label: item.title, - arguments: item.command!.arguments![0], - }; - }), - ], - }; - - // Set a dummy edit, so that VS Code doesn't try to resolve this. - action.edit = new WorkspaceEdit(); - - result[index] = action; - } - } - return result; - }, - (_error) => undefined - ); - }, - }, - markdown: { - supportHtml: true, - }, - }; - - const client = new lc.LanguageClient( - "rust-analyzer", - "Rust Analyzer Language Server", - serverOptions, - clientOptions - ); - - // To turn on all proposed features use: client.registerProposedFeatures(); - client.registerFeature(new ExperimentalFeatures()); - - return client; -} - -class ExperimentalFeatures implements lc.StaticFeature { - fillClientCapabilities(capabilities: lc.ClientCapabilities): void { - const caps: any = capabilities.experimental ?? {}; - caps.snippetTextEdit = true; - caps.codeActionGroup = true; - caps.hoverActions = true; - caps.serverStatusNotification = true; - caps.commands = { - commands: [ - "rust-analyzer.runSingle", - "rust-analyzer.debugSingle", - "rust-analyzer.showReferences", - "rust-analyzer.gotoLocation", - "editor.action.triggerParameterHints", - ], - }; - capabilities.experimental = caps; - } - initialize( - _capabilities: lc.ServerCapabilities, - _documentSelector: lc.DocumentSelector | undefined - ): void {} - dispose(): void {} -} - -function isCodeActionWithoutEditsAndCommands(value: any): boolean { - const candidate: lc.CodeAction = value; - return ( - candidate && - Is.string(candidate.title) && - (candidate.diagnostics === void 0 || - Is.typedArray(candidate.diagnostics, lc.Diagnostic.is)) && - (candidate.kind === void 0 || Is.string(candidate.kind)) && - candidate.edit === void 0 && - candidate.command === void 0 - ); -} diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts deleted file mode 100644 index bf55329ca1f55..0000000000000 --- a/src/tools/rust-analyzer/editors/code/src/commands.ts +++ /dev/null @@ -1,952 +0,0 @@ -import * as vscode from "vscode"; -import * as lc from "vscode-languageclient"; -import * as ra from "./lsp_ext"; -import * as path from "path"; - -import { Ctx, Cmd } from "./ctx"; -import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets"; -import { spawnSync } from "child_process"; -import { RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run"; -import { AstInspector } from "./ast_inspector"; -import { isRustDocument, isCargoTomlDocument, sleep, isRustEditor } from "./util"; -import { startDebugSession, makeDebugConfig } from "./debug"; -import { LanguageClient } from "vscode-languageclient/node"; -import { LINKED_COMMANDS } from "./client"; - -export * from "./ast_inspector"; -export * from "./run"; - -export function analyzerStatus(ctx: Ctx): Cmd { - const tdcp = new (class implements vscode.TextDocumentContentProvider { - readonly uri = vscode.Uri.parse("rust-analyzer-status://status"); - readonly eventEmitter = new vscode.EventEmitter(); - - provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult { - if (!vscode.window.activeTextEditor) return ""; - - const params: ra.AnalyzerStatusParams = {}; - const doc = ctx.activeRustEditor?.document; - if (doc != null) { - params.textDocument = - ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(doc); - } - return ctx.client.sendRequest(ra.analyzerStatus, params); - } - - get onDidChange(): vscode.Event { - return this.eventEmitter.event; - } - })(); - - ctx.pushCleanup( - vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-status", tdcp) - ); - - return async () => { - const document = await vscode.workspace.openTextDocument(tdcp.uri); - tdcp.eventEmitter.fire(tdcp.uri); - void (await vscode.window.showTextDocument(document, { - viewColumn: vscode.ViewColumn.Two, - preserveFocus: true, - })); - }; -} - -export function memoryUsage(ctx: Ctx): Cmd { - const tdcp = new (class implements vscode.TextDocumentContentProvider { - readonly uri = vscode.Uri.parse("rust-analyzer-memory://memory"); - readonly eventEmitter = new vscode.EventEmitter(); - - provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult { - if (!vscode.window.activeTextEditor) return ""; - - return ctx.client.sendRequest(ra.memoryUsage).then((mem: any) => { - return "Per-query memory usage:\n" + mem + "\n(note: database has been cleared)"; - }); - } - - get onDidChange(): vscode.Event { - return this.eventEmitter.event; - } - })(); - - ctx.pushCleanup( - vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-memory", tdcp) - ); - - return async () => { - tdcp.eventEmitter.fire(tdcp.uri); - const document = await vscode.workspace.openTextDocument(tdcp.uri); - return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true); - }; -} - -export function shuffleCrateGraph(ctx: Ctx): Cmd { - return async () => { - const client = ctx.client; - if (!client) return; - - await client.sendRequest(ra.shuffleCrateGraph); - }; -} - -export function matchingBrace(ctx: Ctx): Cmd { - return async () => { - const editor = ctx.activeRustEditor; - const client = ctx.client; - if (!editor || !client) return; - - const response = await client.sendRequest(ra.matchingBrace, { - textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( - editor.document - ), - positions: editor.selections.map((s) => - client.code2ProtocolConverter.asPosition(s.active) - ), - }); - editor.selections = editor.selections.map((sel, idx) => { - const active = client.protocol2CodeConverter.asPosition(response[idx]); - const anchor = sel.isEmpty ? active : sel.anchor; - return new vscode.Selection(anchor, active); - }); - editor.revealRange(editor.selection); - }; -} - -export function joinLines(ctx: Ctx): Cmd { - return async () => { - const editor = ctx.activeRustEditor; - const client = ctx.client; - if (!editor || !client) return; - - const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, { - ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)), - textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( - editor.document - ), - }); - const textEdits = await client.protocol2CodeConverter.asTextEdits(items); - await editor.edit((builder) => { - textEdits.forEach((edit: any) => { - builder.replace(edit.range, edit.newText); - }); - }); - }; -} - -export function moveItemUp(ctx: Ctx): Cmd { - return moveItem(ctx, ra.Direction.Up); -} - -export function moveItemDown(ctx: Ctx): Cmd { - return moveItem(ctx, ra.Direction.Down); -} - -export function moveItem(ctx: Ctx, direction: ra.Direction): Cmd { - return async () => { - const editor = ctx.activeRustEditor; - const client = ctx.client; - if (!editor || !client) return; - - const lcEdits = await client.sendRequest(ra.moveItem, { - range: client.code2ProtocolConverter.asRange(editor.selection), - textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( - editor.document - ), - direction, - }); - - if (!lcEdits) return; - - const edits = await client.protocol2CodeConverter.asTextEdits(lcEdits); - await applySnippetTextEdits(editor, edits); - }; -} - -export function onEnter(ctx: Ctx): Cmd { - async function handleKeypress() { - const editor = ctx.activeRustEditor; - const client = ctx.client; - - if (!editor || !client) return false; - - const lcEdits = await client - .sendRequest(ra.onEnter, { - textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( - editor.document - ), - position: client.code2ProtocolConverter.asPosition(editor.selection.active), - }) - .catch((_error: any) => { - // client.handleFailedRequest(OnEnterRequest.type, error, null); - return null; - }); - if (!lcEdits) return false; - - const edits = await client.protocol2CodeConverter.asTextEdits(lcEdits); - await applySnippetTextEdits(editor, edits); - return true; - } - - return async () => { - if (await handleKeypress()) return; - - await vscode.commands.executeCommand("default:type", { text: "\n" }); - }; -} - -export function parentModule(ctx: Ctx): Cmd { - return async () => { - const editor = vscode.window.activeTextEditor; - const client = ctx.client; - if (!editor || !client) return; - if (!(isRustDocument(editor.document) || isCargoTomlDocument(editor.document))) return; - - const locations = await client.sendRequest(ra.parentModule, { - textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( - editor.document - ), - position: client.code2ProtocolConverter.asPosition(editor.selection.active), - }); - if (!locations) return; - - if (locations.length === 1) { - const loc = locations[0]; - - const uri = client.protocol2CodeConverter.asUri(loc.targetUri); - const range = client.protocol2CodeConverter.asRange(loc.targetRange); - - const doc = await vscode.workspace.openTextDocument(uri); - const e = await vscode.window.showTextDocument(doc); - e.selection = new vscode.Selection(range.start, range.start); - e.revealRange(range, vscode.TextEditorRevealType.InCenter); - } else { - const uri = editor.document.uri.toString(); - const position = client.code2ProtocolConverter.asPosition(editor.selection.active); - await showReferencesImpl( - client, - uri, - position, - locations.map((loc) => lc.Location.create(loc.targetUri, loc.targetRange)) - ); - } - }; -} - -export function openCargoToml(ctx: Ctx): Cmd { - return async () => { - const editor = ctx.activeRustEditor; - const client = ctx.client; - if (!editor || !client) return; - - const response = await client.sendRequest(ra.openCargoToml, { - textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( - editor.document - ), - }); - if (!response) return; - - const uri = client.protocol2CodeConverter.asUri(response.uri); - const range = client.protocol2CodeConverter.asRange(response.range); - - const doc = await vscode.workspace.openTextDocument(uri); - const e = await vscode.window.showTextDocument(doc); - e.selection = new vscode.Selection(range.start, range.start); - e.revealRange(range, vscode.TextEditorRevealType.InCenter); - }; -} - -export function ssr(ctx: Ctx): Cmd { - return async () => { - const editor = vscode.window.activeTextEditor; - const client = ctx.client; - if (!editor || !client) return; - - const position = editor.selection.active; - const selections = editor.selections; - const textDocument = ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( - editor.document - ); - - const options: vscode.InputBoxOptions = { - value: "() ==>> ()", - prompt: "Enter request, for example 'Foo($a) ==>> Foo::new($a)' ", - validateInput: async (x: string) => { - try { - await client.sendRequest(ra.ssr, { - query: x, - parseOnly: true, - textDocument, - position, - selections, - }); - } catch (e) { - return e.toString(); - } - return null; - }, - }; - const request = await vscode.window.showInputBox(options); - if (!request) return; - - await vscode.window.withProgress( - { - location: vscode.ProgressLocation.Notification, - title: "Structured search replace in progress...", - cancellable: false, - }, - async (_progress, token) => { - const edit = await client.sendRequest(ra.ssr, { - query: request, - parseOnly: false, - textDocument, - position, - selections, - }); - - await vscode.workspace.applyEdit( - await client.protocol2CodeConverter.asWorkspaceEdit(edit, token) - ); - } - ); - }; -} - -export function serverVersion(ctx: Ctx): Cmd { - return async () => { - const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" }); - const versionString = stdout.slice(`rust-analyzer `.length).trim(); - - void vscode.window.showInformationMessage(`rust-analyzer version: ${versionString}`); - }; -} - -export function toggleInlayHints(_ctx: Ctx): Cmd { - return async () => { - const config = vscode.workspace.getConfiguration("editor.inlayHints", { - languageId: "rust", - }); - const value = !config.get("enabled"); - await config.update("enabled", value, vscode.ConfigurationTarget.Global); - }; -} - -// Opens the virtual file that will show the syntax tree -// -// The contents of the file come from the `TextDocumentContentProvider` -export function syntaxTree(ctx: Ctx): Cmd { - const tdcp = new (class implements vscode.TextDocumentContentProvider { - readonly uri = vscode.Uri.parse("rust-analyzer-syntax-tree://syntaxtree/tree.rast"); - readonly eventEmitter = new vscode.EventEmitter(); - constructor() { - vscode.workspace.onDidChangeTextDocument( - this.onDidChangeTextDocument, - this, - ctx.subscriptions - ); - vscode.window.onDidChangeActiveTextEditor( - this.onDidChangeActiveTextEditor, - this, - ctx.subscriptions - ); - } - - private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { - if (isRustDocument(event.document)) { - // We need to order this after language server updates, but there's no API for that. - // Hence, good old sleep(). - void sleep(10).then(() => this.eventEmitter.fire(this.uri)); - } - } - private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { - if (editor && isRustEditor(editor)) { - this.eventEmitter.fire(this.uri); - } - } - - provideTextDocumentContent( - uri: vscode.Uri, - ct: vscode.CancellationToken - ): vscode.ProviderResult { - const rustEditor = ctx.activeRustEditor; - if (!rustEditor) return ""; - - // When the range based query is enabled we take the range of the selection - const range = - uri.query === "range=true" && !rustEditor.selection.isEmpty - ? ctx.client.code2ProtocolConverter.asRange(rustEditor.selection) - : null; - - const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range }; - return ctx.client.sendRequest(ra.syntaxTree, params, ct); - } - - get onDidChange(): vscode.Event { - return this.eventEmitter.event; - } - })(); - - void new AstInspector(ctx); - - ctx.pushCleanup( - vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-syntax-tree", tdcp) - ); - ctx.pushCleanup( - vscode.languages.setLanguageConfiguration("ra_syntax_tree", { - brackets: [["[", ")"]], - }) - ); - - return async () => { - const editor = vscode.window.activeTextEditor; - const rangeEnabled = !!editor && !editor.selection.isEmpty; - - const uri = rangeEnabled ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) : tdcp.uri; - - const document = await vscode.workspace.openTextDocument(uri); - - tdcp.eventEmitter.fire(uri); - - void (await vscode.window.showTextDocument(document, { - viewColumn: vscode.ViewColumn.Two, - preserveFocus: true, - })); - }; -} - -// Opens the virtual file that will show the HIR of the function containing the cursor position -// -// The contents of the file come from the `TextDocumentContentProvider` -export function viewHir(ctx: Ctx): Cmd { - const tdcp = new (class implements vscode.TextDocumentContentProvider { - readonly uri = vscode.Uri.parse("rust-analyzer-hir://viewHir/hir.txt"); - readonly eventEmitter = new vscode.EventEmitter(); - constructor() { - vscode.workspace.onDidChangeTextDocument( - this.onDidChangeTextDocument, - this, - ctx.subscriptions - ); - vscode.window.onDidChangeActiveTextEditor( - this.onDidChangeActiveTextEditor, - this, - ctx.subscriptions - ); - } - - private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { - if (isRustDocument(event.document)) { - // We need to order this after language server updates, but there's no API for that. - // Hence, good old sleep(). - void sleep(10).then(() => this.eventEmitter.fire(this.uri)); - } - } - private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { - if (editor && isRustEditor(editor)) { - this.eventEmitter.fire(this.uri); - } - } - - provideTextDocumentContent( - _uri: vscode.Uri, - ct: vscode.CancellationToken - ): vscode.ProviderResult { - const rustEditor = ctx.activeRustEditor; - const client = ctx.client; - if (!rustEditor || !client) return ""; - - const params = { - textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier( - rustEditor.document - ), - position: client.code2ProtocolConverter.asPosition(rustEditor.selection.active), - }; - return client.sendRequest(ra.viewHir, params, ct); - } - - get onDidChange(): vscode.Event { - return this.eventEmitter.event; - } - })(); - - ctx.pushCleanup( - vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-hir", tdcp) - ); - - return async () => { - const document = await vscode.workspace.openTextDocument(tdcp.uri); - tdcp.eventEmitter.fire(tdcp.uri); - void (await vscode.window.showTextDocument(document, { - viewColumn: vscode.ViewColumn.Two, - preserveFocus: true, - })); - }; -} - -export function viewFileText(ctx: Ctx): Cmd { - const tdcp = new (class implements vscode.TextDocumentContentProvider { - readonly uri = vscode.Uri.parse("rust-analyzer-file-text://viewFileText/file.rs"); - readonly eventEmitter = new vscode.EventEmitter(); - constructor() { - vscode.workspace.onDidChangeTextDocument( - this.onDidChangeTextDocument, - this, - ctx.subscriptions - ); - vscode.window.onDidChangeActiveTextEditor( - this.onDidChangeActiveTextEditor, - this, - ctx.subscriptions - ); - } - - private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { - if (isRustDocument(event.document)) { - // We need to order this after language server updates, but there's no API for that. - // Hence, good old sleep(). - void sleep(10).then(() => this.eventEmitter.fire(this.uri)); - } - } - private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { - if (editor && isRustEditor(editor)) { - this.eventEmitter.fire(this.uri); - } - } - - provideTextDocumentContent( - _uri: vscode.Uri, - ct: vscode.CancellationToken - ): vscode.ProviderResult { - const rustEditor = ctx.activeRustEditor; - const client = ctx.client; - if (!rustEditor || !client) return ""; - - const params = client.code2ProtocolConverter.asTextDocumentIdentifier( - rustEditor.document - ); - return client.sendRequest(ra.viewFileText, params, ct); - } - - get onDidChange(): vscode.Event { - return this.eventEmitter.event; - } - })(); - - ctx.pushCleanup( - vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-file-text", tdcp) - ); - - return async () => { - const document = await vscode.workspace.openTextDocument(tdcp.uri); - tdcp.eventEmitter.fire(tdcp.uri); - void (await vscode.window.showTextDocument(document, { - viewColumn: vscode.ViewColumn.Two, - preserveFocus: true, - })); - }; -} - -export function viewItemTree(ctx: Ctx): Cmd { - const tdcp = new (class implements vscode.TextDocumentContentProvider { - readonly uri = vscode.Uri.parse("rust-analyzer-item-tree://viewItemTree/itemtree.rs"); - readonly eventEmitter = new vscode.EventEmitter(); - constructor() { - vscode.workspace.onDidChangeTextDocument( - this.onDidChangeTextDocument, - this, - ctx.subscriptions - ); - vscode.window.onDidChangeActiveTextEditor( - this.onDidChangeActiveTextEditor, - this, - ctx.subscriptions - ); - } - - private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { - if (isRustDocument(event.document)) { - // We need to order this after language server updates, but there's no API for that. - // Hence, good old sleep(). - void sleep(10).then(() => this.eventEmitter.fire(this.uri)); - } - } - private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { - if (editor && isRustEditor(editor)) { - this.eventEmitter.fire(this.uri); - } - } - - provideTextDocumentContent( - _uri: vscode.Uri, - ct: vscode.CancellationToken - ): vscode.ProviderResult { - const rustEditor = ctx.activeRustEditor; - const client = ctx.client; - if (!rustEditor || !client) return ""; - - const params = { - textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier( - rustEditor.document - ), - }; - return client.sendRequest(ra.viewItemTree, params, ct); - } - - get onDidChange(): vscode.Event { - return this.eventEmitter.event; - } - })(); - - ctx.pushCleanup( - vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-item-tree", tdcp) - ); - - return async () => { - const document = await vscode.workspace.openTextDocument(tdcp.uri); - tdcp.eventEmitter.fire(tdcp.uri); - void (await vscode.window.showTextDocument(document, { - viewColumn: vscode.ViewColumn.Two, - preserveFocus: true, - })); - }; -} - -function crateGraph(ctx: Ctx, full: boolean): Cmd { - return async () => { - const nodeModulesPath = vscode.Uri.file(path.join(ctx.extensionPath, "node_modules")); - - const panel = vscode.window.createWebviewPanel( - "rust-analyzer.crate-graph", - "rust-analyzer crate graph", - vscode.ViewColumn.Two, - { - enableScripts: true, - retainContextWhenHidden: true, - localResourceRoots: [nodeModulesPath], - } - ); - const params = { - full: full, - }; - - const dot = await ctx.client.sendRequest(ra.viewCrateGraph, params); - const uri = panel.webview.asWebviewUri(nodeModulesPath); - - const html = ` - - - - - - - - - -

\ - Layout